Skip to content

Commit

Permalink
Use call_env for username and password in krb5
Browse files Browse the repository at this point in the history
  • Loading branch information
ndptech committed Dec 12, 2024
1 parent 919e3b6 commit f8ed3c1
Showing 1 changed file with 30 additions and 56 deletions.
86 changes: 30 additions & 56 deletions src/modules/rlm_krb5/rlm_krb5.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ RCSID("$Id$")

#include <freeradius-devel/server/base.h>
#include <freeradius-devel/server/module_rlm.h>
#include <freeradius-devel/unlang/call_env.h>
#include <freeradius-devel/util/debug.h>
#include "krb5.h"

Expand All @@ -49,23 +50,10 @@ static const conf_parser_t module_config[] = {
CONF_PARSER_TERMINATOR
};

static fr_dict_t const *dict_radius;

extern fr_dict_autoload_t rlm_krb5_dict[];
fr_dict_autoload_t rlm_krb5_dict[] = {
{ .out = &dict_radius, .proto = "radius" },
{ NULL }
};

static fr_dict_attr_t const *attr_user_name;
static fr_dict_attr_t const *attr_user_password;

extern fr_dict_attr_autoload_t rlm_krb5_dict_attr[];
fr_dict_attr_autoload_t rlm_krb5_dict_attr[] = {
{ .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
{ .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
{ NULL }
};
typedef struct {
fr_value_box_t username;
fr_value_box_t password;
} krb5_auth_call_env_t;

#ifdef KRB5_IS_THREAD_SAFE
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Expand Down Expand Up @@ -262,26 +250,15 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
* @param[in] inst of rlm_krb5.
* @param[in] request Current request.
* @param[in] context Kerberos context.
* @param[in] env call env data containing username.
*/
static rlm_rcode_t krb5_parse_user(krb5_principal *client, KRB5_UNUSED rlm_krb5_t const *inst, request_t *request,
krb5_context context)
krb5_context context, krb5_auth_call_env_t *env)
{
krb5_error_code ret;
char *princ_name;
fr_pair_t *username;

username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);

/*
* We can only authenticate user requests which HAVE
* a User-Name attribute.
*/
if (!username) {
REDEBUG("Attribute \"User-Name\" is required for authentication");
return RLM_MODULE_FAIL;
}

ret = krb5_parse_name(context, username->vp_strvalue, client);
ret = krb5_parse_name(context, env->username.vb_strvalue, client);
if (ret) {
REDEBUG("Failed parsing username as principal: %s", rlm_krb5_error(inst, context, ret));

Expand Down Expand Up @@ -342,6 +319,7 @@ static rlm_rcode_t krb5_process_error(rlm_krb5_t const *inst, request_t *request
*/
static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
{
krb5_auth_call_env_t *env = talloc_get_type_abort(mctx->env_data, krb5_auth_call_env_t);
rlm_krb5_t const *inst = talloc_get_type_abort_const(mctx->mi->data, rlm_krb5_t);
# ifdef KRB5_IS_THREAD_SAFE
rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_krb5_thread_t);
Expand All @@ -350,19 +328,11 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
krb5_error_code ret;
rlm_krb5_handle_t *conn;
krb5_principal client = NULL;
fr_pair_t *password;

password = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);

if (!password) {
REDEBUG("Attribute \"User-Password\" is required for authentication");
RETURN_MODULE_INVALID;
}

/*
* Make sure the supplied password isn't empty
*/
if (password->vp_length == 0) {
if (env->password.vb_length == 0) {
REDEBUG("User-Password must not be empty");
RETURN_MODULE_INVALID;
}
Expand All @@ -371,7 +341,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
* Log the password
*/
if (RDEBUG_ENABLED3) {
RDEBUG("Login attempt with password \"%pV\"", &password->data);
RDEBUG("Login attempt with password \"%pV\"", &env->password);
} else {
RDEBUG2("Login attempt with password");
}
Expand All @@ -383,13 +353,13 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
conn = inst->conn;
# endif

rcode = krb5_parse_user(&client, inst, request, conn->context);
rcode = krb5_parse_user(&client, inst, request, conn->context, env);
if (rcode != RLM_MODULE_OK) goto cleanup;

/*
* Verify the user, using the options we set in instantiate
*/
ret = krb5_verify_user_opt(conn->context, client, password->vp_strvalue, &conn->options);
ret = krb5_verify_user_opt(conn->context, client, env->password.vb_strvalue, &conn->options);
if (ret) {
rcode = krb5_process_error(inst, request, conn, ret);
goto cleanup;
Expand Down Expand Up @@ -436,6 +406,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
*/
static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
{
krb5_auth_call_env_t *env = talloc_get_type_abort(mctx->env_data, krb5_auth_call_env_t);
rlm_krb5_t const *inst = talloc_get_type_abort_const(mctx->mi->data, rlm_krb5_t);
# ifdef KRB5_IS_THREAD_SAFE
rlm_krb5_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_krb5_thread_t);
Expand All @@ -447,19 +418,11 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,

krb5_principal client = NULL; /* actually a pointer value */
krb5_creds init_creds;
fr_pair_t *password;

password = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);

if (!password) {
REDEBUG("Attribute \"User-Password\" is required for authentication");
RETURN_MODULE_INVALID;
}

/*
* Make sure the supplied password isn't empty
*/
if (password->vp_length == 0) {
if (env->password.vb_length == 0) {
REDEBUG("User-Password must not be empty");
RETURN_MODULE_INVALID;
}
Expand All @@ -468,7 +431,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
* Log the password
*/
if (RDEBUG_ENABLED3) {
RDEBUG("Login attempt with password \"%pV\"", &password->data);
RDEBUG("Login attempt with password \"%pV\"", &env->password);
} else {
RDEBUG2("Login attempt with password");
}
Expand All @@ -489,14 +452,14 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
* Check we have all the required VPs, and convert the username
* into a principal.
*/
rcode = krb5_parse_user(&client, inst, request, conn->context);
rcode = krb5_parse_user(&client, inst, request, conn->context, env);
if (rcode != RLM_MODULE_OK) goto cleanup;

/*
* Retrieve the TGT from the TGS/KDC and check we can decrypt it.
*/
RDEBUG2("Retrieving and decrypting TGT");
ret = krb5_get_init_creds_password(conn->context, &init_creds, client, UNCONST(char *, password->vp_strvalue),
ret = krb5_get_init_creds_password(conn->context, &init_creds, client, UNCONST(char *, env->password.vb_strvalue),
NULL, NULL, 0, NULL, inst->gic_options);
if (ret) {
rcode = krb5_process_error(inst, request, conn, ret);
Expand All @@ -519,6 +482,17 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,

#endif /* MIT_KRB5 */

static const call_env_method_t krb5_auth_call_env = {
FR_CALL_ENV_METHOD_OUT(krb5_auth_call_env_t),
.env = (call_env_parser_t[]) {
{ FR_CALL_ENV_OFFSET("username", FR_TYPE_STRING, CALL_ENV_FLAG_REQUIRED, krb5_auth_call_env_t, username),
.pair.dflt = "&User-Name", .pair.dflt_quote = T_BARE_WORD },
{ FR_CALL_ENV_OFFSET("password", FR_TYPE_STRING, CALL_ENV_FLAG_SECRET | CALL_ENV_FLAG_REQUIRED, krb5_auth_call_env_t, password),
.pair.dflt = "&User-Password", .pair.dflt_quote = T_BARE_WORD },
CALL_ENV_TERMINATOR
}
};

extern module_rlm_t rlm_krb5;
module_rlm_t rlm_krb5 = {
.common = {
Expand All @@ -541,7 +515,7 @@ module_rlm_t rlm_krb5 = {
},
.method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &krb5_auth_call_env },
MODULE_BINDING_TERMINATOR
}
}
Expand Down

0 comments on commit f8ed3c1

Please sign in to comment.