1 /* 2 * linux/net/sunrpc/auth.c 3 * 4 * Generic RPC client authentication API. 5 * 6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 7 */ 8 9 #include <linux/types.h> 10 #include <linux/sched.h> 11 #include <linux/module.h> 12 #include <linux/slab.h> 13 #include <linux/errno.h> 14 #include <linux/sunrpc/clnt.h> 15 #include <linux/spinlock.h> 16 17 #ifdef RPC_DEBUG 18 # define RPCDBG_FACILITY RPCDBG_AUTH 19 #endif 20 21 static DEFINE_SPINLOCK(rpc_authflavor_lock); 22 static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { 23 &authnull_ops, /* AUTH_NULL */ 24 &authunix_ops, /* AUTH_UNIX */ 25 NULL, /* others can be loadable modules */ 26 }; 27 28 static LIST_HEAD(cred_unused); 29 static unsigned long number_cred_unused; 30 31 static u32 32 pseudoflavor_to_flavor(u32 flavor) { 33 if (flavor >= RPC_AUTH_MAXFLAVOR) 34 return RPC_AUTH_GSS; 35 return flavor; 36 } 37 38 int 39 rpcauth_register(const struct rpc_authops *ops) 40 { 41 rpc_authflavor_t flavor; 42 int ret = -EPERM; 43 44 if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) 45 return -EINVAL; 46 spin_lock(&rpc_authflavor_lock); 47 if (auth_flavors[flavor] == NULL) { 48 auth_flavors[flavor] = ops; 49 ret = 0; 50 } 51 spin_unlock(&rpc_authflavor_lock); 52 return ret; 53 } 54 55 int 56 rpcauth_unregister(const struct rpc_authops *ops) 57 { 58 rpc_authflavor_t flavor; 59 int ret = -EPERM; 60 61 if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) 62 return -EINVAL; 63 spin_lock(&rpc_authflavor_lock); 64 if (auth_flavors[flavor] == ops) { 65 auth_flavors[flavor] = NULL; 66 ret = 0; 67 } 68 spin_unlock(&rpc_authflavor_lock); 69 return ret; 70 } 71 72 struct rpc_auth * 73 rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) 74 { 75 struct rpc_auth *auth; 76 const struct rpc_authops *ops; 77 u32 flavor = pseudoflavor_to_flavor(pseudoflavor); 78 79 auth = ERR_PTR(-EINVAL); 80 if (flavor >= RPC_AUTH_MAXFLAVOR) 81 goto out; 82 83 #ifdef CONFIG_KMOD 84 if ((ops = auth_flavors[flavor]) == NULL) 85 request_module("rpc-auth-%u", flavor); 86 #endif 87 spin_lock(&rpc_authflavor_lock); 88 ops = auth_flavors[flavor]; 89 if (ops == NULL || !try_module_get(ops->owner)) { 90 spin_unlock(&rpc_authflavor_lock); 91 goto out; 92 } 93 spin_unlock(&rpc_authflavor_lock); 94 auth = ops->create(clnt, pseudoflavor); 95 module_put(ops->owner); 96 if (IS_ERR(auth)) 97 return auth; 98 if (clnt->cl_auth) 99 rpcauth_release(clnt->cl_auth); 100 clnt->cl_auth = auth; 101 102 out: 103 return auth; 104 } 105 106 void 107 rpcauth_release(struct rpc_auth *auth) 108 { 109 if (!atomic_dec_and_test(&auth->au_count)) 110 return; 111 auth->au_ops->destroy(auth); 112 } 113 114 static DEFINE_SPINLOCK(rpc_credcache_lock); 115 116 static void 117 rpcauth_unhash_cred_locked(struct rpc_cred *cred) 118 { 119 hlist_del_rcu(&cred->cr_hash); 120 smp_mb__before_clear_bit(); 121 clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); 122 } 123 124 static void 125 rpcauth_unhash_cred(struct rpc_cred *cred) 126 { 127 spinlock_t *cache_lock; 128 129 cache_lock = &cred->cr_auth->au_credcache->lock; 130 spin_lock(cache_lock); 131 if (atomic_read(&cred->cr_count) == 0) 132 rpcauth_unhash_cred_locked(cred); 133 spin_unlock(cache_lock); 134 } 135 136 /* 137 * Initialize RPC credential cache 138 */ 139 int 140 rpcauth_init_credcache(struct rpc_auth *auth) 141 { 142 struct rpc_cred_cache *new; 143 int i; 144 145 new = kmalloc(sizeof(*new), GFP_KERNEL); 146 if (!new) 147 return -ENOMEM; 148 for (i = 0; i < RPC_CREDCACHE_NR; i++) 149 INIT_HLIST_HEAD(&new->hashtable[i]); 150 spin_lock_init(&new->lock); 151 auth->au_credcache = new; 152 return 0; 153 } 154 155 /* 156 * Destroy a list of credentials 157 */ 158 static inline 159 void rpcauth_destroy_credlist(struct list_head *head) 160 { 161 struct rpc_cred *cred; 162 163 while (!list_empty(head)) { 164 cred = list_entry(head->next, struct rpc_cred, cr_lru); 165 list_del_init(&cred->cr_lru); 166 put_rpccred(cred); 167 } 168 } 169 170 /* 171 * Clear the RPC credential cache, and delete those credentials 172 * that are not referenced. 173 */ 174 void 175 rpcauth_clear_credcache(struct rpc_cred_cache *cache) 176 { 177 LIST_HEAD(free); 178 struct hlist_head *head; 179 struct rpc_cred *cred; 180 int i; 181 182 spin_lock(&rpc_credcache_lock); 183 spin_lock(&cache->lock); 184 for (i = 0; i < RPC_CREDCACHE_NR; i++) { 185 head = &cache->hashtable[i]; 186 while (!hlist_empty(head)) { 187 cred = hlist_entry(head->first, struct rpc_cred, cr_hash); 188 get_rpccred(cred); 189 if (!list_empty(&cred->cr_lru)) { 190 list_del(&cred->cr_lru); 191 number_cred_unused--; 192 } 193 list_add_tail(&cred->cr_lru, &free); 194 rpcauth_unhash_cred_locked(cred); 195 } 196 } 197 spin_unlock(&cache->lock); 198 spin_unlock(&rpc_credcache_lock); 199 rpcauth_destroy_credlist(&free); 200 } 201 202 /* 203 * Destroy the RPC credential cache 204 */ 205 void 206 rpcauth_destroy_credcache(struct rpc_auth *auth) 207 { 208 struct rpc_cred_cache *cache = auth->au_credcache; 209 210 if (cache) { 211 auth->au_credcache = NULL; 212 rpcauth_clear_credcache(cache); 213 kfree(cache); 214 } 215 } 216 217 /* 218 * Remove stale credentials. Avoid sleeping inside the loop. 219 */ 220 static int 221 rpcauth_prune_expired(struct list_head *free, int nr_to_scan) 222 { 223 spinlock_t *cache_lock; 224 struct rpc_cred *cred; 225 226 while (!list_empty(&cred_unused)) { 227 cred = list_entry(cred_unused.next, struct rpc_cred, cr_lru); 228 list_del_init(&cred->cr_lru); 229 number_cred_unused--; 230 if (atomic_read(&cred->cr_count) != 0) 231 continue; 232 cache_lock = &cred->cr_auth->au_credcache->lock; 233 spin_lock(cache_lock); 234 if (atomic_read(&cred->cr_count) == 0) { 235 get_rpccred(cred); 236 list_add_tail(&cred->cr_lru, free); 237 rpcauth_unhash_cred_locked(cred); 238 nr_to_scan--; 239 } 240 spin_unlock(cache_lock); 241 if (nr_to_scan == 0) 242 break; 243 } 244 return nr_to_scan; 245 } 246 247 /* 248 * Run memory cache shrinker. 249 */ 250 static int 251 rpcauth_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) 252 { 253 LIST_HEAD(free); 254 int res; 255 256 if (list_empty(&cred_unused)) 257 return 0; 258 spin_lock(&rpc_credcache_lock); 259 nr_to_scan = rpcauth_prune_expired(&free, nr_to_scan); 260 res = (number_cred_unused / 100) * sysctl_vfs_cache_pressure; 261 spin_unlock(&rpc_credcache_lock); 262 rpcauth_destroy_credlist(&free); 263 return res; 264 } 265 266 /* 267 * Look up a process' credentials in the authentication cache 268 */ 269 struct rpc_cred * 270 rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, 271 int flags) 272 { 273 LIST_HEAD(free); 274 struct rpc_cred_cache *cache = auth->au_credcache; 275 struct hlist_node *pos; 276 struct rpc_cred *cred = NULL, 277 *entry, *new; 278 int nr = 0; 279 280 if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) 281 nr = acred->uid & RPC_CREDCACHE_MASK; 282 283 rcu_read_lock(); 284 hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { 285 if (!entry->cr_ops->crmatch(acred, entry, flags)) 286 continue; 287 spin_lock(&cache->lock); 288 if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { 289 spin_unlock(&cache->lock); 290 continue; 291 } 292 cred = get_rpccred(entry); 293 spin_unlock(&cache->lock); 294 break; 295 } 296 rcu_read_unlock(); 297 298 if (cred != NULL) 299 goto found; 300 301 new = auth->au_ops->crcreate(auth, acred, flags); 302 if (IS_ERR(new)) { 303 cred = new; 304 goto out; 305 } 306 307 spin_lock(&cache->lock); 308 hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) { 309 if (!entry->cr_ops->crmatch(acred, entry, flags)) 310 continue; 311 cred = get_rpccred(entry); 312 break; 313 } 314 if (cred == NULL) { 315 cred = new; 316 set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); 317 hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]); 318 } else 319 list_add_tail(&new->cr_lru, &free); 320 spin_unlock(&cache->lock); 321 found: 322 if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) 323 && cred->cr_ops->cr_init != NULL 324 && !(flags & RPCAUTH_LOOKUP_NEW)) { 325 int res = cred->cr_ops->cr_init(auth, cred); 326 if (res < 0) { 327 put_rpccred(cred); 328 cred = ERR_PTR(res); 329 } 330 } 331 rpcauth_destroy_credlist(&free); 332 out: 333 return cred; 334 } 335 336 struct rpc_cred * 337 rpcauth_lookupcred(struct rpc_auth *auth, int flags) 338 { 339 struct auth_cred acred = { 340 .uid = current->fsuid, 341 .gid = current->fsgid, 342 .group_info = current->group_info, 343 }; 344 struct rpc_cred *ret; 345 346 dprintk("RPC: looking up %s cred\n", 347 auth->au_ops->au_name); 348 get_group_info(acred.group_info); 349 ret = auth->au_ops->lookup_cred(auth, &acred, flags); 350 put_group_info(acred.group_info); 351 return ret; 352 } 353 354 void 355 rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, 356 struct rpc_auth *auth, const struct rpc_credops *ops) 357 { 358 INIT_HLIST_NODE(&cred->cr_hash); 359 INIT_LIST_HEAD(&cred->cr_lru); 360 atomic_set(&cred->cr_count, 1); 361 cred->cr_auth = auth; 362 cred->cr_ops = ops; 363 cred->cr_expire = jiffies; 364 #ifdef RPC_DEBUG 365 cred->cr_magic = RPCAUTH_CRED_MAGIC; 366 #endif 367 cred->cr_uid = acred->uid; 368 } 369 EXPORT_SYMBOL(rpcauth_init_cred); 370 371 struct rpc_cred * 372 rpcauth_bindcred(struct rpc_task *task) 373 { 374 struct rpc_auth *auth = task->tk_client->cl_auth; 375 struct auth_cred acred = { 376 .uid = current->fsuid, 377 .gid = current->fsgid, 378 .group_info = current->group_info, 379 }; 380 struct rpc_cred *ret; 381 int flags = 0; 382 383 dprintk("RPC: %5u looking up %s cred\n", 384 task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); 385 get_group_info(acred.group_info); 386 if (task->tk_flags & RPC_TASK_ROOTCREDS) 387 flags |= RPCAUTH_LOOKUP_ROOTCREDS; 388 ret = auth->au_ops->lookup_cred(auth, &acred, flags); 389 if (!IS_ERR(ret)) 390 task->tk_msg.rpc_cred = ret; 391 else 392 task->tk_status = PTR_ERR(ret); 393 put_group_info(acred.group_info); 394 return ret; 395 } 396 397 void 398 rpcauth_holdcred(struct rpc_task *task) 399 { 400 struct rpc_cred *cred = task->tk_msg.rpc_cred; 401 if (cred != NULL) { 402 get_rpccred(cred); 403 dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, 404 cred->cr_auth->au_ops->au_name, cred); 405 } 406 } 407 408 void 409 put_rpccred(struct rpc_cred *cred) 410 { 411 /* Fast path for unhashed credentials */ 412 if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) 413 goto need_lock; 414 415 if (!atomic_dec_and_test(&cred->cr_count)) 416 return; 417 goto out_destroy; 418 need_lock: 419 if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) 420 return; 421 if (!list_empty(&cred->cr_lru)) { 422 number_cred_unused--; 423 list_del_init(&cred->cr_lru); 424 } 425 if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) 426 rpcauth_unhash_cred(cred); 427 else if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) { 428 cred->cr_expire = jiffies; 429 list_add_tail(&cred->cr_lru, &cred_unused); 430 number_cred_unused++; 431 spin_unlock(&rpc_credcache_lock); 432 return; 433 } 434 spin_unlock(&rpc_credcache_lock); 435 out_destroy: 436 cred->cr_ops->crdestroy(cred); 437 } 438 439 void 440 rpcauth_unbindcred(struct rpc_task *task) 441 { 442 struct rpc_cred *cred = task->tk_msg.rpc_cred; 443 444 dprintk("RPC: %5u releasing %s cred %p\n", 445 task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 446 447 put_rpccred(cred); 448 task->tk_msg.rpc_cred = NULL; 449 } 450 451 __be32 * 452 rpcauth_marshcred(struct rpc_task *task, __be32 *p) 453 { 454 struct rpc_cred *cred = task->tk_msg.rpc_cred; 455 456 dprintk("RPC: %5u marshaling %s cred %p\n", 457 task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 458 459 return cred->cr_ops->crmarshal(task, p); 460 } 461 462 __be32 * 463 rpcauth_checkverf(struct rpc_task *task, __be32 *p) 464 { 465 struct rpc_cred *cred = task->tk_msg.rpc_cred; 466 467 dprintk("RPC: %5u validating %s cred %p\n", 468 task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 469 470 return cred->cr_ops->crvalidate(task, p); 471 } 472 473 int 474 rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, 475 __be32 *data, void *obj) 476 { 477 struct rpc_cred *cred = task->tk_msg.rpc_cred; 478 479 dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", 480 task->tk_pid, cred->cr_ops->cr_name, cred); 481 if (cred->cr_ops->crwrap_req) 482 return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); 483 /* By default, we encode the arguments normally. */ 484 return rpc_call_xdrproc(encode, rqstp, data, obj); 485 } 486 487 int 488 rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, 489 __be32 *data, void *obj) 490 { 491 struct rpc_cred *cred = task->tk_msg.rpc_cred; 492 493 dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", 494 task->tk_pid, cred->cr_ops->cr_name, cred); 495 if (cred->cr_ops->crunwrap_resp) 496 return cred->cr_ops->crunwrap_resp(task, decode, rqstp, 497 data, obj); 498 /* By default, we decode the arguments normally. */ 499 return rpc_call_xdrproc(decode, rqstp, data, obj); 500 } 501 502 int 503 rpcauth_refreshcred(struct rpc_task *task) 504 { 505 struct rpc_cred *cred = task->tk_msg.rpc_cred; 506 int err; 507 508 dprintk("RPC: %5u refreshing %s cred %p\n", 509 task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 510 511 err = cred->cr_ops->crrefresh(task); 512 if (err < 0) 513 task->tk_status = err; 514 return err; 515 } 516 517 void 518 rpcauth_invalcred(struct rpc_task *task) 519 { 520 struct rpc_cred *cred = task->tk_msg.rpc_cred; 521 522 dprintk("RPC: %5u invalidating %s cred %p\n", 523 task->tk_pid, cred->cr_auth->au_ops->au_name, cred); 524 if (cred) 525 clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); 526 } 527 528 int 529 rpcauth_uptodatecred(struct rpc_task *task) 530 { 531 struct rpc_cred *cred = task->tk_msg.rpc_cred; 532 533 return cred == NULL || 534 test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; 535 } 536 537 static struct shrinker rpc_cred_shrinker = { 538 .shrink = rpcauth_cache_shrinker, 539 .seeks = DEFAULT_SEEKS, 540 }; 541 542 void __init rpcauth_init_module(void) 543 { 544 rpc_init_authunix(); 545 register_shrinker(&rpc_cred_shrinker); 546 } 547 548 void __exit rpcauth_remove_module(void) 549 { 550 unregister_shrinker(&rpc_cred_shrinker); 551 } 552