1/*
2 * Copyright (c) 2007-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*************
30 * These functions implement RPCSEC_GSS security for the NFS client and server.
31 * The code is specific to the use of Kerberos v5 and the use of DES MAC MD5
32 * protection as described in Internet RFC 2203 and 2623.
33 *
34 * In contrast to the original AUTH_SYS authentication, RPCSEC_GSS is stateful.
35 * It requires the client and server negotiate a secure connection as part of a
36 * security context. The context state is maintained in client and server structures.
37 * On the client side, each user of an NFS mount is assigned their own context,
38 * identified by UID, on their first use of the mount, and it persists until the
39 * unmount or until the context is renewed.  Each user context has a corresponding
40 * server context which the server maintains until the client destroys it, or
41 * until the context expires.
42 *
43 * The client and server contexts are set up dynamically.  When a user attempts
44 * to send an NFS request, if there is no context for the user, then one is
45 * set up via an exchange of NFS null procedure calls as described in RFC 2203.
46 * During this exchange, the client and server pass a security token that is
47 * forwarded via Mach upcall to the gssd, which invokes the GSS-API to authenticate
48 * the user to the server (and vice-versa). The client and server also receive
49 * a unique session key that can be used to digitally sign the credentials and
50 * verifier or optionally to provide data integrity and/or privacy.
51 *
52 * Once the context is complete, the client and server enter a normal data
53 * exchange phase - beginning with the NFS request that prompted the context
54 * creation. During this phase, the client's RPC header contains an RPCSEC_GSS
55 * credential and verifier, and the server returns a verifier as well.
56 * For simple authentication, the verifier contains a signed checksum of the
57 * RPC header, including the credential.  The server's verifier has a signed
58 * checksum of the current sequence number.
59 *
60 * Each client call contains a sequence number that nominally increases by one
61 * on each request.  The sequence number is intended to prevent replay attacks.
62 * Since the protocol can be used over UDP, there is some allowance for
63 * out-of-sequence requests, so the server checks whether the sequence numbers
64 * are within a sequence "window". If a sequence number is outside the lower
65 * bound of the window, the server silently drops the request. This has some
66 * implications for retransmission. If a request needs to be retransmitted, the
67 * client must bump the sequence number even if the request XID is unchanged.
68 *
69 * When the NFS mount is unmounted, the client sends a "destroy" credential
70 * to delete the server's context for each user of the mount. Since it's
71 * possible for the client to crash or disconnect without sending the destroy
72 * message, the server has a thread that reaps contexts that have been idle
73 * too long.
74 */
75
76#include <stdint.h>
77#include <sys/param.h>
78#include <sys/systm.h>
79#include <sys/proc.h>
80#include <sys/kauth.h>
81#include <sys/kernel.h>
82#include <sys/mount_internal.h>
83#include <sys/vnode.h>
84#include <sys/ubc.h>
85#include <sys/malloc.h>
86#include <sys/kpi_mbuf.h>
87
88#include <kern/host.h>
89#include <libkern/libkern.h>
90
91#include <mach/task.h>
92#include <mach/host_special_ports.h>
93#include <mach/host_priv.h>
94#include <mach/thread_act.h>
95#include <mach/mig_errors.h>
96#include <mach/vm_map.h>
97#include <vm/vm_map.h>
98#include <vm/vm_kern.h>
99#include <gssd/gssd_mach.h>
100
101#include <nfs/rpcv2.h>
102#include <nfs/nfsproto.h>
103#include <nfs/nfs.h>
104#include <nfs/nfsnode.h>
105#include <nfs/nfs_gss.h>
106#include <nfs/nfsmount.h>
107#include <nfs/xdr_subs.h>
108#include <nfs/nfsm_subs.h>
109#include <nfs/nfs_gss.h>
110
111#include "nfs_gss_crypto.h"
112
113#define NFS_GSS_MACH_MAX_RETRIES 3
114
115typedef struct {
116	int type;
117	union {
118		MD5_DESCBC_CTX m_ctx;
119		HMAC_SHA1_DES3KD_CTX h_ctx;
120	};
121} GSS_DIGEST_CTX;
122
123#define MAX_DIGEST SHA_DIGEST_LENGTH
124#ifdef NFS_KERNEL_DEBUG
125#define HASHLEN(ki)  (((ki)->hash_len > MAX_DIGEST) ? \
126		(panic("nfs_gss.c:%d ki->hash_len is invalid = %d\n", __LINE__, (ki)->hash_len), MAX_DIGEST) : (ki)->hash_len)
127#else
128#define HASHLEN(ki)  (((ki)->hash_len > MAX_DIGEST) ? \
129		(printf("nfs_gss.c:%d ki->hash_len is invalid = %d\n", __LINE__, (ki)->hash_len), MAX_DIGEST) : (ki)->hash_len)
130#endif
131
132#if NFSSERVER
133u_long nfs_gss_svc_ctx_hash;
134struct nfs_gss_svc_ctx_hashhead *nfs_gss_svc_ctx_hashtbl;
135lck_mtx_t *nfs_gss_svc_ctx_mutex;
136lck_grp_t *nfs_gss_svc_grp;
137uint32_t nfsrv_gss_context_ttl = GSS_CTX_EXPIRE;
138#define GSS_SVC_CTX_TTL ((uint64_t)max(2*GSS_CTX_PEND, nfsrv_gss_context_ttl) * NSEC_PER_SEC)
139#endif /* NFSSERVER */
140
141#if NFSCLIENT
142lck_grp_t *nfs_gss_clnt_grp;
143int nfs_single_des;
144#endif /* NFSCLIENT */
145
146/*
147 * These octet strings are used to encode/decode ASN.1 tokens
148 * in the RPCSEC_GSS verifiers.
149 */
150static u_char krb5_tokhead[] __attribute__((unused)) = { 0x60, 0x23 };
151       u_char krb5_mech[11] = { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02 };
152static u_char krb5_mic[]  = { 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff };
153static u_char krb5_mic3[]  = { 0x01, 0x01, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff };
154static u_char krb5_wrap[] = { 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
155static u_char krb5_wrap3[] = { 0x02, 0x01, 0x04, 0x00, 0x02, 0x00, 0xff, 0xff };
156static u_char iv0[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // DES MAC Initialization Vector
157
158#define ALG_MIC(ki) (((ki)->type == NFS_GSS_1DES) ? krb5_mic : krb5_mic3)
159#define ALG_WRAP(ki) (((ki)->type == NFS_GSS_1DES) ? krb5_wrap : krb5_wrap3)
160
161/*
162 * The size of the Kerberos v5 ASN.1 token
163 * in the verifier.
164 *
165 * Note that the second octet of the krb5_tokhead (0x23) is a
166 * DER-encoded size field that has variable length.  If the size
167 * is 128 bytes or greater, then it uses two bytes, three bytes
168 * if 65536 or greater, and so on.  Since the MIC tokens are
169 * separate from the data, the size is always the same: 35 bytes (0x23).
170 * However, the wrap token is different. Its size field includes the
171 * size of the token + the encrypted data that follows. So the size
172 * field may be two, three or four bytes.
173 */
174#define KRB5_SZ_TOKHEAD sizeof(krb5_tokhead)
175#define KRB5_SZ_MECH	sizeof(krb5_mech)
176#define KRB5_SZ_ALG	sizeof(krb5_mic) // 8 - same as krb5_wrap
177#define KRB5_SZ_SEQ	8
178#define KRB5_SZ_EXTRA	3  // a wrap token may be longer by up to this many octets
179#define KRB5_SZ_TOKEN_NOSUM	(KRB5_SZ_TOKHEAD + KRB5_SZ_MECH + KRB5_SZ_ALG + KRB5_SZ_SEQ)
180#define KRB5_SZ_TOKEN(cksumlen)		((cksumlen) + KRB5_SZ_TOKEN_NOSUM)
181#define KRB5_SZ_TOKMAX(cksumlen)	(KRB5_SZ_TOKEN(cksumlen) + KRB5_SZ_EXTRA)
182
183#if NFSCLIENT
184static int	nfs_gss_clnt_ctx_find(struct nfsreq *);
185static int	nfs_gss_clnt_ctx_failover(struct nfsreq *);
186static int	nfs_gss_clnt_ctx_init(struct nfsreq *, struct nfs_gss_clnt_ctx *);
187static int	nfs_gss_clnt_ctx_init_retry(struct nfsreq *, struct nfs_gss_clnt_ctx *);
188static int	nfs_gss_clnt_ctx_callserver(struct nfsreq *, struct nfs_gss_clnt_ctx *);
189static char	*nfs_gss_clnt_svcname(struct nfsmount *);
190static int	nfs_gss_clnt_gssd_upcall(struct nfsreq *, struct nfs_gss_clnt_ctx *);
191static void	nfs_gss_clnt_ctx_remove(struct nfsmount *, struct nfs_gss_clnt_ctx *);
192#endif /* NFSCLIENT */
193
194#if NFSSERVER
195static struct nfs_gss_svc_ctx *nfs_gss_svc_ctx_find(uint32_t);
196static void	nfs_gss_svc_ctx_insert(struct nfs_gss_svc_ctx *);
197static void	nfs_gss_svc_ctx_timer(void *, void *);
198static int	nfs_gss_svc_gssd_upcall(struct nfs_gss_svc_ctx *);
199static int	nfs_gss_svc_seqnum_valid(struct nfs_gss_svc_ctx *, uint32_t);
200#endif /* NFSSERVER */
201
202static void	host_release_special_port(mach_port_t);
203static mach_port_t host_copy_special_port(mach_port_t);
204static void	nfs_gss_mach_alloc_buffer(u_char *, uint32_t, vm_map_copy_t *);
205static int	nfs_gss_mach_vmcopyout(vm_map_copy_t, uint32_t, u_char *);
206static int	nfs_gss_token_get(gss_key_info *ki, u_char *, u_char *, int, uint32_t *, u_char *);
207static int	nfs_gss_token_put(gss_key_info *ki, u_char *, u_char *, int, int, u_char *);
208static int	nfs_gss_der_length_size(int);
209static void	nfs_gss_der_length_put(u_char **, int);
210static int	nfs_gss_der_length_get(u_char **);
211static int	nfs_gss_mchain_length(mbuf_t);
212static int	nfs_gss_append_chain(struct nfsm_chain *, mbuf_t);
213static void	nfs_gss_nfsm_chain(struct nfsm_chain *, mbuf_t);
214static void	nfs_gss_cksum_mchain(gss_key_info *, mbuf_t, u_char *, int, int, u_char *);
215static void	nfs_gss_cksum_chain(gss_key_info *, struct nfsm_chain *, u_char *, int, int, u_char *);
216static void	nfs_gss_cksum_rep(gss_key_info *, uint32_t, u_char *);
217static void	nfs_gss_encrypt_mchain(gss_key_info *, mbuf_t, int, int, int);
218static void	nfs_gss_encrypt_chain(gss_key_info *, struct nfsm_chain *, int, int, int);
219
220static void	gss_digest_Init(GSS_DIGEST_CTX *, gss_key_info *);
221static void	gss_digest_Update(GSS_DIGEST_CTX *, void *, size_t);
222static void	gss_digest_Final(GSS_DIGEST_CTX *, void *);
223static void	gss_des_crypt(gss_key_info *, des_cblock *, des_cblock *,
224				int32_t, des_cblock *, des_cblock *, int, int);
225static int	gss_key_init(gss_key_info *, uint32_t);
226
227#if NFSSERVER
228thread_call_t nfs_gss_svc_ctx_timer_call;
229int nfs_gss_timer_on = 0;
230uint32_t nfs_gss_ctx_count = 0;
231const uint32_t nfs_gss_ctx_max = GSS_SVC_MAXCONTEXTS;
232#endif /* NFSSERVER */
233
234/*
235 * Initialization when NFS starts
236 */
237void
238nfs_gss_init(void)
239{
240#if NFSCLIENT
241	nfs_gss_clnt_grp = lck_grp_alloc_init("rpcsec_gss_clnt", LCK_GRP_ATTR_NULL);
242#endif /* NFSCLIENT */
243
244#if NFSSERVER
245	nfs_gss_svc_grp  = lck_grp_alloc_init("rpcsec_gss_svc",  LCK_GRP_ATTR_NULL);
246
247	nfs_gss_svc_ctx_hashtbl = hashinit(SVC_CTX_HASHSZ, M_TEMP, &nfs_gss_svc_ctx_hash);
248	nfs_gss_svc_ctx_mutex = lck_mtx_alloc_init(nfs_gss_svc_grp, LCK_ATTR_NULL);
249
250	nfs_gss_svc_ctx_timer_call = thread_call_allocate(nfs_gss_svc_ctx_timer, NULL);
251#endif /* NFSSERVER */
252}
253
254#if NFSCLIENT
255
256/*
257 * Is it OK to fall back to using AUTH_SYS?
258 */
259static int
260nfs_gss_sysok(struct nfsreq *req)
261{
262	struct nfsmount *nmp = req->r_nmp;
263	int i;
264
265	if (req->r_wrongsec) /* Not OK if we're trying to handle a wrongsec error */
266		return (0);
267	if (!nmp->nm_sec.count) /* assume it's OK if we don't have a set of flavors */
268		return (1);
269	for (i=0; i < nmp->nm_sec.count; i++)
270		if (nmp->nm_sec.flavors[i] == RPCAUTH_SYS)
271			return (1);
272	return (0);
273}
274
275/*
276 * Find the context for a particular user.
277 *
278 * If the context doesn't already exist
279 * then create a new context for this user.
280 *
281 * Note that the code allows superuser (uid == 0)
282 * to adopt the context of another user.
283 */
284static int
285nfs_gss_clnt_ctx_find(struct nfsreq *req)
286{
287	struct nfsmount *nmp = req->r_nmp;
288	struct nfs_gss_clnt_ctx *cp;
289	uid_t uid = kauth_cred_getuid(req->r_cred);
290	int error = 0;
291
292	lck_mtx_lock(&nmp->nm_lock);
293	TAILQ_FOREACH(cp, &nmp->nm_gsscl, gss_clnt_entries) {
294		if (cp->gss_clnt_uid == uid) {
295			if (cp->gss_clnt_flags & GSS_CTX_INVAL)
296				continue;
297			nfs_gss_clnt_ctx_ref(req, cp);
298			lck_mtx_unlock(&nmp->nm_lock);
299			return (0);
300		}
301	}
302
303	if (uid == 0) {
304		/*
305		 * If superuser is trying to get access, then co-opt
306		 * the first valid context in the list.
307		 * XXX Ultimately, we need to allow superuser to
308		 * go ahead and attempt to set up its own context
309		 * in case one is set up for it.
310		 */
311		TAILQ_FOREACH(cp, &nmp->nm_gsscl, gss_clnt_entries) {
312			if (!(cp->gss_clnt_flags & GSS_CTX_INVAL)) {
313				nfs_gss_clnt_ctx_ref(req, cp);
314				lck_mtx_unlock(&nmp->nm_lock);
315				return (0);
316			}
317		}
318	}
319
320	/*
321	 * Not found - create a new context
322	 */
323
324	/*
325	 * If the thread is async, then it cannot get
326	 * kerberos creds and set up a proper context.
327	 * If no sec= mount option is given, attempt
328	 * to failover to sec=sys.
329	 */
330	if (req->r_thread == NULL) {
331		if (nfs_gss_sysok(req)) {
332			error = nfs_gss_clnt_ctx_failover(req);
333		} else {
334			printf("nfs_gss_clnt_ctx_find: no context for async\n");
335			error = NFSERR_EAUTH;
336		}
337
338		lck_mtx_unlock(&nmp->nm_lock);
339		return (error);
340	}
341
342	MALLOC(cp, struct nfs_gss_clnt_ctx *, sizeof(*cp), M_TEMP, M_WAITOK|M_ZERO);
343	if (cp == NULL) {
344		lck_mtx_unlock(&nmp->nm_lock);
345		return (ENOMEM);
346	}
347
348	cp->gss_clnt_uid = uid;
349	cp->gss_clnt_mtx = lck_mtx_alloc_init(nfs_gss_clnt_grp, LCK_ATTR_NULL);
350	cp->gss_clnt_thread = current_thread();
351	nfs_gss_clnt_ctx_ref(req, cp);
352	TAILQ_INSERT_TAIL(&nmp->nm_gsscl, cp, gss_clnt_entries);
353	lck_mtx_unlock(&nmp->nm_lock);
354
355	error = nfs_gss_clnt_ctx_init_retry(req, cp); // Initialize new context
356	if (error)
357		nfs_gss_clnt_ctx_unref(req);
358
359	/*
360	 * If we failed to set up a Kerberos context for this
361	 * user and no sec= mount option was given, but the
362	 * server indicated that it could support AUTH_SYS, then set
363	 * up a dummy context that allows this user to attempt
364	 * sec=sys calls.
365	 */
366	if (error && nfs_gss_sysok(req) &&
367	    (error != ENXIO) && (error != ETIMEDOUT)) {
368		lck_mtx_lock(&nmp->nm_lock);
369		error = nfs_gss_clnt_ctx_failover(req);
370		lck_mtx_unlock(&nmp->nm_lock);
371	}
372
373	return (error);
374}
375
376/*
377 * Set up a dummy context to allow the use of sec=sys
378 * for this user, if the server allows sec=sys.
379 * The context is valid for GSS_CLNT_SYS_VALID seconds,
380 * so that the user will periodically attempt to fail back
381 * and get a real credential.
382 *
383 * Assumes context list (nm_lock) is locked
384 */
385static int
386nfs_gss_clnt_ctx_failover(struct nfsreq *req)
387{
388	struct nfsmount *nmp = req->r_nmp;
389	struct nfs_gss_clnt_ctx *cp;
390	uid_t uid = kauth_cred_getuid(req->r_cred);
391	struct timeval now;
392
393	MALLOC(cp, struct nfs_gss_clnt_ctx *, sizeof(*cp), M_TEMP, M_WAITOK|M_ZERO);
394	if (cp == NULL)
395		return (ENOMEM);
396
397	cp->gss_clnt_service = RPCSEC_GSS_SVC_SYS;
398	cp->gss_clnt_uid = uid;
399	cp->gss_clnt_mtx = lck_mtx_alloc_init(nfs_gss_clnt_grp, LCK_ATTR_NULL);
400	microuptime(&now);
401	cp->gss_clnt_ctime = now.tv_sec;	// time stamp
402	nfs_gss_clnt_ctx_ref(req, cp);
403	TAILQ_INSERT_TAIL(&nmp->nm_gsscl, cp, gss_clnt_entries);
404
405	return (0);
406}
407
408/*
409 * Inserts an RPCSEC_GSS credential into an RPC header.
410 * After the credential is inserted, the code continues
411 * to build the verifier which contains a signed checksum
412 * of the RPC header.
413 */
414int
415nfs_gss_clnt_cred_put(struct nfsreq *req, struct nfsm_chain *nmc, mbuf_t args)
416{
417	struct nfs_gss_clnt_ctx *cp;
418	uint32_t seqnum = 0;
419	int error = 0;
420	int slpflag, recordmark = 0;
421	int start, len, offset = 0;
422	int pad, toklen;
423	struct nfsm_chain nmc_tmp;
424	struct gss_seq *gsp;
425	u_char tokbuf[KRB5_SZ_TOKMAX(MAX_DIGEST)];
426	u_char cksum[MAX_DIGEST];
427	struct timeval now;
428	gss_key_info *ki;
429
430	slpflag = (PZERO-1);
431	if (req->r_nmp) {
432		slpflag |= (NMFLAG(req->r_nmp, INTR) && req->r_thread && !(req->r_flags & R_NOINTR)) ? PCATCH : 0;
433		recordmark = (req->r_nmp->nm_sotype == SOCK_STREAM);
434	}
435retry:
436	if (req->r_gss_ctx == NULL) {
437		/*
438		 * Find the context for this user.
439		 * If no context is found, one will
440		 * be created.
441		 */
442		error = nfs_gss_clnt_ctx_find(req);
443		if (error)
444			return (error);
445	}
446	cp = req->r_gss_ctx;
447
448	/*
449	 * If it's a dummy context for a user that's using
450	 * a fallback to sec=sys, then just return an error
451	 * so rpchead can encode an RPCAUTH_UNIX cred.
452	 */
453	if (cp->gss_clnt_service == RPCSEC_GSS_SVC_SYS) {
454		/*
455		 * The dummy context is valid for just
456		 * GSS_CLNT_SYS_VALID seconds.  If the context
457		 * is older than this, mark it invalid and try
458		 * again to get a real one.
459		 */
460		lck_mtx_lock(cp->gss_clnt_mtx);
461		microuptime(&now);
462		if (now.tv_sec > cp->gss_clnt_ctime + GSS_CLNT_SYS_VALID) {
463			cp->gss_clnt_flags |= GSS_CTX_INVAL;
464			lck_mtx_unlock(cp->gss_clnt_mtx);
465			nfs_gss_clnt_ctx_unref(req);
466			goto retry;
467		}
468		lck_mtx_unlock(cp->gss_clnt_mtx);
469		return (ENEEDAUTH);
470	}
471
472	/*
473	 * If the context thread isn't null, then the context isn't
474	 * yet complete and is for the exclusive use of the thread
475	 * doing the context setup. Wait until the context thread
476	 * is null.
477	 */
478	lck_mtx_lock(cp->gss_clnt_mtx);
479	if (cp->gss_clnt_thread && cp->gss_clnt_thread != current_thread()) {
480		cp->gss_clnt_flags |= GSS_NEEDCTX;
481		msleep(cp, cp->gss_clnt_mtx, slpflag | PDROP, "ctxwait", NULL);
482		slpflag &= ~PCATCH;
483		if ((error = nfs_sigintr(req->r_nmp, req, req->r_thread, 0)))
484			return (error);
485		nfs_gss_clnt_ctx_unref(req);
486		goto retry;
487	}
488	lck_mtx_unlock(cp->gss_clnt_mtx);
489
490	ki = &cp->gss_clnt_kinfo;
491	if (cp->gss_clnt_flags & GSS_CTX_COMPLETE) {
492		/*
493		 * Get a sequence number for this request.
494		 * Check whether the oldest request in the window is complete.
495		 * If it's still pending, then wait until it's done before
496		 * we allocate a new sequence number and allow this request
497		 * to proceed.
498		 */
499		lck_mtx_lock(cp->gss_clnt_mtx);
500		while (win_getbit(cp->gss_clnt_seqbits,
501			((cp->gss_clnt_seqnum - cp->gss_clnt_seqwin) + 1) % cp->gss_clnt_seqwin)) {
502			cp->gss_clnt_flags |= GSS_NEEDSEQ;
503			msleep(cp, cp->gss_clnt_mtx, slpflag | PDROP, "seqwin", NULL);
504			slpflag &= ~PCATCH;
505			if ((error = nfs_sigintr(req->r_nmp, req, req->r_thread, 0))) {
506				return (error);
507			}
508			lck_mtx_lock(cp->gss_clnt_mtx);
509			if (cp->gss_clnt_flags & GSS_CTX_INVAL) {
510				/* Renewed while while we were waiting */
511				lck_mtx_unlock(cp->gss_clnt_mtx);
512				nfs_gss_clnt_ctx_unref(req);
513				goto retry;
514			}
515		}
516		seqnum = ++cp->gss_clnt_seqnum;
517		win_setbit(cp->gss_clnt_seqbits, seqnum % cp->gss_clnt_seqwin);
518		lck_mtx_unlock(cp->gss_clnt_mtx);
519
520		MALLOC(gsp, struct gss_seq *, sizeof(*gsp), M_TEMP, M_WAITOK|M_ZERO);
521		if (gsp == NULL)
522			return (ENOMEM);
523		gsp->gss_seqnum = seqnum;
524		SLIST_INSERT_HEAD(&req->r_gss_seqlist, gsp, gss_seqnext);
525	}
526
527	/* Insert the credential */
528	nfsm_chain_add_32(error, nmc, RPCSEC_GSS);
529	nfsm_chain_add_32(error, nmc, 5 * NFSX_UNSIGNED + cp->gss_clnt_handle_len);
530	nfsm_chain_add_32(error, nmc, RPCSEC_GSS_VERS_1);
531	nfsm_chain_add_32(error, nmc, cp->gss_clnt_proc);
532	nfsm_chain_add_32(error, nmc, seqnum);
533	nfsm_chain_add_32(error, nmc, cp->gss_clnt_service);
534	nfsm_chain_add_32(error, nmc, cp->gss_clnt_handle_len);
535	if (cp->gss_clnt_handle_len > 0) {
536	   	if (cp->gss_clnt_handle == NULL)
537		  	return (EBADRPC);
538		nfsm_chain_add_opaque(error, nmc, cp->gss_clnt_handle, cp->gss_clnt_handle_len);
539	}
540	if (error)
541	    return(error);
542	/*
543	 * Now add the verifier
544	 */
545	if (cp->gss_clnt_proc == RPCSEC_GSS_INIT ||
546		cp->gss_clnt_proc == RPCSEC_GSS_CONTINUE_INIT) {
547		/*
548		 * If the context is still being created
549		 * then use a null verifier.
550		 */
551		nfsm_chain_add_32(error, nmc, RPCAUTH_NULL);	// flavor
552		nfsm_chain_add_32(error, nmc, 0);		// length
553		nfsm_chain_build_done(error, nmc);
554		if (!error)
555			nfs_gss_append_chain(nmc, args);
556		return (error);
557	}
558
559	offset = recordmark ? NFSX_UNSIGNED : 0; // record mark
560	nfsm_chain_build_done(error, nmc);
561	nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), offset, 0, cksum);
562
563	toklen = nfs_gss_token_put(ki, ALG_MIC(ki), tokbuf, 1, 0, cksum);
564	nfsm_chain_add_32(error, nmc, RPCSEC_GSS);	// flavor
565	nfsm_chain_add_32(error, nmc, toklen);		// length
566	nfsm_chain_add_opaque(error, nmc, tokbuf, toklen);
567	nfsm_chain_build_done(error, nmc);
568	if (error)
569		return (error);
570
571	/*
572	 * Now we may have to compute integrity or encrypt the call args
573	 * per RFC 2203 Section 5.3.2
574	 */
575	switch (cp->gss_clnt_service) {
576	case RPCSEC_GSS_SVC_NONE:
577		nfs_gss_append_chain(nmc, args);
578		break;
579	case RPCSEC_GSS_SVC_INTEGRITY:
580		len = nfs_gss_mchain_length(args);	// Find args length
581		req->r_gss_arglen = len;		// Stash the args len
582		len += NFSX_UNSIGNED;			// Add seqnum length
583		nfsm_chain_add_32(error, nmc, len);	// and insert it
584		start = nfsm_chain_offset(nmc);
585		nfsm_chain_add_32(error, nmc, seqnum);	// Insert seqnum
586		req->r_gss_argoff = nfsm_chain_offset(nmc); // Offset to args
587		nfsm_chain_build_done(error, nmc);
588		if (error)
589			return (error);
590		nfs_gss_append_chain(nmc, args);	// Append the args mbufs
591
592		/* Now compute a checksum over the seqnum + args */
593		nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), start, len, cksum);
594
595		/* Insert it into a token and append to the request */
596		toklen = nfs_gss_token_put(ki, ALG_MIC(ki), tokbuf, 1, 0, cksum);
597		nfsm_chain_finish_mbuf(error, nmc);	// force checksum into new mbuf
598		nfsm_chain_add_32(error, nmc, toklen);
599		nfsm_chain_add_opaque(error, nmc, tokbuf, toklen);
600		nfsm_chain_build_done(error, nmc);
601		break;
602	case RPCSEC_GSS_SVC_PRIVACY:
603		/* Prepend a new mbuf with the confounder & sequence number */
604		nfsm_chain_build_alloc_init(error, &nmc_tmp, 3 * NFSX_UNSIGNED);
605		nfsm_chain_add_32(error, &nmc_tmp, random());	// confounder bytes 1-4
606		nfsm_chain_add_32(error, &nmc_tmp, random());	// confounder bytes 4-8
607		nfsm_chain_add_32(error, &nmc_tmp, seqnum);
608		nfsm_chain_build_done(error, &nmc_tmp);
609		if (error)
610			return (error);
611		nfs_gss_append_chain(&nmc_tmp, args);		// Append the args mbufs
612
613		len = nfs_gss_mchain_length(args);		// Find args length
614		len += 3 * NFSX_UNSIGNED;			// add confounder & seqnum
615		req->r_gss_arglen = len;			// Stash length
616
617		/*
618		 * Append a pad trailer - per RFC 1964 section 1.2.2.3
619		 * Since XDR data is always 32-bit aligned, it
620		 * needs to be padded either by 4 bytes or 8 bytes.
621		 */
622		nfsm_chain_finish_mbuf(error, &nmc_tmp);	// force padding into new mbuf
623		if (len % 8 > 0) {
624			nfsm_chain_add_32(error, &nmc_tmp, 0x04040404);
625			len += NFSX_UNSIGNED;
626		} else {
627			nfsm_chain_add_32(error, &nmc_tmp, 0x08080808);
628			nfsm_chain_add_32(error, &nmc_tmp, 0x08080808);
629			len +=  2 * NFSX_UNSIGNED;
630		}
631		nfsm_chain_build_done(error, &nmc_tmp);
632
633		/* Now compute a checksum over the confounder + seqnum + args */
634		nfs_gss_cksum_chain(ki, &nmc_tmp, ALG_WRAP(ki), 0, len, cksum);
635
636		/* Insert it into a token */
637		toklen = nfs_gss_token_put(ki, ALG_WRAP(ki), tokbuf, 1, len, cksum);
638		nfsm_chain_add_32(error, nmc, toklen + len);	// token + args length
639		nfsm_chain_add_opaque_nopad(error, nmc, tokbuf, toklen);
640		req->r_gss_argoff = nfsm_chain_offset(nmc);	// Stash offset
641		nfsm_chain_build_done(error, nmc);
642		if (error)
643			return (error);
644		nfs_gss_append_chain(nmc, nmc_tmp.nmc_mhead);	// Append the args mbufs
645
646		/* Finally, encrypt the args */
647		nfs_gss_encrypt_chain(ki, &nmc_tmp, 0, len, DES_ENCRYPT);
648
649		/* Add null XDR pad if the ASN.1 token misaligned the data */
650		pad = nfsm_pad(toklen + len);
651		if (pad > 0) {
652			nfsm_chain_add_opaque_nopad(error, nmc, iv0, pad);
653			nfsm_chain_build_done(error, nmc);
654		}
655		break;
656	}
657
658	return (error);
659}
660
661/*
662 * When receiving a reply, the client checks the verifier
663 * returned by the server. Check that the verifier is the
664 * correct type, then extract the sequence number checksum
665 * from the token in the credential and compare it with a
666 * computed checksum of the sequence number in the request
667 * that was sent.
668 */
669int
670nfs_gss_clnt_verf_get(
671	struct nfsreq *req,
672	struct nfsm_chain *nmc,
673	uint32_t verftype,
674	uint32_t verflen,
675	uint32_t *accepted_statusp)
676{
677	u_char tokbuf[KRB5_SZ_TOKMAX(MAX_DIGEST)];
678	u_char cksum1[MAX_DIGEST], cksum2[MAX_DIGEST];
679	uint32_t seqnum = 0;
680	struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx;
681	struct nfsm_chain nmc_tmp;
682	struct gss_seq *gsp;
683	uint32_t reslen, start, cksumlen, toklen;
684	int error = 0;
685	gss_key_info *ki = &cp->gss_clnt_kinfo;
686
687	reslen = cksumlen = 0;
688	*accepted_statusp = 0;
689
690	if (cp == NULL)
691		return (NFSERR_EAUTH);
692	/*
693	 * If it's not an RPCSEC_GSS verifier, then it has to
694	 * be a null verifier that resulted from either
695	 * a CONTINUE_NEEDED reply during context setup or
696	 * from the reply to an AUTH_UNIX call from a dummy
697	 * context that resulted from a fallback to sec=sys.
698	 */
699	if (verftype != RPCSEC_GSS) {
700		if (verftype != RPCAUTH_NULL)
701			return (NFSERR_EAUTH);
702		if (cp->gss_clnt_flags & GSS_CTX_COMPLETE &&
703			cp->gss_clnt_service != RPCSEC_GSS_SVC_SYS)
704			return (NFSERR_EAUTH);
705		if (verflen > 0)
706			nfsm_chain_adv(error, nmc, nfsm_rndup(verflen));
707		nfsm_chain_get_32(error, nmc, *accepted_statusp);
708		return (error);
709	}
710
711	/*
712	 * If we received an RPCSEC_GSS verifier but the
713	 * context isn't yet complete, then it must be
714	 * the context complete message from the server.
715	 * The verifier will contain an encrypted checksum
716	 * of the window but we don't have the session key
717	 * yet so we can't decrypt it. Stash the verifier
718	 * and check it later in nfs_gss_clnt_ctx_init() when
719	 * the context is complete.
720	 */
721	if (!(cp->gss_clnt_flags & GSS_CTX_COMPLETE)) {
722		MALLOC(cp->gss_clnt_verf, u_char *, verflen, M_TEMP, M_WAITOK|M_ZERO);
723		if (cp->gss_clnt_verf == NULL)
724			return (ENOMEM);
725		nfsm_chain_get_opaque(error, nmc, verflen, cp->gss_clnt_verf);
726		nfsm_chain_get_32(error, nmc, *accepted_statusp);
727		return (error);
728	}
729
730	if (verflen != KRB5_SZ_TOKEN(ki->hash_len))
731		return (NFSERR_EAUTH);
732
733	/*
734	 * Get the 8 octet sequence number
735	 * checksum out of the verifier token.
736	 */
737	nfsm_chain_get_opaque(error, nmc, verflen, tokbuf);
738	if (error)
739		goto nfsmout;
740	error = nfs_gss_token_get(ki, ALG_MIC(ki), tokbuf, 0, NULL, cksum1);
741	if (error)
742		goto nfsmout;
743
744	/*
745	 * Search the request sequence numbers for this reply, starting
746	 * with the most recent, looking for a checksum that matches
747	 * the one in the verifier returned by the server.
748	 */
749	SLIST_FOREACH(gsp, &req->r_gss_seqlist, gss_seqnext) {
750		nfs_gss_cksum_rep(ki, gsp->gss_seqnum, cksum2);
751		if (bcmp(cksum1, cksum2, HASHLEN(ki)) == 0)
752			break;
753	}
754	if (gsp == NULL)
755		return (NFSERR_EAUTH);
756
757	/*
758	 * Get the RPC accepted status
759	 */
760	nfsm_chain_get_32(error, nmc, *accepted_statusp);
761	if (*accepted_statusp != RPC_SUCCESS)
762		return (0);
763
764	/*
765	 * Now we may have to check integrity or decrypt the results
766	 * per RFC 2203 Section 5.3.2
767	 */
768	switch (cp->gss_clnt_service) {
769	case RPCSEC_GSS_SVC_NONE:
770		/* nothing to do */
771		break;
772	case RPCSEC_GSS_SVC_INTEGRITY:
773		/*
774		 * Here's what we expect in the integrity results:
775		 *
776		 * - length of seq num + results (4 bytes)
777		 * - sequence number (4 bytes)
778		 * - results (variable bytes)
779		 * - length of checksum token (37)
780		 * - checksum of seqnum + results (37 bytes)
781		 */
782		nfsm_chain_get_32(error, nmc, reslen);		// length of results
783		if (reslen > NFS_MAXPACKET) {
784			error = EBADRPC;
785			goto nfsmout;
786		}
787
788		/* Compute a checksum over the sequence number + results */
789		start = nfsm_chain_offset(nmc);
790		nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), start, reslen, cksum1);
791
792		/*
793		 * Get the sequence number prepended to the results
794		 * and compare it against the list in the request.
795		 */
796		nfsm_chain_get_32(error, nmc, seqnum);
797		SLIST_FOREACH(gsp, &req->r_gss_seqlist, gss_seqnext) {
798			if (seqnum == gsp->gss_seqnum)
799				break;
800		}
801		if (gsp == NULL) {
802			error = EBADRPC;
803			goto nfsmout;
804		}
805
806		/*
807		 * Advance to the end of the results and
808		 * fetch the checksum computed by the server.
809		 */
810		nmc_tmp = *nmc;
811		reslen -= NFSX_UNSIGNED;			// already skipped seqnum
812		nfsm_chain_adv(error, &nmc_tmp, reslen);	// skip over the results
813		nfsm_chain_get_32(error, &nmc_tmp, cksumlen);	// length of checksum
814		if (cksumlen != KRB5_SZ_TOKEN(ki->hash_len)) {
815			error = EBADRPC;
816			goto nfsmout;
817		}
818		nfsm_chain_get_opaque(error, &nmc_tmp, cksumlen, tokbuf);
819		if (error)
820			goto nfsmout;
821		error = nfs_gss_token_get(ki, ALG_MIC(ki), tokbuf, 0, NULL, cksum2);
822		if (error)
823			goto nfsmout;
824
825		/* Verify that the checksums are the same */
826		if (bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) {
827			error = EBADRPC;
828			goto nfsmout;
829		}
830		break;
831	case RPCSEC_GSS_SVC_PRIVACY:
832		/*
833		 * Here's what we expect in the privacy results:
834		 *
835		 * - length of confounder + seq num + token + results
836		 * - wrap token (37-40 bytes)
837		 * - confounder (8 bytes)
838		 * - sequence number (4 bytes)
839		 * - results (encrypted)
840		 */
841		nfsm_chain_get_32(error, nmc, reslen);		// length of results
842		if (reslen > NFS_MAXPACKET) {
843			error = EBADRPC;
844			goto nfsmout;
845		}
846
847		/* Get the token that prepends the encrypted results */
848		nfsm_chain_get_opaque(error, nmc, KRB5_SZ_TOKMAX(ki->hash_len), tokbuf);
849		if (error)
850			goto nfsmout;
851		error = nfs_gss_token_get(ki, ALG_WRAP(ki), tokbuf, 0,
852			&toklen, cksum1);
853		if (error)
854			goto nfsmout;
855		nfsm_chain_reverse(nmc, nfsm_pad(toklen));
856		reslen -= toklen;				// size of confounder + seqnum + results
857
858		/* decrypt the confounder + sequence number + results */
859		start = nfsm_chain_offset(nmc);
860		nfs_gss_encrypt_chain(ki, nmc, start, reslen, DES_DECRYPT);
861
862		/* Compute a checksum over the confounder + sequence number + results */
863		nfs_gss_cksum_chain(ki, nmc, ALG_WRAP(ki), start, reslen, cksum2);
864
865		/* Verify that the checksums are the same */
866		if (bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) {
867			error = EBADRPC;
868			goto nfsmout;
869		}
870
871		nfsm_chain_adv(error, nmc, 8);	// skip over the confounder
872
873		/*
874		 * Get the sequence number prepended to the results
875		 * and compare it against the list in the request.
876		 */
877		nfsm_chain_get_32(error, nmc, seqnum);
878		SLIST_FOREACH(gsp, &req->r_gss_seqlist, gss_seqnext) {
879			if (seqnum == gsp->gss_seqnum)
880				break;
881		}
882		if (gsp == NULL) {
883			error = EBADRPC;
884			goto nfsmout;
885		}
886
887		break;
888	}
889nfsmout:
890	return (error);
891}
892
893/*
894 * An RPCSEC_GSS request with no integrity or privacy consists
895 * of just the header mbufs followed by the arg mbufs.
896 *
897 * However, integrity or privacy both trailer mbufs to the args,
898 * which means we have to do some work to restore the arg mbuf
899 * chain to its previous state in case we need to retransmit.
900 *
901 * The location and length of the args is marked by two fields
902 * in the request structure: r_gss_argoff and r_gss_arglen,
903 * which are stashed when the NFS request is built.
904 */
905int
906nfs_gss_clnt_args_restore(struct nfsreq *req)
907{
908	struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx;
909	struct nfsm_chain mchain, *nmc = &mchain;
910	int len, error = 0;
911
912	if (cp == NULL)
913		return (NFSERR_EAUTH);
914
915	if ((cp->gss_clnt_flags & GSS_CTX_COMPLETE) == 0)
916		return (ENEEDAUTH);
917
918	nfsm_chain_dissect_init(error, nmc, req->r_mhead);	// start at RPC header
919	nfsm_chain_adv(error, nmc, req->r_gss_argoff);		// advance to args
920	if (error)
921		return (error);
922
923	switch (cp->gss_clnt_service) {
924	case RPCSEC_GSS_SVC_NONE:
925		/* nothing to do */
926		break;
927	case RPCSEC_GSS_SVC_INTEGRITY:
928		/*
929		 * All we have to do here is remove the appended checksum mbufs.
930		 * We know that the checksum starts in a new mbuf beyond the end
931		 * of the args.
932		 */
933		nfsm_chain_adv(error, nmc, req->r_gss_arglen);	// adv to last args mbuf
934		if (error)
935			return (error);
936
937		mbuf_freem(mbuf_next(nmc->nmc_mcur));		// free the cksum mbuf
938		error = mbuf_setnext(nmc->nmc_mcur, NULL);
939		break;
940	case RPCSEC_GSS_SVC_PRIVACY:
941		/*
942		 * The args are encrypted along with prepended confounders and seqnum.
943		 * First we decrypt, the confounder, seqnum and args then skip to the
944		 * final mbuf of the args.
945		 * The arglen includes 8 bytes of confounder and 4 bytes of seqnum.
946		 * Finally, we remove between 4 and 8 bytes of encryption padding
947		 * as well as any alignment padding in the trailing mbuf.
948		 */
949		len = req->r_gss_arglen;
950		len += len % 8 > 0 ? 4 : 8;			// add DES padding length
951		nfs_gss_encrypt_chain(&cp->gss_clnt_kinfo, nmc,
952					req->r_gss_argoff, len, DES_DECRYPT);
953		nfsm_chain_adv(error, nmc, req->r_gss_arglen);
954		if (error)
955			return (error);
956		mbuf_freem(mbuf_next(nmc->nmc_mcur));		// free the pad mbuf
957		error = mbuf_setnext(nmc->nmc_mcur, NULL);
958		break;
959	}
960
961	return (error);
962}
963
964/*
965 * This function sets up  a new context on the client.
966 * Context setup alternates upcalls to the gssd with NFS nullproc calls
967 * to the server.  Each of these calls exchanges an opaque token, obtained
968 * via the gssd's calls into the GSS-API on either the client or the server.
969 * This cycle of calls ends when the client's upcall to the gssd and the
970 * server's response both return GSS_S_COMPLETE.  At this point, the client
971 * should have its session key and a handle that it can use to refer to its
972 * new context on the server.
973 */
974static int
975nfs_gss_clnt_ctx_init(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp)
976{
977	struct nfsmount *nmp = req->r_nmp;
978	int client_complete = 0;
979	int server_complete = 0;
980	u_char cksum1[MAX_DIGEST], cksum2[MAX_DIGEST];
981	int error = 0;
982	struct timeval now;
983	gss_key_info *ki = &cp->gss_clnt_kinfo;
984
985	/* Initialize a new client context */
986
987	cp->gss_clnt_svcname = nfs_gss_clnt_svcname(nmp);
988	if (cp->gss_clnt_svcname == NULL) {
989		error = NFSERR_EAUTH;
990		goto nfsmout;
991	}
992
993	cp->gss_clnt_proc = RPCSEC_GSS_INIT;
994
995	cp->gss_clnt_service =
996		req->r_auth == RPCAUTH_KRB5  ? RPCSEC_GSS_SVC_NONE :
997		req->r_auth == RPCAUTH_KRB5I ? RPCSEC_GSS_SVC_INTEGRITY :
998		req->r_auth == RPCAUTH_KRB5P ? RPCSEC_GSS_SVC_PRIVACY : 0;
999
1000	cp->gss_clnt_gssd_flags = (nfs_single_des ? GSSD_NFS_1DES : 0);
1001	/*
1002	 * Now loop around alternating gss_init_sec_context and
1003	 * gss_accept_sec_context upcalls to the gssd on the client
1004	 * and server side until the context is complete - or fails.
1005	 */
1006	for (;;) {
1007
1008retry:
1009		/* Upcall to the gss_init_sec_context in the gssd */
1010		error = nfs_gss_clnt_gssd_upcall(req, cp);
1011		if (error)
1012			goto nfsmout;
1013
1014		if (cp->gss_clnt_major == GSS_S_COMPLETE) {
1015			client_complete = 1;
1016			if (server_complete)
1017				break;
1018		} else if (cp->gss_clnt_major != GSS_S_CONTINUE_NEEDED) {
1019			error = NFSERR_EAUTH;
1020			goto nfsmout;
1021		}
1022
1023		/*
1024		 * Pass the token to the server.
1025		 */
1026		error = nfs_gss_clnt_ctx_callserver(req, cp);
1027		if (error) {
1028			if (cp->gss_clnt_proc == RPCSEC_GSS_INIT &&
1029				(cp->gss_clnt_gssd_flags & (GSSD_RESTART | GSSD_NFS_1DES)) == 0) {
1030				cp->gss_clnt_gssd_flags = (GSSD_RESTART | GSSD_NFS_1DES);
1031				if (cp->gss_clnt_token)
1032					FREE(cp->gss_clnt_token, M_TEMP);
1033				cp->gss_clnt_token = NULL;
1034				cp->gss_clnt_tokenlen = 0;
1035				goto retry;
1036			}
1037			// Reset flags, if error = ENEEDAUTH we will try 3des again
1038			cp->gss_clnt_gssd_flags = 0;
1039			goto nfsmout;
1040		}
1041		if (cp->gss_clnt_major == GSS_S_COMPLETE) {
1042			server_complete = 1;
1043			if (client_complete)
1044				break;
1045		} else if (cp->gss_clnt_major != GSS_S_CONTINUE_NEEDED) {
1046			error = NFSERR_EAUTH;
1047			goto nfsmout;
1048		}
1049
1050		cp->gss_clnt_proc = RPCSEC_GSS_CONTINUE_INIT;
1051	}
1052
1053	/*
1054	 * The context is apparently established successfully
1055	 */
1056	lck_mtx_lock(cp->gss_clnt_mtx);
1057	cp->gss_clnt_flags |= GSS_CTX_COMPLETE;
1058	lck_mtx_unlock(cp->gss_clnt_mtx);
1059	cp->gss_clnt_proc = RPCSEC_GSS_DATA;
1060	microuptime(&now);
1061	cp->gss_clnt_ctime = now.tv_sec;	// time stamp
1062
1063
1064	/*
1065	 * Compute checksum of the server's window
1066	 */
1067	nfs_gss_cksum_rep(ki, cp->gss_clnt_seqwin, cksum1);
1068
1069	/*
1070	 * and see if it matches the one in the
1071	 * verifier the server returned.
1072	 */
1073	error = nfs_gss_token_get(ki, ALG_MIC(ki), cp->gss_clnt_verf, 0,
1074		NULL, cksum2);
1075	FREE(cp->gss_clnt_verf, M_TEMP);
1076	cp->gss_clnt_verf = NULL;
1077
1078	if (error || bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) {
1079		error = NFSERR_EAUTH;
1080		goto nfsmout;
1081	}
1082
1083	/*
1084	 * Set an initial sequence number somewhat randomized.
1085	 * Start small so we don't overflow GSS_MAXSEQ too quickly.
1086	 * Add the size of the sequence window so seqbits arithmetic
1087	 * doesn't go negative.
1088	 */
1089	cp->gss_clnt_seqnum = (random() & 0xffff) + cp->gss_clnt_seqwin;
1090
1091	/*
1092	 * Allocate a bitmap to keep track of which requests
1093	 * are pending within the sequence number window.
1094	 */
1095	MALLOC(cp->gss_clnt_seqbits, uint32_t *,
1096		nfsm_rndup((cp->gss_clnt_seqwin + 7) / 8), M_TEMP, M_WAITOK|M_ZERO);
1097	if (cp->gss_clnt_seqbits == NULL)
1098		error = NFSERR_EAUTH;
1099nfsmout:
1100 	/*
1101	 * If the error is ENEEDAUTH we're not done, so no need
1102	 * to wake up other threads again. This thread will retry in
1103	 * the find or renew routines.
1104	 */
1105	if (error == ENEEDAUTH)
1106		return (error);
1107
1108	/*
1109	 * If there's an error, just mark it as invalid.
1110	 * It will be removed when the reference count
1111	 * drops to zero.
1112	 */
1113	lck_mtx_lock(cp->gss_clnt_mtx);
1114	if (error)
1115		cp->gss_clnt_flags |= GSS_CTX_INVAL;
1116
1117	/*
1118	 * Wake any threads waiting to use the context
1119	 */
1120	cp->gss_clnt_thread = NULL;
1121	if (cp->gss_clnt_flags & GSS_NEEDCTX) {
1122		cp->gss_clnt_flags &= ~GSS_NEEDCTX;
1123		wakeup(cp);
1124	}
1125	lck_mtx_unlock(cp->gss_clnt_mtx);
1126
1127	return (error);
1128}
1129
1130/*
1131 * This function calls nfs_gss_clnt_ctx_init() to set up a new context.
1132 * But if there's a failure in trying to establish the context it keeps
1133 * retrying at progressively longer intervals in case the failure is
1134 * due to some transient condition.  For instance, the server might be
1135 * failing the context setup because directory services is not coming
1136 * up in a timely fashion.
1137 */
1138static int
1139nfs_gss_clnt_ctx_init_retry(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp)
1140{
1141	struct nfsmount *nmp = req->r_nmp;
1142	struct timeval now;
1143	time_t waituntil;
1144	int error, slpflag;
1145	int retries = 0;
1146	int timeo = NFS_TRYLATERDEL;
1147
1148	if (nmp == NULL) {
1149		error = ENXIO;
1150		goto bad;
1151	}
1152
1153	/* For an "intr" mount allow a signal to interrupt the retries */
1154	slpflag = (NMFLAG(nmp, INTR) && !(req->r_flags & R_NOINTR)) ? PCATCH : 0;
1155
1156	while ((error = nfs_gss_clnt_ctx_init(req, cp)) == ENEEDAUTH) {
1157		microuptime(&now);
1158		waituntil = now.tv_sec + timeo;
1159		while (now.tv_sec < waituntil) {
1160			tsleep(&lbolt, PSOCK | slpflag, "nfs_gss_clnt_ctx_init_retry", 0);
1161			slpflag = 0;
1162			error = nfs_sigintr(req->r_nmp, req, current_thread(), 0);
1163			if (error)
1164				goto bad;
1165			microuptime(&now);
1166		}
1167
1168		retries++;
1169		/* If it's a soft mount just give up after a while */
1170		if (NMFLAG(nmp, SOFT) && (retries > nmp->nm_retry)) {
1171			error = ETIMEDOUT;
1172			goto bad;
1173		}
1174		timeo *= 2;
1175		if (timeo > 60)
1176			timeo = 60;
1177	}
1178
1179	if (error == 0)
1180		return 0;	// success
1181bad:
1182	/*
1183	 * Give up on this context
1184	 */
1185	lck_mtx_lock(cp->gss_clnt_mtx);
1186	cp->gss_clnt_flags |= GSS_CTX_INVAL;
1187
1188	/*
1189	 * Wake any threads waiting to use the context
1190	 */
1191	cp->gss_clnt_thread = NULL;
1192	if (cp->gss_clnt_flags & GSS_NEEDCTX) {
1193		cp->gss_clnt_flags &= ~GSS_NEEDCTX;
1194		wakeup(cp);
1195	}
1196	lck_mtx_unlock(cp->gss_clnt_mtx);
1197
1198	return error;
1199}
1200
1201/*
1202 * Call the NFS server using a null procedure for context setup.
1203 * Even though it's a null procedure and nominally has no arguments
1204 * RFC 2203 requires that the GSS-API token be passed as an argument
1205 * and received as a reply.
1206 */
1207static int
1208nfs_gss_clnt_ctx_callserver(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp)
1209{
1210	struct nfsm_chain nmreq, nmrep;
1211	int error = 0, status;
1212	int sz;
1213
1214	if (!req->r_nmp)
1215		return (ENXIO);
1216	nfsm_chain_null(&nmreq);
1217	nfsm_chain_null(&nmrep);
1218	sz = NFSX_UNSIGNED + nfsm_rndup(cp->gss_clnt_tokenlen);
1219	nfsm_chain_build_alloc_init(error, &nmreq, sz);
1220	nfsm_chain_add_32(error, &nmreq, cp->gss_clnt_tokenlen);
1221	if (cp->gss_clnt_tokenlen > 0)
1222		nfsm_chain_add_opaque(error, &nmreq, cp->gss_clnt_token, cp->gss_clnt_tokenlen);
1223	nfsm_chain_build_done(error, &nmreq);
1224	if (error)
1225		goto nfsmout;
1226
1227	/* Call the server */
1228	error = nfs_request_gss(req->r_nmp->nm_mountp, &nmreq, req->r_thread, req->r_cred,
1229				(req->r_flags & R_OPTMASK), cp, &nmrep, &status);
1230	if (cp->gss_clnt_token != NULL) {
1231		FREE(cp->gss_clnt_token, M_TEMP);
1232		cp->gss_clnt_token = NULL;
1233	}
1234	if (!error)
1235		error = status;
1236	if (error)
1237		goto nfsmout;
1238
1239	/* Get the server's reply */
1240
1241	nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_handle_len);
1242	if (cp->gss_clnt_handle != NULL) {
1243		FREE(cp->gss_clnt_handle, M_TEMP);
1244		cp->gss_clnt_handle = NULL;
1245	}
1246	if (cp->gss_clnt_handle_len > 0) {
1247		MALLOC(cp->gss_clnt_handle, u_char *, cp->gss_clnt_handle_len, M_TEMP, M_WAITOK);
1248		if (cp->gss_clnt_handle == NULL) {
1249			error = ENOMEM;
1250			goto nfsmout;
1251		}
1252		nfsm_chain_get_opaque(error, &nmrep, cp->gss_clnt_handle_len, cp->gss_clnt_handle);
1253	}
1254	nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_major);
1255	nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_minor);
1256	nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_seqwin);
1257	nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_tokenlen);
1258	if (error)
1259		goto nfsmout;
1260	if (cp->gss_clnt_tokenlen > 0) {
1261		MALLOC(cp->gss_clnt_token, u_char *, cp->gss_clnt_tokenlen, M_TEMP, M_WAITOK);
1262		if (cp->gss_clnt_token == NULL) {
1263			error = ENOMEM;
1264			goto nfsmout;
1265		}
1266		nfsm_chain_get_opaque(error, &nmrep, cp->gss_clnt_tokenlen, cp->gss_clnt_token);
1267	}
1268
1269	/*
1270	 * Make sure any unusual errors are expanded and logged by gssd
1271	 */
1272	if (cp->gss_clnt_major != GSS_S_COMPLETE &&
1273	    cp->gss_clnt_major != GSS_S_CONTINUE_NEEDED) {
1274		char who[] = "server";
1275		char unknown[] = "<unknown>";
1276
1277		(void) mach_gss_log_error(
1278			cp->gss_clnt_mport,
1279			!req->r_nmp ? unknown :
1280			vfs_statfs(req->r_nmp->nm_mountp)->f_mntfromname,
1281			cp->gss_clnt_uid,
1282			who,
1283			cp->gss_clnt_major,
1284			cp->gss_clnt_minor);
1285	}
1286
1287nfsmout:
1288	nfsm_chain_cleanup(&nmreq);
1289	nfsm_chain_cleanup(&nmrep);
1290
1291	return (error);
1292}
1293
1294/*
1295 * Ugly hack to get the service principal from the f_mntfromname field in
1296 * the statfs struct. We assume a format of server:path. We don't currently
1297 * support url's or other bizarre formats like path@server. A better solution
1298 * here might be to allow passing the service principal down in the mount args.
1299 * For kerberos we just use the default realm.
1300 */
1301static char *
1302nfs_gss_clnt_svcname(struct nfsmount *nmp)
1303{
1304	char *svcname, *d, *mntfromhere;
1305	int len;
1306
1307	if (!nmp)
1308		return (NULL);
1309	mntfromhere = &vfs_statfs(nmp->nm_mountp)->f_mntfromname[0];
1310	len = strlen(mntfromhere) + 5; /* "nfs/" plus null */
1311	MALLOC(svcname, char *, len, M_TEMP, M_NOWAIT);
1312	if (svcname == NULL)
1313		return (NULL);
1314	strlcpy(svcname, "nfs/", len);
1315	strlcat(svcname, mntfromhere, len);
1316	d = strchr(svcname, ':');
1317	if (d)
1318		*d = '\0';
1319
1320	return (svcname);
1321}
1322
1323/*
1324 * Get a mach port to talk to gssd.
1325 * gssd lives in the root bootstrap, so we call gssd's lookup routine
1326 * to get a send right to talk to a new gssd instance that launchd has launched
1327 * based on the cred's uid and audit session id.
1328 */
1329#define kauth_cred_getasid(cred) ((cred)->cr_audit.as_aia_p->ai_asid)
1330#define kauth_cred_getauid(cred) ((cred)->cr_audit.as_aia_p->ai_auid)
1331
1332static mach_port_t
1333nfs_gss_clnt_get_upcall_port(kauth_cred_t credp)
1334{
1335	mach_port_t gssd_host_port, uc_port = IPC_PORT_NULL;
1336	kern_return_t kr;
1337	au_asid_t asid;
1338	uid_t uid;
1339
1340	kr = host_get_gssd_port(host_priv_self(), &gssd_host_port);
1341	if (kr != KERN_SUCCESS) {
1342		printf("nfs_gss_get_upcall_port: can't get gssd port, status %x (%d)\n", kr, kr);
1343		return (IPC_PORT_NULL);
1344	}
1345	if (!IPC_PORT_VALID(gssd_host_port)) {
1346		printf("nfs_gss_get_upcall_port: gssd port not valid\n");
1347		return (IPC_PORT_NULL);
1348	}
1349
1350	asid = kauth_cred_getasid(credp);
1351	uid = kauth_cred_getauid(credp);
1352	if (uid == AU_DEFAUDITID)
1353		uid = kauth_cred_getuid(credp);
1354	kr = mach_gss_lookup(gssd_host_port, uid, asid, &uc_port);
1355	if (kr != KERN_SUCCESS)
1356		printf("nfs_gss_clnt_get_upcall_port: mach_gssd_lookup failed: status %x (%d)\n", kr, kr);
1357
1358	return (uc_port);
1359}
1360
1361/*
1362 * Make an upcall to the gssd using Mach RPC
1363 * The upcall is made using a host special port.
1364 * This allows launchd to fire up the gssd in the
1365 * user's session.  This is important, since gssd
1366 * must have access to the user's credential cache.
1367 */
1368static int
1369nfs_gss_clnt_gssd_upcall(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp)
1370{
1371	kern_return_t kr;
1372	gssd_byte_buffer okey = NULL;
1373	uint32_t skeylen = 0;
1374	int retry_cnt = 0;
1375	vm_map_copy_t itoken = NULL;
1376	gssd_byte_buffer otoken = NULL;
1377	mach_msg_type_number_t otokenlen;
1378	int error = 0;
1379	char uprinc[1];
1380	uint32_t ret_flags;
1381
1382	/*
1383	 * NFS currently only supports default principals or
1384	 * principals based on the uid of the caller.
1385	 *
1386	 * N.B. Note we define a one character array for the principal
1387	 * so that we can hold an empty string required by mach, since
1388	 * the kernel is being compiled with -Wwrite-strings.
1389	 */
1390	uprinc[0] = '\0';
1391	if (!IPC_PORT_VALID(cp->gss_clnt_mport)) {
1392		cp->gss_clnt_mport = nfs_gss_clnt_get_upcall_port(req->r_cred);
1393		if (cp->gss_clnt_mport == IPC_PORT_NULL)
1394			goto out;
1395	}
1396
1397	if (cp->gss_clnt_tokenlen > 0)
1398		nfs_gss_mach_alloc_buffer(cp->gss_clnt_token, cp->gss_clnt_tokenlen, &itoken);
1399
1400retry:
1401	kr = mach_gss_init_sec_context(
1402		cp->gss_clnt_mport,
1403		GSSD_KRB5_MECH,
1404		(gssd_byte_buffer) itoken, (mach_msg_type_number_t) cp->gss_clnt_tokenlen,
1405		cp->gss_clnt_uid,
1406		uprinc,
1407		cp->gss_clnt_svcname,
1408		GSSD_MUTUAL_FLAG,
1409		cp->gss_clnt_gssd_flags,
1410		&cp->gss_clnt_context,
1411		&cp->gss_clnt_cred_handle,
1412		&ret_flags,
1413		&okey,  (mach_msg_type_number_t *) &skeylen,
1414		&otoken, &otokenlen,
1415		&cp->gss_clnt_major,
1416		&cp->gss_clnt_minor);
1417
1418	cp->gss_clnt_gssd_flags &= ~GSSD_RESTART;
1419
1420	if (kr != KERN_SUCCESS) {
1421		printf("nfs_gss_clnt_gssd_upcall: mach_gss_init_sec_context failed: %x (%d)\n", kr, kr);
1422		if (kr == MIG_SERVER_DIED && cp->gss_clnt_cred_handle == 0 &&
1423			retry_cnt++ < NFS_GSS_MACH_MAX_RETRIES) {
1424			if (cp->gss_clnt_tokenlen > 0)
1425				nfs_gss_mach_alloc_buffer(cp->gss_clnt_token, cp->gss_clnt_tokenlen, &itoken);
1426			goto retry;
1427		}
1428
1429		host_release_special_port(cp->gss_clnt_mport);
1430		cp->gss_clnt_mport = IPC_PORT_NULL;
1431		goto out;
1432	}
1433
1434	/*
1435	 * Make sure any unusual errors are expanded and logged by gssd
1436	 */
1437	if (cp->gss_clnt_major != GSS_S_COMPLETE &&
1438	    cp->gss_clnt_major != GSS_S_CONTINUE_NEEDED) {
1439		char who[] = "client";
1440		char unknown[] = "<unknown>";
1441
1442		(void) mach_gss_log_error(
1443			cp->gss_clnt_mport,
1444			!req->r_nmp ? unknown :
1445			vfs_statfs(req->r_nmp->nm_mountp)->f_mntfromname,
1446			cp->gss_clnt_uid,
1447			who,
1448			cp->gss_clnt_major,
1449			cp->gss_clnt_minor);
1450	}
1451
1452	if (skeylen > 0) {
1453		if (skeylen != SKEYLEN && skeylen != SKEYLEN3) {
1454			printf("nfs_gss_clnt_gssd_upcall: bad key length (%d)\n", skeylen);
1455			vm_map_copy_discard((vm_map_copy_t) okey);
1456			vm_map_copy_discard((vm_map_copy_t) otoken);
1457			goto out;
1458		}
1459		error = nfs_gss_mach_vmcopyout((vm_map_copy_t) okey, skeylen,
1460				cp->gss_clnt_kinfo.skey);
1461		if (error) {
1462			vm_map_copy_discard((vm_map_copy_t) otoken);
1463			goto out;
1464		}
1465
1466		error = gss_key_init(&cp->gss_clnt_kinfo, skeylen);
1467		if (error)
1468			goto out;
1469	}
1470
1471	/* Free context token used as input */
1472	if (cp->gss_clnt_token)
1473		FREE(cp->gss_clnt_token, M_TEMP);
1474	cp->gss_clnt_token = NULL;
1475	cp->gss_clnt_tokenlen = 0;
1476
1477	if (otokenlen > 0) {
1478		/* Set context token to gss output token */
1479		MALLOC(cp->gss_clnt_token, u_char *, otokenlen, M_TEMP, M_WAITOK);
1480		if (cp->gss_clnt_token == NULL) {
1481			printf("nfs_gss_clnt_gssd_upcall: could not allocate %d bytes\n", otokenlen);
1482			vm_map_copy_discard((vm_map_copy_t) otoken);
1483			return (ENOMEM);
1484		}
1485		error = nfs_gss_mach_vmcopyout((vm_map_copy_t) otoken, otokenlen, cp->gss_clnt_token);
1486		if (error) {
1487			FREE(cp->gss_clnt_token, M_TEMP);
1488			cp->gss_clnt_token = NULL;
1489			return (NFSERR_EAUTH);
1490		}
1491		cp->gss_clnt_tokenlen = otokenlen;
1492	}
1493
1494	return (0);
1495
1496out:
1497	if (cp->gss_clnt_token)
1498		FREE(cp->gss_clnt_token, M_TEMP);
1499	cp->gss_clnt_token = NULL;
1500	cp->gss_clnt_tokenlen = 0;
1501
1502	return (NFSERR_EAUTH);
1503}
1504
1505/*
1506 * Invoked at the completion of an RPC call that uses an RPCSEC_GSS
1507 * credential. The sequence number window that the server returns
1508 * at context setup indicates the maximum number of client calls that
1509 * can be outstanding on a context. The client maintains a bitmap that
1510 * represents the server's window.  Each pending request has a bit set
1511 * in the window bitmap.  When a reply comes in or times out, we reset
1512 * the bit in the bitmap and if there are any other threads waiting for
1513 * a context slot we notify the waiting thread(s).
1514 *
1515 * Note that if a request is retransmitted, it will have a single XID
1516 * but it may be associated with multiple sequence numbers.  So we
1517 * may have to reset multiple sequence number bits in the window bitmap.
1518 */
1519void
1520nfs_gss_clnt_rpcdone(struct nfsreq *req)
1521{
1522	struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx;
1523	struct gss_seq *gsp, *ngsp;
1524	int i = 0;
1525
1526	if (cp == NULL || !(cp->gss_clnt_flags & GSS_CTX_COMPLETE))
1527		return;	// no context - don't bother
1528	/*
1529	 * Reset the bit for this request in the
1530	 * sequence number window to indicate it's done.
1531	 * We do this even if the request timed out.
1532	 */
1533	lck_mtx_lock(cp->gss_clnt_mtx);
1534	gsp = SLIST_FIRST(&req->r_gss_seqlist);
1535	if (gsp && gsp->gss_seqnum > (cp->gss_clnt_seqnum - cp->gss_clnt_seqwin))
1536		win_resetbit(cp->gss_clnt_seqbits,
1537			gsp->gss_seqnum % cp->gss_clnt_seqwin);
1538
1539	/*
1540	 * Limit the seqnum list to GSS_CLNT_SEQLISTMAX entries
1541	 */
1542	SLIST_FOREACH_SAFE(gsp, &req->r_gss_seqlist, gss_seqnext, ngsp) {
1543		if (++i > GSS_CLNT_SEQLISTMAX) {
1544			SLIST_REMOVE(&req->r_gss_seqlist, gsp, gss_seq, gss_seqnext);
1545			FREE(gsp, M_TEMP);
1546		}
1547	}
1548
1549	/*
1550	 * If there's a thread waiting for
1551	 * the window to advance, wake it up.
1552	 */
1553	if (cp->gss_clnt_flags & GSS_NEEDSEQ) {
1554		cp->gss_clnt_flags &= ~GSS_NEEDSEQ;
1555		wakeup(cp);
1556	}
1557	lck_mtx_unlock(cp->gss_clnt_mtx);
1558}
1559
1560/*
1561 * Create a reference to a context from a request
1562 * and bump the reference count
1563 */
1564void
1565nfs_gss_clnt_ctx_ref(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp)
1566{
1567	req->r_gss_ctx = cp;
1568
1569	lck_mtx_lock(cp->gss_clnt_mtx);
1570	cp->gss_clnt_refcnt++;
1571	lck_mtx_unlock(cp->gss_clnt_mtx);
1572}
1573
1574/*
1575 * Remove a context reference from a request
1576 * If the reference count drops to zero, and the
1577 * context is invalid, destroy the context
1578 */
1579void
1580nfs_gss_clnt_ctx_unref(struct nfsreq *req)
1581{
1582	struct nfsmount *nmp = req->r_nmp;
1583	struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx;
1584
1585	if (cp == NULL)
1586		return;
1587
1588	req->r_gss_ctx = NULL;
1589
1590	lck_mtx_lock(cp->gss_clnt_mtx);
1591	if (--cp->gss_clnt_refcnt == 0
1592		&& cp->gss_clnt_flags & GSS_CTX_INVAL) {
1593		lck_mtx_unlock(cp->gss_clnt_mtx);
1594
1595		if (nmp)
1596			lck_mtx_lock(&nmp->nm_lock);
1597		nfs_gss_clnt_ctx_remove(nmp, cp);
1598		if (nmp)
1599			lck_mtx_unlock(&nmp->nm_lock);
1600
1601		return;
1602	}
1603	lck_mtx_unlock(cp->gss_clnt_mtx);
1604}
1605
1606/*
1607 * Remove a context
1608 */
1609static void
1610nfs_gss_clnt_ctx_remove(struct nfsmount *nmp, struct nfs_gss_clnt_ctx *cp)
1611{
1612	/*
1613	 * If dequeueing, assume nmp->nm_lock is held
1614	 */
1615	if (nmp != NULL)
1616		TAILQ_REMOVE(&nmp->nm_gsscl, cp, gss_clnt_entries);
1617
1618	host_release_special_port(cp->gss_clnt_mport);
1619
1620	if (cp->gss_clnt_mtx)
1621		lck_mtx_destroy(cp->gss_clnt_mtx, nfs_gss_clnt_grp);
1622	if (cp->gss_clnt_handle)
1623		FREE(cp->gss_clnt_handle, M_TEMP);
1624	if (cp->gss_clnt_seqbits)
1625		FREE(cp->gss_clnt_seqbits, M_TEMP);
1626	if (cp->gss_clnt_token)
1627		FREE(cp->gss_clnt_token, M_TEMP);
1628	if (cp->gss_clnt_svcname)
1629		FREE(cp->gss_clnt_svcname, M_TEMP);
1630	FREE(cp, M_TEMP);
1631}
1632
1633/*
1634 * The context for a user is invalid.
1635 * Mark the context as invalid, then
1636 * create a new context.
1637 */
1638int
1639nfs_gss_clnt_ctx_renew(struct nfsreq *req)
1640{
1641	struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx;
1642	struct nfsmount *nmp = req->r_nmp;
1643	struct nfs_gss_clnt_ctx *ncp;
1644	int error = 0;
1645	uid_t saved_uid;
1646	mach_port_t saved_mport;
1647
1648	if (cp == NULL)
1649		return (0);
1650
1651	lck_mtx_lock(cp->gss_clnt_mtx);
1652	if (cp->gss_clnt_flags & GSS_CTX_INVAL) {
1653		lck_mtx_unlock(cp->gss_clnt_mtx);
1654		nfs_gss_clnt_ctx_unref(req);
1655		return (0);	// already being renewed
1656	}
1657	saved_uid = cp->gss_clnt_uid;
1658	saved_mport = host_copy_special_port(cp->gss_clnt_mport);
1659
1660	/* Remove the old context */
1661	cp->gss_clnt_flags |= GSS_CTX_INVAL;
1662
1663	/*
1664	 * If there's a thread waiting
1665	 * in the old context, wake it up.
1666	 */
1667	if (cp->gss_clnt_flags & (GSS_NEEDCTX | GSS_NEEDSEQ)) {
1668		cp->gss_clnt_flags &= ~GSS_NEEDSEQ;
1669		wakeup(cp);
1670	}
1671	lck_mtx_unlock(cp->gss_clnt_mtx);
1672
1673	/*
1674	 * Create a new context
1675	 */
1676	MALLOC(ncp, struct nfs_gss_clnt_ctx *, sizeof(*ncp),
1677		M_TEMP, M_WAITOK|M_ZERO);
1678	if (ncp == NULL) {
1679		error = ENOMEM;
1680		goto out;
1681	}
1682
1683	ncp->gss_clnt_uid = saved_uid;
1684	ncp->gss_clnt_mport = host_copy_special_port(saved_mport); // re-use the gssd port
1685	ncp->gss_clnt_mtx = lck_mtx_alloc_init(nfs_gss_clnt_grp, LCK_ATTR_NULL);
1686	ncp->gss_clnt_thread = current_thread();
1687	lck_mtx_lock(&nmp->nm_lock);
1688	TAILQ_INSERT_TAIL(&nmp->nm_gsscl, ncp, gss_clnt_entries);
1689	lck_mtx_unlock(&nmp->nm_lock);
1690
1691	/* Adjust reference counts to new and old context */
1692	nfs_gss_clnt_ctx_unref(req);
1693	nfs_gss_clnt_ctx_ref(req, ncp);
1694
1695	error = nfs_gss_clnt_ctx_init_retry(req, ncp); // Initialize new context
1696out:
1697	host_release_special_port(saved_mport);
1698	if (error)
1699		nfs_gss_clnt_ctx_unref(req);
1700
1701	return (error);
1702}
1703
1704/*
1705 * Destroy all the contexts associated with a mount.
1706 * The contexts are also destroyed by the server.
1707 */
1708void
1709nfs_gss_clnt_ctx_unmount(struct nfsmount *nmp)
1710{
1711	struct nfs_gss_clnt_ctx *cp;
1712	struct nfsm_chain nmreq, nmrep;
1713	int error, status;
1714	struct nfsreq req;
1715
1716	req.r_nmp = nmp;
1717
1718	for (;;) {
1719		lck_mtx_lock(&nmp->nm_lock);
1720		cp = TAILQ_FIRST(&nmp->nm_gsscl);
1721		lck_mtx_unlock(&nmp->nm_lock);
1722		if (cp == NULL)
1723			break;
1724
1725		nfs_gss_clnt_ctx_ref(&req, cp);
1726
1727		/*
1728		 * Tell the server to destroy its context.
1729		 * But don't bother if it's a forced unmount
1730		 * or if it's a dummy sec=sys context.
1731		 */
1732		if (!(nmp->nm_state & NFSSTA_FORCE) && (cp->gss_clnt_service != RPCSEC_GSS_SVC_SYS)) {
1733			kauth_cred_t cred;
1734			struct posix_cred temp_pcred;
1735
1736			bzero((caddr_t) &temp_pcred, sizeof(temp_pcred));
1737			temp_pcred.cr_ngroups = 1;
1738			temp_pcred.cr_uid = cp->gss_clnt_uid;
1739			cred = posix_cred_create(&temp_pcred);
1740			cp->gss_clnt_proc = RPCSEC_GSS_DESTROY;
1741
1742			error = 0;
1743			nfsm_chain_null(&nmreq);
1744			nfsm_chain_null(&nmrep);
1745			nfsm_chain_build_alloc_init(error, &nmreq, 0);
1746			nfsm_chain_build_done(error, &nmreq);
1747			if (!error)
1748				nfs_request_gss(nmp->nm_mountp, &nmreq,
1749					current_thread(), cred, 0, cp, &nmrep, &status);
1750			nfsm_chain_cleanup(&nmreq);
1751			nfsm_chain_cleanup(&nmrep);
1752			kauth_cred_unref(&cred);
1753		}
1754
1755		/*
1756		 * Mark the context invalid then drop
1757		 * the reference to remove it if its
1758		 * refcount is zero.
1759		 */
1760		lck_mtx_lock(cp->gss_clnt_mtx);
1761		cp->gss_clnt_flags |= GSS_CTX_INVAL;
1762		lck_mtx_unlock(cp->gss_clnt_mtx);
1763		nfs_gss_clnt_ctx_unref(&req);
1764	}
1765}
1766
1767#endif /* NFSCLIENT */
1768
1769/*************
1770 *
1771 * Server functions
1772 */
1773
1774#if NFSSERVER
1775
1776/*
1777 * Find a server context based on a handle value received
1778 * in an RPCSEC_GSS credential.
1779 */
1780static struct nfs_gss_svc_ctx *
1781nfs_gss_svc_ctx_find(uint32_t handle)
1782{
1783	struct nfs_gss_svc_ctx_hashhead *head;
1784	struct nfs_gss_svc_ctx *cp;
1785	uint64_t timenow;
1786
1787	if (handle == 0)
1788		return (NULL);
1789
1790	head = &nfs_gss_svc_ctx_hashtbl[SVC_CTX_HASH(handle)];
1791	/*
1792	 * Don't return a context that is going to expire in GSS_CTX_PEND seconds
1793	 */
1794	clock_interval_to_deadline(GSS_CTX_PEND, NSEC_PER_SEC, &timenow);
1795
1796	lck_mtx_lock(nfs_gss_svc_ctx_mutex);
1797
1798	LIST_FOREACH(cp, head, gss_svc_entries) {
1799		if (cp->gss_svc_handle == handle) {
1800			if (timenow > cp->gss_svc_incarnation + GSS_SVC_CTX_TTL) {
1801				/*
1802				 * Context has or is about to expire. Don't use.
1803				 * We'll return null and the client will have to create
1804				 * a new context.
1805				 */
1806				cp->gss_svc_handle = 0;
1807				/*
1808				 * Make sure though that we stay around for GSS_CTX_PEND seconds
1809				 * for other threads that might be using the context.
1810				 */
1811				cp->gss_svc_incarnation = timenow;
1812
1813				cp = NULL;
1814				break;
1815			}
1816			lck_mtx_lock(cp->gss_svc_mtx);
1817			cp->gss_svc_refcnt++;
1818			lck_mtx_unlock(cp->gss_svc_mtx);
1819			break;
1820		}
1821	}
1822
1823	lck_mtx_unlock(nfs_gss_svc_ctx_mutex);
1824
1825	return (cp);
1826}
1827
1828/*
1829 * Insert a new server context into the hash table
1830 * and start the context reap thread if necessary.
1831 */
1832static void
1833nfs_gss_svc_ctx_insert(struct nfs_gss_svc_ctx *cp)
1834{
1835	struct nfs_gss_svc_ctx_hashhead *head;
1836	struct nfs_gss_svc_ctx *p;
1837
1838	lck_mtx_lock(nfs_gss_svc_ctx_mutex);
1839
1840	/*
1841	 * Give the client a random handle so that if we reboot
1842	 * it's unlikely the client will get a bad context match.
1843	 * Make sure it's not zero or already assigned.
1844	 */
1845retry:
1846	cp->gss_svc_handle = random();
1847	if (cp->gss_svc_handle == 0)
1848		goto retry;
1849	head = &nfs_gss_svc_ctx_hashtbl[SVC_CTX_HASH(cp->gss_svc_handle)];
1850	LIST_FOREACH(p, head, gss_svc_entries)
1851		if (p->gss_svc_handle == cp->gss_svc_handle)
1852			goto retry;
1853
1854	clock_interval_to_deadline(GSS_CTX_PEND, NSEC_PER_SEC,
1855		&cp->gss_svc_incarnation);
1856	LIST_INSERT_HEAD(head, cp, gss_svc_entries);
1857	nfs_gss_ctx_count++;
1858
1859	if (!nfs_gss_timer_on) {
1860		nfs_gss_timer_on = 1;
1861
1862		nfs_interval_timer_start(nfs_gss_svc_ctx_timer_call,
1863			min(GSS_TIMER_PERIOD, max(GSS_CTX_TTL_MIN, nfsrv_gss_context_ttl)) * MSECS_PER_SEC);
1864	}
1865
1866	lck_mtx_unlock(nfs_gss_svc_ctx_mutex);
1867}
1868
1869/*
1870 * This function is called via the kernel's callout
1871 * mechanism.  It runs only when there are
1872 * cached RPCSEC_GSS contexts.
1873 */
1874void
1875nfs_gss_svc_ctx_timer(__unused void *param1, __unused void *param2)
1876{
1877	struct nfs_gss_svc_ctx *cp, *next;
1878	uint64_t timenow;
1879	int contexts = 0;
1880	int i;
1881
1882	lck_mtx_lock(nfs_gss_svc_ctx_mutex);
1883	clock_get_uptime(&timenow);
1884
1885	/*
1886	 * Scan all the hash chains
1887	 */
1888	for (i = 0; i < SVC_CTX_HASHSZ; i++) {
1889		/*
1890		 * For each hash chain, look for entries
1891		 * that haven't been used in a while.
1892		 */
1893		LIST_FOREACH_SAFE(cp, &nfs_gss_svc_ctx_hashtbl[i], gss_svc_entries, next) {
1894			contexts++;
1895			if (timenow > cp->gss_svc_incarnation +
1896				(cp->gss_svc_handle ? GSS_SVC_CTX_TTL : 0)
1897				&& cp->gss_svc_refcnt == 0) {
1898				/*
1899				 * A stale context - remove it
1900				 */
1901				LIST_REMOVE(cp, gss_svc_entries);
1902				if (cp->gss_svc_seqbits)
1903					FREE(cp->gss_svc_seqbits, M_TEMP);
1904				lck_mtx_destroy(cp->gss_svc_mtx, nfs_gss_svc_grp);
1905				FREE(cp, M_TEMP);
1906				contexts--;
1907			}
1908		}
1909	}
1910
1911	nfs_gss_ctx_count = contexts;
1912
1913	/*
1914	 * If there are still some cached contexts left,
1915	 * set up another callout to check on them later.
1916	 */
1917	nfs_gss_timer_on = nfs_gss_ctx_count > 0;
1918	if (nfs_gss_timer_on)
1919		nfs_interval_timer_start(nfs_gss_svc_ctx_timer_call,
1920			min(GSS_TIMER_PERIOD, max(GSS_CTX_TTL_MIN, nfsrv_gss_context_ttl)) * MSECS_PER_SEC);
1921
1922	lck_mtx_unlock(nfs_gss_svc_ctx_mutex);
1923}
1924
1925/*
1926 * Here the server receives an RPCSEC_GSS credential in an
1927 * RPC call header.  First there's some checking to make sure
1928 * the credential is appropriate - whether the context is still
1929 * being set up, or is complete.  Then we use the handle to find
1930 * the server's context and validate the verifier, which contains
1931 * a signed checksum of the RPC header. If the verifier checks
1932 * out, we extract the user's UID and groups from the context
1933 * and use it to set up a UNIX credential for the user's request.
1934 */
1935int
1936nfs_gss_svc_cred_get(struct nfsrv_descript *nd, struct nfsm_chain *nmc)
1937{
1938	uint32_t vers, proc, seqnum, service;
1939	uint32_t handle, handle_len;
1940	struct nfs_gss_svc_ctx *cp = NULL;
1941	uint32_t flavor = 0, verflen = 0;
1942	int error = 0;
1943	uint32_t arglen, start, toklen, cksumlen;
1944	u_char tokbuf[KRB5_SZ_TOKMAX(MAX_DIGEST)];
1945	u_char cksum1[MAX_DIGEST], cksum2[MAX_DIGEST];
1946	struct nfsm_chain nmc_tmp;
1947	gss_key_info *ki;
1948
1949	vers = proc = seqnum = service = handle_len = 0;
1950	arglen = cksumlen = 0;
1951
1952	nfsm_chain_get_32(error, nmc, vers);
1953	if (vers != RPCSEC_GSS_VERS_1) {
1954		error = NFSERR_AUTHERR | AUTH_REJECTCRED;
1955		goto nfsmout;
1956	}
1957
1958	nfsm_chain_get_32(error, nmc, proc);
1959	nfsm_chain_get_32(error, nmc, seqnum);
1960	nfsm_chain_get_32(error, nmc, service);
1961	nfsm_chain_get_32(error, nmc, handle_len);
1962	if (error)
1963		goto nfsmout;
1964
1965	/*
1966	 * Make sure context setup/destroy is being done with a nullproc
1967	 */
1968	if (proc != RPCSEC_GSS_DATA && nd->nd_procnum != NFSPROC_NULL) {
1969		error = NFSERR_AUTHERR | RPCSEC_GSS_CREDPROBLEM;
1970		goto nfsmout;
1971	}
1972
1973	/*
1974	 * If the sequence number is greater than the max
1975	 * allowable, reject and have the client init a
1976	 * new context.
1977	 */
1978	if (seqnum > GSS_MAXSEQ) {
1979		error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM;
1980		goto nfsmout;
1981	}
1982
1983	nd->nd_sec =
1984		service == RPCSEC_GSS_SVC_NONE ?      RPCAUTH_KRB5 :
1985		service == RPCSEC_GSS_SVC_INTEGRITY ? RPCAUTH_KRB5I :
1986		service == RPCSEC_GSS_SVC_PRIVACY ?   RPCAUTH_KRB5P : 0;
1987
1988	if (proc == RPCSEC_GSS_INIT) {
1989		/*
1990		 * Limit the total number of contexts
1991		 */
1992		if (nfs_gss_ctx_count > nfs_gss_ctx_max) {
1993			error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM;
1994			goto nfsmout;
1995		}
1996
1997		/*
1998		 * Set up a new context
1999		 */
2000		MALLOC(cp, struct nfs_gss_svc_ctx *, sizeof(*cp), M_TEMP, M_WAITOK|M_ZERO);
2001		if (cp == NULL) {
2002			error = ENOMEM;
2003			goto nfsmout;
2004		}
2005		cp->gss_svc_mtx = lck_mtx_alloc_init(nfs_gss_svc_grp, LCK_ATTR_NULL);
2006		cp->gss_svc_refcnt = 1;
2007	} else {
2008
2009		/*
2010		 * Use the handle to find the context
2011		 */
2012		if (handle_len != sizeof(handle)) {
2013			error = NFSERR_AUTHERR | RPCSEC_GSS_CREDPROBLEM;
2014			goto nfsmout;
2015		}
2016		nfsm_chain_get_32(error, nmc, handle);
2017		if (error)
2018			goto nfsmout;
2019		cp = nfs_gss_svc_ctx_find(handle);
2020		if (cp == NULL) {
2021			error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM;
2022			goto nfsmout;
2023		}
2024	}
2025
2026	cp->gss_svc_proc = proc;
2027	ki = &cp->gss_svc_kinfo;
2028
2029	if (proc == RPCSEC_GSS_DATA || proc == RPCSEC_GSS_DESTROY) {
2030		struct posix_cred temp_pcred;
2031
2032		if (cp->gss_svc_seqwin == 0) {
2033			/*
2034			 * Context isn't complete
2035			 */
2036			error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM;
2037			goto nfsmout;
2038		}
2039
2040		if (!nfs_gss_svc_seqnum_valid(cp, seqnum)) {
2041			/*
2042			 * Sequence number is bad
2043			 */
2044			error = EINVAL;	// drop the request
2045			goto nfsmout;
2046		}
2047
2048		/* Now compute the client's call header checksum */
2049		nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), 0, 0, cksum1);
2050
2051		/*
2052		 * Validate the verifier.
2053		 * The verifier contains an encrypted checksum
2054		 * of the call header from the XID up to and
2055		 * including the credential.  We compute the
2056		 * checksum and compare it with what came in
2057		 * the verifier.
2058		 */
2059		nfsm_chain_get_32(error, nmc, flavor);
2060		nfsm_chain_get_32(error, nmc, verflen);
2061		if (error)
2062			goto nfsmout;
2063		if (flavor != RPCSEC_GSS || verflen != KRB5_SZ_TOKEN(ki->hash_len))
2064			error = NFSERR_AUTHERR | AUTH_BADVERF;
2065		nfsm_chain_get_opaque(error, nmc, verflen, tokbuf);
2066		if (error)
2067			goto nfsmout;
2068
2069		/* Get the checksum from the token inside the verifier */
2070		error = nfs_gss_token_get(ki, ALG_MIC(ki), tokbuf, 1,
2071			NULL, cksum2);
2072		if (error)
2073			goto nfsmout;
2074
2075		if (bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) {
2076			error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM;
2077			goto nfsmout;
2078		}
2079
2080		nd->nd_gss_seqnum = seqnum;
2081
2082		/*
2083		 * Set up the user's cred
2084		 */
2085		bzero(&temp_pcred, sizeof(temp_pcred));
2086		temp_pcred.cr_uid = cp->gss_svc_uid;
2087		bcopy(cp->gss_svc_gids, temp_pcred.cr_groups,
2088				sizeof(gid_t) * cp->gss_svc_ngroups);
2089		temp_pcred.cr_ngroups = cp->gss_svc_ngroups;
2090
2091		nd->nd_cr = posix_cred_create(&temp_pcred);
2092		if (nd->nd_cr == NULL) {
2093			error = ENOMEM;
2094			goto nfsmout;
2095		}
2096		clock_get_uptime(&cp->gss_svc_incarnation);
2097
2098		/*
2099		 * If the call arguments are integrity or privacy protected
2100		 * then we need to check them here.
2101		 */
2102		switch (service) {
2103		case RPCSEC_GSS_SVC_NONE:
2104			/* nothing to do */
2105			break;
2106		case RPCSEC_GSS_SVC_INTEGRITY:
2107			/*
2108			 * Here's what we expect in the integrity call args:
2109			 *
2110			 * - length of seq num + call args (4 bytes)
2111			 * - sequence number (4 bytes)
2112			 * - call args (variable bytes)
2113			 * - length of checksum token (37)
2114			 * - checksum of seqnum + call args (37 bytes)
2115			 */
2116			nfsm_chain_get_32(error, nmc, arglen);		// length of args
2117			if (arglen > NFS_MAXPACKET) {
2118				error = EBADRPC;
2119				goto nfsmout;
2120			}
2121
2122			/* Compute the checksum over the call args */
2123			start = nfsm_chain_offset(nmc);
2124			nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), start, arglen, cksum1);
2125
2126			/*
2127			 * Get the sequence number prepended to the args
2128			 * and compare it against the one sent in the
2129			 * call credential.
2130			 */
2131			nfsm_chain_get_32(error, nmc, seqnum);
2132			if (seqnum != nd->nd_gss_seqnum) {
2133				error = EBADRPC;			// returns as GARBAGEARGS
2134				goto nfsmout;
2135			}
2136
2137			/*
2138			 * Advance to the end of the args and
2139			 * fetch the checksum computed by the client.
2140			 */
2141			nmc_tmp = *nmc;
2142			arglen -= NFSX_UNSIGNED;			// skipped seqnum
2143			nfsm_chain_adv(error, &nmc_tmp, arglen);	// skip args
2144			nfsm_chain_get_32(error, &nmc_tmp, cksumlen);	// length of checksum
2145			if (cksumlen != KRB5_SZ_TOKEN(ki->hash_len)) {
2146				error = EBADRPC;
2147				goto nfsmout;
2148			}
2149			nfsm_chain_get_opaque(error, &nmc_tmp, cksumlen, tokbuf);
2150			if (error)
2151				goto nfsmout;
2152			error = nfs_gss_token_get(ki, ALG_MIC(ki), tokbuf, 1,
2153				NULL, cksum2);
2154
2155			/* Verify that the checksums are the same */
2156			if (error || bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) {
2157				error = EBADRPC;
2158				goto nfsmout;
2159			}
2160			break;
2161		case RPCSEC_GSS_SVC_PRIVACY:
2162			/*
2163			 * Here's what we expect in the privacy call args:
2164			 *
2165			 * - length of confounder + seq num + token + call args
2166			 * - wrap token (37-40 bytes)
2167			 * - confounder (8 bytes)
2168			 * - sequence number (4 bytes)
2169			 * - call args (encrypted)
2170			 */
2171			nfsm_chain_get_32(error, nmc, arglen);		// length of args
2172			if (arglen > NFS_MAXPACKET) {
2173				error = EBADRPC;
2174				goto nfsmout;
2175			}
2176
2177			/* Get the token that prepends the encrypted args */
2178			nfsm_chain_get_opaque(error, nmc, KRB5_SZ_TOKMAX(ki->hash_len), tokbuf);
2179			if (error)
2180				goto nfsmout;
2181			error = nfs_gss_token_get(ki, ALG_WRAP(ki), tokbuf, 1,
2182							&toklen, cksum1);
2183			if (error)
2184				goto nfsmout;
2185			nfsm_chain_reverse(nmc, nfsm_pad(toklen));
2186
2187			/* decrypt the 8 byte confounder + seqnum + args */
2188			start = nfsm_chain_offset(nmc);
2189			arglen -= toklen;
2190			nfs_gss_encrypt_chain(ki, nmc, start, arglen, DES_DECRYPT);
2191
2192			/* Compute a checksum over the sequence number + results */
2193			nfs_gss_cksum_chain(ki, nmc, ALG_WRAP(ki), start, arglen, cksum2);
2194
2195			/* Verify that the checksums are the same */
2196			if (bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) {
2197				error = EBADRPC;
2198				goto nfsmout;
2199			}
2200
2201			/*
2202			 * Get the sequence number prepended to the args
2203			 * and compare it against the one sent in the
2204			 * call credential.
2205			 */
2206			nfsm_chain_adv(error, nmc, 8);			// skip over the confounder
2207			nfsm_chain_get_32(error, nmc, seqnum);
2208			if (seqnum != nd->nd_gss_seqnum) {
2209				error = EBADRPC;			// returns as GARBAGEARGS
2210				goto nfsmout;
2211			}
2212			break;
2213		}
2214	} else {
2215		/*
2216		 * If the proc is RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT
2217		 * then we expect a null verifier.
2218		 */
2219		nfsm_chain_get_32(error, nmc, flavor);
2220		nfsm_chain_get_32(error, nmc, verflen);
2221		if (error || flavor != RPCAUTH_NULL || verflen > 0)
2222			error = NFSERR_AUTHERR | RPCSEC_GSS_CREDPROBLEM;
2223		if (error) {
2224			if (proc == RPCSEC_GSS_INIT) {
2225				lck_mtx_destroy(cp->gss_svc_mtx, nfs_gss_svc_grp);
2226				FREE(cp, M_TEMP);
2227				cp = NULL;
2228			}
2229			goto nfsmout;
2230		}
2231	}
2232
2233	nd->nd_gss_context = cp;
2234	return 0;
2235nfsmout:
2236	if (cp)
2237		nfs_gss_svc_ctx_deref(cp);
2238	return (error);
2239}
2240
2241/*
2242 * Insert the server's verifier into the RPC reply header.
2243 * It contains a signed checksum of the sequence number that
2244 * was received in the RPC call.
2245 * Then go on to add integrity or privacy if necessary.
2246 */
2247int
2248nfs_gss_svc_verf_put(struct nfsrv_descript *nd, struct nfsm_chain *nmc)
2249{
2250	struct nfs_gss_svc_ctx *cp;
2251	int error = 0;
2252	u_char tokbuf[KRB5_SZ_TOKEN(MAX_DIGEST)];
2253	int toklen;
2254	u_char cksum[MAX_DIGEST];
2255	gss_key_info *ki;
2256
2257	cp = nd->nd_gss_context;
2258	ki = &cp->gss_svc_kinfo;
2259
2260	if (cp->gss_svc_major != GSS_S_COMPLETE) {
2261		/*
2262		 * If the context isn't yet complete
2263		 * then return a null verifier.
2264		 */
2265		nfsm_chain_add_32(error, nmc, RPCAUTH_NULL);
2266		nfsm_chain_add_32(error, nmc, 0);
2267		return (error);
2268	}
2269
2270	/*
2271	 * Compute checksum of the request seq number
2272	 * If it's the final reply of context setup
2273	 * then return the checksum of the context
2274	 * window size.
2275	 */
2276	if (cp->gss_svc_proc == RPCSEC_GSS_INIT ||
2277	    cp->gss_svc_proc == RPCSEC_GSS_CONTINUE_INIT)
2278		nfs_gss_cksum_rep(ki, cp->gss_svc_seqwin, cksum);
2279	else
2280		nfs_gss_cksum_rep(ki, nd->nd_gss_seqnum, cksum);
2281	/*
2282	 * Now wrap it in a token and add
2283	 * the verifier to the reply.
2284	 */
2285	toklen = nfs_gss_token_put(ki, ALG_MIC(ki), tokbuf, 0, 0, cksum);
2286	nfsm_chain_add_32(error, nmc, RPCSEC_GSS);
2287	nfsm_chain_add_32(error, nmc, toklen);
2288	nfsm_chain_add_opaque(error, nmc, tokbuf, toklen);
2289
2290	return (error);
2291}
2292
2293/*
2294 * The results aren't available yet, but if they need to be
2295 * checksummed for integrity protection or encrypted, then
2296 * we can record the start offset here, insert a place-holder
2297 * for the results length, as well as the sequence number.
2298 * The rest of the work is done later by nfs_gss_svc_protect_reply()
2299 * when the results are available.
2300 */
2301int
2302nfs_gss_svc_prepare_reply(struct nfsrv_descript *nd, struct nfsm_chain *nmc)
2303{
2304	struct nfs_gss_svc_ctx *cp = nd->nd_gss_context;
2305	int error = 0;
2306
2307	if (cp->gss_svc_proc == RPCSEC_GSS_INIT ||
2308	    cp->gss_svc_proc == RPCSEC_GSS_CONTINUE_INIT)
2309		return (0);
2310
2311	switch (nd->nd_sec) {
2312	case RPCAUTH_KRB5:
2313		/* Nothing to do */
2314		break;
2315	case RPCAUTH_KRB5I:
2316		nd->nd_gss_mb = nmc->nmc_mcur;			// record current mbuf
2317		nfsm_chain_finish_mbuf(error, nmc);		// split the chain here
2318		nfsm_chain_add_32(error, nmc, nd->nd_gss_seqnum); // req sequence number
2319		break;
2320	case RPCAUTH_KRB5P:
2321		nd->nd_gss_mb = nmc->nmc_mcur;			// record current mbuf
2322		nfsm_chain_finish_mbuf(error, nmc);		// split the chain here
2323		nfsm_chain_add_32(error, nmc, random());	// confounder bytes 1-4
2324		nfsm_chain_add_32(error, nmc, random());	// confounder bytes 5-8
2325		nfsm_chain_add_32(error, nmc, nd->nd_gss_seqnum); // req sequence number
2326		break;
2327	}
2328
2329	return (error);
2330}
2331
2332/*
2333 * The results are checksummed or encrypted for return to the client
2334 */
2335int
2336nfs_gss_svc_protect_reply(struct nfsrv_descript *nd, mbuf_t mrep)
2337{
2338	struct nfs_gss_svc_ctx *cp = nd->nd_gss_context;
2339	struct nfsm_chain nmrep_res, *nmc_res = &nmrep_res;
2340	struct nfsm_chain nmrep_pre, *nmc_pre = &nmrep_pre;
2341	mbuf_t mb, results;
2342	uint32_t reslen;
2343	u_char tokbuf[KRB5_SZ_TOKMAX(MAX_DIGEST)];
2344	int pad, toklen;
2345	u_char cksum[MAX_DIGEST];
2346	int error = 0;
2347	gss_key_info *ki = &cp->gss_svc_kinfo;
2348
2349	/*
2350	 * Using a reference to the mbuf where we previously split the reply
2351	 * mbuf chain, we split the mbuf chain argument into two mbuf chains,
2352	 * one that allows us to prepend a length field or token, (nmc_pre)
2353	 * and the second which holds just the results that we're going to
2354	 * checksum and/or encrypt.  When we're done, we join the chains back
2355	 * together.
2356	 */
2357	nfs_gss_nfsm_chain(nmc_res, mrep);		// set up the results chain
2358	mb = nd->nd_gss_mb;				// the mbuf where we split
2359	results = mbuf_next(mb);			// first mbuf in the results
2360	reslen = nfs_gss_mchain_length(results);	// length of results
2361	error = mbuf_setnext(mb, NULL);			// disconnect the chains
2362	if (error)
2363		return (error);
2364	nfs_gss_nfsm_chain(nmc_pre, mb);		// set up the prepend chain
2365
2366	if (nd->nd_sec == RPCAUTH_KRB5I) {
2367		nfsm_chain_add_32(error, nmc_pre, reslen);
2368		nfsm_chain_build_done(error, nmc_pre);
2369		if (error)
2370			return (error);
2371		nfs_gss_append_chain(nmc_pre, results);	// Append the results mbufs
2372
2373		/* Now compute the checksum over the results data */
2374		nfs_gss_cksum_mchain(ki, results, ALG_MIC(ki), 0, reslen, cksum);
2375
2376		/* Put it into a token and append to the request */
2377		toklen = nfs_gss_token_put(ki, ALG_MIC(ki), tokbuf, 0, 0, cksum);
2378		nfsm_chain_add_32(error, nmc_res, toklen);
2379		nfsm_chain_add_opaque(error, nmc_res, tokbuf, toklen);
2380		nfsm_chain_build_done(error, nmc_res);
2381	} else {
2382		/* RPCAUTH_KRB5P */
2383		/*
2384		 * Append a pad trailer - per RFC 1964 section 1.2.2.3
2385		 * Since XDR data is always 32-bit aligned, it
2386		 * needs to be padded either by 4 bytes or 8 bytes.
2387		 */
2388		if (reslen % 8 > 0) {
2389			nfsm_chain_add_32(error, nmc_res, 0x04040404);
2390			reslen += NFSX_UNSIGNED;
2391		} else {
2392			nfsm_chain_add_32(error, nmc_res, 0x08080808);
2393			nfsm_chain_add_32(error, nmc_res, 0x08080808);
2394			reslen +=  2 * NFSX_UNSIGNED;
2395		}
2396		nfsm_chain_build_done(error, nmc_res);
2397
2398		/* Now compute the checksum over the results data */
2399		nfs_gss_cksum_mchain(ki, results, ALG_WRAP(ki), 0, reslen, cksum);
2400
2401		/* Put it into a token and insert in the reply */
2402		toklen = nfs_gss_token_put(ki, ALG_WRAP(ki), tokbuf, 0, reslen, cksum);
2403		nfsm_chain_add_32(error, nmc_pre, toklen + reslen);
2404		nfsm_chain_add_opaque_nopad(error, nmc_pre, tokbuf, toklen);
2405		nfsm_chain_build_done(error, nmc_pre);
2406		if (error)
2407			return (error);
2408		nfs_gss_append_chain(nmc_pre, results);	// Append the results mbufs
2409
2410		/* Encrypt the confounder + seqnum + results */
2411		nfs_gss_encrypt_mchain(ki, results, 0, reslen, DES_ENCRYPT);
2412
2413		/* Add null XDR pad if the ASN.1 token misaligned the data */
2414		pad = nfsm_pad(toklen + reslen);
2415		if (pad > 0) {
2416			nfsm_chain_add_opaque_nopad(error, nmc_pre, iv0, pad);
2417			nfsm_chain_build_done(error, nmc_pre);
2418		}
2419	}
2420
2421	return (error);
2422}
2423
2424/*
2425 * This function handles the context setup calls from the client.
2426 * Essentially, it implements the NFS null procedure calls when
2427 * an RPCSEC_GSS credential is used.
2428 * This is the context maintenance function.  It creates and
2429 * destroys server contexts at the whim of the client.
2430 * During context creation, it receives GSS-API tokens from the
2431 * client, passes them up to gssd, and returns a received token
2432 * back to the client in the null procedure reply.
2433 */
2434int
2435nfs_gss_svc_ctx_init(struct nfsrv_descript *nd, struct nfsrv_sock *slp, mbuf_t *mrepp)
2436{
2437	struct nfs_gss_svc_ctx *cp = NULL;
2438	int error = 0;
2439	int autherr = 0;
2440	struct nfsm_chain *nmreq, nmrep;
2441	int sz;
2442
2443	nmreq = &nd->nd_nmreq;
2444	nfsm_chain_null(&nmrep);
2445	*mrepp = NULL;
2446	cp = nd->nd_gss_context;
2447	nd->nd_repstat = 0;
2448
2449	switch (cp->gss_svc_proc) {
2450	case RPCSEC_GSS_INIT:
2451		nfs_gss_svc_ctx_insert(cp);
2452		/* FALLTHRU */
2453
2454	case RPCSEC_GSS_CONTINUE_INIT:
2455		/* Get the token from the request */
2456		nfsm_chain_get_32(error, nmreq, cp->gss_svc_tokenlen);
2457		if (cp->gss_svc_tokenlen == 0) {
2458			autherr = RPCSEC_GSS_CREDPROBLEM;
2459			break;
2460		}
2461		MALLOC(cp->gss_svc_token, u_char *, cp->gss_svc_tokenlen, M_TEMP, M_WAITOK);
2462		if (cp->gss_svc_token == NULL) {
2463			autherr = RPCSEC_GSS_CREDPROBLEM;
2464			break;
2465		}
2466		nfsm_chain_get_opaque(error, nmreq, cp->gss_svc_tokenlen, cp->gss_svc_token);
2467
2468		/* Use the token in a gss_accept_sec_context upcall */
2469		error = nfs_gss_svc_gssd_upcall(cp);
2470		if (error) {
2471			autherr = RPCSEC_GSS_CREDPROBLEM;
2472			if (error == NFSERR_EAUTH)
2473				error = 0;
2474			break;
2475		}
2476
2477		/*
2478		 * If the context isn't complete, pass the new token
2479		 * back to the client for another round.
2480		 */
2481		if (cp->gss_svc_major != GSS_S_COMPLETE)
2482			break;
2483
2484		/*
2485		 * Now the server context is complete.
2486		 * Finish setup.
2487		 */
2488		clock_get_uptime(&cp->gss_svc_incarnation);
2489
2490		cp->gss_svc_seqwin = GSS_SVC_SEQWINDOW;
2491		MALLOC(cp->gss_svc_seqbits, uint32_t *,
2492			nfsm_rndup((cp->gss_svc_seqwin + 7) / 8), M_TEMP, M_WAITOK|M_ZERO);
2493		if (cp->gss_svc_seqbits == NULL) {
2494			autherr = RPCSEC_GSS_CREDPROBLEM;
2495			break;
2496		}
2497		break;
2498
2499	case RPCSEC_GSS_DATA:
2500		/* Just a nullproc ping - do nothing */
2501		break;
2502
2503	case RPCSEC_GSS_DESTROY:
2504		/*
2505		 * Don't destroy the context immediately because
2506		 * other active requests might still be using it.
2507		 * Instead, schedule it for destruction after
2508		 * GSS_CTX_PEND time has elapsed.
2509		 */
2510		cp = nfs_gss_svc_ctx_find(cp->gss_svc_handle);
2511		if (cp != NULL) {
2512			cp->gss_svc_handle = 0;	// so it can't be found
2513			lck_mtx_lock(cp->gss_svc_mtx);
2514			clock_interval_to_deadline(GSS_CTX_PEND, NSEC_PER_SEC,
2515				&cp->gss_svc_incarnation);
2516			lck_mtx_unlock(cp->gss_svc_mtx);
2517		}
2518		break;
2519	default:
2520		autherr = RPCSEC_GSS_CREDPROBLEM;
2521		break;
2522	}
2523
2524	/* Now build the reply  */
2525
2526	if (nd->nd_repstat == 0)
2527		nd->nd_repstat = autherr ? (NFSERR_AUTHERR | autherr) : NFSERR_RETVOID;
2528	sz = 7 * NFSX_UNSIGNED + nfsm_rndup(cp->gss_svc_tokenlen); // size of results
2529	error = nfsrv_rephead(nd, slp, &nmrep, sz);
2530	*mrepp = nmrep.nmc_mhead;
2531	if (error || autherr)
2532		goto nfsmout;
2533
2534	if (cp->gss_svc_proc == RPCSEC_GSS_INIT ||
2535	    cp->gss_svc_proc == RPCSEC_GSS_CONTINUE_INIT) {
2536		nfsm_chain_add_32(error, &nmrep, sizeof(cp->gss_svc_handle));
2537		nfsm_chain_add_32(error, &nmrep, cp->gss_svc_handle);
2538
2539		nfsm_chain_add_32(error, &nmrep, cp->gss_svc_major);
2540		nfsm_chain_add_32(error, &nmrep, cp->gss_svc_minor);
2541		nfsm_chain_add_32(error, &nmrep, cp->gss_svc_seqwin);
2542
2543		nfsm_chain_add_32(error, &nmrep, cp->gss_svc_tokenlen);
2544		if (cp->gss_svc_token != NULL) {
2545			nfsm_chain_add_opaque(error, &nmrep, cp->gss_svc_token, cp->gss_svc_tokenlen);
2546			FREE(cp->gss_svc_token, M_TEMP);
2547			cp->gss_svc_token = NULL;
2548		}
2549	}
2550
2551nfsmout:
2552	if (autherr != 0) {
2553		nd->nd_gss_context = NULL;
2554		LIST_REMOVE(cp, gss_svc_entries);
2555		if (cp->gss_svc_seqbits != NULL)
2556			FREE(cp->gss_svc_seqbits, M_TEMP);
2557		if (cp->gss_svc_token != NULL)
2558			FREE(cp->gss_svc_token, M_TEMP);
2559		lck_mtx_destroy(cp->gss_svc_mtx, nfs_gss_svc_grp);
2560		FREE(cp, M_TEMP);
2561	}
2562
2563	nfsm_chain_build_done(error, &nmrep);
2564	if (error) {
2565		nfsm_chain_cleanup(&nmrep);
2566		*mrepp = NULL;
2567	}
2568	return (error);
2569}
2570
2571/*
2572 * This is almost a mirror-image of the client side upcall.
2573 * It passes and receives a token, but invokes gss_accept_sec_context.
2574 * If it's the final call of the context setup, then gssd also returns
2575 * the session key and the user's UID.
2576 */
2577static int
2578nfs_gss_svc_gssd_upcall(struct nfs_gss_svc_ctx *cp)
2579{
2580	kern_return_t kr;
2581	mach_port_t mp;
2582	int retry_cnt = 0;
2583	gssd_byte_buffer okey = NULL;
2584	uint32_t skeylen = 0;
2585	uint32_t ret_flags;
2586	vm_map_copy_t itoken = NULL;
2587	gssd_byte_buffer otoken = NULL;
2588	mach_msg_type_number_t otokenlen;
2589	int error = 0;
2590	char svcname[] = "nfs";
2591
2592	kr = host_get_gssd_port(host_priv_self(), &mp);
2593	if (kr != KERN_SUCCESS) {
2594		printf("nfs_gss_svc_gssd_upcall: can't get gssd port, status %x (%d)\n", kr, kr);
2595		goto out;
2596	}
2597	if (!IPC_PORT_VALID(mp)) {
2598		printf("nfs_gss_svc_gssd_upcall: gssd port not valid\n");
2599		goto out;
2600	}
2601
2602	if (cp->gss_svc_tokenlen > 0)
2603		nfs_gss_mach_alloc_buffer(cp->gss_svc_token, cp->gss_svc_tokenlen, &itoken);
2604
2605retry:
2606	kr = mach_gss_accept_sec_context(
2607		mp,
2608		(gssd_byte_buffer) itoken, (mach_msg_type_number_t) cp->gss_svc_tokenlen,
2609		svcname,
2610		0,
2611		&cp->gss_svc_context,
2612		&cp->gss_svc_cred_handle,
2613		&ret_flags,
2614		&cp->gss_svc_uid,
2615		cp->gss_svc_gids,
2616		&cp->gss_svc_ngroups,
2617		&okey, (mach_msg_type_number_t *) &skeylen,
2618		&otoken, &otokenlen,
2619		&cp->gss_svc_major,
2620		&cp->gss_svc_minor);
2621
2622	if (kr != KERN_SUCCESS) {
2623		printf("nfs_gss_svc_gssd_upcall failed: %x (%d)\n", kr, kr);
2624		if (kr == MIG_SERVER_DIED && cp->gss_svc_context == 0 &&
2625			retry_cnt++ < NFS_GSS_MACH_MAX_RETRIES) {
2626			if (cp->gss_svc_tokenlen > 0)
2627				nfs_gss_mach_alloc_buffer(cp->gss_svc_token, cp->gss_svc_tokenlen, &itoken);
2628			goto retry;
2629		}
2630		host_release_special_port(mp);
2631		goto out;
2632	}
2633
2634	host_release_special_port(mp);
2635
2636	if (skeylen > 0) {
2637		if (skeylen != SKEYLEN && skeylen != SKEYLEN3) {
2638			printf("nfs_gss_svc_gssd_upcall: bad key length (%d)\n", skeylen);
2639			vm_map_copy_discard((vm_map_copy_t) okey);
2640			vm_map_copy_discard((vm_map_copy_t) otoken);
2641			goto out;
2642		}
2643		error = nfs_gss_mach_vmcopyout((vm_map_copy_t) okey, skeylen, cp->gss_svc_kinfo.skey);
2644		if (error) {
2645			vm_map_copy_discard((vm_map_copy_t) otoken);
2646			goto out;
2647		}
2648		error = gss_key_init(&cp->gss_svc_kinfo, skeylen);
2649		if (error)
2650			goto out;
2651
2652	}
2653
2654	/* Free context token used as input */
2655	if (cp->gss_svc_token)
2656		FREE(cp->gss_svc_token, M_TEMP);
2657	cp->gss_svc_token = NULL;
2658	cp->gss_svc_tokenlen = 0;
2659
2660	if (otokenlen > 0) {
2661		/* Set context token to gss output token */
2662		MALLOC(cp->gss_svc_token, u_char *, otokenlen, M_TEMP, M_WAITOK);
2663		if (cp->gss_svc_token == NULL) {
2664			printf("nfs_gss_svc_gssd_upcall: could not allocate %d bytes\n", otokenlen);
2665			vm_map_copy_discard((vm_map_copy_t) otoken);
2666			return (ENOMEM);
2667		}
2668		error = nfs_gss_mach_vmcopyout((vm_map_copy_t) otoken, otokenlen, cp->gss_svc_token);
2669		if (error) {
2670			FREE(cp->gss_svc_token, M_TEMP);
2671			cp->gss_svc_token = NULL;
2672			return (NFSERR_EAUTH);
2673		}
2674		cp->gss_svc_tokenlen = otokenlen;
2675	}
2676
2677	return (0);
2678
2679out:
2680	FREE(cp->gss_svc_token, M_TEMP);
2681	cp->gss_svc_tokenlen = 0;
2682	cp->gss_svc_token = NULL;
2683
2684	return (NFSERR_EAUTH);
2685}
2686
2687/*
2688 * Validate the sequence number in the credential as described
2689 * in RFC 2203 Section 5.3.3.1
2690 *
2691 * Here the window of valid sequence numbers is represented by
2692 * a bitmap.  As each sequence number is received, its bit is
2693 * set in the bitmap.  An invalid sequence number lies below
2694 * the lower bound of the window, or is within the window but
2695 * has its bit already set.
2696 */
2697static int
2698nfs_gss_svc_seqnum_valid(struct nfs_gss_svc_ctx *cp, uint32_t seq)
2699{
2700	uint32_t *bits = cp->gss_svc_seqbits;
2701	uint32_t win = cp->gss_svc_seqwin;
2702	uint32_t i;
2703
2704	lck_mtx_lock(cp->gss_svc_mtx);
2705
2706	/*
2707	 * If greater than the window upper bound,
2708	 * move the window up, and set the bit.
2709	 */
2710	if (seq > cp->gss_svc_seqmax) {
2711		if (seq - cp->gss_svc_seqmax > win)
2712			bzero(bits, nfsm_rndup((win + 7) / 8));
2713		else
2714			for (i = cp->gss_svc_seqmax + 1; i < seq; i++)
2715				win_resetbit(bits, i % win);
2716		win_setbit(bits, seq % win);
2717		cp->gss_svc_seqmax = seq;
2718		lck_mtx_unlock(cp->gss_svc_mtx);
2719		return (1);
2720	}
2721
2722	/*
2723	 * Invalid if below the lower bound of the window
2724	 */
2725	if (seq <= cp->gss_svc_seqmax - win) {
2726		lck_mtx_unlock(cp->gss_svc_mtx);
2727		return (0);
2728	}
2729
2730	/*
2731	 * In the window, invalid if the bit is already set
2732	 */
2733	if (win_getbit(bits, seq % win)) {
2734		lck_mtx_unlock(cp->gss_svc_mtx);
2735		return (0);
2736	}
2737	win_setbit(bits, seq % win);
2738	lck_mtx_unlock(cp->gss_svc_mtx);
2739	return (1);
2740}
2741
2742/*
2743 * Drop a reference to a context
2744 *
2745 * Note that it's OK for the context to exist
2746 * with a refcount of zero.  The refcount isn't
2747 * checked until we're about to reap an expired one.
2748 */
2749void
2750nfs_gss_svc_ctx_deref(struct nfs_gss_svc_ctx *cp)
2751{
2752	lck_mtx_lock(cp->gss_svc_mtx);
2753	if (cp->gss_svc_refcnt > 0)
2754		cp->gss_svc_refcnt--;
2755	else
2756		printf("nfs_gss_ctx_deref: zero refcount\n");
2757	lck_mtx_unlock(cp->gss_svc_mtx);
2758}
2759
2760/*
2761 * Called at NFS server shutdown - destroy all contexts
2762 */
2763void
2764nfs_gss_svc_cleanup(void)
2765{
2766	struct nfs_gss_svc_ctx_hashhead *head;
2767	struct nfs_gss_svc_ctx *cp, *ncp;
2768	int i;
2769
2770	lck_mtx_lock(nfs_gss_svc_ctx_mutex);
2771
2772	/*
2773	 * Run through all the buckets
2774	 */
2775	for (i = 0; i < SVC_CTX_HASHSZ; i++) {
2776		/*
2777		 * Remove and free all entries in the bucket
2778		 */
2779		head = &nfs_gss_svc_ctx_hashtbl[i];
2780		LIST_FOREACH_SAFE(cp, head, gss_svc_entries, ncp) {
2781			LIST_REMOVE(cp, gss_svc_entries);
2782			if (cp->gss_svc_seqbits)
2783				FREE(cp->gss_svc_seqbits, M_TEMP);
2784			lck_mtx_destroy(cp->gss_svc_mtx, nfs_gss_svc_grp);
2785			FREE(cp, M_TEMP);
2786		}
2787	}
2788
2789	lck_mtx_unlock(nfs_gss_svc_ctx_mutex);
2790}
2791
2792#endif /* NFSSERVER */
2793
2794
2795/*************
2796 * The following functions are used by both client and server.
2797 */
2798
2799/*
2800 * Release a host special port that was obtained by host_get_special_port
2801 * or one of its macros (host_get_gssd_port in this case).
2802 * This really should be in a public kpi.
2803 */
2804
2805/* This should be in a public header if this routine is not */
2806extern void ipc_port_release_send(ipc_port_t);
2807extern ipc_port_t ipc_port_copy_send(ipc_port_t);
2808
2809static void
2810host_release_special_port(mach_port_t mp)
2811{
2812	if (IPC_PORT_VALID(mp))
2813		ipc_port_release_send(mp);
2814}
2815
2816static mach_port_t
2817host_copy_special_port(mach_port_t mp)
2818{
2819	return (ipc_port_copy_send(mp));
2820}
2821
2822/*
2823 * The token that is sent and received in the gssd upcall
2824 * has unbounded variable length.  Mach RPC does not pass
2825 * the token in-line.  Instead it uses page mapping to handle
2826 * these parameters.  This function allocates a VM buffer
2827 * to hold the token for an upcall and copies the token
2828 * (received from the client) into it.  The VM buffer is
2829 * marked with a src_destroy flag so that the upcall will
2830 * automatically de-allocate the buffer when the upcall is
2831 * complete.
2832 */
2833static void
2834nfs_gss_mach_alloc_buffer(u_char *buf, uint32_t buflen, vm_map_copy_t *addr)
2835{
2836	kern_return_t kr;
2837	vm_offset_t kmem_buf;
2838	vm_size_t tbuflen;
2839
2840	*addr = NULL;
2841	if (buf == NULL || buflen == 0)
2842		return;
2843
2844	tbuflen = round_page(buflen);
2845	kr = vm_allocate(ipc_kernel_map, &kmem_buf, tbuflen, VM_FLAGS_ANYWHERE);
2846	if (kr != 0) {
2847		printf("nfs_gss_mach_alloc_buffer: vm_allocate failed\n");
2848		return;
2849	}
2850
2851	kr = vm_map_wire(ipc_kernel_map, vm_map_trunc_page(kmem_buf),
2852		vm_map_round_page(kmem_buf + tbuflen),
2853		VM_PROT_READ|VM_PROT_WRITE, FALSE);
2854	if (kr != 0) {
2855		printf("nfs_gss_mach_alloc_buffer: vm_map_wire failed\n");
2856		return;
2857	}
2858
2859	bcopy(buf, (void *) kmem_buf, buflen);
2860	// Shouldn't need to bzero below since vm_allocate returns zeroed pages
2861	// bzero(kmem_buf + buflen, tbuflen - buflen);
2862
2863	kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(kmem_buf),
2864		vm_map_round_page(kmem_buf + tbuflen), FALSE);
2865	if (kr != 0) {
2866		printf("nfs_gss_mach_alloc_buffer: vm_map_unwire failed\n");
2867		return;
2868	}
2869
2870	kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t) kmem_buf,
2871		(vm_map_size_t) buflen, TRUE, addr);
2872	if (kr != 0) {
2873		printf("nfs_gss_mach_alloc_buffer: vm_map_copyin failed\n");
2874		return;
2875	}
2876}
2877
2878/*
2879 * Here we handle a token received from the gssd via an upcall.
2880 * The received token resides in an allocate VM buffer.
2881 * We copy the token out of this buffer to a chunk of malloc'ed
2882 * memory of the right size, then de-allocate the VM buffer.
2883 */
2884static int
2885nfs_gss_mach_vmcopyout(vm_map_copy_t in, uint32_t len, u_char *out)
2886{
2887	vm_map_offset_t map_data;
2888	vm_offset_t data;
2889	int error;
2890
2891	error = vm_map_copyout(ipc_kernel_map, &map_data, in);
2892	if (error)
2893		return (error);
2894
2895	data = CAST_DOWN(vm_offset_t, map_data);
2896	bcopy((void *) data, out, len);
2897	vm_deallocate(ipc_kernel_map, data, len);
2898
2899	return (0);
2900}
2901
2902/*
2903 * Encode an ASN.1 token to be wrapped in an RPCSEC_GSS verifier.
2904 * Returns the size of the token, since it contains a variable
2905 * length DER encoded size field.
2906 */
2907static int
2908nfs_gss_token_put(
2909	gss_key_info *ki,
2910	u_char *alg,
2911	u_char *p,
2912	int initiator,
2913	int datalen,
2914	u_char *cksum)
2915{
2916	static uint32_t seqnum = 0;
2917	u_char *psave = p;
2918	u_char plain[8];
2919	int toklen, i;
2920
2921	/*
2922	 * Fill in the token header: 2 octets.
2923	 * This is 0x06 - an ASN.1 tag for APPLICATION, 0, SEQUENCE
2924	 * followed by the length of the token: 35 + 0 octets for a
2925	 * MIC token, or 35 + encrypted octets for a wrap token;
2926	 */
2927	*p++ = 0x060;
2928	toklen = KRB5_SZ_MECH + KRB5_SZ_ALG + KRB5_SZ_SEQ + HASHLEN(ki);
2929	nfs_gss_der_length_put(&p, toklen + datalen);
2930
2931	/*
2932	 * Fill in the DER encoded mech OID for Kerberos v5.
2933	 * This represents the Kerberos OID 1.2.840.113554.1.2.2
2934	 * described in RFC 2623, section 4.2
2935	 */
2936	bcopy(krb5_mech, p, sizeof(krb5_mech));
2937	p += sizeof(krb5_mech);
2938
2939	/*
2940	 * Now at the token described in RFC 1964, section 1.2.1
2941	 * Fill in the token ID, integrity algorithm indicator,
2942	 * for DES MAC MD5, and four filler octets.
2943	 * The alg string encodes the bytes to represent either
2944	 * a MIC token or a WRAP token for Kerberos.
2945	 */
2946	bcopy(alg, p, KRB5_SZ_ALG);
2947	p += KRB5_SZ_ALG;
2948
2949	/*
2950	 * Now encode the sequence number according to
2951	 * RFC 1964, section 1.2.1.2 which dictates 4 octets
2952	 * of sequence number followed by 4 bytes of direction
2953	 * indicator: 0x00 for initiator or 0xff for acceptor.
2954	 * We DES CBC encrypt the sequence number using the first
2955	 * 8 octets of the checksum field as an initialization
2956	 * vector.
2957	 * Note that this sequence number is not at all related
2958	 * to the RPCSEC_GSS protocol sequence number.  This
2959	 * number is private to the ASN.1 token.  The only
2960	 * requirement is that it not be repeated in case the
2961	 * server has replay detection on, which normally should
2962	 * not be the case, since RFC 2203 section 5.2.3 says that
2963	 * replay detection and sequence checking must be turned off.
2964	 */
2965	seqnum++;
2966	for (i = 0; i < 4; i++)
2967		plain[i] = (u_char) ((seqnum >> (i * 8)) & 0xff);
2968	for (i = 4; i < 8; i++)
2969		plain[i] = initiator ? 0x00 : 0xff;
2970	gss_des_crypt(ki, (des_cblock *) plain, (des_cblock *) p, 8,
2971			(des_cblock *) cksum, NULL, DES_ENCRYPT, KG_USAGE_SEQ);
2972	p += 8;
2973
2974	/*
2975	 * Finally, append the octets of the
2976	 * checksum of the alg + plaintext data.
2977	 * The plaintext could be an RPC call header,
2978	 * the window value, or a sequence number.
2979	 */
2980	bcopy(cksum, p, HASHLEN(ki));
2981	p += HASHLEN(ki);
2982
2983	return (p - psave);
2984}
2985
2986/*
2987 * Determine size of ASN.1 DER length
2988 */
2989static int
2990nfs_gss_der_length_size(int len)
2991{
2992	return
2993		len < (1 <<  7) ? 1 :
2994		len < (1 <<  8) ? 2 :
2995		len < (1 << 16) ? 3 :
2996		len < (1 << 24) ? 4 : 5;
2997}
2998
2999/*
3000 * Encode an ASN.1 DER length field
3001 */
3002static void
3003nfs_gss_der_length_put(u_char **pp, int len)
3004{
3005	int sz = nfs_gss_der_length_size(len);
3006	u_char *p = *pp;
3007
3008	if (sz == 1) {
3009		*p++ = (u_char) len;
3010	} else {
3011		*p++ = (u_char) ((sz-1) | 0x80);
3012		sz -= 1;
3013		while (sz--)
3014			*p++ = (u_char) ((len >> (sz * 8)) & 0xff);
3015	}
3016
3017	*pp = p;
3018}
3019
3020/*
3021 * Decode an ASN.1 DER length field
3022 */
3023static int
3024nfs_gss_der_length_get(u_char **pp)
3025{
3026	u_char *p = *pp;
3027	uint32_t flen, len = 0;
3028
3029	flen = *p & 0x7f;
3030
3031	if ((*p++ & 0x80) == 0)
3032		len = flen;
3033	else {
3034		if (flen > sizeof(uint32_t))
3035			return (-1);
3036		while (flen--)
3037			len = (len << 8) + *p++;
3038	}
3039	*pp = p;
3040	return (len);
3041}
3042
3043/*
3044 * Decode an ASN.1 token from an RPCSEC_GSS verifier.
3045 */
3046static int
3047nfs_gss_token_get(
3048	gss_key_info *ki,
3049	u_char *alg,
3050	u_char *p,
3051	int initiator,
3052	uint32_t *len,
3053	u_char *cksum)
3054{
3055	u_char d, plain[8];
3056	u_char *psave = p;
3057	int seqnum, i;
3058
3059	/*
3060	 * Check that we have a valid token header
3061	 */
3062	if (*p++ != 0x60)
3063		return (AUTH_BADCRED);
3064	(void) nfs_gss_der_length_get(&p);	// ignore the size
3065
3066	/*
3067	 * Check that we have the DER encoded Kerberos v5 mech OID
3068	 */
3069	if (bcmp(p, krb5_mech, sizeof(krb5_mech) != 0))
3070		return (AUTH_BADCRED);
3071	p += sizeof(krb5_mech);
3072
3073	/*
3074	 * Now check the token ID, DES MAC MD5 algorithm
3075	 * indicator, and filler octets.
3076	 */
3077	if (bcmp(p, alg, KRB5_SZ_ALG) != 0)
3078		return (AUTH_BADCRED);
3079	p += KRB5_SZ_ALG;
3080
3081	/*
3082	 * Now decrypt the sequence number.
3083	 * Note that the gss decryption uses the first 8 octets
3084	 * of the checksum field as an initialization vector (p + 8).
3085	 * Per RFC 2203 section 5.2.2 we don't check the sequence number
3086	 * in the ASN.1 token because the RPCSEC_GSS protocol has its
3087	 * own sequence number described in section 5.3.3.1
3088	 */
3089	seqnum = 0;
3090	gss_des_crypt(ki, (des_cblock *)p, (des_cblock *) plain, 8,
3091			(des_cblock *) (p + 8), NULL, DES_DECRYPT, KG_USAGE_SEQ);
3092	p += 8;
3093	for (i = 0; i < 4; i++)
3094		seqnum |= plain[i] << (i * 8);
3095
3096	/*
3097	 * Make sure the direction
3098	 * indicator octets are correct.
3099	 */
3100	d = initiator ? 0x00 : 0xff;
3101	for (i = 4; i < 8; i++)
3102		if (plain[i] != d)
3103			return (AUTH_BADCRED);
3104
3105	/*
3106	 * Finally, get the checksum
3107	 */
3108	bcopy(p, cksum, HASHLEN(ki));
3109	p += HASHLEN(ki);
3110
3111	if (len != NULL)
3112		*len = p - psave;
3113
3114	return (0);
3115}
3116
3117/*
3118 * Return the number of bytes in an mbuf chain.
3119 */
3120static int
3121nfs_gss_mchain_length(mbuf_t mhead)
3122{
3123	mbuf_t mb;
3124	int len = 0;
3125
3126	for (mb = mhead; mb; mb = mbuf_next(mb))
3127		len += mbuf_len(mb);
3128
3129	return (len);
3130}
3131
3132/*
3133 * Append an args or results mbuf chain to the header chain
3134 */
3135static int
3136nfs_gss_append_chain(struct nfsm_chain *nmc, mbuf_t mc)
3137{
3138	int error = 0;
3139	mbuf_t mb, tail;
3140
3141	/* Connect the mbuf chains */
3142	error = mbuf_setnext(nmc->nmc_mcur, mc);
3143	if (error)
3144		return (error);
3145
3146	/* Find the last mbuf in the chain */
3147	tail = NULL;
3148	for (mb = mc; mb; mb = mbuf_next(mb))
3149		tail = mb;
3150
3151	nmc->nmc_mcur = tail;
3152	nmc->nmc_ptr = (caddr_t) mbuf_data(tail) + mbuf_len(tail);
3153	nmc->nmc_left = mbuf_trailingspace(tail);
3154
3155	return (0);
3156}
3157
3158/*
3159 * Convert an mbuf chain to an NFS mbuf chain
3160 */
3161static void
3162nfs_gss_nfsm_chain(struct nfsm_chain *nmc, mbuf_t mc)
3163{
3164	mbuf_t mb, tail;
3165
3166	/* Find the last mbuf in the chain */
3167	tail = NULL;
3168	for (mb = mc; mb; mb = mbuf_next(mb))
3169		tail = mb;
3170
3171	nmc->nmc_mhead = mc;
3172	nmc->nmc_mcur = tail;
3173	nmc->nmc_ptr = (caddr_t) mbuf_data(tail) + mbuf_len(tail);
3174	nmc->nmc_left = mbuf_trailingspace(tail);
3175	nmc->nmc_flags = 0;
3176}
3177
3178
3179/*
3180 * Compute a checksum over an mbuf chain.
3181 * Start building an MD5 digest at the given offset and keep
3182 * going until the end of data in the current mbuf is reached.
3183 * Then convert the 16 byte MD5 digest to an 8 byte DES CBC
3184 * checksum.
3185 */
3186static void
3187nfs_gss_cksum_mchain(
3188	gss_key_info *ki,
3189	mbuf_t mhead,
3190	u_char *alg,
3191	int offset,
3192	int len,
3193	u_char *digest)
3194{
3195	mbuf_t mb;
3196	u_char *ptr;
3197	int left, bytes;
3198	GSS_DIGEST_CTX context;
3199
3200	gss_digest_Init(&context, ki);
3201
3202	/*
3203	 * Logically prepend the first 8 bytes of the algorithm
3204	 * field as required by RFC 1964, section 1.2.1.1
3205	 */
3206	gss_digest_Update(&context, alg, KRB5_SZ_ALG);
3207
3208	/*
3209	 * Move down the mbuf chain until we reach the given
3210	 * byte offset, then start MD5 on the mbuf data until
3211	 * we've done len bytes.
3212	 */
3213
3214	for (mb = mhead; mb && len > 0; mb = mbuf_next(mb)) {
3215		ptr  = mbuf_data(mb);
3216		left = mbuf_len(mb);
3217		if (offset >= left) {
3218			/* Offset not yet reached */
3219			offset -= left;
3220			continue;
3221		}
3222		/* At or beyond offset - checksum data */
3223		ptr += offset;
3224		left -= offset;
3225		offset = 0;
3226
3227		bytes = left < len ? left : len;
3228		if (bytes > 0)
3229			gss_digest_Update(&context, ptr, bytes);
3230		len -= bytes;
3231	}
3232
3233	gss_digest_Final(&context, digest);
3234}
3235
3236/*
3237 * Compute a checksum over an NFS mbuf chain.
3238 * Start building an MD5 digest at the given offset and keep
3239 * going until the end of data in the current mbuf is reached.
3240 * Then convert the 16 byte MD5 digest to an 8 byte DES CBC
3241 * checksum.
3242 */
3243static void
3244nfs_gss_cksum_chain(
3245	gss_key_info *ki,
3246	struct nfsm_chain *nmc,
3247	u_char *alg,
3248	int offset,
3249	int len,
3250	u_char *cksum)
3251{
3252	/*
3253	 * If the length parameter is zero, then we need
3254	 * to use the length from the offset to the current
3255	 * encode/decode offset.
3256	 */
3257	if (len == 0)
3258		len = nfsm_chain_offset(nmc) - offset;
3259
3260	return (nfs_gss_cksum_mchain(ki, nmc->nmc_mhead, alg, offset, len, cksum));
3261}
3262
3263/*
3264 * Compute a checksum of the sequence number (or sequence window)
3265 * of an RPCSEC_GSS reply.
3266 */
3267static void
3268nfs_gss_cksum_rep(gss_key_info *ki, uint32_t seqnum, u_char *cksum)
3269{
3270	GSS_DIGEST_CTX context;
3271	uint32_t val = htonl(seqnum);
3272
3273	gss_digest_Init(&context, ki);
3274
3275	/*
3276	 * Logically prepend the first 8 bytes of the MIC
3277	 * token as required by RFC 1964, section 1.2.1.1
3278	 */
3279	gss_digest_Update(&context, ALG_MIC(ki), KRB5_SZ_ALG);
3280
3281	/*
3282	 * Compute the digest of the seqnum in network order
3283	 */
3284	gss_digest_Update(&context, &val, 4);
3285	gss_digest_Final(&context, cksum);
3286}
3287
3288/*
3289 * Encrypt or decrypt data in an mbuf chain with des-cbc.
3290 */
3291static void
3292nfs_gss_encrypt_mchain(
3293	gss_key_info *ki,
3294	mbuf_t mhead,
3295	int offset,
3296	int len,
3297	int encrypt)
3298{
3299	mbuf_t mb, mbn;
3300	u_char *ptr, *nptr;
3301	u_char tmp[8], ivec[8];
3302	int left, left8, remain;
3303
3304
3305	bzero(ivec, 8);
3306
3307	/*
3308	 * Move down the mbuf chain until we reach the given
3309	 * byte offset, then start encrypting the mbuf data until
3310	 * we've done len bytes.
3311	 */
3312
3313	for (mb = mhead; mb && len > 0; mb = mbn) {
3314		mbn  = mbuf_next(mb);
3315		ptr  = mbuf_data(mb);
3316		left = mbuf_len(mb);
3317		if (offset >= left) {
3318			/* Offset not yet reached */
3319			offset -= left;
3320			continue;
3321		}
3322		/* At or beyond offset - encrypt data */
3323		ptr += offset;
3324		left -= offset;
3325		offset = 0;
3326
3327		/*
3328		 * DES or DES3 CBC has to encrypt 8 bytes at a time.
3329		 * If the number of bytes to be encrypted in this
3330		 * mbuf isn't some multiple of 8 bytes, encrypt all
3331		 * the 8 byte blocks, then combine the remaining
3332		 * bytes with enough from the next mbuf to make up
3333		 * an 8 byte block and encrypt that block separately,
3334		 * i.e. that block is split across two mbufs.
3335		 */
3336		remain = left % 8;
3337		left8 = left - remain;
3338		left = left8 < len ? left8 : len;
3339		if (left > 0) {
3340			gss_des_crypt(ki, (des_cblock *) ptr, (des_cblock *) ptr,
3341					left, &ivec, &ivec, encrypt, KG_USAGE_SEAL);
3342			len -= left;
3343		}
3344
3345		if (mbn && remain > 0) {
3346			nptr = mbuf_data(mbn);
3347			offset = 8 - remain;
3348			bcopy(ptr + left, tmp, remain);		// grab from this mbuf
3349			bcopy(nptr, tmp + remain, offset);	// grab from next mbuf
3350			gss_des_crypt(ki, (des_cblock *) tmp, (des_cblock *) tmp, 8,
3351					&ivec, &ivec, encrypt, KG_USAGE_SEAL);
3352			bcopy(tmp, ptr + left, remain);		// return to this mbuf
3353			bcopy(tmp + remain, nptr, offset);	// return to next mbuf
3354			len -= 8;
3355		}
3356	}
3357}
3358
3359/*
3360 * Encrypt or decrypt data in an NFS mbuf chain with des-cbc.
3361 */
3362static void
3363nfs_gss_encrypt_chain(
3364	gss_key_info *ki,
3365	struct nfsm_chain *nmc,
3366	int offset,
3367	int len,
3368	int encrypt)
3369{
3370	/*
3371	 * If the length parameter is zero, then we need
3372	 * to use the length from the offset to the current
3373	 * encode/decode offset.
3374	 */
3375	if (len == 0)
3376		len = nfsm_chain_offset(nmc) - offset;
3377
3378	return (nfs_gss_encrypt_mchain(ki, nmc->nmc_mhead, offset, len, encrypt));
3379}
3380
3381/*
3382 * The routines that follow provide abstractions for doing digests and crypto.
3383 */
3384
3385static void
3386gss_digest_Init(GSS_DIGEST_CTX *ctx, gss_key_info *ki)
3387{
3388	ctx->type = ki->type;
3389	switch (ki->type) {
3390	case NFS_GSS_1DES:	MD5_DESCBC_Init(&ctx->m_ctx, &ki->ks_u.des.gss_sched);
3391				break;
3392	case NFS_GSS_3DES:	HMAC_SHA1_DES3KD_Init(&ctx->h_ctx, ki->ks_u.des3.ckey, 0);
3393				break;
3394	default:
3395			printf("gss_digest_Init: Unknown key info type %d\n", ki->type);
3396	}
3397}
3398
3399static void
3400gss_digest_Update(GSS_DIGEST_CTX *ctx, void *data, size_t len)
3401{
3402	switch (ctx->type) {
3403	case NFS_GSS_1DES:	MD5_DESCBC_Update(&ctx->m_ctx, data, len);
3404				break;
3405	case NFS_GSS_3DES:	HMAC_SHA1_DES3KD_Update(&ctx->h_ctx, data, len);
3406				break;
3407	}
3408}
3409
3410static void
3411gss_digest_Final(GSS_DIGEST_CTX *ctx, void *digest)
3412{
3413	switch (ctx->type) {
3414	case NFS_GSS_1DES:	MD5_DESCBC_Final(digest, &ctx->m_ctx);
3415				break;
3416	case NFS_GSS_3DES:	HMAC_SHA1_DES3KD_Final(digest, &ctx->h_ctx);
3417				break;
3418	}
3419}
3420
3421static void
3422gss_des_crypt(gss_key_info *ki, des_cblock *in, des_cblock *out,
3423		int32_t len, des_cblock *iv, des_cblock *retiv, int encrypt, int usage)
3424{
3425	switch (ki->type) {
3426	case NFS_GSS_1DES:
3427			{
3428				des_cbc_key_schedule *sched = ((usage == KG_USAGE_SEAL) ?
3429							&ki->ks_u.des.gss_sched_Ke :
3430							&ki->ks_u.des.gss_sched);
3431				des_cbc_encrypt(in, out, len, sched, iv, retiv, encrypt);
3432			}
3433			break;
3434	case NFS_GSS_3DES:
3435
3436			des3_cbc_encrypt(in, out, len, &ki->ks_u.des3.gss_sched, iv, retiv, encrypt);
3437			break;
3438	}
3439}
3440
3441static int
3442gss_key_init(gss_key_info *ki, uint32_t skeylen)
3443{
3444	size_t i;
3445	int rc;
3446	des_cblock k[3];
3447
3448	ki->keybytes = skeylen;
3449	switch (skeylen) {
3450	case sizeof(des_cblock):
3451				ki->type = NFS_GSS_1DES;
3452				ki->hash_len = MD5_DESCBC_DIGEST_LENGTH;
3453				ki->ks_u.des.key = (des_cblock *)ki->skey;
3454				rc = des_cbc_key_sched(ki->ks_u.des.key, &ki->ks_u.des.gss_sched);
3455				if (rc)
3456					return (rc);
3457				for (i = 0; i < ki->keybytes; i++)
3458					k[0][i] = 0xf0 ^ (*ki->ks_u.des.key)[i];
3459				rc = des_cbc_key_sched(&k[0], &ki->ks_u.des.gss_sched_Ke);
3460				break;
3461	case 3*sizeof(des_cblock):
3462				ki->type = NFS_GSS_3DES;
3463				ki->hash_len = SHA_DIGEST_LENGTH;
3464				ki->ks_u.des3.key = (des_cblock (*)[3])ki->skey;
3465				des3_derive_key(*ki->ks_u.des3.key, ki->ks_u.des3.ckey,
3466						KEY_USAGE_DES3_SIGN, KEY_USAGE_LEN);
3467				rc = des3_cbc_key_sched(*ki->ks_u.des3.key, &ki->ks_u.des3.gss_sched);
3468				if (rc)
3469					return (rc);
3470				break;
3471	default:
3472				printf("gss_key_init: Invalid key length %d\n", skeylen);
3473				rc = EINVAL;
3474				break;
3475	}
3476
3477	return (rc);
3478}
3479
3480#if 0
3481#define DISPLAYLEN 16
3482#define MAXDISPLAYLEN 256
3483
3484static void
3485hexdump(const char *msg, void *data, size_t len)
3486{
3487	size_t i, j;
3488	u_char *d = data;
3489	char *p, disbuf[3*DISPLAYLEN+1];
3490
3491	printf("NFS DEBUG %s len=%d:\n", msg, (uint32_t)len);
3492	if (len > MAXDISPLAYLEN)
3493		len = MAXDISPLAYLEN;
3494
3495	for (i = 0; i < len; i += DISPLAYLEN) {
3496		for (p = disbuf, j = 0; (j + i) < len && j < DISPLAYLEN; j++, p += 3)
3497			snprintf(p, 4, "%02x ", d[i + j]);
3498		printf("\t%s\n", disbuf);
3499	}
3500}
3501#endif
3502