auth_gss.c 45.7 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 * linux/net/sunrpc/auth_gss/auth_gss.c
L
Linus Torvalds 已提交
3 4
 *
 * RPCSEC_GSS client authentication.
5
 *
L
Linus Torvalds 已提交
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 36 37 38 39 40 41 42 43
 *  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.
 */


#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/sched.h>
44
#include <linux/pagemap.h>
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52 53 54
#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>
#include <asm/uaccess.h>

55 56
#include "../netns.h"

57
static const struct rpc_authops authgss_ops;
L
Linus Torvalds 已提交
58

59
static const struct rpc_credops gss_credops;
60
static const struct rpc_credops gss_nullops;
L
Linus Torvalds 已提交
61

62 63 64
#define GSS_RETRY_EXPIRED 5
static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;

L
Linus Torvalds 已提交
65 66 67 68
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY	RPCDBG_AUTH
#endif

69
#define GSS_CRED_SLACK		(RPC_MAX_AUTH_SIZE * 2)
L
Linus Torvalds 已提交
70 71
/* length of a krb5 verifier (48), plus data added before arguments when
 * using integrity (two 4-byte integers): */
O
Olga Kornievskaia 已提交
72
#define GSS_VERF_SLACK		100
L
Linus Torvalds 已提交
73

74 75 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;
};

L
Linus Torvalds 已提交
81
struct gss_auth {
82
	struct kref kref;
L
Linus Torvalds 已提交
83 84 85 86
	struct rpc_auth rpc_auth;
	struct gss_api_mech *mech;
	enum rpc_gss_svc service;
	struct rpc_clnt *client;
T
Trond Myklebust 已提交
87
	struct net *net;
\
\"J. Bruce Fields\ 已提交
88 89 90 91 92 93
	/*
	 * 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.
	 */
94
	struct gss_pipe *gss_pipe[2];
95
	const char *target_name;
L
Linus Torvalds 已提交
96 97
};

98 99 100 101
/* pipe_version >= 0 if and only if someone has a pipe open. */
static DEFINE_SPINLOCK(pipe_version_lock);
static struct rpc_wait_queue pipe_version_rpc_waitqueue;
static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
102

103
static void gss_free_ctx(struct gss_cl_ctx *);
104 105
static const struct rpc_pipe_ops gss_upcall_ops_v0;
static const struct rpc_pipe_ops gss_upcall_ops_v1;
L
Linus Torvalds 已提交
106 107 108 109 110 111 112 113 114 115 116 117

static inline struct gss_cl_ctx *
gss_get_ctx(struct gss_cl_ctx *ctx)
{
	atomic_inc(&ctx->count);
	return ctx;
}

static inline void
gss_put_ctx(struct gss_cl_ctx *ctx)
{
	if (atomic_dec_and_test(&ctx->count))
118
		gss_free_ctx(ctx);
L
Linus Torvalds 已提交
119 120
}

121 122 123
/* 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
124
 * and a new one is protected by the pipe->lock.
125
 */
L
Linus Torvalds 已提交
126 127 128 129
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);
130

131 132
	if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
		return;
133
	gss_get_ctx(ctx);
134
	rcu_assign_pointer(gss_cred->gc_ctx, ctx);
135
	set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
136
	smp_mb__before_clear_bit();
137
	clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
L
Linus Torvalds 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
}

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);
162
	dest->data = kmemdup(p, len, GFP_NOFS);
L
Linus Torvalds 已提交
163 164 165 166 167 168 169 170 171 172 173 174
	if (unlikely(dest->data == NULL))
		return ERR_PTR(-ENOMEM);
	dest->len = len;
	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;

175
	rcu_read_lock();
L
Linus Torvalds 已提交
176 177
	if (gss_cred->gc_ctx)
		ctx = gss_get_ctx(gss_cred->gc_ctx);
178
	rcu_read_unlock();
L
Linus Torvalds 已提交
179 180 181 182 183 184 185 186
	return ctx;
}

static struct gss_cl_ctx *
gss_alloc_context(void)
{
	struct gss_cl_ctx *ctx;

187
	ctx = kzalloc(sizeof(*ctx), GFP_NOFS);
L
Linus Torvalds 已提交
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
	if (ctx != NULL) {
		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);
		atomic_set(&ctx->count,1);
	}
	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;
204
	unsigned long now = jiffies;
L
Linus Torvalds 已提交
205 206 207
	u32 window_size;
	int ret;

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.
	 */
L
Linus Torvalds 已提交
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;
217 218 219 220
	ctx->gc_expiry = now + ((unsigned long)timeout * HZ);
	/* Sequence number window. Determines the maximum number of
	 * simultaneous requests
	 */
L
Linus Torvalds 已提交
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) {
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);
L
Linus Torvalds 已提交
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;
	}
250
	ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, NULL, GFP_NOFS);
L
Linus Torvalds 已提交
251 252 253 254
	if (ret < 0) {
		p = ERR_PTR(ret);
		goto err;
	}
255 256
	dprintk("RPC:       %s Success. gc_expiry %lu now %lu timeout %u\n",
		__func__, ctx->gc_expiry, now, timeout);
L
Linus Torvalds 已提交
257 258
	return q;
err:
259
	dprintk("RPC:       %s returns error %ld\n", __func__, -PTR_ERR(p));
L
Linus Torvalds 已提交
260 261 262
	return p;
}

\
\"J. Bruce Fields\ 已提交
263
#define UPCALL_BUF_LEN 128
L
Linus Torvalds 已提交
264 265 266

struct gss_upcall_msg {
	atomic_t count;
267
	kuid_t	uid;
L
Linus Torvalds 已提交
268 269 270
	struct rpc_pipe_msg msg;
	struct list_head list;
	struct gss_auth *auth;
271
	struct rpc_pipe *pipe;
L
Linus Torvalds 已提交
272 273 274
	struct rpc_wait_queue rpc_waitqueue;
	wait_queue_head_t waitqueue;
	struct gss_cl_ctx *ctx;
\
\"J. Bruce Fields\ 已提交
275
	char databuf[UPCALL_BUF_LEN];
L
Linus Torvalds 已提交
276 277
};

278
static int get_pipe_version(struct net *net)
279
{
280
	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
281 282 283
	int ret;

	spin_lock(&pipe_version_lock);
284 285 286
	if (sn->pipe_version >= 0) {
		atomic_inc(&sn->pipe_users);
		ret = sn->pipe_version;
287 288 289 290 291 292
	} else
		ret = -EAGAIN;
	spin_unlock(&pipe_version_lock);
	return ret;
}

293
static void put_pipe_version(struct net *net)
294
{
295 296 297 298
	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;
299 300 301 302
		spin_unlock(&pipe_version_lock);
	}
}

L
Linus Torvalds 已提交
303 304 305
static void
gss_release_msg(struct gss_upcall_msg *gss_msg)
{
T
Trond Myklebust 已提交
306
	struct net *net = gss_msg->auth->net;
L
Linus Torvalds 已提交
307 308
	if (!atomic_dec_and_test(&gss_msg->count))
		return;
309
	put_pipe_version(net);
L
Linus Torvalds 已提交
310 311 312
	BUG_ON(!list_empty(&gss_msg->list));
	if (gss_msg->ctx != NULL)
		gss_put_ctx(gss_msg->ctx);
313
	rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
L
Linus Torvalds 已提交
314 315 316 317
	kfree(gss_msg);
}

static struct gss_upcall_msg *
318
__gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid)
L
Linus Torvalds 已提交
319 320
{
	struct gss_upcall_msg *pos;
321
	list_for_each_entry(pos, &pipe->in_downcall, list) {
322
		if (!uid_eq(pos->uid, uid))
L
Linus Torvalds 已提交
323 324
			continue;
		atomic_inc(&pos->count);
325
		dprintk("RPC:       %s found msg %p\n", __func__, pos);
L
Linus Torvalds 已提交
326 327
		return pos;
	}
328
	dprintk("RPC:       %s found nothing\n", __func__);
L
Linus Torvalds 已提交
329 330 331
	return NULL;
}

332
/* Try to add an upcall to the pipefs queue.
L
Linus Torvalds 已提交
333 334 335 336
 * 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 *
337
gss_add_msg(struct gss_upcall_msg *gss_msg)
L
Linus Torvalds 已提交
338
{
339
	struct rpc_pipe *pipe = gss_msg->pipe;
L
Linus Torvalds 已提交
340 341
	struct gss_upcall_msg *old;

342 343
	spin_lock(&pipe->lock);
	old = __gss_find_upcall(pipe, gss_msg->uid);
L
Linus Torvalds 已提交
344 345
	if (old == NULL) {
		atomic_inc(&gss_msg->count);
346
		list_add(&gss_msg->list, &pipe->in_downcall);
L
Linus Torvalds 已提交
347 348
	} else
		gss_msg = old;
349
	spin_unlock(&pipe->lock);
L
Linus Torvalds 已提交
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
	return gss_msg;
}

static void
__gss_unhash_msg(struct gss_upcall_msg *gss_msg)
{
	list_del_init(&gss_msg->list);
	rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
	wake_up_all(&gss_msg->waitqueue);
	atomic_dec(&gss_msg->count);
}

static void
gss_unhash_msg(struct gss_upcall_msg *gss_msg)
{
365
	struct rpc_pipe *pipe = gss_msg->pipe;
L
Linus Torvalds 已提交
366

367 368
	if (list_empty(&gss_msg->list))
		return;
369
	spin_lock(&pipe->lock);
370 371
	if (!list_empty(&gss_msg->list))
		__gss_unhash_msg(gss_msg);
372
	spin_unlock(&pipe->lock);
L
Linus Torvalds 已提交
373 374
}

375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
static void
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);
}

L
Linus Torvalds 已提交
393 394 395
static void
gss_upcall_callback(struct rpc_task *task)
{
396
	struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred,
L
Linus Torvalds 已提交
397 398
			struct gss_cred, gc_base);
	struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
399
	struct rpc_pipe *pipe = gss_msg->pipe;
L
Linus Torvalds 已提交
400

401
	spin_lock(&pipe->lock);
402
	gss_handle_downcall_result(gss_cred, gss_msg);
403
	spin_unlock(&pipe->lock);
404
	task->tk_status = gss_msg->msg.errno;
L
Linus Torvalds 已提交
405 406 407
	gss_release_msg(gss_msg);
}

\
\"J. Bruce Fields\ 已提交
408 409
static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
{
410 411 412 413 414
	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);
	BUG_ON(sizeof(uid) > UPCALL_BUF_LEN);
\
\"J. Bruce Fields\ 已提交
415 416
}

417
static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
418 419
				const char *service_name,
				const char *target_name)
\
\"J. Bruce Fields\ 已提交
420
{
421
	struct gss_api_mech *mech = gss_msg->auth->mech;
422 423 424 425
	char *p = gss_msg->databuf;
	int len = 0;

	gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ",
426
				   mech->gm_name,
427
				   from_kuid(&init_user_ns, gss_msg->uid));
428
	p += gss_msg->msg.len;
429 430
	if (target_name) {
		len = sprintf(p, "target=%s ", target_name);
431 432 433
		p += len;
		gss_msg->msg.len += len;
	}
434 435
	if (service_name != NULL) {
		len = sprintf(p, "service=%s ", service_name);
436 437 438
		p += len;
		gss_msg->msg.len += len;
	}
439
	if (mech->gm_upcall_enctypes) {
440
		len = sprintf(p, "enctypes=%s ", mech->gm_upcall_enctypes);
441 442 443
		p += len;
		gss_msg->msg.len += len;
	}
444 445 446
	len = sprintf(p, "\n");
	gss_msg->msg.len += len;

\
\"J. Bruce Fields\ 已提交
447 448 449 450
	gss_msg->msg.data = gss_msg->databuf;
	BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN);
}

451
static struct gss_upcall_msg *
T
Trond Myklebust 已提交
452
gss_alloc_msg(struct gss_auth *gss_auth,
453
		kuid_t uid, const char *service_name)
L
Linus Torvalds 已提交
454 455
{
	struct gss_upcall_msg *gss_msg;
456
	int vers;
L
Linus Torvalds 已提交
457

458
	gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
459 460
	if (gss_msg == NULL)
		return ERR_PTR(-ENOMEM);
T
Trond Myklebust 已提交
461
	vers = get_pipe_version(gss_auth->net);
462 463 464 465
	if (vers < 0) {
		kfree(gss_msg);
		return ERR_PTR(vers);
	}
466
	gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe;
467 468 469 470 471 472
	INIT_LIST_HEAD(&gss_msg->list);
	rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
	init_waitqueue_head(&gss_msg->waitqueue);
	atomic_set(&gss_msg->count, 1);
	gss_msg->uid = uid;
	gss_msg->auth = gss_auth;
473 474 475 476 477 478
	switch (vers) {
	case 0:
		gss_encode_v0_msg(gss_msg);
	default:
		gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
	};
L
Linus Torvalds 已提交
479 480 481 482
	return gss_msg;
}

static struct gss_upcall_msg *
T
Trond Myklebust 已提交
483
gss_setup_upcall(struct gss_auth *gss_auth, struct rpc_cred *cred)
L
Linus Torvalds 已提交
484
{
485 486
	struct gss_cred *gss_cred = container_of(cred,
			struct gss_cred, gc_base);
L
Linus Torvalds 已提交
487
	struct gss_upcall_msg *gss_new, *gss_msg;
488
	kuid_t uid = cred->cr_uid;
L
Linus Torvalds 已提交
489

T
Trond Myklebust 已提交
490
	gss_new = gss_alloc_msg(gss_auth, uid, gss_cred->gc_principal);
491 492
	if (IS_ERR(gss_new))
		return gss_new;
493
	gss_msg = gss_add_msg(gss_new);
L
Linus Torvalds 已提交
494
	if (gss_msg == gss_new) {
495
		int res = rpc_queue_upcall(gss_new->pipe, &gss_new->msg);
L
Linus Torvalds 已提交
496 497 498 499 500 501 502 503 504
		if (res) {
			gss_unhash_msg(gss_new);
			gss_msg = ERR_PTR(res);
		}
	} else
		gss_release_msg(gss_new);
	return gss_msg;
}

505 506 507 508 509 510 511 512 513 514 515 516
static void warn_gssd(void)
{
	static unsigned long ratelimit;
	unsigned long now = jiffies;

	if (time_after(now, ratelimit)) {
		printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n"
				"Please check user daemon is running.\n");
		ratelimit = now + 15*HZ;
	}
}

L
Linus Torvalds 已提交
517 518 519
static inline int
gss_refresh_upcall(struct rpc_task *task)
{
520
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
521
	struct gss_auth *gss_auth = container_of(cred->cr_auth,
L
Linus Torvalds 已提交
522 523 524 525
			struct gss_auth, rpc_auth);
	struct gss_cred *gss_cred = container_of(cred,
			struct gss_cred, gc_base);
	struct gss_upcall_msg *gss_msg;
526
	struct rpc_pipe *pipe;
L
Linus Torvalds 已提交
527 528
	int err = 0;

529
	dprintk("RPC: %5u %s for uid %u\n",
530
		task->tk_pid, __func__, from_kuid(&init_user_ns, cred->cr_uid));
T
Trond Myklebust 已提交
531
	gss_msg = gss_setup_upcall(gss_auth, cred);
R
Roel Kluin 已提交
532
	if (PTR_ERR(gss_msg) == -EAGAIN) {
533 534 535 536 537
		/* 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);
538
		return -EAGAIN;
539
	}
L
Linus Torvalds 已提交
540 541 542 543
	if (IS_ERR(gss_msg)) {
		err = PTR_ERR(gss_msg);
		goto out;
	}
544 545
	pipe = gss_msg->pipe;
	spin_lock(&pipe->lock);
L
Linus Torvalds 已提交
546
	if (gss_cred->gc_upcall != NULL)
547
		rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
548
	else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
L
Linus Torvalds 已提交
549 550 551 552
		task->tk_timeout = 0;
		gss_cred->gc_upcall = gss_msg;
		/* gss_upcall_callback will release the reference to gss_upcall_msg */
		atomic_inc(&gss_msg->count);
553
		rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
554 555
	} else {
		gss_handle_downcall_result(gss_cred, gss_msg);
L
Linus Torvalds 已提交
556
		err = gss_msg->msg.errno;
557
	}
558
	spin_unlock(&pipe->lock);
L
Linus Torvalds 已提交
559 560
	gss_release_msg(gss_msg);
out:
561
	dprintk("RPC: %5u %s for uid %u result %d\n",
562 563
		task->tk_pid, __func__,
		from_kuid(&init_user_ns, cred->cr_uid),	err);
L
Linus Torvalds 已提交
564 565 566 567 568 569
	return err;
}

static inline int
gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
{
T
Trond Myklebust 已提交
570
	struct net *net = gss_auth->net;
571
	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
572
	struct rpc_pipe *pipe;
L
Linus Torvalds 已提交
573 574
	struct rpc_cred *cred = &gss_cred->gc_base;
	struct gss_upcall_msg *gss_msg;
575
	unsigned long timeout;
L
Linus Torvalds 已提交
576
	DEFINE_WAIT(wait);
577
	int err;
L
Linus Torvalds 已提交
578

579 580
	dprintk("RPC:       %s for uid %u\n",
		__func__, from_kuid(&init_user_ns, cred->cr_uid));
581
retry:
582
	err = 0;
583 584 585 586
	/* Default timeout is 15s unless we know that gssd is not running */
	timeout = 15 * HZ;
	if (!sn->gssd_running)
		timeout = HZ >> 2;
T
Trond Myklebust 已提交
587
	gss_msg = gss_setup_upcall(gss_auth, cred);
588 589
	if (PTR_ERR(gss_msg) == -EAGAIN) {
		err = wait_event_interruptible_timeout(pipe_version_waitqueue,
590 591
				sn->pipe_version >= 0, timeout);
		if (sn->pipe_version < 0) {
592 593
			if (err == 0)
				sn->gssd_running = 0;
594 595 596
			warn_gssd();
			err = -EACCES;
		}
597
		if (err < 0)
598 599 600
			goto out;
		goto retry;
	}
L
Linus Torvalds 已提交
601 602 603 604
	if (IS_ERR(gss_msg)) {
		err = PTR_ERR(gss_msg);
		goto out;
	}
605
	pipe = gss_msg->pipe;
L
Linus Torvalds 已提交
606
	for (;;) {
607
		prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE);
608
		spin_lock(&pipe->lock);
L
Linus Torvalds 已提交
609 610 611
		if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
			break;
		}
612
		spin_unlock(&pipe->lock);
613
		if (fatal_signal_pending(current)) {
L
Linus Torvalds 已提交
614 615 616 617 618 619
			err = -ERESTARTSYS;
			goto out_intr;
		}
		schedule();
	}
	if (gss_msg->ctx)
620
		gss_cred_set_ctx(cred, gss_msg->ctx);
L
Linus Torvalds 已提交
621 622
	else
		err = gss_msg->msg.errno;
623
	spin_unlock(&pipe->lock);
L
Linus Torvalds 已提交
624 625 626 627
out_intr:
	finish_wait(&gss_msg->waitqueue, &wait);
	gss_release_msg(gss_msg);
out:
628
	dprintk("RPC:       %s for uid %u result %d\n",
629
		__func__, from_kuid(&init_user_ns, cred->cr_uid), err);
L
Linus Torvalds 已提交
630 631 632 633 634 635 636 637 638 639 640
	return err;
}

#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;
	struct gss_upcall_msg *gss_msg;
A
Al Viro 已提交
641
	struct rpc_pipe *pipe = RPC_I(file_inode(filp))->pipe;
L
Linus Torvalds 已提交
642
	struct gss_cl_ctx *ctx;
643 644
	uid_t id;
	kuid_t uid;
645
	ssize_t err = -EFBIG;
L
Linus Torvalds 已提交
646 647 648 649

	if (mlen > MSG_BUF_MAXSIZE)
		goto out;
	err = -ENOMEM;
650
	buf = kmalloc(mlen, GFP_NOFS);
L
Linus Torvalds 已提交
651 652 653 654 655 656 657 658
	if (!buf)
		goto out;

	err = -EFAULT;
	if (copy_from_user(buf, src, mlen))
		goto err;

	end = (const void *)((char *)buf + mlen);
659
	p = simple_get_bytes(buf, end, &id, sizeof(id));
L
Linus Torvalds 已提交
660 661 662 663 664
	if (IS_ERR(p)) {
		err = PTR_ERR(p);
		goto err;
	}

665 666 667 668 669 670
	uid = make_kuid(&init_user_ns, id);
	if (!uid_valid(uid)) {
		err = -EINVAL;
		goto err;
	}

L
Linus Torvalds 已提交
671 672 673 674
	err = -ENOMEM;
	ctx = gss_alloc_context();
	if (ctx == NULL)
		goto err;
675 676 677

	err = -ENOENT;
	/* Find a matching upcall */
678 679
	spin_lock(&pipe->lock);
	gss_msg = __gss_find_upcall(pipe, uid);
680
	if (gss_msg == NULL) {
681
		spin_unlock(&pipe->lock);
682 683 684
		goto err_put_ctx;
	}
	list_del_init(&gss_msg->list);
685
	spin_unlock(&pipe->lock);
686

687
	p = gss_fill_context(p, end, ctx, gss_msg->auth->mech);
L
Linus Torvalds 已提交
688 689
	if (IS_ERR(p)) {
		err = PTR_ERR(p);
690 691
		switch (err) {
		case -EACCES:
692
		case -EKEYEXPIRED:
693 694 695 696 697 698 699 700 701 702 703
			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 "
R
Randy Dunlap 已提交
704
				"gss_fill_context: %zd\n", __func__, err);
705 706
			BUG();
		}
707
		goto err_release_msg;
L
Linus Torvalds 已提交
708
	}
709 710 711 712
	gss_msg->ctx = gss_get_ctx(ctx);
	err = mlen;

err_release_msg:
713
	spin_lock(&pipe->lock);
714
	__gss_unhash_msg(gss_msg);
715
	spin_unlock(&pipe->lock);
716
	gss_release_msg(gss_msg);
L
Linus Torvalds 已提交
717 718 719 720 721
err_put_ctx:
	gss_put_ctx(ctx);
err:
	kfree(buf);
out:
722
	dprintk("RPC:       %s returning %Zd\n", __func__, err);
L
Linus Torvalds 已提交
723 724 725
	return err;
}

\
\"J. Bruce Fields\ 已提交
726
static int gss_pipe_open(struct inode *inode, int new_version)
727
{
728 729
	struct net *net = inode->i_sb->s_fs_info;
	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
\
\"J. Bruce Fields\ 已提交
730 731
	int ret = 0;

732
	spin_lock(&pipe_version_lock);
733
	if (sn->pipe_version < 0) {
\
\"J. Bruce Fields\ 已提交
734
		/* First open of any gss pipe determines the version: */
735
		sn->pipe_version = new_version;
736 737
		rpc_wake_up(&pipe_version_rpc_waitqueue);
		wake_up(&pipe_version_waitqueue);
738
	} else if (sn->pipe_version != new_version) {
\
\"J. Bruce Fields\ 已提交
739 740 741
		/* Trying to open a pipe of a different version */
		ret = -EBUSY;
		goto out;
742
	}
743
	atomic_inc(&sn->pipe_users);
\
\"J. Bruce Fields\ 已提交
744
out:
745
	spin_unlock(&pipe_version_lock);
\
\"J. Bruce Fields\ 已提交
746 747 748 749 750 751 752 753 754 755 756 757
	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);
758 759
}

L
Linus Torvalds 已提交
760 761 762
static void
gss_pipe_release(struct inode *inode)
{
763
	struct net *net = inode->i_sb->s_fs_info;
764
	struct rpc_pipe *pipe = RPC_I(inode)->pipe;
765
	struct gss_upcall_msg *gss_msg;
L
Linus Torvalds 已提交
766

767
restart:
768 769
	spin_lock(&pipe->lock);
	list_for_each_entry(gss_msg, &pipe->in_downcall, list) {
L
Linus Torvalds 已提交
770

771 772
		if (!list_empty(&gss_msg->msg.list))
			continue;
L
Linus Torvalds 已提交
773 774 775
		gss_msg->msg.errno = -EPIPE;
		atomic_inc(&gss_msg->count);
		__gss_unhash_msg(gss_msg);
776
		spin_unlock(&pipe->lock);
L
Linus Torvalds 已提交
777
		gss_release_msg(gss_msg);
778
		goto restart;
L
Linus Torvalds 已提交
779
	}
780
	spin_unlock(&pipe->lock);
781

782
	put_pipe_version(net);
L
Linus Torvalds 已提交
783 784 785 786 787 788 789 790
}

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);

	if (msg->errno < 0) {
791 792
		dprintk("RPC:       %s releasing msg %p\n",
			__func__, gss_msg);
L
Linus Torvalds 已提交
793 794
		atomic_inc(&gss_msg->count);
		gss_unhash_msg(gss_msg);
795 796
		if (msg->errno == -ETIMEDOUT)
			warn_gssd();
L
Linus Torvalds 已提交
797 798 799 800
		gss_release_msg(gss_msg);
	}
}

801 802
static void gss_pipe_dentry_destroy(struct dentry *dir,
		struct rpc_pipe_dir_object *pdo)
803
{
804 805
	struct gss_pipe *gss_pipe = pdo->pdo_data;
	struct rpc_pipe *pipe = gss_pipe->pipe;
806

807 808 809
	if (pipe->dentry != NULL) {
		rpc_unlink(pipe->dentry);
		pipe->dentry = NULL;
810
	}
811 812
}

813 814
static int gss_pipe_dentry_create(struct dentry *dir,
		struct rpc_pipe_dir_object *pdo)
815
{
816
	struct gss_pipe *p = pdo->pdo_data;
817
	struct dentry *dentry;
818

819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
	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)
{
	struct net *net = rpc_net_ns(clnt);
	struct gss_pipe *p;
	int err = -ENOMEM;
838

839 840
	p = kmalloc(sizeof(*p), GFP_KERNEL);
	if (p == NULL)
841
		goto err;
842 843 844 845
	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;
846
	}
847 848 849 850 851 852 853 854 855 856 857
	p->name = name;
	p->clnt = clnt;
	rpc_init_pipe_dir_object(&p->pdo,
			&gss_pipe_dir_object_ops,
			p);
	err = rpc_add_pipe_dir_object(net, &clnt->cl_pipedir_objects, &p->pdo);
	if (!err)
		return p;
	rpc_destroy_pipe_data(p->pipe);
err_free_gss_pipe:
	kfree(p);
858
err:
859
	return ERR_PTR(err);
860 861
}

862
static void __gss_pipe_free(struct gss_pipe *p)
863
{
864 865
	struct rpc_clnt *clnt = p->clnt;
	struct net *net = rpc_net_ns(clnt);
866

867 868 869 870 871
	rpc_remove_pipe_dir_object(net,
			&clnt->cl_pipedir_objects,
			&p->pdo);
	rpc_destroy_pipe_data(p->pipe);
	kfree(p);
872 873
}

874
static void gss_pipe_free(struct gss_pipe *p)
875
{
876 877
	if (p != NULL)
		__gss_pipe_free(p);
878 879
}

880 881
/*
 * NOTE: we have the opportunity to use different
L
Linus Torvalds 已提交
882 883 884
 * parameters based on the input flavor (which must be a pseudoflavor)
 */
static struct rpc_auth *
885
gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
L
Linus Torvalds 已提交
886
{
887
	rpc_authflavor_t flavor = args->pseudoflavor;
L
Linus Torvalds 已提交
888
	struct gss_auth *gss_auth;
889
	struct gss_pipe *gss_pipe;
L
Linus Torvalds 已提交
890
	struct rpc_auth * auth;
891
	int err = -ENOMEM; /* XXX? */
L
Linus Torvalds 已提交
892

893
	dprintk("RPC:       creating GSS authenticator for client %p\n", clnt);
L
Linus Torvalds 已提交
894 895

	if (!try_module_get(THIS_MODULE))
896
		return ERR_PTR(err);
L
Linus Torvalds 已提交
897 898
	if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL)))
		goto out_dec;
899
	gss_auth->target_name = NULL;
900 901
	if (args->target_name) {
		gss_auth->target_name = kstrdup(args->target_name, GFP_KERNEL);
902 903 904
		if (gss_auth->target_name == NULL)
			goto err_free;
	}
L
Linus Torvalds 已提交
905
	gss_auth->client = clnt;
T
Trond Myklebust 已提交
906
	gss_auth->net = get_net(rpc_net_ns(clnt));
907
	err = -EINVAL;
L
Linus Torvalds 已提交
908 909
	gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
	if (!gss_auth->mech) {
910
		dprintk("RPC:       Pseudoflavor %d not found!\n", flavor);
T
Trond Myklebust 已提交
911
		goto err_put_net;
L
Linus Torvalds 已提交
912 913
	}
	gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
914 915
	if (gss_auth->service == 0)
		goto err_put_mech;
L
Linus Torvalds 已提交
916 917 918 919 920 921
	auth = &gss_auth->rpc_auth;
	auth->au_cslack = GSS_CRED_SLACK >> 2;
	auth->au_rslack = GSS_VERF_SLACK >> 2;
	auth->au_ops = &authgss_ops;
	auth->au_flavor = flavor;
	atomic_set(&auth->au_count, 1);
922
	kref_init(&gss_auth->kref);
L
Linus Torvalds 已提交
923

924 925 926
	err = rpcauth_init_credcache(auth);
	if (err)
		goto err_put_mech;
\
\"J. Bruce Fields\ 已提交
927 928 929 930 931 932
	/*
	 * 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.
	 */
933 934 935 936
	gss_pipe = gss_pipe_alloc(clnt, "gssd", &gss_upcall_ops_v1);
	if (IS_ERR(gss_pipe)) {
		err = PTR_ERR(gss_pipe);
		goto err_destroy_credcache;
937
	}
938
	gss_auth->gss_pipe[1] = gss_pipe;
L
Linus Torvalds 已提交
939

940 941 942 943
	gss_pipe = gss_pipe_alloc(clnt, gss_auth->mech->gm_name,
			&gss_upcall_ops_v0);
	if (IS_ERR(gss_pipe)) {
		err = PTR_ERR(gss_pipe);
944 945
		goto err_destroy_pipe_1;
	}
946
	gss_auth->gss_pipe[0] = gss_pipe;
947

L
Linus Torvalds 已提交
948
	return auth;
949
err_destroy_pipe_1:
950 951 952
	__gss_pipe_free(gss_auth->gss_pipe[1]);
err_destroy_credcache:
	rpcauth_destroy_credcache(auth);
L
Linus Torvalds 已提交
953 954
err_put_mech:
	gss_mech_put(gss_auth->mech);
T
Trond Myklebust 已提交
955 956
err_put_net:
	put_net(gss_auth->net);
L
Linus Torvalds 已提交
957
err_free:
958
	kfree(gss_auth->target_name);
L
Linus Torvalds 已提交
959 960 961
	kfree(gss_auth);
out_dec:
	module_put(THIS_MODULE);
962
	return ERR_PTR(err);
L
Linus Torvalds 已提交
963 964
}

965 966 967
static void
gss_free(struct gss_auth *gss_auth)
{
968 969
	gss_pipe_free(gss_auth->gss_pipe[0]);
	gss_pipe_free(gss_auth->gss_pipe[1]);
970
	gss_mech_put(gss_auth->mech);
T
Trond Myklebust 已提交
971
	put_net(gss_auth->net);
972
	kfree(gss_auth->target_name);
973 974 975 976 977 978 979 980 981 982 983 984 985

	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);
}

L
Linus Torvalds 已提交
986 987 988
static void
gss_destroy(struct rpc_auth *auth)
{
989 990
	struct gss_auth *gss_auth = container_of(auth,
			struct gss_auth, rpc_auth);
L
Linus Torvalds 已提交
991

992 993
	dprintk("RPC:       destroying GSS authenticator %p flavor %d\n",
			auth, auth->au_flavor);
L
Linus Torvalds 已提交
994

995 996 997 998
	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;
999 1000
	rpcauth_destroy_credcache(auth);

1001
	kref_put(&gss_auth->kref, gss_free_callback);
L
Linus Torvalds 已提交
1002 1003
}

1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
/*
 * 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);
	struct rpc_task *task;

	if (gss_cred->gc_ctx == NULL ||
1018
	    test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
1019 1020 1021 1022 1023 1024 1025 1026 1027
		return 0;

	gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY;
	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);

1028
	task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT);
1029 1030 1031 1032 1033 1034 1035 1036
	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
L
Linus Torvalds 已提交
1037 1038 1039
 * to create a new cred or context, so they check that things have been
 * allocated before freeing them. */
static void
1040
gss_do_free_ctx(struct gss_cl_ctx *ctx)
L
Linus Torvalds 已提交
1041
{
1042
	dprintk("RPC:       %s\n", __func__);
L
Linus Torvalds 已提交
1043

1044
	gss_delete_sec_context(&ctx->gc_gss_ctx);
L
Linus Torvalds 已提交
1045 1046 1047 1048
	kfree(ctx->gc_wire_ctx.data);
	kfree(ctx);
}

1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
static void
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);
}

L
Linus Torvalds 已提交
1062
static void
1063
gss_free_cred(struct gss_cred *gss_cred)
L
Linus Torvalds 已提交
1064
{
1065
	dprintk("RPC:       %s cred=%p\n", __func__, gss_cred);
1066 1067
	kfree(gss_cred);
}
L
Linus Torvalds 已提交
1068

1069 1070 1071 1072 1073 1074
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);
}
L
Linus Torvalds 已提交
1075

1076
static void
1077
gss_destroy_nullcred(struct rpc_cred *cred)
1078
{
1079
	struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
1080
	struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
1081 1082
	struct gss_cl_ctx *ctx = gss_cred->gc_ctx;

1083
	RCU_INIT_POINTER(gss_cred->gc_ctx, NULL);
1084
	call_rcu(&cred->cr_rcu, gss_free_cred_callback);
1085 1086
	if (ctx)
		gss_put_ctx(ctx);
1087
	kref_put(&gss_auth->kref, gss_free_callback);
L
Linus Torvalds 已提交
1088 1089
}

1090 1091 1092 1093 1094 1095 1096 1097 1098
static void
gss_destroy_cred(struct rpc_cred *cred)
{

	if (gss_destroying_context(cred))
		return;
	gss_destroy_nullcred(cred);
}

L
Linus Torvalds 已提交
1099 1100 1101 1102
/*
 * Lookup RPCSEC_GSS cred for the current process
 */
static struct rpc_cred *
1103
gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
L
Linus Torvalds 已提交
1104
{
1105
	return rpcauth_lookup_credcache(auth, acred, flags);
L
Linus Torvalds 已提交
1106 1107 1108
}

static struct rpc_cred *
1109
gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
L
Linus Torvalds 已提交
1110 1111 1112 1113 1114
{
	struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
	struct gss_cred	*cred = NULL;
	int err = -ENOMEM;

1115
	dprintk("RPC:       %s for uid %d, flavor %d\n",
1116 1117
		__func__, from_kuid(&init_user_ns, acred->uid),
		auth->au_flavor);
L
Linus Torvalds 已提交
1118

1119
	if (!(cred = kzalloc(sizeof(*cred), GFP_NOFS)))
L
Linus Torvalds 已提交
1120 1121
		goto out_err;

1122
	rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops);
L
Linus Torvalds 已提交
1123 1124 1125 1126
	/*
	 * Note: in order to force a call to call_refresh(), we deliberately
	 * fail to flag the credential as RPCAUTH_CRED_UPTODATE.
	 */
1127
	cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW;
L
Linus Torvalds 已提交
1128
	cred->gc_service = gss_auth->service;
1129 1130 1131
	cred->gc_principal = NULL;
	if (acred->machine_cred)
		cred->gc_principal = acred->principal;
1132
	kref_get(&gss_auth->kref);
L
Linus Torvalds 已提交
1133 1134 1135
	return &cred->gc_base;

out_err:
1136
	dprintk("RPC:       %s failed with error %d\n", __func__, err);
L
Linus Torvalds 已提交
1137 1138 1139
	return ERR_PTR(err);
}

1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
static int
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;
}

L
Linus Torvalds 已提交
1153
static int
1154
gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
L
Linus Torvalds 已提交
1155 1156 1157
{
	struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);

1158
	if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
1159
		goto out;
L
Linus Torvalds 已提交
1160
	/* Don't match with creds that have expired. */
1161 1162 1163
	if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
		return 0;
	if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
L
Linus Torvalds 已提交
1164
		return 0;
1165
out:
1166 1167 1168 1169 1170 1171
	if (acred->principal != NULL) {
		if (gss_cred->gc_principal == NULL)
			return 0;
		return strcmp(acred->principal, gss_cred->gc_principal) == 0;
	}
	if (gss_cred->gc_principal != NULL)
1172
		return 0;
1173
	return uid_eq(rc->cr_uid, acred->uid);
L
Linus Torvalds 已提交
1174 1175 1176 1177 1178 1179
}

/*
* Marshal credentials.
* Maybe we should keep a cached credential for performance reasons.
*/
1180 1181
static __be32 *
gss_marshal(struct rpc_task *task, __be32 *p)
L
Linus Torvalds 已提交
1182
{
1183 1184
	struct rpc_rqst *req = task->tk_rqstp;
	struct rpc_cred *cred = req->rq_cred;
L
Linus Torvalds 已提交
1185 1186 1187
	struct gss_cred	*gss_cred = container_of(cred, struct gss_cred,
						 gc_base);
	struct gss_cl_ctx	*ctx = gss_cred_get_ctx(cred);
1188
	__be32		*cred_len;
L
Linus Torvalds 已提交
1189 1190 1191 1192 1193
	u32             maj_stat = 0;
	struct xdr_netobj mic;
	struct kvec	iov;
	struct xdr_buf	verf_buf;

1194
	dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
L
Linus Torvalds 已提交
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211

	*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: */
1212
	iov.iov_base = xprt_skip_transport_header(req->rq_xprt,
1213
					req->rq_snd_buf.head[0].iov_base);
L
Linus Torvalds 已提交
1214 1215 1216 1217 1218 1219 1220
	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);
1221
	maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
L
Linus Torvalds 已提交
1222
	if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
1223
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
L
Linus Torvalds 已提交
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
	} else if (maj_stat != 0) {
		printk("gss_marshal: gss_get_mic FAILED (%d)\n", 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;
}

1236 1237
static int gss_renew_cred(struct rpc_task *task)
{
1238
	struct rpc_cred *oldcred = task->tk_rqstp->rq_cred;
1239 1240 1241 1242 1243 1244
	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,
1245 1246
		.principal = gss_cred->gc_principal,
		.machine_cred = (gss_cred->gc_principal != NULL ? 1 : 0),
1247 1248 1249 1250 1251 1252
	};
	struct rpc_cred *new;

	new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
	if (IS_ERR(new))
		return PTR_ERR(new);
1253
	task->tk_rqstp->rq_cred = new;
1254 1255 1256 1257
	put_rpccred(oldcred);
	return 0;
}

1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
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;
}

L
Linus Torvalds 已提交
1275 1276 1277 1278 1279 1280
/*
* Refresh credentials. XXX - finish
*/
static int
gss_refresh(struct rpc_task *task)
{
1281
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
1282 1283
	int ret = 0;

1284 1285 1286
	if (gss_cred_is_negative_entry(cred))
		return -EKEYEXPIRED;

1287 1288 1289 1290 1291
	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;
1292
		cred = task->tk_rqstp->rq_cred;
1293
	}
L
Linus Torvalds 已提交
1294

1295 1296 1297 1298
	if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
		ret = gss_refresh_upcall(task);
out:
	return ret;
L
Linus Torvalds 已提交
1299 1300
}

1301 1302 1303 1304 1305 1306 1307
/* Dummy refresh routine: used only when destroying the context */
static int
gss_refresh_null(struct rpc_task *task)
{
	return -EACCES;
}

1308 1309
static __be32 *
gss_validate(struct rpc_task *task, __be32 *p)
L
Linus Torvalds 已提交
1310
{
1311
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
L
Linus Torvalds 已提交
1312
	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
1313
	__be32		seq;
L
Linus Torvalds 已提交
1314 1315 1316 1317 1318 1319
	struct kvec	iov;
	struct xdr_buf	verf_buf;
	struct xdr_netobj mic;
	u32		flav,len;
	u32		maj_stat;

1320
	dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
L
Linus Torvalds 已提交
1321 1322 1323

	flav = ntohl(*p++);
	if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE)
1324
		goto out_bad;
L
Linus Torvalds 已提交
1325 1326 1327 1328 1329 1330 1331 1332 1333
	if (flav != RPC_AUTH_GSS)
		goto out_bad;
	seq = htonl(task->tk_rqstp->rq_seqno);
	iov.iov_base = &seq;
	iov.iov_len = sizeof(seq);
	xdr_buf_from_iov(&iov, &verf_buf);
	mic.data = (u8 *)p;
	mic.len = len;

1334
	maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
L
Linus Torvalds 已提交
1335
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
1336
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
1337
	if (maj_stat) {
1338 1339
		dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n",
			task->tk_pid, __func__, maj_stat);
L
Linus Torvalds 已提交
1340
		goto out_bad;
1341
	}
1342 1343
	/* We leave it to unwrap to calculate au_rslack. For now we just
	 * calculate the length of the verifier: */
1344
	cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2;
L
Linus Torvalds 已提交
1345
	gss_put_ctx(ctx);
1346 1347
	dprintk("RPC: %5u %s: gss_verify_mic succeeded.\n",
			task->tk_pid, __func__);
L
Linus Torvalds 已提交
1348 1349 1350
	return p + XDR_QUADLEN(len);
out_bad:
	gss_put_ctx(ctx);
1351
	dprintk("RPC: %5u %s failed.\n", task->tk_pid, __func__);
L
Linus Torvalds 已提交
1352 1353 1354
	return NULL;
}

1355 1356 1357 1358 1359 1360 1361 1362 1363
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);
}

L
Linus Torvalds 已提交
1364 1365
static inline int
gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
1366 1367
		   kxdreproc_t encode, struct rpc_rqst *rqstp,
		   __be32 *p, void *obj)
L
Linus Torvalds 已提交
1368 1369 1370
{
	struct xdr_buf	*snd_buf = &rqstp->rq_snd_buf;
	struct xdr_buf	integ_buf;
1371
	__be32          *integ_len = NULL;
L
Linus Torvalds 已提交
1372
	struct xdr_netobj mic;
1373 1374
	u32		offset;
	__be32		*q;
L
Linus Torvalds 已提交
1375 1376 1377 1378 1379 1380 1381 1382
	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);

1383
	gss_wrap_req_encode(encode, rqstp, p, obj);
L
Linus Torvalds 已提交
1384 1385 1386 1387 1388 1389 1390

	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: */
1391
	if (snd_buf->page_len || snd_buf->tail[0].iov_len)
L
Linus Torvalds 已提交
1392 1393 1394 1395 1396 1397
		iov = snd_buf->tail;
	else
		iov = snd_buf->head;
	p = iov->iov_base + iov->iov_len;
	mic.data = (u8 *)(p + 1);

1398
	maj_stat = gss_get_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
L
Linus Torvalds 已提交
1399 1400
	status = -EIO; /* XXX? */
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
1401
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
L
Linus Torvalds 已提交
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
	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;
}

1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
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;
	}

	first = snd_buf->page_base >> PAGE_CACHE_SHIFT;
	last = (snd_buf->page_base + snd_buf->page_len - 1) >> PAGE_CACHE_SHIFT;
	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:
1449 1450
	rqstp->rq_enc_pages_num = i;
	priv_release_snd_buf(rqstp);
1451 1452 1453 1454 1455 1456
out:
	return -EAGAIN;
}

static inline int
gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
1457 1458
		  kxdreproc_t encode, struct rpc_rqst *rqstp,
		  __be32 *p, void *obj)
1459 1460 1461 1462 1463
{
	struct xdr_buf	*snd_buf = &rqstp->rq_snd_buf;
	u32		offset;
	u32             maj_stat;
	int		status;
1464
	__be32		*opaque_len;
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
	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);

1475
	gss_wrap_req_encode(encode, rqstp, p, obj);
1476 1477 1478 1479 1480 1481 1482 1483

	status = alloc_enc_pages(rqstp);
	if (status)
		return status;
	first = snd_buf->page_base >> PAGE_CACHE_SHIFT;
	inpages = snd_buf->pages + first;
	snd_buf->pages = rqstp->rq_enc_pages;
	snd_buf->page_base -= first << PAGE_CACHE_SHIFT;
1484 1485 1486 1487 1488 1489 1490 1491
	/*
	 * 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.
	 */
1492 1493 1494 1495 1496
	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;
	}
1497
	maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
1498
	/* slack space should prevent this ever happening: */
1499
	BUG_ON(snd_buf->len > snd_buf->buflen);
1500
	status = -EIO;
1501 1502 1503
	/* 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)
1504
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
	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;
}

L
Linus Torvalds 已提交
1523 1524
static int
gss_wrap_req(struct rpc_task *task,
1525
	     kxdreproc_t encode, void *rqstp, __be32 *p, void *obj)
L
Linus Torvalds 已提交
1526
{
1527
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
L
Linus Torvalds 已提交
1528 1529 1530 1531 1532
	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;

1533
	dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
L
Linus Torvalds 已提交
1534 1535 1536 1537
	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.
		 */
1538 1539
		gss_wrap_req_encode(encode, rqstp, p, obj);
		status = 0;
L
Linus Torvalds 已提交
1540 1541 1542
		goto out;
	}
	switch (gss_cred->gc_service) {
J
Joe Perches 已提交
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
	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;
L
Linus Torvalds 已提交
1553 1554 1555
	}
out:
	gss_put_ctx(ctx);
1556
	dprintk("RPC: %5u %s returning %d\n", task->tk_pid, __func__, status);
L
Linus Torvalds 已提交
1557 1558 1559 1560 1561
	return status;
}

static inline int
gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
1562
		struct rpc_rqst *rqstp, __be32 **p)
L
Linus Torvalds 已提交
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
{
	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;

1589
	maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
L
Linus Torvalds 已提交
1590
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
1591
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
L
Linus Torvalds 已提交
1592 1593 1594 1595 1596
	if (maj_stat != GSS_S_COMPLETE)
		return status;
	return 0;
}

1597 1598
static inline int
gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
1599
		struct rpc_rqst *rqstp, __be32 **p)
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
{
	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;

1614
	maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf);
1615
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
1616
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
1617 1618 1619 1620 1621 1622 1623 1624
	if (maj_stat != GSS_S_COMPLETE)
		return status;
	if (ntohl(*(*p)++) != rqstp->rq_seqno)
		return status;

	return 0;
}

1625 1626 1627 1628 1629 1630 1631 1632 1633
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);
}
1634

L
Linus Torvalds 已提交
1635 1636
static int
gss_unwrap_resp(struct rpc_task *task,
1637
		kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj)
L
Linus Torvalds 已提交
1638
{
1639
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
L
Linus Torvalds 已提交
1640 1641 1642
	struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
			gc_base);
	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
1643
	__be32		*savedp = p;
1644 1645
	struct kvec	*head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
	int		savedlen = head->iov_len;
L
Linus Torvalds 已提交
1646 1647 1648 1649 1650
	int             status = -EIO;

	if (ctx->gc_proc != RPC_GSS_PROC_DATA)
		goto out_decode;
	switch (gss_cred->gc_service) {
J
Joe Perches 已提交
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
	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;
L
Linus Torvalds 已提交
1663
	}
1664
	/* take into account extra slack for integrity and privacy cases: */
1665
	cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp)
1666
						+ (savedlen - head->iov_len);
L
Linus Torvalds 已提交
1667
out_decode:
1668
	status = gss_unwrap_req_decode(decode, rqstp, p, obj);
L
Linus Torvalds 已提交
1669 1670
out:
	gss_put_ctx(ctx);
1671 1672
	dprintk("RPC: %5u %s returning %d\n",
		task->tk_pid, __func__, status);
L
Linus Torvalds 已提交
1673 1674
	return status;
}
1675

1676
static const struct rpc_authops authgss_ops = {
L
Linus Torvalds 已提交
1677 1678 1679 1680 1681 1682
	.owner		= THIS_MODULE,
	.au_flavor	= RPC_AUTH_GSS,
	.au_name	= "RPCSEC_GSS",
	.create		= gss_create,
	.destroy	= gss_destroy,
	.lookup_cred	= gss_lookup_cred,
1683
	.crcreate	= gss_create_cred,
C
Chuck Lever 已提交
1684
	.list_pseudoflavors = gss_mech_list_pseudoflavors,
1685
	.info2flavor	= gss_mech_info2flavor,
1686
	.flavor2info	= gss_mech_flavor2info,
L
Linus Torvalds 已提交
1687 1688
};

1689
static const struct rpc_credops gss_credops = {
L
Linus Torvalds 已提交
1690 1691
	.cr_name	= "AUTH_GSS",
	.crdestroy	= gss_destroy_cred,
1692
	.cr_init	= gss_cred_init,
1693
	.crbind		= rpcauth_generic_bind_cred,
L
Linus Torvalds 已提交
1694 1695 1696 1697 1698 1699 1700 1701
	.crmatch	= gss_match,
	.crmarshal	= gss_marshal,
	.crrefresh	= gss_refresh,
	.crvalidate	= gss_validate,
	.crwrap_req	= gss_wrap_req,
	.crunwrap_resp	= gss_unwrap_resp,
};

1702 1703
static const struct rpc_credops gss_nullops = {
	.cr_name	= "AUTH_GSS",
1704
	.crdestroy	= gss_destroy_nullcred,
1705
	.crbind		= rpcauth_generic_bind_cred,
1706 1707 1708 1709 1710 1711 1712 1713
	.crmatch	= gss_match,
	.crmarshal	= gss_marshal,
	.crrefresh	= gss_refresh_null,
	.crvalidate	= gss_validate,
	.crwrap_req	= gss_wrap_req,
	.crunwrap_resp	= gss_unwrap_resp,
};

1714
static const struct rpc_pipe_ops gss_upcall_ops_v0 = {
1715
	.upcall		= rpc_pipe_generic_upcall,
\
\"J. Bruce Fields\ 已提交
1716 1717 1718 1719 1720 1721
	.downcall	= gss_pipe_downcall,
	.destroy_msg	= gss_pipe_destroy_msg,
	.open_pipe	= gss_pipe_open_v0,
	.release_pipe	= gss_pipe_release,
};

1722
static const struct rpc_pipe_ops gss_upcall_ops_v1 = {
1723
	.upcall		= rpc_pipe_generic_upcall,
L
Linus Torvalds 已提交
1724 1725
	.downcall	= gss_pipe_downcall,
	.destroy_msg	= gss_pipe_destroy_msg,
\
\"J. Bruce Fields\ 已提交
1726
	.open_pipe	= gss_pipe_open_v1,
L
Linus Torvalds 已提交
1727 1728 1729
	.release_pipe	= gss_pipe_release,
};

1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744
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,
};

L
Linus Torvalds 已提交
1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
/*
 * 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;
1758 1759 1760
	err = register_pernet_subsys(&rpcsec_gss_net_ops);
	if (err)
		goto out_svc_exit;
1761
	rpc_init_wait_queue(&pipe_version_rpc_waitqueue, "gss pipe version");
L
Linus Torvalds 已提交
1762
	return 0;
1763 1764
out_svc_exit:
	gss_svc_shutdown();
L
Linus Torvalds 已提交
1765 1766 1767 1768 1769 1770 1771 1772
out_unregister:
	rpcauth_unregister(&authgss_ops);
out:
	return err;
}

static void __exit exit_rpcsec_gss(void)
{
1773
	unregister_pernet_subsys(&rpcsec_gss_net_ops);
L
Linus Torvalds 已提交
1774 1775
	gss_svc_shutdown();
	rpcauth_unregister(&authgss_ops);
1776
	rcu_barrier(); /* Wait for completion of call_rcu()'s */
L
Linus Torvalds 已提交
1777 1778
}

1779
MODULE_ALIAS("rpc-auth-6");
L
Linus Torvalds 已提交
1780
MODULE_LICENSE("GPL");
1781 1782 1783 1784 1785 1786
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");

L
Linus Torvalds 已提交
1787 1788
module_init(init_rpcsec_gss)
module_exit(exit_rpcsec_gss)