diff -u -r -N linux-2.5.49-06-krb5/include/linux/sunrpc/gss_svc_cache.h linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/gss_svc_cache.h --- linux-2.5.49-06-krb5/include/linux/sunrpc/gss_svc_cache.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/gss_svc_cache.h 2002-11-24 00:51:33.000000000 -0500 @@ -0,0 +1,74 @@ +/* + * 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 + +/* Chuck suggested that this should be a dynamically allocated + * hash table size, dependent on the amount of memory on the machine. + */ +#define GSS_HASH_BITS 8 +#define GSS_HASH_SIZE (1 << GSS_HASH_BITS) +#define GSS_HASH_MASK (GSS_HASH_SIZE - 1) + +struct gss_svc_ctx_mapping { + rwlock_t lock; + struct list_head gss_ctx_cache[GSS_HASH_SIZE]; +}; + +#define GSS_SEQ_WIN 5 + +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_ctx_cacheent { + struct gss_ctx *gcc_ctx; + uid_t gcc_uid; + /* spec allow longer ctx handles, but we only use 4 bytes: */ + u32 gcc_wire_ctx; + struct gss_svc_seq_data gcc_sd; + atomic_t gcc_refcount; + struct list_head gcc_cache; +}; + +void gss_ctx_free(struct gss_ctx_cacheent *p); +u32 gss_set_ctx(struct gss_ctx **ctx_id, struct gss_ctx_cacheent *cep); +u32 gss_svc_validate_context(struct gss_ctx *ctx_id); +int gss_svc_cache_context(struct gss_ctx *ctx, uid_t uid, u32 wire_ctx); +struct gss_ctx_cacheent * + gss_svc_searchbyctx(u32 wire_ctx); +void gss_svc_ctx_init(void); +void gss_svc_ctx_shutdown(void); +void gss_svc_ctx_remove(struct gss_ctx_cacheent *); + +static inline void +gss_ctx_put(struct gss_ctx_cacheent *p) +{ + if (atomic_dec_and_test(&p->gcc_refcount)) + gss_ctx_free(p); +} + +#endif /* __KERNEL__ */ +#endif /* _LINUX_GSS_SVC_CACHE_H */ + diff -u -r -N linux-2.5.49-06-krb5/include/linux/sunrpc/gss_xdr.h linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/gss_xdr.h --- linux-2.5.49-06-krb5/include/linux/sunrpc/gss_xdr.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/gss_xdr.h 2002-11-24 00:51:33.000000000 -0500 @@ -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 -u -r -N linux-2.5.49-06-krb5/include/linux/sunrpc/svc.h linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/svc.h --- linux-2.5.49-06-krb5/include/linux/sunrpc/svc.h 2002-11-13 12:49:50.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/svc.h 2002-11-24 00:51:33.000000000 -0500 @@ -130,6 +130,7 @@ 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 -u -r -N linux-2.5.49-06-krb5/include/linux/sunrpc/svcauth.h linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/svcauth.h --- linux-2.5.49-06-krb5/include/linux/sunrpc/svcauth.h 2002-10-19 00:01:48.000000000 -0400 +++ linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/svcauth.h 2002-11-24 00:51:33.000000000 -0500 @@ -63,6 +63,10 @@ * 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). @@ -95,9 +99,10 @@ #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 *statp, u32 *authp, int proc); +extern int svc_authenticate(struct svc_rqst *rqstp, u32 *authp, int proc); extern int svc_authorise(struct svc_rqst *rqstp); extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops); extern void svc_auth_unregister(rpc_authflavor_t flavor); diff -u -r -N linux-2.5.49-06-krb5/include/linux/sunrpc/svcauth_gss.h linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/svcauth_gss.h --- linux-2.5.49-06-krb5/include/linux/sunrpc/svcauth_gss.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/svcauth_gss.h 2002-11-24 00:51:33.000000000 -0500 @@ -0,0 +1,33 @@ +/* + * 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); + +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 -u -r -N linux-2.5.49-06-krb5/include/linux/sunrpc/svcauth_unix.h linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/svcauth_unix.h --- linux-2.5.49-06-krb5/include/linux/sunrpc/svcauth_unix.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/include/linux/sunrpc/svcauth_unix.h 2002-11-24 00:51:33.000000000 -0500 @@ -0,0 +1,37 @@ +/* + * linux/include/linux/sunrpc/svcauth.h + * + * interface to ip-mapping cache used by auth_unix and others + * + * Copyright (C) 1995, 1996 Olaf Kirch + */ + +#ifndef _LINUX_SUNRPC_SVCAUTH_UNIX_H_ +#define _LINUX_SUNRPC_SVCAUTH_UNIX_H_ + +#ifdef __KERNEL__ + +#include + +struct unix_domain { + struct auth_domain h; + int addr_changes; + /* other stuff later */ +}; + +struct ip_map { + struct cache_head h; + char *m_class; /* e.g. "nfsd" */ + struct in_addr m_addr; + struct unix_domain *m_client; + int m_add_change; +}; + +struct ip_map * +unix_ip_map_lookup(struct ip_map * ipmp, int set); + +void ip_map_put(struct cache_head *item, struct cache_detail *cd); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SUNRPC_SVCAUTH_UNIX_H_ */ diff -u -r -N linux-2.5.49-06-krb5/net/sunrpc/auth_gss/Makefile linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/Makefile --- linux-2.5.49-06-krb5/net/sunrpc/auth_gss/Makefile 2002-11-24 00:51:30.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/Makefile 2002-11-24 00:51:33.000000000 -0500 @@ -7,7 +7,8 @@ export-objs := sunrpcgss_syms.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 -u -r -N linux-2.5.49-06-krb5/net/sunrpc/auth_gss/auth_gss.c linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/auth_gss.c --- linux-2.5.49-06-krb5/net/sunrpc/auth_gss/auth_gss.c 2002-11-24 00:51:26.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/auth_gss.c 2002-11-26 19:30:56.000000000 -0500 @@ -49,8 +49,10 @@ #include #include #include +#include #include #include +#include #include static struct rpc_authops authgss_ops; @@ -169,44 +171,6 @@ 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 int gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf, struct gss_cl_ctx **gc, uid_t *uid) @@ -720,6 +684,15 @@ 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 -u -r -N linux-2.5.49-06-krb5/net/sunrpc/auth_gss/gss_svc_cache.c linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/gss_svc_cache.c --- linux-2.5.49-06-krb5/net/sunrpc/auth_gss/gss_svc_cache.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/gss_svc_cache.c 2002-11-24 00:51:33.000000000 -0500 @@ -0,0 +1,186 @@ +/* + * 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 + +static struct gss_svc_ctx_mapping svc_ctx_map; + +/* + ***************** gss context cache functions ********************* + * + * On the server, the gss_svc_ctx_mapping struct holds gss_ctx_cacheents + * hashed by context id. + */ + +struct gss_ctx_cacheent * +gss_ctx_alloc(void) +{ + struct gss_ctx_cacheent *p; + + /* caller must not hold spinlock, since this routine can block */ + + if (!(p = kmalloc(sizeof(struct gss_ctx_cacheent), GFP_KERNEL))) + goto nomem; + dprintk("RPC: gss_ctx_alloc: returning ctx_cacheent %p\n", p); + memset(p,0,sizeof(struct gss_ctx_cacheent)); + spin_lock_init(&p->gcc_sd.sd_lock); +out: + return p; +nomem: + printk("RPC: gss_ctx_alloc: out of memory!\n"); + p = NULL; + goto out; +} + +void +gss_ctx_free(struct gss_ctx_cacheent *p) +{ + dprintk("RPC: gss_ctx_free\n"); + if (p->gcc_ctx) + gss_delete_sec_context(&p->gcc_ctx); + dprintk("RPC: gss_ctx_free: called on cacheent %p\n", p); + kfree(p); +} + +void +gss_svc_ctx_init(void) +{ + int i; + + dprintk("GSS_SVC_CTX_INIT\n"); + rwlock_init(&svc_ctx_map.lock); + for (i = 0; i < GSS_HASH_SIZE; i++) { + INIT_LIST_HEAD(&svc_ctx_map.gss_ctx_cache[i]); + } +} + + +static inline void +gss_svc_ctx_insert(struct gss_ctx_cacheent *p) +{ + unsigned int ptrhash = (unsigned int)(p->gcc_wire_ctx) << 16; + unsigned int ctx_hashval = (ptrhash & GSS_HASH_MASK); + + dprintk("gss_svc_ctx_insert: ctx_hashval: %d\n",ctx_hashval); + /* caller must hold writelock */ + /* gcc_refcount==1 indicates in use by the cache */ + atomic_set(&p->gcc_refcount, 1); + list_add(&p->gcc_cache, &svc_ctx_map.gss_ctx_cache[ctx_hashval]); +} + +void +gss_svc_ctx_shutdown(void) +{ + int i; + struct list_head *l; + struct gss_ctx_cacheent *p; + + for (i = 0; i < GSS_HASH_SIZE; i++) { + l = &svc_ctx_map.gss_ctx_cache[i]; + while (!list_empty(l)) { + write_lock(&svc_ctx_map.lock); + p = list_entry(l->next, struct gss_ctx_cacheent, + gcc_cache); + list_del(&p->gcc_cache); + write_unlock(&svc_ctx_map.lock); + gss_ctx_put(p); + } + } +} + +/* gss_svc_get_context: stores a new context in the server context cache */ + +int +gss_svc_cache_context(struct gss_ctx *ctx, uid_t uid, u32 wire_ctx) +{ + struct gss_ctx_cacheent *cep = NULL; + + dprintk("RPC: gss_svc_cache_context\n"); + + if(!(cep = gss_ctx_alloc())) + return -ENOMEM; + cep->gcc_ctx = ctx; + cep->gcc_uid = uid; + cep->gcc_wire_ctx = wire_ctx; + write_lock(&svc_ctx_map.lock); + gss_svc_ctx_insert(cep); + write_unlock(&svc_ctx_map.lock); + + return 0; +} + +/* gss_svc_searchbyctx: search server context cache for context; return pointer + * to cacheent (and increment refcount) on success, NULL on failure. */ + +struct gss_ctx_cacheent * +gss_svc_searchbyctx(u32 wire_ctx) +{ + struct gss_ctx_cacheent *p; + unsigned int ptrhash = (unsigned int)wire_ctx << 16; + unsigned int ctx_hashval = (ptrhash & GSS_HASH_MASK); + struct list_head *l; + + read_lock(&svc_ctx_map.lock); + list_for_each(l, &svc_ctx_map.gss_ctx_cache[ctx_hashval]) { + p = list_entry(l, struct gss_ctx_cacheent, gcc_cache); + if (p->gcc_wire_ctx == wire_ctx){ + dprintk("gss_svc_searchbyctx returning p: %p\n",p); + atomic_inc(&p->gcc_refcount); + read_unlock(&svc_ctx_map.lock); + return p; + } + } + read_unlock(&svc_ctx_map.lock); + dprintk("gss_svc_searchbyctx returning NULL\n"); + return NULL; +} + +void +gss_svc_ctx_remove(struct gss_ctx_cacheent *gcc) { + write_lock(&svc_ctx_map.lock); + list_del(&gcc->gcc_cache); + write_unlock(&svc_ctx_map.lock); + gss_ctx_put(gcc); +} diff -u -r -N linux-2.5.49-06-krb5/net/sunrpc/auth_gss/gss_xdr.c linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/gss_xdr.c --- linux-2.5.49-06-krb5/net/sunrpc/auth_gss/gss_xdr.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/gss_xdr.c 2002-11-24 00:51:33.000000000 -0500 @@ -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 -u -r -N linux-2.5.49-06-krb5/net/sunrpc/auth_gss/svcauth_gss.c linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/svcauth_gss.c --- linux-2.5.49-06-krb5/net/sunrpc/auth_gss/svcauth_gss.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/auth_gss/svcauth_gss.c 2002-11-26 20:32:57.000000000 -0500 @@ -0,0 +1,871 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#ifdef RPC_DEBUG +# define RPCDBG_FACILITY RPCDBG_AUTH +#endif + +static struct inode *nullrpc_inode = NULL; +static struct inode *downcall_inode = 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; + + lock_kernel(); + 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: + unlock_kernel(); + return ret; +} + +struct file_operations gss_svc_downcall_fops = { + .llseek = no_llseek, + .write = gss_svc_downcall_write, +}; + +struct nullrpc_desc { + struct list_head inode_queue; + struct xdr_netobj req; + int err; + struct xdr_netobj res; + struct completion completion; +}; + +/* XXX does locking using the i_sem make sense here?: */ +static int +init_nullrpc_queue(struct inode *inode) +{ + struct list_head *queue; + int res = -ENOMEM; + + down(&inode->i_sem); + BUG_ON(inode->u.generic_ip); + if (!(queue = kmalloc(sizeof(*queue), GFP_KERNEL))) + goto out_unlock; + INIT_LIST_HEAD(queue); + inode->u.generic_ip = queue; + res = 0; +out_unlock: + up(&inode->i_sem); + return res; +} + +static int +nullrpc_queue_empty(struct inode *inode) +{ + return list_empty(inode->u.generic_ip); +} + +static struct nullrpc_desc * +dequeue_nullrpc(struct inode *inode) +{ + struct nullrpc_desc *desc = NULL; + struct list_head *queue; + + down(&inode->i_sem); + queue = inode->u.generic_ip; + if (list_empty(queue)) + goto out_unlock; + desc = list_entry(queue->next, struct nullrpc_desc, inode_queue); + list_del(queue->next); +out_unlock: + up(&inode->i_sem); + return desc; +} + +static void +enqueue_nullrpc(struct inode *inode, struct nullrpc_desc *desc) +{ + struct list_head *queue; + + down(&inode->i_sem); + queue = inode->u.generic_ip; + list_add_tail(&desc->inode_queue, queue); + up(&inode->i_sem); +} + +/* XXX what are all the lock_kernels below really needed for? */ + +static int +nullrpc_open(struct inode *inode, struct file *filp) +{ + + lock_kernel(); + filp->private_data = NULL; + unlock_kernel(); + return 0; +} + +static int +nullrpc_release(struct inode *inode, struct file *filp) +{ + struct nullrpc_desc *desc; + + lock_kernel(); + if ((desc = filp->private_data)) { + desc->err = -EIO; + complete(&desc->completion); + } + unlock_kernel(); + return 0; +} + +static int +nullrpc_write(struct file *filp, const char *buf, size_t size, loff_t *ppos) +{ + struct nullrpc_desc *desc; + int res = -EAGAIN; + + lock_kernel(); + desc = filp->private_data; + if (!desc || desc->req.len > 0) + goto out_unlock; + res = -ENOSPC; + if (size > desc->res.len) + goto out_unlock; + res = -EFAULT; + if (copy_from_user(desc->res.data, buf, size)) + goto out_unlock; + desc->res.len = size; + filp->private_data = NULL; + complete(&desc->completion); + res = size; +out_unlock: + unlock_kernel(); + return res; +} + +static int +nullrpc_read(struct file *filp, char *buf, size_t size, loff_t *ppos) +{ + struct nullrpc_desc *desc; + struct inode *inode; + int res = -EIO; + + lock_kernel(); + inode = filp->f_dentry->d_inode; + if (!filp->private_data) { + desc = dequeue_nullrpc(inode); + filp->private_data = desc; + if (desc) { + if (size > desc->res.len) + size = desc->res.len; + res = size - copy_to_user(buf, desc->req.data, size); + desc->req.data += res; + desc->req.len -= res; + } + } + unlock_kernel(); + return res; +} + +static DECLARE_WAIT_QUEUE_HEAD(nullrpc_wait); + +static unsigned int +nullrpc_poll(struct file *filp, poll_table *wait) +{ + struct nullrpc_desc *desc; + unsigned int mask = 0; + + lock_kernel(); + poll_wait(filp, &nullrpc_wait, wait); + desc = (struct nullrpc_desc *)filp->private_data; + if (desc) { + if (desc->req.len > 0) + mask |= POLLIN | POLLRDNORM; + else + mask |= POLLOUT | POLLWRNORM; + } else { + if (!nullrpc_queue_empty(filp->f_dentry->d_inode)) + mask |= POLLIN | POLLRDNORM; + } + unlock_kernel(); + return mask; +} + +static int +nullrpc_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct nullrpc_desc *desc; + int res; + int len = 0; + + if (cmd != FIONREAD) + return -EINVAL; + lock_kernel(); + desc = (struct nullrpc_desc *)filp->private_data; + if (desc) + len = desc->req.len; + res = put_user(len, (int *)arg); + unlock_kernel(); + return res; +} + + +struct file_operations nullrpc_fops = { + .llseek = no_llseek, + .read = nullrpc_read, + .write = nullrpc_write, + .poll = nullrpc_poll, + .ioctl = nullrpc_ioctl, + .open = nullrpc_open, + .release = nullrpc_release, +}; + +struct inode * +rpc_svc_gss_get_inode(struct super_block *sb, int mode) { + struct inode *inode = new_inode(sb); + + if (!inode) + return NULL; + inode->i_mode = mode; + inode->i_uid = inode->i_gid = 0; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_nlink++; + return inode; +} + +struct inode * +rpc_svc_gss_add_file(struct dentry *root, char *name, + struct file_operations *fops, int mode) { + struct qstr qname; + struct dentry *dentry; + struct inode *inode; + static int i = 1; + + qname.name = name; + qname.len = strlen(name); + qname.hash = full_name_hash(qname.name, qname.len); + dentry = d_alloc(root, &qname); + if (!dentry) + return NULL; + inode = rpc_svc_gss_get_inode(root->d_inode->i_sb, mode); + if (!inode) { + dput(dentry); + return NULL; + } + inode->i_ino = i++; + inode->i_fop = fops; + d_add(dentry, inode); + return inode; +} + +static int +rpc_svc_gss_populate(struct dentry *root) +{ + downcall_inode = rpc_svc_gss_add_file(root, "init_context", + &gss_svc_downcall_fops, S_IFREG | S_IWUSR); + if (!downcall_inode) + goto out_bad; + nullrpc_inode = rpc_svc_gss_add_file(root, "nullrpc", &nullrpc_fops, + S_IFREG | S_IWUSR | S_IRUSR); + return 0; +out_bad: + printk(KERN_WARNING "%s: %s failed to populate directory %s\n", + __FILE__, __FUNCTION__, root->d_name.name); + return -ENOMEM; +} + +static struct super_operations s_ops = { + .statfs = simple_statfs, +}; + +#define RPC_SVC_AUTH_GSS_MAGIC 0x095b1d9c + +static int +rpc_svc_gss_fill_super(struct super_block *sb, void *data, int silent) +{ + struct inode *inode; + struct dentry *root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = RPC_SVC_AUTH_GSS_MAGIC; + sb->s_op = &s_ops; + + if (!(inode = rpc_svc_gss_get_inode(sb, S_IFDIR | S_IRUSR | S_IXUSR))) + return -ENOMEM; + inode->i_fop = &simple_dir_operations; + inode->i_op = &simple_dir_inode_operations; + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return -ENOMEM; + } + if (rpc_svc_gss_populate(root)) + goto out; + sb->s_root = root; + return 0; +out: + d_genocide(root); + dput(root); + return -ENOMEM; +} + +static struct super_block * +rpc_svc_gss_get_sb(struct file_system_type *fs_type, + int flags, char *dev_name, void *data) +{ + return get_sb_single(fs_type, flags, data, rpc_svc_gss_fill_super); +} + + +static struct file_system_type rpc_svc_gss_fs_type = { + .owner = THIS_MODULE, + .name = "rpc_svc_gss_pipefs", + .get_sb = rpc_svc_gss_get_sb, + .kill_sb = kill_litter_super, +}; + +static struct vfsmount *rpc_svc_gss_mnt; + +int +gss_svc_setup_pipes(void) +{ + int err = -ENODEV; + + register_filesystem(&rpc_svc_gss_fs_type); + rpc_svc_gss_mnt = kern_mount(&rpc_svc_gss_fs_type); + if (IS_ERR(rpc_svc_gss_mnt)) + goto out_err; + BUG_ON(!nullrpc_inode); + err = init_nullrpc_queue(nullrpc_inode); + if (err) + goto out_putmount; + return 0; +out_putmount: + mntput(rpc_svc_gss_mnt); +out_err: + return err; +} + + +static int +gss_svc_do_null_upcall(struct svc_rqst *rqstp) +{ + struct nullrpc_desc desc = { + .req = { + .data = rqstp->rq_arg.head->iov_base, + .len = rqstp->rq_arg.head->iov_len, + }, + .err = 0, + .res = { + .data = rqstp->rq_res.head->iov_base + + rqstp->rq_res.head->iov_len, + .len = PAGE_SIZE + - rqstp->rq_res.head->iov_len, + }, + }; + + init_completion(&desc.completion); + enqueue_nullrpc(nullrpc_inode, &desc); + wait_for_completion(&desc.completion); + + return desc.err; +} + +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_ctx_cacheent *gcc, int seq_num) { + struct gss_svc_seq_data *sd = &gcc->gcc_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. */ +static int +gss_verify_header(struct gss_ctx_cacheent *gcc, u32 **p, u32 *end, + u32 *hdr_start, struct rpc_gss_wire_cred *gc, u32 *authp) +{ + struct gss_ctx *ctx_id = gcc->gcc_ctx; + struct xdr_netobj rpchdr, checksum; + u32 flavor = 0; + + /* data to compute the checksum over: */ + rpchdr.data = (u8 *)hdr_start; + rpchdr.len = (u8 *)p - rpchdr.data; + + 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 (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(gcc, 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 iovec *resp, struct gss_ctx *ctx_id, u32 seq) +{ + u32 xdr_seq; + u32 maj_stat; + struct xdr_netobj bufin, bufout; + + svc_putu32(resp, htonl(RPC_AUTH_GSS)); + xdr_seq = htonl(seq); + bufin.data = (u8 *)&xdr_seq; + bufin.len = sizeof(xdr_seq); + maj_stat = gss_get_mic(ctx_id, 0, &bufin, &bufout); + if(maj_stat != GSS_S_COMPLETE) + return -1; + resp->iov_base = xdr_encode_netobj(resp->iov_base,&bufout); + resp->iov_len += XDR_QUADLEN(bufout.len) + 1; + kfree(bufout.data); + return 0; +} + +/* 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 with *statp = rpc_reply_complete + * to indicate that we've done so. */ +/* XXX This function is too long and complicated. The flow of control and + * the error handling are confusing. */ +static int +svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp, int proc) +{ + 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 rpc_gss_wire_cred *gc; + struct gss_ctx_cacheent *gcc = NULL; + /* beginning of rpc header (xid) is six u32's back. We need this to + * verify checksum: */ + u32 *hdr_start = argp->iov_base - 24; + u32 *argp_end = argp->iov_base + argp->iov_len; + u32 *accept_stat = NULL; + u32 *reject_stat = resp->iov_base; + struct ip_map key, *ipm; + + dprintk("RPC: svcauth_gss: argp->iov_len %d\n",argp->iov_len); + if (argp->iov_len < 6) { + *authp = rpc_autherr_badcred; + goto auth_err; + } + credlen = ntohl(*bufp++); + + if (!rqstp->rq_auth_data) { + if (!(rqstp->rq_auth_data + = kmalloc(sizeof(struct gss_svc_data), GFP_KERNEL))) { + *authp = rpc_autherr_badcred; + goto auth_err; + } + } + + gc = &((struct gss_svc_data *)rqstp->rq_auth_data)->clcred; + if (xdr_decode_rpc_gss_cred(&bufp, argp_end, gc)) { + *authp = rpc_autherr_badcred; + goto auth_err; + } + + if (gc->gc_v != RPC_GSS_VERSION) { + *authp = rpc_autherr_badcred; + goto auth_err; + } + + switch (gc->gc_proc) { + case RPC_GSS_PROC_DATA: + if (gc->gc_ctx.len != sizeof(struct gss_ctx *)) { + *authp = rpc_autherr_badcred; + goto auth_err; + } + if (!(gcc = gss_svc_searchbyctx(*(u32 *)gc->gc_ctx.data))) { + *authp = rpcsec_gsserr_credproblem; + goto auth_err; + } + + switch (gss_verify_header(gcc, &bufp, argp_end, hdr_start, gc, + authp)) { + case SVC_OK: + break; + case SVC_DENIED: + goto auth_err; + case SVC_DROP: + goto drop; + default: + BUG(); + } + + if (gss_write_verifier(resp, gcc->gcc_ctx, gc->gc_seq)) { + *authp = rpcsec_gsserr_ctxproblem; + goto auth_err; + } + accept_stat = resp->iov_base; + + /* do integrity check and/or decryption: */ + switch (gc->gc_svc) { + case RPC_GSS_SVC_NONE: + break; + case RPC_GSS_SVC_INTEGRITY: + case RPC_GSS_SVC_PRIVACY: + default: + dprintk("RPC: svcauth_gss: bad gss_svc type %d.\n", + gc->gc_svc); + *authp = rpc_autherr_badcred; + goto auth_err; + } + cred->cr_uid = gcc->gcc_uid; + cred->cr_gid = (gid_t) -1; + cred->cr_groups[0] = NOGROUP; + + key.m_class = rqstp->rq_server->sv_program->pg_class; + key.m_addr = rqstp->rq_addr.sin_addr; + + ipm = unix_ip_map_lookup(&key, 0); + + rqstp->rq_client = NULL; + + if (ipm) + switch (cache_check(&ip_map_cache, &ipm->h, + &rqstp->rq_chandle)) { + case -EAGAIN: + goto drop; + case -ENOENT: /* rq_client is NULL: */ + break; + case 0: + rqstp->rq_client = &ipm->m_client->h; + cache_get(&rqstp->rq_client->h); + ip_map_put(&ipm->h, &ip_map_cache); + break; + default: BUG(); + } + else goto drop; + + if (rqstp->rq_client == NULL && proc != 0) { + *authp = rpc_autherr_badcred; + goto auth_err; + } + + goto success; + case RPC_GSS_PROC_DESTROY: + if (rqstp->rq_proc != 0) { /* NULLPROC */ + printk("RPC: DESTROY state but not NULLPROC: %d\n", + rqstp->rq_proc); + *authp = rpc_autherr_badcred; + goto auth_err; + } + if((gc->gc_ctx.len != sizeof(struct gss_ctx *)) + || !(gcc = gss_svc_searchbyctx(*(u32 *)gc->gc_ctx.data))){ + printk("svcauth_gss: invalid context handle\n"); + *authp = rpcsec_gsserr_credproblem; + goto auth_err; + } + switch (gss_verify_header(gcc, &bufp, argp_end, hdr_start, gc, + authp)) { + case SVC_OK: + break; + case SVC_DENIED: + goto auth_err; + case SVC_DROP: + goto drop; + default: + BUG(); + } + if (gss_write_verifier(resp, gcc->gcc_ctx, gc->gc_seq)) { + *authp = rpcsec_gsserr_ctxproblem; + goto auth_err; + } + gss_svc_ctx_remove(gcc); + svc_putu32(resp, rpc_success); + goto complete; + case RPC_GSS_PROC_INIT: + case RPC_GSS_PROC_CONTINUE_INIT: + if (rqstp->rq_proc != 0) { + dprintk("RPC: proc == %d on gss context init packet?\n", + rqstp->rq_proc); + *authp = rpc_autherr_badcred; + goto auth_err; + } + if (gss_svc_do_null_upcall(rqstp)) + goto drop; + bufp = argp->iov_base; + goto complete; + default: + dprintk("RPC: unknown RPCSEC_GSS phase %d\n", gc->gc_proc); + *authp = rpc_autherr_rejectedcred; + goto auth_err; + } + +success: + argp->iov_len -= (u8 *)bufp - (u8 *)argp->iov_base; + argp->iov_base = bufp; + ((struct gss_svc_data *)rqstp->rq_auth_data)->body_start + = accept_stat + 1; + return SVC_OK; +complete: + argp->iov_len -= (u8 *)bufp - (u8 *)argp->iov_base; + argp->iov_base = bufp; + return SVC_COMPLETE; +auth_err: + /* Restore write pointer to original value: */ + resp->iov_len -= (u8 *)reject_stat - (u8 *)resp->iov_base; + resp->iov_base = reject_stat; + return SVC_DENIED; +drop: + return SVC_DROP; +} + +/* Returns nonzero on failure, at which point the server should not send + * the response. */ +static int +svcauth_gss_release(struct svc_rqst *rqstp) +{ + struct gss_svc_data *gsd = (struct gss_svc_data *) + rqstp->rq_auth_data; +/* u32 *body_start = gsd->body_start; */ + struct rpc_gss_wire_cred *gc = &gsd->clcred; + + dprintk("RPC: svcauth_wrap_res_gss, gc->gc_svc = %d\n", gc->gc_svc); + + if (rqstp->rq_client) + auth_domain_put(rqstp->rq_client); + rqstp->rq_client = NULL; + + if (gc->gc_proc != RPC_GSS_PROC_DATA) { + dprintk("RPC: svcauth_wrap_res_gss: gc->gc_proc = %d; " + "not wrapping\n", gc->gc_proc); + return 0; + } + switch (gc->gc_svc) { + case RPC_GSS_SVC_NONE: + return 0; + case RPC_GSS_SVC_INTEGRITY: + case RPC_GSS_SVC_PRIVACY: + default: + printk("svcauth_wrap_res_gss: bad gss_svc type %d\n", + gc->gc_svc); + return -1; + } + return 0; +} + +struct auth_ops svcauthops_gss = { + .name = "rpcsec_gss", + .flavour = RPC_AUTH_GSS, + .accept = svcauth_gss_accept, + .release = svcauth_gss_release, +}; + +int +gss_svc_init(void) +{ + int err; + + gss_svc_ctx_init(); + err = gss_svc_setup_pipes(); + if (err) + return err; + svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); + return 0; +} + +void +svc_auth_register_gss(void) +{ + svc_auth_register(RPC_AUTH_GSS,&svcauthops_gss); +} diff -u -r -N linux-2.5.49-06-krb5/net/sunrpc/rpc_pipe.c linux-2.5.49-07-rpc_svcgss/net/sunrpc/rpc_pipe.c --- linux-2.5.49-06-krb5/net/sunrpc/rpc_pipe.c 2002-11-24 00:51:23.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/rpc_pipe.c 2002-11-24 00:51:33.000000000 -0500 @@ -313,6 +313,7 @@ RPCAUTH_nfs, RPCAUTH_portmap, RPCAUTH_statd, + RPCAUTH_nfsd, RPCAUTH_RootEOF }; @@ -342,6 +343,10 @@ .name = "statd", .mode = S_IFDIR | S_IRUSR | S_IXUSR, }, + [RPCAUTH_nfsd] = { + .name = "nfsd", + .mode = S_IFDIR | S_IRUSR | S_IXUSR, + }, }; enum { diff -u -r -N linux-2.5.49-06-krb5/net/sunrpc/sunrpc_syms.c linux-2.5.49-07-rpc_svcgss/net/sunrpc/sunrpc_syms.c --- linux-2.5.49-06-krb5/net/sunrpc/sunrpc_syms.c 2002-11-24 00:51:23.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/sunrpc_syms.c 2002-11-24 00:51:33.000000000 -0500 @@ -23,6 +23,7 @@ #include #include #include +#include /* RPC scheduler */ @@ -83,6 +84,7 @@ EXPORT_SYMBOL(svc_wake_up); EXPORT_SYMBOL(svc_makesock); EXPORT_SYMBOL(svc_reserve); +EXPORT_SYMBOL(svc_auth_register); /* RPC statistics */ #ifdef CONFIG_PROC_FS @@ -113,6 +115,9 @@ EXPORT_SYMBOL(qword_get); EXPORT_SYMBOL(svcauth_unix_purge); EXPORT_SYMBOL(unix_domain_find); +EXPORT_SYMBOL(ip_map_put); +EXPORT_SYMBOL(unix_ip_map_lookup); +EXPORT_SYMBOL(ip_map_cache); /* Generic XDR */ EXPORT_SYMBOL(xdr_encode_array); diff -u -r -N linux-2.5.49-06-krb5/net/sunrpc/svc.c linux-2.5.49-07-rpc_svcgss/net/sunrpc/svc.c --- linux-2.5.49-06-krb5/net/sunrpc/svc.c 2002-11-13 12:49:51.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/svc.c 2002-11-24 00:51:33.000000000 -0500 @@ -195,6 +195,8 @@ 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 */ @@ -304,15 +306,22 @@ * We do this before anything else in order to get a decent * auth verifier. */ - if (svc_authenticate(rqstp, &rpc_stat, &auth_stat, proc)) - /* drop the request, it has probably been deferred */ - goto dropit; - - if (rpc_stat != rpc_success) - goto err_garbage; - - if (auth_stat != rpc_auth_ok) - goto err_bad_auth; + switch (svc_authenticate(rqstp, &auth_stat, proc)) { + case SVC_OK: + break; + case SVC_GARBAGE: + auth_stat = rpc_garbage_args; + goto err_garbage; + case SVC_SYSERR: + auth_stat = rpc_system_err; + goto err_garbage; + case SVC_DENIED: + goto err_bad_auth; + case SVC_DROP: + goto dropit; + case SVC_COMPLETE: + goto sendit; + } progp = serv->sv_program; if (prog != progp->pg_prog) diff -u -r -N linux-2.5.49-06-krb5/net/sunrpc/svcauth.c linux-2.5.49-07-rpc_svcgss/net/sunrpc/svcauth.c --- linux-2.5.49-06-krb5/net/sunrpc/svcauth.c 2002-10-31 11:04:45.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/svcauth.c 2002-11-24 00:51:33.000000000 -0500 @@ -32,12 +32,11 @@ }; int -svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp, int proc) +svc_authenticate(struct svc_rqst *rqstp, u32 *authp, int proc) { rpc_authflavor_t flavor; struct auth_ops *aops; - *statp = rpc_success; *authp = rpc_auth_ok; flavor = ntohl(svc_getu32(&rqstp->rq_arg.head[0])); @@ -45,25 +44,11 @@ dprintk("svc: svc_authenticate (%d)\n", flavor); if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor])) { *authp = rpc_autherr_badcred; - return 0; + return SVC_DENIED; } rqstp->rq_authop = aops; - switch (aops->accept(rqstp, authp, proc)) { - case SVC_OK: - return 0; - case SVC_GARBAGE: - *statp = rpc_garbage_args; - return 0; - case SVC_SYSERR: - *statp = rpc_system_err; - return 0; - case SVC_DENIED: - return 0; - case SVC_DROP: - break; - } - return 1; /* drop the request */ + return aops->accept(rqstp, authp, proc); } /* A reqeust, which was authenticated, has now executed. diff -u -r -N linux-2.5.49-06-krb5/net/sunrpc/svcauth_unix.c linux-2.5.49-07-rpc_svcgss/net/sunrpc/svcauth_unix.c --- linux-2.5.49-06-krb5/net/sunrpc/svcauth_unix.c 2002-10-31 11:04:45.000000000 -0500 +++ linux-2.5.49-07-rpc_svcgss/net/sunrpc/svcauth_unix.c 2002-11-24 00:51:33.000000000 -0500 @@ -4,6 +4,7 @@ #include #include #include +#include #include #define RPCDBG_FACILITY RPCDBG_AUTH @@ -25,12 +26,6 @@ return rv; } -struct unix_domain { - struct auth_domain h; - int addr_changes; - /* other stuff later */ -}; - struct auth_domain *unix_domain_find(char *name) { struct auth_domain *rv, ud; @@ -85,13 +80,6 @@ #define IP_HASHMAX (1<