(2006-08-06) rescue-bootcd
This commit is contained in:
15
extra/linux-2.6.10/net/sunrpc/Makefile
Normal file
15
extra/linux-2.6.10/net/sunrpc/Makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# Makefile for Linux kernel SUN RPC
|
||||
#
|
||||
|
||||
|
||||
obj-$(CONFIG_SUNRPC) += sunrpc.o
|
||||
obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
|
||||
|
||||
sunrpc-y := clnt.o xprt.o sched.o \
|
||||
auth.o auth_null.o auth_unix.o \
|
||||
svc.o svcsock.o svcauth.o svcauth_unix.o \
|
||||
pmap_clnt.o timer.o xdr.o \
|
||||
sunrpc_syms.o cache.o rpc_pipe.o
|
||||
sunrpc-$(CONFIG_PROC_FS) += stats.o
|
||||
sunrpc-$(CONFIG_SYSCTL) += sysctl.o
|
||||
422
extra/linux-2.6.10/net/sunrpc/auth.c
Normal file
422
extra/linux-2.6.10/net/sunrpc/auth.c
Normal file
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* linux/net/sunrpc/auth.c
|
||||
*
|
||||
* Generic RPC client authentication API.
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
static struct rpc_authops * auth_flavors[RPC_AUTH_MAXFLAVOR] = {
|
||||
&authnull_ops, /* AUTH_NULL */
|
||||
&authunix_ops, /* AUTH_UNIX */
|
||||
NULL, /* others can be loadable modules */
|
||||
};
|
||||
|
||||
u32
|
||||
pseudoflavor_to_flavor(u32 flavor) {
|
||||
if (flavor >= RPC_AUTH_MAXFLAVOR)
|
||||
return RPC_AUTH_GSS;
|
||||
return flavor;
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_register(struct rpc_authops *ops)
|
||||
{
|
||||
rpc_authflavor_t flavor;
|
||||
|
||||
if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
|
||||
return -EINVAL;
|
||||
if (auth_flavors[flavor] != NULL)
|
||||
return -EPERM; /* what else? */
|
||||
auth_flavors[flavor] = ops;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_unregister(struct rpc_authops *ops)
|
||||
{
|
||||
rpc_authflavor_t flavor;
|
||||
|
||||
if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
|
||||
return -EINVAL;
|
||||
if (auth_flavors[flavor] != ops)
|
||||
return -EPERM; /* what else? */
|
||||
auth_flavors[flavor] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rpc_auth *
|
||||
rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
|
||||
{
|
||||
struct rpc_auth *auth;
|
||||
struct rpc_authops *ops;
|
||||
u32 flavor = pseudoflavor_to_flavor(pseudoflavor);
|
||||
|
||||
if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor]))
|
||||
return NULL;
|
||||
if (!try_module_get(ops->owner))
|
||||
return NULL;
|
||||
auth = ops->create(clnt, pseudoflavor);
|
||||
if (!auth)
|
||||
return NULL;
|
||||
atomic_set(&auth->au_count, 1);
|
||||
if (clnt->cl_auth)
|
||||
rpcauth_destroy(clnt->cl_auth);
|
||||
clnt->cl_auth = auth;
|
||||
return auth;
|
||||
}
|
||||
|
||||
void
|
||||
rpcauth_destroy(struct rpc_auth *auth)
|
||||
{
|
||||
if (!atomic_dec_and_test(&auth->au_count))
|
||||
return;
|
||||
auth->au_ops->destroy(auth);
|
||||
module_put(auth->au_ops->owner);
|
||||
kfree(auth);
|
||||
}
|
||||
|
||||
static spinlock_t rpc_credcache_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
/*
|
||||
* Initialize RPC credential cache
|
||||
*/
|
||||
void
|
||||
rpcauth_init_credcache(struct rpc_auth *auth)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < RPC_CREDCACHE_NR; i++)
|
||||
INIT_LIST_HEAD(&auth->au_credcache[i]);
|
||||
auth->au_nextgc = jiffies + (auth->au_expire >> 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy an unreferenced credential
|
||||
*/
|
||||
static inline void
|
||||
rpcauth_crdestroy(struct rpc_cred *cred)
|
||||
{
|
||||
#ifdef RPC_DEBUG
|
||||
BUG_ON(cred->cr_magic != RPCAUTH_CRED_MAGIC ||
|
||||
atomic_read(&cred->cr_count) ||
|
||||
!list_empty(&cred->cr_hash));
|
||||
cred->cr_magic = 0;
|
||||
#endif
|
||||
cred->cr_ops->crdestroy(cred);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a list of credentials
|
||||
*/
|
||||
static inline
|
||||
void rpcauth_destroy_credlist(struct list_head *head)
|
||||
{
|
||||
struct rpc_cred *cred;
|
||||
|
||||
while (!list_empty(head)) {
|
||||
cred = list_entry(head->next, struct rpc_cred, cr_hash);
|
||||
list_del_init(&cred->cr_hash);
|
||||
rpcauth_crdestroy(cred);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the RPC credential cache, and delete those credentials
|
||||
* that are not referenced.
|
||||
*/
|
||||
void
|
||||
rpcauth_free_credcache(struct rpc_auth *auth)
|
||||
{
|
||||
LIST_HEAD(free);
|
||||
struct list_head *pos, *next;
|
||||
struct rpc_cred *cred;
|
||||
int i;
|
||||
|
||||
spin_lock(&rpc_credcache_lock);
|
||||
for (i = 0; i < RPC_CREDCACHE_NR; i++) {
|
||||
list_for_each_safe(pos, next, &auth->au_credcache[i]) {
|
||||
cred = list_entry(pos, struct rpc_cred, cr_hash);
|
||||
cred->cr_auth = NULL;
|
||||
list_del_init(&cred->cr_hash);
|
||||
if (atomic_read(&cred->cr_count) == 0)
|
||||
list_add(&cred->cr_hash, &free);
|
||||
}
|
||||
}
|
||||
spin_unlock(&rpc_credcache_lock);
|
||||
rpcauth_destroy_credlist(&free);
|
||||
}
|
||||
|
||||
static inline int
|
||||
rpcauth_prune_expired(struct rpc_cred *cred, struct list_head *free)
|
||||
{
|
||||
if (atomic_read(&cred->cr_count) != 0)
|
||||
return 0;
|
||||
if (time_before(jiffies, cred->cr_expire))
|
||||
return 0;
|
||||
cred->cr_auth = NULL;
|
||||
list_del(&cred->cr_hash);
|
||||
list_add(&cred->cr_hash, free);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove stale credentials. Avoid sleeping inside the loop.
|
||||
*/
|
||||
static void
|
||||
rpcauth_gc_credcache(struct rpc_auth *auth, struct list_head *free)
|
||||
{
|
||||
struct list_head *pos, *next;
|
||||
struct rpc_cred *cred;
|
||||
int i;
|
||||
|
||||
dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
|
||||
for (i = 0; i < RPC_CREDCACHE_NR; i++) {
|
||||
list_for_each_safe(pos, next, &auth->au_credcache[i]) {
|
||||
cred = list_entry(pos, struct rpc_cred, cr_hash);
|
||||
rpcauth_prune_expired(cred, free);
|
||||
}
|
||||
}
|
||||
auth->au_nextgc = jiffies + auth->au_expire;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up a process' credentials in the authentication cache
|
||||
*/
|
||||
struct rpc_cred *
|
||||
rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
|
||||
int taskflags)
|
||||
{
|
||||
LIST_HEAD(free);
|
||||
struct list_head *pos, *next;
|
||||
struct rpc_cred *new = NULL,
|
||||
*cred = NULL;
|
||||
int nr = 0;
|
||||
|
||||
if (!(taskflags & RPC_TASK_ROOTCREDS))
|
||||
nr = acred->uid & RPC_CREDCACHE_MASK;
|
||||
retry:
|
||||
spin_lock(&rpc_credcache_lock);
|
||||
if (time_before(auth->au_nextgc, jiffies))
|
||||
rpcauth_gc_credcache(auth, &free);
|
||||
list_for_each_safe(pos, next, &auth->au_credcache[nr]) {
|
||||
struct rpc_cred *entry;
|
||||
entry = list_entry(pos, struct rpc_cred, cr_hash);
|
||||
if (entry->cr_flags & RPCAUTH_CRED_DEAD)
|
||||
continue;
|
||||
if (rpcauth_prune_expired(entry, &free))
|
||||
continue;
|
||||
if (entry->cr_ops->crmatch(acred, entry, taskflags)) {
|
||||
list_del(&entry->cr_hash);
|
||||
cred = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (new) {
|
||||
if (cred)
|
||||
list_add(&new->cr_hash, &free);
|
||||
else
|
||||
cred = new;
|
||||
}
|
||||
if (cred) {
|
||||
list_add(&cred->cr_hash, &auth->au_credcache[nr]);
|
||||
cred->cr_auth = auth;
|
||||
get_rpccred(cred);
|
||||
}
|
||||
spin_unlock(&rpc_credcache_lock);
|
||||
|
||||
rpcauth_destroy_credlist(&free);
|
||||
|
||||
if (!cred) {
|
||||
new = auth->au_ops->crcreate(auth, acred, taskflags);
|
||||
if (new) {
|
||||
#ifdef RPC_DEBUG
|
||||
new->cr_magic = RPCAUTH_CRED_MAGIC;
|
||||
#endif
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
return (struct rpc_cred *) cred;
|
||||
}
|
||||
|
||||
struct rpc_cred *
|
||||
rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
|
||||
{
|
||||
struct auth_cred acred;
|
||||
struct rpc_cred *ret;
|
||||
|
||||
get_group_info(current->group_info);
|
||||
acred.uid = current->fsuid;
|
||||
acred.gid = current->fsgid;
|
||||
acred.group_info = current->group_info;
|
||||
|
||||
dprintk("RPC: looking up %s cred\n",
|
||||
auth->au_ops->au_name);
|
||||
ret = rpcauth_lookup_credcache(auth, &acred, taskflags);
|
||||
put_group_info(current->group_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct rpc_cred *
|
||||
rpcauth_bindcred(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_auth *auth = task->tk_auth;
|
||||
struct auth_cred acred;
|
||||
struct rpc_cred *ret;
|
||||
|
||||
get_group_info(current->group_info);
|
||||
acred.uid = current->fsuid;
|
||||
acred.gid = current->fsgid;
|
||||
acred.group_info = current->group_info;
|
||||
|
||||
dprintk("RPC: %4d looking up %s cred\n",
|
||||
task->tk_pid, task->tk_auth->au_ops->au_name);
|
||||
task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, &acred, task->tk_flags);
|
||||
if (task->tk_msg.rpc_cred == 0)
|
||||
task->tk_status = -ENOMEM;
|
||||
ret = task->tk_msg.rpc_cred;
|
||||
put_group_info(current->group_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
rpcauth_holdcred(struct rpc_task *task)
|
||||
{
|
||||
dprintk("RPC: %4d holding %s cred %p\n",
|
||||
task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
|
||||
if (task->tk_msg.rpc_cred)
|
||||
get_rpccred(task->tk_msg.rpc_cred);
|
||||
}
|
||||
|
||||
void
|
||||
put_rpccred(struct rpc_cred *cred)
|
||||
{
|
||||
if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
|
||||
return;
|
||||
|
||||
if ((cred->cr_flags & RPCAUTH_CRED_DEAD) && !list_empty(&cred->cr_hash))
|
||||
list_del_init(&cred->cr_hash);
|
||||
|
||||
if (list_empty(&cred->cr_hash)) {
|
||||
spin_unlock(&rpc_credcache_lock);
|
||||
rpcauth_crdestroy(cred);
|
||||
return;
|
||||
}
|
||||
cred->cr_expire = jiffies + cred->cr_auth->au_expire;
|
||||
spin_unlock(&rpc_credcache_lock);
|
||||
}
|
||||
|
||||
void
|
||||
rpcauth_unbindcred(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_auth *auth = task->tk_auth;
|
||||
struct rpc_cred *cred = task->tk_msg.rpc_cred;
|
||||
|
||||
dprintk("RPC: %4d releasing %s cred %p\n",
|
||||
task->tk_pid, auth->au_ops->au_name, cred);
|
||||
|
||||
put_rpccred(cred);
|
||||
task->tk_msg.rpc_cred = NULL;
|
||||
}
|
||||
|
||||
u32 *
|
||||
rpcauth_marshcred(struct rpc_task *task, u32 *p)
|
||||
{
|
||||
struct rpc_auth *auth = task->tk_auth;
|
||||
struct rpc_cred *cred = task->tk_msg.rpc_cred;
|
||||
|
||||
dprintk("RPC: %4d marshaling %s cred %p\n",
|
||||
task->tk_pid, auth->au_ops->au_name, cred);
|
||||
return cred->cr_ops->crmarshal(task, p,
|
||||
task->tk_flags & RPC_CALL_REALUID);
|
||||
}
|
||||
|
||||
u32 *
|
||||
rpcauth_checkverf(struct rpc_task *task, u32 *p)
|
||||
{
|
||||
struct rpc_auth *auth = task->tk_auth;
|
||||
struct rpc_cred *cred = task->tk_msg.rpc_cred;
|
||||
|
||||
dprintk("RPC: %4d validating %s cred %p\n",
|
||||
task->tk_pid, auth->au_ops->au_name, cred);
|
||||
return cred->cr_ops->crvalidate(task, p);
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
|
||||
u32 *data, void *obj)
|
||||
{
|
||||
struct rpc_cred *cred = task->tk_msg.rpc_cred;
|
||||
|
||||
dprintk("RPC: %4d using %s cred %p to wrap rpc data\n",
|
||||
task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
|
||||
if (cred->cr_ops->crwrap_req)
|
||||
return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
|
||||
/* By default, we encode the arguments normally. */
|
||||
return encode(rqstp, data, obj);
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
|
||||
u32 *data, void *obj)
|
||||
{
|
||||
struct rpc_cred *cred = task->tk_msg.rpc_cred;
|
||||
|
||||
dprintk("RPC: %4d using %s cred %p to unwrap rpc data\n",
|
||||
task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
|
||||
if (cred->cr_ops->crunwrap_resp)
|
||||
return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
|
||||
data, obj);
|
||||
/* By default, we decode the arguments normally. */
|
||||
return decode(rqstp, data, obj);
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_refreshcred(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_auth *auth = task->tk_auth;
|
||||
struct rpc_cred *cred = task->tk_msg.rpc_cred;
|
||||
|
||||
dprintk("RPC: %4d refreshing %s cred %p\n",
|
||||
task->tk_pid, auth->au_ops->au_name, cred);
|
||||
task->tk_status = cred->cr_ops->crrefresh(task);
|
||||
return task->tk_status;
|
||||
}
|
||||
|
||||
void
|
||||
rpcauth_invalcred(struct rpc_task *task)
|
||||
{
|
||||
dprintk("RPC: %4d invalidating %s cred %p\n",
|
||||
task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
|
||||
spin_lock(&rpc_credcache_lock);
|
||||
if (task->tk_msg.rpc_cred)
|
||||
task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
|
||||
spin_unlock(&rpc_credcache_lock);
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_uptodatecred(struct rpc_task *task)
|
||||
{
|
||||
return !(task->tk_msg.rpc_cred) ||
|
||||
(task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_deadcred(struct rpc_task *task)
|
||||
{
|
||||
return !(task->tk_msg.rpc_cred) ||
|
||||
(task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_DEAD);
|
||||
}
|
||||
18
extra/linux-2.6.10/net/sunrpc/auth_gss/Makefile
Normal file
18
extra/linux-2.6.10/net/sunrpc/auth_gss/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Makefile for Linux kernel rpcsec_gss implementation
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o
|
||||
|
||||
auth_rpcgss-objs := auth_gss.o gss_generic_token.o \
|
||||
gss_mech_switch.o svcauth_gss.o gss_krb5_crypto.o
|
||||
|
||||
obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
|
||||
|
||||
rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
|
||||
gss_krb5_seqnum.o
|
||||
|
||||
obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o
|
||||
|
||||
rpcsec_gss_spkm3-objs := gss_spkm3_mech.o gss_spkm3_seal.o gss_spkm3_unseal.o \
|
||||
gss_spkm3_token.o
|
||||
1039
extra/linux-2.6.10/net/sunrpc/auth_gss/auth_gss.c
Normal file
1039
extra/linux-2.6.10/net/sunrpc/auth_gss/auth_gss.c
Normal file
File diff suppressed because it is too large
Load Diff
270
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_generic_token.c
Normal file
270
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_generic_token.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_generic_token.c
|
||||
*
|
||||
* Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic/util_token.c
|
||||
*
|
||||
* Copyright (c) 2000 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 1993 by OpenVision Technologies, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appears in all copies and
|
||||
* that both that copyright notice and this permission notice appear in
|
||||
* supporting documentation, and that the name of OpenVision not be used
|
||||
* in advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. OpenVision makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
||||
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/sunrpc/gss_asn1.h>
|
||||
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
|
||||
/* TWRITE_STR from gssapiP_generic.h */
|
||||
#define TWRITE_STR(ptr, str, len) \
|
||||
memcpy((ptr), (char *) (str), (len)); \
|
||||
(ptr) += (len);
|
||||
|
||||
/* XXXX this code currently makes the assumption that a mech oid will
|
||||
never be longer than 127 bytes. This assumption is not inherent in
|
||||
the interfaces, so the code can be fixed if the OSI namespace
|
||||
balloons unexpectedly. */
|
||||
|
||||
/* Each token looks like this:
|
||||
|
||||
0x60 tag for APPLICATION 0, SEQUENCE
|
||||
(constructed, definite-length)
|
||||
<length> possible multiple bytes, need to parse/generate
|
||||
0x06 tag for OBJECT IDENTIFIER
|
||||
<moid_length> compile-time constant string (assume 1 byte)
|
||||
<moid_bytes> compile-time constant string
|
||||
<inner_bytes> the ANY containing the application token
|
||||
bytes 0,1 are the token type
|
||||
bytes 2,n are the token data
|
||||
|
||||
For the purposes of this abstraction, the token "header" consists of
|
||||
the sequence tag and length octets, the mech OID DER encoding, and the
|
||||
first two inner bytes, which indicate the token type. The token
|
||||
"body" consists of everything else.
|
||||
|
||||
*/
|
||||
|
||||
static int
|
||||
der_length_size( int length)
|
||||
{
|
||||
if (length < (1<<7))
|
||||
return(1);
|
||||
else if (length < (1<<8))
|
||||
return(2);
|
||||
#if (SIZEOF_INT == 2)
|
||||
else
|
||||
return(3);
|
||||
#else
|
||||
else if (length < (1<<16))
|
||||
return(3);
|
||||
else if (length < (1<<24))
|
||||
return(4);
|
||||
else
|
||||
return(5);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
der_write_length(unsigned char **buf, int length)
|
||||
{
|
||||
if (length < (1<<7)) {
|
||||
*(*buf)++ = (unsigned char) length;
|
||||
} else {
|
||||
*(*buf)++ = (unsigned char) (der_length_size(length)+127);
|
||||
#if (SIZEOF_INT > 2)
|
||||
if (length >= (1<<24))
|
||||
*(*buf)++ = (unsigned char) (length>>24);
|
||||
if (length >= (1<<16))
|
||||
*(*buf)++ = (unsigned char) ((length>>16)&0xff);
|
||||
#endif
|
||||
if (length >= (1<<8))
|
||||
*(*buf)++ = (unsigned char) ((length>>8)&0xff);
|
||||
*(*buf)++ = (unsigned char) (length&0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/* returns decoded length, or < 0 on failure. Advances buf and
|
||||
decrements bufsize */
|
||||
|
||||
static int
|
||||
der_read_length(unsigned char **buf, int *bufsize)
|
||||
{
|
||||
unsigned char sf;
|
||||
int ret;
|
||||
|
||||
if (*bufsize < 1)
|
||||
return(-1);
|
||||
sf = *(*buf)++;
|
||||
(*bufsize)--;
|
||||
if (sf & 0x80) {
|
||||
if ((sf &= 0x7f) > ((*bufsize)-1))
|
||||
return(-1);
|
||||
if (sf > SIZEOF_INT)
|
||||
return (-1);
|
||||
ret = 0;
|
||||
for (; sf; sf--) {
|
||||
ret = (ret<<8) + (*(*buf)++);
|
||||
(*bufsize)--;
|
||||
}
|
||||
} else {
|
||||
ret = sf;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* returns the length of a token, given the mech oid and the body size */
|
||||
|
||||
int
|
||||
g_token_size(struct xdr_netobj *mech, unsigned int body_size)
|
||||
{
|
||||
/* set body_size to sequence contents size */
|
||||
body_size += 4 + (int) mech->len; /* NEED overflow check */
|
||||
return(1 + der_length_size(body_size) + body_size);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(g_token_size);
|
||||
|
||||
/* fills in a buffer with the token header. The buffer is assumed to
|
||||
be the right size. buf is advanced past the token header */
|
||||
|
||||
void
|
||||
g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf)
|
||||
{
|
||||
*(*buf)++ = 0x60;
|
||||
der_write_length(buf, 4 + mech->len + body_size);
|
||||
*(*buf)++ = 0x06;
|
||||
*(*buf)++ = (unsigned char) mech->len;
|
||||
TWRITE_STR(*buf, mech->data, ((int) mech->len));
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(g_make_token_header);
|
||||
|
||||
/*
|
||||
* Given a buffer containing a token, reads and verifies the token,
|
||||
* leaving buf advanced past the token header, and setting body_size
|
||||
* to the number of remaining bytes. Returns 0 on success,
|
||||
* G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
|
||||
* mechanism in the token does not match the mech argument. buf and
|
||||
* *body_size are left unmodified on error.
|
||||
*/
|
||||
u32
|
||||
g_verify_token_header(struct xdr_netobj *mech, int *body_size,
|
||||
unsigned char **buf_in, int toksize)
|
||||
{
|
||||
unsigned char *buf = *buf_in;
|
||||
int seqsize;
|
||||
struct xdr_netobj toid;
|
||||
int ret = 0;
|
||||
|
||||
if ((toksize-=1) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
if (*buf++ != 0x60)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
|
||||
if ((seqsize = der_read_length(&buf, &toksize)) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
|
||||
if (seqsize != toksize)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
|
||||
if ((toksize-=1) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
if (*buf++ != 0x06)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
|
||||
if ((toksize-=1) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
toid.len = *buf++;
|
||||
|
||||
if ((toksize-=toid.len) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
toid.data = buf;
|
||||
buf+=toid.len;
|
||||
|
||||
if (! g_OID_equal(&toid, mech))
|
||||
ret = G_WRONG_MECH;
|
||||
|
||||
/* G_WRONG_MECH is not returned immediately because it's more important
|
||||
to return G_BAD_TOK_HEADER if the token header is in fact bad */
|
||||
|
||||
if ((toksize-=2) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
|
||||
if (ret)
|
||||
return(ret);
|
||||
|
||||
if (!ret) {
|
||||
*buf_in = buf;
|
||||
*body_size = toksize;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(g_verify_token_header);
|
||||
|
||||
/* Given a buffer containing a token, returns a copy of the mech oid in
|
||||
* the parameter mech. */
|
||||
u32
|
||||
g_get_mech_oid(struct xdr_netobj *mech, struct xdr_netobj * in_buf)
|
||||
{
|
||||
unsigned char *buf = in_buf->data;
|
||||
int len = in_buf->len;
|
||||
int ret=0;
|
||||
int seqsize;
|
||||
|
||||
if ((len-=1) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
if (*buf++ != 0x60)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
|
||||
if ((seqsize = der_read_length(&buf, &len)) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
|
||||
if ((len-=1) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
if (*buf++ != 0x06)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
|
||||
if ((len-=1) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
mech->len = *buf++;
|
||||
|
||||
if ((len-=mech->len) < 0)
|
||||
return(G_BAD_TOK_HEADER);
|
||||
if (!(mech->data = kmalloc(mech->len, GFP_KERNEL)))
|
||||
return(G_BUFFER_ALLOC);
|
||||
memcpy(mech->data, buf, mech->len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
209
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_crypto.c
Normal file
209
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_crypto.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_krb5_crypto.c
|
||||
*
|
||||
* Copyright (c) 2000 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
* Bruce Fields <bfields@umich.edu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1998 by the FundsXpress, INC.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Export of this software from the United States of America may require
|
||||
* a specific license from the United States Government. It is the
|
||||
* responsibility of any person or organization contemplating export to
|
||||
* obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of FundsXpress. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. FundsXpress makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/scatterlist.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
u32
|
||||
krb5_encrypt(
|
||||
struct crypto_tfm *tfm,
|
||||
void * iv,
|
||||
void * in,
|
||||
void * out,
|
||||
int length)
|
||||
{
|
||||
u32 ret = -EINVAL;
|
||||
struct scatterlist sg[1];
|
||||
u8 local_iv[16] = {0};
|
||||
|
||||
dprintk("RPC: krb5_encrypt: input data:\n");
|
||||
print_hexl((u32 *)in, length, 0);
|
||||
|
||||
if (length % crypto_tfm_alg_blocksize(tfm) != 0)
|
||||
goto out;
|
||||
|
||||
if (crypto_tfm_alg_ivsize(tfm) > 16) {
|
||||
dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n",
|
||||
crypto_tfm_alg_ivsize(tfm));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iv)
|
||||
memcpy(local_iv, iv, crypto_tfm_alg_ivsize(tfm));
|
||||
|
||||
memcpy(out, in, length);
|
||||
sg[0].page = virt_to_page(out);
|
||||
sg[0].offset = offset_in_page(out);
|
||||
sg[0].length = length;
|
||||
|
||||
ret = crypto_cipher_encrypt_iv(tfm, sg, sg, length, local_iv);
|
||||
|
||||
dprintk("RPC: krb5_encrypt: output data:\n");
|
||||
print_hexl((u32 *)out, length, 0);
|
||||
out:
|
||||
dprintk("RPC: krb5_encrypt returns %d\n",ret);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(krb5_encrypt);
|
||||
|
||||
u32
|
||||
krb5_decrypt(
|
||||
struct crypto_tfm *tfm,
|
||||
void * iv,
|
||||
void * in,
|
||||
void * out,
|
||||
int length)
|
||||
{
|
||||
u32 ret = -EINVAL;
|
||||
struct scatterlist sg[1];
|
||||
u8 local_iv[16] = {0};
|
||||
|
||||
dprintk("RPC: krb5_decrypt: input data:\n");
|
||||
print_hexl((u32 *)in, length, 0);
|
||||
|
||||
if (length % crypto_tfm_alg_blocksize(tfm) != 0)
|
||||
goto out;
|
||||
|
||||
if (crypto_tfm_alg_ivsize(tfm) > 16) {
|
||||
dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n",
|
||||
crypto_tfm_alg_ivsize(tfm));
|
||||
goto out;
|
||||
}
|
||||
if (iv)
|
||||
memcpy(local_iv,iv, crypto_tfm_alg_ivsize(tfm));
|
||||
|
||||
memcpy(out, in, length);
|
||||
sg[0].page = virt_to_page(out);
|
||||
sg[0].offset = offset_in_page(out);
|
||||
sg[0].length = length;
|
||||
|
||||
ret = crypto_cipher_decrypt_iv(tfm, sg, sg, length, local_iv);
|
||||
|
||||
dprintk("RPC: krb5_decrypt: output_data:\n");
|
||||
print_hexl((u32 *)out, length, 0);
|
||||
out:
|
||||
dprintk("RPC: gss_k5decrypt returns %d\n",ret);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(krb5_decrypt);
|
||||
|
||||
void
|
||||
buf_to_sg(struct scatterlist *sg, char *ptr, int len) {
|
||||
sg->page = virt_to_page(ptr);
|
||||
sg->offset = offset_in_page(ptr);
|
||||
sg->length = len;
|
||||
}
|
||||
|
||||
/* checksum the plaintext data and hdrlen bytes of the token header */
|
||||
s32
|
||||
make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
|
||||
struct xdr_netobj *cksum)
|
||||
{
|
||||
char *cksumname;
|
||||
struct crypto_tfm *tfm = NULL; /* XXX add to ctx? */
|
||||
struct scatterlist sg[1];
|
||||
u32 code = GSS_S_FAILURE;
|
||||
int len, thislen, offset;
|
||||
int i;
|
||||
|
||||
switch (cksumtype) {
|
||||
case CKSUMTYPE_RSA_MD5:
|
||||
cksumname = "md5";
|
||||
break;
|
||||
default:
|
||||
dprintk("RPC: krb5_make_checksum:"
|
||||
" unsupported checksum %d", cksumtype);
|
||||
goto out;
|
||||
}
|
||||
if (!(tfm = crypto_alloc_tfm(cksumname, 0)))
|
||||
goto out;
|
||||
cksum->len = crypto_tfm_alg_digestsize(tfm);
|
||||
if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL)
|
||||
goto out;
|
||||
|
||||
crypto_digest_init(tfm);
|
||||
buf_to_sg(sg, header, hdrlen);
|
||||
crypto_digest_update(tfm, sg, 1);
|
||||
if (body->head[0].iov_len) {
|
||||
buf_to_sg(sg, body->head[0].iov_base, body->head[0].iov_len);
|
||||
crypto_digest_update(tfm, sg, 1);
|
||||
}
|
||||
|
||||
len = body->page_len;
|
||||
if (len != 0) {
|
||||
offset = body->page_base & (PAGE_CACHE_SIZE - 1);
|
||||
i = body->page_base >> PAGE_CACHE_SHIFT;
|
||||
thislen = PAGE_CACHE_SIZE - offset;
|
||||
do {
|
||||
if (thislen > len)
|
||||
thislen = len;
|
||||
sg->page = body->pages[i];
|
||||
sg->offset = offset;
|
||||
sg->length = thislen;
|
||||
kmap(sg->page); /* XXX kmap_atomic? */
|
||||
crypto_digest_update(tfm, sg, 1);
|
||||
kunmap(sg->page);
|
||||
len -= thislen;
|
||||
i++;
|
||||
offset = 0;
|
||||
thislen = PAGE_CACHE_SIZE;
|
||||
} while(len != 0);
|
||||
}
|
||||
if (body->tail[0].iov_len) {
|
||||
buf_to_sg(sg, body->tail[0].iov_base, body->tail[0].iov_len);
|
||||
crypto_digest_update(tfm, sg, 1);
|
||||
}
|
||||
crypto_digest_final(tfm, cksum->data);
|
||||
code = 0;
|
||||
out:
|
||||
if (tfm)
|
||||
crypto_free_tfm(tfm);
|
||||
return code;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(make_checksum);
|
||||
263
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_mech.c
Normal file
263
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_mech.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_krb5_mech.c
|
||||
*
|
||||
* Copyright (c) 2001 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
* J. Bruce Fields <bfields@umich.edu>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sunrpc/auth.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
struct xdr_netobj gss_mech_krb5_oid =
|
||||
{9, "\052\206\110\206\367\022\001\002\002"};
|
||||
|
||||
static inline int
|
||||
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
|
||||
get_netobj(char **ptr, const char *end, struct xdr_netobj *res)
|
||||
{
|
||||
char *p, *q;
|
||||
p = *ptr;
|
||||
if (get_bytes(&p, end, &res->len, sizeof(res->len)))
|
||||
return -1;
|
||||
q = p + res->len;
|
||||
if (q > end || q < p)
|
||||
return -1;
|
||||
if (!(res->data = kmalloc(res->len, GFP_KERNEL)))
|
||||
return -1;
|
||||
memcpy(res->data, p, res->len);
|
||||
*ptr = q;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
get_key(char **p, char *end, struct crypto_tfm **res)
|
||||
{
|
||||
struct xdr_netobj key;
|
||||
int alg, alg_mode;
|
||||
char *alg_name;
|
||||
|
||||
if (get_bytes(p, end, &alg, sizeof(alg)))
|
||||
goto out_err;
|
||||
if ((get_netobj(p, end, &key)))
|
||||
goto out_err;
|
||||
|
||||
switch (alg) {
|
||||
case ENCTYPE_DES_CBC_RAW:
|
||||
alg_name = "des";
|
||||
alg_mode = CRYPTO_TFM_MODE_CBC;
|
||||
break;
|
||||
default:
|
||||
dprintk("RPC: get_key: unsupported algorithm %d\n", alg);
|
||||
goto out_err_free_key;
|
||||
}
|
||||
if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
|
||||
goto out_err_free_key;
|
||||
if (crypto_cipher_setkey(*res, key.data, key.len))
|
||||
goto out_err_free_tfm;
|
||||
|
||||
kfree(key.data);
|
||||
return 0;
|
||||
|
||||
out_err_free_tfm:
|
||||
crypto_free_tfm(*res);
|
||||
out_err_free_key:
|
||||
kfree(key.data);
|
||||
out_err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static u32
|
||||
gss_import_sec_context_kerberos(struct xdr_netobj *inbuf,
|
||||
struct gss_ctx *ctx_id)
|
||||
{
|
||||
char *p = inbuf->data;
|
||||
char *end = inbuf->data + inbuf->len;
|
||||
struct krb5_ctx *ctx;
|
||||
|
||||
if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
|
||||
goto out_err;
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
if (get_bytes(&p, end, &ctx->initiate, sizeof(ctx->initiate)))
|
||||
goto out_err_free_ctx;
|
||||
if (get_bytes(&p, end, &ctx->seed_init, sizeof(ctx->seed_init)))
|
||||
goto out_err_free_ctx;
|
||||
if (get_bytes(&p, end, ctx->seed, sizeof(ctx->seed)))
|
||||
goto out_err_free_ctx;
|
||||
if (get_bytes(&p, end, &ctx->signalg, sizeof(ctx->signalg)))
|
||||
goto out_err_free_ctx;
|
||||
if (get_bytes(&p, end, &ctx->sealalg, sizeof(ctx->sealalg)))
|
||||
goto out_err_free_ctx;
|
||||
if (get_bytes(&p, end, &ctx->endtime, sizeof(ctx->endtime)))
|
||||
goto out_err_free_ctx;
|
||||
if (get_bytes(&p, end, &ctx->seq_send, sizeof(ctx->seq_send)))
|
||||
goto out_err_free_ctx;
|
||||
if (get_netobj(&p, end, &ctx->mech_used))
|
||||
goto out_err_free_ctx;
|
||||
if (get_key(&p, end, &ctx->enc))
|
||||
goto out_err_free_mech;
|
||||
if (get_key(&p, end, &ctx->seq))
|
||||
goto out_err_free_key1;
|
||||
if (p != end)
|
||||
goto out_err_free_key2;
|
||||
|
||||
ctx_id->internal_ctx_id = ctx;
|
||||
dprintk("RPC: Succesfully imported new context.\n");
|
||||
return 0;
|
||||
|
||||
out_err_free_key2:
|
||||
crypto_free_tfm(ctx->seq);
|
||||
out_err_free_key1:
|
||||
crypto_free_tfm(ctx->enc);
|
||||
out_err_free_mech:
|
||||
kfree(ctx->mech_used.data);
|
||||
out_err_free_ctx:
|
||||
kfree(ctx);
|
||||
out_err:
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
static void
|
||||
gss_delete_sec_context_kerberos(void *internal_ctx) {
|
||||
struct krb5_ctx *kctx = internal_ctx;
|
||||
|
||||
if (kctx->seq)
|
||||
crypto_free_tfm(kctx->seq);
|
||||
if (kctx->enc)
|
||||
crypto_free_tfm(kctx->enc);
|
||||
if (kctx->mech_used.data)
|
||||
kfree(kctx->mech_used.data);
|
||||
kfree(kctx);
|
||||
}
|
||||
|
||||
static u32
|
||||
gss_verify_mic_kerberos(struct gss_ctx *ctx,
|
||||
struct xdr_buf *message,
|
||||
struct xdr_netobj *mic_token,
|
||||
u32 *qstate) {
|
||||
u32 maj_stat = 0;
|
||||
int qop_state;
|
||||
struct krb5_ctx *kctx = ctx->internal_ctx_id;
|
||||
|
||||
maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state,
|
||||
KG_TOK_MIC_MSG);
|
||||
if (!maj_stat && qop_state)
|
||||
*qstate = qop_state;
|
||||
|
||||
dprintk("RPC: gss_verify_mic_kerberos returning %d\n", maj_stat);
|
||||
return maj_stat;
|
||||
}
|
||||
|
||||
static u32
|
||||
gss_get_mic_kerberos(struct gss_ctx *ctx,
|
||||
u32 qop,
|
||||
struct xdr_buf *message,
|
||||
struct xdr_netobj *mic_token) {
|
||||
u32 err = 0;
|
||||
struct krb5_ctx *kctx = ctx->internal_ctx_id;
|
||||
|
||||
err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG);
|
||||
|
||||
dprintk("RPC: gss_get_mic_kerberos returning %d\n",err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct gss_api_ops gss_kerberos_ops = {
|
||||
.gss_import_sec_context = gss_import_sec_context_kerberos,
|
||||
.gss_get_mic = gss_get_mic_kerberos,
|
||||
.gss_verify_mic = gss_verify_mic_kerberos,
|
||||
.gss_delete_sec_context = gss_delete_sec_context_kerberos,
|
||||
};
|
||||
|
||||
static struct pf_desc gss_kerberos_pfs[] = {
|
||||
[0] = {
|
||||
.pseudoflavor = RPC_AUTH_GSS_KRB5,
|
||||
.service = RPC_GSS_SVC_NONE,
|
||||
.name = "krb5",
|
||||
},
|
||||
[1] = {
|
||||
.pseudoflavor = RPC_AUTH_GSS_KRB5I,
|
||||
.service = RPC_GSS_SVC_INTEGRITY,
|
||||
.name = "krb5i",
|
||||
},
|
||||
};
|
||||
|
||||
static struct gss_api_mech gss_kerberos_mech = {
|
||||
.gm_name = "krb5",
|
||||
.gm_owner = THIS_MODULE,
|
||||
.gm_ops = &gss_kerberos_ops,
|
||||
.gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs),
|
||||
.gm_pfs = gss_kerberos_pfs,
|
||||
};
|
||||
|
||||
static int __init init_kerberos_module(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = gss_mech_register(&gss_kerberos_mech);
|
||||
if (status)
|
||||
printk("Failed to register kerberos gss mechanism!\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit cleanup_kerberos_module(void)
|
||||
{
|
||||
gss_mech_unregister(&gss_kerberos_mech);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(init_kerberos_module);
|
||||
module_exit(cleanup_kerberos_module);
|
||||
176
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_seal.c
Normal file
176
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_seal.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_krb5_seal.c
|
||||
*
|
||||
* Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5seal.c
|
||||
*
|
||||
* Copyright (c) 2000 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
* J. Bruce Fields <bfields@umich.edu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 1993 by OpenVision Technologies, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appears in all copies and
|
||||
* that both that copyright notice and this permission notice appear in
|
||||
* supporting documentation, and that the name of OpenVision not be used
|
||||
* in advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. OpenVision makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
||||
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1998 by the FundsXpress, INC.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Export of this software from the United States of America may require
|
||||
* a specific license from the United States Government. It is the
|
||||
* responsibility of any person or organization contemplating export to
|
||||
* obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of FundsXpress. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. FundsXpress makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
#include <linux/random.h>
|
||||
#include <asm/scatterlist.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
gss_krb5_padding(int blocksize, int length) {
|
||||
/* Most of the code is block-size independent but in practice we
|
||||
* use only 8: */
|
||||
BUG_ON(blocksize != 8);
|
||||
return 8 - (length & 7);
|
||||
}
|
||||
|
||||
u32
|
||||
krb5_make_token(struct krb5_ctx *ctx, int qop_req,
|
||||
struct xdr_buf *text, struct xdr_netobj *token,
|
||||
int toktype)
|
||||
{
|
||||
s32 checksum_type;
|
||||
struct xdr_netobj md5cksum = {.len = 0, .data = NULL};
|
||||
int blocksize = 0, tmsglen;
|
||||
unsigned char *ptr, *krb5_hdr, *msg_start;
|
||||
s32 now;
|
||||
|
||||
dprintk("RPC: gss_krb5_seal\n");
|
||||
|
||||
now = get_seconds();
|
||||
|
||||
if (qop_req != 0)
|
||||
goto out_err;
|
||||
|
||||
switch (ctx->signalg) {
|
||||
case SGN_ALG_DES_MAC_MD5:
|
||||
checksum_type = CKSUMTYPE_RSA_MD5;
|
||||
break;
|
||||
default:
|
||||
dprintk("RPC: gss_krb5_seal: ctx->signalg %d not"
|
||||
" supported\n", ctx->signalg);
|
||||
goto out_err;
|
||||
}
|
||||
if (ctx->sealalg != SEAL_ALG_NONE && ctx->sealalg != SEAL_ALG_DES) {
|
||||
dprintk("RPC: gss_krb5_seal: ctx->sealalg %d not supported\n",
|
||||
ctx->sealalg);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (toktype == KG_TOK_WRAP_MSG) {
|
||||
blocksize = crypto_tfm_alg_blocksize(ctx->enc);
|
||||
tmsglen = blocksize + text->len
|
||||
+ gss_krb5_padding(blocksize, blocksize + text->len);
|
||||
} else {
|
||||
tmsglen = 0;
|
||||
}
|
||||
|
||||
token->len = g_token_size(&ctx->mech_used, 22 + tmsglen);
|
||||
|
||||
ptr = token->data;
|
||||
g_make_token_header(&ctx->mech_used, 22 + tmsglen, &ptr);
|
||||
|
||||
*ptr++ = (unsigned char) ((toktype>>8)&0xff);
|
||||
*ptr++ = (unsigned char) (toktype&0xff);
|
||||
|
||||
/* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */
|
||||
krb5_hdr = ptr - 2;
|
||||
msg_start = krb5_hdr + 24;
|
||||
|
||||
*(u16 *)(krb5_hdr + 2) = htons(ctx->signalg);
|
||||
memset(krb5_hdr + 4, 0xff, 4);
|
||||
if (toktype == KG_TOK_WRAP_MSG)
|
||||
*(u16 *)(krb5_hdr + 4) = htons(ctx->sealalg);
|
||||
|
||||
if (toktype == KG_TOK_WRAP_MSG) {
|
||||
/* XXX removing support for now */
|
||||
goto out_err;
|
||||
} else { /* Sign only. */
|
||||
if (make_checksum(checksum_type, krb5_hdr, 8, text,
|
||||
&md5cksum))
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
switch (ctx->signalg) {
|
||||
case SGN_ALG_DES_MAC_MD5:
|
||||
if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
|
||||
md5cksum.data, md5cksum.len))
|
||||
goto out_err;
|
||||
memcpy(krb5_hdr + 16,
|
||||
md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
|
||||
KRB5_CKSUM_LENGTH);
|
||||
|
||||
dprintk("RPC: make_seal_token: cksum data: \n");
|
||||
print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
kfree(md5cksum.data);
|
||||
|
||||
if ((krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
|
||||
ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8)))
|
||||
goto out_err;
|
||||
|
||||
ctx->seq_send++;
|
||||
|
||||
return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE);
|
||||
out_err:
|
||||
if (md5cksum.data) kfree(md5cksum.data);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
88
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_seqnum.c
Normal file
88
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_seqnum.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_krb5_seqnum.c
|
||||
*
|
||||
* Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/util_seqnum.c
|
||||
*
|
||||
* Copyright (c) 2000 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 1993 by OpenVision Technologies, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appears in all copies and
|
||||
* that both that copyright notice and this permission notice appear in
|
||||
* supporting documentation, and that the name of OpenVision not be used
|
||||
* in advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. OpenVision makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
||||
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
s32
|
||||
krb5_make_seq_num(struct crypto_tfm *key,
|
||||
int direction,
|
||||
s32 seqnum,
|
||||
unsigned char *cksum, unsigned char *buf)
|
||||
{
|
||||
unsigned char plain[8];
|
||||
|
||||
plain[0] = (unsigned char) (seqnum & 0xff);
|
||||
plain[1] = (unsigned char) ((seqnum >> 8) & 0xff);
|
||||
plain[2] = (unsigned char) ((seqnum >> 16) & 0xff);
|
||||
plain[3] = (unsigned char) ((seqnum >> 24) & 0xff);
|
||||
|
||||
plain[4] = direction;
|
||||
plain[5] = direction;
|
||||
plain[6] = direction;
|
||||
plain[7] = direction;
|
||||
|
||||
return krb5_encrypt(key, cksum, plain, buf, 8);
|
||||
}
|
||||
|
||||
s32
|
||||
krb5_get_seq_num(struct crypto_tfm *key,
|
||||
unsigned char *cksum,
|
||||
unsigned char *buf,
|
||||
int *direction, s32 * seqnum)
|
||||
{
|
||||
s32 code;
|
||||
unsigned char plain[8];
|
||||
|
||||
dprintk("RPC: krb5_get_seq_num:\n");
|
||||
|
||||
if ((code = krb5_decrypt(key, cksum, buf, plain, 8)))
|
||||
return code;
|
||||
|
||||
if ((plain[4] != plain[5]) || (plain[4] != plain[6])
|
||||
|| (plain[4] != plain[7]))
|
||||
return (s32)KG_BAD_SEQ;
|
||||
|
||||
*direction = plain[4];
|
||||
|
||||
*seqnum = ((plain[0]) |
|
||||
(plain[1] << 8) | (plain[2] << 16) | (plain[3] << 24));
|
||||
|
||||
return (0);
|
||||
}
|
||||
202
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_unseal.c
Normal file
202
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_krb5_unseal.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_krb5_unseal.c
|
||||
*
|
||||
* Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5unseal.c
|
||||
*
|
||||
* Copyright (c) 2000 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 1993 by OpenVision Technologies, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appears in all copies and
|
||||
* that both that copyright notice and this permission notice appear in
|
||||
* supporting documentation, and that the name of OpenVision not be used
|
||||
* in advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. OpenVision makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
||||
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1998 by the FundsXpress, INC.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Export of this software from the United States of America may require
|
||||
* a specific license from the United States Government. It is the
|
||||
* responsibility of any person or organization contemplating export to
|
||||
* obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of FundsXpress. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. FundsXpress makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
|
||||
/* message_buffer is an input if toktype is MIC and an output if it is WRAP:
|
||||
* If toktype is MIC: read_token is a mic token, and message_buffer is the
|
||||
* data that the mic was supposedly taken over.
|
||||
* If toktype is WRAP: read_token is a wrap token, and message_buffer is used
|
||||
* to return the decrypted data.
|
||||
*/
|
||||
|
||||
/* XXX will need to change prototype and/or just split into a separate function
|
||||
* when we add privacy (because read_token will be in pages too). */
|
||||
u32
|
||||
krb5_read_token(struct krb5_ctx *ctx,
|
||||
struct xdr_netobj *read_token,
|
||||
struct xdr_buf *message_buffer,
|
||||
int *qop_state, int toktype)
|
||||
{
|
||||
int signalg;
|
||||
int sealalg;
|
||||
s32 checksum_type;
|
||||
struct xdr_netobj md5cksum = {.len = 0, .data = NULL};
|
||||
s32 now;
|
||||
int direction;
|
||||
s32 seqnum;
|
||||
unsigned char *ptr = (unsigned char *)read_token->data;
|
||||
int bodysize;
|
||||
u32 ret = GSS_S_DEFECTIVE_TOKEN;
|
||||
|
||||
dprintk("RPC: krb5_read_token\n");
|
||||
|
||||
if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr,
|
||||
read_token->len))
|
||||
goto out;
|
||||
|
||||
if ((*ptr++ != ((toktype>>8)&0xff)) || (*ptr++ != (toktype&0xff)))
|
||||
goto out;
|
||||
|
||||
/* XXX sanity-check bodysize?? */
|
||||
|
||||
if (toktype == KG_TOK_WRAP_MSG) {
|
||||
/* XXX gone */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* get the sign and seal algorithms */
|
||||
|
||||
signalg = ptr[0] + (ptr[1] << 8);
|
||||
sealalg = ptr[2] + (ptr[3] << 8);
|
||||
|
||||
/* Sanity checks */
|
||||
|
||||
if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
|
||||
goto out;
|
||||
|
||||
if (((toktype != KG_TOK_WRAP_MSG) && (sealalg != 0xffff)) ||
|
||||
((toktype == KG_TOK_WRAP_MSG) && (sealalg == 0xffff)))
|
||||
goto out;
|
||||
|
||||
/* in the current spec, there is only one valid seal algorithm per
|
||||
key type, so a simple comparison is ok */
|
||||
|
||||
if ((toktype == KG_TOK_WRAP_MSG) && !(sealalg == ctx->sealalg))
|
||||
goto out;
|
||||
|
||||
/* there are several mappings of seal algorithms to sign algorithms,
|
||||
but few enough that we can try them all. */
|
||||
|
||||
if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
|
||||
(ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
|
||||
(ctx->sealalg == SEAL_ALG_DES3KD &&
|
||||
signalg != SGN_ALG_HMAC_SHA1_DES3_KD))
|
||||
goto out;
|
||||
|
||||
/* compute the checksum of the message */
|
||||
|
||||
/* initialize the the cksum */
|
||||
switch (signalg) {
|
||||
case SGN_ALG_DES_MAC_MD5:
|
||||
checksum_type = CKSUMTYPE_RSA_MD5;
|
||||
break;
|
||||
default:
|
||||
ret = GSS_S_DEFECTIVE_TOKEN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (signalg) {
|
||||
case SGN_ALG_DES_MAC_MD5:
|
||||
ret = make_checksum(checksum_type, ptr - 2, 8,
|
||||
message_buffer, &md5cksum);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_encrypt(ctx->seq, NULL, md5cksum.data,
|
||||
md5cksum.data, 16);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (memcmp(md5cksum.data + 8, ptr + 14, 8)) {
|
||||
ret = GSS_S_BAD_SIG;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = GSS_S_DEFECTIVE_TOKEN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* it got through unscathed. Make sure the context is unexpired */
|
||||
|
||||
if (qop_state)
|
||||
*qop_state = GSS_C_QOP_DEFAULT;
|
||||
|
||||
now = get_seconds();
|
||||
|
||||
ret = GSS_S_CONTEXT_EXPIRED;
|
||||
if (now > ctx->endtime)
|
||||
goto out;
|
||||
|
||||
/* do sequencing checks */
|
||||
|
||||
ret = GSS_S_BAD_SIG;
|
||||
if ((ret = krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction,
|
||||
&seqnum)))
|
||||
goto out;
|
||||
|
||||
if ((ctx->initiate && direction != 0xff) ||
|
||||
(!ctx->initiate && direction != 0))
|
||||
goto out;
|
||||
|
||||
ret = GSS_S_COMPLETE;
|
||||
out:
|
||||
if (md5cksum.data) kfree(md5cksum.data);
|
||||
return ret;
|
||||
}
|
||||
303
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_mech_switch.c
Normal file
303
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_mech_switch.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_mech_switch.c
|
||||
*
|
||||
* Copyright (c) 2001 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* J. Bruce Fields <bfields@umich.edu>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sunrpc/msg_prot.h>
|
||||
#include <linux/sunrpc/gss_asn1.h>
|
||||
#include <linux/sunrpc/auth_gss.h>
|
||||
#include <linux/sunrpc/svcauth_gss.h>
|
||||
#include <linux/sunrpc/gss_err.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/sunrpc/gss_api.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
static LIST_HEAD(registered_mechs);
|
||||
static spinlock_t registered_mechs_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static void
|
||||
gss_mech_free(struct gss_api_mech *gm)
|
||||
{
|
||||
struct pf_desc *pf;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gm->gm_pf_num; i++) {
|
||||
pf = &gm->gm_pfs[i];
|
||||
if (pf->auth_domain_name)
|
||||
kfree(pf->auth_domain_name);
|
||||
pf->auth_domain_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline char *
|
||||
make_auth_domain_name(char *name)
|
||||
{
|
||||
static char *prefix = "gss/";
|
||||
char *new;
|
||||
|
||||
new = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL);
|
||||
if (new) {
|
||||
strcpy(new, prefix);
|
||||
strcat(new, name);
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
static int
|
||||
gss_mech_svc_setup(struct gss_api_mech *gm)
|
||||
{
|
||||
struct pf_desc *pf;
|
||||
int i, status;
|
||||
|
||||
for (i = 0; i < gm->gm_pf_num; i++) {
|
||||
pf = &gm->gm_pfs[i];
|
||||
pf->auth_domain_name = make_auth_domain_name(pf->name);
|
||||
status = -ENOMEM;
|
||||
if (pf->auth_domain_name == NULL)
|
||||
goto out;
|
||||
status = svcauth_gss_register_pseudoflavor(pf->pseudoflavor,
|
||||
pf->auth_domain_name);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
out:
|
||||
gss_mech_free(gm);
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
gss_mech_register(struct gss_api_mech *gm)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = gss_mech_svc_setup(gm);
|
||||
if (status)
|
||||
return status;
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_add(&gm->gm_list, ®istered_mechs);
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
dprintk("RPC: registered gss mechanism %s\n", gm->gm_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(gss_mech_register);
|
||||
|
||||
void
|
||||
gss_mech_unregister(struct gss_api_mech *gm)
|
||||
{
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_del(&gm->gm_list);
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name);
|
||||
gss_mech_free(gm);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(gss_mech_unregister);
|
||||
|
||||
struct gss_api_mech *
|
||||
gss_mech_get(struct gss_api_mech *gm)
|
||||
{
|
||||
__module_get(gm->gm_owner);
|
||||
return gm;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(gss_mech_get);
|
||||
|
||||
struct gss_api_mech *
|
||||
gss_mech_get_by_name(char *name)
|
||||
{
|
||||
struct gss_api_mech *pos, *gm = NULL;
|
||||
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_for_each_entry(pos, ®istered_mechs, gm_list) {
|
||||
if (0 == strcmp(name, pos->gm_name)) {
|
||||
if (!try_module_get(pos->gm_owner))
|
||||
continue;
|
||||
gm = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
return gm;
|
||||
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(gss_mech_get_by_name);
|
||||
|
||||
static inline int
|
||||
mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gm->gm_pf_num; i++) {
|
||||
if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct gss_api_mech *
|
||||
gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
|
||||
{
|
||||
struct gss_api_mech *pos, *gm = NULL;
|
||||
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_for_each_entry(pos, ®istered_mechs, gm_list) {
|
||||
if (!try_module_get(pos->gm_owner))
|
||||
continue;
|
||||
if (!mech_supports_pseudoflavor(pos, pseudoflavor)) {
|
||||
module_put(pos->gm_owner);
|
||||
continue;
|
||||
}
|
||||
gm = pos;
|
||||
break;
|
||||
}
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
return gm;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(gss_mech_get_by_pseudoflavor);
|
||||
|
||||
u32
|
||||
gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gm->gm_pf_num; i++) {
|
||||
if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
|
||||
return gm->gm_pfs[i].service;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(gss_pseudoflavor_to_service);
|
||||
|
||||
char *
|
||||
gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gm->gm_pf_num; i++) {
|
||||
if (gm->gm_pfs[i].service == service)
|
||||
return gm->gm_pfs[i].auth_domain_name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(gss_service_to_auth_domain_name);
|
||||
|
||||
void
|
||||
gss_mech_put(struct gss_api_mech * gm)
|
||||
{
|
||||
module_put(gm->gm_owner);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(gss_mech_put);
|
||||
|
||||
/* The mech could probably be determined from the token instead, but it's just
|
||||
* as easy for now to pass it in. */
|
||||
u32
|
||||
gss_import_sec_context(struct xdr_netobj *input_token,
|
||||
struct gss_api_mech *mech,
|
||||
struct gss_ctx **ctx_id)
|
||||
{
|
||||
if (!(*ctx_id = kmalloc(sizeof(**ctx_id), GFP_KERNEL)))
|
||||
return GSS_S_FAILURE;
|
||||
memset(*ctx_id, 0, sizeof(**ctx_id));
|
||||
(*ctx_id)->mech_type = gss_mech_get(mech);
|
||||
|
||||
return mech->gm_ops
|
||||
->gss_import_sec_context(input_token, *ctx_id);
|
||||
}
|
||||
|
||||
/* gss_get_mic: compute a mic over message and return mic_token. */
|
||||
|
||||
u32
|
||||
gss_get_mic(struct gss_ctx *context_handle,
|
||||
u32 qop,
|
||||
struct xdr_buf *message,
|
||||
struct xdr_netobj *mic_token)
|
||||
{
|
||||
return context_handle->mech_type->gm_ops
|
||||
->gss_get_mic(context_handle,
|
||||
qop,
|
||||
message,
|
||||
mic_token);
|
||||
}
|
||||
|
||||
/* gss_verify_mic: check whether the provided mic_token verifies message. */
|
||||
|
||||
u32
|
||||
gss_verify_mic(struct gss_ctx *context_handle,
|
||||
struct xdr_buf *message,
|
||||
struct xdr_netobj *mic_token,
|
||||
u32 *qstate)
|
||||
{
|
||||
return context_handle->mech_type->gm_ops
|
||||
->gss_verify_mic(context_handle,
|
||||
message,
|
||||
mic_token,
|
||||
qstate);
|
||||
}
|
||||
|
||||
/* gss_delete_sec_context: free all resources associated with context_handle.
|
||||
* Note this differs from the RFC 2744-specified prototype in that we don't
|
||||
* bother returning an output token, since it would never be used anyway. */
|
||||
|
||||
u32
|
||||
gss_delete_sec_context(struct gss_ctx **context_handle)
|
||||
{
|
||||
dprintk("RPC: gss_delete_sec_context deleting %p\n",
|
||||
*context_handle);
|
||||
|
||||
if (!*context_handle)
|
||||
return(GSS_S_NO_CONTEXT);
|
||||
if ((*context_handle)->internal_ctx_id != 0)
|
||||
(*context_handle)->mech_type->gm_ops
|
||||
->gss_delete_sec_context((*context_handle)
|
||||
->internal_ctx_id);
|
||||
if ((*context_handle)->mech_type)
|
||||
gss_mech_put((*context_handle)->mech_type);
|
||||
kfree(*context_handle);
|
||||
*context_handle=NULL;
|
||||
return GSS_S_COMPLETE;
|
||||
}
|
||||
237
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_pseudoflavors.c
Normal file
237
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_pseudoflavors.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_union.c
|
||||
*
|
||||
* Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic code
|
||||
*
|
||||
* Copyright (c) 2001 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 1993 by OpenVision Technologies, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appears in all copies and
|
||||
* that both that copyright notice and this permission notice appear in
|
||||
* supporting documentation, and that the name of OpenVision not be used
|
||||
* in advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. OpenVision makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
||||
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sunrpc/gss_asn1.h>
|
||||
#include <linux/sunrpc/auth_gss.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
static LIST_HEAD(registered_triples);
|
||||
static spinlock_t registered_triples_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
/* The following must be called with spinlock held: */
|
||||
static struct sup_sec_triple *
|
||||
do_lookup_triple_by_pseudoflavor(u32 pseudoflavor)
|
||||
{
|
||||
struct sup_sec_triple *pos, *triple = NULL;
|
||||
|
||||
list_for_each_entry(pos, ®istered_triples, triples) {
|
||||
if (pos->pseudoflavor == pseudoflavor) {
|
||||
triple = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return triple;
|
||||
}
|
||||
|
||||
/* XXX Need to think about reference counting of triples and of mechs.
|
||||
* Currently we do no reference counting of triples, and I think that's
|
||||
* probably OK given the reference counting on mechs, but there's probably
|
||||
* a better way to do all this. */
|
||||
|
||||
int
|
||||
gss_register_triple(u32 pseudoflavor, struct gss_api_mech *mech,
|
||||
u32 qop, u32 service)
|
||||
{
|
||||
struct sup_sec_triple *triple;
|
||||
|
||||
if (!(triple = kmalloc(sizeof(*triple), GFP_KERNEL))) {
|
||||
printk("Alloc failed in gss_register_triple");
|
||||
goto err;
|
||||
}
|
||||
triple->pseudoflavor = pseudoflavor;
|
||||
triple->mech = gss_mech_get_by_OID(&mech->gm_oid);
|
||||
triple->qop = qop;
|
||||
triple->service = service;
|
||||
|
||||
spin_lock(®istered_triples_lock);
|
||||
if (do_lookup_triple_by_pseudoflavor(pseudoflavor)) {
|
||||
printk(KERN_WARNING "RPC: Registered pseudoflavor %d again\n",
|
||||
pseudoflavor);
|
||||
goto err_unlock;
|
||||
}
|
||||
list_add(&triple->triples, ®istered_triples);
|
||||
spin_unlock(®istered_triples_lock);
|
||||
dprintk("RPC: registered pseudoflavor %d\n", pseudoflavor);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unlock:
|
||||
kfree(triple);
|
||||
spin_unlock(®istered_triples_lock);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
gss_unregister_triple(u32 pseudoflavor)
|
||||
{
|
||||
struct sup_sec_triple *triple;
|
||||
|
||||
spin_lock(®istered_triples_lock);
|
||||
if (!(triple = do_lookup_triple_by_pseudoflavor(pseudoflavor))) {
|
||||
spin_unlock(®istered_triples_lock);
|
||||
printk("Can't unregister unregistered pseudoflavor %d\n",
|
||||
pseudoflavor);
|
||||
return -1;
|
||||
}
|
||||
list_del(&triple->triples);
|
||||
spin_unlock(®istered_triples_lock);
|
||||
gss_mech_put(triple->mech);
|
||||
kfree(triple);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
print_sec_triple(struct xdr_netobj *oid,u32 qop,u32 service)
|
||||
{
|
||||
dprintk("RPC: print_sec_triple:\n");
|
||||
dprintk(" oid_len %d\n oid :\n",oid->len);
|
||||
print_hexl((u32 *)oid->data,oid->len,0);
|
||||
dprintk(" qop %d\n",qop);
|
||||
dprintk(" service %d\n",service);
|
||||
}
|
||||
|
||||
/* Function: gss_get_cmp_triples
|
||||
*
|
||||
* Description: search sec_triples for a matching security triple
|
||||
* return pseudoflavor if match, else 0
|
||||
* (Note that 0 is a valid pseudoflavor, but not for any gss pseudoflavor
|
||||
* (0 means auth_null), so this shouldn't cause confusion.)
|
||||
*/
|
||||
u32
|
||||
gss_cmp_triples(u32 oid_len, char *oid_data, u32 qop, u32 service)
|
||||
{
|
||||
struct sup_sec_triple *triple;
|
||||
u32 pseudoflavor = 0;
|
||||
struct xdr_netobj oid;
|
||||
|
||||
oid.len = oid_len;
|
||||
oid.data = oid_data;
|
||||
|
||||
dprintk("RPC: gss_cmp_triples\n");
|
||||
print_sec_triple(&oid,qop,service);
|
||||
|
||||
spin_lock(®istered_triples_lock);
|
||||
list_for_each_entry(triple, ®istered_triples, triples) {
|
||||
if((g_OID_equal(&oid, &triple->mech->gm_oid))
|
||||
&& (qop == triple->qop)
|
||||
&& (service == triple->service)) {
|
||||
pseudoflavor = triple->pseudoflavor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(®istered_triples_lock);
|
||||
dprintk("RPC: gss_cmp_triples return %d\n", pseudoflavor);
|
||||
return pseudoflavor;
|
||||
}
|
||||
|
||||
u32
|
||||
gss_get_pseudoflavor(struct gss_ctx *ctx, u32 qop, u32 service)
|
||||
{
|
||||
return gss_cmp_triples(ctx->mech_type->gm_oid.len,
|
||||
ctx->mech_type->gm_oid.data,
|
||||
qop, service);
|
||||
}
|
||||
|
||||
/* Returns nonzero iff the given pseudoflavor is in the supported list.
|
||||
* (Note that without incrementing a reference count or anything, this
|
||||
* doesn't give any guarantees.) */
|
||||
int
|
||||
gss_pseudoflavor_supported(u32 pseudoflavor)
|
||||
{
|
||||
struct sup_sec_triple *triple;
|
||||
|
||||
spin_lock(®istered_triples_lock);
|
||||
triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
|
||||
spin_unlock(®istered_triples_lock);
|
||||
return (triple ? 1 : 0);
|
||||
}
|
||||
|
||||
u32
|
||||
gss_pseudoflavor_to_service(u32 pseudoflavor)
|
||||
{
|
||||
struct sup_sec_triple *triple;
|
||||
|
||||
spin_lock(®istered_triples_lock);
|
||||
triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
|
||||
spin_unlock(®istered_triples_lock);
|
||||
if (!triple) {
|
||||
dprintk("RPC: gss_pseudoflavor_to_service called with unsupported pseudoflavor %d\n",
|
||||
pseudoflavor);
|
||||
return 0;
|
||||
}
|
||||
return triple->service;
|
||||
}
|
||||
|
||||
struct gss_api_mech *
|
||||
gss_pseudoflavor_to_mech(u32 pseudoflavor) {
|
||||
struct sup_sec_triple *triple;
|
||||
struct gss_api_mech *mech = NULL;
|
||||
|
||||
spin_lock(®istered_triples_lock);
|
||||
triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
|
||||
spin_unlock(®istered_triples_lock);
|
||||
if (triple)
|
||||
mech = gss_mech_get(triple->mech);
|
||||
else
|
||||
dprintk("RPC: gss_pseudoflavor_to_mech called with unsupported pseudoflavor %d\n",
|
||||
pseudoflavor);
|
||||
return mech;
|
||||
}
|
||||
|
||||
int
|
||||
gss_pseudoflavor_to_mechOID(u32 pseudoflavor, struct xdr_netobj * oid)
|
||||
{
|
||||
struct gss_api_mech *mech;
|
||||
|
||||
mech = gss_pseudoflavor_to_mech(pseudoflavor);
|
||||
if (!mech) {
|
||||
dprintk("RPC: gss_pseudoflavor_to_mechOID called with unsupported pseudoflavor %d\n",
|
||||
pseudoflavor);
|
||||
return -1;
|
||||
}
|
||||
oid->len = mech->gm_oid.len;
|
||||
if (!(oid->data = kmalloc(oid->len, GFP_KERNEL)))
|
||||
return -1;
|
||||
memcpy(oid->data, mech->gm_oid.data, oid->len);
|
||||
gss_mech_put(mech);
|
||||
return 0;
|
||||
}
|
||||
296
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_spkm3_mech.c
Normal file
296
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_spkm3_mech.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_spkm3_mech.c
|
||||
*
|
||||
* Copyright (c) 2003 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
* J. Bruce Fields <bfields@umich.edu>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sunrpc/auth.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/sunrpc/svcauth_gss.h>
|
||||
#include <linux/sunrpc/gss_spkm3.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
struct xdr_netobj gss_mech_spkm3_oid =
|
||||
{7, "\053\006\001\005\005\001\003"};
|
||||
|
||||
static inline int
|
||||
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
|
||||
get_netobj(char **ptr, const char *end, struct xdr_netobj *res)
|
||||
{
|
||||
char *p, *q;
|
||||
p = *ptr;
|
||||
if (get_bytes(&p, end, &res->len, sizeof(res->len)))
|
||||
return -1;
|
||||
q = p + res->len;
|
||||
if(res->len == 0)
|
||||
goto out_nocopy;
|
||||
if (q > end || q < p)
|
||||
return -1;
|
||||
if (!(res->data = kmalloc(res->len, GFP_KERNEL)))
|
||||
return -1;
|
||||
memcpy(res->data, p, res->len);
|
||||
out_nocopy:
|
||||
*ptr = q;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
get_key(char **p, char *end, struct crypto_tfm **res, int *resalg)
|
||||
{
|
||||
struct xdr_netobj key = {
|
||||
.len = 0,
|
||||
.data = NULL,
|
||||
};
|
||||
int alg_mode,setkey = 0;
|
||||
char *alg_name;
|
||||
|
||||
if (get_bytes(p, end, resalg, sizeof(int)))
|
||||
goto out_err;
|
||||
if ((get_netobj(p, end, &key)))
|
||||
goto out_err;
|
||||
|
||||
switch (*resalg) {
|
||||
case NID_des_cbc:
|
||||
alg_name = "des";
|
||||
alg_mode = CRYPTO_TFM_MODE_CBC;
|
||||
setkey = 1;
|
||||
break;
|
||||
case NID_md5:
|
||||
if (key.len == 0) {
|
||||
dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n");
|
||||
}
|
||||
alg_name = "md5";
|
||||
alg_mode = 0;
|
||||
setkey = 0;
|
||||
break;
|
||||
case NID_cast5_cbc:
|
||||
dprintk("RPC: SPKM3 get_key: case cast5_cbc, UNSUPPORTED \n");
|
||||
goto out_err;
|
||||
break;
|
||||
default:
|
||||
dprintk("RPC: SPKM3 get_key: unsupported algorithm %d", *resalg);
|
||||
goto out_err_free_key;
|
||||
}
|
||||
if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
|
||||
goto out_err_free_key;
|
||||
if (setkey) {
|
||||
if (crypto_cipher_setkey(*res, key.data, key.len))
|
||||
goto out_err_free_tfm;
|
||||
}
|
||||
|
||||
if(key.len > 0)
|
||||
kfree(key.data);
|
||||
return 0;
|
||||
|
||||
out_err_free_tfm:
|
||||
crypto_free_tfm(*res);
|
||||
out_err_free_key:
|
||||
if(key.len > 0)
|
||||
kfree(key.data);
|
||||
out_err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static u32
|
||||
gss_import_sec_context_spkm3(struct xdr_netobj *inbuf,
|
||||
struct gss_ctx *ctx_id)
|
||||
{
|
||||
char *p = inbuf->data;
|
||||
char *end = inbuf->data + inbuf->len;
|
||||
struct spkm3_ctx *ctx;
|
||||
|
||||
if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
|
||||
goto out_err;
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
if (get_netobj(&p, end, &ctx->ctx_id))
|
||||
goto out_err_free_ctx;
|
||||
|
||||
if (get_bytes(&p, end, &ctx->qop, sizeof(ctx->qop)))
|
||||
goto out_err_free_ctx_id;
|
||||
|
||||
if (get_netobj(&p, end, &ctx->mech_used))
|
||||
goto out_err_free_mech;
|
||||
|
||||
if (get_bytes(&p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)))
|
||||
goto out_err_free_mech;
|
||||
|
||||
if (get_bytes(&p, end, &ctx->req_flags, sizeof(ctx->req_flags)))
|
||||
goto out_err_free_mech;
|
||||
|
||||
if (get_netobj(&p, end, &ctx->share_key))
|
||||
goto out_err_free_s_key;
|
||||
|
||||
if (get_key(&p, end, &ctx->derived_conf_key, &ctx->conf_alg)) {
|
||||
dprintk("RPC: SPKM3 confidentiality key will be NULL\n");
|
||||
}
|
||||
|
||||
if (get_key(&p, end, &ctx->derived_integ_key, &ctx->intg_alg)) {
|
||||
dprintk("RPC: SPKM3 integrity key will be NULL\n");
|
||||
}
|
||||
|
||||
if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
|
||||
goto out_err_free_s_key;
|
||||
|
||||
if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
|
||||
goto out_err_free_s_key;
|
||||
|
||||
if (p != end)
|
||||
goto out_err_free_s_key;
|
||||
|
||||
ctx_id->internal_ctx_id = ctx;
|
||||
|
||||
dprintk("Succesfully imported new spkm context.\n");
|
||||
return 0;
|
||||
|
||||
out_err_free_s_key:
|
||||
kfree(ctx->share_key.data);
|
||||
out_err_free_mech:
|
||||
kfree(ctx->mech_used.data);
|
||||
out_err_free_ctx_id:
|
||||
kfree(ctx->ctx_id.data);
|
||||
out_err_free_ctx:
|
||||
kfree(ctx);
|
||||
out_err:
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
void
|
||||
gss_delete_sec_context_spkm3(void *internal_ctx) {
|
||||
struct spkm3_ctx *sctx = internal_ctx;
|
||||
|
||||
if(sctx->derived_integ_key)
|
||||
crypto_free_tfm(sctx->derived_integ_key);
|
||||
if(sctx->derived_conf_key)
|
||||
crypto_free_tfm(sctx->derived_conf_key);
|
||||
if(sctx->share_key.data)
|
||||
kfree(sctx->share_key.data);
|
||||
if(sctx->mech_used.data)
|
||||
kfree(sctx->mech_used.data);
|
||||
kfree(sctx);
|
||||
}
|
||||
|
||||
u32
|
||||
gss_verify_mic_spkm3(struct gss_ctx *ctx,
|
||||
struct xdr_buf *signbuf,
|
||||
struct xdr_netobj *checksum,
|
||||
u32 *qstate) {
|
||||
u32 maj_stat = 0;
|
||||
int qop_state = 0;
|
||||
struct spkm3_ctx *sctx = ctx->internal_ctx_id;
|
||||
|
||||
dprintk("RPC: gss_verify_mic_spkm3 calling spkm3_read_token\n");
|
||||
maj_stat = spkm3_read_token(sctx, checksum, signbuf, &qop_state,
|
||||
SPKM_MIC_TOK);
|
||||
|
||||
if (!maj_stat && qop_state)
|
||||
*qstate = qop_state;
|
||||
|
||||
dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat);
|
||||
return maj_stat;
|
||||
}
|
||||
|
||||
u32
|
||||
gss_get_mic_spkm3(struct gss_ctx *ctx,
|
||||
u32 qop,
|
||||
struct xdr_buf *message_buffer,
|
||||
struct xdr_netobj *message_token) {
|
||||
u32 err = 0;
|
||||
struct spkm3_ctx *sctx = ctx->internal_ctx_id;
|
||||
|
||||
dprintk("RPC: gss_get_mic_spkm3\n");
|
||||
|
||||
err = spkm3_make_token(sctx, qop, message_buffer,
|
||||
message_token, SPKM_MIC_TOK);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct gss_api_ops gss_spkm3_ops = {
|
||||
.gss_import_sec_context = gss_import_sec_context_spkm3,
|
||||
.gss_get_mic = gss_get_mic_spkm3,
|
||||
.gss_verify_mic = gss_verify_mic_spkm3,
|
||||
.gss_delete_sec_context = gss_delete_sec_context_spkm3,
|
||||
};
|
||||
|
||||
static struct pf_desc gss_spkm3_pfs[] = {
|
||||
{RPC_AUTH_GSS_SPKM, 0, RPC_GSS_SVC_NONE, "spkm3"},
|
||||
{RPC_AUTH_GSS_SPKMI, 0, RPC_GSS_SVC_INTEGRITY, "spkm3i"},
|
||||
};
|
||||
|
||||
static struct gss_api_mech gss_spkm3_mech = {
|
||||
.gm_name = "spkm3",
|
||||
.gm_owner = THIS_MODULE,
|
||||
.gm_ops = &gss_spkm3_ops,
|
||||
.gm_pf_num = ARRAY_SIZE(gss_spkm3_pfs),
|
||||
.gm_pfs = gss_spkm3_pfs,
|
||||
};
|
||||
|
||||
static int __init init_spkm3_module(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = gss_mech_register(&gss_spkm3_mech);
|
||||
if (status)
|
||||
printk("Failed to register spkm3 gss mechanism!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cleanup_spkm3_module(void)
|
||||
{
|
||||
gss_mech_unregister(&gss_spkm3_mech);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(init_spkm3_module);
|
||||
module_exit(cleanup_spkm3_module);
|
||||
132
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_spkm3_seal.c
Normal file
132
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_spkm3_seal.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_spkm3_seal.c
|
||||
*
|
||||
* Copyright (c) 2003 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sunrpc/gss_spkm3.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
/*
|
||||
* spkm3_make_token()
|
||||
*
|
||||
* Only SPKM_MIC_TOK with md5 intg-alg is supported
|
||||
*/
|
||||
|
||||
u32
|
||||
spkm3_make_token(struct spkm3_ctx *ctx, int qop_req,
|
||||
struct xdr_buf * text, struct xdr_netobj * token,
|
||||
int toktype)
|
||||
{
|
||||
s32 checksum_type;
|
||||
char tokhdrbuf[25];
|
||||
struct xdr_netobj md5cksum = {.len = 0, .data = NULL};
|
||||
struct xdr_netobj mic_hdr = {.len = 0, .data = tokhdrbuf};
|
||||
int tmsglen, tokenlen = 0;
|
||||
unsigned char *ptr;
|
||||
s32 now;
|
||||
int ctxelen = 0, ctxzbit = 0;
|
||||
int md5elen = 0, md5zbit = 0;
|
||||
|
||||
dprintk("RPC: spkm3_make_token\n");
|
||||
|
||||
now = jiffies;
|
||||
if (qop_req != 0)
|
||||
goto out_err;
|
||||
|
||||
if (ctx->ctx_id.len != 16) {
|
||||
dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n",
|
||||
ctx->ctx_id.len);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
switch (ctx->intg_alg) {
|
||||
case NID_md5:
|
||||
checksum_type = CKSUMTYPE_RSA_MD5;
|
||||
break;
|
||||
default:
|
||||
dprintk("RPC: gss_spkm3_seal: ctx->signalg %d not"
|
||||
" supported\n", ctx->intg_alg);
|
||||
goto out_err;
|
||||
}
|
||||
/* XXX since we don't support WRAP, perhaps we don't care... */
|
||||
if (ctx->conf_alg != NID_cast5_cbc) {
|
||||
dprintk("RPC: gss_spkm3_seal: ctx->sealalg %d not supported\n",
|
||||
ctx->conf_alg);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (toktype == SPKM_MIC_TOK) {
|
||||
tmsglen = 0;
|
||||
/* Calculate checksum over the mic-header */
|
||||
asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit);
|
||||
spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data,
|
||||
ctxelen, ctxzbit);
|
||||
|
||||
if (make_checksum(checksum_type, mic_hdr.data, mic_hdr.len,
|
||||
text, &md5cksum))
|
||||
goto out_err;
|
||||
|
||||
asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
|
||||
tokenlen = 10 + ctxelen + 1 + 2 + md5elen + 1;
|
||||
|
||||
/* Create token header using generic routines */
|
||||
token->len = g_token_size(&ctx->mech_used, tokenlen + tmsglen);
|
||||
|
||||
ptr = token->data;
|
||||
g_make_token_header(&ctx->mech_used, tokenlen + tmsglen, &ptr);
|
||||
|
||||
spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
|
||||
} else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
|
||||
dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK not supported\n");
|
||||
goto out_err;
|
||||
}
|
||||
kfree(md5cksum.data);
|
||||
|
||||
/* XXX need to implement sequence numbers, and ctx->expired */
|
||||
|
||||
return GSS_S_COMPLETE;
|
||||
out_err:
|
||||
if (md5cksum.data)
|
||||
kfree(md5cksum.data);
|
||||
token->data = NULL;
|
||||
token->len = 0;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
266
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_spkm3_token.c
Normal file
266
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_spkm3_token.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_spkm3_token.c
|
||||
*
|
||||
* Copyright (c) 2003 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sunrpc/gss_spkm3.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
/*
|
||||
* asn1_bitstring_len()
|
||||
*
|
||||
* calculate the asn1 bitstring length of the xdr_netobject
|
||||
*/
|
||||
void
|
||||
asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
|
||||
{
|
||||
int i, zbit = 0,elen = in->len;
|
||||
char *ptr;
|
||||
|
||||
ptr = &in->data[in->len -1];
|
||||
|
||||
/* count trailing 0's */
|
||||
for(i = in->len; i > 0; i--) {
|
||||
if (*ptr == 0) {
|
||||
ptr--;
|
||||
elen--;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
/* count number of 0 bits in final octet */
|
||||
ptr = &in->data[elen - 1];
|
||||
for(i = 0; i < 8; i++) {
|
||||
short mask = 0x01;
|
||||
|
||||
if (!((mask << i) & *ptr))
|
||||
zbit++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
*enclen = elen;
|
||||
*zerobits = zbit;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_asn1_bitstring()
|
||||
*
|
||||
* decode a bitstring into a buffer of the expected length.
|
||||
* enclen = bit string length
|
||||
* explen = expected length (define in rfc)
|
||||
*/
|
||||
int
|
||||
decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
|
||||
{
|
||||
if (!(out->data = kmalloc(explen,GFP_KERNEL)))
|
||||
return 0;
|
||||
out->len = explen;
|
||||
memset(out->data, 0, explen);
|
||||
memcpy(out->data, in, enclen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SPKMInnerContextToken choice SPKM_MIC asn1 token layout
|
||||
*
|
||||
* contextid is always 16 bytes plain data. max asn1 bitstring len = 17.
|
||||
*
|
||||
* tokenlen = pos[0] to end of token (max pos[45] with MD5 cksum)
|
||||
*
|
||||
* pos value
|
||||
* ----------
|
||||
* [0] a4 SPKM-MIC tag
|
||||
* [1] ?? innertoken length (max 44)
|
||||
*
|
||||
*
|
||||
* tok_hdr piece of checksum data starts here
|
||||
*
|
||||
* the maximum mic-header len = 9 + 17 = 26
|
||||
* mic-header
|
||||
* ----------
|
||||
* [2] 30 SEQUENCE tag
|
||||
* [3] ?? mic-header length: (max 23) = TokenID + ContextID
|
||||
*
|
||||
* TokenID - all fields constant and can be hardcoded
|
||||
* -------
|
||||
* [4] 02 Type 2
|
||||
* [5] 02 Length 2
|
||||
* [6][7] 01 01 TokenID (SPKM_MIC_TOK)
|
||||
*
|
||||
* ContextID - encoded length not constant, calculated
|
||||
* ---------
|
||||
* [8] 03 Type 3
|
||||
* [9] ?? encoded length
|
||||
* [10] ?? ctxzbit
|
||||
* [11] contextid
|
||||
*
|
||||
* mic_header piece of checksum data ends here.
|
||||
*
|
||||
* int-cksum - encoded length not constant, calculated
|
||||
* ---------
|
||||
* [??] 03 Type 3
|
||||
* [??] ?? encoded length
|
||||
* [??] ?? md5zbit
|
||||
* [??] int-cksum (NID_md5 = 16)
|
||||
*
|
||||
* maximum SPKM-MIC innercontext token length =
|
||||
* 10 + encoded contextid_size(17 max) + 2 + encoded
|
||||
* cksum_size (17 maxfor NID_md5) = 46
|
||||
*/
|
||||
|
||||
/*
|
||||
* spkm3_mic_header()
|
||||
*
|
||||
* Prepare the SPKM_MIC_TOK mic-header for check-sum calculation
|
||||
* elen: 16 byte context id asn1 bitstring encoded length
|
||||
*/
|
||||
void
|
||||
spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ctxdata, int elen, int zbit)
|
||||
{
|
||||
char *hptr = *hdrbuf;
|
||||
char *top = *hdrbuf;
|
||||
|
||||
*(u8 *)hptr++ = 0x30;
|
||||
*(u8 *)hptr++ = elen + 7; /* on the wire header length */
|
||||
|
||||
/* tokenid */
|
||||
*(u8 *)hptr++ = 0x02;
|
||||
*(u8 *)hptr++ = 0x02;
|
||||
*(u8 *)hptr++ = 0x01;
|
||||
*(u8 *)hptr++ = 0x01;
|
||||
|
||||
/* coniextid */
|
||||
*(u8 *)hptr++ = 0x03;
|
||||
*(u8 *)hptr++ = elen + 1; /* add 1 to include zbit */
|
||||
*(u8 *)hptr++ = zbit;
|
||||
memcpy(hptr, ctxdata, elen);
|
||||
hptr += elen;
|
||||
*hdrlen = hptr - top;
|
||||
}
|
||||
|
||||
/*
|
||||
* spkm3_mic_innercontext_token()
|
||||
*
|
||||
* *tokp points to the beginning of the SPKM_MIC token described
|
||||
* in rfc 2025, section 3.2.1:
|
||||
*
|
||||
*/
|
||||
void
|
||||
spkm3_make_mic_token(unsigned char **tokp, int toklen, struct xdr_netobj *mic_hdr, struct xdr_netobj *md5cksum, int md5elen, int md5zbit)
|
||||
{
|
||||
unsigned char *ict = *tokp;
|
||||
|
||||
*(u8 *)ict++ = 0xa4;
|
||||
*(u8 *)ict++ = toklen - 2;
|
||||
memcpy(ict, mic_hdr->data, mic_hdr->len);
|
||||
ict += mic_hdr->len;
|
||||
|
||||
*(u8 *)ict++ = 0x03;
|
||||
*(u8 *)ict++ = md5elen + 1; /* add 1 to include zbit */
|
||||
*(u8 *)ict++ = md5zbit;
|
||||
memcpy(ict, md5cksum->data, md5elen);
|
||||
}
|
||||
|
||||
u32
|
||||
spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **cksum)
|
||||
{
|
||||
struct xdr_netobj spkm3_ctx_id = {.len =0, .data = NULL};
|
||||
unsigned char *ptr = *tokp;
|
||||
int ctxelen;
|
||||
u32 ret = GSS_S_DEFECTIVE_TOKEN;
|
||||
|
||||
/* spkm3 innercontext token preamble */
|
||||
if ((ptr[0] != 0xa4) || (ptr[2] != 0x30)) {
|
||||
dprintk("RPC: BAD SPKM ictoken preamble\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*mic_hdrlen = ptr[3];
|
||||
|
||||
/* token type */
|
||||
if ((ptr[4] != 0x02) || (ptr[5] != 0x02)) {
|
||||
dprintk("RPC: BAD asn1 SPKM3 token type\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* only support SPKM_MIC_TOK */
|
||||
if((ptr[6] != 0x01) || (ptr[7] != 0x01)) {
|
||||
dprintk("RPC: ERROR unsupported SPKM3 token \n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* contextid */
|
||||
if (ptr[8] != 0x03) {
|
||||
dprintk("RPC: BAD SPKM3 asn1 context-id type\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctxelen = ptr[9];
|
||||
if (ctxelen > 17) { /* length includes asn1 zbit octet */
|
||||
dprintk("RPC: BAD SPKM3 contextid len %d\n", ctxelen);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* ignore ptr[10] */
|
||||
|
||||
if(!decode_asn1_bitstring(&spkm3_ctx_id, &ptr[11], ctxelen - 1, 16))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* in the current implementation: the optional int-alg is not present
|
||||
* so the default int-alg (md5) is used the optional snd-seq field is
|
||||
* also not present
|
||||
*/
|
||||
|
||||
if (*mic_hdrlen != 6 + ctxelen) {
|
||||
dprintk("RPC: BAD SPKM_ MIC_TOK header len %d: we only support default int-alg (should be absent) and do not support snd-seq\n", *mic_hdrlen);
|
||||
goto out;
|
||||
}
|
||||
/* checksum */
|
||||
*cksum = (&ptr[10] + ctxelen); /* ctxelen includes ptr[10] */
|
||||
|
||||
ret = GSS_S_COMPLETE;
|
||||
out:
|
||||
if (spkm3_ctx_id.data)
|
||||
kfree(spkm3_ctx_id.data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
128
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_spkm3_unseal.c
Normal file
128
extra/linux-2.6.10/net/sunrpc/auth_gss/gss_spkm3_unseal.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* linux/net/sunrpc/gss_spkm3_unseal.c
|
||||
*
|
||||
* Copyright (c) 2003 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sunrpc/gss_spkm3.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
/*
|
||||
* spkm3_read_token()
|
||||
*
|
||||
* only SPKM_MIC_TOK with md5 intg-alg is supported
|
||||
*/
|
||||
u32
|
||||
spkm3_read_token(struct spkm3_ctx *ctx,
|
||||
struct xdr_netobj *read_token, /* checksum */
|
||||
struct xdr_buf *message_buffer, /* signbuf */
|
||||
int *qop_state, int toktype)
|
||||
{
|
||||
s32 code;
|
||||
struct xdr_netobj wire_cksum = {.len =0, .data = NULL};
|
||||
struct xdr_netobj md5cksum = {.len = 0, .data = NULL};
|
||||
unsigned char *ptr = (unsigned char *)read_token->data;
|
||||
unsigned char *cksum;
|
||||
int bodysize, md5elen;
|
||||
int mic_hdrlen;
|
||||
u32 ret = GSS_S_DEFECTIVE_TOKEN;
|
||||
|
||||
dprintk("RPC: spkm3_read_token read_token->len %d\n", read_token->len);
|
||||
|
||||
if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
|
||||
&bodysize, &ptr, read_token->len))
|
||||
goto out;
|
||||
|
||||
/* decode the token */
|
||||
|
||||
if (toktype == SPKM_MIC_TOK) {
|
||||
|
||||
if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum)))
|
||||
goto out;
|
||||
|
||||
if (*cksum++ != 0x03) {
|
||||
dprintk("RPC: spkm3_read_token BAD checksum type\n");
|
||||
goto out;
|
||||
}
|
||||
md5elen = *cksum++;
|
||||
cksum++; /* move past the zbit */
|
||||
|
||||
if(!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
|
||||
goto out;
|
||||
|
||||
/* HARD CODED FOR MD5 */
|
||||
|
||||
/* compute the checksum of the message.
|
||||
* ptr + 2 = start of header piece of checksum
|
||||
* mic_hdrlen + 2 = length of header piece of checksum
|
||||
*/
|
||||
ret = GSS_S_DEFECTIVE_TOKEN;
|
||||
code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2,
|
||||
mic_hdrlen + 2,
|
||||
message_buffer, &md5cksum);
|
||||
|
||||
if (code)
|
||||
goto out;
|
||||
|
||||
dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n",
|
||||
wire_cksum.len);
|
||||
dprintk(" md5cksum.data\n");
|
||||
print_hexl((u32 *) md5cksum.data, 16, 0);
|
||||
dprintk(" cksum.data:\n");
|
||||
print_hexl((u32 *) wire_cksum.data, wire_cksum.len, 0);
|
||||
|
||||
ret = GSS_S_BAD_SIG;
|
||||
code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
|
||||
if (code)
|
||||
goto out;
|
||||
|
||||
} else {
|
||||
dprintk("RPC: BAD or UNSUPPORTED SPKM3 token type: %d\n",toktype);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX: need to add expiration and sequencing */
|
||||
ret = GSS_S_COMPLETE;
|
||||
out:
|
||||
if (md5cksum.data)
|
||||
kfree(md5cksum.data);
|
||||
if (wire_cksum.data)
|
||||
kfree(wire_cksum.data);
|
||||
return ret;
|
||||
}
|
||||
37
extra/linux-2.6.10/net/sunrpc/auth_gss/sunrpcgss_syms.c
Normal file
37
extra/linux-2.6.10/net/sunrpc/auth_gss/sunrpcgss_syms.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/unistd.h>
|
||||
|
||||
#include <linux/sunrpc/auth_gss.h>
|
||||
#include <linux/sunrpc/svcauth_gss.h>
|
||||
#include <linux/sunrpc/gss_asn1.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
|
||||
/* svcauth_gss.c: */
|
||||
EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor);
|
||||
|
||||
/* registering gss mechanisms to the mech switching code: */
|
||||
EXPORT_SYMBOL(gss_mech_register);
|
||||
EXPORT_SYMBOL(gss_mech_unregister);
|
||||
EXPORT_SYMBOL(gss_mech_get);
|
||||
EXPORT_SYMBOL(gss_mech_get_by_pseudoflavor);
|
||||
EXPORT_SYMBOL(gss_mech_get_by_name);
|
||||
EXPORT_SYMBOL(gss_mech_put);
|
||||
EXPORT_SYMBOL(gss_pseudoflavor_to_service);
|
||||
EXPORT_SYMBOL(gss_service_to_auth_domain_name);
|
||||
|
||||
/* generic functionality in gss code: */
|
||||
EXPORT_SYMBOL(g_make_token_header);
|
||||
EXPORT_SYMBOL(g_verify_token_header);
|
||||
EXPORT_SYMBOL(g_token_size);
|
||||
EXPORT_SYMBOL(make_checksum);
|
||||
EXPORT_SYMBOL(krb5_encrypt);
|
||||
EXPORT_SYMBOL(krb5_decrypt);
|
||||
|
||||
/* debug */
|
||||
EXPORT_SYMBOL(print_hexl);
|
||||
1074
extra/linux-2.6.10/net/sunrpc/auth_gss/svcauth_gss.c
Normal file
1074
extra/linux-2.6.10/net/sunrpc/auth_gss/svcauth_gss.c
Normal file
File diff suppressed because it is too large
Load Diff
145
extra/linux-2.6.10/net/sunrpc/auth_null.c
Normal file
145
extra/linux-2.6.10/net/sunrpc/auth_null.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* linux/net/sunrpc/auth_null.c
|
||||
*
|
||||
* AUTH_NULL authentication. Really :-)
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
static struct rpc_credops null_credops;
|
||||
|
||||
static struct rpc_auth *
|
||||
nul_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
|
||||
{
|
||||
struct rpc_auth *auth;
|
||||
|
||||
dprintk("RPC: creating NULL authenticator for client %p\n", clnt);
|
||||
if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth),GFP_KERNEL)))
|
||||
return NULL;
|
||||
auth->au_cslack = 4;
|
||||
auth->au_rslack = 2;
|
||||
auth->au_ops = &authnull_ops;
|
||||
auth->au_expire = 1800 * HZ;
|
||||
rpcauth_init_credcache(auth);
|
||||
|
||||
return (struct rpc_auth *) auth;
|
||||
}
|
||||
|
||||
static void
|
||||
nul_destroy(struct rpc_auth *auth)
|
||||
{
|
||||
dprintk("RPC: destroying NULL authenticator %p\n", auth);
|
||||
rpcauth_free_credcache(auth);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create NULL creds for current process
|
||||
*/
|
||||
static struct rpc_cred *
|
||||
nul_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
|
||||
{
|
||||
struct rpc_cred *cred;
|
||||
|
||||
if (!(cred = (struct rpc_cred *) kmalloc(sizeof(*cred),GFP_KERNEL)))
|
||||
return NULL;
|
||||
atomic_set(&cred->cr_count, 0);
|
||||
cred->cr_flags = RPCAUTH_CRED_UPTODATE;
|
||||
cred->cr_uid = acred->uid;
|
||||
cred->cr_ops = &null_credops;
|
||||
|
||||
return cred;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy cred handle.
|
||||
*/
|
||||
static void
|
||||
nul_destroy_cred(struct rpc_cred *cred)
|
||||
{
|
||||
kfree(cred);
|
||||
}
|
||||
|
||||
/*
|
||||
* Match cred handle against current process
|
||||
*/
|
||||
static int
|
||||
nul_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Marshal credential.
|
||||
*/
|
||||
static u32 *
|
||||
nul_marshal(struct rpc_task *task, u32 *p, int ruid)
|
||||
{
|
||||
*p++ = htonl(RPC_AUTH_NULL);
|
||||
*p++ = 0;
|
||||
*p++ = htonl(RPC_AUTH_NULL);
|
||||
*p++ = 0;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Refresh credential. This is a no-op for AUTH_NULL
|
||||
*/
|
||||
static int
|
||||
nul_refresh(struct rpc_task *task)
|
||||
{
|
||||
return task->tk_status = -EACCES;
|
||||
}
|
||||
|
||||
static u32 *
|
||||
nul_validate(struct rpc_task *task, u32 *p)
|
||||
{
|
||||
rpc_authflavor_t flavor;
|
||||
u32 size;
|
||||
|
||||
flavor = ntohl(*p++);
|
||||
if (flavor != RPC_AUTH_NULL) {
|
||||
printk("RPC: bad verf flavor: %u\n", flavor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = ntohl(*p++);
|
||||
if (size != 0) {
|
||||
printk("RPC: bad verf size: %u\n", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
struct rpc_authops authnull_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.au_flavor = RPC_AUTH_NULL,
|
||||
#ifdef RPC_DEBUG
|
||||
.au_name = "NULL",
|
||||
#endif
|
||||
.create = nul_create,
|
||||
.destroy = nul_destroy,
|
||||
.crcreate = nul_create_cred,
|
||||
};
|
||||
|
||||
static
|
||||
struct rpc_credops null_credops = {
|
||||
.crdestroy = nul_destroy_cred,
|
||||
.crmatch = nul_match,
|
||||
.crmarshal = nul_marshal,
|
||||
.crrefresh = nul_refresh,
|
||||
.crvalidate = nul_validate,
|
||||
};
|
||||
236
extra/linux-2.6.10/net/sunrpc/auth_unix.c
Normal file
236
extra/linux-2.6.10/net/sunrpc/auth_unix.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* linux/net/sunrpc/auth_unix.c
|
||||
*
|
||||
* UNIX-style authentication; no AUTH_SHORT support
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/auth.h>
|
||||
|
||||
#define NFS_NGROUPS 16
|
||||
|
||||
struct unx_cred {
|
||||
struct rpc_cred uc_base;
|
||||
gid_t uc_gid;
|
||||
uid_t uc_puid; /* process uid */
|
||||
gid_t uc_pgid; /* process gid */
|
||||
gid_t uc_gids[NFS_NGROUPS];
|
||||
};
|
||||
#define uc_uid uc_base.cr_uid
|
||||
#define uc_count uc_base.cr_count
|
||||
#define uc_flags uc_base.cr_flags
|
||||
#define uc_expire uc_base.cr_expire
|
||||
|
||||
#define UNX_CRED_EXPIRE (60 * HZ)
|
||||
|
||||
#define UNX_WRITESLACK (21 + (UNX_MAXNODENAME >> 2))
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
static struct rpc_credops unix_credops;
|
||||
|
||||
static struct rpc_auth *
|
||||
unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
|
||||
{
|
||||
struct rpc_auth *auth;
|
||||
|
||||
dprintk("RPC: creating UNIX authenticator for client %p\n", clnt);
|
||||
if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth), GFP_KERNEL)))
|
||||
return NULL;
|
||||
auth->au_cslack = UNX_WRITESLACK;
|
||||
auth->au_rslack = 2; /* assume AUTH_NULL verf */
|
||||
auth->au_expire = UNX_CRED_EXPIRE;
|
||||
auth->au_ops = &authunix_ops;
|
||||
|
||||
rpcauth_init_credcache(auth);
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
static void
|
||||
unx_destroy(struct rpc_auth *auth)
|
||||
{
|
||||
dprintk("RPC: destroying UNIX authenticator %p\n", auth);
|
||||
rpcauth_free_credcache(auth);
|
||||
}
|
||||
|
||||
static struct rpc_cred *
|
||||
unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
|
||||
{
|
||||
struct unx_cred *cred;
|
||||
int i;
|
||||
|
||||
dprintk("RPC: allocating UNIX cred for uid %d gid %d\n",
|
||||
acred->uid, acred->gid);
|
||||
|
||||
if (!(cred = (struct unx_cred *) kmalloc(sizeof(*cred), GFP_KERNEL)))
|
||||
return NULL;
|
||||
|
||||
atomic_set(&cred->uc_count, 0);
|
||||
cred->uc_flags = RPCAUTH_CRED_UPTODATE;
|
||||
if (flags & RPC_TASK_ROOTCREDS) {
|
||||
cred->uc_uid = cred->uc_puid = 0;
|
||||
cred->uc_gid = cred->uc_pgid = 0;
|
||||
cred->uc_gids[0] = NOGROUP;
|
||||
} else {
|
||||
int groups = acred->group_info->ngroups;
|
||||
if (groups > NFS_NGROUPS)
|
||||
groups = NFS_NGROUPS;
|
||||
|
||||
cred->uc_uid = acred->uid;
|
||||
cred->uc_gid = acred->gid;
|
||||
cred->uc_puid = current->uid;
|
||||
cred->uc_pgid = current->gid;
|
||||
for (i = 0; i < groups; i++)
|
||||
cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
|
||||
if (i < NFS_NGROUPS)
|
||||
cred->uc_gids[i] = NOGROUP;
|
||||
}
|
||||
cred->uc_base.cr_ops = &unix_credops;
|
||||
|
||||
return (struct rpc_cred *) cred;
|
||||
}
|
||||
|
||||
static void
|
||||
unx_destroy_cred(struct rpc_cred *cred)
|
||||
{
|
||||
kfree(cred);
|
||||
}
|
||||
|
||||
/*
|
||||
* Match credentials against current process creds.
|
||||
* The root_override argument takes care of cases where the caller may
|
||||
* request root creds (e.g. for NFS swapping).
|
||||
*/
|
||||
static int
|
||||
unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
|
||||
{
|
||||
struct unx_cred *cred = (struct unx_cred *) rcred;
|
||||
int i;
|
||||
|
||||
if (!(taskflags & RPC_TASK_ROOTCREDS)) {
|
||||
int groups;
|
||||
|
||||
if (cred->uc_uid != acred->uid
|
||||
|| cred->uc_gid != acred->gid
|
||||
|| cred->uc_puid != current->uid
|
||||
|| cred->uc_pgid != current->gid)
|
||||
return 0;
|
||||
|
||||
groups = acred->group_info->ngroups;
|
||||
if (groups > NFS_NGROUPS)
|
||||
groups = NFS_NGROUPS;
|
||||
for (i = 0; i < groups ; i++)
|
||||
if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
return (cred->uc_uid == 0 && cred->uc_puid == 0
|
||||
&& cred->uc_gid == 0 && cred->uc_pgid == 0
|
||||
&& cred->uc_gids[0] == (gid_t) NOGROUP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Marshal credentials.
|
||||
* Maybe we should keep a cached credential for performance reasons.
|
||||
*/
|
||||
static u32 *
|
||||
unx_marshal(struct rpc_task *task, u32 *p, int ruid)
|
||||
{
|
||||
struct rpc_clnt *clnt = task->tk_client;
|
||||
struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred;
|
||||
u32 *base, *hold;
|
||||
int i;
|
||||
|
||||
*p++ = htonl(RPC_AUTH_UNIX);
|
||||
base = p++;
|
||||
*p++ = htonl(jiffies/HZ);
|
||||
|
||||
/*
|
||||
* Copy the UTS nodename captured when the client was created.
|
||||
*/
|
||||
p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
|
||||
|
||||
/* Note: we don't use real uid if it involves raising privilege */
|
||||
if (ruid && cred->uc_puid != 0 && cred->uc_pgid != 0) {
|
||||
*p++ = htonl((u32) cred->uc_puid);
|
||||
*p++ = htonl((u32) cred->uc_pgid);
|
||||
} else {
|
||||
*p++ = htonl((u32) cred->uc_uid);
|
||||
*p++ = htonl((u32) cred->uc_gid);
|
||||
}
|
||||
hold = p++;
|
||||
for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
|
||||
*p++ = htonl((u32) cred->uc_gids[i]);
|
||||
*hold = htonl(p - hold - 1); /* gid array length */
|
||||
*base = htonl((p - base - 1) << 2); /* cred length */
|
||||
|
||||
*p++ = htonl(RPC_AUTH_NULL);
|
||||
*p++ = htonl(0);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Refresh credentials. This is a no-op for AUTH_UNIX
|
||||
*/
|
||||
static int
|
||||
unx_refresh(struct rpc_task *task)
|
||||
{
|
||||
task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
|
||||
return task->tk_status = -EACCES;
|
||||
}
|
||||
|
||||
static u32 *
|
||||
unx_validate(struct rpc_task *task, u32 *p)
|
||||
{
|
||||
rpc_authflavor_t flavor;
|
||||
u32 size;
|
||||
|
||||
flavor = ntohl(*p++);
|
||||
if (flavor != RPC_AUTH_NULL &&
|
||||
flavor != RPC_AUTH_UNIX &&
|
||||
flavor != RPC_AUTH_SHORT) {
|
||||
printk("RPC: bad verf flavor: %u\n", flavor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = ntohl(*p++);
|
||||
if (size > RPC_MAX_AUTH_SIZE) {
|
||||
printk("RPC: giant verf size: %u\n", size);
|
||||
return NULL;
|
||||
}
|
||||
task->tk_auth->au_rslack = (size >> 2) + 2;
|
||||
p += (size >> 2);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
struct rpc_authops authunix_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.au_flavor = RPC_AUTH_UNIX,
|
||||
#ifdef RPC_DEBUG
|
||||
.au_name = "UNIX",
|
||||
#endif
|
||||
.create = unx_create,
|
||||
.destroy = unx_destroy,
|
||||
.crcreate = unx_create_cred,
|
||||
};
|
||||
|
||||
static
|
||||
struct rpc_credops unix_credops = {
|
||||
.crdestroy = unx_destroy_cred,
|
||||
.crmatch = unx_match,
|
||||
.crmarshal = unx_marshal,
|
||||
.crrefresh = unx_refresh,
|
||||
.crvalidate = unx_validate,
|
||||
};
|
||||
1214
extra/linux-2.6.10/net/sunrpc/cache.c
Normal file
1214
extra/linux-2.6.10/net/sunrpc/cache.c
Normal file
File diff suppressed because it is too large
Load Diff
1075
extra/linux-2.6.10/net/sunrpc/clnt.c
Normal file
1075
extra/linux-2.6.10/net/sunrpc/clnt.c
Normal file
File diff suppressed because it is too large
Load Diff
301
extra/linux-2.6.10/net/sunrpc/pmap_clnt.c
Normal file
301
extra/linux-2.6.10/net/sunrpc/pmap_clnt.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* linux/net/sunrpc/pmap.c
|
||||
*
|
||||
* Portmapper client.
|
||||
*
|
||||
* FIXME: In a secure environment, we may want to use an authentication
|
||||
* flavor other than AUTH_NULL.
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
# define RPCDBG_FACILITY RPCDBG_PMAP
|
||||
#endif
|
||||
|
||||
#define PMAP_SET 1
|
||||
#define PMAP_UNSET 2
|
||||
#define PMAP_GETPORT 3
|
||||
|
||||
static struct rpc_procinfo pmap_procedures[];
|
||||
static struct rpc_clnt * pmap_create(char *, struct sockaddr_in *, int);
|
||||
static void pmap_getport_done(struct rpc_task *);
|
||||
extern struct rpc_program pmap_program;
|
||||
static spinlock_t pmap_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
/*
|
||||
* Obtain the port for a given RPC service on a given host. This one can
|
||||
* be called for an ongoing RPC request.
|
||||
*/
|
||||
void
|
||||
rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
|
||||
{
|
||||
struct rpc_portmap *map = clnt->cl_pmap;
|
||||
struct sockaddr_in *sap = &clnt->cl_xprt->addr;
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &pmap_procedures[PMAP_GETPORT],
|
||||
.rpc_argp = map,
|
||||
.rpc_resp = &clnt->cl_port,
|
||||
.rpc_cred = NULL
|
||||
};
|
||||
struct rpc_clnt *pmap_clnt;
|
||||
struct rpc_task *child;
|
||||
|
||||
dprintk("RPC: %4d rpc_getport(%s, %d, %d, %d)\n",
|
||||
task->tk_pid, clnt->cl_server,
|
||||
map->pm_prog, map->pm_vers, map->pm_prot);
|
||||
|
||||
spin_lock(&pmap_lock);
|
||||
if (map->pm_binding) {
|
||||
rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL);
|
||||
spin_unlock(&pmap_lock);
|
||||
return;
|
||||
}
|
||||
map->pm_binding = 1;
|
||||
spin_unlock(&pmap_lock);
|
||||
|
||||
pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot);
|
||||
if (IS_ERR(pmap_clnt)) {
|
||||
task->tk_status = PTR_ERR(pmap_clnt);
|
||||
goto bailout;
|
||||
}
|
||||
task->tk_status = 0;
|
||||
|
||||
/*
|
||||
* Note: rpc_new_child will release client after a failure.
|
||||
*/
|
||||
if (!(child = rpc_new_child(pmap_clnt, task)))
|
||||
goto bailout;
|
||||
|
||||
/* Setup the call info struct */
|
||||
rpc_call_setup(child, &msg, 0);
|
||||
|
||||
/* ... and run the child task */
|
||||
rpc_run_child(task, child, pmap_getport_done);
|
||||
return;
|
||||
|
||||
bailout:
|
||||
spin_lock(&pmap_lock);
|
||||
map->pm_binding = 0;
|
||||
rpc_wake_up(&map->pm_bindwait);
|
||||
spin_unlock(&pmap_lock);
|
||||
task->tk_status = -EIO;
|
||||
task->tk_action = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ROOT_NFS
|
||||
int
|
||||
rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
|
||||
{
|
||||
struct rpc_portmap map = {
|
||||
.pm_prog = prog,
|
||||
.pm_vers = vers,
|
||||
.pm_prot = prot,
|
||||
.pm_port = 0
|
||||
};
|
||||
struct rpc_clnt *pmap_clnt;
|
||||
char hostname[32];
|
||||
int status;
|
||||
|
||||
dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %d, %d, %d)\n",
|
||||
NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
|
||||
|
||||
sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
|
||||
pmap_clnt = pmap_create(hostname, sin, prot);
|
||||
if (IS_ERR(pmap_clnt))
|
||||
return PTR_ERR(pmap_clnt);
|
||||
|
||||
/* Setup the call info struct */
|
||||
status = rpc_call(pmap_clnt, PMAP_GETPORT, &map, &map.pm_port, 0);
|
||||
|
||||
if (status >= 0) {
|
||||
if (map.pm_port != 0)
|
||||
return map.pm_port;
|
||||
status = -EACCES;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
pmap_getport_done(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_clnt *clnt = task->tk_client;
|
||||
struct rpc_portmap *map = clnt->cl_pmap;
|
||||
|
||||
dprintk("RPC: %4d pmap_getport_done(status %d, port %d)\n",
|
||||
task->tk_pid, task->tk_status, clnt->cl_port);
|
||||
if (task->tk_status < 0) {
|
||||
/* Make the calling task exit with an error */
|
||||
task->tk_action = NULL;
|
||||
} else if (clnt->cl_port == 0) {
|
||||
/* Program not registered */
|
||||
task->tk_status = -EACCES;
|
||||
task->tk_action = NULL;
|
||||
} else {
|
||||
/* byte-swap port number first */
|
||||
clnt->cl_port = htons(clnt->cl_port);
|
||||
clnt->cl_xprt->addr.sin_port = clnt->cl_port;
|
||||
}
|
||||
spin_lock(&pmap_lock);
|
||||
map->pm_binding = 0;
|
||||
rpc_wake_up(&map->pm_bindwait);
|
||||
spin_unlock(&pmap_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set or unset a port registration with the local portmapper.
|
||||
* port == 0 means unregister, port != 0 means register.
|
||||
*/
|
||||
int
|
||||
rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
struct rpc_portmap map;
|
||||
struct rpc_clnt *pmap_clnt;
|
||||
int error = 0;
|
||||
|
||||
dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.\n",
|
||||
prog, vers, prot, port);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP);
|
||||
if (IS_ERR(pmap_clnt)) {
|
||||
error = PTR_ERR(pmap_clnt);
|
||||
dprintk("RPC: couldn't create pmap client. Error = %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
map.pm_prog = prog;
|
||||
map.pm_vers = vers;
|
||||
map.pm_prot = prot;
|
||||
map.pm_port = port;
|
||||
|
||||
error = rpc_call(pmap_clnt, port? PMAP_SET : PMAP_UNSET,
|
||||
&map, okay, 0);
|
||||
|
||||
if (error < 0) {
|
||||
printk(KERN_WARNING
|
||||
"RPC: failed to contact portmap (errno %d).\n",
|
||||
error);
|
||||
}
|
||||
dprintk("RPC: registration status %d/%d\n", error, *okay);
|
||||
|
||||
/* Client deleted automatically because cl_oneshot == 1 */
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct rpc_clnt *
|
||||
pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto)
|
||||
{
|
||||
struct rpc_xprt *xprt;
|
||||
struct rpc_clnt *clnt;
|
||||
|
||||
/* printk("pmap: create xprt\n"); */
|
||||
xprt = xprt_create_proto(proto, srvaddr, NULL);
|
||||
if (IS_ERR(xprt))
|
||||
return (struct rpc_clnt *)xprt;
|
||||
xprt->addr.sin_port = htons(RPC_PMAP_PORT);
|
||||
|
||||
/* printk("pmap: create clnt\n"); */
|
||||
clnt = rpc_create_client(xprt, hostname,
|
||||
&pmap_program, RPC_PMAP_VERSION,
|
||||
RPC_AUTH_NULL);
|
||||
if (IS_ERR(clnt)) {
|
||||
xprt_destroy(xprt);
|
||||
} else {
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_chatty = 1;
|
||||
clnt->cl_oneshot = 1;
|
||||
}
|
||||
return clnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* XDR encode/decode functions for PMAP
|
||||
*/
|
||||
static int
|
||||
xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct rpc_portmap *map)
|
||||
{
|
||||
dprintk("RPC: xdr_encode_mapping(%d, %d, %d, %d)\n",
|
||||
map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port);
|
||||
*p++ = htonl(map->pm_prog);
|
||||
*p++ = htonl(map->pm_vers);
|
||||
*p++ = htonl(map->pm_prot);
|
||||
*p++ = htonl(map->pm_port);
|
||||
|
||||
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp)
|
||||
{
|
||||
*portp = (unsigned short) ntohl(*p++);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp)
|
||||
{
|
||||
*boolp = (unsigned int) ntohl(*p++);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rpc_procinfo pmap_procedures[] = {
|
||||
[PMAP_SET] = {
|
||||
.p_proc = PMAP_SET,
|
||||
.p_encode = (kxdrproc_t) xdr_encode_mapping,
|
||||
.p_decode = (kxdrproc_t) xdr_decode_bool,
|
||||
.p_bufsiz = 4,
|
||||
.p_count = 1,
|
||||
},
|
||||
[PMAP_UNSET] = {
|
||||
.p_proc = PMAP_UNSET,
|
||||
.p_encode = (kxdrproc_t) xdr_encode_mapping,
|
||||
.p_decode = (kxdrproc_t) xdr_decode_bool,
|
||||
.p_bufsiz = 4,
|
||||
.p_count = 1,
|
||||
},
|
||||
[PMAP_GETPORT] = {
|
||||
.p_proc = PMAP_GETPORT,
|
||||
.p_encode = (kxdrproc_t) xdr_encode_mapping,
|
||||
.p_decode = (kxdrproc_t) xdr_decode_port,
|
||||
.p_bufsiz = 4,
|
||||
.p_count = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct rpc_version pmap_version2 = {
|
||||
.number = 2,
|
||||
.nrprocs = 4,
|
||||
.procs = pmap_procedures
|
||||
};
|
||||
|
||||
static struct rpc_version * pmap_version[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
&pmap_version2
|
||||
};
|
||||
|
||||
static struct rpc_stat pmap_stats;
|
||||
|
||||
struct rpc_program pmap_program = {
|
||||
.name = "portmap",
|
||||
.number = RPC_PMAP_PROGRAM,
|
||||
.nrvers = ARRAY_SIZE(pmap_version),
|
||||
.version = pmap_version,
|
||||
.stats = &pmap_stats,
|
||||
};
|
||||
842
extra/linux-2.6.10/net/sunrpc/rpc_pipe.c
Normal file
842
extra/linux-2.6.10/net/sunrpc/rpc_pipe.c
Normal file
@@ -0,0 +1,842 @@
|
||||
/*
|
||||
* net/sunrpc/rpc_pipe.c
|
||||
*
|
||||
* Userland/kernel interface for rpcauth_gss.
|
||||
* Code shamelessly plagiarized from fs/nfsd/nfsctl.c
|
||||
* and fs/driverfs/inode.c
|
||||
*
|
||||
* Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no>
|
||||
*
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <asm/ioctls.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||
|
||||
static struct vfsmount *rpc_mount;
|
||||
static int rpc_mount_count;
|
||||
|
||||
static struct file_system_type rpc_pipe_fs_type;
|
||||
|
||||
|
||||
static kmem_cache_t *rpc_inode_cachep;
|
||||
|
||||
#define RPC_UPCALL_TIMEOUT (30*HZ)
|
||||
|
||||
static void
|
||||
__rpc_purge_upcall(struct inode *inode, int err)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
struct rpc_pipe_msg *msg;
|
||||
|
||||
while (!list_empty(&rpci->pipe)) {
|
||||
msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, list);
|
||||
list_del_init(&msg->list);
|
||||
msg->errno = err;
|
||||
rpci->ops->destroy_msg(msg);
|
||||
}
|
||||
while (!list_empty(&rpci->in_upcall)) {
|
||||
msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, list);
|
||||
list_del_init(&msg->list);
|
||||
msg->errno = err;
|
||||
rpci->ops->destroy_msg(msg);
|
||||
}
|
||||
rpci->pipelen = 0;
|
||||
wake_up(&rpci->waitq);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_timeout_upcall_queue(void *data)
|
||||
{
|
||||
struct rpc_inode *rpci = (struct rpc_inode *)data;
|
||||
struct inode *inode = &rpci->vfs_inode;
|
||||
|
||||
down(&inode->i_sem);
|
||||
if (rpci->nreaders == 0 && !list_empty(&rpci->pipe))
|
||||
__rpc_purge_upcall(inode, -ETIMEDOUT);
|
||||
up(&inode->i_sem);
|
||||
}
|
||||
|
||||
int
|
||||
rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
int res = 0;
|
||||
|
||||
down(&inode->i_sem);
|
||||
if (rpci->nreaders) {
|
||||
list_add_tail(&msg->list, &rpci->pipe);
|
||||
rpci->pipelen += msg->len;
|
||||
} else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) {
|
||||
if (list_empty(&rpci->pipe))
|
||||
schedule_delayed_work(&rpci->queue_timeout,
|
||||
RPC_UPCALL_TIMEOUT);
|
||||
list_add_tail(&msg->list, &rpci->pipe);
|
||||
rpci->pipelen += msg->len;
|
||||
} else
|
||||
res = -EPIPE;
|
||||
up(&inode->i_sem);
|
||||
wake_up(&rpci->waitq);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_close_pipes(struct inode *inode)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
|
||||
cancel_delayed_work(&rpci->queue_timeout);
|
||||
flush_scheduled_work();
|
||||
down(&inode->i_sem);
|
||||
if (rpci->ops != NULL) {
|
||||
rpci->nreaders = 0;
|
||||
__rpc_purge_upcall(inode, -EPIPE);
|
||||
rpci->nwriters = 0;
|
||||
if (rpci->ops->release_pipe)
|
||||
rpci->ops->release_pipe(inode);
|
||||
rpci->ops = NULL;
|
||||
}
|
||||
up(&inode->i_sem);
|
||||
}
|
||||
|
||||
static inline void
|
||||
rpc_inode_setowner(struct inode *inode, void *private)
|
||||
{
|
||||
RPC_I(inode)->private = private;
|
||||
}
|
||||
|
||||
static struct inode *
|
||||
rpc_alloc_inode(struct super_block *sb)
|
||||
{
|
||||
struct rpc_inode *rpci;
|
||||
rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, SLAB_KERNEL);
|
||||
if (!rpci)
|
||||
return NULL;
|
||||
return &rpci->vfs_inode;
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_destroy_inode(struct inode *inode)
|
||||
{
|
||||
kmem_cache_free(rpc_inode_cachep, RPC_I(inode));
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_pipe_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
int res = -ENXIO;
|
||||
|
||||
down(&inode->i_sem);
|
||||
if (rpci->ops != NULL) {
|
||||
if (filp->f_mode & FMODE_READ)
|
||||
rpci->nreaders ++;
|
||||
if (filp->f_mode & FMODE_WRITE)
|
||||
rpci->nwriters ++;
|
||||
res = 0;
|
||||
}
|
||||
up(&inode->i_sem);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_pipe_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
|
||||
struct rpc_pipe_msg *msg;
|
||||
|
||||
down(&inode->i_sem);
|
||||
if (rpci->ops == NULL)
|
||||
goto out;
|
||||
msg = (struct rpc_pipe_msg *)filp->private_data;
|
||||
if (msg != NULL) {
|
||||
msg->errno = -EPIPE;
|
||||
list_del_init(&msg->list);
|
||||
rpci->ops->destroy_msg(msg);
|
||||
}
|
||||
if (filp->f_mode & FMODE_WRITE)
|
||||
rpci->nwriters --;
|
||||
if (filp->f_mode & FMODE_READ)
|
||||
rpci->nreaders --;
|
||||
if (!rpci->nreaders)
|
||||
__rpc_purge_upcall(inode, -EPIPE);
|
||||
if (rpci->ops->release_pipe)
|
||||
rpci->ops->release_pipe(inode);
|
||||
out:
|
||||
up(&inode->i_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
|
||||
{
|
||||
struct inode *inode = filp->f_dentry->d_inode;
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
struct rpc_pipe_msg *msg;
|
||||
int res = 0;
|
||||
|
||||
down(&inode->i_sem);
|
||||
if (rpci->ops == NULL) {
|
||||
res = -EPIPE;
|
||||
goto out_unlock;
|
||||
}
|
||||
msg = filp->private_data;
|
||||
if (msg == NULL) {
|
||||
if (!list_empty(&rpci->pipe)) {
|
||||
msg = list_entry(rpci->pipe.next,
|
||||
struct rpc_pipe_msg,
|
||||
list);
|
||||
list_move(&msg->list, &rpci->in_upcall);
|
||||
rpci->pipelen -= msg->len;
|
||||
filp->private_data = msg;
|
||||
msg->copied = 0;
|
||||
}
|
||||
if (msg == NULL)
|
||||
goto out_unlock;
|
||||
}
|
||||
/* NOTE: it is up to the callback to update msg->copied */
|
||||
res = rpci->ops->upcall(filp, msg, buf, len);
|
||||
if (res < 0 || msg->len == msg->copied) {
|
||||
filp->private_data = NULL;
|
||||
list_del_init(&msg->list);
|
||||
rpci->ops->destroy_msg(msg);
|
||||
}
|
||||
out_unlock:
|
||||
up(&inode->i_sem);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
|
||||
{
|
||||
struct inode *inode = filp->f_dentry->d_inode;
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
int res;
|
||||
|
||||
down(&inode->i_sem);
|
||||
res = -EPIPE;
|
||||
if (rpci->ops != NULL)
|
||||
res = rpci->ops->downcall(filp, buf, len);
|
||||
up(&inode->i_sem);
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait)
|
||||
{
|
||||
struct rpc_inode *rpci;
|
||||
unsigned int mask = 0;
|
||||
|
||||
rpci = RPC_I(filp->f_dentry->d_inode);
|
||||
poll_wait(filp, &rpci->waitq, wait);
|
||||
|
||||
mask = POLLOUT | POLLWRNORM;
|
||||
if (rpci->ops == NULL)
|
||||
mask |= POLLERR | POLLHUP;
|
||||
if (!list_empty(&rpci->pipe))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_pipe_ioctl(struct inode *ino, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
|
||||
int len;
|
||||
|
||||
switch (cmd) {
|
||||
case FIONREAD:
|
||||
if (rpci->ops == NULL)
|
||||
return -EPIPE;
|
||||
len = rpci->pipelen;
|
||||
if (filp->private_data) {
|
||||
struct rpc_pipe_msg *msg;
|
||||
msg = (struct rpc_pipe_msg *)filp->private_data;
|
||||
len += msg->len - msg->copied;
|
||||
}
|
||||
return put_user(len, (int __user *)arg);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
struct inode_operations rpc_pipe_iops = {
|
||||
.lookup = simple_lookup,
|
||||
};
|
||||
|
||||
|
||||
struct file_operations rpc_pipe_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = rpc_pipe_read,
|
||||
.write = rpc_pipe_write,
|
||||
.poll = rpc_pipe_poll,
|
||||
.ioctl = rpc_pipe_ioctl,
|
||||
.open = rpc_pipe_open,
|
||||
.release = rpc_pipe_release,
|
||||
};
|
||||
|
||||
static int
|
||||
rpc_show_info(struct seq_file *m, void *v)
|
||||
{
|
||||
struct rpc_clnt *clnt = m->private;
|
||||
|
||||
seq_printf(m, "RPC server: %s\n", clnt->cl_server);
|
||||
seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname,
|
||||
clnt->cl_prog, clnt->cl_vers);
|
||||
seq_printf(m, "address: %u.%u.%u.%u\n",
|
||||
NIPQUAD(clnt->cl_xprt->addr.sin_addr.s_addr));
|
||||
seq_printf(m, "protocol: %s\n",
|
||||
clnt->cl_xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_info_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct rpc_clnt *clnt;
|
||||
int ret = single_open(file, rpc_show_info, NULL);
|
||||
|
||||
if (!ret) {
|
||||
struct seq_file *m = file->private_data;
|
||||
down(&inode->i_sem);
|
||||
clnt = RPC_I(inode)->private;
|
||||
if (clnt) {
|
||||
atomic_inc(&clnt->cl_users);
|
||||
m->private = clnt;
|
||||
} else {
|
||||
single_release(inode, file);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
up(&inode->i_sem);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_info_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *m = file->private_data;
|
||||
struct rpc_clnt *clnt = (struct rpc_clnt *)m->private;
|
||||
|
||||
if (clnt)
|
||||
rpc_release_client(clnt);
|
||||
return single_release(inode, file);
|
||||
}
|
||||
|
||||
static struct file_operations rpc_info_operations = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = rpc_info_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = rpc_info_release,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* We have a single directory with 1 node in it.
|
||||
*/
|
||||
enum {
|
||||
RPCAUTH_Root = 1,
|
||||
RPCAUTH_lockd,
|
||||
RPCAUTH_mount,
|
||||
RPCAUTH_nfs,
|
||||
RPCAUTH_portmap,
|
||||
RPCAUTH_statd,
|
||||
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",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_mount] = {
|
||||
.name = "mount",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_nfs] = {
|
||||
.name = "nfs",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_portmap] = {
|
||||
.name = "portmap",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_statd] = {
|
||||
.name = "statd",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
};
|
||||
|
||||
enum {
|
||||
RPCAUTH_info = 2,
|
||||
RPCAUTH_EOF
|
||||
};
|
||||
|
||||
static struct rpc_filelist authfiles[] = {
|
||||
[RPCAUTH_info] = {
|
||||
.name = "info",
|
||||
.i_fop = &rpc_info_operations,
|
||||
.mode = S_IFREG | S_IRUSR,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
rpc_get_mount(void)
|
||||
{
|
||||
return simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_put_mount(void)
|
||||
{
|
||||
simple_release_fs(&rpc_mount, &rpc_mount_count);
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_lookup_parent(char *path, struct nameidata *nd)
|
||||
{
|
||||
if (path[0] == '\0')
|
||||
return -ENOENT;
|
||||
if (rpc_get_mount()) {
|
||||
printk(KERN_WARNING "%s: %s failed to mount "
|
||||
"pseudofilesystem \n", __FILE__, __FUNCTION__);
|
||||
return -ENODEV;
|
||||
}
|
||||
nd->mnt = mntget(rpc_mount);
|
||||
nd->dentry = dget(rpc_mount->mnt_root);
|
||||
nd->last_type = LAST_ROOT;
|
||||
nd->flags = LOOKUP_PARENT;
|
||||
nd->depth = 0;
|
||||
|
||||
if (path_walk(path, nd)) {
|
||||
printk(KERN_WARNING "%s: %s failed to find path %s\n",
|
||||
__FILE__, __FUNCTION__, path);
|
||||
rpc_put_mount();
|
||||
return -ENOENT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_release_path(struct nameidata *nd)
|
||||
{
|
||||
path_release(nd);
|
||||
rpc_put_mount();
|
||||
}
|
||||
|
||||
static struct inode *
|
||||
rpc_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_blksize = PAGE_CACHE_SIZE;
|
||||
inode->i_blocks = 0;
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||
switch(mode & S_IFMT) {
|
||||
case S_IFDIR:
|
||||
inode->i_fop = &simple_dir_operations;
|
||||
inode->i_op = &simple_dir_inode_operations;
|
||||
inode->i_nlink++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return inode;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: This probably has races.
|
||||
*/
|
||||
static void
|
||||
rpc_depopulate(struct dentry *parent)
|
||||
{
|
||||
struct inode *dir = parent->d_inode;
|
||||
struct list_head *pos, *next;
|
||||
struct dentry *dentry, *dvec[10];
|
||||
int n = 0;
|
||||
|
||||
down(&dir->i_sem);
|
||||
repeat:
|
||||
spin_lock(&dcache_lock);
|
||||
list_for_each_safe(pos, next, &parent->d_subdirs) {
|
||||
dentry = list_entry(pos, struct dentry, d_child);
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (!d_unhashed(dentry)) {
|
||||
dget_locked(dentry);
|
||||
__d_drop(dentry);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
dvec[n++] = dentry;
|
||||
if (n == ARRAY_SIZE(dvec))
|
||||
break;
|
||||
} else
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
if (n) {
|
||||
do {
|
||||
dentry = dvec[--n];
|
||||
if (dentry->d_inode) {
|
||||
rpc_close_pipes(dentry->d_inode);
|
||||
rpc_inode_setowner(dentry->d_inode, NULL);
|
||||
simple_unlink(dir, dentry);
|
||||
}
|
||||
dput(dentry);
|
||||
} while (n);
|
||||
goto repeat;
|
||||
}
|
||||
up(&dir->i_sem);
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_populate(struct dentry *parent,
|
||||
struct rpc_filelist *files,
|
||||
int start, int eof)
|
||||
{
|
||||
struct inode *inode, *dir = parent->d_inode;
|
||||
void *private = RPC_I(dir)->private;
|
||||
struct dentry *dentry;
|
||||
int mode, i;
|
||||
|
||||
down(&dir->i_sem);
|
||||
for (i = start; i < eof; i++) {
|
||||
dentry = d_alloc_name(parent, files[i].name);
|
||||
if (!dentry)
|
||||
goto out_bad;
|
||||
mode = files[i].mode;
|
||||
inode = rpc_get_inode(dir->i_sb, mode);
|
||||
if (!inode) {
|
||||
dput(dentry);
|
||||
goto out_bad;
|
||||
}
|
||||
inode->i_ino = i;
|
||||
if (files[i].i_fop)
|
||||
inode->i_fop = files[i].i_fop;
|
||||
if (private)
|
||||
rpc_inode_setowner(inode, private);
|
||||
if (S_ISDIR(mode))
|
||||
dir->i_nlink++;
|
||||
d_add(dentry, inode);
|
||||
}
|
||||
up(&dir->i_sem);
|
||||
return 0;
|
||||
out_bad:
|
||||
up(&dir->i_sem);
|
||||
printk(KERN_WARNING "%s: %s failed to populate directory %s\n",
|
||||
__FILE__, __FUNCTION__, parent->d_name.name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int
|
||||
__rpc_mkdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUSR | S_IXUSR);
|
||||
if (!inode)
|
||||
goto out_err;
|
||||
inode->i_ino = iunique(dir->i_sb, 100);
|
||||
d_instantiate(dentry, inode);
|
||||
dir->i_nlink++;
|
||||
inode_dir_notify(dir, DN_CREATE);
|
||||
rpc_get_mount();
|
||||
return 0;
|
||||
out_err:
|
||||
printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
|
||||
__FILE__, __FUNCTION__, dentry->d_name.name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int
|
||||
__rpc_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int error;
|
||||
|
||||
shrink_dcache_parent(dentry);
|
||||
if (dentry->d_inode) {
|
||||
rpc_close_pipes(dentry->d_inode);
|
||||
rpc_inode_setowner(dentry->d_inode, NULL);
|
||||
}
|
||||
if ((error = simple_rmdir(dir, dentry)) != 0)
|
||||
return error;
|
||||
if (!error) {
|
||||
inode_dir_notify(dir, DN_DELETE);
|
||||
d_drop(dentry);
|
||||
rpc_put_mount();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dentry *
|
||||
rpc_lookup_negative(char *path, struct nameidata *nd)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct inode *dir;
|
||||
int error;
|
||||
|
||||
if ((error = rpc_lookup_parent(path, nd)) != 0)
|
||||
return ERR_PTR(error);
|
||||
dir = nd->dentry->d_inode;
|
||||
down(&dir->i_sem);
|
||||
dentry = lookup_hash(&nd->last, nd->dentry);
|
||||
if (IS_ERR(dentry))
|
||||
goto out_err;
|
||||
if (dentry->d_inode) {
|
||||
dput(dentry);
|
||||
dentry = ERR_PTR(-EEXIST);
|
||||
goto out_err;
|
||||
}
|
||||
return dentry;
|
||||
out_err:
|
||||
up(&dir->i_sem);
|
||||
rpc_release_path(nd);
|
||||
return dentry;
|
||||
}
|
||||
|
||||
|
||||
struct dentry *
|
||||
rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct dentry *dentry;
|
||||
struct inode *dir;
|
||||
int error;
|
||||
|
||||
dentry = rpc_lookup_negative(path, &nd);
|
||||
if (IS_ERR(dentry))
|
||||
return dentry;
|
||||
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);
|
||||
if (error)
|
||||
goto err_depopulate;
|
||||
out:
|
||||
up(&dir->i_sem);
|
||||
rpc_release_path(&nd);
|
||||
return dentry;
|
||||
err_depopulate:
|
||||
rpc_depopulate(dentry);
|
||||
__rpc_rmdir(dir, dentry);
|
||||
err_dput:
|
||||
dput(dentry);
|
||||
printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n",
|
||||
__FILE__, __FUNCTION__, path, error);
|
||||
dentry = ERR_PTR(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
int
|
||||
rpc_rmdir(char *path)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct dentry *dentry;
|
||||
struct inode *dir;
|
||||
int error;
|
||||
|
||||
if ((error = rpc_lookup_parent(path, &nd)) != 0)
|
||||
return error;
|
||||
dir = nd.dentry->d_inode;
|
||||
down(&dir->i_sem);
|
||||
dentry = lookup_hash(&nd.last, nd.dentry);
|
||||
if (IS_ERR(dentry)) {
|
||||
error = PTR_ERR(dentry);
|
||||
goto out_release;
|
||||
}
|
||||
rpc_depopulate(dentry);
|
||||
error = __rpc_rmdir(dir, dentry);
|
||||
dput(dentry);
|
||||
out_release:
|
||||
up(&dir->i_sem);
|
||||
rpc_release_path(&nd);
|
||||
return error;
|
||||
}
|
||||
|
||||
struct dentry *
|
||||
rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct dentry *dentry;
|
||||
struct inode *dir, *inode;
|
||||
struct rpc_inode *rpci;
|
||||
|
||||
dentry = rpc_lookup_negative(path, &nd);
|
||||
if (IS_ERR(dentry))
|
||||
return dentry;
|
||||
dir = nd.dentry->d_inode;
|
||||
inode = rpc_get_inode(dir->i_sb, S_IFSOCK | S_IRUSR | S_IWUSR);
|
||||
if (!inode)
|
||||
goto err_dput;
|
||||
inode->i_ino = iunique(dir->i_sb, 100);
|
||||
inode->i_fop = &rpc_pipe_fops;
|
||||
d_instantiate(dentry, inode);
|
||||
rpci = RPC_I(inode);
|
||||
rpci->private = private;
|
||||
rpci->flags = flags;
|
||||
rpci->ops = ops;
|
||||
inode_dir_notify(dir, DN_CREATE);
|
||||
out:
|
||||
up(&dir->i_sem);
|
||||
rpc_release_path(&nd);
|
||||
return dentry;
|
||||
err_dput:
|
||||
dput(dentry);
|
||||
dentry = ERR_PTR(-ENOMEM);
|
||||
printk(KERN_WARNING "%s: %s() failed to create pipe %s (errno = %d)\n",
|
||||
__FILE__, __FUNCTION__, path, -ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
int
|
||||
rpc_unlink(char *path)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct dentry *dentry;
|
||||
struct inode *dir;
|
||||
int error;
|
||||
|
||||
if ((error = rpc_lookup_parent(path, &nd)) != 0)
|
||||
return error;
|
||||
dir = nd.dentry->d_inode;
|
||||
down(&dir->i_sem);
|
||||
dentry = lookup_hash(&nd.last, nd.dentry);
|
||||
if (IS_ERR(dentry)) {
|
||||
error = PTR_ERR(dentry);
|
||||
goto out_release;
|
||||
}
|
||||
d_drop(dentry);
|
||||
if (dentry->d_inode) {
|
||||
rpc_close_pipes(dentry->d_inode);
|
||||
rpc_inode_setowner(dentry->d_inode, NULL);
|
||||
error = simple_unlink(dir, dentry);
|
||||
}
|
||||
dput(dentry);
|
||||
inode_dir_notify(dir, DN_DELETE);
|
||||
out_release:
|
||||
up(&dir->i_sem);
|
||||
rpc_release_path(&nd);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* populate the filesystem
|
||||
*/
|
||||
static struct super_operations s_ops = {
|
||||
.alloc_inode = rpc_alloc_inode,
|
||||
.destroy_inode = rpc_destroy_inode,
|
||||
.statfs = simple_statfs,
|
||||
};
|
||||
|
||||
#define RPCAUTH_GSSMAGIC 0x67596969
|
||||
|
||||
static int
|
||||
rpc_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 = RPCAUTH_GSSMAGIC;
|
||||
sb->s_op = &s_ops;
|
||||
|
||||
inode = rpc_get_inode(sb, S_IFDIR | 0755);
|
||||
if (!inode)
|
||||
return -ENOMEM;
|
||||
root = d_alloc_root(inode);
|
||||
if (!root) {
|
||||
iput(inode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF))
|
||||
goto out;
|
||||
sb->s_root = root;
|
||||
return 0;
|
||||
out:
|
||||
d_genocide(root);
|
||||
dput(root);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct super_block *
|
||||
rpc_get_sb(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data)
|
||||
{
|
||||
return get_sb_single(fs_type, flags, data, rpc_fill_super);
|
||||
}
|
||||
|
||||
static struct file_system_type rpc_pipe_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "rpc_pipefs",
|
||||
.get_sb = rpc_get_sb,
|
||||
.kill_sb = kill_litter_super,
|
||||
};
|
||||
|
||||
static void
|
||||
init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
|
||||
{
|
||||
struct rpc_inode *rpci = (struct rpc_inode *) foo;
|
||||
|
||||
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
|
||||
SLAB_CTOR_CONSTRUCTOR) {
|
||||
inode_init_once(&rpci->vfs_inode);
|
||||
rpci->private = NULL;
|
||||
rpci->nreaders = 0;
|
||||
rpci->nwriters = 0;
|
||||
INIT_LIST_HEAD(&rpci->in_upcall);
|
||||
INIT_LIST_HEAD(&rpci->pipe);
|
||||
rpci->pipelen = 0;
|
||||
init_waitqueue_head(&rpci->waitq);
|
||||
INIT_WORK(&rpci->queue_timeout, rpc_timeout_upcall_queue, rpci);
|
||||
rpci->ops = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int register_rpc_pipefs(void)
|
||||
{
|
||||
rpc_inode_cachep = kmem_cache_create("rpc_inode_cache",
|
||||
sizeof(struct rpc_inode),
|
||||
0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
|
||||
init_once, NULL);
|
||||
if (!rpc_inode_cachep)
|
||||
return -ENOMEM;
|
||||
register_filesystem(&rpc_pipe_fs_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unregister_rpc_pipefs(void)
|
||||
{
|
||||
if (kmem_cache_destroy(rpc_inode_cachep))
|
||||
printk(KERN_WARNING "RPC: unable to free inode cache\n");
|
||||
unregister_filesystem(&rpc_pipe_fs_type);
|
||||
}
|
||||
1319
extra/linux-2.6.10/net/sunrpc/sched.c
Normal file
1319
extra/linux-2.6.10/net/sunrpc/sched.c
Normal file
File diff suppressed because it is too large
Load Diff
175
extra/linux-2.6.10/net/sunrpc/stats.c
Normal file
175
extra/linux-2.6.10/net/sunrpc/stats.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* linux/net/sunrpc/stats.c
|
||||
*
|
||||
* procfs-based user access to generic RPC statistics. The stats files
|
||||
* reside in /proc/net/rpc.
|
||||
*
|
||||
* The read routines assume that the buffer passed in is just big enough.
|
||||
* If you implement an RPC service that has its own stats routine which
|
||||
* appends the generic RPC stats, make sure you don't exceed the PAGE_SIZE
|
||||
* limit.
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_MISC
|
||||
|
||||
struct proc_dir_entry *proc_net_rpc = NULL;
|
||||
|
||||
/*
|
||||
* Get RPC client stats
|
||||
*/
|
||||
static int rpc_proc_show(struct seq_file *seq, void *v) {
|
||||
const struct rpc_stat *statp = seq->private;
|
||||
const struct rpc_program *prog = statp->program;
|
||||
int i, j;
|
||||
|
||||
seq_printf(seq,
|
||||
"net %d %d %d %d\n",
|
||||
statp->netcnt,
|
||||
statp->netudpcnt,
|
||||
statp->nettcpcnt,
|
||||
statp->nettcpconn);
|
||||
seq_printf(seq,
|
||||
"rpc %d %d %d\n",
|
||||
statp->rpccnt,
|
||||
statp->rpcretrans,
|
||||
statp->rpcauthrefresh);
|
||||
|
||||
for (i = 0; i < prog->nrvers; i++) {
|
||||
const struct rpc_version *vers = prog->version[i];
|
||||
if (!vers)
|
||||
continue;
|
||||
seq_printf(seq, "proc%d %d",
|
||||
vers->number, vers->nrprocs);
|
||||
for (j = 0; j < vers->nrprocs; j++)
|
||||
seq_printf(seq, " %d",
|
||||
vers->procs[j].p_count);
|
||||
seq_putc(seq, '\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpc_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, rpc_proc_show, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static struct file_operations rpc_proc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = rpc_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* Get RPC server stats
|
||||
*/
|
||||
void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
|
||||
const struct svc_program *prog = statp->program;
|
||||
const struct svc_procedure *proc;
|
||||
const struct svc_version *vers;
|
||||
int i, j;
|
||||
|
||||
seq_printf(seq,
|
||||
"net %d %d %d %d\n",
|
||||
statp->netcnt,
|
||||
statp->netudpcnt,
|
||||
statp->nettcpcnt,
|
||||
statp->nettcpconn);
|
||||
seq_printf(seq,
|
||||
"rpc %d %d %d %d %d\n",
|
||||
statp->rpccnt,
|
||||
statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
|
||||
statp->rpcbadfmt,
|
||||
statp->rpcbadauth,
|
||||
statp->rpcbadclnt);
|
||||
|
||||
for (i = 0; i < prog->pg_nvers; i++) {
|
||||
if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
|
||||
continue;
|
||||
seq_printf(seq, "proc%d %d", i, vers->vs_nproc);
|
||||
for (j = 0; j < vers->vs_nproc; j++, proc++)
|
||||
seq_printf(seq, " %d", proc->pc_count);
|
||||
seq_putc(seq, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Register/unregister RPC proc files
|
||||
*/
|
||||
static inline struct proc_dir_entry *
|
||||
do_register(const char *name, void *data, struct file_operations *fops)
|
||||
{
|
||||
struct proc_dir_entry *ent;
|
||||
|
||||
rpc_proc_init();
|
||||
dprintk("RPC: registering /proc/net/rpc/%s\n", name);
|
||||
|
||||
ent = create_proc_entry(name, 0, proc_net_rpc);
|
||||
if (ent) {
|
||||
ent->proc_fops = fops;
|
||||
ent->data = data;
|
||||
}
|
||||
return ent;
|
||||
}
|
||||
|
||||
struct proc_dir_entry *
|
||||
rpc_proc_register(struct rpc_stat *statp)
|
||||
{
|
||||
return do_register(statp->program->name, statp, &rpc_proc_fops);
|
||||
}
|
||||
|
||||
void
|
||||
rpc_proc_unregister(const char *name)
|
||||
{
|
||||
remove_proc_entry(name, proc_net_rpc);
|
||||
}
|
||||
|
||||
struct proc_dir_entry *
|
||||
svc_proc_register(struct svc_stat *statp, struct file_operations *fops)
|
||||
{
|
||||
return do_register(statp->program->pg_name, statp, fops);
|
||||
}
|
||||
|
||||
void
|
||||
svc_proc_unregister(const char *name)
|
||||
{
|
||||
remove_proc_entry(name, proc_net_rpc);
|
||||
}
|
||||
|
||||
void
|
||||
rpc_proc_init(void)
|
||||
{
|
||||
dprintk("RPC: registering /proc/net/rpc\n");
|
||||
if (!proc_net_rpc) {
|
||||
struct proc_dir_entry *ent;
|
||||
ent = proc_mkdir("rpc", proc_net);
|
||||
if (ent) {
|
||||
ent->owner = THIS_MODULE;
|
||||
proc_net_rpc = ent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rpc_proc_exit(void)
|
||||
{
|
||||
dprintk("RPC: unregistering /proc/net/rpc\n");
|
||||
if (proc_net_rpc) {
|
||||
proc_net_rpc = NULL;
|
||||
remove_proc_entry("net/rpc", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
185
extra/linux-2.6.10/net/sunrpc/sunrpc_syms.c
Normal file
185
extra/linux-2.6.10/net/sunrpc/sunrpc_syms.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* linux/net/sunrpc/sunrpc_syms.c
|
||||
*
|
||||
* Symbols exported by the sunrpc module.
|
||||
*
|
||||
* Copyright (C) 1997 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/sunrpc/auth.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||
|
||||
|
||||
/* RPC scheduler */
|
||||
EXPORT_SYMBOL(rpc_execute);
|
||||
EXPORT_SYMBOL(rpc_init_task);
|
||||
EXPORT_SYMBOL(rpc_sleep_on);
|
||||
EXPORT_SYMBOL(rpc_wake_up_next);
|
||||
EXPORT_SYMBOL(rpc_wake_up_task);
|
||||
EXPORT_SYMBOL(rpc_new_child);
|
||||
EXPORT_SYMBOL(rpc_run_child);
|
||||
EXPORT_SYMBOL(rpciod_down);
|
||||
EXPORT_SYMBOL(rpciod_up);
|
||||
EXPORT_SYMBOL(rpc_new_task);
|
||||
EXPORT_SYMBOL(rpc_wake_up_status);
|
||||
EXPORT_SYMBOL(rpc_release_task);
|
||||
|
||||
/* RPC client functions */
|
||||
EXPORT_SYMBOL(rpc_create_client);
|
||||
EXPORT_SYMBOL(rpc_clone_client);
|
||||
EXPORT_SYMBOL(rpc_destroy_client);
|
||||
EXPORT_SYMBOL(rpc_shutdown_client);
|
||||
EXPORT_SYMBOL(rpc_release_client);
|
||||
EXPORT_SYMBOL(rpc_killall_tasks);
|
||||
EXPORT_SYMBOL(rpc_call_sync);
|
||||
EXPORT_SYMBOL(rpc_call_async);
|
||||
EXPORT_SYMBOL(rpc_call_setup);
|
||||
EXPORT_SYMBOL(rpc_clnt_sigmask);
|
||||
EXPORT_SYMBOL(rpc_clnt_sigunmask);
|
||||
EXPORT_SYMBOL(rpc_delay);
|
||||
EXPORT_SYMBOL(rpc_restart_call);
|
||||
EXPORT_SYMBOL(rpc_setbufsize);
|
||||
EXPORT_SYMBOL(rpc_unlink);
|
||||
EXPORT_SYMBOL(rpc_wake_up);
|
||||
EXPORT_SYMBOL(rpc_queue_upcall);
|
||||
EXPORT_SYMBOL(rpc_mkpipe);
|
||||
|
||||
/* Client transport */
|
||||
EXPORT_SYMBOL(xprt_create_proto);
|
||||
EXPORT_SYMBOL(xprt_destroy);
|
||||
EXPORT_SYMBOL(xprt_set_timeout);
|
||||
EXPORT_SYMBOL(xprt_udp_slot_table_entries);
|
||||
EXPORT_SYMBOL(xprt_tcp_slot_table_entries);
|
||||
|
||||
/* Client credential cache */
|
||||
EXPORT_SYMBOL(rpcauth_register);
|
||||
EXPORT_SYMBOL(rpcauth_unregister);
|
||||
EXPORT_SYMBOL(rpcauth_create);
|
||||
EXPORT_SYMBOL(rpcauth_lookupcred);
|
||||
EXPORT_SYMBOL(rpcauth_lookup_credcache);
|
||||
EXPORT_SYMBOL(rpcauth_free_credcache);
|
||||
EXPORT_SYMBOL(rpcauth_init_credcache);
|
||||
EXPORT_SYMBOL(put_rpccred);
|
||||
|
||||
/* RPC server stuff */
|
||||
EXPORT_SYMBOL(svc_create);
|
||||
EXPORT_SYMBOL(svc_create_thread);
|
||||
EXPORT_SYMBOL(svc_exit_thread);
|
||||
EXPORT_SYMBOL(svc_destroy);
|
||||
EXPORT_SYMBOL(svc_drop);
|
||||
EXPORT_SYMBOL(svc_process);
|
||||
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);
|
||||
EXPORT_SYMBOL(svc_authenticate);
|
||||
|
||||
/* RPC statistics */
|
||||
#ifdef CONFIG_PROC_FS
|
||||
EXPORT_SYMBOL(rpc_proc_register);
|
||||
EXPORT_SYMBOL(rpc_proc_unregister);
|
||||
EXPORT_SYMBOL(svc_proc_register);
|
||||
EXPORT_SYMBOL(svc_proc_unregister);
|
||||
EXPORT_SYMBOL(svc_seq_show);
|
||||
#endif
|
||||
|
||||
/* caching... */
|
||||
EXPORT_SYMBOL(auth_domain_find);
|
||||
EXPORT_SYMBOL(auth_domain_put);
|
||||
EXPORT_SYMBOL(auth_unix_add_addr);
|
||||
EXPORT_SYMBOL(auth_unix_forget_old);
|
||||
EXPORT_SYMBOL(auth_unix_lookup);
|
||||
EXPORT_SYMBOL(cache_check);
|
||||
EXPORT_SYMBOL(cache_clean);
|
||||
EXPORT_SYMBOL(cache_flush);
|
||||
EXPORT_SYMBOL(cache_purge);
|
||||
EXPORT_SYMBOL(cache_fresh);
|
||||
EXPORT_SYMBOL(cache_init);
|
||||
EXPORT_SYMBOL(cache_register);
|
||||
EXPORT_SYMBOL(cache_unregister);
|
||||
EXPORT_SYMBOL(qword_add);
|
||||
EXPORT_SYMBOL(qword_addhex);
|
||||
EXPORT_SYMBOL(qword_get);
|
||||
EXPORT_SYMBOL(svcauth_unix_purge);
|
||||
EXPORT_SYMBOL(unix_domain_find);
|
||||
|
||||
/* Generic XDR */
|
||||
EXPORT_SYMBOL(xdr_encode_string);
|
||||
EXPORT_SYMBOL(xdr_decode_string);
|
||||
EXPORT_SYMBOL(xdr_decode_string_inplace);
|
||||
EXPORT_SYMBOL(xdr_decode_netobj);
|
||||
EXPORT_SYMBOL(xdr_encode_netobj);
|
||||
EXPORT_SYMBOL(xdr_encode_pages);
|
||||
EXPORT_SYMBOL(xdr_inline_pages);
|
||||
EXPORT_SYMBOL(xdr_shift_buf);
|
||||
EXPORT_SYMBOL(xdr_buf_from_iov);
|
||||
EXPORT_SYMBOL(xdr_buf_subsegment);
|
||||
EXPORT_SYMBOL(xdr_buf_read_netobj);
|
||||
EXPORT_SYMBOL(read_bytes_from_xdr_buf);
|
||||
|
||||
/* Debugging symbols */
|
||||
#ifdef RPC_DEBUG
|
||||
EXPORT_SYMBOL(rpc_debug);
|
||||
EXPORT_SYMBOL(nfs_debug);
|
||||
EXPORT_SYMBOL(nfsd_debug);
|
||||
EXPORT_SYMBOL(nlm_debug);
|
||||
#endif
|
||||
|
||||
extern int register_rpc_pipefs(void);
|
||||
extern void unregister_rpc_pipefs(void);
|
||||
|
||||
static int __init
|
||||
init_sunrpc(void)
|
||||
{
|
||||
int err = register_rpc_pipefs();
|
||||
if (err)
|
||||
goto out;
|
||||
err = rpc_init_mempool() != 0;
|
||||
if (err)
|
||||
goto out;
|
||||
#ifdef RPC_DEBUG
|
||||
rpc_register_sysctl();
|
||||
#endif
|
||||
#ifdef CONFIG_PROC_FS
|
||||
rpc_proc_init();
|
||||
#endif
|
||||
cache_register(&auth_domain_cache);
|
||||
cache_register(&ip_map_cache);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
cleanup_sunrpc(void)
|
||||
{
|
||||
unregister_rpc_pipefs();
|
||||
rpc_destroy_mempool();
|
||||
cache_unregister(&auth_domain_cache);
|
||||
cache_unregister(&ip_map_cache);
|
||||
#ifdef RPC_DEBUG
|
||||
rpc_unregister_sysctl();
|
||||
#endif
|
||||
#ifdef CONFIG_PROC_FS
|
||||
rpc_proc_exit();
|
||||
#endif
|
||||
}
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(init_sunrpc);
|
||||
module_exit(cleanup_sunrpc);
|
||||
483
extra/linux-2.6.10/net/sunrpc/svc.c
Normal file
483
extra/linux-2.6.10/net/sunrpc/svc.c
Normal file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* linux/net/sunrpc/svc.c
|
||||
*
|
||||
* High-level RPC service routines
|
||||
*
|
||||
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/sunrpc/types.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_SVCDSP
|
||||
#define RPC_PARANOIA 1
|
||||
|
||||
/*
|
||||
* Create an RPC service
|
||||
*/
|
||||
struct svc_serv *
|
||||
svc_create(struct svc_program *prog, unsigned int bufsize)
|
||||
{
|
||||
struct svc_serv *serv;
|
||||
int vers;
|
||||
unsigned int xdrsize;
|
||||
|
||||
if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL)))
|
||||
return NULL;
|
||||
memset(serv, 0, sizeof(*serv));
|
||||
serv->sv_program = prog;
|
||||
serv->sv_nrthreads = 1;
|
||||
serv->sv_stats = prog->pg_stats;
|
||||
serv->sv_bufsz = bufsize? bufsize : 4096;
|
||||
prog->pg_lovers = prog->pg_nvers-1;
|
||||
xdrsize = 0;
|
||||
for (vers=0; vers<prog->pg_nvers ; vers++)
|
||||
if (prog->pg_vers[vers]) {
|
||||
prog->pg_hivers = vers;
|
||||
if (prog->pg_lovers > vers)
|
||||
prog->pg_lovers = vers;
|
||||
if (prog->pg_vers[vers]->vs_xdrsize > xdrsize)
|
||||
xdrsize = prog->pg_vers[vers]->vs_xdrsize;
|
||||
}
|
||||
serv->sv_xdrsize = xdrsize;
|
||||
INIT_LIST_HEAD(&serv->sv_threads);
|
||||
INIT_LIST_HEAD(&serv->sv_sockets);
|
||||
INIT_LIST_HEAD(&serv->sv_tempsocks);
|
||||
INIT_LIST_HEAD(&serv->sv_permsocks);
|
||||
spin_lock_init(&serv->sv_lock);
|
||||
|
||||
serv->sv_name = prog->pg_name;
|
||||
|
||||
/* Remove any stale portmap registrations */
|
||||
svc_register(serv, 0, 0);
|
||||
|
||||
return serv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy an RPC service
|
||||
*/
|
||||
void
|
||||
svc_destroy(struct svc_serv *serv)
|
||||
{
|
||||
struct svc_sock *svsk;
|
||||
|
||||
dprintk("RPC: svc_destroy(%s, %d)\n",
|
||||
serv->sv_program->pg_name,
|
||||
serv->sv_nrthreads);
|
||||
|
||||
if (serv->sv_nrthreads) {
|
||||
if (--(serv->sv_nrthreads) != 0) {
|
||||
svc_sock_update_bufs(serv);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
printk("svc_destroy: no threads for serv=%p!\n", serv);
|
||||
|
||||
while (!list_empty(&serv->sv_tempsocks)) {
|
||||
svsk = list_entry(serv->sv_tempsocks.next,
|
||||
struct svc_sock,
|
||||
sk_list);
|
||||
svc_delete_socket(svsk);
|
||||
}
|
||||
while (!list_empty(&serv->sv_permsocks)) {
|
||||
svsk = list_entry(serv->sv_permsocks.next,
|
||||
struct svc_sock,
|
||||
sk_list);
|
||||
svc_delete_socket(svsk);
|
||||
}
|
||||
|
||||
cache_clean_deferred(serv);
|
||||
|
||||
/* Unregister service with the portmapper */
|
||||
svc_register(serv, 0, 0);
|
||||
kfree(serv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate an RPC server's buffer space.
|
||||
* We allocate pages and place them in rq_argpages.
|
||||
*/
|
||||
static int
|
||||
svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
|
||||
{
|
||||
int pages;
|
||||
int arghi;
|
||||
|
||||
if (size > RPCSVC_MAXPAYLOAD)
|
||||
size = RPCSVC_MAXPAYLOAD;
|
||||
pages = 2 + (size+ PAGE_SIZE -1) / PAGE_SIZE;
|
||||
rqstp->rq_argused = 0;
|
||||
rqstp->rq_resused = 0;
|
||||
arghi = 0;
|
||||
if (pages > RPCSVC_MAXPAGES)
|
||||
BUG();
|
||||
while (pages) {
|
||||
struct page *p = alloc_page(GFP_KERNEL);
|
||||
if (!p)
|
||||
break;
|
||||
rqstp->rq_argpages[arghi++] = p;
|
||||
pages--;
|
||||
}
|
||||
rqstp->rq_arghi = arghi;
|
||||
return ! pages;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release an RPC server buffer
|
||||
*/
|
||||
static void
|
||||
svc_release_buffer(struct svc_rqst *rqstp)
|
||||
{
|
||||
while (rqstp->rq_arghi)
|
||||
put_page(rqstp->rq_argpages[--rqstp->rq_arghi]);
|
||||
while (rqstp->rq_resused) {
|
||||
if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
|
||||
continue;
|
||||
put_page(rqstp->rq_respages[rqstp->rq_resused]);
|
||||
}
|
||||
rqstp->rq_argused = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a server thread
|
||||
*/
|
||||
int
|
||||
svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
|
||||
{
|
||||
struct svc_rqst *rqstp;
|
||||
int error = -ENOMEM;
|
||||
|
||||
rqstp = kmalloc(sizeof(*rqstp), GFP_KERNEL);
|
||||
if (!rqstp)
|
||||
goto out;
|
||||
|
||||
memset(rqstp, 0, sizeof(*rqstp));
|
||||
init_waitqueue_head(&rqstp->rq_wait);
|
||||
|
||||
if (!(rqstp->rq_argp = (u32 *) kmalloc(serv->sv_xdrsize, GFP_KERNEL))
|
||||
|| !(rqstp->rq_resp = (u32 *) kmalloc(serv->sv_xdrsize, GFP_KERNEL))
|
||||
|| !svc_init_buffer(rqstp, serv->sv_bufsz))
|
||||
goto out_thread;
|
||||
|
||||
serv->sv_nrthreads++;
|
||||
rqstp->rq_server = serv;
|
||||
error = kernel_thread((int (*)(void *)) func, rqstp, 0);
|
||||
if (error < 0)
|
||||
goto out_thread;
|
||||
svc_sock_update_bufs(serv);
|
||||
error = 0;
|
||||
out:
|
||||
return error;
|
||||
|
||||
out_thread:
|
||||
svc_exit_thread(rqstp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy an RPC server thread
|
||||
*/
|
||||
void
|
||||
svc_exit_thread(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct svc_serv *serv = rqstp->rq_server;
|
||||
|
||||
svc_release_buffer(rqstp);
|
||||
if (rqstp->rq_resp)
|
||||
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 */
|
||||
if (serv)
|
||||
svc_destroy(serv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register an RPC service with the local portmapper.
|
||||
* To unregister a service, call this routine with
|
||||
* proto and port == 0.
|
||||
*/
|
||||
int
|
||||
svc_register(struct svc_serv *serv, int proto, unsigned short port)
|
||||
{
|
||||
struct svc_program *progp;
|
||||
unsigned long flags;
|
||||
int i, error = 0, dummy;
|
||||
|
||||
progp = serv->sv_program;
|
||||
|
||||
dprintk("RPC: svc_register(%s, %s, %d)\n",
|
||||
progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);
|
||||
|
||||
if (!port)
|
||||
clear_thread_flag(TIF_SIGPENDING);
|
||||
|
||||
for (i = 0; i < progp->pg_nvers; i++) {
|
||||
if (progp->pg_vers[i] == NULL)
|
||||
continue;
|
||||
error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
|
||||
if (error < 0)
|
||||
break;
|
||||
if (port && !dummy) {
|
||||
error = -EACCES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the RPC request.
|
||||
*/
|
||||
int
|
||||
svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
|
||||
{
|
||||
struct svc_program *progp;
|
||||
struct svc_version *versp = NULL; /* compiler food */
|
||||
struct svc_procedure *procp = NULL;
|
||||
struct kvec * argv = &rqstp->rq_arg.head[0];
|
||||
struct kvec * resv = &rqstp->rq_res.head[0];
|
||||
kxdrproc_t xdr;
|
||||
u32 *statp;
|
||||
u32 dir, prog, vers, proc,
|
||||
auth_stat, rpc_stat;
|
||||
int auth_res;
|
||||
|
||||
rpc_stat = rpc_success;
|
||||
|
||||
if (argv->iov_len < 6*4)
|
||||
goto err_short_len;
|
||||
|
||||
/* setup response xdr_buf.
|
||||
* Initially it has just one page
|
||||
*/
|
||||
svc_take_page(rqstp); /* must succeed */
|
||||
resv->iov_base = page_address(rqstp->rq_respages[0]);
|
||||
resv->iov_len = 0;
|
||||
rqstp->rq_res.pages = rqstp->rq_respages+1;
|
||||
rqstp->rq_res.len = 0;
|
||||
rqstp->rq_res.page_base = 0;
|
||||
rqstp->rq_res.page_len = 0;
|
||||
rqstp->rq_res.tail[0].iov_len = 0;
|
||||
/* tcp needs a space for the record length... */
|
||||
if (rqstp->rq_prot == IPPROTO_TCP)
|
||||
svc_putu32(resv, 0);
|
||||
|
||||
rqstp->rq_xid = svc_getu32(argv);
|
||||
svc_putu32(resv, rqstp->rq_xid);
|
||||
|
||||
dir = ntohl(svc_getu32(argv));
|
||||
vers = ntohl(svc_getu32(argv));
|
||||
|
||||
/* First words of reply: */
|
||||
svc_putu32(resv, xdr_one); /* REPLY */
|
||||
|
||||
if (dir != 0) /* direction != CALL */
|
||||
goto err_bad_dir;
|
||||
if (vers != 2) /* RPC version number */
|
||||
goto err_bad_rpc;
|
||||
|
||||
svc_putu32(resv, xdr_zero); /* ACCEPT */
|
||||
|
||||
rqstp->rq_prog = prog = ntohl(svc_getu32(argv)); /* program number */
|
||||
rqstp->rq_vers = vers = ntohl(svc_getu32(argv)); /* version number */
|
||||
rqstp->rq_proc = proc = ntohl(svc_getu32(argv)); /* procedure number */
|
||||
|
||||
progp = serv->sv_program;
|
||||
/*
|
||||
* Decode auth data, and add verifier to reply buffer.
|
||||
* We do this before anything else in order to get a decent
|
||||
* auth verifier.
|
||||
*/
|
||||
if (progp->pg_authenticate != NULL)
|
||||
auth_res = progp->pg_authenticate(rqstp, &auth_stat);
|
||||
else
|
||||
auth_res = svc_authenticate(rqstp, &auth_stat);
|
||||
switch (auth_res) {
|
||||
case SVC_OK:
|
||||
break;
|
||||
case SVC_GARBAGE:
|
||||
rpc_stat = rpc_garbage_args;
|
||||
goto err_bad;
|
||||
case SVC_SYSERR:
|
||||
rpc_stat = rpc_system_err;
|
||||
goto err_bad;
|
||||
case SVC_DENIED:
|
||||
goto err_bad_auth;
|
||||
case SVC_DROP:
|
||||
goto dropit;
|
||||
case SVC_COMPLETE:
|
||||
goto sendit;
|
||||
}
|
||||
|
||||
if (prog != progp->pg_prog)
|
||||
goto err_bad_prog;
|
||||
|
||||
if (vers >= progp->pg_nvers ||
|
||||
!(versp = progp->pg_vers[vers]))
|
||||
goto err_bad_vers;
|
||||
|
||||
procp = versp->vs_proc + proc;
|
||||
if (proc >= versp->vs_nproc || !procp->pc_func)
|
||||
goto err_bad_proc;
|
||||
rqstp->rq_server = serv;
|
||||
rqstp->rq_procinfo = procp;
|
||||
|
||||
/* Syntactic check complete */
|
||||
serv->sv_stats->rpccnt++;
|
||||
|
||||
/* Build the reply header. */
|
||||
statp = resv->iov_base +resv->iov_len;
|
||||
svc_putu32(resv, rpc_success); /* RPC_SUCCESS */
|
||||
|
||||
/* Bump per-procedure stats counter */
|
||||
procp->pc_count++;
|
||||
|
||||
/* Initialize storage for argp and resp */
|
||||
memset(rqstp->rq_argp, 0, procp->pc_argsize);
|
||||
memset(rqstp->rq_resp, 0, procp->pc_ressize);
|
||||
|
||||
/* un-reserve some of the out-queue now that we have a
|
||||
* better idea of reply size
|
||||
*/
|
||||
if (procp->pc_xdrressize)
|
||||
svc_reserve(rqstp, procp->pc_xdrressize<<2);
|
||||
|
||||
/* Call the function that processes the request. */
|
||||
if (!versp->vs_dispatch) {
|
||||
/* Decode arguments */
|
||||
xdr = procp->pc_decode;
|
||||
if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp))
|
||||
goto err_garbage;
|
||||
|
||||
*statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
|
||||
|
||||
/* Encode reply */
|
||||
if (*statp == rpc_success && (xdr = procp->pc_encode)
|
||||
&& !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
|
||||
dprintk("svc: failed to encode reply\n");
|
||||
/* serv->sv_stats->rpcsystemerr++; */
|
||||
*statp = rpc_system_err;
|
||||
}
|
||||
} else {
|
||||
dprintk("svc: calling dispatcher\n");
|
||||
if (!versp->vs_dispatch(rqstp, statp)) {
|
||||
/* Release reply info */
|
||||
if (procp->pc_release)
|
||||
procp->pc_release(rqstp, NULL, rqstp->rq_resp);
|
||||
goto dropit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check RPC status result */
|
||||
if (*statp != rpc_success)
|
||||
resv->iov_len = ((void*)statp) - resv->iov_base + 4;
|
||||
|
||||
/* Release reply info */
|
||||
if (procp->pc_release)
|
||||
procp->pc_release(rqstp, NULL, rqstp->rq_resp);
|
||||
|
||||
if (procp->pc_encode == NULL)
|
||||
goto dropit;
|
||||
|
||||
sendit:
|
||||
if (svc_authorise(rqstp))
|
||||
goto dropit;
|
||||
return svc_send(rqstp);
|
||||
|
||||
dropit:
|
||||
svc_authorise(rqstp); /* doesn't hurt to call this twice */
|
||||
dprintk("svc: svc_process dropit\n");
|
||||
svc_drop(rqstp);
|
||||
return 0;
|
||||
|
||||
err_short_len:
|
||||
#ifdef RPC_PARANOIA
|
||||
printk("svc: short len %Zd, dropping request\n", argv->iov_len);
|
||||
#endif
|
||||
goto dropit; /* drop request */
|
||||
|
||||
err_bad_dir:
|
||||
#ifdef RPC_PARANOIA
|
||||
printk("svc: bad direction %d, dropping request\n", dir);
|
||||
#endif
|
||||
serv->sv_stats->rpcbadfmt++;
|
||||
goto dropit; /* drop request */
|
||||
|
||||
err_bad_rpc:
|
||||
serv->sv_stats->rpcbadfmt++;
|
||||
svc_putu32(resv, xdr_one); /* REJECT */
|
||||
svc_putu32(resv, xdr_zero); /* RPC_MISMATCH */
|
||||
svc_putu32(resv, xdr_two); /* Only RPCv2 supported */
|
||||
svc_putu32(resv, xdr_two);
|
||||
goto sendit;
|
||||
|
||||
err_bad_auth:
|
||||
dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
|
||||
serv->sv_stats->rpcbadauth++;
|
||||
resv->iov_len -= 4;
|
||||
svc_putu32(resv, xdr_one); /* REJECT */
|
||||
svc_putu32(resv, xdr_one); /* AUTH_ERROR */
|
||||
svc_putu32(resv, auth_stat); /* status */
|
||||
goto sendit;
|
||||
|
||||
err_bad_prog:
|
||||
#ifdef RPC_PARANOIA
|
||||
if (prog != 100227 || progp->pg_prog != 100003)
|
||||
printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog);
|
||||
/* else it is just a Solaris client seeing if ACLs are supported */
|
||||
#endif
|
||||
serv->sv_stats->rpcbadfmt++;
|
||||
svc_putu32(resv, rpc_prog_unavail);
|
||||
goto sendit;
|
||||
|
||||
err_bad_vers:
|
||||
#ifdef RPC_PARANOIA
|
||||
printk("svc: unknown version (%d)\n", vers);
|
||||
#endif
|
||||
serv->sv_stats->rpcbadfmt++;
|
||||
svc_putu32(resv, rpc_prog_mismatch);
|
||||
svc_putu32(resv, htonl(progp->pg_lovers));
|
||||
svc_putu32(resv, htonl(progp->pg_hivers));
|
||||
goto sendit;
|
||||
|
||||
err_bad_proc:
|
||||
#ifdef RPC_PARANOIA
|
||||
printk("svc: unknown procedure (%d)\n", proc);
|
||||
#endif
|
||||
serv->sv_stats->rpcbadfmt++;
|
||||
svc_putu32(resv, rpc_proc_unavail);
|
||||
goto sendit;
|
||||
|
||||
err_garbage:
|
||||
#ifdef RPC_PARANOIA
|
||||
printk("svc: failed to decode args\n");
|
||||
#endif
|
||||
rpc_stat = rpc_garbage_args;
|
||||
err_bad:
|
||||
serv->sv_stats->rpcbadfmt++;
|
||||
svc_putu32(resv, rpc_stat);
|
||||
goto sendit;
|
||||
}
|
||||
210
extra/linux-2.6.10/net/sunrpc/svcauth.c
Normal file
210
extra/linux-2.6.10/net/sunrpc/svcauth.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* linux/net/sunrpc/svcauth.c
|
||||
*
|
||||
* The generic interface for RPC authentication on the server side.
|
||||
*
|
||||
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*
|
||||
* CHANGES
|
||||
* 19-Apr-2000 Chris Evans - Security fix
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sunrpc/types.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/sunrpc/svcauth.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hash.h>
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
|
||||
|
||||
/*
|
||||
* Table of authenticators
|
||||
*/
|
||||
extern struct auth_ops svcauth_null;
|
||||
extern struct auth_ops svcauth_unix;
|
||||
|
||||
static spinlock_t authtab_lock = SPIN_LOCK_UNLOCKED;
|
||||
static struct auth_ops *authtab[RPC_AUTH_MAXFLAVOR] = {
|
||||
[0] = &svcauth_null,
|
||||
[1] = &svcauth_unix,
|
||||
};
|
||||
|
||||
int
|
||||
svc_authenticate(struct svc_rqst *rqstp, u32 *authp)
|
||||
{
|
||||
rpc_authflavor_t flavor;
|
||||
struct auth_ops *aops;
|
||||
|
||||
*authp = rpc_auth_ok;
|
||||
|
||||
flavor = ntohl(svc_getu32(&rqstp->rq_arg.head[0]));
|
||||
|
||||
dprintk("svc: svc_authenticate (%d)\n", flavor);
|
||||
|
||||
spin_lock(&authtab_lock);
|
||||
if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor])
|
||||
|| !try_module_get(aops->owner)) {
|
||||
spin_unlock(&authtab_lock);
|
||||
*authp = rpc_autherr_badcred;
|
||||
return SVC_DENIED;
|
||||
}
|
||||
spin_unlock(&authtab_lock);
|
||||
|
||||
rqstp->rq_authop = aops;
|
||||
return aops->accept(rqstp, authp);
|
||||
}
|
||||
|
||||
/* A request, which was authenticated, has now executed.
|
||||
* Time to finalise the the credentials and verifier
|
||||
* and release and resources
|
||||
*/
|
||||
int svc_authorise(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct auth_ops *aops = rqstp->rq_authop;
|
||||
int rv = 0;
|
||||
|
||||
rqstp->rq_authop = NULL;
|
||||
|
||||
if (aops) {
|
||||
rv = aops->release(rqstp);
|
||||
module_put(aops->owner);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
|
||||
{
|
||||
int rv = -EINVAL;
|
||||
spin_lock(&authtab_lock);
|
||||
if (flavor < RPC_AUTH_MAXFLAVOR && authtab[flavor] == NULL) {
|
||||
authtab[flavor] = aops;
|
||||
rv = 0;
|
||||
}
|
||||
spin_unlock(&authtab_lock);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
svc_auth_unregister(rpc_authflavor_t flavor)
|
||||
{
|
||||
spin_lock(&authtab_lock);
|
||||
if (flavor < RPC_AUTH_MAXFLAVOR)
|
||||
authtab[flavor] = NULL;
|
||||
spin_unlock(&authtab_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_auth_unregister);
|
||||
|
||||
/**************************************************
|
||||
* cache for domain name to auth_domain
|
||||
* Entries are only added by flavours which will normally
|
||||
* have a structure that 'inherits' from auth_domain.
|
||||
* e.g. when an IP -> domainname is given to auth_unix,
|
||||
* and the domain name doesn't exist, it will create a
|
||||
* auth_unix_domain and add it to this hash table.
|
||||
* If it finds the name does exist, but isn't AUTH_UNIX,
|
||||
* it will complain.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Auth auth_domain cache is somewhat different to other caches,
|
||||
* largely because the entries are possibly of different types:
|
||||
* each auth flavour has it's own type.
|
||||
* One consequence of this that DefineCacheLookup cannot
|
||||
* allocate a new structure as it cannot know the size.
|
||||
* Notice that the "INIT" code fragment is quite different
|
||||
* from other caches. When auth_domain_lookup might be
|
||||
* creating a new domain, the new domain is passed in
|
||||
* complete and it is used as-is rather than being copied into
|
||||
* another structure.
|
||||
*/
|
||||
#define DN_HASHBITS 6
|
||||
#define DN_HASHMAX (1<<DN_HASHBITS)
|
||||
#define DN_HASHMASK (DN_HASHMAX-1)
|
||||
|
||||
static struct cache_head *auth_domain_table[DN_HASHMAX];
|
||||
void auth_domain_drop(struct cache_head *item, struct cache_detail *cd)
|
||||
{
|
||||
struct auth_domain *dom = container_of(item, struct auth_domain, h);
|
||||
if (cache_put(item,cd))
|
||||
authtab[dom->flavour]->domain_release(dom);
|
||||
}
|
||||
|
||||
|
||||
struct cache_detail auth_domain_cache = {
|
||||
.hash_size = DN_HASHMAX,
|
||||
.hash_table = auth_domain_table,
|
||||
.name = "auth.domain",
|
||||
.cache_put = auth_domain_drop,
|
||||
};
|
||||
|
||||
void auth_domain_put(struct auth_domain *dom)
|
||||
{
|
||||
auth_domain_drop(&dom->h, &auth_domain_cache);
|
||||
}
|
||||
|
||||
static inline int auth_domain_hash(struct auth_domain *item)
|
||||
{
|
||||
return hash_str(item->name, DN_HASHBITS);
|
||||
}
|
||||
static inline int auth_domain_match(struct auth_domain *tmp, struct auth_domain *item)
|
||||
{
|
||||
return strcmp(tmp->name, item->name) == 0;
|
||||
}
|
||||
|
||||
struct auth_domain *
|
||||
auth_domain_lookup(struct auth_domain *item, int set)
|
||||
{
|
||||
struct auth_domain *tmp = NULL;
|
||||
struct cache_head **hp, **head;
|
||||
head = &auth_domain_cache.hash_table[auth_domain_hash(item)];
|
||||
|
||||
if (set)
|
||||
write_lock(&auth_domain_cache.hash_lock);
|
||||
else
|
||||
read_lock(&auth_domain_cache.hash_lock);
|
||||
for (hp=head; *hp != NULL; hp = &tmp->h.next) {
|
||||
tmp = container_of(*hp, struct auth_domain, h);
|
||||
if (!auth_domain_match(tmp, item))
|
||||
continue;
|
||||
cache_get(&tmp->h);
|
||||
if (!set)
|
||||
goto out_noset;
|
||||
*hp = tmp->h.next;
|
||||
tmp->h.next = NULL;
|
||||
clear_bit(CACHE_HASHED, &tmp->h.flags);
|
||||
auth_domain_drop(&tmp->h, &auth_domain_cache);
|
||||
goto out_set;
|
||||
}
|
||||
/* Didn't find anything */
|
||||
if (!set)
|
||||
goto out_nada;
|
||||
auth_domain_cache.entries++;
|
||||
out_set:
|
||||
set_bit(CACHE_HASHED, &item->h.flags);
|
||||
item->h.next = *head;
|
||||
*head = &item->h;
|
||||
write_unlock(&auth_domain_cache.hash_lock);
|
||||
cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time);
|
||||
cache_get(&item->h);
|
||||
return item;
|
||||
out_nada:
|
||||
tmp = NULL;
|
||||
out_noset:
|
||||
read_unlock(&auth_domain_cache.hash_lock);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
struct auth_domain *auth_domain_find(char *name)
|
||||
{
|
||||
struct auth_domain *rv, ad;
|
||||
|
||||
ad.name = name;
|
||||
rv = auth_domain_lookup(&ad, 0);
|
||||
return rv;
|
||||
}
|
||||
215
extra/linux-2.6.10/net/sunrpc/svcauth_des.c
Normal file
215
extra/linux-2.6.10/net/sunrpc/svcauth_des.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* linux/net/sunrpc/svcauth_des.c
|
||||
*
|
||||
* Server-side AUTH_DES handling.
|
||||
*
|
||||
* Copyright (C) 1996, 1997 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sunrpc/types.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/svcauth.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
|
||||
/*
|
||||
* DES cedential cache.
|
||||
* The cache is indexed by fullname/key to allow for multiple sessions
|
||||
* by the same user from different hosts.
|
||||
* It would be tempting to use the client's IP address rather than the
|
||||
* conversation key as an index, but that could become problematic for
|
||||
* multi-homed hosts that distribute traffic across their interfaces.
|
||||
*/
|
||||
struct des_cred {
|
||||
struct des_cred * dc_next;
|
||||
char * dc_fullname;
|
||||
u32 dc_nickname;
|
||||
des_cblock dc_key; /* conversation key */
|
||||
des_cblock dc_xkey; /* encrypted conv. key */
|
||||
des_key_schedule dc_keysched;
|
||||
};
|
||||
|
||||
#define ADN_FULLNAME 0
|
||||
#define ADN_NICKNAME 1
|
||||
|
||||
/*
|
||||
* The default slack allowed when checking for replayed credentials
|
||||
* (in milliseconds).
|
||||
*/
|
||||
#define DES_REPLAY_SLACK 2000
|
||||
|
||||
/*
|
||||
* Make sure we don't place more than one call to the key server at
|
||||
* a time.
|
||||
*/
|
||||
static int in_keycall;
|
||||
|
||||
#define FAIL(err) \
|
||||
{ if (data) put_cred(data); \
|
||||
*authp = rpc_autherr_##err; \
|
||||
return; \
|
||||
}
|
||||
|
||||
void
|
||||
svcauth_des(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
|
||||
{
|
||||
struct svc_buf *argp = &rqstp->rq_argbuf;
|
||||
struct svc_buf *resp = &rqstp->rq_resbuf;
|
||||
struct svc_cred *cred = &rqstp->rq_cred;
|
||||
struct des_cred *data = NULL;
|
||||
u32 cryptkey[2];
|
||||
u32 cryptbuf[4];
|
||||
u32 *p = argp->buf;
|
||||
int len = argp->len, slen, i;
|
||||
|
||||
*authp = rpc_auth_ok;
|
||||
|
||||
if ((argp->len -= 3) < 0) {
|
||||
*statp = rpc_garbage_args;
|
||||
return;
|
||||
}
|
||||
|
||||
p++; /* skip length field */
|
||||
namekind = ntohl(*p++); /* fullname/nickname */
|
||||
|
||||
/* Get the credentials */
|
||||
if (namekind == ADN_NICKNAME) {
|
||||
/* If we can't find the cached session key, initiate a
|
||||
* new session. */
|
||||
if (!(data = get_cred_bynick(*p++)))
|
||||
FAIL(rejectedcred);
|
||||
} else if (namekind == ADN_FULLNAME) {
|
||||
p = xdr_decode_string(p, &fullname, &len, RPC_MAXNETNAMELEN);
|
||||
if (p == NULL)
|
||||
FAIL(badcred);
|
||||
cryptkey[0] = *p++; /* get the encrypted key */
|
||||
cryptkey[1] = *p++;
|
||||
cryptbuf[2] = *p++; /* get the encrypted window */
|
||||
} else {
|
||||
FAIL(badcred);
|
||||
}
|
||||
|
||||
/* If we're just updating the key, silently discard the request. */
|
||||
if (data && data->dc_locked) {
|
||||
*authp = rpc_autherr_dropit;
|
||||
_put_cred(data); /* release but don't unlock */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the verifier flavor and length */
|
||||
if (ntohl(*p++) != RPC_AUTH_DES && ntohl(*p++) != 12)
|
||||
FAIL(badverf);
|
||||
|
||||
cryptbuf[0] = *p++; /* encrypted time stamp */
|
||||
cryptbuf[1] = *p++;
|
||||
cryptbuf[3] = *p++; /* 0 or window - 1 */
|
||||
|
||||
if (namekind == ADN_NICKNAME) {
|
||||
status = des_ecb_encrypt((des_block *) cryptbuf,
|
||||
(des_block *) cryptbuf,
|
||||
data->dc_keysched, DES_DECRYPT);
|
||||
} else {
|
||||
/* We first have to decrypt the new session key and
|
||||
* fill in the UNIX creds. */
|
||||
if (!(data = get_cred_byname(rqstp, authp, fullname, cryptkey)))
|
||||
return;
|
||||
status = des_cbc_encrypt((des_cblock *) cryptbuf,
|
||||
(des_cblock *) cryptbuf, 16,
|
||||
data->dc_keysched,
|
||||
(des_cblock *) &ivec,
|
||||
DES_DECRYPT);
|
||||
}
|
||||
if (status) {
|
||||
printk("svcauth_des: DES decryption failed (status %d)\n",
|
||||
status);
|
||||
FAIL(badverf);
|
||||
}
|
||||
|
||||
/* Now check the whole lot */
|
||||
if (namekind == ADN_FULLNAME) {
|
||||
unsigned long winverf;
|
||||
|
||||
data->dc_window = ntohl(cryptbuf[2]);
|
||||
winverf = ntohl(cryptbuf[2]);
|
||||
if (window != winverf - 1) {
|
||||
printk("svcauth_des: bad window verifier!\n");
|
||||
FAIL(badverf);
|
||||
}
|
||||
}
|
||||
|
||||
/* XDR the decrypted timestamp */
|
||||
cryptbuf[0] = ntohl(cryptbuf[0]);
|
||||
cryptbuf[1] = ntohl(cryptbuf[1]);
|
||||
if (cryptbuf[1] > 1000000) {
|
||||
dprintk("svcauth_des: bad usec value %u\n", cryptbuf[1]);
|
||||
if (namekind == ADN_NICKNAME)
|
||||
FAIL(rejectedverf);
|
||||
FAIL(badverf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for replayed credentials. We must allow for reordering
|
||||
* of requests by the network, and the OS scheduler, hence we
|
||||
* cannot expect timestamps to be increasing monotonically.
|
||||
* This opens a small security hole, therefore the replay_slack
|
||||
* value shouldn't be too large.
|
||||
*/
|
||||
if ((delta = cryptbuf[0] - data->dc_timestamp[0]) <= 0) {
|
||||
switch (delta) {
|
||||
case -1:
|
||||
delta = -1000000;
|
||||
case 0:
|
||||
delta += cryptbuf[1] - data->dc_timestamp[1];
|
||||
break;
|
||||
default:
|
||||
delta = -1000000;
|
||||
}
|
||||
if (delta < DES_REPLAY_SLACK)
|
||||
FAIL(rejectedverf);
|
||||
#ifdef STRICT_REPLAY_CHECKS
|
||||
/* TODO: compare time stamp to last five timestamps cached
|
||||
* and reject (drop?) request if a match is found. */
|
||||
#endif
|
||||
}
|
||||
|
||||
now = xtime;
|
||||
now.tv_secs -= data->dc_window;
|
||||
if (now.tv_secs < cryptbuf[0] ||
|
||||
(now.tv_secs == cryptbuf[0] && now.tv_usec < cryptbuf[1]))
|
||||
FAIL(rejectedverf);
|
||||
|
||||
/* Okay, we're done. Update the lot */
|
||||
if (namekind == ADN_FULLNAME)
|
||||
data->dc_valid = 1;
|
||||
data->dc_timestamp[0] = cryptbuf[0];
|
||||
data->dc_timestamp[1] = cryptbuf[1];
|
||||
|
||||
put_cred(data);
|
||||
return;
|
||||
garbage:
|
||||
*statp = rpc_garbage_args;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the keyserver to obtain the decrypted conversation key and
|
||||
* UNIX creds. We use a Linux-specific keycall extension that does
|
||||
* both things in one go.
|
||||
*/
|
||||
static struct des_cred *
|
||||
get_cred_byname(struct svc_rqst *rqstp, u32 *authp, char *fullname, u32 *cryptkey)
|
||||
{
|
||||
static int in_keycall;
|
||||
struct des_cred *cred;
|
||||
|
||||
if (in_keycall) {
|
||||
*authp = rpc_autherr_dropit;
|
||||
return NULL;
|
||||
}
|
||||
in_keycall = 1;
|
||||
in_keycall = 0;
|
||||
return cred;
|
||||
}
|
||||
524
extra/linux-2.6.10/net/sunrpc/svcauth_unix.c
Normal file
524
extra/linux-2.6.10/net/sunrpc/svcauth_unix.c
Normal file
@@ -0,0 +1,524 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sunrpc/types.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/sunrpc/svcauth.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/hash.h>
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
|
||||
|
||||
/*
|
||||
* AUTHUNIX and AUTHNULL credentials are both handled here.
|
||||
* AUTHNULL is treated just like AUTHUNIX except that the uid/gid
|
||||
* are always nobody (-2). i.e. we do the same IP address checks for
|
||||
* AUTHNULL as for AUTHUNIX, and that is done here.
|
||||
*/
|
||||
|
||||
|
||||
static char *strdup(char *s)
|
||||
{
|
||||
char *rv = kmalloc(strlen(s)+1, GFP_KERNEL);
|
||||
if (rv)
|
||||
strcpy(rv, s);
|
||||
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;
|
||||
struct unix_domain *new;
|
||||
|
||||
ud.name = name;
|
||||
|
||||
rv = auth_domain_lookup(&ud, 0);
|
||||
|
||||
foundit:
|
||||
if (rv && rv->flavour != RPC_AUTH_UNIX) {
|
||||
auth_domain_put(rv);
|
||||
return NULL;
|
||||
}
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
new = kmalloc(sizeof(*new), GFP_KERNEL);
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
cache_init(&new->h.h);
|
||||
new->h.name = strdup(name);
|
||||
new->h.flavour = RPC_AUTH_UNIX;
|
||||
new->addr_changes = 0;
|
||||
new->h.h.expiry_time = NEVER;
|
||||
|
||||
rv = auth_domain_lookup(&new->h, 2);
|
||||
if (rv == &new->h) {
|
||||
if (atomic_dec_and_test(&new->h.h.refcnt)) BUG();
|
||||
} else {
|
||||
auth_domain_put(&new->h);
|
||||
goto foundit;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void svcauth_unix_domain_release(struct auth_domain *dom)
|
||||
{
|
||||
struct unix_domain *ud = container_of(dom, struct unix_domain, h);
|
||||
|
||||
kfree(dom->name);
|
||||
kfree(ud);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************
|
||||
* cache for IP address to unix_domain
|
||||
* as needed by AUTH_UNIX
|
||||
*/
|
||||
#define IP_HASHBITS 8
|
||||
#define IP_HASHMAX (1<<IP_HASHBITS)
|
||||
#define IP_HASHMASK (IP_HASHMAX-1)
|
||||
|
||||
struct ip_map {
|
||||
struct cache_head h;
|
||||
char m_class[8]; /* e.g. "nfsd" */
|
||||
struct in_addr m_addr;
|
||||
struct unix_domain *m_client;
|
||||
int m_add_change;
|
||||
};
|
||||
static struct cache_head *ip_table[IP_HASHMAX];
|
||||
|
||||
void ip_map_put(struct cache_head *item, struct cache_detail *cd)
|
||||
{
|
||||
struct ip_map *im = container_of(item, struct ip_map,h);
|
||||
if (cache_put(item, cd)) {
|
||||
if (test_bit(CACHE_VALID, &item->flags) &&
|
||||
!test_bit(CACHE_NEGATIVE, &item->flags))
|
||||
auth_domain_put(&im->m_client->h);
|
||||
kfree(im);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int ip_map_hash(struct ip_map *item)
|
||||
{
|
||||
return hash_str(item->m_class, IP_HASHBITS) ^
|
||||
hash_long((unsigned long)item->m_addr.s_addr, IP_HASHBITS);
|
||||
}
|
||||
static inline int ip_map_match(struct ip_map *item, struct ip_map *tmp)
|
||||
{
|
||||
return strcmp(tmp->m_class, item->m_class) == 0
|
||||
&& tmp->m_addr.s_addr == item->m_addr.s_addr;
|
||||
}
|
||||
static inline void ip_map_init(struct ip_map *new, struct ip_map *item)
|
||||
{
|
||||
strcpy(new->m_class, item->m_class);
|
||||
new->m_addr.s_addr = item->m_addr.s_addr;
|
||||
}
|
||||
static inline void ip_map_update(struct ip_map *new, struct ip_map *item)
|
||||
{
|
||||
cache_get(&item->m_client->h.h);
|
||||
new->m_client = item->m_client;
|
||||
new->m_add_change = item->m_add_change;
|
||||
}
|
||||
|
||||
static void ip_map_request(struct cache_detail *cd,
|
||||
struct cache_head *h,
|
||||
char **bpp, int *blen)
|
||||
{
|
||||
char text_addr[20];
|
||||
struct ip_map *im = container_of(h, struct ip_map, h);
|
||||
__u32 addr = im->m_addr.s_addr;
|
||||
|
||||
snprintf(text_addr, 20, "%u.%u.%u.%u",
|
||||
ntohl(addr) >> 24 & 0xff,
|
||||
ntohl(addr) >> 16 & 0xff,
|
||||
ntohl(addr) >> 8 & 0xff,
|
||||
ntohl(addr) >> 0 & 0xff);
|
||||
|
||||
qword_add(bpp, blen, im->m_class);
|
||||
qword_add(bpp, blen, text_addr);
|
||||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static struct ip_map *ip_map_lookup(struct ip_map *, int);
|
||||
|
||||
static int ip_map_parse(struct cache_detail *cd,
|
||||
char *mesg, int mlen)
|
||||
{
|
||||
/* class ipaddress [domainname] */
|
||||
/* should be safe just to use the start of the input buffer
|
||||
* for scratch: */
|
||||
char *buf = mesg;
|
||||
int len;
|
||||
int b1,b2,b3,b4;
|
||||
char c;
|
||||
struct ip_map ipm, *ipmp;
|
||||
struct auth_domain *dom;
|
||||
time_t expiry;
|
||||
|
||||
if (mesg[mlen-1] != '\n')
|
||||
return -EINVAL;
|
||||
mesg[mlen-1] = 0;
|
||||
|
||||
/* class */
|
||||
len = qword_get(&mesg, ipm.m_class, sizeof(ipm.m_class));
|
||||
if (len <= 0) return -EINVAL;
|
||||
|
||||
/* ip address */
|
||||
len = qword_get(&mesg, buf, mlen);
|
||||
if (len <= 0) return -EINVAL;
|
||||
|
||||
if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
|
||||
return -EINVAL;
|
||||
|
||||
expiry = get_expiry(&mesg);
|
||||
if (expiry ==0)
|
||||
return -EINVAL;
|
||||
|
||||
/* domainname, or empty for NEGATIVE */
|
||||
len = qword_get(&mesg, buf, mlen);
|
||||
if (len < 0) return -EINVAL;
|
||||
|
||||
if (len) {
|
||||
dom = unix_domain_find(buf);
|
||||
if (dom == NULL)
|
||||
return -ENOENT;
|
||||
} else
|
||||
dom = NULL;
|
||||
|
||||
ipm.m_addr.s_addr =
|
||||
htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
|
||||
ipm.h.flags = 0;
|
||||
if (dom) {
|
||||
ipm.m_client = container_of(dom, struct unix_domain, h);
|
||||
ipm.m_add_change = ipm.m_client->addr_changes;
|
||||
} else
|
||||
set_bit(CACHE_NEGATIVE, &ipm.h.flags);
|
||||
ipm.h.expiry_time = expiry;
|
||||
|
||||
ipmp = ip_map_lookup(&ipm, 1);
|
||||
if (ipmp)
|
||||
ip_map_put(&ipmp->h, &ip_map_cache);
|
||||
if (dom)
|
||||
auth_domain_put(dom);
|
||||
if (!ipmp)
|
||||
return -ENOMEM;
|
||||
cache_flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ip_map_show(struct seq_file *m,
|
||||
struct cache_detail *cd,
|
||||
struct cache_head *h)
|
||||
{
|
||||
struct ip_map *im;
|
||||
struct in_addr addr;
|
||||
char *dom = "-no-domain-";
|
||||
|
||||
if (h == NULL) {
|
||||
seq_puts(m, "#class IP domain\n");
|
||||
return 0;
|
||||
}
|
||||
im = container_of(h, struct ip_map, h);
|
||||
/* class addr domain */
|
||||
addr = im->m_addr;
|
||||
|
||||
if (test_bit(CACHE_VALID, &h->flags) &&
|
||||
!test_bit(CACHE_NEGATIVE, &h->flags))
|
||||
dom = im->m_client->h.name;
|
||||
|
||||
seq_printf(m, "%s %d.%d.%d.%d %s\n",
|
||||
im->m_class,
|
||||
htonl(addr.s_addr) >> 24 & 0xff,
|
||||
htonl(addr.s_addr) >> 16 & 0xff,
|
||||
htonl(addr.s_addr) >> 8 & 0xff,
|
||||
htonl(addr.s_addr) >> 0 & 0xff,
|
||||
dom
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct cache_detail ip_map_cache = {
|
||||
.hash_size = IP_HASHMAX,
|
||||
.hash_table = ip_table,
|
||||
.name = "auth.unix.ip",
|
||||
.cache_put = ip_map_put,
|
||||
.cache_request = ip_map_request,
|
||||
.cache_parse = ip_map_parse,
|
||||
.cache_show = ip_map_show,
|
||||
};
|
||||
|
||||
static DefineSimpleCacheLookup(ip_map, 0)
|
||||
|
||||
|
||||
int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
|
||||
{
|
||||
struct unix_domain *udom;
|
||||
struct ip_map ip, *ipmp;
|
||||
|
||||
if (dom->flavour != RPC_AUTH_UNIX)
|
||||
return -EINVAL;
|
||||
udom = container_of(dom, struct unix_domain, h);
|
||||
strcpy(ip.m_class, "nfsd");
|
||||
ip.m_addr = addr;
|
||||
ip.m_client = udom;
|
||||
ip.m_add_change = udom->addr_changes+1;
|
||||
ip.h.flags = 0;
|
||||
ip.h.expiry_time = NEVER;
|
||||
|
||||
ipmp = ip_map_lookup(&ip, 1);
|
||||
|
||||
if (ipmp) {
|
||||
ip_map_put(&ipmp->h, &ip_map_cache);
|
||||
return 0;
|
||||
} else
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int auth_unix_forget_old(struct auth_domain *dom)
|
||||
{
|
||||
struct unix_domain *udom;
|
||||
|
||||
if (dom->flavour != RPC_AUTH_UNIX)
|
||||
return -EINVAL;
|
||||
udom = container_of(dom, struct unix_domain, h);
|
||||
udom->addr_changes++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct auth_domain *auth_unix_lookup(struct in_addr addr)
|
||||
{
|
||||
struct ip_map key, *ipm;
|
||||
struct auth_domain *rv;
|
||||
|
||||
strcpy(key.m_class, "nfsd");
|
||||
key.m_addr = addr;
|
||||
|
||||
ipm = ip_map_lookup(&key, 0);
|
||||
|
||||
if (!ipm)
|
||||
return NULL;
|
||||
if (cache_check(&ip_map_cache, &ipm->h, NULL))
|
||||
return NULL;
|
||||
|
||||
if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) {
|
||||
if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0)
|
||||
auth_domain_put(&ipm->m_client->h);
|
||||
rv = NULL;
|
||||
} else {
|
||||
rv = &ipm->m_client->h;
|
||||
cache_get(&rv->h);
|
||||
}
|
||||
ip_map_put(&ipm->h, &ip_map_cache);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void svcauth_unix_purge(void)
|
||||
{
|
||||
cache_purge(&ip_map_cache);
|
||||
cache_purge(&auth_domain_cache);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp)
|
||||
{
|
||||
struct kvec *argv = &rqstp->rq_arg.head[0];
|
||||
struct kvec *resv = &rqstp->rq_res.head[0];
|
||||
int rv=0;
|
||||
struct ip_map key, *ipm;
|
||||
|
||||
if (argv->iov_len < 3*4)
|
||||
return SVC_GARBAGE;
|
||||
|
||||
if (svc_getu32(argv) != 0) {
|
||||
dprintk("svc: bad null cred\n");
|
||||
*authp = rpc_autherr_badcred;
|
||||
return SVC_DENIED;
|
||||
}
|
||||
if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
|
||||
dprintk("svc: bad null verf\n");
|
||||
*authp = rpc_autherr_badverf;
|
||||
return SVC_DENIED;
|
||||
}
|
||||
|
||||
/* Signal that mapping to nobody uid/gid is required */
|
||||
rqstp->rq_cred.cr_uid = (uid_t) -1;
|
||||
rqstp->rq_cred.cr_gid = (gid_t) -1;
|
||||
rqstp->rq_cred.cr_group_info = groups_alloc(0);
|
||||
if (rqstp->rq_cred.cr_group_info == NULL)
|
||||
return SVC_DROP; /* kmalloc failure - client must retry */
|
||||
|
||||
/* Put NULL verifier */
|
||||
svc_putu32(resv, RPC_AUTH_NULL);
|
||||
svc_putu32(resv, 0);
|
||||
|
||||
strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class);
|
||||
key.m_addr = rqstp->rq_addr.sin_addr;
|
||||
|
||||
ipm = ip_map_lookup(&key, 0);
|
||||
|
||||
rqstp->rq_client = NULL;
|
||||
|
||||
if (ipm)
|
||||
switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
|
||||
case -EAGAIN:
|
||||
rv = SVC_DROP;
|
||||
break;
|
||||
case -ENOENT:
|
||||
rv = SVC_OK; /* 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);
|
||||
rv = SVC_OK;
|
||||
break;
|
||||
default: BUG();
|
||||
}
|
||||
else rv = SVC_DROP;
|
||||
|
||||
if (rqstp->rq_client == NULL && rqstp->rq_proc != 0)
|
||||
*authp = rpc_autherr_badcred;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
svcauth_null_release(struct svc_rqst *rqstp)
|
||||
{
|
||||
if (rqstp->rq_client)
|
||||
auth_domain_put(rqstp->rq_client);
|
||||
rqstp->rq_client = NULL;
|
||||
if (rqstp->rq_cred.cr_group_info)
|
||||
put_group_info(rqstp->rq_cred.cr_group_info);
|
||||
rqstp->rq_cred.cr_group_info = NULL;
|
||||
|
||||
return 0; /* don't drop */
|
||||
}
|
||||
|
||||
|
||||
struct auth_ops svcauth_null = {
|
||||
.name = "null",
|
||||
.owner = THIS_MODULE,
|
||||
.flavour = RPC_AUTH_NULL,
|
||||
.accept = svcauth_null_accept,
|
||||
.release = svcauth_null_release,
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp)
|
||||
{
|
||||
struct kvec *argv = &rqstp->rq_arg.head[0];
|
||||
struct kvec *resv = &rqstp->rq_res.head[0];
|
||||
struct svc_cred *cred = &rqstp->rq_cred;
|
||||
u32 slen, i;
|
||||
int len = argv->iov_len;
|
||||
int rv=0;
|
||||
struct ip_map key, *ipm;
|
||||
|
||||
cred->cr_group_info = NULL;
|
||||
rqstp->rq_client = NULL;
|
||||
|
||||
if ((len -= 3*4) < 0)
|
||||
return SVC_GARBAGE;
|
||||
|
||||
svc_getu32(argv); /* length */
|
||||
svc_getu32(argv); /* time stamp */
|
||||
slen = XDR_QUADLEN(ntohl(svc_getu32(argv))); /* machname length */
|
||||
if (slen > 64 || (len -= (slen + 3)*4) < 0)
|
||||
goto badcred;
|
||||
argv->iov_base = (void*)((u32*)argv->iov_base + slen); /* skip machname */
|
||||
argv->iov_len -= slen*4;
|
||||
|
||||
cred->cr_uid = ntohl(svc_getu32(argv)); /* uid */
|
||||
cred->cr_gid = ntohl(svc_getu32(argv)); /* gid */
|
||||
slen = ntohl(svc_getu32(argv)); /* gids length */
|
||||
if (slen > 16 || (len -= (slen + 2)*4) < 0)
|
||||
goto badcred;
|
||||
cred->cr_group_info = groups_alloc(slen);
|
||||
if (cred->cr_group_info == NULL)
|
||||
return SVC_DROP;
|
||||
for (i = 0; i < slen; i++)
|
||||
GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv));
|
||||
|
||||
if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
|
||||
*authp = rpc_autherr_badverf;
|
||||
return SVC_DENIED;
|
||||
}
|
||||
|
||||
|
||||
strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class);
|
||||
key.m_addr = rqstp->rq_addr.sin_addr;
|
||||
|
||||
|
||||
ipm = ip_map_lookup(&key, 0);
|
||||
|
||||
if (ipm)
|
||||
switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
|
||||
case -EAGAIN:
|
||||
rv = SVC_DROP;
|
||||
break;
|
||||
case -ENOENT:
|
||||
rv = SVC_OK; /* 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);
|
||||
rv = SVC_OK;
|
||||
break;
|
||||
default: BUG();
|
||||
}
|
||||
else rv = SVC_DROP;
|
||||
|
||||
if (rv == SVC_OK && rqstp->rq_client == NULL && rqstp->rq_proc != 0)
|
||||
goto badcred;
|
||||
|
||||
/* Put NULL verifier */
|
||||
svc_putu32(resv, RPC_AUTH_NULL);
|
||||
svc_putu32(resv, 0);
|
||||
|
||||
return rv;
|
||||
|
||||
badcred:
|
||||
*authp = rpc_autherr_badcred;
|
||||
return SVC_DENIED;
|
||||
}
|
||||
|
||||
int
|
||||
svcauth_unix_release(struct svc_rqst *rqstp)
|
||||
{
|
||||
/* Verifier (such as it is) is already in place.
|
||||
*/
|
||||
if (rqstp->rq_client)
|
||||
auth_domain_put(rqstp->rq_client);
|
||||
rqstp->rq_client = NULL;
|
||||
if (rqstp->rq_cred.cr_group_info)
|
||||
put_group_info(rqstp->rq_cred.cr_group_info);
|
||||
rqstp->rq_cred.cr_group_info = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct auth_ops svcauth_unix = {
|
||||
.name = "unix",
|
||||
.owner = THIS_MODULE,
|
||||
.flavour = RPC_AUTH_UNIX,
|
||||
.accept = svcauth_unix_accept,
|
||||
.release = svcauth_unix_release,
|
||||
.domain_release = svcauth_unix_domain_release,
|
||||
};
|
||||
|
||||
1586
extra/linux-2.6.10/net/sunrpc/svcsock.c
Normal file
1586
extra/linux-2.6.10/net/sunrpc/svcsock.c
Normal file
File diff suppressed because it is too large
Load Diff
193
extra/linux-2.6.10/net/sunrpc/sysctl.c
Normal file
193
extra/linux-2.6.10/net/sunrpc/sysctl.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* linux/net/sunrpc/sysctl.c
|
||||
*
|
||||
* Sysctl interface to sunrpc module.
|
||||
*
|
||||
* I would prefer to register the sunrpc table below sys/net, but that's
|
||||
* impossible at the moment.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/sunrpc/types.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
|
||||
/*
|
||||
* Declare the debug flags here
|
||||
*/
|
||||
unsigned int rpc_debug;
|
||||
unsigned int nfs_debug;
|
||||
unsigned int nfsd_debug;
|
||||
unsigned int nlm_debug;
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
|
||||
static struct ctl_table_header *sunrpc_table_header;
|
||||
static ctl_table sunrpc_table[];
|
||||
|
||||
void
|
||||
rpc_register_sysctl(void)
|
||||
{
|
||||
if (!sunrpc_table_header) {
|
||||
sunrpc_table_header = register_sysctl_table(sunrpc_table, 1);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (sunrpc_table[0].de)
|
||||
sunrpc_table[0].de->owner = THIS_MODULE;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
rpc_unregister_sysctl(void)
|
||||
{
|
||||
if (sunrpc_table_header) {
|
||||
unregister_sysctl_table(sunrpc_table_header);
|
||||
sunrpc_table_header = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
proc_dodebug(ctl_table *table, int write, struct file *file,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
char tmpbuf[20], c, *s;
|
||||
char __user *p;
|
||||
unsigned int value;
|
||||
size_t left, len;
|
||||
|
||||
if ((*ppos && !write) || !*lenp) {
|
||||
*lenp = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
left = *lenp;
|
||||
|
||||
if (write) {
|
||||
if (!access_ok(VERIFY_READ, buffer, left))
|
||||
return -EFAULT;
|
||||
p = buffer;
|
||||
while (left && __get_user(c, p) >= 0 && isspace(c))
|
||||
left--, p++;
|
||||
if (!left)
|
||||
goto done;
|
||||
|
||||
if (left > sizeof(tmpbuf) - 1)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(tmpbuf, p, left))
|
||||
return -EFAULT;
|
||||
tmpbuf[left] = '\0';
|
||||
|
||||
for (s = tmpbuf, value = 0; '0' <= *s && *s <= '9'; s++, left--)
|
||||
value = 10 * value + (*s - '0');
|
||||
if (*s && !isspace(*s))
|
||||
return -EINVAL;
|
||||
while (left && isspace(*s))
|
||||
left--, s++;
|
||||
*(unsigned int *) table->data = value;
|
||||
/* Display the RPC tasks on writing to rpc_debug */
|
||||
if (table->ctl_name == CTL_RPCDEBUG) {
|
||||
rpc_show_tasks();
|
||||
}
|
||||
} else {
|
||||
if (!access_ok(VERIFY_WRITE, buffer, left))
|
||||
return -EFAULT;
|
||||
len = sprintf(tmpbuf, "%d", *(unsigned int *) table->data);
|
||||
if (len > left)
|
||||
len = left;
|
||||
if (__copy_to_user(buffer, tmpbuf, len))
|
||||
return -EFAULT;
|
||||
if ((left -= len) > 0) {
|
||||
if (put_user('\n', (char __user *)buffer + len))
|
||||
return -EFAULT;
|
||||
left--;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
*lenp -= left;
|
||||
*ppos += *lenp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE;
|
||||
static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE;
|
||||
|
||||
static ctl_table debug_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_RPCDEBUG,
|
||||
.procname = "rpc_debug",
|
||||
.data = &rpc_debug,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dodebug
|
||||
},
|
||||
{
|
||||
.ctl_name = CTL_NFSDEBUG,
|
||||
.procname = "nfs_debug",
|
||||
.data = &nfs_debug,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dodebug
|
||||
},
|
||||
{
|
||||
.ctl_name = CTL_NFSDDEBUG,
|
||||
.procname = "nfsd_debug",
|
||||
.data = &nfsd_debug,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dodebug
|
||||
},
|
||||
{
|
||||
.ctl_name = CTL_NLMDEBUG,
|
||||
.procname = "nlm_debug",
|
||||
.data = &nlm_debug,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dodebug
|
||||
},
|
||||
{
|
||||
.ctl_name = CTL_SLOTTABLE_UDP,
|
||||
.procname = "udp_slot_table_entries",
|
||||
.data = &xprt_udp_slot_table_entries,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_minmax,
|
||||
.strategy = &sysctl_intvec,
|
||||
.extra1 = &min_slot_table_size,
|
||||
.extra2 = &max_slot_table_size
|
||||
},
|
||||
{
|
||||
.ctl_name = CTL_SLOTTABLE_TCP,
|
||||
.procname = "tcp_slot_table_entries",
|
||||
.data = &xprt_tcp_slot_table_entries,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_minmax,
|
||||
.strategy = &sysctl_intvec,
|
||||
.extra1 = &min_slot_table_size,
|
||||
.extra2 = &max_slot_table_size
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
static ctl_table sunrpc_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_SUNRPC,
|
||||
.procname = "sunrpc",
|
||||
.mode = 0555,
|
||||
.child = debug_table
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
#endif
|
||||
107
extra/linux-2.6.10/net/sunrpc/timer.c
Normal file
107
extra/linux-2.6.10/net/sunrpc/timer.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* linux/net/sunrpc/timer.c
|
||||
*
|
||||
* Estimate RPC request round trip time.
|
||||
*
|
||||
* Based on packet round-trip and variance estimator algorithms described
|
||||
* in appendix A of "Congestion Avoidance and Control" by Van Jacobson
|
||||
* and Michael J. Karels (ACM Computer Communication Review; Proceedings
|
||||
* of the Sigcomm '88 Symposium in Stanford, CA, August, 1988).
|
||||
*
|
||||
* This RTT estimator is used only for RPC over datagram protocols.
|
||||
*
|
||||
* Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
|
||||
*/
|
||||
|
||||
#include <asm/param.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/unistd.h>
|
||||
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/sunrpc/timer.h>
|
||||
|
||||
#define RPC_RTO_MAX (60*HZ)
|
||||
#define RPC_RTO_INIT (HZ/5)
|
||||
#define RPC_RTO_MIN (HZ/10)
|
||||
|
||||
void
|
||||
rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
|
||||
{
|
||||
unsigned long init = 0;
|
||||
unsigned i;
|
||||
|
||||
rt->timeo = timeo;
|
||||
|
||||
if (timeo > RPC_RTO_INIT)
|
||||
init = (timeo - RPC_RTO_INIT) << 3;
|
||||
for (i = 0; i < 5; i++) {
|
||||
rt->srtt[i] = init;
|
||||
rt->sdrtt[i] = RPC_RTO_INIT;
|
||||
rt->ntimeouts[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: When computing the smoothed RTT and standard deviation,
|
||||
* be careful not to produce negative intermediate results.
|
||||
*/
|
||||
void
|
||||
rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m)
|
||||
{
|
||||
long *srtt, *sdrtt;
|
||||
|
||||
if (timer-- == 0)
|
||||
return;
|
||||
|
||||
/* jiffies wrapped; ignore this one */
|
||||
if (m < 0)
|
||||
return;
|
||||
|
||||
if (m == 0)
|
||||
m = 1L;
|
||||
|
||||
srtt = (long *)&rt->srtt[timer];
|
||||
m -= *srtt >> 3;
|
||||
*srtt += m;
|
||||
|
||||
if (m < 0)
|
||||
m = -m;
|
||||
|
||||
sdrtt = (long *)&rt->sdrtt[timer];
|
||||
m -= *sdrtt >> 2;
|
||||
*sdrtt += m;
|
||||
|
||||
/* Set lower bound on the variance */
|
||||
if (*sdrtt < RPC_RTO_MIN)
|
||||
*sdrtt = RPC_RTO_MIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Estimate rto for an nfs rpc sent via. an unreliable datagram.
|
||||
* Use the mean and mean deviation of rtt for the appropriate type of rpc
|
||||
* for the frequent rpcs and a default for the others.
|
||||
* The justification for doing "other" this way is that these rpcs
|
||||
* happen so infrequently that timer est. would probably be stale.
|
||||
* Also, since many of these rpcs are
|
||||
* non-idempotent, a conservative timeout is desired.
|
||||
* getattr, lookup,
|
||||
* read, write, commit - A+4D
|
||||
* other - timeo
|
||||
*/
|
||||
|
||||
unsigned long
|
||||
rpc_calc_rto(struct rpc_rtt *rt, unsigned timer)
|
||||
{
|
||||
unsigned long res;
|
||||
|
||||
if (timer-- == 0)
|
||||
return rt->timeo;
|
||||
|
||||
res = ((rt->srtt[timer] + 7) >> 3) + rt->sdrtt[timer];
|
||||
if (res > RPC_RTO_MAX)
|
||||
res = RPC_RTO_MAX;
|
||||
|
||||
return res;
|
||||
}
|
||||
1040
extra/linux-2.6.10/net/sunrpc/xdr.c
Normal file
1040
extra/linux-2.6.10/net/sunrpc/xdr.c
Normal file
File diff suppressed because it is too large
Load Diff
1672
extra/linux-2.6.10/net/sunrpc/xprt.c
Normal file
1672
extra/linux-2.6.10/net/sunrpc/xprt.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user