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 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
36 #include <stdio_ext.h>
39 #include <sys/types.h>
42 #include <sys/param.h>
45 #include <netconfig.h>
49 #include <sys/errno.h>
50 #include <rpcsvc/mount.h>
51 #include <sys/pathconf.h>
52 #include <sys/systeminfo.h>
53 #include <sys/utsname.h>
55 #include <sys/resource.h>
60 #include <sys/socket.h>
61 #include <netinet/in.h>
62 #include <arpa/inet.h>
66 #include <priv_utils.h>
68 #include <nfs/nfssys.h>
70 #include <nfs/nfs_sec.h>
71 #include <rpcsvc/daemon_utils.h>
73 #include "../../fslib.h"
74 #include <sharefs/share.h>
75 #include <sharefs/sharetab.h>
76 #include "../lib/sharetab.h"
81 #include <sys/nvpair.h>
88 extern int daemonize_init(void);
89 extern void daemonize_fini(int);
91 extern int _nfssys(int, void *);
93 struct sh_list
*share_list
;
95 rwlock_t sharetab_lock
; /* lock to protect the cached sharetab */
96 static mutex_t mnttab_lock
; /* prevent concurrent mnttab readers */
98 static mutex_t logging_queue_lock
;
99 static cond_t logging_queue_cv
;
101 static share_t
*find_lofsentry(char *, int *);
102 static int getclientsflavors_old(share_t
*, struct cln
*, int *);
103 static int getclientsflavors_new(share_t
*, struct cln
*, int *);
104 static int check_client_old(share_t
*, struct cln
*, int, uid_t
, gid_t
, uint_t
,
105 gid_t
*, uid_t
*, gid_t
*, uint_t
*, gid_t
**);
106 static int check_client_new(share_t
*, struct cln
*, int, uid_t
, gid_t
, uint_t
,
107 gid_t
*, uid_t
*, gid_t
*i
, uint_t
*, gid_t
**);
108 static void mnt(struct svc_req
*, SVCXPRT
*);
109 static void mnt_pathconf(struct svc_req
*);
110 static int mount(struct svc_req
*r
);
111 static void sh_free(struct sh_list
*);
112 static void umount(struct svc_req
*);
113 static void umountall(struct svc_req
*);
114 static int newopts(char *);
117 static int rejecting
;
118 static int mount_vers_min
= MOUNTVERS
;
119 static int mount_vers_max
= MOUNTVERS3
;
121 extern void nfscmd_func(void *, char *, size_t, door_desc_t
*, uint_t
);
123 thread_t nfsauth_thread
;
125 thread_t logging_thread
;
127 typedef struct logging_data
{
133 struct netbuf
*ld_nb
;
134 struct logging_data
*ld_next
;
137 static logging_data
*logging_head
= NULL
;
138 static logging_data
*logging_tail
= NULL
;
141 * Our copy of some system variables obtained using sysconf(3c)
143 static long ngroups_max
; /* _SC_NGROUPS_MAX */
144 static long pw_size
; /* _SC_GETPW_R_SIZE_MAX */
148 nfsauth_svc(void *arg
)
156 if ((doorfd
= door_create(nfsauth_func
, NULL
,
157 DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
)) == -1) {
158 syslog(LOG_ERR
, "Unable to create door: %m\n");
164 * Create a file system path for the door
166 if ((dfd
= open(MOUNTD_DOOR
, O_RDWR
|O_CREAT
|O_TRUNC
,
167 S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
)) == -1) {
168 syslog(LOG_ERR
, "Unable to open %s: %m\n", MOUNTD_DOOR
);
169 (void) close(doorfd
);
174 * Clean up any stale namespace associations
176 (void) fdetach(MOUNTD_DOOR
);
179 * Register in namespace to pass to the kernel to door_ki_open
181 if (fattach(doorfd
, MOUNTD_DOOR
) == -1) {
182 syslog(LOG_ERR
, "Unable to fattach door: %m\n");
184 (void) close(doorfd
);
191 * Must pass the doorfd down to the kernel.
194 (void) _nfssys(MOUNTD_ARGS
, &darg
);
197 * Wait for incoming calls
204 syslog(LOG_ERR
, gettext("Door server exited"));
209 * NFS command service thread code for setup and handling of the
210 * nfs_cmd requests for character set conversion and other future
220 if ((doorfd
= door_create(nfscmd_func
, NULL
,
221 DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
)) == -1) {
222 syslog(LOG_ERR
, "Unable to create cmd door: %m\n");
227 * Must pass the doorfd down to the kernel.
230 (void) _nfssys(NFSCMD_ARGS
, &darg
);
233 * Wait for incoming calls
240 syslog(LOG_ERR
, gettext("Cmd door server exited"));
245 free_logging_data(logging_data
*lq
)
251 if (lq
->ld_nb
!= NULL
) {
252 free(lq
->ld_nb
->buf
);
263 static logging_data
*
264 remove_head_of_queue(void)
269 * Pull it off the queue.
273 logging_head
= lq
->ld_next
;
278 if (logging_head
== NULL
) {
287 do_logging_queue(logging_data
*lq
)
295 if (lq
->ld_host
== NULL
) {
296 DTRACE_PROBE(mountd
, name_by_lazy
);
297 cln_init_lazy(&cln
, lq
->ld_netid
, lq
->ld_nb
);
298 host
= cln_gethost(&cln
);
302 audit_mountd_mount(host
, lq
->ld_path
, lq
->ld_status
); /* BSM */
304 /* add entry to mount list */
306 mntlist_new(host
, lq
->ld_rpath
);
308 if (lq
->ld_host
== NULL
)
311 free_logging_data(lq
);
314 (void) mutex_lock(&logging_queue_lock
);
315 lq
= remove_head_of_queue();
316 (void) mutex_unlock(&logging_queue_lock
);
319 DTRACE_PROBE1(mountd
, logging_cleared
, cleared
);
323 logging_svc(void *arg
)
328 (void) mutex_lock(&logging_queue_lock
);
329 while (logging_head
== NULL
) {
330 (void) cond_wait(&logging_queue_cv
,
331 &logging_queue_lock
);
334 lq
= remove_head_of_queue();
335 (void) mutex_unlock(&logging_queue_lock
);
337 do_logging_queue(lq
);
341 syslog(LOG_ERR
, gettext("Logging server exited"));
346 convert_int(int *val
, char *str
)
350 if (str
== NULL
|| !isdigit(*str
))
353 lval
= strtol(str
, &str
, 10);
354 if (*str
!= '\0' || lval
> INT_MAX
)
362 main(int argc
, char *argv
[])
366 int rpc_svc_fdunlim
= 1;
367 int rpc_svc_mode
= RPC_SVC_MT_AUTO
;
368 int maxrecsz
= RPC_MAXDATASIZE
;
369 bool_t exclbind
= TRUE
;
370 long thr_flags
= (THR_NEW_LWP
|THR_DAEMON
);
372 int defvers
, ret
, bufsz
;
374 int listen_backlog
= 0;
381 * Mountd requires uid 0 for:
382 * /etc/rmtab updates (we could chown it to daemon)
383 * /etc/dfs/dfstab reading (it wants to lock out share which
384 * doesn't do any locking before first truncate;
385 * NFS share does; should use fcntl locking instead)
389 * file dac search (so it can stat all files)
391 if (__init_daemon_priv(PU_RESETGROUPS
|PU_CLEARLIMITSET
, -1, -1,
392 PRIV_SYS_NFS
, PRIV_PROC_AUDIT
, PRIV_FILE_DAC_SEARCH
, NULL
) == -1) {
393 (void) fprintf(stderr
,
394 "%s: must be run with sufficient privileges\n",
399 if (getrlimit(RLIMIT_NOFILE
, &rl
) != 0) {
400 syslog(LOG_ERR
, "getrlimit failed");
402 rl
.rlim_cur
= rl
.rlim_max
;
403 if (setrlimit(RLIMIT_NOFILE
, &rl
) != 0)
404 syslog(LOG_ERR
, "setrlimit failed");
407 (void) enable_extended_FILE_stdio(-1, -1);
409 ret
= nfs_smf_get_iprop("mountd_max_threads", &max_threads
,
410 DEFAULT_INSTANCE
, SCF_TYPE_INTEGER
, NFSD
);
412 syslog(LOG_ERR
, "Reading of mountd_max_threads from SMF "
413 "failed, using default value");
416 while ((c
= getopt(argc
, argv
, "vrm:")) != EOF
) {
425 if (convert_int(&tmp
, optarg
) != 0 || tmp
< 1) {
426 (void) fprintf(stderr
, "%s: invalid "
427 "max_threads option, using defaults\n",
434 fprintf(stderr
, "usage: mountd [-v] [-r]\n");
440 * Read in the NFS version values from config file.
443 ret
= nfs_smf_get_prop("server_versmin", defval
, DEFAULT_INSTANCE
,
444 SCF_TYPE_INTEGER
, NFSD
, &bufsz
);
447 defvers
= strtol(defval
, (char **)NULL
, 10);
449 mount_vers_min
= defvers
;
451 * special because NFSv2 is
452 * supported by mount v1 & v2
454 if (defvers
== NFS_VERSION
)
455 mount_vers_min
= MOUNTVERS
;
460 ret
= nfs_smf_get_prop("server_versmax", defval
, DEFAULT_INSTANCE
,
461 SCF_TYPE_INTEGER
, NFSD
, &bufsz
);
464 defvers
= strtol(defval
, (char **)NULL
, 10);
466 mount_vers_max
= defvers
;
470 ret
= nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog
,
471 DEFAULT_INSTANCE
, SCF_TYPE_INTEGER
, NFSD
);
473 syslog(LOG_ERR
, "Reading of mountd_listen_backlog from SMF "
474 "failed, using default value");
478 * Sanity check versions,
479 * even though we may get versions > MOUNTVERS3, we still need
480 * to start nfsauth service, so continue on regardless of values.
482 if (mount_vers_min
> mount_vers_max
) {
483 fprintf(stderr
, "server_versmin > server_versmax\n");
484 mount_vers_max
= mount_vers_min
;
486 (void) setlocale(LC_ALL
, "");
487 (void) rwlock_init(&sharetab_lock
, USYNC_THREAD
, NULL
);
488 (void) mutex_init(&mnttab_lock
, USYNC_THREAD
, NULL
);
489 (void) mutex_init(&logging_queue_lock
, USYNC_THREAD
, NULL
);
490 (void) cond_init(&logging_queue_cv
, USYNC_THREAD
, NULL
);
494 #if !defined(TEXT_DOMAIN)
495 #define TEXT_DOMAIN "SYS_TEST"
497 (void) textdomain(TEXT_DOMAIN
);
499 /* Don't drop core if the NFS module isn't loaded. */
500 (void) signal(SIGSYS
, SIG_IGN
);
502 pipe_fd
= daemonize_init();
505 * If we coredump it'll be in /core
508 fprintf(stderr
, "chdir /: %s\n", strerror(errno
));
510 openlog("mountd", LOG_PID
, LOG_DAEMON
);
513 * establish our lock on the lock file and write our pid to it.
514 * exit if some other process holds the lock, or if there's any
515 * error in writing/locking the file.
517 pid
= _enter_daemon_lock(MOUNTD
);
522 fprintf(stderr
, "error locking for %s: %s\n", MOUNTD
,
526 /* daemon was already running */
530 audit_mountd_setup(); /* BSM */
533 * Get required system variables
535 if ((ngroups_max
= sysconf(_SC_NGROUPS_MAX
)) == -1) {
536 syslog(LOG_ERR
, "Unable to get _SC_NGROUPS_MAX");
539 if ((pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
)) == -1) {
540 syslog(LOG_ERR
, "Unable to get _SC_GETPW_R_SIZE_MAX");
545 * Set number of file descriptors to unlimited
547 if (!rpc_control(RPC_SVC_USE_POLLFD
, &rpc_svc_fdunlim
)) {
548 syslog(LOG_INFO
, "unable to set number of FDs to unlimited");
552 * Tell RPC that we want automatic thread mode.
553 * A new thread will be spawned for each request.
555 if (!rpc_control(RPC_SVC_MTMODE_SET
, &rpc_svc_mode
)) {
556 fprintf(stderr
, "unable to set automatic MT mode\n");
561 * Enable non-blocking mode and maximum record size checks for
562 * connection oriented transports.
564 if (!rpc_control(RPC_SVC_CONNMAXREC_SET
, &maxrecsz
)) {
565 fprintf(stderr
, "unable to set RPC max record size\n");
569 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
570 * from being hijacked by a bind to a more specific addr.
572 if (!rpc_control(__RPC_SVC_EXCLBIND_SET
, &exclbind
)) {
573 fprintf(stderr
, "warning: unable to set udp/tcp EXCLBIND\n");
577 * Set the maximum number of outstanding connection
578 * indications (listen backlog) to the value specified.
580 if (listen_backlog
> 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET
,
582 fprintf(stderr
, "unable to set listen backlog\n");
587 * If max_threads was specified, then set the
588 * maximum number of threads to the value specified.
590 if (max_threads
> 0 && !rpc_control(RPC_SVC_THRMAX_SET
, &max_threads
)) {
591 fprintf(stderr
, "unable to set max_threads\n");
596 * Make sure to unregister any previous versions in case the
597 * user is reconfiguring the server in interesting ways.
599 svc_unreg(MOUNTPROG
, MOUNTVERS
);
600 svc_unreg(MOUNTPROG
, MOUNTVERS_POSIX
);
601 svc_unreg(MOUNTPROG
, MOUNTVERS3
);
604 * Create the nfsauth thread with same signal disposition
605 * as the main thread. We need to create a separate thread
606 * since mountd() will be both an RPC server (for remote
607 * traffic) _and_ a doors server (for kernel upcalls).
609 if (thr_create(NULL
, 0, nfsauth_svc
, 0, thr_flags
, &nfsauth_thread
)) {
611 gettext("Failed to create NFSAUTH svc thread\n"));
616 * Create the cmd service thread with same signal disposition
617 * as the main thread. We need to create a separate thread
618 * since mountd() will be both an RPC server (for remote
619 * traffic) _and_ a doors server (for kernel upcalls).
621 if (thr_create(NULL
, 0, cmd_svc
, 0, thr_flags
, &cmd_thread
)) {
622 syslog(LOG_ERR
, gettext("Failed to create CMD svc thread"));
627 * Create an additional thread to service the rmtab and
628 * audit_mountd_mount logging for mount requests. Use the same
629 * signal disposition as the main thread. We create
630 * a separate thread to allow the mount request threads to
631 * clear as soon as possible.
633 if (thr_create(NULL
, 0, logging_svc
, 0, thr_flags
, &logging_thread
)) {
634 syslog(LOG_ERR
, gettext("Failed to create LOGGING svc thread"));
639 * Create datagram and connection oriented services
641 if (mount_vers_max
>= MOUNTVERS
) {
642 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS
, "datagram_v") == 0) {
644 "couldn't register datagram_v MOUNTVERS\n");
647 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS
, "circuit_v") == 0) {
649 "couldn't register circuit_v MOUNTVERS\n");
654 if (mount_vers_max
>= MOUNTVERS_POSIX
) {
655 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS_POSIX
,
656 "datagram_v") == 0) {
658 "couldn't register datagram_v MOUNTVERS_POSIX\n");
661 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS_POSIX
,
664 "couldn't register circuit_v MOUNTVERS_POSIX\n");
669 if (mount_vers_max
>= MOUNTVERS3
) {
670 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS3
, "datagram_v") == 0) {
672 "couldn't register datagram_v MOUNTVERS3\n");
675 if (svc_create(mnt
, MOUNTPROG
, MOUNTVERS3
, "circuit_v") == 0) {
677 "couldn't register circuit_v MOUNTVERS3\n");
687 daemonize_fini(pipe_fd
);
689 /* Get rid of the most dangerous basic privileges. */
690 __fini_daemon_priv(PRIV_PROC_EXEC
, PRIV_PROC_INFO
, PRIV_PROC_SESSION
,
694 syslog(LOG_ERR
, "Error: svc_run shouldn't have returned");
702 * Server procedure switch routine
705 mnt(struct svc_req
*rqstp
, SVCXPRT
*transp
)
707 switch (rqstp
->rq_proc
) {
710 if (!svc_sendreply(transp
, xdr_void
, (char *)0))
711 log_cant_reply(transp
);
719 mntlist_send(transp
);
726 case MOUNTPROC_UMNTALL
:
730 case MOUNTPROC_EXPORT
:
731 case MOUNTPROC_EXPORTALL
:
735 case MOUNTPROC_PATHCONF
:
736 if (rqstp
->rq_vers
== MOUNTVERS_POSIX
)
739 svcerr_noproc(transp
);
743 svcerr_noproc(transp
);
749 log_cant_reply_cln(struct cln
*cln
)
754 saverrno
= errno
; /* save error code */
756 host
= cln_gethost(cln
);
762 syslog(LOG_ERR
, "couldn't send reply to %s", host
);
764 syslog(LOG_ERR
, "couldn't send reply to %s: %m", host
);
768 log_cant_reply(SVCXPRT
*transp
)
773 saverrno
= errno
; /* save error code */
774 cln_init(&cln
, transp
);
777 log_cant_reply_cln(&cln
);
783 * Answer pathconf questions for the mount point fs
786 mnt_pathconf(struct svc_req
*rqstp
)
790 char *path
, rpath
[MAXPATHLEN
];
793 transp
= rqstp
->rq_xprt
;
795 (void) memset((caddr_t
)&p
, 0, sizeof (p
));
797 if (!svc_getargs(transp
, xdr_dirpath
, (caddr_t
)&path
)) {
798 svcerr_decode(transp
);
801 if (lstat(path
, &st
) < 0) {
802 _PC_SET(_PC_ERROR
, p
.pc_mask
);
806 * Get a path without symbolic links.
808 if (realpath(path
, rpath
) == NULL
) {
810 "mount request: realpath failed on %s: %m",
812 _PC_SET(_PC_ERROR
, p
.pc_mask
);
815 (void) memset((caddr_t
)&p
, 0, sizeof (p
));
817 * can't ask about devices over NFS
819 _PC_SET(_PC_MAX_CANON
, p
.pc_mask
);
820 _PC_SET(_PC_MAX_INPUT
, p
.pc_mask
);
821 _PC_SET(_PC_PIPE_BUF
, p
.pc_mask
);
822 _PC_SET(_PC_VDISABLE
, p
.pc_mask
);
825 p
.pc_link_max
= pathconf(rpath
, _PC_LINK_MAX
);
827 _PC_SET(_PC_LINK_MAX
, p
.pc_mask
);
828 p
.pc_name_max
= pathconf(rpath
, _PC_NAME_MAX
);
830 _PC_SET(_PC_NAME_MAX
, p
.pc_mask
);
831 p
.pc_path_max
= pathconf(rpath
, _PC_PATH_MAX
);
833 _PC_SET(_PC_PATH_MAX
, p
.pc_mask
);
834 if (pathconf(rpath
, _PC_NO_TRUNC
) == 1)
835 _PC_SET(_PC_NO_TRUNC
, p
.pc_mask
);
836 if (pathconf(rpath
, _PC_CHOWN_RESTRICTED
) == 1)
837 _PC_SET(_PC_CHOWN_RESTRICTED
, p
.pc_mask
);
841 if (!svc_sendreply(transp
, xdr_ppathcnf
, (char *)&p
))
842 log_cant_reply(transp
);
844 svc_freeargs(transp
, xdr_dirpath
, (caddr_t
)&path
);
848 * If the rootmount (export) option is specified, the all mount requests for
849 * subdirectories return EACCES.
852 checkrootmount(share_t
*sh
, char *rpath
)
856 if ((val
= getshareopt(sh
->sh_opts
, SHOPT_NOSUB
)) != NULL
) {
858 if (strcmp(sh
->sh_path
, rpath
) != 0)
866 #define MAX_FLAVORS 128
869 * Return only EACCES if client does not have access
871 * "If the server exports only /a/b, an attempt to
872 * mount a/b/c will fail with ENOENT if the directory
873 * does not exist"... However, if the client
874 * does not have access to /a/b, an attacker can
875 * determine whether the directory exists.
876 * This routine checks either existence of the file or
877 * existence of the file name entry in the mount table.
878 * If the file exists and there is no file name entry,
879 * the error returned should be EACCES.
880 * If the file does not exist, it must be determined
881 * whether the client has access to a parent
882 * directory. If the client has access to a parent
883 * directory, the error returned should be ENOENT,
887 mount_enoent_error(struct cln
*cln
, char *path
, char *rpath
, int *flavor_list
)
889 char *checkpath
, *dp
;
891 int realpath_error
= ENOENT
, reply_error
= EACCES
, lofs_tried
= 0;
894 checkpath
= strdup(path
);
895 if (checkpath
== NULL
) {
896 syslog(LOG_ERR
, "mount_enoent: no memory");
907 if ((sh
= findentry(rpath
)) == NULL
&&
908 (sh
= find_lofsentry(rpath
, &lofs_tried
)) == NULL
) {
910 * There is no file name entry.
911 * If the file (with symbolic links resolved) exists,
912 * the error returned should be EACCES.
914 if (realpath_error
== 0)
916 } else if (checkrootmount(sh
, rpath
) == 0) {
918 * This is a "nosub" only export, in which case,
919 * mounting subdirectories isn't allowed.
920 * If the file (with symbolic links resolved) exists,
921 * the error returned should be EACCES.
923 if (realpath_error
== 0)
927 * Check permissions in mount table.
929 if (newopts(sh
->sh_opts
))
930 flavor_count
= getclientsflavors_new(sh
, cln
,
933 flavor_count
= getclientsflavors_old(sh
, cln
,
935 if (flavor_count
!= 0) {
937 * Found entry in table and
938 * client has correct permissions.
940 reply_error
= ENOENT
;
946 * Check all parent directories.
948 dp
= strrchr(checkpath
, '/');
952 if (strlen(checkpath
) == 0)
955 * Get the real path (no symbolic links in it)
957 if (realpath(checkpath
, rpath
) == NULL
) {
968 return (reply_error
);
972 * We need to inform the caller whether or not we were
973 * able to add a node to the queue. If we are not, then
974 * it is up to the caller to go ahead and log the data.
977 enqueue_logging_data(char *host
, SVCXPRT
*transp
, char *path
,
978 char *rpath
, int status
, int error
)
983 lq
= (logging_data
*)calloc(1, sizeof (logging_data
));
988 * We might not yet have the host...
991 DTRACE_PROBE1(mountd
, log_host
, host
);
992 lq
->ld_host
= strdup(host
);
993 if (lq
->ld_host
== NULL
)
996 DTRACE_PROBE(mountd
, log_no_host
);
998 lq
->ld_netid
= strdup(transp
->xp_netid
);
999 if (lq
->ld_netid
== NULL
)
1002 lq
->ld_nb
= calloc(1, sizeof (struct netbuf
));
1003 if (lq
->ld_nb
== NULL
)
1006 nb
= svc_getrpccaller(transp
);
1008 DTRACE_PROBE(mountd
, e__nb__enqueue
);
1012 DTRACE_PROBE(mountd
, nb_set_enqueue
);
1014 lq
->ld_nb
->maxlen
= nb
->maxlen
;
1015 lq
->ld_nb
->len
= nb
->len
;
1017 lq
->ld_nb
->buf
= malloc(lq
->ld_nb
->len
);
1018 if (lq
->ld_nb
->buf
== NULL
)
1021 bcopy(nb
->buf
, lq
->ld_nb
->buf
, lq
->ld_nb
->len
);
1024 lq
->ld_path
= strdup(path
);
1025 if (lq
->ld_path
== NULL
)
1029 lq
->ld_rpath
= strdup(rpath
);
1030 if (lq
->ld_rpath
== NULL
)
1034 lq
->ld_status
= status
;
1037 * Add to the tail of the logging queue.
1039 (void) mutex_lock(&logging_queue_lock
);
1040 if (logging_tail
== NULL
) {
1041 logging_tail
= logging_head
= lq
;
1043 logging_tail
->ld_next
= lq
;
1046 (void) cond_signal(&logging_queue_cv
);
1047 (void) mutex_unlock(&logging_queue_lock
);
1053 free_logging_data(lq
);
1059 #define CLN_CLNAMES (1 << 0)
1060 #define CLN_HOST (1 << 1)
1063 cln_init_common(struct cln
*cln
, SVCXPRT
*transp
, char *netid
,
1064 struct netbuf
*nbuf
)
1066 if ((cln
->transp
= transp
) != NULL
) {
1067 assert(netid
== NULL
&& nbuf
== NULL
);
1068 cln
->netid
= transp
->xp_netid
;
1069 cln
->nbuf
= svc_getrpccaller(transp
);
1076 cln
->clnames
= NULL
;
1083 cln_init(struct cln
*cln
, SVCXPRT
*transp
)
1085 cln_init_common(cln
, transp
, NULL
, NULL
);
1089 cln_init_lazy(struct cln
*cln
, char *netid
, struct netbuf
*nbuf
)
1091 cln_init_common(cln
, NULL
, netid
, nbuf
);
1095 cln_fini(struct cln
*cln
)
1097 if (cln
->nconf
!= NULL
)
1098 freenetconfigent(cln
->nconf
);
1100 if (cln
->clnames
!= NULL
)
1101 netdir_free(cln
->clnames
, ND_HOSTSERVLIST
);
1107 cln_getnbuf(struct cln
*cln
)
1112 struct nd_hostservlist
*
1113 cln_getclientsnames(struct cln
*cln
)
1115 if ((cln
->flags
& CLN_CLNAMES
) == 0) {
1117 * nconf is not needed if we do not have nbuf (see
1118 * cln_gethost() too), so we check for nbuf and in a case it is
1119 * NULL we do not try to get nconf.
1121 if (cln
->netid
!= NULL
&& cln
->nbuf
!= NULL
) {
1122 cln
->nconf
= getnetconfigent(cln
->netid
);
1123 if (cln
->nconf
== NULL
)
1124 syslog(LOG_ERR
, "%s: getnetconfigent failed",
1128 if (cln
->nconf
!= NULL
&& cln
->nbuf
!= NULL
)
1129 (void) __netdir_getbyaddr_nosrv(cln
->nconf
,
1130 &cln
->clnames
, cln
->nbuf
);
1132 cln
->flags
|= CLN_CLNAMES
;
1135 return (cln
->clnames
);
1139 * Return B_TRUE if the host is already available at no cost
1142 cln_havehost(struct cln
*cln
)
1144 return ((cln
->flags
& (CLN_CLNAMES
| CLN_HOST
)) != 0);
1148 cln_gethost(struct cln
*cln
)
1150 if (cln_getclientsnames(cln
) != NULL
)
1151 return (cln
->clnames
->h_hostservs
[0].h_host
);
1153 if ((cln
->flags
& CLN_HOST
) == 0) {
1154 if (cln
->nconf
== NULL
|| cln
->nbuf
== NULL
) {
1155 cln
->host
= strdup("(anon)");
1157 char host
[MAXIPADDRLEN
];
1159 if (strcmp(cln
->nconf
->nc_protofmly
, NC_INET
) == 0) {
1160 struct sockaddr_in
*sa
;
1162 /* LINTED pointer alignment */
1163 sa
= (struct sockaddr_in
*)(cln
->nbuf
->buf
);
1164 (void) inet_ntoa_r(sa
->sin_addr
, host
);
1166 cln
->host
= strdup(host
);
1167 } else if (strcmp(cln
->nconf
->nc_protofmly
,
1169 struct sockaddr_in6
*sa
;
1171 /* LINTED pointer alignment */
1172 sa
= (struct sockaddr_in6
*)(cln
->nbuf
->buf
);
1173 (void) inet_ntop(AF_INET6
,
1174 sa
->sin6_addr
.s6_addr
,
1175 host
, INET6_ADDRSTRLEN
);
1177 cln
->host
= strdup(host
);
1179 syslog(LOG_ERR
, gettext("Client's address is "
1180 "neither IPv4 nor IPv6"));
1182 cln
->host
= strdup("(anon)");
1186 cln
->flags
|= CLN_HOST
;
1193 * Check mount requests, add to mounted list if ok
1196 mount(struct svc_req
*rqstp
)
1200 struct fhstatus fhs
;
1201 struct mountres3 mountres3
;
1204 char *path
, rpath
[MAXPATHLEN
];
1208 int error
= 0, lofs_tried
= 0, enqueued
;
1209 int flavor_list
[MAX_FLAVORS
];
1215 transp
= rqstp
->rq_xprt
;
1216 version
= rqstp
->rq_vers
;
1219 if (!svc_getargs(transp
, xdr_dirpath
, (caddr_t
)&path
)) {
1220 svcerr_decode(transp
);
1224 cln_init(&cln
, transp
);
1227 * Put off getting the name for the client until we
1228 * need it. This is a performance gain. If we are logging,
1229 * then we don't care about performance and might as well
1230 * get the host name now in case we need to spit out an
1234 DTRACE_PROBE(mountd
, name_by_verbose
);
1235 if ((host
= cln_gethost(&cln
)) == NULL
) {
1237 * We failed to get a name for the client, even
1238 * 'anon', probably because we ran out of memory.
1239 * In this situation it doesn't make sense to
1240 * allow the mount to succeed.
1248 * If the version being used is less than the minimum version,
1249 * the filehandle translation should not be provided to the
1252 if (rejecting
|| version
< mount_vers_min
) {
1254 syslog(LOG_NOTICE
, "Rejected mount: %s for %s",
1261 * Get the real path (no symbolic links in it)
1263 if (realpath(path
, rpath
) == NULL
) {
1267 "mount request: realpath: %s: %m", path
);
1268 if (error
== ENOENT
)
1269 error
= mount_enoent_error(&cln
, path
, rpath
,
1274 if ((sh
= findentry(rpath
)) == NULL
&&
1275 (sh
= find_lofsentry(rpath
, &lofs_tried
)) == NULL
) {
1281 * Check if this is a "nosub" only export, in which case, mounting
1282 * subdirectories isn't allowed. Bug 1184573.
1284 if (checkrootmount(sh
, rpath
) == 0) {
1289 if (newopts(sh
->sh_opts
))
1290 flavor_count
= getclientsflavors_new(sh
, &cln
, flavor_list
);
1292 flavor_count
= getclientsflavors_old(sh
, &cln
, flavor_list
);
1294 if (flavor_count
== 0) {
1300 * Now get the filehandle.
1302 * NFS V2 clients get a 32 byte filehandle.
1303 * NFS V3 clients get a 32 or 64 byte filehandle, depending on
1304 * the embedded FIDs.
1306 vers
= (version
== MOUNTVERS3
) ? NFS_V3
: NFS_VERSION
;
1308 /* LINTED pointer alignment */
1309 while (nfs_getfh(rpath
, vers
, &len
, fh
) < 0) {
1310 if (errno
== EINVAL
&&
1311 (sh
= find_lofsentry(rpath
, &lofs_tried
)) != NULL
) {
1315 error
= errno
== EINVAL
? EACCES
: errno
;
1316 syslog(LOG_DEBUG
, "mount request: getfh failed on %s: %m",
1321 if (version
== MOUNTVERS3
) {
1322 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_len
= len
;
1323 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_val
= fh
;
1325 bcopy(fh
, &fhs
.fhstatus_u
.fhs_fhandle
, NFS_FHSIZE
);
1334 case MOUNTVERS_POSIX
:
1335 if (error
== EINVAL
)
1336 fhs
.fhs_status
= NFSERR_ACCES
;
1337 else if (error
== EREMOTE
)
1338 fhs
.fhs_status
= NFSERR_REMOTE
;
1340 fhs
.fhs_status
= error
;
1342 if (!svc_sendreply(transp
, xdr_fhstatus
, (char *)&fhs
))
1343 log_cant_reply_cln(&cln
);
1345 audit_status
= fhs
.fhs_status
;
1350 mountres3
.mountres3_u
.mountinfo
.auth_flavors
.auth_flavors_val
=
1352 mountres3
.mountres3_u
.mountinfo
.auth_flavors
.auth_flavors_len
=
1355 } else if (error
== ENAMETOOLONG
)
1356 error
= MNT3ERR_NAMETOOLONG
;
1358 mountres3
.fhs_status
= error
;
1359 if (!svc_sendreply(transp
, xdr_mountres3
, (char *)&mountres3
))
1360 log_cant_reply_cln(&cln
);
1362 audit_status
= mountres3
.fhs_status
;
1366 if (cln_havehost(&cln
))
1367 host
= cln_gethost(&cln
);
1370 syslog(LOG_NOTICE
, "MOUNT: %s %s %s",
1371 (host
== NULL
) ? "unknown host" : host
,
1372 error
? "denied" : "mounted", path
);
1375 * If we can not create a queue entry, go ahead and do it
1376 * in the context of this thread.
1378 enqueued
= enqueue_logging_data(host
, transp
, path
, rpath
,
1379 audit_status
, error
);
1380 if (enqueued
== FALSE
) {
1382 DTRACE_PROBE(mountd
, name_by_in_thread
);
1383 host
= cln_gethost(&cln
);
1386 DTRACE_PROBE(mountd
, logged_in_thread
);
1387 audit_mountd_mount(host
, path
, audit_status
); /* BSM */
1389 mntlist_new(host
, rpath
); /* add entry to mount list */
1393 svc_freeargs(transp
, xdr_dirpath
, (caddr_t
)&path
);
1404 * Determine whether two paths are within the same file system.
1405 * Returns nonzero (true) if paths are the same, zero (false) if
1406 * they are different. If an error occurs, return false.
1408 * Use the actual FSID if it's available (via getattrat()); otherwise,
1409 * fall back on st_dev.
1411 * With ZFS snapshots, st_dev differs from the regular file system
1412 * versus the snapshot. But the fsid is the same throughout. Thus
1413 * the fsid is a better test.
1416 same_file_system(const char *path1
, const char *path2
)
1418 uint64_t fsid1
, fsid2
;
1419 struct stat64 st1
, st2
;
1420 nvlist_t
*nvl1
= NULL
;
1421 nvlist_t
*nvl2
= NULL
;
1423 if ((getattrat(AT_FDCWD
, XATTR_VIEW_READONLY
, path1
, &nvl1
) == 0) &&
1424 (getattrat(AT_FDCWD
, XATTR_VIEW_READONLY
, path2
, &nvl2
) == 0) &&
1425 (nvlist_lookup_uint64(nvl1
, A_FSID
, &fsid1
) == 0) &&
1426 (nvlist_lookup_uint64(nvl2
, A_FSID
, &fsid2
) == 0)) {
1430 * We have found fsid's for both paths.
1443 * We were unable to find fsid's for at least one of the paths.
1444 * fall back on st_dev.
1447 if (stat64(path1
, &st1
) < 0) {
1448 syslog(LOG_NOTICE
, "%s: %m", path1
);
1451 if (stat64(path2
, &st2
) < 0) {
1452 syslog(LOG_NOTICE
, "%s: %m", path2
);
1456 if (st1
.st_dev
== st2
.st_dev
)
1463 findentry(char *path
)
1466 struct sh_list
*shp
;
1471 (void) rw_rdlock(&sharetab_lock
);
1473 for (shp
= share_list
; shp
; shp
= shp
->shl_next
) {
1475 for (p1
= sh
->sh_path
, p2
= path
; *p1
== *p2
; p1
++, p2
++)
1477 goto done
; /* exact match */
1480 * Now compare the pathnames for three cases:
1482 * Parent: /export/foo (no trailing slash on parent)
1483 * Child: /export/foo/bar
1485 * Parent: /export/foo/ (trailing slash on parent)
1486 * Child: /export/foo/bar
1488 * Parent: /export/foo/ (no trailing slash on child)
1489 * Child: /export/foo
1491 if ((*p1
== '\0' && *p2
== '/') ||
1492 (*p1
== '\0' && *(p1
-1) == '/') ||
1493 (*p2
== '\0' && *p1
== '/' && *(p1
+1) == '\0')) {
1495 * We have a subdirectory. Test whether the
1496 * subdirectory is in the same file system.
1498 if (same_file_system(path
, sh
->sh_path
))
1503 sh
= shp
? sharedup(sh
) : NULL
;
1505 (void) rw_unlock(&sharetab_lock
);
1512 is_substring(char **mntp
, char **path
)
1514 char *p1
= *mntp
, *p2
= *path
;
1516 if (*p1
== '\0' && *p2
== '\0') /* exact match */
1518 else if (*p1
== '\0' && *p2
== '/')
1520 else if (*p1
== '\0' && *(p1
-1) == '/') {
1521 *path
= --p2
; /* we need the slash in p2 */
1523 } else if (*p2
== '\0') {
1526 if (*p1
== '\0') /* exact match */
1533 * find_lofsentry() searches for the real path which this requested LOFS path
1534 * (rpath) shadows. If found, it will return the sharetab entry of
1535 * the real path that corresponds to the LOFS path.
1536 * We first search mnttab to see if the requested path is an automounted
1537 * path. If it is an automounted path, it will trigger the mount by stat()ing
1538 * the requested path. Note that it is important to check that this path is
1539 * actually an automounted path, otherwise we would stat() a path which may
1540 * turn out to be NFS and block indefinitely on a dead server. The automounter
1541 * times-out if the server is dead, so there's no risk of hanging this
1542 * thread waiting for stat().
1543 * After the mount has been triggered (if necessary), we look for a
1544 * mountpoint of type LOFS (by searching /etc/mnttab again) which
1545 * is a substring of the rpath. If found, we construct a new path by
1546 * concatenating the mnt_special and the remaining of rpath, call findentry()
1547 * to make sure the 'real path' is shared.
1550 find_lofsentry(char *rpath
, int *done_flag
)
1552 struct stat r_stbuf
;
1553 mntlist_t
*ml
, *mntl
, *mntpnt
= NULL
;
1554 share_t
*retcode
= NULL
;
1555 char tmp_path
[MAXPATHLEN
];
1556 int mntpnt_len
= 0, tmp
;
1563 * While fsgetmntlist() uses lockf() to
1564 * lock the mnttab before reading it in,
1565 * the lock ignores threads in the same process.
1566 * Read in the mnttab with the protection of a mutex.
1568 (void) mutex_lock(&mnttab_lock
);
1569 mntl
= fsgetmntlist();
1570 (void) mutex_unlock(&mnttab_lock
);
1573 * Obtain the mountpoint for the requested path.
1575 for (ml
= mntl
; ml
; ml
= ml
->mntl_next
) {
1576 for (p1
= ml
->mntl_mnt
->mnt_mountp
, p2
= rpath
;
1577 *p1
== *p2
&& *p1
; p1
++, p2
++)
1579 if (is_substring(&p1
, &p2
) &&
1580 (tmp
= strlen(ml
->mntl_mnt
->mnt_mountp
)) >= mntpnt_len
) {
1587 * If the path needs to be autoFS mounted, trigger the mount by
1588 * stat()ing it. This is determined by checking whether the
1589 * mountpoint we just found is of type autofs.
1591 if (mntpnt
!= NULL
&&
1592 strcmp(mntpnt
->mntl_mnt
->mnt_fstype
, "autofs") == 0) {
1594 * The requested path is a substring of an autoFS filesystem.
1595 * Trigger the mount.
1597 if (stat(rpath
, &r_stbuf
) < 0) {
1599 syslog(LOG_NOTICE
, "%s: %m", rpath
);
1602 if ((r_stbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
1604 * The requested path is a directory, stat(2) it
1605 * again with a trailing '.' to force the autoFS
1606 * module to trigger the mount of indirect
1607 * automount entries, such as /net/jurassic/.
1609 if (strlen(rpath
) + 2 > MAXPATHLEN
) {
1612 "%s/.: exceeds MAXPATHLEN %d",
1617 (void) strcpy(tmp_path
, rpath
);
1618 (void) strcat(tmp_path
, "/.");
1620 if (stat(tmp_path
, &r_stbuf
) < 0) {
1622 syslog(LOG_NOTICE
, "%s: %m", tmp_path
);
1628 * The mount has been triggered, re-read mnttab to pick up
1629 * the changes made by autoFS.
1631 fsfreemntlist(mntl
);
1632 (void) mutex_lock(&mnttab_lock
);
1633 mntl
= fsgetmntlist();
1634 (void) mutex_unlock(&mnttab_lock
);
1638 * The autoFS mountpoint has been triggered if necessary,
1639 * now search mnttab again to determine if the requested path
1640 * is an LOFS mount of a shared path.
1643 for (ml
= mntl
; ml
; ml
= ml
->mntl_next
) {
1644 if (strcmp(ml
->mntl_mnt
->mnt_fstype
, "lofs"))
1647 for (p1
= ml
->mntl_mnt
->mnt_mountp
, p2
= rpath
;
1648 *p1
== *p2
&& *p1
; p1
++, p2
++)
1651 if (is_substring(&p1
, &p2
) &&
1652 ((tmp
= strlen(ml
->mntl_mnt
->mnt_mountp
)) >= mntpnt_len
)) {
1655 if ((strlen(ml
->mntl_mnt
->mnt_special
) + strlen(p2
)) >
1658 syslog(LOG_NOTICE
, "%s%s: exceeds %d",
1659 ml
->mntl_mnt
->mnt_special
, p2
,
1668 (void) strcpy(tmp_path
, ml
->mntl_mnt
->mnt_special
);
1669 (void) strcat(tmp_path
, p2
);
1672 retcode
= findentry(tmp_path
);
1677 assert(strlen(tmp_path
) > 0);
1678 (void) strcpy(rpath
, tmp_path
);
1682 fsfreemntlist(mntl
);
1687 * Determine whether an access list grants rights to a particular host.
1688 * We match on aliases of the hostname as well as on the canonical name.
1689 * Names in the access list may be either hosts or netgroups; they're
1690 * not distinguished syntactically. We check for hosts first because
1691 * it's cheaper, then try netgroups.
1694 * 1 - access is granted
1695 * 0 - access is denied
1696 * -1 - an error occured
1699 in_access_list(struct cln
*cln
,
1700 char *access_list
) /* N.B. we clobber this "input" parameter */
1702 char addr
[INET_ADDRSTRLEN
];
1705 char *cstr
= access_list
;
1706 char *gr
= access_list
;
1711 struct nd_hostservlist
*clnames
= NULL
;
1713 /* If no access list - then it's unrestricted */
1714 if (access_list
== NULL
|| *access_list
== '\0')
1717 if ((pnb
= cln_getnbuf(cln
)) == NULL
)
1721 if ((cstr
= strpbrk(cstr
, "[:")) != NULL
) {
1725 assert(*cstr
== '[');
1726 cstr
= strchr(cstr
+ 1, ']');
1735 * If the list name has a '-' prepended then a match of
1736 * the following name implies failure instead of success.
1746 * First check if we have '@' entry, as it doesn't
1747 * require client hostname.
1752 /* Netname support */
1753 if (!isdigit(*gr
) && *gr
!= '[') {
1754 struct netent n
, *np
;
1756 if ((np
= getnetbyname_r(gr
, &n
, buff
,
1757 sizeof (buff
))) != NULL
&&
1759 while ((np
->n_net
& 0xFF000000u
) == 0)
1761 np
->n_net
= htonl(np
->n_net
);
1762 if (inet_ntop(AF_INET
, &np
->n_net
, addr
,
1763 INET_ADDRSTRLEN
) == NULL
)
1765 ret
= inet_matchaddr(pnb
->buf
, addr
);
1767 if (errno
== EINVAL
) {
1774 } else if (ret
== 1) {
1779 ret
= inet_matchaddr(pnb
->buf
, gr
);
1781 if (errno
== EINVAL
) {
1783 "invalid access list "
1787 } else if (ret
== 1) {
1796 * No other checks can be performed if client address
1797 * can't be resolved.
1799 if ((clnames
= cln_getclientsnames(cln
)) == NULL
)
1802 /* Otherwise loop through all client hostname aliases */
1803 for (i
= 0; i
< clnames
->h_cnt
; i
++) {
1804 char *host
= clnames
->h_hostservs
[i
].h_host
;
1807 * If the list name begins with a dot then
1808 * do a domain name suffix comparison.
1809 * A single dot matches any name with no
1813 if (*(gr
+ 1) == '\0') { /* single dot */
1814 if (strchr(host
, '.') == NULL
)
1817 int off
= strlen(host
) - strlen(gr
);
1819 strcasecmp(host
+ off
, gr
) == 0) {
1824 /* Just do a hostname match */
1825 if (strcasecmp(gr
, host
) == 0)
1839 if (clnames
== NULL
)
1842 return (netgroup_check(clnames
, access_list
, nentries
));
1846 static char *optlist
[] = {
1853 #define OPT_SECURE 3
1857 #define OPT_WINDOW 5
1859 #define OPT_NOSUID 6
1867 #define OPT_UIDMAP 10
1869 #define OPT_GIDMAP 11
1875 map_flavor(char *str
)
1879 if (nfs_getseconfig_byname(str
, &sec
))
1882 return (sec
.sc_nfsnum
);
1886 * If the option string contains a "sec="
1887 * option, then use new option syntax.
1892 char *head
, *p
, *val
;
1894 if (!opts
|| *opts
== '\0')
1897 head
= strdup(opts
);
1899 syslog(LOG_ERR
, "opts: no memory");
1905 if (getsubopt(&p
, optlist
, &val
) == OPT_SEC
) {
1916 * Given an export and the clients hostname(s)
1917 * determine the security flavors that this
1918 * client is permitted to use.
1920 * This routine is called only for "old" syntax, i.e.
1921 * only one security flavor is allowed. So we need
1922 * to determine two things: the particular flavor,
1923 * and whether the client is allowed to use this
1924 * flavor, i.e. is in the access list.
1926 * Note that if there is no access list, then the
1927 * default is that access is granted.
1930 getclientsflavors_old(share_t
*sh
, struct cln
*cln
, int *flavors
)
1932 char *opts
, *p
, *val
;
1933 boolean_t ok
= B_FALSE
;
1934 int defaultaccess
= 1;
1935 boolean_t reject
= B_FALSE
;
1937 opts
= strdup(sh
->sh_opts
);
1939 syslog(LOG_ERR
, "getclientsflavors: no memory");
1943 flavors
[0] = AUTH_SYS
;
1948 switch (getsubopt(&p
, optlist
, &val
)) {
1950 flavors
[0] = AUTH_DES
;
1956 if (in_access_list(cln
, val
) > 0)
1962 if (in_access_list(cln
, val
) > 0)
1969 /* none takes precedence over everything else */
1973 return (defaultaccess
|| ok
);
1977 * Given an export and the clients hostname(s)
1978 * determine the security flavors that this
1979 * client is permitted to use.
1981 * This is somewhat more complicated than the "old"
1982 * routine because the options may contain multiple
1983 * security flavors (sec=) each with its own access
1984 * lists. So a client could be granted access based
1985 * on a number of security flavors. Note that the
1986 * type of access might not always be the same, the
1987 * client may get readonly access with one flavor
1988 * and readwrite with another, however the client
1989 * is not told this detail, it gets only the list
1990 * of flavors, and only if the client is using
1991 * version 3 of the mount protocol.
1994 getclientsflavors_new(share_t
*sh
, struct cln
*cln
, int *flavors
)
1996 char *opts
, *p
, *val
;
1999 boolean_t defaultaccess
= B_TRUE
; /* default access is rw */
2000 boolean_t access_ok
= B_FALSE
;
2002 boolean_t reject
= B_FALSE
;
2004 opts
= strdup(sh
->sh_opts
);
2006 syslog(LOG_ERR
, "getclientsflavors: no memory");
2014 switch (getsubopt(&p
, optlist
, &val
)) {
2017 access_ok
= B_FALSE
;
2020 * Before a new sec=xxx option, check if we need
2021 * to move the c index back to the previous count.
2023 if (!defaultaccess
&& !access_ok
) {
2027 /* get all the sec=f1[:f2] flavors */
2028 while ((f
= strtok_r(val
, ":", &lasts
)) != NULL
) {
2029 flavors
[c
++] = map_flavor(f
);
2033 /* for a new sec=xxx option, default is rw access */
2034 defaultaccess
= B_TRUE
;
2035 access_ok
= B_FALSE
;
2041 defaultaccess
= B_FALSE
;
2042 if (in_access_list(cln
, val
) > 0)
2047 defaultaccess
= B_FALSE
;
2048 if (in_access_list(cln
, val
) > 0)
2049 reject
= B_TRUE
; /* none overides rw/ro */
2055 access_ok
= B_FALSE
;
2057 if (!defaultaccess
&& !access_ok
)
2066 * This is a tricky piece of code that parses the
2067 * share options looking for a match on the auth
2068 * flavor that the client is using. If it finds
2069 * a match, then the client is given ro, rw, or
2070 * no access depending whether it is in the access
2071 * list. There is a special case for "secure"
2072 * flavor. Other flavors are values of the new "sec=" option.
2075 check_client(share_t
*sh
, struct cln
*cln
, int flavor
, uid_t clnt_uid
,
2076 gid_t clnt_gid
, uint_t clnt_ngids
, gid_t
*clnt_gids
, uid_t
*srv_uid
,
2077 gid_t
*srv_gid
, uint_t
*srv_ngids
, gid_t
**srv_gids
)
2079 if (newopts(sh
->sh_opts
))
2080 return (check_client_new(sh
, cln
, flavor
, clnt_uid
, clnt_gid
,
2081 clnt_ngids
, clnt_gids
, srv_uid
, srv_gid
, srv_ngids
,
2084 return (check_client_old(sh
, cln
, flavor
, clnt_uid
, clnt_gid
,
2085 clnt_ngids
, clnt_gids
, srv_uid
, srv_gid
, srv_ngids
,
2089 extern int _getgroupsbymember(const char *, gid_t
[], int, int);
2092 * Get supplemental groups for uid
2095 getusergroups(uid_t uid
, uint_t
*ngrps
, gid_t
**grps
)
2098 char *pwbuf
= alloca(pw_size
);
2099 gid_t
*tmpgrps
= alloca(ngroups_max
* sizeof (gid_t
));
2101 struct passwd
*result
;
2103 getpwuid_r(uid
, &pwd
, pwbuf
, pw_size
, &result
);
2107 tmpgrps
[0] = pwd
.pw_gid
;
2109 tmpngrps
= _getgroupsbymember(pwd
.pw_name
, tmpgrps
, ngroups_max
, 1);
2110 if (tmpngrps
<= 0) {
2112 "getusergroups(): Unable to get groups for user %s",
2118 *grps
= malloc(tmpngrps
* sizeof (gid_t
));
2119 if (*grps
== NULL
) {
2121 "getusergroups(): Memory allocation failed: %m");
2127 (void) memcpy(*grps
, tmpgrps
, tmpngrps
* sizeof (gid_t
));
2133 * is_a_number(number)
2135 * is the string a number in one of the forms we want to use?
2139 is_a_number(char *number
)
2144 if (strncmp(number
, "0x", 2) == 0) {
2147 } else if (*number
== '-') {
2148 number
++; /* skip the minus */
2150 while (ret
== 1 && *number
!= '\0') {
2152 ret
= isxdigit(*number
++);
2154 ret
= isdigit(*number
++);
2161 get_uid(char *value
, uid_t
*uid
)
2163 if (!is_a_number(value
)) {
2166 * in this case it would have to be a
2169 pw
= getpwnam(value
);
2176 intval
= strtoull(value
, NULL
, 0);
2177 if (intval
> UID_MAX
&& intval
!= -1)
2179 *uid
= (uid_t
)intval
;
2186 get_gid(char *value
, gid_t
*gid
)
2188 if (!is_a_number(value
)) {
2191 * in this case it would have to be a
2194 gr
= getgrnam(value
);
2201 intval
= strtoull(value
, NULL
, 0);
2202 if (intval
> UID_MAX
&& intval
!= -1)
2204 *gid
= (gid_t
)intval
;
2211 check_client_old(share_t
*sh
, struct cln
*cln
, int flavor
, uid_t clnt_uid
,
2212 gid_t clnt_gid
, uint_t clnt_ngids
, gid_t
*clnt_gids
, uid_t
*srv_uid
,
2213 gid_t
*srv_gid
, uint_t
*srv_ngids
, gid_t
**srv_gids
)
2215 char *opts
, *p
, *val
;
2216 int match
; /* Set when a flavor is matched */
2217 int perm
= 0; /* Set when "ro", "rw" or "root" is matched */
2218 int list
= 0; /* Set when "ro", "rw" is found */
2219 int ro_val
= 0; /* Set if ro option is 'ro=' */
2220 int rw_val
= 0; /* Set if rw option is 'rw=' */
2222 boolean_t map_deny
= B_FALSE
;
2224 opts
= strdup(sh
->sh_opts
);
2226 syslog(LOG_ERR
, "check_client: no memory");
2231 * If client provided 16 supplemental groups with AUTH_SYS, lookup
2232 * locally for all of them
2234 if (flavor
== AUTH_SYS
&& clnt_ngids
== NGRPS
&& ngroups_max
> NGRPS
)
2235 if (getusergroups(clnt_uid
, srv_ngids
, srv_gids
) == 0)
2236 perm
|= NFSAUTH_GROUPS
;
2242 switch (getsubopt(&p
, optlist
, &val
)) {
2247 if (perm
& NFSAUTH_GROUPS
) {
2251 perm
&= ~NFSAUTH_GROUPS
;
2260 if (in_access_list(cln
, val
) > 0)
2268 if (in_access_list(cln
, val
) > 0)
2274 * Check if the client is in
2275 * the root list. Only valid
2278 if (flavor
!= AUTH_SYS
)
2281 if (val
== NULL
|| *val
== '\0')
2287 if (in_access_list(cln
, val
) > 0) {
2288 perm
|= NFSAUTH_ROOT
;
2289 perm
|= NFSAUTH_UIDMAP
| NFSAUTH_GIDMAP
;
2292 if (perm
& NFSAUTH_GROUPS
) {
2296 perm
&= ~NFSAUTH_GROUPS
;
2303 * Check if the client should have no access
2304 * to this share at all. This option behaves
2305 * more like "root" than either "rw" or "ro".
2307 if (in_access_list(cln
, val
) > 0)
2308 perm
|= NFSAUTH_DENIED
;
2316 * The uidmap is supported for AUTH_SYS only.
2318 if (flavor
!= AUTH_SYS
)
2321 if (perm
& NFSAUTH_UIDMAP
|| map_deny
)
2324 for (c
= val
; c
!= NULL
; c
= n
) {
2336 al
= strchr(s
, ':');
2341 if (s
== NULL
|| al
== NULL
)
2345 if (clnt_uid
!= (uid_t
)-1)
2347 } else if (strcmp(c
, "*") != 0) {
2350 if (!get_uid(c
, &clnt
))
2353 if (clnt_uid
!= clnt
)
2359 else if (!get_uid(s
, &srv
))
2361 else if (srv
== (uid_t
)-1) {
2366 if (in_access_list(cln
, al
) > 0) {
2368 perm
|= NFSAUTH_UIDMAP
;
2370 if (perm
& NFSAUTH_GROUPS
) {
2374 perm
&= ~NFSAUTH_GROUPS
;
2389 * The gidmap is supported for AUTH_SYS only.
2391 if (flavor
!= AUTH_SYS
)
2394 if (perm
& NFSAUTH_GIDMAP
|| map_deny
)
2397 for (c
= val
; c
!= NULL
; c
= n
) {
2409 al
= strchr(s
, ':');
2414 if (s
== NULL
|| al
== NULL
)
2418 if (clnt_gid
!= (gid_t
)-1)
2420 } else if (strcmp(c
, "*") != 0) {
2423 if (!get_gid(c
, &clnt
))
2426 if (clnt_gid
!= clnt
)
2432 else if (!get_gid(s
, &srv
))
2434 else if (srv
== (gid_t
)-1) {
2439 if (in_access_list(cln
, al
) > 0) {
2441 perm
|= NFSAUTH_GIDMAP
;
2443 if (perm
& NFSAUTH_GROUPS
) {
2447 perm
&= ~NFSAUTH_GROUPS
;
2464 if (perm
& NFSAUTH_ROOT
) {
2470 perm
|= NFSAUTH_DENIED
;
2472 if (!(perm
& NFSAUTH_UIDMAP
))
2473 *srv_uid
= clnt_uid
;
2474 if (!(perm
& NFSAUTH_GIDMAP
))
2475 *srv_gid
= clnt_gid
;
2477 if (flavor
!= match
|| perm
& NFSAUTH_DENIED
)
2478 return (NFSAUTH_DENIED
);
2482 * If the client doesn't match an "ro" or "rw"
2483 * list then set no access.
2485 if ((perm
& (NFSAUTH_RO
| NFSAUTH_RW
)) == 0)
2486 perm
|= NFSAUTH_DENIED
;
2489 * The client matched a flavor entry that
2490 * has no explicit "rw" or "ro" determination.
2491 * Default it to "rw".
2497 * The client may show up in both ro= and rw=
2498 * lists. If so, then turn off the RO access
2499 * bit leaving RW access.
2501 if (perm
& NFSAUTH_RO
&& perm
& NFSAUTH_RW
) {
2503 * Logically cover all permutations of rw=,ro=.
2504 * In the case where, rw,ro=<host> we would like
2505 * to remove RW access for the host. In all other cases
2506 * RW wins the precedence battle.
2508 if (!rw_val
&& ro_val
) {
2509 perm
&= ~(NFSAUTH_RW
);
2511 perm
&= ~(NFSAUTH_RO
);
2519 * Check if the client has access by using a flavor different from
2520 * the given "flavor". If "flavor" is not in the flavor list,
2521 * return TRUE to indicate that this "flavor" is a wrong sec.
2524 is_wrongsec(share_t
*sh
, struct cln
*cln
, int flavor
)
2526 int flavor_list
[MAX_FLAVORS
];
2527 int flavor_count
, i
;
2529 /* get the flavor list that the client has access with */
2530 flavor_count
= getclientsflavors_new(sh
, cln
, flavor_list
);
2532 if (flavor_count
== 0)
2536 * Check if the given "flavor" is in the flavor_list.
2538 for (i
= 0; i
< flavor_count
; i
++) {
2539 if (flavor
== flavor_list
[i
])
2544 * If "flavor" is not in the flavor_list, return TRUE to indicate
2545 * that the client should have access by using a security flavor
2546 * different from this "flavor".
2552 * Given an export and the client's hostname, we
2553 * check the security options to see whether the
2554 * client is allowed to use the given security flavor.
2556 * The strategy is to proceed through the options looking
2557 * for a flavor match, then pay attention to the ro, rw,
2560 * Note that an entry may list several flavors in a
2561 * single entry, e.g.
2563 * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
2568 check_client_new(share_t
*sh
, struct cln
*cln
, int flavor
, uid_t clnt_uid
,
2569 gid_t clnt_gid
, uint_t clnt_ngids
, gid_t
*clnt_gids
, uid_t
*srv_uid
,
2570 gid_t
*srv_gid
, uint_t
*srv_ngids
, gid_t
**srv_gids
)
2572 char *opts
, *p
, *val
;
2575 int match
= 0; /* Set when a flavor is matched */
2576 int perm
= 0; /* Set when "ro", "rw" or "root" is matched */
2577 int list
= 0; /* Set when "ro", "rw" is found */
2578 int ro_val
= 0; /* Set if ro option is 'ro=' */
2579 int rw_val
= 0; /* Set if rw option is 'rw=' */
2581 boolean_t map_deny
= B_FALSE
;
2583 opts
= strdup(sh
->sh_opts
);
2585 syslog(LOG_ERR
, "check_client: no memory");
2590 * If client provided 16 supplemental groups with AUTH_SYS, lookup
2591 * locally for all of them
2593 if (flavor
== AUTH_SYS
&& clnt_ngids
== NGRPS
&& ngroups_max
> NGRPS
)
2594 if (getusergroups(clnt_uid
, srv_ngids
, srv_gids
) == 0)
2595 perm
|= NFSAUTH_GROUPS
;
2600 switch (getsubopt(&p
, optlist
, &val
)) {
2606 while ((f
= strtok_r(val
, ":", &lasts
))
2608 if (flavor
== map_flavor(f
)) {
2623 if (in_access_list(cln
, val
) > 0)
2634 if (in_access_list(cln
, val
) > 0)
2640 * Check if the client is in
2641 * the root list. Only valid
2644 if (flavor
!= AUTH_SYS
)
2650 if (val
== NULL
|| *val
== '\0')
2656 if (in_access_list(cln
, val
) > 0) {
2657 perm
|= NFSAUTH_ROOT
;
2658 perm
|= NFSAUTH_UIDMAP
| NFSAUTH_GIDMAP
;
2661 if (perm
& NFSAUTH_GROUPS
) {
2665 perm
&= ~NFSAUTH_GROUPS
;
2672 * Check if the client should have no access
2673 * to this share at all. This option behaves
2674 * more like "root" than either "rw" or "ro".
2676 if (in_access_list(cln
, val
) > 0)
2677 perm
|= NFSAUTH_DENIED
;
2685 * The uidmap is supported for AUTH_SYS only.
2687 if (flavor
!= AUTH_SYS
)
2690 if (!match
|| perm
& NFSAUTH_UIDMAP
|| map_deny
)
2693 for (c
= val
; c
!= NULL
; c
= n
) {
2705 al
= strchr(s
, ':');
2710 if (s
== NULL
|| al
== NULL
)
2714 if (clnt_uid
!= (uid_t
)-1)
2716 } else if (strcmp(c
, "*") != 0) {
2719 if (!get_uid(c
, &clnt
))
2722 if (clnt_uid
!= clnt
)
2728 else if (!get_uid(s
, &srv
))
2730 else if (srv
== (uid_t
)-1) {
2735 if (in_access_list(cln
, al
) > 0) {
2737 perm
|= NFSAUTH_UIDMAP
;
2739 if (perm
& NFSAUTH_GROUPS
) {
2743 perm
&= ~NFSAUTH_GROUPS
;
2758 * The gidmap is supported for AUTH_SYS only.
2760 if (flavor
!= AUTH_SYS
)
2763 if (!match
|| perm
& NFSAUTH_GIDMAP
|| map_deny
)
2766 for (c
= val
; c
!= NULL
; c
= n
) {
2778 al
= strchr(s
, ':');
2783 if (s
== NULL
|| al
== NULL
)
2787 if (clnt_gid
!= (gid_t
)-1)
2789 } else if (strcmp(c
, "*") != 0) {
2792 if (!get_gid(c
, &clnt
))
2795 if (clnt_gid
!= clnt
)
2801 else if (!get_gid(s
, &srv
))
2803 else if (srv
== (gid_t
)-1) {
2808 if (in_access_list(cln
, al
) > 0) {
2810 perm
|= NFSAUTH_GIDMAP
;
2812 if (perm
& NFSAUTH_GROUPS
) {
2816 perm
&= ~NFSAUTH_GROUPS
;
2832 if (perm
& NFSAUTH_ROOT
) {
2838 perm
|= NFSAUTH_DENIED
;
2840 if (!(perm
& NFSAUTH_UIDMAP
))
2841 *srv_uid
= clnt_uid
;
2842 if (!(perm
& NFSAUTH_GIDMAP
))
2843 *srv_gid
= clnt_gid
;
2846 * If no match then set the perm accordingly
2848 if (!match
|| perm
& NFSAUTH_DENIED
) {
2850 return (NFSAUTH_DENIED
);
2855 * If the client doesn't match an "ro" or "rw" list then
2856 * check if it may have access by using a different flavor.
2857 * If so, return NFSAUTH_WRONGSEC.
2858 * If not, return NFSAUTH_DENIED.
2860 if ((perm
& (NFSAUTH_RO
| NFSAUTH_RW
)) == 0) {
2861 if (is_wrongsec(sh
, cln
, flavor
))
2862 perm
|= NFSAUTH_WRONGSEC
;
2864 perm
|= NFSAUTH_DENIED
;
2868 * The client matched a flavor entry that
2869 * has no explicit "rw" or "ro" determination.
2870 * Make sure it defaults to "rw".
2876 * The client may show up in both ro= and rw=
2877 * lists. If so, then turn off the RO access
2878 * bit leaving RW access.
2880 if (perm
& NFSAUTH_RO
&& perm
& NFSAUTH_RW
) {
2882 * Logically cover all permutations of rw=,ro=.
2883 * In the case where, rw,ro=<host> we would like
2884 * to remove RW access for the host. In all other cases
2885 * RW wins the precedence battle.
2887 if (!rw_val
&& ro_val
) {
2888 perm
&= ~(NFSAUTH_RW
);
2890 perm
&= ~(NFSAUTH_RO
);
2904 static timestruc_t last_sharetab_time
;
2905 timestruc_t prev_sharetab_time
;
2907 struct sh_list
*shp
, *shp_prev
;
2911 * read in /etc/dfs/sharetab if it has changed
2913 if (stat(SHARETAB
, &st
) != 0) {
2914 syslog(LOG_ERR
, "Cannot stat %s: %m", SHARETAB
);
2918 if (st
.st_mtim
.tv_sec
== last_sharetab_time
.tv_sec
&&
2919 st
.st_mtim
.tv_nsec
== last_sharetab_time
.tv_nsec
) {
2927 * Remember the mod time, then after getting the
2928 * write lock check again. If another thread
2929 * already did the update, then there's no
2932 prev_sharetab_time
= last_sharetab_time
;
2934 (void) rw_wrlock(&sharetab_lock
);
2936 if (prev_sharetab_time
.tv_sec
!= last_sharetab_time
.tv_sec
||
2937 prev_sharetab_time
.tv_nsec
!= last_sharetab_time
.tv_nsec
) {
2938 (void) rw_unlock(&sharetab_lock
);
2943 * Note that since the sharetab is now in memory
2944 * and a snapshot is taken, we no longer have to
2947 f
= fopen(SHARETAB
, "r");
2949 syslog(LOG_ERR
, "Cannot open %s: %m", SHARETAB
);
2950 (void) rw_unlock(&sharetab_lock
);
2955 * Once we are sure /etc/dfs/sharetab has been
2956 * modified, flush netgroup cache entries.
2958 netgrp_cache_flush();
2960 sh_free(share_list
); /* free old list */
2963 while ((res
= getshare(f
, &sh
)) > 0) {
2965 if (strcmp(sh
->sh_fstype
, "nfs") != 0)
2968 shp
= malloc(sizeof (*shp
));
2971 if (share_list
== NULL
)
2974 /* LINTED not used before set */
2975 shp_prev
->shl_next
= shp
;
2977 shp
->shl_next
= NULL
;
2978 shp
->shl_sh
= sharedup(sh
);
2979 if (shp
->shl_sh
== NULL
)
2984 syslog(LOG_ERR
, "%s: invalid at line %d\n",
2987 if (stat(SHARETAB
, &st
) != 0) {
2988 syslog(LOG_ERR
, "Cannot stat %s: %m", SHARETAB
);
2990 (void) rw_unlock(&sharetab_lock
);
2994 last_sharetab_time
= st
.st_mtim
;
2996 (void) rw_unlock(&sharetab_lock
);
3002 syslog(LOG_ERR
, "check_sharetab: no memory");
3003 sh_free(share_list
);
3006 (void) rw_unlock(&sharetab_lock
);
3010 sh_free(struct sh_list
*shp
)
3012 struct sh_list
*next
;
3015 sharefree(shp
->shl_sh
);
3016 next
= shp
->shl_next
;
3024 * Remove an entry from mounted list
3027 umount(struct svc_req
*rqstp
)
3029 char *host
, *path
, *remove_path
;
3030 char rpath
[MAXPATHLEN
];
3034 transp
= rqstp
->rq_xprt
;
3036 if (!svc_getargs(transp
, xdr_dirpath
, (caddr_t
)&path
)) {
3037 svcerr_decode(transp
);
3041 cln_init(&cln
, transp
);
3044 if (!svc_sendreply(transp
, xdr_void
, NULL
))
3045 log_cant_reply_cln(&cln
);
3047 host
= cln_gethost(&cln
);
3050 * Without the hostname we can't do audit or delete
3051 * this host from the mount entries.
3053 svc_freeargs(transp
, xdr_dirpath
, (caddr_t
)&path
);
3058 syslog(LOG_NOTICE
, "UNMOUNT: %s unmounted %s", host
, path
);
3060 audit_mountd_umount(host
, path
);
3062 remove_path
= rpath
; /* assume we will use the cannonical path */
3063 if (realpath(path
, rpath
) == NULL
) {
3065 syslog(LOG_WARNING
, "UNMOUNT: realpath: %s: %m ", path
);
3066 remove_path
= path
; /* use path provided instead */
3069 mntlist_delete(host
, remove_path
); /* remove from mount list */
3073 svc_freeargs(transp
, xdr_dirpath
, (caddr_t
)&path
);
3077 * Remove all entries for one machine from mounted list
3080 umountall(struct svc_req
*rqstp
)
3086 transp
= rqstp
->rq_xprt
;
3087 if (!svc_getargs(transp
, xdr_void
, NULL
)) {
3088 svcerr_decode(transp
);
3092 * We assume that this call is asynchronous and made via rpcbind
3093 * callit routine. Therefore return control immediately. The error
3094 * causes rpcbind to remain silent, as opposed to every machine
3095 * on the net blasting the requester with a response.
3097 svcerr_systemerr(transp
);
3099 cln_init(&cln
, transp
);
3101 host
= cln_gethost(&cln
);
3103 /* Can't do anything without the name of the client */
3108 * Remove all hosts entries from mount list
3110 mntlist_delete_all(host
);
3113 syslog(LOG_NOTICE
, "UNMOUNTALL: from %s", host
);
3119 exmalloc(size_t size
)
3123 if ((ret
= malloc(size
)) == NULL
) {
3124 syslog(LOG_ERR
, "Out of memory");