* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000,2006,2012 The FreeRADIUS server project
* Copyright 2000 Nathan Neulinger <nneul@umr.edu>
* Copyright 2000 Alan DeKok <aland@ox.org>
*/
#include <com_err.h>
/* Arbitrary 64char limit on service names */
-#define SERVICE_NAME_LEN 64;
+#define SERVICE_NAME_LEN 64
typedef struct rlm_krb5_t {
const char *keytab;
#ifndef HEIMDAL_KRB5
-static int krb5_build_auth_context(rlm_krb5_t *instance,
+static int krb5_build_auth_context(rlm_krb5_t *inst,
krb5_context context,
krb5_auth_context *auth_context)
{
- int r;
+ int ret;
krb5_int32 flags;
- r = krb5_auth_con_init(context, auth_context);
- if (r)
- return r;
+ ret = krb5_auth_con_init(context, auth_context);
+ if (ret)
+ return ret;
- r = krb5_auth_con_getflags(context, *auth_context, &flags);
- if (r)
- return r;
+ ret = krb5_auth_con_getflags(context, *auth_context, &flags);
+ if (ret)
+ return ret;
- if (!instance->cache && (flags & KRB5_AUTH_CONTEXT_DO_TIME)) {
- r = krb5_auth_con_setflags(context, *auth_context, flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
+ if (!inst->cache && (flags & KRB5_AUTH_CONTEXT_DO_TIME)) {
+ ret = krb5_auth_con_setflags(context, *auth_context, flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
- if (r)
- return r;
+ if (ret)
+ return ret;
}
return 0;
}
-static int verify_krb5_tgt(krb5_context context, rlm_krb5_t *instance,
- const char *user, krb5_ccache ccache)
+static int verify_krb5_tgt(krb5_context context, rlm_krb5_t *inst,
+ const char *user, krb5_ccache ccache)
{
- int r;
+ int rcode;
+ int ret;
char phost[BUFSIZ];
krb5_principal princ;
krb5_keyblock *keyblock = 0;
krb5_data packet, *server;
krb5_auth_context auth_context = NULL;
krb5_keytab keytab;
+
char service[SERVICE_NAME_LEN] = "host";
- char *servername = NULL;
+ char *server_name = NULL;
+ char *keytab_name;
+
+ /* krb5_kt_read_service_key lacks const qualifier */
+ memcpy(keytab_name, inst->keytab, sizeof(keytab_name));
- if (instance->service_princ != NULL) {
- servername = strchr(instance->service_princ, '/');
- if (servername != NULL) {
- *servername = '\0';
+ if (inst->service_princ != NULL) {
+ server_name = strchr(inst->service_princ, '/');
+ if (server_name != NULL) {
+ *server_name = '\0';
}
- strlcpy(service,instance->service_princ,sizeof(service));
- service[sizeof(service)-1] = '\0';
+ strlcpy(service, inst->service_princ, sizeof(service));
- if (servername != NULL) {
- *servername = '/';
- servername++;
+ if (server_name != NULL) {
+ *server_name = '/';
+ server_name++;
}
}
memset(&packet, 0, sizeof packet);
- if ((r = krb5_sname_to_principal(context, servername, service,
- KRB5_NT_SRV_HST, &princ)))
- {
+ ret = krb5_sname_to_principal(context, server_name, service,
+ KRB5_NT_SRV_HST, &princ);
+ if (ret) {
radlog(L_DBG, "rlm_krb5: [%s] krb5_sname_to_principal failed: %s",
- user, error_message(r));
+ user, error_message(ret));
+
return RLM_MODULE_REJECT;
}
if (!server) {
radlog(L_DBG, "rlm_krb5: [%s] krb5_princ_component failed.",
user);
+
return RLM_MODULE_REJECT;
}
- strlcpy(phost, server->data, BUFSIZ);
- phost[BUFSIZ - 1] = '\0';
+
+ strlcpy(phost, server->data, sizeof(phost));
/*
- * Do we have host/<host> keys?
- * (use default/configured keytab, kvno IGNORE_VNO to get the
- * first match, and enctype is currently ignored anyhow.)
+ * Do we have host/<host> keys?
+ * (use default/configured keytab, kvno IGNORE_VNO to get the
+ * first match, and enctype is currently ignored anyhow.)
*/
- if ((r = krb5_kt_read_service_key(context, instance->keytab, princ, 0,
- ENCTYPE_DES_CBC_MD5, &keyblock)))
- {
+ ret = krb5_kt_read_service_key(context, keytab_name, princ, 0,
+ ENCTYPE_DES_CBC_MD5, &keyblock);
+ if (ret) {
/* Keytab or service key does not exist */
radlog(L_DBG, "rlm_krb5: verify_krb_v5_tgt: host key not found : %s",
- error_message(r));
+ error_message(ret));
+
return RLM_MODULE_OK;
}
+
if (keyblock)
krb5_free_keyblock(context, keyblock);
- /* Talk to the kdc and construct the ticket. */
- r = krb5_build_auth_context(instance, context, &auth_context);
- if (r) {
+ /*
+ * Talk to the kdc and construct the ticket.
+ */
+ ret = krb5_build_auth_context(inst, context, &auth_context);
+ if (ret) {
radlog(L_DBG, "rlm_krb5: [%s] krb5_build_auth_context() failed: %s",
- user, error_message(r));
- r = RLM_MODULE_REJECT;
+ user, error_message(ret));
+
+ rcode = RLM_MODULE_REJECT;
goto cleanup;
}
- r = krb5_mk_req(context, &auth_context, 0, service, phost, NULL,
- ccache, &packet);
+ ret = krb5_mk_req(context, &auth_context, 0, service, phost, NULL,
+ ccache, &packet);
if (auth_context) {
krb5_auth_con_free(context, auth_context);
auth_context = NULL; /* setup for rd_req */
}
- if (r) {
+ if (ret) {
radlog(L_DBG, "rlm_krb5: [%s] krb5_mk_req() failed: %s",
- user, error_message(r));
- r = RLM_MODULE_REJECT;
+ user, error_message(ret));
+
+ rcode = RLM_MODULE_REJECT;
goto cleanup;
}
- if (instance->keytab != NULL) {
- r = krb5_kt_resolve(context, instance->keytab, &keytab);
+ if (keytab_name != NULL) {
+ ret = krb5_kt_resolve(context, keytab_name, &keytab);
}
- if (instance->keytab == NULL || r) {
- r = krb5_kt_default(context, &keytab);
+ if (keytab_name == NULL || ret) {
+ ret = krb5_kt_default(context, &keytab);
}
/* Hmm? The keytab was just fine a second ago! */
- if (r) {
+ if (ret) {
radlog(L_AUTH, "rlm_krb5: [%s] krb5_kt_resolve failed: %s",
- user, error_message(r));
- r = RLM_MODULE_REJECT;
+ user, error_message(ret));
+
+ rcode = RLM_MODULE_REJECT;
goto cleanup;
}
/* Try to use the ticket. */
- r = krb5_build_auth_context(instance, context, &auth_context);
- if (r) {
+ ret = krb5_build_auth_context(inst, context, &auth_context);
+ if (ret) {
radlog(L_DBG, "rlm_krb5: [%s] krb5_build_auth_context() failed: %s",
- user, error_message(r));
- r = RLM_MODULE_REJECT;
+ user, error_message(ret));
+
+ rcode = RLM_MODULE_REJECT;
goto cleanup;
}
- r = krb5_rd_req(context, &auth_context, &packet, princ,
- keytab, NULL, NULL);
+ ret = krb5_rd_req(context, &auth_context, &packet, princ,
+ keytab, NULL, NULL);
if (auth_context)
krb5_auth_con_free(context, auth_context);
krb5_kt_close(context, keytab);
- if (r) {
+ if (ret) {
radlog(L_AUTH, "rlm_krb5: [%s] krb5_rd_req() failed: %s",
- user, error_message(r));
- r = RLM_MODULE_REJECT;
+ user, error_message(ret));
+
+ rcode = RLM_MODULE_REJECT;
} else {
- r = RLM_MODULE_OK;
+ rcode = RLM_MODULE_OK;
}
-
+
cleanup:
- if (packet.data)
+ if (packet.data) {
krb5_free_data_contents(context, &packet);
- return r;
+ }
+
+ return rcode;
}
#endif
-/* instantiate */
static int krb5_instantiate(CONF_SECTION *conf, void **instance)
{
- int r;
+ int ret;
rlm_krb5_t *data;
krb5_context *context;
free(data);
return -1;
}
-
+
context = data->context = rad_malloc(sizeof(*context));
- if ((r = krb5_init_context(context)) ) {
+ ret = krb5_init_context(context);
+ if (ret) {
radlog(L_AUTH, "rlm_krb5: krb5_init failed: %s",
- error_message(r));
+ error_message(ret));
+
free(data);
- return -1;
- } else {
+ return -1;
+ } else {
radlog(L_AUTH, "rlm_krb5: krb5_init ok");
}
-
+
*instance = data;
+
return 0;
}
-/* detach */
static int krb5_detach(void *instance)
{
free(((rlm_krb5_t *)instance)->context);
free(instance);
+
return 0;
}
-/* validate userid/passwd */
-/* MIT case */
+/*
+ * Validate userid/passwd (MIT)
+ */
#ifndef HEIMDAL_KRB5
static int krb5_auth(void *instance, REQUEST *request)
{
rlm_krb5_t *inst = instance;
- int r;
+ int ret;
- krb5_data tgtname = {
- 0,
- KRB5_TGS_NAME_SIZE,
- KRB5_TGS_NAME
- };
- krb5_creds kcreds;
+ static char tgs_name[] = KRB5_TGS_NAME;
+ krb5_data tgtname = {
+ 0,
+ KRB5_TGS_NAME_SIZE,
+ tgs_name
+ };
+
+ krb5_creds kcreds;
krb5_ccache ccache;
- char cache_name[L_tmpnam + 8];
+
+ /* MEMORY: + unsigned int (20) + NULL */
+ char cache_name[28];
krb5_context context = *(inst->context); /* copy data */
const char *user, *pass;
/*
- * We can only authenticate user requests which HAVE
- * a User-Name attribute.
+ * We can only authenticate user requests which HAVE
+ * a User-Name attribute.
*/
if (!request->username) {
radlog(L_AUTH, "rlm_krb5: Attribute \"User-Name\" is required for authentication.");
+
return RLM_MODULE_INVALID;
}
/*
- * We can only authenticate user requests which HAVE
- * a User-Password attribute.
+ * We can only authenticate user requests which HAVE
+ * a User-Password attribute.
*/
if (!request->password) {
radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication.");
+
return RLM_MODULE_INVALID;
}
*/
if (request->password->attribute != PW_USER_PASSWORD) {
radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
+
return RLM_MODULE_INVALID;
}
- /*
- * shortcuts
- */
user = request->username->vp_strvalue;
pass = request->password->vp_strvalue;
- /* Generate a unique cache_name */
- memset(cache_name, 0, sizeof(cache_name));
- strcpy(cache_name, "MEMORY:");
- (void) tmpnam(&cache_name[7]);
+ /*
+ * Generate a unique cache_name.
+ */
+ snprintf(cache_name, sizeof(cache_name), "MEMORY:%u", request->number);
- if ((r = krb5_cc_resolve(context, cache_name, &ccache))) {
+ ret = krb5_cc_resolve(context, cache_name, &ccache);
+ if (ret) {
radlog(L_AUTH, "rlm_krb5: [%s] krb5_cc_resolve(): %s",
- user, error_message(r));
+ user, error_message(ret));
+
return RLM_MODULE_REJECT;
}
/*
- * Actually perform the authentication
+ * Actually perform the authentication.
*/
memset((char *)&kcreds, 0, sizeof(kcreds));
- if ( (r = krb5_parse_name(context, user, &kcreds.client)) ) {
+ ret = krb5_parse_name(context, user, &kcreds.client);
+ if (ret) {
radlog(L_AUTH, "rlm_krb5: [%s] krb5_parse_name failed: %s",
- user, error_message(r));
+ user, error_message(ret));
+
return RLM_MODULE_REJECT;
}
- if ((r = krb5_cc_initialize(context, ccache, kcreds.client))) {
+ ret = krb5_cc_initialize(context, ccache, kcreds.client);
+ if (ret) {
radlog(L_AUTH, "rlm_krb5: [%s] krb5_cc_initialize(): %s",
- user, error_message(r));
+ user, error_message(ret));
+
return RLM_MODULE_REJECT;
}
/*
- * MIT krb5 verification
+ * MIT krb5 verification.
*/
- if ( (r = krb5_build_principal_ext(context, &kcreds.server,
- krb5_princ_realm(context, kcreds.client)->length,
- krb5_princ_realm(context, kcreds.client)->data,
- tgtname.length,
- tgtname.data,
- krb5_princ_realm(context, kcreds.client)->length,
- krb5_princ_realm(context, kcreds.client)->data,
- 0)) ) {
+ ret = krb5_build_principal_ext(context, &kcreds.server,
+ krb5_princ_realm(context, kcreds.client)->length,
+ krb5_princ_realm(context, kcreds.client)->data,
+ tgtname.length,
+ tgtname.data,
+ krb5_princ_realm(context, kcreds.client)->length,
+ krb5_princ_realm(context, kcreds.client)->data,
+ 0);
+ if (ret) {
radlog(L_AUTH, "rlm_krb5: [%s] krb5_build_principal_ext failed: %s",
- user, error_message(r));
+ user, error_message(ret));
krb5_cc_destroy(context, ccache);
+
return RLM_MODULE_REJECT;
}
- if ( (r = krb5_get_in_tkt_with_password(context,
- 0, NULL, NULL, NULL, pass, ccache, &kcreds, 0)) ) {
+ ret = krb5_get_in_tkt_with_password(context, 0, NULL, NULL, NULL, pass,
+ ccache, &kcreds, 0);
+ if (ret) {
radlog(L_AUTH, "rlm_krb5: [%s] krb5_g_i_t_w_p failed: %s",
- user, error_message(r));
+ user, error_message(ret));
krb5_free_cred_contents(context, &kcreds);
krb5_cc_destroy(context, ccache);
+
return RLM_MODULE_REJECT;
- } else {
- /* Now verify the KDC's identity. */
- r = verify_krb5_tgt(context, inst, user, ccache);
- krb5_free_cred_contents(context, &kcreds);
- krb5_cc_destroy(context, ccache);
- return r;
}
- return RLM_MODULE_REJECT;
+ /*
+ * Now verify the KDC's identity.
+ */
+ ret = verify_krb5_tgt(context, inst, user, ccache);
+ krb5_free_cred_contents(context, &kcreds);
+ krb5_cc_destroy(context, ccache);
+
+ return ret;
}
#else /* HEIMDAL_KRB5 */
-/* validate user/pass, heimdal krb5 way */
+/*
+ * validate user/pass (Heimdal)
+ */
static int krb5_auth(void *instance, REQUEST *request)
{
rlm_krb5_t *inst = instance;
- int r;
+
krb5_error_code ret;
krb5_ccache id;
krb5_principal userP;
const char *user, *pass;
char service[SERVICE_NAME_LEN] = "host";
- char *servername = NULL;
+ char *server_name = NULL;
char *princ_name;
krb5_verify_opt krb_verify_options;
krb5_keytab keytab;
if (inst->service_princ != NULL) {
- servername = strchr(inst->service_princ, '/');
- if (servername != NULL) {
- *servername = '\0';
+ server_name = strchr(inst->service_princ, '/');
+ if (server_name != NULL) {
+ *server_name = '\0';
}
strlcpy(service, inst->service_princ, sizeof(service));
- if (servername != NULL) {
- *servername = '/';
- servername++;
+ if (server_name != NULL) {
+ *server_name = '/';
+ server_name++;
}
}
/*
- * We can only authenticate user requests which HAVE
- * a User-Name attribute.
+ * We can only authenticate user requests which HAVE
+ * a User-Name attribute.
*/
if (!request->username) {
radlog(L_AUTH, "rlm_krb5: Attribute \"User-Name\" is required for authentication.");
+
return RLM_MODULE_INVALID;
}
/*
- * We can only authenticate user requests which HAVE
- * a User-Password attribute.
+ * We can only authenticate user requests which HAVE
+ * a User-Password attribute.
*/
if (!request->password) {
radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication.");
+
return RLM_MODULE_INVALID;
}
*/
if (request->password->attribute != PW_USER_PASSWORD) {
radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
+
return RLM_MODULE_INVALID;
}
- /*
- * shortcuts
- */
user = request->username->vp_strvalue;
pass = request->password->vp_strvalue;
- if ( (r = krb5_parse_name(context, user, &userP)) ) {
+ ret = krb5_parse_name(context, user, &userP);
+ if (ret) {
radlog(L_AUTH, "rlm_krb5: [%s] krb5_parse_name failed: %s",
- user, error_message(r));
+ user, error_message(ret));
+
return RLM_MODULE_REJECT;
}
/*
- * Heimdal krb5 verification
+ * Heimdal krb5 verification.
*/
-
-
+
/*
* The following bit allows us to also log user/instance@REALM if someone
- * logs in using an instance
+ * logs in using an instance.
*/
ret = krb5_unparse_name(context, userP, &princ_name);
if (ret != 0) {
krb5_cc_default(context, &id);
- /* Set up krb5_verify_user options */
- krb5_verify_opt_init(&krb_verify_options);
-
- krb5_verify_opt_set_ccache(&krb_verify_options, id);
+ /*
+ * Set up krb5_verify_user options.
+ */
+ krb5_verify_opt_init(&krb_verify_options);
+ krb5_verify_opt_set_ccache(&krb_verify_options, id);
- /*
+ /*
* Resolve keytab name. This allows us to use something other than
* the default system keytab
*/
if (inst->keytab != NULL) {
ret = krb5_kt_resolve(context, inst->keytab, &keytab);
-
if (ret) {
- radlog(L_AUTH, "rlm_krb: unable to resolve keytab %s: %s",
+ radlog(L_AUTH, "rlm_krb5: unable to resolve keytab %s: %s",
inst->keytab, error_message(ret));
krb5_kt_close(context, keytab);
+
return RLM_MODULE_REJECT;
}
+
krb5_verify_opt_set_keytab(&krb_verify_options, keytab);
}
/*
- * Verify aquired credentials against the keytab
+ * Verify aquired credentials against the keytab.
*/
krb5_verify_opt_set_secure(&krb_verify_options, 1);
/*
- * Allow us to use an arbitrary service name
+ * Allow us to use an arbitrary service name.
*/
- krb5_verify_opt_set_service(&krb_verify_options, service);
+ krb5_verify_opt_set_service(&krb_verify_options, service);
/*
- * Verify the user, using the above set options
+ * Verify the user, using the above set options.
*/
ret = krb5_verify_user_opt(context, userP, pass, &krb_verify_options);
/*
- * We are done with the keytab, close it
+ * We are done with the keytab, close it.
*/
- krb5_kt_close(context, keytab);
+ krb5_kt_close(context, keytab);
if (ret == 0)
return RLM_MODULE_OK;