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_auth_slack = 0;
  58        init_svc_cred(&rqstp->rq_cred);
  59
  60        rqstp->rq_authop = aops;
  61        return aops->accept(rqstp, authp);
  62}
  63EXPORT_SYMBOL_GPL(svc_authenticate);
  64
  65int svc_set_client(struct svc_rqst *rqstp)
  66{
  67        rqstp->rq_client = NULL;
  68        return rqstp->rq_authop->set_client(rqstp);
  69}
  70EXPORT_SYMBOL_GPL(svc_set_client);
  71
  72/* A request, which was authenticated, has now executed.
  73 * Time to finalise the credentials and verifier
  74 * and release and resources
  75 */
  76int svc_authorise(struct svc_rqst *rqstp)
  77{
  78        struct auth_ops *aops = rqstp->rq_authop;
  79        int rv = 0;
  80
  81        rqstp->rq_authop = NULL;
  82
  83        if (aops) {
  84                rv = aops->release(rqstp);
  85                module_put(aops->owner);
  86        }
  87        return rv;
  88}
  89
  90int
  91svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
  92{
  93        int rv = -EINVAL;
  94        spin_lock(&authtab_lock);
  95        if (flavor < RPC_AUTH_MAXFLAVOR && authtab[flavor] == NULL) {
  96                authtab[flavor] = aops;
  97                rv = 0;
  98        }
  99        spin_unlock(&authtab_lock);
 100        return rv;
 101}
 102EXPORT_SYMBOL_GPL(svc_auth_register);
 103
 104void
 105svc_auth_unregister(rpc_authflavor_t flavor)
 106{
 107        spin_lock(&authtab_lock);
 108        if (flavor < RPC_AUTH_MAXFLAVOR)
 109                authtab[flavor] = NULL;
 110        spin_unlock(&authtab_lock);
 111}
 112EXPORT_SYMBOL_GPL(svc_auth_unregister);
 113
 114/**************************************************
 115 * 'auth_domains' are stored in a hash table indexed by name.
 116 * When the last reference to an 'auth_domain' is dropped,
 117 * the object is unhashed and freed.
 118 * If auth_domain_lookup fails to find an entry, it will return
 119 * it's second argument 'new'.  If this is non-null, it will
 120 * have been atomically linked into the table.
 121 */
 122
 123#define DN_HASHBITS     6
 124#define DN_HASHMAX      (1<<DN_HASHBITS)
 125
 126static struct hlist_head        auth_domain_table[DN_HASHMAX];
 127static spinlock_t       auth_domain_lock =
 128        __SPIN_LOCK_UNLOCKED(auth_domain_lock);
 129
 130void auth_domain_put(struct auth_domain *dom)
 131{
 132        if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) {
 133                hlist_del(&dom->hash);
 134                dom->flavour->domain_release(dom);
 135                spin_unlock(&auth_domain_lock);
 136        }
 137}
 138EXPORT_SYMBOL_GPL(auth_domain_put);
 139
 140struct auth_domain *
 141auth_domain_lookup(char *name, struct auth_domain *new)
 142{
 143        struct auth_domain *hp;
 144        struct hlist_head *head;
 145
 146        head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
 147
 148        spin_lock(&auth_domain_lock);
 149
 150        hlist_for_each_entry(hp, head, hash) {
 151                if (strcmp(hp->name, name)==0) {
 152                        kref_get(&hp->ref);
 153                        spin_unlock(&auth_domain_lock);
 154                        return hp;
 155                }
 156        }
 157        if (new)
 158                hlist_add_head(&new->hash, head);
 159        spin_unlock(&auth_domain_lock);
 160        return new;
 161}
 162EXPORT_SYMBOL_GPL(auth_domain_lookup);
 163
 164struct auth_domain *auth_domain_find(char *name)
 165{
 166        return auth_domain_lookup(name, NULL);
 167}
 168EXPORT_SYMBOL_GPL(auth_domain_find);
 169