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