diff -u -r -N linux-2.5.48-06-krb5/include/linux/sunrpc/gss_svc_cache.h linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/gss_svc_cache.h --- linux-2.5.48-06-krb5/include/linux/sunrpc/gss_svc_cache.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/gss_svc_cache.h 2002-11-19 19:12:41.000000000 -0500 @@ -0,0 +1,73 @@ +/* + * 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_id; + struct gss_svc_seq_data gcc_sd; + uid_t initiator_uid; + +/* fields after this point are private, for use by the gss cache */ + atomic_t gcc_refcount; + struct list_head gss_ctx_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); +struct gss_ctx_cacheent * + gss_svc_searchbyctx(struct gss_ctx *ctx_id); +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.48-06-krb5/include/linux/sunrpc/gss_xdr.h linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/gss_xdr.h --- linux-2.5.48-06-krb5/include/linux/sunrpc/gss_xdr.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/gss_xdr.h 2002-11-19 16:32:14.000000000 -0500 @@ -0,0 +1,20 @@ +/* + * 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); + +#endif /* __KERNEL__ */ + +#endif /* _SUNRPC_GSS_XDR_H_ */ diff -u -r -N linux-2.5.48-06-krb5/include/linux/sunrpc/svc.h linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/svc.h --- linux-2.5.48-06-krb5/include/linux/sunrpc/svc.h 2002-11-13 12:49:50.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/svc.h 2002-11-19 16:32:14.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.48-06-krb5/include/linux/sunrpc/svcauth.h linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/svcauth.h --- linux-2.5.48-06-krb5/include/linux/sunrpc/svcauth.h 2002-10-19 00:01:48.000000000 -0400 +++ linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/svcauth.h 2002-11-19 16:32:14.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.48-06-krb5/include/linux/sunrpc/svcauth_gss.h linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/svcauth_gss.h --- linux-2.5.48-06-krb5/include/linux/sunrpc/svcauth_gss.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/svcauth_gss.h 2002-11-19 16:32:14.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 + +extern void svc_auth_register_gss(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.48-06-krb5/include/linux/sunrpc/svcauth_unix.h linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/svcauth_unix.h --- linux-2.5.48-06-krb5/include/linux/sunrpc/svcauth_unix.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/include/linux/sunrpc/svcauth_unix.h 2002-11-19 16:32:14.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.48-06-krb5/net/sunrpc/auth_gss/Makefile linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/Makefile --- linux-2.5.48-06-krb5/net/sunrpc/auth_gss/Makefile 2002-11-19 19:21:35.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/Makefile 2002-11-19 19:22:27.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.48-06-krb5/net/sunrpc/auth_gss/auth_gss.c linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/auth_gss.c --- linux-2.5.48-06-krb5/net/sunrpc/auth_gss/auth_gss.c 2002-11-19 13:35:47.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/auth_gss.c 2002-11-19 16:32:33.000000000 -0500 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -720,6 +721,11 @@ int err = 0; err = rpcauth_register(&authgss_ops); + if (err) + goto out; + svc_auth_register_gss(); + gss_svc_ctx_init(); +out: return err; } diff -u -r -N linux-2.5.48-06-krb5/net/sunrpc/auth_gss/gss_svc_cache.c linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/gss_svc_cache.c --- linux-2.5.48-06-krb5/net/sunrpc/auth_gss/gss_svc_cache.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/gss_svc_cache.c 2002-11-19 19:29:57.000000000 -0500 @@ -0,0 +1,190 @@ +/* + * 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. + */ + +/* Function: gss_ctx_alloc +* +* Description: allocate and initialize a gss_ctx_cacheent structure. +*/ + +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_id) + gss_delete_sec_context(&p->gcc_ctx_id); + 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_ctx_id) << 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->gss_ctx_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, + gss_ctx_cache); + list_del(&p->gss_ctx_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_id, uid_t uid) +{ + struct gss_ctx_cacheent *cep = NULL; + + dprintk("RPC: gss_svc_cache_context\n"); + + if(!(cep = gss_ctx_alloc())) + return -ENOMEM; + cep->gcc_ctx_id = ctx_id; + cep->initiator_uid = uid; + 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(struct gss_ctx *ctx_id) +{ + struct gss_ctx_cacheent *p; + unsigned int ptrhash = (unsigned int)ctx_id << 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, gss_ctx_cache); + if (p->gcc_ctx_id == ctx_id){ + 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->gss_ctx_cache); + write_unlock(&svc_ctx_map.lock); + gss_ctx_put(gcc); +} diff -u -r -N linux-2.5.48-06-krb5/net/sunrpc/auth_gss/gss_xdr.c linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/gss_xdr.c --- linux-2.5.48-06-krb5/net/sunrpc/auth_gss/gss_xdr.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/gss_xdr.c 2002-11-19 16:32: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.48-06-krb5/net/sunrpc/auth_gss/svcauth_gss.c linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/svcauth_gss.c --- linux-2.5.48-06-krb5/net/sunrpc/auth_gss/svcauth_gss.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/net/sunrpc/auth_gss/svcauth_gss.c 2002-11-19 19:31:07.000000000 -0500 @@ -0,0 +1,572 @@ +/* + * 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 + * + * 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 + +#ifdef RPC_DEBUG +# define RPCDBG_FACILITY RPCDBG_AUTH +#endif + +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; +} + +static int +xdr_decode_gss_init_arg(u32 **p, u32 *end, struct xdr_netobj *arg) +{ + if (xdr_bounded_get_netobj(p, end, arg)) return -1; + dprintk("RPC: xdr_decode_gss_init_arg() = (%p:%d)\n", + arg->data, arg->len); + return 0; +} + +static int +xdr_encode_rpc_gss_init_res(struct svc_rqst *req, u32 *p, + struct rpc_gss_init_res *resp) +{ + + dprintk("RPC: xdr_encode_rpc_gss_init_res" + "(%p:%d, %d, %d, %d, %p:%d)\n", + resp->gr_ctx.data, resp->gr_ctx.len, + resp->gr_major, resp->gr_minor, resp->gr_win, + resp->gr_token.data, resp->gr_token.len); + + p = xdr_encode_netobj(p, &resp->gr_ctx); + *p++ = (u32) htonl(resp->gr_major); + *p++ = (u32) htonl(resp->gr_minor); + *p++ = (u32) htonl(resp->gr_win); + p = xdr_encode_netobj(p, &resp->gr_token); + + return xdr_ressize_check(req, p); +} + +/* 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_id; + 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 rpc_gss_init_res gr; + struct xdr_netobj input_token; + struct gss_ctx_cacheent *gcc = NULL; + struct gss_ctx *ctx_id = NULL; + u32 ret_flags; + u32 pf = 0; + /* argp->iov_base now points to beginning of cred; 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; + int rv = 0; + 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++); + dprintk("RPC: svcauth_gss. credlen %d\n",credlen); + + 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: + dprintk("RPC: RPCSEC_GSS_DATA\n"); + if (rqstp->rq_proc == 0) { + printk("RPC: DATA state but NULLPROC: %d\n", + rqstp->rq_proc); + *authp = rpc_autherr_badcred; + goto auth_err; + } + if (gc->gc_ctx.len != sizeof(struct gss_ctx *)) { + *authp = rpc_autherr_badcred; + goto auth_err; + } + ctx_id = *(struct gss_ctx **)gc->gc_ctx.data; + if (!(gcc = gss_svc_searchbyctx(ctx_id))) { + *authp = rpcsec_gsserr_credproblem; + goto auth_err; + } + /* Assuming qop = 0. */ + if (!(pf = gss_get_pseudoflavor(ctx_id, 0, gc->gc_svc))) + BUG(); + + 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, ctx_id, 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->initiator_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: + dprintk("RPC: RPCSEC_GSS_DESTROY\n"); + 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; + } + ctx_id = *(struct gss_ctx **)gc->gc_ctx.data; + + if((gc->gc_ctx.len != sizeof(struct gss_ctx *)) + || !(gcc = gss_svc_searchbyctx(ctx_id))){ + 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, ctx_id, 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: *INIT state but not NULLPROC: %d\n", + rqstp->rq_proc); + *authp = rpc_autherr_badcred; + goto auth_err; + } + /* creation request, thus a null verifier */ + dprintk("RPC: svcauth_gss: verifier flavor %d\n",ntohl(*bufp)); + if((ntohl(*bufp++) != RPC_AUTH_NULL) || (ntohl(*bufp++) != 0)){ + printk("RPC: svcauth_gss: bad verifier flavor or" + " length on creation request.\n"); + *authp = rpc_autherr_badverf; + goto auth_err; + } + if (gc->gc_proc == RPC_GSS_PROC_INIT) { + dprintk("RPC: RPCSEC_GSS_INIT\n"); + if (gc->gc_ctx.len != 0) { + dprintk("RPC: non-empty handle on initial" + " context creation request\n"); + *authp = rpc_autherr_badcred; + goto auth_err; + } + } else { + dprintk("RPC: RPCSEC_GSS_CONTINUE_INIT\n"); + if (gc->gc_ctx.len == 0) { + dprintk("RPC: expected non-empty handle in" + " continue\n"); + *authp = rpc_autherr_badcred; + goto auth_err; + } + } + /* Decode arguments. */ + if (xdr_decode_gss_init_arg(&bufp, argp_end, &input_token)) { + rv = SVC_GARBAGE; + goto rpc_err; + } + memset(&gr, 0, sizeof(gr)); + gr.gr_major = gss_accept_sec_context(&ctx_id, + &input_token, + &cred->cr_uid, + &gr.gr_token, + &ret_flags); + if (gr.gr_major != GSS_S_COMPLETE && + gr.gr_major != GSS_S_CONTINUE_NEEDED) { + dprintk("RPC: accept_sec_context failed!\n"); + rv = SVC_GARBAGE; /* ? */ + goto rpc_err; + } + if (gr.gr_major == GSS_S_CONTINUE_NEEDED) { + dprintk("RPC: GSS_S_CONTINUE_NEEDED not supported."); + *authp = rpc_autherr_rejectedcred; + goto auth_err; + } + if (gss_svc_cache_context(ctx_id, cred->cr_uid)) { + rv = SVC_SYSERR; + goto rpc_err; + } + dprintk("RPC: imported and cached context ctx_id=%p\n", + ctx_id); + + gr.gr_win = GSS_SEQ_WIN; + gr.gr_ctx.len = sizeof(ctx_id); + if (!(gr.gr_ctx.data = kmalloc(sizeof(ctx_id), GFP_KERNEL))) { + rv = SVC_SYSERR; + goto rpc_err; + } + memcpy(gr.gr_ctx.data, &ctx_id, sizeof(ctx_id)); + if (gr.gr_major == GSS_S_COMPLETE) { + if (gss_write_verifier(resp, ctx_id, gr.gr_win)) { + *authp = rpcsec_gsserr_ctxproblem; + goto auth_err; + } + } else { + svc_putu32(resp, RPC_AUTH_NULL); + svc_putu32(resp, 0); + } + svc_putu32(resp, rpc_success); + dprintk("RPC encoding init_sec_ctx response: ctx (%p:%d)" + " maj:min (%d:%d) win %d token (%p:%d)\n", + gr.gr_ctx.data, gr.gr_ctx.len, gr.gr_major, gr.gr_minor, + gr.gr_win, gr.gr_token.data, gr.gr_token.len); + if (!xdr_encode_rpc_gss_init_res(rqstp, resp->iov_base, &gr)) { + if (gr.gr_ctx.len) + kfree(gr.gr_ctx.data); + rv = SVC_SYSERR; + goto rpc_err; + } + kfree(gr.gr_ctx.data); + 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; +rpc_err: + if (!accept_stat) { /* Add a null verifier: */ + resp->iov_len -= (u8 *)reject_stat - (u8 *)resp->iov_base; + resp->iov_base = reject_stat; + svc_putu32(resp, htonl(RPC_AUTH_NULL)); + svc_putu32(resp, 0); + return rv; + } + resp->iov_len -= (u8 *)accept_stat - (u8 *)resp->iov_base; + resp->iov_base = accept_stat; + return rv; +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, +}; + +void +svc_auth_register_gss(void) +{ + svc_auth_register(RPC_AUTH_GSS,&svcauthops_gss); +} diff -u -r -N linux-2.5.48-06-krb5/net/sunrpc/sunrpc_syms.c linux-2.5.48-07-rpc_svcgss/net/sunrpc/sunrpc_syms.c --- linux-2.5.48-06-krb5/net/sunrpc/sunrpc_syms.c 2002-11-18 15:10:32.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/net/sunrpc/sunrpc_syms.c 2002-11-19 16:32:33.000000000 -0500 @@ -22,6 +22,7 @@ #include #include #include +#include /* RPC scheduler */ @@ -74,6 +75,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 @@ -104,6 +106,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.48-06-krb5/net/sunrpc/svc.c linux-2.5.48-07-rpc_svcgss/net/sunrpc/svc.c --- linux-2.5.48-06-krb5/net/sunrpc/svc.c 2002-11-13 12:49:51.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/net/sunrpc/svc.c 2002-11-19 16:32: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.48-06-krb5/net/sunrpc/svcauth.c linux-2.5.48-07-rpc_svcgss/net/sunrpc/svcauth.c --- linux-2.5.48-06-krb5/net/sunrpc/svcauth.c 2002-10-31 11:04:45.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/net/sunrpc/svcauth.c 2002-11-19 16:32: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.48-06-krb5/net/sunrpc/svcauth_unix.c linux-2.5.48-07-rpc_svcgss/net/sunrpc/svcauth_unix.c --- linux-2.5.48-06-krb5/net/sunrpc/svcauth_unix.c 2002-10-31 11:04:45.000000000 -0500 +++ linux-2.5.48-07-rpc_svcgss/net/sunrpc/svcauth_unix.c 2002-11-19 16:32: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<