2 * Copyright (c) 2006-2011 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@
30 * miscellaneous support functions for NFSv4
32 #include <sys/param.h>
34 #include <sys/kauth.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/mount_internal.h>
38 #include <sys/vnode_internal.h>
39 #include <sys/kpi_mbuf.h>
40 #include <sys/socket.h>
42 #include <sys/malloc.h>
43 #include <sys/syscall.h>
44 #include <sys/ubc_internal.h>
45 #include <sys/fcntl.h>
46 #include <sys/quota.h>
47 #include <sys/domain.h>
48 #include <libkern/OSAtomic.h>
49 #include <kern/thread_call.h>
52 #include <sys/vmparam.h>
55 #include <kern/clock.h>
57 #include <nfs/rpcv2.h>
58 #include <nfs/nfsproto.h>
60 #include <nfs/nfsnode.h>
61 #include <nfs/xdr_subs.h>
62 #include <nfs/nfsm_subs.h>
63 #include <nfs/nfs_gss.h>
64 #include <nfs/nfsmount.h>
65 #include <nfs/nfs_lock.h>
67 #include <miscfs/specfs/specdev.h>
69 #include <netinet/in.h>
70 #include <net/kpi_interface.h>
74 * Create the unique client ID to use for this mount.
76 * Format: unique ID + en0_address + server_address + mntfromname + mntonname
78 * We could possibly use one client ID for all mounts of the same server;
79 * however, that would complicate some aspects of state management.
81 * Each mount socket connection sends a SETCLIENTID. If the ID is the same but
82 * the verifier (mounttime) changes, then all previous (mounts') state gets dropped.
84 * State is typically managed per-mount and in order to keep it that way
85 * each mount needs to use a separate client ID. However, we also need to
86 * make sure that each mount uses the same client ID each time.
88 * In an attempt to differentiate mounts we include the mntfromname and mntonname
89 * strings to the client ID (as long as they fit). We also make sure that the
90 * value does not conflict with any existing values in use (changing the unique ID).
92 * Note that info such as the server's address may change over the lifetime of the
93 * mount. But the client ID will not be updated because we don't want it changing
94 * simply because we switched to a different server address.
97 nfs4_init_clientid(struct nfsmount
*nmp
)
99 struct nfs_client_id
*ncip
, *ncip2
;
100 struct sockaddr
*saddr
;
101 int error
, len
, len2
, cmp
;
102 struct vfsstatfs
*vsfs
;
104 static uint8_t en0addr
[6];
105 static uint8_t en0addr_set
= 0;
107 lck_mtx_lock(nfs_global_mutex
);
109 ifnet_t interface
= NULL
;
110 error
= ifnet_find_by_name("en0", &interface
);
112 error
= ifnet_lladdr_copy_bytes(interface
, en0addr
, sizeof(en0addr
));
114 printf("nfs4_init_clientid: error getting en0 address, %d\n", error
);
118 ifnet_release(interface
);
120 lck_mtx_unlock(nfs_global_mutex
);
122 MALLOC(ncip
, struct nfs_client_id
*, sizeof(struct nfs_client_id
), M_TEMP
, M_WAITOK
);
126 vsfs
= vfs_statfs(nmp
->nm_mountp
);
127 saddr
= nmp
->nm_saddr
;
128 ncip
->nci_idlen
= sizeof(uint32_t) + sizeof(en0addr
) + saddr
->sa_len
+
129 strlen(vsfs
->f_mntfromname
) + 1 + strlen(vsfs
->f_mntonname
) + 1;
130 if (ncip
->nci_idlen
> NFS4_OPAQUE_LIMIT
)
131 ncip
->nci_idlen
= NFS4_OPAQUE_LIMIT
;
132 MALLOC(ncip
->nci_id
, char *, ncip
->nci_idlen
, M_TEMP
, M_WAITOK
);
138 *(uint32_t*)ncip
->nci_id
= 0;
139 len
= sizeof(uint32_t);
140 len2
= min(sizeof(en0addr
), ncip
->nci_idlen
-len
);
141 bcopy(en0addr
, &ncip
->nci_id
[len
], len2
);
142 len
+= sizeof(en0addr
);
143 len2
= min(saddr
->sa_len
, ncip
->nci_idlen
-len
);
144 bcopy(saddr
, &ncip
->nci_id
[len
], len2
);
146 if (len
< ncip
->nci_idlen
) {
147 len2
= strlcpy(&ncip
->nci_id
[len
], vsfs
->f_mntfromname
, ncip
->nci_idlen
-len
);
148 if (len2
< (ncip
->nci_idlen
- len
))
151 len
= ncip
->nci_idlen
;
153 if (len
< ncip
->nci_idlen
) {
154 len2
= strlcpy(&ncip
->nci_id
[len
], vsfs
->f_mntonname
, ncip
->nci_idlen
-len
);
155 if (len2
< (ncip
->nci_idlen
- len
))
158 len
= ncip
->nci_idlen
;
161 /* make sure the ID is unique, and add it to the sorted list */
162 lck_mtx_lock(nfs_global_mutex
);
163 TAILQ_FOREACH(ncip2
, &nfsclientids
, nci_link
) {
164 if (ncip
->nci_idlen
> ncip2
->nci_idlen
)
166 if (ncip
->nci_idlen
< ncip2
->nci_idlen
)
168 cmp
= bcmp(ncip
->nci_id
+ sizeof(uint32_t),
169 ncip2
->nci_id
+ sizeof(uint32_t),
170 ncip
->nci_idlen
- sizeof(uint32_t));
175 if (*(uint32_t*)ncip
->nci_id
> *(uint32_t*)ncip2
->nci_id
)
177 if (*(uint32_t*)ncip
->nci_id
< *(uint32_t*)ncip2
->nci_id
)
179 *(uint32_t*)ncip
->nci_id
+= 1;
181 if (*(uint32_t*)ncip
->nci_id
)
182 printf("nfs client ID collision (%d) for %s on %s\n", *(uint32_t*)ncip
->nci_id
,
183 vsfs
->f_mntfromname
, vsfs
->f_mntonname
);
185 TAILQ_INSERT_BEFORE(ncip2
, ncip
, nci_link
);
187 TAILQ_INSERT_TAIL(&nfsclientids
, ncip
, nci_link
);
188 nmp
->nm_longid
= ncip
;
189 lck_mtx_unlock(nfs_global_mutex
);
198 nfs4_setclientid(struct nfsmount
*nmp
)
200 uint64_t verifier
, xid
;
201 int error
= 0, status
, numops
;
202 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
205 struct nfsm_chain nmreq
, nmrep
;
206 struct sockaddr_storage ss
;
207 void *sinaddr
= NULL
;
208 char raddr
[MAX_IPv6_STR_LEN
];
209 char uaddr
[MAX_IPv6_STR_LEN
+16];
213 thd
= current_thread();
214 cred
= IS_VALID_CRED(nmp
->nm_mcred
) ? nmp
->nm_mcred
: vfs_context_ucred(vfs_context_kernel());
215 kauth_cred_ref(cred
);
217 nfsm_chain_null(&nmreq
);
218 nfsm_chain_null(&nmrep
);
221 error
= nfs4_init_clientid(nmp
);
225 nfsm_chain_build_alloc_init(error
, &nmreq
, 14 * NFSX_UNSIGNED
+ nmp
->nm_longid
->nci_idlen
);
226 nfsm_chain_add_compound_header(error
, &nmreq
, "setclid", numops
);
228 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SETCLIENTID
);
229 /* nfs_client_id4 client; */
230 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_mounttime
);
231 nfsm_chain_add_32(error
, &nmreq
, nmp
->nm_longid
->nci_idlen
);
232 nfsm_chain_add_opaque(error
, &nmreq
, nmp
->nm_longid
->nci_id
, nmp
->nm_longid
->nci_idlen
);
234 /* cb_client4 callback; */
235 if (!NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
&& nfs4_cb_port
&&
236 !sock_getsockname(nmp
->nm_nso
->nso_so
, (struct sockaddr
*)&ss
, sizeof(ss
))) {
237 if (ss
.ss_family
== AF_INET
) {
238 sinaddr
= &((struct sockaddr_in
*)&ss
)->sin_addr
;
240 } else if (ss
.ss_family
== AF_INET6
) {
241 sinaddr
= &((struct sockaddr_in6
*)&ss
)->sin6_addr
;
242 port
= nfs4_cb_port6
;
244 if (sinaddr
&& port
&& (inet_ntop(ss
.ss_family
, sinaddr
, raddr
, sizeof(raddr
)) == raddr
)) {
245 /* assemble r_addr = universal address (nmp->nm_nso->nso_so source IP addr + port) */
246 ualen
= snprintf(uaddr
, sizeof(uaddr
), "%s.%d.%d", raddr
,
247 ((port
>> 8) & 0xff),
249 /* make sure it fit, give up if it didn't */
250 if (ualen
>= (int)sizeof(uaddr
))
255 /* add callback info */
256 nfsm_chain_add_32(error
, &nmreq
, NFS4_CALLBACK_PROG
); /* callback program */
257 if (ss
.ss_family
== AF_INET
)
258 nfsm_chain_add_string(error
, &nmreq
, "tcp", 3); /* callback r_netid */
259 else if (ss
.ss_family
== AF_INET6
)
260 nfsm_chain_add_string(error
, &nmreq
, "tcp6", 4); /* callback r_netid */
261 nfsm_chain_add_string(error
, &nmreq
, uaddr
, ualen
); /* callback r_addr */
262 nfsm_chain_add_32(error
, &nmreq
, nmp
->nm_cbid
); /* callback_ident */
264 /* don't provide valid callback info */
265 nfsm_chain_add_32(error
, &nmreq
, 0); /* callback program */
266 nfsm_chain_add_string(error
, &nmreq
, "", 0); /* callback r_netid */
267 nfsm_chain_add_string(error
, &nmreq
, "", 0); /* callback r_addr */
268 nfsm_chain_add_32(error
, &nmreq
, 0); /* callback_ident */
270 nfsm_chain_build_done(error
, &nmreq
);
271 nfsm_assert(error
, (numops
== 0), EPROTO
);
273 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, NULL
, R_SETUP
, &nmrep
, &xid
, &status
);
274 nfsm_chain_skip_tag(error
, &nmrep
);
275 nfsm_chain_get_32(error
, &nmrep
, numops
);
276 if (!error
&& (numops
!= 1) && status
)
278 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SETCLIENTID
);
279 if (error
== NFSERR_CLID_INUSE
)
280 printf("nfs4_setclientid: client ID in use?\n");
282 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_clientid
);
283 nfsm_chain_get_64(error
, &nmrep
, verifier
);
284 nfsm_chain_cleanup(&nmreq
);
285 nfsm_chain_cleanup(&nmrep
);
287 // SETCLIENTID_CONFIRM
289 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
290 nfsm_chain_add_compound_header(error
, &nmreq
, "setclid_conf", numops
);
292 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SETCLIENTID_CONFIRM
);
293 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_clientid
);
294 nfsm_chain_add_64(error
, &nmreq
, verifier
);
295 nfsm_chain_build_done(error
, &nmreq
);
296 nfsm_assert(error
, (numops
== 0), EPROTO
);
298 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, NULL
, R_SETUP
, &nmrep
, &xid
, &status
);
299 nfsm_chain_skip_tag(error
, &nmrep
);
300 nfsm_chain_get_32(error
, &nmrep
, numops
);
301 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SETCLIENTID_CONFIRM
);
303 printf("nfs4_setclientid: confirm error %d\n", error
);
304 lck_mtx_lock(&nmp
->nm_lock
);
306 nmp
->nm_state
|= NFSSTA_CLIENTID
;
307 lck_mtx_unlock(&nmp
->nm_lock
);
309 nfsmout_if(error
|| !nmp
->nm_dnp
);
311 /* take the opportunity to refresh fs attributes too */
312 // PUTFH, GETATTR(FS)
314 nfsm_chain_build_alloc_init(error
, &nmreq
, 23 * NFSX_UNSIGNED
);
315 nfsm_chain_add_compound_header(error
, &nmreq
, "setclid_attr", numops
);
317 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
318 nfsm_chain_add_fh(error
, &nmreq
, nmp
->nm_vers
, nmp
->nm_dnp
->n_fhp
, nmp
->nm_dnp
->n_fhsize
);
320 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
321 NFS_CLEAR_ATTRIBUTES(bitmap
);
322 NFS4_PER_FS_ATTRIBUTES(bitmap
);
323 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
324 nfsm_chain_build_done(error
, &nmreq
);
325 nfsm_assert(error
, (numops
== 0), EPROTO
);
327 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, NULL
, R_SETUP
, &nmrep
, &xid
, &status
);
328 nfsm_chain_skip_tag(error
, &nmrep
);
329 nfsm_chain_get_32(error
, &nmrep
, numops
);
330 lck_mtx_lock(&nmp
->nm_lock
);
331 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
332 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
334 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, NULL
, NULL
, NULL
, NULL
);
335 lck_mtx_unlock(&nmp
->nm_lock
);
336 if (error
) /* ignore any error from the getattr */
339 nfsm_chain_cleanup(&nmreq
);
340 nfsm_chain_cleanup(&nmrep
);
341 kauth_cred_unref(&cred
);
343 printf("nfs4_setclientid failed, %d\n", error
);
348 * renew/check lease state on server
351 nfs4_renew(struct nfsmount
*nmp
, int rpcflag
)
353 int error
= 0, status
, numops
;
355 struct nfsm_chain nmreq
, nmrep
;
358 cred
= IS_VALID_CRED(nmp
->nm_mcred
) ? nmp
->nm_mcred
: vfs_context_ucred(vfs_context_kernel());
359 kauth_cred_ref(cred
);
361 nfsm_chain_null(&nmreq
);
362 nfsm_chain_null(&nmrep
);
366 nfsm_chain_build_alloc_init(error
, &nmreq
, 8 * NFSX_UNSIGNED
);
367 nfsm_chain_add_compound_header(error
, &nmreq
, "renew", numops
);
369 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_RENEW
);
370 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_clientid
);
371 nfsm_chain_build_done(error
, &nmreq
);
372 nfsm_assert(error
, (numops
== 0), EPROTO
);
374 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
375 current_thread(), cred
, NULL
, rpcflag
, &nmrep
, &xid
, &status
);
376 nfsm_chain_skip_tag(error
, &nmrep
);
377 nfsm_chain_get_32(error
, &nmrep
, numops
);
378 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_RENEW
);
380 nfsm_chain_cleanup(&nmreq
);
381 nfsm_chain_cleanup(&nmrep
);
382 kauth_cred_unref(&cred
);
388 * periodic timer to renew lease state on server
391 nfs4_renew_timer(void *param0
, __unused
void *param1
)
393 struct nfsmount
*nmp
= param0
;
395 int error
= 0, interval
;
397 lck_mtx_lock(&nmp
->nm_lock
);
398 clientid
= nmp
->nm_clientid
;
399 if ((nmp
->nm_state
& NFSSTA_RECOVER
) || !(nmp
->nm_sockflags
& NMSOCK_READY
)) {
400 lck_mtx_unlock(&nmp
->nm_lock
);
403 lck_mtx_unlock(&nmp
->nm_lock
);
405 error
= nfs4_renew(nmp
, R_RECOVER
);
407 if (error
== ETIMEDOUT
)
408 nfs_need_reconnect(nmp
);
410 printf("nfs4_renew_timer: error %d\n", error
);
411 lck_mtx_lock(&nmp
->nm_lock
);
412 if (error
&& (error
!= ETIMEDOUT
) &&
413 (nmp
->nm_clientid
== clientid
) && !(nmp
->nm_state
& NFSSTA_RECOVER
)) {
414 printf("nfs4_renew_timer: error %d, initiating recovery\n", error
);
415 nfs_need_recover(nmp
, error
);
418 interval
= nmp
->nm_fsattr
.nfsa_lease
/ (error
? 4 : 2);
419 if ((interval
< 1) || (nmp
->nm_state
& NFSSTA_RECOVER
))
421 lck_mtx_unlock(&nmp
->nm_lock
);
422 nfs_interval_timer_start(nmp
->nm_renew_timer
, interval
* 1000);
426 * get the list of supported security flavors
428 * How we get them depends on what args we are given:
432 * YES YES Use the fh and name provided
433 * YES NO 4.1-only just use the fh provided
434 * NO YES Use the node's (or root) fh and the name provided
435 * NO NO Use the node's parent and the node's name (4.1 will just use node's fh)
438 nfs4_secinfo_rpc(struct nfsmount
*nmp
, struct nfsreq_secinfo_args
*siap
, kauth_cred_t cred
, uint32_t *sec
, int *seccountp
)
440 int error
= 0, status
, nfsvers
, numops
, namelen
, fhsize
;
441 vnode_t dvp
= NULLVP
;
444 const char *vname
= NULL
, *name
;
446 struct nfsm_chain nmreq
, nmrep
;
451 nfsvers
= nmp
->nm_vers
;
454 nfsm_chain_null(&nmreq
);
455 nfsm_chain_null(&nmrep
);
458 fhsize
= fhp
? siap
->rsia_fhsize
: 0;
459 name
= siap
->rsia_name
;
460 namelen
= name
? siap
->rsia_namelen
: 0;
461 if (name
&& !namelen
)
462 namelen
= strlen(name
);
464 if (!np
) /* use PUTROOTFH */
467 fhsize
= np
->n_fhsize
;
474 nfs_node_lock_force(np
);
475 if ((vnode_vtype(NFSTOV(np
)) != VDIR
) && np
->n_sillyrename
) {
477 * The node's been sillyrenamed, so we need to use
478 * the sillyrename directory/name to do the open.
480 struct nfs_sillyrename
*nsp
= np
->n_sillyrename
;
483 if ((error
= vnode_get(dvp
))) {
488 fhsize
= dnp
->n_fhsize
;
489 name
= nsp
->nsr_name
;
490 namelen
= nsp
->nsr_namlen
;
493 * [sigh] We can't trust VFS to get the parent right for named
494 * attribute nodes. (It likes to reparent the nodes after we've
495 * created them.) Luckily we can probably get the right parent
496 * from the n_parent we have stashed away.
498 if ((np
->n_vattr
.nva_flags
& NFS_FFLAG_IS_ATTR
) &&
499 (((dvp
= np
->n_parent
)) && (error
= vnode_get(dvp
))))
502 dvp
= vnode_getparent(NFSTOV(np
));
503 vname
= vnode_getname(NFSTOV(np
));
504 if (!dvp
|| !vname
) {
512 fhsize
= dnp
->n_fhsize
;
514 namelen
= strnlen(vname
, MAXPATHLEN
);
519 // PUT(ROOT)FH + SECINFO
521 nfsm_chain_build_alloc_init(error
, &nmreq
,
522 4 * NFSX_UNSIGNED
+ NFSX_FH(nfsvers
) + nfsm_rndup(namelen
));
523 nfsm_chain_add_compound_header(error
, &nmreq
, "secinfo", numops
);
526 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
527 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, fhp
, fhsize
);
529 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
532 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SECINFO
);
533 nfsm_chain_add_name(error
, &nmreq
, name
, namelen
, nmp
);
534 nfsm_chain_build_done(error
, &nmreq
);
535 nfsm_assert(error
, (numops
== 0), EPROTO
);
537 error
= nfs_request2(np
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
538 current_thread(), cred
, NULL
, 0, &nmrep
, &xid
, &status
);
539 nfsm_chain_skip_tag(error
, &nmrep
);
540 nfsm_chain_get_32(error
, &nmrep
, numops
);
541 nfsm_chain_op_check(error
, &nmrep
, fhp
? NFS_OP_PUTFH
: NFS_OP_PUTROOTFH
);
542 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SECINFO
);
544 error
= nfsm_chain_get_secinfo(&nmrep
, sec
, seccountp
);
546 nfsm_chain_cleanup(&nmreq
);
547 nfsm_chain_cleanup(&nmrep
);
549 vnode_putname(vname
);
556 * Parse an NFSv4 SECINFO array to an array of pseudo flavors.
557 * (Note: also works for MOUNTv3 security arrays.)
560 nfsm_chain_get_secinfo(struct nfsm_chain
*nmc
, uint32_t *sec
, int *seccountp
)
562 int error
= 0, secmax
, seccount
, srvcount
;
563 uint32_t flavor
, val
;
566 seccount
= srvcount
= 0;
570 nfsm_chain_get_32(error
, nmc
, srvcount
);
571 while (!error
&& (srvcount
> 0) && (seccount
< secmax
)) {
572 nfsm_chain_get_32(error
, nmc
, flavor
);
580 sec
[seccount
++] = flavor
;
583 /* we only recognize KRB5, KRB5I, KRB5P */
584 nfsm_chain_get_32(error
, nmc
, val
); /* OID length */
586 if (val
!= sizeof(krb5_mech
)) {
587 nfsm_chain_adv(error
, nmc
, val
);
588 nfsm_chain_adv(error
, nmc
, 2*NFSX_UNSIGNED
);
591 nfsm_chain_get_opaque(error
, nmc
, val
, oid
); /* OID bytes */
593 if (bcmp(oid
, krb5_mech
, sizeof(krb5_mech
))) {
594 nfsm_chain_adv(error
, nmc
, 2*NFSX_UNSIGNED
);
597 nfsm_chain_get_32(error
, nmc
, val
); /* QOP */
598 nfsm_chain_get_32(error
, nmc
, val
); /* SERVICE */
601 case RPCSEC_GSS_SVC_NONE
:
602 sec
[seccount
++] = RPCAUTH_KRB5
;
604 case RPCSEC_GSS_SVC_INTEGRITY
:
605 sec
[seccount
++] = RPCAUTH_KRB5I
;
607 case RPCSEC_GSS_SVC_PRIVACY
:
608 sec
[seccount
++] = RPCAUTH_KRB5P
;
617 *seccountp
= seccount
;
623 * Fetch the FS_LOCATIONS attribute for the node found at directory/name.
626 nfs4_get_fs_locations(
627 struct nfsmount
*nmp
,
633 struct nfs_fs_locations
*nfslsp
)
635 int error
= 0, numops
, status
;
636 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
637 struct nfsreq rq
, *req
= &rq
;
638 struct nfsreq_secinfo_args si
;
639 struct nfsm_chain nmreq
, nmrep
;
644 fhsize
= dnp
->n_fhsize
;
649 nfsm_chain_null(&nmreq
);
650 nfsm_chain_null(&nmrep
);
652 NFSREQ_SECINFO_SET(&si
, NULL
, fhp
, fhsize
, name
, 0);
654 nfsm_chain_build_alloc_init(error
, &nmreq
, 18 * NFSX_UNSIGNED
);
655 nfsm_chain_add_compound_header(error
, &nmreq
, "fs_locations", numops
);
657 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
658 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, fhp
, fhsize
);
660 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUP
);
661 nfsm_chain_add_name(error
, &nmreq
, name
, strlen(name
), nmp
);
663 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
664 NFS_CLEAR_ATTRIBUTES(bitmap
);
665 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FS_LOCATIONS
);
666 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
667 nfsm_chain_build_done(error
, &nmreq
);
668 nfsm_assert(error
, (numops
== 0), EPROTO
);
670 error
= nfs_request_async(dnp
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
671 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
673 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
674 nfsm_chain_skip_tag(error
, &nmrep
);
675 nfsm_chain_get_32(error
, &nmrep
, numops
);
676 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
677 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_LOOKUP
);
678 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
680 error
= nfs4_parsefattr(&nmrep
, NULL
, NULL
, NULL
, NULL
, nfslsp
);
682 nfsm_chain_cleanup(&nmrep
);
683 nfsm_chain_cleanup(&nmreq
);
688 * Referral trigger nodes may not have many attributes provided by the
689 * server, so put some default values in place.
692 nfs4_default_attrs_for_referral_trigger(
696 struct nfs_vattr
*nvap
,
703 nvap
->nva_flags
= NFS_FFLAG_TRIGGER
| NFS_FFLAG_TRIGGER_REFERRAL
;
704 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TYPE
)) {
705 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TYPE
);
706 nvap
->nva_type
= VDIR
;
708 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FSID
)) {
709 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_FSID
);
710 nvap
->nva_fsid
.major
= 0;
711 nvap
->nva_fsid
.minor
= 0;
713 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_OWNER
) && dnp
) {
714 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_OWNER
);
715 nvap
->nva_uid
= dnp
->n_vattr
.nva_uid
;
716 nvap
->nva_uuuid
= dnp
->n_vattr
.nva_uuuid
;
718 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_OWNER_GROUP
) && dnp
) {
719 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_OWNER_GROUP
);
720 nvap
->nva_gid
= dnp
->n_vattr
.nva_gid
;
721 nvap
->nva_guuid
= dnp
->n_vattr
.nva_guuid
;
723 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_MODE
)) {
724 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_MODE
);
725 nvap
->nva_mode
= 0777;
727 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_SIZE
)) {
728 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_SIZE
);
731 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_SPACE_USED
)) {
732 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_SPACE_USED
);
735 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_NUMLINKS
)) {
736 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_NUMLINKS
);
739 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TIME_ACCESS
)) {
740 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TIME_ACCESS
);
741 nvap
->nva_timesec
[NFSTIME_ACCESS
] = now
.tv_sec
;
742 nvap
->nva_timensec
[NFSTIME_ACCESS
] = now
.tv_usec
* 1000;
744 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TIME_MODIFY
)) {
745 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TIME_MODIFY
);
746 nvap
->nva_timesec
[NFSTIME_MODIFY
] = now
.tv_sec
;
747 nvap
->nva_timensec
[NFSTIME_MODIFY
] = now
.tv_usec
* 1000;
749 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TIME_METADATA
)) {
750 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TIME_METADATA
);
751 nvap
->nva_timesec
[NFSTIME_CHANGE
] = now
.tv_sec
;
752 nvap
->nva_timensec
[NFSTIME_CHANGE
] = now
.tv_usec
* 1000;
754 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FILEID
)) {
755 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_FILEID
);
756 nvap
->nva_fileid
= 42;
758 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FILEHANDLE
) && dnp
&& name
&& fhp
) {
759 /* Build a fake filehandle made up of parent node pointer and name */
760 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_FILEHANDLE
);
761 bcopy(&dnp
, &fhp
->fh_data
[0], sizeof(dnp
));
762 len
= sizeof(fhp
->fh_data
) - sizeof(dnp
);
763 bcopy(name
, &fhp
->fh_data
[0] + sizeof(dnp
), MIN(len
, namelen
));
764 fhp
->fh_len
= sizeof(dnp
) + namelen
;
765 if (fhp
->fh_len
> (int)sizeof(fhp
->fh_data
))
766 fhp
->fh_len
= sizeof(fhp
->fh_data
);
771 * Set NFS bitmap according to what's set in vnode_attr (and supported by the server).
774 nfs_vattr_set_bitmap(struct nfsmount
*nmp
, uint32_t *bitmap
, struct vnode_attr
*vap
)
778 NFS_CLEAR_ATTRIBUTES(bitmap
);
779 if (VATTR_IS_ACTIVE(vap
, va_data_size
))
780 NFS_BITMAP_SET(bitmap
, NFS_FATTR_SIZE
);
781 if (VATTR_IS_ACTIVE(vap
, va_acl
) && (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
))
782 NFS_BITMAP_SET(bitmap
, NFS_FATTR_ACL
);
783 if (VATTR_IS_ACTIVE(vap
, va_flags
)) {
784 NFS_BITMAP_SET(bitmap
, NFS_FATTR_ARCHIVE
);
785 NFS_BITMAP_SET(bitmap
, NFS_FATTR_HIDDEN
);
787 // NFS_BITMAP_SET(bitmap, NFS_FATTR_MIMETYPE)
788 if (VATTR_IS_ACTIVE(vap
, va_mode
) && !NMFLAG(nmp
, ACLONLY
))
789 NFS_BITMAP_SET(bitmap
, NFS_FATTR_MODE
);
790 if (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_uuuid
))
791 NFS_BITMAP_SET(bitmap
, NFS_FATTR_OWNER
);
792 if (VATTR_IS_ACTIVE(vap
, va_gid
) || VATTR_IS_ACTIVE(vap
, va_guuid
))
793 NFS_BITMAP_SET(bitmap
, NFS_FATTR_OWNER_GROUP
);
794 // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
795 if (vap
->va_vaflags
& VA_UTIMES_NULL
) {
796 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
);
797 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
);
799 if (VATTR_IS_ACTIVE(vap
, va_access_time
))
800 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
);
801 if (VATTR_IS_ACTIVE(vap
, va_modify_time
))
802 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
);
804 if (VATTR_IS_ACTIVE(vap
, va_backup_time
))
805 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_BACKUP
);
806 if (VATTR_IS_ACTIVE(vap
, va_create_time
))
807 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_CREATE
);
808 /* and limit to what is supported by server */
809 for (i
=0; i
< NFS_ATTR_BITMAP_LEN
; i
++)
810 bitmap
[i
] &= nmp
->nm_fsattr
.nfsa_supp_attr
[i
];
814 * Convert between NFSv4 and VFS ACE types
817 nfs4_ace_nfstype_to_vfstype(uint32_t nfsacetype
, int *errorp
)
819 switch (nfsacetype
) {
820 case NFS_ACE_ACCESS_ALLOWED_ACE_TYPE
:
821 return KAUTH_ACE_PERMIT
;
822 case NFS_ACE_ACCESS_DENIED_ACE_TYPE
:
823 return KAUTH_ACE_DENY
;
824 case NFS_ACE_SYSTEM_AUDIT_ACE_TYPE
:
825 return KAUTH_ACE_AUDIT
;
826 case NFS_ACE_SYSTEM_ALARM_ACE_TYPE
:
827 return KAUTH_ACE_ALARM
;
834 nfs4_ace_vfstype_to_nfstype(uint32_t vfstype
, int *errorp
)
837 case KAUTH_ACE_PERMIT
:
838 return NFS_ACE_ACCESS_ALLOWED_ACE_TYPE
;
840 return NFS_ACE_ACCESS_DENIED_ACE_TYPE
;
841 case KAUTH_ACE_AUDIT
:
842 return NFS_ACE_SYSTEM_AUDIT_ACE_TYPE
;
843 case KAUTH_ACE_ALARM
:
844 return NFS_ACE_SYSTEM_ALARM_ACE_TYPE
;
851 * Convert between NFSv4 and VFS ACE flags
854 nfs4_ace_nfsflags_to_vfsflags(uint32_t nfsflags
)
856 uint32_t vfsflags
= 0;
858 if (nfsflags
& NFS_ACE_FILE_INHERIT_ACE
)
859 vfsflags
|= KAUTH_ACE_FILE_INHERIT
;
860 if (nfsflags
& NFS_ACE_DIRECTORY_INHERIT_ACE
)
861 vfsflags
|= KAUTH_ACE_DIRECTORY_INHERIT
;
862 if (nfsflags
& NFS_ACE_NO_PROPAGATE_INHERIT_ACE
)
863 vfsflags
|= KAUTH_ACE_LIMIT_INHERIT
;
864 if (nfsflags
& NFS_ACE_INHERIT_ONLY_ACE
)
865 vfsflags
|= KAUTH_ACE_ONLY_INHERIT
;
866 if (nfsflags
& NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG
)
867 vfsflags
|= KAUTH_ACE_SUCCESS
;
868 if (nfsflags
& NFS_ACE_FAILED_ACCESS_ACE_FLAG
)
869 vfsflags
|= KAUTH_ACE_FAILURE
;
870 if (nfsflags
& NFS_ACE_INHERITED_ACE
)
871 vfsflags
|= KAUTH_ACE_INHERITED
;
877 nfs4_ace_vfsflags_to_nfsflags(uint32_t vfsflags
)
879 uint32_t nfsflags
= 0;
881 if (vfsflags
& KAUTH_ACE_FILE_INHERIT
)
882 nfsflags
|= NFS_ACE_FILE_INHERIT_ACE
;
883 if (vfsflags
& KAUTH_ACE_DIRECTORY_INHERIT
)
884 nfsflags
|= NFS_ACE_DIRECTORY_INHERIT_ACE
;
885 if (vfsflags
& KAUTH_ACE_LIMIT_INHERIT
)
886 nfsflags
|= NFS_ACE_NO_PROPAGATE_INHERIT_ACE
;
887 if (vfsflags
& KAUTH_ACE_ONLY_INHERIT
)
888 nfsflags
|= NFS_ACE_INHERIT_ONLY_ACE
;
889 if (vfsflags
& KAUTH_ACE_SUCCESS
)
890 nfsflags
|= NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG
;
891 if (vfsflags
& KAUTH_ACE_FAILURE
)
892 nfsflags
|= NFS_ACE_FAILED_ACCESS_ACE_FLAG
;
893 if (vfsflags
& KAUTH_ACE_INHERITED
)
894 nfsflags
|= NFS_ACE_INHERITED_ACE
;
900 * Convert between NFSv4 ACE access masks and VFS access rights
903 nfs4_ace_nfsmask_to_vfsrights(uint32_t nfsmask
)
905 uint32_t vfsrights
= 0;
907 if (nfsmask
& NFS_ACE_READ_DATA
)
908 vfsrights
|= KAUTH_VNODE_READ_DATA
;
909 if (nfsmask
& NFS_ACE_LIST_DIRECTORY
)
910 vfsrights
|= KAUTH_VNODE_LIST_DIRECTORY
;
911 if (nfsmask
& NFS_ACE_WRITE_DATA
)
912 vfsrights
|= KAUTH_VNODE_WRITE_DATA
;
913 if (nfsmask
& NFS_ACE_ADD_FILE
)
914 vfsrights
|= KAUTH_VNODE_ADD_FILE
;
915 if (nfsmask
& NFS_ACE_APPEND_DATA
)
916 vfsrights
|= KAUTH_VNODE_APPEND_DATA
;
917 if (nfsmask
& NFS_ACE_ADD_SUBDIRECTORY
)
918 vfsrights
|= KAUTH_VNODE_ADD_SUBDIRECTORY
;
919 if (nfsmask
& NFS_ACE_READ_NAMED_ATTRS
)
920 vfsrights
|= KAUTH_VNODE_READ_EXTATTRIBUTES
;
921 if (nfsmask
& NFS_ACE_WRITE_NAMED_ATTRS
)
922 vfsrights
|= KAUTH_VNODE_WRITE_EXTATTRIBUTES
;
923 if (nfsmask
& NFS_ACE_EXECUTE
)
924 vfsrights
|= KAUTH_VNODE_EXECUTE
;
925 if (nfsmask
& NFS_ACE_DELETE_CHILD
)
926 vfsrights
|= KAUTH_VNODE_DELETE_CHILD
;
927 if (nfsmask
& NFS_ACE_READ_ATTRIBUTES
)
928 vfsrights
|= KAUTH_VNODE_READ_ATTRIBUTES
;
929 if (nfsmask
& NFS_ACE_WRITE_ATTRIBUTES
)
930 vfsrights
|= KAUTH_VNODE_WRITE_ATTRIBUTES
;
931 if (nfsmask
& NFS_ACE_DELETE
)
932 vfsrights
|= KAUTH_VNODE_DELETE
;
933 if (nfsmask
& NFS_ACE_READ_ACL
)
934 vfsrights
|= KAUTH_VNODE_READ_SECURITY
;
935 if (nfsmask
& NFS_ACE_WRITE_ACL
)
936 vfsrights
|= KAUTH_VNODE_WRITE_SECURITY
;
937 if (nfsmask
& NFS_ACE_WRITE_OWNER
)
938 vfsrights
|= KAUTH_VNODE_CHANGE_OWNER
;
939 if (nfsmask
& NFS_ACE_SYNCHRONIZE
)
940 vfsrights
|= KAUTH_VNODE_SYNCHRONIZE
;
941 if ((nfsmask
& NFS_ACE_GENERIC_READ
) == NFS_ACE_GENERIC_READ
)
942 vfsrights
|= KAUTH_ACE_GENERIC_READ
;
943 if ((nfsmask
& NFS_ACE_GENERIC_WRITE
) == NFS_ACE_GENERIC_WRITE
)
944 vfsrights
|= KAUTH_ACE_GENERIC_WRITE
;
945 if ((nfsmask
& NFS_ACE_GENERIC_EXECUTE
) == NFS_ACE_GENERIC_EXECUTE
)
946 vfsrights
|= KAUTH_ACE_GENERIC_EXECUTE
;
952 nfs4_ace_vfsrights_to_nfsmask(uint32_t vfsrights
)
954 uint32_t nfsmask
= 0;
956 if (vfsrights
& KAUTH_VNODE_READ_DATA
)
957 nfsmask
|= NFS_ACE_READ_DATA
;
958 if (vfsrights
& KAUTH_VNODE_LIST_DIRECTORY
)
959 nfsmask
|= NFS_ACE_LIST_DIRECTORY
;
960 if (vfsrights
& KAUTH_VNODE_WRITE_DATA
)
961 nfsmask
|= NFS_ACE_WRITE_DATA
;
962 if (vfsrights
& KAUTH_VNODE_ADD_FILE
)
963 nfsmask
|= NFS_ACE_ADD_FILE
;
964 if (vfsrights
& KAUTH_VNODE_APPEND_DATA
)
965 nfsmask
|= NFS_ACE_APPEND_DATA
;
966 if (vfsrights
& KAUTH_VNODE_ADD_SUBDIRECTORY
)
967 nfsmask
|= NFS_ACE_ADD_SUBDIRECTORY
;
968 if (vfsrights
& KAUTH_VNODE_READ_EXTATTRIBUTES
)
969 nfsmask
|= NFS_ACE_READ_NAMED_ATTRS
;
970 if (vfsrights
& KAUTH_VNODE_WRITE_EXTATTRIBUTES
)
971 nfsmask
|= NFS_ACE_WRITE_NAMED_ATTRS
;
972 if (vfsrights
& KAUTH_VNODE_EXECUTE
)
973 nfsmask
|= NFS_ACE_EXECUTE
;
974 if (vfsrights
& KAUTH_VNODE_DELETE_CHILD
)
975 nfsmask
|= NFS_ACE_DELETE_CHILD
;
976 if (vfsrights
& KAUTH_VNODE_READ_ATTRIBUTES
)
977 nfsmask
|= NFS_ACE_READ_ATTRIBUTES
;
978 if (vfsrights
& KAUTH_VNODE_WRITE_ATTRIBUTES
)
979 nfsmask
|= NFS_ACE_WRITE_ATTRIBUTES
;
980 if (vfsrights
& KAUTH_VNODE_DELETE
)
981 nfsmask
|= NFS_ACE_DELETE
;
982 if (vfsrights
& KAUTH_VNODE_READ_SECURITY
)
983 nfsmask
|= NFS_ACE_READ_ACL
;
984 if (vfsrights
& KAUTH_VNODE_WRITE_SECURITY
)
985 nfsmask
|= NFS_ACE_WRITE_ACL
;
986 if (vfsrights
& KAUTH_VNODE_CHANGE_OWNER
)
987 nfsmask
|= NFS_ACE_WRITE_OWNER
;
988 if (vfsrights
& KAUTH_VNODE_SYNCHRONIZE
)
989 nfsmask
|= NFS_ACE_SYNCHRONIZE
;
990 if (vfsrights
& KAUTH_ACE_GENERIC_READ
)
991 nfsmask
|= NFS_ACE_GENERIC_READ
;
992 if (vfsrights
& KAUTH_ACE_GENERIC_WRITE
)
993 nfsmask
|= NFS_ACE_GENERIC_WRITE
;
994 if (vfsrights
& KAUTH_ACE_GENERIC_EXECUTE
)
995 nfsmask
|= NFS_ACE_GENERIC_EXECUTE
;
996 if (vfsrights
& KAUTH_ACE_GENERIC_ALL
)
997 nfsmask
|= (KAUTH_ACE_GENERIC_READ
|KAUTH_ACE_GENERIC_WRITE
|NFS_ACE_GENERIC_EXECUTE
);
1003 * Map an NFSv4 ID string to a VFS guid.
1005 * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
1008 nfs4_id2guid(/*const*/ char *id
, guid_t
*guidp
, int isgroup
)
1010 int error1
= 0, error
= 0, compare
;
1011 guid_t guid1
, guid2
, *gp
;
1016 *guidp
= kauth_null_guid
;
1017 compare
= ((nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) &&
1018 (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_COMPARE_RESULTS
));
1019 unknown
= (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_UNKNOWN_IS_99
) ? 99 : -2;
1022 * First check if it is just a simple numeric ID string or a special "XXX@" name.
1023 * If it's a number, there's no need trying to ask the IDMAP service to map it.
1024 * If it's a special "XXX@" name, we want to make sure to treat it as a group.
1030 if ((*p
< '0') || (*p
> '9'))
1036 if (at
&& !at
[1] && !isgroup
)
1037 isgroup
= 1; /* special "XXX@" names should always be treated as groups */
1039 /* must be numeric ID (or empty) */
1040 num
= *id
? strtol(id
, NULL
, 10) : unknown
;
1045 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) {
1047 * Ask the ID mapping service to map the ID string to a GUID.
1049 * [sigh] this isn't a "pwnam/grnam" it's an NFS ID string!
1051 gp
= compare
? &guid1
: guidp
;
1053 error
= kauth_cred_grnam2guid(id
, gp
);
1055 error
= kauth_cred_pwnam2guid(id
, gp
);
1056 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1057 printf("nfs4_id2guid: idmap failed for %s %s error %d\n", id
, isgroup
? "G" : " ", error
);
1058 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
))
1059 printf("nfs4_id2guid: idmap for %s %s got guid "
1060 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1061 id
, isgroup
? "G" : " ",
1062 gp
->g_guid
[0], gp
->g_guid
[1], gp
->g_guid
[2], gp
->g_guid
[3],
1063 gp
->g_guid
[4], gp
->g_guid
[5], gp
->g_guid
[6], gp
->g_guid
[7],
1064 gp
->g_guid
[8], gp
->g_guid
[9], gp
->g_guid
[10], gp
->g_guid
[11],
1065 gp
->g_guid
[12], gp
->g_guid
[13], gp
->g_guid
[14], gp
->g_guid
[15]);
1068 if (error
|| compare
|| !(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
)) {
1070 * fallback path... see if we can come up with an answer ourselves.
1072 gp
= compare
? &guid2
: guidp
;
1074 if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_WELLKNOWN_IDS
) && at
&& !at
[1]) {
1075 /* must be a special ACE "who" ID */
1076 bzero(&sid
, sizeof(sid
));
1078 sid
.sid_authcount
= 1;
1079 if (!strcmp(id
, "OWNER@")) {
1081 sid
.sid_authority
[5] = 3;
1082 sid
.sid_authorities
[0] = 0;
1083 } else if (!strcmp(id
, "GROUP@")) {
1085 sid
.sid_authority
[5] = 3;
1086 sid
.sid_authorities
[0] = 1;
1087 } else if (!strcmp(id
, "EVERYONE@")) {
1089 sid
.sid_authority
[5] = 1;
1090 sid
.sid_authorities
[0] = 0;
1091 } else if (!strcmp(id
, "INTERACTIVE@")) {
1093 sid
.sid_authority
[5] = 5;
1094 sid
.sid_authorities
[0] = 4;
1095 } else if (!strcmp(id
, "NETWORK@")) {
1097 sid
.sid_authority
[5] = 5;
1098 sid
.sid_authorities
[0] = 2;
1099 } else if (!strcmp(id
, "DIALUP@")) {
1101 sid
.sid_authority
[5] = 5;
1102 sid
.sid_authorities
[0] = 1;
1103 } else if (!strcmp(id
, "BATCH@")) {
1105 sid
.sid_authority
[5] = 5;
1106 sid
.sid_authorities
[0] = 3;
1107 } else if (!strcmp(id
, "ANONYMOUS@")) {
1109 sid
.sid_authority
[5] = 5;
1110 sid
.sid_authorities
[0] = 7;
1111 } else if (!strcmp(id
, "AUTHENTICATED@")) {
1113 sid
.sid_authority
[5] = 5;
1114 sid
.sid_authorities
[0] = 11;
1115 } else if (!strcmp(id
, "SERVICE@")) {
1117 sid
.sid_authority
[5] = 5;
1118 sid
.sid_authorities
[0] = 6;
1121 sid
.sid_authority
[5] = 0;
1122 sid
.sid_authorities
[0] = 0;
1124 error
= kauth_cred_ntsid2guid(&sid
, gp
);
1126 if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS
) && at
) {
1127 /* must be user@domain */
1128 /* try to identify some well-known IDs */
1129 if (!strncmp(id
, "root@", 5))
1131 else if (!strncmp(id
, "wheel@", 6))
1133 else if (!strncmp(id
, "nobody@", 7))
1135 else if (!strncmp(id
, "nfsnobody@", 10))
1139 } else if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS
) && !strcmp(id
, "nobody")) {
1146 error
= kauth_cred_gid2guid((gid_t
)num
, gp
);
1148 error
= kauth_cred_uid2guid((uid_t
)num
, gp
);
1150 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1151 printf("nfs4_id2guid: fallback map failed for %s %s error %d\n", id
, isgroup
? "G" : " ", error
);
1152 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
))
1153 printf("nfs4_id2guid: fallback map for %s %s got guid "
1154 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1155 id
, isgroup
? "G" : " ",
1156 gp
->g_guid
[0], gp
->g_guid
[1], gp
->g_guid
[2], gp
->g_guid
[3],
1157 gp
->g_guid
[4], gp
->g_guid
[5], gp
->g_guid
[6], gp
->g_guid
[7],
1158 gp
->g_guid
[8], gp
->g_guid
[9], gp
->g_guid
[10], gp
->g_guid
[11],
1159 gp
->g_guid
[12], gp
->g_guid
[13], gp
->g_guid
[14], gp
->g_guid
[15]);
1163 /* compare the results, log if different */
1164 if (!error1
&& !error
) {
1165 if (!kauth_guid_equal(&guid1
, &guid2
))
1166 printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1167 "idmap %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x "
1168 "fallback %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1169 id
, isgroup
? "G" : " ",
1170 guid1
.g_guid
[0], guid1
.g_guid
[1], guid1
.g_guid
[2], guid1
.g_guid
[3],
1171 guid1
.g_guid
[4], guid1
.g_guid
[5], guid1
.g_guid
[6], guid1
.g_guid
[7],
1172 guid1
.g_guid
[8], guid1
.g_guid
[9], guid1
.g_guid
[10], guid1
.g_guid
[11],
1173 guid1
.g_guid
[12], guid1
.g_guid
[13], guid1
.g_guid
[14], guid1
.g_guid
[15],
1174 guid2
.g_guid
[0], guid2
.g_guid
[1], guid2
.g_guid
[2], guid2
.g_guid
[3],
1175 guid2
.g_guid
[4], guid2
.g_guid
[5], guid2
.g_guid
[6], guid2
.g_guid
[7],
1176 guid2
.g_guid
[8], guid2
.g_guid
[9], guid2
.g_guid
[10], guid2
.g_guid
[11],
1177 guid2
.g_guid
[12], guid2
.g_guid
[13], guid2
.g_guid
[14], guid2
.g_guid
[15]);
1178 /* copy idmap result to output guid */
1180 } else if (error1
&& !error
) {
1181 printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1183 "fallback %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1184 id
, isgroup
? "G" : " ",
1186 guid2
.g_guid
[0], guid2
.g_guid
[1], guid2
.g_guid
[2], guid2
.g_guid
[3],
1187 guid2
.g_guid
[4], guid2
.g_guid
[5], guid2
.g_guid
[6], guid2
.g_guid
[7],
1188 guid2
.g_guid
[8], guid2
.g_guid
[9], guid2
.g_guid
[10], guid2
.g_guid
[11],
1189 guid2
.g_guid
[12], guid2
.g_guid
[13], guid2
.g_guid
[14], guid2
.g_guid
[15]);
1190 /* copy fallback result to output guid */
1192 } else if (!error1
&& error
) {
1193 printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1194 "idmap %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x "
1195 "fallback error %d\n",
1196 id
, isgroup
? "G" : " ",
1197 guid1
.g_guid
[0], guid1
.g_guid
[1], guid1
.g_guid
[2], guid1
.g_guid
[3],
1198 guid1
.g_guid
[4], guid1
.g_guid
[5], guid1
.g_guid
[6], guid1
.g_guid
[7],
1199 guid1
.g_guid
[8], guid1
.g_guid
[9], guid1
.g_guid
[10], guid1
.g_guid
[11],
1200 guid1
.g_guid
[12], guid1
.g_guid
[13], guid1
.g_guid
[14], guid1
.g_guid
[15],
1202 /* copy idmap result to output guid */
1206 if (error1
!= error
)
1207 printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1208 "idmap error %d fallback error %d\n",
1209 id
, isgroup
? "G" : " ", error1
, error
);
1217 * Map a VFS guid to an NFSv4 ID string.
1219 * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
1222 nfs4_guid2id(guid_t
*guidp
, char *id
, int *idlen
, int isgroup
)
1224 int error1
= 0, error
= 0, compare
;
1225 int id1len
, id2len
, len
;
1228 const char *id2
= NULL
;
1230 id1buf
= id1
= NULL
;
1231 id1len
= id2len
= 0;
1232 compare
= ((nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) &&
1233 (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_COMPARE_RESULTS
));
1235 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) {
1237 * Ask the ID mapping service to map the GUID to an ID string.
1239 * [sigh] this isn't a "pwnam" it's an NFS id string!
1243 * Stupid kauth_cred_guid2pwnam() function requires that the buffer
1244 * be at least MAXPATHLEN bytes long even though most if not all ID
1245 * strings will be much much shorter than that.
1247 if (compare
|| (*idlen
< MAXPATHLEN
)) {
1248 MALLOC_ZONE(id1buf
, char*, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1252 id1len
= MAXPATHLEN
;
1259 error
= kauth_cred_guid2grnam(guidp
, id1
);
1261 error
= kauth_cred_guid2pwnam(guidp
, id1
);
1262 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1263 printf("nfs4_guid2id: idmap failed for "
1264 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1266 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1267 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1268 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1269 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1270 isgroup
? "G" : " ", error
);
1271 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
))
1272 printf("nfs4_guid2id: idmap for "
1273 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1275 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1276 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1277 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1278 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1279 isgroup
? "G" : " ", id1
);
1283 id1len
= strnlen(id1
, id1len
);
1284 } else if (id1
== id1buf
) {
1285 /* copy idmap result to output buffer */
1286 len
= strlcpy(id
, id1
, *idlen
);
1294 if (error
|| compare
|| !(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
)) {
1296 * fallback path... see if we can come up with an answer ourselves.
1301 if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_WELLKNOWN_IDS
)) {
1302 error
= kauth_cred_guid2ntsid(guidp
, &sid
);
1303 if (!error
&& (sid
.sid_kind
== 1) && (sid
.sid_authcount
== 1)) {
1304 /* check if it's one of our well-known ACE WHO names */
1305 if (sid
.sid_authority
[5] == 0) {
1306 if (sid
.sid_authorities
[0] == 0) // S-1-0-0
1307 id2
= "nobody@localdomain";
1308 } else if (sid
.sid_authority
[5] == 1) {
1309 if (sid
.sid_authorities
[0] == 0) // S-1-1-0
1311 } else if (sid
.sid_authority
[5] == 3) {
1312 if (sid
.sid_authorities
[0] == 0) // S-1-3-0
1314 else if (sid
.sid_authorities
[0] == 1) // S-1-3-1
1316 } else if (sid
.sid_authority
[5] == 5) {
1317 if (sid
.sid_authorities
[0] == ntohl(1)) // S-1-5-1
1319 else if (sid
.sid_authorities
[0] == ntohl(2)) // S-1-5-2
1321 else if (sid
.sid_authorities
[0] == ntohl(3)) // S-1-5-3
1323 else if (sid
.sid_authorities
[0] == ntohl(4)) // S-1-5-4
1324 id2
= "INTERACTIVE@";
1325 else if (sid
.sid_authorities
[0] == ntohl(6)) // S-1-5-6
1327 else if (sid
.sid_authorities
[0] == ntohl(7)) // S-1-5-7
1329 else if (sid
.sid_authorities
[0] == ntohl(11)) // S-1-5-11
1330 id2
= "AUTHENTICATED@";
1335 /* OK, let's just try mapping it to a UID/GID */
1337 error
= kauth_cred_guid2gid(guidp
, (gid_t
*)&uid
);
1339 error
= kauth_cred_guid2uid(guidp
, &uid
);
1341 if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS
)) {
1342 /* map well known uid's to strings */
1344 id2
= isgroup
? "wheel@localdomain" : "root@localdomain";
1345 else if (uid
== (uid_t
)-2)
1346 id2
= "nobody@localdomain";
1349 /* or just use a decimal number string. */
1350 snprintf(numbuf
, sizeof(numbuf
), "%d", uid
);
1355 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1356 printf("nfs4_guid2id: fallback map failed for "
1357 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1359 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1360 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1361 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1362 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1363 isgroup
? "G" : " ", error
);
1364 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
))
1365 printf("nfs4_guid2id: fallback map for "
1366 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1368 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1369 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1370 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1371 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1372 isgroup
? "G" : " ", id2
);
1373 if (!error
&& id2
) {
1375 id2len
= strnlen(id2
, MAXPATHLEN
);
1377 /* copy fallback result to output buffer */
1378 len
= strlcpy(id
, id2
, *idlen
);
1388 /* compare the results, log if different */
1389 if (!error1
&& !error
) {
1390 if ((id1len
!= id2len
) || strncmp(id1
, id2
, id1len
))
1391 printf("nfs4_guid2id: idmap/fallback results differ for "
1392 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1393 "idmap %s fallback %s\n",
1394 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1395 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1396 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1397 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1398 isgroup
? "G" : " ", id1
, id2
);
1399 if (id1
== id1buf
) {
1400 /* copy idmap result to output buffer */
1401 len
= strlcpy(id
, id1
, *idlen
);
1407 } else if (error1
&& !error
) {
1408 printf("nfs4_guid2id: idmap/fallback results differ for "
1409 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1410 "idmap error %d fallback %s\n",
1411 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1412 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1413 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1414 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1415 isgroup
? "G" : " ", error1
, id2
);
1416 /* copy fallback result to output buffer */
1417 len
= strlcpy(id
, id2
, *idlen
);
1422 } else if (!error1
&& error
) {
1423 printf("nfs4_guid2id: idmap/fallback results differ for "
1424 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1425 "idmap %s fallback error %d\n",
1426 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1427 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1428 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1429 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1430 isgroup
? "G" : " ", id1
, error
);
1431 if (id1
== id1buf
) {
1432 /* copy idmap result to output buffer */
1433 len
= strlcpy(id
, id1
, *idlen
);
1441 if (error1
!= error
)
1442 printf("nfs4_guid2id: idmap/fallback results differ for %s %s - "
1443 "idmap error %d fallback error %d\n",
1444 id
, isgroup
? "G" : " ", error1
, error
);
1448 FREE_ZONE(id1buf
, MAXPATHLEN
, M_NAMEI
);
1454 * Set a vnode attr's supported bits according to the given bitmap
1457 nfs_vattr_set_supported(uint32_t *bitmap
, struct vnode_attr
*vap
)
1459 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TYPE
))
1460 VATTR_SET_SUPPORTED(vap
, va_type
);
1461 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHANGE))
1462 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
))
1463 VATTR_SET_SUPPORTED(vap
, va_data_size
);
1464 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FSID
))
1465 VATTR_SET_SUPPORTED(vap
, va_fsid
);
1466 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACL
))
1467 VATTR_SET_SUPPORTED(vap
, va_acl
);
1468 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
))
1469 VATTR_SET_SUPPORTED(vap
, va_flags
);
1470 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEID
))
1471 VATTR_SET_SUPPORTED(vap
, va_fileid
);
1472 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
))
1473 VATTR_SET_SUPPORTED(vap
, va_flags
);
1474 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE))
1475 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
))
1476 VATTR_SET_SUPPORTED(vap
, va_mode
);
1477 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NUMLINKS
))
1478 VATTR_SET_SUPPORTED(vap
, va_nlink
);
1479 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER
)) {
1480 VATTR_SET_SUPPORTED(vap
, va_uid
);
1481 VATTR_SET_SUPPORTED(vap
, va_uuuid
);
1483 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER_GROUP
)) {
1484 VATTR_SET_SUPPORTED(vap
, va_gid
);
1485 VATTR_SET_SUPPORTED(vap
, va_guuid
);
1487 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RAWDEV
))
1488 VATTR_SET_SUPPORTED(vap
, va_rdev
);
1489 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_USED
))
1490 VATTR_SET_SUPPORTED(vap
, va_total_alloc
);
1491 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYSTEM))
1492 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS
))
1493 VATTR_SET_SUPPORTED(vap
, va_access_time
);
1494 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_BACKUP
))
1495 VATTR_SET_SUPPORTED(vap
, va_backup_time
);
1496 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_CREATE
))
1497 VATTR_SET_SUPPORTED(vap
, va_create_time
);
1498 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_METADATA
))
1499 VATTR_SET_SUPPORTED(vap
, va_change_time
);
1500 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY
))
1501 VATTR_SET_SUPPORTED(vap
, va_modify_time
);
1505 * Parse the attributes that are in the mbuf list and store them in
1506 * the given structures.
1510 struct nfsm_chain
*nmc
,
1511 struct nfs_fsattr
*nfsap
,
1512 struct nfs_vattr
*nvap
,
1515 struct nfs_fs_locations
*nfslsp
)
1517 int error
= 0, error2
, rderror
= 0, attrbytes
;
1518 uint32_t val
, val2
, val3
, i
;
1519 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], len
, slen
;
1521 struct nfs_fsattr nfsa_dummy
;
1522 struct nfs_vattr nva_dummy
;
1523 struct dqblk dqb_dummy
;
1524 kauth_acl_t acl
= NULL
;
1525 uint32_t ace_type
, ace_flags
, ace_mask
;
1526 struct nfs_fs_locations nfsls_dummy
;
1527 struct sockaddr_storage ss
;
1529 /* if not interested in some values... throw 'em into a local dummy variable */
1531 nfsap
= &nfsa_dummy
;
1537 nfslsp
= &nfsls_dummy
;
1538 bzero(nfslsp
, sizeof(*nfslsp
));
1540 attrbytes
= val
= val2
= val3
= 0;
1542 slen
= sizeof(sbuf
);
1545 len
= NFS_ATTR_BITMAP_LEN
;
1546 nfsm_chain_get_bitmap(error
, nmc
, bitmap
, len
);
1547 /* add bits to object/fs attr bitmaps */
1548 for (i
=0; i
< NFS_ATTR_BITMAP_LEN
; i
++) {
1549 nvap
->nva_bitmap
[i
] |= bitmap
[i
] & nfs_object_attr_bitmap
[i
];
1550 nfsap
->nfsa_bitmap
[i
] |= bitmap
[i
] & nfs_fs_attr_bitmap
[i
];
1553 nfsm_chain_get_32(error
, nmc
, attrbytes
);
1556 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SUPPORTED_ATTRS
)) {
1557 len
= NFS_ATTR_BITMAP_LEN
;
1558 nfsm_chain_get_bitmap(error
, nmc
, nfsap
->nfsa_supp_attr
, len
);
1559 attrbytes
-= (len
+ 1) * NFSX_UNSIGNED
;
1561 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TYPE
)) {
1562 nfsm_chain_get_32(error
, nmc
, val
);
1563 nvap
->nva_type
= nfstov_type(val
, NFS_VER4
);
1564 if ((val
== NFATTRDIR
) || (val
== NFNAMEDATTR
))
1565 nvap
->nva_flags
|= NFS_FFLAG_IS_ATTR
;
1567 nvap
->nva_flags
&= ~NFS_FFLAG_IS_ATTR
;
1568 attrbytes
-= NFSX_UNSIGNED
;
1570 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FH_EXPIRE_TYPE
)) {
1571 nfsm_chain_get_32(error
, nmc
, val
);
1573 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_FHTYPE_MASK
;
1574 nfsap
->nfsa_flags
|= val
<< NFS_FSFLAG_FHTYPE_SHIFT
;
1576 printf("nfs: warning unknown fh type: 0x%x\n", val
);
1577 attrbytes
-= NFSX_UNSIGNED
;
1579 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CHANGE
)) {
1580 nfsm_chain_get_64(error
, nmc
, nvap
->nva_change
);
1581 attrbytes
-= 2 * NFSX_UNSIGNED
;
1583 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
)) {
1584 nfsm_chain_get_64(error
, nmc
, nvap
->nva_size
);
1585 attrbytes
-= 2 * NFSX_UNSIGNED
;
1587 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_LINK_SUPPORT
)) {
1588 nfsm_chain_get_32(error
, nmc
, val
);
1590 nfsap
->nfsa_flags
|= NFS_FSFLAG_LINK
;
1592 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_LINK
;
1593 attrbytes
-= NFSX_UNSIGNED
;
1595 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SYMLINK_SUPPORT
)) {
1596 nfsm_chain_get_32(error
, nmc
, val
);
1598 nfsap
->nfsa_flags
|= NFS_FSFLAG_SYMLINK
;
1600 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_SYMLINK
;
1601 attrbytes
-= NFSX_UNSIGNED
;
1603 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NAMED_ATTR
)) {
1604 nfsm_chain_get_32(error
, nmc
, val
);
1606 nvap
->nva_flags
|= NFS_FFLAG_HAS_NAMED_ATTRS
;
1608 nvap
->nva_flags
&= ~NFS_FFLAG_HAS_NAMED_ATTRS
;
1609 attrbytes
-= NFSX_UNSIGNED
;
1611 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FSID
)) {
1612 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fsid
.major
);
1613 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fsid
.minor
);
1614 attrbytes
-= 4 * NFSX_UNSIGNED
;
1616 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_UNIQUE_HANDLES
)) {
1617 nfsm_chain_get_32(error
, nmc
, val
);
1619 nfsap
->nfsa_flags
|= NFS_FSFLAG_UNIQUE_FH
;
1621 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_UNIQUE_FH
;
1622 attrbytes
-= NFSX_UNSIGNED
;
1624 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_LEASE_TIME
)) {
1625 nfsm_chain_get_32(error
, nmc
, nfsap
->nfsa_lease
);
1626 attrbytes
-= NFSX_UNSIGNED
;
1628 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RDATTR_ERROR
)) {
1629 nfsm_chain_get_32(error
, nmc
, rderror
);
1630 attrbytes
-= NFSX_UNSIGNED
;
1631 if (!rderror
) { /* no error */
1632 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_RDATTR_ERROR
);
1633 NFS_BITMAP_CLR(nvap
->nva_bitmap
, NFS_FATTR_RDATTR_ERROR
);
1636 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACL
)) {
1638 ace_type
= ace_flags
= ace_mask
= 0;
1639 nfsm_chain_get_32(error
, nmc
, val
); /* ACE count */
1640 if (!error
&& (val
> KAUTH_ACL_MAX_ENTRIES
))
1642 if (!error
&& !((acl
= kauth_acl_alloc(val
))))
1644 if (!error
&& acl
) {
1645 acl
->acl_entrycount
= val
;
1648 attrbytes
-= NFSX_UNSIGNED
;
1649 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
1650 for (i
=0; !error
&& (i
< val
); i
++) {
1651 nfsm_chain_get_32(error
, nmc
, ace_type
);
1652 nfsm_chain_get_32(error
, nmc
, ace_flags
);
1653 nfsm_chain_get_32(error
, nmc
, ace_mask
);
1654 nfsm_chain_get_32(error
, nmc
, len
);
1655 acl
->acl_ace
[i
].ace_flags
= nfs4_ace_nfstype_to_vfstype(ace_type
, &error
);
1656 acl
->acl_ace
[i
].ace_flags
|= nfs4_ace_nfsflags_to_vfsflags(ace_flags
);
1657 acl
->acl_ace
[i
].ace_rights
= nfs4_ace_nfsmask_to_vfsrights(ace_mask
);
1658 if (!error
&& !error2
&& (len
>= slen
)) {
1662 slen
= sizeof(sbuf
);
1664 MALLOC(s
, char*, len
+16, M_TEMP
, M_WAITOK
);
1671 nfsm_chain_adv(error
, nmc
, nfsm_rndup(len
));
1673 nfsm_chain_get_opaque(error
, nmc
, len
, s
);
1674 if (!error
&& !error2
) {
1676 error2
= nfs4_id2guid(s
, &acl
->acl_ace
[i
].ace_applicable
,
1677 (ace_flags
& NFS_ACE_IDENTIFIER_GROUP
));
1678 if (error2
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1679 printf("nfs4_parsefattr: ACE WHO %s is no one, no guid?, error %d\n", s
, error2
);
1681 attrbytes
-= 4*NFSX_UNSIGNED
+ nfsm_rndup(len
);
1682 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
1685 if ((nvap
!= &nva_dummy
) && !error2
) {
1686 nvap
->nva_acl
= acl
;
1690 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACLSUPPORT
)) {
1692 * Support ACLs if: the server supports DENY/ALLOC ACEs and
1693 * (just to be safe) FATTR_ACL is in the supported list too.
1695 nfsm_chain_get_32(error
, nmc
, val
);
1696 if ((val
& (NFS_ACL_SUPPORT_ALLOW_ACL
|NFS_ACL_SUPPORT_DENY_ACL
)) &&
1697 NFS_BITMAP_ISSET(nfsap
->nfsa_supp_attr
, NFS_FATTR_ACL
)) {
1698 nfsap
->nfsa_flags
|= NFS_FSFLAG_ACL
;
1700 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_ACL
;
1702 attrbytes
-= NFSX_UNSIGNED
;
1704 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
)) { /* SF_ARCHIVED */
1705 nfsm_chain_get_32(error
, nmc
, val
);
1707 nvap
->nva_flags
|= NFS_FFLAG_ARCHIVED
;
1709 nvap
->nva_flags
&= ~NFS_FFLAG_ARCHIVED
;
1710 attrbytes
-= NFSX_UNSIGNED
;
1712 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CANSETTIME
)) {
1713 nfsm_chain_get_32(error
, nmc
, val
);
1715 nfsap
->nfsa_flags
|= NFS_FSFLAG_SET_TIME
;
1717 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_SET_TIME
;
1718 attrbytes
-= NFSX_UNSIGNED
;
1720 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CASE_INSENSITIVE
)) {
1721 nfsm_chain_get_32(error
, nmc
, val
);
1723 nfsap
->nfsa_flags
|= NFS_FSFLAG_CASE_INSENSITIVE
;
1725 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CASE_INSENSITIVE
;
1726 attrbytes
-= NFSX_UNSIGNED
;
1728 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CASE_PRESERVING
)) {
1729 nfsm_chain_get_32(error
, nmc
, val
);
1731 nfsap
->nfsa_flags
|= NFS_FSFLAG_CASE_PRESERVING
;
1733 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CASE_PRESERVING
;
1734 attrbytes
-= NFSX_UNSIGNED
;
1736 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CHOWN_RESTRICTED
)) {
1737 nfsm_chain_get_32(error
, nmc
, val
);
1739 nfsap
->nfsa_flags
|= NFS_FSFLAG_CHOWN_RESTRICTED
;
1741 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CHOWN_RESTRICTED
;
1742 attrbytes
-= NFSX_UNSIGNED
;
1744 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEHANDLE
)) {
1745 nfsm_chain_get_32(error
, nmc
, val
);
1748 nfsm_chain_get_opaque(error
, nmc
, nfsm_rndup(val
), fhp
->fh_data
);
1750 nfsm_chain_adv(error
, nmc
, nfsm_rndup(val
));
1752 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
1754 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEID
)) {
1755 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fileid
);
1756 attrbytes
-= 2 * NFSX_UNSIGNED
;
1758 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILES_AVAIL
)) {
1759 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_files_avail
);
1760 attrbytes
-= 2 * NFSX_UNSIGNED
;
1762 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILES_FREE
)) {
1763 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_files_free
);
1764 attrbytes
-= 2 * NFSX_UNSIGNED
;
1766 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILES_TOTAL
)) {
1767 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_files_total
);
1768 attrbytes
-= 2 * NFSX_UNSIGNED
;
1770 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FS_LOCATIONS
)) {
1771 uint32_t loc
, serv
, comp
;
1772 struct nfs_fs_location
*fsl
;
1773 struct nfs_fs_server
*fss
;
1774 struct nfs_fs_path
*fsp
;
1776 /* get root pathname */
1777 fsp
= &nfslsp
->nl_root
;
1778 nfsm_chain_get_32(error
, nmc
, fsp
->np_compcount
); /* component count */
1779 attrbytes
-= NFSX_UNSIGNED
;
1780 /* sanity check component count */
1781 if (!error
&& (fsp
->np_compcount
> MAXPATHLEN
))
1784 if (fsp
->np_compcount
) {
1785 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
1786 if (!fsp
->np_components
)
1789 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
1790 nfsm_chain_get_32(error
, nmc
, val
); /* component length */
1791 /* sanity check component length */
1792 if (!error
&& (val
== 0)) {
1794 * Apparently some people think a path with zero components should
1795 * be encoded with one zero-length component. So, just ignore any
1796 * zero length components.
1799 fsp
->np_compcount
--;
1800 if (fsp
->np_compcount
== 0) {
1801 FREE(fsp
->np_components
, M_TEMP
);
1802 fsp
->np_components
= NULL
;
1804 attrbytes
-= NFSX_UNSIGNED
;
1807 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
1810 MALLOC(fsp
->np_components
[comp
], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
1811 if (!fsp
->np_components
[comp
])
1814 nfsm_chain_get_opaque(error
, nmc
, val
, fsp
->np_components
[comp
]); /* component */
1815 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
1817 nfsm_chain_get_32(error
, nmc
, nfslsp
->nl_numlocs
); /* fs location count */
1818 attrbytes
-= NFSX_UNSIGNED
;
1819 /* sanity check location count */
1820 if (!error
&& (nfslsp
->nl_numlocs
> 256))
1823 if (nfslsp
->nl_numlocs
> 0) {
1824 MALLOC(nfslsp
->nl_locations
, struct nfs_fs_location
**, nfslsp
->nl_numlocs
* sizeof(struct nfs_fs_location
*), M_TEMP
, M_WAITOK
|M_ZERO
);
1825 if (!nfslsp
->nl_locations
)
1829 for (loc
= 0; loc
< nfslsp
->nl_numlocs
; loc
++) {
1831 MALLOC(fsl
, struct nfs_fs_location
*, sizeof(struct nfs_fs_location
), M_TEMP
, M_WAITOK
|M_ZERO
);
1834 nfslsp
->nl_locations
[loc
] = fsl
;
1835 nfsm_chain_get_32(error
, nmc
, fsl
->nl_servcount
); /* server count */
1836 attrbytes
-= NFSX_UNSIGNED
;
1837 /* sanity check server count */
1838 if (!error
&& ((fsl
->nl_servcount
< 1) || (fsl
->nl_servcount
> 256)))
1841 MALLOC(fsl
->nl_servers
, struct nfs_fs_server
**, fsl
->nl_servcount
* sizeof(struct nfs_fs_server
*), M_TEMP
, M_WAITOK
|M_ZERO
);
1842 if (!fsl
->nl_servers
)
1844 for (serv
= 0; serv
< fsl
->nl_servcount
; serv
++) {
1846 MALLOC(fss
, struct nfs_fs_server
*, sizeof(struct nfs_fs_server
), M_TEMP
, M_WAITOK
|M_ZERO
);
1849 fsl
->nl_servers
[serv
] = fss
;
1850 nfsm_chain_get_32(error
, nmc
, val
); /* server name length */
1851 /* sanity check server name length */
1852 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
1855 MALLOC(fss
->ns_name
, char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
1858 nfsm_chain_get_opaque(error
, nmc
, val
, fss
->ns_name
); /* server name */
1859 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
1861 /* copy name to address if it converts to a sockaddr */
1862 if (nfs_uaddr2sockaddr(fss
->ns_name
, (struct sockaddr
*)&ss
)) {
1863 fss
->ns_addrcount
= 1;
1864 MALLOC(fss
->ns_addresses
, char **, sizeof(char *), M_TEMP
, M_WAITOK
|M_ZERO
);
1865 if (!fss
->ns_addresses
)
1868 MALLOC(fss
->ns_addresses
[0], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
1869 if (!fss
->ns_addresses
[0])
1872 strlcpy(fss
->ns_addresses
[0], fss
->ns_name
, val
+1);
1876 fsp
= &fsl
->nl_path
;
1877 nfsm_chain_get_32(error
, nmc
, fsp
->np_compcount
); /* component count */
1878 attrbytes
-= NFSX_UNSIGNED
;
1879 /* sanity check component count */
1880 if (!error
&& (fsp
->np_compcount
> MAXPATHLEN
))
1883 if (fsp
->np_compcount
) {
1884 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
1885 if (!fsp
->np_components
)
1888 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
1889 nfsm_chain_get_32(error
, nmc
, val
); /* component length */
1890 /* sanity check component length */
1891 if (!error
&& (val
== 0)) {
1893 * Apparently some people think a path with zero components should
1894 * be encoded with one zero-length component. So, just ignore any
1895 * zero length components.
1898 fsp
->np_compcount
--;
1899 if (fsp
->np_compcount
== 0) {
1900 FREE(fsp
->np_components
, M_TEMP
);
1901 fsp
->np_components
= NULL
;
1903 attrbytes
-= NFSX_UNSIGNED
;
1906 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
1909 MALLOC(fsp
->np_components
[comp
], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
1910 if (!fsp
->np_components
[comp
])
1912 nfsm_chain_get_opaque(error
, nmc
, val
, fsp
->np_components
[comp
]); /* component */
1913 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
1916 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
1918 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
)) { /* UF_HIDDEN */
1919 nfsm_chain_get_32(error
, nmc
, val
);
1921 nvap
->nva_flags
|= NFS_FFLAG_HIDDEN
;
1923 nvap
->nva_flags
&= ~NFS_FFLAG_HIDDEN
;
1924 attrbytes
-= NFSX_UNSIGNED
;
1926 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HOMOGENEOUS
)) {
1927 /* XXX If NOT homogeneous, we may need to clear flags on the mount */
1928 nfsm_chain_get_32(error
, nmc
, val
);
1930 nfsap
->nfsa_flags
|= NFS_FSFLAG_HOMOGENEOUS
;
1932 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_HOMOGENEOUS
;
1933 attrbytes
-= NFSX_UNSIGNED
;
1935 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXFILESIZE
)) {
1936 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxfilesize
);
1937 attrbytes
-= 2 * NFSX_UNSIGNED
;
1939 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXLINK
)) {
1940 nfsm_chain_get_32(error
, nmc
, nvap
->nva_maxlink
);
1941 if (!error
&& (nfsap
->nfsa_maxlink
> INT32_MAX
))
1942 nfsap
->nfsa_maxlink
= INT32_MAX
;
1943 attrbytes
-= NFSX_UNSIGNED
;
1945 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXNAME
)) {
1946 nfsm_chain_get_32(error
, nmc
, nfsap
->nfsa_maxname
);
1947 if (!error
&& (nfsap
->nfsa_maxname
> INT32_MAX
))
1948 nfsap
->nfsa_maxname
= INT32_MAX
;
1949 attrbytes
-= NFSX_UNSIGNED
;
1951 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXREAD
)) {
1952 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxread
);
1953 attrbytes
-= 2 * NFSX_UNSIGNED
;
1955 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXWRITE
)) {
1956 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxwrite
);
1957 attrbytes
-= 2 * NFSX_UNSIGNED
;
1959 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MIMETYPE
)) {
1960 nfsm_chain_get_32(error
, nmc
, val
);
1961 nfsm_chain_adv(error
, nmc
, nfsm_rndup(val
));
1962 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
1964 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
)) {
1965 nfsm_chain_get_32(error
, nmc
, nvap
->nva_mode
);
1966 attrbytes
-= NFSX_UNSIGNED
;
1968 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NO_TRUNC
)) {
1969 nfsm_chain_get_32(error
, nmc
, val
);
1971 nfsap
->nfsa_flags
|= NFS_FSFLAG_NO_TRUNC
;
1973 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_NO_TRUNC
;
1974 attrbytes
-= NFSX_UNSIGNED
;
1976 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NUMLINKS
)) {
1977 nfsm_chain_get_32(error
, nmc
, val
);
1978 nvap
->nva_nlink
= val
;
1979 attrbytes
-= NFSX_UNSIGNED
;
1981 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER
)) {
1982 nfsm_chain_get_32(error
, nmc
, len
);
1983 if (!error
&& (len
>= slen
)) {
1987 slen
= sizeof(sbuf
);
1989 MALLOC(s
, char*, len
+16, M_TEMP
, M_WAITOK
);
1995 nfsm_chain_get_opaque(error
, nmc
, len
, s
);
1998 error
= nfs4_id2guid(s
, &nvap
->nva_uuuid
, 0);
2000 error
= kauth_cred_guid2uid(&nvap
->nva_uuuid
, &nvap
->nva_uid
);
2002 /* unable to get either GUID or UID, set to default */
2003 nvap
->nva_uid
= (uid_t
)((nfs_idmap_ctrl
& NFS_IDMAP_CTRL_UNKNOWN_IS_99
) ? 99 : -2);
2004 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
)
2005 printf("nfs4_parsefattr: owner %s is no one, no %s?, error %d\n", s
,
2006 kauth_guid_equal(&nvap
->nva_uuuid
, &kauth_null_guid
) ? "guid" : "uid",
2011 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2013 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER_GROUP
)) {
2014 nfsm_chain_get_32(error
, nmc
, len
);
2015 if (!error
&& (len
>= slen
)) {
2019 slen
= sizeof(sbuf
);
2021 MALLOC(s
, char*, len
+16, M_TEMP
, M_WAITOK
);
2027 nfsm_chain_get_opaque(error
, nmc
, len
, s
);
2030 error
= nfs4_id2guid(s
, &nvap
->nva_guuid
, 1);
2032 error
= kauth_cred_guid2gid(&nvap
->nva_guuid
, &nvap
->nva_gid
);
2034 /* unable to get either GUID or GID, set to default */
2035 nvap
->nva_gid
= (gid_t
)((nfs_idmap_ctrl
& NFS_IDMAP_CTRL_UNKNOWN_IS_99
) ? 99 : -2);
2036 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
)
2037 printf("nfs4_parsefattr: group %s is no one, no %s?, error %d\n", s
,
2038 kauth_guid_equal(&nvap
->nva_guuid
, &kauth_null_guid
) ? "guid" : "gid",
2043 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2045 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_QUOTA_AVAIL_HARD
)) {
2046 nfsm_chain_get_64(error
, nmc
, dqbp
->dqb_bhardlimit
);
2047 attrbytes
-= 2 * NFSX_UNSIGNED
;
2049 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_QUOTA_AVAIL_SOFT
)) {
2050 nfsm_chain_get_64(error
, nmc
, dqbp
->dqb_bsoftlimit
);
2051 attrbytes
-= 2 * NFSX_UNSIGNED
;
2053 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_QUOTA_USED
)) {
2054 nfsm_chain_get_64(error
, nmc
, dqbp
->dqb_curbytes
);
2055 attrbytes
-= 2 * NFSX_UNSIGNED
;
2057 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RAWDEV
)) {
2058 nfsm_chain_get_32(error
, nmc
, nvap
->nva_rawdev
.specdata1
);
2059 nfsm_chain_get_32(error
, nmc
, nvap
->nva_rawdev
.specdata2
);
2060 attrbytes
-= 2 * NFSX_UNSIGNED
;
2062 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_AVAIL
)) {
2063 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_space_avail
);
2064 attrbytes
-= 2 * NFSX_UNSIGNED
;
2066 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_FREE
)) {
2067 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_space_free
);
2068 attrbytes
-= 2 * NFSX_UNSIGNED
;
2070 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_TOTAL
)) {
2071 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_space_total
);
2072 attrbytes
-= 2 * NFSX_UNSIGNED
;
2074 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_USED
)) {
2075 nfsm_chain_get_64(error
, nmc
, nvap
->nva_bytes
);
2076 attrbytes
-= 2 * NFSX_UNSIGNED
;
2078 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SYSTEM
)) {
2079 /* we'd support this if we had a flag to map it to... */
2080 nfsm_chain_adv(error
, nmc
, NFSX_UNSIGNED
);
2081 attrbytes
-= NFSX_UNSIGNED
;
2083 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS
)) {
2084 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_ACCESS
]);
2085 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_ACCESS
]);
2086 attrbytes
-= 3 * NFSX_UNSIGNED
;
2088 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
)) {
2089 nfsm_chain_adv(error
, nmc
, 4*NFSX_UNSIGNED
); /* just skip it */
2090 attrbytes
-= 4 * NFSX_UNSIGNED
;
2092 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_BACKUP
)) {
2093 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_BACKUP
]);
2094 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_BACKUP
]);
2095 attrbytes
-= 3 * NFSX_UNSIGNED
;
2097 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_CREATE
)) {
2098 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_CREATE
]);
2099 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_CREATE
]);
2100 attrbytes
-= 3 * NFSX_UNSIGNED
;
2102 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_DELTA
)) { /* skip for now */
2103 nfsm_chain_adv(error
, nmc
, 3*NFSX_UNSIGNED
);
2104 attrbytes
-= 3 * NFSX_UNSIGNED
;
2106 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_METADATA
)) {
2107 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_CHANGE
]);
2108 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_CHANGE
]);
2109 attrbytes
-= 3 * NFSX_UNSIGNED
;
2111 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY
)) {
2112 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_MODIFY
]);
2113 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_MODIFY
]);
2114 attrbytes
-= 3 * NFSX_UNSIGNED
;
2116 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
)) {
2117 nfsm_chain_adv(error
, nmc
, 4*NFSX_UNSIGNED
); /* just skip it */
2118 attrbytes
-= 4 * NFSX_UNSIGNED
;
2120 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MOUNTED_ON_FILEID
)) {
2122 /* we prefer the mounted on file ID, so just replace the fileid */
2123 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fileid
);
2125 nfsm_chain_adv(error
, nmc
, 2*NFSX_UNSIGNED
);
2127 attrbytes
-= 2 * NFSX_UNSIGNED
;
2129 /* advance over any leftover attrbytes */
2130 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
2131 nfsm_chain_adv(error
, nmc
, nfsm_rndup(attrbytes
));
2134 nfs_fs_locations_cleanup(nfslsp
);
2135 if (!error
&& rderror
)
2137 /* free up temporary resources */
2138 if (s
&& (s
!= sbuf
))
2141 kauth_acl_free(acl
);
2142 if (error
&& nvap
->nva_acl
) {
2143 kauth_acl_free(nvap
->nva_acl
);
2144 nvap
->nva_acl
= NULL
;
2150 * Add an NFSv4 "sattr" structure to an mbuf chain
2153 nfsm_chain_add_fattr4_f(struct nfsm_chain
*nmc
, struct vnode_attr
*vap
, struct nfsmount
*nmp
)
2155 int error
= 0, attrbytes
, slen
, len
, i
, isgroup
;
2156 uint32_t *pattrbytes
, val
, acecount
;;
2157 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
2163 slen
= sizeof(sbuf
);
2165 /* First calculate the bitmap... */
2166 nfs_vattr_set_bitmap(nmp
, bitmap
, vap
);
2169 * Now pack it all together:
2170 * BITMAP, #BYTES, ATTRS
2171 * Keep a pointer to the length so we can set it later.
2173 nfsm_chain_add_bitmap(error
, nmc
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2175 nfsm_chain_add_32(error
, nmc
, attrbytes
);
2176 pattrbytes
= (uint32_t*)(nmc
->nmc_ptr
- NFSX_UNSIGNED
);
2178 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
)) {
2179 nfsm_chain_add_64(error
, nmc
, vap
->va_data_size
);
2180 attrbytes
+= 2*NFSX_UNSIGNED
;
2182 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACL
)) {
2184 if (!acl
|| (acl
->acl_entrycount
== KAUTH_FILESEC_NOACL
))
2187 acecount
= acl
->acl_entrycount
;
2188 nfsm_chain_add_32(error
, nmc
, acecount
);
2189 attrbytes
+= NFSX_UNSIGNED
;
2190 for (i
=0; !error
&& (i
< (int)acecount
); i
++) {
2191 val
= (acl
->acl_ace
[i
].ace_flags
& KAUTH_ACE_KINDMASK
);
2192 val
= nfs4_ace_vfstype_to_nfstype(val
, &error
);
2193 nfsm_chain_add_32(error
, nmc
, val
);
2194 val
= nfs4_ace_vfsflags_to_nfsflags(acl
->acl_ace
[i
].ace_flags
);
2195 nfsm_chain_add_32(error
, nmc
, val
);
2196 val
= nfs4_ace_vfsrights_to_nfsmask(acl
->acl_ace
[i
].ace_rights
);
2197 nfsm_chain_add_32(error
, nmc
, val
);
2199 isgroup
= (kauth_cred_guid2gid(&acl
->acl_ace
[i
].ace_applicable
, &gid
) == 0);
2200 error
= nfs4_guid2id(&acl
->acl_ace
[i
].ace_applicable
, s
, &len
, isgroup
);
2201 if (error
== ENOSPC
) {
2207 MALLOC(s
, char*, len
, M_TEMP
, M_WAITOK
);
2210 error
= nfs4_guid2id(&acl
->acl_ace
[i
].ace_applicable
, s
, &len
, isgroup
);
2215 nfsm_chain_add_name(error
, nmc
, s
, len
, nmp
);
2216 attrbytes
+= 4*NFSX_UNSIGNED
+ nfsm_rndup(len
);
2219 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
)) {
2220 nfsm_chain_add_32(error
, nmc
, (vap
->va_flags
& SF_ARCHIVED
) ? 1 : 0);
2221 attrbytes
+= NFSX_UNSIGNED
;
2223 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
)) {
2224 nfsm_chain_add_32(error
, nmc
, (vap
->va_flags
& UF_HIDDEN
) ? 1 : 0);
2225 attrbytes
+= NFSX_UNSIGNED
;
2227 // NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE)
2228 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
)) {
2229 nfsm_chain_add_32(error
, nmc
, vap
->va_mode
);
2230 attrbytes
+= NFSX_UNSIGNED
;
2232 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER
)) {
2234 /* if we have va_uuuid use it, otherwise use uid */
2235 if (!VATTR_IS_ACTIVE(vap
, va_uuuid
)) {
2236 error
= kauth_cred_uid2guid(vap
->va_uid
, &vap
->va_uuuid
);
2240 error
= nfs4_guid2id(&vap
->va_uuuid
, s
, &len
, 0);
2241 if (error
== ENOSPC
) {
2247 MALLOC(s
, char*, len
, M_TEMP
, M_WAITOK
);
2250 error
= nfs4_guid2id(&vap
->va_uuuid
, s
, &len
, 0);
2255 nfsm_chain_add_name(error
, nmc
, s
, len
, nmp
);
2256 attrbytes
+= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2258 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER_GROUP
)) {
2260 /* if we have va_guuid use it, otherwise use gid */
2261 if (!VATTR_IS_ACTIVE(vap
, va_guuid
)) {
2262 error
= kauth_cred_gid2guid(vap
->va_gid
, &vap
->va_guuid
);
2266 error
= nfs4_guid2id(&vap
->va_guuid
, s
, &len
, 1);
2267 if (error
== ENOSPC
) {
2273 MALLOC(s
, char*, len
, M_TEMP
, M_WAITOK
);
2276 error
= nfs4_guid2id(&vap
->va_guuid
, s
, &len
, 1);
2281 nfsm_chain_add_name(error
, nmc
, s
, len
, nmp
);
2282 attrbytes
+= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2284 // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
2285 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
)) {
2286 if (vap
->va_vaflags
& VA_UTIMES_NULL
) {
2287 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_SERVER
);
2288 attrbytes
+= NFSX_UNSIGNED
;
2290 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_CLIENT
);
2291 nfsm_chain_add_64(error
, nmc
, vap
->va_access_time
.tv_sec
);
2292 nfsm_chain_add_32(error
, nmc
, vap
->va_access_time
.tv_nsec
);
2293 attrbytes
+= 4*NFSX_UNSIGNED
;
2296 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_BACKUP
)) {
2297 nfsm_chain_add_64(error
, nmc
, vap
->va_backup_time
.tv_sec
);
2298 nfsm_chain_add_32(error
, nmc
, vap
->va_backup_time
.tv_nsec
);
2299 attrbytes
+= 3*NFSX_UNSIGNED
;
2301 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_CREATE
)) {
2302 nfsm_chain_add_64(error
, nmc
, vap
->va_create_time
.tv_sec
);
2303 nfsm_chain_add_32(error
, nmc
, vap
->va_create_time
.tv_nsec
);
2304 attrbytes
+= 3*NFSX_UNSIGNED
;
2306 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
)) {
2307 if (vap
->va_vaflags
& VA_UTIMES_NULL
) {
2308 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_SERVER
);
2309 attrbytes
+= NFSX_UNSIGNED
;
2311 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_CLIENT
);
2312 nfsm_chain_add_64(error
, nmc
, vap
->va_modify_time
.tv_sec
);
2313 nfsm_chain_add_32(error
, nmc
, vap
->va_modify_time
.tv_nsec
);
2314 attrbytes
+= 4*NFSX_UNSIGNED
;
2318 /* Now, set the attribute data length */
2319 *pattrbytes
= txdr_unsigned(attrbytes
);
2321 if (s
&& (s
!= sbuf
))
2327 * Got the given error and need to start recovery (if not already started).
2328 * Note: nmp must be locked!
2331 nfs_need_recover(struct nfsmount
*nmp
, int error
)
2333 int wake
= !(nmp
->nm_state
& NFSSTA_RECOVER
);
2335 nmp
->nm_state
|= NFSSTA_RECOVER
;
2336 if ((error
== NFSERR_ADMIN_REVOKED
) ||
2337 (error
== NFSERR_EXPIRED
) ||
2338 (error
== NFSERR_STALE_CLIENTID
))
2339 nmp
->nm_state
|= NFSSTA_RECOVER_EXPIRED
;
2341 nfs_mount_sock_thread_wake(nmp
);
2345 * After recovery due to state expiry, check each node and
2346 * drop any lingering delegation we thought we had.
2348 * If a node has an open that is not lost and is not marked
2349 * for reopen, then we hold onto any delegation because it is
2350 * likely newly-granted.
2353 nfs4_expired_check_delegation(nfsnode_t np
, vfs_context_t ctx
)
2355 struct nfsmount
*nmp
= NFSTONMP(np
);
2356 struct nfs_open_file
*nofp
;
2359 if ((np
->n_flag
& NREVOKE
) || !(np
->n_openflags
& N_DELEG_MASK
))
2362 lck_mtx_lock(&np
->n_openlock
);
2364 TAILQ_FOREACH(nofp
, &np
->n_opens
, nof_link
) {
2365 if (!nofp
->nof_opencnt
)
2367 if (nofp
->nof_flags
& NFS_OPEN_FILE_LOST
)
2369 if (nofp
->nof_flags
& NFS_OPEN_FILE_REOPEN
)
2371 /* we have an open that is not lost and not marked for reopen */
2372 // XXX print out what's keeping this node from dropping the delegation.
2373 NP(nofp
->nof_np
, "nfs4_expired_check_delegation: !drop: opencnt %d flags 0x%x access %d %d mmap %d %d",
2374 nofp
->nof_opencnt
, nofp
->nof_flags
,
2375 nofp
->nof_access
, nofp
->nof_deny
,
2376 nofp
->nof_mmap_access
, nofp
->nof_mmap_deny
);
2382 /* need to drop a delegation */
2383 if (np
->n_dreturn
.tqe_next
!= NFSNOLIST
) {
2384 /* remove this node from the delegation return list */
2385 lck_mtx_lock(&nmp
->nm_lock
);
2386 if (np
->n_dreturn
.tqe_next
!= NFSNOLIST
) {
2387 TAILQ_REMOVE(&nmp
->nm_dreturnq
, np
, n_dreturn
);
2388 np
->n_dreturn
.tqe_next
= NFSNOLIST
;
2390 lck_mtx_unlock(&nmp
->nm_lock
);
2392 if (np
->n_openflags
& N_DELEG_MASK
) {
2393 np
->n_openflags
&= ~N_DELEG_MASK
;
2394 lck_mtx_lock(&nmp
->nm_lock
);
2395 if (np
->n_dlink
.tqe_next
!= NFSNOLIST
) {
2396 TAILQ_REMOVE(&nmp
->nm_delegations
, np
, n_dlink
);
2397 np
->n_dlink
.tqe_next
= NFSNOLIST
;
2399 lck_mtx_unlock(&nmp
->nm_lock
);
2400 nfs4_delegreturn_rpc(nmp
, np
->n_fhp
, np
->n_fhsize
, &np
->n_dstateid
,
2401 0, vfs_context_thread(ctx
), vfs_context_ucred(ctx
));
2405 lck_mtx_unlock(&np
->n_openlock
);
2409 * Recover state for an NFS mount.
2411 * Iterates over all open files, reclaiming opens and lock state.
2414 nfs_recover(struct nfsmount
*nmp
)
2416 struct timespec ts
= { 1, 0 };
2417 int error
, lost
, reopen
;
2418 struct nfs_open_owner
*noop
;
2419 struct nfs_open_file
*nofp
;
2420 struct nfs_file_lock
*nflp
, *nextnflp
;
2421 struct nfs_lock_owner
*nlop
;
2422 thread_t thd
= current_thread();
2423 nfsnode_t np
, nextnp
;
2428 lck_mtx_lock(&nmp
->nm_lock
);
2430 * First, wait for the state inuse count to go to zero so
2431 * we know there are no state operations in progress.
2434 if ((error
= nfs_sigintr(nmp
, NULL
, NULL
, 1)))
2436 if (!(nmp
->nm_sockflags
& NMSOCK_READY
))
2438 if (nmp
->nm_state
& NFSSTA_FORCE
)
2440 if (nmp
->nm_sockflags
& NMSOCK_UNMOUNT
)
2444 if (nmp
->nm_stateinuse
)
2445 msleep(&nmp
->nm_stateinuse
, &nmp
->nm_lock
, (PZERO
-1), "nfsrecoverstartwait", &ts
);
2446 } while (nmp
->nm_stateinuse
);
2449 printf("nfs recovery reconnecting for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2451 printf("nfs recovery aborted for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2452 lck_mtx_unlock(&nmp
->nm_lock
);
2457 if (now
.tv_sec
== nmp
->nm_recover_start
) {
2458 printf("nfs recovery throttled for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2459 lck_mtx_unlock(&nmp
->nm_lock
);
2460 tsleep(&lbolt
, (PZERO
-1), "nfsrecoverrestart", hz
);
2463 nmp
->nm_recover_start
= now
.tv_sec
;
2464 if (++nmp
->nm_stategenid
== 0)
2465 ++nmp
->nm_stategenid
;
2466 printf("nfs recovery started for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2467 lck_mtx_unlock(&nmp
->nm_lock
);
2469 /* for each open owner... */
2470 TAILQ_FOREACH(noop
, &nmp
->nm_open_owners
, noo_link
) {
2471 /* for each of its opens... */
2472 TAILQ_FOREACH(nofp
, &noop
->noo_opens
, nof_oolink
) {
2473 if (!nofp
->nof_access
|| (nofp
->nof_flags
& NFS_OPEN_FILE_LOST
) || (nofp
->nof_np
->n_flag
& NREVOKE
))
2476 /* for NFSv2/v3, just skip straight to lock reclaim */
2477 if (nmp
->nm_vers
< NFS_VER4
)
2479 if (nofp
->nof_rw_drw
)
2480 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_BOTH
);
2481 if (!error
&& nofp
->nof_w_drw
)
2482 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_WRITE
, NFS_OPEN_SHARE_DENY_BOTH
);
2483 if (!error
&& nofp
->nof_r_drw
)
2484 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_BOTH
);
2485 if (!error
&& nofp
->nof_rw_dw
)
2486 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_WRITE
);
2487 if (!error
&& nofp
->nof_w_dw
)
2488 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_WRITE
, NFS_OPEN_SHARE_DENY_WRITE
);
2489 if (!error
&& nofp
->nof_r_dw
)
2490 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_WRITE
);
2492 * deny-none opens with no locks can just be reopened (later) if reclaim fails.
2494 if (!error
&& nofp
->nof_rw
) {
2495 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_NONE
);
2496 if ((error
== NFSERR_ADMIN_REVOKED
) || (error
== NFSERR_EXPIRED
) || (error
== NFSERR_NO_GRACE
)) {
2501 if (!error
&& !reopen
&& nofp
->nof_w
) {
2502 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_WRITE
, NFS_OPEN_SHARE_DENY_NONE
);
2503 if ((error
== NFSERR_ADMIN_REVOKED
) || (error
== NFSERR_EXPIRED
) || (error
== NFSERR_NO_GRACE
)) {
2508 if (!error
&& !reopen
&& nofp
->nof_r
) {
2509 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_NONE
);
2510 if ((error
== NFSERR_ADMIN_REVOKED
) || (error
== NFSERR_EXPIRED
) || (error
== NFSERR_NO_GRACE
)) {
2517 * If we hold delegated state but we don't have any non-delegated opens,
2518 * then we should attempt to claim that state now (but don't return the
2519 * delegation unless asked to).
2521 if ((nofp
->nof_d_rw_drw
|| nofp
->nof_d_w_drw
|| nofp
->nof_d_r_drw
||
2522 nofp
->nof_d_rw_dw
|| nofp
->nof_d_w_dw
|| nofp
->nof_d_r_dw
||
2523 nofp
->nof_d_rw
|| nofp
->nof_d_w
|| nofp
->nof_d_r
) &&
2524 (!nofp
->nof_rw_drw
&& !nofp
->nof_w_drw
&& !nofp
->nof_r_drw
&&
2525 !nofp
->nof_rw_dw
&& !nofp
->nof_w_dw
&& !nofp
->nof_r_dw
&&
2526 !nofp
->nof_rw
&& !nofp
->nof_w
&& !nofp
->nof_r
)) {
2527 if (!error
&& !nfs_open_state_set_busy(nofp
->nof_np
, NULL
)) {
2528 error
= nfs4_claim_delegated_state_for_node(nofp
->nof_np
, R_RECOVER
);
2529 if (!error
&& (nofp
->nof_flags
& NFS_OPEN_FILE_REOPEN
))
2531 nfs_open_state_clear_busy(nofp
->nof_np
);
2532 /* if claim didn't go well, we may need to return delegation now */
2533 if (nofp
->nof_np
->n_openflags
& N_DELEG_RETURN
) {
2534 nfs4_delegation_return(nofp
->nof_np
, R_RECOVER
, thd
, noop
->noo_cred
);
2535 if (!(nmp
->nm_sockflags
& NMSOCK_READY
))
2536 error
= ETIMEDOUT
; /* looks like we need a reconnect */
2542 * Handle any issue claiming open state.
2543 * Potential reopens need to first confirm that there are no locks.
2545 if (error
|| reopen
) {
2546 /* restart recovery? */
2547 if ((error
== ETIMEDOUT
) || nfs_mount_state_error_should_restart(error
)) {
2548 if (error
== ETIMEDOUT
)
2549 nfs_need_reconnect(nmp
);
2550 tsleep(&lbolt
, (PZERO
-1), "nfsrecoverrestart", 0);
2551 printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2552 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
2555 if (reopen
&& (nfs_check_for_locks(noop
, nofp
) == 0)) {
2556 /* just reopen the file on next access */
2557 NP(nofp
->nof_np
, "nfs_recover: %d, need reopen for %d %p 0x%x", reopen
,
2558 kauth_cred_getuid(noop
->noo_cred
), nofp
->nof_np
, nofp
->nof_np
->n_flag
);
2559 lck_mtx_lock(&nofp
->nof_lock
);
2560 nofp
->nof_flags
|= NFS_OPEN_FILE_REOPEN
;
2561 lck_mtx_unlock(&nofp
->nof_lock
);
2563 /* open file state lost */
2565 NP(nofp
->nof_np
, "nfs_recover: %d, can't reopen because of locks %d %p", reopen
,
2566 kauth_cred_getuid(noop
->noo_cred
), nofp
->nof_np
);
2572 /* no error, so make sure the reopen flag isn't set */
2573 lck_mtx_lock(&nofp
->nof_lock
);
2574 nofp
->nof_flags
&= ~NFS_OPEN_FILE_REOPEN
;
2575 lck_mtx_unlock(&nofp
->nof_lock
);
2579 * Scan this node's lock owner list for entries with this open owner,
2580 * then walk the lock owner's held lock list recovering each lock.
2583 TAILQ_FOREACH(nlop
, &nofp
->nof_np
->n_lock_owners
, nlo_link
) {
2586 if (nlop
->nlo_open_owner
!= noop
)
2588 TAILQ_FOREACH_SAFE(nflp
, &nlop
->nlo_locks
, nfl_lolink
, nextnflp
) {
2589 /* skip dead & blocked lock requests (shouldn't be any in the held lock list) */
2590 if (nflp
->nfl_flags
& (NFS_FILE_LOCK_DEAD
|NFS_FILE_LOCK_BLOCKED
))
2592 /* skip delegated locks */
2593 if (nflp
->nfl_flags
& NFS_FILE_LOCK_DELEGATED
)
2595 error
= nmp
->nm_funcs
->nf_setlock_rpc(nofp
->nof_np
, nofp
, nflp
, 1, R_RECOVER
, thd
, noop
->noo_cred
);
2597 NP(nofp
->nof_np
, "nfs: lock reclaim (0x%llx, 0x%llx) %s %d",
2598 nflp
->nfl_start
, nflp
->nfl_end
,
2599 error
? "failed" : "succeeded", error
);
2602 /* restart recovery? */
2603 if ((error
== ETIMEDOUT
) || nfs_mount_state_error_should_restart(error
)) {
2604 if (error
== ETIMEDOUT
)
2605 nfs_need_reconnect(nmp
);
2606 tsleep(&lbolt
, (PZERO
-1), "nfsrecoverrestart", 0);
2607 printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2608 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
2611 /* lock state lost - attempt to close file */
2619 * If we've determined that we need to reopen the file then we probably
2620 * didn't receive any delegation we think we hold. We should attempt to
2621 * return that delegation (and claim any delegated state).
2623 * If we hold a delegation that is marked for return, then we should
2626 if ((nofp
->nof_np
->n_openflags
& N_DELEG_RETURN
) ||
2627 (reopen
&& (nofp
->nof_np
->n_openflags
& N_DELEG_MASK
))) {
2628 nfs4_delegation_return(nofp
->nof_np
, R_RECOVER
, thd
, noop
->noo_cred
);
2629 if (!(nmp
->nm_sockflags
& NMSOCK_READY
)) {
2630 /* looks like we need a reconnect */
2631 tsleep(&lbolt
, (PZERO
-1), "nfsrecoverrestart", 0);
2632 printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2633 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
2639 /* revoke open file state */
2640 NP(nofp
->nof_np
, "nfs_recover: state lost for %d %p 0x%x",
2641 kauth_cred_getuid(noop
->noo_cred
), nofp
->nof_np
, nofp
->nof_np
->n_flag
);
2642 nfs_revoke_open_state_for_node(nofp
->nof_np
);
2648 /* If state expired, make sure we're not holding onto any stale delegations */
2649 lck_mtx_lock(&nmp
->nm_lock
);
2650 if ((nmp
->nm_vers
>= NFS_VER4
) && (nmp
->nm_state
& NFSSTA_RECOVER_EXPIRED
)) {
2652 TAILQ_FOREACH_SAFE(np
, &nmp
->nm_delegations
, n_dlink
, nextnp
) {
2653 lck_mtx_unlock(&nmp
->nm_lock
);
2654 nfs4_expired_check_delegation(np
, vfs_context_kernel());
2655 lck_mtx_lock(&nmp
->nm_lock
);
2656 if (nextnp
== NFSNOLIST
)
2660 nmp
->nm_state
&= ~(NFSSTA_RECOVER
|NFSSTA_RECOVER_EXPIRED
);
2661 wakeup(&nmp
->nm_state
);
2662 printf("nfs recovery completed for %s, 0x%x\n",
2663 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2664 lck_mtx_unlock(&nmp
->nm_lock
);
2666 printf("nfs recovery failed for %s, 0x%x, error %d\n",
2667 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);