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