~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/sunrpc/svcauth.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * linux/net/sunrpc/svcauth.c
  4  *
  5  * The generic interface for RPC authentication on the server side.
  6  *
  7  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
  8  *
  9  * CHANGES
 10  * 19-Apr-2000 Chris Evans      - Security fix
 11  */
 12 
 13 #include <linux/types.h>
 14 #include <linux/module.h>
 15 #include <linux/sunrpc/types.h>
 16 #include <linux/sunrpc/xdr.h>
 17 #include <linux/sunrpc/svcsock.h>
 18 #include <linux/sunrpc/svcauth.h>
 19 #include <linux/err.h>
 20 #include <linux/hash.h>
 21 
 22 #include <trace/events/sunrpc.h>
 23 
 24 #include "sunrpc.h"
 25 
 26 #define RPCDBG_FACILITY RPCDBG_AUTH
 27 
 28 
 29 /*
 30  * Table of authenticators
 31  */
 32 extern struct auth_ops svcauth_null;
 33 extern struct auth_ops svcauth_unix;
 34 extern struct auth_ops svcauth_tls;
 35 
 36 static struct auth_ops __rcu *authtab[RPC_AUTH_MAXFLAVOR] = {
 37         [RPC_AUTH_NULL] = (struct auth_ops __force __rcu *)&svcauth_null,
 38         [RPC_AUTH_UNIX] = (struct auth_ops __force __rcu *)&svcauth_unix,
 39         [RPC_AUTH_TLS]  = (struct auth_ops __force __rcu *)&svcauth_tls,
 40 };
 41 
 42 static struct auth_ops *
 43 svc_get_auth_ops(rpc_authflavor_t flavor)
 44 {
 45         struct auth_ops         *aops;
 46 
 47         if (flavor >= RPC_AUTH_MAXFLAVOR)
 48                 return NULL;
 49         rcu_read_lock();
 50         aops = rcu_dereference(authtab[flavor]);
 51         if (aops != NULL && !try_module_get(aops->owner))
 52                 aops = NULL;
 53         rcu_read_unlock();
 54         return aops;
 55 }
 56 
 57 static void
 58 svc_put_auth_ops(struct auth_ops *aops)
 59 {
 60         module_put(aops->owner);
 61 }
 62 
 63 /**
 64  * svc_authenticate - Initialize an outgoing credential
 65  * @rqstp: RPC execution context
 66  *
 67  * Return values:
 68  *   %SVC_OK: XDR encoding of the result can begin
 69  *   %SVC_DENIED: Credential or verifier is not valid
 70  *   %SVC_GARBAGE: Failed to decode credential or verifier
 71  *   %SVC_COMPLETE: GSS context lifetime event; no further action
 72  *   %SVC_DROP: Drop this request; no further action
 73  *   %SVC_CLOSE: Like drop, but also close transport connection
 74  */
 75 enum svc_auth_status svc_authenticate(struct svc_rqst *rqstp)
 76 {
 77         struct auth_ops *aops;
 78         u32 flavor;
 79 
 80         rqstp->rq_auth_stat = rpc_auth_ok;
 81 
 82         /*
 83          * Decode the Call credential's flavor field. The credential's
 84          * body field is decoded in the chosen ->accept method below.
 85          */
 86         if (xdr_stream_decode_u32(&rqstp->rq_arg_stream, &flavor) < 0)
 87                 return SVC_GARBAGE;
 88 
 89         aops = svc_get_auth_ops(flavor);
 90         if (aops == NULL) {
 91                 rqstp->rq_auth_stat = rpc_autherr_badcred;
 92                 return SVC_DENIED;
 93         }
 94 
 95         rqstp->rq_auth_slack = 0;
 96         init_svc_cred(&rqstp->rq_cred);
 97 
 98         rqstp->rq_authop = aops;
 99         return aops->accept(rqstp);
100 }
101 EXPORT_SYMBOL_GPL(svc_authenticate);
102 
103 /**
104  * svc_set_client - Assign an appropriate 'auth_domain' as the client
105  * @rqstp: RPC execution context
106  *
107  * Return values:
108  *   %SVC_OK: Client was found and assigned
109  *   %SVC_DENY: Client was explicitly denied
110  *   %SVC_DROP: Ignore this request
111  *   %SVC_CLOSE: Ignore this request and close the connection
112  */
113 enum svc_auth_status svc_set_client(struct svc_rqst *rqstp)
114 {
115         rqstp->rq_client = NULL;
116         return rqstp->rq_authop->set_client(rqstp);
117 }
118 EXPORT_SYMBOL_GPL(svc_set_client);
119 
120 /**
121  * svc_authorise - Finalize credentials/verifier and release resources
122  * @rqstp: RPC execution context
123  *
124  * Returns zero on success, or a negative errno.
125  */
126 int svc_authorise(struct svc_rqst *rqstp)
127 {
128         struct auth_ops *aops = rqstp->rq_authop;
129         int rv = 0;
130 
131         rqstp->rq_authop = NULL;
132 
133         if (aops) {
134                 rv = aops->release(rqstp);
135                 svc_put_auth_ops(aops);
136         }
137         return rv;
138 }
139 
140 int
141 svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
142 {
143         struct auth_ops *old;
144         int rv = -EINVAL;
145 
146         if (flavor < RPC_AUTH_MAXFLAVOR) {
147                 old = cmpxchg((struct auth_ops ** __force)&authtab[flavor], NULL, aops);
148                 if (old == NULL || old == aops)
149                         rv = 0;
150         }
151         return rv;
152 }
153 EXPORT_SYMBOL_GPL(svc_auth_register);
154 
155 void
156 svc_auth_unregister(rpc_authflavor_t flavor)
157 {
158         if (flavor < RPC_AUTH_MAXFLAVOR)
159                 rcu_assign_pointer(authtab[flavor], NULL);
160 }
161 EXPORT_SYMBOL_GPL(svc_auth_unregister);
162 
163 /**
164  * svc_auth_flavor - return RPC transaction's RPC_AUTH flavor
165  * @rqstp: RPC transaction context
166  *
167  * Returns an RPC flavor or GSS pseudoflavor.
168  */
169 rpc_authflavor_t svc_auth_flavor(struct svc_rqst *rqstp)
170 {
171         struct auth_ops *aops = rqstp->rq_authop;
172 
173         if (!aops->pseudoflavor)
174                 return aops->flavour;
175         return aops->pseudoflavor(rqstp);
176 }
177 EXPORT_SYMBOL_GPL(svc_auth_flavor);
178 
179 /**************************************************
180  * 'auth_domains' are stored in a hash table indexed by name.
181  * When the last reference to an 'auth_domain' is dropped,
182  * the object is unhashed and freed.
183  * If auth_domain_lookup fails to find an entry, it will return
184  * it's second argument 'new'.  If this is non-null, it will
185  * have been atomically linked into the table.
186  */
187 
188 #define DN_HASHBITS     6
189 #define DN_HASHMAX      (1<<DN_HASHBITS)
190 
191 static struct hlist_head        auth_domain_table[DN_HASHMAX];
192 static DEFINE_SPINLOCK(auth_domain_lock);
193 
194 static void auth_domain_release(struct kref *kref)
195         __releases(&auth_domain_lock)
196 {
197         struct auth_domain *dom = container_of(kref, struct auth_domain, ref);
198 
199         hlist_del_rcu(&dom->hash);
200         dom->flavour->domain_release(dom);
201         spin_unlock(&auth_domain_lock);
202 }
203 
204 void auth_domain_put(struct auth_domain *dom)
205 {
206         kref_put_lock(&dom->ref, auth_domain_release, &auth_domain_lock);
207 }
208 EXPORT_SYMBOL_GPL(auth_domain_put);
209 
210 struct auth_domain *
211 auth_domain_lookup(char *name, struct auth_domain *new)
212 {
213         struct auth_domain *hp;
214         struct hlist_head *head;
215 
216         head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
217 
218         spin_lock(&auth_domain_lock);
219 
220         hlist_for_each_entry(hp, head, hash) {
221                 if (strcmp(hp->name, name)==0) {
222                         kref_get(&hp->ref);
223                         spin_unlock(&auth_domain_lock);
224                         return hp;
225                 }
226         }
227         if (new)
228                 hlist_add_head_rcu(&new->hash, head);
229         spin_unlock(&auth_domain_lock);
230         return new;
231 }
232 EXPORT_SYMBOL_GPL(auth_domain_lookup);
233 
234 struct auth_domain *auth_domain_find(char *name)
235 {
236         struct auth_domain *hp;
237         struct hlist_head *head;
238 
239         head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
240 
241         rcu_read_lock();
242         hlist_for_each_entry_rcu(hp, head, hash) {
243                 if (strcmp(hp->name, name)==0) {
244                         if (!kref_get_unless_zero(&hp->ref))
245                                 hp = NULL;
246                         rcu_read_unlock();
247                         return hp;
248                 }
249         }
250         rcu_read_unlock();
251         return NULL;
252 }
253 EXPORT_SYMBOL_GPL(auth_domain_find);
254 
255 /**
256  * auth_domain_cleanup - check that the auth_domain table is empty
257  *
258  * On module unload the auth_domain_table must be empty.  To make it
259  * easier to catch bugs which don't clean up domains properly, we
260  * warn if anything remains in the table at cleanup time.
261  *
262  * Note that we cannot proactively remove the domains at this stage.
263  * The ->release() function might be in a module that has already been
264  * unloaded.
265  */
266 
267 void auth_domain_cleanup(void)
268 {
269         int h;
270         struct auth_domain *hp;
271 
272         for (h = 0; h < DN_HASHMAX; h++)
273                 hlist_for_each_entry(hp, &auth_domain_table[h], hash)
274                         pr_warn("svc: domain %s still present at module unload.\n",
275                                 hp->name);
276 }
277 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php