rlm_krb5 hardware preauth

Benjamin Bennett ben at psc.edu
Sun Nov 20 08:37:44 CET 2005


Hi,

  I posted a patch to bugzilla
(http://bugs.freeradius.org/show_bug.cgi?id=296) which adds kerberos
hardware preauthentication support to rlm_krb5 when using MIT krb5 libs.
Also pasted below.

  Any feedback from people involved with rlm_krb5 or other modules which
use challenge-response would be appreciated. This patch takes advantage
of the krb5 libs (and hence rlm_krb5) being thread-unsafe already, but
could be changed if that bothers people.

--ben


--- src/modules/rlm_krb5/rlm_krb5.c.dist	2005-11-18 18:06:03.000000000
-0500
+++ src/modules/rlm_krb5/rlm_krb5.c	2005-11-18 21:44:49.000000000 -0500
@@ -20,6 +20,7 @@
  * Copyright 2000  The FreeRADIUS server project
  * Copyright 2000  Nathan Neulinger <nneul at umr.edu>
  * Copyright 2000  Alan DeKok <aland at ox.org>
+ * Copyright 2005  Benjamin Bennett <ben at psc.edu>
  */
 

@@ -39,6 +40,8 @@
 #include <krb5.h>
 #include <com_err.h>
 
+REQUEST *global_request;
+
 typedef struct rlm_krb5_t {
 	const char *keytab;
 	const char *service_princ;
@@ -205,12 +208,83 @@
 	return 0;
 }
 
+#ifndef HEIMDAL_KRB5
+static krb5_error_code KRB5_CALLCONV
+krb5_radius_prompter(krb5_context context, void *data, const char *name,
+			const char *banner, int num_prompts,
+			krb5_prompt prompts[])
+{
+	VALUE_PAIR *state;
+	VALUE_PAIR *reply;
+	char *challenge;
+	char *newstate;
+	int clen;
+	int r;
+
+	/* Squelch unused param warnings */
+	context = context;
+	data = data;
+
+	if(num_prompts != 1) {
+		radlog(L_DBG, "rlm_krb5: [%s] krb5_radius_prompter failed: num_prompts (%d) != 1", global_request->username->strvalue, num_prompts);
+		global_request->reply->code = PW_AUTHENTICATION_REJECT;
+		return KRB5_LIBOS_CANTREADPWD;
+	}
+
+	state = pairfind(global_request->packet->vps, PW_STATE);
+	
+	if(!state) {	/* NEW Request */
+		radlog(L_DBG, "rlm_krb5: [%s] krb5_radius_prompter: additional token required", global_request->username->strvalue);
+
+		/* Setup challenge prompt */
+		clen = strlen(name)+strlen(banner)+strlen(prompts[0].prompt)+5;
+		challenge = rad_malloc(clen);
+		snprintf(challenge, clen, "%s\n%s\n%s: ", name, banner,
+			prompts[0].prompt);
+
+		/* Re-encode User-Password to send back */
+		rad_pwencode((char *)global_request->password->strvalue,
+			&global_request->password->length,
+			global_request->secret,
+			(char *)global_request->packet->vector);
+
+		/* Setup State with current Authenticator and User-Password */
+		newstate = rad_malloc(AUTH_VECTOR_LEN+
+			global_request->password->length+1);
+		memcpy(newstate, global_request->packet->vector, AUTH_VECTOR_LEN);
+		memcpy(newstate+AUTH_VECTOR_LEN, global_request->password->strvalue,
+			global_request->password->length+1);
+
+		/* Put State into a challenge reply */
+		reply = pairmake("Reply-Message", challenge, T_OP_EQ);
+		pairadd(&global_request->reply->vps, reply);
+		state = pairmake("State", newstate, T_OP_EQ);
+		pairadd(&global_request->reply->vps, state);
+		global_request->reply->code = PW_ACCESS_CHALLENGE;
+		free(challenge);
+		free(newstate);
+		r = KRB5_LIBOS_CANTREADPWD;
+	} else {	/* Challenge Response */
+		radlog(L_DBG, "rlm_krb5: [%s] krb5_radius_prompter: using additional token", global_request->username->strvalue);
+
+		strncpy(prompts[0].reply->data,
+			(char *)global_request->password->strvalue,
+			prompts[0].reply->length);
+		prompts[0].reply->data[(prompts[0].reply->length)-1] = '\0';
+		prompts[0].reply->length = strlen(prompts[0].reply->data);
+		r = 0;
+	}
+	return r;
+}
+#endif
+
 /* validate userid/passwd */
 /* MIT case */
 #ifndef HEIMDAL_KRB5
 static int krb5_auth(void *instance, REQUEST *request)
 {
 	int r;
+	VALUE_PAIR *state;
 
         krb5_data tgtname = {
                 0,
@@ -218,11 +292,13 @@
                 KRB5_TGS_NAME
         };
         krb5_creds kcreds;
+	krb5_get_init_creds_opt opts;
 	krb5_ccache ccache;
 	char cache_name[L_tmpnam + 8];
 
 	krb5_context context = *((rlm_krb5_t *)instance)->context; /* copy data */
-	const char *user, *pass;
+	const char *user;
+	char *pass;
 
 	/*
 	 *	We can only authenticate user requests which HAVE
@@ -271,6 +347,8 @@
 	/*
 	 *	Actually perform the authentication
 	 */
+	krb5_get_init_creds_opt_init(&opts);
+
 	memset((char *)&kcreds, 0, sizeof(kcreds));
 
 	if ( (r = krb5_parse_name(context, user, &kcreds.client)) ) {
@@ -302,22 +380,40 @@
 		return RLM_MODULE_REJECT;
 	}
 
-	if ( (r = krb5_get_in_tkt_with_password(context,
-		0, NULL, NULL, NULL, pass, ccache, &kcreds, 0)) ) {
-		radlog(L_AUTH, "rlm_krb5: [%s] krb5_g_i_t_w_p failed: %s",
-			user, error_message(r));
-		krb5_free_cred_contents(context, &kcreds);
-		krb5_cc_destroy(context, ccache);
-		return RLM_MODULE_REJECT;
-	} else {
+	global_request = request;
+	state = pairfind(request->packet->vps, PW_STATE);
+	if(state) {
+		radlog(L_DBG, "rlm_krb5: [%s] challenge response", user);
+		if(state->length <= AUTH_VECTOR_LEN) {
+			radlog(L_AUTH, "rlm_krb5: [%s] BAD State data", user);
+			return RLM_MODULE_REJECT;
+		}
+		pass = (char *)state->strvalue+AUTH_VECTOR_LEN;
+		rad_pwdecode(pass, state->length-AUTH_VECTOR_LEN,
+				request->secret, (char *)state->strvalue);
+	}
+
+	if(!(r = krb5_get_init_creds_password(context, &kcreds,
+			kcreds.client, pass, krb5_radius_prompter, NULL,
+			(krb5_deltat)0, NULL, &opts))) {
+		if( (r = krb5_cc_store_cred(context, ccache, &kcreds)) ) {
+			radlog(L_AUTH, "rlm_krb5: [%s] krb5_cc_store_cred failed: %s",
+				user, error_message(r));
+			return RLM_MODULE_REJECT;
+		}
 		/* Now verify the KDC's identity. */
 		r = verify_krb5_tgt(context, (rlm_krb5_t *)instance, user, ccache);
-		krb5_free_cred_contents(context, &kcreds);
-		krb5_cc_destroy(context, ccache);
-		return r;
+	} else if(r == KRB5_LIBOS_CANTREADPWD) {
+		r = RLM_MODULE_HANDLED;
+	} else {
+		radlog(L_AUTH, "rlm_krb5: [%s] krb5_g_i_c_p failed: %s", user,
+			error_message(r));
+		r = RLM_MODULE_REJECT;
 	}
 
-	return RLM_MODULE_REJECT;
+	krb5_free_cred_contents(context, &kcreds);
+	krb5_cc_destroy(context, ccache);
+	return r;
 }
 
 #else /* HEIMDAL_KRB5 */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
URL: <http://lists.freeradius.org/pipermail/freeradius-devel/attachments/20051120/a3bbd39a/attachment.pgp>


More information about the Freeradius-Devel mailing list