2 * Generic RPC credential
4 * Copyright (C) 2008, Trond Myklebust <Trond.Myklebust@netapp.com>
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>
17 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
18 # define RPCDBG_FACILITY RPCDBG_AUTH
21 #define RPC_MACHINE_CRED_USERID GLOBAL_ROOT_UID
22 #define RPC_MACHINE_CRED_GROUPID GLOBAL_ROOT_GID
25 struct rpc_cred gc_base
;
26 struct auth_cred acred
;
29 static struct rpc_auth generic_auth
;
30 static const struct rpc_credops generic_credops
;
33 * Public call interface
35 struct rpc_cred
*rpc_lookup_cred(void)
37 return rpcauth_lookupcred(&generic_auth
, 0);
39 EXPORT_SYMBOL_GPL(rpc_lookup_cred
);
42 rpc_lookup_generic_cred(struct auth_cred
*acred
, int flags
, gfp_t gfp
)
44 return rpcauth_lookup_credcache(&generic_auth
, acred
, flags
, gfp
);
46 EXPORT_SYMBOL_GPL(rpc_lookup_generic_cred
);
48 struct rpc_cred
*rpc_lookup_cred_nonblock(void)
50 return rpcauth_lookupcred(&generic_auth
, RPCAUTH_LOOKUP_RCU
);
52 EXPORT_SYMBOL_GPL(rpc_lookup_cred_nonblock
);
55 * Public call interface for looking up machine creds.
57 struct rpc_cred
*rpc_lookup_machine_cred(const char *service_name
)
59 struct auth_cred acred
= {
60 .uid
= RPC_MACHINE_CRED_USERID
,
61 .gid
= RPC_MACHINE_CRED_GROUPID
,
62 .principal
= service_name
,
66 dprintk("RPC: looking up machine cred for service %s\n",
68 return generic_auth
.au_ops
->lookup_cred(&generic_auth
, &acred
, 0);
70 EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred
);
72 static struct rpc_cred
*generic_bind_cred(struct rpc_task
*task
,
73 struct rpc_cred
*cred
, int lookupflags
)
75 struct rpc_auth
*auth
= task
->tk_client
->cl_auth
;
76 struct auth_cred
*acred
= &container_of(cred
, struct generic_cred
, gc_base
)->acred
;
78 return auth
->au_ops
->lookup_cred(auth
, acred
, lookupflags
);
82 generic_hash_cred(struct auth_cred
*acred
, unsigned int hashbits
)
84 return hash_64(from_kgid(&init_user_ns
, acred
->gid
) |
85 ((u64
)from_kuid(&init_user_ns
, acred
->uid
) <<
86 (sizeof(gid_t
) * 8)), hashbits
);
90 * Lookup generic creds for current process
92 static struct rpc_cred
*
93 generic_lookup_cred(struct rpc_auth
*auth
, struct auth_cred
*acred
, int flags
)
95 return rpcauth_lookup_credcache(&generic_auth
, acred
, flags
, GFP_KERNEL
);
98 static struct rpc_cred
*
99 generic_create_cred(struct rpc_auth
*auth
, struct auth_cred
*acred
, int flags
, gfp_t gfp
)
101 struct generic_cred
*gcred
;
103 gcred
= kmalloc(sizeof(*gcred
), gfp
);
105 return ERR_PTR(-ENOMEM
);
107 rpcauth_init_cred(&gcred
->gc_base
, acred
, &generic_auth
, &generic_credops
);
108 gcred
->gc_base
.cr_flags
= 1UL << RPCAUTH_CRED_UPTODATE
;
110 gcred
->acred
.uid
= acred
->uid
;
111 gcred
->acred
.gid
= acred
->gid
;
112 gcred
->acred
.group_info
= acred
->group_info
;
113 gcred
->acred
.ac_flags
= 0;
114 if (gcred
->acred
.group_info
!= NULL
)
115 get_group_info(gcred
->acred
.group_info
);
116 gcred
->acred
.machine_cred
= acred
->machine_cred
;
117 gcred
->acred
.principal
= acred
->principal
;
119 dprintk("RPC: allocated %s cred %p for uid %d gid %d\n",
120 gcred
->acred
.machine_cred
? "machine" : "generic",
122 from_kuid(&init_user_ns
, acred
->uid
),
123 from_kgid(&init_user_ns
, acred
->gid
));
124 return &gcred
->gc_base
;
128 generic_free_cred(struct rpc_cred
*cred
)
130 struct generic_cred
*gcred
= container_of(cred
, struct generic_cred
, gc_base
);
132 dprintk("RPC: generic_free_cred %p\n", gcred
);
133 if (gcred
->acred
.group_info
!= NULL
)
134 put_group_info(gcred
->acred
.group_info
);
139 generic_free_cred_callback(struct rcu_head
*head
)
141 struct rpc_cred
*cred
= container_of(head
, struct rpc_cred
, cr_rcu
);
142 generic_free_cred(cred
);
146 generic_destroy_cred(struct rpc_cred
*cred
)
148 call_rcu(&cred
->cr_rcu
, generic_free_cred_callback
);
152 machine_cred_match(struct auth_cred
*acred
, struct generic_cred
*gcred
, int flags
)
154 if (!gcred
->acred
.machine_cred
||
155 gcred
->acred
.principal
!= acred
->principal
||
156 !uid_eq(gcred
->acred
.uid
, acred
->uid
) ||
157 !gid_eq(gcred
->acred
.gid
, acred
->gid
))
163 * Match credentials against current process creds.
166 generic_match(struct auth_cred
*acred
, struct rpc_cred
*cred
, int flags
)
168 struct generic_cred
*gcred
= container_of(cred
, struct generic_cred
, gc_base
);
171 if (acred
->machine_cred
)
172 return machine_cred_match(acred
, gcred
, flags
);
174 if (!uid_eq(gcred
->acred
.uid
, acred
->uid
) ||
175 !gid_eq(gcred
->acred
.gid
, acred
->gid
) ||
176 gcred
->acred
.machine_cred
!= 0)
179 /* Optimisation in the case where pointers are identical... */
180 if (gcred
->acred
.group_info
== acred
->group_info
)
184 if (gcred
->acred
.group_info
->ngroups
!= acred
->group_info
->ngroups
)
186 for (i
= 0; i
< gcred
->acred
.group_info
->ngroups
; i
++) {
187 if (!gid_eq(gcred
->acred
.group_info
->gid
[i
],
188 acred
->group_info
->gid
[i
]))
197 int __init
rpc_init_generic_auth(void)
199 return rpcauth_init_credcache(&generic_auth
);
202 void rpc_destroy_generic_auth(void)
204 rpcauth_destroy_credcache(&generic_auth
);
208 * Test the the current time (now) against the underlying credential key expiry
209 * minus a timeout and setup notification.
212 * If 'now' is before the key expiry minus RPC_KEY_EXPIRE_TIMEO, set
213 * the RPC_CRED_NOTIFY_TIMEOUT flag to setup the underlying credential
214 * rpc_credops crmatch routine to notify this generic cred when it's key
215 * expiration is within RPC_KEY_EXPIRE_TIMEO, and return 0.
218 * If the underlying cred lookup fails, return -EACCES.
220 * The 'almost' error case:
221 * If 'now' is within key expiry minus RPC_KEY_EXPIRE_TIMEO, but not within
222 * key expiry minus RPC_KEY_EXPIRE_FAIL, set the RPC_CRED_EXPIRE_SOON bit
223 * on the acred ac_flags and return 0.
226 generic_key_timeout(struct rpc_auth
*auth
, struct rpc_cred
*cred
)
228 struct auth_cred
*acred
= &container_of(cred
, struct generic_cred
,
230 struct rpc_cred
*tcred
;
234 /* Fast track for non crkey_timeout (no key) underlying credentials */
235 if (auth
->au_flags
& RPCAUTH_AUTH_NO_CRKEY_TIMEOUT
)
238 /* Fast track for the normal case */
239 if (test_bit(RPC_CRED_NOTIFY_TIMEOUT
, &acred
->ac_flags
))
242 /* lookup_cred either returns a valid referenced rpc_cred, or PTR_ERR */
243 tcred
= auth
->au_ops
->lookup_cred(auth
, acred
, 0);
247 /* Test for the almost error case */
248 ret
= tcred
->cr_ops
->crkey_timeout(tcred
);
250 set_bit(RPC_CRED_KEY_EXPIRE_SOON
, &acred
->ac_flags
);
253 /* In case underlying cred key has been reset */
254 if (test_and_clear_bit(RPC_CRED_KEY_EXPIRE_SOON
,
256 dprintk("RPC: UID %d Credential key reset\n",
257 from_kuid(&init_user_ns
, tcred
->cr_uid
));
258 /* set up fasttrack for the normal case */
259 set_bit(RPC_CRED_NOTIFY_TIMEOUT
, &acred
->ac_flags
);
266 static const struct rpc_authops generic_auth_ops
= {
267 .owner
= THIS_MODULE
,
268 .au_name
= "Generic",
269 .hash_cred
= generic_hash_cred
,
270 .lookup_cred
= generic_lookup_cred
,
271 .crcreate
= generic_create_cred
,
272 .key_timeout
= generic_key_timeout
,
275 static struct rpc_auth generic_auth
= {
276 .au_ops
= &generic_auth_ops
,
277 .au_count
= ATOMIC_INIT(0),
280 static bool generic_key_to_expire(struct rpc_cred
*cred
)
282 struct auth_cred
*acred
= &container_of(cred
, struct generic_cred
,
287 ret
= test_bit(RPC_CRED_KEY_EXPIRE_SOON
, &acred
->ac_flags
);
293 static const struct rpc_credops generic_credops
= {
294 .cr_name
= "Generic cred",
295 .crdestroy
= generic_destroy_cred
,
296 .crbind
= generic_bind_cred
,
297 .crmatch
= generic_match
,
298 .crkey_to_expire
= generic_key_to_expire
,