Blame view

net/sunrpc/auth.c 13.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * linux/net/sunrpc/auth.c
   *
   * Generic RPC client authentication API.
   *
   * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
   */
  
  #include <linux/types.h>
  #include <linux/sched.h>
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/errno.h>
25337fdc8   Trond Myklebust   SUNRPC: Fix a bug...
14
  #include <linux/hash.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
  #include <linux/sunrpc/clnt.h>
  #include <linux/spinlock.h>
  
  #ifdef RPC_DEBUG
  # define RPCDBG_FACILITY	RPCDBG_AUTH
  #endif
fc1b356f5   Trond Myklebust   SUNRPC: Fix races...
21
  static DEFINE_SPINLOCK(rpc_authflavor_lock);
f1c0a8615   Trond Myklebust   SUNRPC: Mark auth...
22
  static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
  	&authnull_ops,		/* AUTH_NULL */
  	&authunix_ops,		/* AUTH_UNIX */
  	NULL,			/* others can be loadable modules */
  };
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
27
  static LIST_HEAD(cred_unused);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
28
  static unsigned long number_cred_unused;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
29

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
36
37
  static u32
  pseudoflavor_to_flavor(u32 flavor) {
  	if (flavor >= RPC_AUTH_MAXFLAVOR)
  		return RPC_AUTH_GSS;
  	return flavor;
  }
  
  int
f1c0a8615   Trond Myklebust   SUNRPC: Mark auth...
38
  rpcauth_register(const struct rpc_authops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  {
  	rpc_authflavor_t flavor;
fc1b356f5   Trond Myklebust   SUNRPC: Fix races...
41
  	int ret = -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  
  	if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
  		return -EINVAL;
fc1b356f5   Trond Myklebust   SUNRPC: Fix races...
45
46
47
48
49
50
51
  	spin_lock(&rpc_authflavor_lock);
  	if (auth_flavors[flavor] == NULL) {
  		auth_flavors[flavor] = ops;
  		ret = 0;
  	}
  	spin_unlock(&rpc_authflavor_lock);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
53
  EXPORT_SYMBOL_GPL(rpcauth_register);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
  
  int
f1c0a8615   Trond Myklebust   SUNRPC: Mark auth...
56
  rpcauth_unregister(const struct rpc_authops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
  {
  	rpc_authflavor_t flavor;
fc1b356f5   Trond Myklebust   SUNRPC: Fix races...
59
  	int ret = -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
  
  	if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
  		return -EINVAL;
fc1b356f5   Trond Myklebust   SUNRPC: Fix races...
63
64
65
66
67
68
69
  	spin_lock(&rpc_authflavor_lock);
  	if (auth_flavors[flavor] == ops) {
  		auth_flavors[flavor] = NULL;
  		ret = 0;
  	}
  	spin_unlock(&rpc_authflavor_lock);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
71
  EXPORT_SYMBOL_GPL(rpcauth_unregister);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
  
  struct rpc_auth *
  rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
  {
  	struct rpc_auth		*auth;
f1c0a8615   Trond Myklebust   SUNRPC: Mark auth...
77
  	const struct rpc_authops *ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  	u32			flavor = pseudoflavor_to_flavor(pseudoflavor);
f344f6df4   Olaf Kirch   SUNRPC: Auto-load...
79
80
81
  	auth = ERR_PTR(-EINVAL);
  	if (flavor >= RPC_AUTH_MAXFLAVOR)
  		goto out;
f344f6df4   Olaf Kirch   SUNRPC: Auto-load...
82
83
  	if ((ops = auth_flavors[flavor]) == NULL)
  		request_module("rpc-auth-%u", flavor);
fc1b356f5   Trond Myklebust   SUNRPC: Fix races...
84
85
86
87
  	spin_lock(&rpc_authflavor_lock);
  	ops = auth_flavors[flavor];
  	if (ops == NULL || !try_module_get(ops->owner)) {
  		spin_unlock(&rpc_authflavor_lock);
f344f6df4   Olaf Kirch   SUNRPC: Auto-load...
88
  		goto out;
fc1b356f5   Trond Myklebust   SUNRPC: Fix races...
89
90
  	}
  	spin_unlock(&rpc_authflavor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  	auth = ops->create(clnt, pseudoflavor);
fc1b356f5   Trond Myklebust   SUNRPC: Fix races...
92
  	module_put(ops->owner);
6a19275ad   J. Bruce Fields   [PATCH] RPC: [PAT...
93
94
  	if (IS_ERR(auth))
  		return auth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  	if (clnt->cl_auth)
de7a8ce38   Trond Myklebust   SUNRPC: Rename rp...
96
  		rpcauth_release(clnt->cl_auth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  	clnt->cl_auth = auth;
f344f6df4   Olaf Kirch   SUNRPC: Auto-load...
98
99
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
  	return auth;
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
102
  EXPORT_SYMBOL_GPL(rpcauth_create);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
  
  void
de7a8ce38   Trond Myklebust   SUNRPC: Rename rp...
105
  rpcauth_release(struct rpc_auth *auth)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
109
110
111
112
  {
  	if (!atomic_dec_and_test(&auth->au_count))
  		return;
  	auth->au_ops->destroy(auth);
  }
  
  static DEFINE_SPINLOCK(rpc_credcache_lock);
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
113
114
115
116
117
118
119
  static void
  rpcauth_unhash_cred_locked(struct rpc_cred *cred)
  {
  	hlist_del_rcu(&cred->cr_hash);
  	smp_mb__before_clear_bit();
  	clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
  }
9499b4341   Trond Myklebust   SUNRPC: Give cred...
120
121
122
123
124
125
126
127
128
129
130
  static void
  rpcauth_unhash_cred(struct rpc_cred *cred)
  {
  	spinlock_t *cache_lock;
  
  	cache_lock = &cred->cr_auth->au_credcache->lock;
  	spin_lock(cache_lock);
  	if (atomic_read(&cred->cr_count) == 0)
  		rpcauth_unhash_cred_locked(cred);
  	spin_unlock(cache_lock);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
  /*
   * Initialize RPC credential cache
   */
  int
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
135
  rpcauth_init_credcache(struct rpc_auth *auth)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
  {
  	struct rpc_cred_cache *new;
  	int i;
8b3a70058   Kris Katterjohn   [NET]: Remove mor...
139
  	new = kmalloc(sizeof(*new), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
  	if (!new)
  		return -ENOMEM;
  	for (i = 0; i < RPC_CREDCACHE_NR; i++)
  		INIT_HLIST_HEAD(&new->hashtable[i]);
9499b4341   Trond Myklebust   SUNRPC: Give cred...
144
  	spin_lock_init(&new->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
  	auth->au_credcache = new;
  	return 0;
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
148
  EXPORT_SYMBOL_GPL(rpcauth_init_credcache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
  
  /*
   * Destroy a list of credentials
   */
  static inline
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
154
  void rpcauth_destroy_credlist(struct list_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
  {
  	struct rpc_cred *cred;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
157
158
159
  	while (!list_empty(head)) {
  		cred = list_entry(head->next, struct rpc_cred, cr_lru);
  		list_del_init(&cred->cr_lru);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
165
166
167
168
  		put_rpccred(cred);
  	}
  }
  
  /*
   * Clear the RPC credential cache, and delete those credentials
   * that are not referenced.
   */
  void
3ab9bb724   Trond Myklebust   SUNRPC: Fix a mem...
169
  rpcauth_clear_credcache(struct rpc_cred_cache *cache)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  {
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
171
172
  	LIST_HEAD(free);
  	struct hlist_head *head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
  	struct rpc_cred	*cred;
  	int		i;
  
  	spin_lock(&rpc_credcache_lock);
9499b4341   Trond Myklebust   SUNRPC: Give cred...
177
  	spin_lock(&cache->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  	for (i = 0; i < RPC_CREDCACHE_NR; i++) {
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
179
180
181
182
  		head = &cache->hashtable[i];
  		while (!hlist_empty(head)) {
  			cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
  			get_rpccred(cred);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
183
184
185
186
187
  			if (!list_empty(&cred->cr_lru)) {
  				list_del(&cred->cr_lru);
  				number_cred_unused--;
  			}
  			list_add_tail(&cred->cr_lru, &free);
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
188
  			rpcauth_unhash_cred_locked(cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
  		}
  	}
9499b4341   Trond Myklebust   SUNRPC: Give cred...
191
  	spin_unlock(&cache->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
  	spin_unlock(&rpc_credcache_lock);
  	rpcauth_destroy_credlist(&free);
  }
3ab9bb724   Trond Myklebust   SUNRPC: Fix a mem...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  /*
   * Destroy the RPC credential cache
   */
  void
  rpcauth_destroy_credcache(struct rpc_auth *auth)
  {
  	struct rpc_cred_cache *cache = auth->au_credcache;
  
  	if (cache) {
  		auth->au_credcache = NULL;
  		rpcauth_clear_credcache(cache);
  		kfree(cache);
  	}
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
209
  EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache);
3ab9bb724   Trond Myklebust   SUNRPC: Fix a mem...
210

d2b831416   Trond Myklebust   SUNRPC: Protect c...
211
212
  
  #define RPC_AUTH_EXPIRY_MORATORIUM (60 * HZ)
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
213
214
215
  /*
   * Remove stale credentials. Avoid sleeping inside the loop.
   */
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
216
217
  static int
  rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  {
9499b4341   Trond Myklebust   SUNRPC: Give cred...
219
  	spinlock_t *cache_lock;
eac0d18d4   Trond Myklebust   SUNRPC: Fix rpcau...
220
  	struct rpc_cred *cred, *next;
d2b831416   Trond Myklebust   SUNRPC: Protect c...
221
  	unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
222

eac0d18d4   Trond Myklebust   SUNRPC: Fix rpcau...
223
224
225
  	list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) {
  
  		/* Enforce a 60 second garbage collection moratorium */
64672d55d   Peter Staubach   optimize attribut...
226
  		if (time_in_range_open(cred->cr_expire, expired, jiffies) &&
eac0d18d4   Trond Myklebust   SUNRPC: Fix rpcau...
227
228
  		    test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
  			continue;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
229
  		list_del_init(&cred->cr_lru);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
230
  		number_cred_unused--;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
231
232
  		if (atomic_read(&cred->cr_count) != 0)
  			continue;
eac0d18d4   Trond Myklebust   SUNRPC: Fix rpcau...
233

9499b4341   Trond Myklebust   SUNRPC: Give cred...
234
235
236
237
238
239
  		cache_lock = &cred->cr_auth->au_credcache->lock;
  		spin_lock(cache_lock);
  		if (atomic_read(&cred->cr_count) == 0) {
  			get_rpccred(cred);
  			list_add_tail(&cred->cr_lru, free);
  			rpcauth_unhash_cred_locked(cred);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
240
  			nr_to_scan--;
9499b4341   Trond Myklebust   SUNRPC: Give cred...
241
242
  		}
  		spin_unlock(cache_lock);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
243
244
  		if (nr_to_scan == 0)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  	}
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
246
  	return nr_to_scan;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
  }
  
  /*
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
250
   * Run memory cache shrinker.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
   */
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
252
253
  static int
  rpcauth_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  {
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
255
256
257
258
259
  	LIST_HEAD(free);
  	int res;
  
  	if (list_empty(&cred_unused))
  		return 0;
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
260
  	spin_lock(&rpc_credcache_lock);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
261
262
  	nr_to_scan = rpcauth_prune_expired(&free, nr_to_scan);
  	res = (number_cred_unused / 100) * sysctl_vfs_cache_pressure;
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
263
  	spin_unlock(&rpc_credcache_lock);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
264
265
  	rpcauth_destroy_credlist(&free);
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
270
271
272
  }
  
  /*
   * Look up a process' credentials in the authentication cache
   */
  struct rpc_cred *
  rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
8a3177604   Trond Myklebust   SUNRPC: Fix a loc...
273
  		int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  {
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
275
  	LIST_HEAD(free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  	struct rpc_cred_cache *cache = auth->au_credcache;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
277
  	struct hlist_node *pos;
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
278
279
  	struct rpc_cred	*cred = NULL,
  			*entry, *new;
25337fdc8   Trond Myklebust   SUNRPC: Fix a bug...
280
281
282
  	unsigned int nr;
  
  	nr = hash_long(acred->uid, RPC_CREDCACHE_HASHBITS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

31be5bf15   Trond Myklebust   SUNRPC: Convert t...
284
285
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) {
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
286
287
  		if (!entry->cr_ops->crmatch(acred, entry, flags))
  			continue;
9499b4341   Trond Myklebust   SUNRPC: Give cred...
288
  		spin_lock(&cache->lock);
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
289
  		if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) {
9499b4341   Trond Myklebust   SUNRPC: Give cred...
290
  			spin_unlock(&cache->lock);
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
291
292
  			continue;
  		}
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
293
  		cred = get_rpccred(entry);
9499b4341   Trond Myklebust   SUNRPC: Give cred...
294
  		spin_unlock(&cache->lock);
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
295
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  	}
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
297
  	rcu_read_unlock();
9499b4341   Trond Myklebust   SUNRPC: Give cred...
298
  	if (cred != NULL)
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
299
  		goto found;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300

31be5bf15   Trond Myklebust   SUNRPC: Convert t...
301
302
303
304
305
  	new = auth->au_ops->crcreate(auth, acred, flags);
  	if (IS_ERR(new)) {
  		cred = new;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306

9499b4341   Trond Myklebust   SUNRPC: Give cred...
307
  	spin_lock(&cache->lock);
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
308
309
310
311
312
313
314
  	hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) {
  		if (!entry->cr_ops->crmatch(acred, entry, flags))
  			continue;
  		cred = get_rpccred(entry);
  		break;
  	}
  	if (cred == NULL) {
5fe4755e2   Trond Myklebust   SUNRPC: Clean up ...
315
  		cred = new;
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
316
317
318
319
  		set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
  		hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]);
  	} else
  		list_add_tail(&new->cr_lru, &free);
9499b4341   Trond Myklebust   SUNRPC: Give cred...
320
  	spin_unlock(&cache->lock);
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
321
322
  found:
  	if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)
fba3bad48   Trond Myklebust   SUNRPC: Move upca...
323
324
325
326
327
328
329
  			&& cred->cr_ops->cr_init != NULL
  			&& !(flags & RPCAUTH_LOOKUP_NEW)) {
  		int res = cred->cr_ops->cr_init(auth, cred);
  		if (res < 0) {
  			put_rpccred(cred);
  			cred = ERR_PTR(res);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  	}
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
331
332
333
  	rpcauth_destroy_credlist(&free);
  out:
  	return cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
335
  EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
  
  struct rpc_cred *
8a3177604   Trond Myklebust   SUNRPC: Fix a loc...
338
  rpcauth_lookupcred(struct rpc_auth *auth, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  {
86a264abe   David Howells   CRED: Wrap curren...
340
  	struct auth_cred acred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
  	struct rpc_cred *ret;
86a264abe   David Howells   CRED: Wrap curren...
342
  	const struct cred *cred = current_cred();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343

46121cf7d   Chuck Lever   SUNRPC: fix print...
344
345
  	dprintk("RPC:       looking up %s cred
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  		auth->au_ops->au_name);
86a264abe   David Howells   CRED: Wrap curren...
347
348
349
350
351
  
  	memset(&acred, 0, sizeof(acred));
  	acred.uid = cred->fsuid;
  	acred.gid = cred->fsgid;
  	acred.group_info = get_group_info(((struct cred *)cred)->group_info);
8a3177604   Trond Myklebust   SUNRPC: Fix a loc...
352
  	ret = auth->au_ops->lookup_cred(auth, &acred, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
  	put_group_info(acred.group_info);
  	return ret;
  }
5fe4755e2   Trond Myklebust   SUNRPC: Clean up ...
356
357
358
359
360
  void
  rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
  		  struct rpc_auth *auth, const struct rpc_credops *ops)
  {
  	INIT_HLIST_NODE(&cred->cr_hash);
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
361
  	INIT_LIST_HEAD(&cred->cr_lru);
5fe4755e2   Trond Myklebust   SUNRPC: Clean up ...
362
363
364
365
366
367
368
369
370
  	atomic_set(&cred->cr_count, 1);
  	cred->cr_auth = auth;
  	cred->cr_ops = ops;
  	cred->cr_expire = jiffies;
  #ifdef RPC_DEBUG
  	cred->cr_magic = RPCAUTH_CRED_MAGIC;
  #endif
  	cred->cr_uid = acred->uid;
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
371
  EXPORT_SYMBOL_GPL(rpcauth_init_cred);
5fe4755e2   Trond Myklebust   SUNRPC: Clean up ...
372

5c691044e   Trond Myklebust   SUNRPC: Add an rp...
373
  void
4ccda2cdd   Trond Myklebust   SUNRPC: Clean up ...
374
375
376
377
378
379
380
  rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred)
  {
  	task->tk_msg.rpc_cred = get_rpccred(cred);
  	dprintk("RPC: %5u holding %s cred %p
  ", task->tk_pid,
  			cred->cr_auth->au_ops->au_name, cred);
  }
5c691044e   Trond Myklebust   SUNRPC: Add an rp...
381
  EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred);
4ccda2cdd   Trond Myklebust   SUNRPC: Clean up ...
382
383
  
  static void
af0938357   Trond Myklebust   SUNRPC: Fix RPCAU...
384
  rpcauth_bind_root_cred(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  {
1be27f366   Trond Myklebust   SUNRPC: Remove th...
386
  	struct rpc_auth *auth = task->tk_client->cl_auth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  	struct auth_cred acred = {
af0938357   Trond Myklebust   SUNRPC: Fix RPCAU...
388
389
  		.uid = 0,
  		.gid = 0,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  	};
  	struct rpc_cred *ret;
46121cf7d   Chuck Lever   SUNRPC: fix print...
392
393
  	dprintk("RPC: %5u looking up %s cred
  ",
1be27f366   Trond Myklebust   SUNRPC: Remove th...
394
  		task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
af0938357   Trond Myklebust   SUNRPC: Fix RPCAU...
395
396
397
398
399
400
  	ret = auth->au_ops->lookup_cred(auth, &acred, 0);
  	if (!IS_ERR(ret))
  		task->tk_msg.rpc_cred = ret;
  	else
  		task->tk_status = PTR_ERR(ret);
  }
4ccda2cdd   Trond Myklebust   SUNRPC: Clean up ...
401
402
  static void
  rpcauth_bind_new_cred(struct rpc_task *task)
af0938357   Trond Myklebust   SUNRPC: Fix RPCAU...
403
404
405
406
407
408
409
410
  {
  	struct rpc_auth *auth = task->tk_client->cl_auth;
  	struct rpc_cred *ret;
  
  	dprintk("RPC: %5u looking up %s cred
  ",
  		task->tk_pid, auth->au_ops->au_name);
  	ret = rpcauth_lookupcred(auth, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
  	if (!IS_ERR(ret))
  		task->tk_msg.rpc_cred = ret;
  	else
  		task->tk_status = PTR_ERR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
  }
  
  void
4ccda2cdd   Trond Myklebust   SUNRPC: Clean up ...
418
  rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  {
4ccda2cdd   Trond Myklebust   SUNRPC: Clean up ...
420
  	if (cred != NULL)
5c691044e   Trond Myklebust   SUNRPC: Add an rp...
421
  		cred->cr_ops->crbind(task, cred);
4ccda2cdd   Trond Myklebust   SUNRPC: Clean up ...
422
423
424
425
  	else if (flags & RPC_TASK_ROOTCREDS)
  		rpcauth_bind_root_cred(task);
  	else
  		rpcauth_bind_new_cred(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
429
430
  }
  
  void
  put_rpccred(struct rpc_cred *cred)
  {
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
431
  	/* Fast path for unhashed credentials */
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
432
  	if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
433
  		goto need_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
  	if (!atomic_dec_and_test(&cred->cr_count))
  		return;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
436
  	goto out_destroy;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
437
438
439
  need_lock:
  	if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
  		return;
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
440
441
  	if (!list_empty(&cred->cr_lru)) {
  		number_cred_unused--;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
442
  		list_del_init(&cred->cr_lru);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
443
  	}
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
444
  	if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
9499b4341   Trond Myklebust   SUNRPC: Give cred...
445
  		rpcauth_unhash_cred(cred);
5f707eb42   Trond Myklebust   SUNRPC: Fix poten...
446
  	if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
447
448
  		cred->cr_expire = jiffies;
  		list_add_tail(&cred->cr_lru, &cred_unused);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
449
  		number_cred_unused++;
e092bdcd9   Trond Myklebust   SUNRPC: cleanup r...
450
451
452
453
454
  		spin_unlock(&rpc_credcache_lock);
  		return;
  	}
  	spin_unlock(&rpc_credcache_lock);
  out_destroy:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
  	cred->cr_ops->crdestroy(cred);
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
457
  EXPORT_SYMBOL_GPL(put_rpccred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
  
  void
  rpcauth_unbindcred(struct rpc_task *task)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
46121cf7d   Chuck Lever   SUNRPC: fix print...
463
464
  	dprintk("RPC: %5u releasing %s cred %p
  ",
1be27f366   Trond Myklebust   SUNRPC: Remove th...
465
  		task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
468
469
  
  	put_rpccred(cred);
  	task->tk_msg.rpc_cred = NULL;
  }
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
470
471
  __be32 *
  rpcauth_marshcred(struct rpc_task *task, __be32 *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
  	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
46121cf7d   Chuck Lever   SUNRPC: fix print...
474
475
  	dprintk("RPC: %5u marshaling %s cred %p
  ",
1be27f366   Trond Myklebust   SUNRPC: Remove th...
476
  		task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
0bbacc402   Chuck Lever   NFS,SUNRPC,NLM: f...
477

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
  	return cred->cr_ops->crmarshal(task, p);
  }
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
480
481
  __be32 *
  rpcauth_checkverf(struct rpc_task *task, __be32 *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
  	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
46121cf7d   Chuck Lever   SUNRPC: fix print...
484
485
  	dprintk("RPC: %5u validating %s cred %p
  ",
1be27f366   Trond Myklebust   SUNRPC: Remove th...
486
  		task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
0bbacc402   Chuck Lever   NFS,SUNRPC,NLM: f...
487

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
491
492
  	return cred->cr_ops->crvalidate(task, p);
  }
  
  int
  rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
493
  		__be32 *data, void *obj)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
  {
  	struct rpc_cred *cred = task->tk_msg.rpc_cred;
46121cf7d   Chuck Lever   SUNRPC: fix print...
496
497
  	dprintk("RPC: %5u using %s cred %p to wrap rpc data
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
  			task->tk_pid, cred->cr_ops->cr_name, cred);
  	if (cred->cr_ops->crwrap_req)
  		return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
  	/* By default, we encode the arguments normally. */
88a9fe8ca   Trond Myklebust   SUNRPC: Remove th...
502
  	return encode(rqstp, data, obj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
  }
  
  int
  rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
507
  		__be32 *data, void *obj)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
  {
  	struct rpc_cred *cred = task->tk_msg.rpc_cred;
46121cf7d   Chuck Lever   SUNRPC: fix print...
510
511
  	dprintk("RPC: %5u using %s cred %p to unwrap rpc data
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
516
  			task->tk_pid, cred->cr_ops->cr_name, cred);
  	if (cred->cr_ops->crunwrap_resp)
  		return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
  						   data, obj);
  	/* By default, we decode the arguments normally. */
88a9fe8ca   Trond Myklebust   SUNRPC: Remove th...
517
  	return decode(rqstp, data, obj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
521
522
  }
  
  int
  rpcauth_refreshcred(struct rpc_task *task)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
  	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
  	int err;
46121cf7d   Chuck Lever   SUNRPC: fix print...
525
526
  	dprintk("RPC: %5u refreshing %s cred %p
  ",
1be27f366   Trond Myklebust   SUNRPC: Remove th...
527
  		task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
0bbacc402   Chuck Lever   NFS,SUNRPC,NLM: f...
528

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
533
534
535
536
537
  	err = cred->cr_ops->crrefresh(task);
  	if (err < 0)
  		task->tk_status = err;
  	return err;
  }
  
  void
  rpcauth_invalcred(struct rpc_task *task)
  {
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
538
  	struct rpc_cred *cred = task->tk_msg.rpc_cred;
46121cf7d   Chuck Lever   SUNRPC: fix print...
539
540
  	dprintk("RPC: %5u invalidating %s cred %p
  ",
1be27f366   Trond Myklebust   SUNRPC: Remove th...
541
  		task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
542
543
  	if (cred)
  		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
  }
  
  int
  rpcauth_uptodatecred(struct rpc_task *task)
  {
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
549
550
551
552
  	struct rpc_cred *cred = task->tk_msg.rpc_cred;
  
  	return cred == NULL ||
  		test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  }
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
554

8e1f936b7   Rusty Russell   mm: clean up and ...
555
556
557
558
  static struct shrinker rpc_cred_shrinker = {
  	.shrink = rpcauth_cache_shrinker,
  	.seeks = DEFAULT_SEEKS,
  };
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
559
560
561
562
  
  void __init rpcauth_init_module(void)
  {
  	rpc_init_authunix();
9a559efd4   Trond Myklebust   SUNRPC: Add a gen...
563
  	rpc_init_generic_auth();
8e1f936b7   Rusty Russell   mm: clean up and ...
564
  	register_shrinker(&rpc_cred_shrinker);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
565
566
567
568
  }
  
  void __exit rpcauth_remove_module(void)
  {
8e1f936b7   Rusty Russell   mm: clean up and ...
569
  	unregister_shrinker(&rpc_cred_shrinker);
f5c2187cf   Trond Myklebust   SUNRPC: Convert t...
570
  }