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