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

📄 svcauth_gss.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct rsc *rsci = svcdata->rsci;	struct rpc_gss_wire_cred *gc = &svcdata->clcred;	rqstp->rq_client = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);	if (rqstp->rq_client == NULL)		return SVC_DENIED;	return SVC_OK;}static inline intgss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip){	struct rsc *rsci;	int        rc;	if (rsip->major_status != GSS_S_COMPLETE)		return gss_write_null_verf(rqstp);	rsci = gss_svc_searchbyctx(&rsip->out_handle);	if (rsci == NULL) {		rsip->major_status = GSS_S_NO_CONTEXT;		return gss_write_null_verf(rqstp);	}	rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);	cache_put(&rsci->h, &rsc_cache);	return rc;}/* * Accept an rpcsec packet. * If context establishment, punt to user space * If data exchange, verify/decrypt * If context destruction, handle here * In the context establishment and destruction case we encode * response here and return SVC_COMPLETE. */static intsvcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp){	struct kvec	*argv = &rqstp->rq_arg.head[0];	struct kvec	*resv = &rqstp->rq_res.head[0];	u32		crlen;	struct xdr_netobj tmpobj;	struct gss_svc_data *svcdata = rqstp->rq_auth_data;	struct rpc_gss_wire_cred *gc;	struct rsc	*rsci = NULL;	struct rsi	*rsip, rsikey;	__be32		*rpcstart;	__be32		*reject_stat = resv->iov_base + resv->iov_len;	int		ret;	dprintk("RPC:       svcauth_gss: argv->iov_len = %zd\n",			argv->iov_len);	*authp = rpc_autherr_badcred;	if (!svcdata)		svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL);	if (!svcdata)		goto auth_err;	rqstp->rq_auth_data = svcdata;	svcdata->verf_start = NULL;	svcdata->rsci = NULL;	gc = &svcdata->clcred;	/* start of rpc packet is 7 u32's back from here:	 * xid direction rpcversion prog vers proc flavour	 */	rpcstart = argv->iov_base;	rpcstart -= 7;	/* credential is:	 *   version(==1), proc(0,1,2,3), seq, service (1,2,3), handle	 * at least 5 u32s, and is preceeded by length, so that makes 6.	 */	if (argv->iov_len < 5 * 4)		goto auth_err;	crlen = svc_getnl(argv);	if (svc_getnl(argv) != RPC_GSS_VERSION)		goto auth_err;	gc->gc_proc = svc_getnl(argv);	gc->gc_seq = svc_getnl(argv);	gc->gc_svc = svc_getnl(argv);	if (svc_safe_getnetobj(argv, &gc->gc_ctx))		goto auth_err;	if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)		goto auth_err;	if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0))		goto auth_err;	/*	 * We've successfully parsed the credential. Let's check out the	 * verifier.  An AUTH_NULL verifier is allowed (and required) for	 * INIT and CONTINUE_INIT requests. AUTH_RPCSEC_GSS is required for	 * PROC_DATA and PROC_DESTROY.	 *	 * AUTH_NULL verifier is 0 (AUTH_NULL), 0 (length).	 * AUTH_RPCSEC_GSS verifier is:	 *   6 (AUTH_RPCSEC_GSS), length, checksum.	 * checksum is calculated over rpcheader from xid up to here.	 */	*authp = rpc_autherr_badverf;	switch (gc->gc_proc) {	case RPC_GSS_PROC_INIT:	case RPC_GSS_PROC_CONTINUE_INIT:		if (argv->iov_len < 2 * 4)			goto auth_err;		if (svc_getnl(argv) != RPC_AUTH_NULL)			goto auth_err;		if (svc_getnl(argv) != 0)			goto auth_err;		break;	case RPC_GSS_PROC_DATA:	case RPC_GSS_PROC_DESTROY:		*authp = rpcsec_gsserr_credproblem;		rsci = gss_svc_searchbyctx(&gc->gc_ctx);		if (!rsci)			goto auth_err;		switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) {		case SVC_OK:			break;		case SVC_DENIED:			goto auth_err;		case SVC_DROP:			goto drop;		}		break;	default:		*authp = rpc_autherr_rejectedcred;		goto auth_err;	}	/* now act upon the command: */	switch (gc->gc_proc) {	case RPC_GSS_PROC_INIT:	case RPC_GSS_PROC_CONTINUE_INIT:		*authp = rpc_autherr_badcred;		if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)			goto auth_err;		memset(&rsikey, 0, sizeof(rsikey));		if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))			goto drop;		*authp = rpc_autherr_badverf;		if (svc_safe_getnetobj(argv, &tmpobj)) {			kfree(rsikey.in_handle.data);			goto auth_err;		}		if (dup_netobj(&rsikey.in_token, &tmpobj)) {			kfree(rsikey.in_handle.data);			goto drop;		}		rsip = rsi_lookup(&rsikey);		rsi_free(&rsikey);		if (!rsip) {			goto drop;		}		switch(cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {		case -EAGAIN:		case -ETIMEDOUT:		case -ENOENT:			goto drop;		case 0:			if (gss_write_init_verf(rqstp, rsip))				goto drop;			if (resv->iov_len + 4 > PAGE_SIZE)				goto drop;			svc_putnl(resv, RPC_SUCCESS);			if (svc_safe_putnetobj(resv, &rsip->out_handle))				goto drop;			if (resv->iov_len + 3 * 4 > PAGE_SIZE)				goto drop;			svc_putnl(resv, rsip->major_status);			svc_putnl(resv, rsip->minor_status);			svc_putnl(resv, GSS_SEQ_WIN);			if (svc_safe_putnetobj(resv, &rsip->out_token))				goto drop;			rqstp->rq_client = NULL;		}		goto complete;	case RPC_GSS_PROC_DESTROY:		if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))			goto auth_err;		set_bit(CACHE_NEGATIVE, &rsci->h.flags);		if (resv->iov_len + 4 > PAGE_SIZE)			goto drop;		svc_putnl(resv, RPC_SUCCESS);		goto complete;	case RPC_GSS_PROC_DATA:		*authp = rpcsec_gsserr_ctxproblem;		svcdata->verf_start = resv->iov_base + resv->iov_len;		if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))			goto auth_err;		rqstp->rq_cred = rsci->cred;		get_group_info(rsci->cred.cr_group_info);		*authp = rpc_autherr_badcred;		switch (gc->gc_svc) {		case RPC_GSS_SVC_NONE:			break;		case RPC_GSS_SVC_INTEGRITY:			if (unwrap_integ_data(&rqstp->rq_arg,					gc->gc_seq, rsci->mechctx))				goto auth_err;			/* placeholders for length and seq. number: */			svc_putnl(resv, 0);			svc_putnl(resv, 0);			break;		case RPC_GSS_SVC_PRIVACY:			if (unwrap_priv_data(rqstp, &rqstp->rq_arg,					gc->gc_seq, rsci->mechctx))				goto auth_err;			/* placeholders for length and seq. number: */			svc_putnl(resv, 0);			svc_putnl(resv, 0);			break;		default:			goto auth_err;		}		svcdata->rsci = rsci;		cache_get(&rsci->h);		ret = SVC_OK;		goto out;	}auth_err:	/* Restore write pointer to original value: */	xdr_ressize_check(rqstp, reject_stat);	ret = SVC_DENIED;	goto out;complete:	ret = SVC_COMPLETE;	goto out;drop:	ret = SVC_DROP;out:	if (rsci)		cache_put(&rsci->h, &rsc_cache);	return ret;}static __be32 *svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd){	__be32 *p;	u32 verf_len;	p = gsd->verf_start;	gsd->verf_start = NULL;	/* If the reply stat is nonzero, don't wrap: */	if (*(p-1) != rpc_success)		return NULL;	/* Skip the verifier: */	p += 1;	verf_len = ntohl(*p++);	p += XDR_QUADLEN(verf_len);	/* move accept_stat to right place: */	memcpy(p, p + 2, 4);	/* Also don't wrap if the accept stat is nonzero: */	if (*p != rpc_success) {		resbuf->head[0].iov_len -= 2 * 4;		return NULL;	}	p++;	return p;}static inline intsvcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp){	struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;	struct rpc_gss_wire_cred *gc = &gsd->clcred;	struct xdr_buf *resbuf = &rqstp->rq_res;	struct xdr_buf integ_buf;	struct xdr_netobj mic;	struct kvec *resv;	__be32 *p;	int integ_offset, integ_len;	int stat = -EINVAL;	p = svcauth_gss_prepare_to_wrap(resbuf, gsd);	if (p == NULL)		goto out;	integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;	integ_len = resbuf->len - integ_offset;	BUG_ON(integ_len % 4);	*p++ = htonl(integ_len);	*p++ = htonl(gc->gc_seq);	if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,				integ_len))		BUG();	if (resbuf->tail[0].iov_base == NULL) {		if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)			goto out_err;		resbuf->tail[0].iov_base = resbuf->head[0].iov_base						+ resbuf->head[0].iov_len;		resbuf->tail[0].iov_len = 0;		resv = &resbuf->tail[0];	} else {		resv = &resbuf->tail[0];	}	mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;	if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic))		goto out_err;	svc_putnl(resv, mic.len);	memset(mic.data + mic.len, 0,			round_up_to_quad(mic.len) - mic.len);	resv->iov_len += XDR_QUADLEN(mic.len) << 2;	/* not strictly required: */	resbuf->len += XDR_QUADLEN(mic.len) << 2;	BUG_ON(resv->iov_len > PAGE_SIZE);out:	stat = 0;out_err:	return stat;}static inline intsvcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp){	struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;	struct rpc_gss_wire_cred *gc = &gsd->clcred;	struct xdr_buf *resbuf = &rqstp->rq_res;	struct page **inpages = NULL;	__be32 *p, *len;	int offset;	int pad;	p = svcauth_gss_prepare_to_wrap(resbuf, gsd);	if (p == NULL)		return 0;	len = p++;	offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;	*p++ = htonl(gc->gc_seq);	inpages = resbuf->pages;	/* XXX: Would be better to write some xdr helper functions for	 * nfs{2,3,4}xdr.c that place the data right, instead of copying: */	if (resbuf->tail[0].iov_base) {		BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base							+ PAGE_SIZE);		BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base);		if (resbuf->tail[0].iov_len + resbuf->head[0].iov_len				+ 2 * RPC_MAX_AUTH_SIZE > PAGE_SIZE)			return -ENOMEM;		memmove(resbuf->tail[0].iov_base + RPC_MAX_AUTH_SIZE,			resbuf->tail[0].iov_base,			resbuf->tail[0].iov_len);		resbuf->tail[0].iov_base += RPC_MAX_AUTH_SIZE;	}	if (resbuf->tail[0].iov_base == NULL) {		if (resbuf->head[0].iov_len + 2*RPC_MAX_AUTH_SIZE > PAGE_SIZE)			return -ENOMEM;		resbuf->tail[0].iov_base = resbuf->head[0].iov_base			+ resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;		resbuf->tail[0].iov_len = 0;	}	if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))		return -ENOMEM;	*len = htonl(resbuf->len - offset);	pad = 3 - ((resbuf->len - offset - 1)&3);	p = (__be32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len);	memset(p, 0, pad);	resbuf->tail[0].iov_len += pad;	resbuf->len += pad;	return 0;}static intsvcauth_gss_release(struct svc_rqst *rqstp){	struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;	struct rpc_gss_wire_cred *gc = &gsd->clcred;	struct xdr_buf *resbuf = &rqstp->rq_res;	int stat = -EINVAL;	if (gc->gc_proc != RPC_GSS_PROC_DATA)		goto out;	/* Release can be called twice, but we only wrap once. */	if (gsd->verf_start == NULL)		goto out;	/* normally not set till svc_send, but we need it here: */	/* XXX: what for?  Do we mess it up the moment we call svc_putu32	 * or whatever? */	resbuf->len = total_buf_len(resbuf);	switch (gc->gc_svc) {	case RPC_GSS_SVC_NONE:		break;	case RPC_GSS_SVC_INTEGRITY:		stat = svcauth_gss_wrap_resp_integ(rqstp);		if (stat)			goto out_err;		break;	case RPC_GSS_SVC_PRIVACY:		stat = svcauth_gss_wrap_resp_priv(rqstp);		if (stat)			goto out_err;		break;	default:		goto out_err;	}out:	stat = 0;out_err:	if (rqstp->rq_client)		auth_domain_put(rqstp->rq_client);	rqstp->rq_client = NULL;	if (rqstp->rq_cred.cr_group_info)		put_group_info(rqstp->rq_cred.cr_group_info);	rqstp->rq_cred.cr_group_info = NULL;	if (gsd->rsci)		cache_put(&gsd->rsci->h, &rsc_cache);	gsd->rsci = NULL;	return stat;}static voidsvcauth_gss_domain_release(struct auth_domain *dom){	struct gss_domain *gd = container_of(dom, struct gss_domain, h);	kfree(dom->name);	kfree(gd);}static struct auth_ops svcauthops_gss = {	.name		= "rpcsec_gss",	.owner		= THIS_MODULE,	.flavour	= RPC_AUTH_GSS,	.accept		= svcauth_gss_accept,	.release	= svcauth_gss_release,	.domain_release = svcauth_gss_domain_release,	.set_client	= svcauth_gss_set_client,};intgss_svc_init(void){	int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);	if (rv == 0) {		cache_register(&rsc_cache);		cache_register(&rsi_cache);	}	return rv;}voidgss_svc_shutdown(void){	if (cache_unregister(&rsc_cache))		printk(KERN_ERR "auth_rpcgss: failed to unregister rsc cache\n");	if (cache_unregister(&rsi_cache))		printk(KERN_ERR "auth_rpcgss: failed to unregister rsi cache\n");	svc_auth_unregister(RPC_AUTH_GSS);}

⌨️ 快捷键说明

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