27RCSID(
"$Id: 9ef3cd59f854b0a5ee33d20c0aa65c03a7a0fb2b $")
29#define LOG_PREFIX inst->name
31#include <freeradius-devel/server/base.h>
32#include <freeradius-devel/server/module_rlm.h>
35#ifdef KRB5_IS_THREAD_SAFE
45#ifdef KRB5_IS_THREAD_SAFE
56#ifdef KRB5_IS_THREAD_SAFE
60 rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->
thread, rlm_krb5_thread_t);
64 ERROR(
"Handle pool instantiation failed");
73 rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->
thread, rlm_krb5_thread_t);
86 if (
inst->gic_options) krb5_get_init_creds_opt_free(
inst->context,
inst->gic_options);
87 if (
inst->server) krb5_free_principal(
inst->context,
inst->server);
93 if (
inst->context) krb5_free_context(
inst->context);
104 char keytab_name[200];
109 DEBUG(
"Using Heimdal Kerberos library");
111 DEBUG(
"Using MIT Kerberos library");
115 if (!krb5_is_thread_safe()) {
119#ifdef KRB5_IS_THREAD_SAFE
120 ERROR(
"Build time libkrb5 was threadsafe, but run time library claims not to be");
121 ERROR(
"Modify runtime linker path (LD_LIBRARY_PATH on most systems), to prefer threadsafe libkrb5");
128 "libkrb5 is not threadsafe, recompile it with thread support enabled ("
130 "--enable-pthread-support"
132 "--disable-thread-support=no"
135 WARN(
"rlm_krb5 will run in single threaded mode, performance may be degraded");
137 WARN(
"Build time libkrb5 was not threadsafe, but run time library claims to be");
138 WARN(
"Reconfigure and recompile rlm_krb5 to enable thread support");
142 ret = krb5_init_context(&
inst->context);
154 if (
inst->service_princ) {
157 inst->hostname = strchr(
inst->service_princ,
'/');
158 if (
inst->hostname) {
159 len = (
inst->hostname -
inst->service_princ);
162 len = strlen(
inst->service_princ);
166 inst->service = talloc_array(
inst,
char, (len + 1));
172 if (
inst->hostname)
DEBUG(
"Ignoring hostname component of service principal \"%s\", not "
173 "needed/supported by Heimdal",
inst->hostname);
179 ret = krb5_sname_to_principal(
inst->context,
inst->hostname,
inst->service, KRB5_NT_SRV_HST, &(
inst->server));
186 ret = krb5_unparse_name(
inst->context,
inst->server, &princ_name);
197 DEBUG(
"Using service principal \"%s\"", princ_name);
198 krb5_free_unparsed_name(
inst->context, princ_name);
203 ret = krb5_get_init_creds_opt_alloc(
inst->context, &(
inst->gic_options));
214 ret =
inst->keytabname ?
215 krb5_kt_resolve(
inst->context,
inst->keytabname, &keytab) :
216 krb5_kt_default(
inst->context, &keytab);
223 ret = krb5_kt_get_name(
inst->context, keytab, keytab_name,
sizeof(keytab_name));
224 krb5_kt_close(
inst->context, keytab);
231 DEBUG(
"Using keytab \"%s\"", keytab_name);
233 MEM(
inst->vic_options = talloc_zero(
inst, krb5_verify_init_creds_opt));
234 krb5_verify_init_creds_opt_init(
inst->vic_options);
235 krb5_verify_init_creds_opt_set_ap_req_nofail(
inst->vic_options,
true);
238#ifndef KRB5_IS_THREAD_SAFE
240 if (!
inst->conn)
return -1;
266 krb5_unparse_name(
context, *client, &princ_name);
267 RDEBUG2(
"Using client principal \"%s\"", princ_name);
271 krb5_free_unparsed_name(
context, princ_name);
292 case KRB5_LIBOS_BADPWDMATCH:
293 case KRB5KRB_AP_ERR_BAD_INTEGRITY:
297 case KRB5KDC_ERR_KEY_EXP:
298 case KRB5KDC_ERR_CLIENT_REVOKED:
299 case KRB5KDC_ERR_SERVICE_REVOKED:
303 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
322# ifdef KRB5_IS_THREAD_SAFE
323 rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->
thread, rlm_krb5_thread_t);
328 krb5_principal client = NULL;
334 REDEBUG(
"User-Password must not be empty");
344 RDEBUG2(
"Login attempt with password");
347# ifdef KRB5_IS_THREAD_SAFE
348 conn = krb5_slab_reserve(t->slab);
360 ret = krb5_verify_user_opt(conn->
context, client, env->
password.vb_strvalue, &conn->options);
377 krb5_cc_cursor cursor;
380 krb5_cc_start_seq_get(conn->
context, conn->ccache, &cursor);
381 for (ret = krb5_cc_next_cred(conn->
context, conn->ccache, &cursor, &cred);
383 ret = krb5_cc_next_cred(conn->
context, conn->ccache, &cursor, &cred)) {
384 krb5_cc_remove_cred(conn->
context, conn->ccache, 0, &cred);
386 krb5_cc_end_seq_get(conn->
context, conn->ccache, &cursor);
391 krb5_free_principal(conn->
context, client);
394# ifdef KRB5_IS_THREAD_SAFE
395 krb5_slab_release(conn);
409# ifdef KRB5_IS_THREAD_SAFE
410 rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->
thread, rlm_krb5_thread_t);
417 krb5_principal client = NULL;
418 krb5_creds init_creds;
424 REDEBUG(
"User-Password must not be empty");
434 RDEBUG2(
"Login attempt with password");
437# ifdef KRB5_IS_THREAD_SAFE
438 conn = krb5_slab_reserve(t->slab);
447 memset(&init_creds, 0,
sizeof(init_creds));
459 RDEBUG2(
"Retrieving and decrypting TGT");
460 ret = krb5_get_init_creds_password(conn->
context, &init_creds, client,
UNCONST(
char *, env->
password.vb_strvalue),
461 NULL, NULL, 0, NULL,
inst->gic_options);
467 RDEBUG2(
"Attempting to authenticate against service principal");
468 ret = krb5_verify_init_creds(conn->
context, &init_creds,
inst->server, conn->
keytab, NULL,
inst->vic_options);
472 if (client) krb5_free_principal(conn->
context, client);
473 krb5_free_cred_contents(conn->
context, &init_creds);
475# ifdef KRB5_IS_THREAD_SAFE
476 krb5_slab_release(conn);
487 .pair.dflt =
"User-Name", .pair.dflt_quote =
T_BARE_WORD },
489 .pair.dflt =
"User-Password", .pair.dflt_quote =
T_BARE_WORD },
502#ifndef KRB5_IS_THREAD_SAFE
505 .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.
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
#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_UNLANG_INVALID
#define RETURN_UNLANG_RCODE(_rcode)
#define RETURN_UNLANG_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 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 unlang_action_t mod_authenticate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
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)