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