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