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/module.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/types.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/xdr.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/svcsock.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/svcauth.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hash.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RPCDBG_FACILITY	RPCDBG_AUTH
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Table of authenticators
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern struct auth_ops svcauth_null;
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern struct auth_ops svcauth_unix;
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(authtab_lock);
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct auth_ops	*authtab[RPC_AUTH_MAXFLAVOR] = {
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[0] = &svcauth_null,
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[1] = &svcauth_unix,
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
37d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyansvc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rpc_authflavor_t	flavor;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct auth_ops		*aops;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*authp = rpc_auth_ok;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
447699431301b189fca7ccbb64fe54e5a5170f8497Alexey Dobriyan	flavor = svc_getnl(&rqstp->rq_arg.head[0]);
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("svc: svc_authenticate (%d)\n", flavor);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&authtab_lock);
49f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches	if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor]) ||
50f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches	    !try_module_get(aops->owner)) {
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock(&authtab_lock);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*authp = rpc_autherr_badcred;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SVC_DENIED;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&authtab_lock);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
57a5cddc885b99458df963a75abbe0b40cbef56c48J. Bruce Fields	rqstp->rq_auth_slack = 0;
58a5cddc885b99458df963a75abbe0b40cbef56c48J. Bruce Fields
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rqstp->rq_authop = aops;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return aops->accept(rqstp, authp);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6224c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_authenticate);
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint svc_set_client(struct svc_rqst *rqstp)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rqstp->rq_authop->set_client(rqstp);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6824c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_set_client);
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A request, which was authenticated, has now executed.
7159c51591a0ac7568824f541f57de967e88adaa07Michael Opdenacker * Time to finalise the credentials and verifier
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and release and resources
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint svc_authorise(struct svc_rqst *rqstp)
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct auth_ops *aops = rqstp->rq_authop;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rv = 0;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rqstp->rq_authop = NULL;
80cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (aops) {
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rv = aops->release(rqstp);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		module_put(aops->owner);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rv;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssvc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rv = -EINVAL;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&authtab_lock);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flavor < RPC_AUTH_MAXFLAVOR && authtab[flavor] == NULL) {
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		authtab[flavor] = aops;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rv = 0;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&authtab_lock);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rv;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10024c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_auth_register);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssvc_auth_unregister(rpc_authflavor_t flavor)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&authtab_lock);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flavor < RPC_AUTH_MAXFLAVOR)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		authtab[flavor] = NULL;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&authtab_lock);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11024c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(svc_auth_unregister);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**************************************************
113efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * 'auth_domains' are stored in a hash table indexed by name.
114efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * When the last reference to an 'auth_domain' is dropped,
115efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * the object is unhashed and freed.
116efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * If auth_domain_lookup fails to find an entry, it will return
117efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * it's second argument 'new'.  If this is non-null, it will
118efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown * have been atomically linked into the table.
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DN_HASHBITS	6
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DN_HASHMAX	(1<<DN_HASHBITS)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
124efc36aa5608f5717338747e152c23f2cfdb14697NeilBrownstatic struct hlist_head	auth_domain_table[DN_HASHMAX];
1256cfd76a26d9fe2ba54b9d496a48c1d9285e5c5edPeter Zijlstrastatic spinlock_t	auth_domain_lock =
1266cfd76a26d9fe2ba54b9d496a48c1d9285e5c5edPeter Zijlstra	__SPIN_LOCK_UNLOCKED(auth_domain_lock);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid auth_domain_put(struct auth_domain *dom)
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
130efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) {
131efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown		hlist_del(&dom->hash);
132efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown		dom->flavour->domain_release(dom);
1330c7bb31db0e35d4b772fac452b722460ca368acfAkinobu Mita		spin_unlock(&auth_domain_lock);
134efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	}
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13624c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(auth_domain_put);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct auth_domain *
139efc36aa5608f5717338747e152c23f2cfdb14697NeilBrownauth_domain_lookup(char *name, struct auth_domain *new)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
141efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	struct auth_domain *hp;
142efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	struct hlist_head *head;
143efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown
144efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
145efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown
146efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	spin_lock(&auth_domain_lock);
147efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown
148b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin	hlist_for_each_entry(hp, head, hash) {
149efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown		if (strcmp(hp->name, name)==0) {
150efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown			kref_get(&hp->ref);
151efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown			spin_unlock(&auth_domain_lock);
152efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown			return hp;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
155d6740df98e12a8e49ef3a699dcc1e2913f22c51bNeil Brown	if (new)
156efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown		hlist_add_head(&new->hash, head);
157efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	spin_unlock(&auth_domain_lock);
158efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	return new;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16024c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(auth_domain_lookup);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct auth_domain *auth_domain_find(char *name)
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
164efc36aa5608f5717338747e152c23f2cfdb14697NeilBrown	return auth_domain_lookup(name, NULL);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16624c3767e41a6a59d32bb45abe899eb194e6bf1b8Trond MyklebustEXPORT_SYMBOL_GPL(auth_domain_find);
167