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

📄 svcauth_des.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/* * linux/net/sunrpc/svcauth_des.c * * Server-side AUTH_DES handling. *  * Copyright (C) 1996, 1997 Olaf Kirch <okir@monad.swb.de> */#include <linux/types.h>#include <linux/sched.h>#include <linux/sunrpc/types.h>#include <linux/sunrpc/xdr.h>#include <linux/sunrpc/svcauth.h>#include <linux/sunrpc/svcsock.h>#define RPCDBG_FACILITY	RPCDBG_AUTH/* * DES cedential cache. * The cache is indexed by fullname/key to allow for multiple sessions * by the same user from different hosts. * It would be tempting to use the client's IP address rather than the * conversation key as an index, but that could become problematic for * multi-homed hosts that distribute traffic across their interfaces. */struct des_cred {	struct des_cred *	dc_next;	char *			dc_fullname;	u32			dc_nickname;	des_cblock		dc_key;		/* conversation key */	des_cblock		dc_xkey;	/* encrypted conv. key */	des_key_schedule	dc_keysched;};#define ADN_FULLNAME		0#define ADN_NICKNAME		1/* * The default slack allowed when checking for replayed credentials * (in milliseconds). */#define DES_REPLAY_SLACK	2000/* * Make sure we don't place more than one call to the key server at * a time. */static int			in_keycall = 0;#define FAIL(err) \	{ if (data) put_cred(data);			\	  *authp = rpc_autherr_##err;			\	  return;					\	}voidsvcauth_des(struct svc_rqst *rqstp, u32 *statp, u32 *authp){	struct svc_buf	*argp = &rqstp->rq_argbuf;	struct svc_buf	*resp = &rqstp->rq_resbuf;	struct svc_cred	*cred = &rqstp->rq_cred;	struct des_cred	*data = NULL;	u32		cryptkey[2];	u32		cryptbuf[4];	u32		*p = argp->buf;	int		len   = argp->len, slen, i;	*authp = rpc_auth_ok;	if ((argp->len -= 3) < 0) {		*statp = rpc_garbage_args;		return;	}	p++;					/* skip length field */	namekind = ntohl(*p++);			/* fullname/nickname */	/* Get the credentials */	if (namekind == ADN_NICKNAME) {		/* If we can't find the cached session key, initiate a		 * new session. */		if (!(data = get_cred_bynick(*p++)))			FAIL(rejectedcred);	} else if (namekind == ADN_FULLNAME) {		p = xdr_decode_string(p, &fullname, &len, RPC_MAXNETNAMELEN);		if (p == NULL)			FAIL(badcred);		cryptkey[0] = *p++;		/* get the encrypted key */		cryptkey[1] = *p++;		cryptbuf[2] = *p++;		/* get the encrypted window */	} else {		FAIL(badcred);	}	/* If we're just updating the key, silently discard the request. */	if (data && data->dc_locked) {		*authp = rpc_autherr_dropit;		_put_cred(data);	/* release but don't unlock */		return;	}	/* Get the verifier flavor and length */	if (ntohl(*p++) != RPC_AUTH_DES && ntohl(*p++) != 12)		FAIL(badverf);	cryptbuf[0] = *p++;			/* encrypted time stamp */	cryptbuf[1] = *p++;	cryptbuf[3] = *p++;			/* 0 or window - 1 */	if (namekind == ADN_NICKNAME) {		status = des_ecb_encrypt((des_block *) cryptbuf,					 (des_block *) cryptbuf,					 data->dc_keysched, DES_DECRYPT);	} else {		/* We first have to decrypt the new session key and		 * fill in the UNIX creds. */		if (!(data = get_cred_byname(rqstp, authp, fullname, cryptkey)))			return;		status = des_cbc_encrypt((des_cblock *) cryptbuf,					 (des_cblock *) cryptbuf, 16,					 data->dc_keysched,					 (des_cblock *) &ivec,					 DES_DECRYPT);	}	if (status) {		printk("svcauth_des: DES decryption failed (status %d)\n",				status);		FAIL(badverf);	}	/* Now check the whole lot */	if (namekind == ADN_FULLNAME) {		unsigned long	winverf;		data->dc_window = ntohl(cryptbuf[2]);		winverf = ntohl(cryptbuf[2]);		if (window != winverf - 1) {			printk("svcauth_des: bad window verifier!\n");			FAIL(badverf);		}	}	/* XDR the decrypted timestamp */	cryptbuf[0] = ntohl(cryptbuf[0]);	cryptbuf[1] = ntohl(cryptbuf[1]);	if (cryptbuf[1] > 1000000) {		dprintk("svcauth_des: bad usec value %u\n", cryptbuf[1]);		if (namekind == ADN_NICKNAME)			FAIL(rejectedverf);		FAIL(badverf);	}		/*	 * Check for replayed credentials. We must allow for reordering	 * of requests by the network, and the OS scheduler, hence we	 * cannot expect timestamps to be increasing monotonically.	 * This opens a small security hole, therefore the replay_slack	 * value shouldn't be too large.	 */	if ((delta = cryptbuf[0] - data->dc_timestamp[0]) <= 0) {		switch (delta) {		case -1:				delta = -1000000;		case 0:			delta += cryptbuf[1] - data->dc_timestamp[1];			break;		default:			delta = -1000000;		}		if (delta < DES_REPLAY_SLACK)			FAIL(rejectedverf);#ifdef STRICT_REPLAY_CHECKS		/* TODO: compare time stamp to last five timestamps cached		 * and reject (drop?) request if a match is found. */#endif	}	now = xtime;	now.tv_secs -= data->dc_window;	if (now.tv_secs < cryptbuf[0] ||	    (now.tv_secs == cryptbuf[0] && now.tv_usec < cryptbuf[1]))		FAIL(rejectedverf);	/* Okay, we're done. Update the lot */	if (namekind == ADN_FULLNAME)		data->dc_valid = 1;	data->dc_timestamp[0] = cryptbuf[0];	data->dc_timestamp[1] = cryptbuf[1];	put_cred(data);	return;garbage:	*statp = rpc_garbage_args;	return;}/* * Call the keyserver to obtain the decrypted conversation key and * UNIX creds. We use a Linux-specific keycall extension that does * both things in one go. */static struct des_cred *get_cred_byname(struct svc_rqst *rqstp, u32 *authp, char *fullname, u32 *cryptkey){	static int	in_keycall = 0;	struct des_cred	*cred;	if (in_keycall) {		*authp = rpc_autherr_dropit;		return NULL;	}	in_keycall = 1;	in_keycall = 0;	return cred;}

⌨️ 快捷键说明

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