27RCSID(
"$Id: 3007de21eba2a53aeceb3a6aba76f00e10712d9c $")
29#define LOG_PREFIX inst->name
31#include <freeradius-devel/server/base.h>
32#include <freeradius-devel/server/module_rlm.h>
33#include <freeradius-devel/unlang/call_env.h>
34#include <freeradius-devel/util/debug.h>
37#ifdef KRB5_IS_THREAD_SAFE
47#ifdef KRB5_IS_THREAD_SAFE
58#ifdef KRB5_IS_THREAD_SAFE
62 rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->
thread, rlm_krb5_thread_t);
66 ERROR(
"Handle pool instantiation failed");
75 rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->
thread, rlm_krb5_thread_t);
88 if (
inst->gic_options) krb5_get_init_creds_opt_free(
inst->context,
inst->gic_options);
89 if (
inst->server) krb5_free_principal(
inst->context,
inst->server);
95 if (
inst->context) krb5_free_context(
inst->context);
106 char keytab_name[200];
111 DEBUG(
"Using Heimdal Kerberos library");
113 DEBUG(
"Using MIT Kerberos library");
117 if (!krb5_is_thread_safe()) {
121#ifdef KRB5_IS_THREAD_SAFE
122 ERROR(
"Build time libkrb5 was threadsafe, but run time library claims not to be");
123 ERROR(
"Modify runtime linker path (LD_LIBRARY_PATH on most systems), to prefer threadsafe libkrb5");
130 "libkrb5 is not threadsafe, recompile it with thread support enabled ("
132 "--enable-pthread-support"
134 "--disable-thread-support=no"
137 WARN(
"rlm_krb5 will run in single threaded mode, performance may be degraded");
139 WARN(
"Build time libkrb5 was not threadsafe, but run time library claims to be");
140 WARN(
"Reconfigure and recompile rlm_krb5 to enable thread support");
144 ret = krb5_init_context(&
inst->context);
156 if (
inst->service_princ) {
159 inst->hostname = strchr(
inst->service_princ,
'/');
160 if (
inst->hostname) {
161 len = (
inst->hostname -
inst->service_princ);
164 len = strlen(
inst->service_princ);
168 inst->service = talloc_array(
inst,
char, (len + 1));
174 if (
inst->hostname)
DEBUG(
"Ignoring hostname component of service principal \"%s\", not "
175 "needed/supported by Heimdal",
inst->hostname);
181 ret = krb5_sname_to_principal(
inst->context,
inst->hostname,
inst->service, KRB5_NT_SRV_HST, &(
inst->server));
188 ret = krb5_unparse_name(
inst->context,
inst->server, &princ_name);
199 DEBUG(
"Using service principal \"%s\"", princ_name);
200 krb5_free_unparsed_name(
inst->context, princ_name);
205 ret = krb5_get_init_creds_opt_alloc(
inst->context, &(
inst->gic_options));
216 ret =
inst->keytabname ?
217 krb5_kt_resolve(
inst->context,
inst->keytabname, &keytab) :
218 krb5_kt_default(
inst->context, &keytab);
225 ret = krb5_kt_get_name(
inst->context, keytab, keytab_name,
sizeof(keytab_name));
226 krb5_kt_close(
inst->context, keytab);
233 DEBUG(
"Using keytab \"%s\"", keytab_name);
235 MEM(
inst->vic_options = talloc_zero(
inst, krb5_verify_init_creds_opt));
236 krb5_verify_init_creds_opt_init(
inst->vic_options);
237 krb5_verify_init_creds_opt_set_ap_req_nofail(
inst->vic_options,
true);
240#ifndef KRB5_IS_THREAD_SAFE
242 if (!
inst->conn)
return -1;
268 krb5_unparse_name(
context, *client, &princ_name);
269 RDEBUG2(
"Using client principal \"%s\"", princ_name);
273 krb5_free_unparsed_name(
context, princ_name);
294 case KRB5_LIBOS_BADPWDMATCH:
295 case KRB5KRB_AP_ERR_BAD_INTEGRITY:
299 case KRB5KDC_ERR_KEY_EXP:
300 case KRB5KDC_ERR_CLIENT_REVOKED:
301 case KRB5KDC_ERR_SERVICE_REVOKED:
305 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
324# ifdef KRB5_IS_THREAD_SAFE
325 rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->
thread, rlm_krb5_thread_t);
330 krb5_principal client = NULL;
336 REDEBUG(
"User-Password must not be empty");
346 RDEBUG2(
"Login attempt with password");
349# ifdef KRB5_IS_THREAD_SAFE
350 conn = krb5_slab_reserve(t->slab);
362 ret = krb5_verify_user_opt(conn->
context, client, env->
password.vb_strvalue, &conn->options);
379 krb5_cc_cursor cursor;
382 krb5_cc_start_seq_get(conn->
context, conn->ccache, &cursor);
383 for (ret = krb5_cc_next_cred(conn->
context, conn->ccache, &cursor, &cred);
385 ret = krb5_cc_next_cred(conn->
context, conn->ccache, &cursor, &cred)) {
386 krb5_cc_remove_cred(conn->
context, conn->ccache, 0, &cred);
388 krb5_cc_end_seq_get(conn->
context, conn->ccache, &cursor);
393 krb5_free_principal(conn->
context, client);
396# ifdef KRB5_IS_THREAD_SAFE
397 krb5_slab_release(conn);
411# ifdef KRB5_IS_THREAD_SAFE
412 rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->
thread, rlm_krb5_thread_t);
419 krb5_principal client = NULL;
420 krb5_creds init_creds;
426 REDEBUG(
"User-Password must not be empty");
436 RDEBUG2(
"Login attempt with password");
439# ifdef KRB5_IS_THREAD_SAFE
440 conn = krb5_slab_reserve(t->slab);
449 memset(&init_creds, 0,
sizeof(init_creds));
461 RDEBUG2(
"Retrieving and decrypting TGT");
462 ret = krb5_get_init_creds_password(conn->
context, &init_creds, client,
UNCONST(
char *, env->
password.vb_strvalue),
463 NULL, NULL, 0, NULL,
inst->gic_options);
469 RDEBUG2(
"Attempting to authenticate against service principal");
470 ret = krb5_verify_init_creds(conn->
context, &init_creds,
inst->server, conn->
keytab, NULL,
inst->vic_options);
474 if (client) krb5_free_principal(conn->
context, client);
475 krb5_free_cred_contents(conn->
context, &init_creds);
477# ifdef KRB5_IS_THREAD_SAFE
478 krb5_slab_release(conn);
489 .pair.dflt =
"&User-Name", .pair.dflt_quote =
T_BARE_WORD },
491 .pair.dflt =
"&User-Password", .pair.dflt_quote =
T_BARE_WORD },
504#ifndef KRB5_IS_THREAD_SAFE
507 .thread_inst_size =
sizeof(rlm_krb5_thread_t),
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define CALL_ENV_TERMINATOR
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
call_env_parser_t const * env
Parsing rules for call method env.
@ CALL_ENV_FLAG_SECRET
The value is a secret, and should not be logged.
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Defines a CONF_PAIR to C data type mapping.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
int krb5_handle_init(rlm_krb5_handle_t *conn, void *uctx)
void * krb5_mod_conn_create(TALLOC_CTX *ctx, void *instance, UNUSED fr_time_delta_t timeout)
Create and return a new connection.
Context management functions for rlm_krb5.
#define rlm_krb5_error(_x, _y, _z)
Instance configuration for rlm_krb5.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
@ FR_TYPE_STRING
String of printable characters.
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
void * thread
Thread specific instance data.
fr_event_list_t * el
Event list to register any IO handlers and timers against.
module_instance_t * mi
Module instance to detach.
void * thread
Thread instance data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for detach calls.
Temporary structure to hold arguments for instantiation calls.
Temporary structure to hold arguments for thread_instantiation calls.
module_t common
Common fields presented by all modules.
static void thread_detach(UNUSED void *uctx)
Explicitly cleanup module/xlat resources.
static int thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el, UNUSED void *uctx)
Create module and xlat per-thread instances.
#define RETURN_MODULE_RCODE(_rcode)
#define RETURN_MODULE_INVALID
#define RETURN_MODULE_FAIL
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_FAIL
Module failed, don't reply.
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
@ RLM_MODULE_REJECT
Immediately reject the request.
@ RLM_MODULE_NOTFOUND
User not found.
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int mod_detach(module_detach_ctx_t const *mctx)
static rlm_rcode_t krb5_process_error(rlm_krb5_t const *inst, request_t *request, rlm_krb5_handle_t *conn, int ret)
Log error message and return appropriate rcode.
static const call_env_method_t krb5_auth_call_env
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
static rlm_rcode_t krb5_parse_user(krb5_principal *client, KRB5_UNUSED rlm_krb5_t const *inst, request_t *request, krb5_context context, krb5_auth_call_env_t *env)
Common function for transforming a User-Name string into a principal.
static const conf_parser_t module_config[]
static int mod_instantiate(module_inst_ctx_t const *mctx)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
module_flags_t flags
Flags that control how a module starts up and how a module is called.
void * data
Module's instance data.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
#define FR_SLAB_CONFIG_CONF_PARSER
conf_parser_t entries to populate user configurable slab values
eap_aka_sim_process_conf_t * inst
size_t strlcpy(char *dst, char const *src, size_t siz)
#define talloc_get_type_abort_const
#define fr_time_delta_wrap(_time)