## freeradius-krb5.patch

#  This patch makes the freeradius krb5 module useful to us.
#  In particular...
#  - It does validation of the tickets it obtains
#  - It provides a 'keytab' option to set the keytab location
#  - It provides a 'service' option to set the service principal name
#  - It actually links against -lkrb5, so it can be useful
#
#  -- Jeffrey Hutzelman, jhutz+@cmu.edu, 15-Jan-2002

diff -ru X/freeradius-0.3/src/modules/rlm_krb5/configure.in freeradius-0.3/src/modules/rlm_krb5/configure.in
--- X/freeradius-0.3/src/modules/rlm_krb5/configure.in	Sat Jul 28 13:59:39 2001
+++ freeradius-0.3/src/modules/rlm_krb5/configure.in	Tue Nov 27 17:18:04 2001
@@ -63,7 +63,7 @@
 
 	AC_CHECK_LIB(krb5, krb5_init_context, 
 		[ 
-			krb5_ldflags="${krblibcrypto} ${krb5libcomerr}"
+			krb5_ldflags="-lkrb5 ${krb5libcrypto} ${krb5libcomerr}"
 			krb5_cflags=""  #fixme?
 		],
 		[ fail=$fail" krb5" ],
diff -ru X/freeradius-0.3/src/modules/rlm_krb5/rlm_krb5.c freeradius-0.3/src/modules/rlm_krb5/rlm_krb5.c
--- X/freeradius-0.3/src/modules/rlm_krb5/rlm_krb5.c	Tue Feb 20 15:51:33 2001
+++ freeradius-0.3/src/modules/rlm_krb5/rlm_krb5.c	Thu Nov 29 13:42:22 2001
@@ -39,29 +39,52 @@
 #include <krb5.h>
 #include <com_err.h>
 
+typedef struct rlm_krb5_t {
+	krb5_context context;
+	char *keytab;
+	char *service;
+} rlm_krb5_t;
+
+static CONF_PARSER module_config[] = {
+  { "keytab",  PW_TYPE_STRING_PTR, offsetof(rlm_krb5_t,keytab),  NULL, NULL     },
+  { "service", PW_TYPE_STRING_PTR, offsetof(rlm_krb5_t,service), NULL, "radius" },
+  { NULL, -1, 0, NULL, NULL }
+};
+
 /* instantiate */
 static int krb5_instantiate(CONF_SECTION *conf, void **instance)
 {
 	int r;
-	krb5_context *context;
+	rlm_krb5_t *data;
+
+	data = rad_malloc(sizeof(*data));
 
-	context = rad_malloc(sizeof(*context));
+	if (cf_section_parse(conf, data, module_config) < 0) {
+		free(data);
+		return -1;
+	}
 
-        if ((r = krb5_init_context(context)) ) {
+        if ((r = krb5_init_context(&data->context)) ) {
 		radlog(L_AUTH, "rlm_krb5: krb5_init failed: %s",
 		       error_message(r));
+		if (data->keytab)  free(data->keytab);
+		if (data->service) free(data->service);
                 return -1;
         } else {
 		radlog(L_AUTH, "rlm_krb5: krb5_init ok");
 	}
 
-	*instance = context;
+	*instance = data;
 	return 0;
 }
 
 /* detach */
 static int krb5_detach(void *instance)
 {
+	rlm_krb5_t *data = (rlm_krb5_t *)instance;
+	krb5_free_context(data->context);
+	if (data->keytab)  free(data->keytab);
+	if (data->service) free(data->service);
 	free(instance);
 	return 0;
 }
@@ -69,15 +92,13 @@
 /* validate userid/passwd */
 static int krb5_auth(void *instance, REQUEST *request)
 {
-	int r;
-        krb5_data tgtname = {
-                0,
-                KRB5_TGS_NAME_SIZE,
-                KRB5_TGS_NAME
-        };
-        krb5_creds kcreds;
-	krb5_context context = *(krb5_context *) instance; /* copy data */
-	const char *user, *pass;
+	rlm_krb5_t *data = (rlm_krb5_t *)instance;
+	krb5_verify_opt opt;
+	krb5_error_code ret;
+        krb5_principal userP;
+	krb5_keytab kt = NULL;
+	const char *user;
+	char *name;
 
 	/*
 	 *	We can only authenticate user requests which HAVE
@@ -87,6 +108,7 @@
 		radlog(L_AUTH, "rlm_krb5: Attribute \"User-Name\" is required for authentication.");
 		return RLM_MODULE_INVALID;
 	}
+	user = request->username->strvalue;
 
 	/*
 	 *	We can only authenticate user requests which HAVE
@@ -107,45 +129,53 @@
 	}
 
 	/*
-	 *	shortcuts
+	 *	Open the keytab
 	 */
-	user = request->username->strvalue;
-	pass = request->password->strvalue;
+	if (data->keytab) {
+		if ((ret = krb5_kt_resolve(data->context, data->keytab, &kt))) {
+			radlog(L_AUTH, "rlm_krb5: [%s] krb5_kt_resolve failed: %s",
+			       user, error_message(ret));
+			return RLM_MODULE_REJECT;
+		}
+	}
 
 	/*
 	 *	Actually perform the authentication
 	 */
-	memset((char *)&kcreds, 0, sizeof(kcreds));
+
+	krb5_verify_opt_init(&opt);
+	krb5_verify_opt_set_keytab(&opt,  kt);
+	krb5_verify_opt_set_secure(&opt,  1);
+	krb5_verify_opt_set_service(&opt, data->service);
 	
-	if ( (r = krb5_parse_name(context, user, &kcreds.client)) ) {
+	if ((ret = krb5_parse_name(data->context, request->username->strvalue, &userP))) {
 		radlog(L_AUTH, "rlm_krb5: [%s] krb5_parse_name failed: %s",
-		       user, error_message(r));
+		       user, error_message(ret));
+		if (kt) krb5_kt_close(data->context, kt);
 		return RLM_MODULE_REJECT;
 	}
 
-	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)) ) {
-		radlog(L_AUTH, "rlm_krb5: [%s] krb5_build_principal_ext failed: %s",
-			user, error_message(r));
+	if ((ret = krb5_unparse_name(data->context, userP, &name))) {
+		radlog(L_AUTH, "rlm_krb5: [%s] krb5_unparse_name failed: %s",
+		       user, error_message(ret));
+		if (kt) krb5_kt_close(data->context, kt);
 		return RLM_MODULE_REJECT;
 	}
 
-	if ( (r = krb5_get_in_tkt_with_password(context,
-		0, NULL, NULL, NULL, pass, 0, &kcreds, 0)) ) {
-		radlog(L_AUTH, "rlm_krb5: [%s] krb5_g_i_t_w_p failed: %s",
-			user, error_message(r));
-		return RLM_MODULE_REJECT;
-	} else {
+	radlog(L_AUTH, "rlm_krb5: Parsed name is: %s\n", name);
+
+	ret = krb5_verify_user_opt(data->context, userP, request->password->strvalue, &opt);
+	if (kt) krb5_kt_close(data->context, kt);
+	
+	if (ret == 0) {
+		free(name);
 		return RLM_MODULE_OK;
 	}
+
+	radlog(L_AUTH, "rlm_krb5: failed verify_user: %s (%s)", error_message(ret), name);
 	
-	return RLM_MODULE_REJECT;
+	free(name);
+  	return RLM_MODULE_REJECT;
 }
 
 module_t rlm_krb5 = {
