Blame view

net/sunrpc/auth_gss/auth_gss.c 53.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
f30c22695   Uwe Zeisberger   fix file specific...
2
   * linux/net/sunrpc/auth_gss/auth_gss.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
   *
   * RPCSEC_GSS client authentication.
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
5
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
   *  Copyright (c) 2000 The Regents of the University of Michigan.
   *  All rights reserved.
   *
   *  Dug Song       <dugsong@monkey.org>
   *  Andy Adamson   <andros@umich.edu>
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *  1. Redistributions of source code must retain the above copyright
   *     notice, this list of conditions and the following disclaimer.
   *  2. Redistributions in binary form must reproduce the above copyright
   *     notice, this list of conditions and the following disclaimer in the
   *     documentation and/or other materials provided with the distribution.
   *  3. Neither the name of the University nor the names of its
   *     contributors may be used to endorse or promote products derived
   *     from this software without specific prior written permission.
   *
   *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
   *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
   */
  
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/types.h>
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  #include <linux/sched.h>
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
44
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
52
  #include <linux/sunrpc/clnt.h>
  #include <linux/sunrpc/auth.h>
  #include <linux/sunrpc/auth_gss.h>
  #include <linux/sunrpc/svcauth_gss.h>
  #include <linux/sunrpc/gss_err.h>
  #include <linux/workqueue.h>
  #include <linux/sunrpc/rpc_pipe_fs.h>
  #include <linux/sunrpc/gss_api.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
53
  #include <linux/uaccess.h>
eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
54
  #include <linux/hashtable.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55

abfdbd53a   Trond Myklebust   SUNRPC: Faster de...
56
  #include "../netns.h"
f1c0a8615   Trond Myklebust   SUNRPC: Mark auth...
57
  static const struct rpc_authops authgss_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

f1c0a8615   Trond Myklebust   SUNRPC: Mark auth...
59
  static const struct rpc_credops gss_credops;
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
60
  static const struct rpc_credops gss_nullops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61

126e216a8   Trond Myklebust   SUNRPC: Don't spa...
62
63
  #define GSS_RETRY_EXPIRED 5
  static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;
4de6caa27   Andy Adamson   SUNRPC new rpc_cr...
64
65
  #define GSS_KEY_EXPIRE_TIMEO 240
  static unsigned int gss_key_expire_timeo = GSS_KEY_EXPIRE_TIMEO;
f895b252d   Jeff Layton   sunrpc: eliminate...
66
  #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  # define RPCDBG_FACILITY	RPCDBG_AUTH
  #endif
725f2865d   Kevin Coffman   gss_krb5: Introdu...
69
  #define GSS_CRED_SLACK		(RPC_MAX_AUTH_SIZE * 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  /* length of a krb5 verifier (48), plus data added before arguments when
   * using integrity (two 4-byte integers): */
adeb8133d   Olga Kornievskaia   rpc: spkm3 update
72
  #define GSS_VERF_SLACK		100
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73

23c323af0   Trond Myklebust   SUNRPC: No, I did...
74
  static DEFINE_HASHTABLE(gss_auth_hash_table, 4);
eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
75
  static DEFINE_SPINLOCK(gss_auth_hash_lock);
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
76
77
78
79
80
  struct gss_pipe {
  	struct rpc_pipe_dir_object pdo;
  	struct rpc_pipe *pipe;
  	struct rpc_clnt *clnt;
  	const char *name;
414a62959   Trond Myklebust   RPCSEC_GSS: Share...
81
  	struct kref kref;
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
82
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
  struct gss_auth {
0285ed1f1   Trond Myklebust   SUNRPC: Ensure th...
84
  	struct kref kref;
eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
85
  	struct hlist_node hash;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
  	struct rpc_auth rpc_auth;
  	struct gss_api_mech *mech;
  	enum rpc_gss_svc service;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  	struct rpc_clnt *client;
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
90
  	struct net *net;
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
91
92
93
94
95
96
  	/*
  	 * There are two upcall pipes; dentry[1], named "gssd", is used
  	 * for the new text-based upcall; dentry[0] is named after the
  	 * mechanism (for example, "krb5") and exists for
  	 * backwards-compatibility with older gssd's.
  	 */
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
97
  	struct gss_pipe *gss_pipe[2];
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
98
  	const char *target_name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
  };
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
100
  /* pipe_version >= 0 if and only if someone has a pipe open. */
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
101
102
103
  static DEFINE_SPINLOCK(pipe_version_lock);
  static struct rpc_wait_queue pipe_version_rpc_waitqueue;
  static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
9eb2ddb48   Trond Myklebust   SUNRPC: Ensure th...
104
  static void gss_put_auth(struct gss_auth *gss_auth);
cf81939d6   \"J. Bruce Fields\   rpc: track number...
105

5d28dc820   Trond Myklebust   SUNRPC: Convert g...
106
  static void gss_free_ctx(struct gss_cl_ctx *);
b693ba4a3   Trond Myklebust   SUNRPC: Constify ...
107
108
  static const struct rpc_pipe_ops gss_upcall_ops_v0;
  static const struct rpc_pipe_ops gss_upcall_ops_v1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
  static inline struct gss_cl_ctx *
  gss_get_ctx(struct gss_cl_ctx *ctx)
  {
0fa104726   Reshetova, Elena   net, sunrpc: conv...
113
  	refcount_inc(&ctx->count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
  	return ctx;
  }
  
  static inline void
  gss_put_ctx(struct gss_cl_ctx *ctx)
  {
0fa104726   Reshetova, Elena   net, sunrpc: conv...
120
  	if (refcount_dec_and_test(&ctx->count))
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
121
  		gss_free_ctx(ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  }
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
123
124
125
  /* gss_cred_set_ctx:
   * called by gss_upcall_callback and gss_create_upcall in order
   * to set the gss context. The actual exchange of an old context
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
126
   * and a new one is protected by the pipe->lock.
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
127
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
  static void
  gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
  {
  	struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
132

cd019f751   Trond Myklebust   SUNRPC: Don't cha...
133
134
  	if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
  		return;
7b6962b0a   Trond Myklebust   SUNRPC: Fix a rac...
135
  	gss_get_ctx(ctx);
cf778b00e   Eric Dumazet   net: reintroduce ...
136
  	rcu_assign_pointer(gss_cred->gc_ctx, ctx);
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
137
  	set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
4e857c58e   Peter Zijlstra   arch: Mass conver...
138
  	smp_mb__before_atomic();
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
139
  	clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  }
  
  static const void *
  simple_get_bytes(const void *p, const void *end, void *res, size_t len)
  {
  	const void *q = (const void *)((const char *)p + len);
  	if (unlikely(q > end || q < p))
  		return ERR_PTR(-EFAULT);
  	memcpy(res, p, len);
  	return q;
  }
  
  static inline const void *
  simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
  {
  	const void *q;
  	unsigned int len;
  
  	p = simple_get_bytes(p, end, &len, sizeof(len));
  	if (IS_ERR(p))
  		return p;
  	q = (const void *)((const char *)p + len);
  	if (unlikely(q > end || q < p))
  		return ERR_PTR(-EFAULT);
0f38b873a   Trond Myklebust   SUNRPC: Use GFP_N...
164
  	dest->data = kmemdup(p, len, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
  	if (unlikely(dest->data == NULL))
  		return ERR_PTR(-ENOMEM);
  	dest->len = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
172
173
174
175
  	return q;
  }
  
  static struct gss_cl_ctx *
  gss_cred_get_ctx(struct rpc_cred *cred)
  {
  	struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
  	struct gss_cl_ctx *ctx = NULL;
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
176
  	rcu_read_lock();
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
177
178
179
  	ctx = rcu_dereference(gss_cred->gc_ctx);
  	if (ctx)
  		gss_get_ctx(ctx);
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
180
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
  	return ctx;
  }
  
  static struct gss_cl_ctx *
  gss_alloc_context(void)
  {
  	struct gss_cl_ctx *ctx;
0f38b873a   Trond Myklebust   SUNRPC: Use GFP_N...
188
  	ctx = kzalloc(sizeof(*ctx), GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  	if (ctx != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
  		ctx->gc_proc = RPC_GSS_PROC_DATA;
  		ctx->gc_seq = 1;	/* NetApp 6.4R1 doesn't accept seq. no. 0 */
  		spin_lock_init(&ctx->gc_seq_lock);
0fa104726   Reshetova, Elena   net, sunrpc: conv...
193
  		refcount_set(&ctx->count,1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
201
202
203
204
  	}
  	return ctx;
  }
  
  #define GSSD_MIN_TIMEOUT (60 * 60)
  static const void *
  gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct gss_api_mech *gm)
  {
  	const void *q;
  	unsigned int seclen;
  	unsigned int timeout;
620038f6d   Andy Adamson   SUNRPC set gss gc...
205
  	unsigned long now = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
  	u32 window_size;
  	int ret;
620038f6d   Andy Adamson   SUNRPC set gss gc...
208
209
210
211
  	/* First unsigned int gives the remaining lifetime in seconds of the
  	 * credential - e.g. the remaining TGT lifetime for Kerberos or
  	 * the -t value passed to GSSD.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
  	p = simple_get_bytes(p, end, &timeout, sizeof(timeout));
  	if (IS_ERR(p))
  		goto err;
  	if (timeout == 0)
  		timeout = GSSD_MIN_TIMEOUT;
620038f6d   Andy Adamson   SUNRPC set gss gc...
217
218
219
220
  	ctx->gc_expiry = now + ((unsigned long)timeout * HZ);
  	/* Sequence number window. Determines the maximum number of
  	 * simultaneous requests
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
  	p = simple_get_bytes(p, end, &window_size, sizeof(window_size));
  	if (IS_ERR(p))
  		goto err;
  	ctx->gc_win = window_size;
  	/* gssd signals an error by passing ctx->gc_win = 0: */
  	if (ctx->gc_win == 0) {
dc5ddce95   Jeff Layton   sunrpc: parse and...
227
228
229
230
231
232
233
234
  		/*
  		 * in which case, p points to an error code. Anything other
  		 * than -EKEYEXPIRED gets converted to -EACCES.
  		 */
  		p = simple_get_bytes(p, end, &ret, sizeof(ret));
  		if (!IS_ERR(p))
  			p = (ret == -EKEYEXPIRED) ? ERR_PTR(-EKEYEXPIRED) :
  						    ERR_PTR(-EACCES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  		goto err;
  	}
  	/* copy the opaque wire context */
  	p = simple_get_netobj(p, end, &ctx->gc_wire_ctx);
  	if (IS_ERR(p))
  		goto err;
  	/* import the opaque security context */
  	p  = simple_get_bytes(p, end, &seclen, sizeof(seclen));
  	if (IS_ERR(p))
  		goto err;
  	q = (const void *)((const char *)p + seclen);
  	if (unlikely(q > end || q < p)) {
  		p = ERR_PTR(-EFAULT);
  		goto err;
  	}
400f26b54   Simo Sorce   SUNRPC: condition...
250
  	ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, NULL, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
  	if (ret < 0) {
  		p = ERR_PTR(ret);
  		goto err;
  	}
2004c726b   Jeff Layton   auth_gss: fetch t...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  
  	/* is there any trailing data? */
  	if (q == end) {
  		p = q;
  		goto done;
  	}
  
  	/* pull in acceptor name (if there is one) */
  	p = simple_get_netobj(q, end, &ctx->gc_acceptor);
  	if (IS_ERR(p))
  		goto err;
  done:
  	dprintk("RPC:       %s Success. gc_expiry %lu now %lu timeout %u acceptor %.*s
  ",
  		__func__, ctx->gc_expiry, now, timeout, ctx->gc_acceptor.len,
  		ctx->gc_acceptor.data);
  	return p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  err:
173db3093   Jeff Layton   sunrpc: silence b...
273
274
  	dprintk("RPC:       %s returns error %ld
  ", __func__, -PTR_ERR(p));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
  	return p;
  }
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
277
  #define UPCALL_BUF_LEN 128
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
  
  struct gss_upcall_msg {
7ff139696   Reshetova, Elena   net, sunrpc: conv...
280
  	refcount_t count;
7eaf040b7   Eric W. Biederman   sunrpc: Use kuid_...
281
  	kuid_t	uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
  	struct rpc_pipe_msg msg;
  	struct list_head list;
  	struct gss_auth *auth;
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
285
  	struct rpc_pipe *pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
  	struct rpc_wait_queue rpc_waitqueue;
  	wait_queue_head_t waitqueue;
  	struct gss_cl_ctx *ctx;
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
289
  	char databuf[UPCALL_BUF_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  };
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
291
  static int get_pipe_version(struct net *net)
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
292
  {
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
293
  	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
294
295
296
  	int ret;
  
  	spin_lock(&pipe_version_lock);
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
297
298
299
  	if (sn->pipe_version >= 0) {
  		atomic_inc(&sn->pipe_users);
  		ret = sn->pipe_version;
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
300
301
302
303
304
  	} else
  		ret = -EAGAIN;
  	spin_unlock(&pipe_version_lock);
  	return ret;
  }
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
305
  static void put_pipe_version(struct net *net)
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
306
  {
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
307
308
309
310
  	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
  
  	if (atomic_dec_and_lock(&sn->pipe_users, &pipe_version_lock)) {
  		sn->pipe_version = -1;
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
311
312
313
  		spin_unlock(&pipe_version_lock);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
  static void
  gss_release_msg(struct gss_upcall_msg *gss_msg)
  {
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
317
  	struct net *net = gss_msg->auth->net;
7ff139696   Reshetova, Elena   net, sunrpc: conv...
318
  	if (!refcount_dec_and_test(&gss_msg->count))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  		return;
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
320
  	put_pipe_version(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
  	BUG_ON(!list_empty(&gss_msg->list));
  	if (gss_msg->ctx != NULL)
  		gss_put_ctx(gss_msg->ctx);
f6a1cc893   Trond Myklebust   SUNRPC: Add a (em...
324
  	rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
9eb2ddb48   Trond Myklebust   SUNRPC: Ensure th...
325
  	gss_put_auth(gss_msg->auth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
  	kfree(gss_msg);
  }
  
  static struct gss_upcall_msg *
9130b8dbc   Olga Kornievskaia   SUNRPC: allow for...
330
  __gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid, const struct gss_auth *auth)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
  {
  	struct gss_upcall_msg *pos;
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
333
  	list_for_each_entry(pos, &pipe->in_downcall, list) {
0b4d51b02   Eric W. Biederman   sunrpc: Use uid_e...
334
  		if (!uid_eq(pos->uid, uid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  			continue;
9130b8dbc   Olga Kornievskaia   SUNRPC: allow for...
336
337
  		if (auth && pos->auth->service != auth->service)
  			continue;
7ff139696   Reshetova, Elena   net, sunrpc: conv...
338
  		refcount_inc(&pos->count);
632f0d050   Chuck Lever   SUNRPC: Use __fun...
339
340
  		dprintk("RPC:       %s found msg %p
  ", __func__, pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
  		return pos;
  	}
632f0d050   Chuck Lever   SUNRPC: Use __fun...
343
344
  	dprintk("RPC:       %s found nothing
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
  	return NULL;
  }
720b8f2d6   \\\"J. Bruce Fields\\\   rpc: eliminate un...
347
  /* Try to add an upcall to the pipefs queue.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
   * If an upcall owned by our uid already exists, then we return a reference
   * to that upcall instead of adding the new upcall.
   */
  static inline struct gss_upcall_msg *
053e324f6   Suresh Jayaraman   rpc: remove unnee...
352
  gss_add_msg(struct gss_upcall_msg *gss_msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  {
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
354
  	struct rpc_pipe *pipe = gss_msg->pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
  	struct gss_upcall_msg *old;
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
356
  	spin_lock(&pipe->lock);
9130b8dbc   Olga Kornievskaia   SUNRPC: allow for...
357
  	old = __gss_find_upcall(pipe, gss_msg->uid, gss_msg->auth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  	if (old == NULL) {
7ff139696   Reshetova, Elena   net, sunrpc: conv...
359
  		refcount_inc(&gss_msg->count);
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
360
  		list_add(&gss_msg->list, &pipe->in_downcall);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
  	} else
  		gss_msg = old;
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
363
  	spin_unlock(&pipe->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
367
368
369
  	return gss_msg;
  }
  
  static void
  __gss_unhash_msg(struct gss_upcall_msg *gss_msg)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
  	list_del_init(&gss_msg->list);
  	rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
  	wake_up_all(&gss_msg->waitqueue);
7ff139696   Reshetova, Elena   net, sunrpc: conv...
373
  	refcount_dec(&gss_msg->count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
  }
  
  static void
  gss_unhash_msg(struct gss_upcall_msg *gss_msg)
  {
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
379
  	struct rpc_pipe *pipe = gss_msg->pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380

3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
381
382
  	if (list_empty(&gss_msg->list))
  		return;
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
383
  	spin_lock(&pipe->lock);
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
384
385
  	if (!list_empty(&gss_msg->list))
  		__gss_unhash_msg(gss_msg);
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
386
  	spin_unlock(&pipe->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
  }
  
  static void
126e216a8   Trond Myklebust   SUNRPC: Don't spa...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss_msg)
  {
  	switch (gss_msg->msg.errno) {
  	case 0:
  		if (gss_msg->ctx == NULL)
  			break;
  		clear_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags);
  		gss_cred_set_ctx(&gss_cred->gc_base, gss_msg->ctx);
  		break;
  	case -EKEYEXPIRED:
  		set_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags);
  	}
  	gss_cred->gc_upcall_timestamp = jiffies;
  	gss_cred->gc_upcall = NULL;
  	rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
  }
  
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
  gss_upcall_callback(struct rpc_task *task)
  {
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
410
  	struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
  			struct gss_cred, gc_base);
  	struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
413
  	struct rpc_pipe *pipe = gss_msg->pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414

9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
415
  	spin_lock(&pipe->lock);
126e216a8   Trond Myklebust   SUNRPC: Don't spa...
416
  	gss_handle_downcall_result(gss_cred, gss_msg);
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
417
  	spin_unlock(&pipe->lock);
126e216a8   Trond Myklebust   SUNRPC: Don't spa...
418
  	task->tk_status = gss_msg->msg.errno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
  	gss_release_msg(gss_msg);
  }
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
421
422
  static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
  {
90602c7b1   Eric W. Biederman   sunrpc: Update gs...
423
424
425
426
  	uid_t uid = from_kuid(&init_user_ns, gss_msg->uid);
  	memcpy(gss_msg->databuf, &uid, sizeof(uid));
  	gss_msg->msg.data = gss_msg->databuf;
  	gss_msg->msg.len = sizeof(uid);
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
427
428
  
  	BUILD_BUG_ON(sizeof(uid) > sizeof(gss_msg->databuf));
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
429
  }
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
430
  static int gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
431
432
  				const char *service_name,
  				const char *target_name)
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
433
  {
683ac6656   Trond Myklebust   gss_krb5: Add upc...
434
  	struct gss_api_mech *mech = gss_msg->auth->mech;
8b1c7bf5b   Olga Kornievskaia   rpc: add target f...
435
  	char *p = gss_msg->databuf;
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
436
437
438
439
440
441
442
443
  	size_t buflen = sizeof(gss_msg->databuf);
  	int len;
  
  	len = scnprintf(p, buflen, "mech=%s uid=%d ", mech->gm_name,
  			from_kuid(&init_user_ns, gss_msg->uid));
  	buflen -= len;
  	p += len;
  	gss_msg->msg.len = len;
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
444
  	if (target_name) {
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
445
446
  		len = scnprintf(p, buflen, "target=%s ", target_name);
  		buflen -= len;
8b1c7bf5b   Olga Kornievskaia   rpc: add target f...
447
448
449
  		p += len;
  		gss_msg->msg.len += len;
  	}
68c97153f   Trond Myklebust   SUNRPC: Clean up ...
450
  	if (service_name != NULL) {
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
451
452
  		len = scnprintf(p, buflen, "service=%s ", service_name);
  		buflen -= len;
2efef7080   Olga Kornievskaia   rpc: add service ...
453
454
455
  		p += len;
  		gss_msg->msg.len += len;
  	}
683ac6656   Trond Myklebust   gss_krb5: Add upc...
456
  	if (mech->gm_upcall_enctypes) {
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
457
458
459
  		len = scnprintf(p, buflen, "enctypes=%s ",
  				mech->gm_upcall_enctypes);
  		buflen -= len;
683ac6656   Trond Myklebust   gss_krb5: Add upc...
460
461
462
  		p += len;
  		gss_msg->msg.len += len;
  	}
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
463
464
465
466
  	len = scnprintf(p, buflen, "
  ");
  	if (len == 0)
  		goto out_overflow;
8b1c7bf5b   Olga Kornievskaia   rpc: add target f...
467
  	gss_msg->msg.len += len;
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
468
  	gss_msg->msg.data = gss_msg->databuf;
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
469
470
471
472
  	return 0;
  out_overflow:
  	WARN_ON_ONCE(1);
  	return -ENOMEM;
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
473
  }
68c97153f   Trond Myklebust   SUNRPC: Clean up ...
474
  static struct gss_upcall_msg *
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
475
  gss_alloc_msg(struct gss_auth *gss_auth,
7eaf040b7   Eric W. Biederman   sunrpc: Use kuid_...
476
  		kuid_t uid, const char *service_name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
  {
  	struct gss_upcall_msg *gss_msg;
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
479
  	int vers;
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
480
  	int err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481

0f38b873a   Trond Myklebust   SUNRPC: Use GFP_N...
482
  	gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
db75b3d6b   \"J. Bruce Fields\   rpc: minor gss_al...
483
  	if (gss_msg == NULL)
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
484
  		goto err;
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
485
  	vers = get_pipe_version(gss_auth->net);
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
486
487
488
  	err = vers;
  	if (err < 0)
  		goto err_free_msg;
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
489
  	gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe;
db75b3d6b   \"J. Bruce Fields\   rpc: minor gss_al...
490
491
492
  	INIT_LIST_HEAD(&gss_msg->list);
  	rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
  	init_waitqueue_head(&gss_msg->waitqueue);
7ff139696   Reshetova, Elena   net, sunrpc: conv...
493
  	refcount_set(&gss_msg->count, 1);
db75b3d6b   \"J. Bruce Fields\   rpc: minor gss_al...
494
495
  	gss_msg->uid = uid;
  	gss_msg->auth = gss_auth;
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
496
497
498
  	switch (vers) {
  	case 0:
  		gss_encode_v0_msg(gss_msg);
5fccc5b52   Trond Myklebust   SUNRPC: gss_alloc...
499
  		break;
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
500
  	default:
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
501
502
  		err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
  		if (err)
e9776d0f4   Trond Myklebust   SUNRPC: Fix a pip...
503
  			goto err_put_pipe_version;
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
504
  	};
9eb2ddb48   Trond Myklebust   SUNRPC: Ensure th...
505
  	kref_get(&gss_auth->kref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  	return gss_msg;
e9776d0f4   Trond Myklebust   SUNRPC: Fix a pip...
507
508
  err_put_pipe_version:
  	put_pipe_version(gss_auth->net);
9d3a2260f   Trond Myklebust   SUNRPC: Fix buffe...
509
510
511
512
  err_free_msg:
  	kfree(gss_msg);
  err:
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
  }
  
  static struct gss_upcall_msg *
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
516
  gss_setup_upcall(struct gss_auth *gss_auth, struct rpc_cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  {
7c67db3a8   Trond Myklebust   NFSv4: Reintroduc...
518
519
  	struct gss_cred *gss_cred = container_of(cred,
  			struct gss_cred, gc_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  	struct gss_upcall_msg *gss_new, *gss_msg;
7eaf040b7   Eric W. Biederman   sunrpc: Use kuid_...
521
  	kuid_t uid = cred->cr_uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522

e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
523
  	gss_new = gss_alloc_msg(gss_auth, uid, gss_cred->gc_principal);
db75b3d6b   \"J. Bruce Fields\   rpc: minor gss_al...
524
525
  	if (IS_ERR(gss_new))
  		return gss_new;
053e324f6   Suresh Jayaraman   rpc: remove unnee...
526
  	gss_msg = gss_add_msg(gss_new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  	if (gss_msg == gss_new) {
1cded9d29   NeilBrown   SUNRPC: fix refco...
528
  		int res;
7ff139696   Reshetova, Elena   net, sunrpc: conv...
529
  		refcount_inc(&gss_msg->count);
1cded9d29   NeilBrown   SUNRPC: fix refco...
530
  		res = rpc_queue_upcall(gss_new->pipe, &gss_new->msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
  		if (res) {
  			gss_unhash_msg(gss_new);
7ff139696   Reshetova, Elena   net, sunrpc: conv...
533
  			refcount_dec(&gss_msg->count);
1cded9d29   NeilBrown   SUNRPC: fix refco...
534
  			gss_release_msg(gss_new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
540
  			gss_msg = ERR_PTR(res);
  		}
  	} else
  		gss_release_msg(gss_new);
  	return gss_msg;
  }
b03568c32   \"J. Bruce Fields\   rpc: factor out w...
541
542
  static void warn_gssd(void)
  {
0ea9de0ea   Jeff Layton   sunrpc: turn warn...
543
544
  	dprintk("AUTH_GSS upcall failed. Please check user daemon is running.
  ");
b03568c32   \"J. Bruce Fields\   rpc: factor out w...
545
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
  static inline int
  gss_refresh_upcall(struct rpc_task *task)
  {
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
549
  	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
4a8c1344d   Trond Myklebust   SUNRPC: Add a bac...
550
  	struct gss_auth *gss_auth = container_of(cred->cr_auth,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
  			struct gss_auth, rpc_auth);
  	struct gss_cred *gss_cred = container_of(cred,
  			struct gss_cred, gc_base);
  	struct gss_upcall_msg *gss_msg;
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
555
  	struct rpc_pipe *pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  	int err = 0;
632f0d050   Chuck Lever   SUNRPC: Use __fun...
557
558
  	dprintk("RPC: %5u %s for uid %u
  ",
cdba321e2   Eric W. Biederman   sunrpc: Convert k...
559
  		task->tk_pid, __func__, from_kuid(&init_user_ns, cred->cr_uid));
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
560
  	gss_msg = gss_setup_upcall(gss_auth, cred);
480e3243d   Roel Kluin   SUNRPC: IS_ERR/PT...
561
  	if (PTR_ERR(gss_msg) == -EAGAIN) {
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
562
563
564
565
566
  		/* XXX: warning on the first, under the assumption we
  		 * shouldn't normally hit this case on a refresh. */
  		warn_gssd();
  		task->tk_timeout = 15*HZ;
  		rpc_sleep_on(&pipe_version_rpc_waitqueue, task, NULL);
d1a8016a2   Bryan Schumaker   NFS: Fix infinite...
567
  		return -EAGAIN;
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
568
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
571
572
  	if (IS_ERR(gss_msg)) {
  		err = PTR_ERR(gss_msg);
  		goto out;
  	}
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
573
574
  	pipe = gss_msg->pipe;
  	spin_lock(&pipe->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
  	if (gss_cred->gc_upcall != NULL)
5d00837b9   Trond Myklebust   SUNRPC: Run rpc t...
576
  		rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
126e216a8   Trond Myklebust   SUNRPC: Don't spa...
577
  	else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
  		task->tk_timeout = 0;
  		gss_cred->gc_upcall = gss_msg;
  		/* gss_upcall_callback will release the reference to gss_upcall_msg */
7ff139696   Reshetova, Elena   net, sunrpc: conv...
581
  		refcount_inc(&gss_msg->count);
5d00837b9   Trond Myklebust   SUNRPC: Run rpc t...
582
  		rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
126e216a8   Trond Myklebust   SUNRPC: Don't spa...
583
584
  	} else {
  		gss_handle_downcall_result(gss_cred, gss_msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
  		err = gss_msg->msg.errno;
126e216a8   Trond Myklebust   SUNRPC: Don't spa...
586
  	}
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
587
  	spin_unlock(&pipe->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
  	gss_release_msg(gss_msg);
  out:
632f0d050   Chuck Lever   SUNRPC: Use __fun...
590
591
  	dprintk("RPC: %5u %s for uid %u result %d
  ",
cdba321e2   Eric W. Biederman   sunrpc: Convert k...
592
593
  		task->tk_pid, __func__,
  		from_kuid(&init_user_ns, cred->cr_uid),	err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
597
598
599
  	return err;
  }
  
  static inline int
  gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
  {
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
600
  	struct net *net = gss_auth->net;
abfdbd53a   Trond Myklebust   SUNRPC: Faster de...
601
  	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
602
  	struct rpc_pipe *pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
  	struct rpc_cred *cred = &gss_cred->gc_base;
  	struct gss_upcall_msg *gss_msg;
  	DEFINE_WAIT(wait);
d36ccb9ce   Trond Myklebust   SUNRPC: Fix a bug...
606
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607

cdba321e2   Eric W. Biederman   sunrpc: Convert k...
608
609
610
  	dprintk("RPC:       %s for uid %u
  ",
  		__func__, from_kuid(&init_user_ns, cred->cr_uid));
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
611
  retry:
d36ccb9ce   Trond Myklebust   SUNRPC: Fix a bug...
612
  	err = 0;
89f842435   Jeff Layton   sunrpc: replace s...
613
614
615
616
617
  	/* if gssd is down, just skip upcalling altogether */
  	if (!gssd_running(net)) {
  		warn_gssd();
  		return -EACCES;
  	}
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
618
  	gss_msg = gss_setup_upcall(gss_auth, cred);
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
619
620
  	if (PTR_ERR(gss_msg) == -EAGAIN) {
  		err = wait_event_interruptible_timeout(pipe_version_waitqueue,
89f842435   Jeff Layton   sunrpc: replace s...
621
  				sn->pipe_version >= 0, 15 * HZ);
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
622
  		if (sn->pipe_version < 0) {
d1a8016a2   Bryan Schumaker   NFS: Fix infinite...
623
624
625
  			warn_gssd();
  			err = -EACCES;
  		}
d36ccb9ce   Trond Myklebust   SUNRPC: Fix a bug...
626
  		if (err < 0)
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
627
  			goto out;
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
628
629
  		goto retry;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
  	if (IS_ERR(gss_msg)) {
  		err = PTR_ERR(gss_msg);
  		goto out;
  	}
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
634
  	pipe = gss_msg->pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  	for (;;) {
5afa9133c   Trond Myklebust   SUNRPC: Ensure th...
636
  		prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE);
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
637
  		spin_lock(&pipe->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
  		if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
640
  			break;
  		}
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
641
  		spin_unlock(&pipe->lock);
5afa9133c   Trond Myklebust   SUNRPC: Ensure th...
642
  		if (fatal_signal_pending(current)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
647
648
  			err = -ERESTARTSYS;
  			goto out_intr;
  		}
  		schedule();
  	}
  	if (gss_msg->ctx)
7b6962b0a   Trond Myklebust   SUNRPC: Fix a rac...
649
  		gss_cred_set_ctx(cred, gss_msg->ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
  	else
  		err = gss_msg->msg.errno;
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
652
  	spin_unlock(&pipe->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
654
655
656
  out_intr:
  	finish_wait(&gss_msg->waitqueue, &wait);
  	gss_release_msg(gss_msg);
  out:
632f0d050   Chuck Lever   SUNRPC: Use __fun...
657
658
  	dprintk("RPC:       %s for uid %u result %d
  ",
cdba321e2   Eric W. Biederman   sunrpc: Convert k...
659
  		__func__, from_kuid(&init_user_ns, cred->cr_uid), err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
666
667
668
  #define MSG_BUF_MAXSIZE 1024
  
  static ssize_t
  gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
  {
  	const void *p, *end;
  	void *buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  	struct gss_upcall_msg *gss_msg;
496ad9aa8   Al Viro   new helper: file_...
670
  	struct rpc_pipe *pipe = RPC_I(file_inode(filp))->pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  	struct gss_cl_ctx *ctx;
90602c7b1   Eric W. Biederman   sunrpc: Update gs...
672
673
  	uid_t id;
  	kuid_t uid;
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
674
  	ssize_t err = -EFBIG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
678
  
  	if (mlen > MSG_BUF_MAXSIZE)
  		goto out;
  	err = -ENOMEM;
0f38b873a   Trond Myklebust   SUNRPC: Use GFP_N...
679
  	buf = kmalloc(mlen, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
  	if (!buf)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
683
684
685
686
  	err = -EFAULT;
  	if (copy_from_user(buf, src, mlen))
  		goto err;
  
  	end = (const void *)((char *)buf + mlen);
90602c7b1   Eric W. Biederman   sunrpc: Update gs...
687
  	p = simple_get_bytes(buf, end, &id, sizeof(id));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
689
690
691
  	if (IS_ERR(p)) {
  		err = PTR_ERR(p);
  		goto err;
  	}
90602c7b1   Eric W. Biederman   sunrpc: Update gs...
692
693
694
695
696
  	uid = make_kuid(&init_user_ns, id);
  	if (!uid_valid(uid)) {
  		err = -EINVAL;
  		goto err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
700
  	err = -ENOMEM;
  	ctx = gss_alloc_context();
  	if (ctx == NULL)
  		goto err;
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
701
702
703
  
  	err = -ENOENT;
  	/* Find a matching upcall */
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
704
  	spin_lock(&pipe->lock);
9130b8dbc   Olga Kornievskaia   SUNRPC: allow for...
705
  	gss_msg = __gss_find_upcall(pipe, uid, NULL);
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
706
  	if (gss_msg == NULL) {
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
707
  		spin_unlock(&pipe->lock);
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
708
709
710
  		goto err_put_ctx;
  	}
  	list_del_init(&gss_msg->list);
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
711
  	spin_unlock(&pipe->lock);
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
712

6e84c7b66   Trond Myklebust   SUNRPC: Add a dow...
713
  	p = gss_fill_context(p, end, ctx, gss_msg->auth->mech);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
  	if (IS_ERR(p)) {
  		err = PTR_ERR(p);
486bad2e4   Jeff Layton   sunrpc: on succes...
716
717
  		switch (err) {
  		case -EACCES:
dc5ddce95   Jeff Layton   sunrpc: parse and...
718
  		case -EKEYEXPIRED:
486bad2e4   Jeff Layton   sunrpc: on succes...
719
720
721
722
723
724
725
726
727
728
729
  			gss_msg->msg.errno = err;
  			err = mlen;
  			break;
  		case -EFAULT:
  		case -ENOMEM:
  		case -EINVAL:
  		case -ENOSYS:
  			gss_msg->msg.errno = -EAGAIN;
  			break;
  		default:
  			printk(KERN_CRIT "%s: bad return from "
6c8530993   Randy Dunlap   sunrpc: fix build...
730
731
  				"gss_fill_context: %zd
  ", __func__, err);
437b300c6   Scott Mayhew   auth_gss: fix pan...
732
  			gss_msg->msg.errno = -EIO;
486bad2e4   Jeff Layton   sunrpc: on succes...
733
  		}
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
734
  		goto err_release_msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
  	}
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
736
737
738
739
  	gss_msg->ctx = gss_get_ctx(ctx);
  	err = mlen;
  
  err_release_msg:
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
740
  	spin_lock(&pipe->lock);
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
741
  	__gss_unhash_msg(gss_msg);
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
742
  	spin_unlock(&pipe->lock);
3b68aaeaf   Trond Myklebust   SUNRPC: Always ma...
743
  	gss_release_msg(gss_msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
747
748
  err_put_ctx:
  	gss_put_ctx(ctx);
  err:
  	kfree(buf);
  out:
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
749
750
  	dprintk("RPC:       %s returning %zd
  ", __func__, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
  	return err;
  }
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
753
  static int gss_pipe_open(struct inode *inode, int new_version)
cf81939d6   \"J. Bruce Fields\   rpc: track number...
754
  {
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
755
756
  	struct net *net = inode->i_sb->s_fs_info;
  	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
757
  	int ret = 0;
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
758
  	spin_lock(&pipe_version_lock);
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
759
  	if (sn->pipe_version < 0) {
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
760
  		/* First open of any gss pipe determines the version: */
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
761
  		sn->pipe_version = new_version;
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
762
763
  		rpc_wake_up(&pipe_version_rpc_waitqueue);
  		wake_up(&pipe_version_waitqueue);
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
764
  	} else if (sn->pipe_version != new_version) {
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
765
766
767
  		/* Trying to open a pipe of a different version */
  		ret = -EBUSY;
  		goto out;
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
768
  	}
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
769
  	atomic_inc(&sn->pipe_users);
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
770
  out:
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
771
  	spin_unlock(&pipe_version_lock);
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
772
773
774
775
776
777
778
779
780
781
782
783
  	return ret;
  
  }
  
  static int gss_pipe_open_v0(struct inode *inode)
  {
  	return gss_pipe_open(inode, 0);
  }
  
  static int gss_pipe_open_v1(struct inode *inode)
  {
  	return gss_pipe_open(inode, 1);
cf81939d6   \"J. Bruce Fields\   rpc: track number...
784
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
  static void
  gss_pipe_release(struct inode *inode)
  {
2aed8b476   Trond Myklebust   SUNRPC: Convert a...
788
  	struct net *net = inode->i_sb->s_fs_info;
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
789
  	struct rpc_pipe *pipe = RPC_I(inode)->pipe;
6e84c7b66   Trond Myklebust   SUNRPC: Add a dow...
790
  	struct gss_upcall_msg *gss_msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791

5a67657a2   Trond Myklebust   SUNRPC: Fix race ...
792
  restart:
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
793
794
  	spin_lock(&pipe->lock);
  	list_for_each_entry(gss_msg, &pipe->in_downcall, list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795

5a67657a2   Trond Myklebust   SUNRPC: Fix race ...
796
797
  		if (!list_empty(&gss_msg->msg.list))
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  		gss_msg->msg.errno = -EPIPE;
7ff139696   Reshetova, Elena   net, sunrpc: conv...
799
  		refcount_inc(&gss_msg->count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  		__gss_unhash_msg(gss_msg);
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
801
  		spin_unlock(&pipe->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  		gss_release_msg(gss_msg);
5a67657a2   Trond Myklebust   SUNRPC: Fix race ...
803
  		goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  	}
9beae4677   Stanislav Kinsbursky   SUNRPC: cleanup G...
805
  	spin_unlock(&pipe->lock);
cf81939d6   \"J. Bruce Fields\   rpc: track number...
806

2aed8b476   Trond Myklebust   SUNRPC: Convert a...
807
  	put_pipe_version(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
813
  }
  
  static void
  gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
  {
  	struct gss_upcall_msg *gss_msg = container_of(msg, struct gss_upcall_msg, msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
  
  	if (msg->errno < 0) {
632f0d050   Chuck Lever   SUNRPC: Use __fun...
816
817
818
  		dprintk("RPC:       %s releasing msg %p
  ",
  			__func__, gss_msg);
7ff139696   Reshetova, Elena   net, sunrpc: conv...
819
  		refcount_inc(&gss_msg->count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
  		gss_unhash_msg(gss_msg);
b03568c32   \"J. Bruce Fields\   rpc: factor out w...
821
822
  		if (msg->errno == -ETIMEDOUT)
  			warn_gssd();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
  		gss_release_msg(gss_msg);
  	}
1cded9d29   NeilBrown   SUNRPC: fix refco...
825
  	gss_release_msg(gss_msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  }
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
827
828
  static void gss_pipe_dentry_destroy(struct dentry *dir,
  		struct rpc_pipe_dir_object *pdo)
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
829
  {
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
830
831
  	struct gss_pipe *gss_pipe = pdo->pdo_data;
  	struct rpc_pipe *pipe = gss_pipe->pipe;
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
832

191722843   Trond Myklebust   RPCSEC_GSS: Switc...
833
834
835
  	if (pipe->dentry != NULL) {
  		rpc_unlink(pipe->dentry);
  		pipe->dentry = NULL;
6b2fddd3e   Trond Myklebust   RPCSEC_GSS: Fix a...
836
  	}
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
837
  }
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
838
839
  static int gss_pipe_dentry_create(struct dentry *dir,
  		struct rpc_pipe_dir_object *pdo)
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
840
  {
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
841
  	struct gss_pipe *p = pdo->pdo_data;
6b2fddd3e   Trond Myklebust   RPCSEC_GSS: Fix a...
842
  	struct dentry *dentry;
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
843

191722843   Trond Myklebust   RPCSEC_GSS: Switc...
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
  	dentry = rpc_mkpipe_dentry(dir, p->name, p->clnt, p->pipe);
  	if (IS_ERR(dentry))
  		return PTR_ERR(dentry);
  	p->pipe->dentry = dentry;
  	return 0;
  }
  
  static const struct rpc_pipe_dir_object_ops gss_pipe_dir_object_ops = {
  	.create = gss_pipe_dentry_create,
  	.destroy = gss_pipe_dentry_destroy,
  };
  
  static struct gss_pipe *gss_pipe_alloc(struct rpc_clnt *clnt,
  		const char *name,
  		const struct rpc_pipe_ops *upcall_ops)
  {
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
860
861
  	struct gss_pipe *p;
  	int err = -ENOMEM;
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
862

191722843   Trond Myklebust   RPCSEC_GSS: Switc...
863
864
  	p = kmalloc(sizeof(*p), GFP_KERNEL);
  	if (p == NULL)
6b2fddd3e   Trond Myklebust   RPCSEC_GSS: Fix a...
865
  		goto err;
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
866
867
868
869
  	p->pipe = rpc_mkpipe_data(upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
  	if (IS_ERR(p->pipe)) {
  		err = PTR_ERR(p->pipe);
  		goto err_free_gss_pipe;
6b2fddd3e   Trond Myklebust   RPCSEC_GSS: Fix a...
870
  	}
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
871
872
  	p->name = name;
  	p->clnt = clnt;
414a62959   Trond Myklebust   RPCSEC_GSS: Share...
873
  	kref_init(&p->kref);
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
874
875
876
  	rpc_init_pipe_dir_object(&p->pdo,
  			&gss_pipe_dir_object_ops,
  			p);
414a62959   Trond Myklebust   RPCSEC_GSS: Share...
877
  	return p;
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
878
879
  err_free_gss_pipe:
  	kfree(p);
6b2fddd3e   Trond Myklebust   RPCSEC_GSS: Fix a...
880
  err:
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
881
  	return ERR_PTR(err);
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
882
  }
414a62959   Trond Myklebust   RPCSEC_GSS: Share...
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
  struct gss_alloc_pdo {
  	struct rpc_clnt *clnt;
  	const char *name;
  	const struct rpc_pipe_ops *upcall_ops;
  };
  
  static int gss_pipe_match_pdo(struct rpc_pipe_dir_object *pdo, void *data)
  {
  	struct gss_pipe *gss_pipe;
  	struct gss_alloc_pdo *args = data;
  
  	if (pdo->pdo_ops != &gss_pipe_dir_object_ops)
  		return 0;
  	gss_pipe = container_of(pdo, struct gss_pipe, pdo);
  	if (strcmp(gss_pipe->name, args->name) != 0)
  		return 0;
  	if (!kref_get_unless_zero(&gss_pipe->kref))
  		return 0;
  	return 1;
  }
  
  static struct rpc_pipe_dir_object *gss_pipe_alloc_pdo(void *data)
  {
  	struct gss_pipe *gss_pipe;
  	struct gss_alloc_pdo *args = data;
  
  	gss_pipe = gss_pipe_alloc(args->clnt, args->name, args->upcall_ops);
  	if (!IS_ERR(gss_pipe))
  		return &gss_pipe->pdo;
  	return NULL;
  }
  
  static struct gss_pipe *gss_pipe_get(struct rpc_clnt *clnt,
  		const char *name,
  		const struct rpc_pipe_ops *upcall_ops)
  {
  	struct net *net = rpc_net_ns(clnt);
  	struct rpc_pipe_dir_object *pdo;
  	struct gss_alloc_pdo args = {
  		.clnt = clnt,
  		.name = name,
  		.upcall_ops = upcall_ops,
  	};
  
  	pdo = rpc_find_or_alloc_pipe_dir_object(net,
  			&clnt->cl_pipedir_objects,
  			gss_pipe_match_pdo,
  			gss_pipe_alloc_pdo,
  			&args);
  	if (pdo != NULL)
  		return container_of(pdo, struct gss_pipe, pdo);
  	return ERR_PTR(-ENOMEM);
  }
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
936
  static void __gss_pipe_free(struct gss_pipe *p)
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
937
  {
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
938
939
  	struct rpc_clnt *clnt = p->clnt;
  	struct net *net = rpc_net_ns(clnt);
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
940

191722843   Trond Myklebust   RPCSEC_GSS: Switc...
941
942
943
944
945
  	rpc_remove_pipe_dir_object(net,
  			&clnt->cl_pipedir_objects,
  			&p->pdo);
  	rpc_destroy_pipe_data(p->pipe);
  	kfree(p);
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
946
  }
414a62959   Trond Myklebust   RPCSEC_GSS: Share...
947
948
949
950
951
952
  static void __gss_pipe_release(struct kref *kref)
  {
  	struct gss_pipe *p = container_of(kref, struct gss_pipe, kref);
  
  	__gss_pipe_free(p);
  }
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
953
  static void gss_pipe_free(struct gss_pipe *p)
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
954
  {
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
955
  	if (p != NULL)
414a62959   Trond Myklebust   RPCSEC_GSS: Share...
956
  		kref_put(&p->kref, __gss_pipe_release);
ccdc28f81   Stanislav Kinsbursky   SUNRPC: handle GS...
957
  }
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
958
959
  /*
   * NOTE: we have the opportunity to use different
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
   * parameters based on the input flavor (which must be a pseudoflavor)
   */
eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
962
963
  static struct gss_auth *
  gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
  {
c21906610   Trond Myklebust   SUNRPC: Replace c...
965
  	rpc_authflavor_t flavor = args->pseudoflavor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
  	struct gss_auth *gss_auth;
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
967
  	struct gss_pipe *gss_pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
  	struct rpc_auth * auth;
6a19275ad   J. Bruce Fields   [PATCH] RPC: [PAT...
969
  	int err = -ENOMEM; /* XXX? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970

8885cb367   Chuck Lever   SUNRPC: fix print...
971
972
  	dprintk("RPC:       creating GSS authenticator for client %p
  ", clnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973
974
  
  	if (!try_module_get(THIS_MODULE))
6a19275ad   J. Bruce Fields   [PATCH] RPC: [PAT...
975
  		return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
  	if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL)))
  		goto out_dec;
eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
978
  	INIT_HLIST_NODE(&gss_auth->hash);
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
979
  	gss_auth->target_name = NULL;
c21906610   Trond Myklebust   SUNRPC: Replace c...
980
981
  	if (args->target_name) {
  		gss_auth->target_name = kstrdup(args->target_name, GFP_KERNEL);
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
982
983
984
  		if (gss_auth->target_name == NULL)
  			goto err_free;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
  	gss_auth->client = clnt;
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
986
  	gss_auth->net = get_net(rpc_net_ns(clnt));
6a19275ad   J. Bruce Fields   [PATCH] RPC: [PAT...
987
  	err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
  	gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
  	if (!gss_auth->mech) {
9b1d75b75   Trond Myklebust   SUNRPC: Don't spa...
990
991
  		dprintk("RPC:       Pseudoflavor %d not found!
  ", flavor);
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
992
  		goto err_put_net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
994
  	}
  	gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
438b6fdeb   J. Bruce Fields   [PATCH] RPC: Don'...
995
996
  	if (gss_auth->service == 0)
  		goto err_put_mech;
a699d65ec   Trond Myklebust   SUNRPC: Don't cre...
997
998
  	if (!gssd_running(gss_auth->net))
  		goto err_put_mech;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
  	auth = &gss_auth->rpc_auth;
  	auth->au_cslack = GSS_CRED_SLACK >> 2;
  	auth->au_rslack = GSS_VERF_SLACK >> 2;
ce52914eb   Scott Mayhew   sunrpc: move NO_C...
1002
  	auth->au_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
1004
  	auth->au_ops = &authgss_ops;
  	auth->au_flavor = flavor;
65b80179f   Chuck Lever   xprtrdma: No dire...
1005
1006
  	if (gss_pseudoflavor_to_datatouch(gss_auth->mech, flavor))
  		auth->au_flags |= RPCAUTH_AUTH_DATATOUCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  	atomic_set(&auth->au_count, 1);
0285ed1f1   Trond Myklebust   SUNRPC: Ensure th...
1008
  	kref_init(&gss_auth->kref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009

191722843   Trond Myklebust   RPCSEC_GSS: Switc...
1010
1011
1012
  	err = rpcauth_init_credcache(auth);
  	if (err)
  		goto err_put_mech;
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
1013
1014
1015
1016
1017
1018
  	/*
  	 * Note: if we created the old pipe first, then someone who
  	 * examined the directory at the right moment might conclude
  	 * that we supported only the old pipe.  So we instead create
  	 * the new pipe first.
  	 */
414a62959   Trond Myklebust   RPCSEC_GSS: Share...
1019
  	gss_pipe = gss_pipe_get(clnt, "gssd", &gss_upcall_ops_v1);
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
1020
1021
1022
  	if (IS_ERR(gss_pipe)) {
  		err = PTR_ERR(gss_pipe);
  		goto err_destroy_credcache;
6a19275ad   J. Bruce Fields   [PATCH] RPC: [PAT...
1023
  	}
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
1024
  	gss_auth->gss_pipe[1] = gss_pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025

414a62959   Trond Myklebust   RPCSEC_GSS: Share...
1026
  	gss_pipe = gss_pipe_get(clnt, gss_auth->mech->gm_name,
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
1027
1028
1029
  			&gss_upcall_ops_v0);
  	if (IS_ERR(gss_pipe)) {
  		err = PTR_ERR(gss_pipe);
c239d83b9   Stanislav Kinsbursky   SUNRPC: split SUN...
1030
1031
  		goto err_destroy_pipe_1;
  	}
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
1032
  	gss_auth->gss_pipe[0] = gss_pipe;
07a2bf1da   Trond Myklebust   SUNRPC: Fix a mem...
1033

eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
1034
  	return gss_auth;
c239d83b9   Stanislav Kinsbursky   SUNRPC: split SUN...
1035
  err_destroy_pipe_1:
414a62959   Trond Myklebust   RPCSEC_GSS: Share...
1036
  	gss_pipe_free(gss_auth->gss_pipe[1]);
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
1037
1038
  err_destroy_credcache:
  	rpcauth_destroy_credcache(auth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
  err_put_mech:
  	gss_mech_put(gss_auth->mech);
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
1041
1042
  err_put_net:
  	put_net(gss_auth->net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
  err_free:
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
1044
  	kfree(gss_auth->target_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
1047
  	kfree(gss_auth);
  out_dec:
  	module_put(THIS_MODULE);
6a19275ad   J. Bruce Fields   [PATCH] RPC: [PAT...
1048
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
1050
1051
  }
  
  static void
0285ed1f1   Trond Myklebust   SUNRPC: Ensure th...
1052
1053
  gss_free(struct gss_auth *gss_auth)
  {
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
1054
1055
  	gss_pipe_free(gss_auth->gss_pipe[0]);
  	gss_pipe_free(gss_auth->gss_pipe[1]);
0285ed1f1   Trond Myklebust   SUNRPC: Ensure th...
1056
  	gss_mech_put(gss_auth->mech);
e726340ac   Trond Myklebust   RPCSEC_GSS: Furth...
1057
  	put_net(gss_auth->net);
bd4a3eb15   Trond Myklebust   RPCSEC_GSS: Clean...
1058
  	kfree(gss_auth->target_name);
0285ed1f1   Trond Myklebust   SUNRPC: Ensure th...
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
  
  	kfree(gss_auth);
  	module_put(THIS_MODULE);
  }
  
  static void
  gss_free_callback(struct kref *kref)
  {
  	struct gss_auth *gss_auth = container_of(kref, struct gss_auth, kref);
  
  	gss_free(gss_auth);
  }
  
  static void
9eb2ddb48   Trond Myklebust   SUNRPC: Ensure th...
1073
1074
1075
1076
1077
1078
  gss_put_auth(struct gss_auth *gss_auth)
  {
  	kref_put(&gss_auth->kref, gss_free_callback);
  }
  
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
  gss_destroy(struct rpc_auth *auth)
  {
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
1081
1082
  	struct gss_auth *gss_auth = container_of(auth,
  			struct gss_auth, rpc_auth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083

8885cb367   Chuck Lever   SUNRPC: fix print...
1084
1085
1086
  	dprintk("RPC:       destroying GSS authenticator %p flavor %d
  ",
  			auth, auth->au_flavor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087

eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
1088
1089
1090
1091
1092
  	if (hash_hashed(&gss_auth->hash)) {
  		spin_lock(&gss_auth_hash_lock);
  		hash_del(&gss_auth->hash);
  		spin_unlock(&gss_auth_hash_lock);
  	}
191722843   Trond Myklebust   RPCSEC_GSS: Switc...
1093
1094
1095
1096
  	gss_pipe_free(gss_auth->gss_pipe[0]);
  	gss_auth->gss_pipe[0] = NULL;
  	gss_pipe_free(gss_auth->gss_pipe[1]);
  	gss_auth->gss_pipe[1] = NULL;
3ab9bb724   Trond Myklebust   SUNRPC: Fix a mem...
1097
  	rpcauth_destroy_credcache(auth);
9eb2ddb48   Trond Myklebust   SUNRPC: Ensure th...
1098
  	gss_put_auth(gss_auth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
  }
a0f6ed8eb   J. Bruce Fields   RPCSEC_GSS: fix c...
1100
1101
1102
1103
1104
1105
1106
1107
1108
  /*
   * Auths may be shared between rpc clients that were cloned from a
   * common client with the same xprt, if they also share the flavor and
   * target_name.
   *
   * The auth is looked up from the oldest parent sharing the same
   * cl_xprt, and the auth itself references only that common parent
   * (which is guaranteed to last as long as any of its descendants).
   */
eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
  static struct gss_auth *
  gss_auth_find_or_add_hashed(struct rpc_auth_create_args *args,
  		struct rpc_clnt *clnt,
  		struct gss_auth *new)
  {
  	struct gss_auth *gss_auth;
  	unsigned long hashval = (unsigned long)clnt;
  
  	spin_lock(&gss_auth_hash_lock);
  	hash_for_each_possible(gss_auth_hash_table,
  			gss_auth,
  			hash,
  			hashval) {
a0f6ed8eb   J. Bruce Fields   RPCSEC_GSS: fix c...
1122
1123
  		if (gss_auth->client != clnt)
  			continue;
eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
  		if (gss_auth->rpc_auth.au_flavor != args->pseudoflavor)
  			continue;
  		if (gss_auth->target_name != args->target_name) {
  			if (gss_auth->target_name == NULL)
  				continue;
  			if (args->target_name == NULL)
  				continue;
  			if (strcmp(gss_auth->target_name, args->target_name))
  				continue;
  		}
  		if (!atomic_inc_not_zero(&gss_auth->rpc_auth.au_count))
  			continue;
  		goto out;
  	}
  	if (new)
  		hash_add(gss_auth_hash_table, &new->hash, hashval);
  	gss_auth = new;
  out:
  	spin_unlock(&gss_auth_hash_lock);
  	return gss_auth;
  }
  
  static struct gss_auth *
  gss_create_hashed(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
  {
  	struct gss_auth *gss_auth;
  	struct gss_auth *new;
  
  	gss_auth = gss_auth_find_or_add_hashed(args, clnt, NULL);
  	if (gss_auth != NULL)
  		goto out;
  	new = gss_create_new(args, clnt);
  	if (IS_ERR(new))
  		return new;
  	gss_auth = gss_auth_find_or_add_hashed(args, clnt, new);
  	if (gss_auth != new)
  		gss_destroy(&new->rpc_auth);
  out:
  	return gss_auth;
  }
  
  static struct rpc_auth *
  gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
  {
  	struct gss_auth *gss_auth;
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
1169
  	struct rpc_xprt_switch *xps = rcu_access_pointer(clnt->cl_xpi.xpi_xpswitch);
eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
1170
1171
1172
1173
  
  	while (clnt != clnt->cl_parent) {
  		struct rpc_clnt *parent = clnt->cl_parent;
  		/* Find the original parent for this transport */
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
1174
  		if (rcu_access_pointer(parent->cl_xpi.xpi_xpswitch) != xps)
eb6dc19d8   Trond Myklebust   RPCSEC_GSS: Share...
1175
1176
1177
1178
1179
1180
1181
1182
1183
  			break;
  		clnt = parent;
  	}
  
  	gss_auth = gss_create_hashed(args, clnt);
  	if (IS_ERR(gss_auth))
  		return ERR_CAST(gss_auth);
  	return &gss_auth->rpc_auth;
  }
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
  /*
   * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call
   * to the server with the GSS control procedure field set to
   * RPC_GSS_PROC_DESTROY. This should normally cause the server to release
   * all RPCSEC_GSS state associated with that context.
   */
  static int
  gss_destroying_context(struct rpc_cred *cred)
  {
  	struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
  	struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1195
  	struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1);
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1196
  	struct rpc_task *task;
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1197
  	if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1198
  		return 0;
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1199
  	ctx->gc_proc = RPC_GSS_PROC_DESTROY;
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1200
1201
1202
1203
1204
  	cred->cr_ops = &gss_nullops;
  
  	/* Take a reference to ensure the cred will be destroyed either
  	 * by the RPC call or by the put_rpccred() below */
  	get_rpccred(cred);
080a1f148   Trond Myklebust   SUNRPC: Don't att...
1205
  	task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT);
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1206
1207
1208
1209
1210
1211
1212
1213
  	if (!IS_ERR(task))
  		rpc_put_task(task);
  
  	put_rpccred(cred);
  	return 1;
  }
  
  /* gss_destroy_cred (and gss_free_ctx) are used to clean up after failure
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
1215
1216
   * to create a new cred or context, so they check that things have been
   * allocated before freeing them. */
  static void
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
1217
  gss_do_free_ctx(struct gss_cl_ctx *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
  {
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1219
1220
  	dprintk("RPC:       %s
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221

0d8a37467   Trond Myklebust   SUNRPC: Defer del...
1222
  	gss_delete_sec_context(&ctx->gc_gss_ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
  	kfree(ctx->gc_wire_ctx.data);
2004c726b   Jeff Layton   auth_gss: fetch t...
1224
  	kfree(ctx->gc_acceptor.data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
1226
1227
1228
  	kfree(ctx);
  }
  
  static void
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  gss_free_ctx_callback(struct rcu_head *head)
  {
  	struct gss_cl_ctx *ctx = container_of(head, struct gss_cl_ctx, gc_rcu);
  	gss_do_free_ctx(ctx);
  }
  
  static void
  gss_free_ctx(struct gss_cl_ctx *ctx)
  {
  	call_rcu(&ctx->gc_rcu, gss_free_ctx_callback);
  }
  
  static void
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
1242
  gss_free_cred(struct gss_cred *gss_cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1243
  {
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1244
1245
  	dprintk("RPC:       %s cred=%p
  ", __func__, gss_cred);
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
1246
1247
  	kfree(gss_cred);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1248

31be5bf15   Trond Myklebust   SUNRPC: Convert t...
1249
1250
1251
1252
1253
1254
  static void
  gss_free_cred_callback(struct rcu_head *head)
  {
  	struct gss_cred *gss_cred = container_of(head, struct gss_cred, gc_base.cr_rcu);
  	gss_free_cred(gss_cred);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1255

31be5bf15   Trond Myklebust   SUNRPC: Convert t...
1256
  static void
6dcd3926b   Jeff Layton   sunrpc: fix code ...
1257
  gss_destroy_nullcred(struct rpc_cred *cred)
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
1258
  {
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
1259
  	struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
0285ed1f1   Trond Myklebust   SUNRPC: Ensure th...
1260
  	struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1261
  	struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1);
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
1262

a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
1263
  	RCU_INIT_POINTER(gss_cred->gc_ctx, NULL);
31be5bf15   Trond Myklebust   SUNRPC: Convert t...
1264
  	call_rcu(&cred->cr_rcu, gss_free_cred_callback);
5d28dc820   Trond Myklebust   SUNRPC: Convert g...
1265
1266
  	if (ctx)
  		gss_put_ctx(ctx);
9eb2ddb48   Trond Myklebust   SUNRPC: Ensure th...
1267
  	gss_put_auth(gss_auth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
  }
6dcd3926b   Jeff Layton   sunrpc: fix code ...
1269
1270
1271
1272
1273
1274
1275
1276
  static void
  gss_destroy_cred(struct rpc_cred *cred)
  {
  
  	if (gss_destroying_context(cred))
  		return;
  	gss_destroy_nullcred(cred);
  }
a960f8d6d   Frank Sorenson   sunrpc: add RPCSE...
1277
1278
1279
1280
1281
  static int
  gss_hash_cred(struct auth_cred *acred, unsigned int hashbits)
  {
  	return hash_64(from_kuid(&init_user_ns, acred->uid), hashbits);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
1283
1284
1285
  /*
   * Lookup RPCSEC_GSS cred for the current process
   */
  static struct rpc_cred *
8a3177604   Trond Myklebust   SUNRPC: Fix a loc...
1286
  gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
  {
3c6e0bc8a   Jeff Layton   sunrpc: plumb gfp...
1288
  	return rpcauth_lookup_credcache(auth, acred, flags, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289
1290
1291
  }
  
  static struct rpc_cred *
3c6e0bc8a   Jeff Layton   sunrpc: plumb gfp...
1292
  gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
1294
1295
1296
  {
  	struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
  	struct gss_cred	*cred = NULL;
  	int err = -ENOMEM;
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1297
1298
  	dprintk("RPC:       %s for uid %d, flavor %d
  ",
cdba321e2   Eric W. Biederman   sunrpc: Convert k...
1299
1300
  		__func__, from_kuid(&init_user_ns, acred->uid),
  		auth->au_flavor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301

3c6e0bc8a   Jeff Layton   sunrpc: plumb gfp...
1302
  	if (!(cred = kzalloc(sizeof(*cred), gfp)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
  		goto out_err;
5fe4755e2   Trond Myklebust   SUNRPC: Clean up ...
1304
  	rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1305
1306
1307
1308
  	/*
  	 * Note: in order to force a call to call_refresh(), we deliberately
  	 * fail to flag the credential as RPCAUTH_CRED_UPTODATE.
  	 */
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
1309
  	cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1310
  	cred->gc_service = gss_auth->service;
68c97153f   Trond Myklebust   SUNRPC: Clean up ...
1311
1312
1313
  	cred->gc_principal = NULL;
  	if (acred->machine_cred)
  		cred->gc_principal = acred->principal;
0285ed1f1   Trond Myklebust   SUNRPC: Ensure th...
1314
  	kref_get(&gss_auth->kref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315
1316
1317
  	return &cred->gc_base;
  
  out_err:
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1318
1319
  	dprintk("RPC:       %s failed with error %d
  ", __func__, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
1321
1322
1323
  	return ERR_PTR(err);
  }
  
  static int
fba3bad48   Trond Myklebust   SUNRPC: Move upca...
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
  gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
  {
  	struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
  	struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base);
  	int err;
  
  	do {
  		err = gss_create_upcall(gss_auth, gss_cred);
  	} while (err == -EAGAIN);
  	return err;
  }
a0337d1dd   Jeff Layton   sunrpc: add a new...
1335
1336
1337
  static char *
  gss_stringify_acceptor(struct rpc_cred *cred)
  {
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1338
  	char *string = NULL;
a0337d1dd   Jeff Layton   sunrpc: add a new...
1339
  	struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1340
  	struct gss_cl_ctx *ctx;
b3ecba096   Jeff Layton   sunrpc: fix sleep...
1341
  	unsigned int len;
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1342
1343
1344
1345
1346
1347
  	struct xdr_netobj *acceptor;
  
  	rcu_read_lock();
  	ctx = rcu_dereference(gss_cred->gc_ctx);
  	if (!ctx)
  		goto out;
b3ecba096   Jeff Layton   sunrpc: fix sleep...
1348
1349
  	len = ctx->gc_acceptor.len;
  	rcu_read_unlock();
a0337d1dd   Jeff Layton   sunrpc: add a new...
1350
1351
  
  	/* no point if there's no string */
b3ecba096   Jeff Layton   sunrpc: fix sleep...
1352
1353
1354
1355
  	if (!len)
  		return NULL;
  realloc:
  	string = kmalloc(len + 1, GFP_KERNEL);
a0337d1dd   Jeff Layton   sunrpc: add a new...
1356
  	if (!string)
b3ecba096   Jeff Layton   sunrpc: fix sleep...
1357
1358
1359
1360
1361
1362
1363
1364
1365
  		return NULL;
  
  	rcu_read_lock();
  	ctx = rcu_dereference(gss_cred->gc_ctx);
  
  	/* did the ctx disappear or was it replaced by one with no acceptor? */
  	if (!ctx || !ctx->gc_acceptor.len) {
  		kfree(string);
  		string = NULL;
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1366
  		goto out;
b3ecba096   Jeff Layton   sunrpc: fix sleep...
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
  	}
  
  	acceptor = &ctx->gc_acceptor;
  
  	/*
  	 * Did we find a new acceptor that's longer than the original? Allocate
  	 * a longer buffer and try again.
  	 */
  	if (len < acceptor->len) {
  		len = acceptor->len;
  		rcu_read_unlock();
  		kfree(string);
  		goto realloc;
  	}
a0337d1dd   Jeff Layton   sunrpc: add a new...
1381
1382
1383
  
  	memcpy(string, acceptor->data, acceptor->len);
  	string[acceptor->len] = '\0';
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1384
1385
  out:
  	rcu_read_unlock();
a0337d1dd   Jeff Layton   sunrpc: add a new...
1386
1387
  	return string;
  }
4de6caa27   Andy Adamson   SUNRPC new rpc_cr...
1388
1389
1390
1391
1392
1393
1394
1395
  /*
   * Returns -EACCES if GSS context is NULL or will expire within the
   * timeout (miliseconds)
   */
  static int
  gss_key_timeout(struct rpc_cred *rc)
  {
  	struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1396
  	struct gss_cl_ctx *ctx;
cc6a7aab5   Arnd Bergmann   sunrpc: avoid war...
1397
1398
  	unsigned long timeout = jiffies + (gss_key_expire_timeo * HZ);
  	int ret = 0;
4de6caa27   Andy Adamson   SUNRPC new rpc_cr...
1399

c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1400
1401
  	rcu_read_lock();
  	ctx = rcu_dereference(gss_cred->gc_ctx);
cc6a7aab5   Arnd Bergmann   sunrpc: avoid war...
1402
1403
  	if (!ctx || time_after(timeout, ctx->gc_expiry))
  		ret = -EACCES;
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1404
  	rcu_read_unlock();
cc6a7aab5   Arnd Bergmann   sunrpc: avoid war...
1405
1406
  
  	return ret;
4de6caa27   Andy Adamson   SUNRPC new rpc_cr...
1407
  }
fba3bad48   Trond Myklebust   SUNRPC: Move upca...
1408
  static int
8a3177604   Trond Myklebust   SUNRPC: Fix a loc...
1409
  gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
1411
  {
  	struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1412
  	struct gss_cl_ctx *ctx;
4de6caa27   Andy Adamson   SUNRPC new rpc_cr...
1413
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1414

cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1415
  	if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
8a3177604   Trond Myklebust   SUNRPC: Fix a loc...
1416
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1417
  	/* Don't match with creds that have expired. */
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1418
1419
1420
1421
  	rcu_read_lock();
  	ctx = rcu_dereference(gss_cred->gc_ctx);
  	if (!ctx || time_after(jiffies, ctx->gc_expiry)) {
  		rcu_read_unlock();
cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1422
  		return 0;
c5e6aecd0   Jeff Layton   sunrpc: fix RCU h...
1423
1424
  	}
  	rcu_read_unlock();
cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1425
  	if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
  		return 0;
8a3177604   Trond Myklebust   SUNRPC: Fix a loc...
1427
  out:
68c97153f   Trond Myklebust   SUNRPC: Clean up ...
1428
1429
1430
  	if (acred->principal != NULL) {
  		if (gss_cred->gc_principal == NULL)
  			return 0;
4de6caa27   Andy Adamson   SUNRPC new rpc_cr...
1431
1432
  		ret = strcmp(acred->principal, gss_cred->gc_principal) == 0;
  		goto check_expire;
68c97153f   Trond Myklebust   SUNRPC: Clean up ...
1433
1434
  	}
  	if (gss_cred->gc_principal != NULL)
7c67db3a8   Trond Myklebust   NFSv4: Reintroduc...
1435
  		return 0;
4de6caa27   Andy Adamson   SUNRPC new rpc_cr...
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
  	ret = uid_eq(rc->cr_uid, acred->uid);
  
  check_expire:
  	if (ret == 0)
  		return ret;
  
  	/* Notify acred users of GSS context expiration timeout */
  	if (test_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags) &&
  	    (gss_key_timeout(rc) != 0)) {
  		/* test will now be done from generic cred */
  		test_and_clear_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags);
  		/* tell NFS layer that key will expire soon */
  		set_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
  	}
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1451
1452
1453
1454
1455
1456
  }
  
  /*
  * Marshal credentials.
  * Maybe we should keep a cached credential for performance reasons.
  */
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1457
1458
  static __be32 *
  gss_marshal(struct rpc_task *task, __be32 *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1459
  {
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
1460
1461
  	struct rpc_rqst *req = task->tk_rqstp;
  	struct rpc_cred *cred = req->rq_cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
1463
1464
  	struct gss_cred	*gss_cred = container_of(cred, struct gss_cred,
  						 gc_base);
  	struct gss_cl_ctx	*ctx = gss_cred_get_ctx(cred);
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1465
  	__be32		*cred_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
1467
1468
1469
  	u32             maj_stat = 0;
  	struct xdr_netobj mic;
  	struct kvec	iov;
  	struct xdr_buf	verf_buf;
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1470
1471
  	dprintk("RPC: %5u %s
  ", task->tk_pid, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
  
  	*p++ = htonl(RPC_AUTH_GSS);
  	cred_len = p++;
  
  	spin_lock(&ctx->gc_seq_lock);
  	req->rq_seqno = ctx->gc_seq++;
  	spin_unlock(&ctx->gc_seq_lock);
  
  	*p++ = htonl((u32) RPC_GSS_VERSION);
  	*p++ = htonl((u32) ctx->gc_proc);
  	*p++ = htonl((u32) req->rq_seqno);
  	*p++ = htonl((u32) gss_cred->gc_service);
  	p = xdr_encode_netobj(p, &ctx->gc_wire_ctx);
  	*cred_len = htonl((p - (cred_len + 1)) << 2);
  
  	/* We compute the checksum for the verifier over the xdr-encoded bytes
  	 * starting with the xid and ending at the end of the credential: */
a4f0835c6   Trond Myklebust   SUNRPC: Eliminate...
1489
  	iov.iov_base = xprt_skip_transport_header(req->rq_xprt,
808012fbb   Chuck Lever   [PATCH] RPC: skip...
1490
  					req->rq_snd_buf.head[0].iov_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1491
1492
1493
1494
1495
1496
1497
  	iov.iov_len = (u8 *)p - (u8 *)iov.iov_base;
  	xdr_buf_from_iov(&iov, &verf_buf);
  
  	/* set verifier flavor*/
  	*p++ = htonl(RPC_AUTH_GSS);
  
  	mic.data = (u8 *)(p + 1);
00fd6e142   J. Bruce Fields   RPCSEC_GSS remove...
1498
  	maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1499
  	if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
1500
  		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
  	} else if (maj_stat != 0) {
  		printk("gss_marshal: gss_get_mic FAILED (%d)
  ", maj_stat);
  		goto out_put_ctx;
  	}
  	p = xdr_encode_opaque(p, NULL, mic.len);
  	gss_put_ctx(ctx);
  	return p;
  out_put_ctx:
  	gss_put_ctx(ctx);
  	return NULL;
  }
cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1513
1514
  static int gss_renew_cred(struct rpc_task *task)
  {
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
1515
  	struct rpc_cred *oldcred = task->tk_rqstp->rq_cred;
cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1516
1517
1518
1519
1520
1521
  	struct gss_cred *gss_cred = container_of(oldcred,
  						 struct gss_cred,
  						 gc_base);
  	struct rpc_auth *auth = oldcred->cr_auth;
  	struct auth_cred acred = {
  		.uid = oldcred->cr_uid,
68c97153f   Trond Myklebust   SUNRPC: Clean up ...
1522
1523
  		.principal = gss_cred->gc_principal,
  		.machine_cred = (gss_cred->gc_principal != NULL ? 1 : 0),
cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1524
1525
1526
1527
1528
1529
  	};
  	struct rpc_cred *new;
  
  	new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
  	if (IS_ERR(new))
  		return PTR_ERR(new);
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
1530
  	task->tk_rqstp->rq_cred = new;
cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1531
1532
1533
  	put_rpccred(oldcred);
  	return 0;
  }
126e216a8   Trond Myklebust   SUNRPC: Don't spa...
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
  static int gss_cred_is_negative_entry(struct rpc_cred *cred)
  {
  	if (test_bit(RPCAUTH_CRED_NEGATIVE, &cred->cr_flags)) {
  		unsigned long now = jiffies;
  		unsigned long begin, expire;
  		struct gss_cred *gss_cred; 
  
  		gss_cred = container_of(cred, struct gss_cred, gc_base);
  		begin = gss_cred->gc_upcall_timestamp;
  		expire = begin + gss_expired_cred_retry_delay * HZ;
  
  		if (time_in_range_open(now, begin, expire))
  			return 1;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1550
1551
1552
1553
1554
1555
  /*
  * Refresh credentials. XXX - finish
  */
  static int
  gss_refresh(struct rpc_task *task)
  {
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
1556
  	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1557
  	int ret = 0;
126e216a8   Trond Myklebust   SUNRPC: Don't spa...
1558
1559
  	if (gss_cred_is_negative_entry(cred))
  		return -EKEYEXPIRED;
cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1560
1561
1562
1563
1564
  	if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
  			!test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
  		ret = gss_renew_cred(task);
  		if (ret < 0)
  			goto out;
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
1565
  		cred = task->tk_rqstp->rq_cred;
cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1566
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1567

cd019f751   Trond Myklebust   SUNRPC: Don't cha...
1568
1569
1570
1571
  	if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
  		ret = gss_refresh_upcall(task);
  out:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
  }
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1573
1574
1575
1576
  /* Dummy refresh routine: used only when destroying the context */
  static int
  gss_refresh_null(struct rpc_task *task)
  {
c297c8b99   Andy Adamson   SUNRPC: do not fa...
1577
  	return 0;
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1578
  }
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1579
1580
  static __be32 *
  gss_validate(struct rpc_task *task, __be32 *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1581
  {
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
1582
  	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1583
  	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
2876a3446   J. Bruce Fields   sunrpc: don't pas...
1584
  	__be32		*seq = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1585
1586
1587
1588
1589
  	struct kvec	iov;
  	struct xdr_buf	verf_buf;
  	struct xdr_netobj mic;
  	u32		flav,len;
  	u32		maj_stat;
35fa5f7b3   Andy Adamson   SUNRPC refactor r...
1590
  	__be32		*ret = ERR_PTR(-EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591

632f0d050   Chuck Lever   SUNRPC: Use __fun...
1592
1593
  	dprintk("RPC: %5u %s
  ", task->tk_pid, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1594
1595
1596
  
  	flav = ntohl(*p++);
  	if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE)
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
1597
  		goto out_bad;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1598
1599
  	if (flav != RPC_AUTH_GSS)
  		goto out_bad;
2876a3446   J. Bruce Fields   sunrpc: don't pas...
1600
1601
1602
1603
1604
1605
  	seq = kmalloc(4, GFP_NOFS);
  	if (!seq)
  		goto out_bad;
  	*seq = htonl(task->tk_rqstp->rq_seqno);
  	iov.iov_base = seq;
  	iov.iov_len = 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606
1607
1608
  	xdr_buf_from_iov(&iov, &verf_buf);
  	mic.data = (u8 *)p;
  	mic.len = len;
35fa5f7b3   Andy Adamson   SUNRPC refactor r...
1609
  	ret = ERR_PTR(-EACCES);
00fd6e142   J. Bruce Fields   RPCSEC_GSS remove...
1610
  	maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
  	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
1612
  		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1613
  	if (maj_stat) {
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1614
1615
1616
  		dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x
  ",
  			task->tk_pid, __func__, maj_stat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617
  		goto out_bad;
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1618
  	}
24b2605be   J. Bruce Fields   RPCSEC_GSS: clean...
1619
1620
  	/* We leave it to unwrap to calculate au_rslack. For now we just
  	 * calculate the length of the verifier: */
1be27f366   Trond Myklebust   SUNRPC: Remove th...
1621
  	cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1622
  	gss_put_ctx(ctx);
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1623
1624
1625
  	dprintk("RPC: %5u %s: gss_verify_mic succeeded.
  ",
  			task->tk_pid, __func__);
2876a3446   J. Bruce Fields   sunrpc: don't pas...
1626
  	kfree(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1627
1628
1629
  	return p + XDR_QUADLEN(len);
  out_bad:
  	gss_put_ctx(ctx);
35fa5f7b3   Andy Adamson   SUNRPC refactor r...
1630
1631
1632
  	dprintk("RPC: %5u %s failed ret %ld.
  ", task->tk_pid, __func__,
  		PTR_ERR(ret));
2876a3446   J. Bruce Fields   sunrpc: don't pas...
1633
  	kfree(seq);
35fa5f7b3   Andy Adamson   SUNRPC refactor r...
1634
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
  }
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
1636
1637
1638
1639
1640
1641
1642
1643
  static void gss_wrap_req_encode(kxdreproc_t encode, struct rpc_rqst *rqstp,
  				__be32 *p, void *obj)
  {
  	struct xdr_stream xdr;
  
  	xdr_init_encode(&xdr, &rqstp->rq_snd_buf, p);
  	encode(rqstp, &xdr, obj);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644
1645
  static inline int
  gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
1646
1647
  		   kxdreproc_t encode, struct rpc_rqst *rqstp,
  		   __be32 *p, void *obj)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1648
1649
1650
  {
  	struct xdr_buf	*snd_buf = &rqstp->rq_snd_buf;
  	struct xdr_buf	integ_buf;
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1651
  	__be32          *integ_len = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1652
  	struct xdr_netobj mic;
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1653
1654
  	u32		offset;
  	__be32		*q;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1655
1656
1657
1658
1659
1660
1661
  	struct kvec	*iov;
  	u32             maj_stat = 0;
  	int		status = -EIO;
  
  	integ_len = p++;
  	offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
  	*p++ = htonl(rqstp->rq_seqno);
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
1662
  	gss_wrap_req_encode(encode, rqstp, p, obj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663
1664
1665
1666
1667
1668
1669
  
  	if (xdr_buf_subsegment(snd_buf, &integ_buf,
  				offset, snd_buf->len - offset))
  		return status;
  	*integ_len = htonl(integ_buf.len);
  
  	/* guess whether we're in the head or the tail: */
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
1670
  	if (snd_buf->page_len || snd_buf->tail[0].iov_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671
1672
1673
1674
1675
  		iov = snd_buf->tail;
  	else
  		iov = snd_buf->head;
  	p = iov->iov_base + iov->iov_len;
  	mic.data = (u8 *)(p + 1);
00fd6e142   J. Bruce Fields   RPCSEC_GSS remove...
1676
  	maj_stat = gss_get_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
1678
  	status = -EIO; /* XXX? */
  	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
1679
  		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1680
1681
1682
1683
1684
1685
1686
1687
1688
  	else if (maj_stat)
  		return status;
  	q = xdr_encode_opaque(p, NULL, mic.len);
  
  	offset = (u8 *)q - (u8 *)p;
  	iov->iov_len += offset;
  	snd_buf->len += offset;
  	return 0;
  }
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
  static void
  priv_release_snd_buf(struct rpc_rqst *rqstp)
  {
  	int i;
  
  	for (i=0; i < rqstp->rq_enc_pages_num; i++)
  		__free_page(rqstp->rq_enc_pages[i]);
  	kfree(rqstp->rq_enc_pages);
  }
  
  static int
  alloc_enc_pages(struct rpc_rqst *rqstp)
  {
  	struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
  	int first, last, i;
  
  	if (snd_buf->page_len == 0) {
  		rqstp->rq_enc_pages_num = 0;
  		return 0;
  	}
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
1709
1710
  	first = snd_buf->page_base >> PAGE_SHIFT;
  	last = (snd_buf->page_base + snd_buf->page_len - 1) >> PAGE_SHIFT;
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
  	rqstp->rq_enc_pages_num = last - first + 1 + 1;
  	rqstp->rq_enc_pages
  		= kmalloc(rqstp->rq_enc_pages_num * sizeof(struct page *),
  				GFP_NOFS);
  	if (!rqstp->rq_enc_pages)
  		goto out;
  	for (i=0; i < rqstp->rq_enc_pages_num; i++) {
  		rqstp->rq_enc_pages[i] = alloc_page(GFP_NOFS);
  		if (rqstp->rq_enc_pages[i] == NULL)
  			goto out_free;
  	}
  	rqstp->rq_release_snd_buf = priv_release_snd_buf;
  	return 0;
  out_free:
cdead7cf1   Trond Myklebust   SUNRPC: Fix a pot...
1725
1726
  	rqstp->rq_enc_pages_num = i;
  	priv_release_snd_buf(rqstp);
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1727
1728
1729
1730
1731
1732
  out:
  	return -EAGAIN;
  }
  
  static inline int
  gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
1733
1734
  		  kxdreproc_t encode, struct rpc_rqst *rqstp,
  		  __be32 *p, void *obj)
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1735
1736
1737
1738
1739
  {
  	struct xdr_buf	*snd_buf = &rqstp->rq_snd_buf;
  	u32		offset;
  	u32             maj_stat;
  	int		status;
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1740
  	__be32		*opaque_len;
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1741
1742
1743
1744
1745
1746
1747
1748
1749
  	struct page	**inpages;
  	int		first;
  	int		pad;
  	struct kvec	*iov;
  	char		*tmp;
  
  	opaque_len = p++;
  	offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
  	*p++ = htonl(rqstp->rq_seqno);
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
1750
  	gss_wrap_req_encode(encode, rqstp, p, obj);
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1751
1752
1753
1754
  
  	status = alloc_enc_pages(rqstp);
  	if (status)
  		return status;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
1755
  	first = snd_buf->page_base >> PAGE_SHIFT;
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1756
1757
  	inpages = snd_buf->pages + first;
  	snd_buf->pages = rqstp->rq_enc_pages;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
1758
  	snd_buf->page_base -= first << PAGE_SHIFT;
7561042fb   Kevin Coffman   gss_krb5: Added a...
1759
1760
1761
1762
1763
1764
1765
1766
  	/*
  	 * Give the tail its own page, in case we need extra space in the
  	 * head when wrapping:
  	 *
  	 * call_allocate() allocates twice the slack space required
  	 * by the authentication flavor to rq_callsize.
  	 * For GSS, slack is GSS_CRED_SLACK.
  	 */
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1767
1768
1769
1770
1771
  	if (snd_buf->page_len || snd_buf->tail[0].iov_len) {
  		tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]);
  		memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len);
  		snd_buf->tail[0].iov_base = tmp;
  	}
00fd6e142   J. Bruce Fields   RPCSEC_GSS remove...
1772
  	maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
7561042fb   Kevin Coffman   gss_krb5: Added a...
1773
  	/* slack space should prevent this ever happening: */
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1774
  	BUG_ON(snd_buf->len > snd_buf->buflen);
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
1775
  	status = -EIO;
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1776
1777
1778
  	/* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was
  	 * done anyway, so it's safe to put the request on the wire: */
  	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
1779
  		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
  	else if (maj_stat)
  		return status;
  
  	*opaque_len = htonl(snd_buf->len - offset);
  	/* guess whether we're in the head or the tail: */
  	if (snd_buf->page_len || snd_buf->tail[0].iov_len)
  		iov = snd_buf->tail;
  	else
  		iov = snd_buf->head;
  	p = iov->iov_base + iov->iov_len;
  	pad = 3 - ((snd_buf->len - offset - 1) & 3);
  	memset(p, 0, pad);
  	iov->iov_len += pad;
  	snd_buf->len += pad;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
1798
  static int
  gss_wrap_req(struct rpc_task *task,
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
1799
  	     kxdreproc_t encode, void *rqstp, __be32 *p, void *obj)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1800
  {
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
1801
  	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1802
1803
1804
1805
  	struct gss_cred	*gss_cred = container_of(cred, struct gss_cred,
  			gc_base);
  	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
  	int             status = -EIO;
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1806
1807
  	dprintk("RPC: %5u %s
  ", task->tk_pid, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1808
1809
1810
1811
  	if (ctx->gc_proc != RPC_GSS_PROC_DATA) {
  		/* The spec seems a little ambiguous here, but I think that not
  		 * wrapping context destruction requests makes the most sense.
  		 */
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
1812
1813
  		gss_wrap_req_encode(encode, rqstp, p, obj);
  		status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814
1815
1816
  		goto out;
  	}
  	switch (gss_cred->gc_service) {
89f0e4fea   Joe Perches   sunrpc: Reduce sw...
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
  	case RPC_GSS_SVC_NONE:
  		gss_wrap_req_encode(encode, rqstp, p, obj);
  		status = 0;
  		break;
  	case RPC_GSS_SVC_INTEGRITY:
  		status = gss_wrap_req_integ(cred, ctx, encode, rqstp, p, obj);
  		break;
  	case RPC_GSS_SVC_PRIVACY:
  		status = gss_wrap_req_priv(cred, ctx, encode, rqstp, p, obj);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1827
1828
1829
  	}
  out:
  	gss_put_ctx(ctx);
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1830
1831
  	dprintk("RPC: %5u %s returning %d
  ", task->tk_pid, __func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1832
1833
1834
1835
1836
  	return status;
  }
  
  static inline int
  gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1837
  		struct rpc_rqst *rqstp, __be32 **p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
  {
  	struct xdr_buf	*rcv_buf = &rqstp->rq_rcv_buf;
  	struct xdr_buf integ_buf;
  	struct xdr_netobj mic;
  	u32 data_offset, mic_offset;
  	u32 integ_len;
  	u32 maj_stat;
  	int status = -EIO;
  
  	integ_len = ntohl(*(*p)++);
  	if (integ_len & 3)
  		return status;
  	data_offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base;
  	mic_offset = integ_len + data_offset;
  	if (mic_offset > rcv_buf->len)
  		return status;
  	if (ntohl(*(*p)++) != rqstp->rq_seqno)
  		return status;
  
  	if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset,
  				mic_offset - data_offset))
  		return status;
  
  	if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset))
  		return status;
00fd6e142   J. Bruce Fields   RPCSEC_GSS remove...
1863
  	maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1864
  	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
1865
  		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1866
1867
1868
1869
  	if (maj_stat != GSS_S_COMPLETE)
  		return status;
  	return 0;
  }
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1870
1871
  static inline int
  gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1872
  		struct rpc_rqst *rqstp, __be32 **p)
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
  {
  	struct xdr_buf  *rcv_buf = &rqstp->rq_rcv_buf;
  	u32 offset;
  	u32 opaque_len;
  	u32 maj_stat;
  	int status = -EIO;
  
  	opaque_len = ntohl(*(*p)++);
  	offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base;
  	if (offset + opaque_len > rcv_buf->len)
  		return status;
  	/* remove padding: */
  	rcv_buf->len = offset + opaque_len;
00fd6e142   J. Bruce Fields   RPCSEC_GSS remove...
1886
  	maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf);
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1887
  	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
fc432dd90   Trond Myklebust   SUNRPC: Enforce a...
1888
  		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1889
1890
1891
1892
1893
1894
1895
  	if (maj_stat != GSS_S_COMPLETE)
  		return status;
  	if (ntohl(*(*p)++) != rqstp->rq_seqno)
  		return status;
  
  	return 0;
  }
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
1896
1897
1898
1899
1900
1901
1902
1903
1904
  static int
  gss_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp,
  		      __be32 *p, void *obj)
  {
  	struct xdr_stream xdr;
  
  	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
  	return decode(rqstp, &xdr, obj);
  }
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1905

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1906
1907
  static int
  gss_unwrap_resp(struct rpc_task *task,
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
1908
  		kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1909
  {
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
1910
  	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1911
1912
1913
  	struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
  			gc_base);
  	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1914
  	__be32		*savedp = p;
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1915
1916
  	struct kvec	*head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
  	int		savedlen = head->iov_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1917
1918
1919
1920
1921
  	int             status = -EIO;
  
  	if (ctx->gc_proc != RPC_GSS_PROC_DATA)
  		goto out_decode;
  	switch (gss_cred->gc_service) {
89f0e4fea   Joe Perches   sunrpc: Reduce sw...
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
  	case RPC_GSS_SVC_NONE:
  		break;
  	case RPC_GSS_SVC_INTEGRITY:
  		status = gss_unwrap_resp_integ(cred, ctx, rqstp, &p);
  		if (status)
  			goto out;
  		break;
  	case RPC_GSS_SVC_PRIVACY:
  		status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p);
  		if (status)
  			goto out;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1934
  	}
24b2605be   J. Bruce Fields   RPCSEC_GSS: clean...
1935
  	/* take into account extra slack for integrity and privacy cases: */
1be27f366   Trond Myklebust   SUNRPC: Remove th...
1936
  	cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp)
2d2da60c6   J. Bruce Fields   RPCSEC_GSS: clien...
1937
  						+ (savedlen - head->iov_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1938
  out_decode:
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
1939
  	status = gss_unwrap_req_decode(decode, rqstp, p, obj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1940
1941
  out:
  	gss_put_ctx(ctx);
632f0d050   Chuck Lever   SUNRPC: Use __fun...
1942
1943
1944
  	dprintk("RPC: %5u %s returning %d
  ",
  		task->tk_pid, __func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1945
1946
  	return status;
  }
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
1947

f1c0a8615   Trond Myklebust   SUNRPC: Mark auth...
1948
  static const struct rpc_authops authgss_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1949
1950
  	.owner		= THIS_MODULE,
  	.au_flavor	= RPC_AUTH_GSS,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1951
  	.au_name	= "RPCSEC_GSS",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1952
1953
  	.create		= gss_create,
  	.destroy	= gss_destroy,
a960f8d6d   Frank Sorenson   sunrpc: add RPCSE...
1954
  	.hash_cred	= gss_hash_cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1955
  	.lookup_cred	= gss_lookup_cred,
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
1956
  	.crcreate	= gss_create_cred,
6a1a1e34d   Chuck Lever   SUNRPC: Add rpcau...
1957
  	.list_pseudoflavors = gss_mech_list_pseudoflavors,
9568c5e9a   Chuck Lever   SUNRPC: Introduce...
1958
  	.info2flavor	= gss_mech_info2flavor,
a77c806fb   Chuck Lever   SUNRPC: Refactor ...
1959
  	.flavor2info	= gss_mech_flavor2info,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1960
  };
f1c0a8615   Trond Myklebust   SUNRPC: Mark auth...
1961
  static const struct rpc_credops gss_credops = {
a0337d1dd   Jeff Layton   sunrpc: add a new...
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
  	.cr_name		= "AUTH_GSS",
  	.crdestroy		= gss_destroy_cred,
  	.cr_init		= gss_cred_init,
  	.crbind			= rpcauth_generic_bind_cred,
  	.crmatch		= gss_match,
  	.crmarshal		= gss_marshal,
  	.crrefresh		= gss_refresh,
  	.crvalidate		= gss_validate,
  	.crwrap_req		= gss_wrap_req,
  	.crunwrap_resp		= gss_unwrap_resp,
  	.crkey_timeout		= gss_key_timeout,
  	.crstringify_acceptor	= gss_stringify_acceptor,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1974
  };
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1975
  static const struct rpc_credops gss_nullops = {
a0337d1dd   Jeff Layton   sunrpc: add a new...
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
  	.cr_name		= "AUTH_GSS",
  	.crdestroy		= gss_destroy_nullcred,
  	.crbind			= rpcauth_generic_bind_cred,
  	.crmatch		= gss_match,
  	.crmarshal		= gss_marshal,
  	.crrefresh		= gss_refresh_null,
  	.crvalidate		= gss_validate,
  	.crwrap_req		= gss_wrap_req,
  	.crunwrap_resp		= gss_unwrap_resp,
  	.crstringify_acceptor	= gss_stringify_acceptor,
0df7fb74f   Trond Myklebust   SUNRPC: Ensure RP...
1986
  };
b693ba4a3   Trond Myklebust   SUNRPC: Constify ...
1987
  static const struct rpc_pipe_ops gss_upcall_ops_v0 = {
c1225158a   Peng Tao   SUNRPC/NFS: make ...
1988
  	.upcall		= rpc_pipe_generic_upcall,
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
1989
1990
1991
1992
1993
  	.downcall	= gss_pipe_downcall,
  	.destroy_msg	= gss_pipe_destroy_msg,
  	.open_pipe	= gss_pipe_open_v0,
  	.release_pipe	= gss_pipe_release,
  };
b693ba4a3   Trond Myklebust   SUNRPC: Constify ...
1994
  static const struct rpc_pipe_ops gss_upcall_ops_v1 = {
c1225158a   Peng Tao   SUNRPC/NFS: make ...
1995
  	.upcall		= rpc_pipe_generic_upcall,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1996
1997
  	.downcall	= gss_pipe_downcall,
  	.destroy_msg	= gss_pipe_destroy_msg,
34769fc48   \"J. Bruce Fields\   rpc: implement ne...
1998
  	.open_pipe	= gss_pipe_open_v1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1999
2000
  	.release_pipe	= gss_pipe_release,
  };
a1db410d0   Stanislav Kinsbursky   SUNRPC: create GS...
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
  static __net_init int rpcsec_gss_init_net(struct net *net)
  {
  	return gss_svc_init_net(net);
  }
  
  static __net_exit void rpcsec_gss_exit_net(struct net *net)
  {
  	gss_svc_shutdown_net(net);
  }
  
  static struct pernet_operations rpcsec_gss_net_ops = {
  	.init = rpcsec_gss_init_net,
  	.exit = rpcsec_gss_exit_net,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
  /*
   * Initialize RPCSEC_GSS module
   */
  static int __init init_rpcsec_gss(void)
  {
  	int err = 0;
  
  	err = rpcauth_register(&authgss_ops);
  	if (err)
  		goto out;
  	err = gss_svc_init();
  	if (err)
  		goto out_unregister;
a1db410d0   Stanislav Kinsbursky   SUNRPC: create GS...
2028
2029
2030
  	err = register_pernet_subsys(&rpcsec_gss_net_ops);
  	if (err)
  		goto out_svc_exit;
79a3f20b6   \"J. Bruce Fields\   rpc: use count of...
2031
  	rpc_init_wait_queue(&pipe_version_rpc_waitqueue, "gss pipe version");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2032
  	return 0;
a1db410d0   Stanislav Kinsbursky   SUNRPC: create GS...
2033
2034
  out_svc_exit:
  	gss_svc_shutdown();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2035
2036
2037
2038
2039
2040
2041
2042
  out_unregister:
  	rpcauth_unregister(&authgss_ops);
  out:
  	return err;
  }
  
  static void __exit exit_rpcsec_gss(void)
  {
a1db410d0   Stanislav Kinsbursky   SUNRPC: create GS...
2043
  	unregister_pernet_subsys(&rpcsec_gss_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2044
2045
  	gss_svc_shutdown();
  	rpcauth_unregister(&authgss_ops);
bf12691d8   Jesper Dangaard Brouer   sunrpc/auth_gss: ...
2046
  	rcu_barrier(); /* Wait for completion of call_rcu()'s */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2047
  }
71afa85e7   Chuck Lever   SUNRPC: Missing m...
2048
  MODULE_ALIAS("rpc-auth-6");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049
  MODULE_LICENSE("GPL");
126e216a8   Trond Myklebust   SUNRPC: Don't spa...
2050
2051
2052
2053
2054
  module_param_named(expired_cred_retry_delay,
  		   gss_expired_cred_retry_delay,
  		   uint, 0644);
  MODULE_PARM_DESC(expired_cred_retry_delay, "Timeout (in seconds) until "
  		"the RPC engine retries an expired credential");
4de6caa27   Andy Adamson   SUNRPC new rpc_cr...
2055
2056
2057
2058
2059
2060
  module_param_named(key_expire_timeo,
  		   gss_key_expire_timeo,
  		   uint, 0644);
  MODULE_PARM_DESC(key_expire_timeo, "Time (in seconds) at the end of a "
  		"credential keys lifetime where the NFS layer cleans up "
  		"prior to key expiration");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2061
2062
  module_init(init_rpcsec_gss)
  module_exit(exit_rpcsec_gss)