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