27 RCSID(
"$Id: 033f6148c216b1211ebc6f88ef4d121c50c44441 $")
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
499 #ifndef 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.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
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.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Module instance to detach.
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.
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)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
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)