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