1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37 #include <sys/types.h>
38 #include <string.h>
39 #include <syslog.h>
40 #include <sys/param.h>
41 #include <rpc/rpc.h>
42 #include <sys/stat.h>
43 #include <netconfig.h>
44 #include <netdir.h>
45 #include <sys/file.h>
46 #include <sys/time.h>
47 #include <sys/errno.h>
48 #include <rpcsvc/mount.h>
49 #include <sys/pathconf.h>
50 #include <sys/systeminfo.h>
51 #include <sys/utsname.h>
52 #include <sys/wait.h>
53 #include <signal.h>
54 #include <locale.h>
55 #include <unistd.h>
56 #include <errno.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
60 #include <netdb.h>
61 #include <thread.h>
62 #include <assert.h>
63 #include <priv_utils.h>
64 #include <nfs/auth.h>
65 #include <nfs/nfssys.h>
66 #include <nfs/nfs.h>
67 #include <nfs/nfs_sec.h>
68 #include <rpcsvc/daemon_utils.h>
69 #include <deflt.h>
70 #include "../../fslib.h"
71 #include <sharefs/share.h>
72 #include <sharefs/sharetab.h>
73 #include "../lib/sharetab.h"
74 #include "mountd.h"
75 #include <tsol/label.h>
76 #include <sys/tsol/label_macro.h>
77 #include <libtsnet.h>
78 #include <sys/sdt.h>
79 #include <libscf.h>
80 #include <limits.h>
81 #include <sys/nvpair.h>
82 #include <attr.h>
83 #include "smfcfg.h"
84
85 extern int daemonize_init(void);
86 extern void daemonize_fini(int fd);
87
88 struct sh_list *share_list;
89
90 rwlock_t sharetab_lock; /* lock to protect the cached sharetab */
91 static mutex_t mnttab_lock; /* prevent concurrent mnttab readers */
92
93 static mutex_t logging_queue_lock;
94 static cond_t logging_queue_cv;
95
96 static share_t *find_lofsentry(char *, int *);
97 static int getclientsnames_lazy(char *, struct netbuf **,
98 struct nd_hostservlist **);
99 static int getclientsnames(SVCXPRT *, struct netbuf **,
100 struct nd_hostservlist **);
101 static int getclientsflavors_old(share_t *, SVCXPRT *, struct netbuf **,
102 struct nd_hostservlist **, int *);
103 static int getclientsflavors_new(share_t *, SVCXPRT *, struct netbuf **,
104 struct nd_hostservlist **, int *);
105 static int check_client_old(share_t *, SVCXPRT *, struct netbuf **,
106 struct nd_hostservlist **, int);
107 static int check_client_new(share_t *, SVCXPRT *, struct netbuf **,
108 struct nd_hostservlist **, int);
109 static void mnt(struct svc_req *, SVCXPRT *);
110 static void mnt_pathconf(struct svc_req *);
111 static int mount(struct svc_req *r);
112 static void sh_free(struct sh_list *);
113 static void umount(struct svc_req *);
114 static void umountall(struct svc_req *);
115 static int netmatch(struct netbuf *, char *);
116 static void sigexit(int);
117 static int newopts(char *);
118 static tsol_tpent_t *get_client_template(struct sockaddr *);
119
120 static int verbose;
121 static int rejecting;
122 static int mount_vers_min = MOUNTVERS;
123 static int mount_vers_max = MOUNTVERS3;
124
125 /* Needs to be accessed by nfscmd.c */
126 int in_access_list(SVCXPRT *, struct netbuf **,
127 struct nd_hostservlist **, char *);
128
129 extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
130
131 thread_t nfsauth_thread;
132 thread_t cmd_thread;
133 thread_t logging_thread;
134
135 typedef struct logging_data {
136 char *ld_host;
137 char *ld_path;
138 char *ld_rpath;
139 int ld_status;
140 char *ld_netid;
141 struct netbuf *ld_nb;
142 struct logging_data *ld_next;
143 } logging_data;
144
145 static logging_data *logging_head = NULL;
146 static logging_data *logging_tail = NULL;
147
148 /* ARGSUSED */
149 static void *
nfsauth_svc(void * arg)150 nfsauth_svc(void *arg)
151 {
152 int doorfd = -1;
153 uint_t darg;
154 #ifdef DEBUG
155 int dfd;
156 #endif
157
158 if ((doorfd = door_create(nfsauth_func, NULL,
159 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
160 syslog(LOG_ERR, "Unable to create door: %m\n");
161 exit(10);
162 }
163
164 #ifdef DEBUG
165 /*
166 * Create a file system path for the door
167 */
168 if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
169 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
170 syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
171 (void) close(doorfd);
172 exit(11);
173 }
174
175 /*
176 * Clean up any stale namespace associations
177 */
178 (void) fdetach(MOUNTD_DOOR);
179
180 /*
181 * Register in namespace to pass to the kernel to door_ki_open
182 */
183 if (fattach(doorfd, MOUNTD_DOOR) == -1) {
184 syslog(LOG_ERR, "Unable to fattach door: %m\n");
185 (void) close(dfd);
186 (void) close(doorfd);
187 exit(12);
188 }
189 (void) close(dfd);
190 #endif
191
192 /*
193 * Must pass the doorfd down to the kernel.
194 */
195 darg = doorfd;
196 (void) _nfssys(MOUNTD_ARGS, &darg);
197
198 /*
199 * Wait for incoming calls
200 */
201 /*CONSTCOND*/
202 for (;;)
203 (void) pause();
204
205 /*NOTREACHED*/
206 syslog(LOG_ERR, gettext("Door server exited"));
207 return (NULL);
208 }
209
210 /*
211 * NFS command service thread code for setup and handling of the
212 * nfs_cmd requests for character set conversion and other future
213 * events.
214 */
215
216 static void *
cmd_svc(void * arg)217 cmd_svc(void *arg)
218 {
219 int doorfd = -1;
220 uint_t darg;
221
222 if ((doorfd = door_create(nfscmd_func, NULL,
223 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
224 syslog(LOG_ERR, "Unable to create cmd door: %m\n");
225 exit(10);
226 }
227
228 /*
229 * Must pass the doorfd down to the kernel.
230 */
231 darg = doorfd;
232 (void) _nfssys(NFSCMD_ARGS, &darg);
233
234 /*
235 * Wait for incoming calls
236 */
237 /*CONSTCOND*/
238 for (;;)
239 (void) pause();
240
241 /*NOTREACHED*/
242 syslog(LOG_ERR, gettext("Cmd door server exited"));
243 return (NULL);
244 }
245
246 static void
free_logging_data(logging_data * lq)247 free_logging_data(logging_data *lq)
248 {
249 if (lq != NULL) {
250 free(lq->ld_host);
251 free(lq->ld_netid);
252
253 if (lq->ld_nb != NULL) {
254 free(lq->ld_nb->buf);
255 free(lq->ld_nb);
256 }
257
258 free(lq->ld_path);
259 free(lq->ld_rpath);
260
261 free(lq);
262 }
263 }
264
265 static logging_data *
remove_head_of_queue(void)266 remove_head_of_queue(void)
267 {
268 logging_data *lq;
269
270 /*
271 * Pull it off the queue.
272 */
273 lq = logging_head;
274 if (lq) {
275 logging_head = lq->ld_next;
276
277 /*
278 * Drained it.
279 */
280 if (logging_head == NULL) {
281 logging_tail = NULL;
282 }
283 }
284
285 return (lq);
286 }
287
288 static void
do_logging_queue(logging_data * lq)289 do_logging_queue(logging_data *lq)
290 {
291 logging_data *lq_clean = NULL;
292 int cleared = 0;
293 char *host;
294
295 struct nd_hostservlist *clnames;
296
297 while (lq) {
298 if (lq->ld_host == NULL) {
299 DTRACE_PROBE(mountd, name_by_lazy);
300 if (getclientsnames_lazy(lq->ld_netid,
301 &lq->ld_nb, &clnames) != 0)
302 host = NULL;
303 else
304 host = clnames->h_hostservs[0].h_host;
305 } else
306 host = lq->ld_host;
307
308 audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
309
310 /* add entry to mount list */
311 if (lq->ld_rpath)
312 mntlist_new(host, lq->ld_rpath);
313
314 lq->ld_next = lq_clean;
315 lq_clean = lq;
316
317 (void) mutex_lock(&logging_queue_lock);
318 lq = remove_head_of_queue();
319 (void) mutex_unlock(&logging_queue_lock);
320 }
321
322 while (lq_clean) {
323 lq = lq_clean;
324 lq_clean = lq->ld_next;
325
326 free_logging_data(lq);
327 cleared++;
328 }
329
330 DTRACE_PROBE1(mountd, logging_cleared, cleared);
331 }
332
333 static void *
logging_svc(void * arg)334 logging_svc(void *arg)
335 {
336 logging_data *lq;
337
338 for (;;) {
339 (void) mutex_lock(&logging_queue_lock);
340 while (logging_head == NULL) {
341 (void) cond_wait(&logging_queue_cv,
342 &logging_queue_lock);
343 }
344
345 lq = remove_head_of_queue();
346 (void) mutex_unlock(&logging_queue_lock);
347
348 do_logging_queue(lq);
349 }
350
351 /*NOTREACHED*/
352 syslog(LOG_ERR, gettext("Logging server exited"));
353 return (NULL);
354 }
355
356 int
main(int argc,char * argv[])357 main(int argc, char *argv[])
358 {
359 int pid;
360 int c;
361 int rpc_svc_mode = RPC_SVC_MT_AUTO;
362 int maxthreads;
363 int maxrecsz = RPC_MAXDATASIZE;
364 bool_t exclbind = TRUE;
365 bool_t can_do_mlp;
366 long thr_flags = (THR_NEW_LWP|THR_DAEMON);
367 char defval[4];
368 int defvers, ret, bufsz;
369
370 int pipe_fd = -1;
371
372 /*
373 * Mountd requires uid 0 for:
374 * /etc/rmtab updates (we could chown it to daemon)
375 * /etc/dfs/dfstab reading (it wants to lock out share which
376 * doesn't do any locking before first truncate;
377 * NFS share does; should use fcntl locking instead)
378 * Needed privileges:
379 * auditing
380 * nfs syscall
381 * file dac search (so it can stat all files)
382 * Optional privileges:
383 * MLP
384 */
385 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
386 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
387 PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
388 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
389 (void) fprintf(stderr,
390 "%s: must be run with sufficient privileges\n",
391 argv[0]);
392 exit(1);
393 }
394
395 maxthreads = 0;
396
397 while ((c = getopt(argc, argv, "vrm:")) != EOF) {
398 switch (c) {
399 case 'v':
400 verbose++;
401 break;
402 case 'r':
403 rejecting = 1;
404 break;
405 case 'm':
406 maxthreads = atoi(optarg);
407 if (maxthreads < 1) {
408 (void) fprintf(stderr,
409 "%s: must specify positive maximum threads count, using default\n",
410 argv[0]);
411 maxthreads = 0;
412 }
413 break;
414 }
415 }
416
417 /*
418 * Read in the NFS version values from config file.
419 */
420 bufsz = 4;
421 ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE,
422 SCF_TYPE_INTEGER, NFSD, &bufsz);
423 if (ret == SA_OK) {
424 errno = 0;
425 defvers = strtol(defval, (char **)NULL, 10);
426 if (errno == 0) {
427 mount_vers_min = defvers;
428 /*
429 * special because NFSv2 is
430 * supported by mount v1 & v2
431 */
432 if (defvers == NFS_VERSION)
433 mount_vers_min = MOUNTVERS;
434 }
435 }
436
437 bufsz = 4;
438 ret = nfs_smf_get_prop("server_versmax", defval, DEFAULT_INSTANCE,
439 SCF_TYPE_INTEGER, NFSD, &bufsz);
440 if (ret == SA_OK) {
441 errno = 0;
442 defvers = strtol(defval, (char **)NULL, 10);
443 if (errno == 0) {
444 mount_vers_max = defvers;
445 }
446 }
447
448 /*
449 * Sanity check versions,
450 * even though we may get versions > MOUNTVERS3, we still need
451 * to start nfsauth service, so continue on regardless of values.
452 */
453 if (mount_vers_min > mount_vers_max) {
454 fprintf(stderr, "server_versmin > server_versmax");
455 mount_vers_max = mount_vers_min;
456 }
457 (void) setlocale(LC_ALL, "");
458 (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
459 (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
460 (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
461 (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
462
463 netgroup_init();
464
465 #if !defined(TEXT_DOMAIN)
466 #define TEXT_DOMAIN "SYS_TEST"
467 #endif
468 (void) textdomain(TEXT_DOMAIN);
469
470 /* Don't drop core if the NFS module isn't loaded. */
471 (void) signal(SIGSYS, SIG_IGN);
472
473 pipe_fd = daemonize_init();
474
475 /*
476 * If we coredump it'll be in /core
477 */
478 if (chdir("/") < 0)
479 fprintf(stderr, "chdir /: %s", strerror(errno));
480
481 openlog("mountd", LOG_PID, LOG_DAEMON);
482
483 /*
484 * establish our lock on the lock file and write our pid to it.
485 * exit if some other process holds the lock, or if there's any
486 * error in writing/locking the file.
487 */
488 pid = _enter_daemon_lock(MOUNTD);
489 switch (pid) {
490 case 0:
491 break;
492 case -1:
493 fprintf(stderr, "error locking for %s: %s", MOUNTD,
494 strerror(errno));
495 exit(2);
496 default:
497 /* daemon was already running */
498 exit(0);
499 }
500
501 audit_mountd_setup(); /* BSM */
502
503 /*
504 * Tell RPC that we want automatic thread mode.
505 * A new thread will be spawned for each request.
506 */
507 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
508 fprintf(stderr, "unable to set automatic MT mode");
509 exit(1);
510 }
511
512 /*
513 * Enable non-blocking mode and maximum record size checks for
514 * connection oriented transports.
515 */
516 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
517 fprintf(stderr, "unable to set RPC max record size");
518 }
519
520 /*
521 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
522 * from being hijacked by a bind to a more specific addr.
523 */
524 if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
525 fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND");
526 }
527
528 /*
529 * If the -m argument was specified, then set the
530 * maximum number of threads to the value specified.
531 */
532 if (maxthreads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &maxthreads)) {
533 fprintf(stderr, "unable to set maxthreads");
534 exit(1);
535 }
536
537 /*
538 * Make sure to unregister any previous versions in case the
539 * user is reconfiguring the server in interesting ways.
540 */
541 svc_unreg(MOUNTPROG, MOUNTVERS);
542 svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
543 svc_unreg(MOUNTPROG, MOUNTVERS3);
544
545 /*
546 * Create the nfsauth thread with same signal disposition
547 * as the main thread. We need to create a separate thread
548 * since mountd() will be both an RPC server (for remote
549 * traffic) _and_ a doors server (for kernel upcalls).
550 */
551 if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
552 fprintf(stderr, gettext("Failed to create NFSAUTH svc thread"));
553 exit(2);
554 }
555
556 /*
557 * Create the cmd service thread with same signal disposition
558 * as the main thread. We need to create a separate thread
559 * since mountd() will be both an RPC server (for remote
560 * traffic) _and_ a doors server (for kernel upcalls).
561 */
562 if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
563 syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
564 exit(2);
565 }
566
567 /*
568 * Create an additional thread to service the rmtab and
569 * audit_mountd_mount logging for mount requests. Use the same
570 * signal disposition as the main thread. We create
571 * a separate thread to allow the mount request threads to
572 * clear as soon as possible.
573 */
574 if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
575 syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
576 exit(2);
577 }
578
579 /*
580 * Create datagram and connection oriented services
581 */
582 if (mount_vers_max >= MOUNTVERS) {
583 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) {
584 fprintf(stderr,
585 "couldn't register datagram_v MOUNTVERS");
586 exit(1);
587 }
588 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) {
589 fprintf(stderr,
590 "couldn't register circuit_v MOUNTVERS");
591 exit(1);
592 }
593 }
594
595 if (mount_vers_max >= MOUNTVERS_POSIX) {
596 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
597 "datagram_v") == 0) {
598 fprintf(stderr,
599 "couldn't register datagram_v MOUNTVERS_POSIX");
600 exit(1);
601 }
602 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
603 "circuit_v") == 0) {
604 fprintf(stderr,
605 "couldn't register circuit_v MOUNTVERS_POSIX");
606 exit(1);
607 }
608 }
609
610 if (mount_vers_max >= MOUNTVERS3) {
611 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) {
612 fprintf(stderr,
613 "couldn't register datagram_v MOUNTVERS3");
614 exit(1);
615 }
616 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) {
617 fprintf(stderr,
618 "couldn't register circuit_v MOUNTVERS3");
619 exit(1);
620 }
621 }
622
623 /*
624 * Start serving
625 */
626 rmtab_load();
627
628 daemonize_fini(pipe_fd);
629
630 /* Get rid of the most dangerous basic privileges. */
631 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
632 (char *)NULL);
633
634 svc_run();
635 syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
636 abort();
637
638 /* NOTREACHED */
639 return (0);
640 }
641
642 /*
643 * Server procedure switch routine
644 */
645 void
mnt(struct svc_req * rqstp,SVCXPRT * transp)646 mnt(struct svc_req *rqstp, SVCXPRT *transp)
647 {
648 switch (rqstp->rq_proc) {
649 case NULLPROC:
650 errno = 0;
651 if (!svc_sendreply(transp, xdr_void, (char *)0))
652 log_cant_reply(transp);
653 return;
654
655 case MOUNTPROC_MNT:
656 (void) mount(rqstp);
657 return;
658
659 case MOUNTPROC_DUMP:
660 mntlist_send(transp);
661 return;
662
663 case MOUNTPROC_UMNT:
664 umount(rqstp);
665 return;
666
667 case MOUNTPROC_UMNTALL:
668 umountall(rqstp);
669 return;
670
671 case MOUNTPROC_EXPORT:
672 case MOUNTPROC_EXPORTALL:
673 export(rqstp);
674 return;
675
676 case MOUNTPROC_PATHCONF:
677 if (rqstp->rq_vers == MOUNTVERS_POSIX)
678 mnt_pathconf(rqstp);
679 else
680 svcerr_noproc(transp);
681 return;
682
683 default:
684 svcerr_noproc(transp);
685 return;
686 }
687 }
688
689 /* Set up anonymous client */
690
691 struct nd_hostservlist *
anon_client(char * host)692 anon_client(char *host)
693 {
694 struct nd_hostservlist *anon_hsl;
695 struct nd_hostserv *anon_hs;
696
697 anon_hsl = malloc(sizeof (*anon_hsl));
698 if (anon_hsl == NULL)
699 return (NULL);
700
701 anon_hs = malloc(sizeof (*anon_hs));
702 if (anon_hs == NULL) {
703 free(anon_hsl);
704 return (NULL);
705 }
706
707 if (host == NULL)
708 anon_hs->h_host = strdup("(anon)");
709 else
710 anon_hs->h_host = strdup(host);
711
712 if (anon_hs->h_host == NULL) {
713 free(anon_hs);
714 free(anon_hsl);
715 return (NULL);
716 }
717 anon_hs->h_serv = '\0';
718
719 anon_hsl->h_cnt = 1;
720 anon_hsl->h_hostservs = anon_hs;
721
722 return (anon_hsl);
723 }
724
725 static int
getclientsnames_common(struct netconfig * nconf,struct netbuf ** nbuf,struct nd_hostservlist ** serv)726 getclientsnames_common(struct netconfig *nconf, struct netbuf **nbuf,
727 struct nd_hostservlist **serv)
728 {
729 char host[MAXIPADDRLEN];
730
731 assert(*nbuf != NULL);
732
733 /*
734 * Use the this API instead of the netdir_getbyaddr()
735 * to avoid service lookup.
736 */
737 if (__netdir_getbyaddr_nosrv(nconf, serv, *nbuf) != 0) {
738 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
739 struct sockaddr_in *sa;
740
741 /* LINTED pointer alignment */
742 sa = (struct sockaddr_in *)((*nbuf)->buf);
743 (void) inet_ntoa_r(sa->sin_addr, host);
744 } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
745 struct sockaddr_in6 *sa;
746
747 /* LINTED pointer alignment */
748 sa = (struct sockaddr_in6 *)((*nbuf)->buf);
749 (void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr,
750 host, INET6_ADDRSTRLEN);
751 } else {
752 syslog(LOG_ERR, gettext(
753 "Client's address is neither IPv4 nor IPv6"));
754 return (EINVAL);
755 }
756
757 *serv = anon_client(host);
758 if (*serv == NULL)
759 return (ENOMEM);
760 }
761
762 assert(*serv != NULL);
763 return (0);
764 }
765
766 /*
767 * Get the client's hostname from the copy of the
768 * relevant transport handle parts.
769 * If the name is not available then return "(anon)".
770 */
771 static int
getclientsnames_lazy(char * netid,struct netbuf ** nbuf,struct nd_hostservlist ** serv)772 getclientsnames_lazy(char *netid, struct netbuf **nbuf,
773 struct nd_hostservlist **serv)
774 {
775 struct netconfig *nconf;
776 int rc;
777
778 nconf = getnetconfigent(netid);
779 if (nconf == NULL) {
780 syslog(LOG_ERR, "%s: getnetconfigent failed", netid);
781 *serv = anon_client(NULL);
782 if (*serv == NULL)
783 return (ENOMEM);
784 return (0);
785 }
786
787 rc = getclientsnames_common(nconf, nbuf, serv);
788 freenetconfigent(nconf);
789 return (rc);
790 }
791
792 /*
793 * Get the client's hostname from the transport handle.
794 * If the name is not available then return "(anon)".
795 */
796 int
getclientsnames(SVCXPRT * transp,struct netbuf ** nbuf,struct nd_hostservlist ** serv)797 getclientsnames(SVCXPRT *transp, struct netbuf **nbuf,
798 struct nd_hostservlist **serv)
799 {
800 struct netconfig *nconf;
801 int rc;
802
803 nconf = getnetconfigent(transp->xp_netid);
804 if (nconf == NULL) {
805 syslog(LOG_ERR, "%s: getnetconfigent failed",
806 transp->xp_netid);
807 *serv = anon_client(NULL);
808 if (*serv == NULL)
809 return (ENOMEM);
810 return (0);
811 }
812
813 *nbuf = svc_getrpccaller(transp);
814 if (*nbuf == NULL) {
815 freenetconfigent(nconf);
816 *serv = anon_client(NULL);
817 if (*serv == NULL)
818 return (ENOMEM);
819 return (0);
820 }
821
822 rc = getclientsnames_common(nconf, nbuf, serv);
823 freenetconfigent(nconf);
824 return (rc);
825 }
826
827 void
log_cant_reply(SVCXPRT * transp)828 log_cant_reply(SVCXPRT *transp)
829 {
830 int saverrno;
831 struct nd_hostservlist *clnames = NULL;
832 register char *host;
833 struct netbuf *nb;
834
835 saverrno = errno; /* save error code */
836 if (getclientsnames(transp, &nb, &clnames) != 0)
837 return;
838 host = clnames->h_hostservs->h_host;
839
840 errno = saverrno;
841 if (errno == 0)
842 syslog(LOG_ERR, "couldn't send reply to %s", host);
843 else
844 syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
845
846 netdir_free(clnames, ND_HOSTSERVLIST);
847 }
848
849 /*
850 * Answer pathconf questions for the mount point fs
851 */
852 static void
mnt_pathconf(struct svc_req * rqstp)853 mnt_pathconf(struct svc_req *rqstp)
854 {
855 SVCXPRT *transp;
856 struct pathcnf p;
857 char *path, rpath[MAXPATHLEN];
858 struct stat st;
859
860 transp = rqstp->rq_xprt;
861 path = NULL;
862 (void) memset((caddr_t)&p, 0, sizeof (p));
863
864 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
865 svcerr_decode(transp);
866 return;
867 }
868 if (lstat(path, &st) < 0) {
869 _PC_SET(_PC_ERROR, p.pc_mask);
870 goto done;
871 }
872 /*
873 * Get a path without symbolic links.
874 */
875 if (realpath(path, rpath) == NULL) {
876 syslog(LOG_DEBUG,
877 "mount request: realpath failed on %s: %m",
878 path);
879 _PC_SET(_PC_ERROR, p.pc_mask);
880 goto done;
881 }
882 (void) memset((caddr_t)&p, 0, sizeof (p));
883 /*
884 * can't ask about devices over NFS
885 */
886 _PC_SET(_PC_MAX_CANON, p.pc_mask);
887 _PC_SET(_PC_MAX_INPUT, p.pc_mask);
888 _PC_SET(_PC_PIPE_BUF, p.pc_mask);
889 _PC_SET(_PC_VDISABLE, p.pc_mask);
890
891 errno = 0;
892 p.pc_link_max = pathconf(rpath, _PC_LINK_MAX);
893 if (errno)
894 _PC_SET(_PC_LINK_MAX, p.pc_mask);
895 p.pc_name_max = pathconf(rpath, _PC_NAME_MAX);
896 if (errno)
897 _PC_SET(_PC_NAME_MAX, p.pc_mask);
898 p.pc_path_max = pathconf(rpath, _PC_PATH_MAX);
899 if (errno)
900 _PC_SET(_PC_PATH_MAX, p.pc_mask);
901 if (pathconf(rpath, _PC_NO_TRUNC) == 1)
902 _PC_SET(_PC_NO_TRUNC, p.pc_mask);
903 if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1)
904 _PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask);
905
906 done:
907 errno = 0;
908 if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p))
909 log_cant_reply(transp);
910 if (path != NULL)
911 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
912 }
913
914 /*
915 * If the rootmount (export) option is specified, the all mount requests for
916 * subdirectories return EACCES.
917 */
918 static int
checkrootmount(share_t * sh,char * rpath)919 checkrootmount(share_t *sh, char *rpath)
920 {
921 char *val;
922
923 if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) {
924 free(val);
925 if (strcmp(sh->sh_path, rpath) != 0)
926 return (0);
927 else
928 return (1);
929 } else
930 return (1);
931 }
932
933 #define MAX_FLAVORS 128
934
935 /*
936 * Return only EACCES if client does not have access
937 * to this directory.
938 * "If the server exports only /a/b, an attempt to
939 * mount a/b/c will fail with ENOENT if the directory
940 * does not exist"... However, if the client
941 * does not have access to /a/b, an attacker can
942 * determine whether the directory exists.
943 * This routine checks either existence of the file or
944 * existence of the file name entry in the mount table.
945 * If the file exists and there is no file name entry,
946 * the error returned should be EACCES.
947 * If the file does not exist, it must be determined
948 * whether the client has access to a parent
949 * directory. If the client has access to a parent
950 * directory, the error returned should be ENOENT,
951 * otherwise EACCES.
952 */
953 static int
mount_enoent_error(SVCXPRT * transp,char * path,char * rpath,struct nd_hostservlist ** clnames,struct netbuf ** nb,int * flavor_list)954 mount_enoent_error(SVCXPRT *transp, char *path, char *rpath,
955 struct nd_hostservlist **clnames, struct netbuf **nb, int *flavor_list)
956 {
957 char *checkpath, *dp;
958 share_t *sh = NULL;
959 int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0;
960 int flavor_count;
961
962 checkpath = strdup(path);
963 if (checkpath == NULL) {
964 syslog(LOG_ERR, "mount_enoent: no memory");
965 return (EACCES);
966 }
967
968 /* CONSTCOND */
969 while (1) {
970 if (sh) {
971 sharefree(sh);
972 sh = NULL;
973 }
974
975 if ((sh = findentry(rpath)) == NULL &&
976 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
977 /*
978 * There is no file name entry.
979 * If the file (with symbolic links resolved) exists,
980 * the error returned should be EACCES.
981 */
982 if (realpath_error == 0)
983 break;
984 } else if (checkrootmount(sh, rpath) == 0) {
985 /*
986 * This is a "nosub" only export, in which case,
987 * mounting subdirectories isn't allowed.
988 * If the file (with symbolic links resolved) exists,
989 * the error returned should be EACCES.
990 */
991 if (realpath_error == 0)
992 break;
993 } else {
994 /*
995 * Check permissions in mount table.
996 */
997 if (newopts(sh->sh_opts))
998 flavor_count = getclientsflavors_new(sh,
999 transp, nb, clnames, flavor_list);
1000 else
1001 flavor_count = getclientsflavors_old(sh,
1002 transp, nb, clnames, flavor_list);
1003 if (flavor_count != 0) {
1004 /*
1005 * Found entry in table and
1006 * client has correct permissions.
1007 */
1008 reply_error = ENOENT;
1009 break;
1010 }
1011 }
1012
1013 /*
1014 * Check all parent directories.
1015 */
1016 dp = strrchr(checkpath, '/');
1017 if (dp == NULL)
1018 break;
1019 *dp = '\0';
1020 if (strlen(checkpath) == 0)
1021 break;
1022 /*
1023 * Get the real path (no symbolic links in it)
1024 */
1025 if (realpath(checkpath, rpath) == NULL) {
1026 if (errno != ENOENT)
1027 break;
1028 } else {
1029 realpath_error = 0;
1030 }
1031 }
1032
1033 if (sh)
1034 sharefree(sh);
1035 free(checkpath);
1036 return (reply_error);
1037 }
1038
1039 /*
1040 * We need to inform the caller whether or not we were
1041 * able to add a node to the queue. If we are not, then
1042 * it is up to the caller to go ahead and log the data.
1043 */
1044 static int
enqueue_logging_data(char * host,SVCXPRT * transp,char * path,char * rpath,int status,int error)1045 enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
1046 char *rpath, int status, int error)
1047 {
1048 logging_data *lq;
1049 struct netbuf *nb;
1050
1051 lq = (logging_data *)calloc(1, sizeof (logging_data));
1052 if (lq == NULL)
1053 goto cleanup;
1054
1055 /*
1056 * We might not yet have the host...
1057 */
1058 if (host) {
1059 DTRACE_PROBE1(mountd, log_host, host);
1060 lq->ld_host = strdup(host);
1061 if (lq->ld_host == NULL)
1062 goto cleanup;
1063 } else {
1064 DTRACE_PROBE(mountd, log_no_host);
1065
1066 lq->ld_netid = strdup(transp->xp_netid);
1067 if (lq->ld_netid == NULL)
1068 goto cleanup;
1069
1070 lq->ld_nb = calloc(1, sizeof (struct netbuf));
1071 if (lq->ld_nb == NULL)
1072 goto cleanup;
1073
1074 nb = svc_getrpccaller(transp);
1075 if (nb == NULL) {
1076 DTRACE_PROBE(mountd, e__nb__enqueue);
1077 goto cleanup;
1078 }
1079
1080 DTRACE_PROBE(mountd, nb_set_enqueue);
1081
1082 lq->ld_nb->maxlen = nb->maxlen;
1083 lq->ld_nb->len = nb->len;
1084
1085 lq->ld_nb->buf = malloc(lq->ld_nb->len);
1086 if (lq->ld_nb->buf == NULL)
1087 goto cleanup;
1088
1089 bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len);
1090 }
1091
1092 lq->ld_path = strdup(path);
1093 if (lq->ld_path == NULL)
1094 goto cleanup;
1095
1096 if (!error) {
1097 lq->ld_rpath = strdup(rpath);
1098 if (lq->ld_rpath == NULL)
1099 goto cleanup;
1100 }
1101
1102 lq->ld_status = status;
1103
1104 /*
1105 * Add to the tail of the logging queue.
1106 */
1107 (void) mutex_lock(&logging_queue_lock);
1108 if (logging_tail == NULL) {
1109 logging_tail = logging_head = lq;
1110 } else {
1111 logging_tail->ld_next = lq;
1112 logging_tail = lq;
1113 }
1114 (void) cond_signal(&logging_queue_cv);
1115 (void) mutex_unlock(&logging_queue_lock);
1116
1117 return (TRUE);
1118
1119 cleanup:
1120
1121 free_logging_data(lq);
1122
1123 return (FALSE);
1124 }
1125
1126 /*
1127 * Check mount requests, add to mounted list if ok
1128 */
1129 static int
mount(struct svc_req * rqstp)1130 mount(struct svc_req *rqstp)
1131 {
1132 SVCXPRT *transp;
1133 int version, vers;
1134 struct fhstatus fhs;
1135 struct mountres3 mountres3;
1136 char fh[FHSIZE3];
1137 int len = FHSIZE3;
1138 char *path, rpath[MAXPATHLEN];
1139 share_t *sh = NULL;
1140 struct nd_hostservlist *clnames = NULL;
1141 char *host = NULL;
1142 int error = 0, lofs_tried = 0, enqueued;
1143 int flavor_list[MAX_FLAVORS];
1144 int flavor_count;
1145 struct netbuf *nb = NULL;
1146 ucred_t *uc = NULL;
1147
1148 int audit_status;
1149
1150 transp = rqstp->rq_xprt;
1151 version = rqstp->rq_vers;
1152 path = NULL;
1153
1154 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
1155 svcerr_decode(transp);
1156 return (EACCES);
1157 }
1158
1159 /*
1160 * Put off getting the name for the client until we
1161 * need it. This is a performance gain. If we are logging,
1162 * then we don't care about performance and might as well
1163 * get the host name now in case we need to spit out an
1164 * error message.
1165 */
1166 if (verbose) {
1167 DTRACE_PROBE(mountd, name_by_verbose);
1168 if (getclientsnames(transp, &nb, &clnames) != 0) {
1169 /*
1170 * We failed to get a name for the client, even
1171 * 'anon', probably because we ran out of memory.
1172 * In this situation it doesn't make sense to
1173 * allow the mount to succeed.
1174 */
1175 error = EACCES;
1176 goto reply;
1177 }
1178 host = clnames->h_hostservs[0].h_host;
1179 }
1180
1181 /*
1182 * If the version being used is less than the minimum version,
1183 * the filehandle translation should not be provided to the
1184 * client.
1185 */
1186 if (rejecting || version < mount_vers_min) {
1187 if (verbose)
1188 syslog(LOG_NOTICE, "Rejected mount: %s for %s",
1189 host, path);
1190 error = EACCES;
1191 goto reply;
1192 }
1193
1194 /*
1195 * Trusted Extension doesn't support nfsv2. nfsv2 client
1196 * uses MOUNT protocol v1 and v2. To prevent circumventing
1197 * TX label policy via using nfsv2 client, reject a mount
1198 * request with version less than 3 and log an error.
1199 */
1200 if (is_system_labeled()) {
1201 if (version < 3) {
1202 if (verbose)
1203 syslog(LOG_ERR,
1204 "Rejected mount: TX doesn't support NFSv2");
1205 error = EACCES;
1206 goto reply;
1207 }
1208 }
1209
1210 /*
1211 * Get the real path (no symbolic links in it)
1212 */
1213 if (realpath(path, rpath) == NULL) {
1214 error = errno;
1215 if (verbose)
1216 syslog(LOG_ERR,
1217 "mount request: realpath: %s: %m", path);
1218 if (error == ENOENT)
1219 error = mount_enoent_error(transp, path, rpath,
1220 &clnames, &nb, flavor_list);
1221 goto reply;
1222 }
1223
1224 if ((sh = findentry(rpath)) == NULL &&
1225 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
1226 error = EACCES;
1227 goto reply;
1228 }
1229
1230 /*
1231 * Check if this is a "nosub" only export, in which case, mounting
1232 * subdirectories isn't allowed. Bug 1184573.
1233 */
1234 if (checkrootmount(sh, rpath) == 0) {
1235 error = EACCES;
1236 goto reply;
1237 }
1238
1239 if (newopts(sh->sh_opts))
1240 flavor_count = getclientsflavors_new(sh, transp, &nb, &clnames,
1241 flavor_list);
1242 else
1243 flavor_count = getclientsflavors_old(sh, transp, &nb, &clnames,
1244 flavor_list);
1245
1246 if (clnames)
1247 host = clnames->h_hostservs[0].h_host;
1248
1249 if (flavor_count == 0) {
1250 error = EACCES;
1251 goto reply;
1252 }
1253
1254 /*
1255 * Check MAC policy here. The server side policy should be
1256 * consistent with client side mount policy, i.e.
1257 * - we disallow an admin_low unlabeled client to mount
1258 * - we disallow mount from a lower labeled client.
1259 */
1260 if (is_system_labeled()) {
1261 m_label_t *clabel = NULL;
1262 m_label_t *slabel = NULL;
1263 m_label_t admin_low;
1264
1265 if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
1266 syslog(LOG_ERR,
1267 "mount request: Failed to get caller's ucred : %m");
1268 error = EACCES;
1269 goto reply;
1270 }
1271 if ((clabel = ucred_getlabel(uc)) == NULL) {
1272 syslog(LOG_ERR,
1273 "mount request: can't get client label from ucred");
1274 error = EACCES;
1275 goto reply;
1276 }
1277
1278 bsllow(&admin_low);
1279 if (blequal(&admin_low, clabel)) {
1280 struct sockaddr *ca;
1281 tsol_tpent_t *tp;
1282
1283 ca = (struct sockaddr *)(void *)svc_getrpccaller(
1284 rqstp->rq_xprt)->buf;
1285 if (ca == NULL) {
1286 error = EACCES;
1287 goto reply;
1288 }
1289 /*
1290 * get trusted network template associated
1291 * with the client.
1292 */
1293 tp = get_client_template(ca);
1294 if (tp == NULL || tp->host_type != SUN_CIPSO) {
1295 if (tp != NULL)
1296 tsol_freetpent(tp);
1297 error = EACCES;
1298 goto reply;
1299 }
1300 tsol_freetpent(tp);
1301 } else {
1302 if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) {
1303 error = EACCES;
1304 goto reply;
1305 }
1306
1307 if (getlabel(rpath, slabel) != 0) {
1308 m_label_free(slabel);
1309 error = EACCES;
1310 goto reply;
1311 }
1312
1313 if (!bldominates(clabel, slabel)) {
1314 m_label_free(slabel);
1315 error = EACCES;
1316 goto reply;
1317 }
1318 m_label_free(slabel);
1319 }
1320 }
1321
1322 /*
1323 * Now get the filehandle.
1324 *
1325 * NFS V2 clients get a 32 byte filehandle.
1326 * NFS V3 clients get a 32 or 64 byte filehandle, depending on
1327 * the embedded FIDs.
1328 */
1329 vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION;
1330
1331 /* LINTED pointer alignment */
1332 while (nfs_getfh(rpath, vers, &len, fh) < 0) {
1333 if (errno == EINVAL &&
1334 (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) {
1335 errno = 0;
1336 continue;
1337 }
1338 error = errno == EINVAL ? EACCES : errno;
1339 syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m",
1340 path);
1341 break;
1342 }
1343
1344 if (version == MOUNTVERS3) {
1345 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len;
1346 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh;
1347 } else {
1348 bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE);
1349 }
1350
1351 reply:
1352 if (uc != NULL)
1353 ucred_free(uc);
1354
1355 switch (version) {
1356 case MOUNTVERS:
1357 case MOUNTVERS_POSIX:
1358 if (error == EINVAL)
1359 fhs.fhs_status = NFSERR_ACCES;
1360 else if (error == EREMOTE)
1361 fhs.fhs_status = NFSERR_REMOTE;
1362 else
1363 fhs.fhs_status = error;
1364
1365 if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
1366 log_cant_reply(transp);
1367
1368 audit_status = fhs.fhs_status;
1369 break;
1370
1371 case MOUNTVERS3:
1372 if (!error) {
1373 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
1374 flavor_list;
1375 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
1376 flavor_count;
1377
1378 } else if (error == ENAMETOOLONG)
1379 error = MNT3ERR_NAMETOOLONG;
1380
1381 mountres3.fhs_status = error;
1382 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1383 log_cant_reply(transp);
1384
1385 audit_status = mountres3.fhs_status;
1386 break;
1387 }
1388
1389 if (verbose)
1390 syslog(LOG_NOTICE, "MOUNT: %s %s %s",
1391 (host == NULL) ? "unknown host" : host,
1392 error ? "denied" : "mounted", path);
1393
1394 /*
1395 * If we can not create a queue entry, go ahead and do it
1396 * in the context of this thread.
1397 */
1398 enqueued = enqueue_logging_data(host, transp, path, rpath,
1399 audit_status, error);
1400 if (enqueued == FALSE) {
1401 if (host == NULL) {
1402 DTRACE_PROBE(mountd, name_by_in_thread);
1403 if (getclientsnames(transp, &nb, &clnames) == 0)
1404 host = clnames->h_hostservs[0].h_host;
1405 }
1406
1407 DTRACE_PROBE(mountd, logged_in_thread);
1408 audit_mountd_mount(host, path, audit_status); /* BSM */
1409 if (!error)
1410 mntlist_new(host, rpath); /* add entry to mount list */
1411 }
1412
1413 if (path != NULL)
1414 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
1415
1416 done:
1417 if (sh)
1418 sharefree(sh);
1419 netdir_free(clnames, ND_HOSTSERVLIST);
1420
1421 return (error);
1422 }
1423
1424 /*
1425 * Determine whether two paths are within the same file system.
1426 * Returns nonzero (true) if paths are the same, zero (false) if
1427 * they are different. If an error occurs, return false.
1428 *
1429 * Use the actual FSID if it's available (via getattrat()); otherwise,
1430 * fall back on st_dev.
1431 *
1432 * With ZFS snapshots, st_dev differs from the regular file system
1433 * versus the snapshot. But the fsid is the same throughout. Thus
1434 * the fsid is a better test.
1435 */
1436 static int
same_file_system(const char * path1,const char * path2)1437 same_file_system(const char *path1, const char *path2)
1438 {
1439 uint64_t fsid1, fsid2;
1440 struct stat64 st1, st2;
1441 nvlist_t *nvl1 = NULL;
1442 nvlist_t *nvl2 = NULL;
1443
1444 if ((getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path1, &nvl1) == 0) &&
1445 (getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path2, &nvl2) == 0) &&
1446 (nvlist_lookup_uint64(nvl1, A_FSID, &fsid1) == 0) &&
1447 (nvlist_lookup_uint64(nvl2, A_FSID, &fsid2) == 0)) {
1448 nvlist_free(nvl1);
1449 nvlist_free(nvl2);
1450 /*
1451 * We have found fsid's for both paths.
1452 */
1453
1454 if (fsid1 == fsid2)
1455 return (B_TRUE);
1456
1457 return (B_FALSE);
1458 }
1459
1460 if (nvl1 != NULL)
1461 nvlist_free(nvl1);
1462 if (nvl2 != NULL)
1463 nvlist_free(nvl2);
1464
1465 /*
1466 * We were unable to find fsid's for at least one of the paths.
1467 * fall back on st_dev.
1468 */
1469
1470 if (stat64(path1, &st1) < 0) {
1471 syslog(LOG_NOTICE, "%s: %m", path1);
1472 return (B_FALSE);
1473 }
1474 if (stat64(path2, &st2) < 0) {
1475 syslog(LOG_NOTICE, "%s: %m", path2);
1476 return (B_FALSE);
1477 }
1478
1479 if (st1.st_dev == st2.st_dev)
1480 return (B_TRUE);
1481
1482 return (B_FALSE);
1483 }
1484
1485 share_t *
findentry(char * path)1486 findentry(char *path)
1487 {
1488 share_t *sh = NULL;
1489 struct sh_list *shp;
1490 register char *p1, *p2;
1491
1492 check_sharetab();
1493
1494 (void) rw_rdlock(&sharetab_lock);
1495
1496 for (shp = share_list; shp; shp = shp->shl_next) {
1497 sh = shp->shl_sh;
1498 for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++)
1499 if (*p1 == '\0')
1500 goto done; /* exact match */
1501
1502 /*
1503 * Now compare the pathnames for three cases:
1504 *
1505 * Parent: /export/foo (no trailing slash on parent)
1506 * Child: /export/foo/bar
1507 *
1508 * Parent: /export/foo/ (trailing slash on parent)
1509 * Child: /export/foo/bar
1510 *
1511 * Parent: /export/foo/ (no trailing slash on child)
1512 * Child: /export/foo
1513 */
1514 if ((*p1 == '\0' && *p2 == '/') ||
1515 (*p1 == '\0' && *(p1-1) == '/') ||
1516 (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) {
1517 /*
1518 * We have a subdirectory. Test whether the
1519 * subdirectory is in the same file system.
1520 */
1521 if (same_file_system(path, sh->sh_path))
1522 goto done;
1523 }
1524 }
1525 done:
1526 sh = shp ? sharedup(sh) : NULL;
1527
1528 (void) rw_unlock(&sharetab_lock);
1529
1530 return (sh);
1531 }
1532
1533
1534 static int
is_substring(char ** mntp,char ** path)1535 is_substring(char **mntp, char **path)
1536 {
1537 char *p1 = *mntp, *p2 = *path;
1538
1539 if (*p1 == '\0' && *p2 == '\0') /* exact match */
1540 return (1);
1541 else if (*p1 == '\0' && *p2 == '/')
1542 return (1);
1543 else if (*p1 == '\0' && *(p1-1) == '/') {
1544 *path = --p2; /* we need the slash in p2 */
1545 return (1);
1546 } else if (*p2 == '\0') {
1547 while (*p1 == '/')
1548 p1++;
1549 if (*p1 == '\0') /* exact match */
1550 return (1);
1551 }
1552 return (0);
1553 }
1554
1555 /*
1556 * find_lofsentry() searches for the real path which this requested LOFS path
1557 * (rpath) shadows. If found, it will return the sharetab entry of
1558 * the real path that corresponds to the LOFS path.
1559 * We first search mnttab to see if the requested path is an automounted
1560 * path. If it is an automounted path, it will trigger the mount by stat()ing
1561 * the requested path. Note that it is important to check that this path is
1562 * actually an automounted path, otherwise we would stat() a path which may
1563 * turn out to be NFS and block indefinitely on a dead server. The automounter
1564 * times-out if the server is dead, so there's no risk of hanging this
1565 * thread waiting for stat().
1566 * After the mount has been triggered (if necessary), we look for a
1567 * mountpoint of type LOFS (by searching /etc/mnttab again) which
1568 * is a substring of the rpath. If found, we construct a new path by
1569 * concatenating the mnt_special and the remaining of rpath, call findentry()
1570 * to make sure the 'real path' is shared.
1571 */
1572 static share_t *
find_lofsentry(char * rpath,int * done_flag)1573 find_lofsentry(char *rpath, int *done_flag)
1574 {
1575 struct stat r_stbuf;
1576 mntlist_t *ml, *mntl, *mntpnt = NULL;
1577 share_t *retcode = NULL;
1578 char tmp_path[MAXPATHLEN];
1579 int mntpnt_len = 0, tmp;
1580 char *p1, *p2;
1581
1582 if ((*done_flag)++)
1583 return (retcode);
1584
1585 /*
1586 * While fsgetmntlist() uses lockf() to
1587 * lock the mnttab before reading it in,
1588 * the lock ignores threads in the same process.
1589 * Read in the mnttab with the protection of a mutex.
1590 */
1591 (void) mutex_lock(&mnttab_lock);
1592 mntl = fsgetmntlist();
1593 (void) mutex_unlock(&mnttab_lock);
1594
1595 /*
1596 * Obtain the mountpoint for the requested path.
1597 */
1598 for (ml = mntl; ml; ml = ml->mntl_next) {
1599 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1600 *p1 == *p2 && *p1; p1++, p2++)
1601 ;
1602 if (is_substring(&p1, &p2) &&
1603 (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) {
1604 mntpnt = ml;
1605 mntpnt_len = tmp;
1606 }
1607 }
1608
1609 /*
1610 * If the path needs to be autoFS mounted, trigger the mount by
1611 * stat()ing it. This is determined by checking whether the
1612 * mountpoint we just found is of type autofs.
1613 */
1614 if (mntpnt != NULL &&
1615 strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) {
1616 /*
1617 * The requested path is a substring of an autoFS filesystem.
1618 * Trigger the mount.
1619 */
1620 if (stat(rpath, &r_stbuf) < 0) {
1621 if (verbose)
1622 syslog(LOG_NOTICE, "%s: %m", rpath);
1623 goto done;
1624 }
1625 if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) {
1626 /*
1627 * The requested path is a directory, stat(2) it
1628 * again with a trailing '.' to force the autoFS
1629 * module to trigger the mount of indirect
1630 * automount entries, such as /net/jurassic/.
1631 */
1632 if (strlen(rpath) + 2 > MAXPATHLEN) {
1633 if (verbose) {
1634 syslog(LOG_NOTICE,
1635 "%s/.: exceeds MAXPATHLEN %d",
1636 rpath, MAXPATHLEN);
1637 }
1638 goto done;
1639 }
1640 (void) strcpy(tmp_path, rpath);
1641 (void) strcat(tmp_path, "/.");
1642
1643 if (stat(tmp_path, &r_stbuf) < 0) {
1644 if (verbose)
1645 syslog(LOG_NOTICE, "%s: %m", tmp_path);
1646 goto done;
1647 }
1648 }
1649
1650 /*
1651 * The mount has been triggered, re-read mnttab to pick up
1652 * the changes made by autoFS.
1653 */
1654 fsfreemntlist(mntl);
1655 (void) mutex_lock(&mnttab_lock);
1656 mntl = fsgetmntlist();
1657 (void) mutex_unlock(&mnttab_lock);
1658 }
1659
1660 /*
1661 * The autoFS mountpoint has been triggered if necessary,
1662 * now search mnttab again to determine if the requested path
1663 * is an LOFS mount of a shared path.
1664 */
1665 mntpnt_len = 0;
1666 for (ml = mntl; ml; ml = ml->mntl_next) {
1667 if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs"))
1668 continue;
1669
1670 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1671 *p1 == *p2 && *p1; p1++, p2++)
1672 ;
1673
1674 if (is_substring(&p1, &p2) &&
1675 ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) {
1676 mntpnt_len = tmp;
1677
1678 if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) >
1679 MAXPATHLEN) {
1680 if (verbose) {
1681 syslog(LOG_NOTICE, "%s%s: exceeds %d",
1682 ml->mntl_mnt->mnt_special, p2,
1683 MAXPATHLEN);
1684 }
1685 if (retcode)
1686 sharefree(retcode);
1687 retcode = NULL;
1688 goto done;
1689 }
1690
1691 (void) strcpy(tmp_path, ml->mntl_mnt->mnt_special);
1692 (void) strcat(tmp_path, p2);
1693 if (retcode)
1694 sharefree(retcode);
1695 retcode = findentry(tmp_path);
1696 }
1697 }
1698
1699 if (retcode) {
1700 assert(strlen(tmp_path) > 0);
1701 (void) strcpy(rpath, tmp_path);
1702 }
1703
1704 done:
1705 fsfreemntlist(mntl);
1706 return (retcode);
1707 }
1708
1709 /*
1710 * Determine whether an access list grants rights to a particular host.
1711 * We match on aliases of the hostname as well as on the canonical name.
1712 * Names in the access list may be either hosts or netgroups; they're
1713 * not distinguished syntactically. We check for hosts first because
1714 * it's cheaper (just M*N strcmp()s), then try netgroups.
1715 *
1716 * If pnb and pclnames are NULL, it means that we have to use transp
1717 * to resolve client's IP address to host name. If they aren't NULL
1718 * then transp argument won't be used and can be NULL.
1719 */
1720 int
in_access_list(SVCXPRT * transp,struct netbuf ** pnb,struct nd_hostservlist ** pclnames,char * access_list)1721 in_access_list(SVCXPRT *transp, struct netbuf **pnb,
1722 struct nd_hostservlist **pclnames,
1723 char *access_list) /* N.B. we clobber this "input" parameter */
1724 {
1725 int nentries;
1726 char *gr;
1727 char *lasts;
1728 char *host;
1729 int off;
1730 int i;
1731 int netgroup_match;
1732 int response;
1733 struct nd_hostservlist *clnames;
1734
1735 /*
1736 * If no access list - then it's unrestricted
1737 */
1738 if (access_list == NULL || *access_list == '\0')
1739 return (1);
1740
1741 assert(transp != NULL || (*pnb != NULL && *pclnames != NULL));
1742
1743 nentries = 0;
1744
1745 for (gr = strtok_r(access_list, ":", &lasts);
1746 gr != NULL; gr = strtok_r(NULL, ":", &lasts)) {
1747
1748 /*
1749 * If the list name has a '-' prepended
1750 * then a match of the following name
1751 * implies failure instead of success.
1752 */
1753 if (*gr == '-') {
1754 response = 0;
1755 gr++;
1756 } else
1757 response = 1;
1758
1759 /*
1760 * If the list name begins with an at
1761 * sign then do a network comparison.
1762 */
1763 if (*gr == '@') {
1764 /*
1765 * Just get the netbuf, avoiding the costly name
1766 * lookup. This will suffice for access based
1767 * solely on addresses.
1768 */
1769 if (*pnb == NULL) {
1770 /*
1771 * Don't grant access if client's address isn't
1772 * known.
1773 */
1774 if ((*pnb = svc_getrpccaller(transp)) == NULL)
1775 return (0);
1776 }
1777
1778 if (netmatch(*pnb, gr + 1))
1779 return (response);
1780 continue;
1781 }
1782
1783 /*
1784 * We need to get the host name if we haven't gotten
1785 * it by now!
1786 */
1787 if (*pclnames == NULL) {
1788 DTRACE_PROBE(mountd, name_by_addrlist);
1789 /*
1790 * Do not grant access if we can't
1791 * get a name!
1792 */
1793 if (getclientsnames(transp, pnb, pclnames) != 0)
1794 return (0);
1795 }
1796
1797 clnames = *pclnames;
1798
1799 /*
1800 * The following loops through all the
1801 * client's aliases. Usually it's just one name.
1802 */
1803 for (i = 0; i < clnames->h_cnt; i++) {
1804 host = clnames->h_hostservs[i].h_host;
1805
1806 /*
1807 * If the list name begins with a dot then
1808 * do a domain name suffix comparison.
1809 * A single dot matches any name with no
1810 * suffix.
1811 */
1812 if (*gr == '.') {
1813 if (*(gr + 1) == '\0') { /* single dot */
1814 if (strchr(host, '.') == NULL)
1815 return (response);
1816 } else {
1817 off = strlen(host) - strlen(gr);
1818 if (off > 0 &&
1819 strcasecmp(host + off, gr) == 0) {
1820 return (response);
1821 }
1822 }
1823 } else
1824
1825 /*
1826 * Just do a hostname match
1827 */
1828 if (strcasecmp(gr, host) == 0) {
1829 return (response); /* Matched a hostname */
1830 }
1831 }
1832
1833 nentries++;
1834 }
1835
1836 /*
1837 * We need to get the host name if we haven't gotten
1838 * it by now!
1839 */
1840 if (*pclnames == NULL) {
1841 DTRACE_PROBE(mountd, name_by_netgroup);
1842 /*
1843 * Do not grant access if we can't
1844 * get a name!
1845 */
1846 if (getclientsnames(transp, pnb, pclnames) != 0)
1847 return (0);
1848 }
1849
1850 netgroup_match = netgroup_check(*pclnames, access_list, nentries);
1851
1852 return (netgroup_match);
1853 }
1854
1855 int
netmatch(struct netbuf * nb,char * name)1856 netmatch(struct netbuf *nb, char *name)
1857 {
1858 uint_t claddr;
1859 struct netent n, *np;
1860 char *mp, *p;
1861 uint_t addr, mask;
1862 int i, bits;
1863 char buff[256];
1864
1865 /*
1866 * Check if it's an IPv4 addr
1867 */
1868 if (nb->len != sizeof (struct sockaddr_in))
1869 return (0);
1870
1871 (void) memcpy(&claddr,
1872 /* LINTED pointer alignment */
1873 &((struct sockaddr_in *)nb->buf)->sin_addr.s_addr,
1874 sizeof (struct in_addr));
1875 claddr = ntohl(claddr);
1876
1877 mp = strchr(name, '/');
1878 if (mp)
1879 *mp++ = '\0';
1880
1881 if (isdigit(*name)) {
1882 /*
1883 * Convert a dotted IP address
1884 * to an IP address. The conversion
1885 * is not the same as that in inet_addr().
1886 */
1887 p = name;
1888 addr = 0;
1889 for (i = 0; i < 4; i++) {
1890 addr |= atoi(p) << ((3-i) * 8);
1891 p = strchr(p, '.');
1892 if (p == NULL)
1893 break;
1894 p++;
1895 }
1896 } else {
1897 /*
1898 * Turn the netname into
1899 * an IP address.
1900 */
1901 np = getnetbyname_r(name, &n, buff, sizeof (buff));
1902 if (np == NULL) {
1903 syslog(LOG_DEBUG, "getnetbyname_r: %s: %m", name);
1904 return (0);
1905 }
1906 addr = np->n_net;
1907 }
1908
1909 /*
1910 * If the mask is specified explicitly then
1911 * use that value, e.g.
1912 *
1913 * @109.104.56/28
1914 *
1915 * otherwise assume a mask from the zero octets
1916 * in the least significant bits of the address, e.g.
1917 *
1918 * @109.104 or @109.104.0.0
1919 */
1920 if (mp) {
1921 bits = atoi(mp);
1922 mask = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - bits)
1923 : 0;
1924 addr &= mask;
1925 } else {
1926 if ((addr & IN_CLASSA_HOST) == 0)
1927 mask = IN_CLASSA_NET;
1928 else if ((addr & IN_CLASSB_HOST) == 0)
1929 mask = IN_CLASSB_NET;
1930 else if ((addr & IN_CLASSC_HOST) == 0)
1931 mask = IN_CLASSC_NET;
1932 else
1933 mask = IN_CLASSE_NET;
1934 }
1935
1936 return ((claddr & mask) == addr);
1937 }
1938
1939
1940 static char *optlist[] = {
1941 #define OPT_RO 0
1942 SHOPT_RO,
1943 #define OPT_RW 1
1944 SHOPT_RW,
1945 #define OPT_ROOT 2
1946 SHOPT_ROOT,
1947 #define OPT_SECURE 3
1948 SHOPT_SECURE,
1949 #define OPT_ANON 4
1950 SHOPT_ANON,
1951 #define OPT_WINDOW 5
1952 SHOPT_WINDOW,
1953 #define OPT_NOSUID 6
1954 SHOPT_NOSUID,
1955 #define OPT_ACLOK 7
1956 SHOPT_ACLOK,
1957 #define OPT_SEC 8
1958 SHOPT_SEC,
1959 #define OPT_NONE 9
1960 SHOPT_NONE,
1961 NULL
1962 };
1963
1964 static int
map_flavor(char * str)1965 map_flavor(char *str)
1966 {
1967 seconfig_t sec;
1968
1969 if (nfs_getseconfig_byname(str, &sec))
1970 return (-1);
1971
1972 return (sec.sc_nfsnum);
1973 }
1974
1975 /*
1976 * If the option string contains a "sec="
1977 * option, then use new option syntax.
1978 */
1979 static int
newopts(char * opts)1980 newopts(char *opts)
1981 {
1982 char *head, *p, *val;
1983
1984 if (!opts || *opts == '\0')
1985 return (0);
1986
1987 head = strdup(opts);
1988 if (head == NULL) {
1989 syslog(LOG_ERR, "opts: no memory");
1990 return (0);
1991 }
1992
1993 p = head;
1994 while (*p) {
1995 if (getsubopt(&p, optlist, &val) == OPT_SEC) {
1996 free(head);
1997 return (1);
1998 }
1999 }
2000
2001 free(head);
2002 return (0);
2003 }
2004
2005 /*
2006 * Given an export and the clients hostname(s)
2007 * determine the security flavors that this
2008 * client is permitted to use.
2009 *
2010 * This routine is called only for "old" syntax, i.e.
2011 * only one security flavor is allowed. So we need
2012 * to determine two things: the particular flavor,
2013 * and whether the client is allowed to use this
2014 * flavor, i.e. is in the access list.
2015 *
2016 * Note that if there is no access list, then the
2017 * default is that access is granted.
2018 */
2019 static int
getclientsflavors_old(share_t * sh,SVCXPRT * transp,struct netbuf ** nb,struct nd_hostservlist ** clnames,int * flavors)2020 getclientsflavors_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2021 struct nd_hostservlist **clnames, int *flavors)
2022 {
2023 char *opts, *p, *val;
2024 boolean_t ok = B_FALSE;
2025 int defaultaccess = 1;
2026 boolean_t reject = B_FALSE;
2027
2028 opts = strdup(sh->sh_opts);
2029 if (opts == NULL) {
2030 syslog(LOG_ERR, "getclientsflavors: no memory");
2031 return (0);
2032 }
2033
2034 flavors[0] = AUTH_SYS;
2035 p = opts;
2036
2037 while (*p) {
2038
2039 switch (getsubopt(&p, optlist, &val)) {
2040 case OPT_SECURE:
2041 flavors[0] = AUTH_DES;
2042 break;
2043
2044 case OPT_RO:
2045 case OPT_RW:
2046 defaultaccess = 0;
2047 if (in_access_list(transp, nb, clnames, val))
2048 ok++;
2049 break;
2050
2051 case OPT_NONE:
2052 defaultaccess = 0;
2053 if (in_access_list(transp, nb, clnames, val))
2054 reject = B_TRUE;
2055 }
2056 }
2057
2058 free(opts);
2059
2060 /* none takes precedence over everything else */
2061 if (reject)
2062 ok = B_TRUE;
2063
2064 return (defaultaccess || ok);
2065 }
2066
2067 /*
2068 * Given an export and the clients hostname(s)
2069 * determine the security flavors that this
2070 * client is permitted to use.
2071 *
2072 * This is somewhat more complicated than the "old"
2073 * routine because the options may contain multiple
2074 * security flavors (sec=) each with its own access
2075 * lists. So a client could be granted access based
2076 * on a number of security flavors. Note that the
2077 * type of access might not always be the same, the
2078 * client may get readonly access with one flavor
2079 * and readwrite with another, however the client
2080 * is not told this detail, it gets only the list
2081 * of flavors, and only if the client is using
2082 * version 3 of the mount protocol.
2083 */
2084 static int
getclientsflavors_new(share_t * sh,SVCXPRT * transp,struct netbuf ** nb,struct nd_hostservlist ** clnames,int * flavors)2085 getclientsflavors_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2086 struct nd_hostservlist **clnames, int *flavors)
2087 {
2088 char *opts, *p, *val;
2089 char *lasts;
2090 char *f;
2091 boolean_t access_ok;
2092 int count, c, perm;
2093 boolean_t reject = B_FALSE;
2094
2095 opts = strdup(sh->sh_opts);
2096 if (opts == NULL) {
2097 syslog(LOG_ERR, "getclientsflavors: no memory");
2098 return (0);
2099 }
2100
2101 p = opts;
2102 perm = count = c = 0;
2103 /* default access is rw */
2104 access_ok = B_TRUE;
2105
2106 while (*p) {
2107 switch (getsubopt(&p, optlist, &val)) {
2108 case OPT_SEC:
2109 /*
2110 * Before a new sec=xxx option, check if we need
2111 * to move the c index back to the previous count.
2112 */
2113 if (!access_ok) {
2114 c = count;
2115 }
2116
2117 /* get all the sec=f1[:f2] flavors */
2118 while ((f = strtok_r(val, ":", &lasts))
2119 != NULL) {
2120 flavors[c++] = map_flavor(f);
2121 val = NULL;
2122 }
2123
2124 /* for a new sec=xxx option, default is rw access */
2125 access_ok = B_TRUE;
2126 break;
2127
2128 case OPT_RO:
2129 case OPT_RW:
2130 if (in_access_list(transp, nb, clnames, val)) {
2131 count = c;
2132 access_ok = B_TRUE;
2133 } else {
2134 access_ok = B_FALSE;
2135 }
2136 break;
2137
2138 case OPT_NONE:
2139 if (in_access_list(transp, nb, clnames, val))
2140 reject = B_TRUE; /* none overides rw/ro */
2141 break;
2142 }
2143 }
2144
2145 if (reject)
2146 access_ok = B_FALSE;
2147
2148 if (!access_ok)
2149 c = count;
2150
2151 free(opts);
2152
2153 return (c);
2154 }
2155
2156 /*
2157 * This is a tricky piece of code that parses the
2158 * share options looking for a match on the auth
2159 * flavor that the client is using. If it finds
2160 * a match, then the client is given ro, rw, or
2161 * no access depending whether it is in the access
2162 * list. There is a special case for "secure"
2163 * flavor. Other flavors are values of the new "sec=" option.
2164 */
2165 int
check_client(share_t * sh,struct netbuf * nb,struct nd_hostservlist * clnames,int flavor)2166 check_client(share_t *sh, struct netbuf *nb,
2167 struct nd_hostservlist *clnames, int flavor)
2168 {
2169 if (newopts(sh->sh_opts))
2170 return (check_client_new(sh, NULL, &nb, &clnames, flavor));
2171 else
2172 return (check_client_old(sh, NULL, &nb, &clnames, flavor));
2173 }
2174
2175 static int
check_client_old(share_t * sh,SVCXPRT * transp,struct netbuf ** nb,struct nd_hostservlist ** clnames,int flavor)2176 check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2177 struct nd_hostservlist **clnames, int flavor)
2178 {
2179 char *opts, *p, *val;
2180 int match; /* Set when a flavor is matched */
2181 int perm = 0; /* Set when "ro", "rw" or "root" is matched */
2182 int list = 0; /* Set when "ro", "rw" is found */
2183 int ro_val = 0; /* Set if ro option is 'ro=' */
2184 int rw_val = 0; /* Set if rw option is 'rw=' */
2185 boolean_t reject = B_FALSE; /* if none= contains the host */
2186
2187 opts = strdup(sh->sh_opts);
2188 if (opts == NULL) {
2189 syslog(LOG_ERR, "check_client: no memory");
2190 return (0);
2191 }
2192
2193 p = opts;
2194 match = AUTH_UNIX;
2195
2196 while (*p) {
2197 switch (getsubopt(&p, optlist, &val)) {
2198
2199 case OPT_SECURE:
2200 match = AUTH_DES;
2201 break;
2202
2203 case OPT_RO:
2204 list++;
2205 if (val) ro_val++;
2206 if (in_access_list(transp, nb, clnames, val))
2207 perm |= NFSAUTH_RO;
2208 break;
2209
2210 case OPT_RW:
2211 list++;
2212 if (val) rw_val++;
2213 if (in_access_list(transp, nb, clnames, val))
2214 perm |= NFSAUTH_RW;
2215 break;
2216
2217 case OPT_ROOT:
2218 /*
2219 * Check if the client is in
2220 * the root list. Only valid
2221 * for AUTH_SYS.
2222 */
2223 if (flavor != AUTH_SYS)
2224 break;
2225
2226 if (val == NULL || *val == '\0')
2227 break;
2228
2229 if (in_access_list(transp, nb, clnames, val))
2230 perm |= NFSAUTH_ROOT;
2231 break;
2232
2233 case OPT_NONE:
2234 /*
2235 * Check if the client should have no access
2236 * to this share at all. This option behaves
2237 * more like "root" than either "rw" or "ro".
2238 */
2239 if (in_access_list(transp, nb, clnames, val))
2240 reject = B_TRUE;
2241 break;
2242 }
2243 }
2244
2245 free(opts);
2246
2247 if (flavor != match || reject)
2248 return (NFSAUTH_DENIED);
2249
2250 if (list) {
2251 /*
2252 * If the client doesn't match an "ro" or "rw"
2253 * list then set no access.
2254 */
2255 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0)
2256 perm |= NFSAUTH_DENIED;
2257 } else {
2258 /*
2259 * The client matched a flavor entry that
2260 * has no explicit "rw" or "ro" determination.
2261 * Default it to "rw".
2262 */
2263 perm |= NFSAUTH_RW;
2264 }
2265
2266
2267 /*
2268 * The client may show up in both ro= and rw=
2269 * lists. If so, then turn off the RO access
2270 * bit leaving RW access.
2271 */
2272 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2273 /*
2274 * Logically cover all permutations of rw=,ro=.
2275 * In the case where, rw,ro=<host> we would like
2276 * to remove RW access for the host. In all other cases
2277 * RW wins the precedence battle.
2278 */
2279 if (!rw_val && ro_val) {
2280 perm &= ~(NFSAUTH_RW);
2281 } else {
2282 perm &= ~(NFSAUTH_RO);
2283 }
2284 }
2285
2286 return (perm);
2287 }
2288
2289 /*
2290 * Check if the client has access by using a flavor different from
2291 * the given "flavor". If "flavor" is not in the flavor list,
2292 * return TRUE to indicate that this "flavor" is a wrong sec.
2293 */
2294 static bool_t
is_wrongsec(share_t * sh,SVCXPRT * transp,struct netbuf ** nb,struct nd_hostservlist ** clnames,int flavor)2295 is_wrongsec(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2296 struct nd_hostservlist **clnames, int flavor)
2297 {
2298 int flavor_list[MAX_FLAVORS];
2299 int flavor_count, i;
2300
2301 /* get the flavor list that the client has access with */
2302 flavor_count = getclientsflavors_new(sh, transp, nb,
2303 clnames, flavor_list);
2304
2305 if (flavor_count == 0)
2306 return (FALSE);
2307
2308 /*
2309 * Check if the given "flavor" is in the flavor_list.
2310 */
2311 for (i = 0; i < flavor_count; i++) {
2312 if (flavor == flavor_list[i])
2313 return (FALSE);
2314 }
2315
2316 /*
2317 * If "flavor" is not in the flavor_list, return TRUE to indicate
2318 * that the client should have access by using a security flavor
2319 * different from this "flavor".
2320 */
2321 return (TRUE);
2322 }
2323
2324 /*
2325 * Given an export and the client's hostname, we
2326 * check the security options to see whether the
2327 * client is allowed to use the given security flavor.
2328 *
2329 * The strategy is to proceed through the options looking
2330 * for a flavor match, then pay attention to the ro, rw,
2331 * and root options.
2332 *
2333 * Note that an entry may list several flavors in a
2334 * single entry, e.g.
2335 *
2336 * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
2337 *
2338 */
2339
2340 static int
check_client_new(share_t * sh,SVCXPRT * transp,struct netbuf ** nb,struct nd_hostservlist ** clnames,int flavor)2341 check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2342 struct nd_hostservlist **clnames, int flavor)
2343 {
2344 char *opts, *p, *val;
2345 char *lasts;
2346 char *f;
2347 int match = 0; /* Set when a flavor is matched */
2348 int perm = 0; /* Set when "ro", "rw" or "root" is matched */
2349 int list = 0; /* Set when "ro", "rw" is found */
2350 int ro_val = 0; /* Set if ro option is 'ro=' */
2351 int rw_val = 0; /* Set if rw option is 'rw=' */
2352 boolean_t reject;
2353
2354 opts = strdup(sh->sh_opts);
2355 if (opts == NULL) {
2356 syslog(LOG_ERR, "check_client: no memory");
2357 return (0);
2358 }
2359
2360 p = opts;
2361
2362 while (*p) {
2363 switch (getsubopt(&p, optlist, &val)) {
2364
2365 case OPT_SEC:
2366 if (match)
2367 goto done;
2368
2369 while ((f = strtok_r(val, ":", &lasts))
2370 != NULL) {
2371 if (flavor == map_flavor(f)) {
2372 match = 1;
2373 break;
2374 }
2375 val = NULL;
2376 }
2377 break;
2378
2379 case OPT_RO:
2380 if (!match)
2381 break;
2382
2383 list++;
2384 if (val) ro_val++;
2385 if (in_access_list(transp, nb, clnames, val))
2386 perm |= NFSAUTH_RO;
2387 break;
2388
2389 case OPT_RW:
2390 if (!match)
2391 break;
2392
2393 list++;
2394 if (val) rw_val++;
2395 if (in_access_list(transp, nb, clnames, val))
2396 perm |= NFSAUTH_RW;
2397 break;
2398
2399 case OPT_ROOT:
2400 /*
2401 * Check if the client is in
2402 * the root list. Only valid
2403 * for AUTH_SYS.
2404 */
2405 if (flavor != AUTH_SYS)
2406 break;
2407
2408 if (!match)
2409 break;
2410
2411 if (val == NULL || *val == '\0')
2412 break;
2413
2414 if (in_access_list(transp, nb, clnames, val))
2415 perm |= NFSAUTH_ROOT;
2416 break;
2417
2418 case OPT_NONE:
2419 /*
2420 * Check if the client should have no access
2421 * to this share at all. This option behaves
2422 * more like "root" than either "rw" or "ro".
2423 */
2424 if (in_access_list(transp, nb, clnames, val))
2425 perm |= NFSAUTH_DENIED;
2426 break;
2427 }
2428 }
2429
2430 done:
2431 /*
2432 * If no match then set the perm accordingly
2433 */
2434 if (!match || perm & NFSAUTH_DENIED)
2435 return (NFSAUTH_DENIED);
2436
2437 if (list) {
2438 /*
2439 * If the client doesn't match an "ro" or "rw" list then
2440 * check if it may have access by using a different flavor.
2441 * If so, return NFSAUTH_WRONGSEC.
2442 * If not, return NFSAUTH_DENIED.
2443 */
2444 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
2445 if (is_wrongsec(sh, transp, nb, clnames, flavor))
2446 perm |= NFSAUTH_WRONGSEC;
2447 else
2448 perm |= NFSAUTH_DENIED;
2449 }
2450 } else {
2451 /*
2452 * The client matched a flavor entry that
2453 * has no explicit "rw" or "ro" determination.
2454 * Make sure it defaults to "rw".
2455 */
2456 perm |= NFSAUTH_RW;
2457 }
2458
2459 /*
2460 * The client may show up in both ro= and rw=
2461 * lists. If so, then turn off the RO access
2462 * bit leaving RW access.
2463 */
2464 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2465 /*
2466 * Logically cover all permutations of rw=,ro=.
2467 * In the case where, rw,ro=<host> we would like
2468 * to remove RW access for the host. In all other cases
2469 * RW wins the precedence battle.
2470 */
2471 if (!rw_val && ro_val) {
2472 perm &= ~(NFSAUTH_RW);
2473 } else {
2474 perm &= ~(NFSAUTH_RO);
2475 }
2476 }
2477
2478 free(opts);
2479
2480 return (perm);
2481 }
2482
2483 void
check_sharetab()2484 check_sharetab()
2485 {
2486 FILE *f;
2487 struct stat st;
2488 static timestruc_t last_sharetab_time;
2489 timestruc_t prev_sharetab_time;
2490 share_t *sh;
2491 struct sh_list *shp, *shp_prev;
2492 int res, c = 0;
2493
2494 /*
2495 * read in /etc/dfs/sharetab if it has changed
2496 */
2497 if (stat(SHARETAB, &st) != 0) {
2498 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
2499 return;
2500 }
2501
2502 if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec &&
2503 st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) {
2504 /*
2505 * No change.
2506 */
2507 return;
2508 }
2509
2510 /*
2511 * Remember the mod time, then after getting the
2512 * write lock check again. If another thread
2513 * already did the update, then there's no
2514 * work to do.
2515 */
2516 prev_sharetab_time = last_sharetab_time;
2517
2518 (void) rw_wrlock(&sharetab_lock);
2519
2520 if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec ||
2521 prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) {
2522 (void) rw_unlock(&sharetab_lock);
2523 return;
2524 }
2525
2526 /*
2527 * Note that since the sharetab is now in memory
2528 * and a snapshot is taken, we no longer have to
2529 * lock the file.
2530 */
2531 f = fopen(SHARETAB, "r");
2532 if (f == NULL) {
2533 syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB);
2534 (void) rw_unlock(&sharetab_lock);
2535 return;
2536 }
2537
2538 /*
2539 * Once we are sure /etc/dfs/sharetab has been
2540 * modified, flush netgroup cache entries.
2541 */
2542 netgrp_cache_flush();
2543
2544 sh_free(share_list); /* free old list */
2545 share_list = NULL;
2546
2547 while ((res = getshare(f, &sh)) > 0) {
2548 c++;
2549 if (strcmp(sh->sh_fstype, "nfs") != 0)
2550 continue;
2551
2552 shp = malloc(sizeof (*shp));
2553 if (shp == NULL)
2554 goto alloc_failed;
2555 if (share_list == NULL)
2556 share_list = shp;
2557 else
2558 /* LINTED not used before set */
2559 shp_prev->shl_next = shp;
2560 shp_prev = shp;
2561 shp->shl_next = NULL;
2562 shp->shl_sh = sharedup(sh);
2563 if (shp->shl_sh == NULL)
2564 goto alloc_failed;
2565 }
2566
2567 if (res < 0)
2568 syslog(LOG_ERR, "%s: invalid at line %d\n",
2569 SHARETAB, c + 1);
2570
2571 if (stat(SHARETAB, &st) != 0) {
2572 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
2573 (void) fclose(f);
2574 (void) rw_unlock(&sharetab_lock);
2575 return;
2576 }
2577
2578 last_sharetab_time = st.st_mtim;
2579 (void) fclose(f);
2580 (void) rw_unlock(&sharetab_lock);
2581
2582 return;
2583
2584 alloc_failed:
2585
2586 syslog(LOG_ERR, "check_sharetab: no memory");
2587 sh_free(share_list);
2588 share_list = NULL;
2589 (void) fclose(f);
2590 (void) rw_unlock(&sharetab_lock);
2591 }
2592
2593 static void
sh_free(struct sh_list * shp)2594 sh_free(struct sh_list *shp)
2595 {
2596 register struct sh_list *next;
2597
2598 while (shp) {
2599 sharefree(shp->shl_sh);
2600 next = shp->shl_next;
2601 free(shp);
2602 shp = next;
2603 }
2604 }
2605
2606
2607 /*
2608 * Remove an entry from mounted list
2609 */
2610 static void
umount(struct svc_req * rqstp)2611 umount(struct svc_req *rqstp)
2612 {
2613 char *host, *path, *remove_path;
2614 char rpath[MAXPATHLEN];
2615 struct nd_hostservlist *clnames = NULL;
2616 SVCXPRT *transp;
2617 struct netbuf *nb;
2618
2619 transp = rqstp->rq_xprt;
2620 path = NULL;
2621 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
2622 svcerr_decode(transp);
2623 return;
2624 }
2625 errno = 0;
2626 if (!svc_sendreply(transp, xdr_void, (char *)NULL))
2627 log_cant_reply(transp);
2628
2629 if (getclientsnames(transp, &nb, &clnames) != 0) {
2630 /*
2631 * Without the hostname we can't do audit or delete
2632 * this host from the mount entries.
2633 */
2634 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
2635 return;
2636 }
2637 host = clnames->h_hostservs[0].h_host;
2638
2639 if (verbose)
2640 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
2641
2642 audit_mountd_umount(host, path);
2643
2644 remove_path = rpath; /* assume we will use the cannonical path */
2645 if (realpath(path, rpath) == NULL) {
2646 if (verbose)
2647 syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
2648 remove_path = path; /* use path provided instead */
2649 }
2650
2651 mntlist_delete(host, remove_path); /* remove from mount list */
2652
2653 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
2654 netdir_free(clnames, ND_HOSTSERVLIST);
2655 }
2656
2657 /*
2658 * Remove all entries for one machine from mounted list
2659 */
2660 static void
umountall(struct svc_req * rqstp)2661 umountall(struct svc_req *rqstp)
2662 {
2663 struct nd_hostservlist *clnames = NULL;
2664 SVCXPRT *transp;
2665 char *host;
2666 struct netbuf *nb;
2667
2668 transp = rqstp->rq_xprt;
2669 if (!svc_getargs(transp, xdr_void, NULL)) {
2670 svcerr_decode(transp);
2671 return;
2672 }
2673 /*
2674 * We assume that this call is asynchronous and made via rpcbind
2675 * callit routine. Therefore return control immediately. The error
2676 * causes rpcbind to remain silent, as opposed to every machine
2677 * on the net blasting the requester with a response.
2678 */
2679 svcerr_systemerr(transp);
2680 if (getclientsnames(transp, &nb, &clnames) != 0) {
2681 /* Can't do anything without the name of the client */
2682 return;
2683 }
2684
2685 host = clnames->h_hostservs[0].h_host;
2686
2687 /*
2688 * Remove all hosts entries from mount list
2689 */
2690 mntlist_delete_all(host);
2691
2692 if (verbose)
2693 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
2694
2695 netdir_free(clnames, ND_HOSTSERVLIST);
2696 }
2697
2698 void *
exmalloc(size_t size)2699 exmalloc(size_t size)
2700 {
2701 void *ret;
2702
2703 if ((ret = malloc(size)) == NULL) {
2704 syslog(LOG_ERR, "Out of memory");
2705 exit(1);
2706 }
2707 return (ret);
2708 }
2709
2710 static void
sigexit(int signum)2711 sigexit(int signum)
2712 {
2713
2714 if (signum == SIGHUP)
2715 _exit(0);
2716 _exit(1);
2717 }
2718
2719 static tsol_tpent_t *
get_client_template(struct sockaddr * sock)2720 get_client_template(struct sockaddr *sock)
2721 {
2722 in_addr_t v4client;
2723 in6_addr_t v6client;
2724 char v4_addr[INET_ADDRSTRLEN];
2725 char v6_addr[INET6_ADDRSTRLEN];
2726 tsol_rhent_t *rh;
2727 tsol_tpent_t *tp;
2728
2729 switch (sock->sa_family) {
2730 case AF_INET:
2731 v4client = ((struct sockaddr_in *)(void *)sock)->
2732 sin_addr.s_addr;
2733 if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
2734 NULL)
2735 return (NULL);
2736 rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
2737 if (rh == NULL)
2738 return (NULL);
2739 tp = tsol_gettpbyname(rh->rh_template);
2740 tsol_freerhent(rh);
2741 return (tp);
2742 break;
2743 case AF_INET6:
2744 v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
2745 if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
2746 NULL)
2747 return (NULL);
2748 rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
2749 if (rh == NULL)
2750 return (NULL);
2751 tp = tsol_gettpbyname(rh->rh_template);
2752 tsol_freerhent(rh);
2753 return (tp);
2754 break;
2755 default:
2756 return (NULL);
2757 }
2758 }
2759