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.
24 * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
25 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
26 * Copyright 2022 RackTop Systems.
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
33 * Portions of this source code were derived from Berkeley 4.3 BSD
34 * under license from the Regents of the University of California.
38 #include <stdio_ext.h>
41 #include <sys/types.h>
44 #include <sys/param.h>
47 #include <netconfig.h>
51 #include <sys/errno.h>
52 #include <rpcsvc/mount.h>
53 #include <sys/pathconf.h>
54 #include <sys/systeminfo.h>
55 #include <sys/utsname.h>
57 #include <sys/resource.h>
62 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
68 #include <priv_utils.h>
70 #include <nfs/nfssys.h>
72 #include <nfs/nfs_sec.h>
73 #include <rpcsvc/daemon_utils.h>
75 #include "../../fslib.h"
76 #include <sharefs/share.h>
77 #include <sharefs/sharetab.h>
78 #include "../lib/sharetab.h"
80 #include <tsol/label.h>
81 #include <sys/tsol/label_macro.h>
86 #include <sys/nvpair.h>
92 #include <libinetutil.h>
93 #include <libsocket_priv.h>
95 extern int daemonize_init(void);
96 extern void daemonize_fini(int);
98 extern int _nfssys(int, void *);
100 struct sh_list
*share_list
;
102 rwlock_t sharetab_lock
; /* lock to protect the cached sharetab */
103 static mutex_t mnttab_lock
; /* prevent concurrent mnttab readers */
105 static mutex_t logging_queue_lock
;
106 static cond_t logging_queue_cv
;
108 static share_t
*find_lofsentry(char *, int *);
109 static int getclientsflavors_old(share_t
*, struct cln
*, int *);
110 static int getclientsflavors_new(share_t
*, struct cln
*, int *);
111 static int check_client_old(share_t
*, struct cln
*, int, uid_t
, gid_t
, uint_t
,
112 gid_t
*, uid_t
*, gid_t
*, uint_t
*, gid_t
**);
113 static int check_client_new(share_t
*, struct cln
*, int, uid_t
, gid_t
, uint_t
,
114 gid_t
*, uid_t
*, gid_t
*i
, uint_t
*, gid_t
**);
115 static void mnt(struct svc_req
*, SVCXPRT
*);
116 static void mnt_pathconf(struct svc_req
*);
117 static int mount(struct svc_req
*r
);
118 static void sh_free(struct sh_list
*);
119 static void umount(struct svc_req
*);
120 static void umountall(struct svc_req
*);
121 static int newopts(char *);
122 static tsol_tpent_t
*get_client_template(struct sockaddr
*);
126 static int rejecting
;
127 static int mount_vers_min
= MOUNTVERS
;
128 static int mount_vers_max
= MOUNTVERS3
;
129 static int mountd_port
= 0;
130 static boolean_t mountd_remote_dump
= B_FALSE
;
132 extern void nfscmd_func(void *, char *, size_t, door_desc_t
*, uint_t
);
134 thread_t nfsauth_thread
;
136 thread_t logging_thread
;
138 typedef struct logging_data
{
144 struct netbuf
*ld_nb
;
145 struct logging_data
*ld_next
;
148 static logging_data
*logging_head
= NULL
;
149 static logging_data
*logging_tail
= NULL
;
152 * Our copy of some system variables obtained using sysconf(3c)
154 static long ngroups_max
; /* _SC_NGROUPS_MAX */
155 static long pw_size
; /* _SC_GETPW_R_SIZE_MAX */
157 /* Cached address info for this host. */
158 static struct addrinfo
*host_ai
= NULL
;
161 nfsauth_svc(void *arg __unused
)
169 if ((doorfd
= door_create(nfsauth_func
, NULL
,
170 DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
)) == -1) {
171 syslog(LOG_ERR
, "Unable to create door: %m\n");
177 * Create a file system path for the door
179 if ((dfd
= open(MOUNTD_DOOR
, O_RDWR
|O_CREAT
|O_TRUNC
,
180 S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
)) == -1) {
181 syslog(LOG_ERR
, "Unable to open %s: %m\n", MOUNTD_DOOR
);
182 (void) close(doorfd
);
187 * Clean up any stale namespace associations
189 (void) fdetach(MOUNTD_DOOR
);
192 * Register in namespace to pass to the kernel to door_ki_open
194 if (fattach(doorfd
, MOUNTD_DOOR
) == -1) {
195 syslog(LOG_ERR
, "Unable to fattach door: %m\n");
197 (void) close(doorfd
);
204 * Must pass the doorfd down to the kernel.
207 (void) _nfssys(MOUNTD_ARGS
, &darg
);
210 * Wait for incoming calls
217 syslog(LOG_ERR
, gettext("Door server exited"));
222 * NFS command service thread code for setup and handling of the
223 * nfs_cmd requests for character set conversion and other future
233 if ((doorfd
= door_create(nfscmd_func
, NULL
,
234 DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
)) == -1) {
235 syslog(LOG_ERR
, "Unable to create cmd door: %m\n");
240 * Must pass the doorfd down to the kernel.
243 (void) _nfssys(NFSCMD_ARGS
, &darg
);
246 * Wait for incoming calls
253 syslog(LOG_ERR
, gettext("Cmd door server exited"));
258 free_logging_data(logging_data
*lq
)
264 if (lq
->ld_nb
!= NULL
) {
265 free(lq
->ld_nb
->buf
);
276 static logging_data
*
277 remove_head_of_queue(void)
282 * Pull it off the queue.
286 logging_head
= lq
->ld_next
;
291 if (logging_head
== NULL
) {
300 do_logging_queue(logging_data
*lq
)
308 if (lq
->ld_host
== NULL
) {
309 DTRACE_PROBE(mountd
, name_by_lazy
);
310 cln_init_lazy(&cln
, lq
->ld_netid
, lq
->ld_nb
);
311 host
= cln_gethost(&cln
);
315 audit_mountd_mount(host
, lq
->ld_path
, lq
->ld_status
); /* BSM */
317 /* add entry to mount list */
319 mntlist_new(host
, lq
->ld_rpath
);
321 if (lq
->ld_host
== NULL
)
324 free_logging_data(lq
);
327 (void) mutex_lock(&logging_queue_lock
);
328 lq
= remove_head_of_queue();
329 (void) mutex_unlock(&logging_queue_lock
);
332 DTRACE_PROBE1(mountd
, logging_cleared
, cleared
);
336 logging_svc(void *arg __unused
)
341 (void) mutex_lock(&logging_queue_lock
);
342 while (logging_head
== NULL
) {
343 (void) cond_wait(&logging_queue_cv
,
344 &logging_queue_lock
);
347 lq
= remove_head_of_queue();
348 (void) mutex_unlock(&logging_queue_lock
);
350 do_logging_queue(lq
);
354 syslog(LOG_ERR
, gettext("Logging server exited"));
359 * This function is called for each configured network type to
360 * bind and register our RPC service programs.
362 * On TCP or UDP, we may want to bind MOUNTPROG on a specific port
363 * (when mountd_port is specified) in which case we'll use the
364 * variant of svc_tp_create() that lets us pass a bind address.
367 md_svc_tp_create(struct netconfig
*nconf
)
370 struct nd_hostserv hs
;
371 struct nd_addrlist
*al
= NULL
;
372 SVCXPRT
*xprt
= NULL
;
375 vers
= mount_vers_max
;
378 * If mountd_port is set and this is an inet transport,
379 * bind this service on the specified port. The TLI way
380 * to create such a bind address is netdir_getbyname()
381 * with the special "host" HOST_SELF_BIND. This builds
382 * an all-zeros IP address with the specified port.
384 if (mountd_port
!= 0 &&
385 (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0 ||
386 strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0)) {
389 (void) snprintf(port_str
, sizeof (port_str
), "%u",
390 (unsigned short)mountd_port
);
392 hs
.h_host
= HOST_SELF_BIND
;
393 hs
.h_serv
= port_str
;
394 err
= netdir_getbyname((struct netconfig
*)nconf
, &hs
, &al
);
395 if (err
== 0 && al
!= NULL
) {
396 xprt
= svc_tp_create_addr(mnt
, MOUNTPROG
, vers
,
398 netdir_free(al
, ND_ADDRLIST
);
401 syslog(LOG_ERR
, "mountd: unable to create "
402 "(MOUNTD,%d) on transport %s (port %d)",
403 vers
, nconf
->nc_netid
, mountd_port
);
405 /* fall-back to default bind */
409 * Had mountd_port=0, or non-inet transport,
410 * or the bind to a specific port failed.
413 xprt
= svc_tp_create(mnt
, MOUNTPROG
, vers
, nconf
);
416 syslog(LOG_ERR
, "mountd: unable to create "
417 "(MOUNTD,%d) on transport %s",
418 vers
, nconf
->nc_netid
);
423 * Register additional versions on this transport.
425 while (--vers
>= mount_vers_min
) {
426 if (!svc_reg(xprt
, MOUNTPROG
, vers
, mnt
, nconf
)) {
427 (void) syslog(LOG_ERR
, "mountd: "
428 "failed to register vers %d on %s",
429 vers
, nconf
->nc_netid
);
435 main(int argc
, char *argv
[])
439 int rpc_svc_fdunlim
= 1;
440 int rpc_svc_mode
= RPC_SVC_MT_AUTO
;
441 int maxrecsz
= RPC_MAXDATASIZE
;
442 bool_t exclbind
= TRUE
;
444 long thr_flags
= (THR_NEW_LWP
|THR_DAEMON
);
448 int listen_backlog
= 0;
451 struct netconfig
*nconf
;
458 * Mountd requires uid 0 for:
459 * /etc/rmtab updates (we could chown it to daemon)
460 * /etc/dfs/dfstab reading (it wants to lock out share which
461 * doesn't do any locking before first truncate;
462 * NFS share does; should use fcntl locking instead)
466 * file dac search (so it can stat all files)
467 * Optional privileges:
470 can_do_mlp
= priv_ineffect(PRIV_NET_BINDMLP
);
471 if (__init_daemon_priv(PU_RESETGROUPS
|PU_CLEARLIMITSET
, -1, -1,
472 PRIV_SYS_NFS
, PRIV_PROC_AUDIT
, PRIV_FILE_DAC_SEARCH
,
474 can_do_mlp
? PRIV_NET_BINDMLP
: NULL
, NULL
) == -1) {
475 (void) fprintf(stderr
,
476 "%s: must be run with sufficient privileges\n",
481 if (getrlimit(RLIMIT_NOFILE
, &rl
) != 0) {
482 syslog(LOG_ERR
, "getrlimit failed");
484 rl
.rlim_cur
= rl
.rlim_max
;
485 if (setrlimit(RLIMIT_NOFILE
, &rl
) != 0)
486 syslog(LOG_ERR
, "setrlimit failed");
489 (void) enable_extended_FILE_stdio(-1, -1);
491 /* Upgrade SMF settings, if necessary. */
492 nfs_config_upgrade(NFSD
);
494 ret
= nfs_smf_get_iprop("mountd_max_threads", &max_threads
,
495 DEFAULT_INSTANCE
, SCF_TYPE_INTEGER
, NFSD
);
497 syslog(LOG_ERR
, "Reading of mountd_max_threads from SMF "
498 "failed, using default value");
501 ret
= nfs_smf_get_iprop("mountd_port", &mountd_port
,
502 DEFAULT_INSTANCE
, SCF_TYPE_INTEGER
, NFSD
);
504 syslog(LOG_ERR
, "Reading of mountd_port from SMF "
505 "failed, using default value");
508 while ((c
= getopt(argc
, argv
, "dvrm:p:")) != EOF
) {
520 tmp
= strtonum(optarg
, 1, INT_MAX
, &errstr
);
521 if (errstr
!= NULL
) {
522 (void) fprintf(stderr
, "%s: invalid "
523 "max_threads option: %s, using defaults\n",
530 tmp
= strtonum(optarg
, 1, UINT16_MAX
, &errstr
);
531 if (errstr
!= NULL
) {
532 (void) fprintf(stderr
, "%s: invalid port "
533 "number: %s\n", argv
[0], errstr
);
539 fprintf(stderr
, "usage: mountd [-v] [-r]\n");
545 * One might be tempted to use the NFS configuration values
546 * server_versmin, server_versmax to constrain the range of
547 * mountd versions supported here. However, older clients
548 * use mountd V1 for showmount, so just leave all mountd
549 * versions enabled here. (mount_vers_min, mount_vers_max)
552 ret
= nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog
,
553 DEFAULT_INSTANCE
, SCF_TYPE_INTEGER
, NFSD
);
555 syslog(LOG_ERR
, "Reading of mountd_listen_backlog from SMF "
556 "failed, using default value");
559 bufsz
= sizeof (defval
);
560 ret
= nfs_smf_get_prop("mountd_remote_dump", defval
, DEFAULT_INSTANCE
,
561 SCF_TYPE_BOOLEAN
, NFSD
, &bufsz
);
563 mountd_remote_dump
= string_to_boolean(defval
);
565 if (!mountd_remote_dump
) {
566 /* Cache host address list */
567 if (gethostname(hostbuf
, sizeof (hostbuf
)) < 0) {
568 syslog(LOG_ERR
, "gethostname() failed");
571 if (getaddrinfo(hostbuf
, NULL
, NULL
, &host_ai
) != 0) {
572 syslog(LOG_ERR
, "getaddrinfo() failed");
578 * Sanity check versions,
579 * even though we may get versions > MOUNTVERS3, we still need
580 * to start nfsauth service, so continue on regardless of values.
582 if (mount_vers_max
> MOUNTVERS3
)
583 mount_vers_max
= MOUNTVERS3
;
584 if (mount_vers_min
> mount_vers_max
) {
585 fprintf(stderr
, "server_versmin > server_versmax\n");
586 mount_vers_max
= mount_vers_min
;
588 (void) setlocale(LC_ALL
, "");
589 (void) rwlock_init(&sharetab_lock
, USYNC_THREAD
, NULL
);
590 (void) mutex_init(&mnttab_lock
, USYNC_THREAD
, NULL
);
591 (void) mutex_init(&logging_queue_lock
, USYNC_THREAD
, NULL
);
592 (void) cond_init(&logging_queue_cv
, USYNC_THREAD
, NULL
);
596 #if !defined(TEXT_DOMAIN)
597 #define TEXT_DOMAIN "SYS_TEST"
599 (void) textdomain(TEXT_DOMAIN
);
601 /* Don't drop core if the NFS module isn't loaded. */
602 (void) signal(SIGSYS
, SIG_IGN
);
605 pipe_fd
= daemonize_init();
608 * If we coredump it'll be in /core
611 fprintf(stderr
, "chdir /: %s\n", strerror(errno
));
614 openlog("mountd", LOG_PID
, LOG_DAEMON
);
617 * establish our lock on the lock file and write our pid to it.
618 * exit if some other process holds the lock, or if there's any
619 * error in writing/locking the file.
621 pid
= _enter_daemon_lock(MOUNTD
);
626 fprintf(stderr
, "error locking for %s: %s\n", MOUNTD
,
630 /* daemon was already running */
634 audit_mountd_setup(); /* BSM */
637 * Get required system variables
639 if ((ngroups_max
= sysconf(_SC_NGROUPS_MAX
)) == -1) {
640 syslog(LOG_ERR
, "Unable to get _SC_NGROUPS_MAX");
643 if ((pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
)) == -1) {
644 syslog(LOG_ERR
, "Unable to get _SC_GETPW_R_SIZE_MAX");
649 * Set number of file descriptors to unlimited
651 if (!rpc_control(RPC_SVC_USE_POLLFD
, &rpc_svc_fdunlim
)) {
652 syslog(LOG_INFO
, "unable to set number of FDs to unlimited");
656 * Tell RPC that we want automatic thread mode.
657 * A new thread will be spawned for each request.
659 if (!rpc_control(RPC_SVC_MTMODE_SET
, &rpc_svc_mode
)) {
660 fprintf(stderr
, "unable to set automatic MT mode\n");
665 * Enable non-blocking mode and maximum record size checks for
666 * connection oriented transports.
668 if (!rpc_control(RPC_SVC_CONNMAXREC_SET
, &maxrecsz
)) {
669 fprintf(stderr
, "unable to set RPC max record size\n");
673 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
674 * from being hijacked by a bind to a more specific addr.
676 if (!rpc_control(__RPC_SVC_EXCLBIND_SET
, &exclbind
)) {
677 fprintf(stderr
, "warning: unable to set udp/tcp EXCLBIND\n");
681 * Set the maximum number of outstanding connection
682 * indications (listen backlog) to the value specified.
684 if (listen_backlog
> 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET
,
686 fprintf(stderr
, "unable to set listen backlog\n");
691 * If max_threads was specified, then set the
692 * maximum number of threads to the value specified.
694 if (max_threads
> 0 && !rpc_control(RPC_SVC_THRMAX_SET
, &max_threads
)) {
695 fprintf(stderr
, "unable to set max_threads\n");
699 if (mountd_port
< 0 || mountd_port
> UINT16_MAX
) {
700 fprintf(stderr
, "unable to use specified port\n");
705 * Make sure to unregister any previous versions in case the
706 * user is reconfiguring the server in interesting ways.
708 svc_unreg(MOUNTPROG
, MOUNTVERS
);
709 svc_unreg(MOUNTPROG
, MOUNTVERS_POSIX
);
710 svc_unreg(MOUNTPROG
, MOUNTVERS3
);
713 * Create the nfsauth thread with same signal disposition
714 * as the main thread. We need to create a separate thread
715 * since mountd() will be both an RPC server (for remote
716 * traffic) _and_ a doors server (for kernel upcalls).
718 if (thr_create(NULL
, 0, nfsauth_svc
, 0, thr_flags
, &nfsauth_thread
)) {
720 gettext("Failed to create NFSAUTH svc thread\n"));
725 * Create the cmd service thread with same signal disposition
726 * as the main thread. We need to create a separate thread
727 * since mountd() will be both an RPC server (for remote
728 * traffic) _and_ a doors server (for kernel upcalls).
730 if (thr_create(NULL
, 0, cmd_svc
, 0, thr_flags
, &cmd_thread
)) {
731 syslog(LOG_ERR
, gettext("Failed to create CMD svc thread"));
736 * Create an additional thread to service the rmtab and
737 * audit_mountd_mount logging for mount requests. Use the same
738 * signal disposition as the main thread. We create
739 * a separate thread to allow the mount request threads to
740 * clear as soon as possible.
742 if (thr_create(NULL
, 0, logging_svc
, 0, thr_flags
, &logging_thread
)) {
743 syslog(LOG_ERR
, gettext("Failed to create LOGGING svc thread"));
748 * Enumerate network transports and create service listeners
749 * as appropriate for each.
751 if ((nc
= setnetconfig()) == NULL
) {
752 syslog(LOG_ERR
, "setnetconfig failed: %m");
755 while ((nconf
= getnetconfig(nc
)) != NULL
) {
757 * Skip things like tpi_raw, invisible...
759 if ((nconf
->nc_flag
& NC_VISIBLE
) == 0)
761 if (nconf
->nc_semantics
!= NC_TPI_CLTS
&&
762 nconf
->nc_semantics
!= NC_TPI_COTS
&&
763 nconf
->nc_semantics
!= NC_TPI_COTS_ORD
)
766 md_svc_tp_create(nconf
);
768 (void) endnetconfig(nc
);
775 daemonize_fini(pipe_fd
);
777 /* Get rid of the most dangerous basic privileges. */
778 __fini_daemon_priv(PRIV_PROC_EXEC
, PRIV_PROC_INFO
, PRIV_PROC_SESSION
,
782 syslog(LOG_ERR
, "Error: svc_run shouldn't have returned");
790 * copied from usr/src/uts/common/klm/nlm_impl.c
793 caller_is_local(SVCXPRT
*transp
)
797 struct netbuf
*rtaddr
;
798 struct sockaddr_storage addr
;
801 netid
= transp
->xp_netid
;
802 rtaddr
= svc_getrpccaller(transp
);
807 if (strcmp(netid
, "ticlts") == 0 ||
808 strcmp(netid
, "ticotsord") == 0)
811 if (strcmp(netid
, "tcp") == 0 || strcmp(netid
, "udp") == 0) {
812 struct sockaddr_in
*sin
= (void *)rtaddr
->buf
;
814 if (sin
->sin_addr
.s_addr
== htonl(INADDR_LOOPBACK
))
817 memmove(&addr
, sin
, sizeof (*sin
));
819 if (strcmp(netid
, "tcp6") == 0 || strcmp(netid
, "udp6") == 0) {
820 struct sockaddr_in6
*sin6
= (void *)rtaddr
->buf
;
822 if (IN6_IS_ADDR_LOOPBACK(&sin6
->sin6_addr
))
825 memmove(&addr
, sin6
, sizeof (*sin6
));
828 for (a
= host_ai
; a
!= NULL
; a
= a
->ai_next
) {
829 if (sockaddrcmp(&addr
,
830 (struct sockaddr_storage
*)a
->ai_addr
)) {
839 * Server procedure switch routine
842 mnt(struct svc_req
*rqstp
, SVCXPRT
*transp
)
844 switch (rqstp
->rq_proc
) {
847 if (!svc_sendreply(transp
, xdr_void
, (char *)0))
848 log_cant_reply(transp
);
856 if (mountd_remote_dump
|| caller_is_local(transp
))
857 mntlist_send(transp
);
859 svcerr_noproc(transp
);
866 case MOUNTPROC_UMNTALL
:
870 case MOUNTPROC_EXPORT
:
871 case MOUNTPROC_EXPORTALL
:
875 case MOUNTPROC_PATHCONF
:
876 if (rqstp
->rq_vers
== MOUNTVERS_POSIX
)
879 svcerr_noproc(transp
);
883 svcerr_noproc(transp
);
889 log_cant_reply_cln(struct cln
*cln
)
894 saverrno
= errno
; /* save error code */
896 host
= cln_gethost(cln
);
902 syslog(LOG_ERR
, "couldn't send reply to %s", host
);
904 syslog(LOG_ERR
, "couldn't send reply to %s: %m", host
);
908 log_cant_reply(SVCXPRT
*transp
)
913 saverrno
= errno
; /* save error code */
914 cln_init(&cln
, transp
);
917 log_cant_reply_cln(&cln
);
923 * Answer pathconf questions for the mount point fs
926 mnt_pathconf(struct svc_req
*rqstp
)
930 char *path
, rpath
[MAXPATHLEN
];
933 transp
= rqstp
->rq_xprt
;
935 (void) memset((caddr_t
)&p
, 0, sizeof (p
));
937 if (!svc_getargs(transp
, xdr_dirpath
, (caddr_t
)&path
)) {
938 svcerr_decode(transp
);
941 if (lstat(path
, &st
) < 0) {
942 _PC_SET(_PC_ERROR
, p
.pc_mask
);
946 * Get a path without symbolic links.
948 if (realpath(path
, rpath
) == NULL
) {
950 "mount request: realpath failed on %s: %m",
952 _PC_SET(_PC_ERROR
, p
.pc_mask
);
955 (void) memset((caddr_t
)&p
, 0, sizeof (p
));
957 * can't ask about devices over NFS
959 _PC_SET(_PC_MAX_CANON
, p
.pc_mask
);
960 _PC_SET(_PC_MAX_INPUT
, p
.pc_mask
);
961 _PC_SET(_PC_PIPE_BUF
, p
.pc_mask
);
962 _PC_SET(_PC_VDISABLE
, p
.pc_mask
);
965 p
.pc_link_max
= pathconf(rpath
, _PC_LINK_MAX
);
967 _PC_SET(_PC_LINK_MAX
, p
.pc_mask
);
968 p
.pc_name_max
= pathconf(rpath
, _PC_NAME_MAX
);
970 _PC_SET(_PC_NAME_MAX
, p
.pc_mask
);
971 p
.pc_path_max
= pathconf(rpath
, _PC_PATH_MAX
);
973 _PC_SET(_PC_PATH_MAX
, p
.pc_mask
);
974 if (pathconf(rpath
, _PC_NO_TRUNC
) == 1)
975 _PC_SET(_PC_NO_TRUNC
, p
.pc_mask
);
976 if (pathconf(rpath
, _PC_CHOWN_RESTRICTED
) == 1)
977 _PC_SET(_PC_CHOWN_RESTRICTED
, p
.pc_mask
);
981 if (!svc_sendreply(transp
, xdr_ppathcnf
, (char *)&p
))
982 log_cant_reply(transp
);
984 (void) svc_freeargs(transp
, xdr_dirpath
, (caddr_t
)&path
);
988 * If the rootmount (export) option is specified, the all mount requests for
989 * subdirectories return EACCES.
992 checkrootmount(share_t
*sh
, char *rpath
)
996 if ((val
= getshareopt(sh
->sh_opts
, SHOPT_NOSUB
)) != NULL
) {
998 if (strcmp(sh
->sh_path
, rpath
) != 0)
1006 #define MAX_FLAVORS 128
1009 * Return only EACCES if client does not have access
1010 * to this directory.
1011 * "If the server exports only /a/b, an attempt to
1012 * mount a/b/c will fail with ENOENT if the directory
1013 * does not exist"... However, if the client
1014 * does not have access to /a/b, an attacker can
1015 * determine whether the directory exists.
1016 * This routine checks either existence of the file or
1017 * existence of the file name entry in the mount table.
1018 * If the file exists and there is no file name entry,
1019 * the error returned should be EACCES.
1020 * If the file does not exist, it must be determined
1021 * whether the client has access to a parent
1022 * directory. If the client has access to a parent
1023 * directory, the error returned should be ENOENT,
1027 mount_enoent_error(struct cln
*cln
, char *path
, char *rpath
, int *flavor_list
)
1029 char *checkpath
, *dp
;
1031 int realpath_error
= ENOENT
, reply_error
= EACCES
, lofs_tried
= 0;
1034 checkpath
= strdup(path
);
1035 if (checkpath
== NULL
) {
1036 syslog(LOG_ERR
, "mount_enoent: no memory");
1047 if ((sh
= findentry(rpath
)) == NULL
&&
1048 (sh
= find_lofsentry(rpath
, &lofs_tried
)) == NULL
) {
1050 * There is no file name entry.
1051 * If the file (with symbolic links resolved) exists,
1052 * the error returned should be EACCES.
1054 if (realpath_error
== 0)
1056 } else if (checkrootmount(sh
, rpath
) == 0) {
1058 * This is a "nosub" only export, in which case,
1059 * mounting subdirectories isn't allowed.
1060 * If the file (with symbolic links resolved) exists,
1061 * the error returned should be EACCES.
1063 if (realpath_error
== 0)
1067 * Check permissions in mount table.
1069 if (newopts(sh
->sh_opts
))
1070 flavor_count
= getclientsflavors_new(sh
, cln
,
1073 flavor_count
= getclientsflavors_old(sh
, cln
,
1075 if (flavor_count
!= 0) {
1077 * Found entry in table and
1078 * client has correct permissions.
1080 reply_error
= ENOENT
;
1086 * Check all parent directories.
1088 dp
= strrchr(checkpath
, '/');
1092 if (strlen(checkpath
) == 0)
1095 * Get the real path (no symbolic links in it)
1097 if (realpath(checkpath
, rpath
) == NULL
) {
1098 if (errno
!= ENOENT
)
1108 return (reply_error
);
1112 * We need to inform the caller whether or not we were
1113 * able to add a node to the queue. If we are not, then
1114 * it is up to the caller to go ahead and log the data.
1117 enqueue_logging_data(char *host
, SVCXPRT
*transp
, char *path
,
1118 char *rpath
, int status
, int error
)
1123 lq
= (logging_data
*)calloc(1, sizeof (logging_data
));
1128 * We might not yet have the host...
1131 DTRACE_PROBE1(mountd
, log_host
, host
);
1132 lq
->ld_host
= strdup(host
);
1133 if (lq
->ld_host
== NULL
)
1136 DTRACE_PROBE(mountd
, log_no_host
);
1138 lq
->ld_netid
= strdup(transp
->xp_netid
);
1139 if (lq
->ld_netid
== NULL
)
1142 lq
->ld_nb
= calloc(1, sizeof (struct netbuf
));
1143 if (lq
->ld_nb
== NULL
)
1146 nb
= svc_getrpccaller(transp
);
1148 DTRACE_PROBE(mountd
, e__nb__enqueue
);
1152 DTRACE_PROBE(mountd
, nb_set_enqueue
);
1154 lq
->ld_nb
->maxlen
= nb
->maxlen
;
1155 lq
->ld_nb
->len
= nb
->len
;
1157 lq
->ld_nb
->buf
= malloc(lq
->ld_nb
->len
);
1158 if (lq
->ld_nb
->buf
== NULL
)
1161 bcopy(nb
->buf
, lq
->ld_nb
->buf
, lq
->ld_nb
->len
);
1164 lq
->ld_path
= strdup(path
);
1165 if (lq
->ld_path
== NULL
)
1169 lq
->ld_rpath
= strdup(rpath
);
1170 if (lq
->ld_rpath
== NULL
)
1174 lq
->ld_status
= status
;
1177 * Add to the tail of the logging queue.
1179 (void) mutex_lock(&logging_queue_lock
);
1180 if (logging_tail
== NULL
) {
1181 logging_tail
= logging_head
= lq
;
1183 logging_tail
->ld_next
= lq
;
1186 (void) cond_signal(&logging_queue_cv
);
1187 (void) mutex_unlock(&logging_queue_lock
);
1193 free_logging_data(lq
);
1199 #define CLN_CLNAMES (1 << 0)
1200 #define CLN_HOST (1 << 1)
1203 cln_init_common(struct cln
*cln
, SVCXPRT
*transp
, char *netid
,
1204 struct netbuf
*nbuf
)
1206 if ((cln
->transp
= transp
) != NULL
) {
1207 assert(netid
== NULL
&& nbuf
== NULL
);
1208 cln
->netid
= transp
->xp_netid
;
1209 cln
->nbuf
= svc_getrpccaller(transp
);
1216 cln
->clnames
= NULL
;
1223 cln_init(struct cln
*cln
, SVCXPRT
*transp
)
1225 cln_init_common(cln
, transp
, NULL
, NULL
);
1229 cln_init_lazy(struct cln
*cln
, char *netid
, struct netbuf
*nbuf
)
1231 cln_init_common(cln
, NULL
, netid
, nbuf
);
1235 cln_fini(struct cln
*cln
)
1237 if (cln
->nconf
!= NULL
)
1238 freenetconfigent(cln
->nconf
);
1240 if (cln
->clnames
!= NULL
)
1241 netdir_free(cln
->clnames
, ND_HOSTSERVLIST
);
1247 cln_getnbuf(struct cln
*cln
)
1252 struct nd_hostservlist
*
1253 cln_getclientsnames(struct cln
*cln
)
1255 if ((cln
->flags
& CLN_CLNAMES
) == 0) {
1257 * nconf is not needed if we do not have nbuf (see
1258 * cln_gethost() too), so we check for nbuf and in a case it is
1259 * NULL we do not try to get nconf.
1261 if (cln
->netid
!= NULL
&& cln
->nbuf
!= NULL
) {
1262 cln
->nconf
= getnetconfigent(cln
->netid
);
1263 if (cln
->nconf
== NULL
)
1264 syslog(LOG_ERR
, "%s: getnetconfigent failed",
1268 if (cln
->nconf
!= NULL
&& cln
->nbuf
!= NULL
)
1269 (void) __netdir_getbyaddr_nosrv(cln
->nconf
,
1270 &cln
->clnames
, cln
->nbuf
);
1272 cln
->flags
|= CLN_CLNAMES
;
1275 return (cln
->clnames
);
1279 * Return B_TRUE if the host is already available at no cost
1282 cln_havehost(struct cln
*cln
)
1284 return ((cln
->flags
& (CLN_CLNAMES
| CLN_HOST
)) != 0);
1288 cln_gethost(struct cln
*cln
)
1290 if (cln_getclientsnames(cln
) != NULL
)
1291 return (cln
->clnames
->h_hostservs
[0].h_host
);
1293 if ((cln
->flags
& CLN_HOST
) == 0) {
1294 if (cln
->nconf
== NULL
|| cln
->nbuf
== NULL
) {
1295 cln
->host
= strdup("(anon)");
1297 char host
[MAXIPADDRLEN
];
1299 if (strcmp(cln
->nconf
->nc_protofmly
, NC_INET
) == 0) {
1300 struct sockaddr_in
*sa
;
1302 /* LINTED pointer alignment */
1303 sa
= (struct sockaddr_in
*)(cln
->nbuf
->buf
);
1304 (void) inet_ntoa_r(sa
->sin_addr
, host
);
1306 cln
->host
= strdup(host
);
1307 } else if (strcmp(cln
->nconf
->nc_protofmly
,
1309 struct sockaddr_in6
*sa
;
1311 /* LINTED pointer alignment */
1312 sa
= (struct sockaddr_in6
*)(cln
->nbuf
->buf
);
1313 (void) inet_ntop(AF_INET6
,
1314 sa
->sin6_addr
.s6_addr
,
1315 host
, INET6_ADDRSTRLEN
);
1317 cln
->host
= strdup(host
);
1319 syslog(LOG_ERR
, gettext("Client's address is "
1320 "neither IPv4 nor IPv6"));
1322 cln
->host
= strdup("(anon)");
1326 cln
->flags
|= CLN_HOST
;
1333 * Check mount requests, add to mounted list if ok
1336 mount(struct svc_req
*rqstp
)
1340 struct fhstatus fhs
;
1341 struct mountres3 mountres3
;
1344 char *path
, rpath
[MAXPATHLEN
];
1348 int error
= 0, lofs_tried
= 0, enqueued
;
1349 int flavor_list
[MAX_FLAVORS
];
1355 transp
= rqstp
->rq_xprt
;
1356 version
= rqstp
->rq_vers
;
1359 if (!svc_getargs(transp
, xdr_dirpath
, (caddr_t
)&path
)) {
1360 svcerr_decode(transp
);
1364 cln_init(&cln
, transp
);
1367 * Put off getting the name for the client until we
1368 * need it. This is a performance gain. If we are logging,
1369 * then we don't care about performance and might as well
1370 * get the host name now in case we need to spit out an
1374 DTRACE_PROBE(mountd
, name_by_verbose
);
1375 if ((host
= cln_gethost(&cln
)) == NULL
) {
1377 * We failed to get a name for the client, even
1378 * 'anon', probably because we ran out of memory.
1379 * In this situation it doesn't make sense to
1380 * allow the mount to succeed.
1388 * If the version being used is less than the minimum version,
1389 * the filehandle translation should not be provided to the
1392 if (rejecting
|| version
< mount_vers_min
) {
1394 syslog(LOG_NOTICE
, "Rejected mount: %s for %s",
1401 * Trusted Extension doesn't support nfsv2. nfsv2 client
1402 * uses MOUNT protocol v1 and v2. To prevent circumventing
1403 * TX label policy via using nfsv2 client, reject a mount
1404 * request with version less than 3 and log an error.
1406 if (is_system_labeled()) {
1410 "Rejected mount: TX doesn't support NFSv2");
1417 * Get the real path (no symbolic links in it)
1419 if (realpath(path
, rpath
) == NULL
) {
1423 "mount request: realpath: %s: %m", path
);
1424 if (error
== ENOENT
)
1425 error
= mount_enoent_error(&cln
, path
, rpath
,
1430 if ((sh
= findentry(rpath
)) == NULL
&&
1431 (sh
= find_lofsentry(rpath
, &lofs_tried
)) == NULL
) {
1437 * Check if this is a "nosub" only export, in which case, mounting
1438 * subdirectories isn't allowed. Bug 1184573.
1440 if (checkrootmount(sh
, rpath
) == 0) {
1445 if (newopts(sh
->sh_opts
))
1446 flavor_count
= getclientsflavors_new(sh
, &cln
, flavor_list
);
1448 flavor_count
= getclientsflavors_old(sh
, &cln
, flavor_list
);
1450 if (flavor_count
== 0) {
1456 * Check MAC policy here. The server side policy should be
1457 * consistent with client side mount policy, i.e.
1458 * - we disallow an admin_low unlabeled client to mount
1459 * - we disallow mount from a lower labeled client.
1461 if (is_system_labeled()) {
1462 m_label_t
*clabel
= NULL
;
1463 m_label_t
*slabel
= NULL
;
1464 m_label_t admin_low
;
1466 if (svc_getcallerucred(rqstp
->rq_xprt
, &uc
) != 0) {
1468 "mount request: Failed to get caller's ucred : %m");
1472 if ((clabel
= ucred_getlabel(uc
)) == NULL
) {
1474 "mount request: can't get client label from ucred");
1480 if (blequal(&admin_low
, clabel
)) {
1481 struct sockaddr
*ca
;
1484 ca
= (struct sockaddr
*)(void *)svc_getrpccaller(
1485 rqstp
->rq_xprt
)->buf
;
1491 * get trusted network template associated
1494 tp
= get_client_template(ca
);
1495 if (tp
== NULL
|| tp
->host_type
!= SUN_CIPSO
) {
1503 if ((slabel
= m_label_alloc(MAC_LABEL
)) == NULL
) {
1508 if (getlabel(rpath
, slabel
) != 0) {
1509 m_label_free(slabel
);
1514 if (!bldominates(clabel
, slabel
)) {
1515 m_label_free(slabel
);
1519 m_label_free(slabel
);
1524 * Now get the filehandle.
1526 * NFS V2 clients get a 32 byte filehandle.
1527 * NFS V3 clients get a 32 or 64 byte filehandle, depending on
1528 * the embedded FIDs.
1530 vers
= (version
== MOUNTVERS3
) ? NFS_V3
: NFS_VERSION
;
1532 /* LINTED pointer alignment */
1533 while (nfs_getfh(rpath
, vers
, &len
, fh
) < 0) {
1534 if (errno
== EINVAL
&&
1535 (sh
= find_lofsentry(rpath
, &lofs_tried
)) != NULL
) {
1539 error
= errno
== EINVAL
? EACCES
: errno
;
1540 syslog(LOG_DEBUG
, "mount request: getfh failed on %s: %m",
1545 if (version
== MOUNTVERS3
) {
1546 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_len
= len
;
1547 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_val
= fh
;
1549 bcopy(fh
, &fhs
.fhstatus_u
.fhs_fhandle
, NFS_FHSIZE
);
1558 case MOUNTVERS_POSIX
:
1559 if (error
== EINVAL
)
1560 fhs
.fhs_status
= NFSERR_ACCES
;
1561 else if (error
== EREMOTE
)
1562 fhs
.fhs_status
= NFSERR_REMOTE
;
1564 fhs
.fhs_status
= error
;
1566 if (!svc_sendreply(transp
, xdr_fhstatus
, (char *)&fhs
))
1567 log_cant_reply_cln(&cln
);
1569 audit_status
= fhs
.fhs_status
;
1574 mountres3
.mountres3_u
.mountinfo
.auth_flavors
.auth_flavors_val
=
1576 mountres3
.mountres3_u
.mountinfo
.auth_flavors
.auth_flavors_len
=
1579 } else if (error
== ENAMETOOLONG
)
1580 error
= MNT3ERR_NAMETOOLONG
;
1582 mountres3
.fhs_status
= error
;
1583 if (!svc_sendreply(transp
, xdr_mountres3
, (char *)&mountres3
))
1584 log_cant_reply_cln(&cln
);
1586 audit_status
= mountres3
.fhs_status
;
1590 if (cln_havehost(&cln
))
1591 host
= cln_gethost(&cln
);
1594 syslog(LOG_NOTICE
, "MOUNT: %s %s %s",
1595 (host
== NULL
) ? "unknown host" : host
,
1596 error
? "denied" : "mounted", path
);
1599 * If we can not create a queue entry, go ahead and do it
1600 * in the context of this thread.
1602 enqueued
= enqueue_logging_data(host
, transp
, path
, rpath
,
1603 audit_status
, error
);
1604 if (enqueued
== FALSE
) {
1606 DTRACE_PROBE(mountd
, name_by_in_thread
);
1607 host
= cln_gethost(&cln
);
1610 DTRACE_PROBE(mountd
, logged_in_thread
);
1611 audit_mountd_mount(host
, path
, audit_status
); /* BSM */
1613 mntlist_new(host
, rpath
); /* add entry to mount list */
1617 (void) svc_freeargs(transp
, xdr_dirpath
, (caddr_t
)&path
);
1628 * Determine whether two paths are within the same file system.
1629 * Returns nonzero (true) if paths are the same, zero (false) if
1630 * they are different. If an error occurs, return false.
1632 * Use the actual FSID if it's available (via getattrat()); otherwise,
1633 * fall back on st_dev.
1635 * With ZFS snapshots, st_dev differs from the regular file system
1636 * versus the snapshot. But the fsid is the same throughout. Thus
1637 * the fsid is a better test.
1640 same_file_system(const char *path1
, const char *path2
)
1642 uint64_t fsid1
, fsid2
;
1643 struct stat64 st1
, st2
;
1644 nvlist_t
*nvl1
= NULL
;
1645 nvlist_t
*nvl2
= NULL
;
1647 if ((getattrat(AT_FDCWD
, XATTR_VIEW_READONLY
, path1
, &nvl1
) == 0) &&
1648 (getattrat(AT_FDCWD
, XATTR_VIEW_READONLY
, path2
, &nvl2
) == 0) &&
1649 (nvlist_lookup_uint64(nvl1
, A_FSID
, &fsid1
) == 0) &&
1650 (nvlist_lookup_uint64(nvl2
, A_FSID
, &fsid2
) == 0)) {
1654 * We have found fsid's for both paths.
1667 * We were unable to find fsid's for at least one of the paths.
1668 * fall back on st_dev.
1671 if (stat64(path1
, &st1
) < 0) {
1672 syslog(LOG_NOTICE
, "%s: %m", path1
);
1675 if (stat64(path2
, &st2
) < 0) {
1676 syslog(LOG_NOTICE
, "%s: %m", path2
);
1680 if (st1
.st_dev
== st2
.st_dev
)
1687 findentry(char *path
)
1690 struct sh_list
*shp
;
1695 (void) rw_rdlock(&sharetab_lock
);
1697 for (shp
= share_list
; shp
; shp
= shp
->shl_next
) {
1699 for (p1
= sh
->sh_path
, p2
= path
; *p1
== *p2
; p1
++, p2
++)
1701 goto done
; /* exact match */
1704 * Now compare the pathnames for three cases:
1706 * Parent: /export/foo (no trailing slash on parent)
1707 * Child: /export/foo/bar
1709 * Parent: /export/foo/ (trailing slash on parent)
1710 * Child: /export/foo/bar
1712 * Parent: /export/foo/ (no trailing slash on child)
1713 * Child: /export/foo
1715 if ((*p1
== '\0' && *p2
== '/') ||
1716 (*p1
== '\0' && *(p1
-1) == '/') ||
1717 (*p2
== '\0' && *p1
== '/' && *(p1
+1) == '\0')) {
1719 * We have a subdirectory. Test whether the
1720 * subdirectory is in the same file system.
1722 if (same_file_system(path
, sh
->sh_path
))
1727 sh
= shp
? sharedup(sh
) : NULL
;
1729 (void) rw_unlock(&sharetab_lock
);
1736 is_substring(char **mntp
, char **path
)
1738 char *p1
= *mntp
, *p2
= *path
;
1740 if (*p1
== '\0' && *p2
== '\0') /* exact match */
1742 else if (*p1
== '\0' && *p2
== '/')
1744 else if (*p1
== '\0' && *(p1
-1) == '/') {
1745 *path
= --p2
; /* we need the slash in p2 */
1747 } else if (*p2
== '\0') {
1750 if (*p1
== '\0') /* exact match */
1757 * find_lofsentry() searches for the real path which this requested LOFS path
1758 * (rpath) shadows. If found, it will return the sharetab entry of
1759 * the real path that corresponds to the LOFS path.
1760 * We first search mnttab to see if the requested path is an automounted
1761 * path. If it is an automounted path, it will trigger the mount by stat()ing
1762 * the requested path. Note that it is important to check that this path is
1763 * actually an automounted path, otherwise we would stat() a path which may
1764 * turn out to be NFS and block indefinitely on a dead server. The automounter
1765 * times-out if the server is dead, so there's no risk of hanging this
1766 * thread waiting for stat().
1767 * After the mount has been triggered (if necessary), we look for a
1768 * mountpoint of type LOFS (by searching /etc/mnttab again) which
1769 * is a substring of the rpath. If found, we construct a new path by
1770 * concatenating the mnt_special and the remaining of rpath, call findentry()
1771 * to make sure the 'real path' is shared.
1774 find_lofsentry(char *rpath
, int *done_flag
)
1776 struct stat r_stbuf
;
1777 mntlist_t
*ml
, *mntl
, *mntpnt
= NULL
;
1778 share_t
*retcode
= NULL
;
1779 char tmp_path
[MAXPATHLEN
];
1780 int mntpnt_len
= 0, tmp
;
1787 * While fsgetmntlist() uses lockf() to
1788 * lock the mnttab before reading it in,
1789 * the lock ignores threads in the same process.
1790 * Read in the mnttab with the protection of a mutex.
1792 (void) mutex_lock(&mnttab_lock
);
1793 mntl
= fsgetmntlist();
1794 (void) mutex_unlock(&mnttab_lock
);
1797 * Obtain the mountpoint for the requested path.
1799 for (ml
= mntl
; ml
; ml
= ml
->mntl_next
) {
1800 for (p1
= ml
->mntl_mnt
->mnt_mountp
, p2
= rpath
;
1801 *p1
== *p2
&& *p1
; p1
++, p2
++)
1803 if (is_substring(&p1
, &p2
) &&
1804 (tmp
= strlen(ml
->mntl_mnt
->mnt_mountp
)) >= mntpnt_len
) {
1811 * If the path needs to be autoFS mounted, trigger the mount by
1812 * stat()ing it. This is determined by checking whether the
1813 * mountpoint we just found is of type autofs.
1815 if (mntpnt
!= NULL
&&
1816 strcmp(mntpnt
->mntl_mnt
->mnt_fstype
, "autofs") == 0) {
1818 * The requested path is a substring of an autoFS filesystem.
1819 * Trigger the mount.
1821 if (stat(rpath
, &r_stbuf
) < 0) {
1823 syslog(LOG_NOTICE
, "%s: %m", rpath
);
1826 if ((r_stbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
1828 * The requested path is a directory, stat(2) it
1829 * again with a trailing '.' to force the autoFS
1830 * module to trigger the mount of indirect
1831 * automount entries, such as /net/jurassic/.
1833 if (strlen(rpath
) + 2 > MAXPATHLEN
) {
1836 "%s/.: exceeds MAXPATHLEN %d",
1841 (void) strcpy(tmp_path
, rpath
);
1842 (void) strcat(tmp_path
, "/.");
1844 if (stat(tmp_path
, &r_stbuf
) < 0) {
1846 syslog(LOG_NOTICE
, "%s: %m", tmp_path
);
1852 * The mount has been triggered, re-read mnttab to pick up
1853 * the changes made by autoFS.
1855 fsfreemntlist(mntl
);
1856 (void) mutex_lock(&mnttab_lock
);
1857 mntl
= fsgetmntlist();
1858 (void) mutex_unlock(&mnttab_lock
);
1862 * The autoFS mountpoint has been triggered if necessary,
1863 * now search mnttab again to determine if the requested path
1864 * is an LOFS mount of a shared path.
1867 for (ml
= mntl
; ml
; ml
= ml
->mntl_next
) {
1868 if (strcmp(ml
->mntl_mnt
->mnt_fstype
, "lofs"))
1871 for (p1
= ml
->mntl_mnt
->mnt_mountp
, p2
= rpath
;
1872 *p1
== *p2
&& *p1
; p1
++, p2
++)
1875 if (is_substring(&p1
, &p2
) &&
1876 ((tmp
= strlen(ml
->mntl_mnt
->mnt_mountp
)) >= mntpnt_len
)) {
1879 if ((strlen(ml
->mntl_mnt
->mnt_special
) + strlen(p2
)) >
1882 syslog(LOG_NOTICE
, "%s%s: exceeds %d",
1883 ml
->mntl_mnt
->mnt_special
, p2
,
1892 (void) strcpy(tmp_path
, ml
->mntl_mnt
->mnt_special
);
1893 (void) strcat(tmp_path
, p2
);
1896 retcode
= findentry(tmp_path
);
1901 assert(strlen(tmp_path
) > 0);
1902 (void) strcpy(rpath
, tmp_path
);
1906 fsfreemntlist(mntl
);
1911 * Determine whether an access list grants rights to a particular host.
1912 * We match on aliases of the hostname as well as on the canonical name.
1913 * Names in the access list may be either hosts or netgroups; they're
1914 * not distinguished syntactically. We check for hosts first because
1915 * it's cheaper, then try netgroups.
1918 * 1 - access is granted
1919 * 0 - access is denied
1920 * -1 - an error occured
1923 in_access_list(struct cln
*cln
,
1924 char *access_list
) /* N.B. we clobber this "input" parameter */
1926 char addr
[INET_ADDRSTRLEN
];
1929 char *cstr
= access_list
;
1930 char *gr
= access_list
;
1935 struct nd_hostservlist
*clnames
= NULL
;
1937 /* If no access list - then it's unrestricted */
1938 if (access_list
== NULL
|| *access_list
== '\0')
1941 if ((pnb
= cln_getnbuf(cln
)) == NULL
)
1945 if ((cstr
= strpbrk(cstr
, "[:")) != NULL
) {
1949 assert(*cstr
== '[');
1950 cstr
= strchr(cstr
+ 1, ']');
1959 * If the list name has a '-' prepended then a match of
1960 * the following name implies failure instead of success.
1970 * First check if we have '@' entry, as it doesn't
1971 * require client hostname.
1976 /* Netname support */
1977 if (!isdigit(*gr
) && *gr
!= '[') {
1978 struct netent n
, *np
;
1980 if ((np
= getnetbyname_r(gr
, &n
, buff
,
1981 sizeof (buff
))) != NULL
&&
1983 while ((np
->n_net
& 0xFF000000u
) == 0)
1985 np
->n_net
= htonl(np
->n_net
);
1986 if (inet_ntop(AF_INET
, &np
->n_net
, addr
,
1987 INET_ADDRSTRLEN
) == NULL
)
1989 ret
= inet_matchaddr(pnb
->buf
, addr
);
1991 if (errno
== EINVAL
) {
1998 } else if (ret
== 1) {
2003 ret
= inet_matchaddr(pnb
->buf
, gr
);
2005 if (errno
== EINVAL
) {
2007 "invalid access list "
2011 } else if (ret
== 1) {
2020 * No other checks can be performed if client address
2021 * can't be resolved.
2023 if ((clnames
= cln_getclientsnames(cln
)) == NULL
)
2026 /* Otherwise loop through all client hostname aliases */
2027 for (i
= 0; i
< clnames
->h_cnt
; i
++) {
2028 char *host
= clnames
->h_hostservs
[i
].h_host
;
2031 * If the list name begins with a dot then
2032 * do a domain name suffix comparison.
2033 * A single dot matches any name with no
2037 if (*(gr
+ 1) == '\0') { /* single dot */
2038 if (strchr(host
, '.') == NULL
)
2041 int off
= strlen(host
) - strlen(gr
);
2043 strcasecmp(host
+ off
, gr
) == 0) {
2048 /* Just do a hostname match */
2049 if (strcasecmp(gr
, host
) == 0)
2063 if (clnames
== NULL
)
2066 return (netgroup_check(clnames
, access_list
, nentries
));
2070 static char *optlist
[] = {
2077 #define OPT_SECURE 3
2081 #define OPT_WINDOW 5
2083 #define OPT_NOSUID 6
2091 #define OPT_UIDMAP 10
2093 #define OPT_GIDMAP 11
2099 map_flavor(char *str
)
2103 if (nfs_getseconfig_byname(str
, &sec
))
2106 return (sec
.sc_nfsnum
);
2110 * If the option string contains a "sec="
2111 * option, then use new option syntax.
2116 char *head
, *p
, *val
;
2118 if (!opts
|| *opts
== '\0')
2121 head
= strdup(opts
);
2123 syslog(LOG_ERR
, "opts: no memory");
2129 if (getsubopt(&p
, optlist
, &val
) == OPT_SEC
) {
2140 * Given an export and the clients hostname(s)
2141 * determine the security flavors that this
2142 * client is permitted to use.
2144 * This routine is called only for "old" syntax, i.e.
2145 * only one security flavor is allowed. So we need
2146 * to determine two things: the particular flavor,
2147 * and whether the client is allowed to use this
2148 * flavor, i.e. is in the access list.
2150 * Note that if there is no access list, then the
2151 * default is that access is granted.
2154 getclientsflavors_old(share_t
*sh
, struct cln
*cln
, int *flavors
)
2156 char *opts
, *p
, *val
;
2157 boolean_t ok
= B_FALSE
;
2158 int defaultaccess
= 1;
2159 boolean_t reject
= B_FALSE
;
2161 opts
= strdup(sh
->sh_opts
);
2163 syslog(LOG_ERR
, "getclientsflavors: no memory");
2167 flavors
[0] = AUTH_SYS
;
2172 switch (getsubopt(&p
, optlist
, &val
)) {
2174 flavors
[0] = AUTH_DES
;
2180 if (in_access_list(cln
, val
) > 0)
2186 if (in_access_list(cln
, val
) > 0)
2193 /* none takes precedence over everything else */
2197 return (defaultaccess
|| ok
);
2201 * Given an export and the clients hostname(s)
2202 * determine the security flavors that this
2203 * client is permitted to use.
2205 * This is somewhat more complicated than the "old"
2206 * routine because the options may contain multiple
2207 * security flavors (sec=) each with its own access
2208 * lists. So a client could be granted access based
2209 * on a number of security flavors. Note that the
2210 * type of access might not always be the same, the
2211 * client may get readonly access with one flavor
2212 * and readwrite with another, however the client
2213 * is not told this detail, it gets only the list
2214 * of flavors, and only if the client is using
2215 * version 3 of the mount protocol.
2218 getclientsflavors_new(share_t
*sh
, struct cln
*cln
, int *flavors
)
2220 char *opts
, *p
, *val
;
2223 boolean_t defaultaccess
= B_TRUE
; /* default access is rw */
2224 boolean_t access_ok
= B_FALSE
;
2226 boolean_t reject
= B_FALSE
;
2228 opts
= strdup(sh
->sh_opts
);
2230 syslog(LOG_ERR
, "getclientsflavors: no memory");
2238 switch (getsubopt(&p
, optlist
, &val
)) {
2241 access_ok
= B_FALSE
;
2244 * Before a new sec=xxx option, check if we need
2245 * to move the c index back to the previous count.
2247 if (!defaultaccess
&& !access_ok
) {
2251 /* get all the sec=f1[:f2] flavors */
2252 while ((f
= strtok_r(val
, ":", &lasts
)) != NULL
) {
2253 flavors
[c
++] = map_flavor(f
);
2257 /* for a new sec=xxx option, default is rw access */
2258 defaultaccess
= B_TRUE
;
2259 access_ok
= B_FALSE
;
2265 defaultaccess
= B_FALSE
;
2266 if (in_access_list(cln
, val
) > 0)
2271 defaultaccess
= B_FALSE
;
2272 if (in_access_list(cln
, val
) > 0)
2273 reject
= B_TRUE
; /* none overides rw/ro */
2279 access_ok
= B_FALSE
;
2281 if (!defaultaccess
&& !access_ok
)
2290 * This is a tricky piece of code that parses the
2291 * share options looking for a match on the auth
2292 * flavor that the client is using. If it finds
2293 * a match, then the client is given ro, rw, or
2294 * no access depending whether it is in the access
2295 * list. There is a special case for "secure"
2296 * flavor. Other flavors are values of the new "sec=" option.
2299 check_client(share_t
*sh
, struct cln
*cln
, int flavor
, uid_t clnt_uid
,
2300 gid_t clnt_gid
, uint_t clnt_ngids
, gid_t
*clnt_gids
, uid_t
*srv_uid
,
2301 gid_t
*srv_gid
, uint_t
*srv_ngids
, gid_t
**srv_gids
)
2303 if (newopts(sh
->sh_opts
))
2304 return (check_client_new(sh
, cln
, flavor
, clnt_uid
, clnt_gid
,
2305 clnt_ngids
, clnt_gids
, srv_uid
, srv_gid
, srv_ngids
,
2308 return (check_client_old(sh
, cln
, flavor
, clnt_uid
, clnt_gid
,
2309 clnt_ngids
, clnt_gids
, srv_uid
, srv_gid
, srv_ngids
,
2313 extern int _getgroupsbymember(const char *, gid_t
[], int, int);
2316 * Get supplemental groups for uid
2319 getusergroups(uid_t uid
, uint_t
*ngrps
, gid_t
**grps
)
2322 char *pwbuf
= alloca(pw_size
);
2323 gid_t
*tmpgrps
= alloca(ngroups_max
* sizeof (gid_t
));
2326 if (getpwuid_r(uid
, &pwd
, pwbuf
, pw_size
) == NULL
)
2329 tmpgrps
[0] = pwd
.pw_gid
;
2331 tmpngrps
= _getgroupsbymember(pwd
.pw_name
, tmpgrps
, ngroups_max
, 1);
2332 if (tmpngrps
<= 0) {
2334 "getusergroups(): Unable to get groups for user %s",
2340 *grps
= malloc(tmpngrps
* sizeof (gid_t
));
2341 if (*grps
== NULL
) {
2343 "getusergroups(): Memory allocation failed: %m");
2349 (void) memcpy(*grps
, tmpgrps
, tmpngrps
* sizeof (gid_t
));
2355 * is_a_number(number)
2357 * is the string a number in one of the forms we want to use?
2361 is_a_number(char *number
)
2366 if (strncmp(number
, "0x", 2) == 0) {
2369 } else if (*number
== '-') {
2370 number
++; /* skip the minus */
2372 while (ret
== 1 && *number
!= '\0') {
2374 ret
= isxdigit(*number
++);
2376 ret
= isdigit(*number
++);
2383 get_uid(char *value
, uid_t
*uid
)
2385 if (!is_a_number(value
)) {
2388 * in this case it would have to be a
2391 pw
= getpwnam(value
);
2398 intval
= strtoull(value
, NULL
, 0);
2399 if (intval
> UID_MAX
&& intval
!= -1)
2401 *uid
= (uid_t
)intval
;
2408 get_gid(char *value
, gid_t
*gid
)
2410 if (!is_a_number(value
)) {
2413 * in this case it would have to be a
2416 gr
= getgrnam(value
);
2423 intval
= strtoull(value
, NULL
, 0);
2424 if (intval
> UID_MAX
&& intval
!= -1)
2426 *gid
= (gid_t
)intval
;
2433 check_client_old(share_t
*sh
, struct cln
*cln
, int flavor
, uid_t clnt_uid
,
2434 gid_t clnt_gid
, uint_t clnt_ngids
, gid_t
*clnt_gids
, uid_t
*srv_uid
,
2435 gid_t
*srv_gid
, uint_t
*srv_ngids
, gid_t
**srv_gids
)
2437 char *opts
, *p
, *val
;
2438 int match
; /* Set when a flavor is matched */
2439 int perm
= 0; /* Set when "ro", "rw" or "root" is matched */
2440 int list
= 0; /* Set when "ro", "rw" is found */
2441 int ro_val
= 0; /* Set if ro option is 'ro=' */
2442 int rw_val
= 0; /* Set if rw option is 'rw=' */
2444 boolean_t map_deny
= B_FALSE
;
2446 opts
= strdup(sh
->sh_opts
);
2448 syslog(LOG_ERR
, "check_client: no memory");
2453 * If client provided 16 supplemental groups with AUTH_SYS, lookup
2454 * locally for all of them
2456 if (flavor
== AUTH_SYS
&& clnt_ngids
== NGRPS
&& ngroups_max
> NGRPS
)
2457 if (getusergroups(clnt_uid
, srv_ngids
, srv_gids
) == 0)
2458 perm
|= NFSAUTH_GROUPS
;
2464 switch (getsubopt(&p
, optlist
, &val
)) {
2469 if (perm
& NFSAUTH_GROUPS
) {
2473 perm
&= ~NFSAUTH_GROUPS
;
2482 if (in_access_list(cln
, val
) > 0)
2490 if (in_access_list(cln
, val
) > 0)
2496 * Check if the client is in
2497 * the root list. Only valid
2500 if (flavor
!= AUTH_SYS
)
2503 if (val
== NULL
|| *val
== '\0')
2509 if (in_access_list(cln
, val
) > 0) {
2510 perm
|= NFSAUTH_ROOT
;
2511 perm
|= NFSAUTH_UIDMAP
| NFSAUTH_GIDMAP
;
2514 if (perm
& NFSAUTH_GROUPS
) {
2518 perm
&= ~NFSAUTH_GROUPS
;
2525 * Check if the client should have no access
2526 * to this share at all. This option behaves
2527 * more like "root" than either "rw" or "ro".
2529 if (in_access_list(cln
, val
) > 0)
2530 perm
|= NFSAUTH_DENIED
;
2538 * The uidmap is supported for AUTH_SYS only.
2540 if (flavor
!= AUTH_SYS
)
2543 if (perm
& NFSAUTH_UIDMAP
|| map_deny
)
2546 for (c
= val
; c
!= NULL
; c
= n
) {
2558 al
= strchr(s
, ':');
2563 if (s
== NULL
|| al
== NULL
)
2567 if (clnt_uid
!= (uid_t
)-1)
2569 } else if (strcmp(c
, "*") != 0) {
2572 if (!get_uid(c
, &clnt
))
2575 if (clnt_uid
!= clnt
)
2581 else if (!get_uid(s
, &srv
))
2583 else if (srv
== (uid_t
)-1) {
2588 if (in_access_list(cln
, al
) > 0) {
2590 perm
|= NFSAUTH_UIDMAP
;
2592 if (perm
& NFSAUTH_GROUPS
) {
2596 perm
&= ~NFSAUTH_GROUPS
;
2611 * The gidmap is supported for AUTH_SYS only.
2613 if (flavor
!= AUTH_SYS
)
2616 if (perm
& NFSAUTH_GIDMAP
|| map_deny
)
2619 for (c
= val
; c
!= NULL
; c
= n
) {
2631 al
= strchr(s
, ':');
2636 if (s
== NULL
|| al
== NULL
)
2640 if (clnt_gid
!= (gid_t
)-1)
2642 } else if (strcmp(c
, "*") != 0) {
2645 if (!get_gid(c
, &clnt
))
2648 if (clnt_gid
!= clnt
)
2654 else if (!get_gid(s
, &srv
))
2656 else if (srv
== (gid_t
)-1) {
2661 if (in_access_list(cln
, al
) > 0) {
2663 perm
|= NFSAUTH_GIDMAP
;
2665 if (perm
& NFSAUTH_GROUPS
) {
2669 perm
&= ~NFSAUTH_GROUPS
;
2686 if (perm
& NFSAUTH_ROOT
) {
2692 perm
|= NFSAUTH_DENIED
;
2694 if (!(perm
& NFSAUTH_UIDMAP
))
2695 *srv_uid
= clnt_uid
;
2696 if (!(perm
& NFSAUTH_GIDMAP
))
2697 *srv_gid
= clnt_gid
;
2699 if (flavor
!= match
|| perm
& NFSAUTH_DENIED
)
2700 return (NFSAUTH_DENIED
);
2704 * If the client doesn't match an "ro" or "rw"
2705 * list then set no access.
2707 if ((perm
& (NFSAUTH_RO
| NFSAUTH_RW
)) == 0)
2708 perm
|= NFSAUTH_DENIED
;
2711 * The client matched a flavor entry that
2712 * has no explicit "rw" or "ro" determination.
2713 * Default it to "rw".
2719 * The client may show up in both ro= and rw=
2720 * lists. If so, then turn off the RO access
2721 * bit leaving RW access.
2723 if (perm
& NFSAUTH_RO
&& perm
& NFSAUTH_RW
) {
2725 * Logically cover all permutations of rw=,ro=.
2726 * In the case where, rw,ro=<host> we would like
2727 * to remove RW access for the host. In all other cases
2728 * RW wins the precedence battle.
2730 if (!rw_val
&& ro_val
) {
2731 perm
&= ~(NFSAUTH_RW
);
2733 perm
&= ~(NFSAUTH_RO
);
2741 * Check if the client has access by using a flavor different from
2742 * the given "flavor". If "flavor" is not in the flavor list,
2743 * return TRUE to indicate that this "flavor" is a wrong sec.
2746 is_wrongsec(share_t
*sh
, struct cln
*cln
, int flavor
)
2748 int flavor_list
[MAX_FLAVORS
];
2749 int flavor_count
, i
;
2751 /* get the flavor list that the client has access with */
2752 flavor_count
= getclientsflavors_new(sh
, cln
, flavor_list
);
2754 if (flavor_count
== 0)
2758 * Check if the given "flavor" is in the flavor_list.
2760 for (i
= 0; i
< flavor_count
; i
++) {
2761 if (flavor
== flavor_list
[i
])
2766 * If "flavor" is not in the flavor_list, return TRUE to indicate
2767 * that the client should have access by using a security flavor
2768 * different from this "flavor".
2774 * Given an export and the client's hostname, we
2775 * check the security options to see whether the
2776 * client is allowed to use the given security flavor.
2778 * The strategy is to proceed through the options looking
2779 * for a flavor match, then pay attention to the ro, rw,
2782 * Note that an entry may list several flavors in a
2783 * single entry, e.g.
2785 * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
2790 check_client_new(share_t
*sh
, struct cln
*cln
, int flavor
, uid_t clnt_uid
,
2791 gid_t clnt_gid
, uint_t clnt_ngids
, gid_t
*clnt_gids
, uid_t
*srv_uid
,
2792 gid_t
*srv_gid
, uint_t
*srv_ngids
, gid_t
**srv_gids
)
2794 char *opts
, *p
, *val
;
2797 int match
= 0; /* Set when a flavor is matched */
2798 int perm
= 0; /* Set when "ro", "rw" or "root" is matched */
2799 int list
= 0; /* Set when "ro", "rw" is found */
2800 int ro_val
= 0; /* Set if ro option is 'ro=' */
2801 int rw_val
= 0; /* Set if rw option is 'rw=' */
2803 boolean_t map_deny
= B_FALSE
;
2805 opts
= strdup(sh
->sh_opts
);
2807 syslog(LOG_ERR
, "check_client: no memory");
2812 * If client provided 16 supplemental groups with AUTH_SYS, lookup
2813 * locally for all of them
2815 if (flavor
== AUTH_SYS
&& clnt_ngids
== NGRPS
&& ngroups_max
> NGRPS
)
2816 if (getusergroups(clnt_uid
, srv_ngids
, srv_gids
) == 0)
2817 perm
|= NFSAUTH_GROUPS
;
2822 switch (getsubopt(&p
, optlist
, &val
)) {
2828 while ((f
= strtok_r(val
, ":", &lasts
))
2830 if (flavor
== map_flavor(f
)) {
2845 if (in_access_list(cln
, val
) > 0)
2856 if (in_access_list(cln
, val
) > 0)
2862 * Check if the client is in
2863 * the root list. Only valid
2866 if (flavor
!= AUTH_SYS
)
2872 if (val
== NULL
|| *val
== '\0')
2878 if (in_access_list(cln
, val
) > 0) {
2879 perm
|= NFSAUTH_ROOT
;
2880 perm
|= NFSAUTH_UIDMAP
| NFSAUTH_GIDMAP
;
2883 if (perm
& NFSAUTH_GROUPS
) {
2887 perm
&= ~NFSAUTH_GROUPS
;
2894 * Check if the client should have no access
2895 * to this share at all. This option behaves
2896 * more like "root" than either "rw" or "ro".
2898 if (in_access_list(cln
, val
) > 0)
2899 perm
|= NFSAUTH_DENIED
;
2907 * The uidmap is supported for AUTH_SYS only.
2909 if (flavor
!= AUTH_SYS
)
2912 if (!match
|| perm
& NFSAUTH_UIDMAP
|| map_deny
)
2915 for (c
= val
; c
!= NULL
; c
= n
) {
2927 al
= strchr(s
, ':');
2932 if (s
== NULL
|| al
== NULL
)
2936 if (clnt_uid
!= (uid_t
)-1)
2938 } else if (strcmp(c
, "*") != 0) {
2941 if (!get_uid(c
, &clnt
))
2944 if (clnt_uid
!= clnt
)
2950 else if (!get_uid(s
, &srv
))
2952 else if (srv
== (uid_t
)-1) {
2957 if (in_access_list(cln
, al
) > 0) {
2959 perm
|= NFSAUTH_UIDMAP
;
2961 if (perm
& NFSAUTH_GROUPS
) {
2965 perm
&= ~NFSAUTH_GROUPS
;
2980 * The gidmap is supported for AUTH_SYS only.
2982 if (flavor
!= AUTH_SYS
)
2985 if (!match
|| perm
& NFSAUTH_GIDMAP
|| map_deny
)
2988 for (c
= val
; c
!= NULL
; c
= n
) {
3000 al
= strchr(s
, ':');
3005 if (s
== NULL
|| al
== NULL
)
3009 if (clnt_gid
!= (gid_t
)-1)
3011 } else if (strcmp(c
, "*") != 0) {
3014 if (!get_gid(c
, &clnt
))
3017 if (clnt_gid
!= clnt
)
3023 else if (!get_gid(s
, &srv
))
3025 else if (srv
== (gid_t
)-1) {
3030 if (in_access_list(cln
, al
) > 0) {
3032 perm
|= NFSAUTH_GIDMAP
;
3034 if (perm
& NFSAUTH_GROUPS
) {
3038 perm
&= ~NFSAUTH_GROUPS
;
3054 if (perm
& NFSAUTH_ROOT
) {
3060 perm
|= NFSAUTH_DENIED
;
3062 if (!(perm
& NFSAUTH_UIDMAP
))
3063 *srv_uid
= clnt_uid
;
3064 if (!(perm
& NFSAUTH_GIDMAP
))
3065 *srv_gid
= clnt_gid
;
3068 * If no match then set the perm accordingly
3070 if (!match
|| perm
& NFSAUTH_DENIED
) {
3072 return (NFSAUTH_DENIED
);
3077 * If the client doesn't match an "ro" or "rw" list then
3078 * check if it may have access by using a different flavor.
3079 * If so, return NFSAUTH_WRONGSEC.
3080 * If not, return NFSAUTH_DENIED.
3082 if ((perm
& (NFSAUTH_RO
| NFSAUTH_RW
)) == 0) {
3083 if (is_wrongsec(sh
, cln
, flavor
))
3084 perm
|= NFSAUTH_WRONGSEC
;
3086 perm
|= NFSAUTH_DENIED
;
3090 * The client matched a flavor entry that
3091 * has no explicit "rw" or "ro" determination.
3092 * Make sure it defaults to "rw".
3098 * The client may show up in both ro= and rw=
3099 * lists. If so, then turn off the RO access
3100 * bit leaving RW access.
3102 if (perm
& NFSAUTH_RO
&& perm
& NFSAUTH_RW
) {
3104 * Logically cover all permutations of rw=,ro=.
3105 * In the case where, rw,ro=<host> we would like
3106 * to remove RW access for the host. In all other cases
3107 * RW wins the precedence battle.
3109 if (!rw_val
&& ro_val
) {
3110 perm
&= ~(NFSAUTH_RW
);
3112 perm
&= ~(NFSAUTH_RO
);
3126 static timestruc_t last_sharetab_time
;
3127 timestruc_t prev_sharetab_time
;
3129 struct sh_list
*shp
, *shp_prev
;
3133 * read in /etc/dfs/sharetab if it has changed
3135 if (stat(SHARETAB
, &st
) != 0) {
3136 syslog(LOG_ERR
, "Cannot stat %s: %m", SHARETAB
);
3140 if (st
.st_mtim
.tv_sec
== last_sharetab_time
.tv_sec
&&
3141 st
.st_mtim
.tv_nsec
== last_sharetab_time
.tv_nsec
) {
3149 * Remember the mod time, then after getting the
3150 * write lock check again. If another thread
3151 * already did the update, then there's no
3154 prev_sharetab_time
= last_sharetab_time
;
3156 (void) rw_wrlock(&sharetab_lock
);
3158 if (prev_sharetab_time
.tv_sec
!= last_sharetab_time
.tv_sec
||
3159 prev_sharetab_time
.tv_nsec
!= last_sharetab_time
.tv_nsec
) {
3160 (void) rw_unlock(&sharetab_lock
);
3165 * Note that since the sharetab is now in memory
3166 * and a snapshot is taken, we no longer have to
3169 f
= fopen(SHARETAB
, "r");
3171 syslog(LOG_ERR
, "Cannot open %s: %m", SHARETAB
);
3172 (void) rw_unlock(&sharetab_lock
);
3177 * Once we are sure /etc/dfs/sharetab has been
3178 * modified, flush netgroup cache entries.
3180 netgrp_cache_flush();
3182 sh_free(share_list
); /* free old list */
3185 while ((res
= getshare(f
, &sh
)) > 0) {
3187 if (strcmp(sh
->sh_fstype
, "nfs") != 0)
3190 shp
= malloc(sizeof (*shp
));
3193 if (share_list
== NULL
)
3196 /* LINTED not used before set */
3197 shp_prev
->shl_next
= shp
;
3199 shp
->shl_next
= NULL
;
3200 shp
->shl_sh
= sharedup(sh
);
3201 if (shp
->shl_sh
== NULL
)
3206 syslog(LOG_ERR
, "%s: invalid at line %d\n",
3209 if (stat(SHARETAB
, &st
) != 0) {
3210 syslog(LOG_ERR
, "Cannot stat %s: %m", SHARETAB
);
3212 (void) rw_unlock(&sharetab_lock
);
3216 last_sharetab_time
= st
.st_mtim
;
3218 (void) rw_unlock(&sharetab_lock
);
3224 syslog(LOG_ERR
, "check_sharetab: no memory");
3225 sh_free(share_list
);
3228 (void) rw_unlock(&sharetab_lock
);
3232 sh_free(struct sh_list
*shp
)
3234 struct sh_list
*next
;
3237 sharefree(shp
->shl_sh
);
3238 next
= shp
->shl_next
;
3246 * Remove an entry from mounted list
3249 umount(struct svc_req
*rqstp
)
3251 char *host
, *path
, *remove_path
;
3252 char rpath
[MAXPATHLEN
];
3256 transp
= rqstp
->rq_xprt
;
3258 if (!svc_getargs(transp
, xdr_dirpath
, (caddr_t
)&path
)) {
3259 svcerr_decode(transp
);
3263 cln_init(&cln
, transp
);
3266 if (!svc_sendreply(transp
, xdr_void
, (char *)NULL
))
3267 log_cant_reply_cln(&cln
);
3269 host
= cln_gethost(&cln
);
3272 * Without the hostname we can't do audit or delete
3273 * this host from the mount entries.
3275 (void) svc_freeargs(transp
, xdr_dirpath
, (caddr_t
)&path
);
3280 syslog(LOG_NOTICE
, "UNMOUNT: %s unmounted %s", host
, path
);
3282 audit_mountd_umount(host
, path
);
3284 remove_path
= rpath
; /* assume we will use the cannonical path */
3285 if (realpath(path
, rpath
) == NULL
) {
3287 syslog(LOG_WARNING
, "UNMOUNT: realpath: %s: %m ", path
);
3288 remove_path
= path
; /* use path provided instead */
3291 mntlist_delete(host
, remove_path
); /* remove from mount list */
3295 (void) svc_freeargs(transp
, xdr_dirpath
, (caddr_t
)&path
);
3299 * Remove all entries for one machine from mounted list
3302 umountall(struct svc_req
*rqstp
)
3308 transp
= rqstp
->rq_xprt
;
3309 if (!svc_getargs(transp
, xdr_void
, NULL
)) {
3310 svcerr_decode(transp
);
3314 * We assume that this call is asynchronous and made via rpcbind
3315 * callit routine. Therefore return control immediately. The error
3316 * causes rpcbind to remain silent, as opposed to every machine
3317 * on the net blasting the requester with a response.
3319 svcerr_systemerr(transp
);
3321 cln_init(&cln
, transp
);
3323 host
= cln_gethost(&cln
);
3325 /* Can't do anything without the name of the client */
3330 * Remove all hosts entries from mount list
3332 mntlist_delete_all(host
);
3335 syslog(LOG_NOTICE
, "UNMOUNTALL: from %s", host
);
3341 exmalloc(size_t size
)
3345 if ((ret
= malloc(size
)) == NULL
) {
3346 syslog(LOG_ERR
, "Out of memory");
3352 static tsol_tpent_t
*
3353 get_client_template(struct sockaddr
*sock
)
3356 in6_addr_t v6client
;
3357 char v4_addr
[INET_ADDRSTRLEN
];
3358 char v6_addr
[INET6_ADDRSTRLEN
];
3362 switch (sock
->sa_family
) {
3364 v4client
= ((struct sockaddr_in
*)(void *)sock
)->
3366 if (inet_ntop(AF_INET
, &v4client
, v4_addr
, INET_ADDRSTRLEN
) ==
3369 rh
= tsol_getrhbyaddr(v4_addr
, sizeof (v4_addr
), AF_INET
);
3372 tp
= tsol_gettpbyname(rh
->rh_template
);
3377 v6client
= ((struct sockaddr_in6
*)(void *)sock
)->sin6_addr
;
3378 if (inet_ntop(AF_INET6
, &v6client
, v6_addr
, INET6_ADDRSTRLEN
) ==
3381 rh
= tsol_getrhbyaddr(v6_addr
, sizeof (v6_addr
), AF_INET6
);
3384 tp
= tsol_gettpbyname(rh
->rh_template
);