2 * linux/fs/nfs/rpcauth.c
4 * Generic RPC authentication API.
6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
8 * Modified May 1999, Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
11 #include <linux/types.h>
12 #include <linux/string.h>
13 #include <linux/sched.h>
14 #include <linux/malloc.h>
15 #include <linux/errno.h>
16 #include <linux/socket.h>
17 #include <linux/sunrpc/clnt.h>
20 # define RPCDBG_FACILITY RPCDBG_AUTH
23 #define RPC_MAXFLAVOR 8
25 static struct rpc_authops
* auth_flavors
[RPC_MAXFLAVOR
] = {
26 &authnull_ops
, /* AUTH_NULL */
27 &authunix_ops
, /* AUTH_UNIX */
28 NULL
, /* others can be loadable modules */
32 rpcauth_register(struct rpc_authops
*ops
)
36 if ((flavor
= ops
->au_flavor
) >= RPC_MAXFLAVOR
)
38 if (auth_flavors
[flavor
] != NULL
)
39 return -EPERM
; /* what else? */
40 auth_flavors
[flavor
] = ops
;
45 rpcauth_unregister(struct rpc_authops
*ops
)
49 if ((flavor
= ops
->au_flavor
) >= RPC_MAXFLAVOR
)
51 if (auth_flavors
[flavor
] != ops
)
52 return -EPERM
; /* what else? */
53 auth_flavors
[flavor
] = NULL
;
58 rpcauth_create(unsigned int flavor
, struct rpc_clnt
*clnt
)
60 struct rpc_authops
*ops
;
62 if (flavor
>= RPC_MAXFLAVOR
|| !(ops
= auth_flavors
[flavor
]))
64 clnt
->cl_auth
= ops
->create(clnt
);
69 rpcauth_destroy(struct rpc_auth
*auth
)
71 auth
->au_ops
->destroy(auth
);
75 * Initialize RPC credential cache
78 rpcauth_init_credcache(struct rpc_auth
*auth
)
80 memset(auth
->au_credcache
, 0, sizeof(auth
->au_credcache
));
81 auth
->au_nextgc
= jiffies
+ (auth
->au_expire
>> 1);
85 * Clear the RPC credential cache
88 rpcauth_free_credcache(struct rpc_auth
*auth
)
90 struct rpc_cred
**q
, *cred
;
91 void (*destroy
)(struct rpc_cred
*);
94 if (!(destroy
= auth
->au_ops
->crdestroy
))
95 destroy
= (void (*)(struct rpc_cred
*)) rpc_free
;
97 for (i
= 0; i
< RPC_CREDCACHE_NR
; i
++) {
98 q
= &auth
->au_credcache
[i
];
99 while ((cred
= *q
) != NULL
) {
107 * Remove stale credentials. Avoid sleeping inside the loop.
110 rpcauth_gc_credcache(struct rpc_auth
*auth
)
112 struct rpc_cred
**q
, *cred
, *free
= NULL
;
115 dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth
);
116 for (i
= 0; i
< RPC_CREDCACHE_NR
; i
++) {
117 q
= &auth
->au_credcache
[i
];
118 while ((cred
= *q
) != NULL
) {
120 printk("RPC: rpcauth_gc_credcache looping!\n");
123 if (!cred
->cr_count
&& time_before(cred
->cr_expire
, jiffies
)) {
125 cred
->cr_next
= free
;
132 while ((cred
= free
) != NULL
) {
133 free
= cred
->cr_next
;
136 auth
->au_nextgc
= jiffies
+ auth
->au_expire
;
140 * Insert credential into cache
143 rpcauth_insert_credcache(struct rpc_auth
*auth
, struct rpc_cred
*cred
)
147 nr
= (cred
->cr_uid
% RPC_CREDCACHE_NR
);
148 cred
->cr_next
= auth
->au_credcache
[nr
];
149 auth
->au_credcache
[nr
] = cred
;
150 cred
->cr_expire
= jiffies
+ auth
->au_expire
;
155 * Look up a process' credentials in the authentication cache
157 static struct rpc_cred
*
158 rpcauth_lookup_credcache(struct rpc_task
*task
)
160 struct rpc_auth
*auth
= task
->tk_auth
;
161 struct rpc_cred
**q
, *cred
= NULL
;
164 nr
= RPC_DO_ROOTOVERRIDE(task
)? 0 : (current
->uid
% RPC_CREDCACHE_NR
);
166 if (time_before(auth
->au_nextgc
, jiffies
))
167 rpcauth_gc_credcache(auth
);
169 q
= &auth
->au_credcache
[nr
];
170 while ((cred
= *q
) != NULL
) {
171 if (auth
->au_ops
->crmatch(task
, cred
)) {
179 cred
= auth
->au_ops
->crcreate(task
);
182 rpcauth_insert_credcache(auth
, cred
);
184 return (struct rpc_cred
*) cred
;
188 * Remove cred handle from cache
191 rpcauth_remove_credcache(struct rpc_auth
*auth
, struct rpc_cred
*cred
)
193 struct rpc_cred
**q
, *cr
;
196 nr
= (cred
->cr_uid
% RPC_CREDCACHE_NR
);
197 q
= &auth
->au_credcache
[nr
];
198 while ((cr
= *q
) != NULL
) {
208 rpcauth_lookupcred(struct rpc_task
*task
)
210 dprintk("RPC: %4d looking up %s cred\n",
211 task
->tk_pid
, task
->tk_auth
->au_ops
->au_name
);
212 return task
->tk_cred
= rpcauth_lookup_credcache(task
);
216 rpcauth_matchcred(struct rpc_task
*task
, struct rpc_cred
*cred
)
218 struct rpc_auth
*auth
= task
->tk_auth
;
220 dprintk("RPC: %4d matching %s cred %p\n",
221 task
->tk_pid
, auth
->au_ops
->au_name
, task
->tk_cred
);
222 return auth
->au_ops
->crmatch(task
, cred
);
226 rpcauth_holdcred(struct rpc_task
*task
)
228 dprintk("RPC: %4d holding %s cred %p\n",
229 task
->tk_pid
, task
->tk_auth
->au_ops
->au_name
, task
->tk_cred
);
231 task
->tk_cred
->cr_count
++;
235 rpcauth_releasecred(struct rpc_task
*task
)
237 struct rpc_auth
*auth
= task
->tk_auth
;
238 struct rpc_cred
*cred
;
240 dprintk("RPC: %4d releasing %s cred %p\n",
241 task
->tk_pid
, auth
->au_ops
->au_name
, task
->tk_cred
);
242 if ((cred
= task
->tk_cred
) != NULL
) {
244 if (cred
->cr_flags
& RPCAUTH_CRED_DEAD
) {
245 rpcauth_remove_credcache(auth
, cred
);
247 auth
->au_ops
->crdestroy(cred
);
249 task
->tk_cred
= NULL
;
254 rpcauth_marshcred(struct rpc_task
*task
, u32
*p
)
256 struct rpc_auth
*auth
= task
->tk_auth
;
258 dprintk("RPC: %4d marshaling %s cred %p\n",
259 task
->tk_pid
, auth
->au_ops
->au_name
, task
->tk_cred
);
260 return auth
->au_ops
->crmarshal(task
, p
,
261 task
->tk_flags
& RPC_CALL_REALUID
);
265 rpcauth_checkverf(struct rpc_task
*task
, u32
*p
)
267 struct rpc_auth
*auth
= task
->tk_auth
;
269 dprintk("RPC: %4d validating %s cred %p\n",
270 task
->tk_pid
, auth
->au_ops
->au_name
, task
->tk_cred
);
271 return auth
->au_ops
->crvalidate(task
, p
);
275 rpcauth_refreshcred(struct rpc_task
*task
)
277 struct rpc_auth
*auth
= task
->tk_auth
;
279 dprintk("RPC: %4d refreshing %s cred %p\n",
280 task
->tk_pid
, auth
->au_ops
->au_name
, task
->tk_cred
);
281 task
->tk_status
= auth
->au_ops
->crrefresh(task
);
282 return task
->tk_status
;
286 rpcauth_invalcred(struct rpc_task
*task
)
288 dprintk("RPC: %4d invalidating %s cred %p\n",
289 task
->tk_pid
, task
->tk_auth
->au_ops
->au_name
, task
->tk_cred
);
291 task
->tk_cred
->cr_flags
&= ~RPCAUTH_CRED_UPTODATE
;
295 rpcauth_uptodatecred(struct rpc_task
*task
)
297 return !(task
->tk_cred
) ||
298 (task
->tk_cred
->cr_flags
& RPCAUTH_CRED_UPTODATE
);