1/* 2 * Generic RPC credential 3 * 4 * Copyright (C) 2008, Trond Myklebust <Trond.Myklebust@netapp.com> 5 */ 6 7#include <linux/err.h> 8#include <linux/slab.h> 9#include <linux/types.h> 10#include <linux/module.h> 11#include <linux/sched.h> 12#include <linux/sunrpc/auth.h> 13#include <linux/sunrpc/clnt.h> 14#include <linux/sunrpc/debug.h> 15#include <linux/sunrpc/sched.h> 16 17#ifdef RPC_DEBUG 18# define RPCDBG_FACILITY RPCDBG_AUTH 19#endif 20 21#define RPC_MACHINE_CRED_USERID ((uid_t)0) 22#define RPC_MACHINE_CRED_GROUPID ((gid_t)0) 23 24struct generic_cred { 25 struct rpc_cred gc_base; 26 struct auth_cred acred; 27}; 28 29static struct rpc_auth generic_auth; 30static const struct rpc_credops generic_credops; 31 32/* 33 * Public call interface 34 */ 35struct rpc_cred *rpc_lookup_cred(void) 36{ 37 return rpcauth_lookupcred(&generic_auth, 0); 38} 39EXPORT_SYMBOL_GPL(rpc_lookup_cred); 40 41/* 42 * Public call interface for looking up machine creds. 43 */ 44struct rpc_cred *rpc_lookup_machine_cred(void) 45{ 46 struct auth_cred acred = { 47 .uid = RPC_MACHINE_CRED_USERID, 48 .gid = RPC_MACHINE_CRED_GROUPID, 49 .machine_cred = 1, 50 }; 51 52 dprintk("RPC: looking up machine cred\n"); 53 return generic_auth.au_ops->lookup_cred(&generic_auth, &acred, 0); 54} 55EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred); 56 57static struct rpc_cred *generic_bind_cred(struct rpc_task *task, 58 struct rpc_cred *cred, int lookupflags) 59{ 60 struct rpc_auth *auth = task->tk_client->cl_auth; 61 struct auth_cred *acred = &container_of(cred, struct generic_cred, gc_base)->acred; 62 63 return auth->au_ops->lookup_cred(auth, acred, lookupflags); 64} 65 66/* 67 * Lookup generic creds for current process 68 */ 69static struct rpc_cred * 70generic_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) 71{ 72 return rpcauth_lookup_credcache(&generic_auth, acred, flags); 73} 74 75static struct rpc_cred * 76generic_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) 77{ 78 struct generic_cred *gcred; 79 80 gcred = kmalloc(sizeof(*gcred), GFP_KERNEL); 81 if (gcred == NULL) 82 return ERR_PTR(-ENOMEM); 83 84 rpcauth_init_cred(&gcred->gc_base, acred, &generic_auth, &generic_credops); 85 gcred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; 86 87 gcred->acred.uid = acred->uid; 88 gcred->acred.gid = acred->gid; 89 gcred->acred.group_info = acred->group_info; 90 if (gcred->acred.group_info != NULL) 91 get_group_info(gcred->acred.group_info); 92 gcred->acred.machine_cred = acred->machine_cred; 93 94 dprintk("RPC: allocated %s cred %p for uid %d gid %d\n", 95 gcred->acred.machine_cred ? "machine" : "generic", 96 gcred, acred->uid, acred->gid); 97 return &gcred->gc_base; 98} 99 100static void 101generic_free_cred(struct rpc_cred *cred) 102{ 103 struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base); 104 105 dprintk("RPC: generic_free_cred %p\n", gcred); 106 if (gcred->acred.group_info != NULL) 107 put_group_info(gcred->acred.group_info); 108 kfree(gcred); 109} 110 111static void 112generic_free_cred_callback(struct rcu_head *head) 113{ 114 struct rpc_cred *cred = container_of(head, struct rpc_cred, cr_rcu); 115 generic_free_cred(cred); 116} 117 118static void 119generic_destroy_cred(struct rpc_cred *cred) 120{ 121 call_rcu(&cred->cr_rcu, generic_free_cred_callback); 122} 123 124/* 125 * Match credentials against current process creds. 126 */ 127static int 128generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags) 129{ 130 struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base); 131 int i; 132 133 if (gcred->acred.uid != acred->uid || 134 gcred->acred.gid != acred->gid || 135 gcred->acred.machine_cred != acred->machine_cred) 136 goto out_nomatch; 137 138 /* Optimisation in the case where pointers are identical... */ 139 if (gcred->acred.group_info == acred->group_info) 140 goto out_match; 141 142 /* Slow path... */ 143 if (gcred->acred.group_info->ngroups != acred->group_info->ngroups) 144 goto out_nomatch; 145 for (i = 0; i < gcred->acred.group_info->ngroups; i++) { 146 if (GROUP_AT(gcred->acred.group_info, i) != 147 GROUP_AT(acred->group_info, i)) 148 goto out_nomatch; 149 } 150out_match: 151 return 1; 152out_nomatch: 153 return 0; 154} 155 156int __init rpc_init_generic_auth(void) 157{ 158 return rpcauth_init_credcache(&generic_auth); 159} 160 161void __exit rpc_destroy_generic_auth(void) 162{ 163 rpcauth_destroy_credcache(&generic_auth); 164} 165 166static const struct rpc_authops generic_auth_ops = { 167 .owner = THIS_MODULE, 168 .au_name = "Generic", 169 .lookup_cred = generic_lookup_cred, 170 .crcreate = generic_create_cred, 171}; 172 173static struct rpc_auth generic_auth = { 174 .au_ops = &generic_auth_ops, 175 .au_count = ATOMIC_INIT(0), 176}; 177 178static const struct rpc_credops generic_credops = { 179 .cr_name = "Generic cred", 180 .crdestroy = generic_destroy_cred, 181 .crbind = generic_bind_cred, 182 .crmatch = generic_match, 183}; 184