⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rlm_krb5.c

📁 free radius编程。完成AAA的实现
💻 C
字号:
/* * rlm_krb5.c	module to authenticate against krb5 * * Version:	$Id: rlm_krb5.c,v 1.18 2004/02/26 19:04:33 aland Exp $ * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * Copyright 2000  The FreeRADIUS server project * Copyright 2000  Nathan Neulinger <nneul@umr.edu> * Copyright 2000  Alan DeKok <aland@ox.org> */static const char rcsid[] = "$Id: rlm_krb5.c,v 1.18 2004/02/26 19:04:33 aland Exp $";#include	"autoconf.h"#include	"libradius.h"#include	<stdio.h>#include	<stdlib.h>#include	<string.h>#include	"radiusd.h"#include	"modules.h"/* krb5 includes */#include <krb5.h>#include <com_err.h>typedef struct rlm_krb5_t {	const char *keytab;	const char *service_princ;	krb5_context *context;} rlm_krb5_t;static CONF_PARSER module_config[] = {	{ "keytab", PW_TYPE_STRING_PTR,	  offsetof(rlm_krb5_t,keytab), NULL, NULL },	{ "service_principal", PW_TYPE_STRING_PTR,	  offsetof(rlm_krb5_t,service_princ), NULL, NULL },	{ NULL, -1, 0, NULL, NULL }};#ifndef HEIMDAL_KRB5static int verify_krb5_tgt(krb5_context context, rlm_krb5_t *instance,                           const char *user, krb5_ccache ccache){	int r;	char phost[BUFSIZ];	krb5_principal princ;	krb5_keyblock *keyblock = 0;	krb5_data packet;	krb5_auth_context auth_context = NULL;	krb5_keytab keytab;	/* arbitrary 64-byte limit on service names; I've never seen a	   service name this long, and hope never to. -srl */	char service[64] = "host";	char *servername = NULL;	if (instance->service_princ != NULL) {		servername = strchr(instance->service_princ, '/');		if (servername != NULL) {			*servername = '\0';		}		strncpy(service,instance->service_princ,sizeof(service));		service[sizeof(service)-1] = '\0';		if (servername != NULL) {			*servername = '/';			servername++;		}	}	memset(&packet, 0, sizeof packet);	if ((r = krb5_sname_to_principal(context, servername, service,	                                    KRB5_NT_SRV_HST, &princ)))	{		radlog(L_DBG, "rlm_krb5: [%s] krb5_sname_to_principal failed: %s",			user, error_message(r));		return RLM_MODULE_REJECT;	}	strncpy(phost, krb5_princ_component(c, princ, 1)->data, BUFSIZ);	phost[BUFSIZ - 1] = '\0';	/*	 * 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)))	{		/* Keytab or service key does not exist */		radlog(L_DBG, "rlm_krb5: verify_krb_v5_tgt: host key not found : %s",		       error_message(r));		return RLM_MODULE_OK;	}	if (keyblock)		krb5_free_keyblock(context, keyblock);	/* Talk to the kdc and construct the ticket. */	r = 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) {		radlog(L_DBG, "rlm_krb5: [%s] krb5_mk_req() failed: %s",		       user, error_message(r));		r = RLM_MODULE_REJECT;		goto cleanup;	}	if (instance->keytab != NULL) {		r = krb5_kt_resolve(context, instance->keytab, &keytab);	}	if (instance->keytab == NULL || r) {		r = krb5_kt_default(context, &keytab);	}	/* Hmm?  The keytab was just fine a second ago! */	if (r) {		radlog(L_AUTH, "rlm_krb5: [%s] krb5_kt_resolve failed: %s",			user, error_message(r));		r = RLM_MODULE_REJECT;		goto cleanup;	}	/* Try to use the ticket. */	r = 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) {		radlog(L_AUTH, "rlm_krb5: [%s] krb5_rd_req() failed: %s",		       user, error_message(r));		r = RLM_MODULE_REJECT;	} else {		r = RLM_MODULE_OK;	}cleanup:	if (packet.data)		krb5_free_data_contents(context, &packet);	return r;}#endif/* instantiate */static int krb5_instantiate(CONF_SECTION *conf, void **instance){	int r;	rlm_krb5_t *data;	krb5_context *context;	data = rad_malloc(sizeof(*data));	memset(data, 0, sizeof(*data));	if (cf_section_parse(conf, data, module_config) < 0) {		free(data);		return -1;	}	context = data->context = rad_malloc(sizeof(*context));        if ((r = krb5_init_context(context)) ) {		radlog(L_AUTH, "rlm_krb5: krb5_init failed: %s",		       error_message(r));		free(data);                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 */#ifndef HEIMDAL_KRB5static int krb5_auth(void *instance, REQUEST *request){	int r;        krb5_data tgtname = {                0,                KRB5_TGS_NAME_SIZE,                KRB5_TGS_NAME        };        krb5_creds kcreds;	krb5_ccache ccache;	char cache_name[L_tmpnam + 8];	krb5_context context = *((rlm_krb5_t *)instance)->context; /* copy data */	const char *user, *pass;	/*	 *	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.	 */	if (!request->password) {		radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication.");		return RLM_MODULE_INVALID;	}	/*	 *  Ensure that we're being passed a plain-text password,	 *  and not anything else.	 */	if (request->password->attribute != PW_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->strvalue;	pass = request->password->strvalue;	/* Generate a unique cache_name */	memset(cache_name, 0, sizeof(cache_name));	strcpy(cache_name, "MEMORY:");	(void) tmpnam(&cache_name[7]);	if ((r = krb5_cc_resolve(context, cache_name, &ccache))) {		radlog(L_AUTH, "rlm_krb5: [%s] krb5_cc_resolve(): %s",		       user, error_message(r));		return RLM_MODULE_REJECT;	}	/*	 *	Actually perform the authentication	 */	memset((char *)&kcreds, 0, sizeof(kcreds));	if ( (r = krb5_parse_name(context, user, &kcreds.client)) ) {		radlog(L_AUTH, "rlm_krb5: [%s] krb5_parse_name failed: %s",		       user, error_message(r));		return RLM_MODULE_REJECT;	}	if ((r = krb5_cc_initialize(context, ccache, kcreds.client))) {		radlog(L_AUTH, "rlm_krb5: [%s] krb5_cc_initialize(): %s",		       user, error_message(r));		return RLM_MODULE_REJECT;	}	/*	 * 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)) ) {		radlog(L_AUTH, "rlm_krb5: [%s] krb5_build_principal_ext failed: %s",			user, error_message(r));		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)) ) {		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 {		/* 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;	}	return RLM_MODULE_REJECT;}#else /* HEIMDAL_KRB5 *//* validate user/pass, heimdal krb5 way */static int krb5_auth(void *instance, REQUEST *request){	int r;	krb5_error_code ret;	krb5_ccache id;	krb5_principal userP;	krb5_context context = *(krb5_context *) instance; /* copy data */	const char *user, *pass;	/*	 *	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.	 */	if (!request->password) {		radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication.");		return RLM_MODULE_INVALID;	}	/*	 *  Ensure that we're being passed a plain-text password,	 *  and not anything else.	 */	if (request->password->attribute != PW_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->strvalue;	pass = request->password->strvalue;	if ( (r = krb5_parse_name(context, user, &userP)) ) {		radlog(L_AUTH, "rlm_krb5: [%s] krb5_parse_name failed: %s",		       user, error_message(r));		return RLM_MODULE_REJECT;	}	/*	 * Heimdal krb5 verification	 */	radlog(L_AUTH, "rlm_krb5: Parsed name is: %s@%s\n",	       *userP->name.name_string.val,	       userP->realm);	krb5_cc_default(context, &id);	ret = krb5_verify_user(context,			       userP,			       id,			       pass, 1, "radius");       if (ret == 0)	 return RLM_MODULE_OK;       radlog(L_AUTH, "rlm_krb5: failed verify_user: %s (%s@%s )",	      error_message(ret),	      *userP->name.name_string.val,	      userP->realm);       return RLM_MODULE_REJECT;}#endif /* HEIMDAL_KRB5 */module_t rlm_krb5 = {  "Kerberos",  RLM_TYPE_THREAD_UNSAFE,	/* type: not thread safe */  NULL,				/* initialize */  krb5_instantiate,   		/* instantiation */  {	  krb5_auth,		/* authenticate */	  NULL,			/* authorize */	  NULL,			/* pre-accounting */	  NULL,			/* accounting */	  NULL,			/* checksimul */	  NULL,			/* pre-proxy */	  NULL,			/* post-proxy */	  NULL			/* post-auth */  },  krb5_detach,			/* detach */  NULL,				/* destroy */};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -