1 /*
2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30 * Copyright (c) 1989, 1991, 1993, 1995
31 * The Regents of the University of California. All rights reserved.
32 *
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95
65 * FreeBSD-Id: nfs_socket.c,v 1.30 1997/10/28 15:59:07 bde Exp $
66 */
67
68 #include <nfs/nfs_conf.h>
69 #if CONFIG_NFS_SERVER
70
71 /*
72 * Socket operations for use by nfs
73 */
74
75 #include <sys/systm.h>
76 #include <sys/kauth.h>
77 #include <sys/mount_internal.h>
78 #include <sys/kpi_mbuf.h>
79 #include <IOKit/IOLib.h>
80
81 #include <netinet/in.h>
82
83 #include <nfs/rpcv2.h>
84 #include <nfs/nfsproto.h>
85 #include <nfs/nfs.h>
86 #include <nfs/xdr_subs.h>
87 #include <nfs/nfsm_subs.h>
88 #include <nfs/nfs_gss.h>
89
90 ZONE_DEFINE(nfsrv_descript_zone, "NFSV3 srvdesc",
91 sizeof(struct nfsrv_descript), ZC_NONE);
92
93 int nfsrv_sock_max_rec_queue_length = 128; /* max # RPC records queued on (UDP) socket */
94
95 int nfsrv_getstream(struct nfsrv_sock *, int);
96 int nfsrv_getreq(struct nfsrv_descript *);
97 extern int nfsv3_procid[NFS_NPROCS];
98
99 #define NFS_TRYLOCK_MSEC_SLEEP 1
100
101 /*
102 * compare two sockaddr structures
103 */
104 int
nfs_sockaddr_cmp(struct sockaddr * sa1,struct sockaddr * sa2)105 nfs_sockaddr_cmp(struct sockaddr *sa1, struct sockaddr *sa2)
106 {
107 if (!sa1) {
108 return -1;
109 }
110 if (!sa2) {
111 return 1;
112 }
113 if (sa1->sa_family != sa2->sa_family) {
114 return (sa1->sa_family < sa2->sa_family) ? -1 : 1;
115 }
116 if (sa1->sa_len != sa2->sa_len) {
117 return (sa1->sa_len < sa2->sa_len) ? -1 : 1;
118 }
119 if (sa1->sa_family == AF_INET) {
120 return bcmp(&((struct sockaddr_in*)sa1)->sin_addr,
121 &((struct sockaddr_in*)sa2)->sin_addr, sizeof(((struct sockaddr_in*)sa1)->sin_addr));
122 }
123 if (sa1->sa_family == AF_INET6) {
124 return bcmp(&((struct sockaddr_in6*)sa1)->sin6_addr,
125 &((struct sockaddr_in6*)sa2)->sin6_addr, sizeof(((struct sockaddr_in6*)sa1)->sin6_addr));
126 }
127 return -1;
128 }
129
130 /*
131 * Generate the rpc reply header
132 * siz arg. is used to decide if adding a cluster is worthwhile
133 */
134 int
nfsrv_rephead(struct nfsrv_descript * nd,__unused struct nfsrv_sock * slp,struct nfsm_chain * nmrepp,size_t siz)135 nfsrv_rephead(
136 struct nfsrv_descript *nd,
137 __unused struct nfsrv_sock *slp,
138 struct nfsm_chain *nmrepp,
139 size_t siz)
140 {
141 mbuf_t mrep;
142 u_int32_t *tl;
143 struct nfsm_chain nmrep;
144 int err, error;
145
146 err = nd->nd_repstat;
147 if (err && (nd->nd_vers == NFS_VER2)) {
148 siz = 0;
149 }
150
151 /*
152 * If this is a big reply, use a cluster else
153 * try and leave leading space for the lower level headers.
154 */
155 siz += RPC_REPLYSIZ;
156 if (siz >= nfs_mbuf_minclsize) {
157 error = mbuf_getpacket(MBUF_WAITOK, &mrep);
158 } else {
159 error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &mrep);
160 }
161 if (error) {
162 /* unable to allocate packet */
163 /* XXX should we keep statistics for these errors? */
164 return error;
165 }
166 if (siz < nfs_mbuf_minclsize) {
167 /* leave space for lower level headers */
168 tl = mbuf_data(mrep);
169 tl += 80 / sizeof(*tl); /* XXX max_hdr? XXX */
170 mbuf_setdata(mrep, tl, 6 * NFSX_UNSIGNED);
171 }
172 nfsm_chain_init(&nmrep, mrep);
173 nfsm_chain_add_32(error, &nmrep, nd->nd_retxid);
174 nfsm_chain_add_32(error, &nmrep, RPC_REPLY);
175 if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) {
176 nfsm_chain_add_32(error, &nmrep, RPC_MSGDENIED);
177 if (err & NFSERR_AUTHERR) {
178 nfsm_chain_add_32(error, &nmrep, RPC_AUTHERR);
179 nfsm_chain_add_32(error, &nmrep, (err & ~NFSERR_AUTHERR));
180 } else {
181 nfsm_chain_add_32(error, &nmrep, RPC_MISMATCH);
182 nfsm_chain_add_32(error, &nmrep, RPC_VER2);
183 nfsm_chain_add_32(error, &nmrep, RPC_VER2);
184 }
185 } else {
186 /* reply status */
187 nfsm_chain_add_32(error, &nmrep, RPC_MSGACCEPTED);
188 if (nd->nd_gss_context != NULL) {
189 /* RPCSEC_GSS verifier */
190 error = nfs_gss_svc_verf_put(nd, &nmrep);
191 if (error) {
192 nfsm_chain_add_32(error, &nmrep, RPC_SYSTEM_ERR);
193 goto done;
194 }
195 } else {
196 /* RPCAUTH_NULL verifier */
197 nfsm_chain_add_32(error, &nmrep, RPCAUTH_NULL);
198 nfsm_chain_add_32(error, &nmrep, 0);
199 }
200 /* accepted status */
201 switch (err) {
202 case EPROGUNAVAIL:
203 nfsm_chain_add_32(error, &nmrep, RPC_PROGUNAVAIL);
204 break;
205 case EPROGMISMATCH:
206 nfsm_chain_add_32(error, &nmrep, RPC_PROGMISMATCH);
207 /* XXX hard coded versions? */
208 nfsm_chain_add_32(error, &nmrep, NFS_VER2);
209 nfsm_chain_add_32(error, &nmrep, NFS_VER3);
210 break;
211 case EPROCUNAVAIL:
212 nfsm_chain_add_32(error, &nmrep, RPC_PROCUNAVAIL);
213 break;
214 case EBADRPC:
215 nfsm_chain_add_32(error, &nmrep, RPC_GARBAGE);
216 break;
217 default:
218 nfsm_chain_add_32(error, &nmrep, RPC_SUCCESS);
219 if (nd->nd_gss_context != NULL) {
220 error = nfs_gss_svc_prepare_reply(nd, &nmrep);
221 }
222 if (err != NFSERR_RETVOID) {
223 nfsm_chain_add_32(error, &nmrep,
224 (err ? nfsrv_errmap(nd, err) : 0));
225 }
226 break;
227 }
228 }
229
230 done:
231 nfsm_chain_build_done(error, &nmrep);
232 if (error) {
233 /* error composing reply header */
234 /* XXX should we keep statistics for these errors? */
235 mbuf_freem(mrep);
236 return error;
237 }
238
239 *nmrepp = nmrep;
240 if ((err != 0) && (err != NFSERR_RETVOID)) {
241 OSAddAtomic64(1, &nfsrvstats.srvrpc_errs);
242 }
243 return 0;
244 }
245
246 /*
247 * The nfs server send routine.
248 *
249 * - return EINTR or ERESTART if interrupted by a signal
250 * - return EPIPE if a connection is lost for connection based sockets (TCP...)
251 * - do any cleanup required by recoverable socket errors (???)
252 */
253 int
nfsrv_send(struct nfsrv_sock * slp,mbuf_t nam,mbuf_t top)254 nfsrv_send(struct nfsrv_sock *slp, mbuf_t nam, mbuf_t top)
255 {
256 int error;
257 socket_t so = slp->ns_so;
258 struct sockaddr *sendnam;
259 struct msghdr msg;
260
261 bzero(&msg, sizeof(msg));
262 if (nam && !sock_isconnected(so) && (slp->ns_sotype != SOCK_STREAM)) {
263 if ((sendnam = mbuf_data(nam))) {
264 msg.msg_name = (caddr_t)sendnam;
265 msg.msg_namelen = sendnam->sa_len;
266 }
267 }
268 if (NFSRV_IS_DBG(NFSRV_FAC_SRV, 15)) {
269 nfs_dump_mbuf(__func__, __LINE__, "nfsrv_send\n", top);
270 }
271 error = sock_sendmbuf(so, &msg, top, 0, NULL);
272 if (!error) {
273 return 0;
274 }
275 log(LOG_INFO, "nfsd send error %d\n", error);
276
277 if ((error == EWOULDBLOCK) && (slp->ns_sotype == SOCK_STREAM)) {
278 error = EPIPE; /* zap TCP sockets if they time out on send */
279 }
280 /* Handle any recoverable (soft) socket errors here. (???) */
281 if (error != EINTR && error != ERESTART && error != EIO &&
282 error != EWOULDBLOCK && error != EPIPE) {
283 error = 0;
284 }
285
286 return error;
287 }
288
289 /*
290 * Socket upcall routine for the nfsd sockets.
291 * The caddr_t arg is a pointer to the "struct nfsrv_sock".
292 * Essentially do as much as possible non-blocking, else punt and it will
293 * be called with MBUF_WAITOK from an nfsd.
294 */
295 void
nfsrv_rcv(socket_t so,void * arg,int waitflag)296 nfsrv_rcv(socket_t so, void *arg, int waitflag)
297 {
298 struct nfsrv_sock *slp = arg;
299
300 while (1) {
301 if (!nfsd_thread_count || !(slp->ns_flag & SLP_VALID)) {
302 return;
303 }
304 if (lck_rw_try_lock_exclusive(&slp->ns_rwlock)) {
305 /* Exclusive lock acquired */
306 break;
307 }
308 IOSleep(NFS_TRYLOCK_MSEC_SLEEP);
309 }
310
311 nfsrv_rcv_locked(so, slp, waitflag);
312 /* Note: ns_rwlock gets dropped when called with MBUF_DONTWAIT */
313 }
314 void
nfsrv_rcv_locked(socket_t so,struct nfsrv_sock * slp,int waitflag)315 nfsrv_rcv_locked(socket_t so, struct nfsrv_sock *slp, int waitflag)
316 {
317 mbuf_t m, mp, mhck, m2;
318 int ns_flag = 0, error;
319 struct msghdr msg;
320 size_t bytes_read;
321
322 if ((slp->ns_flag & SLP_VALID) == 0) {
323 if (waitflag == MBUF_DONTWAIT) {
324 lck_rw_done(&slp->ns_rwlock);
325 }
326 return;
327 }
328
329 #ifdef notdef
330 /*
331 * Define this to test for nfsds handling this under heavy load.
332 */
333 if (waitflag == MBUF_DONTWAIT) {
334 ns_flag = SLP_NEEDQ;
335 goto dorecs;
336 }
337 #endif
338 if (slp->ns_sotype == SOCK_STREAM) {
339 /*
340 * If there are already records on the queue, defer soreceive()
341 * to an(other) nfsd so that there is feedback to the TCP layer that
342 * the nfs servers are heavily loaded.
343 */
344 if (slp->ns_rec) {
345 ns_flag = SLP_NEEDQ;
346 goto dorecs;
347 }
348
349 /*
350 * Do soreceive().
351 */
352 bytes_read = 1000000000;
353 error = sock_receivembuf(so, NULL, &mp, MSG_DONTWAIT, &bytes_read);
354 if (error || mp == NULL) {
355 if (error == EWOULDBLOCK) {
356 ns_flag = (waitflag == MBUF_DONTWAIT) ? SLP_NEEDQ : 0;
357 } else {
358 ns_flag = SLP_DISCONN;
359 }
360 goto dorecs;
361 }
362 m = mp;
363 if (slp->ns_rawend) {
364 if ((error = mbuf_setnext(slp->ns_rawend, m))) {
365 panic("nfsrv_rcv: mbuf_setnext failed %d", error);
366 }
367 slp->ns_cc += bytes_read;
368 } else {
369 slp->ns_raw = m;
370 slp->ns_cc = bytes_read;
371 }
372 while ((m2 = mbuf_next(m))) {
373 m = m2;
374 }
375 slp->ns_rawend = m;
376
377 /*
378 * Now try and parse record(s) out of the raw stream data.
379 */
380 error = nfsrv_getstream(slp, waitflag);
381 if (error) {
382 if (error == EPERM) {
383 ns_flag = SLP_DISCONN;
384 } else {
385 ns_flag = SLP_NEEDQ;
386 }
387 }
388 } else {
389 struct sockaddr_storage nam;
390
391 if (slp->ns_reccnt >= nfsrv_sock_max_rec_queue_length) {
392 /* already have max # RPC records queued on this socket */
393 ns_flag = SLP_NEEDQ;
394 goto dorecs;
395 }
396
397 bzero(&msg, sizeof(msg));
398 msg.msg_name = (caddr_t)&nam;
399 msg.msg_namelen = sizeof(nam);
400
401 do {
402 bytes_read = 1000000000;
403 error = sock_receivembuf(so, &msg, &mp, MSG_DONTWAIT | MSG_NEEDSA, &bytes_read);
404 if (mp) {
405 if (msg.msg_name && (mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &mhck) == 0)) {
406 mbuf_setlen(mhck, nam.ss_len);
407 bcopy(&nam, mbuf_data(mhck), nam.ss_len);
408 m = mhck;
409 if (mbuf_setnext(m, mp)) {
410 /* trouble... just drop it */
411 printf("nfsrv_rcv: mbuf_setnext failed\n");
412 mbuf_free(mhck);
413 m = mp;
414 }
415 } else {
416 m = mp;
417 }
418 if (slp->ns_recend) {
419 mbuf_setnextpkt(slp->ns_recend, m);
420 } else {
421 slp->ns_rec = m;
422 slp->ns_flag |= SLP_DOREC;
423 }
424 slp->ns_recend = m;
425 mbuf_setnextpkt(m, NULL);
426 slp->ns_reccnt++;
427 }
428 } while (mp);
429 }
430
431 /*
432 * Now try and process the request records, non-blocking.
433 */
434 dorecs:
435 if (ns_flag) {
436 slp->ns_flag |= ns_flag;
437 }
438 if (waitflag == MBUF_DONTWAIT) {
439 int wake = (slp->ns_flag & SLP_WORKTODO);
440 lck_rw_done(&slp->ns_rwlock);
441 if (wake && nfsd_thread_count) {
442 while (1) {
443 if ((slp->ns_flag & SLP_VALID) == 0) {
444 break;
445 }
446 if (lck_mtx_try_lock(&nfsd_mutex)) {
447 /* Mutex acquired */
448 nfsrv_wakenfsd(slp);
449 lck_mtx_unlock(&nfsd_mutex);
450 break;
451 }
452 IOSleep(NFS_TRYLOCK_MSEC_SLEEP);
453 }
454 }
455 }
456 }
457
458 /*
459 * Try and extract an RPC request from the mbuf data list received on a
460 * stream socket. The "waitflag" argument indicates whether or not it
461 * can sleep.
462 */
463 int
nfsrv_getstream(struct nfsrv_sock * slp,int waitflag)464 nfsrv_getstream(struct nfsrv_sock *slp, int waitflag)
465 {
466 mbuf_t m;
467 char *cp1, *cp2, *mdata;
468 int error;
469 size_t len, mlen;
470 mbuf_t om, m2, recm;
471 u_int32_t recmark;
472
473 if (slp->ns_flag & SLP_GETSTREAM) {
474 panic("nfs getstream");
475 }
476 slp->ns_flag |= SLP_GETSTREAM;
477 for (;;) {
478 if (slp->ns_reclen == 0) {
479 if (slp->ns_cc < NFSX_UNSIGNED) {
480 slp->ns_flag &= ~SLP_GETSTREAM;
481 return 0;
482 }
483 m = slp->ns_raw;
484 mdata = mbuf_data(m);
485 mlen = mbuf_len(m);
486 if (mlen >= NFSX_UNSIGNED) {
487 bcopy(mdata, (caddr_t)&recmark, NFSX_UNSIGNED);
488 mdata += NFSX_UNSIGNED;
489 mlen -= NFSX_UNSIGNED;
490 mbuf_setdata(m, mdata, mlen);
491 } else {
492 cp1 = (caddr_t)&recmark;
493 cp2 = mdata;
494 while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) {
495 while (mlen == 0) {
496 m = mbuf_next(m);
497 cp2 = mbuf_data(m);
498 mlen = mbuf_len(m);
499 }
500 *cp1++ = *cp2++;
501 mlen--;
502 mbuf_setdata(m, cp2, mlen);
503 }
504 }
505 slp->ns_cc -= NFSX_UNSIGNED;
506 recmark = ntohl(recmark);
507 slp->ns_reclen = recmark & ~0x80000000;
508 if (recmark & 0x80000000) {
509 slp->ns_flag |= SLP_LASTFRAG;
510 } else {
511 slp->ns_flag &= ~SLP_LASTFRAG;
512 }
513 if (slp->ns_reclen <= 0 || slp->ns_reclen > NFS_MAXPACKET) {
514 slp->ns_flag &= ~SLP_GETSTREAM;
515 return EPERM;
516 }
517 }
518
519 /*
520 * Now get the record part.
521 *
522 * Note that slp->ns_reclen may be 0. Linux sometimes
523 * generates 0-length RPCs
524 */
525 recm = NULL;
526 if (slp->ns_cc == slp->ns_reclen) {
527 recm = slp->ns_raw;
528 slp->ns_raw = slp->ns_rawend = NULL;
529 slp->ns_cc = slp->ns_reclen = 0;
530 } else if (slp->ns_cc > slp->ns_reclen) {
531 len = 0;
532 m = slp->ns_raw;
533 mlen = mbuf_len(m);
534 mdata = mbuf_data(m);
535 om = NULL;
536 while (len < slp->ns_reclen) {
537 if ((len + mlen) > slp->ns_reclen) {
538 if (mbuf_copym(m, 0, slp->ns_reclen - len, waitflag, &m2)) {
539 slp->ns_flag &= ~SLP_GETSTREAM;
540 return EWOULDBLOCK;
541 }
542 if (om) {
543 if (mbuf_setnext(om, m2)) {
544 /* trouble... just drop it */
545 printf("nfsrv_getstream: mbuf_setnext failed\n");
546 mbuf_freem(m2);
547 slp->ns_flag &= ~SLP_GETSTREAM;
548 return EWOULDBLOCK;
549 }
550 recm = slp->ns_raw;
551 } else {
552 recm = m2;
553 }
554 mdata += slp->ns_reclen - len;
555 mlen -= slp->ns_reclen - len;
556 mbuf_setdata(m, mdata, mlen);
557 len = slp->ns_reclen;
558 } else if ((len + mlen) == slp->ns_reclen) {
559 om = m;
560 len += mlen;
561 m = mbuf_next(m);
562 recm = slp->ns_raw;
563 if (mbuf_setnext(om, NULL)) {
564 printf("nfsrv_getstream: mbuf_setnext failed 2\n");
565 slp->ns_flag &= ~SLP_GETSTREAM;
566 return EWOULDBLOCK;
567 }
568 mlen = mbuf_len(m);
569 mdata = mbuf_data(m);
570 } else {
571 om = m;
572 len += mlen;
573 m = mbuf_next(m);
574 mlen = mbuf_len(m);
575 mdata = mbuf_data(m);
576 }
577 }
578 slp->ns_raw = m;
579 slp->ns_cc -= len;
580 slp->ns_reclen = 0;
581 } else {
582 slp->ns_flag &= ~SLP_GETSTREAM;
583 return 0;
584 }
585
586 /*
587 * Accumulate the fragments into a record.
588 */
589 if (slp->ns_frag == NULL) {
590 slp->ns_frag = recm;
591 } else {
592 m = slp->ns_frag;
593 while ((m2 = mbuf_next(m))) {
594 m = m2;
595 }
596 if ((error = mbuf_setnext(m, recm))) {
597 panic("nfsrv_getstream: mbuf_setnext failed 3, %d", error);
598 }
599 }
600 if (slp->ns_flag & SLP_LASTFRAG) {
601 if (slp->ns_recend) {
602 mbuf_setnextpkt(slp->ns_recend, slp->ns_frag);
603 } else {
604 slp->ns_rec = slp->ns_frag;
605 slp->ns_flag |= SLP_DOREC;
606 }
607 slp->ns_recend = slp->ns_frag;
608 slp->ns_frag = NULL;
609 }
610 }
611 }
612
613 /*
614 * Parse an RPC header.
615 */
616 int
nfsrv_dorec(struct nfsrv_sock * slp,struct nfsd * nfsd,struct nfsrv_descript ** ndp)617 nfsrv_dorec(
618 struct nfsrv_sock *slp,
619 struct nfsd *nfsd,
620 struct nfsrv_descript **ndp)
621 {
622 mbuf_t m;
623 mbuf_t nam;
624 struct nfsrv_descript *nd;
625 int error = 0;
626
627 *ndp = NULL;
628 if (!(slp->ns_flag & (SLP_VALID | SLP_DOREC)) || (slp->ns_rec == NULL)) {
629 return ENOBUFS;
630 }
631 nd = zalloc(nfsrv_descript_zone);
632 m = slp->ns_rec;
633 slp->ns_rec = mbuf_nextpkt(m);
634 if (slp->ns_rec) {
635 mbuf_setnextpkt(m, NULL);
636 } else {
637 slp->ns_flag &= ~SLP_DOREC;
638 slp->ns_recend = NULL;
639 }
640 slp->ns_reccnt--;
641 if (mbuf_type(m) == MBUF_TYPE_SONAME) {
642 nam = m;
643 m = mbuf_next(m);
644 if ((error = mbuf_setnext(nam, NULL))) {
645 panic("nfsrv_dorec: mbuf_setnext failed %d", error);
646 }
647 } else {
648 nam = NULL;
649 }
650 nd->nd_nam2 = nam;
651 nfsm_chain_dissect_init(error, &nd->nd_nmreq, m);
652 if (!error) {
653 error = nfsrv_getreq(nd);
654 }
655 if (error) {
656 if (nam) {
657 mbuf_freem(nam);
658 }
659 if (nd->nd_gss_context) {
660 nfs_gss_svc_ctx_deref(nd->nd_gss_context);
661 }
662 NFS_ZFREE(nfsrv_descript_zone, nd);
663 return error;
664 }
665 nd->nd_mrep = NULL;
666 *ndp = nd;
667 nfsd->nfsd_nd = nd;
668 return 0;
669 }
670
671 /*
672 * Parse an RPC request
673 * - verify it
674 * - fill in the cred struct.
675 */
676 int
nfsrv_getreq(struct nfsrv_descript * nd)677 nfsrv_getreq(struct nfsrv_descript *nd)
678 {
679 struct nfsm_chain *nmreq;
680 int len, i;
681 u_int32_t nfsvers, auth_type;
682 int error = 0;
683 uid_t user_id;
684 gid_t group_id;
685 short ngroups;
686 uint32_t val;
687
688 nd->nd_cr = NULL;
689 nd->nd_gss_context = NULL;
690 nd->nd_gss_seqnum = 0;
691 nd->nd_gss_mb = NULL;
692
693 user_id = group_id = -2;
694 val = auth_type = len = 0;
695
696 nmreq = &nd->nd_nmreq;
697 nfsm_chain_get_32(error, nmreq, nd->nd_retxid); // XID
698 nfsm_chain_get_32(error, nmreq, val); // RPC Call
699 if (!error && (val != RPC_CALL)) {
700 error = EBADRPC;
701 }
702 nfsmout_if(error);
703 nd->nd_repstat = 0;
704 nfsm_chain_get_32(error, nmreq, val); // RPC Version
705 nfsmout_if(error);
706 if (val != RPC_VER2) {
707 nd->nd_repstat = ERPCMISMATCH;
708 nd->nd_procnum = NFSPROC_NOOP;
709 return 0;
710 }
711 nfsm_chain_get_32(error, nmreq, val); // RPC Program Number
712 nfsmout_if(error);
713 if (val != NFS_PROG) {
714 nd->nd_repstat = EPROGUNAVAIL;
715 nd->nd_procnum = NFSPROC_NOOP;
716 return 0;
717 }
718 nfsm_chain_get_32(error, nmreq, nfsvers);// NFS Version Number
719 nfsmout_if(error);
720 if ((nfsvers < NFS_VER2) || (nfsvers > NFS_VER3)) {
721 nd->nd_repstat = EPROGMISMATCH;
722 nd->nd_procnum = NFSPROC_NOOP;
723 return 0;
724 }
725 nd->nd_vers = nfsvers;
726 nfsm_chain_get_32(error, nmreq, nd->nd_procnum);// NFS Procedure Number
727 nfsmout_if(error);
728 if ((nd->nd_procnum >= NFS_NPROCS) ||
729 ((nd->nd_vers == NFS_VER2) && (nd->nd_procnum > NFSV2PROC_STATFS))) {
730 nd->nd_repstat = EPROCUNAVAIL;
731 nd->nd_procnum = NFSPROC_NOOP;
732 return 0;
733 }
734 if (nfsvers != NFS_VER3) {
735 nd->nd_procnum = nfsv3_procid[nd->nd_procnum];
736 }
737 nfsm_chain_get_32(error, nmreq, auth_type); // Auth Flavor
738 nfsm_chain_get_32(error, nmreq, len); // Auth Length
739 if (!error && (len < 0 || len > RPCAUTH_MAXSIZ)) {
740 error = EBADRPC;
741 }
742 nfsmout_if(error);
743
744 /* Handle authentication */
745 if (auth_type == RPCAUTH_SYS) {
746 struct posix_cred temp_pcred;
747 if (nd->nd_procnum == NFSPROC_NULL) {
748 return 0;
749 }
750 nd->nd_sec = RPCAUTH_SYS;
751 nfsm_chain_adv(error, nmreq, NFSX_UNSIGNED); // skip stamp
752 nfsm_chain_get_32(error, nmreq, len); // hostname length
753 if (len < 0 || len > NFS_MAXNAMLEN) {
754 error = EBADRPC;
755 }
756 nfsm_chain_adv(error, nmreq, nfsm_rndup(len)); // skip hostname
757 nfsmout_if(error);
758
759 /* create a temporary credential using the bits from the wire */
760 bzero(&temp_pcred, sizeof(temp_pcred));
761 nfsm_chain_get_32(error, nmreq, user_id);
762 nfsm_chain_get_32(error, nmreq, group_id);
763 temp_pcred.cr_groups[0] = group_id;
764 nfsm_chain_get_32(error, nmreq, len); // extra GID count
765 if ((len < 0) || (len > RPCAUTH_UNIXGIDS)) {
766 error = EBADRPC;
767 }
768 nfsmout_if(error);
769 for (i = 1; i <= len; i++) {
770 if (i < NGROUPS) {
771 nfsm_chain_get_32(error, nmreq, temp_pcred.cr_groups[i]);
772 } else {
773 nfsm_chain_adv(error, nmreq, NFSX_UNSIGNED);
774 }
775 }
776 nfsmout_if(error);
777 ngroups = (len >= NGROUPS) ? NGROUPS : (short)(len + 1);
778 if (ngroups > 1) {
779 nfsrv_group_sort(&temp_pcred.cr_groups[0], ngroups);
780 }
781 nfsm_chain_adv(error, nmreq, NFSX_UNSIGNED); // verifier flavor (should be AUTH_NONE)
782 nfsm_chain_get_32(error, nmreq, len); // verifier length
783 if (len < 0 || len > RPCAUTH_MAXSIZ) {
784 error = EBADRPC;
785 }
786 if (len > 0) {
787 nfsm_chain_adv(error, nmreq, nfsm_rndup(len));
788 }
789
790 /* request creation of a real credential */
791 temp_pcred.cr_uid = user_id;
792 temp_pcred.cr_ngroups = ngroups;
793 nd->nd_cr = posix_cred_create(&temp_pcred);
794 if (nd->nd_cr == NULL) {
795 nd->nd_repstat = ENOMEM;
796 nd->nd_procnum = NFSPROC_NOOP;
797 return 0;
798 }
799 } else if (auth_type == RPCSEC_GSS) {
800 error = nfs_gss_svc_cred_get(nd, nmreq);
801 if (error) {
802 if (error == EINVAL) {
803 goto nfsmout; // drop the request
804 }
805 nd->nd_repstat = error;
806 nd->nd_procnum = NFSPROC_NOOP;
807 return 0;
808 }
809 } else {
810 if (nd->nd_procnum == NFSPROC_NULL) { // assume it's AUTH_NONE
811 return 0;
812 }
813 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED);
814 nd->nd_procnum = NFSPROC_NOOP;
815 return 0;
816 }
817 return 0;
818 nfsmout:
819 if (IS_VALID_CRED(nd->nd_cr)) {
820 kauth_cred_unref(&nd->nd_cr);
821 }
822 nfsm_chain_cleanup(nmreq);
823 return error;
824 }
825
826 /*
827 * Search for a sleeping nfsd and wake it up.
828 * SIDE EFFECT: If none found, make sure the socket is queued up so that one
829 * of the running nfsds will go look for the work in the nfsrv_sockwait list.
830 * Note: Must be called with nfsd_mutex held.
831 */
832 void
nfsrv_wakenfsd(struct nfsrv_sock * slp)833 nfsrv_wakenfsd(struct nfsrv_sock *slp)
834 {
835 struct nfsd *nd;
836
837 while (1) {
838 if ((slp->ns_flag & SLP_VALID) == 0) {
839 return;
840 }
841 if (lck_rw_try_lock_exclusive(&slp->ns_rwlock)) {
842 /* Exclusive lock acquired */
843 break;
844 }
845 IOSleep(NFS_TRYLOCK_MSEC_SLEEP);
846 }
847
848 /* if there's work to do on this socket, make sure it's queued up */
849 if ((slp->ns_flag & SLP_WORKTODO) && !(slp->ns_flag & SLP_QUEUED)) {
850 TAILQ_INSERT_TAIL(&nfsrv_sockwait, slp, ns_svcq);
851 slp->ns_flag |= SLP_WAITQ;
852 }
853 lck_rw_done(&slp->ns_rwlock);
854
855 /* wake up a waiting nfsd, if possible */
856 nd = TAILQ_FIRST(&nfsd_queue);
857 if (!nd) {
858 return;
859 }
860
861 TAILQ_REMOVE(&nfsd_queue, nd, nfsd_queue);
862 nd->nfsd_flag &= ~NFSD_WAITING;
863 wakeup(nd);
864 }
865
866 #endif /* CONFIG_NFS_SERVER */
867