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

📄 auth_gss.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/net/sunrpc/auth_gss.c * * RPCSEC_GSS client authentication. *  *  Copyright (c) 2000 The Regents of the University of Michigan. *  All rights reserved. * *  Dug Song       <dugsong@monkey.org> *  Andy Adamson   <andros@umich.edu> * *  Redistribution and use in source and binary forms, with or without *  modification, are permitted provided that the following conditions *  are met: * *  1. Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer. *  2. Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in the *     documentation and/or other materials provided with the distribution. *  3. Neither the name of the University nor the names of its *     contributors may be used to endorse or promote products derived *     from this software without specific prior written permission. * *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id$ */#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/pagemap.h>#include <linux/sunrpc/clnt.h>#include <linux/sunrpc/auth.h>#include <linux/sunrpc/auth_gss.h>#include <linux/sunrpc/svcauth_gss.h>#include <linux/sunrpc/gss_err.h>#include <linux/workqueue.h>#include <linux/sunrpc/rpc_pipe_fs.h>#include <linux/sunrpc/gss_api.h>#include <asm/uaccess.h>static struct rpc_authops authgss_ops;static struct rpc_credops gss_credops;#ifdef RPC_DEBUG# define RPCDBG_FACILITY	RPCDBG_AUTH#endif#define NFS_NGROUPS	16#define GSS_CRED_EXPIRE		(60 * HZ)	/* XXX: reasonable? */#define GSS_CRED_SLACK		1024		/* XXX: unused *//* length of a krb5 verifier (48), plus data added before arguments when * using integrity (two 4-byte integers): */#define GSS_VERF_SLACK		56/* XXX this define must match the gssd define* as it is passed to gssd to signal the use of* machine creds should be part of the shared rpc interface */#define CA_RUN_AS_MACHINE  0x00000200 /* dump the buffer in `emacs-hexl' style */#define isprint(c)      ((c > 0x1f) && (c < 0x7f))static DEFINE_RWLOCK(gss_ctx_lock);struct gss_auth {	struct rpc_auth rpc_auth;	struct gss_api_mech *mech;	enum rpc_gss_svc service;	struct list_head upcalls;	struct rpc_clnt *client;	struct dentry *dentry;	char path[48];	spinlock_t lock;};static void gss_destroy_ctx(struct gss_cl_ctx *);static struct rpc_pipe_ops gss_upcall_ops;voidprint_hexl(u32 *p, u_int length, u_int offset){	u_int i, j, jm;	u8 c, *cp;		dprintk("RPC: print_hexl: length %d\n",length);	dprintk("\n");	cp = (u8 *) p;		for (i = 0; i < length; i += 0x10) {		dprintk("  %04x: ", (u_int)(i + offset));		jm = length - i;		jm = jm > 16 ? 16 : jm;				for (j = 0; j < jm; j++) {			if ((j % 2) == 1)				dprintk("%02x ", (u_int)cp[i+j]);			else				dprintk("%02x", (u_int)cp[i+j]);		}		for (; j < 16; j++) {			if ((j % 2) == 1)				dprintk("   ");			else				dprintk("  ");		}		dprintk(" ");				for (j = 0; j < jm; j++) {			c = cp[i+j];			c = isprint(c) ? c : '.';			dprintk("%c", c);		}		dprintk("\n");	}}EXPORT_SYMBOL(print_hexl);static inline struct gss_cl_ctx *gss_get_ctx(struct gss_cl_ctx *ctx){	atomic_inc(&ctx->count);	return ctx;}static inline voidgss_put_ctx(struct gss_cl_ctx *ctx){	if (atomic_dec_and_test(&ctx->count))		gss_destroy_ctx(ctx);}static voidgss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx){	struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);	struct gss_cl_ctx *old;	write_lock(&gss_ctx_lock);	old = gss_cred->gc_ctx;	gss_cred->gc_ctx = ctx;	cred->cr_flags |= RPCAUTH_CRED_UPTODATE;	write_unlock(&gss_ctx_lock);	if (old)		gss_put_ctx(old);}static intgss_cred_is_uptodate_ctx(struct rpc_cred *cred){	struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);	int res = 0;	read_lock(&gss_ctx_lock);	if ((cred->cr_flags & RPCAUTH_CRED_UPTODATE) && gss_cred->gc_ctx)		res = 1;	read_unlock(&gss_ctx_lock);	return res;}static const void *simple_get_bytes(const void *p, const void *end, void *res, size_t len){	const void *q = (const void *)((const char *)p + len);	if (unlikely(q > end || q < p))		return ERR_PTR(-EFAULT);	memcpy(res, p, len);	return q;}static inline const void *simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest){	const void *q;	unsigned int len;	p = simple_get_bytes(p, end, &len, sizeof(len));	if (IS_ERR(p))		return p;	q = (const void *)((const char *)p + len);	if (unlikely(q > end || q < p))		return ERR_PTR(-EFAULT);	dest->data = kmalloc(len, GFP_KERNEL);	if (unlikely(dest->data == NULL))		return ERR_PTR(-ENOMEM);	dest->len = len;	memcpy(dest->data, p, len);	return q;}static struct gss_cl_ctx *gss_cred_get_ctx(struct rpc_cred *cred){	struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);	struct gss_cl_ctx *ctx = NULL;	read_lock(&gss_ctx_lock);	if (gss_cred->gc_ctx)		ctx = gss_get_ctx(gss_cred->gc_ctx);	read_unlock(&gss_ctx_lock);	return ctx;}static struct gss_cl_ctx *gss_alloc_context(void){	struct gss_cl_ctx *ctx;	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);	if (ctx != NULL) {		memset(ctx, 0, sizeof(*ctx));		ctx->gc_proc = RPC_GSS_PROC_DATA;		ctx->gc_seq = 1;	/* NetApp 6.4R1 doesn't accept seq. no. 0 */		spin_lock_init(&ctx->gc_seq_lock);		atomic_set(&ctx->count,1);	}	return ctx;}#define GSSD_MIN_TIMEOUT (60 * 60)static const void *gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct gss_api_mech *gm){	const void *q;	unsigned int seclen;	unsigned int timeout;	u32 window_size;	int ret;	/* First unsigned int gives the lifetime (in seconds) of the cred */	p = simple_get_bytes(p, end, &timeout, sizeof(timeout));	if (IS_ERR(p))		goto err;	if (timeout == 0)		timeout = GSSD_MIN_TIMEOUT;	ctx->gc_expiry = jiffies + (unsigned long)timeout * HZ * 3 / 4;	/* Sequence number window. Determines the maximum number of simultaneous requests */	p = simple_get_bytes(p, end, &window_size, sizeof(window_size));	if (IS_ERR(p))		goto err;	ctx->gc_win = window_size;	/* gssd signals an error by passing ctx->gc_win = 0: */	if (ctx->gc_win == 0) {		/* in which case, p points to  an error code which we ignore */		p = ERR_PTR(-EACCES);		goto err;	}	/* copy the opaque wire context */	p = simple_get_netobj(p, end, &ctx->gc_wire_ctx);	if (IS_ERR(p))		goto err;	/* import the opaque security context */	p  = simple_get_bytes(p, end, &seclen, sizeof(seclen));	if (IS_ERR(p))		goto err;	q = (const void *)((const char *)p + seclen);	if (unlikely(q > end || q < p)) {		p = ERR_PTR(-EFAULT);		goto err;	}	ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx);	if (ret < 0) {		p = ERR_PTR(ret);		goto err;	}	return q;err:	dprintk("RPC:      gss_fill_context returning %ld\n", -PTR_ERR(p));	return p;}struct gss_upcall_msg {	atomic_t count;	uid_t	uid;	struct rpc_pipe_msg msg;	struct list_head list;	struct gss_auth *auth;	struct rpc_wait_queue rpc_waitqueue;	wait_queue_head_t waitqueue;	struct gss_cl_ctx *ctx;};static voidgss_release_msg(struct gss_upcall_msg *gss_msg){	if (!atomic_dec_and_test(&gss_msg->count))		return;	BUG_ON(!list_empty(&gss_msg->list));	if (gss_msg->ctx != NULL)		gss_put_ctx(gss_msg->ctx);	kfree(gss_msg);}static struct gss_upcall_msg *__gss_find_upcall(struct gss_auth *gss_auth, uid_t uid){	struct gss_upcall_msg *pos;	list_for_each_entry(pos, &gss_auth->upcalls, list) {		if (pos->uid != uid)			continue;		atomic_inc(&pos->count);		dprintk("RPC:      gss_find_upcall found msg %p\n", pos);		return pos;	}	dprintk("RPC:      gss_find_upcall found nothing\n");	return NULL;}/* Try to add a upcall to the pipefs queue. * If an upcall owned by our uid already exists, then we return a reference * to that upcall instead of adding the new upcall. */static inline struct gss_upcall_msg *gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg){	struct gss_upcall_msg *old;	spin_lock(&gss_auth->lock);	old = __gss_find_upcall(gss_auth, gss_msg->uid);	if (old == NULL) {		atomic_inc(&gss_msg->count);		list_add(&gss_msg->list, &gss_auth->upcalls);	} else		gss_msg = old;	spin_unlock(&gss_auth->lock);	return gss_msg;}static void__gss_unhash_msg(struct gss_upcall_msg *gss_msg){	if (list_empty(&gss_msg->list))		return;	list_del_init(&gss_msg->list);	rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);	wake_up_all(&gss_msg->waitqueue);	atomic_dec(&gss_msg->count);}static voidgss_unhash_msg(struct gss_upcall_msg *gss_msg){	struct gss_auth *gss_auth = gss_msg->auth;	spin_lock(&gss_auth->lock);	__gss_unhash_msg(gss_msg);	spin_unlock(&gss_auth->lock);}static voidgss_upcall_callback(struct rpc_task *task){	struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred,			struct gss_cred, gc_base);	struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;	BUG_ON(gss_msg == NULL);	if (gss_msg->ctx)		gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));	else		task->tk_status = gss_msg->msg.errno;	spin_lock(&gss_msg->auth->lock);	gss_cred->gc_upcall = NULL;	rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);	spin_unlock(&gss_msg->auth->lock);	gss_release_msg(gss_msg);}static inline struct gss_upcall_msg *gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid){	struct gss_upcall_msg *gss_msg;	gss_msg = kmalloc(sizeof(*gss_msg), GFP_KERNEL);	if (gss_msg != NULL) {		memset(gss_msg, 0, sizeof(*gss_msg));		INIT_LIST_HEAD(&gss_msg->list);		rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");		init_waitqueue_head(&gss_msg->waitqueue);		atomic_set(&gss_msg->count, 1);		gss_msg->msg.data = &gss_msg->uid;		gss_msg->msg.len = sizeof(gss_msg->uid);		gss_msg->uid = uid;		gss_msg->auth = gss_auth;	}	return gss_msg;}static struct gss_upcall_msg *gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred){	struct gss_upcall_msg *gss_new, *gss_msg;	gss_new = gss_alloc_msg(gss_auth, cred->cr_uid);	if (gss_new == NULL)		return ERR_PTR(-ENOMEM);	gss_msg = gss_add_msg(gss_auth, gss_new);	if (gss_msg == gss_new) {		int res = rpc_queue_upcall(gss_auth->dentry->d_inode, &gss_new->msg);		if (res) {			gss_unhash_msg(gss_new);			gss_msg = ERR_PTR(res);		}	} else		gss_release_msg(gss_new);	return gss_msg;}static inline intgss_refresh_upcall(struct rpc_task *task){

⌨️ 快捷键说明

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