1/*
2 * Copyright (c) 2006-2011 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 * miscellaneous support functions for NFSv4
31 */
32#include <sys/param.h>
33#include <sys/proc.h>
34#include <sys/kauth.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/mount_internal.h>
38#include <sys/vnode_internal.h>
39#include <sys/kpi_mbuf.h>
40#include <sys/socket.h>
41#include <sys/stat.h>
42#include <sys/malloc.h>
43#include <sys/syscall.h>
44#include <sys/ubc_internal.h>
45#include <sys/fcntl.h>
46#include <sys/quota.h>
47#include <sys/domain.h>
48#include <libkern/OSAtomic.h>
49#include <kern/thread_call.h>
50
51#include <sys/vm.h>
52#include <sys/vmparam.h>
53
54#include <sys/time.h>
55#include <kern/clock.h>
56
57#include <nfs/rpcv2.h>
58#include <nfs/nfsproto.h>
59#include <nfs/nfs.h>
60#include <nfs/nfsnode.h>
61#include <nfs/xdr_subs.h>
62#include <nfs/nfsm_subs.h>
63#include <nfs/nfs_gss.h>
64#include <nfs/nfsmount.h>
65#include <nfs/nfs_lock.h>
66
67#include <miscfs/specfs/specdev.h>
68
69#include <netinet/in.h>
70#include <net/kpi_interface.h>
71
72/*
73 * NFS_MAX_WHO is the maximum length of a string representation used
74 * in as an ace who, owner, or group. There is no explicit limit in the
75 * protocol, however the kauth routines have a limit of MAPATHLEN for
76 * strings including the trailing null character, so we impose that
77 * limit. This should be changed if kauth routines change.
78 *
79 * We also want some reasonable maximum, as 32 bits worth of string length
80 * is liable to cause problems. At the very least this limit must guarantee
81 * that any express that contains the 32 bit length from off the wire used in
82 * allocations does not overflow.
83 */
84#define	NFS_MAX_WHO	MAXPATHLEN
85
86/*
87 * Create the unique client ID to use for this mount.
88 *
89 * Format: unique ID + en0_address + server_address + mntfromname + mntonname
90 *
91 * We could possibly use one client ID for all mounts of the same server;
92 * however, that would complicate some aspects of state management.
93 *
94 * Each mount socket connection sends a SETCLIENTID.  If the ID is the same but
95 * the verifier (mounttime) changes, then all previous (mounts') state gets dropped.
96 *
97 * State is typically managed per-mount and in order to keep it that way
98 * each mount needs to use a separate client ID.  However, we also need to
99 * make sure that each mount uses the same client ID each time.
100 *
101 * In an attempt to differentiate mounts we include the mntfromname and mntonname
102 * strings to the client ID (as long as they fit).  We also make sure that the
103 * value does not conflict with any existing values in use (changing the unique ID).
104 *
105 * Note that info such as the server's address may change over the lifetime of the
106 * mount.  But the client ID will not be updated because we don't want it changing
107 * simply because we switched to a different server address.
108 */
109int
110nfs4_init_clientid(struct nfsmount *nmp)
111{
112	struct nfs_client_id *ncip, *ncip2;
113	struct sockaddr *saddr;
114	int error, len, len2, cmp;
115	struct vfsstatfs *vsfs;
116
117	static uint8_t en0addr[6];
118	static uint8_t en0addr_set = 0;
119
120	lck_mtx_lock(nfs_global_mutex);
121	if (!en0addr_set) {
122		ifnet_t interface = NULL;
123		error = ifnet_find_by_name("en0", &interface);
124		if (!error)
125			error = ifnet_lladdr_copy_bytes(interface, en0addr, sizeof(en0addr));
126		if (error)
127			printf("nfs4_init_clientid: error getting en0 address, %d\n", error);
128		if (!error)
129			en0addr_set = 1;
130		if (interface)
131			ifnet_release(interface);
132	}
133	lck_mtx_unlock(nfs_global_mutex);
134
135	MALLOC(ncip, struct nfs_client_id *, sizeof(struct nfs_client_id), M_TEMP, M_WAITOK);
136	if (!ncip)
137		return (ENOMEM);
138
139	vsfs = vfs_statfs(nmp->nm_mountp);
140	saddr = nmp->nm_saddr;
141	ncip->nci_idlen = sizeof(uint32_t) + sizeof(en0addr) + saddr->sa_len +
142		strlen(vsfs->f_mntfromname) + 1 + strlen(vsfs->f_mntonname) + 1;
143	if (ncip->nci_idlen > NFS4_OPAQUE_LIMIT)
144		ncip->nci_idlen = NFS4_OPAQUE_LIMIT;
145	MALLOC(ncip->nci_id, char *, ncip->nci_idlen, M_TEMP, M_WAITOK);
146	if (!ncip->nci_id) {
147		FREE(ncip, M_TEMP);
148		return (ENOMEM);
149	}
150
151	*(uint32_t*)ncip->nci_id = 0;
152	len = sizeof(uint32_t);
153	len2 = min(sizeof(en0addr), ncip->nci_idlen-len);
154	bcopy(en0addr, &ncip->nci_id[len], len2);
155	len += sizeof(en0addr);
156	len2 = min(saddr->sa_len, ncip->nci_idlen-len);
157	bcopy(saddr, &ncip->nci_id[len], len2);
158	len += len2;
159	if (len < ncip->nci_idlen) {
160		len2 = strlcpy(&ncip->nci_id[len], vsfs->f_mntfromname, ncip->nci_idlen-len);
161		if (len2 < (ncip->nci_idlen - len))
162			len += len2 + 1;
163		else
164			len = ncip->nci_idlen;
165	}
166	if (len < ncip->nci_idlen) {
167		len2 = strlcpy(&ncip->nci_id[len], vsfs->f_mntonname, ncip->nci_idlen-len);
168		if (len2 < (ncip->nci_idlen - len))
169			len += len2 + 1;
170		else
171			len = ncip->nci_idlen;
172	}
173
174	/* make sure the ID is unique, and add it to the sorted list */
175	lck_mtx_lock(nfs_global_mutex);
176	TAILQ_FOREACH(ncip2, &nfsclientids, nci_link) {
177		if (ncip->nci_idlen > ncip2->nci_idlen)
178			continue;
179		if (ncip->nci_idlen < ncip2->nci_idlen)
180			break;
181		cmp = bcmp(ncip->nci_id + sizeof(uint32_t),
182			ncip2->nci_id + sizeof(uint32_t),
183			ncip->nci_idlen - sizeof(uint32_t));
184		if (cmp > 0)
185			continue;
186		if (cmp < 0)
187			break;
188		if (*(uint32_t*)ncip->nci_id > *(uint32_t*)ncip2->nci_id)
189			continue;
190		if (*(uint32_t*)ncip->nci_id < *(uint32_t*)ncip2->nci_id)
191			break;
192		*(uint32_t*)ncip->nci_id += 1;
193	}
194	if (*(uint32_t*)ncip->nci_id)
195		printf("nfs client ID collision (%d) for %s on %s\n", *(uint32_t*)ncip->nci_id,
196			vsfs->f_mntfromname, vsfs->f_mntonname);
197	if (ncip2)
198		TAILQ_INSERT_BEFORE(ncip2, ncip, nci_link);
199	else
200		TAILQ_INSERT_TAIL(&nfsclientids, ncip, nci_link);
201	nmp->nm_longid = ncip;
202	lck_mtx_unlock(nfs_global_mutex);
203
204	return (0);
205}
206
207/*
208 * NFSv4 SETCLIENTID
209 */
210int
211nfs4_setclientid(struct nfsmount *nmp)
212{
213	uint64_t verifier, xid;
214	int error = 0, status, numops;
215	uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
216	thread_t thd;
217	kauth_cred_t cred;
218	struct nfsm_chain nmreq, nmrep;
219	struct sockaddr_storage ss;
220	void *sinaddr = NULL;
221	char raddr[MAX_IPv6_STR_LEN];
222	char uaddr[MAX_IPv6_STR_LEN+16];
223	int ualen = 0;
224	in_port_t port;
225
226	thd = current_thread();
227	cred = IS_VALID_CRED(nmp->nm_mcred) ? nmp->nm_mcred : vfs_context_ucred(vfs_context_kernel());
228	kauth_cred_ref(cred);
229
230	nfsm_chain_null(&nmreq);
231	nfsm_chain_null(&nmrep);
232
233	if (!nmp->nm_longid)
234		error = nfs4_init_clientid(nmp);
235
236	// SETCLIENTID
237	numops = 1;
238	nfsm_chain_build_alloc_init(error, &nmreq, 14 * NFSX_UNSIGNED + nmp->nm_longid->nci_idlen);
239	nfsm_chain_add_compound_header(error, &nmreq, "setclid", numops);
240	numops--;
241	nfsm_chain_add_32(error, &nmreq, NFS_OP_SETCLIENTID);
242	/* nfs_client_id4  client; */
243	nfsm_chain_add_64(error, &nmreq, nmp->nm_mounttime);
244	nfsm_chain_add_32(error, &nmreq, nmp->nm_longid->nci_idlen);
245	nfsm_chain_add_opaque(error, &nmreq, nmp->nm_longid->nci_id, nmp->nm_longid->nci_idlen);
246	nfsmout_if(error);
247	/* cb_client4      callback; */
248	if (!NMFLAG(nmp, NOCALLBACK) && nmp->nm_cbid && nfs4_cb_port &&
249	    !sock_getsockname(nmp->nm_nso->nso_so, (struct sockaddr*)&ss, sizeof(ss))) {
250		if (ss.ss_family == AF_INET) {
251			sinaddr = &((struct sockaddr_in*)&ss)->sin_addr;
252			port = nfs4_cb_port;
253		} else if (ss.ss_family == AF_INET6) {
254			sinaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
255			port = nfs4_cb_port6;
256		}
257		if (sinaddr && port && (inet_ntop(ss.ss_family, sinaddr, raddr, sizeof(raddr)) == raddr)) {
258			/* assemble r_addr = universal address (nmp->nm_nso->nso_so source IP addr + port) */
259			ualen = snprintf(uaddr, sizeof(uaddr), "%s.%d.%d", raddr,
260					((port >> 8) & 0xff),
261					(port & 0xff));
262			/* make sure it fit, give up if it didn't */
263			if (ualen >= (int)sizeof(uaddr))
264				ualen = 0;
265		}
266	}
267	if (ualen > 0) {
268		/* add callback info */
269		nfsm_chain_add_32(error, &nmreq, NFS4_CALLBACK_PROG); /* callback program */
270		if (ss.ss_family == AF_INET)
271			nfsm_chain_add_string(error, &nmreq, "tcp", 3); /* callback r_netid */
272		else if (ss.ss_family == AF_INET6)
273			nfsm_chain_add_string(error, &nmreq, "tcp6", 4); /* callback r_netid */
274		nfsm_chain_add_string(error, &nmreq, uaddr, ualen); /* callback r_addr */
275		nfsm_chain_add_32(error, &nmreq, nmp->nm_cbid); /* callback_ident */
276	} else {
277		/* don't provide valid callback info */
278		nfsm_chain_add_32(error, &nmreq, 0); /* callback program */
279		nfsm_chain_add_string(error, &nmreq, "", 0); /* callback r_netid */
280		nfsm_chain_add_string(error, &nmreq, "", 0); /* callback r_addr */
281		nfsm_chain_add_32(error, &nmreq, 0); /* callback_ident */
282	}
283	nfsm_chain_build_done(error, &nmreq);
284	nfsm_assert(error, (numops == 0), EPROTO);
285	nfsmout_if(error);
286	error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, thd, cred, NULL, R_SETUP, &nmrep, &xid, &status);
287	nfsm_chain_skip_tag(error, &nmrep);
288	nfsm_chain_get_32(error, &nmrep, numops);
289	if (!error && (numops != 1) && status)
290		error = status;
291	nfsm_chain_op_check(error, &nmrep, NFS_OP_SETCLIENTID);
292	if (error == NFSERR_CLID_INUSE)
293		printf("nfs4_setclientid: client ID in use?\n");
294	nfsmout_if(error);
295	nfsm_chain_get_64(error, &nmrep, nmp->nm_clientid);
296	nfsm_chain_get_64(error, &nmrep, verifier);
297	nfsm_chain_cleanup(&nmreq);
298	nfsm_chain_cleanup(&nmrep);
299
300	// SETCLIENTID_CONFIRM
301	numops = 1;
302	nfsm_chain_build_alloc_init(error, &nmreq, 15 * NFSX_UNSIGNED);
303	nfsm_chain_add_compound_header(error, &nmreq, "setclid_conf", numops);
304	numops--;
305	nfsm_chain_add_32(error, &nmreq, NFS_OP_SETCLIENTID_CONFIRM);
306	nfsm_chain_add_64(error, &nmreq, nmp->nm_clientid);
307	nfsm_chain_add_64(error, &nmreq, verifier);
308	nfsm_chain_build_done(error, &nmreq);
309	nfsm_assert(error, (numops == 0), EPROTO);
310	nfsmout_if(error);
311	error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, thd, cred, NULL, R_SETUP, &nmrep, &xid, &status);
312	nfsm_chain_skip_tag(error, &nmrep);
313	nfsm_chain_get_32(error, &nmrep, numops);
314	nfsm_chain_op_check(error, &nmrep, NFS_OP_SETCLIENTID_CONFIRM);
315	if (error)
316		printf("nfs4_setclientid: confirm error %d\n", error);
317	lck_mtx_lock(&nmp->nm_lock);
318	if (!error)
319		nmp->nm_state |= NFSSTA_CLIENTID;
320	lck_mtx_unlock(&nmp->nm_lock);
321
322	nfsmout_if(error || !nmp->nm_dnp);
323
324	/* take the opportunity to refresh fs attributes too */
325	// PUTFH, GETATTR(FS)
326	numops = 2;
327	nfsm_chain_build_alloc_init(error, &nmreq, 23 * NFSX_UNSIGNED);
328	nfsm_chain_add_compound_header(error, &nmreq, "setclid_attr", numops);
329	numops--;
330	nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
331	nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, nmp->nm_dnp->n_fhp, nmp->nm_dnp->n_fhsize);
332	numops--;
333	nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
334	NFS_CLEAR_ATTRIBUTES(bitmap);
335	NFS4_PER_FS_ATTRIBUTES(bitmap);
336	nfsm_chain_add_bitmap(error, &nmreq, bitmap, NFS_ATTR_BITMAP_LEN);
337	nfsm_chain_build_done(error, &nmreq);
338	nfsm_assert(error, (numops == 0), EPROTO);
339	nfsmout_if(error);
340	error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, thd, cred, NULL, R_SETUP, &nmrep, &xid, &status);
341	nfsm_chain_skip_tag(error, &nmrep);
342	nfsm_chain_get_32(error, &nmrep, numops);
343	lck_mtx_lock(&nmp->nm_lock);
344	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
345	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
346	if (!error)
347		error = nfs4_parsefattr(&nmrep, &nmp->nm_fsattr, NULL, NULL, NULL, NULL);
348	lck_mtx_unlock(&nmp->nm_lock);
349	if (error)  /* ignore any error from the getattr */
350		error = 0;
351nfsmout:
352	nfsm_chain_cleanup(&nmreq);
353	nfsm_chain_cleanup(&nmrep);
354	kauth_cred_unref(&cred);
355	if (error)
356		printf("nfs4_setclientid failed, %d\n", error);
357	return (error);
358}
359
360/*
361 * renew/check lease state on server
362 */
363int
364nfs4_renew(struct nfsmount *nmp, int rpcflag)
365{
366	int error = 0, status, numops;
367	u_int64_t xid;
368	struct nfsm_chain nmreq, nmrep;
369	kauth_cred_t cred;
370
371	cred = IS_VALID_CRED(nmp->nm_mcred) ? nmp->nm_mcred : vfs_context_ucred(vfs_context_kernel());
372	kauth_cred_ref(cred);
373
374	nfsm_chain_null(&nmreq);
375	nfsm_chain_null(&nmrep);
376
377	// RENEW
378	numops = 1;
379	nfsm_chain_build_alloc_init(error, &nmreq, 8 * NFSX_UNSIGNED);
380	nfsm_chain_add_compound_header(error, &nmreq, "renew", numops);
381	numops--;
382	nfsm_chain_add_32(error, &nmreq, NFS_OP_RENEW);
383	nfsm_chain_add_64(error, &nmreq, nmp->nm_clientid);
384	nfsm_chain_build_done(error, &nmreq);
385	nfsm_assert(error, (numops == 0), EPROTO);
386	nfsmout_if(error);
387	error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
388			current_thread(), cred, NULL, rpcflag, &nmrep, &xid, &status);
389	nfsm_chain_skip_tag(error, &nmrep);
390	nfsm_chain_get_32(error, &nmrep, numops);
391	nfsm_chain_op_check(error, &nmrep, NFS_OP_RENEW);
392nfsmout:
393	nfsm_chain_cleanup(&nmreq);
394	nfsm_chain_cleanup(&nmrep);
395	kauth_cred_unref(&cred);
396	return (error);
397}
398
399
400/*
401 * periodic timer to renew lease state on server
402 */
403void
404nfs4_renew_timer(void *param0, __unused void *param1)
405{
406	struct nfsmount *nmp = param0;
407	u_int64_t clientid;
408	int error = 0, interval;
409
410	lck_mtx_lock(&nmp->nm_lock);
411	clientid = nmp->nm_clientid;
412	if ((nmp->nm_state & NFSSTA_RECOVER) || !(nmp->nm_sockflags & NMSOCK_READY)) {
413		lck_mtx_unlock(&nmp->nm_lock);
414		goto out;
415	}
416	lck_mtx_unlock(&nmp->nm_lock);
417
418	error = nfs4_renew(nmp, R_RECOVER);
419out:
420	if (error == ETIMEDOUT)
421		nfs_need_reconnect(nmp);
422	else if (error)
423		printf("nfs4_renew_timer: error %d\n", error);
424	lck_mtx_lock(&nmp->nm_lock);
425	if (error && (error != ETIMEDOUT) &&
426	    (nmp->nm_clientid == clientid) && !(nmp->nm_state & NFSSTA_RECOVER)) {
427		printf("nfs4_renew_timer: error %d, initiating recovery\n", error);
428		nfs_need_recover(nmp, error);
429	}
430
431	interval = nmp->nm_fsattr.nfsa_lease / (error ? 4 : 2);
432	if ((interval < 1) || (nmp->nm_state & NFSSTA_RECOVER))
433		interval = 1;
434	lck_mtx_unlock(&nmp->nm_lock);
435	nfs_interval_timer_start(nmp->nm_renew_timer, interval * 1000);
436}
437
438/*
439 * get the list of supported security flavors
440 *
441 * How we get them depends on what args we are given:
442 *
443 * FH?   Name?  Action
444 * ----- -----  ------
445 * YES   YES    Use the fh and name provided
446 * YES   NO     4.1-only just use the fh provided
447 * NO    YES    Use the node's (or root) fh and the name provided
448 * NO    NO     Use the node's parent and the node's name (4.1 will just use node's fh)
449 */
450int
451nfs4_secinfo_rpc(struct nfsmount *nmp, struct nfsreq_secinfo_args *siap, kauth_cred_t cred, uint32_t *sec, int *seccountp)
452{
453	int error = 0, status, nfsvers, numops, namelen, fhsize;
454	vnode_t dvp = NULLVP;
455	nfsnode_t np, dnp;
456	u_char *fhp;
457	const char *vname = NULL, *name;
458	uint64_t xid;
459	struct nfsm_chain nmreq, nmrep;
460
461	*seccountp = 0;
462	if (!nmp)
463		return (ENXIO);
464	nfsvers = nmp->nm_vers;
465	np = siap->rsia_np;
466
467	nfsm_chain_null(&nmreq);
468	nfsm_chain_null(&nmrep);
469
470	fhp = siap->rsia_fh;
471	fhsize = fhp ? siap->rsia_fhsize : 0;
472	name = siap->rsia_name;
473	namelen = name ? siap->rsia_namelen : 0;
474	if (name && !namelen)
475		namelen = strlen(name);
476	if (!fhp && name) {
477		if (!np)  /* use PUTROOTFH */
478			goto gotargs;
479		fhp = np->n_fhp;
480		fhsize = np->n_fhsize;
481	}
482	if (fhp && name)
483		goto gotargs;
484
485	if (!np)
486		return (EIO);
487	nfs_node_lock_force(np);
488	if ((vnode_vtype(NFSTOV(np)) != VDIR) && np->n_sillyrename) {
489		/*
490		 * The node's been sillyrenamed, so we need to use
491		 * the sillyrename directory/name to do the open.
492		 */
493		struct nfs_sillyrename *nsp = np->n_sillyrename;
494		dnp = nsp->nsr_dnp;
495		dvp = NFSTOV(dnp);
496		if ((error = vnode_get(dvp))) {
497			nfs_node_unlock(np);
498			goto nfsmout;
499		}
500		fhp = dnp->n_fhp;
501		fhsize = dnp->n_fhsize;
502		name = nsp->nsr_name;
503		namelen = nsp->nsr_namlen;
504	} else {
505		/*
506		 * [sigh] We can't trust VFS to get the parent right for named
507		 * attribute nodes.  (It likes to reparent the nodes after we've
508		 * created them.)  Luckily we can probably get the right parent
509		 * from the n_parent we have stashed away.
510		 */
511		if ((np->n_vattr.nva_flags & NFS_FFLAG_IS_ATTR) &&
512		    (((dvp = np->n_parent)) && (error = vnode_get(dvp))))
513			dvp = NULL;
514		if (!dvp)
515			dvp = vnode_getparent(NFSTOV(np));
516		vname = vnode_getname(NFSTOV(np));
517		if (!dvp || !vname) {
518			if (!error)
519				error = EIO;
520			nfs_node_unlock(np);
521			goto nfsmout;
522		}
523		dnp = VTONFS(dvp);
524		fhp = dnp->n_fhp;
525		fhsize = dnp->n_fhsize;
526		name = vname;
527		namelen = strnlen(vname, MAXPATHLEN);
528	}
529	nfs_node_unlock(np);
530
531gotargs:
532	// PUT(ROOT)FH + SECINFO
533	numops = 2;
534	nfsm_chain_build_alloc_init(error, &nmreq,
535		4 * NFSX_UNSIGNED + NFSX_FH(nfsvers) + nfsm_rndup(namelen));
536	nfsm_chain_add_compound_header(error, &nmreq, "secinfo", numops);
537	numops--;
538	if (fhp) {
539		nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
540		nfsm_chain_add_fh(error, &nmreq, nfsvers, fhp, fhsize);
541	} else {
542		nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTROOTFH);
543	}
544	numops--;
545	nfsm_chain_add_32(error, &nmreq, NFS_OP_SECINFO);
546	nfsm_chain_add_name(error, &nmreq, name, namelen, nmp);
547	nfsm_chain_build_done(error, &nmreq);
548	nfsm_assert(error, (numops == 0), EPROTO);
549	nfsmout_if(error);
550	error = nfs_request2(np, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
551			current_thread(), cred, NULL, 0, &nmrep, &xid, &status);
552	nfsm_chain_skip_tag(error, &nmrep);
553	nfsm_chain_get_32(error, &nmrep, numops);
554	nfsm_chain_op_check(error, &nmrep, fhp ? NFS_OP_PUTFH : NFS_OP_PUTROOTFH);
555	nfsm_chain_op_check(error, &nmrep, NFS_OP_SECINFO);
556	nfsmout_if(error);
557	error = nfsm_chain_get_secinfo(&nmrep, sec, seccountp);
558nfsmout:
559	nfsm_chain_cleanup(&nmreq);
560	nfsm_chain_cleanup(&nmrep);
561	if (vname)
562		vnode_putname(vname);
563	if (dvp != NULLVP)
564		vnode_put(dvp);
565	return (error);
566}
567
568/*
569 * Parse an NFSv4 SECINFO array to an array of pseudo flavors.
570 * (Note: also works for MOUNTv3 security arrays.)
571 */
572int
573nfsm_chain_get_secinfo(struct nfsm_chain *nmc, uint32_t *sec, int *seccountp)
574{
575	int error = 0, secmax, seccount, srvcount;
576	uint32_t flavor, val;
577	u_char oid[12];
578
579	seccount = srvcount = 0;
580	secmax = *seccountp;
581	*seccountp = 0;
582
583	nfsm_chain_get_32(error, nmc, srvcount);
584	while (!error && (srvcount > 0) && (seccount < secmax)) {
585		nfsm_chain_get_32(error, nmc, flavor);
586		nfsmout_if(error);
587		switch (flavor) {
588		case RPCAUTH_NONE:
589		case RPCAUTH_SYS:
590		case RPCAUTH_KRB5:
591		case RPCAUTH_KRB5I:
592		case RPCAUTH_KRB5P:
593			sec[seccount++] = flavor;
594			break;
595		case RPCSEC_GSS:
596			/* we only recognize KRB5, KRB5I, KRB5P */
597			nfsm_chain_get_32(error, nmc, val); /* OID length */
598			nfsmout_if(error);
599			if (val != sizeof(krb5_mech)) {
600				nfsm_chain_adv(error, nmc, val);
601				nfsm_chain_adv(error, nmc, 2*NFSX_UNSIGNED);
602				break;
603			}
604			nfsm_chain_get_opaque(error, nmc, val, oid); /* OID bytes */
605			nfsmout_if(error);
606			if (bcmp(oid, krb5_mech, sizeof(krb5_mech))) {
607				nfsm_chain_adv(error, nmc, 2*NFSX_UNSIGNED);
608				break;
609			}
610			nfsm_chain_get_32(error, nmc, val); /* QOP */
611			nfsm_chain_get_32(error, nmc, val); /* SERVICE */
612			nfsmout_if(error);
613			switch (val) {
614			case RPCSEC_GSS_SVC_NONE:
615				sec[seccount++] = RPCAUTH_KRB5;
616				break;
617			case RPCSEC_GSS_SVC_INTEGRITY:
618				sec[seccount++] = RPCAUTH_KRB5I;
619				break;
620			case RPCSEC_GSS_SVC_PRIVACY:
621				sec[seccount++] = RPCAUTH_KRB5P;
622				break;
623			}
624			break;
625		}
626		srvcount--;
627	}
628nfsmout:
629	if (!error)
630		*seccountp = seccount;
631	return (error);
632}
633
634
635/*
636 * Fetch the FS_LOCATIONS attribute for the node found at directory/name.
637 */
638int
639nfs4_get_fs_locations(
640	struct nfsmount *nmp,
641	nfsnode_t dnp,
642	u_char *fhp,
643	int fhsize,
644	const char *name,
645	vfs_context_t ctx,
646	struct nfs_fs_locations *nfslsp)
647{
648	int error = 0, numops, status;
649	uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
650	struct nfsreq rq, *req = &rq;
651	struct nfsreq_secinfo_args si;
652	struct nfsm_chain nmreq, nmrep;
653	uint64_t xid;
654
655	if (!fhp && dnp) {
656		fhp = dnp->n_fhp;
657		fhsize = dnp->n_fhsize;
658	}
659	if (!fhp)
660		return (EINVAL);
661
662	nfsm_chain_null(&nmreq);
663	nfsm_chain_null(&nmrep);
664
665	NFSREQ_SECINFO_SET(&si, NULL, fhp, fhsize, name, 0);
666	numops = 3;
667	nfsm_chain_build_alloc_init(error, &nmreq, 18 * NFSX_UNSIGNED);
668	nfsm_chain_add_compound_header(error, &nmreq, "fs_locations", numops);
669	numops--;
670	nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
671	nfsm_chain_add_fh(error, &nmreq, NFS_VER4, fhp, fhsize);
672	numops--;
673	nfsm_chain_add_32(error, &nmreq, NFS_OP_LOOKUP);
674	nfsm_chain_add_name(error, &nmreq, name, strlen(name), nmp);
675	numops--;
676	nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
677	NFS_CLEAR_ATTRIBUTES(bitmap);
678	NFS_BITMAP_SET(bitmap, NFS_FATTR_FS_LOCATIONS);
679	nfsm_chain_add_bitmap(error, &nmreq, bitmap, NFS_ATTR_BITMAP_LEN);
680	nfsm_chain_build_done(error, &nmreq);
681	nfsm_assert(error, (numops == 0), EPROTO);
682	nfsmout_if(error);
683	error = nfs_request_async(dnp, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
684			vfs_context_thread(ctx), vfs_context_ucred(ctx), &si, 0, NULL, &req);
685	if (!error)
686		error = nfs_request_async_finish(req, &nmrep, &xid, &status);
687	nfsm_chain_skip_tag(error, &nmrep);
688	nfsm_chain_get_32(error, &nmrep, numops);
689	nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
690	nfsm_chain_op_check(error, &nmrep, NFS_OP_LOOKUP);
691	nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
692	nfsmout_if(error);
693	error = nfs4_parsefattr(&nmrep, NULL, NULL, NULL, NULL, nfslsp);
694nfsmout:
695	nfsm_chain_cleanup(&nmrep);
696	nfsm_chain_cleanup(&nmreq);
697	return (error);
698}
699
700/*
701 * Referral trigger nodes may not have many attributes provided by the
702 * server, so put some default values in place.
703 */
704void
705nfs4_default_attrs_for_referral_trigger(
706	nfsnode_t dnp,
707	char *name,
708	int namelen,
709	struct nfs_vattr *nvap,
710	fhandle_t *fhp)
711{
712	struct timeval now;
713	microtime(&now);
714	int len;
715
716	nvap->nva_flags = NFS_FFLAG_TRIGGER | NFS_FFLAG_TRIGGER_REFERRAL;
717	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TYPE)) {
718		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_TYPE);
719		nvap->nva_type = VDIR;
720	}
721	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_FSID)) {
722		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_FSID);
723		nvap->nva_fsid.major = 0;
724		nvap->nva_fsid.minor = 0;
725	}
726	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER) && dnp) {
727		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_OWNER);
728		nvap->nva_uid = dnp->n_vattr.nva_uid;
729		nvap->nva_uuuid = dnp->n_vattr.nva_uuuid;
730	}
731	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) && dnp) {
732		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP);
733		nvap->nva_gid = dnp->n_vattr.nva_gid;
734		nvap->nva_guuid = dnp->n_vattr.nva_guuid;
735	}
736	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_MODE)) {
737		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_MODE);
738		nvap->nva_mode = 0777;
739	}
740	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_SIZE)) {
741		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_SIZE);
742		nvap->nva_size = 0;
743	}
744	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_SPACE_USED)) {
745		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_SPACE_USED);
746		nvap->nva_bytes = 0;
747	}
748	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_NUMLINKS)) {
749		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_NUMLINKS);
750		nvap->nva_nlink = 2;
751	}
752	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_ACCESS)) {
753		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_TIME_ACCESS);
754		nvap->nva_timesec[NFSTIME_ACCESS] = now.tv_sec;
755		nvap->nva_timensec[NFSTIME_ACCESS] = now.tv_usec * 1000;
756	}
757	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_MODIFY)) {
758		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_TIME_MODIFY);
759		nvap->nva_timesec[NFSTIME_MODIFY] = now.tv_sec;
760		nvap->nva_timensec[NFSTIME_MODIFY] = now.tv_usec * 1000;
761	}
762	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_METADATA)) {
763		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_TIME_METADATA);
764		nvap->nva_timesec[NFSTIME_CHANGE] = now.tv_sec;
765		nvap->nva_timensec[NFSTIME_CHANGE] = now.tv_usec * 1000;
766	}
767	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_FILEID)) {
768		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_FILEID);
769		nvap->nva_fileid = 42;
770	}
771	if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_FILEHANDLE) && dnp && name && fhp) {
772		/* Build a fake filehandle made up of parent node pointer and name */
773		NFS_BITMAP_SET(nvap->nva_bitmap, NFS_FATTR_FILEHANDLE);
774		bcopy(&dnp, &fhp->fh_data[0], sizeof(dnp));
775		len = sizeof(fhp->fh_data) - sizeof(dnp);
776		bcopy(name, &fhp->fh_data[0] + sizeof(dnp), MIN(len, namelen));
777		fhp->fh_len = sizeof(dnp) + namelen;
778		if (fhp->fh_len > (int)sizeof(fhp->fh_data))
779			fhp->fh_len = sizeof(fhp->fh_data);
780	}
781}
782
783/*
784 * Set NFS bitmap according to what's set in vnode_attr (and supported by the server).
785 */
786void
787nfs_vattr_set_bitmap(struct nfsmount *nmp, uint32_t *bitmap, struct vnode_attr *vap)
788{
789	int i;
790
791	NFS_CLEAR_ATTRIBUTES(bitmap);
792	if (VATTR_IS_ACTIVE(vap, va_data_size))
793		NFS_BITMAP_SET(bitmap, NFS_FATTR_SIZE);
794	if (VATTR_IS_ACTIVE(vap, va_acl) && (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_ACL))
795		NFS_BITMAP_SET(bitmap, NFS_FATTR_ACL);
796	if (VATTR_IS_ACTIVE(vap, va_flags)) {
797		NFS_BITMAP_SET(bitmap, NFS_FATTR_ARCHIVE);
798		NFS_BITMAP_SET(bitmap, NFS_FATTR_HIDDEN);
799	}
800	// NFS_BITMAP_SET(bitmap, NFS_FATTR_MIMETYPE)
801	if (VATTR_IS_ACTIVE(vap, va_mode) && !NMFLAG(nmp, ACLONLY))
802		NFS_BITMAP_SET(bitmap, NFS_FATTR_MODE);
803	if (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_uuuid))
804		NFS_BITMAP_SET(bitmap, NFS_FATTR_OWNER);
805	if (VATTR_IS_ACTIVE(vap, va_gid) || VATTR_IS_ACTIVE(vap, va_guuid))
806		NFS_BITMAP_SET(bitmap, NFS_FATTR_OWNER_GROUP);
807	// NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
808	if (vap->va_vaflags & VA_UTIMES_NULL) {
809		NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_ACCESS_SET);
810		NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_MODIFY_SET);
811	} else {
812		if (VATTR_IS_ACTIVE(vap, va_access_time))
813			NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_ACCESS_SET);
814		if (VATTR_IS_ACTIVE(vap, va_modify_time))
815			NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_MODIFY_SET);
816	}
817	if (VATTR_IS_ACTIVE(vap, va_backup_time))
818		NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_BACKUP);
819	if (VATTR_IS_ACTIVE(vap, va_create_time))
820		NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_CREATE);
821	/* and limit to what is supported by server */
822	for (i=0; i < NFS_ATTR_BITMAP_LEN; i++)
823		bitmap[i] &= nmp->nm_fsattr.nfsa_supp_attr[i];
824}
825
826/*
827 * Convert between NFSv4 and VFS ACE types
828 */
829uint32_t
830nfs4_ace_nfstype_to_vfstype(uint32_t nfsacetype, int *errorp)
831{
832	switch (nfsacetype) {
833	case NFS_ACE_ACCESS_ALLOWED_ACE_TYPE:
834		return KAUTH_ACE_PERMIT;
835	case NFS_ACE_ACCESS_DENIED_ACE_TYPE:
836		return KAUTH_ACE_DENY;
837	case NFS_ACE_SYSTEM_AUDIT_ACE_TYPE:
838		return KAUTH_ACE_AUDIT;
839	case NFS_ACE_SYSTEM_ALARM_ACE_TYPE:
840		return KAUTH_ACE_ALARM;
841	}
842	*errorp = EBADRPC;
843	return 0;
844}
845
846uint32_t
847nfs4_ace_vfstype_to_nfstype(uint32_t vfstype, int *errorp)
848{
849	switch (vfstype) {
850	case KAUTH_ACE_PERMIT:
851		return NFS_ACE_ACCESS_ALLOWED_ACE_TYPE;
852	case KAUTH_ACE_DENY:
853		return NFS_ACE_ACCESS_DENIED_ACE_TYPE;
854	case KAUTH_ACE_AUDIT:
855		return NFS_ACE_SYSTEM_AUDIT_ACE_TYPE;
856	case KAUTH_ACE_ALARM:
857		return NFS_ACE_SYSTEM_ALARM_ACE_TYPE;
858	}
859	*errorp = EINVAL;
860	return 0;
861}
862
863/*
864 * Convert between NFSv4 and VFS ACE flags
865 */
866uint32_t
867nfs4_ace_nfsflags_to_vfsflags(uint32_t nfsflags)
868{
869	uint32_t vfsflags = 0;
870
871	if (nfsflags & NFS_ACE_FILE_INHERIT_ACE)
872		vfsflags |= KAUTH_ACE_FILE_INHERIT;
873	if (nfsflags & NFS_ACE_DIRECTORY_INHERIT_ACE)
874		vfsflags |= KAUTH_ACE_DIRECTORY_INHERIT;
875	if (nfsflags & NFS_ACE_NO_PROPAGATE_INHERIT_ACE)
876		vfsflags |= KAUTH_ACE_LIMIT_INHERIT;
877	if (nfsflags & NFS_ACE_INHERIT_ONLY_ACE)
878		vfsflags |= KAUTH_ACE_ONLY_INHERIT;
879	if (nfsflags & NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
880		vfsflags |= KAUTH_ACE_SUCCESS;
881	if (nfsflags & NFS_ACE_FAILED_ACCESS_ACE_FLAG)
882		vfsflags |= KAUTH_ACE_FAILURE;
883	if (nfsflags & NFS_ACE_INHERITED_ACE)
884		vfsflags |= KAUTH_ACE_INHERITED;
885
886	return (vfsflags);
887}
888
889uint32_t
890nfs4_ace_vfsflags_to_nfsflags(uint32_t vfsflags)
891{
892	uint32_t nfsflags = 0;
893
894	if (vfsflags & KAUTH_ACE_FILE_INHERIT)
895		nfsflags |= NFS_ACE_FILE_INHERIT_ACE;
896	if (vfsflags & KAUTH_ACE_DIRECTORY_INHERIT)
897		nfsflags |= NFS_ACE_DIRECTORY_INHERIT_ACE;
898	if (vfsflags & KAUTH_ACE_LIMIT_INHERIT)
899		nfsflags |= NFS_ACE_NO_PROPAGATE_INHERIT_ACE;
900	if (vfsflags & KAUTH_ACE_ONLY_INHERIT)
901		nfsflags |= NFS_ACE_INHERIT_ONLY_ACE;
902	if (vfsflags & KAUTH_ACE_SUCCESS)
903		nfsflags |= NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
904	if (vfsflags & KAUTH_ACE_FAILURE)
905		nfsflags |= NFS_ACE_FAILED_ACCESS_ACE_FLAG;
906	if (vfsflags & KAUTH_ACE_INHERITED)
907		nfsflags |= NFS_ACE_INHERITED_ACE;
908
909	return (nfsflags);
910}
911
912/*
913 * Convert between NFSv4 ACE access masks and VFS access rights
914 */
915uint32_t
916nfs4_ace_nfsmask_to_vfsrights(uint32_t nfsmask)
917{
918	uint32_t vfsrights = 0;
919
920	if (nfsmask & NFS_ACE_READ_DATA)
921		vfsrights |= KAUTH_VNODE_READ_DATA;
922	if (nfsmask & NFS_ACE_LIST_DIRECTORY)
923		vfsrights |= KAUTH_VNODE_LIST_DIRECTORY;
924	if (nfsmask & NFS_ACE_WRITE_DATA)
925		vfsrights |= KAUTH_VNODE_WRITE_DATA;
926	if (nfsmask & NFS_ACE_ADD_FILE)
927		vfsrights |= KAUTH_VNODE_ADD_FILE;
928	if (nfsmask & NFS_ACE_APPEND_DATA)
929		vfsrights |= KAUTH_VNODE_APPEND_DATA;
930	if (nfsmask & NFS_ACE_ADD_SUBDIRECTORY)
931		vfsrights |= KAUTH_VNODE_ADD_SUBDIRECTORY;
932	if (nfsmask & NFS_ACE_READ_NAMED_ATTRS)
933		vfsrights |= KAUTH_VNODE_READ_EXTATTRIBUTES;
934	if (nfsmask & NFS_ACE_WRITE_NAMED_ATTRS)
935		vfsrights |= KAUTH_VNODE_WRITE_EXTATTRIBUTES;
936	if (nfsmask & NFS_ACE_EXECUTE)
937		vfsrights |= KAUTH_VNODE_EXECUTE;
938	if (nfsmask & NFS_ACE_DELETE_CHILD)
939		vfsrights |= KAUTH_VNODE_DELETE_CHILD;
940	if (nfsmask & NFS_ACE_READ_ATTRIBUTES)
941		vfsrights |= KAUTH_VNODE_READ_ATTRIBUTES;
942	if (nfsmask & NFS_ACE_WRITE_ATTRIBUTES)
943		vfsrights |= KAUTH_VNODE_WRITE_ATTRIBUTES;
944	if (nfsmask & NFS_ACE_DELETE)
945		vfsrights |= KAUTH_VNODE_DELETE;
946	if (nfsmask & NFS_ACE_READ_ACL)
947		vfsrights |= KAUTH_VNODE_READ_SECURITY;
948	if (nfsmask & NFS_ACE_WRITE_ACL)
949		vfsrights |= KAUTH_VNODE_WRITE_SECURITY;
950	if (nfsmask & NFS_ACE_WRITE_OWNER)
951		vfsrights |= KAUTH_VNODE_CHANGE_OWNER;
952	if (nfsmask & NFS_ACE_SYNCHRONIZE)
953		vfsrights |= KAUTH_VNODE_SYNCHRONIZE;
954	if ((nfsmask & NFS_ACE_GENERIC_READ) == NFS_ACE_GENERIC_READ)
955		vfsrights |= KAUTH_ACE_GENERIC_READ;
956	if ((nfsmask & NFS_ACE_GENERIC_WRITE) == NFS_ACE_GENERIC_WRITE)
957		vfsrights |= KAUTH_ACE_GENERIC_WRITE;
958	if ((nfsmask & NFS_ACE_GENERIC_EXECUTE) == NFS_ACE_GENERIC_EXECUTE)
959		vfsrights |= KAUTH_ACE_GENERIC_EXECUTE;
960
961	return (vfsrights);
962}
963
964uint32_t
965nfs4_ace_vfsrights_to_nfsmask(uint32_t vfsrights)
966{
967	uint32_t nfsmask = 0;
968
969	if (vfsrights & KAUTH_VNODE_READ_DATA)
970		nfsmask |= NFS_ACE_READ_DATA;
971	if (vfsrights & KAUTH_VNODE_LIST_DIRECTORY)
972		nfsmask |= NFS_ACE_LIST_DIRECTORY;
973	if (vfsrights & KAUTH_VNODE_WRITE_DATA)
974		nfsmask |= NFS_ACE_WRITE_DATA;
975	if (vfsrights & KAUTH_VNODE_ADD_FILE)
976		nfsmask |= NFS_ACE_ADD_FILE;
977	if (vfsrights & KAUTH_VNODE_APPEND_DATA)
978		nfsmask |= NFS_ACE_APPEND_DATA;
979	if (vfsrights & KAUTH_VNODE_ADD_SUBDIRECTORY)
980		nfsmask |= NFS_ACE_ADD_SUBDIRECTORY;
981	if (vfsrights & KAUTH_VNODE_READ_EXTATTRIBUTES)
982		nfsmask |= NFS_ACE_READ_NAMED_ATTRS;
983	if (vfsrights & KAUTH_VNODE_WRITE_EXTATTRIBUTES)
984		nfsmask |= NFS_ACE_WRITE_NAMED_ATTRS;
985	if (vfsrights & KAUTH_VNODE_EXECUTE)
986		nfsmask |= NFS_ACE_EXECUTE;
987	if (vfsrights & KAUTH_VNODE_DELETE_CHILD)
988		nfsmask |= NFS_ACE_DELETE_CHILD;
989	if (vfsrights & KAUTH_VNODE_READ_ATTRIBUTES)
990		nfsmask |= NFS_ACE_READ_ATTRIBUTES;
991	if (vfsrights & KAUTH_VNODE_WRITE_ATTRIBUTES)
992		nfsmask |= NFS_ACE_WRITE_ATTRIBUTES;
993	if (vfsrights & KAUTH_VNODE_DELETE)
994		nfsmask |= NFS_ACE_DELETE;
995	if (vfsrights & KAUTH_VNODE_READ_SECURITY)
996		nfsmask |= NFS_ACE_READ_ACL;
997	if (vfsrights & KAUTH_VNODE_WRITE_SECURITY)
998		nfsmask |= NFS_ACE_WRITE_ACL;
999	if (vfsrights & KAUTH_VNODE_CHANGE_OWNER)
1000		nfsmask |= NFS_ACE_WRITE_OWNER;
1001	if (vfsrights & KAUTH_VNODE_SYNCHRONIZE)
1002		nfsmask |= NFS_ACE_SYNCHRONIZE;
1003	if (vfsrights & KAUTH_ACE_GENERIC_READ)
1004		nfsmask |= NFS_ACE_GENERIC_READ;
1005	if (vfsrights & KAUTH_ACE_GENERIC_WRITE)
1006		nfsmask |= NFS_ACE_GENERIC_WRITE;
1007	if (vfsrights & KAUTH_ACE_GENERIC_EXECUTE)
1008		nfsmask |= NFS_ACE_GENERIC_EXECUTE;
1009	if (vfsrights & KAUTH_ACE_GENERIC_ALL)
1010		nfsmask |= (KAUTH_ACE_GENERIC_READ|KAUTH_ACE_GENERIC_WRITE|NFS_ACE_GENERIC_EXECUTE);
1011
1012	return (nfsmask);
1013}
1014
1015/*
1016 * Map an NFSv4 ID string to a VFS guid.
1017 *
1018 * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
1019 */
1020int
1021nfs4_id2guid(/*const*/ char *id, guid_t *guidp, int isgroup)
1022{
1023	int error1 = 0, error = 0, compare;
1024	guid_t guid1, guid2, *gp;
1025	ntsid_t sid;
1026	long num, unknown;
1027	const char *p, *at;
1028
1029	*guidp = kauth_null_guid;
1030	compare = ((nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE) &&
1031		   (nfs_idmap_ctrl & NFS_IDMAP_CTRL_COMPARE_RESULTS));
1032	unknown = (nfs_idmap_ctrl & NFS_IDMAP_CTRL_UNKNOWN_IS_99) ? 99 : -2;
1033
1034	/*
1035	 * First check if it is just a simple numeric ID string or a special "XXX@" name.
1036	 * If it's a number, there's no need trying to ask the IDMAP service to map it.
1037	 * If it's a special "XXX@" name, we want to make sure to treat it as a group.
1038	 */
1039	num = 1;
1040	at = NULL;
1041	p = id;
1042	while (*p) {
1043		if ((*p < '0') || (*p > '9'))
1044			num = 0;
1045		if (*p == '@')
1046			at = p;
1047		p++;
1048	}
1049	if (at && !at[1] && !isgroup)
1050		isgroup = 1;  /* special "XXX@" names should always be treated as groups */
1051	if (num) {
1052		/* must be numeric ID (or empty) */
1053		num = *id ? strtol(id, NULL, 10) : unknown;
1054		gp = guidp;
1055		goto gotnumid;
1056	}
1057
1058	if (nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE) {
1059		/*
1060		 * Ask the ID mapping service to map the ID string to a GUID.
1061		 *
1062		 * [sigh] this isn't a "pwnam/grnam" it's an NFS ID string!
1063		 */
1064		gp = compare ? &guid1 : guidp;
1065		if (isgroup)
1066			error = kauth_cred_grnam2guid(id, gp);
1067		else
1068			error = kauth_cred_pwnam2guid(id, gp);
1069		if (error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS))
1070			printf("nfs4_id2guid: idmap failed for %s %s error %d\n", id, isgroup ? "G" : " ", error);
1071		if (!error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS))
1072			printf("nfs4_id2guid: idmap for %s %s got guid "
1073				"%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1074				id, isgroup ? "G" : " ",
1075				gp->g_guid[0], gp->g_guid[1], gp->g_guid[2], gp->g_guid[3],
1076				gp->g_guid[4], gp->g_guid[5], gp->g_guid[6], gp->g_guid[7],
1077				gp->g_guid[8], gp->g_guid[9], gp->g_guid[10], gp->g_guid[11],
1078				gp->g_guid[12], gp->g_guid[13], gp->g_guid[14], gp->g_guid[15]);
1079		error1 = error;
1080	}
1081	if (error || compare || !(nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE)) {
1082		/*
1083		 * fallback path... see if we can come up with an answer ourselves.
1084		 */
1085		gp = compare ? &guid2 : guidp;
1086
1087		if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_WELLKNOWN_IDS) && at && !at[1]) {
1088			/* must be a special ACE "who" ID */
1089			bzero(&sid, sizeof(sid));
1090			sid.sid_kind = 1;
1091			sid.sid_authcount = 1;
1092			if (!strcmp(id, "OWNER@")) {
1093				// S-1-3-0
1094				sid.sid_authority[5] = 3;
1095				sid.sid_authorities[0] = 0;
1096			} else if (!strcmp(id, "GROUP@")) {
1097				// S-1-3-1
1098				sid.sid_authority[5] = 3;
1099				sid.sid_authorities[0] = 1;
1100			} else if (!strcmp(id, "EVERYONE@")) {
1101				// S-1-1-0
1102				sid.sid_authority[5] = 1;
1103				sid.sid_authorities[0] = 0;
1104			} else if (!strcmp(id, "INTERACTIVE@")) {
1105				// S-1-5-4
1106				sid.sid_authority[5] = 5;
1107				sid.sid_authorities[0] = 4;
1108			} else if (!strcmp(id, "NETWORK@")) {
1109				// S-1-5-2
1110				sid.sid_authority[5] = 5;
1111				sid.sid_authorities[0] = 2;
1112			} else if (!strcmp(id, "DIALUP@")) {
1113				// S-1-5-1
1114				sid.sid_authority[5] = 5;
1115				sid.sid_authorities[0] = 1;
1116			} else if (!strcmp(id, "BATCH@")) {
1117				// S-1-5-3
1118				sid.sid_authority[5] = 5;
1119				sid.sid_authorities[0] = 3;
1120			} else if (!strcmp(id, "ANONYMOUS@")) {
1121				// S-1-5-7
1122				sid.sid_authority[5] = 5;
1123				sid.sid_authorities[0] = 7;
1124			} else if (!strcmp(id, "AUTHENTICATED@")) {
1125				// S-1-5-11
1126				sid.sid_authority[5] = 5;
1127				sid.sid_authorities[0] = 11;
1128			} else if (!strcmp(id, "SERVICE@")) {
1129				// S-1-5-6
1130				sid.sid_authority[5] = 5;
1131				sid.sid_authorities[0] = 6;
1132			} else {
1133				// S-1-0-0 "NOBODY"
1134				sid.sid_authority[5] = 0;
1135				sid.sid_authorities[0] = 0;
1136			}
1137			error = kauth_cred_ntsid2guid(&sid, gp);
1138		} else {
1139			if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS) && at) {
1140				/* must be user@domain */
1141				/* try to identify some well-known IDs */
1142				if (!strncmp(id, "root@", 5))
1143					num = 0;
1144				else if (!strncmp(id, "wheel@", 6))
1145					num = 0;
1146				else if (!strncmp(id, "nobody@", 7))
1147					num = -2;
1148				else if (!strncmp(id, "nfsnobody@", 10))
1149					num = -2;
1150				else
1151					num = unknown;
1152			} else if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS) && !strcmp(id, "nobody")) {
1153				num = -2;
1154			} else {
1155				num = unknown;
1156			}
1157gotnumid:
1158			if (isgroup)
1159				error = kauth_cred_gid2guid((gid_t)num, gp);
1160			else
1161				error = kauth_cred_uid2guid((uid_t)num, gp);
1162		}
1163		if (error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS))
1164			printf("nfs4_id2guid: fallback map failed for %s %s error %d\n", id, isgroup ? "G" : " ", error);
1165		if (!error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS))
1166			printf("nfs4_id2guid: fallback map for %s %s got guid "
1167				"%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1168				id, isgroup ? "G" : " ",
1169				gp->g_guid[0], gp->g_guid[1], gp->g_guid[2], gp->g_guid[3],
1170				gp->g_guid[4], gp->g_guid[5], gp->g_guid[6], gp->g_guid[7],
1171				gp->g_guid[8], gp->g_guid[9], gp->g_guid[10], gp->g_guid[11],
1172				gp->g_guid[12], gp->g_guid[13], gp->g_guid[14], gp->g_guid[15]);
1173	}
1174
1175	if (compare) {
1176		/* compare the results, log if different */
1177		if (!error1 && !error) {
1178			if (!kauth_guid_equal(&guid1, &guid2))
1179				printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1180					"idmap %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x "
1181					"fallback %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1182					id, isgroup ? "G" : " ",
1183					guid1.g_guid[0], guid1.g_guid[1], guid1.g_guid[2], guid1.g_guid[3],
1184					guid1.g_guid[4], guid1.g_guid[5], guid1.g_guid[6], guid1.g_guid[7],
1185					guid1.g_guid[8], guid1.g_guid[9], guid1.g_guid[10], guid1.g_guid[11],
1186					guid1.g_guid[12], guid1.g_guid[13], guid1.g_guid[14], guid1.g_guid[15],
1187					guid2.g_guid[0], guid2.g_guid[1], guid2.g_guid[2], guid2.g_guid[3],
1188					guid2.g_guid[4], guid2.g_guid[5], guid2.g_guid[6], guid2.g_guid[7],
1189					guid2.g_guid[8], guid2.g_guid[9], guid2.g_guid[10], guid2.g_guid[11],
1190					guid2.g_guid[12], guid2.g_guid[13], guid2.g_guid[14], guid2.g_guid[15]);
1191			/* copy idmap result to output guid */
1192			*guidp = guid1;
1193		} else if (error1 && !error) {
1194			printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1195				"idmap error %d "
1196				"fallback %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1197				id, isgroup ? "G" : " ",
1198				error1,
1199				guid2.g_guid[0], guid2.g_guid[1], guid2.g_guid[2], guid2.g_guid[3],
1200				guid2.g_guid[4], guid2.g_guid[5], guid2.g_guid[6], guid2.g_guid[7],
1201				guid2.g_guid[8], guid2.g_guid[9], guid2.g_guid[10], guid2.g_guid[11],
1202				guid2.g_guid[12], guid2.g_guid[13], guid2.g_guid[14], guid2.g_guid[15]);
1203			/* copy fallback result to output guid */
1204			*guidp = guid2;
1205		} else if (!error1 && error) {
1206			printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1207				"idmap %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x "
1208				"fallback error %d\n",
1209				id, isgroup ? "G" : " ",
1210				guid1.g_guid[0], guid1.g_guid[1], guid1.g_guid[2], guid1.g_guid[3],
1211				guid1.g_guid[4], guid1.g_guid[5], guid1.g_guid[6], guid1.g_guid[7],
1212				guid1.g_guid[8], guid1.g_guid[9], guid1.g_guid[10], guid1.g_guid[11],
1213				guid1.g_guid[12], guid1.g_guid[13], guid1.g_guid[14], guid1.g_guid[15],
1214				error);
1215			/* copy idmap result to output guid */
1216			*guidp = guid1;
1217			error = 0;
1218		} else {
1219			if (error1 != error)
1220				printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1221					"idmap error %d fallback error %d\n",
1222					id, isgroup ? "G" : " ", error1, error);
1223		}
1224	}
1225
1226	return (error);
1227}
1228
1229/*
1230 * Map a VFS guid to an NFSv4 ID string.
1231 *
1232 * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
1233 */
1234int
1235nfs4_guid2id(guid_t *guidp, char *id, int *idlen, int isgroup)
1236{
1237	int error1 = 0, error = 0, compare;
1238	int id1len, id2len, len;
1239	char *id1buf, *id1;
1240	char numbuf[32];
1241	const char *id2 = NULL;
1242
1243	id1buf = id1 = NULL;
1244	id1len = id2len = 0;
1245	compare = ((nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE) &&
1246		   (nfs_idmap_ctrl & NFS_IDMAP_CTRL_COMPARE_RESULTS));
1247
1248	if (nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE) {
1249		/*
1250		 * Ask the ID mapping service to map the GUID to an ID string.
1251		 *
1252		 * [sigh] this isn't a "pwnam" it's an NFS id string!
1253		 */
1254
1255		/*
1256		 * Stupid kauth_cred_guid2pwnam() function requires that the buffer
1257		 * be at least MAXPATHLEN bytes long even though most if not all ID
1258		 * strings will be much much shorter than that.
1259		 */
1260		if (compare || (*idlen < MAXPATHLEN)) {
1261			MALLOC_ZONE(id1buf, char*, MAXPATHLEN, M_NAMEI, M_WAITOK);
1262			if (!id1buf)
1263				return (ENOMEM);
1264			id1 = id1buf;
1265			id1len = MAXPATHLEN;
1266		} else {
1267			id1 = id;
1268			id1len = *idlen;
1269		}
1270
1271		if (isgroup)
1272			error = kauth_cred_guid2grnam(guidp, id1);
1273		else
1274			error = kauth_cred_guid2pwnam(guidp, id1);
1275		if (error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS))
1276			printf("nfs4_guid2id: idmap failed for "
1277				"%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1278				"error %d\n",
1279				guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
1280				guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
1281				guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
1282				guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
1283				isgroup ? "G" : " ", error);
1284		if (!error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS))
1285			printf("nfs4_guid2id: idmap for "
1286				"%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1287				"got ID %s\n",
1288				guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
1289				guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
1290				guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
1291				guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
1292				isgroup ? "G" : " ", id1);
1293		error1 = error;
1294		if (!error) {
1295			if (compare) {
1296				id1len = strnlen(id1, id1len);
1297			} else if (id1 == id1buf) {
1298				/* copy idmap result to output buffer */
1299				len = strlcpy(id, id1, *idlen);
1300				if (len >= *idlen)
1301					error = ENOSPC;
1302				else
1303					*idlen = len;
1304			}
1305		}
1306	}
1307	if (error || compare || !(nfs_idmap_ctrl & NFS_IDMAP_CTRL_USE_IDMAP_SERVICE)) {
1308		/*
1309		 * fallback path... see if we can come up with an answer ourselves.
1310		 */
1311		ntsid_t sid;
1312		uid_t uid;
1313
1314		if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_WELLKNOWN_IDS)) {
1315			error = kauth_cred_guid2ntsid(guidp, &sid);
1316			if (!error && (sid.sid_kind == 1) && (sid.sid_authcount == 1)) {
1317				/* check if it's one of our well-known ACE WHO names */
1318				if (sid.sid_authority[5] == 0) {
1319					if (sid.sid_authorities[0] == 0) // S-1-0-0
1320						id2 = "nobody@localdomain";
1321				} else if (sid.sid_authority[5] == 1) {
1322					if (sid.sid_authorities[0] == 0) // S-1-1-0
1323						id2 = "EVERYONE@";
1324				} else if (sid.sid_authority[5] == 3) {
1325					if (sid.sid_authorities[0] == 0) // S-1-3-0
1326						id2 = "OWNER@";
1327					else if (sid.sid_authorities[0] == 1) // S-1-3-1
1328						id2 = "GROUP@";
1329				} else if (sid.sid_authority[5] == 5) {
1330					if (sid.sid_authorities[0] == ntohl(1)) // S-1-5-1
1331						id2 = "DIALUP@";
1332					else if (sid.sid_authorities[0] == ntohl(2)) // S-1-5-2
1333						id2 = "NETWORK@";
1334					else if (sid.sid_authorities[0] == ntohl(3)) // S-1-5-3
1335						id2 = "BATCH@";
1336					else if (sid.sid_authorities[0] == ntohl(4)) // S-1-5-4
1337						id2 = "INTERACTIVE@";
1338					else if (sid.sid_authorities[0] == ntohl(6)) // S-1-5-6
1339						id2 = "SERVICE@";
1340					else if (sid.sid_authorities[0] == ntohl(7)) // S-1-5-7
1341						id2 = "ANONYMOUS@";
1342					else if (sid.sid_authorities[0] == ntohl(11)) // S-1-5-11
1343						id2 = "AUTHENTICATED@";
1344				}
1345			}
1346		}
1347		if (!id2) {
1348			/* OK, let's just try mapping it to a UID/GID */
1349			if (isgroup)
1350				error = kauth_cred_guid2gid(guidp, (gid_t*)&uid);
1351			else
1352				error = kauth_cred_guid2uid(guidp, &uid);
1353			if (!error) {
1354				if (!(nfs_idmap_ctrl & NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS)) {
1355					/* map well known uid's to strings */
1356					if (uid == 0)
1357						id2 = isgroup ? "wheel@localdomain" : "root@localdomain";
1358					else if (uid == (uid_t)-2)
1359						id2 = "nobody@localdomain";
1360				}
1361				if (!id2) {
1362					/* or just use a decimal number string. */
1363					snprintf(numbuf, sizeof(numbuf), "%d", uid);
1364					id2 = numbuf;
1365				}
1366			}
1367		}
1368		if (error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS))
1369			printf("nfs4_guid2id: fallback map failed for "
1370				"%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1371				"error %d\n",
1372				guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
1373				guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
1374				guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
1375				guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
1376				isgroup ? "G" : " ", error);
1377		if (!error && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS))
1378			printf("nfs4_guid2id: fallback map for "
1379				"%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1380				"got ID %s\n",
1381				guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
1382				guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
1383				guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
1384				guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
1385				isgroup ? "G" : " ", id2);
1386		if (!error && id2) {
1387			if (compare) {
1388				id2len = strnlen(id2, MAXPATHLEN);
1389			} else {
1390				/* copy fallback result to output buffer */
1391				len = strlcpy(id, id2, *idlen);
1392				if (len >= *idlen)
1393					error = ENOSPC;
1394				else
1395					*idlen = len;
1396			}
1397		}
1398	}
1399
1400	if (compare) {
1401		/* compare the results, log if different */
1402		if (!error1 && !error) {
1403			if ((id1len != id2len) || strncmp(id1, id2, id1len))
1404				printf("nfs4_guid2id: idmap/fallback results differ for "
1405					"%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1406					"idmap %s fallback %s\n",
1407					guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
1408					guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
1409					guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
1410					guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
1411					isgroup ? "G" : " ", id1, id2);
1412			if (id1 == id1buf) {
1413				/* copy idmap result to output buffer */
1414				len = strlcpy(id, id1, *idlen);
1415				if (len >= *idlen)
1416					error = ENOSPC;
1417				else
1418					*idlen = len;
1419			}
1420		} else if (error1 && !error) {
1421			printf("nfs4_guid2id: idmap/fallback results differ for "
1422				"%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1423				"idmap error %d fallback %s\n",
1424				guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
1425				guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
1426				guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
1427				guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
1428				isgroup ? "G" : " ", error1, id2);
1429			/* copy fallback result to output buffer */
1430			len = strlcpy(id, id2, *idlen);
1431			if (len >= *idlen)
1432				error = ENOSPC;
1433			else
1434				*idlen = len;
1435		} else if (!error1 && error) {
1436			printf("nfs4_guid2id: idmap/fallback results differ for "
1437				"%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1438				"idmap %s fallback error %d\n",
1439				guidp->g_guid[0], guidp->g_guid[1], guidp->g_guid[2], guidp->g_guid[3],
1440				guidp->g_guid[4], guidp->g_guid[5], guidp->g_guid[6], guidp->g_guid[7],
1441				guidp->g_guid[8], guidp->g_guid[9], guidp->g_guid[10], guidp->g_guid[11],
1442				guidp->g_guid[12], guidp->g_guid[13], guidp->g_guid[14], guidp->g_guid[15],
1443				isgroup ? "G" : " ", id1, error);
1444			if (id1 == id1buf) {
1445				/* copy idmap result to output buffer */
1446				len = strlcpy(id, id1, *idlen);
1447				if (len >= *idlen)
1448					error = ENOSPC;
1449				else
1450					*idlen = len;
1451			}
1452			error = 0;
1453		} else {
1454			if (error1 != error)
1455				printf("nfs4_guid2id: idmap/fallback results differ for %s %s - "
1456					"idmap error %d fallback error %d\n",
1457					id, isgroup ? "G" : " ", error1, error);
1458		}
1459	}
1460	if (id1buf)
1461		FREE_ZONE(id1buf, MAXPATHLEN, M_NAMEI);
1462	return (error);
1463}
1464
1465
1466/*
1467 * Set a vnode attr's supported bits according to the given bitmap
1468 */
1469void
1470nfs_vattr_set_supported(uint32_t *bitmap, struct vnode_attr *vap)
1471{
1472	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TYPE))
1473		VATTR_SET_SUPPORTED(vap, va_type);
1474	// if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHANGE))
1475	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SIZE))
1476		VATTR_SET_SUPPORTED(vap, va_data_size);
1477	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FSID))
1478		VATTR_SET_SUPPORTED(vap, va_fsid);
1479	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL))
1480		VATTR_SET_SUPPORTED(vap, va_acl);
1481	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ARCHIVE))
1482		VATTR_SET_SUPPORTED(vap, va_flags);
1483	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILEID))
1484		VATTR_SET_SUPPORTED(vap, va_fileid);
1485	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HIDDEN))
1486		VATTR_SET_SUPPORTED(vap, va_flags);
1487	// if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE))
1488	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE))
1489		VATTR_SET_SUPPORTED(vap, va_mode);
1490	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NUMLINKS))
1491		VATTR_SET_SUPPORTED(vap, va_nlink);
1492	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER)) {
1493		VATTR_SET_SUPPORTED(vap, va_uid);
1494		VATTR_SET_SUPPORTED(vap, va_uuuid);
1495	}
1496	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER_GROUP)) {
1497		VATTR_SET_SUPPORTED(vap, va_gid);
1498		VATTR_SET_SUPPORTED(vap, va_guuid);
1499	}
1500	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_RAWDEV))
1501		VATTR_SET_SUPPORTED(vap, va_rdev);
1502	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_USED))
1503		VATTR_SET_SUPPORTED(vap, va_total_alloc);
1504	// if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYSTEM))
1505	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS))
1506		VATTR_SET_SUPPORTED(vap, va_access_time);
1507	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_BACKUP))
1508		VATTR_SET_SUPPORTED(vap, va_backup_time);
1509	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_CREATE))
1510		VATTR_SET_SUPPORTED(vap, va_create_time);
1511	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_METADATA))
1512		VATTR_SET_SUPPORTED(vap, va_change_time);
1513	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY))
1514		VATTR_SET_SUPPORTED(vap, va_modify_time);
1515}
1516
1517/*
1518 * Parse the attributes that are in the mbuf list and store them in
1519 * the given structures.
1520 */
1521int
1522nfs4_parsefattr(
1523	struct nfsm_chain *nmc,
1524	struct nfs_fsattr *nfsap,
1525	struct nfs_vattr *nvap,
1526	fhandle_t *fhp,
1527	struct dqblk *dqbp,
1528	struct nfs_fs_locations *nfslsp)
1529{
1530	int error = 0, error2, rderror = 0, attrbytes;
1531	uint32_t val, val2, val3, i;
1532	uint32_t bitmap[NFS_ATTR_BITMAP_LEN], len;
1533	size_t slen;
1534	char sbuf[64], *s;
1535	struct nfs_fsattr nfsa_dummy;
1536	struct nfs_vattr nva_dummy;
1537	struct dqblk dqb_dummy;
1538	kauth_acl_t acl = NULL;
1539	uint32_t ace_type, ace_flags, ace_mask;
1540	struct nfs_fs_locations nfsls_dummy;
1541	struct sockaddr_storage ss;
1542
1543	/* if not interested in some values... throw 'em into a local dummy variable */
1544	if (!nfsap)
1545		nfsap = &nfsa_dummy;
1546	if (!nvap)
1547		nvap = &nva_dummy;
1548	if (!dqbp)
1549		dqbp = &dqb_dummy;
1550	if (!nfslsp)
1551		nfslsp = &nfsls_dummy;
1552	bzero(nfslsp, sizeof(*nfslsp));
1553
1554	attrbytes = val = val2 = val3 = 0;
1555	s = sbuf;
1556	slen = sizeof(sbuf);
1557	NVATTR_INIT(nvap);
1558
1559	len = NFS_ATTR_BITMAP_LEN;
1560	nfsm_chain_get_bitmap(error, nmc, bitmap, len);
1561	/* add bits to object/fs attr bitmaps */
1562	for (i=0; i < NFS_ATTR_BITMAP_LEN; i++) {
1563		nvap->nva_bitmap[i] |= bitmap[i] & nfs_object_attr_bitmap[i];
1564		nfsap->nfsa_bitmap[i] |= bitmap[i] & nfs_fs_attr_bitmap[i];
1565	}
1566
1567	nfsm_chain_get_32(error, nmc, attrbytes);
1568	nfsmout_if(error);
1569
1570	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SUPPORTED_ATTRS)) {
1571		len = NFS_ATTR_BITMAP_LEN;
1572		nfsm_chain_get_bitmap(error, nmc, nfsap->nfsa_supp_attr, len);
1573		attrbytes -= (len + 1) * NFSX_UNSIGNED;
1574	}
1575	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TYPE)) {
1576		nfsm_chain_get_32(error, nmc, val);
1577		nvap->nva_type = nfstov_type(val, NFS_VER4);
1578		if ((val == NFATTRDIR) || (val == NFNAMEDATTR))
1579			nvap->nva_flags |= NFS_FFLAG_IS_ATTR;
1580		else
1581			nvap->nva_flags &= ~NFS_FFLAG_IS_ATTR;
1582		attrbytes -= NFSX_UNSIGNED;
1583	}
1584	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FH_EXPIRE_TYPE)) {
1585		nfsm_chain_get_32(error, nmc, val);
1586		nfsmout_if(error);
1587		nfsap->nfsa_flags &= ~NFS_FSFLAG_FHTYPE_MASK;
1588		nfsap->nfsa_flags |= val << NFS_FSFLAG_FHTYPE_SHIFT;
1589		if (val & ~0xff)
1590			printf("nfs: warning unknown fh type: 0x%x\n", val);
1591		attrbytes -= NFSX_UNSIGNED;
1592	}
1593	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHANGE)) {
1594		nfsm_chain_get_64(error, nmc, nvap->nva_change);
1595		attrbytes -= 2 * NFSX_UNSIGNED;
1596	}
1597	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SIZE)) {
1598		nfsm_chain_get_64(error, nmc, nvap->nva_size);
1599		attrbytes -= 2 * NFSX_UNSIGNED;
1600	}
1601	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_LINK_SUPPORT)) {
1602		nfsm_chain_get_32(error, nmc, val);
1603		if (val)
1604			nfsap->nfsa_flags |= NFS_FSFLAG_LINK;
1605		else
1606			nfsap->nfsa_flags &= ~NFS_FSFLAG_LINK;
1607		attrbytes -= NFSX_UNSIGNED;
1608	}
1609	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYMLINK_SUPPORT)) {
1610		nfsm_chain_get_32(error, nmc, val);
1611		if (val)
1612			nfsap->nfsa_flags |= NFS_FSFLAG_SYMLINK;
1613		else
1614			nfsap->nfsa_flags &= ~NFS_FSFLAG_SYMLINK;
1615		attrbytes -= NFSX_UNSIGNED;
1616	}
1617	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NAMED_ATTR)) {
1618		nfsm_chain_get_32(error, nmc, val);
1619		if (val)
1620			nvap->nva_flags |= NFS_FFLAG_HAS_NAMED_ATTRS;
1621		else
1622			nvap->nva_flags &= ~NFS_FFLAG_HAS_NAMED_ATTRS;
1623		attrbytes -= NFSX_UNSIGNED;
1624	}
1625	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FSID)) {
1626		nfsm_chain_get_64(error, nmc, nvap->nva_fsid.major);
1627		nfsm_chain_get_64(error, nmc, nvap->nva_fsid.minor);
1628		attrbytes -= 4 * NFSX_UNSIGNED;
1629	}
1630	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_UNIQUE_HANDLES)) {
1631		nfsm_chain_get_32(error, nmc, val);
1632		if (val)
1633			nfsap->nfsa_flags |= NFS_FSFLAG_UNIQUE_FH;
1634		else
1635			nfsap->nfsa_flags &= ~NFS_FSFLAG_UNIQUE_FH;
1636		attrbytes -= NFSX_UNSIGNED;
1637	}
1638	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_LEASE_TIME)) {
1639		nfsm_chain_get_32(error, nmc, nfsap->nfsa_lease);
1640		attrbytes -= NFSX_UNSIGNED;
1641	}
1642	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_RDATTR_ERROR)) {
1643		nfsm_chain_get_32(error, nmc, rderror);
1644		attrbytes -= NFSX_UNSIGNED;
1645		if (!rderror) { /* no error */
1646			NFS_BITMAP_CLR(bitmap, NFS_FATTR_RDATTR_ERROR);
1647			NFS_BITMAP_CLR(nvap->nva_bitmap, NFS_FATTR_RDATTR_ERROR);
1648		}
1649	}
1650	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL)) {
1651		error2 = 0;
1652		ace_type = ace_flags = ace_mask = 0;
1653		nfsm_chain_get_32(error, nmc, val); /* ACE count */
1654		if (!error && (val > KAUTH_ACL_MAX_ENTRIES))
1655			error = EOVERFLOW;
1656		if (!error && !((acl = kauth_acl_alloc(val))))
1657			error = ENOMEM;
1658		if (!error && acl) {
1659			acl->acl_entrycount = val;
1660			acl->acl_flags = 0;
1661		}
1662		attrbytes -= NFSX_UNSIGNED;
1663		nfsm_assert(error, (attrbytes >= 0), EBADRPC);
1664		for (i=0; !error && (i < val); i++) {
1665			nfsm_chain_get_32(error, nmc, ace_type);
1666			nfsm_chain_get_32(error, nmc, ace_flags);
1667			nfsm_chain_get_32(error, nmc, ace_mask);
1668			nfsm_chain_get_32(error, nmc, len);
1669			if (!error && len >= NFS_MAX_WHO)
1670				error = EBADRPC;
1671			acl->acl_ace[i].ace_flags = nfs4_ace_nfstype_to_vfstype(ace_type, &error);
1672			acl->acl_ace[i].ace_flags |= nfs4_ace_nfsflags_to_vfsflags(ace_flags);
1673			acl->acl_ace[i].ace_rights = nfs4_ace_nfsmask_to_vfsrights(ace_mask);
1674			if (!error && !error2 && (len >= slen)) {
1675				if (s != sbuf) {
1676					FREE(s, M_TEMP);
1677					s = sbuf;
1678					slen = sizeof(sbuf);
1679				}
1680				/* Let's add a bit more if we can to the allocation as to try and avoid future allocations */
1681				MALLOC(s, char*, (len + 16 < NFS_MAX_WHO) ? len+16 : NFS_MAX_WHO, M_TEMP, M_WAITOK);
1682				if (s)
1683					slen = (len + 16 < NFS_MAX_WHO) ? len+16 : NFS_MAX_WHO;
1684				else
1685					error = ENOMEM;
1686			}
1687			if (error2)
1688				nfsm_chain_adv(error, nmc, nfsm_rndup(len));
1689			else
1690				nfsm_chain_get_opaque(error, nmc, len, s);
1691			if (!error && !error2) {
1692				s[len] = '\0';
1693				error2 = nfs4_id2guid(s, &acl->acl_ace[i].ace_applicable,
1694						(ace_flags & NFS_ACE_IDENTIFIER_GROUP));
1695				if (error2 && (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS))
1696					printf("nfs4_parsefattr: ACE WHO %s is no one, no guid?, error %d\n", s, error2);
1697			}
1698			attrbytes -= 4*NFSX_UNSIGNED + nfsm_rndup(len);
1699			nfsm_assert(error, (attrbytes >= 0), EBADRPC);
1700		}
1701		nfsmout_if(error);
1702		if ((nvap != &nva_dummy) && !error2) {
1703			nvap->nva_acl = acl;
1704			acl = NULL;
1705		}
1706	}
1707	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACLSUPPORT)) {
1708		/*
1709		 * Support ACLs if: the server supports DENY/ALLOC ACEs and
1710		 * (just to be safe) FATTR_ACL is in the supported list too.
1711		 */
1712		nfsm_chain_get_32(error, nmc, val);
1713		if ((val & (NFS_ACL_SUPPORT_ALLOW_ACL|NFS_ACL_SUPPORT_DENY_ACL)) &&
1714		    NFS_BITMAP_ISSET(nfsap->nfsa_supp_attr, NFS_FATTR_ACL)) {
1715			nfsap->nfsa_flags |= NFS_FSFLAG_ACL;
1716		} else {
1717			nfsap->nfsa_flags &= ~NFS_FSFLAG_ACL;
1718		}
1719		attrbytes -= NFSX_UNSIGNED;
1720	}
1721	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ARCHIVE)) { /* SF_ARCHIVED */
1722		nfsm_chain_get_32(error, nmc, val);
1723		if (val)
1724			nvap->nva_flags |= NFS_FFLAG_ARCHIVED;
1725		else
1726			nvap->nva_flags &= ~NFS_FFLAG_ARCHIVED;
1727		attrbytes -= NFSX_UNSIGNED;
1728	}
1729	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CANSETTIME)) {
1730		nfsm_chain_get_32(error, nmc, val);
1731		if (val)
1732			nfsap->nfsa_flags |= NFS_FSFLAG_SET_TIME;
1733		else
1734			nfsap->nfsa_flags &= ~NFS_FSFLAG_SET_TIME;
1735		attrbytes -= NFSX_UNSIGNED;
1736	}
1737	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CASE_INSENSITIVE)) {
1738		nfsm_chain_get_32(error, nmc, val);
1739		if (val)
1740			nfsap->nfsa_flags |= NFS_FSFLAG_CASE_INSENSITIVE;
1741		else
1742			nfsap->nfsa_flags &= ~NFS_FSFLAG_CASE_INSENSITIVE;
1743		attrbytes -= NFSX_UNSIGNED;
1744	}
1745	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CASE_PRESERVING)) {
1746		nfsm_chain_get_32(error, nmc, val);
1747		if (val)
1748			nfsap->nfsa_flags |= NFS_FSFLAG_CASE_PRESERVING;
1749		else
1750			nfsap->nfsa_flags &= ~NFS_FSFLAG_CASE_PRESERVING;
1751		attrbytes -= NFSX_UNSIGNED;
1752	}
1753	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHOWN_RESTRICTED)) {
1754		nfsm_chain_get_32(error, nmc, val);
1755		if (val)
1756			nfsap->nfsa_flags |= NFS_FSFLAG_CHOWN_RESTRICTED;
1757		else
1758			nfsap->nfsa_flags &= ~NFS_FSFLAG_CHOWN_RESTRICTED;
1759		attrbytes -= NFSX_UNSIGNED;
1760	}
1761	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILEHANDLE)) {
1762		nfsm_chain_get_32(error, nmc, val);
1763		if (fhp) {
1764			fhp->fh_len = val;
1765			nfsm_chain_get_opaque(error, nmc, nfsm_rndup(val), fhp->fh_data);
1766		} else {
1767			nfsm_chain_adv(error, nmc, nfsm_rndup(val));
1768		}
1769		attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val);
1770	}
1771	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILEID)) {
1772		nfsm_chain_get_64(error, nmc, nvap->nva_fileid);
1773		attrbytes -= 2 * NFSX_UNSIGNED;
1774	}
1775	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILES_AVAIL)) {
1776		nfsm_chain_get_64(error, nmc, nfsap->nfsa_files_avail);
1777		attrbytes -= 2 * NFSX_UNSIGNED;
1778	}
1779	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILES_FREE)) {
1780		nfsm_chain_get_64(error, nmc, nfsap->nfsa_files_free);
1781		attrbytes -= 2 * NFSX_UNSIGNED;
1782	}
1783	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILES_TOTAL)) {
1784		nfsm_chain_get_64(error, nmc, nfsap->nfsa_files_total);
1785		attrbytes -= 2 * NFSX_UNSIGNED;
1786	}
1787	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FS_LOCATIONS)) {
1788		uint32_t loc, serv, comp;
1789		struct nfs_fs_location *fsl;
1790		struct nfs_fs_server *fss;
1791		struct nfs_fs_path *fsp;
1792
1793		/* get root pathname */
1794		fsp = &nfslsp->nl_root;
1795		nfsm_chain_get_32(error, nmc, fsp->np_compcount); /* component count */
1796		attrbytes -= NFSX_UNSIGNED;
1797		/* sanity check component count */
1798		if (!error && (fsp->np_compcount > MAXPATHLEN))
1799			error = EBADRPC;
1800		nfsmout_if(error);
1801		if (fsp->np_compcount) {
1802			MALLOC(fsp->np_components, char **, fsp->np_compcount * sizeof(char*), M_TEMP, M_WAITOK|M_ZERO);
1803			if (!fsp->np_components)
1804				error = ENOMEM;
1805		}
1806		for (comp = 0; comp < fsp->np_compcount; comp++) {
1807			nfsm_chain_get_32(error, nmc, val); /* component length */
1808			/* sanity check component length */
1809			if (!error && (val == 0)) {
1810				/*
1811				 * Apparently some people think a path with zero components should
1812				 * be encoded with one zero-length component.  So, just ignore any
1813				 * zero length components.
1814				 */
1815				comp--;
1816				fsp->np_compcount--;
1817				if (fsp->np_compcount == 0) {
1818					FREE(fsp->np_components, M_TEMP);
1819					fsp->np_components = NULL;
1820				}
1821				attrbytes -= NFSX_UNSIGNED;
1822				continue;
1823			}
1824			if (!error && ((val < 1) || (val > MAXPATHLEN)))
1825				error = EBADRPC;
1826			nfsmout_if(error);
1827			MALLOC(fsp->np_components[comp], char *, val+1, M_TEMP, M_WAITOK|M_ZERO);
1828			if (!fsp->np_components[comp])
1829				error = ENOMEM;
1830			nfsmout_if(error);
1831			nfsm_chain_get_opaque(error, nmc, val, fsp->np_components[comp]); /* component */
1832			attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val);
1833		}
1834		nfsm_chain_get_32(error, nmc, nfslsp->nl_numlocs); /* fs location count */
1835		attrbytes -= NFSX_UNSIGNED;
1836		/* sanity check location count */
1837		if (!error && (nfslsp->nl_numlocs > 256))
1838			error = EBADRPC;
1839		nfsmout_if(error);
1840		if (nfslsp->nl_numlocs > 0) {
1841			MALLOC(nfslsp->nl_locations, struct nfs_fs_location **, nfslsp->nl_numlocs * sizeof(struct nfs_fs_location*), M_TEMP, M_WAITOK|M_ZERO);
1842			if (!nfslsp->nl_locations)
1843				error = ENOMEM;
1844		}
1845		nfsmout_if(error);
1846		for (loc = 0; loc < nfslsp->nl_numlocs; loc++) {
1847			nfsmout_if(error);
1848			MALLOC(fsl, struct nfs_fs_location *, sizeof(struct nfs_fs_location), M_TEMP, M_WAITOK|M_ZERO);
1849			if (!fsl)
1850				error = ENOMEM;
1851			nfslsp->nl_locations[loc] = fsl;
1852			nfsm_chain_get_32(error, nmc, fsl->nl_servcount); /* server count */
1853			attrbytes -= NFSX_UNSIGNED;
1854			/* sanity check server count */
1855			if (!error && ((fsl->nl_servcount < 1) || (fsl->nl_servcount > 256)))
1856				error = EBADRPC;
1857			nfsmout_if(error);
1858			MALLOC(fsl->nl_servers, struct nfs_fs_server **, fsl->nl_servcount * sizeof(struct nfs_fs_server*), M_TEMP, M_WAITOK|M_ZERO);
1859			if (!fsl->nl_servers)
1860				error = ENOMEM;
1861			for (serv = 0; serv < fsl->nl_servcount; serv++) {
1862				nfsmout_if(error);
1863				MALLOC(fss, struct nfs_fs_server *, sizeof(struct nfs_fs_server), M_TEMP, M_WAITOK|M_ZERO);
1864				if (!fss)
1865					error = ENOMEM;
1866				fsl->nl_servers[serv] = fss;
1867				nfsm_chain_get_32(error, nmc, val); /* server name length */
1868				/* sanity check server name length */
1869				if (!error && ((val < 1) || (val > MAXPATHLEN)))
1870					error = EINVAL;
1871				nfsmout_if(error);
1872				MALLOC(fss->ns_name, char *, val+1, M_TEMP, M_WAITOK|M_ZERO);
1873				if (!fss->ns_name)
1874					error = ENOMEM;
1875				nfsm_chain_get_opaque(error, nmc, val, fss->ns_name); /* server name */
1876				attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val);
1877				nfsmout_if(error);
1878				/* copy name to address if it converts to a sockaddr */
1879				if (nfs_uaddr2sockaddr(fss->ns_name, (struct sockaddr*)&ss)) {
1880					fss->ns_addrcount = 1;
1881					MALLOC(fss->ns_addresses, char **, sizeof(char *), M_TEMP, M_WAITOK|M_ZERO);
1882					if (!fss->ns_addresses)
1883						error = ENOMEM;
1884					nfsmout_if(error);
1885					MALLOC(fss->ns_addresses[0], char *, val+1, M_TEMP, M_WAITOK|M_ZERO);
1886					if (!fss->ns_addresses[0])
1887						error = ENOMEM;
1888					nfsmout_if(error);
1889					strlcpy(fss->ns_addresses[0], fss->ns_name, val+1);
1890				}
1891			}
1892			/* get pathname */
1893			fsp = &fsl->nl_path;
1894			nfsm_chain_get_32(error, nmc, fsp->np_compcount); /* component count */
1895			attrbytes -= NFSX_UNSIGNED;
1896			/* sanity check component count */
1897			if (!error && (fsp->np_compcount > MAXPATHLEN))
1898				error = EINVAL;
1899			nfsmout_if(error);
1900			if (fsp->np_compcount) {
1901				MALLOC(fsp->np_components, char **, fsp->np_compcount * sizeof(char*), M_TEMP, M_WAITOK|M_ZERO);
1902				if (!fsp->np_components)
1903					error = ENOMEM;
1904			}
1905			for (comp = 0; comp < fsp->np_compcount; comp++) {
1906				nfsm_chain_get_32(error, nmc, val); /* component length */
1907				/* sanity check component length */
1908				if (!error && (val == 0)) {
1909					/*
1910					 * Apparently some people think a path with zero components should
1911					 * be encoded with one zero-length component.  So, just ignore any
1912					 * zero length components.
1913					 */
1914					comp--;
1915					fsp->np_compcount--;
1916					if (fsp->np_compcount == 0) {
1917						FREE(fsp->np_components, M_TEMP);
1918						fsp->np_components = NULL;
1919					}
1920					attrbytes -= NFSX_UNSIGNED;
1921					continue;
1922				}
1923				if (!error && ((val < 1) || (val > MAXPATHLEN)))
1924					error = EINVAL;
1925				nfsmout_if(error);
1926				MALLOC(fsp->np_components[comp], char *, val+1, M_TEMP, M_WAITOK|M_ZERO);
1927				if (!fsp->np_components[comp])
1928					error = ENOMEM;
1929				nfsm_chain_get_opaque(error, nmc, val, fsp->np_components[comp]); /* component */
1930				attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val);
1931			}
1932		}
1933		nfsm_assert(error, (attrbytes >= 0), EBADRPC);
1934	}
1935	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HIDDEN)) { /* UF_HIDDEN */
1936		nfsm_chain_get_32(error, nmc, val);
1937		if (val)
1938			nvap->nva_flags |= NFS_FFLAG_HIDDEN;
1939		else
1940			nvap->nva_flags &= ~NFS_FFLAG_HIDDEN;
1941		attrbytes -= NFSX_UNSIGNED;
1942	}
1943	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HOMOGENEOUS)) {
1944		/* XXX If NOT homogeneous, we may need to clear flags on the mount */
1945		nfsm_chain_get_32(error, nmc, val);
1946		if (val)
1947			nfsap->nfsa_flags |= NFS_FSFLAG_HOMOGENEOUS;
1948		else
1949			nfsap->nfsa_flags &= ~NFS_FSFLAG_HOMOGENEOUS;
1950		attrbytes -= NFSX_UNSIGNED;
1951	}
1952	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXFILESIZE)) {
1953		nfsm_chain_get_64(error, nmc, nfsap->nfsa_maxfilesize);
1954		attrbytes -= 2 * NFSX_UNSIGNED;
1955	}
1956	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXLINK)) {
1957		nfsm_chain_get_32(error, nmc, nvap->nva_maxlink);
1958		if (!error && (nfsap->nfsa_maxlink > INT32_MAX))
1959			nfsap->nfsa_maxlink = INT32_MAX;
1960		attrbytes -= NFSX_UNSIGNED;
1961	}
1962	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXNAME)) {
1963		nfsm_chain_get_32(error, nmc, nfsap->nfsa_maxname);
1964		if (!error && (nfsap->nfsa_maxname > INT32_MAX))
1965			nfsap->nfsa_maxname = INT32_MAX;
1966		attrbytes -= NFSX_UNSIGNED;
1967	}
1968	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXREAD)) {
1969		nfsm_chain_get_64(error, nmc, nfsap->nfsa_maxread);
1970		attrbytes -= 2 * NFSX_UNSIGNED;
1971	}
1972	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXWRITE)) {
1973		nfsm_chain_get_64(error, nmc, nfsap->nfsa_maxwrite);
1974		attrbytes -= 2 * NFSX_UNSIGNED;
1975	}
1976	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE)) {
1977		nfsm_chain_get_32(error, nmc, val);
1978		nfsm_chain_adv(error, nmc, nfsm_rndup(val));
1979		attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val);
1980	}
1981	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE)) {
1982		nfsm_chain_get_32(error, nmc, nvap->nva_mode);
1983		attrbytes -= NFSX_UNSIGNED;
1984	}
1985	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NO_TRUNC)) {
1986		nfsm_chain_get_32(error, nmc, val);
1987		if (val)
1988			nfsap->nfsa_flags |= NFS_FSFLAG_NO_TRUNC;
1989		else
1990			nfsap->nfsa_flags &= ~NFS_FSFLAG_NO_TRUNC;
1991		attrbytes -= NFSX_UNSIGNED;
1992	}
1993	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NUMLINKS)) {
1994		nfsm_chain_get_32(error, nmc, val);
1995		nvap->nva_nlink = val;
1996		attrbytes -= NFSX_UNSIGNED;
1997	}
1998	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER)) {
1999		nfsm_chain_get_32(error, nmc, len);
2000		if (!error && len >= NFS_MAX_WHO)
2001			error = EBADRPC;
2002		if (!error && (len >= slen)) {
2003			if (s != sbuf) {
2004				FREE(s, M_TEMP);
2005				s = sbuf;
2006				slen = sizeof(sbuf);
2007			}
2008			/* Let's add a bit more if we can to the allocation as to try and avoid future allocations */
2009			MALLOC(s, char*, (len + 16 < NFS_MAX_WHO) ? len+16 : NFS_MAX_WHO, M_TEMP, M_WAITOK);
2010			if (s)
2011				slen = (len + 16 < NFS_MAX_WHO) ? len+16 : NFS_MAX_WHO;
2012			else
2013				error = ENOMEM;
2014		}
2015		nfsm_chain_get_opaque(error, nmc, len, s);
2016		if (!error) {
2017			s[len] = '\0';
2018			error = nfs4_id2guid(s, &nvap->nva_uuuid, 0);
2019			if (!error)
2020				error = kauth_cred_guid2uid(&nvap->nva_uuuid, &nvap->nva_uid);
2021			if (error) {
2022				/* unable to get either GUID or UID, set to default */
2023				nvap->nva_uid = (uid_t)((nfs_idmap_ctrl & NFS_IDMAP_CTRL_UNKNOWN_IS_99) ? 99 : -2);
2024				if (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS)
2025					printf("nfs4_parsefattr: owner %s is no one, no %s?, error %d\n", s,
2026						kauth_guid_equal(&nvap->nva_uuuid, &kauth_null_guid) ? "guid" : "uid",
2027						error);
2028				error = 0;
2029			}
2030		}
2031		attrbytes -= NFSX_UNSIGNED + nfsm_rndup(len);
2032	}
2033	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER_GROUP)) {
2034		nfsm_chain_get_32(error, nmc, len);
2035		if (!error && len >= NFS_MAX_WHO)
2036			error = EBADRPC;
2037		if (!error && (len >= slen)) {
2038			if (s != sbuf) {
2039				FREE(s, M_TEMP);
2040				s = sbuf;
2041				slen = sizeof(sbuf);
2042			}
2043			/* Let's add a bit more if we can to the allocation as to try and avoid future allocations */
2044			MALLOC(s, char*, (len + 16 < NFS_MAX_WHO) ? len+16 : NFS_MAX_WHO, M_TEMP, M_WAITOK);
2045			if (s)
2046				slen = (len + 16 < NFS_MAX_WHO) ? len+16 : NFS_MAX_WHO;
2047			else
2048				error = ENOMEM;
2049		}
2050		nfsm_chain_get_opaque(error, nmc, len, s);
2051		if (!error) {
2052			s[len] = '\0';
2053			error = nfs4_id2guid(s, &nvap->nva_guuid, 1);
2054			if (!error)
2055				error = kauth_cred_guid2gid(&nvap->nva_guuid, &nvap->nva_gid);
2056			if (error) {
2057				/* unable to get either GUID or GID, set to default */
2058				nvap->nva_gid = (gid_t)((nfs_idmap_ctrl & NFS_IDMAP_CTRL_UNKNOWN_IS_99) ? 99 : -2);
2059				if (nfs_idmap_ctrl & NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS)
2060					printf("nfs4_parsefattr: group %s is no one, no %s?, error %d\n", s,
2061						kauth_guid_equal(&nvap->nva_guuid, &kauth_null_guid) ? "guid" : "gid",
2062						error);
2063				error = 0;
2064			}
2065		}
2066		attrbytes -= NFSX_UNSIGNED + nfsm_rndup(len);
2067	}
2068	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_QUOTA_AVAIL_HARD)) {
2069		nfsm_chain_get_64(error, nmc, dqbp->dqb_bhardlimit);
2070		attrbytes -= 2 * NFSX_UNSIGNED;
2071	}
2072	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_QUOTA_AVAIL_SOFT)) {
2073		nfsm_chain_get_64(error, nmc, dqbp->dqb_bsoftlimit);
2074		attrbytes -= 2 * NFSX_UNSIGNED;
2075	}
2076	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_QUOTA_USED)) {
2077		nfsm_chain_get_64(error, nmc, dqbp->dqb_curbytes);
2078		attrbytes -= 2 * NFSX_UNSIGNED;
2079	}
2080	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_RAWDEV)) {
2081		nfsm_chain_get_32(error, nmc, nvap->nva_rawdev.specdata1);
2082		nfsm_chain_get_32(error, nmc, nvap->nva_rawdev.specdata2);
2083		attrbytes -= 2 * NFSX_UNSIGNED;
2084	}
2085	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_AVAIL)) {
2086		nfsm_chain_get_64(error, nmc, nfsap->nfsa_space_avail);
2087		attrbytes -= 2 * NFSX_UNSIGNED;
2088	}
2089	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_FREE)) {
2090		nfsm_chain_get_64(error, nmc, nfsap->nfsa_space_free);
2091		attrbytes -= 2 * NFSX_UNSIGNED;
2092	}
2093	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_TOTAL)) {
2094		nfsm_chain_get_64(error, nmc, nfsap->nfsa_space_total);
2095		attrbytes -= 2 * NFSX_UNSIGNED;
2096	}
2097	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_USED)) {
2098		nfsm_chain_get_64(error, nmc, nvap->nva_bytes);
2099		attrbytes -= 2 * NFSX_UNSIGNED;
2100	}
2101	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYSTEM)) {
2102		/* we'd support this if we had a flag to map it to... */
2103		nfsm_chain_adv(error, nmc, NFSX_UNSIGNED);
2104		attrbytes -= NFSX_UNSIGNED;
2105	}
2106	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS)) {
2107		nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_ACCESS]);
2108		nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_ACCESS]);
2109		attrbytes -= 3 * NFSX_UNSIGNED;
2110	}
2111	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS_SET)) {
2112		nfsm_chain_adv(error, nmc, 4*NFSX_UNSIGNED); /* just skip it */
2113		attrbytes -= 4 * NFSX_UNSIGNED;
2114	}
2115	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_BACKUP)) {
2116		nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_BACKUP]);
2117		nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_BACKUP]);
2118		attrbytes -= 3 * NFSX_UNSIGNED;
2119	}
2120	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_CREATE)) {
2121		nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_CREATE]);
2122		nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_CREATE]);
2123		attrbytes -= 3 * NFSX_UNSIGNED;
2124	}
2125	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_DELTA)) { /* skip for now */
2126		nfsm_chain_adv(error, nmc, 3*NFSX_UNSIGNED);
2127		attrbytes -= 3 * NFSX_UNSIGNED;
2128	}
2129	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_METADATA)) {
2130		nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_CHANGE]);
2131		nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_CHANGE]);
2132		attrbytes -= 3 * NFSX_UNSIGNED;
2133	}
2134	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY)) {
2135		nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_MODIFY]);
2136		nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_MODIFY]);
2137		attrbytes -= 3 * NFSX_UNSIGNED;
2138	}
2139	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY_SET)) {
2140		nfsm_chain_adv(error, nmc, 4*NFSX_UNSIGNED); /* just skip it */
2141		attrbytes -= 4 * NFSX_UNSIGNED;
2142	}
2143	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MOUNTED_ON_FILEID)) {
2144#if CONFIG_TRIGGERS
2145		/* we prefer the mounted on file ID, so just replace the fileid */
2146		nfsm_chain_get_64(error, nmc, nvap->nva_fileid);
2147#else
2148		nfsm_chain_adv(error, nmc, 2*NFSX_UNSIGNED);
2149#endif
2150		attrbytes -= 2 * NFSX_UNSIGNED;
2151	}
2152	/* advance over any leftover attrbytes */
2153	nfsm_assert(error, (attrbytes >= 0), EBADRPC);
2154	nfsm_chain_adv(error, nmc, nfsm_rndup(attrbytes));
2155nfsmout:
2156	if (error)
2157		nfs_fs_locations_cleanup(nfslsp);
2158	if (!error && rderror)
2159		error = rderror;
2160	/* free up temporary resources */
2161	if (s && (s != sbuf))
2162		FREE(s, M_TEMP);
2163	if (acl)
2164		kauth_acl_free(acl);
2165	if (error && nvap->nva_acl) {
2166		kauth_acl_free(nvap->nva_acl);
2167		nvap->nva_acl = NULL;
2168	}
2169	return (error);
2170}
2171
2172/*
2173 * Add an NFSv4 "sattr" structure to an mbuf chain
2174 */
2175int
2176nfsm_chain_add_fattr4_f(struct nfsm_chain *nmc, struct vnode_attr *vap, struct nfsmount *nmp)
2177{
2178	int error = 0, attrbytes, slen, len, i, isgroup;
2179	uint32_t *pattrbytes, val, acecount;;
2180	uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
2181	char sbuf[64], *s;
2182	kauth_acl_t acl;
2183	gid_t gid;
2184
2185	s = sbuf;
2186	slen = sizeof(sbuf);
2187
2188	/* First calculate the bitmap... */
2189	nfs_vattr_set_bitmap(nmp, bitmap, vap);
2190
2191	/*
2192	 * Now pack it all together:
2193	 *     BITMAP, #BYTES, ATTRS
2194	 * Keep a pointer to the length so we can set it later.
2195	 */
2196	nfsm_chain_add_bitmap(error, nmc, bitmap, NFS_ATTR_BITMAP_LEN);
2197	attrbytes = 0;
2198	nfsm_chain_add_32(error, nmc, attrbytes);
2199	pattrbytes = (uint32_t*)(nmc->nmc_ptr - NFSX_UNSIGNED);
2200
2201	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SIZE)) {
2202		nfsm_chain_add_64(error, nmc, vap->va_data_size);
2203		attrbytes += 2*NFSX_UNSIGNED;
2204	}
2205	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL)) {
2206		acl = vap->va_acl;
2207		if (!acl || (acl->acl_entrycount == KAUTH_FILESEC_NOACL))
2208			acecount = 0;
2209		else
2210			acecount = acl->acl_entrycount;
2211		nfsm_chain_add_32(error, nmc, acecount);
2212		attrbytes += NFSX_UNSIGNED;
2213		for (i=0; !error && (i < (int)acecount); i++) {
2214			val = (acl->acl_ace[i].ace_flags & KAUTH_ACE_KINDMASK);
2215			val = nfs4_ace_vfstype_to_nfstype(val, &error);
2216			nfsm_chain_add_32(error, nmc, val);
2217			val = nfs4_ace_vfsflags_to_nfsflags(acl->acl_ace[i].ace_flags);
2218			nfsm_chain_add_32(error, nmc, val);
2219			val = nfs4_ace_vfsrights_to_nfsmask(acl->acl_ace[i].ace_rights);
2220			nfsm_chain_add_32(error, nmc, val);
2221			len = slen;
2222			isgroup = (kauth_cred_guid2gid(&acl->acl_ace[i].ace_applicable, &gid) == 0);
2223			error = nfs4_guid2id(&acl->acl_ace[i].ace_applicable, s, &len, isgroup);
2224			if (error == ENOSPC) {
2225				if (s != sbuf) {
2226					FREE(s, M_TEMP);
2227					s = sbuf;
2228				}
2229				len += 8;
2230				MALLOC(s, char*, len, M_TEMP, M_WAITOK);
2231				if (s) {
2232					slen = len;
2233					error = nfs4_guid2id(&acl->acl_ace[i].ace_applicable, s, &len, isgroup);
2234				} else {
2235					error = ENOMEM;
2236				}
2237			}
2238			nfsm_chain_add_name(error, nmc, s, len, nmp);
2239			attrbytes += 4*NFSX_UNSIGNED + nfsm_rndup(len);
2240		}
2241	}
2242	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ARCHIVE)) {
2243		nfsm_chain_add_32(error, nmc, (vap->va_flags & SF_ARCHIVED) ? 1 : 0);
2244		attrbytes += NFSX_UNSIGNED;
2245	}
2246	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HIDDEN)) {
2247		nfsm_chain_add_32(error, nmc, (vap->va_flags & UF_HIDDEN) ? 1 : 0);
2248		attrbytes += NFSX_UNSIGNED;
2249	}
2250	// NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE)
2251	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE)) {
2252		nfsm_chain_add_32(error, nmc, vap->va_mode);
2253		attrbytes += NFSX_UNSIGNED;
2254	}
2255	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER)) {
2256		nfsmout_if(error);
2257		/* if we have va_uuuid use it, otherwise use uid */
2258		if (!VATTR_IS_ACTIVE(vap, va_uuuid)) {
2259			error = kauth_cred_uid2guid(vap->va_uid, &vap->va_uuuid);
2260			nfsmout_if(error);
2261		}
2262		len = slen;
2263		error = nfs4_guid2id(&vap->va_uuuid, s, &len, 0);
2264		if (error == ENOSPC) {
2265			if (s != sbuf) {
2266				FREE(s, M_TEMP);
2267				s = sbuf;
2268			}
2269			len += 8;
2270			MALLOC(s, char*, len, M_TEMP, M_WAITOK);
2271			if (s) {
2272				slen = len;
2273				error = nfs4_guid2id(&vap->va_uuuid, s, &len, 0);
2274			} else {
2275				error = ENOMEM;
2276			}
2277		}
2278		nfsm_chain_add_name(error, nmc, s, len, nmp);
2279		attrbytes += NFSX_UNSIGNED + nfsm_rndup(len);
2280	}
2281	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER_GROUP)) {
2282		nfsmout_if(error);
2283		/* if we have va_guuid use it, otherwise use gid */
2284		if (!VATTR_IS_ACTIVE(vap, va_guuid)) {
2285			error = kauth_cred_gid2guid(vap->va_gid, &vap->va_guuid);
2286			nfsmout_if(error);
2287		}
2288		len = slen;
2289		error = nfs4_guid2id(&vap->va_guuid, s, &len, 1);
2290		if (error == ENOSPC) {
2291			if (s != sbuf) {
2292				FREE(s, M_TEMP);
2293				s = sbuf;
2294			}
2295			len += 8;
2296			MALLOC(s, char*, len, M_TEMP, M_WAITOK);
2297			if (s) {
2298				slen = len;
2299				error = nfs4_guid2id(&vap->va_guuid, s, &len, 1);
2300			} else {
2301				error = ENOMEM;
2302			}
2303		}
2304		nfsm_chain_add_name(error, nmc, s, len, nmp);
2305		attrbytes += NFSX_UNSIGNED + nfsm_rndup(len);
2306	}
2307	// NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
2308	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS_SET)) {
2309		if (vap->va_vaflags & VA_UTIMES_NULL) {
2310			nfsm_chain_add_32(error, nmc, NFS4_TIME_SET_TO_SERVER);
2311			attrbytes += NFSX_UNSIGNED;
2312		} else {
2313			nfsm_chain_add_32(error, nmc, NFS4_TIME_SET_TO_CLIENT);
2314			nfsm_chain_add_64(error, nmc, vap->va_access_time.tv_sec);
2315			nfsm_chain_add_32(error, nmc, vap->va_access_time.tv_nsec);
2316			attrbytes += 4*NFSX_UNSIGNED;
2317		}
2318	}
2319	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_BACKUP)) {
2320		nfsm_chain_add_64(error, nmc, vap->va_backup_time.tv_sec);
2321		nfsm_chain_add_32(error, nmc, vap->va_backup_time.tv_nsec);
2322		attrbytes += 3*NFSX_UNSIGNED;
2323	}
2324	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_CREATE)) {
2325		nfsm_chain_add_64(error, nmc, vap->va_create_time.tv_sec);
2326		nfsm_chain_add_32(error, nmc, vap->va_create_time.tv_nsec);
2327		attrbytes += 3*NFSX_UNSIGNED;
2328	}
2329	if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY_SET)) {
2330		if (vap->va_vaflags & VA_UTIMES_NULL) {
2331			nfsm_chain_add_32(error, nmc, NFS4_TIME_SET_TO_SERVER);
2332			attrbytes += NFSX_UNSIGNED;
2333		} else {
2334			nfsm_chain_add_32(error, nmc, NFS4_TIME_SET_TO_CLIENT);
2335			nfsm_chain_add_64(error, nmc, vap->va_modify_time.tv_sec);
2336			nfsm_chain_add_32(error, nmc, vap->va_modify_time.tv_nsec);
2337			attrbytes += 4*NFSX_UNSIGNED;
2338		}
2339	}
2340	nfsmout_if(error);
2341	/* Now, set the attribute data length */
2342	*pattrbytes = txdr_unsigned(attrbytes);
2343nfsmout:
2344	if (s && (s != sbuf))
2345		FREE(s, M_TEMP);
2346	return (error);
2347}
2348
2349/*
2350 * Got the given error and need to start recovery (if not already started).
2351 * Note: nmp must be locked!
2352 */
2353void
2354nfs_need_recover(struct nfsmount *nmp, int error)
2355{
2356	int wake = !(nmp->nm_state & NFSSTA_RECOVER);
2357
2358	nmp->nm_state |= NFSSTA_RECOVER;
2359	if ((error == NFSERR_ADMIN_REVOKED) ||
2360	    (error == NFSERR_EXPIRED) ||
2361	    (error == NFSERR_STALE_CLIENTID))
2362		nmp->nm_state |= NFSSTA_RECOVER_EXPIRED;
2363	if (wake)
2364		nfs_mount_sock_thread_wake(nmp);
2365}
2366
2367/*
2368 * After recovery due to state expiry, check each node and
2369 * drop any lingering delegation we thought we had.
2370 *
2371 * If a node has an open that is not lost and is not marked
2372 * for reopen, then we hold onto any delegation because it is
2373 * likely newly-granted.
2374 */
2375static void
2376nfs4_expired_check_delegation(nfsnode_t np, vfs_context_t ctx)
2377{
2378	struct nfsmount *nmp = NFSTONMP(np);
2379	struct nfs_open_file *nofp;
2380	int drop = 1;
2381
2382	if ((np->n_flag & NREVOKE) || !(np->n_openflags & N_DELEG_MASK))
2383		return;
2384
2385	lck_mtx_lock(&np->n_openlock);
2386
2387	TAILQ_FOREACH(nofp, &np->n_opens, nof_link) {
2388		if (!nofp->nof_opencnt)
2389			continue;
2390		if (nofp->nof_flags & NFS_OPEN_FILE_LOST)
2391			continue;
2392		if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)
2393			continue;
2394		/* we have an open that is not lost and not marked for reopen */
2395		// XXX print out what's keeping this node from dropping the delegation.
2396		NP(nofp->nof_np, "nfs4_expired_check_delegation: !drop: opencnt %d flags 0x%x access %d %d mmap %d %d",
2397			nofp->nof_opencnt, nofp->nof_flags,
2398			nofp->nof_access, nofp->nof_deny,
2399			nofp->nof_mmap_access, nofp->nof_mmap_deny);
2400		drop = 0;
2401		break;
2402	}
2403
2404	if (drop) {
2405		/* need to drop a delegation */
2406		if (np->n_dreturn.tqe_next != NFSNOLIST) {
2407			/* remove this node from the delegation return list */
2408			lck_mtx_lock(&nmp->nm_lock);
2409			if (np->n_dreturn.tqe_next != NFSNOLIST) {
2410				TAILQ_REMOVE(&nmp->nm_dreturnq, np, n_dreturn);
2411				np->n_dreturn.tqe_next = NFSNOLIST;
2412			}
2413			lck_mtx_unlock(&nmp->nm_lock);
2414		}
2415		if (np->n_openflags & N_DELEG_MASK) {
2416			np->n_openflags &= ~N_DELEG_MASK;
2417			lck_mtx_lock(&nmp->nm_lock);
2418			if (np->n_dlink.tqe_next != NFSNOLIST) {
2419				TAILQ_REMOVE(&nmp->nm_delegations, np, n_dlink);
2420				np->n_dlink.tqe_next = NFSNOLIST;
2421			}
2422			lck_mtx_unlock(&nmp->nm_lock);
2423			nfs4_delegreturn_rpc(nmp, np->n_fhp, np->n_fhsize, &np->n_dstateid,
2424				0, vfs_context_thread(ctx), vfs_context_ucred(ctx));
2425		}
2426	}
2427
2428	lck_mtx_unlock(&np->n_openlock);
2429}
2430
2431/*
2432 * Recover state for an NFS mount.
2433 *
2434 * Iterates over all open files, reclaiming opens and lock state.
2435 */
2436void
2437nfs_recover(struct nfsmount *nmp)
2438{
2439	struct timespec ts = { 1, 0 };
2440	int error, lost, reopen;
2441	struct nfs_open_owner *noop;
2442	struct nfs_open_file *nofp;
2443	struct nfs_file_lock *nflp, *nextnflp;
2444	struct nfs_lock_owner *nlop;
2445	thread_t thd = current_thread();
2446	nfsnode_t np, nextnp;
2447	struct timeval now;
2448
2449restart:
2450	error = 0;
2451	lck_mtx_lock(&nmp->nm_lock);
2452	/*
2453	 * First, wait for the state inuse count to go to zero so
2454	 * we know there are no state operations in progress.
2455	 */
2456	do {
2457		if ((error = nfs_sigintr(nmp, NULL, NULL, 1)))
2458			break;
2459		if (!(nmp->nm_sockflags & NMSOCK_READY))
2460			error = EPIPE;
2461		if (nmp->nm_state & NFSSTA_FORCE)
2462			error = ENXIO;
2463		if (nmp->nm_sockflags & NMSOCK_UNMOUNT)
2464			error = ENXIO;
2465		if (error)
2466			break;
2467		if (nmp->nm_stateinuse)
2468			msleep(&nmp->nm_stateinuse, &nmp->nm_lock, (PZERO-1), "nfsrecoverstartwait", &ts);
2469	} while (nmp->nm_stateinuse);
2470	if (error) {
2471		if (error == EPIPE)
2472			printf("nfs recovery reconnecting for %s, 0x%x\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid);
2473		else
2474			printf("nfs recovery aborted for %s, 0x%x\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid);
2475		lck_mtx_unlock(&nmp->nm_lock);
2476		return;
2477	}
2478
2479	microuptime(&now);
2480	if (now.tv_sec == nmp->nm_recover_start) {
2481		printf("nfs recovery throttled for %s, 0x%x\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid);
2482		lck_mtx_unlock(&nmp->nm_lock);
2483		tsleep(nfs_recover, (PZERO-1), "nfsrecoverrestart", hz);
2484		goto restart;
2485	}
2486	nmp->nm_recover_start = now.tv_sec;
2487	if (++nmp->nm_stategenid == 0)
2488		++nmp->nm_stategenid;
2489	printf("nfs recovery started for %s, 0x%x\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid);
2490	lck_mtx_unlock(&nmp->nm_lock);
2491
2492	/* for each open owner... */
2493	TAILQ_FOREACH(noop, &nmp->nm_open_owners, noo_link) {
2494		/* for each of its opens... */
2495		TAILQ_FOREACH(nofp, &noop->noo_opens, nof_oolink) {
2496			if (!nofp->nof_access || (nofp->nof_flags & NFS_OPEN_FILE_LOST) || (nofp->nof_np->n_flag & NREVOKE))
2497				continue;
2498			lost = reopen = 0;
2499			/* for NFSv2/v3, just skip straight to lock reclaim */
2500			if (nmp->nm_vers < NFS_VER4)
2501				goto reclaim_locks;
2502			if (nofp->nof_rw_drw)
2503				error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_BOTH);
2504			if (!error && nofp->nof_w_drw)
2505				error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_BOTH);
2506			if (!error && nofp->nof_r_drw)
2507				error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_BOTH);
2508			if (!error && nofp->nof_rw_dw)
2509				error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_WRITE);
2510			if (!error && nofp->nof_w_dw)
2511				error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_WRITE);
2512			if (!error && nofp->nof_r_dw)
2513				error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_WRITE);
2514			/*
2515			 * deny-none opens with no locks can just be reopened (later) if reclaim fails.
2516			 */
2517			if (!error && nofp->nof_rw) {
2518				error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_NONE);
2519				if ((error == NFSERR_ADMIN_REVOKED) || (error == NFSERR_EXPIRED) || (error == NFSERR_NO_GRACE)) {
2520					reopen = error;
2521					error = 0;
2522				}
2523			}
2524			if (!error && !reopen && nofp->nof_w) {
2525				error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_NONE);
2526				if ((error == NFSERR_ADMIN_REVOKED) || (error == NFSERR_EXPIRED) || (error == NFSERR_NO_GRACE)) {
2527					reopen = error;
2528					error = 0;
2529				}
2530			}
2531			if (!error && !reopen && nofp->nof_r) {
2532				error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE);
2533				if ((error == NFSERR_ADMIN_REVOKED) || (error == NFSERR_EXPIRED) || (error == NFSERR_NO_GRACE)) {
2534					reopen = error;
2535					error = 0;
2536				}
2537			}
2538
2539			/*
2540			 * If we hold delegated state but we don't have any non-delegated opens,
2541			 * then we should attempt to claim that state now (but don't return the
2542			 * delegation unless asked to).
2543			 */
2544			if ((nofp->nof_d_rw_drw || nofp->nof_d_w_drw || nofp->nof_d_r_drw ||
2545				    nofp->nof_d_rw_dw || nofp->nof_d_w_dw || nofp->nof_d_r_dw ||
2546				    nofp->nof_d_rw || nofp->nof_d_w || nofp->nof_d_r) &&
2547				    (!nofp->nof_rw_drw && !nofp->nof_w_drw && !nofp->nof_r_drw &&
2548				     !nofp->nof_rw_dw && !nofp->nof_w_dw && !nofp->nof_r_dw &&
2549				     !nofp->nof_rw && !nofp->nof_w && !nofp->nof_r)) {
2550				if (!error && !nfs_open_state_set_busy(nofp->nof_np, NULL)) {
2551					error = nfs4_claim_delegated_state_for_node(nofp->nof_np, R_RECOVER);
2552					if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN))
2553						reopen = EAGAIN;
2554					nfs_open_state_clear_busy(nofp->nof_np);
2555					/* if claim didn't go well, we may need to return delegation now */
2556					if (nofp->nof_np->n_openflags & N_DELEG_RETURN) {
2557						nfs4_delegation_return(nofp->nof_np, R_RECOVER, thd, noop->noo_cred);
2558						if (!(nmp->nm_sockflags & NMSOCK_READY))
2559							error = ETIMEDOUT;  /* looks like we need a reconnect */
2560					}
2561				}
2562			}
2563
2564			/*
2565			 * Handle any issue claiming open state.
2566			 * Potential reopens need to first confirm that there are no locks.
2567			 */
2568			if (error || reopen) {
2569				/* restart recovery? */
2570				if ((error == ETIMEDOUT) || nfs_mount_state_error_should_restart(error)) {
2571					if (error == ETIMEDOUT)
2572						nfs_need_reconnect(nmp);
2573					tsleep(nfs_recover, (PZERO-1), "nfsrecoverrestart", hz);
2574					printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2575						vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid, error);
2576					goto restart;
2577				}
2578				if (reopen && (nfs_check_for_locks(noop, nofp) == 0)) {
2579					/* just reopen the file on next access */
2580					NP(nofp->nof_np, "nfs_recover: %d, need reopen for %d %p 0x%x", reopen,
2581						kauth_cred_getuid(noop->noo_cred), nofp->nof_np, nofp->nof_np->n_flag);
2582					lck_mtx_lock(&nofp->nof_lock);
2583					nofp->nof_flags |= NFS_OPEN_FILE_REOPEN;
2584					lck_mtx_unlock(&nofp->nof_lock);
2585				} else {
2586					/* open file state lost */
2587					if (reopen)
2588						NP(nofp->nof_np, "nfs_recover: %d, can't reopen because of locks %d %p", reopen,
2589							kauth_cred_getuid(noop->noo_cred), nofp->nof_np);
2590					lost = 1;
2591					error = 0;
2592					reopen = 0;
2593				}
2594			} else {
2595				/* no error, so make sure the reopen flag isn't set */
2596				lck_mtx_lock(&nofp->nof_lock);
2597				nofp->nof_flags &= ~NFS_OPEN_FILE_REOPEN;
2598				lck_mtx_unlock(&nofp->nof_lock);
2599			}
2600
2601			/*
2602			 * Scan this node's lock owner list for entries with this open owner,
2603			 * then walk the lock owner's held lock list recovering each lock.
2604			 */
2605reclaim_locks:
2606			TAILQ_FOREACH(nlop, &nofp->nof_np->n_lock_owners, nlo_link) {
2607				if (lost || reopen)
2608					break;
2609				if (nlop->nlo_open_owner != noop)
2610					continue;
2611				TAILQ_FOREACH_SAFE(nflp, &nlop->nlo_locks, nfl_lolink, nextnflp) {
2612					/* skip dead & blocked lock requests (shouldn't be any in the held lock list) */
2613					if (nflp->nfl_flags & (NFS_FILE_LOCK_DEAD|NFS_FILE_LOCK_BLOCKED))
2614						continue;
2615					/* skip delegated locks */
2616					if (nflp->nfl_flags & NFS_FILE_LOCK_DELEGATED)
2617						continue;
2618					error = nmp->nm_funcs->nf_setlock_rpc(nofp->nof_np, nofp, nflp, 1, R_RECOVER, thd, noop->noo_cred);
2619					if (error)
2620						NP(nofp->nof_np, "nfs: lock reclaim (0x%llx, 0x%llx) %s %d",
2621							nflp->nfl_start, nflp->nfl_end,
2622							error ? "failed" : "succeeded", error);
2623					if (!error)
2624						continue;
2625					/* restart recovery? */
2626					if ((error == ETIMEDOUT) || nfs_mount_state_error_should_restart(error)) {
2627						if (error == ETIMEDOUT)
2628							nfs_need_reconnect(nmp);
2629						tsleep(nfs_recover, (PZERO-1), "nfsrecoverrestart", hz);
2630						printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2631							vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid, error);
2632						goto restart;
2633					}
2634					/* lock state lost - attempt to close file */
2635					lost = 1;
2636					error = 0;
2637					break;
2638				}
2639			}
2640
2641			/*
2642			 * If we've determined that we need to reopen the file then we probably
2643			 * didn't receive any delegation we think we hold.  We should attempt to
2644			 * return that delegation (and claim any delegated state).
2645			 *
2646			 * If we hold a delegation that is marked for return, then we should
2647			 * return it now.
2648			 */
2649			if ((nofp->nof_np->n_openflags & N_DELEG_RETURN) ||
2650			    (reopen && (nofp->nof_np->n_openflags & N_DELEG_MASK))) {
2651				nfs4_delegation_return(nofp->nof_np, R_RECOVER, thd, noop->noo_cred);
2652				if (!(nmp->nm_sockflags & NMSOCK_READY)) {
2653					/* looks like we need a reconnect */
2654					tsleep(nfs_recover, (PZERO-1), "nfsrecoverrestart", hz);
2655					printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2656						vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid, error);
2657					goto restart;
2658				}
2659			}
2660
2661			if (lost) {
2662				/* revoke open file state */
2663				NP(nofp->nof_np, "nfs_recover: state lost for %d %p 0x%x",
2664					kauth_cred_getuid(noop->noo_cred), nofp->nof_np, nofp->nof_np->n_flag);
2665				nfs_revoke_open_state_for_node(nofp->nof_np);
2666			}
2667		}
2668	}
2669
2670	if (!error) {
2671		/* If state expired, make sure we're not holding onto any stale delegations */
2672		lck_mtx_lock(&nmp->nm_lock);
2673		if ((nmp->nm_vers >= NFS_VER4) && (nmp->nm_state & NFSSTA_RECOVER_EXPIRED)) {
2674recheckdeleg:
2675			TAILQ_FOREACH_SAFE(np, &nmp->nm_delegations, n_dlink, nextnp) {
2676				lck_mtx_unlock(&nmp->nm_lock);
2677				nfs4_expired_check_delegation(np, vfs_context_kernel());
2678				lck_mtx_lock(&nmp->nm_lock);
2679				if (nextnp == NFSNOLIST)
2680					goto recheckdeleg;
2681			}
2682		}
2683		nmp->nm_state &= ~(NFSSTA_RECOVER|NFSSTA_RECOVER_EXPIRED);
2684		wakeup(&nmp->nm_state);
2685		printf("nfs recovery completed for %s, 0x%x\n",
2686			vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid);
2687		lck_mtx_unlock(&nmp->nm_lock);
2688	} else {
2689		printf("nfs recovery failed for %s, 0x%x, error %d\n",
2690			vfs_statfs(nmp->nm_mountp)->f_mntfromname, nmp->nm_stategenid, error);
2691	}
2692}
2693