svcauth.c revision cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/net/sunrpc/svcauth.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The generic interface for RPC authentication on the server side.
5cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CHANGES
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 19-Apr-2000 Chris Evans      - Security fix
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/types.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/xdr.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/svcsock.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/svcauth.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hash.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RPCDBG_FACILITY	RPCDBG_AUTH
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Table of authenticators
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern struct auth_ops svcauth_null;
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern struct auth_ops svcauth_unix;
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(authtab_lock);
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct auth_ops	*authtab[RPC_AUTH_MAXFLAVOR] = {
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[0] = &svcauth_null,
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[1] = &svcauth_unix,
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
38d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyansvc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rpc_authflavor_t	flavor;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct auth_ops		*aops;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*authp = rpc_auth_ok;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
457699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	flavor = svc_getnl(&rqstp->rq_arg.head[0]);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("svc: svc_authenticate (%d)\n", flavor);
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&authtab_lock);
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor])
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| !try_module_get(aops->owner)) {
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock(&authtab_lock);
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*authp = rpc_autherr_badcred;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SVC_DENIED;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&authtab_lock);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rqstp->rq_authop = aops;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return aops->accept(rqstp, authp);
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint svc_set_client(struct svc_rqst *rqstp)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rqstp->rq_authop->set_client(rqstp);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A request, which was authenticated, has now executed.
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Time to finalise the the credentials and verifier
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and release and resources
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint svc_authorise(struct svc_rqst *rqstp)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct auth_ops *aops = rqstp->rq_authop;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rv = 0;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rqstp->rq_authop = NULL;
77cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (aops) {
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rv = aops->release(rqstp);
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		module_put(aops->owner);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rv;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssvc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rv = -EINVAL;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&authtab_lock);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flavor < RPC_AUTH_MAXFLAVOR && authtab[flavor] == NULL) {
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		authtab[flavor] = aops;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rv = 0;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&authtab_lock);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rv;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssvc_auth_unregister(rpc_authflavor_t flavor)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&authtab_lock);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flavor < RPC_AUTH_MAXFLAVOR)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		authtab[flavor] = NULL;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&authtab_lock);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(svc_auth_unregister);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**************************************************
109efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * 'auth_domains' are stored in a hash table indexed by name.
110efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * When the last reference to an 'auth_domain' is dropped,
111efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * the object is unhashed and freed.
112efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * If auth_domain_lookup fails to find an entry, it will return
113efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * it's second argument 'new'.  If this is non-null, it will
114efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * have been atomically linked into the table.
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DN_HASHBITS	6
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DN_HASHMAX	(1<<DN_HASHBITS)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DN_HASHMASK	(DN_HASHMAX-1)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121efc36aa5608f5717338747e152c23f2cfdb14697NeilBrownstatic struct hlist_head	auth_domain_table[DN_HASHMAX];
1226cfd76a26d9fe2ba54b9d496a48c1d9285e5c5edPeter Zijlstrastatic spinlock_t	auth_domain_lock =
1236cfd76a26d9fe2ba54b9d496a48c1d9285e5c5edPeter Zijlstra	__SPIN_LOCK_UNLOCKED(auth_domain_lock);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid auth_domain_put(struct auth_domain *dom)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
127efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) {
128efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown		hlist_del(&dom->hash);
129efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown		dom->flavour->domain_release(dom);
1300c7bb31db0e35d4b772fac452b722460ca368acfAkinobu Mita		spin_unlock(&auth_domain_lock);
131efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct auth_domain *
135efc36aa5608f5717338747e152c23f2cfdb14697NeilBrownauth_domain_lookup(char *name, struct auth_domain *new)
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
137efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	struct auth_domain *hp;
138efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	struct hlist_head *head;
139efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	struct hlist_node *np;
140efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown
141efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
142efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown
143efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	spin_lock(&auth_domain_lock);
144efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown
145efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	hlist_for_each_entry(hp, np, head, hash) {
146efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown		if (strcmp(hp->name, name)==0) {
147efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown			kref_get(&hp->ref);
148efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown			spin_unlock(&auth_domain_lock);
149efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown			return hp;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
152d6740df98e12a8e49ef3a699dcc1e2913f22c51bNeil Brown	if (new)
153efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown		hlist_add_head(&new->hash, head);
154efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	spin_unlock(&auth_domain_lock);
155efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	return new;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct auth_domain *auth_domain_find(char *name)
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
160efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	return auth_domain_lookup(name, NULL);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
162