Commit e092bdcd939416ef911090890096fe07d0281a5e
1 parent
fc432dd907
Exists in
master
and in
7 other branches
SUNRPC: cleanup rpc credential cache garbage collection
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 3 changed files with 74 additions and 49 deletions Inline Diff
include/linux/sunrpc/auth.h
1 | /* | 1 | /* |
2 | * linux/include/linux/sunrpc/auth.h | 2 | * linux/include/linux/sunrpc/auth.h |
3 | * | 3 | * |
4 | * Declarations for the RPC client authentication machinery. | 4 | * Declarations for the RPC client authentication machinery. |
5 | * | 5 | * |
6 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #ifndef _LINUX_SUNRPC_AUTH_H | 9 | #ifndef _LINUX_SUNRPC_AUTH_H |
10 | #define _LINUX_SUNRPC_AUTH_H | 10 | #define _LINUX_SUNRPC_AUTH_H |
11 | 11 | ||
12 | #ifdef __KERNEL__ | 12 | #ifdef __KERNEL__ |
13 | 13 | ||
14 | #include <linux/sunrpc/sched.h> | 14 | #include <linux/sunrpc/sched.h> |
15 | #include <linux/sunrpc/msg_prot.h> | 15 | #include <linux/sunrpc/msg_prot.h> |
16 | #include <linux/sunrpc/xdr.h> | 16 | #include <linux/sunrpc/xdr.h> |
17 | 17 | ||
18 | #include <asm/atomic.h> | 18 | #include <asm/atomic.h> |
19 | 19 | ||
20 | /* size of the nodename buffer */ | 20 | /* size of the nodename buffer */ |
21 | #define UNX_MAXNODENAME 32 | 21 | #define UNX_MAXNODENAME 32 |
22 | 22 | ||
23 | /* Work around the lack of a VFS credential */ | 23 | /* Work around the lack of a VFS credential */ |
24 | struct auth_cred { | 24 | struct auth_cred { |
25 | uid_t uid; | 25 | uid_t uid; |
26 | gid_t gid; | 26 | gid_t gid; |
27 | struct group_info *group_info; | 27 | struct group_info *group_info; |
28 | }; | 28 | }; |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Client user credentials | 31 | * Client user credentials |
32 | */ | 32 | */ |
33 | struct rpc_auth; | 33 | struct rpc_auth; |
34 | struct rpc_credops; | 34 | struct rpc_credops; |
35 | struct rpc_cred { | 35 | struct rpc_cred { |
36 | struct hlist_node cr_hash; /* hash chain */ | 36 | struct hlist_node cr_hash; /* hash chain */ |
37 | struct list_head cr_lru; /* lru garbage collection */ | ||
37 | struct rpc_auth * cr_auth; | 38 | struct rpc_auth * cr_auth; |
38 | const struct rpc_credops *cr_ops; | 39 | const struct rpc_credops *cr_ops; |
39 | #ifdef RPC_DEBUG | 40 | #ifdef RPC_DEBUG |
40 | unsigned long cr_magic; /* 0x0f4aa4f0 */ | 41 | unsigned long cr_magic; /* 0x0f4aa4f0 */ |
41 | #endif | 42 | #endif |
42 | unsigned long cr_expire; /* when to gc */ | 43 | unsigned long cr_expire; /* when to gc */ |
43 | unsigned long cr_flags; /* various flags */ | 44 | unsigned long cr_flags; /* various flags */ |
44 | atomic_t cr_count; /* ref count */ | 45 | atomic_t cr_count; /* ref count */ |
45 | 46 | ||
46 | uid_t cr_uid; | 47 | uid_t cr_uid; |
47 | 48 | ||
48 | /* per-flavor data */ | 49 | /* per-flavor data */ |
49 | }; | 50 | }; |
50 | #define RPCAUTH_CRED_NEW 0 | 51 | #define RPCAUTH_CRED_NEW 0 |
51 | #define RPCAUTH_CRED_UPTODATE 1 | 52 | #define RPCAUTH_CRED_UPTODATE 1 |
52 | 53 | ||
53 | #define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 | 54 | #define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 |
54 | 55 | ||
55 | /* | 56 | /* |
56 | * Client authentication handle | 57 | * Client authentication handle |
57 | */ | 58 | */ |
58 | #define RPC_CREDCACHE_NR 8 | 59 | #define RPC_CREDCACHE_NR 8 |
59 | #define RPC_CREDCACHE_MASK (RPC_CREDCACHE_NR - 1) | 60 | #define RPC_CREDCACHE_MASK (RPC_CREDCACHE_NR - 1) |
60 | struct rpc_cred_cache { | 61 | struct rpc_cred_cache { |
61 | struct hlist_head hashtable[RPC_CREDCACHE_NR]; | 62 | struct hlist_head hashtable[RPC_CREDCACHE_NR]; |
62 | unsigned long nextgc; /* next garbage collection */ | 63 | unsigned long nextgc; /* next garbage collection */ |
63 | unsigned long expire; /* cache expiry interval */ | 64 | unsigned long expire; /* cache expiry interval */ |
64 | }; | 65 | }; |
65 | 66 | ||
66 | struct rpc_authops; | 67 | struct rpc_authops; |
67 | struct rpc_auth { | 68 | struct rpc_auth { |
68 | unsigned int au_cslack; /* call cred size estimate */ | 69 | unsigned int au_cslack; /* call cred size estimate */ |
69 | /* guess at number of u32's auth adds before | 70 | /* guess at number of u32's auth adds before |
70 | * reply data; normally the verifier size: */ | 71 | * reply data; normally the verifier size: */ |
71 | unsigned int au_rslack; | 72 | unsigned int au_rslack; |
72 | /* for gss, used to calculate au_rslack: */ | 73 | /* for gss, used to calculate au_rslack: */ |
73 | unsigned int au_verfsize; | 74 | unsigned int au_verfsize; |
74 | 75 | ||
75 | unsigned int au_flags; /* various flags */ | 76 | unsigned int au_flags; /* various flags */ |
76 | const struct rpc_authops *au_ops; /* operations */ | 77 | const struct rpc_authops *au_ops; /* operations */ |
77 | rpc_authflavor_t au_flavor; /* pseudoflavor (note may | 78 | rpc_authflavor_t au_flavor; /* pseudoflavor (note may |
78 | * differ from the flavor in | 79 | * differ from the flavor in |
79 | * au_ops->au_flavor in gss | 80 | * au_ops->au_flavor in gss |
80 | * case) */ | 81 | * case) */ |
81 | atomic_t au_count; /* Reference counter */ | 82 | atomic_t au_count; /* Reference counter */ |
82 | 83 | ||
83 | struct rpc_cred_cache * au_credcache; | 84 | struct rpc_cred_cache * au_credcache; |
84 | /* per-flavor data */ | 85 | /* per-flavor data */ |
85 | }; | 86 | }; |
86 | 87 | ||
87 | /* Flags for rpcauth_lookupcred() */ | 88 | /* Flags for rpcauth_lookupcred() */ |
88 | #define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ | 89 | #define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ |
89 | #define RPCAUTH_LOOKUP_ROOTCREDS 0x02 /* This really ought to go! */ | 90 | #define RPCAUTH_LOOKUP_ROOTCREDS 0x02 /* This really ought to go! */ |
90 | 91 | ||
91 | /* | 92 | /* |
92 | * Client authentication ops | 93 | * Client authentication ops |
93 | */ | 94 | */ |
94 | struct rpc_authops { | 95 | struct rpc_authops { |
95 | struct module *owner; | 96 | struct module *owner; |
96 | rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */ | 97 | rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */ |
97 | #ifdef RPC_DEBUG | 98 | #ifdef RPC_DEBUG |
98 | char * au_name; | 99 | char * au_name; |
99 | #endif | 100 | #endif |
100 | struct rpc_auth * (*create)(struct rpc_clnt *, rpc_authflavor_t); | 101 | struct rpc_auth * (*create)(struct rpc_clnt *, rpc_authflavor_t); |
101 | void (*destroy)(struct rpc_auth *); | 102 | void (*destroy)(struct rpc_auth *); |
102 | 103 | ||
103 | struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); | 104 | struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); |
104 | struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); | 105 | struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); |
105 | }; | 106 | }; |
106 | 107 | ||
107 | struct rpc_credops { | 108 | struct rpc_credops { |
108 | const char * cr_name; /* Name of the auth flavour */ | 109 | const char * cr_name; /* Name of the auth flavour */ |
109 | int (*cr_init)(struct rpc_auth *, struct rpc_cred *); | 110 | int (*cr_init)(struct rpc_auth *, struct rpc_cred *); |
110 | void (*crdestroy)(struct rpc_cred *); | 111 | void (*crdestroy)(struct rpc_cred *); |
111 | 112 | ||
112 | int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); | 113 | int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); |
113 | __be32 * (*crmarshal)(struct rpc_task *, __be32 *); | 114 | __be32 * (*crmarshal)(struct rpc_task *, __be32 *); |
114 | int (*crrefresh)(struct rpc_task *); | 115 | int (*crrefresh)(struct rpc_task *); |
115 | __be32 * (*crvalidate)(struct rpc_task *, __be32 *); | 116 | __be32 * (*crvalidate)(struct rpc_task *, __be32 *); |
116 | int (*crwrap_req)(struct rpc_task *, kxdrproc_t, | 117 | int (*crwrap_req)(struct rpc_task *, kxdrproc_t, |
117 | void *, __be32 *, void *); | 118 | void *, __be32 *, void *); |
118 | int (*crunwrap_resp)(struct rpc_task *, kxdrproc_t, | 119 | int (*crunwrap_resp)(struct rpc_task *, kxdrproc_t, |
119 | void *, __be32 *, void *); | 120 | void *, __be32 *, void *); |
120 | }; | 121 | }; |
121 | 122 | ||
122 | extern const struct rpc_authops authunix_ops; | 123 | extern const struct rpc_authops authunix_ops; |
123 | extern const struct rpc_authops authnull_ops; | 124 | extern const struct rpc_authops authnull_ops; |
124 | 125 | ||
125 | int rpcauth_register(const struct rpc_authops *); | 126 | int rpcauth_register(const struct rpc_authops *); |
126 | int rpcauth_unregister(const struct rpc_authops *); | 127 | int rpcauth_unregister(const struct rpc_authops *); |
127 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); | 128 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); |
128 | void rpcauth_release(struct rpc_auth *); | 129 | void rpcauth_release(struct rpc_auth *); |
129 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); | 130 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); |
130 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); | 131 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); |
131 | struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); | 132 | struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); |
132 | struct rpc_cred * rpcauth_bindcred(struct rpc_task *); | 133 | struct rpc_cred * rpcauth_bindcred(struct rpc_task *); |
133 | void rpcauth_holdcred(struct rpc_task *); | 134 | void rpcauth_holdcred(struct rpc_task *); |
134 | void put_rpccred(struct rpc_cred *); | 135 | void put_rpccred(struct rpc_cred *); |
135 | void rpcauth_unbindcred(struct rpc_task *); | 136 | void rpcauth_unbindcred(struct rpc_task *); |
136 | __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); | 137 | __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); |
137 | __be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); | 138 | __be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); |
138 | int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj); | 139 | int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj); |
139 | int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, __be32 *data, void *obj); | 140 | int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, __be32 *data, void *obj); |
140 | int rpcauth_refreshcred(struct rpc_task *); | 141 | int rpcauth_refreshcred(struct rpc_task *); |
141 | void rpcauth_invalcred(struct rpc_task *); | 142 | void rpcauth_invalcred(struct rpc_task *); |
142 | int rpcauth_uptodatecred(struct rpc_task *); | 143 | int rpcauth_uptodatecred(struct rpc_task *); |
143 | int rpcauth_init_credcache(struct rpc_auth *, unsigned long); | 144 | int rpcauth_init_credcache(struct rpc_auth *, unsigned long); |
144 | void rpcauth_destroy_credcache(struct rpc_auth *); | 145 | void rpcauth_destroy_credcache(struct rpc_auth *); |
145 | void rpcauth_clear_credcache(struct rpc_cred_cache *); | 146 | void rpcauth_clear_credcache(struct rpc_cred_cache *); |
146 | 147 | ||
147 | static inline | 148 | static inline |
148 | struct rpc_cred * get_rpccred(struct rpc_cred *cred) | 149 | struct rpc_cred * get_rpccred(struct rpc_cred *cred) |
149 | { | 150 | { |
150 | atomic_inc(&cred->cr_count); | 151 | atomic_inc(&cred->cr_count); |
151 | return cred; | 152 | return cred; |
152 | } | 153 | } |
153 | 154 | ||
154 | #endif /* __KERNEL__ */ | 155 | #endif /* __KERNEL__ */ |
155 | #endif /* _LINUX_SUNRPC_AUTH_H */ | 156 | #endif /* _LINUX_SUNRPC_AUTH_H */ |
156 | 157 |
net/sunrpc/auth.c
1 | /* | 1 | /* |
2 | * linux/net/sunrpc/auth.c | 2 | * linux/net/sunrpc/auth.c |
3 | * | 3 | * |
4 | * Generic RPC client authentication API. | 4 | * Generic RPC client authentication API. |
5 | * | 5 | * |
6 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/sched.h> | 10 | #include <linux/sched.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/sunrpc/clnt.h> | 14 | #include <linux/sunrpc/clnt.h> |
15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
16 | 16 | ||
17 | #ifdef RPC_DEBUG | 17 | #ifdef RPC_DEBUG |
18 | # define RPCDBG_FACILITY RPCDBG_AUTH | 18 | # define RPCDBG_FACILITY RPCDBG_AUTH |
19 | #endif | 19 | #endif |
20 | 20 | ||
21 | static DEFINE_SPINLOCK(rpc_authflavor_lock); | 21 | static DEFINE_SPINLOCK(rpc_authflavor_lock); |
22 | static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { | 22 | static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { |
23 | &authnull_ops, /* AUTH_NULL */ | 23 | &authnull_ops, /* AUTH_NULL */ |
24 | &authunix_ops, /* AUTH_UNIX */ | 24 | &authunix_ops, /* AUTH_UNIX */ |
25 | NULL, /* others can be loadable modules */ | 25 | NULL, /* others can be loadable modules */ |
26 | }; | 26 | }; |
27 | 27 | ||
28 | static LIST_HEAD(cred_unused); | ||
29 | |||
28 | static u32 | 30 | static u32 |
29 | pseudoflavor_to_flavor(u32 flavor) { | 31 | pseudoflavor_to_flavor(u32 flavor) { |
30 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 32 | if (flavor >= RPC_AUTH_MAXFLAVOR) |
31 | return RPC_AUTH_GSS; | 33 | return RPC_AUTH_GSS; |
32 | return flavor; | 34 | return flavor; |
33 | } | 35 | } |
34 | 36 | ||
35 | int | 37 | int |
36 | rpcauth_register(const struct rpc_authops *ops) | 38 | rpcauth_register(const struct rpc_authops *ops) |
37 | { | 39 | { |
38 | rpc_authflavor_t flavor; | 40 | rpc_authflavor_t flavor; |
39 | int ret = -EPERM; | 41 | int ret = -EPERM; |
40 | 42 | ||
41 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) | 43 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) |
42 | return -EINVAL; | 44 | return -EINVAL; |
43 | spin_lock(&rpc_authflavor_lock); | 45 | spin_lock(&rpc_authflavor_lock); |
44 | if (auth_flavors[flavor] == NULL) { | 46 | if (auth_flavors[flavor] == NULL) { |
45 | auth_flavors[flavor] = ops; | 47 | auth_flavors[flavor] = ops; |
46 | ret = 0; | 48 | ret = 0; |
47 | } | 49 | } |
48 | spin_unlock(&rpc_authflavor_lock); | 50 | spin_unlock(&rpc_authflavor_lock); |
49 | return ret; | 51 | return ret; |
50 | } | 52 | } |
51 | 53 | ||
52 | int | 54 | int |
53 | rpcauth_unregister(const struct rpc_authops *ops) | 55 | rpcauth_unregister(const struct rpc_authops *ops) |
54 | { | 56 | { |
55 | rpc_authflavor_t flavor; | 57 | rpc_authflavor_t flavor; |
56 | int ret = -EPERM; | 58 | int ret = -EPERM; |
57 | 59 | ||
58 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) | 60 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) |
59 | return -EINVAL; | 61 | return -EINVAL; |
60 | spin_lock(&rpc_authflavor_lock); | 62 | spin_lock(&rpc_authflavor_lock); |
61 | if (auth_flavors[flavor] == ops) { | 63 | if (auth_flavors[flavor] == ops) { |
62 | auth_flavors[flavor] = NULL; | 64 | auth_flavors[flavor] = NULL; |
63 | ret = 0; | 65 | ret = 0; |
64 | } | 66 | } |
65 | spin_unlock(&rpc_authflavor_lock); | 67 | spin_unlock(&rpc_authflavor_lock); |
66 | return ret; | 68 | return ret; |
67 | } | 69 | } |
68 | 70 | ||
69 | struct rpc_auth * | 71 | struct rpc_auth * |
70 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | 72 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) |
71 | { | 73 | { |
72 | struct rpc_auth *auth; | 74 | struct rpc_auth *auth; |
73 | const struct rpc_authops *ops; | 75 | const struct rpc_authops *ops; |
74 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); | 76 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); |
75 | 77 | ||
76 | auth = ERR_PTR(-EINVAL); | 78 | auth = ERR_PTR(-EINVAL); |
77 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 79 | if (flavor >= RPC_AUTH_MAXFLAVOR) |
78 | goto out; | 80 | goto out; |
79 | 81 | ||
80 | #ifdef CONFIG_KMOD | 82 | #ifdef CONFIG_KMOD |
81 | if ((ops = auth_flavors[flavor]) == NULL) | 83 | if ((ops = auth_flavors[flavor]) == NULL) |
82 | request_module("rpc-auth-%u", flavor); | 84 | request_module("rpc-auth-%u", flavor); |
83 | #endif | 85 | #endif |
84 | spin_lock(&rpc_authflavor_lock); | 86 | spin_lock(&rpc_authflavor_lock); |
85 | ops = auth_flavors[flavor]; | 87 | ops = auth_flavors[flavor]; |
86 | if (ops == NULL || !try_module_get(ops->owner)) { | 88 | if (ops == NULL || !try_module_get(ops->owner)) { |
87 | spin_unlock(&rpc_authflavor_lock); | 89 | spin_unlock(&rpc_authflavor_lock); |
88 | goto out; | 90 | goto out; |
89 | } | 91 | } |
90 | spin_unlock(&rpc_authflavor_lock); | 92 | spin_unlock(&rpc_authflavor_lock); |
91 | auth = ops->create(clnt, pseudoflavor); | 93 | auth = ops->create(clnt, pseudoflavor); |
92 | module_put(ops->owner); | 94 | module_put(ops->owner); |
93 | if (IS_ERR(auth)) | 95 | if (IS_ERR(auth)) |
94 | return auth; | 96 | return auth; |
95 | if (clnt->cl_auth) | 97 | if (clnt->cl_auth) |
96 | rpcauth_release(clnt->cl_auth); | 98 | rpcauth_release(clnt->cl_auth); |
97 | clnt->cl_auth = auth; | 99 | clnt->cl_auth = auth; |
98 | 100 | ||
99 | out: | 101 | out: |
100 | return auth; | 102 | return auth; |
101 | } | 103 | } |
102 | 104 | ||
103 | void | 105 | void |
104 | rpcauth_release(struct rpc_auth *auth) | 106 | rpcauth_release(struct rpc_auth *auth) |
105 | { | 107 | { |
106 | if (!atomic_dec_and_test(&auth->au_count)) | 108 | if (!atomic_dec_and_test(&auth->au_count)) |
107 | return; | 109 | return; |
108 | auth->au_ops->destroy(auth); | 110 | auth->au_ops->destroy(auth); |
109 | } | 111 | } |
110 | 112 | ||
111 | static DEFINE_SPINLOCK(rpc_credcache_lock); | 113 | static DEFINE_SPINLOCK(rpc_credcache_lock); |
112 | 114 | ||
113 | /* | 115 | /* |
114 | * Initialize RPC credential cache | 116 | * Initialize RPC credential cache |
115 | */ | 117 | */ |
116 | int | 118 | int |
117 | rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire) | 119 | rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire) |
118 | { | 120 | { |
119 | struct rpc_cred_cache *new; | 121 | struct rpc_cred_cache *new; |
120 | int i; | 122 | int i; |
121 | 123 | ||
122 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 124 | new = kmalloc(sizeof(*new), GFP_KERNEL); |
123 | if (!new) | 125 | if (!new) |
124 | return -ENOMEM; | 126 | return -ENOMEM; |
125 | for (i = 0; i < RPC_CREDCACHE_NR; i++) | 127 | for (i = 0; i < RPC_CREDCACHE_NR; i++) |
126 | INIT_HLIST_HEAD(&new->hashtable[i]); | 128 | INIT_HLIST_HEAD(&new->hashtable[i]); |
127 | new->expire = expire; | 129 | new->expire = expire; |
128 | new->nextgc = jiffies + (expire >> 1); | 130 | new->nextgc = jiffies + (expire >> 1); |
129 | auth->au_credcache = new; | 131 | auth->au_credcache = new; |
130 | return 0; | 132 | return 0; |
131 | } | 133 | } |
132 | 134 | ||
133 | /* | 135 | /* |
134 | * Destroy a list of credentials | 136 | * Destroy a list of credentials |
135 | */ | 137 | */ |
136 | static inline | 138 | static inline |
137 | void rpcauth_destroy_credlist(struct hlist_head *head) | 139 | void rpcauth_destroy_credlist(struct list_head *head) |
138 | { | 140 | { |
139 | struct rpc_cred *cred; | 141 | struct rpc_cred *cred; |
140 | 142 | ||
141 | while (!hlist_empty(head)) { | 143 | while (!list_empty(head)) { |
142 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); | 144 | cred = list_entry(head->next, struct rpc_cred, cr_lru); |
143 | hlist_del_init(&cred->cr_hash); | 145 | list_del_init(&cred->cr_lru); |
144 | put_rpccred(cred); | 146 | put_rpccred(cred); |
145 | } | 147 | } |
146 | } | 148 | } |
147 | 149 | ||
148 | /* | 150 | /* |
149 | * Clear the RPC credential cache, and delete those credentials | 151 | * Clear the RPC credential cache, and delete those credentials |
150 | * that are not referenced. | 152 | * that are not referenced. |
151 | */ | 153 | */ |
152 | void | 154 | void |
153 | rpcauth_clear_credcache(struct rpc_cred_cache *cache) | 155 | rpcauth_clear_credcache(struct rpc_cred_cache *cache) |
154 | { | 156 | { |
155 | HLIST_HEAD(free); | 157 | LIST_HEAD(free); |
156 | struct hlist_node *pos, *next; | 158 | struct hlist_head *head; |
157 | struct rpc_cred *cred; | 159 | struct rpc_cred *cred; |
158 | int i; | 160 | int i; |
159 | 161 | ||
160 | spin_lock(&rpc_credcache_lock); | 162 | spin_lock(&rpc_credcache_lock); |
161 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { | 163 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { |
162 | hlist_for_each_safe(pos, next, &cache->hashtable[i]) { | 164 | head = &cache->hashtable[i]; |
163 | cred = hlist_entry(pos, struct rpc_cred, cr_hash); | 165 | while (!hlist_empty(head)) { |
164 | __hlist_del(&cred->cr_hash); | 166 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); |
165 | hlist_add_head(&cred->cr_hash, &free); | 167 | get_rpccred(cred); |
168 | list_move_tail(&cred->cr_lru, &free); | ||
169 | smp_wmb(); | ||
170 | hlist_del_init(&cred->cr_hash); | ||
166 | } | 171 | } |
167 | } | 172 | } |
168 | spin_unlock(&rpc_credcache_lock); | 173 | spin_unlock(&rpc_credcache_lock); |
169 | rpcauth_destroy_credlist(&free); | 174 | rpcauth_destroy_credlist(&free); |
170 | } | 175 | } |
171 | 176 | ||
172 | /* | 177 | /* |
173 | * Destroy the RPC credential cache | 178 | * Destroy the RPC credential cache |
174 | */ | 179 | */ |
175 | void | 180 | void |
176 | rpcauth_destroy_credcache(struct rpc_auth *auth) | 181 | rpcauth_destroy_credcache(struct rpc_auth *auth) |
177 | { | 182 | { |
178 | struct rpc_cred_cache *cache = auth->au_credcache; | 183 | struct rpc_cred_cache *cache = auth->au_credcache; |
179 | 184 | ||
180 | if (cache) { | 185 | if (cache) { |
181 | auth->au_credcache = NULL; | 186 | auth->au_credcache = NULL; |
182 | rpcauth_clear_credcache(cache); | 187 | rpcauth_clear_credcache(cache); |
183 | kfree(cache); | 188 | kfree(cache); |
184 | } | 189 | } |
185 | } | 190 | } |
186 | 191 | ||
192 | /* | ||
193 | * Remove stale credentials. Avoid sleeping inside the loop. | ||
194 | */ | ||
187 | static void | 195 | static void |
188 | rpcauth_prune_expired(struct rpc_auth *auth, struct rpc_cred *cred, struct hlist_head *free) | 196 | rpcauth_prune_expired(struct list_head *free) |
189 | { | 197 | { |
190 | if (atomic_read(&cred->cr_count) != 1) | 198 | struct rpc_cred *cred; |
191 | return; | 199 | |
192 | if (time_after(jiffies, cred->cr_expire + auth->au_credcache->expire)) | 200 | while (!list_empty(&cred_unused)) { |
193 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 201 | cred = list_entry(cred_unused.next, struct rpc_cred, cr_lru); |
194 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) { | 202 | if (time_after(jiffies, cred->cr_expire + |
195 | __hlist_del(&cred->cr_hash); | 203 | cred->cr_auth->au_credcache->expire)) |
196 | hlist_add_head(&cred->cr_hash, free); | 204 | break; |
205 | list_del_init(&cred->cr_lru); | ||
206 | if (atomic_read(&cred->cr_count) != 0) | ||
207 | continue; | ||
208 | get_rpccred(cred); | ||
209 | list_add_tail(&cred->cr_lru, free); | ||
210 | smp_wmb(); | ||
211 | hlist_del_init(&cred->cr_hash); | ||
197 | } | 212 | } |
198 | } | 213 | } |
199 | 214 | ||
200 | /* | 215 | /* |
201 | * Remove stale credentials. Avoid sleeping inside the loop. | 216 | * Run garbage collector. |
202 | */ | 217 | */ |
203 | static void | 218 | static void |
204 | rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free) | 219 | rpcauth_gc_credcache(struct rpc_cred_cache *cache, struct list_head *free) |
205 | { | 220 | { |
206 | struct rpc_cred_cache *cache = auth->au_credcache; | 221 | if (time_before(jiffies, cache->nextgc)) |
207 | struct hlist_node *pos, *next; | 222 | return; |
208 | struct rpc_cred *cred; | ||
209 | int i; | ||
210 | |||
211 | dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth); | ||
212 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { | ||
213 | hlist_for_each_safe(pos, next, &cache->hashtable[i]) { | ||
214 | cred = hlist_entry(pos, struct rpc_cred, cr_hash); | ||
215 | rpcauth_prune_expired(auth, cred, free); | ||
216 | } | ||
217 | } | ||
218 | cache->nextgc = jiffies + cache->expire; | 223 | cache->nextgc = jiffies + cache->expire; |
224 | rpcauth_prune_expired(free); | ||
219 | } | 225 | } |
220 | 226 | ||
221 | /* | 227 | /* |
222 | * Look up a process' credentials in the authentication cache | 228 | * Look up a process' credentials in the authentication cache |
223 | */ | 229 | */ |
224 | struct rpc_cred * | 230 | struct rpc_cred * |
225 | rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | 231 | rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, |
226 | int flags) | 232 | int flags) |
227 | { | 233 | { |
234 | LIST_HEAD(free); | ||
228 | struct rpc_cred_cache *cache = auth->au_credcache; | 235 | struct rpc_cred_cache *cache = auth->au_credcache; |
229 | HLIST_HEAD(free); | 236 | struct hlist_node *pos; |
230 | struct hlist_node *pos, *next; | ||
231 | struct rpc_cred *new = NULL, | 237 | struct rpc_cred *new = NULL, |
232 | *cred = NULL; | 238 | *cred = NULL, |
239 | *entry; | ||
233 | int nr = 0; | 240 | int nr = 0; |
234 | 241 | ||
235 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) | 242 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) |
236 | nr = acred->uid & RPC_CREDCACHE_MASK; | 243 | nr = acred->uid & RPC_CREDCACHE_MASK; |
237 | retry: | 244 | retry: |
238 | spin_lock(&rpc_credcache_lock); | 245 | spin_lock(&rpc_credcache_lock); |
239 | if (time_before(cache->nextgc, jiffies)) | 246 | hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) { |
240 | rpcauth_gc_credcache(auth, &free); | 247 | if (!entry->cr_ops->crmatch(acred, entry, flags)) |
241 | hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { | 248 | continue; |
242 | struct rpc_cred *entry; | 249 | cred = get_rpccred(entry); |
243 | entry = hlist_entry(pos, struct rpc_cred, cr_hash); | 250 | hlist_del(&entry->cr_hash); |
244 | if (entry->cr_ops->crmatch(acred, entry, flags)) { | 251 | break; |
245 | hlist_del(&entry->cr_hash); | ||
246 | cred = entry; | ||
247 | break; | ||
248 | } | ||
249 | rpcauth_prune_expired(auth, entry, &free); | ||
250 | } | 252 | } |
251 | if (new) { | 253 | if (new) { |
252 | if (cred) | 254 | if (cred) |
253 | hlist_add_head(&new->cr_hash, &free); | 255 | list_add_tail(&new->cr_lru, &free); |
254 | else | 256 | else |
255 | cred = new; | 257 | cred = new; |
256 | } | 258 | } |
257 | if (cred) { | 259 | if (cred) { |
258 | hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]); | 260 | hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]); |
259 | get_rpccred(cred); | ||
260 | } | 261 | } |
262 | rpcauth_gc_credcache(cache, &free); | ||
261 | spin_unlock(&rpc_credcache_lock); | 263 | spin_unlock(&rpc_credcache_lock); |
262 | 264 | ||
263 | rpcauth_destroy_credlist(&free); | 265 | rpcauth_destroy_credlist(&free); |
264 | 266 | ||
265 | if (!cred) { | 267 | if (!cred) { |
266 | new = auth->au_ops->crcreate(auth, acred, flags); | 268 | new = auth->au_ops->crcreate(auth, acred, flags); |
267 | if (!IS_ERR(new)) | 269 | if (!IS_ERR(new)) |
268 | goto retry; | 270 | goto retry; |
269 | cred = new; | 271 | cred = new; |
270 | } else if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) | 272 | } else if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) |
271 | && cred->cr_ops->cr_init != NULL | 273 | && cred->cr_ops->cr_init != NULL |
272 | && !(flags & RPCAUTH_LOOKUP_NEW)) { | 274 | && !(flags & RPCAUTH_LOOKUP_NEW)) { |
273 | int res = cred->cr_ops->cr_init(auth, cred); | 275 | int res = cred->cr_ops->cr_init(auth, cred); |
274 | if (res < 0) { | 276 | if (res < 0) { |
275 | put_rpccred(cred); | 277 | put_rpccred(cred); |
276 | cred = ERR_PTR(res); | 278 | cred = ERR_PTR(res); |
277 | } | 279 | } |
278 | } | 280 | } |
279 | 281 | ||
280 | return (struct rpc_cred *) cred; | 282 | return (struct rpc_cred *) cred; |
281 | } | 283 | } |
282 | 284 | ||
283 | struct rpc_cred * | 285 | struct rpc_cred * |
284 | rpcauth_lookupcred(struct rpc_auth *auth, int flags) | 286 | rpcauth_lookupcred(struct rpc_auth *auth, int flags) |
285 | { | 287 | { |
286 | struct auth_cred acred = { | 288 | struct auth_cred acred = { |
287 | .uid = current->fsuid, | 289 | .uid = current->fsuid, |
288 | .gid = current->fsgid, | 290 | .gid = current->fsgid, |
289 | .group_info = current->group_info, | 291 | .group_info = current->group_info, |
290 | }; | 292 | }; |
291 | struct rpc_cred *ret; | 293 | struct rpc_cred *ret; |
292 | 294 | ||
293 | dprintk("RPC: looking up %s cred\n", | 295 | dprintk("RPC: looking up %s cred\n", |
294 | auth->au_ops->au_name); | 296 | auth->au_ops->au_name); |
295 | get_group_info(acred.group_info); | 297 | get_group_info(acred.group_info); |
296 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); | 298 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); |
297 | put_group_info(acred.group_info); | 299 | put_group_info(acred.group_info); |
298 | return ret; | 300 | return ret; |
299 | } | 301 | } |
300 | 302 | ||
301 | void | 303 | void |
302 | rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, | 304 | rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, |
303 | struct rpc_auth *auth, const struct rpc_credops *ops) | 305 | struct rpc_auth *auth, const struct rpc_credops *ops) |
304 | { | 306 | { |
305 | INIT_HLIST_NODE(&cred->cr_hash); | 307 | INIT_HLIST_NODE(&cred->cr_hash); |
308 | INIT_LIST_HEAD(&cred->cr_lru); | ||
306 | atomic_set(&cred->cr_count, 1); | 309 | atomic_set(&cred->cr_count, 1); |
307 | cred->cr_auth = auth; | 310 | cred->cr_auth = auth; |
308 | cred->cr_ops = ops; | 311 | cred->cr_ops = ops; |
309 | cred->cr_expire = jiffies; | 312 | cred->cr_expire = jiffies; |
310 | #ifdef RPC_DEBUG | 313 | #ifdef RPC_DEBUG |
311 | cred->cr_magic = RPCAUTH_CRED_MAGIC; | 314 | cred->cr_magic = RPCAUTH_CRED_MAGIC; |
312 | #endif | 315 | #endif |
313 | cred->cr_uid = acred->uid; | 316 | cred->cr_uid = acred->uid; |
314 | } | 317 | } |
315 | EXPORT_SYMBOL(rpcauth_init_cred); | 318 | EXPORT_SYMBOL(rpcauth_init_cred); |
316 | 319 | ||
317 | struct rpc_cred * | 320 | struct rpc_cred * |
318 | rpcauth_bindcred(struct rpc_task *task) | 321 | rpcauth_bindcred(struct rpc_task *task) |
319 | { | 322 | { |
320 | struct rpc_auth *auth = task->tk_auth; | 323 | struct rpc_auth *auth = task->tk_auth; |
321 | struct auth_cred acred = { | 324 | struct auth_cred acred = { |
322 | .uid = current->fsuid, | 325 | .uid = current->fsuid, |
323 | .gid = current->fsgid, | 326 | .gid = current->fsgid, |
324 | .group_info = current->group_info, | 327 | .group_info = current->group_info, |
325 | }; | 328 | }; |
326 | struct rpc_cred *ret; | 329 | struct rpc_cred *ret; |
327 | int flags = 0; | 330 | int flags = 0; |
328 | 331 | ||
329 | dprintk("RPC: %5u looking up %s cred\n", | 332 | dprintk("RPC: %5u looking up %s cred\n", |
330 | task->tk_pid, task->tk_auth->au_ops->au_name); | 333 | task->tk_pid, task->tk_auth->au_ops->au_name); |
331 | get_group_info(acred.group_info); | 334 | get_group_info(acred.group_info); |
332 | if (task->tk_flags & RPC_TASK_ROOTCREDS) | 335 | if (task->tk_flags & RPC_TASK_ROOTCREDS) |
333 | flags |= RPCAUTH_LOOKUP_ROOTCREDS; | 336 | flags |= RPCAUTH_LOOKUP_ROOTCREDS; |
334 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); | 337 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); |
335 | if (!IS_ERR(ret)) | 338 | if (!IS_ERR(ret)) |
336 | task->tk_msg.rpc_cred = ret; | 339 | task->tk_msg.rpc_cred = ret; |
337 | else | 340 | else |
338 | task->tk_status = PTR_ERR(ret); | 341 | task->tk_status = PTR_ERR(ret); |
339 | put_group_info(acred.group_info); | 342 | put_group_info(acred.group_info); |
340 | return ret; | 343 | return ret; |
341 | } | 344 | } |
342 | 345 | ||
343 | void | 346 | void |
344 | rpcauth_holdcred(struct rpc_task *task) | 347 | rpcauth_holdcred(struct rpc_task *task) |
345 | { | 348 | { |
346 | dprintk("RPC: %5u holding %s cred %p\n", | 349 | dprintk("RPC: %5u holding %s cred %p\n", |
347 | task->tk_pid, task->tk_auth->au_ops->au_name, | 350 | task->tk_pid, task->tk_auth->au_ops->au_name, |
348 | task->tk_msg.rpc_cred); | 351 | task->tk_msg.rpc_cred); |
349 | if (task->tk_msg.rpc_cred) | 352 | if (task->tk_msg.rpc_cred) |
350 | get_rpccred(task->tk_msg.rpc_cred); | 353 | get_rpccred(task->tk_msg.rpc_cred); |
351 | } | 354 | } |
352 | 355 | ||
353 | void | 356 | void |
354 | put_rpccred(struct rpc_cred *cred) | 357 | put_rpccred(struct rpc_cred *cred) |
355 | { | 358 | { |
356 | cred->cr_expire = jiffies; | 359 | /* Fast path for unhashed credentials */ |
360 | if (!hlist_unhashed(&cred->cr_hash)) | ||
361 | goto need_lock; | ||
362 | |||
357 | if (!atomic_dec_and_test(&cred->cr_count)) | 363 | if (!atomic_dec_and_test(&cred->cr_count)) |
358 | return; | 364 | return; |
365 | goto out_destroy; | ||
366 | |||
367 | need_lock: | ||
368 | if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) | ||
369 | return; | ||
370 | if (!list_empty(&cred->cr_lru)) | ||
371 | list_del_init(&cred->cr_lru); | ||
372 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) | ||
373 | hlist_del(&cred->cr_hash); | ||
374 | else if (!hlist_unhashed(&cred->cr_hash)) { | ||
375 | cred->cr_expire = jiffies; | ||
376 | list_add_tail(&cred->cr_lru, &cred_unused); | ||
377 | spin_unlock(&rpc_credcache_lock); | ||
378 | return; | ||
379 | } | ||
380 | spin_unlock(&rpc_credcache_lock); | ||
381 | out_destroy: | ||
359 | cred->cr_ops->crdestroy(cred); | 382 | cred->cr_ops->crdestroy(cred); |
360 | } | 383 | } |
361 | 384 | ||
362 | void | 385 | void |
363 | rpcauth_unbindcred(struct rpc_task *task) | 386 | rpcauth_unbindcred(struct rpc_task *task) |
364 | { | 387 | { |
365 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 388 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
366 | 389 | ||
367 | dprintk("RPC: %5u releasing %s cred %p\n", | 390 | dprintk("RPC: %5u releasing %s cred %p\n", |
368 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); | 391 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); |
369 | 392 | ||
370 | put_rpccred(cred); | 393 | put_rpccred(cred); |
371 | task->tk_msg.rpc_cred = NULL; | 394 | task->tk_msg.rpc_cred = NULL; |
372 | } | 395 | } |
373 | 396 | ||
374 | __be32 * | 397 | __be32 * |
375 | rpcauth_marshcred(struct rpc_task *task, __be32 *p) | 398 | rpcauth_marshcred(struct rpc_task *task, __be32 *p) |
376 | { | 399 | { |
377 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 400 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
378 | 401 | ||
379 | dprintk("RPC: %5u marshaling %s cred %p\n", | 402 | dprintk("RPC: %5u marshaling %s cred %p\n", |
380 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); | 403 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); |
381 | 404 | ||
382 | return cred->cr_ops->crmarshal(task, p); | 405 | return cred->cr_ops->crmarshal(task, p); |
383 | } | 406 | } |
384 | 407 | ||
385 | __be32 * | 408 | __be32 * |
386 | rpcauth_checkverf(struct rpc_task *task, __be32 *p) | 409 | rpcauth_checkverf(struct rpc_task *task, __be32 *p) |
387 | { | 410 | { |
388 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 411 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
389 | 412 | ||
390 | dprintk("RPC: %5u validating %s cred %p\n", | 413 | dprintk("RPC: %5u validating %s cred %p\n", |
391 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); | 414 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); |
392 | 415 | ||
393 | return cred->cr_ops->crvalidate(task, p); | 416 | return cred->cr_ops->crvalidate(task, p); |
394 | } | 417 | } |
395 | 418 | ||
396 | int | 419 | int |
397 | rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, | 420 | rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, |
398 | __be32 *data, void *obj) | 421 | __be32 *data, void *obj) |
399 | { | 422 | { |
400 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 423 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
401 | 424 | ||
402 | dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", | 425 | dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", |
403 | task->tk_pid, cred->cr_ops->cr_name, cred); | 426 | task->tk_pid, cred->cr_ops->cr_name, cred); |
404 | if (cred->cr_ops->crwrap_req) | 427 | if (cred->cr_ops->crwrap_req) |
405 | return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); | 428 | return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); |
406 | /* By default, we encode the arguments normally. */ | 429 | /* By default, we encode the arguments normally. */ |
407 | return encode(rqstp, data, obj); | 430 | return encode(rqstp, data, obj); |
408 | } | 431 | } |
409 | 432 | ||
410 | int | 433 | int |
411 | rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, | 434 | rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, |
412 | __be32 *data, void *obj) | 435 | __be32 *data, void *obj) |
413 | { | 436 | { |
414 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 437 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
415 | 438 | ||
416 | dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", | 439 | dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", |
417 | task->tk_pid, cred->cr_ops->cr_name, cred); | 440 | task->tk_pid, cred->cr_ops->cr_name, cred); |
418 | if (cred->cr_ops->crunwrap_resp) | 441 | if (cred->cr_ops->crunwrap_resp) |
419 | return cred->cr_ops->crunwrap_resp(task, decode, rqstp, | 442 | return cred->cr_ops->crunwrap_resp(task, decode, rqstp, |
420 | data, obj); | 443 | data, obj); |
421 | /* By default, we decode the arguments normally. */ | 444 | /* By default, we decode the arguments normally. */ |
422 | return decode(rqstp, data, obj); | 445 | return decode(rqstp, data, obj); |
423 | } | 446 | } |
424 | 447 | ||
425 | int | 448 | int |
426 | rpcauth_refreshcred(struct rpc_task *task) | 449 | rpcauth_refreshcred(struct rpc_task *task) |
427 | { | 450 | { |
428 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 451 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
429 | int err; | 452 | int err; |
430 | 453 | ||
431 | dprintk("RPC: %5u refreshing %s cred %p\n", | 454 | dprintk("RPC: %5u refreshing %s cred %p\n", |
432 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); | 455 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); |
433 | 456 | ||
434 | err = cred->cr_ops->crrefresh(task); | 457 | err = cred->cr_ops->crrefresh(task); |
435 | if (err < 0) | 458 | if (err < 0) |
436 | task->tk_status = err; | 459 | task->tk_status = err; |
437 | return err; | 460 | return err; |
438 | } | 461 | } |
439 | 462 | ||
440 | void | 463 | void |
441 | rpcauth_invalcred(struct rpc_task *task) | 464 | rpcauth_invalcred(struct rpc_task *task) |
442 | { | 465 | { |
net/sunrpc/auth_null.c
1 | /* | 1 | /* |
2 | * linux/net/sunrpc/auth_null.c | 2 | * linux/net/sunrpc/auth_null.c |
3 | * | 3 | * |
4 | * AUTH_NULL authentication. Really :-) | 4 | * AUTH_NULL authentication. Really :-) |
5 | * | 5 | * |
6 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/utsname.h> | 11 | #include <linux/utsname.h> |
12 | #include <linux/sunrpc/clnt.h> | 12 | #include <linux/sunrpc/clnt.h> |
13 | 13 | ||
14 | #ifdef RPC_DEBUG | 14 | #ifdef RPC_DEBUG |
15 | # define RPCDBG_FACILITY RPCDBG_AUTH | 15 | # define RPCDBG_FACILITY RPCDBG_AUTH |
16 | #endif | 16 | #endif |
17 | 17 | ||
18 | static struct rpc_auth null_auth; | 18 | static struct rpc_auth null_auth; |
19 | static struct rpc_cred null_cred; | 19 | static struct rpc_cred null_cred; |
20 | 20 | ||
21 | static struct rpc_auth * | 21 | static struct rpc_auth * |
22 | nul_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | 22 | nul_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) |
23 | { | 23 | { |
24 | atomic_inc(&null_auth.au_count); | 24 | atomic_inc(&null_auth.au_count); |
25 | return &null_auth; | 25 | return &null_auth; |
26 | } | 26 | } |
27 | 27 | ||
28 | static void | 28 | static void |
29 | nul_destroy(struct rpc_auth *auth) | 29 | nul_destroy(struct rpc_auth *auth) |
30 | { | 30 | { |
31 | } | 31 | } |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * Lookup NULL creds for current process | 34 | * Lookup NULL creds for current process |
35 | */ | 35 | */ |
36 | static struct rpc_cred * | 36 | static struct rpc_cred * |
37 | nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | 37 | nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) |
38 | { | 38 | { |
39 | return get_rpccred(&null_cred); | 39 | return get_rpccred(&null_cred); |
40 | } | 40 | } |
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Destroy cred handle. | 43 | * Destroy cred handle. |
44 | */ | 44 | */ |
45 | static void | 45 | static void |
46 | nul_destroy_cred(struct rpc_cred *cred) | 46 | nul_destroy_cred(struct rpc_cred *cred) |
47 | { | 47 | { |
48 | } | 48 | } |
49 | 49 | ||
50 | /* | 50 | /* |
51 | * Match cred handle against current process | 51 | * Match cred handle against current process |
52 | */ | 52 | */ |
53 | static int | 53 | static int |
54 | nul_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags) | 54 | nul_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags) |
55 | { | 55 | { |
56 | return 1; | 56 | return 1; |
57 | } | 57 | } |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * Marshal credential. | 60 | * Marshal credential. |
61 | */ | 61 | */ |
62 | static __be32 * | 62 | static __be32 * |
63 | nul_marshal(struct rpc_task *task, __be32 *p) | 63 | nul_marshal(struct rpc_task *task, __be32 *p) |
64 | { | 64 | { |
65 | *p++ = htonl(RPC_AUTH_NULL); | 65 | *p++ = htonl(RPC_AUTH_NULL); |
66 | *p++ = 0; | 66 | *p++ = 0; |
67 | *p++ = htonl(RPC_AUTH_NULL); | 67 | *p++ = htonl(RPC_AUTH_NULL); |
68 | *p++ = 0; | 68 | *p++ = 0; |
69 | 69 | ||
70 | return p; | 70 | return p; |
71 | } | 71 | } |
72 | 72 | ||
73 | /* | 73 | /* |
74 | * Refresh credential. This is a no-op for AUTH_NULL | 74 | * Refresh credential. This is a no-op for AUTH_NULL |
75 | */ | 75 | */ |
76 | static int | 76 | static int |
77 | nul_refresh(struct rpc_task *task) | 77 | nul_refresh(struct rpc_task *task) |
78 | { | 78 | { |
79 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags); | 79 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags); |
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static __be32 * | 83 | static __be32 * |
84 | nul_validate(struct rpc_task *task, __be32 *p) | 84 | nul_validate(struct rpc_task *task, __be32 *p) |
85 | { | 85 | { |
86 | rpc_authflavor_t flavor; | 86 | rpc_authflavor_t flavor; |
87 | u32 size; | 87 | u32 size; |
88 | 88 | ||
89 | flavor = ntohl(*p++); | 89 | flavor = ntohl(*p++); |
90 | if (flavor != RPC_AUTH_NULL) { | 90 | if (flavor != RPC_AUTH_NULL) { |
91 | printk("RPC: bad verf flavor: %u\n", flavor); | 91 | printk("RPC: bad verf flavor: %u\n", flavor); |
92 | return NULL; | 92 | return NULL; |
93 | } | 93 | } |
94 | 94 | ||
95 | size = ntohl(*p++); | 95 | size = ntohl(*p++); |
96 | if (size != 0) { | 96 | if (size != 0) { |
97 | printk("RPC: bad verf size: %u\n", size); | 97 | printk("RPC: bad verf size: %u\n", size); |
98 | return NULL; | 98 | return NULL; |
99 | } | 99 | } |
100 | 100 | ||
101 | return p; | 101 | return p; |
102 | } | 102 | } |
103 | 103 | ||
104 | const struct rpc_authops authnull_ops = { | 104 | const struct rpc_authops authnull_ops = { |
105 | .owner = THIS_MODULE, | 105 | .owner = THIS_MODULE, |
106 | .au_flavor = RPC_AUTH_NULL, | 106 | .au_flavor = RPC_AUTH_NULL, |
107 | #ifdef RPC_DEBUG | 107 | #ifdef RPC_DEBUG |
108 | .au_name = "NULL", | 108 | .au_name = "NULL", |
109 | #endif | 109 | #endif |
110 | .create = nul_create, | 110 | .create = nul_create, |
111 | .destroy = nul_destroy, | 111 | .destroy = nul_destroy, |
112 | .lookup_cred = nul_lookup_cred, | 112 | .lookup_cred = nul_lookup_cred, |
113 | }; | 113 | }; |
114 | 114 | ||
115 | static | 115 | static |
116 | struct rpc_auth null_auth = { | 116 | struct rpc_auth null_auth = { |
117 | .au_cslack = 4, | 117 | .au_cslack = 4, |
118 | .au_rslack = 2, | 118 | .au_rslack = 2, |
119 | .au_ops = &authnull_ops, | 119 | .au_ops = &authnull_ops, |
120 | .au_flavor = RPC_AUTH_NULL, | 120 | .au_flavor = RPC_AUTH_NULL, |
121 | .au_count = ATOMIC_INIT(0), | 121 | .au_count = ATOMIC_INIT(0), |
122 | }; | 122 | }; |
123 | 123 | ||
124 | static | 124 | static |
125 | const struct rpc_credops null_credops = { | 125 | const struct rpc_credops null_credops = { |
126 | .cr_name = "AUTH_NULL", | 126 | .cr_name = "AUTH_NULL", |
127 | .crdestroy = nul_destroy_cred, | 127 | .crdestroy = nul_destroy_cred, |
128 | .crmatch = nul_match, | 128 | .crmatch = nul_match, |
129 | .crmarshal = nul_marshal, | 129 | .crmarshal = nul_marshal, |
130 | .crrefresh = nul_refresh, | 130 | .crrefresh = nul_refresh, |
131 | .crvalidate = nul_validate, | 131 | .crvalidate = nul_validate, |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static | 134 | static |
135 | struct rpc_cred null_cred = { | 135 | struct rpc_cred null_cred = { |
136 | .cr_lru = LIST_HEAD_INIT(null_cred.cr_lru), | ||
136 | .cr_auth = &null_auth, | 137 | .cr_auth = &null_auth, |
137 | .cr_ops = &null_credops, | 138 | .cr_ops = &null_credops, |
138 | .cr_count = ATOMIC_INIT(1), | 139 | .cr_count = ATOMIC_INIT(1), |
139 | .cr_flags = 1UL << RPCAUTH_CRED_UPTODATE, | 140 | .cr_flags = 1UL << RPCAUTH_CRED_UPTODATE, |
140 | #ifdef RPC_DEBUG | 141 | #ifdef RPC_DEBUG |
141 | .cr_magic = RPCAUTH_CRED_MAGIC, | 142 | .cr_magic = RPCAUTH_CRED_MAGIC, |
142 | #endif | 143 | #endif |
143 | }; | 144 | }; |
144 | 145 |