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>
73 * NFS_MAX_WHO is the maximum length of a string representation used
74 * in as an ace who, owner, or group. There is no explicit limit in the
75 * protocol, however the kauth routines have a limit of MAPATHLEN for
76 * strings including the trailing null character, so we impose that
77 * limit. This should be changed if kauth routines change.
79 * We also want some reasonable maximum, as 32 bits worth of string length
80 * is liable to cause problems. At the very least this limit must guarantee
81 * that any express that contains the 32 bit length from off the wire used in
82 * allocations does not overflow.
84 #define NFS_MAX_WHO MAXPATHLEN
87 * Create the unique client ID to use for this mount.
89 * Format: unique ID + en0_address + server_address + mntfromname + mntonname
91 * We could possibly use one client ID for all mounts of the same server;
92 * however, that would complicate some aspects of state management.
94 * Each mount socket connection sends a SETCLIENTID. If the ID is the same but
95 * the verifier (mounttime) changes, then all previous (mounts') state gets dropped.
97 * State is typically managed per-mount and in order to keep it that way
98 * each mount needs to use a separate client ID. However, we also need to
99 * make sure that each mount uses the same client ID each time.
101 * In an attempt to differentiate mounts we include the mntfromname and mntonname
102 * strings to the client ID (as long as they fit). We also make sure that the
103 * value does not conflict with any existing values in use (changing the unique ID).
105 * Note that info such as the server's address may change over the lifetime of the
106 * mount. But the client ID will not be updated because we don't want it changing
107 * simply because we switched to a different server address.
110 nfs4_init_clientid(struct nfsmount
*nmp
)
112 struct nfs_client_id
*ncip
, *ncip2
;
113 struct sockaddr
*saddr
;
114 int error
, len
, len2
, cmp
;
115 struct vfsstatfs
*vsfs
;
117 static uint8_t en0addr
[6];
118 static uint8_t en0addr_set
= 0;
120 lck_mtx_lock(nfs_global_mutex
);
122 ifnet_t interface
= NULL
;
123 error
= ifnet_find_by_name("en0", &interface
);
125 error
= ifnet_lladdr_copy_bytes(interface
, en0addr
, sizeof(en0addr
));
127 printf("nfs4_init_clientid: error getting en0 address, %d\n", error
);
131 ifnet_release(interface
);
133 lck_mtx_unlock(nfs_global_mutex
);
135 MALLOC(ncip
, struct nfs_client_id
*, sizeof(struct nfs_client_id
), M_TEMP
, M_WAITOK
);
139 vsfs
= vfs_statfs(nmp
->nm_mountp
);
140 saddr
= nmp
->nm_saddr
;
141 ncip
->nci_idlen
= sizeof(uint32_t) + sizeof(en0addr
) + saddr
->sa_len
+
142 strlen(vsfs
->f_mntfromname
) + 1 + strlen(vsfs
->f_mntonname
) + 1;
143 if (ncip
->nci_idlen
> NFS4_OPAQUE_LIMIT
)
144 ncip
->nci_idlen
= NFS4_OPAQUE_LIMIT
;
145 MALLOC(ncip
->nci_id
, char *, ncip
->nci_idlen
, M_TEMP
, M_WAITOK
);
151 *(uint32_t*)ncip
->nci_id
= 0;
152 len
= sizeof(uint32_t);
153 len2
= min(sizeof(en0addr
), ncip
->nci_idlen
-len
);
154 bcopy(en0addr
, &ncip
->nci_id
[len
], len2
);
155 len
+= sizeof(en0addr
);
156 len2
= min(saddr
->sa_len
, ncip
->nci_idlen
-len
);
157 bcopy(saddr
, &ncip
->nci_id
[len
], len2
);
159 if (len
< ncip
->nci_idlen
) {
160 len2
= strlcpy(&ncip
->nci_id
[len
], vsfs
->f_mntfromname
, ncip
->nci_idlen
-len
);
161 if (len2
< (ncip
->nci_idlen
- len
))
164 len
= ncip
->nci_idlen
;
166 if (len
< ncip
->nci_idlen
) {
167 len2
= strlcpy(&ncip
->nci_id
[len
], vsfs
->f_mntonname
, ncip
->nci_idlen
-len
);
168 if (len2
< (ncip
->nci_idlen
- len
))
171 len
= ncip
->nci_idlen
;
174 /* make sure the ID is unique, and add it to the sorted list */
175 lck_mtx_lock(nfs_global_mutex
);
176 TAILQ_FOREACH(ncip2
, &nfsclientids
, nci_link
) {
177 if (ncip
->nci_idlen
> ncip2
->nci_idlen
)
179 if (ncip
->nci_idlen
< ncip2
->nci_idlen
)
181 cmp
= bcmp(ncip
->nci_id
+ sizeof(uint32_t),
182 ncip2
->nci_id
+ sizeof(uint32_t),
183 ncip
->nci_idlen
- sizeof(uint32_t));
188 if (*(uint32_t*)ncip
->nci_id
> *(uint32_t*)ncip2
->nci_id
)
190 if (*(uint32_t*)ncip
->nci_id
< *(uint32_t*)ncip2
->nci_id
)
192 *(uint32_t*)ncip
->nci_id
+= 1;
194 if (*(uint32_t*)ncip
->nci_id
)
195 printf("nfs client ID collision (%d) for %s on %s\n", *(uint32_t*)ncip
->nci_id
,
196 vsfs
->f_mntfromname
, vsfs
->f_mntonname
);
198 TAILQ_INSERT_BEFORE(ncip2
, ncip
, nci_link
);
200 TAILQ_INSERT_TAIL(&nfsclientids
, ncip
, nci_link
);
201 nmp
->nm_longid
= ncip
;
202 lck_mtx_unlock(nfs_global_mutex
);
211 nfs4_setclientid(struct nfsmount
*nmp
)
213 uint64_t verifier
, xid
;
214 int error
= 0, status
, numops
;
215 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
218 struct nfsm_chain nmreq
, nmrep
;
219 struct sockaddr_storage ss
;
220 void *sinaddr
= NULL
;
221 char raddr
[MAX_IPv6_STR_LEN
];
222 char uaddr
[MAX_IPv6_STR_LEN
+16];
226 thd
= current_thread();
227 cred
= IS_VALID_CRED(nmp
->nm_mcred
) ? nmp
->nm_mcred
: vfs_context_ucred(vfs_context_kernel());
228 kauth_cred_ref(cred
);
230 nfsm_chain_null(&nmreq
);
231 nfsm_chain_null(&nmrep
);
234 error
= nfs4_init_clientid(nmp
);
238 nfsm_chain_build_alloc_init(error
, &nmreq
, 14 * NFSX_UNSIGNED
+ nmp
->nm_longid
->nci_idlen
);
239 nfsm_chain_add_compound_header(error
, &nmreq
, "setclid", nmp
->nm_minor_vers
, numops
);
241 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SETCLIENTID
);
242 /* nfs_client_id4 client; */
243 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_mounttime
);
244 nfsm_chain_add_32(error
, &nmreq
, nmp
->nm_longid
->nci_idlen
);
245 nfsm_chain_add_opaque(error
, &nmreq
, nmp
->nm_longid
->nci_id
, nmp
->nm_longid
->nci_idlen
);
247 /* cb_client4 callback; */
248 if (!NMFLAG(nmp
, NOCALLBACK
) && nmp
->nm_cbid
&& nfs4_cb_port
&&
249 !sock_getsockname(nmp
->nm_nso
->nso_so
, (struct sockaddr
*)&ss
, sizeof(ss
))) {
250 if (ss
.ss_family
== AF_INET
) {
251 sinaddr
= &((struct sockaddr_in
*)&ss
)->sin_addr
;
253 } else if (ss
.ss_family
== AF_INET6
) {
254 sinaddr
= &((struct sockaddr_in6
*)&ss
)->sin6_addr
;
255 port
= nfs4_cb_port6
;
257 if (sinaddr
&& port
&& (inet_ntop(ss
.ss_family
, sinaddr
, raddr
, sizeof(raddr
)) == raddr
)) {
258 /* assemble r_addr = universal address (nmp->nm_nso->nso_so source IP addr + port) */
259 ualen
= snprintf(uaddr
, sizeof(uaddr
), "%s.%d.%d", raddr
,
260 ((port
>> 8) & 0xff),
262 /* make sure it fit, give up if it didn't */
263 if (ualen
>= (int)sizeof(uaddr
))
268 /* add callback info */
269 nfsm_chain_add_32(error
, &nmreq
, NFS4_CALLBACK_PROG
); /* callback program */
270 if (ss
.ss_family
== AF_INET
)
271 nfsm_chain_add_string(error
, &nmreq
, "tcp", 3); /* callback r_netid */
272 else if (ss
.ss_family
== AF_INET6
)
273 nfsm_chain_add_string(error
, &nmreq
, "tcp6", 4); /* callback r_netid */
274 nfsm_chain_add_string(error
, &nmreq
, uaddr
, ualen
); /* callback r_addr */
275 nfsm_chain_add_32(error
, &nmreq
, nmp
->nm_cbid
); /* callback_ident */
277 /* don't provide valid callback info */
278 nfsm_chain_add_32(error
, &nmreq
, 0); /* callback program */
279 nfsm_chain_add_string(error
, &nmreq
, "", 0); /* callback r_netid */
280 nfsm_chain_add_string(error
, &nmreq
, "", 0); /* callback r_addr */
281 nfsm_chain_add_32(error
, &nmreq
, 0); /* callback_ident */
283 nfsm_chain_build_done(error
, &nmreq
);
284 nfsm_assert(error
, (numops
== 0), EPROTO
);
286 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, NULL
, R_SETUP
, &nmrep
, &xid
, &status
);
287 nfsm_chain_skip_tag(error
, &nmrep
);
288 nfsm_chain_get_32(error
, &nmrep
, numops
);
289 if (!error
&& (numops
!= 1) && status
)
291 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SETCLIENTID
);
292 if (error
== NFSERR_CLID_INUSE
)
293 printf("nfs4_setclientid: client ID in use?\n");
295 nfsm_chain_get_64(error
, &nmrep
, nmp
->nm_clientid
);
296 nfsm_chain_get_64(error
, &nmrep
, verifier
);
297 nfsm_chain_cleanup(&nmreq
);
298 nfsm_chain_cleanup(&nmrep
);
300 // SETCLIENTID_CONFIRM
302 nfsm_chain_build_alloc_init(error
, &nmreq
, 15 * NFSX_UNSIGNED
);
303 nfsm_chain_add_compound_header(error
, &nmreq
, "setclid_conf", nmp
->nm_minor_vers
, numops
);
305 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SETCLIENTID_CONFIRM
);
306 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_clientid
);
307 nfsm_chain_add_64(error
, &nmreq
, verifier
);
308 nfsm_chain_build_done(error
, &nmreq
);
309 nfsm_assert(error
, (numops
== 0), EPROTO
);
311 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
, thd
, cred
, NULL
, R_SETUP
, &nmrep
, &xid
, &status
);
312 nfsm_chain_skip_tag(error
, &nmrep
);
313 nfsm_chain_get_32(error
, &nmrep
, numops
);
314 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SETCLIENTID_CONFIRM
);
316 printf("nfs4_setclientid: confirm error %d\n", error
);
317 lck_mtx_lock(&nmp
->nm_lock
);
319 nmp
->nm_state
|= NFSSTA_CLIENTID
;
320 lck_mtx_unlock(&nmp
->nm_lock
);
322 nfsmout_if(error
|| !nmp
->nm_dnp
);
324 /* take the opportunity to refresh fs attributes too */
325 // PUTFH, GETATTR(FS)
327 nfsm_chain_build_alloc_init(error
, &nmreq
, 23 * NFSX_UNSIGNED
);
328 nfsm_chain_add_compound_header(error
, &nmreq
, "setclid_attr", nmp
->nm_minor_vers
, numops
);
330 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
331 nfsm_chain_add_fh(error
, &nmreq
, nmp
->nm_vers
, nmp
->nm_dnp
->n_fhp
, nmp
->nm_dnp
->n_fhsize
);
333 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
334 NFS_CLEAR_ATTRIBUTES(bitmap
);
335 NFS4_PER_FS_ATTRIBUTES(bitmap
);
336 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
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 lck_mtx_lock(&nmp
->nm_lock
);
344 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
345 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
347 error
= nfs4_parsefattr(&nmrep
, &nmp
->nm_fsattr
, NULL
, NULL
, NULL
, NULL
);
348 lck_mtx_unlock(&nmp
->nm_lock
);
349 if (error
) /* ignore any error from the getattr */
352 nfsm_chain_cleanup(&nmreq
);
353 nfsm_chain_cleanup(&nmrep
);
354 kauth_cred_unref(&cred
);
356 printf("nfs4_setclientid failed, %d\n", error
);
361 * renew/check lease state on server
364 nfs4_renew(struct nfsmount
*nmp
, int rpcflag
)
366 int error
= 0, status
, numops
;
368 struct nfsm_chain nmreq
, nmrep
;
371 cred
= IS_VALID_CRED(nmp
->nm_mcred
) ? nmp
->nm_mcred
: vfs_context_ucred(vfs_context_kernel());
372 kauth_cred_ref(cred
);
374 nfsm_chain_null(&nmreq
);
375 nfsm_chain_null(&nmrep
);
379 nfsm_chain_build_alloc_init(error
, &nmreq
, 8 * NFSX_UNSIGNED
);
380 nfsm_chain_add_compound_header(error
, &nmreq
, "renew", nmp
->nm_minor_vers
, numops
);
382 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_RENEW
);
383 nfsm_chain_add_64(error
, &nmreq
, nmp
->nm_clientid
);
384 nfsm_chain_build_done(error
, &nmreq
);
385 nfsm_assert(error
, (numops
== 0), EPROTO
);
387 error
= nfs_request2(NULL
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
388 current_thread(), cred
, NULL
, rpcflag
, &nmrep
, &xid
, &status
);
389 nfsm_chain_skip_tag(error
, &nmrep
);
390 nfsm_chain_get_32(error
, &nmrep
, numops
);
391 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_RENEW
);
393 nfsm_chain_cleanup(&nmreq
);
394 nfsm_chain_cleanup(&nmrep
);
395 kauth_cred_unref(&cred
);
401 * periodic timer to renew lease state on server
404 nfs4_renew_timer(void *param0
, __unused
void *param1
)
406 struct nfsmount
*nmp
= param0
;
408 int error
= 0, interval
;
410 lck_mtx_lock(&nmp
->nm_lock
);
411 clientid
= nmp
->nm_clientid
;
412 if ((nmp
->nm_state
& NFSSTA_RECOVER
) || !(nmp
->nm_sockflags
& NMSOCK_READY
)) {
413 lck_mtx_unlock(&nmp
->nm_lock
);
416 lck_mtx_unlock(&nmp
->nm_lock
);
418 error
= nfs4_renew(nmp
, R_RECOVER
);
420 if (error
== ETIMEDOUT
)
421 nfs_need_reconnect(nmp
);
423 printf("nfs4_renew_timer: error %d\n", error
);
424 lck_mtx_lock(&nmp
->nm_lock
);
425 if (error
&& (error
!= ETIMEDOUT
) &&
426 (nmp
->nm_clientid
== clientid
) && !(nmp
->nm_state
& NFSSTA_RECOVER
)) {
427 printf("nfs4_renew_timer: error %d, initiating recovery\n", error
);
428 nfs_need_recover(nmp
, error
);
431 interval
= nmp
->nm_fsattr
.nfsa_lease
/ (error
? 4 : 2);
432 if ((interval
< 1) || (nmp
->nm_state
& NFSSTA_RECOVER
))
434 lck_mtx_unlock(&nmp
->nm_lock
);
435 nfs_interval_timer_start(nmp
->nm_renew_timer
, interval
* 1000);
439 * get the list of supported security flavors
441 * How we get them depends on what args we are given:
445 * YES YES Use the fh and name provided
446 * YES NO 4.1-only just use the fh provided
447 * NO YES Use the node's (or root) fh and the name provided
448 * NO NO Use the node's parent and the node's name (4.1 will just use node's fh)
451 nfs4_secinfo_rpc(struct nfsmount
*nmp
, struct nfsreq_secinfo_args
*siap
, kauth_cred_t cred
, uint32_t *sec
, int *seccountp
)
453 int error
= 0, status
, nfsvers
, numops
, namelen
, fhsize
;
454 vnode_t dvp
= NULLVP
;
457 const char *vname
= NULL
, *name
;
459 struct nfsm_chain nmreq
, nmrep
;
462 if (nfs_mount_gone(nmp
))
464 nfsvers
= nmp
->nm_vers
;
467 nfsm_chain_null(&nmreq
);
468 nfsm_chain_null(&nmrep
);
471 fhsize
= fhp
? siap
->rsia_fhsize
: 0;
472 name
= siap
->rsia_name
;
473 namelen
= name
? siap
->rsia_namelen
: 0;
474 if (name
&& !namelen
)
475 namelen
= strlen(name
);
477 if (!np
) /* use PUTROOTFH */
480 fhsize
= np
->n_fhsize
;
487 nfs_node_lock_force(np
);
488 if ((vnode_vtype(NFSTOV(np
)) != VDIR
) && np
->n_sillyrename
) {
490 * The node's been sillyrenamed, so we need to use
491 * the sillyrename directory/name to do the open.
493 struct nfs_sillyrename
*nsp
= np
->n_sillyrename
;
496 if ((error
= vnode_get(dvp
))) {
501 fhsize
= dnp
->n_fhsize
;
502 name
= nsp
->nsr_name
;
503 namelen
= nsp
->nsr_namlen
;
506 * [sigh] We can't trust VFS to get the parent right for named
507 * attribute nodes. (It likes to reparent the nodes after we've
508 * created them.) Luckily we can probably get the right parent
509 * from the n_parent we have stashed away.
511 if ((np
->n_vattr
.nva_flags
& NFS_FFLAG_IS_ATTR
) &&
512 (((dvp
= np
->n_parent
)) && (error
= vnode_get(dvp
))))
515 dvp
= vnode_getparent(NFSTOV(np
));
516 vname
= vnode_getname(NFSTOV(np
));
517 if (!dvp
|| !vname
) {
525 fhsize
= dnp
->n_fhsize
;
527 namelen
= strnlen(vname
, MAXPATHLEN
);
532 // PUT(ROOT)FH + SECINFO
534 nfsm_chain_build_alloc_init(error
, &nmreq
,
535 4 * NFSX_UNSIGNED
+ NFSX_FH(nfsvers
) + nfsm_rndup(namelen
));
536 nfsm_chain_add_compound_header(error
, &nmreq
, "secinfo", nmp
->nm_minor_vers
, numops
);
539 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
540 nfsm_chain_add_fh(error
, &nmreq
, nfsvers
, fhp
, fhsize
);
542 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTROOTFH
);
545 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_SECINFO
);
546 nfsm_chain_add_name(error
, &nmreq
, name
, namelen
, nmp
);
547 nfsm_chain_build_done(error
, &nmreq
);
548 nfsm_assert(error
, (numops
== 0), EPROTO
);
550 error
= nfs_request2(np
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
551 current_thread(), cred
, NULL
, 0, &nmrep
, &xid
, &status
);
552 nfsm_chain_skip_tag(error
, &nmrep
);
553 nfsm_chain_get_32(error
, &nmrep
, numops
);
554 nfsm_chain_op_check(error
, &nmrep
, fhp
? NFS_OP_PUTFH
: NFS_OP_PUTROOTFH
);
555 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_SECINFO
);
557 error
= nfsm_chain_get_secinfo(&nmrep
, sec
, seccountp
);
559 nfsm_chain_cleanup(&nmreq
);
560 nfsm_chain_cleanup(&nmrep
);
562 vnode_putname(vname
);
569 * Parse an NFSv4 SECINFO array to an array of pseudo flavors.
570 * (Note: also works for MOUNTv3 security arrays.)
573 nfsm_chain_get_secinfo(struct nfsm_chain
*nmc
, uint32_t *sec
, int *seccountp
)
575 int error
= 0, secmax
, seccount
, srvcount
;
576 uint32_t flavor
, val
;
579 seccount
= srvcount
= 0;
583 nfsm_chain_get_32(error
, nmc
, srvcount
);
584 while (!error
&& (srvcount
> 0) && (seccount
< secmax
)) {
585 nfsm_chain_get_32(error
, nmc
, flavor
);
593 sec
[seccount
++] = flavor
;
596 /* we only recognize KRB5, KRB5I, KRB5P */
597 nfsm_chain_get_32(error
, nmc
, val
); /* OID length */
599 if (val
!= sizeof(krb5_mech_oid
)) {
600 nfsm_chain_adv(error
, nmc
, val
);
601 nfsm_chain_adv(error
, nmc
, 2*NFSX_UNSIGNED
);
604 nfsm_chain_get_opaque(error
, nmc
, val
, oid
); /* OID bytes */
606 if (bcmp(oid
, krb5_mech_oid
, sizeof(krb5_mech_oid
))) {
607 nfsm_chain_adv(error
, nmc
, 2*NFSX_UNSIGNED
);
610 nfsm_chain_get_32(error
, nmc
, val
); /* QOP */
611 nfsm_chain_get_32(error
, nmc
, val
); /* SERVICE */
614 case RPCSEC_GSS_SVC_NONE
:
615 sec
[seccount
++] = RPCAUTH_KRB5
;
617 case RPCSEC_GSS_SVC_INTEGRITY
:
618 sec
[seccount
++] = RPCAUTH_KRB5I
;
620 case RPCSEC_GSS_SVC_PRIVACY
:
621 sec
[seccount
++] = RPCAUTH_KRB5P
;
630 *seccountp
= seccount
;
636 * Fetch the FS_LOCATIONS attribute for the node found at directory/name.
639 nfs4_get_fs_locations(
640 struct nfsmount
*nmp
,
646 struct nfs_fs_locations
*nfslsp
)
648 int error
= 0, numops
, status
;
649 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
650 struct nfsreq rq
, *req
= &rq
;
651 struct nfsreq_secinfo_args si
;
652 struct nfsm_chain nmreq
, nmrep
;
657 fhsize
= dnp
->n_fhsize
;
662 nfsm_chain_null(&nmreq
);
663 nfsm_chain_null(&nmrep
);
665 NFSREQ_SECINFO_SET(&si
, NULL
, fhp
, fhsize
, name
, 0);
667 nfsm_chain_build_alloc_init(error
, &nmreq
, 18 * NFSX_UNSIGNED
);
668 nfsm_chain_add_compound_header(error
, &nmreq
, "fs_locations", nmp
->nm_minor_vers
, numops
);
670 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_PUTFH
);
671 nfsm_chain_add_fh(error
, &nmreq
, NFS_VER4
, fhp
, fhsize
);
673 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_LOOKUP
);
674 nfsm_chain_add_name(error
, &nmreq
, name
, strlen(name
), nmp
);
676 nfsm_chain_add_32(error
, &nmreq
, NFS_OP_GETATTR
);
677 NFS_CLEAR_ATTRIBUTES(bitmap
);
678 NFS_BITMAP_SET(bitmap
, NFS_FATTR_FS_LOCATIONS
);
679 nfsm_chain_add_bitmap(error
, &nmreq
, bitmap
, NFS_ATTR_BITMAP_LEN
);
680 nfsm_chain_build_done(error
, &nmreq
);
681 nfsm_assert(error
, (numops
== 0), EPROTO
);
683 error
= nfs_request_async(dnp
, nmp
->nm_mountp
, &nmreq
, NFSPROC4_COMPOUND
,
684 vfs_context_thread(ctx
), vfs_context_ucred(ctx
), &si
, 0, NULL
, &req
);
686 error
= nfs_request_async_finish(req
, &nmrep
, &xid
, &status
);
687 nfsm_chain_skip_tag(error
, &nmrep
);
688 nfsm_chain_get_32(error
, &nmrep
, numops
);
689 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
690 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_LOOKUP
);
691 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
693 error
= nfs4_parsefattr(&nmrep
, NULL
, NULL
, NULL
, NULL
, nfslsp
);
695 nfsm_chain_cleanup(&nmrep
);
696 nfsm_chain_cleanup(&nmreq
);
701 * Referral trigger nodes may not have many attributes provided by the
702 * server, so put some default values in place.
705 nfs4_default_attrs_for_referral_trigger(
709 struct nfs_vattr
*nvap
,
716 nvap
->nva_flags
= NFS_FFLAG_TRIGGER
| NFS_FFLAG_TRIGGER_REFERRAL
;
717 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TYPE
)) {
718 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TYPE
);
719 nvap
->nva_type
= VDIR
;
721 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FSID
)) {
722 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_FSID
);
723 nvap
->nva_fsid
.major
= 0;
724 nvap
->nva_fsid
.minor
= 0;
726 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_OWNER
) && dnp
) {
727 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_OWNER
);
728 nvap
->nva_uid
= dnp
->n_vattr
.nva_uid
;
729 nvap
->nva_uuuid
= dnp
->n_vattr
.nva_uuuid
;
731 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_OWNER_GROUP
) && dnp
) {
732 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_OWNER_GROUP
);
733 nvap
->nva_gid
= dnp
->n_vattr
.nva_gid
;
734 nvap
->nva_guuid
= dnp
->n_vattr
.nva_guuid
;
736 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_MODE
)) {
737 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_MODE
);
738 nvap
->nva_mode
= 0777;
740 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_SIZE
)) {
741 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_SIZE
);
744 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_SPACE_USED
)) {
745 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_SPACE_USED
);
748 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_NUMLINKS
)) {
749 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_NUMLINKS
);
752 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TIME_ACCESS
)) {
753 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TIME_ACCESS
);
754 nvap
->nva_timesec
[NFSTIME_ACCESS
] = now
.tv_sec
;
755 nvap
->nva_timensec
[NFSTIME_ACCESS
] = now
.tv_usec
* 1000;
757 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TIME_MODIFY
)) {
758 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TIME_MODIFY
);
759 nvap
->nva_timesec
[NFSTIME_MODIFY
] = now
.tv_sec
;
760 nvap
->nva_timensec
[NFSTIME_MODIFY
] = now
.tv_usec
* 1000;
762 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_TIME_METADATA
)) {
763 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_TIME_METADATA
);
764 nvap
->nva_timesec
[NFSTIME_CHANGE
] = now
.tv_sec
;
765 nvap
->nva_timensec
[NFSTIME_CHANGE
] = now
.tv_usec
* 1000;
767 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FILEID
)) {
768 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_FILEID
);
769 nvap
->nva_fileid
= 42;
771 if (!NFS_BITMAP_ISSET(nvap
->nva_bitmap
, NFS_FATTR_FILEHANDLE
) && dnp
&& name
&& fhp
) {
772 /* Build a fake filehandle made up of parent node pointer and name */
773 NFS_BITMAP_SET(nvap
->nva_bitmap
, NFS_FATTR_FILEHANDLE
);
774 bcopy(&dnp
, &fhp
->fh_data
[0], sizeof(dnp
));
775 len
= sizeof(fhp
->fh_data
) - sizeof(dnp
);
776 bcopy(name
, &fhp
->fh_data
[0] + sizeof(dnp
), MIN(len
, namelen
));
777 fhp
->fh_len
= sizeof(dnp
) + namelen
;
778 if (fhp
->fh_len
> (int)sizeof(fhp
->fh_data
))
779 fhp
->fh_len
= sizeof(fhp
->fh_data
);
784 * Set NFS bitmap according to what's set in vnode_attr (and supported by the server).
787 nfs_vattr_set_bitmap(struct nfsmount
*nmp
, uint32_t *bitmap
, struct vnode_attr
*vap
)
791 NFS_CLEAR_ATTRIBUTES(bitmap
);
792 if (VATTR_IS_ACTIVE(vap
, va_data_size
))
793 NFS_BITMAP_SET(bitmap
, NFS_FATTR_SIZE
);
794 if (VATTR_IS_ACTIVE(vap
, va_acl
) && (nmp
->nm_fsattr
.nfsa_flags
& NFS_FSFLAG_ACL
))
795 NFS_BITMAP_SET(bitmap
, NFS_FATTR_ACL
);
796 if (VATTR_IS_ACTIVE(vap
, va_flags
)) {
797 NFS_BITMAP_SET(bitmap
, NFS_FATTR_ARCHIVE
);
798 NFS_BITMAP_SET(bitmap
, NFS_FATTR_HIDDEN
);
800 // NFS_BITMAP_SET(bitmap, NFS_FATTR_MIMETYPE)
801 if (VATTR_IS_ACTIVE(vap
, va_mode
) && !NMFLAG(nmp
, ACLONLY
))
802 NFS_BITMAP_SET(bitmap
, NFS_FATTR_MODE
);
803 if (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_uuuid
))
804 NFS_BITMAP_SET(bitmap
, NFS_FATTR_OWNER
);
805 if (VATTR_IS_ACTIVE(vap
, va_gid
) || VATTR_IS_ACTIVE(vap
, va_guuid
))
806 NFS_BITMAP_SET(bitmap
, NFS_FATTR_OWNER_GROUP
);
807 // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
808 if (vap
->va_vaflags
& VA_UTIMES_NULL
) {
809 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
);
810 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
);
812 if (VATTR_IS_ACTIVE(vap
, va_access_time
))
813 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
);
814 if (VATTR_IS_ACTIVE(vap
, va_modify_time
))
815 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
);
817 if (VATTR_IS_ACTIVE(vap
, va_backup_time
))
818 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_BACKUP
);
819 if (VATTR_IS_ACTIVE(vap
, va_create_time
))
820 NFS_BITMAP_SET(bitmap
, NFS_FATTR_TIME_CREATE
);
821 /* and limit to what is supported by server */
822 for (i
=0; i
< NFS_ATTR_BITMAP_LEN
; i
++)
823 bitmap
[i
] &= nmp
->nm_fsattr
.nfsa_supp_attr
[i
];
827 * Convert between NFSv4 and VFS ACE types
830 nfs4_ace_nfstype_to_vfstype(uint32_t nfsacetype
, int *errorp
)
832 switch (nfsacetype
) {
833 case NFS_ACE_ACCESS_ALLOWED_ACE_TYPE
:
834 return KAUTH_ACE_PERMIT
;
835 case NFS_ACE_ACCESS_DENIED_ACE_TYPE
:
836 return KAUTH_ACE_DENY
;
837 case NFS_ACE_SYSTEM_AUDIT_ACE_TYPE
:
838 return KAUTH_ACE_AUDIT
;
839 case NFS_ACE_SYSTEM_ALARM_ACE_TYPE
:
840 return KAUTH_ACE_ALARM
;
847 nfs4_ace_vfstype_to_nfstype(uint32_t vfstype
, int *errorp
)
850 case KAUTH_ACE_PERMIT
:
851 return NFS_ACE_ACCESS_ALLOWED_ACE_TYPE
;
853 return NFS_ACE_ACCESS_DENIED_ACE_TYPE
;
854 case KAUTH_ACE_AUDIT
:
855 return NFS_ACE_SYSTEM_AUDIT_ACE_TYPE
;
856 case KAUTH_ACE_ALARM
:
857 return NFS_ACE_SYSTEM_ALARM_ACE_TYPE
;
864 * Convert between NFSv4 and VFS ACE flags
867 nfs4_ace_nfsflags_to_vfsflags(uint32_t nfsflags
)
869 uint32_t vfsflags
= 0;
871 if (nfsflags
& NFS_ACE_FILE_INHERIT_ACE
)
872 vfsflags
|= KAUTH_ACE_FILE_INHERIT
;
873 if (nfsflags
& NFS_ACE_DIRECTORY_INHERIT_ACE
)
874 vfsflags
|= KAUTH_ACE_DIRECTORY_INHERIT
;
875 if (nfsflags
& NFS_ACE_NO_PROPAGATE_INHERIT_ACE
)
876 vfsflags
|= KAUTH_ACE_LIMIT_INHERIT
;
877 if (nfsflags
& NFS_ACE_INHERIT_ONLY_ACE
)
878 vfsflags
|= KAUTH_ACE_ONLY_INHERIT
;
879 if (nfsflags
& NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG
)
880 vfsflags
|= KAUTH_ACE_SUCCESS
;
881 if (nfsflags
& NFS_ACE_FAILED_ACCESS_ACE_FLAG
)
882 vfsflags
|= KAUTH_ACE_FAILURE
;
883 if (nfsflags
& NFS_ACE_INHERITED_ACE
)
884 vfsflags
|= KAUTH_ACE_INHERITED
;
890 nfs4_ace_vfsflags_to_nfsflags(uint32_t vfsflags
)
892 uint32_t nfsflags
= 0;
894 if (vfsflags
& KAUTH_ACE_FILE_INHERIT
)
895 nfsflags
|= NFS_ACE_FILE_INHERIT_ACE
;
896 if (vfsflags
& KAUTH_ACE_DIRECTORY_INHERIT
)
897 nfsflags
|= NFS_ACE_DIRECTORY_INHERIT_ACE
;
898 if (vfsflags
& KAUTH_ACE_LIMIT_INHERIT
)
899 nfsflags
|= NFS_ACE_NO_PROPAGATE_INHERIT_ACE
;
900 if (vfsflags
& KAUTH_ACE_ONLY_INHERIT
)
901 nfsflags
|= NFS_ACE_INHERIT_ONLY_ACE
;
902 if (vfsflags
& KAUTH_ACE_SUCCESS
)
903 nfsflags
|= NFS_ACE_SUCCESSFUL_ACCESS_ACE_FLAG
;
904 if (vfsflags
& KAUTH_ACE_FAILURE
)
905 nfsflags
|= NFS_ACE_FAILED_ACCESS_ACE_FLAG
;
906 if (vfsflags
& KAUTH_ACE_INHERITED
)
907 nfsflags
|= NFS_ACE_INHERITED_ACE
;
913 * Convert between NFSv4 ACE access masks and VFS access rights
916 nfs4_ace_nfsmask_to_vfsrights(uint32_t nfsmask
)
918 uint32_t vfsrights
= 0;
920 if (nfsmask
& NFS_ACE_READ_DATA
)
921 vfsrights
|= KAUTH_VNODE_READ_DATA
;
922 if (nfsmask
& NFS_ACE_LIST_DIRECTORY
)
923 vfsrights
|= KAUTH_VNODE_LIST_DIRECTORY
;
924 if (nfsmask
& NFS_ACE_WRITE_DATA
)
925 vfsrights
|= KAUTH_VNODE_WRITE_DATA
;
926 if (nfsmask
& NFS_ACE_ADD_FILE
)
927 vfsrights
|= KAUTH_VNODE_ADD_FILE
;
928 if (nfsmask
& NFS_ACE_APPEND_DATA
)
929 vfsrights
|= KAUTH_VNODE_APPEND_DATA
;
930 if (nfsmask
& NFS_ACE_ADD_SUBDIRECTORY
)
931 vfsrights
|= KAUTH_VNODE_ADD_SUBDIRECTORY
;
932 if (nfsmask
& NFS_ACE_READ_NAMED_ATTRS
)
933 vfsrights
|= KAUTH_VNODE_READ_EXTATTRIBUTES
;
934 if (nfsmask
& NFS_ACE_WRITE_NAMED_ATTRS
)
935 vfsrights
|= KAUTH_VNODE_WRITE_EXTATTRIBUTES
;
936 if (nfsmask
& NFS_ACE_EXECUTE
)
937 vfsrights
|= KAUTH_VNODE_EXECUTE
;
938 if (nfsmask
& NFS_ACE_DELETE_CHILD
)
939 vfsrights
|= KAUTH_VNODE_DELETE_CHILD
;
940 if (nfsmask
& NFS_ACE_READ_ATTRIBUTES
)
941 vfsrights
|= KAUTH_VNODE_READ_ATTRIBUTES
;
942 if (nfsmask
& NFS_ACE_WRITE_ATTRIBUTES
)
943 vfsrights
|= KAUTH_VNODE_WRITE_ATTRIBUTES
;
944 if (nfsmask
& NFS_ACE_DELETE
)
945 vfsrights
|= KAUTH_VNODE_DELETE
;
946 if (nfsmask
& NFS_ACE_READ_ACL
)
947 vfsrights
|= KAUTH_VNODE_READ_SECURITY
;
948 if (nfsmask
& NFS_ACE_WRITE_ACL
)
949 vfsrights
|= KAUTH_VNODE_WRITE_SECURITY
;
950 if (nfsmask
& NFS_ACE_WRITE_OWNER
)
951 vfsrights
|= KAUTH_VNODE_CHANGE_OWNER
;
952 if (nfsmask
& NFS_ACE_SYNCHRONIZE
)
953 vfsrights
|= KAUTH_VNODE_SYNCHRONIZE
;
954 if ((nfsmask
& NFS_ACE_GENERIC_READ
) == NFS_ACE_GENERIC_READ
)
955 vfsrights
|= KAUTH_ACE_GENERIC_READ
;
956 if ((nfsmask
& NFS_ACE_GENERIC_WRITE
) == NFS_ACE_GENERIC_WRITE
)
957 vfsrights
|= KAUTH_ACE_GENERIC_WRITE
;
958 if ((nfsmask
& NFS_ACE_GENERIC_EXECUTE
) == NFS_ACE_GENERIC_EXECUTE
)
959 vfsrights
|= KAUTH_ACE_GENERIC_EXECUTE
;
965 nfs4_ace_vfsrights_to_nfsmask(uint32_t vfsrights
)
967 uint32_t nfsmask
= 0;
969 if (vfsrights
& KAUTH_VNODE_READ_DATA
)
970 nfsmask
|= NFS_ACE_READ_DATA
;
971 if (vfsrights
& KAUTH_VNODE_LIST_DIRECTORY
)
972 nfsmask
|= NFS_ACE_LIST_DIRECTORY
;
973 if (vfsrights
& KAUTH_VNODE_WRITE_DATA
)
974 nfsmask
|= NFS_ACE_WRITE_DATA
;
975 if (vfsrights
& KAUTH_VNODE_ADD_FILE
)
976 nfsmask
|= NFS_ACE_ADD_FILE
;
977 if (vfsrights
& KAUTH_VNODE_APPEND_DATA
)
978 nfsmask
|= NFS_ACE_APPEND_DATA
;
979 if (vfsrights
& KAUTH_VNODE_ADD_SUBDIRECTORY
)
980 nfsmask
|= NFS_ACE_ADD_SUBDIRECTORY
;
981 if (vfsrights
& KAUTH_VNODE_READ_EXTATTRIBUTES
)
982 nfsmask
|= NFS_ACE_READ_NAMED_ATTRS
;
983 if (vfsrights
& KAUTH_VNODE_WRITE_EXTATTRIBUTES
)
984 nfsmask
|= NFS_ACE_WRITE_NAMED_ATTRS
;
985 if (vfsrights
& KAUTH_VNODE_EXECUTE
)
986 nfsmask
|= NFS_ACE_EXECUTE
;
987 if (vfsrights
& KAUTH_VNODE_DELETE_CHILD
)
988 nfsmask
|= NFS_ACE_DELETE_CHILD
;
989 if (vfsrights
& KAUTH_VNODE_READ_ATTRIBUTES
)
990 nfsmask
|= NFS_ACE_READ_ATTRIBUTES
;
991 if (vfsrights
& KAUTH_VNODE_WRITE_ATTRIBUTES
)
992 nfsmask
|= NFS_ACE_WRITE_ATTRIBUTES
;
993 if (vfsrights
& KAUTH_VNODE_DELETE
)
994 nfsmask
|= NFS_ACE_DELETE
;
995 if (vfsrights
& KAUTH_VNODE_READ_SECURITY
)
996 nfsmask
|= NFS_ACE_READ_ACL
;
997 if (vfsrights
& KAUTH_VNODE_WRITE_SECURITY
)
998 nfsmask
|= NFS_ACE_WRITE_ACL
;
999 if (vfsrights
& KAUTH_VNODE_CHANGE_OWNER
)
1000 nfsmask
|= NFS_ACE_WRITE_OWNER
;
1001 if (vfsrights
& KAUTH_VNODE_SYNCHRONIZE
)
1002 nfsmask
|= NFS_ACE_SYNCHRONIZE
;
1003 if (vfsrights
& KAUTH_ACE_GENERIC_READ
)
1004 nfsmask
|= NFS_ACE_GENERIC_READ
;
1005 if (vfsrights
& KAUTH_ACE_GENERIC_WRITE
)
1006 nfsmask
|= NFS_ACE_GENERIC_WRITE
;
1007 if (vfsrights
& KAUTH_ACE_GENERIC_EXECUTE
)
1008 nfsmask
|= NFS_ACE_GENERIC_EXECUTE
;
1009 if (vfsrights
& KAUTH_ACE_GENERIC_ALL
)
1010 nfsmask
|= (KAUTH_ACE_GENERIC_READ
|KAUTH_ACE_GENERIC_WRITE
|NFS_ACE_GENERIC_EXECUTE
);
1016 * Map an NFSv4 ID string to a VFS guid.
1018 * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
1021 nfs4_id2guid(/*const*/ char *id
, guid_t
*guidp
, int isgroup
)
1023 int error1
= 0, error
= 0, compare
;
1024 guid_t guid1
, guid2
, *gp
;
1027 char *p
, *at
, *new_id
= NULL
;
1029 *guidp
= kauth_null_guid
;
1030 compare
= ((nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) &&
1031 (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_COMPARE_RESULTS
));
1032 unknown
= (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_UNKNOWN_IS_99
) ? 99 : -2;
1035 * First check if it is just a simple numeric ID string or a special "XXX@" name.
1036 * If it's a number, there's no need trying to ask the IDMAP service to map it.
1037 * If it's a special "XXX@" name, we want to make sure to treat it as a group.
1043 if ((*p
< '0') || (*p
> '9'))
1049 if (at
&& !at
[1] && !isgroup
)
1050 isgroup
= 1; /* special "XXX@" names should always be treated as groups */
1052 /* must be numeric ID (or empty) */
1053 num
= *id
? strtol(id
, NULL
, 10) : unknown
;
1055 /* Since we are not initilizing guid1 and guid2, skip compare */
1060 /* Handle nfs4 domain first */
1062 /* Try mapping nfs4 domain */
1063 char *dsnode
, *nfs4domain
= at
+ 1;
1064 size_t otw_domain_len
= strnlen(nfs4domain
, MAXPATHLEN
);
1065 int otw_id_2_at_len
= at
- id
+ 1;
1067 MALLOC(dsnode
, char*, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1069 /* first try to map nfs4 domain to dsnode for scoped lookups */
1070 memset(dsnode
, 0, MAXPATHLEN
);
1071 error
= kauth_cred_nfs4domain2dsnode(nfs4domain
, dsnode
);
1073 /* Success! Make new id be id@dsnode */
1074 int dsnode_len
= strnlen(dsnode
, MAXPATHLEN
);
1075 int new_id_len
= otw_id_2_at_len
+ dsnode_len
+ 1;
1077 MALLOC(new_id
, char*, new_id_len
, M_NAMEI
, M_WAITOK
);
1079 (void)strlcpy(new_id
, id
, otw_id_2_at_len
+ 1);
1080 (void)strlcpy(new_id
+ otw_id_2_at_len
, dsnode
, dsnode_len
+ 1);
1083 while (*at
++ != '@');
1087 /* Bummer:-( See if default nfs4 set for unscoped lookup */
1088 size_t default_domain_len
= strnlen(nfs4_domain
, MAXPATHLEN
);
1090 if ((otw_domain_len
== default_domain_len
) && (strncmp(nfs4domain
, nfs4_domain
, otw_domain_len
) == 0)) {
1091 /* Woohoo! We have matching domains, do unscoped lookups */
1095 FREE(dsnode
, M_NAMEI
);
1098 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
) {
1099 printf("nfs4_id2guid: after domain mapping id is %s\n", id
);
1103 /* Now try to do actual id mapping */
1104 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) {
1106 * Ask the ID mapping service to map the ID string to a GUID.
1108 * [sigh] this isn't a "pwnam/grnam" it's an NFS ID string!
1110 gp
= compare
? &guid1
: guidp
;
1112 error
= kauth_cred_grnam2guid(id
, gp
);
1114 error
= kauth_cred_pwnam2guid(id
, gp
);
1115 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1116 printf("nfs4_id2guid: idmap failed for %s %s error %d\n", id
, isgroup
? "G" : " ", error
);
1117 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
))
1118 printf("nfs4_id2guid: idmap for %s %s got guid "
1119 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1120 id
, isgroup
? "G" : " ",
1121 gp
->g_guid
[0], gp
->g_guid
[1], gp
->g_guid
[2], gp
->g_guid
[3],
1122 gp
->g_guid
[4], gp
->g_guid
[5], gp
->g_guid
[6], gp
->g_guid
[7],
1123 gp
->g_guid
[8], gp
->g_guid
[9], gp
->g_guid
[10], gp
->g_guid
[11],
1124 gp
->g_guid
[12], gp
->g_guid
[13], gp
->g_guid
[14], gp
->g_guid
[15]);
1127 if (error
|| compare
|| !(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
)) {
1129 * fallback path... see if we can come up with an answer ourselves.
1131 gp
= compare
? &guid2
: guidp
;
1133 if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_WELLKNOWN_IDS
) && at
&& !at
[1]) {
1134 /* must be a special ACE "who" ID */
1135 bzero(&sid
, sizeof(sid
));
1137 sid
.sid_authcount
= 1;
1138 if (!strcmp(id
, "OWNER@")) {
1140 sid
.sid_authority
[5] = 3;
1141 sid
.sid_authorities
[0] = 0;
1142 } else if (!strcmp(id
, "GROUP@")) {
1144 sid
.sid_authority
[5] = 3;
1145 sid
.sid_authorities
[0] = 1;
1146 } else if (!strcmp(id
, "EVERYONE@")) {
1148 sid
.sid_authority
[5] = 1;
1149 sid
.sid_authorities
[0] = 0;
1150 } else if (!strcmp(id
, "INTERACTIVE@")) {
1152 sid
.sid_authority
[5] = 5;
1153 sid
.sid_authorities
[0] = 4;
1154 } else if (!strcmp(id
, "NETWORK@")) {
1156 sid
.sid_authority
[5] = 5;
1157 sid
.sid_authorities
[0] = 2;
1158 } else if (!strcmp(id
, "DIALUP@")) {
1160 sid
.sid_authority
[5] = 5;
1161 sid
.sid_authorities
[0] = 1;
1162 } else if (!strcmp(id
, "BATCH@")) {
1164 sid
.sid_authority
[5] = 5;
1165 sid
.sid_authorities
[0] = 3;
1166 } else if (!strcmp(id
, "ANONYMOUS@")) {
1168 sid
.sid_authority
[5] = 5;
1169 sid
.sid_authorities
[0] = 7;
1170 } else if (!strcmp(id
, "AUTHENTICATED@")) {
1172 sid
.sid_authority
[5] = 5;
1173 sid
.sid_authorities
[0] = 11;
1174 } else if (!strcmp(id
, "SERVICE@")) {
1176 sid
.sid_authority
[5] = 5;
1177 sid
.sid_authorities
[0] = 6;
1180 sid
.sid_authority
[5] = 0;
1181 sid
.sid_authorities
[0] = 0;
1183 error
= kauth_cred_ntsid2guid(&sid
, gp
);
1185 if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS
) && at
) {
1186 /* must be user@domain */
1187 /* try to identify some well-known IDs */
1188 if (!strncmp(id
, "root@", 5))
1190 else if (!strncmp(id
, "wheel@", 6))
1192 else if (!strncmp(id
, "nobody@", 7))
1194 else if (!strncmp(id
, "nfsnobody@", 10))
1198 } else if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS
) && !strcmp(id
, "nobody")) {
1205 error
= kauth_cred_gid2guid((gid_t
)num
, gp
);
1207 error
= kauth_cred_uid2guid((uid_t
)num
, gp
);
1209 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1210 printf("nfs4_id2guid: fallback map failed for %s %s error %d\n", id
, isgroup
? "G" : " ", error
);
1211 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
))
1212 printf("nfs4_id2guid: fallback map for %s %s got guid "
1213 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1214 id
, isgroup
? "G" : " ",
1215 gp
->g_guid
[0], gp
->g_guid
[1], gp
->g_guid
[2], gp
->g_guid
[3],
1216 gp
->g_guid
[4], gp
->g_guid
[5], gp
->g_guid
[6], gp
->g_guid
[7],
1217 gp
->g_guid
[8], gp
->g_guid
[9], gp
->g_guid
[10], gp
->g_guid
[11],
1218 gp
->g_guid
[12], gp
->g_guid
[13], gp
->g_guid
[14], gp
->g_guid
[15]);
1222 /* compare the results, log if different */
1223 if (!error1
&& !error
) {
1224 if (!kauth_guid_equal(&guid1
, &guid2
))
1225 printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1226 "idmap %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x "
1227 "fallback %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1228 id
, isgroup
? "G" : " ",
1229 guid1
.g_guid
[0], guid1
.g_guid
[1], guid1
.g_guid
[2], guid1
.g_guid
[3],
1230 guid1
.g_guid
[4], guid1
.g_guid
[5], guid1
.g_guid
[6], guid1
.g_guid
[7],
1231 guid1
.g_guid
[8], guid1
.g_guid
[9], guid1
.g_guid
[10], guid1
.g_guid
[11],
1232 guid1
.g_guid
[12], guid1
.g_guid
[13], guid1
.g_guid
[14], guid1
.g_guid
[15],
1233 guid2
.g_guid
[0], guid2
.g_guid
[1], guid2
.g_guid
[2], guid2
.g_guid
[3],
1234 guid2
.g_guid
[4], guid2
.g_guid
[5], guid2
.g_guid
[6], guid2
.g_guid
[7],
1235 guid2
.g_guid
[8], guid2
.g_guid
[9], guid2
.g_guid
[10], guid2
.g_guid
[11],
1236 guid2
.g_guid
[12], guid2
.g_guid
[13], guid2
.g_guid
[14], guid2
.g_guid
[15]);
1237 /* copy idmap result to output guid */
1239 } else if (error1
&& !error
) {
1240 printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1242 "fallback %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x\n",
1243 id
, isgroup
? "G" : " ",
1245 guid2
.g_guid
[0], guid2
.g_guid
[1], guid2
.g_guid
[2], guid2
.g_guid
[3],
1246 guid2
.g_guid
[4], guid2
.g_guid
[5], guid2
.g_guid
[6], guid2
.g_guid
[7],
1247 guid2
.g_guid
[8], guid2
.g_guid
[9], guid2
.g_guid
[10], guid2
.g_guid
[11],
1248 guid2
.g_guid
[12], guid2
.g_guid
[13], guid2
.g_guid
[14], guid2
.g_guid
[15]);
1249 /* copy fallback result to output guid */
1251 } else if (!error1
&& error
) {
1252 printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1253 "idmap %02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x "
1254 "fallback error %d\n",
1255 id
, isgroup
? "G" : " ",
1256 guid1
.g_guid
[0], guid1
.g_guid
[1], guid1
.g_guid
[2], guid1
.g_guid
[3],
1257 guid1
.g_guid
[4], guid1
.g_guid
[5], guid1
.g_guid
[6], guid1
.g_guid
[7],
1258 guid1
.g_guid
[8], guid1
.g_guid
[9], guid1
.g_guid
[10], guid1
.g_guid
[11],
1259 guid1
.g_guid
[12], guid1
.g_guid
[13], guid1
.g_guid
[14], guid1
.g_guid
[15],
1261 /* copy idmap result to output guid */
1265 if (error1
!= error
)
1266 printf("nfs4_id2guid: idmap/fallback results differ for %s %s - "
1267 "idmap error %d fallback error %d\n",
1268 id
, isgroup
? "G" : " ", error1
, error
);
1272 /* restore @ symbol in case we clobered for unscoped lookup */
1273 if (at
&& *at
== '\0')
1276 /* free mapped domain id string */
1284 * Map a VFS guid to an NFSv4 ID string.
1286 * Try to use the ID mapping service... but we may fallback to trying to do it ourselves.
1289 nfs4_guid2id(guid_t
*guidp
, char *id
, int *idlen
, int isgroup
)
1291 int error1
= 0, error
= 0, compare
;
1292 int id1len
, id2len
, len
;
1293 char *id1buf
, *id1
, *at
;
1295 const char *id2
= NULL
;
1297 id1buf
= id1
= NULL
;
1298 id1len
= id2len
= 0;
1299 compare
= ((nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) &&
1300 (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_COMPARE_RESULTS
));
1302 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
) {
1304 * Ask the ID mapping service to map the GUID to an ID string.
1306 * [sigh] this isn't a "pwnam" it's an NFS id string!
1310 * Stupid kauth_cred_guid2pwnam() function requires that the buffer
1311 * be at least MAXPATHLEN bytes long even though most if not all ID
1312 * strings will be much much shorter than that.
1314 if (compare
|| (*idlen
< MAXPATHLEN
)) {
1315 MALLOC_ZONE(id1buf
, char*, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1319 id1len
= MAXPATHLEN
;
1325 memset(id1
, 0, id1len
);
1327 error
= kauth_cred_guid2grnam(guidp
, id1
);
1329 error
= kauth_cred_guid2pwnam(guidp
, id1
);
1330 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1331 printf("nfs4_guid2id: idmap failed for "
1332 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1334 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1335 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1336 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1337 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1338 isgroup
? "G" : " ", error
);
1339 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
))
1340 printf("nfs4_guid2id: idmap for "
1341 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1343 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1344 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1345 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1346 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1347 isgroup
? "G" : " ", id1
);
1351 id1len
= strnlen(id1
, id1len
);
1352 } else if (id1
== id1buf
) {
1353 /* copy idmap result to output buffer */
1354 len
= strlcpy(id
, id1
, *idlen
);
1362 if (error
|| compare
|| !(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_USE_IDMAP_SERVICE
)) {
1364 * fallback path... see if we can come up with an answer ourselves.
1369 if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_WELLKNOWN_IDS
)) {
1370 error
= kauth_cred_guid2ntsid(guidp
, &sid
);
1371 if (!error
&& (sid
.sid_kind
== 1) && (sid
.sid_authcount
== 1)) {
1372 /* check if it's one of our well-known ACE WHO names */
1373 if (sid
.sid_authority
[5] == 0) {
1374 if (sid
.sid_authorities
[0] == 0) // S-1-0-0
1375 id2
= "nobody@localdomain";
1376 } else if (sid
.sid_authority
[5] == 1) {
1377 if (sid
.sid_authorities
[0] == 0) // S-1-1-0
1379 } else if (sid
.sid_authority
[5] == 3) {
1380 if (sid
.sid_authorities
[0] == 0) // S-1-3-0
1382 else if (sid
.sid_authorities
[0] == 1) // S-1-3-1
1384 } else if (sid
.sid_authority
[5] == 5) {
1385 if (sid
.sid_authorities
[0] == ntohl(1)) // S-1-5-1
1387 else if (sid
.sid_authorities
[0] == ntohl(2)) // S-1-5-2
1389 else if (sid
.sid_authorities
[0] == ntohl(3)) // S-1-5-3
1391 else if (sid
.sid_authorities
[0] == ntohl(4)) // S-1-5-4
1392 id2
= "INTERACTIVE@";
1393 else if (sid
.sid_authorities
[0] == ntohl(6)) // S-1-5-6
1395 else if (sid
.sid_authorities
[0] == ntohl(7)) // S-1-5-7
1397 else if (sid
.sid_authorities
[0] == ntohl(11)) // S-1-5-11
1398 id2
= "AUTHENTICATED@";
1403 /* OK, let's just try mapping it to a UID/GID */
1405 error
= kauth_cred_guid2gid(guidp
, (gid_t
*)&uid
);
1407 error
= kauth_cred_guid2uid(guidp
, &uid
);
1409 if (!(nfs_idmap_ctrl
& NFS_IDMAP_CTRL_FALLBACK_NO_COMMON_IDS
)) {
1410 /* map well known uid's to strings */
1412 id2
= isgroup
? "wheel@localdomain" : "root@localdomain";
1413 else if (uid
== (uid_t
)-2)
1414 id2
= "nobody@localdomain";
1417 /* or just use a decimal number string. */
1418 snprintf(numbuf
, sizeof(numbuf
), "%d", uid
);
1423 if (error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1424 printf("nfs4_guid2id: fallback map failed for "
1425 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1427 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1428 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1429 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1430 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1431 isgroup
? "G" : " ", error
);
1432 if (!error
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
))
1433 printf("nfs4_guid2id: fallback map for "
1434 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1436 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1437 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1438 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1439 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1440 isgroup
? "G" : " ", id2
);
1441 if (!error
&& id2
) {
1443 id2len
= strnlen(id2
, MAXPATHLEN
);
1445 /* copy fallback result to output buffer */
1446 len
= strlcpy(id
, id2
, *idlen
);
1456 /* compare the results, log if different */
1457 if (!error1
&& !error
) {
1458 if ((id1len
!= id2len
) || strncmp(id1
, id2
, id1len
))
1459 printf("nfs4_guid2id: idmap/fallback results differ for "
1460 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1461 "idmap %s fallback %s\n",
1462 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1463 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1464 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1465 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1466 isgroup
? "G" : " ", id1
, id2
);
1467 if (id1
== id1buf
) {
1468 /* copy idmap result to output buffer */
1469 len
= strlcpy(id
, id1
, *idlen
);
1475 } else if (error1
&& !error
) {
1476 printf("nfs4_guid2id: idmap/fallback results differ for "
1477 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1478 "idmap error %d fallback %s\n",
1479 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1480 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1481 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1482 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1483 isgroup
? "G" : " ", error1
, id2
);
1484 /* copy fallback result to output buffer */
1485 len
= strlcpy(id
, id2
, *idlen
);
1490 } else if (!error1
&& error
) {
1491 printf("nfs4_guid2id: idmap/fallback results differ for "
1492 "%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x_%02x%02x%02x%02x %s "
1493 "idmap %s fallback error %d\n",
1494 guidp
->g_guid
[0], guidp
->g_guid
[1], guidp
->g_guid
[2], guidp
->g_guid
[3],
1495 guidp
->g_guid
[4], guidp
->g_guid
[5], guidp
->g_guid
[6], guidp
->g_guid
[7],
1496 guidp
->g_guid
[8], guidp
->g_guid
[9], guidp
->g_guid
[10], guidp
->g_guid
[11],
1497 guidp
->g_guid
[12], guidp
->g_guid
[13], guidp
->g_guid
[14], guidp
->g_guid
[15],
1498 isgroup
? "G" : " ", id1
, error
);
1499 if (id1
== id1buf
) {
1500 /* copy idmap result to output buffer */
1501 len
= strlcpy(id
, id1
, *idlen
);
1509 if (error1
!= error
)
1510 printf("nfs4_guid2id: idmap/fallback results differ for %s %s - "
1511 "idmap error %d fallback error %d\n",
1512 id
, isgroup
? "G" : " ", error1
, error
);
1517 while (at
&& at
[0] != '@' && at
[0] != '\0' && at
++);
1518 if (at
&& at
[0] == '@' && at
[1] != '\0') {
1519 char *dsnode
= at
+ 1;
1520 int id_2_at_len
= at
- id
+ 1;
1521 char *nfs4domain
, *new_id
;
1522 MALLOC(nfs4domain
, char*, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1525 char *mapped_domain
;
1526 memset(nfs4domain
, 0, MAXPATHLEN
);
1527 error
= kauth_cred_dsnode2nfs4domain(dsnode
, nfs4domain
);
1529 domain_len
= strnlen(nfs4domain
, MAXPATHLEN
);
1530 mapped_domain
= nfs4domain
;
1532 domain_len
= strnlen(nfs4_domain
, MAXPATHLEN
);
1533 mapped_domain
= nfs4_domain
;
1536 MALLOC(new_id
, char*, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1538 strlcpy(new_id
, id
, id_2_at_len
+ 1);
1539 strlcpy(new_id
+ id_2_at_len
, mapped_domain
, domain_len
+ 1);
1540 strlcpy(id
, new_id
, strnlen(new_id
, MAXPATHLEN
) + 1);
1541 *idlen
= strnlen(id
, MAXPATHLEN
);
1542 FREE(new_id
, M_NAMEI
);
1545 FREE(nfs4domain
, M_NAMEI
);
1547 } else if (at
&& at
[0] == '\0') {
1548 int default_domain_len
= strnlen(nfs4_domain
, MAXPATHLEN
);
1550 if (default_domain_len
&& MAXPATHLEN
- *idlen
> default_domain_len
) {
1552 strlcpy(at
+ 1, nfs4_domain
, default_domain_len
+ 1);
1553 *idlen
= strnlen(id
, MAXPATHLEN
);
1557 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_SUCCESSFUL_MAPPINGS
)
1558 printf("nfs4_guid2id: id after nfs4 domain map: %s[%d].\n", id
, *idlen
);
1561 FREE_ZONE(id1buf
, MAXPATHLEN
, M_NAMEI
);
1566 * Set a vnode attr's supported bits according to the given bitmap
1569 nfs_vattr_set_supported(uint32_t *bitmap
, struct vnode_attr
*vap
)
1571 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TYPE
))
1572 VATTR_SET_SUPPORTED(vap
, va_type
);
1573 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHANGE))
1574 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
))
1575 VATTR_SET_SUPPORTED(vap
, va_data_size
);
1576 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FSID
))
1577 VATTR_SET_SUPPORTED(vap
, va_fsid
);
1578 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACL
))
1579 VATTR_SET_SUPPORTED(vap
, va_acl
);
1580 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
))
1581 VATTR_SET_SUPPORTED(vap
, va_flags
);
1582 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEID
))
1583 VATTR_SET_SUPPORTED(vap
, va_fileid
);
1584 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
))
1585 VATTR_SET_SUPPORTED(vap
, va_flags
);
1586 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE))
1587 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
))
1588 VATTR_SET_SUPPORTED(vap
, va_mode
);
1589 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NUMLINKS
))
1590 VATTR_SET_SUPPORTED(vap
, va_nlink
);
1591 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER
)) {
1592 VATTR_SET_SUPPORTED(vap
, va_uid
);
1593 VATTR_SET_SUPPORTED(vap
, va_uuuid
);
1595 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER_GROUP
)) {
1596 VATTR_SET_SUPPORTED(vap
, va_gid
);
1597 VATTR_SET_SUPPORTED(vap
, va_guuid
);
1599 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RAWDEV
))
1600 VATTR_SET_SUPPORTED(vap
, va_rdev
);
1601 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_USED
))
1602 VATTR_SET_SUPPORTED(vap
, va_total_alloc
);
1603 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYSTEM))
1604 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS
))
1605 VATTR_SET_SUPPORTED(vap
, va_access_time
);
1606 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_BACKUP
))
1607 VATTR_SET_SUPPORTED(vap
, va_backup_time
);
1608 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_CREATE
))
1609 VATTR_SET_SUPPORTED(vap
, va_create_time
);
1610 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_METADATA
))
1611 VATTR_SET_SUPPORTED(vap
, va_change_time
);
1612 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY
))
1613 VATTR_SET_SUPPORTED(vap
, va_modify_time
);
1617 * Parse the attributes that are in the mbuf list and store them in
1618 * the given structures.
1622 struct nfsm_chain
*nmc
,
1623 struct nfs_fsattr
*nfsap
,
1624 struct nfs_vattr
*nvap
,
1627 struct nfs_fs_locations
*nfslsp
)
1629 int error
= 0, error2
, rderror
= 0, attrbytes
;
1630 uint32_t val
, val2
, val3
, i
;
1631 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], len
;
1634 struct nfs_fsattr nfsa_dummy
;
1635 struct nfs_vattr nva_dummy
;
1636 struct dqblk dqb_dummy
;
1637 kauth_acl_t acl
= NULL
;
1638 uint32_t ace_type
, ace_flags
, ace_mask
;
1639 struct nfs_fs_locations nfsls_dummy
;
1640 struct sockaddr_storage ss
;
1642 /* if not interested in some values... throw 'em into a local dummy variable */
1644 nfsap
= &nfsa_dummy
;
1650 nfslsp
= &nfsls_dummy
;
1651 bzero(nfslsp
, sizeof(*nfslsp
));
1653 attrbytes
= val
= val2
= val3
= 0;
1655 slen
= sizeof(sbuf
);
1658 len
= NFS_ATTR_BITMAP_LEN
;
1659 nfsm_chain_get_bitmap(error
, nmc
, bitmap
, len
);
1660 /* add bits to object/fs attr bitmaps */
1661 for (i
=0; i
< NFS_ATTR_BITMAP_LEN
; i
++) {
1662 nvap
->nva_bitmap
[i
] |= bitmap
[i
] & nfs_object_attr_bitmap
[i
];
1663 nfsap
->nfsa_bitmap
[i
] |= bitmap
[i
] & nfs_fs_attr_bitmap
[i
];
1666 nfsm_chain_get_32(error
, nmc
, attrbytes
);
1669 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SUPPORTED_ATTRS
)) {
1670 len
= NFS_ATTR_BITMAP_LEN
;
1671 nfsm_chain_get_bitmap(error
, nmc
, nfsap
->nfsa_supp_attr
, len
);
1672 attrbytes
-= (len
+ 1) * NFSX_UNSIGNED
;
1674 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TYPE
)) {
1675 nfsm_chain_get_32(error
, nmc
, val
);
1676 nvap
->nva_type
= nfstov_type(val
, NFS_VER4
);
1677 if ((val
== NFATTRDIR
) || (val
== NFNAMEDATTR
))
1678 nvap
->nva_flags
|= NFS_FFLAG_IS_ATTR
;
1680 nvap
->nva_flags
&= ~NFS_FFLAG_IS_ATTR
;
1681 attrbytes
-= NFSX_UNSIGNED
;
1683 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FH_EXPIRE_TYPE
)) {
1684 nfsm_chain_get_32(error
, nmc
, val
);
1686 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_FHTYPE_MASK
;
1687 nfsap
->nfsa_flags
|= val
<< NFS_FSFLAG_FHTYPE_SHIFT
;
1689 printf("nfs: warning unknown fh type: 0x%x\n", val
);
1690 attrbytes
-= NFSX_UNSIGNED
;
1692 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CHANGE
)) {
1693 nfsm_chain_get_64(error
, nmc
, nvap
->nva_change
);
1694 attrbytes
-= 2 * NFSX_UNSIGNED
;
1696 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
)) {
1697 nfsm_chain_get_64(error
, nmc
, nvap
->nva_size
);
1698 attrbytes
-= 2 * NFSX_UNSIGNED
;
1700 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_LINK_SUPPORT
)) {
1701 nfsm_chain_get_32(error
, nmc
, val
);
1703 nfsap
->nfsa_flags
|= NFS_FSFLAG_LINK
;
1705 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_LINK
;
1706 attrbytes
-= NFSX_UNSIGNED
;
1708 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SYMLINK_SUPPORT
)) {
1709 nfsm_chain_get_32(error
, nmc
, val
);
1711 nfsap
->nfsa_flags
|= NFS_FSFLAG_SYMLINK
;
1713 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_SYMLINK
;
1714 attrbytes
-= NFSX_UNSIGNED
;
1716 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NAMED_ATTR
)) {
1717 nfsm_chain_get_32(error
, nmc
, val
);
1719 nvap
->nva_flags
|= NFS_FFLAG_HAS_NAMED_ATTRS
;
1721 nvap
->nva_flags
&= ~NFS_FFLAG_HAS_NAMED_ATTRS
;
1722 attrbytes
-= NFSX_UNSIGNED
;
1724 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FSID
)) {
1725 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fsid
.major
);
1726 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fsid
.minor
);
1727 attrbytes
-= 4 * NFSX_UNSIGNED
;
1729 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_UNIQUE_HANDLES
)) {
1730 nfsm_chain_get_32(error
, nmc
, val
);
1732 nfsap
->nfsa_flags
|= NFS_FSFLAG_UNIQUE_FH
;
1734 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_UNIQUE_FH
;
1735 attrbytes
-= NFSX_UNSIGNED
;
1737 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_LEASE_TIME
)) {
1738 nfsm_chain_get_32(error
, nmc
, nfsap
->nfsa_lease
);
1739 attrbytes
-= NFSX_UNSIGNED
;
1741 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RDATTR_ERROR
)) {
1742 nfsm_chain_get_32(error
, nmc
, rderror
);
1743 attrbytes
-= NFSX_UNSIGNED
;
1744 if (!rderror
) { /* no error */
1745 NFS_BITMAP_CLR(bitmap
, NFS_FATTR_RDATTR_ERROR
);
1746 NFS_BITMAP_CLR(nvap
->nva_bitmap
, NFS_FATTR_RDATTR_ERROR
);
1749 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACL
)) {
1751 ace_type
= ace_flags
= ace_mask
= 0;
1752 nfsm_chain_get_32(error
, nmc
, val
); /* ACE count */
1753 if (!error
&& (val
> KAUTH_ACL_MAX_ENTRIES
))
1755 if (!error
&& !((acl
= kauth_acl_alloc(val
))))
1757 if (!error
&& acl
) {
1758 acl
->acl_entrycount
= val
;
1761 attrbytes
-= NFSX_UNSIGNED
;
1762 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
1763 for (i
=0; !error
&& (i
< val
); i
++) {
1764 nfsm_chain_get_32(error
, nmc
, ace_type
);
1765 nfsm_chain_get_32(error
, nmc
, ace_flags
);
1766 nfsm_chain_get_32(error
, nmc
, ace_mask
);
1767 nfsm_chain_get_32(error
, nmc
, len
);
1768 if (!error
&& len
>= NFS_MAX_WHO
)
1770 acl
->acl_ace
[i
].ace_flags
= nfs4_ace_nfstype_to_vfstype(ace_type
, &error
);
1771 acl
->acl_ace
[i
].ace_flags
|= nfs4_ace_nfsflags_to_vfsflags(ace_flags
);
1772 acl
->acl_ace
[i
].ace_rights
= nfs4_ace_nfsmask_to_vfsrights(ace_mask
);
1773 if (!error
&& !error2
&& (len
>= slen
)) {
1777 slen
= sizeof(sbuf
);
1779 /* Let's add a bit more if we can to the allocation as to try and avoid future allocations */
1780 MALLOC(s
, char*, (len
+ 16 < NFS_MAX_WHO
) ? len
+16 : NFS_MAX_WHO
, M_TEMP
, M_WAITOK
);
1782 slen
= (len
+ 16 < NFS_MAX_WHO
) ? len
+16 : NFS_MAX_WHO
;
1787 nfsm_chain_adv(error
, nmc
, nfsm_rndup(len
));
1789 nfsm_chain_get_opaque(error
, nmc
, len
, s
);
1790 if (!error
&& !error2
) {
1792 error2
= nfs4_id2guid(s
, &acl
->acl_ace
[i
].ace_applicable
,
1793 (ace_flags
& NFS_ACE_IDENTIFIER_GROUP
));
1794 if (error2
&& (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
))
1795 printf("nfs4_parsefattr: ACE WHO %s is no one, no guid?, error %d\n", s
, error2
);
1797 attrbytes
-= 4*NFSX_UNSIGNED
+ nfsm_rndup(len
);
1798 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
1801 if ((nvap
!= &nva_dummy
) && !error2
) {
1802 nvap
->nva_acl
= acl
;
1806 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACLSUPPORT
)) {
1808 * Support ACLs if: the server supports DENY/ALLOC ACEs and
1809 * (just to be safe) FATTR_ACL is in the supported list too.
1811 nfsm_chain_get_32(error
, nmc
, val
);
1812 if ((val
& (NFS_ACL_SUPPORT_ALLOW_ACL
|NFS_ACL_SUPPORT_DENY_ACL
)) &&
1813 NFS_BITMAP_ISSET(nfsap
->nfsa_supp_attr
, NFS_FATTR_ACL
)) {
1814 nfsap
->nfsa_flags
|= NFS_FSFLAG_ACL
;
1816 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_ACL
;
1818 attrbytes
-= NFSX_UNSIGNED
;
1820 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
)) { /* SF_ARCHIVED */
1821 nfsm_chain_get_32(error
, nmc
, val
);
1823 nvap
->nva_flags
|= NFS_FFLAG_ARCHIVED
;
1825 nvap
->nva_flags
&= ~NFS_FFLAG_ARCHIVED
;
1826 attrbytes
-= NFSX_UNSIGNED
;
1828 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CANSETTIME
)) {
1829 nfsm_chain_get_32(error
, nmc
, val
);
1831 nfsap
->nfsa_flags
|= NFS_FSFLAG_SET_TIME
;
1833 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_SET_TIME
;
1834 attrbytes
-= NFSX_UNSIGNED
;
1836 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CASE_INSENSITIVE
)) {
1837 nfsm_chain_get_32(error
, nmc
, val
);
1839 nfsap
->nfsa_flags
|= NFS_FSFLAG_CASE_INSENSITIVE
;
1841 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CASE_INSENSITIVE
;
1842 attrbytes
-= NFSX_UNSIGNED
;
1844 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CASE_PRESERVING
)) {
1845 nfsm_chain_get_32(error
, nmc
, val
);
1847 nfsap
->nfsa_flags
|= NFS_FSFLAG_CASE_PRESERVING
;
1849 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CASE_PRESERVING
;
1850 attrbytes
-= NFSX_UNSIGNED
;
1852 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CHOWN_RESTRICTED
)) {
1853 nfsm_chain_get_32(error
, nmc
, val
);
1855 nfsap
->nfsa_flags
|= NFS_FSFLAG_CHOWN_RESTRICTED
;
1857 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CHOWN_RESTRICTED
;
1858 attrbytes
-= NFSX_UNSIGNED
;
1860 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEHANDLE
)) {
1861 nfsm_chain_get_32(error
, nmc
, val
);
1864 nfsm_chain_get_opaque(error
, nmc
, nfsm_rndup(val
), fhp
->fh_data
);
1866 nfsm_chain_adv(error
, nmc
, nfsm_rndup(val
));
1868 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
1870 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEID
)) {
1871 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fileid
);
1872 attrbytes
-= 2 * NFSX_UNSIGNED
;
1874 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILES_AVAIL
)) {
1875 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_files_avail
);
1876 attrbytes
-= 2 * NFSX_UNSIGNED
;
1878 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILES_FREE
)) {
1879 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_files_free
);
1880 attrbytes
-= 2 * NFSX_UNSIGNED
;
1882 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILES_TOTAL
)) {
1883 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_files_total
);
1884 attrbytes
-= 2 * NFSX_UNSIGNED
;
1886 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FS_LOCATIONS
)) {
1887 uint32_t loc
, serv
, comp
;
1888 struct nfs_fs_location
*fsl
;
1889 struct nfs_fs_server
*fss
;
1890 struct nfs_fs_path
*fsp
;
1892 /* get root pathname */
1893 fsp
= &nfslsp
->nl_root
;
1894 nfsm_chain_get_32(error
, nmc
, fsp
->np_compcount
); /* component count */
1895 attrbytes
-= NFSX_UNSIGNED
;
1896 /* sanity check component count */
1897 if (!error
&& (fsp
->np_compcount
> MAXPATHLEN
))
1900 if (fsp
->np_compcount
) {
1901 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
1902 if (!fsp
->np_components
)
1905 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
1906 nfsm_chain_get_32(error
, nmc
, val
); /* component length */
1907 /* sanity check component length */
1908 if (!error
&& (val
== 0)) {
1910 * Apparently some people think a path with zero components should
1911 * be encoded with one zero-length component. So, just ignore any
1912 * zero length components.
1915 fsp
->np_compcount
--;
1916 if (fsp
->np_compcount
== 0) {
1917 FREE(fsp
->np_components
, M_TEMP
);
1918 fsp
->np_components
= NULL
;
1920 attrbytes
-= NFSX_UNSIGNED
;
1923 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
1926 MALLOC(fsp
->np_components
[comp
], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
1927 if (!fsp
->np_components
[comp
])
1930 nfsm_chain_get_opaque(error
, nmc
, val
, fsp
->np_components
[comp
]); /* component */
1931 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
1933 nfsm_chain_get_32(error
, nmc
, nfslsp
->nl_numlocs
); /* fs location count */
1934 attrbytes
-= NFSX_UNSIGNED
;
1935 /* sanity check location count */
1936 if (!error
&& (nfslsp
->nl_numlocs
> 256))
1939 if (nfslsp
->nl_numlocs
> 0) {
1940 MALLOC(nfslsp
->nl_locations
, struct nfs_fs_location
**, nfslsp
->nl_numlocs
* sizeof(struct nfs_fs_location
*), M_TEMP
, M_WAITOK
|M_ZERO
);
1941 if (!nfslsp
->nl_locations
)
1945 for (loc
= 0; loc
< nfslsp
->nl_numlocs
; loc
++) {
1947 MALLOC(fsl
, struct nfs_fs_location
*, sizeof(struct nfs_fs_location
), M_TEMP
, M_WAITOK
|M_ZERO
);
1950 nfslsp
->nl_locations
[loc
] = fsl
;
1951 nfsm_chain_get_32(error
, nmc
, fsl
->nl_servcount
); /* server count */
1952 attrbytes
-= NFSX_UNSIGNED
;
1953 /* sanity check server count */
1954 if (!error
&& ((fsl
->nl_servcount
< 1) || (fsl
->nl_servcount
> 256)))
1957 MALLOC(fsl
->nl_servers
, struct nfs_fs_server
**, fsl
->nl_servcount
* sizeof(struct nfs_fs_server
*), M_TEMP
, M_WAITOK
|M_ZERO
);
1958 if (!fsl
->nl_servers
)
1960 for (serv
= 0; serv
< fsl
->nl_servcount
; serv
++) {
1962 MALLOC(fss
, struct nfs_fs_server
*, sizeof(struct nfs_fs_server
), M_TEMP
, M_WAITOK
|M_ZERO
);
1965 fsl
->nl_servers
[serv
] = fss
;
1966 nfsm_chain_get_32(error
, nmc
, val
); /* server name length */
1967 /* sanity check server name length */
1968 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
1971 MALLOC(fss
->ns_name
, char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
1974 nfsm_chain_get_opaque(error
, nmc
, val
, fss
->ns_name
); /* server name */
1975 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
1977 /* copy name to address if it converts to a sockaddr */
1978 if (nfs_uaddr2sockaddr(fss
->ns_name
, (struct sockaddr
*)&ss
)) {
1979 fss
->ns_addrcount
= 1;
1980 MALLOC(fss
->ns_addresses
, char **, sizeof(char *), M_TEMP
, M_WAITOK
|M_ZERO
);
1981 if (!fss
->ns_addresses
)
1984 MALLOC(fss
->ns_addresses
[0], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
1985 if (!fss
->ns_addresses
[0])
1988 strlcpy(fss
->ns_addresses
[0], fss
->ns_name
, val
+1);
1992 fsp
= &fsl
->nl_path
;
1993 nfsm_chain_get_32(error
, nmc
, fsp
->np_compcount
); /* component count */
1994 attrbytes
-= NFSX_UNSIGNED
;
1995 /* sanity check component count */
1996 if (!error
&& (fsp
->np_compcount
> MAXPATHLEN
))
1999 if (fsp
->np_compcount
) {
2000 MALLOC(fsp
->np_components
, char **, fsp
->np_compcount
* sizeof(char*), M_TEMP
, M_WAITOK
|M_ZERO
);
2001 if (!fsp
->np_components
)
2004 for (comp
= 0; comp
< fsp
->np_compcount
; comp
++) {
2005 nfsm_chain_get_32(error
, nmc
, val
); /* component length */
2006 /* sanity check component length */
2007 if (!error
&& (val
== 0)) {
2009 * Apparently some people think a path with zero components should
2010 * be encoded with one zero-length component. So, just ignore any
2011 * zero length components.
2014 fsp
->np_compcount
--;
2015 if (fsp
->np_compcount
== 0) {
2016 FREE(fsp
->np_components
, M_TEMP
);
2017 fsp
->np_components
= NULL
;
2019 attrbytes
-= NFSX_UNSIGNED
;
2022 if (!error
&& ((val
< 1) || (val
> MAXPATHLEN
)))
2025 MALLOC(fsp
->np_components
[comp
], char *, val
+1, M_TEMP
, M_WAITOK
|M_ZERO
);
2026 if (!fsp
->np_components
[comp
])
2028 nfsm_chain_get_opaque(error
, nmc
, val
, fsp
->np_components
[comp
]); /* component */
2029 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
2032 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
2034 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
)) { /* UF_HIDDEN */
2035 nfsm_chain_get_32(error
, nmc
, val
);
2037 nvap
->nva_flags
|= NFS_FFLAG_HIDDEN
;
2039 nvap
->nva_flags
&= ~NFS_FFLAG_HIDDEN
;
2040 attrbytes
-= NFSX_UNSIGNED
;
2042 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HOMOGENEOUS
)) {
2043 /* XXX If NOT homogeneous, we may need to clear flags on the mount */
2044 nfsm_chain_get_32(error
, nmc
, val
);
2046 nfsap
->nfsa_flags
|= NFS_FSFLAG_HOMOGENEOUS
;
2048 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_HOMOGENEOUS
;
2049 attrbytes
-= NFSX_UNSIGNED
;
2051 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXFILESIZE
)) {
2052 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxfilesize
);
2053 attrbytes
-= 2 * NFSX_UNSIGNED
;
2055 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXLINK
)) {
2056 nfsm_chain_get_32(error
, nmc
, nvap
->nva_maxlink
);
2057 if (!error
&& (nfsap
->nfsa_maxlink
> INT32_MAX
))
2058 nfsap
->nfsa_maxlink
= INT32_MAX
;
2059 attrbytes
-= NFSX_UNSIGNED
;
2061 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXNAME
)) {
2062 nfsm_chain_get_32(error
, nmc
, nfsap
->nfsa_maxname
);
2063 if (!error
&& (nfsap
->nfsa_maxname
> INT32_MAX
))
2064 nfsap
->nfsa_maxname
= INT32_MAX
;
2065 attrbytes
-= NFSX_UNSIGNED
;
2067 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXREAD
)) {
2068 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxread
);
2069 attrbytes
-= 2 * NFSX_UNSIGNED
;
2071 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXWRITE
)) {
2072 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxwrite
);
2073 attrbytes
-= 2 * NFSX_UNSIGNED
;
2075 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MIMETYPE
)) {
2076 nfsm_chain_get_32(error
, nmc
, val
);
2077 nfsm_chain_adv(error
, nmc
, nfsm_rndup(val
));
2078 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
2080 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
)) {
2081 nfsm_chain_get_32(error
, nmc
, nvap
->nva_mode
);
2082 attrbytes
-= NFSX_UNSIGNED
;
2084 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NO_TRUNC
)) {
2085 nfsm_chain_get_32(error
, nmc
, val
);
2087 nfsap
->nfsa_flags
|= NFS_FSFLAG_NO_TRUNC
;
2089 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_NO_TRUNC
;
2090 attrbytes
-= NFSX_UNSIGNED
;
2092 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NUMLINKS
)) {
2093 nfsm_chain_get_32(error
, nmc
, val
);
2094 nvap
->nva_nlink
= val
;
2095 attrbytes
-= NFSX_UNSIGNED
;
2097 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER
)) {
2098 nfsm_chain_get_32(error
, nmc
, len
);
2099 if (!error
&& len
>= NFS_MAX_WHO
)
2101 if (!error
&& (len
>= slen
)) {
2105 slen
= sizeof(sbuf
);
2107 /* Let's add a bit more if we can to the allocation as to try and avoid future allocations */
2108 MALLOC(s
, char*, (len
+ 16 < NFS_MAX_WHO
) ? len
+16 : NFS_MAX_WHO
, M_TEMP
, M_WAITOK
);
2110 slen
= (len
+ 16 < NFS_MAX_WHO
) ? len
+16 : NFS_MAX_WHO
;
2114 nfsm_chain_get_opaque(error
, nmc
, len
, s
);
2117 error
= nfs4_id2guid(s
, &nvap
->nva_uuuid
, 0);
2119 error
= kauth_cred_guid2uid(&nvap
->nva_uuuid
, &nvap
->nva_uid
);
2121 /* unable to get either GUID or UID, set to default */
2122 nvap
->nva_uid
= (uid_t
)((nfs_idmap_ctrl
& NFS_IDMAP_CTRL_UNKNOWN_IS_99
) ? 99 : -2);
2123 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
)
2124 printf("nfs4_parsefattr: owner %s is no one, no %s?, error %d\n", s
,
2125 kauth_guid_equal(&nvap
->nva_uuuid
, &kauth_null_guid
) ? "guid" : "uid",
2130 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2132 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER_GROUP
)) {
2133 nfsm_chain_get_32(error
, nmc
, len
);
2134 if (!error
&& len
>= NFS_MAX_WHO
)
2136 if (!error
&& (len
>= slen
)) {
2140 slen
= sizeof(sbuf
);
2142 /* Let's add a bit more if we can to the allocation as to try and avoid future allocations */
2143 MALLOC(s
, char*, (len
+ 16 < NFS_MAX_WHO
) ? len
+16 : NFS_MAX_WHO
, M_TEMP
, M_WAITOK
);
2145 slen
= (len
+ 16 < NFS_MAX_WHO
) ? len
+16 : NFS_MAX_WHO
;
2149 nfsm_chain_get_opaque(error
, nmc
, len
, s
);
2152 error
= nfs4_id2guid(s
, &nvap
->nva_guuid
, 1);
2154 error
= kauth_cred_guid2gid(&nvap
->nva_guuid
, &nvap
->nva_gid
);
2156 /* unable to get either GUID or GID, set to default */
2157 nvap
->nva_gid
= (gid_t
)((nfs_idmap_ctrl
& NFS_IDMAP_CTRL_UNKNOWN_IS_99
) ? 99 : -2);
2158 if (nfs_idmap_ctrl
& NFS_IDMAP_CTRL_LOG_FAILED_MAPPINGS
)
2159 printf("nfs4_parsefattr: group %s is no one, no %s?, error %d\n", s
,
2160 kauth_guid_equal(&nvap
->nva_guuid
, &kauth_null_guid
) ? "guid" : "gid",
2165 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2167 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_QUOTA_AVAIL_HARD
)) {
2168 nfsm_chain_get_64(error
, nmc
, dqbp
->dqb_bhardlimit
);
2169 attrbytes
-= 2 * NFSX_UNSIGNED
;
2171 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_QUOTA_AVAIL_SOFT
)) {
2172 nfsm_chain_get_64(error
, nmc
, dqbp
->dqb_bsoftlimit
);
2173 attrbytes
-= 2 * NFSX_UNSIGNED
;
2175 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_QUOTA_USED
)) {
2176 nfsm_chain_get_64(error
, nmc
, dqbp
->dqb_curbytes
);
2177 attrbytes
-= 2 * NFSX_UNSIGNED
;
2179 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RAWDEV
)) {
2180 nfsm_chain_get_32(error
, nmc
, nvap
->nva_rawdev
.specdata1
);
2181 nfsm_chain_get_32(error
, nmc
, nvap
->nva_rawdev
.specdata2
);
2182 attrbytes
-= 2 * NFSX_UNSIGNED
;
2184 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_AVAIL
)) {
2185 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_space_avail
);
2186 attrbytes
-= 2 * NFSX_UNSIGNED
;
2188 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_FREE
)) {
2189 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_space_free
);
2190 attrbytes
-= 2 * NFSX_UNSIGNED
;
2192 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_TOTAL
)) {
2193 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_space_total
);
2194 attrbytes
-= 2 * NFSX_UNSIGNED
;
2196 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SPACE_USED
)) {
2197 nfsm_chain_get_64(error
, nmc
, nvap
->nva_bytes
);
2198 attrbytes
-= 2 * NFSX_UNSIGNED
;
2200 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SYSTEM
)) {
2201 /* we'd support this if we had a flag to map it to... */
2202 nfsm_chain_adv(error
, nmc
, NFSX_UNSIGNED
);
2203 attrbytes
-= NFSX_UNSIGNED
;
2205 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS
)) {
2206 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_ACCESS
]);
2207 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_ACCESS
]);
2208 attrbytes
-= 3 * NFSX_UNSIGNED
;
2210 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
)) {
2211 nfsm_chain_adv(error
, nmc
, 4*NFSX_UNSIGNED
); /* just skip it */
2212 attrbytes
-= 4 * NFSX_UNSIGNED
;
2214 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_BACKUP
)) {
2215 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_BACKUP
]);
2216 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_BACKUP
]);
2217 attrbytes
-= 3 * NFSX_UNSIGNED
;
2219 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_CREATE
)) {
2220 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_CREATE
]);
2221 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_CREATE
]);
2222 attrbytes
-= 3 * NFSX_UNSIGNED
;
2224 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_DELTA
)) { /* skip for now */
2225 nfsm_chain_adv(error
, nmc
, 3*NFSX_UNSIGNED
);
2226 attrbytes
-= 3 * NFSX_UNSIGNED
;
2228 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_METADATA
)) {
2229 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_CHANGE
]);
2230 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_CHANGE
]);
2231 attrbytes
-= 3 * NFSX_UNSIGNED
;
2233 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY
)) {
2234 nfsm_chain_get_64(error
, nmc
, nvap
->nva_timesec
[NFSTIME_MODIFY
]);
2235 nfsm_chain_get_32(error
, nmc
, nvap
->nva_timensec
[NFSTIME_MODIFY
]);
2236 attrbytes
-= 3 * NFSX_UNSIGNED
;
2238 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
)) {
2239 nfsm_chain_adv(error
, nmc
, 4*NFSX_UNSIGNED
); /* just skip it */
2240 attrbytes
-= 4 * NFSX_UNSIGNED
;
2242 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MOUNTED_ON_FILEID
)) {
2244 /* we prefer the mounted on file ID, so just replace the fileid */
2245 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fileid
);
2247 nfsm_chain_adv(error
, nmc
, 2*NFSX_UNSIGNED
);
2249 attrbytes
-= 2 * NFSX_UNSIGNED
;
2251 /* advance over any leftover attrbytes */
2252 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
2253 nfsm_chain_adv(error
, nmc
, nfsm_rndup(attrbytes
));
2256 nfs_fs_locations_cleanup(nfslsp
);
2257 if (!error
&& rderror
)
2259 /* free up temporary resources */
2260 if (s
&& (s
!= sbuf
))
2263 kauth_acl_free(acl
);
2264 if (error
&& nvap
->nva_acl
) {
2265 kauth_acl_free(nvap
->nva_acl
);
2266 nvap
->nva_acl
= NULL
;
2272 * Add an NFSv4 "sattr" structure to an mbuf chain
2275 nfsm_chain_add_fattr4_f(struct nfsm_chain
*nmc
, struct vnode_attr
*vap
, struct nfsmount
*nmp
)
2277 int error
= 0, attrbytes
, slen
, len
, i
, isgroup
;
2278 uint32_t *pattrbytes
, val
, acecount
;;
2279 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
2285 slen
= sizeof(sbuf
);
2287 /* First calculate the bitmap... */
2288 nfs_vattr_set_bitmap(nmp
, bitmap
, vap
);
2291 * Now pack it all together:
2292 * BITMAP, #BYTES, ATTRS
2293 * Keep a pointer to the length so we can set it later.
2295 nfsm_chain_add_bitmap(error
, nmc
, bitmap
, NFS_ATTR_BITMAP_LEN
);
2297 nfsm_chain_add_32(error
, nmc
, attrbytes
);
2298 pattrbytes
= (uint32_t*)(nmc
->nmc_ptr
- NFSX_UNSIGNED
);
2300 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
)) {
2301 nfsm_chain_add_64(error
, nmc
, vap
->va_data_size
);
2302 attrbytes
+= 2*NFSX_UNSIGNED
;
2304 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACL
)) {
2306 if (!acl
|| (acl
->acl_entrycount
== KAUTH_FILESEC_NOACL
))
2309 acecount
= acl
->acl_entrycount
;
2310 nfsm_chain_add_32(error
, nmc
, acecount
);
2311 attrbytes
+= NFSX_UNSIGNED
;
2312 for (i
=0; !error
&& (i
< (int)acecount
); i
++) {
2313 val
= (acl
->acl_ace
[i
].ace_flags
& KAUTH_ACE_KINDMASK
);
2314 val
= nfs4_ace_vfstype_to_nfstype(val
, &error
);
2315 nfsm_chain_add_32(error
, nmc
, val
);
2316 val
= nfs4_ace_vfsflags_to_nfsflags(acl
->acl_ace
[i
].ace_flags
);
2317 nfsm_chain_add_32(error
, nmc
, val
);
2318 val
= nfs4_ace_vfsrights_to_nfsmask(acl
->acl_ace
[i
].ace_rights
);
2319 nfsm_chain_add_32(error
, nmc
, val
);
2321 isgroup
= (kauth_cred_guid2gid(&acl
->acl_ace
[i
].ace_applicable
, &gid
) == 0);
2322 error
= nfs4_guid2id(&acl
->acl_ace
[i
].ace_applicable
, s
, &len
, isgroup
);
2323 if (error
== ENOSPC
) {
2329 MALLOC(s
, char*, len
, M_TEMP
, M_WAITOK
);
2332 error
= nfs4_guid2id(&acl
->acl_ace
[i
].ace_applicable
, s
, &len
, isgroup
);
2337 nfsm_chain_add_name(error
, nmc
, s
, len
, nmp
);
2338 attrbytes
+= 4*NFSX_UNSIGNED
+ nfsm_rndup(len
);
2341 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
)) {
2342 nfsm_chain_add_32(error
, nmc
, (vap
->va_flags
& SF_ARCHIVED
) ? 1 : 0);
2343 attrbytes
+= NFSX_UNSIGNED
;
2345 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
)) {
2346 nfsm_chain_add_32(error
, nmc
, (vap
->va_flags
& UF_HIDDEN
) ? 1 : 0);
2347 attrbytes
+= NFSX_UNSIGNED
;
2349 // NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE)
2350 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
)) {
2351 nfsm_chain_add_32(error
, nmc
, vap
->va_mode
);
2352 attrbytes
+= NFSX_UNSIGNED
;
2354 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER
)) {
2356 /* if we have va_uuuid use it, otherwise use uid */
2357 if (!VATTR_IS_ACTIVE(vap
, va_uuuid
)) {
2358 error
= kauth_cred_uid2guid(vap
->va_uid
, &vap
->va_uuuid
);
2362 error
= nfs4_guid2id(&vap
->va_uuuid
, s
, &len
, 0);
2363 if (error
== ENOSPC
) {
2369 MALLOC(s
, char*, len
, M_TEMP
, M_WAITOK
);
2372 error
= nfs4_guid2id(&vap
->va_uuuid
, s
, &len
, 0);
2377 nfsm_chain_add_name(error
, nmc
, s
, len
, nmp
);
2378 attrbytes
+= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2380 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_OWNER_GROUP
)) {
2382 /* if we have va_guuid use it, otherwise use gid */
2383 if (!VATTR_IS_ACTIVE(vap
, va_guuid
)) {
2384 error
= kauth_cred_gid2guid(vap
->va_gid
, &vap
->va_guuid
);
2388 error
= nfs4_guid2id(&vap
->va_guuid
, s
, &len
, 1);
2389 if (error
== ENOSPC
) {
2395 MALLOC(s
, char*, len
, M_TEMP
, M_WAITOK
);
2398 error
= nfs4_guid2id(&vap
->va_guuid
, s
, &len
, 1);
2403 nfsm_chain_add_name(error
, nmc
, s
, len
, nmp
);
2404 attrbytes
+= NFSX_UNSIGNED
+ nfsm_rndup(len
);
2406 // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
2407 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_ACCESS_SET
)) {
2408 if (vap
->va_vaflags
& VA_UTIMES_NULL
) {
2409 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_SERVER
);
2410 attrbytes
+= NFSX_UNSIGNED
;
2412 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_CLIENT
);
2413 nfsm_chain_add_64(error
, nmc
, vap
->va_access_time
.tv_sec
);
2414 nfsm_chain_add_32(error
, nmc
, vap
->va_access_time
.tv_nsec
);
2415 attrbytes
+= 4*NFSX_UNSIGNED
;
2418 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_BACKUP
)) {
2419 nfsm_chain_add_64(error
, nmc
, vap
->va_backup_time
.tv_sec
);
2420 nfsm_chain_add_32(error
, nmc
, vap
->va_backup_time
.tv_nsec
);
2421 attrbytes
+= 3*NFSX_UNSIGNED
;
2423 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_CREATE
)) {
2424 nfsm_chain_add_64(error
, nmc
, vap
->va_create_time
.tv_sec
);
2425 nfsm_chain_add_32(error
, nmc
, vap
->va_create_time
.tv_nsec
);
2426 attrbytes
+= 3*NFSX_UNSIGNED
;
2428 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_TIME_MODIFY_SET
)) {
2429 if (vap
->va_vaflags
& VA_UTIMES_NULL
) {
2430 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_SERVER
);
2431 attrbytes
+= NFSX_UNSIGNED
;
2433 nfsm_chain_add_32(error
, nmc
, NFS4_TIME_SET_TO_CLIENT
);
2434 nfsm_chain_add_64(error
, nmc
, vap
->va_modify_time
.tv_sec
);
2435 nfsm_chain_add_32(error
, nmc
, vap
->va_modify_time
.tv_nsec
);
2436 attrbytes
+= 4*NFSX_UNSIGNED
;
2440 /* Now, set the attribute data length */
2441 *pattrbytes
= txdr_unsigned(attrbytes
);
2443 if (s
&& (s
!= sbuf
))
2449 * Got the given error and need to start recovery (if not already started).
2450 * Note: nmp must be locked!
2453 nfs_need_recover(struct nfsmount
*nmp
, int error
)
2455 int wake
= !(nmp
->nm_state
& NFSSTA_RECOVER
);
2457 nmp
->nm_state
|= NFSSTA_RECOVER
;
2458 if ((error
== NFSERR_ADMIN_REVOKED
) ||
2459 (error
== NFSERR_EXPIRED
) ||
2460 (error
== NFSERR_STALE_CLIENTID
))
2461 nmp
->nm_state
|= NFSSTA_RECOVER_EXPIRED
;
2463 nfs_mount_sock_thread_wake(nmp
);
2467 * After recovery due to state expiry, check each node and
2468 * drop any lingering delegation we thought we had.
2470 * If a node has an open that is not lost and is not marked
2471 * for reopen, then we hold onto any delegation because it is
2472 * likely newly-granted.
2475 nfs4_expired_check_delegation(nfsnode_t np
, vfs_context_t ctx
)
2477 struct nfsmount
*nmp
= NFSTONMP(np
);
2478 struct nfs_open_file
*nofp
;
2481 if ((np
->n_flag
& NREVOKE
) || !(np
->n_openflags
& N_DELEG_MASK
))
2484 lck_mtx_lock(&np
->n_openlock
);
2486 TAILQ_FOREACH(nofp
, &np
->n_opens
, nof_link
) {
2487 if (!nofp
->nof_opencnt
)
2489 if (nofp
->nof_flags
& NFS_OPEN_FILE_LOST
)
2491 if (nofp
->nof_flags
& NFS_OPEN_FILE_REOPEN
)
2493 /* we have an open that is not lost and not marked for reopen */
2494 // XXX print out what's keeping this node from dropping the delegation.
2495 NP(nofp
->nof_np
, "nfs4_expired_check_delegation: !drop: opencnt %d flags 0x%x access %d %d mmap %d %d",
2496 nofp
->nof_opencnt
, nofp
->nof_flags
,
2497 nofp
->nof_access
, nofp
->nof_deny
,
2498 nofp
->nof_mmap_access
, nofp
->nof_mmap_deny
);
2504 /* need to drop a delegation */
2505 if (np
->n_dreturn
.tqe_next
!= NFSNOLIST
) {
2506 /* remove this node from the delegation return list */
2507 lck_mtx_lock(&nmp
->nm_lock
);
2508 if (np
->n_dreturn
.tqe_next
!= NFSNOLIST
) {
2509 TAILQ_REMOVE(&nmp
->nm_dreturnq
, np
, n_dreturn
);
2510 np
->n_dreturn
.tqe_next
= NFSNOLIST
;
2512 lck_mtx_unlock(&nmp
->nm_lock
);
2514 if (np
->n_openflags
& N_DELEG_MASK
) {
2515 np
->n_openflags
&= ~N_DELEG_MASK
;
2516 lck_mtx_lock(&nmp
->nm_lock
);
2517 if (np
->n_dlink
.tqe_next
!= NFSNOLIST
) {
2518 TAILQ_REMOVE(&nmp
->nm_delegations
, np
, n_dlink
);
2519 np
->n_dlink
.tqe_next
= NFSNOLIST
;
2521 lck_mtx_unlock(&nmp
->nm_lock
);
2522 nfs4_delegreturn_rpc(nmp
, np
->n_fhp
, np
->n_fhsize
, &np
->n_dstateid
,
2523 0, vfs_context_thread(ctx
), vfs_context_ucred(ctx
));
2527 lck_mtx_unlock(&np
->n_openlock
);
2531 * Recover state for an NFS mount.
2533 * Iterates over all open files, reclaiming opens and lock state.
2536 nfs_recover(struct nfsmount
*nmp
)
2538 struct timespec ts
= { 1, 0 };
2539 int error
, lost
, reopen
;
2540 struct nfs_open_owner
*noop
;
2541 struct nfs_open_file
*nofp
;
2542 struct nfs_file_lock
*nflp
, *nextnflp
;
2543 struct nfs_lock_owner
*nlop
;
2544 thread_t thd
= current_thread();
2545 nfsnode_t np
, nextnp
;
2550 lck_mtx_lock(&nmp
->nm_lock
);
2552 * First, wait for the state inuse count to go to zero so
2553 * we know there are no state operations in progress.
2556 if ((error
= nfs_sigintr(nmp
, NULL
, NULL
, 1)))
2558 if (!(nmp
->nm_sockflags
& NMSOCK_READY
))
2560 if (nmp
->nm_state
& (NFSSTA_FORCE
|NFSSTA_DEAD
))
2562 if (nmp
->nm_sockflags
& NMSOCK_UNMOUNT
)
2566 if (nmp
->nm_stateinuse
)
2567 msleep(&nmp
->nm_stateinuse
, &nmp
->nm_lock
, (PZERO
-1), "nfsrecoverstartwait", &ts
);
2568 } while (nmp
->nm_stateinuse
);
2571 printf("nfs recovery reconnecting for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2573 printf("nfs recovery aborted for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2574 lck_mtx_unlock(&nmp
->nm_lock
);
2579 if (now
.tv_sec
== nmp
->nm_recover_start
) {
2580 printf("nfs recovery throttled for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2581 lck_mtx_unlock(&nmp
->nm_lock
);
2582 tsleep(nfs_recover
, (PZERO
-1), "nfsrecoverrestart", hz
);
2585 nmp
->nm_recover_start
= now
.tv_sec
;
2586 if (++nmp
->nm_stategenid
== 0)
2587 ++nmp
->nm_stategenid
;
2588 printf("nfs recovery started for %s, 0x%x\n", vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2589 lck_mtx_unlock(&nmp
->nm_lock
);
2591 /* for each open owner... */
2592 TAILQ_FOREACH(noop
, &nmp
->nm_open_owners
, noo_link
) {
2593 /* for each of its opens... */
2594 TAILQ_FOREACH(nofp
, &noop
->noo_opens
, nof_oolink
) {
2595 if (!nofp
->nof_access
|| (nofp
->nof_flags
& NFS_OPEN_FILE_LOST
) || (nofp
->nof_np
->n_flag
& NREVOKE
))
2598 /* for NFSv2/v3, just skip straight to lock reclaim */
2599 if (nmp
->nm_vers
< NFS_VER4
)
2601 if (nofp
->nof_rw_drw
)
2602 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_BOTH
);
2603 if (!error
&& nofp
->nof_w_drw
)
2604 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_WRITE
, NFS_OPEN_SHARE_DENY_BOTH
);
2605 if (!error
&& nofp
->nof_r_drw
)
2606 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_BOTH
);
2607 if (!error
&& nofp
->nof_rw_dw
)
2608 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_WRITE
);
2609 if (!error
&& nofp
->nof_w_dw
)
2610 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_WRITE
, NFS_OPEN_SHARE_DENY_WRITE
);
2611 if (!error
&& nofp
->nof_r_dw
)
2612 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_WRITE
);
2614 * deny-none opens with no locks can just be reopened (later) if reclaim fails.
2616 if (!error
&& nofp
->nof_rw
) {
2617 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_BOTH
, NFS_OPEN_SHARE_DENY_NONE
);
2618 if ((error
== NFSERR_ADMIN_REVOKED
) || (error
== NFSERR_EXPIRED
) || (error
== NFSERR_NO_GRACE
)) {
2623 if (!error
&& !reopen
&& nofp
->nof_w
) {
2624 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_WRITE
, NFS_OPEN_SHARE_DENY_NONE
);
2625 if ((error
== NFSERR_ADMIN_REVOKED
) || (error
== NFSERR_EXPIRED
) || (error
== NFSERR_NO_GRACE
)) {
2630 if (!error
&& !reopen
&& nofp
->nof_r
) {
2631 error
= nfs4_open_reclaim_rpc(nofp
, NFS_OPEN_SHARE_ACCESS_READ
, NFS_OPEN_SHARE_DENY_NONE
);
2632 if ((error
== NFSERR_ADMIN_REVOKED
) || (error
== NFSERR_EXPIRED
) || (error
== NFSERR_NO_GRACE
)) {
2639 * If we hold delegated state but we don't have any non-delegated opens,
2640 * then we should attempt to claim that state now (but don't return the
2641 * delegation unless asked to).
2643 if ((nofp
->nof_d_rw_drw
|| nofp
->nof_d_w_drw
|| nofp
->nof_d_r_drw
||
2644 nofp
->nof_d_rw_dw
|| nofp
->nof_d_w_dw
|| nofp
->nof_d_r_dw
||
2645 nofp
->nof_d_rw
|| nofp
->nof_d_w
|| nofp
->nof_d_r
) &&
2646 (!nofp
->nof_rw_drw
&& !nofp
->nof_w_drw
&& !nofp
->nof_r_drw
&&
2647 !nofp
->nof_rw_dw
&& !nofp
->nof_w_dw
&& !nofp
->nof_r_dw
&&
2648 !nofp
->nof_rw
&& !nofp
->nof_w
&& !nofp
->nof_r
)) {
2649 if (!error
&& !nfs_open_state_set_busy(nofp
->nof_np
, NULL
)) {
2650 error
= nfs4_claim_delegated_state_for_node(nofp
->nof_np
, R_RECOVER
);
2651 if (!error
&& (nofp
->nof_flags
& NFS_OPEN_FILE_REOPEN
))
2653 nfs_open_state_clear_busy(nofp
->nof_np
);
2654 /* if claim didn't go well, we may need to return delegation now */
2655 if (nofp
->nof_np
->n_openflags
& N_DELEG_RETURN
) {
2656 nfs4_delegation_return(nofp
->nof_np
, R_RECOVER
, thd
, noop
->noo_cred
);
2657 if (!(nmp
->nm_sockflags
& NMSOCK_READY
))
2658 error
= ETIMEDOUT
; /* looks like we need a reconnect */
2664 * Handle any issue claiming open state.
2665 * Potential reopens need to first confirm that there are no locks.
2667 if (error
|| reopen
) {
2668 /* restart recovery? */
2669 if ((error
== ETIMEDOUT
) || nfs_mount_state_error_should_restart(error
)) {
2670 if (error
== ETIMEDOUT
)
2671 nfs_need_reconnect(nmp
);
2672 tsleep(nfs_recover
, (PZERO
-1), "nfsrecoverrestart", hz
);
2673 printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2674 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
2677 if (reopen
&& (nfs_check_for_locks(noop
, nofp
) == 0)) {
2678 /* just reopen the file on next access */
2679 NP(nofp
->nof_np
, "nfs_recover: %d, need reopen for %d %p 0x%x", reopen
,
2680 kauth_cred_getuid(noop
->noo_cred
), nofp
->nof_np
, nofp
->nof_np
->n_flag
);
2681 lck_mtx_lock(&nofp
->nof_lock
);
2682 nofp
->nof_flags
|= NFS_OPEN_FILE_REOPEN
;
2683 lck_mtx_unlock(&nofp
->nof_lock
);
2685 /* open file state lost */
2687 NP(nofp
->nof_np
, "nfs_recover: %d, can't reopen because of locks %d %p", reopen
,
2688 kauth_cred_getuid(noop
->noo_cred
), nofp
->nof_np
);
2694 /* no error, so make sure the reopen flag isn't set */
2695 lck_mtx_lock(&nofp
->nof_lock
);
2696 nofp
->nof_flags
&= ~NFS_OPEN_FILE_REOPEN
;
2697 lck_mtx_unlock(&nofp
->nof_lock
);
2701 * Scan this node's lock owner list for entries with this open owner,
2702 * then walk the lock owner's held lock list recovering each lock.
2705 TAILQ_FOREACH(nlop
, &nofp
->nof_np
->n_lock_owners
, nlo_link
) {
2708 if (nlop
->nlo_open_owner
!= noop
)
2710 TAILQ_FOREACH_SAFE(nflp
, &nlop
->nlo_locks
, nfl_lolink
, nextnflp
) {
2711 /* skip dead & blocked lock requests (shouldn't be any in the held lock list) */
2712 if (nflp
->nfl_flags
& (NFS_FILE_LOCK_DEAD
|NFS_FILE_LOCK_BLOCKED
))
2714 /* skip delegated locks */
2715 if (nflp
->nfl_flags
& NFS_FILE_LOCK_DELEGATED
)
2717 error
= nmp
->nm_funcs
->nf_setlock_rpc(nofp
->nof_np
, nofp
, nflp
, 1, R_RECOVER
, thd
, noop
->noo_cred
);
2719 NP(nofp
->nof_np
, "nfs: lock reclaim (0x%llx, 0x%llx) %s %d",
2720 nflp
->nfl_start
, nflp
->nfl_end
,
2721 error
? "failed" : "succeeded", error
);
2724 /* restart recovery? */
2725 if ((error
== ETIMEDOUT
) || nfs_mount_state_error_should_restart(error
)) {
2726 if (error
== ETIMEDOUT
)
2727 nfs_need_reconnect(nmp
);
2728 tsleep(nfs_recover
, (PZERO
-1), "nfsrecoverrestart", hz
);
2729 printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2730 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
2733 /* lock state lost - attempt to close file */
2741 * If we've determined that we need to reopen the file then we probably
2742 * didn't receive any delegation we think we hold. We should attempt to
2743 * return that delegation (and claim any delegated state).
2745 * If we hold a delegation that is marked for return, then we should
2748 if ((nofp
->nof_np
->n_openflags
& N_DELEG_RETURN
) ||
2749 (reopen
&& (nofp
->nof_np
->n_openflags
& N_DELEG_MASK
))) {
2750 nfs4_delegation_return(nofp
->nof_np
, R_RECOVER
, thd
, noop
->noo_cred
);
2751 if (!(nmp
->nm_sockflags
& NMSOCK_READY
)) {
2752 /* looks like we need a reconnect */
2753 tsleep(nfs_recover
, (PZERO
-1), "nfsrecoverrestart", hz
);
2754 printf("nfs recovery restarting for %s, 0x%x, error %d\n",
2755 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);
2761 /* revoke open file state */
2762 NP(nofp
->nof_np
, "nfs_recover: state lost for %d %p 0x%x",
2763 kauth_cred_getuid(noop
->noo_cred
), nofp
->nof_np
, nofp
->nof_np
->n_flag
);
2764 nfs_revoke_open_state_for_node(nofp
->nof_np
);
2770 /* If state expired, make sure we're not holding onto any stale delegations */
2771 lck_mtx_lock(&nmp
->nm_lock
);
2772 if ((nmp
->nm_vers
>= NFS_VER4
) && (nmp
->nm_state
& NFSSTA_RECOVER_EXPIRED
)) {
2774 TAILQ_FOREACH_SAFE(np
, &nmp
->nm_delegations
, n_dlink
, nextnp
) {
2775 lck_mtx_unlock(&nmp
->nm_lock
);
2776 nfs4_expired_check_delegation(np
, vfs_context_kernel());
2777 lck_mtx_lock(&nmp
->nm_lock
);
2778 if (nextnp
== NFSNOLIST
)
2782 nmp
->nm_state
&= ~(NFSSTA_RECOVER
|NFSSTA_RECOVER_EXPIRED
);
2783 wakeup(&nmp
->nm_state
);
2784 printf("nfs recovery completed for %s, 0x%x\n",
2785 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
);
2786 lck_mtx_unlock(&nmp
->nm_lock
);
2788 printf("nfs recovery failed for %s, 0x%x, error %d\n",
2789 vfs_statfs(nmp
->nm_mountp
)->f_mntfromname
, nmp
->nm_stategenid
, error
);