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