2 * Copyright (c) 2006-2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <nfs/nfs_conf.h>
33 * miscellaneous support functions for NFSv4
35 #include <sys/param.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>
45 #include <sys/malloc.h>
46 #include <sys/syscall.h>
47 #include <sys/ubc_internal.h>
48 #include <sys/fcntl.h>
49 #include <sys/quota.h>
50 #include <sys/domain.h>
51 #include <libkern/OSAtomic.h>
52 #include <kern/thread_call.h>
55 #include <sys/vmparam.h>
58 #include <kern/clock.h>
60 #include <nfs/rpcv2.h>
61 #include <nfs/nfsproto.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>
70 #include <miscfs/specfs/specdev.h>
72 #include <netinet/in.h>
73 #include <net/kpi_interface.h>
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.
83 * We also want some reasonable maximum, as 32 bits worth of string length
84 * is liable to cause problems. At the very least this limit must guarantee
85 * that any express that contains the 32 bit length from off the wire used in
86 * allocations does not overflow.
88 #define NFS_MAX_WHO MAXPATHLEN
91 * Create the unique client ID to use for this mount.
93 * Format: unique ID + en0_address + server_address + mntfromname + mntonname
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.
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.
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.
105 * In an attempt to differentiate mounts we include the mntfromname and mntonname
106 * strings to the client ID (as long as they fit). We also make sure that the
107 * value does not conflict with any existing values in use (changing the unique ID).
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.
114 nfs4_init_clientid(struct nfsmount
*nmp
)
116 struct nfs_client_id
*ncip
, *ncip2
;
117 struct sockaddr
*saddr
;
120 struct vfsstatfs
*vsfs
;
122 static uint8_t en0addr
[6];
123 static uint8_t en0addr_set
= 0;
125 lck_mtx_lock(&nfs_global_mutex
);
127 ifnet_t interface
= NULL
;
128 error
= ifnet_find_by_name("en0", &interface
);
130 error
= ifnet_lladdr_copy_bytes(interface
, en0addr
, sizeof(en0addr
));
133 printf("nfs4_init_clientid: error getting en0 address, %d\n", error
);
139 ifnet_release(interface
);
142 lck_mtx_unlock(&nfs_global_mutex
);
144 MALLOC(ncip
, struct nfs_client_id
*, sizeof(struct nfs_client_id
), M_TEMP
, M_WAITOK
);
149 vsfs
= vfs_statfs(nmp
->nm_mountp
);
150 saddr
= nmp
->nm_saddr
;
151 ncip
->nci_idlen
= sizeof(uint32_t) + sizeof(en0addr
) + saddr
->sa_len
+
152 strlen(vsfs
->f_mntfromname
) + 1 + strlen(vsfs
->f_mntonname
) + 1;
153 if (ncip
->nci_idlen
> NFS4_OPAQUE_LIMIT
) {
154 ncip
->nci_idlen
= NFS4_OPAQUE_LIMIT
;
156 MALLOC(ncip
->nci_id
, char *, ncip
->nci_idlen
, M_TEMP
, M_WAITOK
);
162 *(uint32_t*)ncip
->nci_id
= 0;
163 len
= sizeof(uint32_t);
164 len2
= lmin(sizeof(en0addr
), ncip
->nci_idlen
- len
);
165 bcopy(en0addr
, &ncip
->nci_id
[len
], len2
);
166 len
+= sizeof(en0addr
);
167 len2
= lmin(saddr
->sa_len
, ncip
->nci_idlen
- len
);
168 bcopy(saddr
, &ncip
->nci_id
[len
], len2
);
170 if (len
< ncip
->nci_idlen
) {
171 len2
= strlcpy(&ncip
->nci_id
[len
], vsfs
->f_mntfromname
, ncip
->nci_idlen
- len
);
172 if (len2
< (ncip
->nci_idlen
- len
)) {
175 len
= ncip
->nci_idlen
;
178 if (len
< ncip
->nci_idlen
) {
179 len2
= strlcpy(&ncip
->nci_id
[len
], vsfs
->f_mntonname
, ncip
->nci_idlen
- len
);
180 if (len2
< (ncip
->nci_idlen
- len
)) {
183 len
= ncip
->nci_idlen
;
187 /* make sure the ID is unique, and add it to the sorted list */
188 lck_mtx_lock(&nfs_global_mutex
);
189 TAILQ_FOREACH(ncip2
, &nfsclientids
, nci_link
) {
190 if (ncip
->nci_idlen
> ncip2
->nci_idlen
) {
193 if (ncip
->nci_idlen
< ncip2
->nci_idlen
) {
196 cmp
= bcmp(ncip
->nci_id
+ sizeof(uint32_t),
197 ncip2
->nci_id
+ sizeof(uint32_t),
198 ncip
->nci_idlen
- sizeof(uint32_t));
205 if (*(uint32_t*)ncip
->nci_id
> *(uint32_t*)ncip2
->nci_id
) {
208 if (*(uint32_t*)ncip
->nci_id
< *(uint32_t*)ncip2
->nci_id
) {
211 *(uint32_t*)ncip
->nci_id
+= 1;
213 if (*(uint32_t*)ncip
->nci_id
) {
214 printf("nfs client ID collision (%d) for %s on %s\n", *(uint32_t*)ncip
->nci_id
,
215 vsfs
->f_mntfromname
, vsfs
->f_mntonname
);
218 TAILQ_INSERT_BEFORE(ncip2
, ncip
, nci_link
);
220 TAILQ_INSERT_TAIL(&nfsclientids
, ncip
, nci_link
);
222 nmp
->nm_longid
= ncip
;
223 lck_mtx_unlock(&nfs_global_mutex
);
232 nfs4_setclientid(struct nfsmount
*nmp
)
234 uint64_t verifier
, xid
;
235 int error
= 0, status
, numops
;
236 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
239 struct nfsm_chain nmreq
, nmrep
;
240 struct sockaddr_storage ss
;
241 void *sinaddr
= NULL
;
242 char raddr
[MAX_IPv6_STR_LEN
];
243 char uaddr
[MAX_IPv6_STR_LEN
+ 16];
247 thd
= current_thread();
248 cred
= IS_VALID_CRED(nmp
->nm_mcred
) ? nmp
->nm_mcred
: vfs_context_ucred(vfs_context_kernel());
249 kauth_cred_ref(cred
);
251 nfsm_chain_null(&nmreq
);
252 nfsm_chain_null(&nmrep
);
254 if (!nmp
->nm_longid
) {
255 error
= nfs4_init_clientid(nmp
);
260 nfsm_chain_build_alloc_init(error
, &nmreq
, 14 * NFSX_UNSIGNED
+ nmp
->nm_longid
->nci_idlen
);
261 nfsm_chain_add_compound_header(error
, &nmreq
, "setclid", nmp
->nm_minor_vers
, numops
);
263 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SETCLIENTID
);
264 /* nfs_client_id4 client; */
265 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_mounttime
);
266 nfsm_chain_add_32(error
, &nmreq
, nmp
->nm_longid
->nci_idlen
);
267 nfsm_chain_add_opaque(error
, &nmreq
, nmp
->nm_longid
->nci_id
, nmp
->nm_longid
->nci_idlen
);
269 /* cb_client4 callback; */
270 if (!NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
&& nfs4_cb_port
&&
271 !sock_getsockname(nmp
->nm_nso
->nso_so
, (struct sockaddr
*)&ss
, sizeof(ss
))) {
272 if (ss
.ss_family
== AF_INET
) {
273 sinaddr
= &((struct sockaddr_in
*)&ss
)->sin_addr
;
275 } else if (ss
.ss_family
== AF_INET6
) {
276 sinaddr
= &((struct sockaddr_in6
*)&ss
)->sin6_addr
;
277 port
= nfs4_cb_port6
;
282 if (sinaddr
&& port
&& (inet_ntop(ss
.ss_family
, sinaddr
, raddr
, sizeof(raddr
)) == raddr
)) {
283 /* assemble r_addr = universal address (nmp->nm_nso->nso_so source IP addr + port) */
284 ualen
= snprintf(uaddr
, sizeof(uaddr
), "%s.%d.%d", raddr
,
285 ((port
>> 8) & 0xff),
287 /* make sure it fit, give up if it didn't */
288 if (ualen
>= (int)sizeof(uaddr
)) {
294 /* add callback info */
295 nfsm_chain_add_32(error
, &nmreq
, NFS4_CALLBACK_PROG
); /* callback program */
296 if (ss
.ss_family
== AF_INET
) {
297 nfsm_chain_add_string(error
, &nmreq
, "tcp", 3); /* callback r_netid */
298 } else if (ss
.ss_family
== AF_INET6
) {
299 nfsm_chain_add_string(error
, &nmreq
, "tcp6", 4); /* callback r_netid */
301 nfsm_chain_add_string(error
, &nmreq
, uaddr
, ualen
); /* callback r_addr */
302 nfsm_chain_add_32(error
, &nmreq
, nmp
->nm_cbid
); /* callback_ident */
304 /* don't provide valid callback info */
305 nfsm_chain_add_32(error
, &nmreq
, 0); /* callback program */
306 nfsm_chain_add_string(error
, &nmreq
, "", 0); /* callback r_netid */
307 nfsm_chain_add_string(error
, &nmreq
, "", 0); /* callback r_addr */
308 nfsm_chain_add_32(error
, &nmreq
, 0); /* callback_ident */
310 nfsm_chain_build_done(error
, &nmreq
);
311 nfsm_assert(error
, (numops
== 0), EPROTO
);
313 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, NULL
, R_SETUP
, &nmrep
, &xid
, &status
);
314 nfsm_chain_skip_tag(error
, &nmrep
);
315 nfsm_chain_get_32(error
, &nmrep
, numops
);
316 if (!error
&& (numops
!= 1) && status
) {
319 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SETCLIENTID
);
320 if (error
== NFSERR_CLID_INUSE
) {
321 printf("nfs4_setclientid: client ID in use?\n");
324 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_clientid
);
325 nfsm_chain_get_64(error
, &nmrep
, verifier
);
326 nfsm_chain_cleanup(&nmreq
);
327 nfsm_chain_cleanup(&nmrep
);
329 // SETCLIENTID_CONFIRM
331 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
332 nfsm_chain_add_compound_header(error
, &nmreq
, "setclid_conf", nmp
->nm_minor_vers
, numops
);
334 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SETCLIENTID_CONFIRM
);
335 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_clientid
);
336 nfsm_chain_add_64(error
, &nmreq
, verifier
);
337 nfsm_chain_build_done(error
, &nmreq
);
338 nfsm_assert(error
, (numops
== 0), EPROTO
);
340 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, NULL
, R_SETUP
, &nmrep
, &xid
, &status
);
341 nfsm_chain_skip_tag(error
, &nmrep
);
342 nfsm_chain_get_32(error
, &nmrep
, numops
);
343 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SETCLIENTID_CONFIRM
);
345 printf("nfs4_setclientid: confirm error %d\n", error
);
347 lck_mtx_lock(&nmp
->nm_lock
);
349 nmp
->nm_state
|= NFSSTA_CLIENTID
;
351 lck_mtx_unlock(&nmp
->nm_lock
);
353 nfsmout_if(error
|| !nmp
->nm_dnp
);
355 /* take the opportunity to refresh fs attributes too */
356 // PUTFH, GETATTR(FS)
358 nfsm_chain_build_alloc_init(error
, &nmreq
, 23 * NFSX_UNSIGNED
);
359 nfsm_chain_add_compound_header(error
, &nmreq
, "setclid_attr", nmp
->nm_minor_vers
, numops
);
361 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
362 nfsm_chain_add_fh(error
, &nmreq
, nmp
->nm_vers
, nmp
->nm_dnp
->n_fhp
, nmp
->nm_dnp
->n_fhsize
);
364 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
365 NFS_CLEAR_ATTRIBUTES(bitmap
);
366 NFS4_PER_FS_ATTRIBUTES(bitmap
);
367 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
368 nfsm_chain_build_done(error
, &nmreq
);
369 nfsm_assert(error
, (numops
== 0), EPROTO
);
371 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, NULL
, R_SETUP
, &nmrep
, &xid
, &status
);
372 nfsm_chain_skip_tag(error
, &nmrep
);
373 nfsm_chain_get_32(error
, &nmrep
, numops
);
374 lck_mtx_lock(&nmp
->nm_lock
);
375 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
376 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
378 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, NULL
, NULL
, NULL
, NULL
);
380 lck_mtx_unlock(&nmp
->nm_lock
);
381 if (error
) { /* ignore any error from the getattr */
385 nfsm_chain_cleanup(&nmreq
);
386 nfsm_chain_cleanup(&nmrep
);
387 kauth_cred_unref(&cred
);
389 printf("nfs4_setclientid failed, %d\n", error
);
395 * renew/check lease state on server
398 nfs4_renew(struct nfsmount
*nmp
, int rpcflag
)
400 int error
= 0, status
, numops
;
402 struct nfsm_chain nmreq
, nmrep
;
405 cred
= IS_VALID_CRED(nmp
->nm_mcred
) ? nmp
->nm_mcred
: vfs_context_ucred(vfs_context_kernel());
406 kauth_cred_ref(cred
);
408 nfsm_chain_null(&nmreq
);
409 nfsm_chain_null(&nmrep
);
413 nfsm_chain_build_alloc_init(error
, &nmreq
, 8 * NFSX_UNSIGNED
);
414 nfsm_chain_add_compound_header(error
, &nmreq
, "renew", nmp
->nm_minor_vers
, numops
);
416 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_RENEW
);
417 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_clientid
);
418 nfsm_chain_build_done(error
, &nmreq
);
419 nfsm_assert(error
, (numops
== 0), EPROTO
);
421 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
422 current_thread(), cred
, NULL
, rpcflag
, &nmrep
, &xid
, &status
);
423 nfsm_chain_skip_tag(error
, &nmrep
);
424 nfsm_chain_get_32(error
, &nmrep
, numops
);
425 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_RENEW
);
427 nfsm_chain_cleanup(&nmreq
);
428 nfsm_chain_cleanup(&nmrep
);
429 kauth_cred_unref(&cred
);
435 * periodic timer to renew lease state on server
438 nfs4_renew_timer(void *param0
, __unused
void *param1
)
440 struct nfsmount
*nmp
= param0
;
442 int error
= 0, interval
;
444 lck_mtx_lock(&nmp
->nm_lock
);
445 clientid
= nmp
->nm_clientid
;
446 if ((nmp
->nm_state
& NFSSTA_RECOVER
) || !(nmp
->nm_sockflags
& NMSOCK_READY
)) {
447 lck_mtx_unlock(&nmp
->nm_lock
);
450 lck_mtx_unlock(&nmp
->nm_lock
);
452 error
= nfs4_renew(nmp
, R_RECOVER
);
454 if (error
== ETIMEDOUT
) {
455 nfs_need_reconnect(nmp
);
457 printf("nfs4_renew_timer: error %d\n", error
);
459 lck_mtx_lock(&nmp
->nm_lock
);
460 if (error
&& (error
!= ETIMEDOUT
) &&
461 (nmp
->nm_clientid
== clientid
) && !(nmp
->nm_state
& NFSSTA_RECOVER
)) {
462 printf("nfs4_renew_timer: error %d, initiating recovery\n", error
);
463 nfs_need_recover(nmp
, error
);
466 interval
= nmp
->nm_fsattr
.nfsa_lease
/ (error
? 4 : 2);
467 if ((interval
< 1) || (nmp
->nm_state
& NFSSTA_RECOVER
)) {
470 lck_mtx_unlock(&nmp
->nm_lock
);
472 lck_mtx_lock(&nmp
->nm_timer_lock
);
473 if (nmp
->nm_renew_timer
) {
474 nfs_interval_timer_start(nmp
->nm_renew_timer
, interval
* 1000);
476 lck_mtx_unlock(&nmp
->nm_timer_lock
);
480 * get the list of supported security flavors
482 * How we get them depends on what args we are given:
486 * YES YES Use the fh and name provided
487 * YES NO 4.1-only just use the fh provided
488 * NO YES Use the node's (or root) fh and the name provided
489 * NO NO Use the node's parent and the node's name (4.1 will just use node's fh)
492 nfs4_secinfo_rpc(struct nfsmount
*nmp
, struct nfsreq_secinfo_args
*siap
, kauth_cred_t cred
, uint32_t *sec
, int *seccountp
)
494 int error
= 0, status
, nfsvers
, numops
, fhsize
;
495 vnode_t dvp
= NULLVP
;
498 const char *vname
= NULL
, *name
;
501 struct nfsm_chain nmreq
, nmrep
;
504 if (nfs_mount_gone(nmp
)) {
507 nfsvers
= nmp
->nm_vers
;
510 nfsm_chain_null(&nmreq
);
511 nfsm_chain_null(&nmrep
);
514 fhsize
= fhp
? siap
->rsia_fhsize
: 0;
515 name
= siap
->rsia_name
;
516 namelen
= name
? siap
->rsia_namelen
: 0;
517 if (name
&& !namelen
) {
518 namelen
= strlen(name
);
521 if (!np
) { /* use PUTROOTFH */
525 fhsize
= np
->n_fhsize
;
534 nfs_node_lock_force(np
);
535 if ((vnode_vtype(NFSTOV(np
)) != VDIR
) && np
->n_sillyrename
) {
537 * The node's been sillyrenamed, so we need to use
538 * the sillyrename directory/name to do the open.
540 struct nfs_sillyrename
*nsp
= np
->n_sillyrename
;
543 if ((error
= vnode_get(dvp
))) {
549 fhsize
= dnp
->n_fhsize
;
550 name
= nsp
->nsr_name
;
551 namelen
= nsp
->nsr_namlen
;
554 * [sigh] We can't trust VFS to get the parent right for named
555 * attribute nodes. (It likes to reparent the nodes after we've
556 * created them.) Luckily we can probably get the right parent
557 * from the n_parent we have stashed away.
559 if ((np
->n_vattr
.nva_flags
& NFS_FFLAG_IS_ATTR
) &&
560 (((dvp
= np
->n_parent
)) && (error
= vnode_get(dvp
)))) {
564 dvp
= vnode_getparent(NFSTOV(np
));
566 vname
= vnode_getname(NFSTOV(np
));
567 if (!dvp
|| !vname
) {
576 fhsize
= dnp
->n_fhsize
;
578 namelen
= strnlen(vname
, MAXPATHLEN
);
583 // PUT(ROOT)FH + SECINFO
585 nfsm_chain_build_alloc_init(error
, &nmreq
,
586 4 * NFSX_UNSIGNED
+ NFSX_FH(nfsvers
) + nfsm_rndup(namelen
));
587 nfsm_chain_add_compound_header(error
, &nmreq
, "secinfo", nmp
->nm_minor_vers
, numops
);
590 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
591 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, fhp
, fhsize
);
593 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
596 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SECINFO
);
597 nfsm_chain_add_name(error
, &nmreq
, name
, namelen
, nmp
);
598 nfsm_chain_build_done(error
, &nmreq
);
599 nfsm_assert(error
, (numops
== 0), EPROTO
);
601 error
= nfs_request2(np
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
602 current_thread(), cred
, NULL
, 0, &nmrep
, &xid
, &status
);
603 nfsm_chain_skip_tag(error
, &nmrep
);
604 nfsm_chain_get_32(error
, &nmrep
, numops
);
605 nfsm_chain_op_check(error
, &nmrep
, fhp
? NFS_OP_PUTFH
: NFS_OP_PUTROOTFH
);
606 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SECINFO
);
608 error
= nfsm_chain_get_secinfo(&nmrep
, sec
, seccountp
);
610 nfsm_chain_cleanup(&nmreq
);
611 nfsm_chain_cleanup(&nmrep
);
613 vnode_putname(vname
);
620 #endif /* CONFIG_NFS4 */
623 * Parse an NFSv4 SECINFO array to an array of pseudo flavors.
624 * (Note: also works for MOUNTv3 security arrays.)
627 nfsm_chain_get_secinfo(struct nfsm_chain
*nmc
, uint32_t *sec
, int *seccountp
)
629 int error
= 0, secmax
, seccount
, srvcount
;
637 seccount
= srvcount
= 0;
641 nfsm_chain_get_32(error
, nmc
, srvcount
);
642 while (!error
&& (srvcount
> 0) && (seccount
< secmax
)) {
643 nfsm_chain_get_32(error
, nmc
, flavor
);
652 #endif /* CONFIG_NFS_GSS */
653 sec
[seccount
++] = flavor
;
657 /* we only recognize KRB5, KRB5I, KRB5P */
658 nfsm_chain_get_32(error
, nmc
, val
); /* OID length */
660 if (val
!= sizeof(krb5_mech_oid
)) {
661 nfsm_chain_adv(error
, nmc
, val
);
662 nfsm_chain_adv(error
, nmc
, 2 * NFSX_UNSIGNED
);
665 nfsm_chain_get_opaque(error
, nmc
, val
, oid
); /* OID bytes */
667 if (bcmp(oid
, krb5_mech_oid
, sizeof(krb5_mech_oid
))) {
668 nfsm_chain_adv(error
, nmc
, 2 * NFSX_UNSIGNED
);
671 nfsm_chain_get_32(error
, nmc
, val
); /* QOP */
672 nfsm_chain_get_32(error
, nmc
, val
); /* SERVICE */
675 case RPCSEC_GSS_SVC_NONE
:
676 sec
[seccount
++] = RPCAUTH_KRB5
;
678 case RPCSEC_GSS_SVC_INTEGRITY
:
679 sec
[seccount
++] = RPCAUTH_KRB5I
;
681 case RPCSEC_GSS_SVC_PRIVACY
:
682 sec
[seccount
++] = RPCAUTH_KRB5P
;
686 #endif /* CONFIG_NFS_GSS */
692 *seccountp
= seccount
;
699 * Fetch the FS_LOCATIONS attribute for the node found at directory/name.
702 nfs4_get_fs_locations(
703 struct nfsmount
*nmp
,
709 struct nfs_fs_locations
*nfslsp
)
711 int error
= 0, numops
, status
;
712 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
714 struct nfsreq_secinfo_args si
;
715 struct nfsm_chain nmreq
, nmrep
;
720 fhsize
= dnp
->n_fhsize
;
726 req
= zalloc(nfs_req_zone
);
727 nfsm_chain_null(&nmreq
);
728 nfsm_chain_null(&nmrep
);
730 NFSREQ_SECINFO_SET(&si
, NULL
, fhp
, fhsize
, name
, 0);
732 nfsm_chain_build_alloc_init(error
, &nmreq
, 18 * NFSX_UNSIGNED
);
733 nfsm_chain_add_compound_header(error
, &nmreq
, "fs_locations", nmp
->nm_minor_vers
, numops
);
735 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
736 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, fhp
, fhsize
);
738 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUP
);
739 nfsm_chain_add_name(error
, &nmreq
, name
, strlen(name
), nmp
);
741 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
742 NFS_CLEAR_ATTRIBUTES(bitmap
);
743 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FS_LOCATIONS
);
744 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
745 nfsm_chain_build_done(error
, &nmreq
);
746 nfsm_assert(error
, (numops
== 0), EPROTO
);
748 error
= nfs_request_async(dnp
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
749 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
751 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
753 nfsm_chain_skip_tag(error
, &nmrep
);
754 nfsm_chain_get_32(error
, &nmrep
, numops
);
755 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
756 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_LOOKUP
);
757 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
759 error
= nfs4_parsefattr(&nmrep
, NULL
, NULL
, NULL
, NULL
, nfslsp
);
761 NFS_ZFREE(nfs_req_zone
, req
);
762 nfsm_chain_cleanup(&nmrep
);
763 nfsm_chain_cleanup(&nmreq
);
768 * Referral trigger nodes may not have many attributes provided by the
769 * server, so put some default values in place.
772 nfs4_default_attrs_for_referral_trigger(
776 struct nfs_vattr
*nvap
,
783 nvap
->nva_flags
= NFS_FFLAG_TRIGGER
| NFS_FFLAG_TRIGGER_REFERRAL
;
784 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TYPE
)) {
785 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TYPE
);
786 nvap
->nva_type
= VDIR
;
788 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FSID
)) {
789 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_FSID
);
790 nvap
->nva_fsid
.major
= 0;
791 nvap
->nva_fsid
.minor
= 0;
793 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_OWNER
) && dnp
) {
794 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_OWNER
);
795 nvap
->nva_uid
= dnp
->n_vattr
.nva_uid
;
796 nvap
->nva_uuuid
= dnp
->n_vattr
.nva_uuuid
;
798 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_OWNER_GROUP
) && dnp
) {
799 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_OWNER_GROUP
);
800 nvap
->nva_gid
= dnp
->n_vattr
.nva_gid
;
801 nvap
->nva_guuid
= dnp
->n_vattr
.nva_guuid
;
803 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_MODE
)) {
804 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_MODE
);
805 nvap
->nva_mode
= 0777;
807 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_SIZE
)) {
808 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_SIZE
);
811 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_SPACE_USED
)) {
812 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_SPACE_USED
);
815 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_NUMLINKS
)) {
816 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_NUMLINKS
);
819 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TIME_ACCESS
)) {
820 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TIME_ACCESS
);
821 nvap
->nva_timesec
[NFSTIME_ACCESS
] = now
.tv_sec
;
822 nvap
->nva_timensec
[NFSTIME_ACCESS
] = now
.tv_nsec
;
824 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TIME_MODIFY
)) {
825 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TIME_MODIFY
);
826 nvap
->nva_timesec
[NFSTIME_MODIFY
] = now
.tv_sec
;
827 nvap
->nva_timensec
[NFSTIME_MODIFY
] = now
.tv_nsec
;
829 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TIME_METADATA
)) {
830 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TIME_METADATA
);
831 nvap
->nva_timesec
[NFSTIME_CHANGE
] = now
.tv_sec
;
832 nvap
->nva_timensec
[NFSTIME_CHANGE
] = now
.tv_nsec
;
834 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FILEID
)) {
835 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_FILEID
);
836 nvap
->nva_fileid
= 42;
838 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FILEHANDLE
) && dnp
&& name
&& fhp
) {
839 /* Build a fake filehandle made up of parent node pointer and name */
840 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_FILEHANDLE
);
841 bcopy(&dnp
, &fhp
->fh_data
[0], sizeof(dnp
));
842 len
= sizeof(fhp
->fh_data
) - sizeof(dnp
);
843 bcopy(name
, &fhp
->fh_data
[0] + sizeof(dnp
), MIN(len
, namelen
));
844 fhp
->fh_len
= sizeof(dnp
) + namelen
;
845 if (fhp
->fh_len
> (int)sizeof(fhp
->fh_data
)) {
846 fhp
->fh_len
= sizeof(fhp
->fh_data
);
852 * Set NFS bitmap according to what's set in vnode_attr (and supported by the server).
855 nfs_vattr_set_bitmap(struct nfsmount
*nmp
, uint32_t *bitmap
, struct vnode_attr
*vap
)
859 NFS_CLEAR_ATTRIBUTES(bitmap
);
860 if (VATTR_IS_ACTIVE(vap
, va_data_size
)) {
861 NFS_BITMAP_SET(bitmap
, NFS_FATTR_SIZE
);
863 if (VATTR_IS_ACTIVE(vap
, va_acl
) && (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
)) {
864 NFS_BITMAP_SET(bitmap
, NFS_FATTR_ACL
);
866 if (VATTR_IS_ACTIVE(vap
, va_flags
)) {
867 NFS_BITMAP_SET(bitmap
, NFS_FATTR_ARCHIVE
);
868 NFS_BITMAP_SET(bitmap
, NFS_FATTR_HIDDEN
);
870 // NFS_BITMAP_SET(bitmap, NFS_FATTR_MIMETYPE)
871 if (VATTR_IS_ACTIVE(vap
, va_mode
) && !NMFLAG(nmp
, ACLONLY
)) {
872 NFS_BITMAP_SET(bitmap
, NFS_FATTR_MODE
);
874 if (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_uuuid
)) {
875 NFS_BITMAP_SET(bitmap
, NFS_FATTR_OWNER
);
877 if (VATTR_IS_ACTIVE(vap
, va_gid
) || VATTR_IS_ACTIVE(vap
, va_guuid
)) {
878 NFS_BITMAP_SET(bitmap
, NFS_FATTR_OWNER_GROUP
);
880 // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
881 if (vap
->va_vaflags
& VA_UTIMES_NULL
) {
882 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
);
883 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
);
885 if (VATTR_IS_ACTIVE(vap
, va_access_time
)) {
886 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
);
888 if (VATTR_IS_ACTIVE(vap
, va_modify_time
)) {
889 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
);
892 if (VATTR_IS_ACTIVE(vap
, va_backup_time
)) {
893 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_BACKUP
);
895 if (VATTR_IS_ACTIVE(vap
, va_create_time
)) {
896 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_CREATE
);
898 /* and limit to what is supported by server */
899 for (i
= 0; i
< NFS_ATTR_BITMAP_LEN
; i
++) {
900 bitmap
[i
] &= nmp
->nm_fsattr
.nfsa_supp_attr
[i
];
905 * Convert between NFSv4 and VFS ACE types
908 nfs4_ace_nfstype_to_vfstype(uint32_t nfsacetype
, int *errorp
)
910 switch (nfsacetype
) {
911 case NFS_ACE_ACCESS_ALLOWED_ACE_TYPE
:
912 return KAUTH_ACE_PERMIT
;
913 case NFS_ACE_ACCESS_DENIED_ACE_TYPE
:
914 return KAUTH_ACE_DENY
;
915 case NFS_ACE_SYSTEM_AUDIT_ACE_TYPE
:
916 return KAUTH_ACE_AUDIT
;
917 case NFS_ACE_SYSTEM_ALARM_ACE_TYPE
:
918 return KAUTH_ACE_ALARM
;
925 nfs4_ace_vfstype_to_nfstype(uint32_t vfstype
, int *errorp
)
928 case KAUTH_ACE_PERMIT
:
929 return NFS_ACE_ACCESS_ALLOWED_ACE_TYPE
;
931 return NFS_ACE_ACCESS_DENIED_ACE_TYPE
;
932 case KAUTH_ACE_AUDIT
:
933 return NFS_ACE_SYSTEM_AUDIT_ACE_TYPE
;
934 case KAUTH_ACE_ALARM
:
935 return NFS_ACE_SYSTEM_ALARM_ACE_TYPE
;
942 * Convert between NFSv4 and VFS ACE flags
945 nfs4_ace_nfsflags_to_vfsflags(uint32_t nfsflags
)
947 uint32_t vfsflags
= 0;
949 if (nfsflags
& NFS_ACE_FILE_INHERIT_ACE
) {
950 vfsflags
|= KAUTH_ACE_FILE_INHERIT
;
952 if (nfsflags
& NFS_ACE_DIRECTORY_INHERIT_ACE
) {
953 vfsflags
|= KAUTH_ACE_DIRECTORY_INHERIT
;
955 if (nfsflags
& NFS_ACE_NO_PROPAGATE_INHERIT_ACE
) {
956 vfsflags
|= KAUTH_ACE_LIMIT_INHERIT
;
958 if (nfsflags
& NFS_ACE_INHERIT_ONLY_ACE
) {
959 vfsflags
|= KAUTH_ACE_ONLY_INHERIT
;
961 if (nfsflags
& NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG
) {
962 vfsflags
|= KAUTH_ACE_SUCCESS
;
964 if (nfsflags
& NFS_ACE_FAILED_ACCESS_ACE_FLAG
) {
965 vfsflags
|= KAUTH_ACE_FAILURE
;
967 if (nfsflags
& NFS_ACE_INHERITED_ACE
) {
968 vfsflags
|= KAUTH_ACE_INHERITED
;
975 nfs4_ace_vfsflags_to_nfsflags(uint32_t vfsflags
)
977 uint32_t nfsflags
= 0;
979 if (vfsflags
& KAUTH_ACE_FILE_INHERIT
) {
980 nfsflags
|= NFS_ACE_FILE_INHERIT_ACE
;
982 if (vfsflags
& KAUTH_ACE_DIRECTORY_INHERIT
) {
983 nfsflags
|= NFS_ACE_DIRECTORY_INHERIT_ACE
;
985 if (vfsflags
& KAUTH_ACE_LIMIT_INHERIT
) {
986 nfsflags
|= NFS_ACE_NO_PROPAGATE_INHERIT_ACE
;
988 if (vfsflags
& KAUTH_ACE_ONLY_INHERIT
) {
989 nfsflags
|= NFS_ACE_INHERIT_ONLY_ACE
;
991 if (vfsflags
& KAUTH_ACE_SUCCESS
) {
992 nfsflags
|= NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG
;
994 if (vfsflags
& KAUTH_ACE_FAILURE
) {
995 nfsflags
|= NFS_ACE_FAILED_ACCESS_ACE_FLAG
;
997 if (vfsflags
& KAUTH_ACE_INHERITED
) {
998 nfsflags
|= NFS_ACE_INHERITED_ACE
;
1005 * Convert between NFSv4 ACE access masks and VFS access rights
1008 nfs4_ace_nfsmask_to_vfsrights(uint32_t nfsmask
)
1010 uint32_t vfsrights
= 0;
1012 if (nfsmask
& NFS_ACE_READ_DATA
) {
1013 vfsrights
|= KAUTH_VNODE_READ_DATA
;
1015 if (nfsmask
& NFS_ACE_LIST_DIRECTORY
) {
1016 vfsrights
|= KAUTH_VNODE_LIST_DIRECTORY
;
1018 if (nfsmask
& NFS_ACE_WRITE_DATA
) {
1019 vfsrights
|= KAUTH_VNODE_WRITE_DATA
;
1021 if (nfsmask
& NFS_ACE_ADD_FILE
) {
1022 vfsrights
|= KAUTH_VNODE_ADD_FILE
;
1024 if (nfsmask
& NFS_ACE_APPEND_DATA
) {
1025 vfsrights
|= KAUTH_VNODE_APPEND_DATA
;
1027 if (nfsmask
& NFS_ACE_ADD_SUBDIRECTORY
) {
1028 vfsrights
|= KAUTH_VNODE_ADD_SUBDIRECTORY
;
1030 if (nfsmask
& NFS_ACE_READ_NAMED_ATTRS
) {
1031 vfsrights
|= KAUTH_VNODE_READ_EXTATTRIBUTES
;
1033 if (nfsmask
& NFS_ACE_WRITE_NAMED_ATTRS
) {
1034 vfsrights
|= KAUTH_VNODE_WRITE_EXTATTRIBUTES
;
1036 if (nfsmask
& NFS_ACE_EXECUTE
) {
1037 vfsrights
|= KAUTH_VNODE_EXECUTE
;
1039 if (nfsmask
& NFS_ACE_DELETE_CHILD
) {
1040 vfsrights
|= KAUTH_VNODE_DELETE_CHILD
;
1042 if (nfsmask
& NFS_ACE_READ_ATTRIBUTES
) {
1043 vfsrights
|= KAUTH_VNODE_READ_ATTRIBUTES
;
1045 if (nfsmask
& NFS_ACE_WRITE_ATTRIBUTES
) {
1046 vfsrights
|= KAUTH_VNODE_WRITE_ATTRIBUTES
;
1048 if (nfsmask
& NFS_ACE_DELETE
) {
1049 vfsrights
|= KAUTH_VNODE_DELETE
;
1051 if (nfsmask
& NFS_ACE_READ_ACL
) {
1052 vfsrights
|= KAUTH_VNODE_READ_SECURITY
;
1054 if (nfsmask
& NFS_ACE_WRITE_ACL
) {
1055 vfsrights
|= KAUTH_VNODE_WRITE_SECURITY
;
1057 if (nfsmask
& NFS_ACE_WRITE_OWNER
) {
1058 vfsrights
|= KAUTH_VNODE_CHANGE_OWNER
;
1060 if (nfsmask
& NFS_ACE_SYNCHRONIZE
) {
1061 vfsrights
|= KAUTH_VNODE_SYNCHRONIZE
;
1063 if ((nfsmask
& NFS_ACE_GENERIC_READ
) == NFS_ACE_GENERIC_READ
) {
1064 vfsrights
|= KAUTH_ACE_GENERIC_READ
;
1066 if ((nfsmask
& NFS_ACE_GENERIC_WRITE
) == NFS_ACE_GENERIC_WRITE
) {
1067 vfsrights
|= KAUTH_ACE_GENERIC_WRITE
;
1069 if ((nfsmask
& NFS_ACE_GENERIC_EXECUTE
) == NFS_ACE_GENERIC_EXECUTE
) {
1070 vfsrights
|= KAUTH_ACE_GENERIC_EXECUTE
;
1077 nfs4_ace_vfsrights_to_nfsmask(uint32_t vfsrights
)
1079 uint32_t nfsmask
= 0;
1081 if (vfsrights
& KAUTH_VNODE_READ_DATA
) {
1082 nfsmask
|= NFS_ACE_READ_DATA
;
1084 if (vfsrights
& KAUTH_VNODE_LIST_DIRECTORY
) {
1085 nfsmask
|= NFS_ACE_LIST_DIRECTORY
;
1087 if (vfsrights
& KAUTH_VNODE_WRITE_DATA
) {
1088 nfsmask
|= NFS_ACE_WRITE_DATA
;
1090 if (vfsrights
& KAUTH_VNODE_ADD_FILE
) {
1091 nfsmask
|= NFS_ACE_ADD_FILE
;
1093 if (vfsrights
& KAUTH_VNODE_APPEND_DATA
) {
1094 nfsmask
|= NFS_ACE_APPEND_DATA
;
1096 if (vfsrights
& KAUTH_VNODE_ADD_SUBDIRECTORY
) {
1097 nfsmask
|= NFS_ACE_ADD_SUBDIRECTORY
;
1099 if (vfsrights
& KAUTH_VNODE_READ_EXTATTRIBUTES
) {
1100 nfsmask
|= NFS_ACE_READ_NAMED_ATTRS
;
1102 if (vfsrights
& KAUTH_VNODE_WRITE_EXTATTRIBUTES
) {
1103 nfsmask
|= NFS_ACE_WRITE_NAMED_ATTRS
;
1105 if (vfsrights
& KAUTH_VNODE_EXECUTE
) {
1106 nfsmask
|= NFS_ACE_EXECUTE
;
1108 if (vfsrights
& KAUTH_VNODE_DELETE_CHILD
) {
1109 nfsmask
|= NFS_ACE_DELETE_CHILD
;
1111 if (vfsrights
& KAUTH_VNODE_READ_ATTRIBUTES
) {
1112 nfsmask
|= NFS_ACE_READ_ATTRIBUTES
;
1114 if (vfsrights
& KAUTH_VNODE_WRITE_ATTRIBUTES
) {
1115 nfsmask
|= NFS_ACE_WRITE_ATTRIBUTES
;
1117 if (vfsrights
& KAUTH_VNODE_DELETE
) {
1118 nfsmask
|= NFS_ACE_DELETE
;
1120 if (vfsrights
& KAUTH_VNODE_READ_SECURITY
) {
1121 nfsmask
|= NFS_ACE_READ_ACL
;
1123 if (vfsrights
& KAUTH_VNODE_WRITE_SECURITY
) {
1124 nfsmask
|= NFS_ACE_WRITE_ACL
;
1126 if (vfsrights
& KAUTH_VNODE_CHANGE_OWNER
) {
1127 nfsmask
|= NFS_ACE_WRITE_OWNER
;
1129 if (vfsrights
& KAUTH_VNODE_SYNCHRONIZE
) {
1130 nfsmask
|= NFS_ACE_SYNCHRONIZE
;
1132 if (vfsrights
& KAUTH_ACE_GENERIC_READ
) {
1133 nfsmask
|= NFS_ACE_GENERIC_READ
;
1135 if (vfsrights
& KAUTH_ACE_GENERIC_WRITE
) {
1136 nfsmask
|= NFS_ACE_GENERIC_WRITE
;
1138 if (vfsrights
& KAUTH_ACE_GENERIC_EXECUTE
) {
1139 nfsmask
|= NFS_ACE_GENERIC_EXECUTE
;
1141 if (vfsrights
& KAUTH_ACE_GENERIC_ALL
) {
1142 nfsmask
|= (KAUTH_ACE_GENERIC_READ
| KAUTH_ACE_GENERIC_WRITE
| NFS_ACE_GENERIC_EXECUTE
);
1150 * mapid a wellknown identity to guid.
1151 * Return 0 on success ENOENT if id does not map and EINVAL if the id is not a well known name.
1154 nfs4_wkid2sid(const char *id
, ntsid_t
*sp
)
1156 size_t len
= strnlen(id
, MAXIDNAMELEN
);
1158 if (len
== MAXIDNAMELEN
|| id
[len
- 1] != '@') {
1162 bzero(sp
, sizeof(ntsid_t
));
1164 sp
->sid_authcount
= 1;
1165 if (!strcmp(id
, "OWNER@")) {
1167 sp
->sid_authority
[5] = 3;
1168 sp
->sid_authorities
[0] = 0;
1169 } else if (!strcmp(id
, "GROUP@")) {
1171 sp
->sid_authority
[5] = 3;
1172 sp
->sid_authorities
[0] = 1;
1173 } else if (!strcmp(id
, "EVERYONE@")) {
1175 sp
->sid_authority
[5] = 1;
1176 sp
->sid_authorities
[0] = 0;
1177 } else if (!strcmp(id
, "INTERACTIVE@")) {
1179 sp
->sid_authority
[5] = 5;
1180 sp
->sid_authorities
[0] = 4;
1181 } else if (!strcmp(id
, "NETWORK@")) {
1183 sp
->sid_authority
[5] = 5;
1184 sp
->sid_authorities
[0] = 2;
1185 } else if (!strcmp(id
, "DIALUP@")) {
1187 sp
->sid_authority
[5] = 5;
1188 sp
->sid_authorities
[0] = 1;
1189 } else if (!strcmp(id
, "BATCH@")) {
1191 sp
->sid_authority
[5] = 5;
1192 sp
->sid_authorities
[0] = 3;
1193 } else if (!strcmp(id
, "ANONYMOUS@")) {
1195 sp
->sid_authority
[5] = 5;
1196 sp
->sid_authorities
[0] = 7;
1197 } else if (!strcmp(id
, "AUTHENTICATED@")) {
1199 sp
->sid_authority
[5] = 5;
1200 sp
->sid_authorities
[0] = 11;
1201 } else if (!strcmp(id
, "SERVICE@")) {
1203 sp
->sid_authority
[5] = 5;
1204 sp
->sid_authorities
[0] = 6;
1207 sp
->sid_authority
[5] = 0;
1208 sp
->sid_authorities
[0] = 0;
1214 nfs4_fallback_name(const char *id
, int have_at
)
1217 /* must be user@domain */
1218 /* try to identify some well-known IDs */
1219 if (!strncmp(id
, "root@", 5)) {
1221 } else if (!strncmp(id
, "wheel@", 6)) {
1223 } else if (!strncmp(id
, "nobody@", 7)) {
1225 } else if (!strncmp(id
, "nfsnobody@", 10)) {
1233 nfs4_mapid_log(int error
, const char *idstr
, int isgroup
, guid_t
*gp
)
1235 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
)) {
1236 printf("nfs4_id2guid: idmap failed for %s %s error %d\n", idstr
, isgroup
? "G" : " ", error
);
1238 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
)) {
1239 printf("nfs4_id2guid: idmap for %s %s got guid "
1240 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1241 idstr
, isgroup
? "G" : " ",
1242 gp
->g_guid
[0], gp
->g_guid
[1], gp
->g_guid
[2], gp
->g_guid
[3],
1243 gp
->g_guid
[4], gp
->g_guid
[5], gp
->g_guid
[6], gp
->g_guid
[7],
1244 gp
->g_guid
[8], gp
->g_guid
[9], gp
->g_guid
[10], gp
->g_guid
[11],
1245 gp
->g_guid
[12], gp
->g_guid
[13], gp
->g_guid
[14], gp
->g_guid
[15]);
1250 nfs4_map_domain(char *id
, char **atp
)
1253 char *dsnode
, *otw_nfs4domain
;
1254 char *new_id
= NULL
;
1255 size_t otw_domain_len
;
1256 size_t otw_id_2_at_len
;
1260 at
= strchr(id
, '@');
1262 if (at
== NULL
|| *at
!= '@') {
1266 otw_nfs4domain
= at
+ 1;
1267 otw_domain_len
= strnlen(otw_nfs4domain
, MAXPATHLEN
);
1268 otw_id_2_at_len
= at
- id
+ 1;
1270 dsnode
= zalloc(ZV_NAMEI
);
1271 /* first try to map nfs4 domain to dsnode for scoped lookups */
1272 error
= kauth_cred_nfs4domain2dsnode(otw_nfs4domain
, dsnode
);
1274 /* Success! Make new id be id@dsnode */
1275 size_t dsnode_len
= strnlen(dsnode
, MAXPATHLEN
);
1276 size_t new_id_len
= otw_id_2_at_len
+ dsnode_len
+ 1;
1279 MALLOC(new_id
, char*, new_id_len
, M_TEMP
, M_WAITOK
);
1280 tmp
= *otw_nfs4domain
;
1281 *otw_nfs4domain
= '\0'; /* Chop of the old domain */
1282 strlcpy(new_id
, id
, MAXPATHLEN
);
1283 *otw_nfs4domain
= tmp
; /* Be nice and preserve callers original id */
1284 strlcat(new_id
, dsnode
, MAXPATHLEN
);
1285 at
= strchr(new_id
, '@');
1287 /* Bummer:-( See if default nfs4 set for unscoped lookup */
1288 size_t default_domain_len
= strnlen(nfs4_default_domain
, MAXPATHLEN
);
1290 if ((otw_domain_len
== default_domain_len
) &&
1291 (strncmp(otw_nfs4domain
, nfs4_default_domain
, otw_domain_len
) == 0)) {
1292 /* Woohoo! We have matching domains, do unscoped lookups */
1296 NFS_ZFREE(ZV_NAMEI
, dsnode
);
1298 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
) {
1299 printf("nfs4_id2guid: after domain mapping id is %s\n", id
);
1307 * Map an NFSv4 ID string to a VFS guid.
1309 * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
1312 nfs4_id2guid(/*const*/ char *id
, guid_t
*guidp
, int isgroup
)
1317 char *p
, *at
, *new_id
= NULL
;
1319 *guidp
= kauth_null_guid
;
1322 * First check if it is just a simple numeric ID string or a special "XXX@" name.
1323 * If it's a number, there's no need trying to ask the IDMAP service to map it.
1324 * If it's a special "XXX@" name, we want to make sure to treat it as a group.
1330 if ((*p
< '0') || (*p
> '9')) {
1340 /* must be numeric ID (or empty) */
1341 num
= *id
? strtol(id
, NULL
, 10) : -2;
1343 error
= kauth_cred_gid2guid((gid_t
)num
, guidp
);
1345 error
= kauth_cred_uid2guid((uid_t
)num
, guidp
);
1347 nfs4_mapid_log(error
, id
, isgroup
, guidp
);
1351 /* See if this is a well known NFSv4 name */
1352 error
= nfs4_wkid2sid(id
, &sid
);
1354 error
= kauth_cred_ntsid2guid(&sid
, guidp
);
1355 nfs4_mapid_log(error
, id
, 1, guidp
);
1359 /* Handle nfs4 domain first */
1361 new_id
= nfs4_map_domain(id
, &at
);
1367 /* Now try to do actual id mapping */
1368 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) {
1370 * Ask the ID mapping service to map the ID string to a GUID.
1372 * [sigh] this isn't a "pwnam/grnam" it's an NFS ID string!
1375 error
= kauth_cred_grnam2guid(id
, guidp
);
1377 error
= kauth_cred_pwnam2guid(id
, guidp
);
1379 nfs4_mapid_log(error
, id
, isgroup
, guidp
);
1386 * fallback path... see if we can come up with an answer ourselves.
1388 num
= nfs4_fallback_name(id
, at
!= NULL
);
1390 error
= kauth_cred_gid2guid((gid_t
)num
, guidp
);
1392 error
= kauth_cred_uid2guid((uid_t
)num
, guidp
);
1394 nfs4_mapid_log(error
, id
, isgroup
, guidp
);
1398 /* restore @ symbol in case we clobered for unscoped lookup */
1399 if (at
&& *at
== '\0') {
1403 /* free mapped domain id string */
1405 FREE(new_id
, M_TEMP
);
1413 * mapid a wellknown identity to guid.
1414 * returns well known name for the sid or NULL if sid does not map.
1416 #define MAXWELLKNOWNID 18
1419 nfs4_sid2wkid(ntsid_t
*sp
)
1421 if ((sp
->sid_kind
== 1) && (sp
->sid_authcount
== 1)) {
1422 /* check if it's one of our well-known ACE WHO names */
1423 if (sp
->sid_authority
[5] == 0) {
1424 if (sp
->sid_authorities
[0] == 0) { // S-1-0-0
1425 return "nobody@localdomain";
1427 } else if (sp
->sid_authority
[5] == 1) {
1428 if (sp
->sid_authorities
[0] == 0) { // S-1-1-0
1431 } else if (sp
->sid_authority
[5] == 3) {
1432 if (sp
->sid_authorities
[0] == 0) { // S-1-3-0
1434 } else if (sp
->sid_authorities
[0] == 1) { // S-1-3-1
1437 } else if (sp
->sid_authority
[5] == 5) {
1438 if (sp
->sid_authorities
[0] == 1) { // S-1-5-1
1440 } else if (sp
->sid_authorities
[0] == 2) { // S-1-5-2
1442 } else if (sp
->sid_authorities
[0] == 3) { // S-1-5-3
1444 } else if (sp
->sid_authorities
[0] == 4) { // S-1-5-4
1445 return "INTERACTIVE@";
1446 } else if (sp
->sid_authorities
[0] == 6) { // S-1-5-6
1448 } else if (sp
->sid_authorities
[0] == 7) { // S-1-5-7
1449 return "ANONYMOUS@";
1450 } else if (sp
->sid_authorities
[0] == 11) { // S-1-5-11
1451 return "AUTHENTICATED@";
1459 nfs4_mapguid_log(int error
, const char *where
, guid_t
*gp
, int isgroup
, const char *idstr
)
1461 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
)) {
1462 printf("nfs4_guid2id: %s idmap failed for "
1463 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1464 "error %d\n", where
,
1465 gp
->g_guid
[0], gp
->g_guid
[1], gp
->g_guid
[2], gp
->g_guid
[3],
1466 gp
->g_guid
[4], gp
->g_guid
[5], gp
->g_guid
[6], gp
->g_guid
[7],
1467 gp
->g_guid
[8], gp
->g_guid
[9], gp
->g_guid
[10], gp
->g_guid
[11],
1468 gp
->g_guid
[12], gp
->g_guid
[13], gp
->g_guid
[14], gp
->g_guid
[15],
1469 isgroup
? "G" : " ", error
);
1471 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
)) {
1472 printf("nfs4_guid2id: %s idmap for "
1473 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1474 "got ID %s\n", where
,
1475 gp
->g_guid
[0], gp
->g_guid
[1], gp
->g_guid
[2], gp
->g_guid
[3],
1476 gp
->g_guid
[4], gp
->g_guid
[5], gp
->g_guid
[6], gp
->g_guid
[7],
1477 gp
->g_guid
[8], gp
->g_guid
[9], gp
->g_guid
[10], gp
->g_guid
[11],
1478 gp
->g_guid
[12], gp
->g_guid
[13], gp
->g_guid
[14], gp
->g_guid
[15],
1479 isgroup
? "G" : " ", idstr
);
1484 nfs4_addv4domain(char *id
, size_t *idlen
)
1486 char *at
= NULL
, *cp
;
1492 if (id
== NULL
|| *id
== '\0') {
1496 for (cp
= id
; *cp
!= '\0'; cp
++) {
1503 have_domain
= (at
&& at
[1] != '\0');
1506 char *dsnode
= at
+ 1;
1509 char *mapped_domain
;
1511 nfs4domain
= zalloc(ZV_NAMEI
);
1512 error
= kauth_cred_dsnode2nfs4domain(dsnode
, nfs4domain
);
1514 domain_len
= strnlen(nfs4domain
, MAXPATHLEN
);
1515 mapped_domain
= nfs4domain
;
1518 domain_len
= strnlen(nfs4_default_domain
, MAXPATHLEN
);
1519 mapped_domain
= nfs4_default_domain
;
1522 /* chop off id after the '@' */
1524 /* Add our mapped_domain */
1525 idsize
= strlcat(id
, mapped_domain
, *idlen
);
1526 if (*idlen
> idsize
) {
1532 NFS_ZFREE(ZV_NAMEI
, nfs4domain
);
1533 } else if (at
== NULL
) {
1535 * If we didn't find an 'at' then cp points to the end of id passed in.
1536 * and if we have a nfs4_default_domain set. Try to append the
1537 * default domain if we have root or set ENOSPC.
1539 size_t default_domain_len
= strnlen(nfs4_default_domain
, MAXPATHLEN
);
1541 if (default_domain_len
) {
1542 strlcat(id
, "@", *idlen
);
1543 idsize
= strlcat(id
, nfs4_default_domain
, *idlen
);
1544 if (*idlen
> idsize
) {
1550 ; /* Unscoped name otw */
1554 if (!error
&& nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
) {
1555 printf("nfs4_guid2id: id after nfs4 domain map: %s[%zd].\n", id
, *idlen
);
1562 nfs4_fallback_id(int numid
, int isgrp
, char *buf
, size_t size
)
1564 const char *idp
= NULL
;
1566 if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS
)) {
1567 /* map well known uid's to strings */
1569 idp
= isgrp
? "wheel" : "root";
1570 } else if (numid
== -2) {
1575 /* or just use a decimal number string. */
1576 snprintf(buf
, size
- 1, "%d", numid
);
1577 buf
[size
- 1] = '\0';
1579 size_t idplen
= strlcpy(buf
, idp
, size
);
1580 if (idplen
>= size
) {
1589 * Map a VFS guid to an NFSv4 ID string.
1591 * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
1594 nfs4_guid2id(guid_t
*guidp
, char *id
, size_t *idlen
, int isgroup
)
1602 id1buf
= id1
= NULL
;
1606 * See if our guid maps to a well known NFSv4 name
1608 error
= kauth_cred_guid2ntsid(guidp
, &sid
);
1610 const char *wkid
= nfs4_sid2wkid(&sid
);
1612 len
= strnlen(wkid
, MAXWELLKNOWNID
);
1613 strlcpy(id
, wkid
, *idlen
);
1614 error
= (len
< *idlen
) ? 0 : ENOSPC
;
1616 nfs4_mapguid_log(error
, "kauth_cred_guid2ntsid", guidp
, 1, id
);
1620 nfs4_mapguid_log(error
, "kauth_cred_guid2ntsid", guidp
, isgroup
, NULL
);
1623 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) {
1625 * Ask the ID mapping service to map the GUID to an ID string.
1627 * [sigh] this isn't a "pwnam" it's an NFS id string!
1631 * Stupid kauth_cred_guid2pwnam() function requires that the buffer
1632 * be at least MAXPATHLEN bytes long even though most if not all ID
1633 * strings will be much much shorter than that.
1636 if (*idlen
< MAXPATHLEN
) {
1637 id1buf
= zalloc(ZV_NAMEI
);
1639 id1len
= MAXPATHLEN
;
1646 error
= kauth_cred_guid2grnam(guidp
, id1
);
1648 error
= kauth_cred_guid2pwnam(guidp
, id1
);
1651 nfs4_mapguid_log(error
, "kauth_cred2[pw|gr]nam", guidp
, isgroup
, id1
);
1659 * fallback path... see if we can come up with an answer ourselves.
1663 /* OK, let's just try mapping it to a UID/GID */
1665 error
= kauth_cred_guid2gid(guidp
, (gid_t
*)&uid
);
1667 error
= kauth_cred_guid2uid(guidp
, &uid
);
1670 char *fbidp
= nfs4_fallback_id(uid
, isgroup
, numbuf
, sizeof(numbuf
));
1671 if (fbidp
== NULL
) {
1678 error
= nfs4_addv4domain(id1
, &id1len
);
1683 /* copy idmap result to output buffer */
1684 len
= strlcpy(id
, id1
, *idlen
);
1685 if (len
>= *idlen
) {
1692 nfs4_mapguid_log(error
, "End of routine", guidp
, isgroup
, id1
);
1695 NFS_ZFREE(ZV_NAMEI
, id1buf
);
1702 * Set a vnode attr's supported bits according to the given bitmap
1705 nfs_vattr_set_supported(uint32_t *bitmap
, struct vnode_attr
*vap
)
1707 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TYPE
)) {
1708 VATTR_SET_SUPPORTED(vap
, va_type
);
1710 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHANGE))
1711 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
)) {
1712 VATTR_SET_SUPPORTED(vap
, va_data_size
);
1714 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FSID
)) {
1715 VATTR_SET_SUPPORTED(vap
, va_fsid
);
1717 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACL
)) {
1718 VATTR_SET_SUPPORTED(vap
, va_acl
);
1720 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
)) {
1721 VATTR_SET_SUPPORTED(vap
, va_flags
);
1723 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEID
)) {
1724 VATTR_SET_SUPPORTED(vap
, va_fileid
);
1726 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
)) {
1727 VATTR_SET_SUPPORTED(vap
, va_flags
);
1729 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE))
1730 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
)) {
1731 VATTR_SET_SUPPORTED(vap
, va_mode
);
1733 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NUMLINKS
)) {
1734 VATTR_SET_SUPPORTED(vap
, va_nlink
);
1736 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER
)) {
1737 VATTR_SET_SUPPORTED(vap
, va_uid
);
1738 VATTR_SET_SUPPORTED(vap
, va_uuuid
);
1740 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER_GROUP
)) {
1741 VATTR_SET_SUPPORTED(vap
, va_gid
);
1742 VATTR_SET_SUPPORTED(vap
, va_guuid
);
1744 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RAWDEV
)) {
1745 VATTR_SET_SUPPORTED(vap
, va_rdev
);
1747 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_USED
)) {
1748 VATTR_SET_SUPPORTED(vap
, va_total_alloc
);
1750 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYSTEM))
1751 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS
)) {
1752 VATTR_SET_SUPPORTED(vap
, va_access_time
);
1754 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_BACKUP
)) {
1755 VATTR_SET_SUPPORTED(vap
, va_backup_time
);
1757 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_CREATE
)) {
1758 VATTR_SET_SUPPORTED(vap
, va_create_time
);
1760 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_METADATA
)) {
1761 VATTR_SET_SUPPORTED(vap
, va_change_time
);
1763 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY
)) {
1764 VATTR_SET_SUPPORTED(vap
, va_modify_time
);
1769 * Parse the attributes that are in the mbuf list and store them in
1770 * the given structures.
1774 struct nfsm_chain
*nmc
,
1775 struct nfs_fsattr
*nfsap
,
1776 struct nfs_vattr
*nvap
,
1779 struct nfs_fs_locations
*nfslsp
)
1781 int error
= 0, error2
, rderror
= 0, attrbytes
;
1782 uint32_t val
, val2
, val3
, i
;
1783 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], len
;
1786 struct nfs_fsattr nfsa_dummy
;
1787 struct nfs_vattr
*nva_dummy
= NULL
;
1788 struct dqblk dqb_dummy
;
1789 kauth_acl_t acl
= NULL
;
1790 uint32_t ace_type
, ace_flags
, ace_mask
;
1791 struct nfs_fs_locations nfsls_dummy
;
1792 struct sockaddr_storage ss
;
1794 /* if not interested in some values... throw 'em into a local dummy variable */
1796 nfsap
= &nfsa_dummy
;
1799 MALLOC(nva_dummy
, struct nfs_vattr
*, sizeof(*nva_dummy
), M_TEMP
, M_WAITOK
);
1806 nfslsp
= &nfsls_dummy
;
1808 bzero(nfslsp
, sizeof(*nfslsp
));
1810 attrbytes
= val
= val2
= val3
= 0;
1812 slen
= sizeof(sbuf
);
1815 len
= NFS_ATTR_BITMAP_LEN
;
1816 nfsm_chain_get_bitmap(error
, nmc
, bitmap
, len
);
1817 /* add bits to object/fs attr bitmaps */
1818 for (i
= 0; i
< NFS_ATTR_BITMAP_LEN
; i
++) {
1819 nvap
->nva_bitmap
[i
] |= bitmap
[i
] & nfs_object_attr_bitmap
[i
];
1820 nfsap
->nfsa_bitmap
[i
] |= bitmap
[i
] & nfs_fs_attr_bitmap
[i
];
1823 nfsm_chain_get_32(error
, nmc
, attrbytes
);
1826 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SUPPORTED_ATTRS
)) {
1827 len
= NFS_ATTR_BITMAP_LEN
;
1828 nfsm_chain_get_bitmap(error
, nmc
, nfsap
->nfsa_supp_attr
, len
);
1829 attrbytes
-= (len
+ 1) * NFSX_UNSIGNED
;
1831 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TYPE
)) {
1832 nfsm_chain_get_32(error
, nmc
, val
);
1833 nvap
->nva_type
= nfstov_type(val
, NFS_VER4
);
1834 if ((val
== NFATTRDIR
) || (val
== NFNAMEDATTR
)) {
1835 nvap
->nva_flags
|= NFS_FFLAG_IS_ATTR
;
1837 nvap
->nva_flags
&= ~NFS_FFLAG_IS_ATTR
;
1839 attrbytes
-= NFSX_UNSIGNED
;
1841 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FH_EXPIRE_TYPE
)) {
1842 nfsm_chain_get_32(error
, nmc
, val
);
1844 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_FHTYPE_MASK
;
1845 nfsap
->nfsa_flags
|= val
<< NFS_FSFLAG_FHTYPE_SHIFT
;
1847 printf("nfs: warning unknown fh type: 0x%x\n", val
);
1849 attrbytes
-= NFSX_UNSIGNED
;
1851 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CHANGE
)) {
1852 nfsm_chain_get_64(error
, nmc
, nvap
->nva_change
);
1853 attrbytes
-= 2 * NFSX_UNSIGNED
;
1855 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
)) {
1856 nfsm_chain_get_64(error
, nmc
, nvap
->nva_size
);
1857 attrbytes
-= 2 * NFSX_UNSIGNED
;
1859 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_LINK_SUPPORT
)) {
1860 nfsm_chain_get_32(error
, nmc
, val
);
1862 nfsap
->nfsa_flags
|= NFS_FSFLAG_LINK
;
1864 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_LINK
;
1866 attrbytes
-= NFSX_UNSIGNED
;
1868 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SYMLINK_SUPPORT
)) {
1869 nfsm_chain_get_32(error
, nmc
, val
);
1871 nfsap
->nfsa_flags
|= NFS_FSFLAG_SYMLINK
;
1873 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_SYMLINK
;
1875 attrbytes
-= NFSX_UNSIGNED
;
1877 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NAMED_ATTR
)) {
1878 nfsm_chain_get_32(error
, nmc
, val
);
1880 nvap
->nva_flags
|= NFS_FFLAG_HAS_NAMED_ATTRS
;
1882 nvap
->nva_flags
&= ~NFS_FFLAG_HAS_NAMED_ATTRS
;
1884 attrbytes
-= NFSX_UNSIGNED
;
1886 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FSID
)) {
1887 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fsid
.major
);
1888 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fsid
.minor
);
1889 attrbytes
-= 4 * NFSX_UNSIGNED
;
1891 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_UNIQUE_HANDLES
)) {
1892 nfsm_chain_get_32(error
, nmc
, val
);
1894 nfsap
->nfsa_flags
|= NFS_FSFLAG_UNIQUE_FH
;
1896 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_UNIQUE_FH
;
1898 attrbytes
-= NFSX_UNSIGNED
;
1900 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_LEASE_TIME
)) {
1901 nfsm_chain_get_32(error
, nmc
, nfsap
->nfsa_lease
);
1902 attrbytes
-= NFSX_UNSIGNED
;
1904 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RDATTR_ERROR
)) {
1905 nfsm_chain_get_32(error
, nmc
, rderror
);
1906 attrbytes
-= NFSX_UNSIGNED
;
1907 if (!rderror
) { /* no error */
1908 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_RDATTR_ERROR
);
1909 NFS_BITMAP_CLR(nvap
->nva_bitmap
, NFS_FATTR_RDATTR_ERROR
);
1912 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACL
)) {
1914 ace_type
= ace_flags
= ace_mask
= 0;
1915 nfsm_chain_get_32(error
, nmc
, val
); /* ACE count */
1916 if (!error
&& (val
> KAUTH_ACL_MAX_ENTRIES
)) {
1919 if (!error
&& !((acl
= kauth_acl_alloc(val
)))) {
1922 if (!error
&& acl
) {
1923 acl
->acl_entrycount
= val
;
1926 attrbytes
-= NFSX_UNSIGNED
;
1927 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
1928 for (i
= 0; !error
&& (i
< val
); i
++) {
1929 nfsm_chain_get_32(error
, nmc
, ace_type
);
1930 nfsm_chain_get_32(error
, nmc
, ace_flags
);
1931 nfsm_chain_get_32(error
, nmc
, ace_mask
);
1932 nfsm_chain_get_32(error
, nmc
, len
);
1933 if (!error
&& len
>= NFS_MAX_WHO
) {
1936 acl
->acl_ace
[i
].ace_flags
= nfs4_ace_nfstype_to_vfstype(ace_type
, &error
);
1937 acl
->acl_ace
[i
].ace_flags
|= nfs4_ace_nfsflags_to_vfsflags(ace_flags
);
1938 acl
->acl_ace
[i
].ace_rights
= nfs4_ace_nfsmask_to_vfsrights(ace_mask
);
1939 if (!error
&& !error2
&& (len
>= slen
)) {
1943 slen
= sizeof(sbuf
);
1945 /* Let's add a bit more if we can to the allocation as to try and avoid future allocations */
1946 MALLOC(s
, char*, (len
+ 16 < NFS_MAX_WHO
) ? len
+ 16 : NFS_MAX_WHO
, M_TEMP
, M_WAITOK
);
1948 slen
= (len
+ 16 < NFS_MAX_WHO
) ? len
+ 16 : NFS_MAX_WHO
;
1954 nfsm_chain_adv(error
, nmc
, nfsm_rndup(len
));
1956 nfsm_chain_get_opaque(error
, nmc
, len
, s
);
1958 if (!error
&& !error2
) {
1960 error2
= nfs4_id2guid(s
, &acl
->acl_ace
[i
].ace_applicable
,
1961 (ace_flags
& NFS_ACE_IDENTIFIER_GROUP
));
1962 if (error2
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
)) {
1963 printf("nfs4_parsefattr: ACE WHO %s is no one, no guid?, error %d\n", s
, error2
);
1966 attrbytes
-= 4 * NFSX_UNSIGNED
+ nfsm_rndup(len
);
1967 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
1970 if ((nvap
!= nva_dummy
) && !error2
) {
1971 nvap
->nva_acl
= acl
;
1975 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACLSUPPORT
)) {
1977 * Support ACLs if: the server supports DENY/ALLOC ACEs and
1978 * (just to be safe) FATTR_ACL is in the supported list too.
1980 nfsm_chain_get_32(error
, nmc
, val
);
1981 if ((val
& (NFS_ACL_SUPPORT_ALLOW_ACL
| NFS_ACL_SUPPORT_DENY_ACL
)) &&
1982 NFS_BITMAP_ISSET(nfsap
->nfsa_supp_attr
, NFS_FATTR_ACL
)) {
1983 nfsap
->nfsa_flags
|= NFS_FSFLAG_ACL
;
1985 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_ACL
;
1987 attrbytes
-= NFSX_UNSIGNED
;
1989 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
)) { /* SF_ARCHIVED */
1990 nfsm_chain_get_32(error
, nmc
, val
);
1992 nvap
->nva_flags
|= NFS_FFLAG_ARCHIVED
;
1994 nvap
->nva_flags
&= ~NFS_FFLAG_ARCHIVED
;
1996 attrbytes
-= NFSX_UNSIGNED
;
1998 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CANSETTIME
)) {
1999 nfsm_chain_get_32(error
, nmc
, val
);
2001 nfsap
->nfsa_flags
|= NFS_FSFLAG_SET_TIME
;
2003 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_SET_TIME
;
2005 attrbytes
-= NFSX_UNSIGNED
;
2007 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CASE_INSENSITIVE
)) {
2008 nfsm_chain_get_32(error
, nmc
, val
);
2010 nfsap
->nfsa_flags
|= NFS_FSFLAG_CASE_INSENSITIVE
;
2012 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CASE_INSENSITIVE
;
2014 attrbytes
-= NFSX_UNSIGNED
;
2016 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CASE_PRESERVING
)) {
2017 nfsm_chain_get_32(error
, nmc
, val
);
2019 nfsap
->nfsa_flags
|= NFS_FSFLAG_CASE_PRESERVING
;
2021 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CASE_PRESERVING
;
2023 attrbytes
-= NFSX_UNSIGNED
;
2025 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CHOWN_RESTRICTED
)) {
2026 nfsm_chain_get_32(error
, nmc
, val
);
2028 nfsap
->nfsa_flags
|= NFS_FSFLAG_CHOWN_RESTRICTED
;
2030 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CHOWN_RESTRICTED
;
2032 attrbytes
-= NFSX_UNSIGNED
;
2034 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEHANDLE
)) {
2035 nfsm_chain_get_32(error
, nmc
, val
);
2036 if (error
== 0 && val
> NFS_MAX_FH_SIZE
) {
2042 nfsm_chain_get_opaque(error
, nmc
, nfsm_rndup(val
), fhp
->fh_data
);
2044 nfsm_chain_adv(error
, nmc
, nfsm_rndup(val
));
2046 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
2048 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEID
)) {
2049 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fileid
);
2050 attrbytes
-= 2 * NFSX_UNSIGNED
;
2052 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILES_AVAIL
)) {
2053 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_files_avail
);
2054 attrbytes
-= 2 * NFSX_UNSIGNED
;
2056 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILES_FREE
)) {
2057 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_files_free
);
2058 attrbytes
-= 2 * NFSX_UNSIGNED
;
2060 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILES_TOTAL
)) {
2061 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_files_total
);
2062 attrbytes
-= 2 * NFSX_UNSIGNED
;
2064 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FS_LOCATIONS
)) {
2065 uint32_t loc
, serv
, comp
;
2066 struct nfs_fs_location
*fsl
;
2067 struct nfs_fs_server
*fss
;
2068 struct nfs_fs_path
*fsp
;
2070 /* get root pathname */
2071 fsp
= &nfslsp
->nl_root
;
2072 nfsm_chain_get_32(error
, nmc
, fsp
->np_compcount
); /* component count */
2073 attrbytes
-= NFSX_UNSIGNED
;
2074 /* sanity check component count */
2075 if (!error
&& (fsp
->np_compcount
> MAXPATHLEN
)) {
2079 if (fsp
->np_compcount
) {
2080 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
| M_ZERO
);
2081 if (!fsp
->np_components
) {
2085 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
2086 nfsm_chain_get_32(error
, nmc
, val
); /* component length */
2087 /* sanity check component length */
2088 if (!error
&& (val
== 0)) {
2090 * Apparently some people think a path with zero components should
2091 * be encoded with one zero-length component. So, just ignore any
2092 * zero length components.
2095 fsp
->np_compcount
--;
2096 if (fsp
->np_compcount
== 0) {
2097 FREE(fsp
->np_components
, M_TEMP
);
2098 fsp
->np_components
= NULL
;
2100 attrbytes
-= NFSX_UNSIGNED
;
2103 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
))) {
2107 MALLOC(fsp
->np_components
[comp
], char *, val
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
2108 if (!fsp
->np_components
[comp
]) {
2112 nfsm_chain_get_opaque(error
, nmc
, val
, fsp
->np_components
[comp
]); /* component */
2113 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
2115 nfsm_chain_get_32(error
, nmc
, nfslsp
->nl_numlocs
); /* fs location count */
2116 attrbytes
-= NFSX_UNSIGNED
;
2117 /* sanity check location count */
2118 if (!error
&& (nfslsp
->nl_numlocs
> 256)) {
2122 if (nfslsp
->nl_numlocs
> 0) {
2123 MALLOC(nfslsp
->nl_locations
, struct nfs_fs_location
**, nfslsp
->nl_numlocs
* sizeof(struct nfs_fs_location
*), M_TEMP
, M_WAITOK
| M_ZERO
);
2124 if (!nfslsp
->nl_locations
) {
2129 for (loc
= 0; loc
< nfslsp
->nl_numlocs
; loc
++) {
2131 MALLOC(fsl
, struct nfs_fs_location
*, sizeof(struct nfs_fs_location
), M_TEMP
, M_WAITOK
| M_ZERO
);
2135 nfslsp
->nl_locations
[loc
] = fsl
;
2136 nfsm_chain_get_32(error
, nmc
, fsl
->nl_servcount
); /* server count */
2137 attrbytes
-= NFSX_UNSIGNED
;
2138 /* sanity check server count */
2139 if (!error
&& ((fsl
->nl_servcount
< 1) || (fsl
->nl_servcount
> 256))) {
2143 MALLOC(fsl
->nl_servers
, struct nfs_fs_server
**, fsl
->nl_servcount
* sizeof(struct nfs_fs_server
*), M_TEMP
, M_WAITOK
| M_ZERO
);
2144 if (!fsl
->nl_servers
) {
2147 for (serv
= 0; serv
< fsl
->nl_servcount
; serv
++) {
2149 MALLOC(fss
, struct nfs_fs_server
*, sizeof(struct nfs_fs_server
), M_TEMP
, M_WAITOK
| M_ZERO
);
2153 fsl
->nl_servers
[serv
] = fss
;
2154 nfsm_chain_get_32(error
, nmc
, val
); /* server name length */
2155 /* sanity check server name length */
2156 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
))) {
2160 MALLOC(fss
->ns_name
, char *, val
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
2161 if (!fss
->ns_name
) {
2164 nfsm_chain_get_opaque(error
, nmc
, val
, fss
->ns_name
); /* server name */
2165 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
2167 /* copy name to address if it converts to a sockaddr */
2168 if (nfs_uaddr2sockaddr(fss
->ns_name
, (struct sockaddr
*)&ss
)) {
2169 fss
->ns_addrcount
= 1;
2170 MALLOC(fss
->ns_addresses
, char **, sizeof(char *), M_TEMP
, M_WAITOK
| M_ZERO
);
2171 if (!fss
->ns_addresses
) {
2175 MALLOC(fss
->ns_addresses
[0], char *, val
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
2176 if (!fss
->ns_addresses
[0]) {
2180 strlcpy(fss
->ns_addresses
[0], fss
->ns_name
, val
+ 1);
2184 fsp
= &fsl
->nl_path
;
2185 nfsm_chain_get_32(error
, nmc
, fsp
->np_compcount
); /* component count */
2186 attrbytes
-= NFSX_UNSIGNED
;
2187 /* sanity check component count */
2188 if (!error
&& (fsp
->np_compcount
> MAXPATHLEN
)) {
2192 if (fsp
->np_compcount
) {
2193 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
| M_ZERO
);
2194 if (!fsp
->np_components
) {
2198 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
2199 nfsm_chain_get_32(error
, nmc
, val
); /* component length */
2200 /* sanity check component length */
2201 if (!error
&& (val
== 0)) {
2203 * Apparently some people think a path with zero components should
2204 * be encoded with one zero-length component. So, just ignore any
2205 * zero length components.
2208 fsp
->np_compcount
--;
2209 if (fsp
->np_compcount
== 0) {
2210 FREE(fsp
->np_components
, M_TEMP
);
2211 fsp
->np_components
= NULL
;
2213 attrbytes
-= NFSX_UNSIGNED
;
2216 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
))) {
2220 MALLOC(fsp
->np_components
[comp
], char *, val
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
2221 if (!fsp
->np_components
[comp
]) {
2224 nfsm_chain_get_opaque(error
, nmc
, val
, fsp
->np_components
[comp
]); /* component */
2225 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
2228 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
2230 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
)) { /* UF_HIDDEN */
2231 nfsm_chain_get_32(error
, nmc
, val
);
2233 nvap
->nva_flags
|= NFS_FFLAG_HIDDEN
;
2235 nvap
->nva_flags
&= ~NFS_FFLAG_HIDDEN
;
2237 attrbytes
-= NFSX_UNSIGNED
;
2239 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HOMOGENEOUS
)) {
2240 /* XXX If NOT homogeneous, we may need to clear flags on the mount */
2241 nfsm_chain_get_32(error
, nmc
, val
);
2243 nfsap
->nfsa_flags
|= NFS_FSFLAG_HOMOGENEOUS
;
2245 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_HOMOGENEOUS
;
2247 attrbytes
-= NFSX_UNSIGNED
;
2249 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXFILESIZE
)) {
2250 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxfilesize
);
2251 attrbytes
-= 2 * NFSX_UNSIGNED
;
2253 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXLINK
)) {
2254 nfsm_chain_get_32(error
, nmc
, nvap
->nva_maxlink
);
2255 if (!error
&& (nfsap
->nfsa_maxlink
> INT32_MAX
)) {
2256 nfsap
->nfsa_maxlink
= INT32_MAX
;
2258 attrbytes
-= NFSX_UNSIGNED
;
2260 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXNAME
)) {
2261 nfsm_chain_get_32(error
, nmc
, nfsap
->nfsa_maxname
);
2262 if (!error
&& (nfsap
->nfsa_maxname
> INT32_MAX
)) {
2263 nfsap
->nfsa_maxname
= INT32_MAX
;
2265 attrbytes
-= NFSX_UNSIGNED
;
2267 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXREAD
)) {
2268 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxread
);
2269 attrbytes
-= 2 * NFSX_UNSIGNED
;
2271 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXWRITE
)) {
2272 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxwrite
);
2273 attrbytes
-= 2 * NFSX_UNSIGNED
;
2275 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MIMETYPE
)) {
2276 nfsm_chain_get_32(error
, nmc
, val
);
2277 nfsm_chain_adv(error
, nmc
, nfsm_rndup(val
));
2278 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
2280 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
)) {
2281 nfsm_chain_get_32(error
, nmc
, val
);
2282 if (val
> ALLPERMS
) {
2285 nvap
->nva_mode
= (mode_t
)val
;
2287 attrbytes
-= NFSX_UNSIGNED
;
2289 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NO_TRUNC
)) {
2290 nfsm_chain_get_32(error
, nmc
, val
);
2292 nfsap
->nfsa_flags
|= NFS_FSFLAG_NO_TRUNC
;
2294 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_NO_TRUNC
;
2296 attrbytes
-= NFSX_UNSIGNED
;
2298 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NUMLINKS
)) {
2299 nfsm_chain_get_32(error
, nmc
, val
);
2300 nvap
->nva_nlink
= val
;
2301 attrbytes
-= NFSX_UNSIGNED
;
2303 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER
)) {
2304 nfsm_chain_get_32(error
, nmc
, len
);
2305 if (!error
&& len
>= NFS_MAX_WHO
) {
2308 if (!error
&& (len
>= slen
)) {
2312 slen
= sizeof(sbuf
);
2314 /* Let's add a bit more if we can to the allocation as to try and avoid future allocations */
2315 MALLOC(s
, char*, (len
+ 16 < NFS_MAX_WHO
) ? len
+ 16 : NFS_MAX_WHO
, M_TEMP
, M_WAITOK
);
2317 slen
= (len
+ 16 < NFS_MAX_WHO
) ? len
+ 16 : NFS_MAX_WHO
;
2322 nfsm_chain_get_opaque(error
, nmc
, len
, s
);
2325 error
= nfs4_id2guid(s
, &nvap
->nva_uuuid
, 0);
2327 error
= kauth_cred_guid2uid(&nvap
->nva_uuuid
, &nvap
->nva_uid
);
2330 /* unable to get either GUID or UID, set to default */
2331 nvap
->nva_uid
= (uid_t
)(-2);
2332 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
) {
2333 printf("nfs4_parsefattr: owner %s is no one, no %s?, error %d\n", s
,
2334 kauth_guid_equal(&nvap
->nva_uuuid
, &kauth_null_guid
) ? "guid" : "uid",
2340 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2342 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER_GROUP
)) {
2343 nfsm_chain_get_32(error
, nmc
, len
);
2344 if (!error
&& len
>= NFS_MAX_WHO
) {
2347 if (!error
&& (len
>= slen
)) {
2351 slen
= sizeof(sbuf
);
2353 /* Let's add a bit more if we can to the allocation as to try and avoid future allocations */
2354 MALLOC(s
, char*, (len
+ 16 < NFS_MAX_WHO
) ? len
+ 16 : NFS_MAX_WHO
, M_TEMP
, M_WAITOK
);
2356 slen
= (len
+ 16 < NFS_MAX_WHO
) ? len
+ 16 : NFS_MAX_WHO
;
2361 nfsm_chain_get_opaque(error
, nmc
, len
, s
);
2364 error
= nfs4_id2guid(s
, &nvap
->nva_guuid
, 1);
2366 error
= kauth_cred_guid2gid(&nvap
->nva_guuid
, &nvap
->nva_gid
);
2369 /* unable to get either GUID or GID, set to default */
2370 nvap
->nva_gid
= (gid_t
)(-2);
2371 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
) {
2372 printf("nfs4_parsefattr: group %s is no one, no %s?, error %d\n", s
,
2373 kauth_guid_equal(&nvap
->nva_guuid
, &kauth_null_guid
) ? "guid" : "gid",
2379 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2381 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_QUOTA_AVAIL_HARD
)) {
2382 nfsm_chain_get_64(error
, nmc
, dqbp
->dqb_bhardlimit
);
2383 attrbytes
-= 2 * NFSX_UNSIGNED
;
2385 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_QUOTA_AVAIL_SOFT
)) {
2386 nfsm_chain_get_64(error
, nmc
, dqbp
->dqb_bsoftlimit
);
2387 attrbytes
-= 2 * NFSX_UNSIGNED
;
2389 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_QUOTA_USED
)) {
2390 nfsm_chain_get_64(error
, nmc
, dqbp
->dqb_curbytes
);
2391 attrbytes
-= 2 * NFSX_UNSIGNED
;
2393 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RAWDEV
)) {
2394 nfsm_chain_get_32(error
, nmc
, nvap
->nva_rawdev
.specdata1
);
2395 nfsm_chain_get_32(error
, nmc
, nvap
->nva_rawdev
.specdata2
);
2396 attrbytes
-= 2 * NFSX_UNSIGNED
;
2398 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_AVAIL
)) {
2399 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_space_avail
);
2400 attrbytes
-= 2 * NFSX_UNSIGNED
;
2402 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_FREE
)) {
2403 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_space_free
);
2404 attrbytes
-= 2 * NFSX_UNSIGNED
;
2406 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_TOTAL
)) {
2407 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_space_total
);
2408 attrbytes
-= 2 * NFSX_UNSIGNED
;
2410 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_USED
)) {
2411 nfsm_chain_get_64(error
, nmc
, nvap
->nva_bytes
);
2412 attrbytes
-= 2 * NFSX_UNSIGNED
;
2414 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SYSTEM
)) {
2415 /* we'd support this if we had a flag to map it to... */
2416 nfsm_chain_adv(error
, nmc
, NFSX_UNSIGNED
);
2417 attrbytes
-= NFSX_UNSIGNED
;
2419 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS
)) {
2420 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_ACCESS
]);
2421 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_ACCESS
]);
2422 attrbytes
-= 3 * NFSX_UNSIGNED
;
2424 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
)) {
2425 nfsm_chain_adv(error
, nmc
, 4 * NFSX_UNSIGNED
); /* just skip it */
2426 attrbytes
-= 4 * NFSX_UNSIGNED
;
2428 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_BACKUP
)) {
2429 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_BACKUP
]);
2430 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_BACKUP
]);
2431 attrbytes
-= 3 * NFSX_UNSIGNED
;
2433 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_CREATE
)) {
2434 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_CREATE
]);
2435 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_CREATE
]);
2436 attrbytes
-= 3 * NFSX_UNSIGNED
;
2438 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_DELTA
)) { /* skip for now */
2439 nfsm_chain_adv(error
, nmc
, 3 * NFSX_UNSIGNED
);
2440 attrbytes
-= 3 * NFSX_UNSIGNED
;
2442 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_METADATA
)) {
2443 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_CHANGE
]);
2444 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_CHANGE
]);
2445 attrbytes
-= 3 * NFSX_UNSIGNED
;
2447 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY
)) {
2448 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_MODIFY
]);
2449 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_MODIFY
]);
2450 attrbytes
-= 3 * NFSX_UNSIGNED
;
2452 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
)) {
2453 nfsm_chain_adv(error
, nmc
, 4 * NFSX_UNSIGNED
); /* just skip it */
2454 attrbytes
-= 4 * NFSX_UNSIGNED
;
2456 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MOUNTED_ON_FILEID
)) {
2458 /* we prefer the mounted on file ID, so just replace the fileid */
2459 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fileid
);
2461 nfsm_chain_adv(error
, nmc
, 2 * NFSX_UNSIGNED
);
2463 attrbytes
-= 2 * NFSX_UNSIGNED
;
2465 /* advance over any leftover attrbytes */
2466 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
2467 nfsm_chain_adv(error
, nmc
, nfsm_rndup(attrbytes
));
2470 nfs_fs_locations_cleanup(nfslsp
);
2472 if (!error
&& rderror
) {
2475 /* free up temporary resources */
2476 if (s
&& (s
!= sbuf
)) {
2480 kauth_acl_free(acl
);
2482 if (error
&& nvap
->nva_acl
) {
2483 kauth_acl_free(nvap
->nva_acl
);
2484 nvap
->nva_acl
= NULL
;
2486 FREE(nva_dummy
, M_TEMP
);
2491 * Add an NFSv4 "sattr" structure to an mbuf chain
2494 nfsm_chain_add_fattr4_f(struct nfsm_chain
*nmc
, struct vnode_attr
*vap
, struct nfsmount
*nmp
)
2496 int error
= 0, attrbytes
, i
, isgroup
;
2498 uint32_t *pattrbytes
, val
, acecount
;;
2499 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
2505 slen
= sizeof(sbuf
);
2507 /* First calculate the bitmap... */
2508 nfs_vattr_set_bitmap(nmp
, bitmap
, vap
);
2511 * Now pack it all together:
2512 * BITMAP, #BYTES, ATTRS
2513 * Keep a pointer to the length so we can set it later.
2515 nfsm_chain_add_bitmap(error
, nmc
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2517 nfsm_chain_add_32(error
, nmc
, attrbytes
);
2518 pattrbytes
= (uint32_t*)(nmc
->nmc_ptr
- NFSX_UNSIGNED
);
2520 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
)) {
2521 nfsm_chain_add_64(error
, nmc
, vap
->va_data_size
);
2522 attrbytes
+= 2 * NFSX_UNSIGNED
;
2524 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACL
)) {
2526 if (!acl
|| (acl
->acl_entrycount
== KAUTH_FILESEC_NOACL
)) {
2529 acecount
= acl
->acl_entrycount
;
2531 nfsm_chain_add_32(error
, nmc
, acecount
);
2532 attrbytes
+= NFSX_UNSIGNED
;
2533 for (i
= 0; !error
&& (i
< (int)acecount
); i
++) {
2534 val
= (acl
->acl_ace
[i
].ace_flags
& KAUTH_ACE_KINDMASK
);
2535 val
= nfs4_ace_vfstype_to_nfstype(val
, &error
);
2536 nfsm_chain_add_32(error
, nmc
, val
);
2537 val
= nfs4_ace_vfsflags_to_nfsflags(acl
->acl_ace
[i
].ace_flags
);
2538 isgroup
= (kauth_cred_guid2gid(&acl
->acl_ace
[i
].ace_applicable
, &gid
) == 0);
2539 val
|= (isgroup
) ? NFS_ACE_IDENTIFIER_GROUP
: 0;
2540 nfsm_chain_add_32(error
, nmc
, val
);
2541 val
= nfs4_ace_vfsrights_to_nfsmask(acl
->acl_ace
[i
].ace_rights
);
2542 nfsm_chain_add_32(error
, nmc
, val
);
2544 error
= nfs4_guid2id(&acl
->acl_ace
[i
].ace_applicable
, s
, &len
, isgroup
);
2545 if (error
== ENOSPC
) {
2551 MALLOC(s
, char*, len
, M_TEMP
, M_WAITOK
);
2554 error
= nfs4_guid2id(&acl
->acl_ace
[i
].ace_applicable
, s
, &len
, isgroup
);
2559 nfsm_chain_add_name(error
, nmc
, s
, len
, nmp
);
2560 attrbytes
+= 4 * NFSX_UNSIGNED
+ nfsm_rndup(len
);
2563 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
)) {
2564 nfsm_chain_add_32(error
, nmc
, (vap
->va_flags
& SF_ARCHIVED
) ? 1 : 0);
2565 attrbytes
+= NFSX_UNSIGNED
;
2567 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
)) {
2568 nfsm_chain_add_32(error
, nmc
, (vap
->va_flags
& UF_HIDDEN
) ? 1 : 0);
2569 attrbytes
+= NFSX_UNSIGNED
;
2571 // NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE)
2572 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
)) {
2573 nfsm_chain_add_32(error
, nmc
, vap
->va_mode
);
2574 attrbytes
+= NFSX_UNSIGNED
;
2576 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER
)) {
2578 /* if we have va_uuuid use it, otherwise use uid */
2579 if (!VATTR_IS_ACTIVE(vap
, va_uuuid
)) {
2580 error
= kauth_cred_uid2guid(vap
->va_uid
, &vap
->va_uuuid
);
2584 error
= nfs4_guid2id(&vap
->va_uuuid
, s
, &len
, 0);
2585 if (error
== ENOSPC
) {
2591 MALLOC(s
, char*, len
, M_TEMP
, M_WAITOK
);
2594 error
= nfs4_guid2id(&vap
->va_uuuid
, s
, &len
, 0);
2599 nfsm_chain_add_name(error
, nmc
, s
, len
, nmp
);
2600 attrbytes
+= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2602 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER_GROUP
)) {
2604 /* if we have va_guuid use it, otherwise use gid */
2605 if (!VATTR_IS_ACTIVE(vap
, va_guuid
)) {
2606 error
= kauth_cred_gid2guid(vap
->va_gid
, &vap
->va_guuid
);
2610 error
= nfs4_guid2id(&vap
->va_guuid
, s
, &len
, 1);
2611 if (error
== ENOSPC
) {
2617 MALLOC(s
, char*, len
, M_TEMP
, M_WAITOK
);
2620 error
= nfs4_guid2id(&vap
->va_guuid
, s
, &len
, 1);
2625 nfsm_chain_add_name(error
, nmc
, s
, len
, nmp
);
2626 attrbytes
+= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2628 // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
2629 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
)) {
2630 if (vap
->va_vaflags
& VA_UTIMES_NULL
) {
2631 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_SERVER
);
2632 attrbytes
+= NFSX_UNSIGNED
;
2634 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_CLIENT
);
2635 nfsm_chain_add_64(error
, nmc
, vap
->va_access_time
.tv_sec
);
2636 nfsm_chain_add_32(error
, nmc
, vap
->va_access_time
.tv_nsec
);
2637 attrbytes
+= 4 * NFSX_UNSIGNED
;
2640 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_BACKUP
)) {
2641 nfsm_chain_add_64(error
, nmc
, vap
->va_backup_time
.tv_sec
);
2642 nfsm_chain_add_32(error
, nmc
, vap
->va_backup_time
.tv_nsec
);
2643 attrbytes
+= 3 * NFSX_UNSIGNED
;
2645 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_CREATE
)) {
2646 nfsm_chain_add_64(error
, nmc
, vap
->va_create_time
.tv_sec
);
2647 nfsm_chain_add_32(error
, nmc
, vap
->va_create_time
.tv_nsec
);
2648 attrbytes
+= 3 * NFSX_UNSIGNED
;
2650 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
)) {
2651 if (vap
->va_vaflags
& VA_UTIMES_NULL
) {
2652 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_SERVER
);
2653 attrbytes
+= NFSX_UNSIGNED
;
2655 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_CLIENT
);
2656 nfsm_chain_add_64(error
, nmc
, vap
->va_modify_time
.tv_sec
);
2657 nfsm_chain_add_32(error
, nmc
, vap
->va_modify_time
.tv_nsec
);
2658 attrbytes
+= 4 * NFSX_UNSIGNED
;
2662 /* Now, set the attribute data length */
2663 *pattrbytes
= txdr_unsigned(attrbytes
);
2665 if (s
&& (s
!= sbuf
)) {
2670 #endif /* CONFIG_NFS4 */
2673 * Got the given error and need to start recovery (if not already started).
2674 * Note: nmp must be locked!
2677 nfs_need_recover(struct nfsmount
*nmp
, int error
)
2679 int wake
= !(nmp
->nm_state
& NFSSTA_RECOVER
);
2681 nmp
->nm_state
|= NFSSTA_RECOVER
;
2682 if ((error
== NFSERR_ADMIN_REVOKED
) ||
2683 (error
== NFSERR_EXPIRED
) ||
2684 (error
== NFSERR_STALE_CLIENTID
)) {
2685 nmp
->nm_state
|= NFSSTA_RECOVER_EXPIRED
;
2688 nfs_mount_sock_thread_wake(nmp
);
2694 * After recovery due to state expiry, check each node and
2695 * drop any lingering delegation we thought we had.
2697 * If a node has an open that is not lost and is not marked
2698 * for reopen, then we hold onto any delegation because it is
2699 * likely newly-granted.
2702 nfs4_expired_check_delegation(nfsnode_t np
, vfs_context_t ctx
)
2704 struct nfsmount
*nmp
= NFSTONMP(np
);
2705 struct nfs_open_file
*nofp
;
2708 if ((np
->n_flag
& NREVOKE
) || !(np
->n_openflags
& N_DELEG_MASK
)) {
2712 lck_mtx_lock(&np
->n_openlock
);
2714 TAILQ_FOREACH(nofp
, &np
->n_opens
, nof_link
) {
2715 if (!nofp
->nof_opencnt
) {
2718 if (nofp
->nof_flags
& NFS_OPEN_FILE_LOST
) {
2721 if (nofp
->nof_flags
& NFS_OPEN_FILE_REOPEN
) {
2724 /* we have an open that is not lost and not marked for reopen */
2725 // XXX print out what's keeping this node from dropping the delegation.
2726 NP(nofp
->nof_np
, "nfs4_expired_check_delegation: !drop: opencnt %d flags 0x%x access %d %d mmap %d %d",
2727 nofp
->nof_opencnt
, nofp
->nof_flags
,
2728 nofp
->nof_access
, nofp
->nof_deny
,
2729 nofp
->nof_mmap_access
, nofp
->nof_mmap_deny
);
2735 /* need to drop a delegation */
2736 if (np
->n_dreturn
.tqe_next
!= NFSNOLIST
) {
2737 /* remove this node from the delegation return list */
2738 lck_mtx_lock(&nmp
->nm_lock
);
2739 if (np
->n_dreturn
.tqe_next
!= NFSNOLIST
) {
2740 TAILQ_REMOVE(&nmp
->nm_dreturnq
, np
, n_dreturn
);
2741 np
->n_dreturn
.tqe_next
= NFSNOLIST
;
2743 lck_mtx_unlock(&nmp
->nm_lock
);
2745 if (np
->n_openflags
& N_DELEG_MASK
) {
2746 np
->n_openflags
&= ~N_DELEG_MASK
;
2747 lck_mtx_lock(&nmp
->nm_lock
);
2748 if (np
->n_dlink
.tqe_next
!= NFSNOLIST
) {
2749 TAILQ_REMOVE(&nmp
->nm_delegations
, np
, n_dlink
);
2750 np
->n_dlink
.tqe_next
= NFSNOLIST
;
2752 lck_mtx_unlock(&nmp
->nm_lock
);
2753 nfs4_delegreturn_rpc(nmp
, np
->n_fhp
, np
->n_fhsize
, &np
->n_dstateid
,
2754 0, vfs_context_thread(ctx
), vfs_context_ucred(ctx
));
2758 lck_mtx_unlock(&np
->n_openlock
);
2760 #endif /* CONFIG_NFS4*/
2763 * Recover state for an NFS mount.
2765 * Iterates over all open files, reclaiming opens and lock state.
2768 nfs_recover(struct nfsmount
*nmp
)
2770 struct timespec ts
= { .tv_sec
= 1, .tv_nsec
= 0 };
2771 int error
, lost
, reopen
;
2772 struct nfs_open_owner
*noop
;
2773 struct nfs_open_file
*nofp
;
2774 struct nfs_file_lock
*nflp
, *nextnflp
;
2775 struct nfs_lock_owner
*nlop
;
2776 thread_t thd
= current_thread();
2778 nfsnode_t np
, nextnp
;
2784 lck_mtx_lock(&nmp
->nm_lock
);
2786 * First, wait for the state inuse count to go to zero so
2787 * we know there are no state operations in progress.
2790 if ((error
= nfs_sigintr(nmp
, NULL
, NULL
, 1))) {
2793 if (!(nmp
->nm_sockflags
& NMSOCK_READY
)) {
2796 if (nmp
->nm_state
& (NFSSTA_FORCE
| NFSSTA_DEAD
)) {
2799 if (nmp
->nm_sockflags
& NMSOCK_UNMOUNT
) {
2805 if (nmp
->nm_stateinuse
) {
2806 msleep(&nmp
->nm_stateinuse
, &nmp
->nm_lock
, (PZERO
- 1), "nfsrecoverstartwait", &ts
);
2808 } while (nmp
->nm_stateinuse
);
2810 if (error
== EPIPE
) {
2811 printf("nfs recovery reconnecting for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2813 printf("nfs recovery aborted for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2815 lck_mtx_unlock(&nmp
->nm_lock
);
2820 if (now
.tv_sec
== nmp
->nm_recover_start
) {
2821 printf("nfs recovery throttled for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2822 lck_mtx_unlock(&nmp
->nm_lock
);
2823 tsleep(nfs_recover
, (PZERO
- 1), "nfsrecoverrestart", hz
);
2826 nmp
->nm_recover_start
= now
.tv_sec
;
2827 if (++nmp
->nm_stategenid
== 0) {
2828 ++nmp
->nm_stategenid
;
2830 printf("nfs recovery started for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2831 lck_mtx_unlock(&nmp
->nm_lock
);
2833 /* for each open owner... */
2834 TAILQ_FOREACH(noop
, &nmp
->nm_open_owners
, noo_link
) {
2835 /* for each of its opens... */
2836 TAILQ_FOREACH(nofp
, &noop
->noo_opens
, nof_oolink
) {
2837 if (!nofp
->nof_access
|| (nofp
->nof_flags
& NFS_OPEN_FILE_LOST
) || (nofp
->nof_np
->n_flag
& NREVOKE
)) {
2841 /* for NFSv2/v3, just skip straight to lock reclaim */
2842 if (nmp
->nm_vers
< NFS_VER4
) {
2846 if (nofp
->nof_rw_drw
) {
2847 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_BOTH
);
2849 if (!error
&& nofp
->nof_w_drw
) {
2850 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_WRITE
, NFS_OPEN_SHARE_DENY_BOTH
);
2852 if (!error
&& nofp
->nof_r_drw
) {
2853 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_BOTH
);
2855 if (!error
&& nofp
->nof_rw_dw
) {
2856 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_WRITE
);
2858 if (!error
&& nofp
->nof_w_dw
) {
2859 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_WRITE
, NFS_OPEN_SHARE_DENY_WRITE
);
2861 if (!error
&& nofp
->nof_r_dw
) {
2862 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_WRITE
);
2865 * deny-none opens with no locks can just be reopened (later) if reclaim fails.
2867 if (!error
&& nofp
->nof_rw
) {
2868 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_NONE
);
2869 if ((error
== NFSERR_ADMIN_REVOKED
) || (error
== NFSERR_EXPIRED
) || (error
== NFSERR_NO_GRACE
)) {
2874 if (!error
&& !reopen
&& nofp
->nof_w
) {
2875 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_WRITE
, NFS_OPEN_SHARE_DENY_NONE
);
2876 if ((error
== NFSERR_ADMIN_REVOKED
) || (error
== NFSERR_EXPIRED
) || (error
== NFSERR_NO_GRACE
)) {
2881 if (!error
&& !reopen
&& nofp
->nof_r
) {
2882 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_NONE
);
2883 if ((error
== NFSERR_ADMIN_REVOKED
) || (error
== NFSERR_EXPIRED
) || (error
== NFSERR_NO_GRACE
)) {
2890 * If we hold delegated state but we don't have any non-delegated opens,
2891 * then we should attempt to claim that state now (but don't return the
2892 * delegation unless asked to).
2894 if ((nofp
->nof_d_rw_drw
|| nofp
->nof_d_w_drw
|| nofp
->nof_d_r_drw
||
2895 nofp
->nof_d_rw_dw
|| nofp
->nof_d_w_dw
|| nofp
->nof_d_r_dw
||
2896 nofp
->nof_d_rw
|| nofp
->nof_d_w
|| nofp
->nof_d_r
) &&
2897 (!nofp
->nof_rw_drw
&& !nofp
->nof_w_drw
&& !nofp
->nof_r_drw
&&
2898 !nofp
->nof_rw_dw
&& !nofp
->nof_w_dw
&& !nofp
->nof_r_dw
&&
2899 !nofp
->nof_rw
&& !nofp
->nof_w
&& !nofp
->nof_r
)) {
2900 if (!error
&& !nfs_open_state_set_busy(nofp
->nof_np
, NULL
)) {
2901 error
= nfs4_claim_delegated_state_for_node(nofp
->nof_np
, R_RECOVER
);
2902 if (!error
&& (nofp
->nof_flags
& NFS_OPEN_FILE_REOPEN
)) {
2905 nfs_open_state_clear_busy(nofp
->nof_np
);
2906 /* if claim didn't go well, we may need to return delegation now */
2907 if (nofp
->nof_np
->n_openflags
& N_DELEG_RETURN
) {
2908 nfs4_delegation_return(nofp
->nof_np
, R_RECOVER
, thd
, noop
->noo_cred
);
2909 if (!(nmp
->nm_sockflags
& NMSOCK_READY
)) {
2910 error
= ETIMEDOUT
; /* looks like we need a reconnect */
2917 * Handle any issue claiming open state.
2918 * Potential reopens need to first confirm that there are no locks.
2920 if (error
|| reopen
) {
2921 /* restart recovery? */
2922 if ((error
== ETIMEDOUT
) || nfs_mount_state_error_should_restart(error
)) {
2923 if (error
== ETIMEDOUT
) {
2924 nfs_need_reconnect(nmp
);
2926 tsleep(nfs_recover
, (PZERO
- 1), "nfsrecoverrestart", hz
);
2927 printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2928 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
2931 if (reopen
&& (nfs_check_for_locks(noop
, nofp
) == 0)) {
2932 /* just reopen the file on next access */
2933 NP(nofp
->nof_np
, "nfs_recover: %d, need reopen for %d %p 0x%x", reopen
,
2934 kauth_cred_getuid(noop
->noo_cred
), nofp
->nof_np
, nofp
->nof_np
->n_flag
);
2935 lck_mtx_lock(&nofp
->nof_lock
);
2936 nofp
->nof_flags
|= NFS_OPEN_FILE_REOPEN
;
2937 lck_mtx_unlock(&nofp
->nof_lock
);
2939 /* open file state lost */
2941 NP(nofp
->nof_np
, "nfs_recover: %d, can't reopen because of locks %d %p", reopen
,
2942 kauth_cred_getuid(noop
->noo_cred
), nofp
->nof_np
);
2949 /* no error, so make sure the reopen flag isn't set */
2950 lck_mtx_lock(&nofp
->nof_lock
);
2951 nofp
->nof_flags
&= ~NFS_OPEN_FILE_REOPEN
;
2952 lck_mtx_unlock(&nofp
->nof_lock
);
2954 #endif /* CONFIG_NFS4 */
2956 * Scan this node's lock owner list for entries with this open owner,
2957 * then walk the lock owner's held lock list recovering each lock.
2960 TAILQ_FOREACH(nlop
, &nofp
->nof_np
->n_lock_owners
, nlo_link
) {
2961 if (lost
|| reopen
) {
2964 if (nlop
->nlo_open_owner
!= noop
) {
2967 TAILQ_FOREACH_SAFE(nflp
, &nlop
->nlo_locks
, nfl_lolink
, nextnflp
) {
2968 /* skip dead & blocked lock requests (shouldn't be any in the held lock list) */
2969 if (nflp
->nfl_flags
& (NFS_FILE_LOCK_DEAD
| NFS_FILE_LOCK_BLOCKED
)) {
2972 /* skip delegated locks */
2973 if (nflp
->nfl_flags
& NFS_FILE_LOCK_DELEGATED
) {
2976 error
= nmp
->nm_funcs
->nf_setlock_rpc(nofp
->nof_np
, nofp
, nflp
, 1, R_RECOVER
, thd
, noop
->noo_cred
);
2978 NP(nofp
->nof_np
, "nfs: lock reclaim (0x%llx, 0x%llx) %s %d",
2979 nflp
->nfl_start
, nflp
->nfl_end
,
2980 error
? "failed" : "succeeded", error
);
2985 /* restart recovery? */
2986 if ((error
== ETIMEDOUT
) || nfs_mount_state_error_should_restart(error
)) {
2987 if (error
== ETIMEDOUT
) {
2988 nfs_need_reconnect(nmp
);
2990 tsleep(nfs_recover
, (PZERO
- 1), "nfsrecoverrestart", hz
);
2991 printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2992 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
2995 /* lock state lost - attempt to close file */
3003 * If we've determined that we need to reopen the file then we probably
3004 * didn't receive any delegation we think we hold. We should attempt to
3005 * return that delegation (and claim any delegated state).
3007 * If we hold a delegation that is marked for return, then we should
3010 if ((nofp
->nof_np
->n_openflags
& N_DELEG_RETURN
) ||
3011 (reopen
&& (nofp
->nof_np
->n_openflags
& N_DELEG_MASK
))) {
3012 nfs4_delegation_return(nofp
->nof_np
, R_RECOVER
, thd
, noop
->noo_cred
);
3013 if (!(nmp
->nm_sockflags
& NMSOCK_READY
)) {
3014 /* looks like we need a reconnect */
3015 tsleep(nfs_recover
, (PZERO
- 1), "nfsrecoverrestart", hz
);
3016 printf("nfs recovery restarting for %s, 0x%x, error %d\n",
3017 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
3023 /* revoke open file state */
3024 NP(nofp
->nof_np
, "nfs_recover: state lost for %d %p 0x%x",
3025 kauth_cred_getuid(noop
->noo_cred
), nofp
->nof_np
, nofp
->nof_np
->n_flag
);
3026 nfs_revoke_open_state_for_node(nofp
->nof_np
);
3032 /* If state expired, make sure we're not holding onto any stale delegations */
3033 lck_mtx_lock(&nmp
->nm_lock
);
3035 if ((nmp
->nm_vers
>= NFS_VER4
) && (nmp
->nm_state
& NFSSTA_RECOVER_EXPIRED
)) {
3037 TAILQ_FOREACH_SAFE(np
, &nmp
->nm_delegations
, n_dlink
, nextnp
) {
3038 lck_mtx_unlock(&nmp
->nm_lock
);
3039 nfs4_expired_check_delegation(np
, vfs_context_kernel());
3040 lck_mtx_lock(&nmp
->nm_lock
);
3041 if (nextnp
== NFSNOLIST
) {
3047 nmp
->nm_state
&= ~(NFSSTA_RECOVER
| NFSSTA_RECOVER_EXPIRED
);
3048 wakeup(&nmp
->nm_state
);
3049 printf("nfs recovery completed for %s, 0x%x\n",
3050 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
3051 lck_mtx_unlock(&nmp
->nm_lock
);
3053 printf("nfs recovery failed for %s, 0x%x, error %d\n",
3054 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
3058 #endif /* CONFIG_NFS_CLIENT */