27 RCSID(
"$Id: d8ae10906d40630b8451fa6e4400c7591a331275 $")
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/util/debug.h>
67 if (
inst->gic_options) krb5_get_init_creds_opt_free(
inst->context,
inst->gic_options);
68 if (
inst->server) krb5_free_principal(
inst->context,
inst->server);
74 if (
inst->context) krb5_free_context(
inst->context);
75 #ifdef KRB5_IS_THREAD_SAFE
88 char keytab_name[200];
93 DEBUG(
"Using Heimdal Kerberos library");
95 DEBUG(
"Using MIT Kerberos library");
99 if (!krb5_is_thread_safe()) {
103 #ifdef KRB5_IS_THREAD_SAFE
104 ERROR(
"Build time libkrb5 was threadsafe, but run time library claims not to be");
105 ERROR(
"Modify runtime linker path (LD_LIBRARY_PATH on most systems), to prefer threadsafe libkrb5");
112 "libkrb5 is not threadsafe, recompile it with thread support enabled ("
114 "--enable-pthread-support"
116 "--disable-thread-support=no"
119 WARN(
"rlm_krb5 will run in single threaded mode, performance may be degraded");
121 WARN(
"Build time libkrb5 was not threadsafe, but run time library claims to be");
122 WARN(
"Reconfigure and recompile rlm_krb5 to enable thread support");
126 ret = krb5_init_context(&
inst->context);
138 if (
inst->service_princ) {
141 inst->hostname = strchr(
inst->service_princ,
'/');
142 if (
inst->hostname) {
143 len = (
inst->hostname -
inst->service_princ);
146 len = strlen(
inst->service_princ);
150 inst->service = talloc_array(
inst,
char, (len + 1));
156 if (
inst->hostname)
DEBUG(
"Ignoring hostname component of service principal \"%s\", not "
157 "needed/supported by Heimdal",
inst->hostname);
163 ret = krb5_sname_to_principal(
inst->context,
inst->hostname,
inst->service, KRB5_NT_SRV_HST, &(
inst->server));
170 ret = krb5_unparse_name(
inst->context,
inst->server, &princ_name);
181 DEBUG(
"Using service principal \"%s\"", princ_name);
182 krb5_free_unparsed_name(
inst->context, princ_name);
187 ret = krb5_get_init_creds_opt_alloc(
inst->context, &(
inst->gic_options));
198 ret =
inst->keytabname ?
199 krb5_kt_resolve(
inst->context,
inst->keytabname, &keytab) :
200 krb5_kt_default(
inst->context, &keytab);
207 ret = krb5_kt_get_name(
inst->context, keytab, keytab_name,
sizeof(keytab_name));
208 krb5_kt_close(
inst->context, keytab);
215 DEBUG(
"Using keytab \"%s\"", keytab_name);
217 MEM(
inst->vic_options = talloc_zero(
inst, krb5_verify_init_creds_opt));
218 krb5_verify_init_creds_opt_init(
inst->vic_options);
221 #ifdef KRB5_IS_THREAD_SAFE
226 if (!
inst->pool)
return -1;
229 if (!
inst->conn)
return -1;
255 REDEBUG(
"Attribute \"User-Name\" is required for authentication");
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:
324 krb5_principal client = NULL;
330 REDEBUG(
"Attribute \"User-Password\" is required for authentication");
337 if (password->vp_length == 0) {
338 REDEBUG(
"User-Password must not be empty");
346 RDEBUG(
"Login attempt with password \"%pV\"", &password->data);
348 RDEBUG2(
"Login attempt with password");
351 # ifdef KRB5_IS_THREAD_SAFE
364 ret = krb5_verify_user_opt(conn->
context, client, password->vp_strvalue, &conn->options);
381 krb5_cc_cursor cursor;
384 krb5_cc_start_seq_get(conn->
context, conn->ccache, &cursor);
385 for (ret = krb5_cc_next_cred(conn->
context, conn->ccache, &cursor, &cred);
387 ret = krb5_cc_next_cred(conn->
context, conn->ccache, &cursor, &cred)) {
388 krb5_cc_remove_cred(conn->
context, conn->ccache, 0, &cred);
390 krb5_cc_end_seq_get(conn->
context, conn->ccache, &cursor);
395 krb5_free_principal(conn->
context, client);
398 # ifdef KRB5_IS_THREAD_SAFE
417 krb5_principal client = NULL;
418 krb5_creds init_creds;
424 REDEBUG(
"Attribute \"User-Password\" is required for authentication");
431 if (password->vp_length == 0) {
432 REDEBUG(
"User-Password must not be empty");
440 RDEBUG(
"Login attempt with password \"%pV\"", &password->data);
442 RDEBUG2(
"Login attempt with password");
445 # ifdef KRB5_IS_THREAD_SAFE
455 memset(&init_creds, 0,
sizeof(init_creds));
467 RDEBUG2(
"Retrieving and decrypting TGT");
468 ret = krb5_get_init_creds_password(conn->
context, &init_creds, client,
UNCONST(
char *, password->vp_strvalue),
469 NULL, NULL, 0, NULL,
inst->gic_options);
475 RDEBUG2(
"Attempting to authenticate against service principal");
476 ret = krb5_verify_init_creds(conn->
context, &init_creds,
inst->server, conn->
keytab, NULL,
inst->vic_options);
480 if (client) krb5_free_principal(conn->
context, client);
481 krb5_free_cred_contents(conn->
context, &init_creds);
483 # ifdef KRB5_IS_THREAD_SAFE
496 #ifdef KRB5_IS_THREAD_SAFE
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 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
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.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
void *_CONST data
Module instance's parsed configuration.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
CONF_SECTION *_CONST conf
Module's instance configuration.
dl_module_inst_t const * inst
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.
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
Specifies a module method identifier.
fr_pool_t * module_rlm_connection_pool_init(CONF_SECTION *module, void *opaque, fr_pool_connection_create_t c, fr_pool_connection_alive_t a, char const *log_prefix, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Initialise a module specific connection pool.
module_t common
Common fields presented by all modules.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
Release a connection.
void fr_pool_free(fr_pool_t *pool)
Delete a connection pool.
void * fr_pool_connection_get(fr_pool_t *pool, request_t *request)
Reserve a connection in the connection pool.
static const conf_parser_t config[]
#define RETURN_MODULE_RCODE(_rcode)
#define RETURN_MODULE_INVALID
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_detach(module_detach_ctx_t const *mctx)
static fr_dict_attr_t const * attr_user_password
fr_dict_autoload_t rlm_krb5_dict[]
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.
fr_dict_attr_autoload_t rlm_krb5_dict_attr[]
static fr_dict_t const * dict_radius
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)
Common function for transforming a User-Name string into a principal.
static fr_dict_attr_t const * attr_user_name
static const conf_parser_t module_config[]
static int mod_instantiate(module_inst_ctx_t const *mctx)
static int instantiate(module_inst_ctx_t const *mctx)
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
@ MODULE_TYPE_THREAD_SAFE
Module is threadsafe.
#define MODULE_NAME_TERMINATOR
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
size_t strlcpy(char *dst, char const *src, size_t siz)
Stores an attribute, a value and various bits of other data.
#define talloc_get_type_abort_const
#define fr_time_delta_wrap(_time)