Add minimal server-side support for rpcsec_gss. Note that the user (or exportfs, on the user's behalf) allows a gss pseudoflavor to be used to access an export by exporting to a special client named "gss/pseudoflavor-name", e.g., "gss/krb5" or "gss/lipkey-i". diff -puN /dev/null include/linux/sunrpc/gss_svc_cache.h --- /dev/null 2003-06-12 22:04:49.000000000 -0400 +++ linux-2.5.74-bfields/include/linux/sunrpc/gss_svc_cache.h 2003-07-03 16:07:24.000000000 -0400 @@ -0,0 +1,48 @@ +/* + * linux/include/linux/gss_svc_cache.h + * + * Declarations for server cache of gss contexts + * + * Dug Song + * Andy Adamson + * Bruce Fields + * Copyright (c) 2000 The Regents of the University of Michigan + * + * $Id$ + */ + +#ifndef _LINUX_SUNRPC_GSS_SVC_CACHE_H +#define _LINUX_SUNRPC_GSS_SVC_CACHE_H + +#ifdef __KERNEL__ +#include + +#define GSS_SEQ_WIN 128 + +struct gss_svc_seq_data { + /* highest seq number seen so far: */ + int sd_max; + /* sd_win records whether we've seen seq numbers less than sd_max; + * for i such that sd_max-GSS_SEQ_WIN < i <= sd_max, + * sd_win[i % GSS_SEQ_WIN] is nonzero iff sequence number i has been + * seen already: */ + u8 sd_win[GSS_SEQ_WIN]; + spinlock_t sd_lock; +}; + +struct gss_svc_ctx { + struct cache_head h; + struct gss_ctx *gsc_ctx; + uid_t gsc_uid; + /* spec allow longer ctx handles, but we only use 4 bytes: */ + u32 gsc_wire_ctx; + struct gss_svc_seq_data gsc_sd; +}; + +void gss_svc_put_ctx(struct gss_svc_ctx *gsc); +int gss_svc_cache_context(struct gss_ctx *ctx, uid_t uid, u32 wire_ctx); +struct gss_svc_ctx * gss_svc_searchbyctx(u32 wire_ctx); +void gss_svc_ctx_remove(struct gss_svc_ctx *); + +#endif /* __KERNEL__ */ +#endif /* _LINUX_GSS_SVC_CACHE_H */ diff -puN /dev/null include/linux/sunrpc/gss_xdr.h --- /dev/null 2003-06-12 22:04:49.000000000 -0400 +++ linux-2.5.74-bfields/include/linux/sunrpc/gss_xdr.h 2003-07-03 16:07:24.000000000 -0400 @@ -0,0 +1,59 @@ +/* + * Bruce Fields + * Copyright (c) 2000 The Regents of the University of Michigan + */ + +#ifndef _SUNRPC_GSS_XDR_H_ +#define _SUNRPC_GSS_XDR_H_ + +#ifdef __KERNEL__ + +#include +#include +#include + +int xdr_bounded_get_u32(u32 **p, u32 *end, u32 *result); +int xdr_bounded_get_netobj(u32 **p, u32 *end, struct xdr_netobj *result); + +static inline int +simple_get_bytes(char **ptr, const char *end, void *res, int len) +{ + char *p, *q; + p = *ptr; + q = p + len; + if (q > end || q < p) + return -1; + memcpy(res, p, len); + *ptr = q; + return 0; +} + +static inline int +simple_get_netobj(char **ptr, const char *end, struct xdr_netobj *res) +{ + char *p, *q; + p = *ptr; + if (simple_get_bytes(&p, end, &res->len, sizeof(res->len))) + return -1; + q = p + res->len; + if (q > end || q < p) + return -1; + res->data = p; + *ptr = q; + return 0; +} + +static inline int +dup_netobj(struct xdr_netobj *source, struct xdr_netobj *dest) +{ + dest->len = source->len; + if (!(dest->data = kmalloc(dest->len, GFP_KERNEL))) + return -1; + memcpy(dest->data, source->data, dest->len); + return 0; +} + + +#endif /* __KERNEL__ */ + +#endif /* _SUNRPC_GSS_XDR_H_ */ diff -puN include/linux/sunrpc/svc.h~rpc_svcgss include/linux/sunrpc/svc.h --- linux-2.5.74/include/linux/sunrpc/svc.h~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/include/linux/sunrpc/svc.h 2003-07-03 16:07:24.000000000 -0400 @@ -133,6 +133,7 @@ struct svc_rqst { void * rq_argp; /* decoded arguments */ void * rq_resp; /* xdr'd results */ + void * rq_auth_data; /* flavor-specific data */ int rq_reserved; /* space on socket outq * reserved for this request diff -puN include/linux/sunrpc/svcauth.h~rpc_svcgss include/linux/sunrpc/svcauth.h --- linux-2.5.74/include/linux/sunrpc/svcauth.h~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/include/linux/sunrpc/svcauth.h 2003-07-03 16:07:24.000000000 -0400 @@ -65,6 +65,10 @@ struct auth_domain { * GARBAGE - rpc garbage_args error * SYSERR - rpc system_err error * DENIED - authp holds reason for denial. + * COMPLETE - the reply is encoded already and ready to be sent; no + * further processing is necessary. (This is used for processing + * null procedure calls which are used to set up encryption + * contexts.) * * accept is passed the proc number so that it can accept NULL rpc requests * even if it cannot authenticate the client (as is sometimes appropriate). @@ -97,6 +101,7 @@ extern struct auth_ops *authtab[RPC_AUTH #define SVC_DROP 6 #define SVC_DENIED 7 #define SVC_PENDING 8 +#define SVC_COMPLETE 9 extern int svc_authenticate(struct svc_rqst *rqstp, u32 *authp); diff -puN /dev/null include/linux/sunrpc/svcauth_gss.h --- /dev/null 2003-06-12 22:04:49.000000000 -0400 +++ linux-2.5.74-bfields/include/linux/sunrpc/svcauth_gss.h 2003-07-03 16:07:24.000000000 -0400 @@ -0,0 +1,35 @@ +/* + * linux/include/linux/svcauth_gss.h + * + * Bruce Fields + * Copyright (c) 2002 The Regents of the Unviersity of Michigan + * + * $Id$ + * + */ + +#ifndef _LINUX_SUNRPC_SVCAUTH_GSS_H +#define _LINUX_SUNRPC_SVCAUTH_GSS_H + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include + +int gss_svc_init(void); +int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); + + +struct gss_svc_data { + /* decoded gss client cred: */ + struct rpc_gss_wire_cred clcred; + /* pointer to the beginning of the procedure-specific results, which + * may be encrypted/checksummed in svcauth_gss_release: */ + u32 *body_start; +}; + +#endif /* __KERNEL__ */ +#endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */ diff -puN net/sunrpc/auth_gss/Makefile~rpc_svcgss net/sunrpc/auth_gss/Makefile --- linux-2.5.74/net/sunrpc/auth_gss/Makefile~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/auth_gss/Makefile 2003-07-03 16:07:24.000000000 -0400 @@ -5,7 +5,8 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o auth_rpcgss-objs := auth_gss.o gss_pseudoflavors.o gss_generic_token.o \ - sunrpcgss_syms.o gss_mech_switch.o + sunrpcgss_syms.o gss_mech_switch.o gss_svc_cache.o svcauth_gss.o \ + gss_xdr.o obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o diff -puN net/sunrpc/auth_gss/auth_gss.c~rpc_svcgss net/sunrpc/auth_gss/auth_gss.c --- linux-2.5.74/net/sunrpc/auth_gss/auth_gss.c~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/auth_gss/auth_gss.c 2003-07-03 16:07:24.000000000 -0400 @@ -48,9 +48,11 @@ #include #include #include +#include #include #include #include +#include #include static struct rpc_authops authgss_ops; @@ -171,44 +173,6 @@ gss_cred_get_uptodate_ctx(struct rpc_cre return ctx; } -static inline int -simple_get_bytes(char **ptr, const char *end, void *res, int len) -{ - char *p, *q; - p = *ptr; - q = p + len; - if (q > end || q < p) - return -1; - memcpy(res, p, len); - *ptr = q; - return 0; -} - -static inline int -simple_get_netobj(char **ptr, const char *end, struct xdr_netobj *res) -{ - char *p, *q; - p = *ptr; - if (simple_get_bytes(&p, end, &res->len, sizeof(res->len))) - return -1; - q = p + res->len; - if (q > end || q < p) - return -1; - res->data = p; - *ptr = q; - return 0; -} - -static int -dup_netobj(struct xdr_netobj *source, struct xdr_netobj *dest) -{ - dest->len = source->len; - if (!(dest->data = kmalloc(dest->len, GFP_KERNEL))) - return -1; - memcpy(dest->data, source->data, dest->len); - return 0; -} - static struct gss_cl_ctx * gss_cred_get_ctx(struct rpc_cred *cred) { @@ -943,6 +907,15 @@ static int __init init_rpcsec_gss(void) int err = 0; err = rpcauth_register(&authgss_ops); + if (err) + goto out; + err = gss_svc_init(); + if (err) + goto out_unregister; + return 0; +out_unregister: + rpcauth_unregister(&authgss_ops); +out: return err; } diff -puN /dev/null net/sunrpc/auth_gss/gss_svc_cache.c --- /dev/null 2003-06-12 22:04:49.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/auth_gss/gss_svc_cache.c 2003-07-03 16:07:24.000000000 -0400 @@ -0,0 +1,148 @@ +/* + * linux/net/sunrpc/gss_svc_cache.c + * + * Copyright (c) 2001 The Regents of the University of Michigan + * All rights reserved. + * + * Kendrick Smith + * Andy Adamson + * Dug Song + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +#ifdef RPC_DEBUG +# define RPCDBG_FACILITY RPCDBG_AUTH +#endif + +#define GSS_HASH_BITS 8 +#define GSS_HASH_SIZE (1 << GSS_HASH_BITS) +#define GSS_HASH_MASK (GSS_HASH_SIZE - 1) + +static void +gss_svc_ctx_put(struct cache_head *item, struct cache_detail *cd) +{ + struct gss_svc_ctx *gsc = container_of(item, struct gss_svc_ctx, h); + + if (cache_put(item, cd)) { + gss_delete_sec_context(&gsc->gsc_ctx); + kfree(gsc); + } +} + +static inline int +gss_svc_ctx_hash(struct gss_svc_ctx *gsc) +{ + return hash_long((unsigned long)gsc->gsc_wire_ctx, GSS_HASH_BITS); +} + +static inline int +gss_svc_ctx_match(struct gss_svc_ctx *new, struct gss_svc_ctx *tmp) +{ + return new->gsc_wire_ctx == tmp->gsc_wire_ctx; +} + +static inline void +gss_svc_ctx_init(struct gss_svc_ctx *new, struct gss_svc_ctx *tmp) +{ + memset(new, 0, sizeof(*new)); + new->gsc_wire_ctx = tmp->gsc_wire_ctx; +} + +static inline void +gss_svc_ctx_update(struct gss_svc_ctx *new, struct gss_svc_ctx *tmp) +{ + spin_lock_init(&new->gsc_sd.sd_lock); + new->gsc_ctx = tmp->gsc_ctx; + new->gsc_uid = tmp->gsc_uid; + new->gsc_wire_ctx = tmp->gsc_wire_ctx; +} + +static struct cache_head *gss_svc_ctx_table[GSS_HASH_MASK]; + +struct cache_detail gss_svc_ctx_cache = { + .hash_size = GSS_HASH_SIZE, + .hash_table = gss_svc_ctx_table, + .name = "auth.gss.ctx", + .cache_put = gss_svc_ctx_put, +}; + +static DefineSimpleCacheLookup(gss_svc_ctx, 1); + +void +gss_svc_put_ctx(struct gss_svc_ctx *gsc) +{ + gss_svc_ctx_put(&gsc->h, &gss_svc_ctx_cache); +} + +int +gss_svc_cache_context(struct gss_ctx *ctx, uid_t uid, u32 wire_ctx) +{ + struct gss_svc_ctx gsc, *p; + + dprintk("RPC: gss_svc_cache_context wire_ctx = %d\n", wire_ctx); + + gsc.gsc_uid = uid; + gsc.gsc_wire_ctx = wire_ctx; + gsc.gsc_ctx = ctx; + gsc.h.flags = 0; + gsc.h.expiry_time = NEVER; /* XXX? */ + + p = gss_svc_ctx_lookup(&gsc, 1); + if (p) { + gss_svc_put_ctx(p); + return 0; + } else + return -ENOMEM; +} + +struct gss_svc_ctx * +gss_svc_searchbyctx(u32 wire_ctx) +{ + struct gss_svc_ctx gsc; + struct gss_svc_ctx *found; + + gsc.gsc_wire_ctx = wire_ctx; + found = gss_svc_ctx_lookup(&gsc, 0); + if (!found) + return NULL; + if (cache_check(&gss_svc_ctx_cache, &found->h, NULL)) + return NULL; + return found; +} + +void +gss_svc_ctx_remove(struct gss_svc_ctx *gsc) +{ + set_bit(CACHE_NEGATIVE, &gsc->h.flags); +} diff -puN /dev/null net/sunrpc/auth_gss/gss_xdr.c --- /dev/null 2003-06-12 22:04:49.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/auth_gss/gss_xdr.c 2003-07-03 16:07:24.000000000 -0400 @@ -0,0 +1,54 @@ +/* + * linux/net/sunrpc/gss_xdr.c + * + * Generic XDR support. + * + * Copyright (C) 1995, 1996 Olaf Kirch + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RPC_DEBUG +# define RPCDBG_FACILITY RPCDBG_AUTH +#endif + +/* The xdr_bounded_get functions all return 0 on success, return the decoded + * object in result, and increment *p to point to the first u32 after the + * object. On failure (in particular, whenever *p would be left greater than + * end) they return nonzero and leave *p unchanged.*/ + +int +xdr_bounded_get_u32(u32 **p, u32 *end, u32 *result) +{ + if (*p + 1 > end) + return -1; + *result = ntohl(*(*p)++); + return 0; +} + +int +xdr_bounded_get_netobj(u32 **p, u32 *end, struct xdr_netobj *result) +{ + u32 *q; + u32 buflen; + + if (xdr_bounded_get_u32(p, end, &buflen)) + return -1; + q = *p + XDR_QUADLEN(buflen); + if (q > end || q < *p) { + /* return to state before xdr_bounded_get_u32: */ + (*p)--; + return -1; + } + result->len = buflen; + result->data = (u8 *)*p; + *p = q; + return 0; +} diff -puN /dev/null net/sunrpc/auth_gss/svcauth_gss.c --- /dev/null 2003-06-12 22:04:49.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/auth_gss/svcauth_gss.c 2003-07-03 17:23:28.000000000 -0400 @@ -0,0 +1,711 @@ +/* + * linux/net/sunrpc/svcauth_gss.c + * + * RPCSEC_GSS server authentication. + * + * Copyright (c) 2000 The Regents of the University of Michigan. + * All rights reserved. + * + * Dug Song + * Andy Adamson + * Bruce Fields + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RPC_DEBUG +# define RPCDBG_FACILITY RPCDBG_AUTH +#endif + +static struct dentry *nullrpc_dentry = NULL; + +static int +gss_svc_parse_init_downcall(struct xdr_netobj *buf, struct gss_ctx **ctx, + u32 *uid, u32 *wire_ctx) +{ + char *end = buf->data + buf->len; + char *p = buf->data; + struct xdr_netobj tmp_buf; + unsigned int timeout; + struct gss_api_mech *gm; + int err = -EIO; + + if (simple_get_bytes(&p, end, wire_ctx, sizeof(*wire_ctx))) + goto err; + /* XXX: discarding timeout for now: */ + if (simple_get_bytes(&p, end, &timeout, sizeof(timeout))) + goto err; + if (simple_get_bytes(&p, end, uid, sizeof(*uid))) + goto err; + if (simple_get_netobj(&p, end, &tmp_buf)) + goto err; + if (!(gm = gss_mech_get_by_OID(&tmp_buf))) + goto err; + if (simple_get_netobj(&p, end, &tmp_buf)) + goto err_release_mech; + if (gss_import_sec_context(&tmp_buf, gm, ctx)) + goto err_release_mech; + return 0; +err_release_mech: + gss_mech_put(gm); +err: + dprintk("RPC: %s returning %d\n", __FUNCTION__, err); + return err; +} + +static int +gss_svc_downcall_write(struct file *filp, const char *buf, size_t size, + loff_t *ppos) +{ + char tmpbuf[1024]; + struct xdr_netobj data = { + .len = size, + .data = tmpbuf, + }; + struct gss_ctx *ctx; + uid_t uid; + u32 wire_ctx; + ssize_t left; + int ret; + + down(&filp->f_dentry->d_inode->i_sem); + ret = -ENOSPC; + if (size > sizeof(tmpbuf)) + goto out_unlock; + left = copy_from_user(tmpbuf, buf, size); + ret = -EFAULT; + if (left) + goto out_unlock; + ret = gss_svc_parse_init_downcall(&data, &ctx, &uid, &wire_ctx); + if (ret) + goto out_unlock; + ret = gss_svc_cache_context(ctx, uid, wire_ctx); + if (ret) + goto out_unlock; + ret = size; +out_unlock: + up(&filp->f_dentry->d_inode->i_sem); + return ret; +} + +/* rpc.svcgssd uses this as a source of unique context handles; on its own + * it would have difficulty maintaining uniqueness across rpc.svcgssd + * invocations. */ +static int +gss_svc_downcall_read(struct file *filp, char *buf, size_t size, loff_t *ppos) +{ + static u32 counter = 1; + static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED; + u32 i; + int res = -ENOSPC; + + /* ensure uniqueness of i: */ + spin_lock(&counter_lock); + i = counter; + counter++; /* XXX check for overflow? */ + spin_unlock(&counter_lock); + + if (size >= sizeof(i)) { + res = copy_to_user(buf, &i, sizeof(i)); + if (res) + res = -EFAULT; + else + res = sizeof(i); + } + return res; +} + +struct file_operations gss_svc_downcall_fops = { + .llseek = no_llseek, + .write = gss_svc_downcall_write, + .read = gss_svc_downcall_read, +}; + +struct nullrpc_pipe_msg { + struct rpc_pipe_msg msg; + struct xdr_netobj res; + struct cache_deferred_req *dreq; +}; + +static ssize_t +gss_nullrpc_pipe_read(struct file *filp, struct rpc_pipe_msg *msg, + char *dst, size_t buflen) +{ + struct nullrpc_pipe_msg *nullmsg = container_of(msg, + struct nullrpc_pipe_msg, msg); + int res = -ENOSPC; + int left; + + if (buflen >= nullmsg->msg.len) { + left = copy_to_user(dst, nullmsg->msg.data, nullmsg->msg.len); + if (left) + res = -EFAULT; + else + res = nullmsg->msg.len; + } + /* XXXX for now don't want to return error and destroy msg: */ + if (res < 0) res = 0; + return res; +} + +static ssize_t +gss_nullrpc_pipe_write(struct file *filp, const char *src, size_t mlen) +{ + struct rpc_pipe_msg *msg = filp->private_data; + struct nullrpc_pipe_msg *nullmsg; + struct cache_deferred_req *dreq; + int res = -EAGAIN; + + if (!msg) + goto out; + nullmsg = container_of(msg, struct nullrpc_pipe_msg, msg); + dreq = nullmsg->dreq; + res = -ENOSPC; + if (mlen > nullmsg->res.len) + goto out; + res = -ENOMEM; + nullmsg->res.data = kmalloc(mlen, GFP_KERNEL); + if (!nullmsg->res.data) + goto out; + res = -EFAULT; + if (copy_from_user(nullmsg->res.data, src, mlen)) + goto out_free; + nullmsg->res.len = mlen; + __rpc_purge_current_upcall(filp); + dreq->revisit(nullmsg->dreq, 0); + res = mlen; + return res; +out_free: + kfree(nullmsg->res.data); +out: + return res; +} + +void +gss_nullrpc_destroy_msg(struct rpc_pipe_msg *msg) +{ + struct nullrpc_pipe_msg *nullmsg + = container_of(msg, struct nullrpc_pipe_msg, msg); + + kfree(nullmsg->res.data); + kfree(nullmsg->msg.data); + kfree(nullmsg); +} + +struct rpc_pipe_ops gss_svc_nullrpc_ops = { + .upcall = gss_nullrpc_pipe_read, + .downcall = gss_nullrpc_pipe_write, + .destroy_msg = gss_nullrpc_destroy_msg, +}; + +enum { + NFSDFILE_init_context = 2, + NFSDFILE_EOF +}; + +static struct rpc_filelist nfsdfiles[] = { + [NFSDFILE_init_context] = { + .name = "init_context", + .i_fop = &gss_svc_downcall_fops, + .mode = S_IFREG | S_IWUSR | S_IRUSR, + }, +}; + +int +gss_svc_setup_pipes(void) +{ + struct dentry *dentry; + + dentry = rpc_mkdir("/nfsd", NULL, nfsdfiles, + NFSDFILE_init_context, NFSDFILE_EOF); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + dput(dentry); + + nullrpc_dentry = rpc_mkpipe("/nfsd/nullrpc/", + (void *)0xdeadbeef, /* XXX */ + &gss_svc_nullrpc_ops, RPC_PIPE_WAIT_FOR_OPEN); + if (IS_ERR(nullrpc_dentry)) + return PTR_ERR(dentry); + return 0; +} + +static void +copy_upcall_response_to_resbuf(struct svc_rqst *rqstp) +{ + struct nullrpc_pipe_msg *nullmsg /* Ugh: */ + = (struct nullrpc_pipe_msg *)rqstp->rq_deferred->handle.item; + /* userspace returns response packet starting at the replystate: */ + char *res_start = rqstp->rq_res.head->iov_base + + rqstp->rq_res.head->iov_len - 4; + + memcpy(res_start, nullmsg->res.data, nullmsg->res.len); + if (!xdr_ressize_check(rqstp, (u32 *)(res_start + nullmsg->res.len))) + BUG(); + kfree(nullmsg->res.data); + kfree(nullmsg->msg.data); + kfree(nullmsg); +} + +static void +do_gss_svc_upcall(struct svc_rqst *rqstp) +{ + struct cache_deferred_req *dreq; + struct nullrpc_pipe_msg *nullmsg; + + dreq = rqstp->rq_chandle.defer(&rqstp->rq_chandle); + nullmsg = kmalloc(sizeof(*nullmsg), GFP_KERNEL); + if (!nullmsg) + goto out_err; + nullmsg->msg.len = rqstp->rq_arg.head->iov_len; + nullmsg->msg.data = kmalloc(nullmsg->msg.len, GFP_KERNEL); + if (!nullmsg->msg.data) + goto out_err; + memcpy(nullmsg->msg.data, rqstp->rq_arg.head->iov_base, + nullmsg->msg.len); + nullmsg->msg.copied = nullmsg->msg.errno = 0; + /* userspace will return to us the response packet starting + * with the replystate; set res.len to the maximum allowable + * length of the data that userspace can return: */ + nullmsg->res.len = PAGE_SIZE - (rqstp->rq_res.head->iov_len - 4); + nullmsg->res.data = NULL; + nullmsg->dreq = dreq; + dreq->item = (struct cache_head *)nullmsg; /* Double-Ugh. */ + if (rpc_queue_upcall(nullrpc_dentry->d_inode, &nullmsg->msg)) + BUG(); + return; +out_err: + kfree(nullmsg); + return; +} + +static int +gss_svc_handle_init(struct svc_rqst *rqstp) +{ + if (rqstp->rq_deferred) { + copy_upcall_response_to_resbuf(rqstp); + return SVC_COMPLETE; + } else { + do_gss_svc_upcall(rqstp); + return SVC_DROP; + } +} + +static int +xdr_decode_rpc_gss_cred(u32 **p, u32 *end, struct rpc_gss_wire_cred *gc) +{ + if (xdr_bounded_get_u32(p, end, &gc->gc_v)) return -1; + if (xdr_bounded_get_u32(p, end, &gc->gc_proc)) return -1; + if (xdr_bounded_get_u32(p, end, &gc->gc_seq)) return -1; + if (xdr_bounded_get_u32(p, end, &gc->gc_svc)) return -1; + if (xdr_bounded_get_netobj(p, end, &gc->gc_ctx)) return -1; + dprintk("RPC: xdr_decode_rpc_gss_cred() = (%d, %d, %d, %d, %p:%d)\n", + gc->gc_v, gc->gc_proc, gc->gc_seq, gc->gc_svc, + gc->gc_ctx.data, gc->gc_ctx.len); + + return 0; +} + +/* Implements sequence number algorithm as specified in RFC 2203. + * Assumes ctx_id has been validated. */ +static int +gss_check_seq_num(struct gss_svc_ctx *gsc, int seq_num) +{ + struct gss_svc_seq_data *sd = &gsc->gsc_sd; + + spin_lock(&sd->sd_lock); + if (seq_num > sd->sd_max) { + if (seq_num >= sd->sd_max + GSS_SEQ_WIN) + memset(sd->sd_win,0,sizeof(sd->sd_win)); + else while (sd->sd_max < seq_num) { + sd->sd_max++; + sd->sd_win[sd->sd_max % GSS_SEQ_WIN] = 0; + } + sd->sd_max = seq_num; + sd->sd_win[seq_num % GSS_SEQ_WIN] = 1; + goto ok; + } else if (seq_num <= sd->sd_max - GSS_SEQ_WIN) { + goto drop; + } else { /* sd_max - GSS_SEQ_WIN < seq_num <= sd_max */ + if (sd->sd_win[seq_num % GSS_SEQ_WIN]) + goto drop; + else { + sd->sd_win[seq_num % GSS_SEQ_WIN] = 1; + goto ok; + } + } + BUG(); +drop: + spin_unlock(&sd->sd_lock); + return 0; +ok: + spin_unlock(&sd->sd_lock); + return 1; +} + +/* Verify the checksum on the header and return SVC_OK on success, advancing + * *p (which should begin at the start of the verifier) past the end of the + * verifier. Otherwise, return SVC_DROP (in the case of a bad sequence + * number) or return SVC_DENIED and indicate error in authp. + * Caller verifies ctx_id. */ +/* XXX the prototype of this function has gotten way too long. */ +static int +gss_verify_header(struct svc_rqst *rqstp, struct gss_svc_ctx *gsc, u32 **p, u32 *end, + u32 *hdr_start, struct rpc_gss_wire_cred *gc, u32 *authp) +{ + struct gss_ctx *ctx_id = gsc->gsc_ctx; + struct xdr_buf rpchdr; + struct xdr_netobj checksum; + u32 flavor = 0; + struct iovec iov; + + /* data to compute the checksum over: */ + iov.iov_base = hdr_start; + iov.iov_len = (u8 *)*p - (u8 *)hdr_start; + xdr_buf_from_iov(&iov, &rpchdr); + + if (xdr_bounded_get_u32(p, end, &flavor)) { + *authp = rpc_autherr_badverf; + return SVC_DENIED; + } + if (flavor != RPC_AUTH_GSS) { + dprintk("RPC: svcauth_gss: bad verifier flavor %d\n", flavor); + *authp = rpc_autherr_badverf; + return SVC_DENIED; + } + if (xdr_bounded_get_netobj(p, end, &checksum)) { + *authp = rpc_autherr_badverf; + return SVC_DENIED; + } + dprintk("RPC: svcauth_gss: verifier len %d\n", checksum.len); + dprintk("RPC: verifier:\n"); + print_hexl((u32 *)checksum.data, checksum.len, 0); + + if (rqstp->rq_deferred) /* skip verification of revisited request */ + return SVC_OK; + if (gss_verify_mic(ctx_id, &rpchdr, &checksum, NULL) + != GSS_S_COMPLETE) { + *authp = rpc_autherr_badverf; + return SVC_DENIED; + } + + if ((gc->gc_proc != RPC_GSS_PROC_INIT) + && (gc->gc_proc != RPC_GSS_PROC_CONTINUE_INIT)) { + if (gc->gc_seq > MAXSEQ) { + dprintk("svcauth_gss: discarding request with large" + " sequence number %d\n", gc->gc_seq); + *authp = rpcsec_gsserr_ctxproblem; + return SVC_DENIED; + } + if (!gss_check_seq_num(gsc, gc->gc_seq)) { + dprintk("svcauth_gss: discarding request with old" + " sequence number %d\n", gc->gc_seq); + return SVC_DROP; + } + } + return SVC_OK; +} + +static int +gss_write_verifier(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq) +{ + u32 xdr_seq; + u32 maj_stat; + struct xdr_buf verf_data; + struct xdr_netobj mic; + u32 *p; + struct iovec iov; + + svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_GSS)); + xdr_seq = htonl(seq); + + iov.iov_base = &xdr_seq; + iov.iov_len = sizeof(xdr_seq); + xdr_buf_from_iov(&iov, &verf_data); + p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len; + mic.data = (u8 *)(p + 1); + maj_stat = gss_get_mic(ctx_id, 0, &verf_data, &mic); + if(maj_stat != GSS_S_COMPLETE) + return -1; + *p++ = htonl(mic.len); + p += XDR_QUADLEN(mic.len); + if (!xdr_ressize_check(rqstp, p)) + return -1; + return 0; +} + +struct gss_domain { + struct auth_domain h; + u32 pseudoflavor; +}; + +/* XXX this should be done in gss_pseudoflavors, and probably shouldn't + * be hardcoded: */ +static struct auth_domain * +find_gss_auth_domain(struct gss_ctx *ctx, u32 svc) +{ + switch(gss_get_pseudoflavor(ctx, 0, svc)) { + case RPC_AUTH_GSS_KRB5: + return auth_domain_find("gss/krb5"); + case RPC_AUTH_GSS_KRB5I: + return auth_domain_find("gss/krb5i"); + case RPC_AUTH_GSS_KRB5P: + return auth_domain_find("gss/krb5p"); + } + return NULL; +} + +int +svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) +{ + struct gss_domain *new; + struct auth_domain *test; + static char *prefix = "gss/"; + int stat = -1; + + new = kmalloc(sizeof(*new), GFP_KERNEL); + if (!new) + goto out; + cache_init(&new->h.h); + atomic_inc(&new->h.h.refcnt); + new->h.name = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL); + if (!new->h.name) + goto out_free_dom; + strcpy(new->h.name, prefix); + strcat(new->h.name, name); + new->h.flavour = RPC_AUTH_GSS; + new->pseudoflavor = pseudoflavor; + new->h.h.expiry_time = NEVER; + new->h.h.flags = 0; + + test = auth_domain_lookup(&new->h, 2); + if (test == &new->h) { + if (atomic_dec_and_test(&new->h.h.refcnt)) BUG(); + } else { /* Duplicate registration? */ + auth_domain_put(&new->h); + goto out; /* Note auth_domain_put does the kfrees. */ + } + return 0; + +out_free_dom: + kfree(new); +out: + return stat; +} + +static struct gss_svc_ctx * +gss_read_ctxhandle(struct xdr_netobj *ctxhandle) +{ + if (ctxhandle->len != sizeof(u32)) + return NULL; + + return gss_svc_searchbyctx(*(u32 *)ctxhandle->data); +} + +/* In the case of an authentication error, rqstp->rq_resbuf is left pointing + * at the place where the reject_stat will go. + * For other errors (rpc_garbage_args, rpc_system_err, etc.) and for success, + * we leave the pointer where that error (the accept_stat) will go, right + * after the verifier. + * Note that an authentication error is sometimes returned in cases where + * rpc_system_err would make more sense (e.g., memory allocation failures) + * because there's no way to return rpc_system_err until we've already + * produced a verifier. + * In special rpcsec_gss cases (e.g. context initialization or destruction) we + * encode a complete reply here and return the value SVC_COMPLETE to + * indicate that we've done so. */ +static int +svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) +{ + struct iovec *argp = rqstp->rq_arg.head; + struct iovec *resp = rqstp->rq_res.head; + struct svc_cred *cred = &rqstp->rq_cred; + u32 *bufp = argp->iov_base, credlen; + struct gss_svc_data *svcdata = rqstp->rq_auth_data; + struct rpc_gss_wire_cred *gc; + struct gss_svc_ctx *gsc = NULL; + /* beginning of rpc header (xid) is seven u32's back. We need this to + * verify checksum: */ + u32 *hdr_start = argp->iov_base - 28; + u32 *argp_end = argp->iov_base + argp->iov_len; + u32 *accept_stat = NULL; + u32 *reject_stat = resp->iov_base; + int ret; + + dprintk("RPC: svcauth_gss: argp->iov_len %d\n",argp->iov_len); + + *authp = rpc_autherr_badcred; + + if (argp->iov_len < 6) + goto auth_err; + credlen = ntohl(*bufp++); + + if (!svcdata) + svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL); + if (!svcdata) + goto auth_err; + rqstp->rq_auth_data = svcdata; + + gc = &svcdata->clcred; + if (xdr_decode_rpc_gss_cred(&bufp, argp_end, gc)) + goto auth_err; + + if (gc->gc_v != RPC_GSS_VERSION) + goto auth_err; + + if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0)) + goto auth_err; + + if ((gc->gc_proc == RPC_GSS_PROC_INIT) + || (gc->gc_proc == RPC_GSS_PROC_CONTINUE_INIT)) { + if (gss_svc_handle_init(rqstp) == SVC_COMPLETE) + goto complete; + else + goto drop; + } + *authp = rpc_autherr_rejectedcred; + if ((gc->gc_proc != RPC_GSS_PROC_DESTROY) + && (gc->gc_proc != RPC_GSS_PROC_DATA)) + goto auth_err; + + /* integrity and privacy unsupported: */ + if (gc->gc_svc != RPC_GSS_SVC_NONE) + goto auth_err; + + *authp = rpcsec_gsserr_credproblem; + gsc = gss_read_ctxhandle(&gc->gc_ctx); + if (!gsc) + goto auth_err; + + rqstp->rq_client = find_gss_auth_domain(gsc->gsc_ctx, gc->gc_svc); + if (rqstp->rq_client == NULL) + goto auth_err; + + switch (gss_verify_header(rqstp, gsc, &bufp, argp_end, hdr_start, gc, + authp)) { + case SVC_OK: + break; + case SVC_DENIED: + goto auth_err; + case SVC_DROP: + goto drop; + default: + BUG(); + } + + *authp = rpcsec_gsserr_ctxproblem; + if (gss_write_verifier(rqstp, gsc->gsc_ctx, gc->gc_seq)) + goto auth_err; + + if (gc->gc_proc == RPC_GSS_PROC_DESTROY) { + gss_svc_ctx_remove(gsc); + svc_putu32(resp, rpc_success); + goto complete; + } + accept_stat = resp->iov_base; + + cred->cr_uid = gsc->gsc_uid; + cred->cr_gid = (gid_t) -1; + cred->cr_groups[0] = NOGROUP; + + argp->iov_len -= (u8 *)bufp - (u8 *)argp->iov_base; + argp->iov_base = bufp; + svcdata->body_start = accept_stat + 1; + 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 (gsc) + gss_svc_put_ctx(gsc); + return ret; +} + +static int +svcauth_gss_release(struct svc_rqst *rqstp) +{ + if (rqstp->rq_client) + auth_domain_put(rqstp->rq_client); + rqstp->rq_client = NULL; + + return 0; +} + +static void +svcauth_gss_domain_release(struct auth_domain *dom) +{ + struct gss_domain *gd = container_of(dom, struct gss_domain, h); + + kfree(dom->name); + kfree(gd); +} + +struct auth_ops svcauthops_gss = { + .name = "rpcsec_gss", + .flavour = RPC_AUTH_GSS, + .accept = svcauth_gss_accept, + .release = svcauth_gss_release, + .domain_release = svcauth_gss_domain_release, +}; + +int +gss_svc_init(void) +{ + int err; + + err = register_rpc_pipefs(); + if (err) + return err; + err = gss_svc_setup_pipes(); + if (err) + return err; + svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); + return 0; +} diff -puN net/sunrpc/sunrpc_syms.c~rpc_svcgss net/sunrpc/sunrpc_syms.c --- linux-2.5.74/net/sunrpc/sunrpc_syms.c~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/sunrpc_syms.c 2003-07-03 16:07:24.000000000 -0400 @@ -56,8 +56,10 @@ EXPORT_SYMBOL(rpc_unlink); EXPORT_SYMBOL(rpc_wake_up); EXPORT_SYMBOL(rpc_queue_upcall); EXPORT_SYMBOL(rpc_mkpipe); +EXPORT_SYMBOL(rpc_mkdir); EXPORT_SYMBOL(__rpc_purge_current_upcall); EXPORT_SYMBOL(__rpc_purge_one_upcall); +EXPORT_SYMBOL(register_rpc_pipefs); /* Client transport */ EXPORT_SYMBOL(xprt_create_proto); @@ -84,6 +86,8 @@ EXPORT_SYMBOL(svc_recv); EXPORT_SYMBOL(svc_wake_up); EXPORT_SYMBOL(svc_makesock); EXPORT_SYMBOL(svc_reserve); +EXPORT_SYMBOL(svc_auth_register); +EXPORT_SYMBOL(auth_domain_lookup); /* RPC statistics */ #ifdef CONFIG_PROC_FS diff -puN net/sunrpc/svc.c~rpc_svcgss net/sunrpc/svc.c --- linux-2.5.74/net/sunrpc/svc.c~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/svc.c 2003-07-03 16:07:24.000000000 -0400 @@ -200,6 +200,8 @@ svc_exit_thread(struct svc_rqst *rqstp) kfree(rqstp->rq_resp); if (rqstp->rq_argp) kfree(rqstp->rq_argp); + if (rqstp->rq_auth_data) + kfree(rqstp->rq_auth_data); kfree(rqstp); /* Release the server */ @@ -322,6 +324,8 @@ svc_process(struct svc_serv *serv, struc goto err_bad_auth; case SVC_DROP: goto dropit; + case SVC_COMPLETE: + goto sendit; } progp = serv->sv_program; diff -puN net/sunrpc/auth_gss/gss_krb5_mech.c~rpc_svcgss net/sunrpc/auth_gss/gss_krb5_mech.c --- linux-2.5.74/net/sunrpc/auth_gss/gss_krb5_mech.c~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/auth_gss/gss_krb5_mech.c 2003-07-03 16:07:24.000000000 -0400 @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -232,6 +234,8 @@ static int __init init_kerberos_module(v gm = gss_mech_get_by_OID(&gss_mech_krb5_oid); gss_register_triple(RPC_AUTH_GSS_KRB5 , gm, 0, RPC_GSS_SVC_NONE); gss_register_triple(RPC_AUTH_GSS_KRB5I, gm, 0, RPC_GSS_SVC_INTEGRITY); + if (svcauth_gss_register_pseudoflavor(RPC_AUTH_GSS_KRB5, "krb5")) + printk("Failed to register %s with server!\n", "krb5"); gss_mech_put(gm); return 0; } diff -puN net/sunrpc/rpc_pipe.c~rpc_svcgss net/sunrpc/rpc_pipe.c --- linux-2.5.74/net/sunrpc/rpc_pipe.c~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/rpc_pipe.c 2003-07-03 16:07:24.000000000 -0400 @@ -355,15 +355,6 @@ enum { RPCAUTH_RootEOF }; -/* - * Description of fs contents. - */ -struct rpc_filelist { - char *name; - struct file_operations *i_fop; - int mode; -}; - static struct rpc_filelist files[] = { [RPCAUTH_lockd] = { .name = "lockd", @@ -615,7 +606,8 @@ out_err: struct dentry * -rpc_mkdir(char *path, struct rpc_clnt *rpc_client) +rpc_mkdir(char *path, void *private, struct rpc_filelist *files, + int start, int eof) { struct nameidata nd; struct dentry *dentry; @@ -628,9 +620,8 @@ rpc_mkdir(char *path, struct rpc_clnt *r dir = nd.dentry->d_inode; if ((error = __rpc_mkdir(dir, dentry)) != 0) goto err_dput; - RPC_I(dentry->d_inode)->private = rpc_client; - error = rpc_populate(dentry, authfiles, - RPCAUTH_info, RPCAUTH_EOF); + RPC_I(dentry->d_inode)->private = private; + error = rpc_populate(dentry, files, start, eof); if (error) goto err_depopulate; out: @@ -648,6 +639,12 @@ err_dput: goto out; } +struct dentry * +rpc_mkdir_client(char *path, struct rpc_clnt *rpc_client) +{ + return rpc_mkdir(path, rpc_client, authfiles, RPCAUTH_info, RPCAUTH_EOF); +} + int rpc_rmdir(char *path) { @@ -810,8 +807,13 @@ init_once(void * foo, kmem_cache_t * cac } } +static atomic_t first_to_register = ATOMIC_INIT(1); +int registered = 0; + int register_rpc_pipefs(void) { + if (!atomic_dec_and_test(&first_to_register)) + return registered ? 0 : -ENOMEM; rpc_inode_cachep = kmem_cache_create("rpc_inode_cache", sizeof(struct rpc_inode), 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, @@ -819,6 +821,7 @@ int register_rpc_pipefs(void) if (!rpc_inode_cachep) return -ENOMEM; register_filesystem(&rpc_pipe_fs_type); + registered = 1; return 0; } diff -puN include/linux/sunrpc/rpc_pipe_fs.h~rpc_svcgss include/linux/sunrpc/rpc_pipe_fs.h --- linux-2.5.74/include/linux/sunrpc/rpc_pipe_fs.h~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/include/linux/sunrpc/rpc_pipe_fs.h 2003-07-03 16:07:24.000000000 -0400 @@ -3,6 +3,9 @@ #ifdef __KERNEL__ +#include +#include + struct rpc_pipe_msg { struct list_head list; void *data; @@ -11,6 +14,15 @@ struct rpc_pipe_msg { int errno; }; +/* + * Description of fs contents. + */ +struct rpc_filelist { + char *name; + struct file_operations *i_fop; + int mode; +}; + struct rpc_pipe_ops { ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t); ssize_t (*downcall)(struct file *, const char __user *, size_t); @@ -38,11 +50,15 @@ RPC_I(struct inode *inode) extern void rpc_inode_setowner(struct inode *, void *); extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); -extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); +extern struct dentry *rpc_mkdir_client(char *, struct rpc_clnt *); extern int rpc_rmdir(char *); extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags); extern int rpc_unlink(char *); +extern struct dentry *rpc_mkdir(char *path, void *private, + struct rpc_filelist *files, int start, int eof); +extern int register_rpc_pipefs(void); + void __rpc_purge_current_upcall(struct file *); void __rpc_purge_one_upcall(struct file *filp, struct rpc_pipe_msg *target); diff -puN net/sunrpc/clnt.c~rpc_svcgss net/sunrpc/clnt.c --- linux-2.5.74/net/sunrpc/clnt.c~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/clnt.c 2003-07-03 16:07:24.000000000 -0400 @@ -75,7 +75,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, "%s/clnt%x", dir_name, (unsigned int)clntid++); clnt->cl_pathname[sizeof(clnt->cl_pathname) - 1] = '\0'; - clnt->cl_dentry = rpc_mkdir(clnt->cl_pathname, clnt); + clnt->cl_dentry = rpc_mkdir_client(clnt->cl_pathname, clnt); if (!IS_ERR(clnt->cl_dentry)) return 0; error = PTR_ERR(clnt->cl_dentry); diff -puN net/sunrpc/svcsock.c~rpc_svcgss net/sunrpc/svcsock.c diff -puN include/linux/sunrpc/auth_gss.h~rpc_svcgss include/linux/sunrpc/auth_gss.h --- linux-2.5.74/include/linux/sunrpc/auth_gss.h~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/include/linux/sunrpc/auth_gss.h 2003-07-03 16:07:24.000000000 -0400 @@ -62,8 +62,6 @@ struct rpc_gss_init_res { struct xdr_netobj gr_token; /* token */ }; -#define GSS_SEQ_WIN 5 - /* The gss_cl_ctx struct holds all the information the rpcsec_gss client * code needs to know about a single security context. In particular, * gc_gss_ctx is the context handle that is used to do gss-api calls, while diff -puN net/sunrpc/auth_gss/sunrpcgss_syms.c~rpc_svcgss net/sunrpc/auth_gss/sunrpcgss_syms.c --- linux-2.5.74/net/sunrpc/auth_gss/sunrpcgss_syms.c~rpc_svcgss 2003-07-03 16:07:24.000000000 -0400 +++ linux-2.5.74-bfields/net/sunrpc/auth_gss/sunrpcgss_syms.c 2003-07-03 16:07:24.000000000 -0400 @@ -8,6 +8,7 @@ #include #include +#include #include /* sec_triples: */ @@ -17,6 +18,7 @@ EXPORT_SYMBOL(gss_cmp_triples); EXPORT_SYMBOL(gss_pseudoflavor_to_mechOID); EXPORT_SYMBOL(gss_pseudoflavor_supported); EXPORT_SYMBOL(gss_pseudoflavor_to_service); +EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor); /* registering gss mechanisms to the mech switching code: */ EXPORT_SYMBOL(gss_mech_register); _