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