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