linux/net/sunrpc/svcauth.c
<<
>>
Prefs
   1/*
   2 * linux/net/sunrpc/svcauth.c
   3 *
   4 * The generic interface for RPC authentication on the server side.
   5 *
   6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   7 *
   8 * CHANGES
   9 * 19-Apr-2000 Chris Evans      - Security fix
  10 */
  11
  12#include <linux/types.h>
  13#include <linux/module.h>
  14#include <linux/sunrpc/types.h>
  15#include <linux/sunrpc/xdr.h>
  16#include <linux/sunrpc/svcsock.h>
  17#include <linux/sunrpc/svcauth.h>
  18#include <linux/err.h>
  19#include <linux/hash.h>
  20
  21#define RPCDBG_FACILITY RPCDBG_AUTH
  22
  23
  24/*
  25 * Table of authenticators
  26 */
  27extern struct auth_ops svcauth_null;
  28extern struct auth_ops svcauth_unix;
  29
  30static DEFINE_SPINLOCK(authtab_lock);
  31static struct auth_ops  *authtab[RPC_AUTH_MAXFLAVOR] = {
  32        [0] = &svcauth_null,
  33        [1] = &svcauth_unix,
  34};
  35
  36int
  37svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
  38{
  39        rpc_authflavor_t        flavor;
  40        struct auth_ops         *aops;
  41
  42        *authp = rpc_auth_ok;
  43
  44        flavor = svc_getnl(&rqstp->rq_arg.head[0]);
  45
  46        dprintk("svc: svc_authenticate (%d)\n", flavor);
  47
  48        spin_lock(&authtab_lock);
  49        if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor]) ||
  50            !try_module_get(aops->owner)) {
  51                spin_unlock(&authtab_lock);
  52                *authp = rpc_autherr_badcred;
  53                return SVC_DENIED;
  54        }
  55        spin_unlock(&authtab_lock);
  56
  57        rqstp->rq_authop = aops;
  58        return aops->accept(rqstp, authp);
  59}
  60EXPORT_SYMBOL_GPL(svc_authenticate);
  61
  62int svc_set_client(struct svc_rqst *rqstp)
  63{
  64        return rqstp->rq_authop->set_client(rqstp);
  65}
  66EXPORT_SYMBOL_GPL(svc_set_client);
  67
  68/* A request, which was authenticated, has now executed.
  69 * Time to finalise the credentials and verifier
  70 * and release and resources
  71 */
  72int svc_authorise(struct svc_rqst *rqstp)
  73{
  74        struct auth_ops *aops = rqstp->rq_authop;
  75        int rv = 0;
  76
  77        rqstp->rq_authop = NULL;
  78
  79        if (aops) {
  80                rv = aops->release(rqstp);
  81                module_put(aops->owner);
  82        }
  83        return rv;
  84}
  85
  86int
  87svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
  88{
  89        int rv = -EINVAL;
  90        spin_lock(&authtab_lock);
  91        if (flavor < RPC_AUTH_MAXFLAVOR && authtab[flavor] == NULL) {
  92                authtab[flavor] = aops;
  93                rv = 0;
  94        }
  95        spin_unlock(&authtab_lock);
  96        return rv;
  97}
  98EXPORT_SYMBOL_GPL(svc_auth_register);
  99
 100void
 101svc_auth_unregister(rpc_authflavor_t flavor)
 102{
 103        spin_lock(&authtab_lock);
 104        if (flavor < RPC_AUTH_MAXFLAVOR)
 105                authtab[flavor] = NULL;
 106        spin_unlock(&authtab_lock);
 107}
 108EXPORT_SYMBOL_GPL(svc_auth_unregister);
 109
 110/**************************************************
 111 * 'auth_domains' are stored in a hash table indexed by name.
 112 * When the last reference to an 'auth_domain' is dropped,
 113 * the object is unhashed and freed.
 114 * If auth_domain_lookup fails to find an entry, it will return
 115 * it's second argument 'new'.  If this is non-null, it will
 116 * have been atomically linked into the table.
 117 */
 118
 119#define DN_HASHBITS     6
 120#define DN_HASHMAX      (1<<DN_HASHBITS)
 121
 122static struct hlist_head        auth_domain_table[DN_HASHMAX];
 123static spinlock_t       auth_domain_lock =
 124        __SPIN_LOCK_UNLOCKED(auth_domain_lock);
 125
 126void auth_domain_put(struct auth_domain *dom)
 127{
 128        if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) {
 129                hlist_del(&dom->hash);
 130                dom->flavour->domain_release(dom);
 131                spin_unlock(&auth_domain_lock);
 132        }
 133}
 134EXPORT_SYMBOL_GPL(auth_domain_put);
 135
 136struct auth_domain *
 137auth_domain_lookup(char *name, struct auth_domain *new)
 138{
 139        struct auth_domain *hp;
 140        struct hlist_head *head;
 141
 142        head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
 143
 144        spin_lock(&auth_domain_lock);
 145
 146        hlist_for_each_entry(hp, head, hash) {
 147                if (strcmp(hp->name, name)==0) {
 148                        kref_get(&hp->ref);
 149                        spin_unlock(&auth_domain_lock);
 150                        return hp;
 151                }
 152        }
 153        if (new)
 154                hlist_add_head(&new->hash, head);
 155        spin_unlock(&auth_domain_lock);
 156        return new;
 157}
 158EXPORT_SYMBOL_GPL(auth_domain_lookup);
 159
 160struct auth_domain *auth_domain_find(char *name)
 161{
 162        return auth_domain_lookup(name, NULL);
 163}
 164EXPORT_SYMBOL_GPL(auth_domain_find);
 165