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]
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.
37 #include <sys/types.h>
40 #include <sys/param.h>
43 #include <netconfig.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>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
63 #include <priv_utils.h>
65 #include <nfs/nfssys.h>
67 #include <nfs/nfs_sec.h>
68 #include <rpcsvc/daemon_utils.h>
70 #include "../../fslib.h"
71 #include <sharefs/share.h>
72 #include <sharefs/sharetab.h>
73 #include "../lib/sharetab.h"
75 #include <tsol/label.h>
76 #include <sys/tsol/label_macro.h>
79 #include <sys/nvpair.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
*);
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
;
130 thread_t logging_thread
;
132 typedef struct logging_data
{
138 struct netbuf
*ld_nb
;
139 struct logging_data
*ld_next
;
142 static logging_data
*logging_head
= NULL
;
143 static logging_data
*logging_tail
= NULL
;
147 nfsauth_svc(void *arg
)
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");
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
);
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");
183 (void) close(doorfd
);
190 * Must pass the doorfd down to the kernel.
193 (void) _nfssys(MOUNTD_ARGS
, &darg
);
196 * Wait for incoming calls
203 syslog(LOG_ERR
, gettext("Door server exited"));
208 * NFS command service thread code for setup and handling of the
209 * nfs_cmd requests for character set conversion and other future
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");
226 * Must pass the doorfd down to the kernel.
229 (void) _nfssys(NFSCMD_ARGS
, &darg
);
232 * Wait for incoming calls
239 syslog(LOG_ERR
, gettext("Cmd door server exited"));
244 free_logging_data(logging_data
*lq
)
250 if (lq
->ld_nb
!= NULL
) {
251 free(lq
->ld_nb
->buf
);
262 static logging_data
*
263 remove_head_of_queue(void)
268 * Pull it off the queue.
272 logging_head
= lq
->ld_next
;
277 if (logging_head
== NULL
) {
286 do_logging_queue(logging_data
*lq
)
288 logging_data
*lq_clean
= NULL
;
292 struct nd_hostservlist
*clnames
;
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)
301 host
= clnames
->h_hostservs
[0].h_host
;
305 audit_mountd_mount(host
, lq
->ld_path
, lq
->ld_status
); /* BSM */
307 /* add entry to mount list */
309 mntlist_new(host
, lq
->ld_rpath
);
311 lq
->ld_next
= lq_clean
;
314 (void) mutex_lock(&logging_queue_lock
);
315 lq
= remove_head_of_queue();
316 (void) mutex_unlock(&logging_queue_lock
);
321 lq_clean
= lq
->ld_next
;
323 free_logging_data(lq
);
327 DTRACE_PROBE1(mountd
, logging_cleared
, cleared
);
331 logging_svc(void *arg
)
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
);
349 syslog(LOG_ERR
, gettext("Logging server exited"));
354 main(int argc
, char *argv
[])
358 int rpc_svc_mode
= RPC_SVC_MT_AUTO
;
360 int maxrecsz
= RPC_MAXDATASIZE
;
361 bool_t exclbind
= TRUE
;
363 long thr_flags
= (THR_NEW_LWP
|THR_DAEMON
);
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)
376 * file dac search (so it can stat all files)
377 * Optional privileges:
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",
392 while ((c
= getopt(argc
, argv
, "vrm:")) != EOF
) {
401 maxthreads
= atoi(optarg
);
402 if (maxthreads
< 1) {
403 (void) fprintf(stderr
,
404 "%s: must specify positive maximum threads count, using default\n",
413 * Read in the NFS version values from config file.
415 if ((defopen(NFSADMIN
)) == 0) {
419 if ((defval
= defread("NFS_SERVER_VERSMIN=")) != NULL
) {
421 defvers
= strtol(defval
, (char **)NULL
, 10);
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
) {
434 defvers
= strtol(defval
, (char **)NULL
, 10);
436 mount_vers_max
= defvers
;
440 /* close defaults file */
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
);
461 #if !defined(TEXT_DOMAIN)
462 #define TEXT_DOMAIN "SYS_TEST"
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
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
);
489 fprintf(stderr
, "error locking for %s: %s", MOUNTD
,
493 /* daemon was already running */
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");
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");
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"));
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"));
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"));
576 * Create datagram and connection oriented services
578 if (mount_vers_max
>= MOUNTVERS
) {
579 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS
, "datagram_v") == 0) {
581 "couldn't register datagram_v MOUNTVERS");
584 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS
, "circuit_v") == 0) {
586 "couldn't register circuit_v MOUNTVERS");
591 if (mount_vers_max
>= MOUNTVERS_POSIX
) {
592 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS_POSIX
,
593 "datagram_v") == 0) {
595 "couldn't register datagram_v MOUNTVERS_POSIX");
598 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS_POSIX
,
601 "couldn't register circuit_v MOUNTVERS_POSIX");
606 if (mount_vers_max
>= MOUNTVERS3
) {
607 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS3
, "datagram_v") == 0) {
609 "couldn't register datagram_v MOUNTVERS3");
612 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS3
, "circuit_v") == 0) {
614 "couldn't register circuit_v MOUNTVERS3");
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
,
631 syslog(LOG_ERR
, "Error: svc_run shouldn't have returned");
639 * Server procedure switch routine
642 mnt(struct svc_req
*rqstp
, SVCXPRT
*transp
)
644 switch (rqstp
->rq_proc
) {
647 if (!svc_sendreply(transp
, xdr_void
, (char *)0))
648 log_cant_reply(transp
);
656 mntlist_send(transp
);
663 case MOUNTPROC_UMNTALL
:
667 case MOUNTPROC_EXPORT
:
668 case MOUNTPROC_EXPORTALL
:
672 case MOUNTPROC_PATHCONF
:
673 if (rqstp
->rq_vers
== MOUNTVERS_POSIX
)
676 svcerr_noproc(transp
);
680 svcerr_noproc(transp
);
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
)
697 anon_hs
= malloc(sizeof (*anon_hs
));
698 if (anon_hs
== NULL
) {
704 anon_hs
->h_host
= strdup("(anon)");
706 anon_hs
->h_host
= strdup(host
);
708 if (anon_hs
->h_host
== NULL
) {
713 anon_hs
->h_serv
= '\0';
716 anon_hsl
->h_hostservs
= anon_hs
;
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
);
748 syslog(LOG_ERR
, gettext(
749 "Client's address is neither IPv4 nor IPv6"));
753 *serv
= anon_client(host
);
758 assert(*serv
!= NULL
);
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)".
768 getclientsnames_lazy(char *netid
, struct netbuf
**nbuf
,
769 struct nd_hostservlist
**serv
)
771 struct netconfig
*nconf
;
774 nconf
= getnetconfigent(netid
);
776 syslog(LOG_ERR
, "%s: getnetconfigent failed", netid
);
777 *serv
= anon_client(NULL
);
783 rc
= getclientsnames_common(nconf
, nbuf
, serv
);
784 freenetconfigent(nconf
);
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
;
799 nconf
= getnetconfigent(transp
->xp_netid
);
801 syslog(LOG_ERR
, "%s: getnetconfigent failed",
803 *serv
= anon_client(NULL
);
809 *nbuf
= svc_getrpccaller(transp
);
811 freenetconfigent(nconf
);
812 *serv
= anon_client(NULL
);
818 rc
= getclientsnames_common(nconf
, nbuf
, serv
);
819 freenetconfigent(nconf
);
824 log_cant_reply(SVCXPRT
*transp
)
827 struct nd_hostservlist
*clnames
= NULL
;
831 saverrno
= errno
; /* save error code */
832 if (getclientsnames(transp
, &nb
, &clnames
) != 0)
834 host
= clnames
->h_hostservs
->h_host
;
838 syslog(LOG_ERR
, "couldn't send reply to %s", host
);
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
849 mnt_pathconf(struct svc_req
*rqstp
)
853 char *path
, rpath
[MAXPATHLEN
];
856 transp
= rqstp
->rq_xprt
;
858 (void) memset((caddr_t
)&p
, 0, sizeof (p
));
860 if (!svc_getargs(transp
, xdr_dirpath
, (caddr_t
)&path
)) {
861 svcerr_decode(transp
);
864 if (lstat(path
, &st
) < 0) {
865 _PC_SET(_PC_ERROR
, p
.pc_mask
);
869 * Get a path without symbolic links.
871 if (realpath(path
, rpath
) == NULL
) {
873 "mount request: realpath failed on %s: %m",
875 _PC_SET(_PC_ERROR
, p
.pc_mask
);
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
);
888 p
.pc_link_max
= pathconf(rpath
, _PC_LINK_MAX
);
890 _PC_SET(_PC_LINK_MAX
, p
.pc_mask
);
891 p
.pc_name_max
= pathconf(rpath
, _PC_NAME_MAX
);
893 _PC_SET(_PC_NAME_MAX
, p
.pc_mask
);
894 p
.pc_path_max
= pathconf(rpath
, _PC_PATH_MAX
);
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
);
904 if (!svc_sendreply(transp
, xdr_ppathcnf
, (char *)&p
))
905 log_cant_reply(transp
);
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.
915 checkrootmount(share_t
*sh
, char *rpath
)
919 if ((val
= getshareopt(sh
->sh_opts
, SHOPT_NOSUB
)) != NULL
) {
921 if (strcmp(sh
->sh_path
, rpath
) != 0)
929 #define MAX_FLAVORS 128
932 * Return only EACCES if client does not have access
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,
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
;
955 int realpath_error
= ENOENT
, reply_error
= EACCES
, lofs_tried
= 0;
958 checkpath
= strdup(path
);
959 if (checkpath
== NULL
) {
960 syslog(LOG_ERR
, "mount_enoent: no memory");
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)
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)
991 * Check permissions in mount table.
993 if (newopts(sh
->sh_opts
))
994 flavor_count
= getclientsflavors_new(sh
,
995 transp
, nb
, clnames
, flavor_list
);
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
;
1010 * Check all parent directories.
1012 dp
= strrchr(checkpath
, '/');
1016 if (strlen(checkpath
) == 0)
1019 * Get the real path (no symbolic links in it)
1021 if (realpath(checkpath
, rpath
) == NULL
) {
1022 if (errno
!= ENOENT
)
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.
1041 enqueue_logging_data(char *host
, SVCXPRT
*transp
, char *path
,
1042 char *rpath
, int status
, int error
)
1047 lq
= (logging_data
*)calloc(1, sizeof (logging_data
));
1052 * We might not yet have the host...
1055 DTRACE_PROBE1(mountd
, log_host
, host
);
1056 lq
->ld_host
= strdup(host
);
1057 if (lq
->ld_host
== NULL
)
1060 DTRACE_PROBE(mountd
, log_no_host
);
1062 lq
->ld_netid
= strdup(transp
->xp_netid
);
1063 if (lq
->ld_netid
== NULL
)
1066 lq
->ld_nb
= calloc(1, sizeof (struct netbuf
));
1067 if (lq
->ld_nb
== NULL
)
1070 nb
= svc_getrpccaller(transp
);
1072 DTRACE_PROBE(mountd
, e__nb__enqueue
);
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
)
1085 bcopy(nb
->buf
, lq
->ld_nb
->buf
, lq
->ld_nb
->len
);
1088 lq
->ld_path
= strdup(path
);
1089 if (lq
->ld_path
== NULL
)
1093 lq
->ld_rpath
= strdup(rpath
);
1094 if (lq
->ld_rpath
== NULL
)
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
;
1107 logging_tail
->ld_next
= lq
;
1110 (void) cond_signal(&logging_queue_cv
);
1111 (void) mutex_unlock(&logging_queue_lock
);
1117 free_logging_data(lq
);
1123 * Check mount requests, add to mounted list if ok
1126 mount(struct svc_req
*rqstp
)
1130 struct fhstatus fhs
;
1131 struct mountres3 mountres3
;
1134 char *path
, rpath
[MAXPATHLEN
];
1136 struct nd_hostservlist
*clnames
= NULL
;
1138 int error
= 0, lofs_tried
= 0, enqueued
;
1139 int flavor_list
[MAX_FLAVORS
];
1141 struct netbuf
*nb
= NULL
;
1146 transp
= rqstp
->rq_xprt
;
1147 version
= rqstp
->rq_vers
;
1150 if (!svc_getargs(transp
, xdr_dirpath
, (caddr_t
)&path
)) {
1151 svcerr_decode(transp
);
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
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.
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
1182 if (rejecting
|| version
< mount_vers_min
) {
1184 syslog(LOG_NOTICE
, "Rejected mount: %s for %s",
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()) {
1200 "Rejected mount: TX doesn't support NFSv2");
1207 * Get the real path (no symbolic links in it)
1209 if (realpath(path
, rpath
) == NULL
) {
1213 "mount request: realpath: %s: %m", path
);
1214 if (error
== ENOENT
)
1215 error
= mount_enoent_error(transp
, path
, rpath
,
1216 &clnames
, &nb
, flavor_list
);
1220 if ((sh
= findentry(rpath
)) == NULL
&&
1221 (sh
= find_lofsentry(rpath
, &lofs_tried
)) == NULL
) {
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) {
1235 if (newopts(sh
->sh_opts
))
1236 flavor_count
= getclientsflavors_new(sh
, transp
, &nb
, &clnames
,
1239 flavor_count
= getclientsflavors_old(sh
, transp
, &nb
, &clnames
,
1243 host
= clnames
->h_hostservs
[0].h_host
;
1245 if (flavor_count
== 0) {
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) {
1263 "mount request: Failed to get caller's ucred : %m");
1267 if ((clabel
= ucred_getlabel(uc
)) == NULL
) {
1269 "mount request: can't get client label from ucred");
1275 if (blequal(&admin_low
, clabel
)) {
1276 struct sockaddr
*ca
;
1279 ca
= (struct sockaddr
*)(void *)svc_getrpccaller(
1280 rqstp
->rq_xprt
)->buf
;
1286 * get trusted network template associated
1289 tp
= get_client_template(ca
);
1290 if (tp
== NULL
|| tp
->host_type
!= SUN_CIPSO
) {
1298 if ((slabel
= m_label_alloc(MAC_LABEL
)) == NULL
) {
1303 if (getlabel(rpath
, slabel
) != 0) {
1304 m_label_free(slabel
);
1309 if (!bldominates(clabel
, slabel
)) {
1310 m_label_free(slabel
);
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
) {
1334 error
= errno
== EINVAL
? EACCES
: errno
;
1335 syslog(LOG_DEBUG
, "mount request: getfh failed on %s: %m",
1340 if (version
== MOUNTVERS3
) {
1341 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_len
= len
;
1342 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_val
= fh
;
1344 bcopy(fh
, &fhs
.fhstatus_u
.fhs_fhandle
, NFS_FHSIZE
);
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
;
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
;
1369 mountres3
.mountres3_u
.mountinfo
.auth_flavors
.auth_flavors_val
=
1371 mountres3
.mountres3_u
.mountinfo
.auth_flavors
.auth_flavors_len
=
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
;
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
) {
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 */
1406 mntlist_new(host
, rpath
); /* add entry to mount list */
1410 svc_freeargs(transp
, xdr_dirpath
, (caddr_t
)&path
);
1415 netdir_free(clnames
, ND_HOSTSERVLIST
);
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.
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)) {
1447 * We have found fsid's for both paths.
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
);
1470 if (stat64(path2
, &st2
) < 0) {
1471 syslog(LOG_NOTICE
, "%s: %m", path2
);
1475 if (st1
.st_dev
== st2
.st_dev
)
1482 findentry(char *path
)
1485 struct sh_list
*shp
;
1486 register char *p1
, *p2
;
1490 (void) rw_rdlock(&sharetab_lock
);
1492 for (shp
= share_list
; shp
; shp
= shp
->shl_next
) {
1494 for (p1
= sh
->sh_path
, p2
= path
; *p1
== *p2
; p1
++, p2
++)
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
))
1522 sh
= shp
? sharedup(sh
) : NULL
;
1524 (void) rw_unlock(&sharetab_lock
);
1531 is_substring(char **mntp
, char **path
)
1533 char *p1
= *mntp
, *p2
= *path
;
1535 if (*p1
== '\0' && *p2
== '\0') /* exact match */
1537 else if (*p1
== '\0' && *p2
== '/')
1539 else if (*p1
== '\0' && *(p1
-1) == '/') {
1540 *path
= --p2
; /* we need the slash in p2 */
1542 } else if (*p2
== '\0') {
1545 if (*p1
== '\0') /* exact match */
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.
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
;
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
) {
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) {
1618 syslog(LOG_NOTICE
, "%s: %m", rpath
);
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
) {
1631 "%s/.: exceeds MAXPATHLEN %d",
1636 (void) strcpy(tmp_path
, rpath
);
1637 (void) strcat(tmp_path
, "/.");
1639 if (stat(tmp_path
, &r_stbuf
) < 0) {
1641 syslog(LOG_NOTICE
, "%s: %m", tmp_path
);
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.
1662 for (ml
= mntl
; ml
; ml
= ml
->mntl_next
) {
1663 if (strcmp(ml
->mntl_mnt
->mnt_fstype
, "lofs"))
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
)) {
1674 if ((strlen(ml
->mntl_mnt
->mnt_special
) + strlen(p2
)) >
1677 syslog(LOG_NOTICE
, "%s%s: exceeds %d",
1678 ml
->mntl_mnt
->mnt_special
, p2
,
1687 (void) strcpy(tmp_path
, ml
->mntl_mnt
->mnt_special
);
1688 (void) strcat(tmp_path
, p2
);
1691 retcode
= findentry(tmp_path
);
1696 assert(strlen(tmp_path
) > 0);
1697 (void) strcpy(rpath
, tmp_path
);
1701 fsfreemntlist(mntl
);
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 */
1729 struct nd_hostservlist
*clnames
;
1732 * If no access list - then it's unrestricted
1734 if (access_list
== NULL
|| *access_list
== '\0')
1737 assert(transp
!= NULL
|| (*pnb
!= NULL
&& *pclnames
!= NULL
));
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.
1756 * If the list name begins with an at
1757 * sign then do a network comparison.
1761 * Just get the netbuf, avoiding the costly name
1762 * lookup. This will suffice for access based
1763 * solely on addresses.
1767 * Don't grant access if client's address isn't
1770 if ((*pnb
= svc_getrpccaller(transp
)) == NULL
)
1774 if (netmatch(*pnb
, gr
+ 1))
1780 * We need to get the host name if we haven't gotten
1783 if (*pclnames
== NULL
) {
1784 DTRACE_PROBE(mountd
, name_by_addrlist
);
1786 * Do not grant access if we can't
1789 if (getclientsnames(transp
, pnb
, pclnames
) != 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
1809 if (*(gr
+ 1) == '\0') { /* single dot */
1810 if (strchr(host
, '.') == NULL
)
1813 off
= strlen(host
) - strlen(gr
);
1815 strcasecmp(host
+ off
, gr
) == 0) {
1822 * Just do a hostname match
1824 if (strcasecmp(gr
, host
) == 0) {
1825 return (response
); /* Matched a hostname */
1833 * We need to get the host name if we haven't gotten
1836 if (*pclnames
== NULL
) {
1837 DTRACE_PROBE(mountd
, name_by_netgroup
);
1839 * Do not grant access if we can't
1842 if (getclientsnames(transp
, pnb
, pclnames
) != 0)
1846 netgroup_match
= netgroup_check(*pclnames
, access_list
, nentries
);
1848 return (netgroup_match
);
1852 netmatch(struct netbuf
*nb
, char *name
)
1855 struct netent n
, *np
;
1862 * Check if it's an IPv4 addr
1864 if (nb
->len
!= sizeof (struct sockaddr_in
))
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
, '/');
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().
1885 for (i
= 0; i
< 4; i
++) {
1886 addr
|= atoi(p
) << ((3-i
) * 8);
1894 * Turn the netname into
1897 np
= getnetbyname_r(name
, &n
, buff
, sizeof (buff
));
1899 syslog(LOG_DEBUG
, "getnetbyname_r: %s: %m", name
);
1906 * If the mask is specified explicitly then
1907 * use that value, e.g.
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
1918 mask
= bits
? ~0 << ((sizeof (struct in_addr
) * NBBY
) - bits
)
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
;
1929 mask
= IN_CLASSE_NET
;
1932 return ((claddr
& mask
) == addr
);
1936 static char *optlist
[] = {
1943 #define OPT_SECURE 3
1947 #define OPT_WINDOW 5
1949 #define OPT_NOSUID 6
1961 map_flavor(char *str
)
1965 if (nfs_getseconfig_byname(str
, &sec
))
1968 return (sec
.sc_nfsnum
);
1972 * If the option string contains a "sec="
1973 * option, then use new option syntax.
1978 char *head
, *p
, *val
;
1980 if (!opts
|| *opts
== '\0')
1983 head
= strdup(opts
);
1985 syslog(LOG_ERR
, "opts: no memory");
1991 if (getsubopt(&p
, optlist
, &val
) == OPT_SEC
) {
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.
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
);
2026 syslog(LOG_ERR
, "getclientsflavors: no memory");
2030 flavors
[0] = AUTH_SYS
;
2035 switch (getsubopt(&p
, optlist
, &val
)) {
2037 flavors
[0] = AUTH_DES
;
2043 if (in_access_list(transp
, nb
, clnames
, val
))
2049 if (in_access_list(transp
, nb
, clnames
, val
))
2056 /* none takes precedence over everything else */
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.
2081 getclientsflavors_new(share_t
*sh
, SVCXPRT
*transp
, struct netbuf
**nb
,
2082 struct nd_hostservlist
**clnames
, int *flavors
)
2084 char *opts
, *p
, *val
;
2087 boolean_t access_ok
;
2089 boolean_t reject
= B_FALSE
;
2091 opts
= strdup(sh
->sh_opts
);
2093 syslog(LOG_ERR
, "getclientsflavors: no memory");
2098 perm
= count
= c
= 0;
2099 /* default access is rw */
2103 switch (getsubopt(&p
, optlist
, &val
)) {
2106 * Before a new sec=xxx option, check if we need
2107 * to move the c index back to the previous count.
2113 /* get all the sec=f1[:f2] flavors */
2114 while ((f
= strtok_r(val
, ":", &lasts
))
2116 flavors
[c
++] = map_flavor(f
);
2120 /* for a new sec=xxx option, default is rw access */
2126 if (in_access_list(transp
, nb
, clnames
, val
)) {
2130 access_ok
= B_FALSE
;
2135 if (in_access_list(transp
, nb
, clnames
, val
))
2136 reject
= B_TRUE
; /* none overides rw/ro */
2142 access_ok
= B_FALSE
;
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
));
2168 return (check_client_old(sh
, NULL
, &nb
, &clnames
, flavor
));
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
);
2185 syslog(LOG_ERR
, "check_client: no memory");
2193 switch (getsubopt(&p
, optlist
, &val
)) {
2202 if (in_access_list(transp
, nb
, clnames
, val
))
2209 if (in_access_list(transp
, nb
, clnames
, val
))
2215 * Check if the client is in
2216 * the root list. Only valid
2219 if (flavor
!= AUTH_SYS
)
2222 if (val
== NULL
|| *val
== '\0')
2225 if (in_access_list(transp
, nb
, clnames
, val
))
2226 perm
|= NFSAUTH_ROOT
;
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
))
2243 if (flavor
!= match
|| reject
)
2244 return (NFSAUTH_DENIED
);
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
;
2255 * The client matched a flavor entry that
2256 * has no explicit "rw" or "ro" determination.
2257 * Default it to "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
);
2278 perm
&= ~(NFSAUTH_RO
);
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.
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)
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
])
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".
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,
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
2337 check_client_new(share_t
*sh
, SVCXPRT
*transp
, struct netbuf
**nb
,
2338 struct nd_hostservlist
**clnames
, int flavor
)
2340 char *opts
, *p
, *val
;
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=' */
2350 opts
= strdup(sh
->sh_opts
);
2352 syslog(LOG_ERR
, "check_client: no memory");
2359 switch (getsubopt(&p
, optlist
, &val
)) {
2365 while ((f
= strtok_r(val
, ":", &lasts
))
2367 if (flavor
== map_flavor(f
)) {
2381 if (in_access_list(transp
, nb
, clnames
, val
))
2391 if (in_access_list(transp
, nb
, clnames
, val
))
2397 * Check if the client is in
2398 * the root list. Only valid
2401 if (flavor
!= AUTH_SYS
)
2407 if (val
== NULL
|| *val
== '\0')
2410 if (in_access_list(transp
, nb
, clnames
, val
))
2411 perm
|= NFSAUTH_ROOT
;
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
;
2428 * If no match then set the perm accordingly
2430 if (!match
|| perm
& NFSAUTH_DENIED
)
2431 return (NFSAUTH_DENIED
);
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
;
2444 perm
|= NFSAUTH_DENIED
;
2448 * The client matched a flavor entry that
2449 * has no explicit "rw" or "ro" determination.
2450 * Make sure it defaults to "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
);
2470 perm
&= ~(NFSAUTH_RO
);
2484 static timestruc_t last_sharetab_time
;
2485 timestruc_t prev_sharetab_time
;
2487 struct sh_list
*shp
, *shp_prev
;
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
);
2498 if (st
.st_mtim
.tv_sec
== last_sharetab_time
.tv_sec
&&
2499 st
.st_mtim
.tv_nsec
== last_sharetab_time
.tv_nsec
) {
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
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
);
2523 * Note that since the sharetab is now in memory
2524 * and a snapshot is taken, we no longer have to
2527 f
= fopen(SHARETAB
, "r");
2529 syslog(LOG_ERR
, "Cannot open %s: %m", SHARETAB
);
2530 (void) rw_unlock(&sharetab_lock
);
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 */
2543 while ((res
= getshare(f
, &sh
)) > 0) {
2545 if (strcmp(sh
->sh_fstype
, "nfs") != 0)
2548 shp
= malloc(sizeof (*shp
));
2551 if (share_list
== NULL
)
2554 /* LINTED not used before set */
2555 shp_prev
->shl_next
= shp
;
2557 shp
->shl_next
= NULL
;
2558 shp
->shl_sh
= sharedup(sh
);
2559 if (shp
->shl_sh
== NULL
)
2564 syslog(LOG_ERR
, "%s: invalid at line %d\n",
2567 if (stat(SHARETAB
, &st
) != 0) {
2568 syslog(LOG_ERR
, "Cannot stat %s: %m", SHARETAB
);
2570 (void) rw_unlock(&sharetab_lock
);
2574 last_sharetab_time
= st
.st_mtim
;
2576 (void) rw_unlock(&sharetab_lock
);
2582 syslog(LOG_ERR
, "check_sharetab: no memory");
2583 sh_free(share_list
);
2586 (void) rw_unlock(&sharetab_lock
);
2590 sh_free(struct sh_list
*shp
)
2592 register struct sh_list
*next
;
2595 sharefree(shp
->shl_sh
);
2596 next
= shp
->shl_next
;
2604 * Remove an entry from mounted list
2607 umount(struct svc_req
*rqstp
)
2609 char *host
, *path
, *remove_path
;
2610 char rpath
[MAXPATHLEN
];
2611 struct nd_hostservlist
*clnames
= NULL
;
2615 transp
= rqstp
->rq_xprt
;
2617 if (!svc_getargs(transp
, xdr_dirpath
, (caddr_t
)&path
)) {
2618 svcerr_decode(transp
);
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
);
2633 host
= clnames
->h_hostservs
[0].h_host
;
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
) {
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
2657 umountall(struct svc_req
*rqstp
)
2659 struct nd_hostservlist
*clnames
= NULL
;
2664 transp
= rqstp
->rq_xprt
;
2665 if (!svc_getargs(transp
, xdr_void
, NULL
)) {
2666 svcerr_decode(transp
);
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 */
2681 host
= clnames
->h_hostservs
[0].h_host
;
2684 * Remove all hosts entries from mount list
2686 mntlist_delete_all(host
);
2689 syslog(LOG_NOTICE
, "UNMOUNTALL: from %s", host
);
2691 netdir_free(clnames
, ND_HOSTSERVLIST
);
2695 exmalloc(size_t size
)
2699 if ((ret
= malloc(size
)) == NULL
) {
2700 syslog(LOG_ERR
, "Out of memory");
2710 if (signum
== SIGHUP
)
2715 static tsol_tpent_t
*
2716 get_client_template(struct sockaddr
*sock
)
2719 in6_addr_t v6client
;
2720 char v4_addr
[INET_ADDRSTRLEN
];
2721 char v6_addr
[INET6_ADDRSTRLEN
];
2725 switch (sock
->sa_family
) {
2727 v4client
= ((struct sockaddr_in
*)(void *)sock
)->
2729 if (inet_ntop(AF_INET
, &v4client
, v4_addr
, INET_ADDRSTRLEN
) ==
2732 rh
= tsol_getrhbyaddr(v4_addr
, sizeof (v4_addr
), AF_INET
);
2735 tp
= tsol_gettpbyname(rh
->rh_template
);
2740 v6client
= ((struct sockaddr_in6
*)(void *)sock
)->sin6_addr
;
2741 if (inet_ntop(AF_INET6
, &v6client
, v6_addr
, INET6_ADDRSTRLEN
) ==
2744 rh
= tsol_getrhbyaddr(v6_addr
, sizeof (v6_addr
), AF_INET6
);
2747 tp
= tsol_gettpbyname(rh
->rh_template
);