6923303 mountd dumped core on server if the file system was shared with "none=-<CLNT...
[illumos-gate.git] / usr / src / cmd / fs.d / nfs / mountd / mountd.c
bloba82a06c93c0586f6d8ba1b8b53dedf7c4e008c16
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
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 <sys/nvpair.h>
80 #include <attr.h>
82 extern int daemonize_init(void);
83 extern void daemonize_fini(int fd);
85 struct sh_list *share_list;
87 rwlock_t sharetab_lock; /* lock to protect the cached sharetab */
88 static mutex_t mnttab_lock; /* prevent concurrent mnttab readers */
90 static mutex_t logging_queue_lock;
91 static cond_t logging_queue_cv;
93 static share_t *find_lofsentry(char *, int *);
94 static int getclientsnames_lazy(char *, struct netbuf **,
95 struct nd_hostservlist **);
96 static int getclientsnames(SVCXPRT *, struct netbuf **,
97 struct nd_hostservlist **);
98 static int getclientsflavors_old(share_t *, SVCXPRT *, struct netbuf **,
99 struct nd_hostservlist **, int *);
100 static int getclientsflavors_new(share_t *, SVCXPRT *, struct netbuf **,
101 struct nd_hostservlist **, int *);
102 static int check_client_old(share_t *, SVCXPRT *, struct netbuf **,
103 struct nd_hostservlist **, int);
104 static int check_client_new(share_t *, SVCXPRT *, struct netbuf **,
105 struct nd_hostservlist **, int);
106 static void mnt(struct svc_req *, SVCXPRT *);
107 static void mnt_pathconf(struct svc_req *);
108 static int mount(struct svc_req *r);
109 static void sh_free(struct sh_list *);
110 static void umount(struct svc_req *);
111 static void umountall(struct svc_req *);
112 static int netmatch(struct netbuf *, char *);
113 static void sigexit(int);
114 static int newopts(char *);
115 static tsol_tpent_t *get_client_template(struct sockaddr *);
117 static int verbose;
118 static int rejecting;
119 static int mount_vers_min = MOUNTVERS;
120 static int mount_vers_max = MOUNTVERS3;
122 /* Needs to be accessed by nfscmd.c */
123 int in_access_list(SVCXPRT *, struct netbuf **,
124 struct nd_hostservlist **, char *);
126 extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
128 thread_t nfsauth_thread;
129 thread_t cmd_thread;
130 thread_t logging_thread;
132 typedef struct logging_data {
133 char *ld_host;
134 char *ld_path;
135 char *ld_rpath;
136 int ld_status;
137 char *ld_netid;
138 struct netbuf *ld_nb;
139 struct logging_data *ld_next;
140 } logging_data;
142 static logging_data *logging_head = NULL;
143 static logging_data *logging_tail = NULL;
145 /* ARGSUSED */
146 static void *
147 nfsauth_svc(void *arg)
149 int doorfd = -1;
150 uint_t darg;
151 #ifdef DEBUG
152 int dfd;
153 #endif
155 if ((doorfd = door_create(nfsauth_func, NULL,
156 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
157 syslog(LOG_ERR, "Unable to create door: %m\n");
158 exit(10);
161 #ifdef DEBUG
163 * Create a file system path for the door
165 if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
166 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
167 syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
168 (void) close(doorfd);
169 exit(11);
173 * Clean up any stale namespace associations
175 (void) fdetach(MOUNTD_DOOR);
178 * Register in namespace to pass to the kernel to door_ki_open
180 if (fattach(doorfd, MOUNTD_DOOR) == -1) {
181 syslog(LOG_ERR, "Unable to fattach door: %m\n");
182 (void) close(dfd);
183 (void) close(doorfd);
184 exit(12);
186 (void) close(dfd);
187 #endif
190 * Must pass the doorfd down to the kernel.
192 darg = doorfd;
193 (void) _nfssys(MOUNTD_ARGS, &darg);
196 * Wait for incoming calls
198 /*CONSTCOND*/
199 for (;;)
200 (void) pause();
202 /*NOTREACHED*/
203 syslog(LOG_ERR, gettext("Door server exited"));
204 return (NULL);
208 * NFS command service thread code for setup and handling of the
209 * nfs_cmd requests for character set conversion and other future
210 * events.
213 static void *
214 cmd_svc(void *arg)
216 int doorfd = -1;
217 uint_t darg;
219 if ((doorfd = door_create(nfscmd_func, NULL,
220 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
221 syslog(LOG_ERR, "Unable to create cmd door: %m\n");
222 exit(10);
226 * Must pass the doorfd down to the kernel.
228 darg = doorfd;
229 (void) _nfssys(NFSCMD_ARGS, &darg);
232 * Wait for incoming calls
234 /*CONSTCOND*/
235 for (;;)
236 (void) pause();
238 /*NOTREACHED*/
239 syslog(LOG_ERR, gettext("Cmd door server exited"));
240 return (NULL);
243 static void
244 free_logging_data(logging_data *lq)
246 if (lq != NULL) {
247 free(lq->ld_host);
248 free(lq->ld_netid);
250 if (lq->ld_nb != NULL) {
251 free(lq->ld_nb->buf);
252 free(lq->ld_nb);
255 free(lq->ld_path);
256 free(lq->ld_rpath);
258 free(lq);
262 static logging_data *
263 remove_head_of_queue(void)
265 logging_data *lq;
268 * Pull it off the queue.
270 lq = logging_head;
271 if (lq) {
272 logging_head = lq->ld_next;
275 * Drained it.
277 if (logging_head == NULL) {
278 logging_tail = NULL;
282 return (lq);
285 static void
286 do_logging_queue(logging_data *lq)
288 logging_data *lq_clean = NULL;
289 int cleared = 0;
290 char *host;
292 struct nd_hostservlist *clnames;
294 while (lq) {
295 if (lq->ld_host == NULL) {
296 DTRACE_PROBE(mountd, name_by_lazy);
297 if (getclientsnames_lazy(lq->ld_netid,
298 &lq->ld_nb, &clnames) != 0)
299 host = NULL;
300 else
301 host = clnames->h_hostservs[0].h_host;
302 } else
303 host = lq->ld_host;
305 audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
307 /* add entry to mount list */
308 if (lq->ld_rpath)
309 mntlist_new(host, lq->ld_rpath);
311 lq->ld_next = lq_clean;
312 lq_clean = lq;
314 (void) mutex_lock(&logging_queue_lock);
315 lq = remove_head_of_queue();
316 (void) mutex_unlock(&logging_queue_lock);
319 while (lq_clean) {
320 lq = lq_clean;
321 lq_clean = lq->ld_next;
323 free_logging_data(lq);
324 cleared++;
327 DTRACE_PROBE1(mountd, logging_cleared, cleared);
330 static void *
331 logging_svc(void *arg)
333 logging_data *lq;
335 for (;;) {
336 (void) mutex_lock(&logging_queue_lock);
337 while (logging_head == NULL) {
338 (void) cond_wait(&logging_queue_cv,
339 &logging_queue_lock);
342 lq = remove_head_of_queue();
343 (void) mutex_unlock(&logging_queue_lock);
345 do_logging_queue(lq);
348 /*NOTREACHED*/
349 syslog(LOG_ERR, gettext("Logging server exited"));
350 return (NULL);
354 main(int argc, char *argv[])
356 int pid;
357 int c;
358 int rpc_svc_mode = RPC_SVC_MT_AUTO;
359 int maxthreads;
360 int maxrecsz = RPC_MAXDATASIZE;
361 bool_t exclbind = TRUE;
362 bool_t can_do_mlp;
363 long thr_flags = (THR_NEW_LWP|THR_DAEMON);
365 int pipe_fd = -1;
368 * Mountd requires uid 0 for:
369 * /etc/rmtab updates (we could chown it to daemon)
370 * /etc/dfs/dfstab reading (it wants to lock out share which
371 * doesn't do any locking before first truncate;
372 * NFS share does; should use fcntl locking instead)
373 * Needed privileges:
374 * auditing
375 * nfs syscall
376 * file dac search (so it can stat all files)
377 * Optional privileges:
378 * MLP
380 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
381 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
382 PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
383 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
384 (void) fprintf(stderr,
385 "%s: must be run with sufficient privileges\n",
386 argv[0]);
387 exit(1);
390 maxthreads = 0;
392 while ((c = getopt(argc, argv, "vrm:")) != EOF) {
393 switch (c) {
394 case 'v':
395 verbose++;
396 break;
397 case 'r':
398 rejecting = 1;
399 break;
400 case 'm':
401 maxthreads = atoi(optarg);
402 if (maxthreads < 1) {
403 (void) fprintf(stderr,
404 "%s: must specify positive maximum threads count, using default\n",
405 argv[0]);
406 maxthreads = 0;
408 break;
413 * Read in the NFS version values from config file.
415 if ((defopen(NFSADMIN)) == 0) {
416 char *defval;
417 int defvers;
419 if ((defval = defread("NFS_SERVER_VERSMIN=")) != NULL) {
420 errno = 0;
421 defvers = strtol(defval, (char **)NULL, 10);
422 if (errno == 0) {
423 mount_vers_min = defvers;
425 * special because NFSv2 is
426 * supported by mount v1 & v2
428 if (defvers == NFS_VERSION)
429 mount_vers_min = MOUNTVERS;
432 if ((defval = defread("NFS_SERVER_VERSMAX=")) != NULL) {
433 errno = 0;
434 defvers = strtol(defval, (char **)NULL, 10);
435 if (errno == 0) {
436 mount_vers_max = defvers;
440 /* close defaults file */
441 defopen(NULL);
445 * Sanity check versions,
446 * even though we may get versions > MOUNTVERS3, we still need
447 * to start nfsauth service, so continue on regardless of values.
449 if (mount_vers_min > mount_vers_max) {
450 fprintf(stderr, "NFS_SERVER_VERSMIN > NFS_SERVER_VERSMAX");
451 mount_vers_max = mount_vers_min;
453 (void) setlocale(LC_ALL, "");
454 (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
455 (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
456 (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
457 (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
459 netgroup_init();
461 #if !defined(TEXT_DOMAIN)
462 #define TEXT_DOMAIN "SYS_TEST"
463 #endif
464 (void) textdomain(TEXT_DOMAIN);
466 /* Don't drop core if the NFS module isn't loaded. */
467 (void) signal(SIGSYS, SIG_IGN);
469 pipe_fd = daemonize_init();
472 * If we coredump it'll be in /core
474 if (chdir("/") < 0)
475 fprintf(stderr, "chdir /: %s", strerror(errno));
477 openlog("mountd", LOG_PID, LOG_DAEMON);
480 * establish our lock on the lock file and write our pid to it.
481 * exit if some other process holds the lock, or if there's any
482 * error in writing/locking the file.
484 pid = _enter_daemon_lock(MOUNTD);
485 switch (pid) {
486 case 0:
487 break;
488 case -1:
489 fprintf(stderr, "error locking for %s: %s", MOUNTD,
490 strerror(errno));
491 exit(2);
492 default:
493 /* daemon was already running */
494 exit(0);
497 audit_mountd_setup(); /* BSM */
500 * Tell RPC that we want automatic thread mode.
501 * A new thread will be spawned for each request.
503 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
504 fprintf(stderr, "unable to set automatic MT mode");
505 exit(1);
509 * Enable non-blocking mode and maximum record size checks for
510 * connection oriented transports.
512 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
513 fprintf(stderr, "unable to set RPC max record size");
517 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
518 * from being hijacked by a bind to a more specific addr.
520 if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
521 fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND");
525 * If the -m argument was specified, then set the
526 * maximum number of threads to the value specified.
528 if (maxthreads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &maxthreads)) {
529 fprintf(stderr, "unable to set maxthreads");
530 exit(1);
534 * Make sure to unregister any previous versions in case the
535 * user is reconfiguring the server in interesting ways.
537 svc_unreg(MOUNTPROG, MOUNTVERS);
538 svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
539 svc_unreg(MOUNTPROG, MOUNTVERS3);
542 * Create the nfsauth thread with same signal disposition
543 * as the main thread. We need to create a separate thread
544 * since mountd() will be both an RPC server (for remote
545 * traffic) _and_ a doors server (for kernel upcalls).
547 if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
548 fprintf(stderr, gettext("Failed to create NFSAUTH svc thread"));
549 exit(2);
553 * Create the cmd service thread with same signal disposition
554 * as the main thread. We need to create a separate thread
555 * since mountd() will be both an RPC server (for remote
556 * traffic) _and_ a doors server (for kernel upcalls).
558 if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
559 syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
560 exit(2);
564 * Create an additional thread to service the rmtab and
565 * audit_mountd_mount logging for mount requests. Use the same
566 * signal disposition as the main thread. We create
567 * a separate thread to allow the mount request threads to
568 * clear as soon as possible.
570 if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
571 syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
572 exit(2);
576 * Create datagram and connection oriented services
578 if (mount_vers_max >= MOUNTVERS) {
579 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) {
580 fprintf(stderr,
581 "couldn't register datagram_v MOUNTVERS");
582 exit(1);
584 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) {
585 fprintf(stderr,
586 "couldn't register circuit_v MOUNTVERS");
587 exit(1);
591 if (mount_vers_max >= MOUNTVERS_POSIX) {
592 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
593 "datagram_v") == 0) {
594 fprintf(stderr,
595 "couldn't register datagram_v MOUNTVERS_POSIX");
596 exit(1);
598 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
599 "circuit_v") == 0) {
600 fprintf(stderr,
601 "couldn't register circuit_v MOUNTVERS_POSIX");
602 exit(1);
606 if (mount_vers_max >= MOUNTVERS3) {
607 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) {
608 fprintf(stderr,
609 "couldn't register datagram_v MOUNTVERS3");
610 exit(1);
612 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) {
613 fprintf(stderr,
614 "couldn't register circuit_v MOUNTVERS3");
615 exit(1);
620 * Start serving
622 rmtab_load();
624 daemonize_fini(pipe_fd);
626 /* Get rid of the most dangerous basic privileges. */
627 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
628 (char *)NULL);
630 svc_run();
631 syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
632 abort();
634 /* NOTREACHED */
635 return (0);
639 * Server procedure switch routine
641 void
642 mnt(struct svc_req *rqstp, SVCXPRT *transp)
644 switch (rqstp->rq_proc) {
645 case NULLPROC:
646 errno = 0;
647 if (!svc_sendreply(transp, xdr_void, (char *)0))
648 log_cant_reply(transp);
649 return;
651 case MOUNTPROC_MNT:
652 (void) mount(rqstp);
653 return;
655 case MOUNTPROC_DUMP:
656 mntlist_send(transp);
657 return;
659 case MOUNTPROC_UMNT:
660 umount(rqstp);
661 return;
663 case MOUNTPROC_UMNTALL:
664 umountall(rqstp);
665 return;
667 case MOUNTPROC_EXPORT:
668 case MOUNTPROC_EXPORTALL:
669 export(rqstp);
670 return;
672 case MOUNTPROC_PATHCONF:
673 if (rqstp->rq_vers == MOUNTVERS_POSIX)
674 mnt_pathconf(rqstp);
675 else
676 svcerr_noproc(transp);
677 return;
679 default:
680 svcerr_noproc(transp);
681 return;
685 /* Set up anonymous client */
687 struct nd_hostservlist *
688 anon_client(char *host)
690 struct nd_hostservlist *anon_hsl;
691 struct nd_hostserv *anon_hs;
693 anon_hsl = malloc(sizeof (*anon_hsl));
694 if (anon_hsl == NULL)
695 return (NULL);
697 anon_hs = malloc(sizeof (*anon_hs));
698 if (anon_hs == NULL) {
699 free(anon_hsl);
700 return (NULL);
703 if (host == NULL)
704 anon_hs->h_host = strdup("(anon)");
705 else
706 anon_hs->h_host = strdup(host);
708 if (anon_hs->h_host == NULL) {
709 free(anon_hs);
710 free(anon_hsl);
711 return (NULL);
713 anon_hs->h_serv = '\0';
715 anon_hsl->h_cnt = 1;
716 anon_hsl->h_hostservs = anon_hs;
718 return (anon_hsl);
721 static int
722 getclientsnames_common(struct netconfig *nconf, struct netbuf **nbuf,
723 struct nd_hostservlist **serv)
725 char host[MAXIPADDRLEN];
727 assert(*nbuf != NULL);
730 * Use the this API instead of the netdir_getbyaddr()
731 * to avoid service lookup.
733 if (__netdir_getbyaddr_nosrv(nconf, serv, *nbuf) != 0) {
734 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
735 struct sockaddr_in *sa;
737 /* LINTED pointer alignment */
738 sa = (struct sockaddr_in *)((*nbuf)->buf);
739 (void) inet_ntoa_r(sa->sin_addr, host);
740 } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
741 struct sockaddr_in6 *sa;
743 /* LINTED pointer alignment */
744 sa = (struct sockaddr_in6 *)((*nbuf)->buf);
745 (void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr,
746 host, INET6_ADDRSTRLEN);
747 } else {
748 syslog(LOG_ERR, gettext(
749 "Client's address is neither IPv4 nor IPv6"));
750 return (EINVAL);
753 *serv = anon_client(host);
754 if (*serv == NULL)
755 return (ENOMEM);
758 assert(*serv != NULL);
759 return (0);
763 * Get the client's hostname from the copy of the
764 * relevant transport handle parts.
765 * If the name is not available then return "(anon)".
767 static int
768 getclientsnames_lazy(char *netid, struct netbuf **nbuf,
769 struct nd_hostservlist **serv)
771 struct netconfig *nconf;
772 int rc;
774 nconf = getnetconfigent(netid);
775 if (nconf == NULL) {
776 syslog(LOG_ERR, "%s: getnetconfigent failed", netid);
777 *serv = anon_client(NULL);
778 if (*serv == NULL)
779 return (ENOMEM);
780 return (0);
783 rc = getclientsnames_common(nconf, nbuf, serv);
784 freenetconfigent(nconf);
785 return (rc);
789 * Get the client's hostname from the transport handle.
790 * If the name is not available then return "(anon)".
793 getclientsnames(SVCXPRT *transp, struct netbuf **nbuf,
794 struct nd_hostservlist **serv)
796 struct netconfig *nconf;
797 int rc;
799 nconf = getnetconfigent(transp->xp_netid);
800 if (nconf == NULL) {
801 syslog(LOG_ERR, "%s: getnetconfigent failed",
802 transp->xp_netid);
803 *serv = anon_client(NULL);
804 if (*serv == NULL)
805 return (ENOMEM);
806 return (0);
809 *nbuf = svc_getrpccaller(transp);
810 if (*nbuf == NULL) {
811 freenetconfigent(nconf);
812 *serv = anon_client(NULL);
813 if (*serv == NULL)
814 return (ENOMEM);
815 return (0);
818 rc = getclientsnames_common(nconf, nbuf, serv);
819 freenetconfigent(nconf);
820 return (rc);
823 void
824 log_cant_reply(SVCXPRT *transp)
826 int saverrno;
827 struct nd_hostservlist *clnames = NULL;
828 register char *host;
829 struct netbuf *nb;
831 saverrno = errno; /* save error code */
832 if (getclientsnames(transp, &nb, &clnames) != 0)
833 return;
834 host = clnames->h_hostservs->h_host;
836 errno = saverrno;
837 if (errno == 0)
838 syslog(LOG_ERR, "couldn't send reply to %s", host);
839 else
840 syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
842 netdir_free(clnames, ND_HOSTSERVLIST);
846 * Answer pathconf questions for the mount point fs
848 static void
849 mnt_pathconf(struct svc_req *rqstp)
851 SVCXPRT *transp;
852 struct pathcnf p;
853 char *path, rpath[MAXPATHLEN];
854 struct stat st;
856 transp = rqstp->rq_xprt;
857 path = NULL;
858 (void) memset((caddr_t)&p, 0, sizeof (p));
860 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
861 svcerr_decode(transp);
862 return;
864 if (lstat(path, &st) < 0) {
865 _PC_SET(_PC_ERROR, p.pc_mask);
866 goto done;
869 * Get a path without symbolic links.
871 if (realpath(path, rpath) == NULL) {
872 syslog(LOG_DEBUG,
873 "mount request: realpath failed on %s: %m",
874 path);
875 _PC_SET(_PC_ERROR, p.pc_mask);
876 goto done;
878 (void) memset((caddr_t)&p, 0, sizeof (p));
880 * can't ask about devices over NFS
882 _PC_SET(_PC_MAX_CANON, p.pc_mask);
883 _PC_SET(_PC_MAX_INPUT, p.pc_mask);
884 _PC_SET(_PC_PIPE_BUF, p.pc_mask);
885 _PC_SET(_PC_VDISABLE, p.pc_mask);
887 errno = 0;
888 p.pc_link_max = pathconf(rpath, _PC_LINK_MAX);
889 if (errno)
890 _PC_SET(_PC_LINK_MAX, p.pc_mask);
891 p.pc_name_max = pathconf(rpath, _PC_NAME_MAX);
892 if (errno)
893 _PC_SET(_PC_NAME_MAX, p.pc_mask);
894 p.pc_path_max = pathconf(rpath, _PC_PATH_MAX);
895 if (errno)
896 _PC_SET(_PC_PATH_MAX, p.pc_mask);
897 if (pathconf(rpath, _PC_NO_TRUNC) == 1)
898 _PC_SET(_PC_NO_TRUNC, p.pc_mask);
899 if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1)
900 _PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask);
902 done:
903 errno = 0;
904 if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p))
905 log_cant_reply(transp);
906 if (path != NULL)
907 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
911 * If the rootmount (export) option is specified, the all mount requests for
912 * subdirectories return EACCES.
914 static int
915 checkrootmount(share_t *sh, char *rpath)
917 char *val;
919 if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) {
920 free(val);
921 if (strcmp(sh->sh_path, rpath) != 0)
922 return (0);
923 else
924 return (1);
925 } else
926 return (1);
929 #define MAX_FLAVORS 128
932 * Return only EACCES if client does not have access
933 * to this directory.
934 * "If the server exports only /a/b, an attempt to
935 * mount a/b/c will fail with ENOENT if the directory
936 * does not exist"... However, if the client
937 * does not have access to /a/b, an attacker can
938 * determine whether the directory exists.
939 * This routine checks either existence of the file or
940 * existence of the file name entry in the mount table.
941 * If the file exists and there is no file name entry,
942 * the error returned should be EACCES.
943 * If the file does not exist, it must be determined
944 * whether the client has access to a parent
945 * directory. If the client has access to a parent
946 * directory, the error returned should be ENOENT,
947 * otherwise EACCES.
949 static int
950 mount_enoent_error(SVCXPRT *transp, char *path, char *rpath,
951 struct nd_hostservlist **clnames, struct netbuf **nb, int *flavor_list)
953 char *checkpath, *dp;
954 share_t *sh = NULL;
955 int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0;
956 int flavor_count;
958 checkpath = strdup(path);
959 if (checkpath == NULL) {
960 syslog(LOG_ERR, "mount_enoent: no memory");
961 return (EACCES);
964 /* CONSTCOND */
965 while (1) {
966 if (sh) {
967 sharefree(sh);
968 sh = NULL;
971 if ((sh = findentry(rpath)) == NULL &&
972 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
974 * There is no file name entry.
975 * If the file (with symbolic links resolved) exists,
976 * the error returned should be EACCES.
978 if (realpath_error == 0)
979 break;
980 } else if (checkrootmount(sh, rpath) == 0) {
982 * This is a "nosub" only export, in which case,
983 * mounting subdirectories isn't allowed.
984 * If the file (with symbolic links resolved) exists,
985 * the error returned should be EACCES.
987 if (realpath_error == 0)
988 break;
989 } else {
991 * Check permissions in mount table.
993 if (newopts(sh->sh_opts))
994 flavor_count = getclientsflavors_new(sh,
995 transp, nb, clnames, flavor_list);
996 else
997 flavor_count = getclientsflavors_old(sh,
998 transp, nb, clnames, flavor_list);
999 if (flavor_count != 0) {
1001 * Found entry in table and
1002 * client has correct permissions.
1004 reply_error = ENOENT;
1005 break;
1010 * Check all parent directories.
1012 dp = strrchr(checkpath, '/');
1013 if (dp == NULL)
1014 break;
1015 *dp = '\0';
1016 if (strlen(checkpath) == 0)
1017 break;
1019 * Get the real path (no symbolic links in it)
1021 if (realpath(checkpath, rpath) == NULL) {
1022 if (errno != ENOENT)
1023 break;
1024 } else {
1025 realpath_error = 0;
1029 if (sh)
1030 sharefree(sh);
1031 free(checkpath);
1032 return (reply_error);
1036 * We need to inform the caller whether or not we were
1037 * able to add a node to the queue. If we are not, then
1038 * it is up to the caller to go ahead and log the data.
1040 static int
1041 enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
1042 char *rpath, int status, int error)
1044 logging_data *lq;
1045 struct netbuf *nb;
1047 lq = (logging_data *)calloc(1, sizeof (logging_data));
1048 if (lq == NULL)
1049 goto cleanup;
1052 * We might not yet have the host...
1054 if (host) {
1055 DTRACE_PROBE1(mountd, log_host, host);
1056 lq->ld_host = strdup(host);
1057 if (lq->ld_host == NULL)
1058 goto cleanup;
1059 } else {
1060 DTRACE_PROBE(mountd, log_no_host);
1062 lq->ld_netid = strdup(transp->xp_netid);
1063 if (lq->ld_netid == NULL)
1064 goto cleanup;
1066 lq->ld_nb = calloc(1, sizeof (struct netbuf));
1067 if (lq->ld_nb == NULL)
1068 goto cleanup;
1070 nb = svc_getrpccaller(transp);
1071 if (nb == NULL) {
1072 DTRACE_PROBE(mountd, e__nb__enqueue);
1073 goto cleanup;
1076 DTRACE_PROBE(mountd, nb_set_enqueue);
1078 lq->ld_nb->maxlen = nb->maxlen;
1079 lq->ld_nb->len = nb->len;
1081 lq->ld_nb->buf = malloc(lq->ld_nb->len);
1082 if (lq->ld_nb->buf == NULL)
1083 goto cleanup;
1085 bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len);
1088 lq->ld_path = strdup(path);
1089 if (lq->ld_path == NULL)
1090 goto cleanup;
1092 if (!error) {
1093 lq->ld_rpath = strdup(rpath);
1094 if (lq->ld_rpath == NULL)
1095 goto cleanup;
1098 lq->ld_status = status;
1101 * Add to the tail of the logging queue.
1103 (void) mutex_lock(&logging_queue_lock);
1104 if (logging_tail == NULL) {
1105 logging_tail = logging_head = lq;
1106 } else {
1107 logging_tail->ld_next = lq;
1108 logging_tail = lq;
1110 (void) cond_signal(&logging_queue_cv);
1111 (void) mutex_unlock(&logging_queue_lock);
1113 return (TRUE);
1115 cleanup:
1117 free_logging_data(lq);
1119 return (FALSE);
1123 * Check mount requests, add to mounted list if ok
1125 static int
1126 mount(struct svc_req *rqstp)
1128 SVCXPRT *transp;
1129 int version, vers;
1130 struct fhstatus fhs;
1131 struct mountres3 mountres3;
1132 char fh[FHSIZE3];
1133 int len = FHSIZE3;
1134 char *path, rpath[MAXPATHLEN];
1135 share_t *sh = NULL;
1136 struct nd_hostservlist *clnames = NULL;
1137 char *host = NULL;
1138 int error = 0, lofs_tried = 0, enqueued;
1139 int flavor_list[MAX_FLAVORS];
1140 int flavor_count;
1141 struct netbuf *nb = NULL;
1142 ucred_t *uc = NULL;
1144 int audit_status;
1146 transp = rqstp->rq_xprt;
1147 version = rqstp->rq_vers;
1148 path = NULL;
1150 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
1151 svcerr_decode(transp);
1152 return (EACCES);
1156 * Put off getting the name for the client until we
1157 * need it. This is a performance gain. If we are logging,
1158 * then we don't care about performance and might as well
1159 * get the host name now in case we need to spit out an
1160 * error message.
1162 if (verbose) {
1163 DTRACE_PROBE(mountd, name_by_verbose);
1164 if (getclientsnames(transp, &nb, &clnames) != 0) {
1166 * We failed to get a name for the client, even
1167 * 'anon', probably because we ran out of memory.
1168 * In this situation it doesn't make sense to
1169 * allow the mount to succeed.
1171 error = EACCES;
1172 goto reply;
1174 host = clnames->h_hostservs[0].h_host;
1178 * If the version being used is less than the minimum version,
1179 * the filehandle translation should not be provided to the
1180 * client.
1182 if (rejecting || version < mount_vers_min) {
1183 if (verbose)
1184 syslog(LOG_NOTICE, "Rejected mount: %s for %s",
1185 host, path);
1186 error = EACCES;
1187 goto reply;
1191 * Trusted Extension doesn't support nfsv2. nfsv2 client
1192 * uses MOUNT protocol v1 and v2. To prevent circumventing
1193 * TX label policy via using nfsv2 client, reject a mount
1194 * request with version less than 3 and log an error.
1196 if (is_system_labeled()) {
1197 if (version < 3) {
1198 if (verbose)
1199 syslog(LOG_ERR,
1200 "Rejected mount: TX doesn't support NFSv2");
1201 error = EACCES;
1202 goto reply;
1207 * Get the real path (no symbolic links in it)
1209 if (realpath(path, rpath) == NULL) {
1210 error = errno;
1211 if (verbose)
1212 syslog(LOG_ERR,
1213 "mount request: realpath: %s: %m", path);
1214 if (error == ENOENT)
1215 error = mount_enoent_error(transp, path, rpath,
1216 &clnames, &nb, flavor_list);
1217 goto reply;
1220 if ((sh = findentry(rpath)) == NULL &&
1221 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
1222 error = EACCES;
1223 goto reply;
1227 * Check if this is a "nosub" only export, in which case, mounting
1228 * subdirectories isn't allowed. Bug 1184573.
1230 if (checkrootmount(sh, rpath) == 0) {
1231 error = EACCES;
1232 goto reply;
1235 if (newopts(sh->sh_opts))
1236 flavor_count = getclientsflavors_new(sh, transp, &nb, &clnames,
1237 flavor_list);
1238 else
1239 flavor_count = getclientsflavors_old(sh, transp, &nb, &clnames,
1240 flavor_list);
1242 if (clnames)
1243 host = clnames->h_hostservs[0].h_host;
1245 if (flavor_count == 0) {
1246 error = EACCES;
1247 goto reply;
1251 * Check MAC policy here. The server side policy should be
1252 * consistent with client side mount policy, i.e.
1253 * - we disallow an admin_low unlabeled client to mount
1254 * - we disallow mount from a lower labeled client.
1256 if (is_system_labeled()) {
1257 m_label_t *clabel = NULL;
1258 m_label_t *slabel = NULL;
1259 m_label_t admin_low;
1261 if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
1262 syslog(LOG_ERR,
1263 "mount request: Failed to get caller's ucred : %m");
1264 error = EACCES;
1265 goto reply;
1267 if ((clabel = ucred_getlabel(uc)) == NULL) {
1268 syslog(LOG_ERR,
1269 "mount request: can't get client label from ucred");
1270 error = EACCES;
1271 goto reply;
1274 bsllow(&admin_low);
1275 if (blequal(&admin_low, clabel)) {
1276 struct sockaddr *ca;
1277 tsol_tpent_t *tp;
1279 ca = (struct sockaddr *)(void *)svc_getrpccaller(
1280 rqstp->rq_xprt)->buf;
1281 if (ca == NULL) {
1282 error = EACCES;
1283 goto reply;
1286 * get trusted network template associated
1287 * with the client.
1289 tp = get_client_template(ca);
1290 if (tp == NULL || tp->host_type != SUN_CIPSO) {
1291 if (tp != NULL)
1292 tsol_freetpent(tp);
1293 error = EACCES;
1294 goto reply;
1296 tsol_freetpent(tp);
1297 } else {
1298 if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) {
1299 error = EACCES;
1300 goto reply;
1303 if (getlabel(rpath, slabel) != 0) {
1304 m_label_free(slabel);
1305 error = EACCES;
1306 goto reply;
1309 if (!bldominates(clabel, slabel)) {
1310 m_label_free(slabel);
1311 error = EACCES;
1312 goto reply;
1314 m_label_free(slabel);
1319 * Now get the filehandle.
1321 * NFS V2 clients get a 32 byte filehandle.
1322 * NFS V3 clients get a 32 or 64 byte filehandle, depending on
1323 * the embedded FIDs.
1325 vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION;
1327 /* LINTED pointer alignment */
1328 while (nfs_getfh(rpath, vers, &len, fh) < 0) {
1329 if (errno == EINVAL &&
1330 (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) {
1331 errno = 0;
1332 continue;
1334 error = errno == EINVAL ? EACCES : errno;
1335 syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m",
1336 path);
1337 break;
1340 if (version == MOUNTVERS3) {
1341 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len;
1342 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh;
1343 } else {
1344 bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE);
1347 reply:
1348 if (uc != NULL)
1349 ucred_free(uc);
1351 switch (version) {
1352 case MOUNTVERS:
1353 case MOUNTVERS_POSIX:
1354 if (error == EINVAL)
1355 fhs.fhs_status = NFSERR_ACCES;
1356 else if (error == EREMOTE)
1357 fhs.fhs_status = NFSERR_REMOTE;
1358 else
1359 fhs.fhs_status = error;
1361 if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
1362 log_cant_reply(transp);
1364 audit_status = fhs.fhs_status;
1365 break;
1367 case MOUNTVERS3:
1368 if (!error) {
1369 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
1370 flavor_list;
1371 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
1372 flavor_count;
1374 } else if (error == ENAMETOOLONG)
1375 error = MNT3ERR_NAMETOOLONG;
1377 mountres3.fhs_status = error;
1378 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1379 log_cant_reply(transp);
1381 audit_status = mountres3.fhs_status;
1382 break;
1385 if (verbose)
1386 syslog(LOG_NOTICE, "MOUNT: %s %s %s",
1387 (host == NULL) ? "unknown host" : host,
1388 error ? "denied" : "mounted", path);
1391 * If we can not create a queue entry, go ahead and do it
1392 * in the context of this thread.
1394 enqueued = enqueue_logging_data(host, transp, path, rpath,
1395 audit_status, error);
1396 if (enqueued == FALSE) {
1397 if (host == NULL) {
1398 DTRACE_PROBE(mountd, name_by_in_thread);
1399 if (getclientsnames(transp, &nb, &clnames) == 0)
1400 host = clnames->h_hostservs[0].h_host;
1403 DTRACE_PROBE(mountd, logged_in_thread);
1404 audit_mountd_mount(host, path, audit_status); /* BSM */
1405 if (!error)
1406 mntlist_new(host, rpath); /* add entry to mount list */
1409 if (path != NULL)
1410 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
1412 done:
1413 if (sh)
1414 sharefree(sh);
1415 netdir_free(clnames, ND_HOSTSERVLIST);
1417 return (error);
1421 * Determine whether two paths are within the same file system.
1422 * Returns nonzero (true) if paths are the same, zero (false) if
1423 * they are different. If an error occurs, return false.
1425 * Use the actual FSID if it's available (via getattrat()); otherwise,
1426 * fall back on st_dev.
1428 * With ZFS snapshots, st_dev differs from the regular file system
1429 * versus the snapshot. But the fsid is the same throughout. Thus
1430 * the fsid is a better test.
1432 static int
1433 same_file_system(const char *path1, const char *path2)
1435 uint64_t fsid1, fsid2;
1436 struct stat64 st1, st2;
1437 nvlist_t *nvl1 = NULL;
1438 nvlist_t *nvl2 = NULL;
1440 if ((getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path1, &nvl1) == 0) &&
1441 (getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path2, &nvl2) == 0) &&
1442 (nvlist_lookup_uint64(nvl1, A_FSID, &fsid1) == 0) &&
1443 (nvlist_lookup_uint64(nvl2, A_FSID, &fsid2) == 0)) {
1444 nvlist_free(nvl1);
1445 nvlist_free(nvl2);
1447 * We have found fsid's for both paths.
1450 if (fsid1 == fsid2)
1451 return (B_TRUE);
1453 return (B_FALSE);
1456 if (nvl1 != NULL)
1457 nvlist_free(nvl1);
1458 if (nvl2 != NULL)
1459 nvlist_free(nvl2);
1462 * We were unable to find fsid's for at least one of the paths.
1463 * fall back on st_dev.
1466 if (stat64(path1, &st1) < 0) {
1467 syslog(LOG_NOTICE, "%s: %m", path1);
1468 return (B_FALSE);
1470 if (stat64(path2, &st2) < 0) {
1471 syslog(LOG_NOTICE, "%s: %m", path2);
1472 return (B_FALSE);
1475 if (st1.st_dev == st2.st_dev)
1476 return (B_TRUE);
1478 return (B_FALSE);
1481 share_t *
1482 findentry(char *path)
1484 share_t *sh = NULL;
1485 struct sh_list *shp;
1486 register char *p1, *p2;
1488 check_sharetab();
1490 (void) rw_rdlock(&sharetab_lock);
1492 for (shp = share_list; shp; shp = shp->shl_next) {
1493 sh = shp->shl_sh;
1494 for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++)
1495 if (*p1 == '\0')
1496 goto done; /* exact match */
1499 * Now compare the pathnames for three cases:
1501 * Parent: /export/foo (no trailing slash on parent)
1502 * Child: /export/foo/bar
1504 * Parent: /export/foo/ (trailing slash on parent)
1505 * Child: /export/foo/bar
1507 * Parent: /export/foo/ (no trailing slash on child)
1508 * Child: /export/foo
1510 if ((*p1 == '\0' && *p2 == '/') ||
1511 (*p1 == '\0' && *(p1-1) == '/') ||
1512 (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) {
1514 * We have a subdirectory. Test whether the
1515 * subdirectory is in the same file system.
1517 if (same_file_system(path, sh->sh_path))
1518 goto done;
1521 done:
1522 sh = shp ? sharedup(sh) : NULL;
1524 (void) rw_unlock(&sharetab_lock);
1526 return (sh);
1530 static int
1531 is_substring(char **mntp, char **path)
1533 char *p1 = *mntp, *p2 = *path;
1535 if (*p1 == '\0' && *p2 == '\0') /* exact match */
1536 return (1);
1537 else if (*p1 == '\0' && *p2 == '/')
1538 return (1);
1539 else if (*p1 == '\0' && *(p1-1) == '/') {
1540 *path = --p2; /* we need the slash in p2 */
1541 return (1);
1542 } else if (*p2 == '\0') {
1543 while (*p1 == '/')
1544 p1++;
1545 if (*p1 == '\0') /* exact match */
1546 return (1);
1548 return (0);
1552 * find_lofsentry() searches for the real path which this requested LOFS path
1553 * (rpath) shadows. If found, it will return the sharetab entry of
1554 * the real path that corresponds to the LOFS path.
1555 * We first search mnttab to see if the requested path is an automounted
1556 * path. If it is an automounted path, it will trigger the mount by stat()ing
1557 * the requested path. Note that it is important to check that this path is
1558 * actually an automounted path, otherwise we would stat() a path which may
1559 * turn out to be NFS and block indefinitely on a dead server. The automounter
1560 * times-out if the server is dead, so there's no risk of hanging this
1561 * thread waiting for stat().
1562 * After the mount has been triggered (if necessary), we look for a
1563 * mountpoint of type LOFS (by searching /etc/mnttab again) which
1564 * is a substring of the rpath. If found, we construct a new path by
1565 * concatenating the mnt_special and the remaining of rpath, call findentry()
1566 * to make sure the 'real path' is shared.
1568 static share_t *
1569 find_lofsentry(char *rpath, int *done_flag)
1571 struct stat r_stbuf;
1572 mntlist_t *ml, *mntl, *mntpnt = NULL;
1573 share_t *retcode = NULL;
1574 char tmp_path[MAXPATHLEN];
1575 int mntpnt_len = 0, tmp;
1576 char *p1, *p2;
1578 if ((*done_flag)++)
1579 return (retcode);
1582 * While fsgetmntlist() uses lockf() to
1583 * lock the mnttab before reading it in,
1584 * the lock ignores threads in the same process.
1585 * Read in the mnttab with the protection of a mutex.
1587 (void) mutex_lock(&mnttab_lock);
1588 mntl = fsgetmntlist();
1589 (void) mutex_unlock(&mnttab_lock);
1592 * Obtain the mountpoint for the requested path.
1594 for (ml = mntl; ml; ml = ml->mntl_next) {
1595 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1596 *p1 == *p2 && *p1; p1++, p2++)
1598 if (is_substring(&p1, &p2) &&
1599 (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) {
1600 mntpnt = ml;
1601 mntpnt_len = tmp;
1606 * If the path needs to be autoFS mounted, trigger the mount by
1607 * stat()ing it. This is determined by checking whether the
1608 * mountpoint we just found is of type autofs.
1610 if (mntpnt != NULL &&
1611 strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) {
1613 * The requested path is a substring of an autoFS filesystem.
1614 * Trigger the mount.
1616 if (stat(rpath, &r_stbuf) < 0) {
1617 if (verbose)
1618 syslog(LOG_NOTICE, "%s: %m", rpath);
1619 goto done;
1621 if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) {
1623 * The requested path is a directory, stat(2) it
1624 * again with a trailing '.' to force the autoFS
1625 * module to trigger the mount of indirect
1626 * automount entries, such as /net/jurassic/.
1628 if (strlen(rpath) + 2 > MAXPATHLEN) {
1629 if (verbose) {
1630 syslog(LOG_NOTICE,
1631 "%s/.: exceeds MAXPATHLEN %d",
1632 rpath, MAXPATHLEN);
1634 goto done;
1636 (void) strcpy(tmp_path, rpath);
1637 (void) strcat(tmp_path, "/.");
1639 if (stat(tmp_path, &r_stbuf) < 0) {
1640 if (verbose)
1641 syslog(LOG_NOTICE, "%s: %m", tmp_path);
1642 goto done;
1647 * The mount has been triggered, re-read mnttab to pick up
1648 * the changes made by autoFS.
1650 fsfreemntlist(mntl);
1651 (void) mutex_lock(&mnttab_lock);
1652 mntl = fsgetmntlist();
1653 (void) mutex_unlock(&mnttab_lock);
1657 * The autoFS mountpoint has been triggered if necessary,
1658 * now search mnttab again to determine if the requested path
1659 * is an LOFS mount of a shared path.
1661 mntpnt_len = 0;
1662 for (ml = mntl; ml; ml = ml->mntl_next) {
1663 if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs"))
1664 continue;
1666 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1667 *p1 == *p2 && *p1; p1++, p2++)
1670 if (is_substring(&p1, &p2) &&
1671 ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) {
1672 mntpnt_len = tmp;
1674 if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) >
1675 MAXPATHLEN) {
1676 if (verbose) {
1677 syslog(LOG_NOTICE, "%s%s: exceeds %d",
1678 ml->mntl_mnt->mnt_special, p2,
1679 MAXPATHLEN);
1681 if (retcode)
1682 sharefree(retcode);
1683 retcode = NULL;
1684 goto done;
1687 (void) strcpy(tmp_path, ml->mntl_mnt->mnt_special);
1688 (void) strcat(tmp_path, p2);
1689 if (retcode)
1690 sharefree(retcode);
1691 retcode = findentry(tmp_path);
1695 if (retcode) {
1696 assert(strlen(tmp_path) > 0);
1697 (void) strcpy(rpath, tmp_path);
1700 done:
1701 fsfreemntlist(mntl);
1702 return (retcode);
1706 * Determine whether an access list grants rights to a particular host.
1707 * We match on aliases of the hostname as well as on the canonical name.
1708 * Names in the access list may be either hosts or netgroups; they're
1709 * not distinguished syntactically. We check for hosts first because
1710 * it's cheaper (just M*N strcmp()s), then try netgroups.
1712 * If pnb and pclnames are NULL, it means that we have to use transp
1713 * to resolve client's IP address to host name. If they aren't NULL
1714 * then transp argument won't be used and can be NULL.
1717 in_access_list(SVCXPRT *transp, struct netbuf **pnb,
1718 struct nd_hostservlist **pclnames,
1719 char *access_list) /* N.B. we clobber this "input" parameter */
1721 int nentries;
1722 char *gr;
1723 char *lasts;
1724 char *host;
1725 int off;
1726 int i;
1727 int netgroup_match;
1728 int response;
1729 struct nd_hostservlist *clnames;
1732 * If no access list - then it's unrestricted
1734 if (access_list == NULL || *access_list == '\0')
1735 return (1);
1737 assert(transp != NULL || (*pnb != NULL && *pclnames != NULL));
1739 nentries = 0;
1741 for (gr = strtok_r(access_list, ":", &lasts);
1742 gr != NULL; gr = strtok_r(NULL, ":", &lasts)) {
1745 * If the list name has a '-' prepended
1746 * then a match of the following name
1747 * implies failure instead of success.
1749 if (*gr == '-') {
1750 response = 0;
1751 gr++;
1752 } else
1753 response = 1;
1756 * If the list name begins with an at
1757 * sign then do a network comparison.
1759 if (*gr == '@') {
1761 * Just get the netbuf, avoiding the costly name
1762 * lookup. This will suffice for access based
1763 * solely on addresses.
1765 if (*pnb == NULL) {
1767 * Don't grant access if client's address isn't
1768 * known.
1770 if ((*pnb = svc_getrpccaller(transp)) == NULL)
1771 return (0);
1774 if (netmatch(*pnb, gr + 1))
1775 return (response);
1776 continue;
1780 * We need to get the host name if we haven't gotten
1781 * it by now!
1783 if (*pclnames == NULL) {
1784 DTRACE_PROBE(mountd, name_by_addrlist);
1786 * Do not grant access if we can't
1787 * get a name!
1789 if (getclientsnames(transp, pnb, pclnames) != 0)
1790 return (0);
1793 clnames = *pclnames;
1796 * The following loops through all the
1797 * client's aliases. Usually it's just one name.
1799 for (i = 0; i < clnames->h_cnt; i++) {
1800 host = clnames->h_hostservs[i].h_host;
1803 * If the list name begins with a dot then
1804 * do a domain name suffix comparison.
1805 * A single dot matches any name with no
1806 * suffix.
1808 if (*gr == '.') {
1809 if (*(gr + 1) == '\0') { /* single dot */
1810 if (strchr(host, '.') == NULL)
1811 return (response);
1812 } else {
1813 off = strlen(host) - strlen(gr);
1814 if (off > 0 &&
1815 strcasecmp(host + off, gr) == 0) {
1816 return (response);
1819 } else
1822 * Just do a hostname match
1824 if (strcasecmp(gr, host) == 0) {
1825 return (response); /* Matched a hostname */
1829 nentries++;
1833 * We need to get the host name if we haven't gotten
1834 * it by now!
1836 if (*pclnames == NULL) {
1837 DTRACE_PROBE(mountd, name_by_netgroup);
1839 * Do not grant access if we can't
1840 * get a name!
1842 if (getclientsnames(transp, pnb, pclnames) != 0)
1843 return (0);
1846 netgroup_match = netgroup_check(*pclnames, access_list, nentries);
1848 return (netgroup_match);
1852 netmatch(struct netbuf *nb, char *name)
1854 uint_t claddr;
1855 struct netent n, *np;
1856 char *mp, *p;
1857 uint_t addr, mask;
1858 int i, bits;
1859 char buff[256];
1862 * Check if it's an IPv4 addr
1864 if (nb->len != sizeof (struct sockaddr_in))
1865 return (0);
1867 (void) memcpy(&claddr,
1868 /* LINTED pointer alignment */
1869 &((struct sockaddr_in *)nb->buf)->sin_addr.s_addr,
1870 sizeof (struct in_addr));
1871 claddr = ntohl(claddr);
1873 mp = strchr(name, '/');
1874 if (mp)
1875 *mp++ = '\0';
1877 if (isdigit(*name)) {
1879 * Convert a dotted IP address
1880 * to an IP address. The conversion
1881 * is not the same as that in inet_addr().
1883 p = name;
1884 addr = 0;
1885 for (i = 0; i < 4; i++) {
1886 addr |= atoi(p) << ((3-i) * 8);
1887 p = strchr(p, '.');
1888 if (p == NULL)
1889 break;
1890 p++;
1892 } else {
1894 * Turn the netname into
1895 * an IP address.
1897 np = getnetbyname_r(name, &n, buff, sizeof (buff));
1898 if (np == NULL) {
1899 syslog(LOG_DEBUG, "getnetbyname_r: %s: %m", name);
1900 return (0);
1902 addr = np->n_net;
1906 * If the mask is specified explicitly then
1907 * use that value, e.g.
1909 * @109.104.56/28
1911 * otherwise assume a mask from the zero octets
1912 * in the least significant bits of the address, e.g.
1914 * @109.104 or @109.104.0.0
1916 if (mp) {
1917 bits = atoi(mp);
1918 mask = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - bits)
1919 : 0;
1920 addr &= mask;
1921 } else {
1922 if ((addr & IN_CLASSA_HOST) == 0)
1923 mask = IN_CLASSA_NET;
1924 else if ((addr & IN_CLASSB_HOST) == 0)
1925 mask = IN_CLASSB_NET;
1926 else if ((addr & IN_CLASSC_HOST) == 0)
1927 mask = IN_CLASSC_NET;
1928 else
1929 mask = IN_CLASSE_NET;
1932 return ((claddr & mask) == addr);
1936 static char *optlist[] = {
1937 #define OPT_RO 0
1938 SHOPT_RO,
1939 #define OPT_RW 1
1940 SHOPT_RW,
1941 #define OPT_ROOT 2
1942 SHOPT_ROOT,
1943 #define OPT_SECURE 3
1944 SHOPT_SECURE,
1945 #define OPT_ANON 4
1946 SHOPT_ANON,
1947 #define OPT_WINDOW 5
1948 SHOPT_WINDOW,
1949 #define OPT_NOSUID 6
1950 SHOPT_NOSUID,
1951 #define OPT_ACLOK 7
1952 SHOPT_ACLOK,
1953 #define OPT_SEC 8
1954 SHOPT_SEC,
1955 #define OPT_NONE 9
1956 SHOPT_NONE,
1957 NULL
1960 static int
1961 map_flavor(char *str)
1963 seconfig_t sec;
1965 if (nfs_getseconfig_byname(str, &sec))
1966 return (-1);
1968 return (sec.sc_nfsnum);
1972 * If the option string contains a "sec="
1973 * option, then use new option syntax.
1975 static int
1976 newopts(char *opts)
1978 char *head, *p, *val;
1980 if (!opts || *opts == '\0')
1981 return (0);
1983 head = strdup(opts);
1984 if (head == NULL) {
1985 syslog(LOG_ERR, "opts: no memory");
1986 return (0);
1989 p = head;
1990 while (*p) {
1991 if (getsubopt(&p, optlist, &val) == OPT_SEC) {
1992 free(head);
1993 return (1);
1997 free(head);
1998 return (0);
2002 * Given an export and the clients hostname(s)
2003 * determine the security flavors that this
2004 * client is permitted to use.
2006 * This routine is called only for "old" syntax, i.e.
2007 * only one security flavor is allowed. So we need
2008 * to determine two things: the particular flavor,
2009 * and whether the client is allowed to use this
2010 * flavor, i.e. is in the access list.
2012 * Note that if there is no access list, then the
2013 * default is that access is granted.
2015 static int
2016 getclientsflavors_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2017 struct nd_hostservlist **clnames, int *flavors)
2019 char *opts, *p, *val;
2020 boolean_t ok = B_FALSE;
2021 int defaultaccess = 1;
2022 boolean_t reject = B_FALSE;
2024 opts = strdup(sh->sh_opts);
2025 if (opts == NULL) {
2026 syslog(LOG_ERR, "getclientsflavors: no memory");
2027 return (0);
2030 flavors[0] = AUTH_SYS;
2031 p = opts;
2033 while (*p) {
2035 switch (getsubopt(&p, optlist, &val)) {
2036 case OPT_SECURE:
2037 flavors[0] = AUTH_DES;
2038 break;
2040 case OPT_RO:
2041 case OPT_RW:
2042 defaultaccess = 0;
2043 if (in_access_list(transp, nb, clnames, val))
2044 ok++;
2045 break;
2047 case OPT_NONE:
2048 defaultaccess = 0;
2049 if (in_access_list(transp, nb, clnames, val))
2050 reject = B_TRUE;
2054 free(opts);
2056 /* none takes precedence over everything else */
2057 if (reject)
2058 ok = B_TRUE;
2060 return (defaultaccess || ok);
2064 * Given an export and the clients hostname(s)
2065 * determine the security flavors that this
2066 * client is permitted to use.
2068 * This is somewhat more complicated than the "old"
2069 * routine because the options may contain multiple
2070 * security flavors (sec=) each with its own access
2071 * lists. So a client could be granted access based
2072 * on a number of security flavors. Note that the
2073 * type of access might not always be the same, the
2074 * client may get readonly access with one flavor
2075 * and readwrite with another, however the client
2076 * is not told this detail, it gets only the list
2077 * of flavors, and only if the client is using
2078 * version 3 of the mount protocol.
2080 static int
2081 getclientsflavors_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2082 struct nd_hostservlist **clnames, int *flavors)
2084 char *opts, *p, *val;
2085 char *lasts;
2086 char *f;
2087 boolean_t access_ok;
2088 int count, c, perm;
2089 boolean_t reject = B_FALSE;
2091 opts = strdup(sh->sh_opts);
2092 if (opts == NULL) {
2093 syslog(LOG_ERR, "getclientsflavors: no memory");
2094 return (0);
2097 p = opts;
2098 perm = count = c = 0;
2099 /* default access is rw */
2100 access_ok = B_TRUE;
2102 while (*p) {
2103 switch (getsubopt(&p, optlist, &val)) {
2104 case OPT_SEC:
2106 * Before a new sec=xxx option, check if we need
2107 * to move the c index back to the previous count.
2109 if (!access_ok) {
2110 c = count;
2113 /* get all the sec=f1[:f2] flavors */
2114 while ((f = strtok_r(val, ":", &lasts))
2115 != NULL) {
2116 flavors[c++] = map_flavor(f);
2117 val = NULL;
2120 /* for a new sec=xxx option, default is rw access */
2121 access_ok = B_TRUE;
2122 break;
2124 case OPT_RO:
2125 case OPT_RW:
2126 if (in_access_list(transp, nb, clnames, val)) {
2127 count = c;
2128 access_ok = B_TRUE;
2129 } else {
2130 access_ok = B_FALSE;
2132 break;
2134 case OPT_NONE:
2135 if (in_access_list(transp, nb, clnames, val))
2136 reject = B_TRUE; /* none overides rw/ro */
2137 break;
2141 if (reject)
2142 access_ok = B_FALSE;
2144 if (!access_ok)
2145 c = count;
2147 free(opts);
2149 return (c);
2153 * This is a tricky piece of code that parses the
2154 * share options looking for a match on the auth
2155 * flavor that the client is using. If it finds
2156 * a match, then the client is given ro, rw, or
2157 * no access depending whether it is in the access
2158 * list. There is a special case for "secure"
2159 * flavor. Other flavors are values of the new "sec=" option.
2162 check_client(share_t *sh, struct netbuf *nb,
2163 struct nd_hostservlist *clnames, int flavor)
2165 if (newopts(sh->sh_opts))
2166 return (check_client_new(sh, NULL, &nb, &clnames, flavor));
2167 else
2168 return (check_client_old(sh, NULL, &nb, &clnames, flavor));
2171 static int
2172 check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2173 struct nd_hostservlist **clnames, int flavor)
2175 char *opts, *p, *val;
2176 int match; /* Set when a flavor is matched */
2177 int perm = 0; /* Set when "ro", "rw" or "root" is matched */
2178 int list = 0; /* Set when "ro", "rw" is found */
2179 int ro_val = 0; /* Set if ro option is 'ro=' */
2180 int rw_val = 0; /* Set if rw option is 'rw=' */
2181 boolean_t reject = B_FALSE; /* if none= contains the host */
2183 opts = strdup(sh->sh_opts);
2184 if (opts == NULL) {
2185 syslog(LOG_ERR, "check_client: no memory");
2186 return (0);
2189 p = opts;
2190 match = AUTH_UNIX;
2192 while (*p) {
2193 switch (getsubopt(&p, optlist, &val)) {
2195 case OPT_SECURE:
2196 match = AUTH_DES;
2197 break;
2199 case OPT_RO:
2200 list++;
2201 if (val) ro_val++;
2202 if (in_access_list(transp, nb, clnames, val))
2203 perm |= NFSAUTH_RO;
2204 break;
2206 case OPT_RW:
2207 list++;
2208 if (val) rw_val++;
2209 if (in_access_list(transp, nb, clnames, val))
2210 perm |= NFSAUTH_RW;
2211 break;
2213 case OPT_ROOT:
2215 * Check if the client is in
2216 * the root list. Only valid
2217 * for AUTH_SYS.
2219 if (flavor != AUTH_SYS)
2220 break;
2222 if (val == NULL || *val == '\0')
2223 break;
2225 if (in_access_list(transp, nb, clnames, val))
2226 perm |= NFSAUTH_ROOT;
2227 break;
2229 case OPT_NONE:
2231 * Check if the client should have no access
2232 * to this share at all. This option behaves
2233 * more like "root" than either "rw" or "ro".
2235 if (in_access_list(transp, nb, clnames, val))
2236 reject = B_TRUE;
2237 break;
2241 free(opts);
2243 if (flavor != match || reject)
2244 return (NFSAUTH_DENIED);
2246 if (list) {
2248 * If the client doesn't match an "ro" or "rw"
2249 * list then set no access.
2251 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0)
2252 perm |= NFSAUTH_DENIED;
2253 } else {
2255 * The client matched a flavor entry that
2256 * has no explicit "rw" or "ro" determination.
2257 * Default it to "rw".
2259 perm |= NFSAUTH_RW;
2264 * The client may show up in both ro= and rw=
2265 * lists. If so, then turn off the RO access
2266 * bit leaving RW access.
2268 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2270 * Logically cover all permutations of rw=,ro=.
2271 * In the case where, rw,ro=<host> we would like
2272 * to remove RW access for the host. In all other cases
2273 * RW wins the precedence battle.
2275 if (!rw_val && ro_val) {
2276 perm &= ~(NFSAUTH_RW);
2277 } else {
2278 perm &= ~(NFSAUTH_RO);
2282 return (perm);
2286 * Check if the client has access by using a flavor different from
2287 * the given "flavor". If "flavor" is not in the flavor list,
2288 * return TRUE to indicate that this "flavor" is a wrong sec.
2290 static bool_t
2291 is_wrongsec(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2292 struct nd_hostservlist **clnames, int flavor)
2294 int flavor_list[MAX_FLAVORS];
2295 int flavor_count, i;
2297 /* get the flavor list that the client has access with */
2298 flavor_count = getclientsflavors_new(sh, transp, nb,
2299 clnames, flavor_list);
2301 if (flavor_count == 0)
2302 return (FALSE);
2305 * Check if the given "flavor" is in the flavor_list.
2307 for (i = 0; i < flavor_count; i++) {
2308 if (flavor == flavor_list[i])
2309 return (FALSE);
2313 * If "flavor" is not in the flavor_list, return TRUE to indicate
2314 * that the client should have access by using a security flavor
2315 * different from this "flavor".
2317 return (TRUE);
2321 * Given an export and the client's hostname, we
2322 * check the security options to see whether the
2323 * client is allowed to use the given security flavor.
2325 * The strategy is to proceed through the options looking
2326 * for a flavor match, then pay attention to the ro, rw,
2327 * and root options.
2329 * Note that an entry may list several flavors in a
2330 * single entry, e.g.
2332 * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
2336 static int
2337 check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2338 struct nd_hostservlist **clnames, int flavor)
2340 char *opts, *p, *val;
2341 char *lasts;
2342 char *f;
2343 int match = 0; /* Set when a flavor is matched */
2344 int perm = 0; /* Set when "ro", "rw" or "root" is matched */
2345 int list = 0; /* Set when "ro", "rw" is found */
2346 int ro_val = 0; /* Set if ro option is 'ro=' */
2347 int rw_val = 0; /* Set if rw option is 'rw=' */
2348 boolean_t reject;
2350 opts = strdup(sh->sh_opts);
2351 if (opts == NULL) {
2352 syslog(LOG_ERR, "check_client: no memory");
2353 return (0);
2356 p = opts;
2358 while (*p) {
2359 switch (getsubopt(&p, optlist, &val)) {
2361 case OPT_SEC:
2362 if (match)
2363 goto done;
2365 while ((f = strtok_r(val, ":", &lasts))
2366 != NULL) {
2367 if (flavor == map_flavor(f)) {
2368 match = 1;
2369 break;
2371 val = NULL;
2373 break;
2375 case OPT_RO:
2376 if (!match)
2377 break;
2379 list++;
2380 if (val) ro_val++;
2381 if (in_access_list(transp, nb, clnames, val))
2382 perm |= NFSAUTH_RO;
2383 break;
2385 case OPT_RW:
2386 if (!match)
2387 break;
2389 list++;
2390 if (val) rw_val++;
2391 if (in_access_list(transp, nb, clnames, val))
2392 perm |= NFSAUTH_RW;
2393 break;
2395 case OPT_ROOT:
2397 * Check if the client is in
2398 * the root list. Only valid
2399 * for AUTH_SYS.
2401 if (flavor != AUTH_SYS)
2402 break;
2404 if (!match)
2405 break;
2407 if (val == NULL || *val == '\0')
2408 break;
2410 if (in_access_list(transp, nb, clnames, val))
2411 perm |= NFSAUTH_ROOT;
2412 break;
2414 case OPT_NONE:
2416 * Check if the client should have no access
2417 * to this share at all. This option behaves
2418 * more like "root" than either "rw" or "ro".
2420 if (in_access_list(transp, nb, clnames, val))
2421 perm |= NFSAUTH_DENIED;
2422 break;
2426 done:
2428 * If no match then set the perm accordingly
2430 if (!match || perm & NFSAUTH_DENIED)
2431 return (NFSAUTH_DENIED);
2433 if (list) {
2435 * If the client doesn't match an "ro" or "rw" list then
2436 * check if it may have access by using a different flavor.
2437 * If so, return NFSAUTH_WRONGSEC.
2438 * If not, return NFSAUTH_DENIED.
2440 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
2441 if (is_wrongsec(sh, transp, nb, clnames, flavor))
2442 perm |= NFSAUTH_WRONGSEC;
2443 else
2444 perm |= NFSAUTH_DENIED;
2446 } else {
2448 * The client matched a flavor entry that
2449 * has no explicit "rw" or "ro" determination.
2450 * Make sure it defaults to "rw".
2452 perm |= NFSAUTH_RW;
2456 * The client may show up in both ro= and rw=
2457 * lists. If so, then turn off the RO access
2458 * bit leaving RW access.
2460 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2462 * Logically cover all permutations of rw=,ro=.
2463 * In the case where, rw,ro=<host> we would like
2464 * to remove RW access for the host. In all other cases
2465 * RW wins the precedence battle.
2467 if (!rw_val && ro_val) {
2468 perm &= ~(NFSAUTH_RW);
2469 } else {
2470 perm &= ~(NFSAUTH_RO);
2474 free(opts);
2476 return (perm);
2479 void
2480 check_sharetab()
2482 FILE *f;
2483 struct stat st;
2484 static timestruc_t last_sharetab_time;
2485 timestruc_t prev_sharetab_time;
2486 share_t *sh;
2487 struct sh_list *shp, *shp_prev;
2488 int res, c = 0;
2491 * read in /etc/dfs/sharetab if it has changed
2493 if (stat(SHARETAB, &st) != 0) {
2494 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
2495 return;
2498 if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec &&
2499 st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) {
2501 * No change.
2503 return;
2507 * Remember the mod time, then after getting the
2508 * write lock check again. If another thread
2509 * already did the update, then there's no
2510 * work to do.
2512 prev_sharetab_time = last_sharetab_time;
2514 (void) rw_wrlock(&sharetab_lock);
2516 if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec ||
2517 prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) {
2518 (void) rw_unlock(&sharetab_lock);
2519 return;
2523 * Note that since the sharetab is now in memory
2524 * and a snapshot is taken, we no longer have to
2525 * lock the file.
2527 f = fopen(SHARETAB, "r");
2528 if (f == NULL) {
2529 syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB);
2530 (void) rw_unlock(&sharetab_lock);
2531 return;
2535 * Once we are sure /etc/dfs/sharetab has been
2536 * modified, flush netgroup cache entries.
2538 netgrp_cache_flush();
2540 sh_free(share_list); /* free old list */
2541 share_list = NULL;
2543 while ((res = getshare(f, &sh)) > 0) {
2544 c++;
2545 if (strcmp(sh->sh_fstype, "nfs") != 0)
2546 continue;
2548 shp = malloc(sizeof (*shp));
2549 if (shp == NULL)
2550 goto alloc_failed;
2551 if (share_list == NULL)
2552 share_list = shp;
2553 else
2554 /* LINTED not used before set */
2555 shp_prev->shl_next = shp;
2556 shp_prev = shp;
2557 shp->shl_next = NULL;
2558 shp->shl_sh = sharedup(sh);
2559 if (shp->shl_sh == NULL)
2560 goto alloc_failed;
2563 if (res < 0)
2564 syslog(LOG_ERR, "%s: invalid at line %d\n",
2565 SHARETAB, c + 1);
2567 if (stat(SHARETAB, &st) != 0) {
2568 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
2569 (void) fclose(f);
2570 (void) rw_unlock(&sharetab_lock);
2571 return;
2574 last_sharetab_time = st.st_mtim;
2575 (void) fclose(f);
2576 (void) rw_unlock(&sharetab_lock);
2578 return;
2580 alloc_failed:
2582 syslog(LOG_ERR, "check_sharetab: no memory");
2583 sh_free(share_list);
2584 share_list = NULL;
2585 (void) fclose(f);
2586 (void) rw_unlock(&sharetab_lock);
2589 static void
2590 sh_free(struct sh_list *shp)
2592 register struct sh_list *next;
2594 while (shp) {
2595 sharefree(shp->shl_sh);
2596 next = shp->shl_next;
2597 free(shp);
2598 shp = next;
2604 * Remove an entry from mounted list
2606 static void
2607 umount(struct svc_req *rqstp)
2609 char *host, *path, *remove_path;
2610 char rpath[MAXPATHLEN];
2611 struct nd_hostservlist *clnames = NULL;
2612 SVCXPRT *transp;
2613 struct netbuf *nb;
2615 transp = rqstp->rq_xprt;
2616 path = NULL;
2617 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
2618 svcerr_decode(transp);
2619 return;
2621 errno = 0;
2622 if (!svc_sendreply(transp, xdr_void, (char *)NULL))
2623 log_cant_reply(transp);
2625 if (getclientsnames(transp, &nb, &clnames) != 0) {
2627 * Without the hostname we can't do audit or delete
2628 * this host from the mount entries.
2630 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
2631 return;
2633 host = clnames->h_hostservs[0].h_host;
2635 if (verbose)
2636 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
2638 audit_mountd_umount(host, path);
2640 remove_path = rpath; /* assume we will use the cannonical path */
2641 if (realpath(path, rpath) == NULL) {
2642 if (verbose)
2643 syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
2644 remove_path = path; /* use path provided instead */
2647 mntlist_delete(host, remove_path); /* remove from mount list */
2649 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
2650 netdir_free(clnames, ND_HOSTSERVLIST);
2654 * Remove all entries for one machine from mounted list
2656 static void
2657 umountall(struct svc_req *rqstp)
2659 struct nd_hostservlist *clnames = NULL;
2660 SVCXPRT *transp;
2661 char *host;
2662 struct netbuf *nb;
2664 transp = rqstp->rq_xprt;
2665 if (!svc_getargs(transp, xdr_void, NULL)) {
2666 svcerr_decode(transp);
2667 return;
2670 * We assume that this call is asynchronous and made via rpcbind
2671 * callit routine. Therefore return control immediately. The error
2672 * causes rpcbind to remain silent, as opposed to every machine
2673 * on the net blasting the requester with a response.
2675 svcerr_systemerr(transp);
2676 if (getclientsnames(transp, &nb, &clnames) != 0) {
2677 /* Can't do anything without the name of the client */
2678 return;
2681 host = clnames->h_hostservs[0].h_host;
2684 * Remove all hosts entries from mount list
2686 mntlist_delete_all(host);
2688 if (verbose)
2689 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
2691 netdir_free(clnames, ND_HOSTSERVLIST);
2694 void *
2695 exmalloc(size_t size)
2697 void *ret;
2699 if ((ret = malloc(size)) == NULL) {
2700 syslog(LOG_ERR, "Out of memory");
2701 exit(1);
2703 return (ret);
2706 static void
2707 sigexit(int signum)
2710 if (signum == SIGHUP)
2711 _exit(0);
2712 _exit(1);
2715 static tsol_tpent_t *
2716 get_client_template(struct sockaddr *sock)
2718 in_addr_t v4client;
2719 in6_addr_t v6client;
2720 char v4_addr[INET_ADDRSTRLEN];
2721 char v6_addr[INET6_ADDRSTRLEN];
2722 tsol_rhent_t *rh;
2723 tsol_tpent_t *tp;
2725 switch (sock->sa_family) {
2726 case AF_INET:
2727 v4client = ((struct sockaddr_in *)(void *)sock)->
2728 sin_addr.s_addr;
2729 if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
2730 NULL)
2731 return (NULL);
2732 rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
2733 if (rh == NULL)
2734 return (NULL);
2735 tp = tsol_gettpbyname(rh->rh_template);
2736 tsol_freerhent(rh);
2737 return (tp);
2738 break;
2739 case AF_INET6:
2740 v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
2741 if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
2742 NULL)
2743 return (NULL);
2744 rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
2745 if (rh == NULL)
2746 return (NULL);
2747 tp = tsol_gettpbyname(rh->rh_template);
2748 tsol_freerhent(rh);
2749 return (tp);
2750 break;
2751 default:
2752 return (NULL);