Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/net/sunrpc/svcauth.c
0004  *
0005  * The generic interface for RPC authentication on the server side.
0006  *
0007  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
0008  *
0009  * CHANGES
0010  * 19-Apr-2000 Chris Evans      - Security fix
0011  */
0012 
0013 #include <linux/types.h>
0014 #include <linux/module.h>
0015 #include <linux/sunrpc/types.h>
0016 #include <linux/sunrpc/xdr.h>
0017 #include <linux/sunrpc/svcsock.h>
0018 #include <linux/sunrpc/svcauth.h>
0019 #include <linux/err.h>
0020 #include <linux/hash.h>
0021 
0022 #include <trace/events/sunrpc.h>
0023 
0024 #include "sunrpc.h"
0025 
0026 #define RPCDBG_FACILITY RPCDBG_AUTH
0027 
0028 
0029 /*
0030  * Table of authenticators
0031  */
0032 extern struct auth_ops svcauth_null;
0033 extern struct auth_ops svcauth_unix;
0034 extern struct auth_ops svcauth_tls;
0035 
0036 static struct auth_ops __rcu *authtab[RPC_AUTH_MAXFLAVOR] = {
0037     [RPC_AUTH_NULL] = (struct auth_ops __force __rcu *)&svcauth_null,
0038     [RPC_AUTH_UNIX] = (struct auth_ops __force __rcu *)&svcauth_unix,
0039     [RPC_AUTH_TLS]  = (struct auth_ops __force __rcu *)&svcauth_tls,
0040 };
0041 
0042 static struct auth_ops *
0043 svc_get_auth_ops(rpc_authflavor_t flavor)
0044 {
0045     struct auth_ops     *aops;
0046 
0047     if (flavor >= RPC_AUTH_MAXFLAVOR)
0048         return NULL;
0049     rcu_read_lock();
0050     aops = rcu_dereference(authtab[flavor]);
0051     if (aops != NULL && !try_module_get(aops->owner))
0052         aops = NULL;
0053     rcu_read_unlock();
0054     return aops;
0055 }
0056 
0057 static void
0058 svc_put_auth_ops(struct auth_ops *aops)
0059 {
0060     module_put(aops->owner);
0061 }
0062 
0063 int
0064 svc_authenticate(struct svc_rqst *rqstp)
0065 {
0066     rpc_authflavor_t    flavor;
0067     struct auth_ops     *aops;
0068 
0069     rqstp->rq_auth_stat = rpc_auth_ok;
0070 
0071     flavor = svc_getnl(&rqstp->rq_arg.head[0]);
0072 
0073     dprintk("svc: svc_authenticate (%d)\n", flavor);
0074 
0075     aops = svc_get_auth_ops(flavor);
0076     if (aops == NULL) {
0077         rqstp->rq_auth_stat = rpc_autherr_badcred;
0078         return SVC_DENIED;
0079     }
0080 
0081     rqstp->rq_auth_slack = 0;
0082     init_svc_cred(&rqstp->rq_cred);
0083 
0084     rqstp->rq_authop = aops;
0085     return aops->accept(rqstp);
0086 }
0087 EXPORT_SYMBOL_GPL(svc_authenticate);
0088 
0089 int svc_set_client(struct svc_rqst *rqstp)
0090 {
0091     rqstp->rq_client = NULL;
0092     return rqstp->rq_authop->set_client(rqstp);
0093 }
0094 EXPORT_SYMBOL_GPL(svc_set_client);
0095 
0096 /* A request, which was authenticated, has now executed.
0097  * Time to finalise the credentials and verifier
0098  * and release and resources
0099  */
0100 int svc_authorise(struct svc_rqst *rqstp)
0101 {
0102     struct auth_ops *aops = rqstp->rq_authop;
0103     int rv = 0;
0104 
0105     rqstp->rq_authop = NULL;
0106 
0107     if (aops) {
0108         rv = aops->release(rqstp);
0109         svc_put_auth_ops(aops);
0110     }
0111     return rv;
0112 }
0113 
0114 int
0115 svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
0116 {
0117     struct auth_ops *old;
0118     int rv = -EINVAL;
0119 
0120     if (flavor < RPC_AUTH_MAXFLAVOR) {
0121         old = cmpxchg((struct auth_ops ** __force)&authtab[flavor], NULL, aops);
0122         if (old == NULL || old == aops)
0123             rv = 0;
0124     }
0125     return rv;
0126 }
0127 EXPORT_SYMBOL_GPL(svc_auth_register);
0128 
0129 void
0130 svc_auth_unregister(rpc_authflavor_t flavor)
0131 {
0132     if (flavor < RPC_AUTH_MAXFLAVOR)
0133         rcu_assign_pointer(authtab[flavor], NULL);
0134 }
0135 EXPORT_SYMBOL_GPL(svc_auth_unregister);
0136 
0137 /**************************************************
0138  * 'auth_domains' are stored in a hash table indexed by name.
0139  * When the last reference to an 'auth_domain' is dropped,
0140  * the object is unhashed and freed.
0141  * If auth_domain_lookup fails to find an entry, it will return
0142  * it's second argument 'new'.  If this is non-null, it will
0143  * have been atomically linked into the table.
0144  */
0145 
0146 #define DN_HASHBITS 6
0147 #define DN_HASHMAX  (1<<DN_HASHBITS)
0148 
0149 static struct hlist_head    auth_domain_table[DN_HASHMAX];
0150 static DEFINE_SPINLOCK(auth_domain_lock);
0151 
0152 static void auth_domain_release(struct kref *kref)
0153     __releases(&auth_domain_lock)
0154 {
0155     struct auth_domain *dom = container_of(kref, struct auth_domain, ref);
0156 
0157     hlist_del_rcu(&dom->hash);
0158     dom->flavour->domain_release(dom);
0159     spin_unlock(&auth_domain_lock);
0160 }
0161 
0162 void auth_domain_put(struct auth_domain *dom)
0163 {
0164     kref_put_lock(&dom->ref, auth_domain_release, &auth_domain_lock);
0165 }
0166 EXPORT_SYMBOL_GPL(auth_domain_put);
0167 
0168 struct auth_domain *
0169 auth_domain_lookup(char *name, struct auth_domain *new)
0170 {
0171     struct auth_domain *hp;
0172     struct hlist_head *head;
0173 
0174     head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
0175 
0176     spin_lock(&auth_domain_lock);
0177 
0178     hlist_for_each_entry(hp, head, hash) {
0179         if (strcmp(hp->name, name)==0) {
0180             kref_get(&hp->ref);
0181             spin_unlock(&auth_domain_lock);
0182             return hp;
0183         }
0184     }
0185     if (new)
0186         hlist_add_head_rcu(&new->hash, head);
0187     spin_unlock(&auth_domain_lock);
0188     return new;
0189 }
0190 EXPORT_SYMBOL_GPL(auth_domain_lookup);
0191 
0192 struct auth_domain *auth_domain_find(char *name)
0193 {
0194     struct auth_domain *hp;
0195     struct hlist_head *head;
0196 
0197     head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
0198 
0199     rcu_read_lock();
0200     hlist_for_each_entry_rcu(hp, head, hash) {
0201         if (strcmp(hp->name, name)==0) {
0202             if (!kref_get_unless_zero(&hp->ref))
0203                 hp = NULL;
0204             rcu_read_unlock();
0205             return hp;
0206         }
0207     }
0208     rcu_read_unlock();
0209     return NULL;
0210 }
0211 EXPORT_SYMBOL_GPL(auth_domain_find);
0212 
0213 /**
0214  * auth_domain_cleanup - check that the auth_domain table is empty
0215  *
0216  * On module unload the auth_domain_table must be empty.  To make it
0217  * easier to catch bugs which don't clean up domains properly, we
0218  * warn if anything remains in the table at cleanup time.
0219  *
0220  * Note that we cannot proactively remove the domains at this stage.
0221  * The ->release() function might be in a module that has already been
0222  * unloaded.
0223  */
0224 
0225 void auth_domain_cleanup(void)
0226 {
0227     int h;
0228     struct auth_domain *hp;
0229 
0230     for (h = 0; h < DN_HASHMAX; h++)
0231         hlist_for_each_entry(hp, &auth_domain_table[h], hash)
0232             pr_warn("svc: domain %s still present at module unload.\n",
0233                 hp->name);
0234 }