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