4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
25 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 /*
32 * Portions of this source code were derived from Berkeley 4.3 BSD
33 * under license from the Regents of the University of California.
34 */
35
36 #include <stdio.h>
37 #include <stdio_ext.h>
38 #include <stdlib.h>
39 #include <ctype.h>
40 #include <sys/types.h>
41 #include <string.h>
42 #include <syslog.h>
43 #include <sys/param.h>
44 #include <rpc/rpc.h>
45 #include <sys/stat.h>
46 #include <netconfig.h>
47 #include <netdir.h>
48 #include <sys/file.h>
49 #include <sys/time.h>
50 #include <sys/errno.h>
51 #include <rpcsvc/mount.h>
52 #include <sys/pathconf.h>
53 #include <sys/systeminfo.h>
54 #include <sys/utsname.h>
55 #include <sys/wait.h>
56 #include <sys/resource.h>
57 #include <signal.h>
58 #include <locale.h>
59 #include <unistd.h>
60 #include <errno.h>
61 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <arpa/inet.h>
64 #include <netdb.h>
65 #include <thread.h>
66 #include <assert.h>
67 #include <priv_utils.h>
68 #include <nfs/auth.h>
69 #include <nfs/nfssys.h>
70 #include <nfs/nfs.h>
71 #include <nfs/nfs_sec.h>
72 #include <rpcsvc/daemon_utils.h>
73 #include <deflt.h>
74 #include "../../fslib.h"
75 #include <sharefs/share.h>
76 #include <sharefs/sharetab.h>
77 #include "../lib/sharetab.h"
78 #include "mountd.h"
79 #include <tsol/label.h>
80 #include <sys/tsol/label_macro.h>
81 #include <libtsnet.h>
82 #include <sys/sdt.h>
83 #include <libscf.h>
84 #include <limits.h>
85 #include <sys/nvpair.h>
86 #include <attr.h>
87 #include "smfcfg.h"
88 #include <pwd.h>
89 #include <grp.h>
90 #include <alloca.h>
91
92 extern int daemonize_init(void);
93 extern void daemonize_fini(int);
94
95 extern int _nfssys(int, void *);
96
97 struct sh_list *share_list;
98
99 rwlock_t sharetab_lock; /* lock to protect the cached sharetab */
100 static mutex_t mnttab_lock; /* prevent concurrent mnttab readers */
101
102 static mutex_t logging_queue_lock;
103 static cond_t logging_queue_cv;
104
105 static share_t *find_lofsentry(char *, int *);
106 static int getclientsflavors_old(share_t *, struct cln *, int *);
107 static int getclientsflavors_new(share_t *, struct cln *, int *);
108 static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
109 gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
110 static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
112 static void mnt(struct svc_req *, SVCXPRT *);
113 static void mnt_pathconf(struct svc_req *);
114 static int mount(struct svc_req *r);
115 static void sh_free(struct sh_list *);
116 static void umount(struct svc_req *);
117 static void umountall(struct svc_req *);
118 static int newopts(char *);
119 static tsol_tpent_t *get_client_template(struct sockaddr *);
120
121 static int debug;
122 static int verbose;
123 static int rejecting;
124 static int mount_vers_min = MOUNTVERS;
125 static int mount_vers_max = MOUNTVERS3;
126 static int mountd_port = 0;
127
128 extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
129
130 thread_t nfsauth_thread;
131 thread_t cmd_thread;
132 thread_t logging_thread;
133
134 typedef struct logging_data {
135 char *ld_host;
136 char *ld_path;
137 char *ld_rpath;
138 int ld_status;
139 char *ld_netid;
140 struct netbuf *ld_nb;
141 struct logging_data *ld_next;
142 } logging_data;
143
144 static logging_data *logging_head = NULL;
145 static logging_data *logging_tail = NULL;
146
147 /*
148 * Our copy of some system variables obtained using sysconf(3c)
149 */
150 static long ngroups_max; /* _SC_NGROUPS_MAX */
151 static long pw_size; /* _SC_GETPW_R_SIZE_MAX */
152
153 /* ARGSUSED */
154 static void *
155 nfsauth_svc(void *arg)
156 {
157 int doorfd = -1;
158 uint_t darg;
159 #ifdef DEBUG
160 int dfd;
161 #endif
162
163 if ((doorfd = door_create(nfsauth_func, NULL,
164 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
165 syslog(LOG_ERR, "Unable to create door: %m\n");
166 exit(10);
167 }
168
169 #ifdef DEBUG
170 /*
171 * Create a file system path for the door
172 */
173 if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
174 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
175 syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
176 (void) close(doorfd);
177 exit(11);
178 }
179
180 /*
181 * Clean up any stale namespace associations
182 */
183 (void) fdetach(MOUNTD_DOOR);
184
185 /*
186 * Register in namespace to pass to the kernel to door_ki_open
187 */
188 if (fattach(doorfd, MOUNTD_DOOR) == -1) {
189 syslog(LOG_ERR, "Unable to fattach door: %m\n");
190 (void) close(dfd);
191 (void) close(doorfd);
192 exit(12);
193 }
194 (void) close(dfd);
195 #endif
196
197 /*
198 * Must pass the doorfd down to the kernel.
199 */
200 darg = doorfd;
201 (void) _nfssys(MOUNTD_ARGS, &darg);
202
203 /*
204 * Wait for incoming calls
205 */
206 /*CONSTCOND*/
207 for (;;)
208 (void) pause();
209
210 /*NOTREACHED*/
211 syslog(LOG_ERR, gettext("Door server exited"));
212 return (NULL);
213 }
214
215 /*
216 * NFS command service thread code for setup and handling of the
217 * nfs_cmd requests for character set conversion and other future
218 * events.
219 */
220
221 static void *
222 cmd_svc(void *arg)
223 {
224 int doorfd = -1;
225 uint_t darg;
226
227 if ((doorfd = door_create(nfscmd_func, NULL,
228 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
229 syslog(LOG_ERR, "Unable to create cmd door: %m\n");
230 exit(10);
231 }
232
233 /*
234 * Must pass the doorfd down to the kernel.
235 */
236 darg = doorfd;
237 (void) _nfssys(NFSCMD_ARGS, &darg);
238
239 /*
240 * Wait for incoming calls
241 */
242 /*CONSTCOND*/
243 for (;;)
244 (void) pause();
245
246 /*NOTREACHED*/
247 syslog(LOG_ERR, gettext("Cmd door server exited"));
248 return (NULL);
249 }
250
251 static void
252 free_logging_data(logging_data *lq)
253 {
254 if (lq != NULL) {
255 free(lq->ld_host);
256 free(lq->ld_netid);
257
258 if (lq->ld_nb != NULL) {
259 free(lq->ld_nb->buf);
260 free(lq->ld_nb);
261 }
262
263 free(lq->ld_path);
264 free(lq->ld_rpath);
265
266 free(lq);
267 }
268 }
269
270 static logging_data *
271 remove_head_of_queue(void)
272 {
273 logging_data *lq;
274
275 /*
276 * Pull it off the queue.
277 */
278 lq = logging_head;
279 if (lq) {
280 logging_head = lq->ld_next;
281
282 /*
283 * Drained it.
284 */
285 if (logging_head == NULL) {
286 logging_tail = NULL;
287 }
288 }
289
290 return (lq);
291 }
292
293 static void
294 do_logging_queue(logging_data *lq)
295 {
296 int cleared = 0;
297 char *host;
298
299 while (lq) {
300 struct cln cln;
301
302 if (lq->ld_host == NULL) {
303 DTRACE_PROBE(mountd, name_by_lazy);
304 cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb);
305 host = cln_gethost(&cln);
306 } else
307 host = lq->ld_host;
308
309 audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
310
311 /* add entry to mount list */
312 if (lq->ld_rpath)
313 mntlist_new(host, lq->ld_rpath);
314
315 if (lq->ld_host == NULL)
316 cln_fini(&cln);
317
318 free_logging_data(lq);
319 cleared++;
320
321 (void) mutex_lock(&logging_queue_lock);
322 lq = remove_head_of_queue();
323 (void) mutex_unlock(&logging_queue_lock);
324 }
325
326 DTRACE_PROBE1(mountd, logging_cleared, cleared);
327 }
328
329 static void *
330 logging_svc(void *arg)
331 {
332 logging_data *lq;
333
334 for (;;) {
335 (void) mutex_lock(&logging_queue_lock);
336 while (logging_head == NULL) {
337 (void) cond_wait(&logging_queue_cv,
338 &logging_queue_lock);
339 }
340
341 lq = remove_head_of_queue();
342 (void) mutex_unlock(&logging_queue_lock);
343
344 do_logging_queue(lq);
345 }
346
347 /*NOTREACHED*/
348 syslog(LOG_ERR, gettext("Logging server exited"));
349 return (NULL);
350 }
351
352 static int
353 convert_int(int *val, char *str)
494 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
495 syslog(LOG_ERR, "setrlimit failed");
496 }
497
498 (void) enable_extended_FILE_stdio(-1, -1);
499
500 ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads,
501 DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
502 if (ret != SA_OK) {
503 syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
504 "failed, using default value");
505 }
506
507 ret = nfs_smf_get_iprop("mountd_port", &mountd_port,
508 DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
509 if (ret != SA_OK) {
510 syslog(LOG_ERR, "Reading of mountd_port from SMF "
511 "failed, using default value");
512 }
513
514 while ((c = getopt(argc, argv, "dvrm:p:")) != EOF) {
515 switch (c) {
516 case 'd':
517 debug++;
518 break;
519 case 'v':
520 verbose++;
521 break;
522 case 'r':
523 rejecting = 1;
524 break;
525 case 'm':
526 if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
527 (void) fprintf(stderr, "%s: invalid "
528 "max_threads option, using defaults\n",
529 argv[0]);
530 break;
531 }
532 max_threads = tmp;
533 break;
534 case 'p':
535 if (convert_int(&tmp, optarg) != 0 || tmp < 1 ||
536 tmp > UINT16_MAX) {
537 (void) fprintf(stderr, "%s: invalid port "
538 "number\n", argv[0]);
539 break;
540 }
541 mountd_port = tmp;
542 break;
543 default:
544 fprintf(stderr, "usage: mountd [-v] [-r]\n");
545 exit(1);
546 }
547 }
548
549 /*
550 * Read in the NFS version values from config file.
551 */
552 bufsz = 4;
553 ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE,
581 DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
582 if (ret != SA_OK) {
583 syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF "
584 "failed, using default value");
585 }
586
587 /*
588 * Sanity check versions,
589 * even though we may get versions > MOUNTVERS3, we still need
590 * to start nfsauth service, so continue on regardless of values.
591 */
592 if (mount_vers_max > MOUNTVERS3)
593 mount_vers_max = MOUNTVERS3;
594 if (mount_vers_min > mount_vers_max) {
595 fprintf(stderr, "server_versmin > server_versmax\n");
596 mount_vers_max = mount_vers_min;
597 }
598 (void) setlocale(LC_ALL, "");
599 (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
600 (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
601 (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
602 (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
603
604 netgroup_init();
605
606 #if !defined(TEXT_DOMAIN)
607 #define TEXT_DOMAIN "SYS_TEST"
608 #endif
609 (void) textdomain(TEXT_DOMAIN);
610
611 /* Don't drop core if the NFS module isn't loaded. */
612 (void) signal(SIGSYS, SIG_IGN);
613
614 if (!debug)
615 pipe_fd = daemonize_init();
616
617 /*
618 * If we coredump it'll be in /core
619 */
620 if (chdir("/") < 0)
621 fprintf(stderr, "chdir /: %s\n", strerror(errno));
622
624 openlog("mountd", LOG_PID, LOG_DAEMON);
625
626 /*
627 * establish our lock on the lock file and write our pid to it.
628 * exit if some other process holds the lock, or if there's any
629 * error in writing/locking the file.
630 */
631 pid = _enter_daemon_lock(MOUNTD);
632 switch (pid) {
633 case 0:
634 break;
635 case -1:
636 fprintf(stderr, "error locking for %s: %s\n", MOUNTD,
637 strerror(errno));
638 exit(2);
639 default:
640 /* daemon was already running */
641 exit(0);
642 }
643
644 audit_mountd_setup(); /* BSM */
645
646 /*
647 * Get required system variables
648 */
649 if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) == -1) {
650 syslog(LOG_ERR, "Unable to get _SC_NGROUPS_MAX");
651 exit(1);
652 }
653 if ((pw_size = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
654 syslog(LOG_ERR, "Unable to get _SC_GETPW_R_SIZE_MAX");
655 exit(1);
656 }
657
658 /*
659 * Set number of file descriptors to unlimited
660 */
661 if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
662 syslog(LOG_INFO, "unable to set number of FDs to unlimited");
663 }
684 * from being hijacked by a bind to a more specific addr.
685 */
686 if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
687 fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
688 }
689
690 /*
691 * Set the maximum number of outstanding connection
692 * indications (listen backlog) to the value specified.
693 */
694 if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET,
695 &listen_backlog)) {
696 fprintf(stderr, "unable to set listen backlog\n");
697 exit(1);
698 }
699
700 /*
701 * If max_threads was specified, then set the
702 * maximum number of threads to the value specified.
703 */
704 if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
705 fprintf(stderr, "unable to set max_threads\n");
706 exit(1);
707 }
708
709 if (mountd_port < 0 || mountd_port > UINT16_MAX) {
710 fprintf(stderr, "unable to use specified port\n");
711 exit(1);
712 }
713
714 /*
715 * Make sure to unregister any previous versions in case the
716 * user is reconfiguring the server in interesting ways.
717 */
718 svc_unreg(MOUNTPROG, MOUNTVERS);
719 svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
720 svc_unreg(MOUNTPROG, MOUNTVERS3);
721
722 /*
723 * Create the nfsauth thread with same signal disposition
724 * as the main thread. We need to create a separate thread
725 * since mountd() will be both an RPC server (for remote
726 * traffic) _and_ a doors server (for kernel upcalls).
727 */
728 if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
729 fprintf(stderr,
730 gettext("Failed to create NFSAUTH svc thread\n"));
731 exit(2);
732 }
733
734 /*
735 * Create the cmd service thread with same signal disposition
736 * as the main thread. We need to create a separate thread
737 * since mountd() will be both an RPC server (for remote
738 * traffic) _and_ a doors server (for kernel upcalls).
739 */
740 if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
741 syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
742 exit(2);
743 }
744
745 /*
746 * Create an additional thread to service the rmtab and
747 * audit_mountd_mount logging for mount requests. Use the same
748 * signal disposition as the main thread. We create
749 * a separate thread to allow the mount request threads to
750 * clear as soon as possible.
751 */
752 if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
753 syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
754 exit(2);
755 }
756
757 /*
758 * Enumerate network transports and create service listeners
759 * as appropriate for each.
760 */
761 if ((nc = setnetconfig()) == NULL) {
762 syslog(LOG_ERR, "setnetconfig failed: %m");
763 return (-1);
764 }
765 while ((nconf = getnetconfig(nc)) != NULL) {
766 /*
767 * Skip things like tpi_raw, invisible...
768 */
769 if ((nconf->nc_flag & NC_VISIBLE) == 0)
770 continue;
771 if (nconf->nc_semantics != NC_TPI_CLTS &&
772 nconf->nc_semantics != NC_TPI_COTS &&
773 nconf->nc_semantics != NC_TPI_COTS_ORD)
774 continue;
775
835 mnt_pathconf(rqstp);
836 else
837 svcerr_noproc(transp);
838 return;
839
840 default:
841 svcerr_noproc(transp);
842 return;
843 }
844 }
845
846 void
847 log_cant_reply_cln(struct cln *cln)
848 {
849 int saverrno;
850 char *host;
851
852 saverrno = errno; /* save error code */
853
854 host = cln_gethost(cln);
855 if (host == NULL)
856 return;
857
858 errno = saverrno;
859 if (errno == 0)
860 syslog(LOG_ERR, "couldn't send reply to %s", host);
861 else
862 syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
863 }
864
865 void
866 log_cant_reply(SVCXPRT *transp)
867 {
868 int saverrno;
869 struct cln cln;
870
871 saverrno = errno; /* save error code */
872 cln_init(&cln, transp);
873 errno = saverrno;
874
875 log_cant_reply_cln(&cln);
876
1061 }
1062
1063 if (sh)
1064 sharefree(sh);
1065 free(checkpath);
1066 return (reply_error);
1067 }
1068
1069 /*
1070 * We need to inform the caller whether or not we were
1071 * able to add a node to the queue. If we are not, then
1072 * it is up to the caller to go ahead and log the data.
1073 */
1074 static int
1075 enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
1076 char *rpath, int status, int error)
1077 {
1078 logging_data *lq;
1079 struct netbuf *nb;
1080
1081 lq = (logging_data *)calloc(1, sizeof (logging_data));
1082 if (lq == NULL)
1083 goto cleanup;
1084
1085 /*
1086 * We might not yet have the host...
1087 */
1088 if (host) {
1089 DTRACE_PROBE1(mountd, log_host, host);
1090 lq->ld_host = strdup(host);
1091 if (lq->ld_host == NULL)
1092 goto cleanup;
1093 } else {
1094 DTRACE_PROBE(mountd, log_no_host);
1095
1096 lq->ld_netid = strdup(transp->xp_netid);
1097 if (lq->ld_netid == NULL)
1098 goto cleanup;
1099
1100 lq->ld_nb = calloc(1, sizeof (struct netbuf));
1138 if (logging_tail == NULL) {
1139 logging_tail = logging_head = lq;
1140 } else {
1141 logging_tail->ld_next = lq;
1142 logging_tail = lq;
1143 }
1144 (void) cond_signal(&logging_queue_cv);
1145 (void) mutex_unlock(&logging_queue_lock);
1146
1147 return (TRUE);
1148
1149 cleanup:
1150
1151 free_logging_data(lq);
1152
1153 return (FALSE);
1154 }
1155
1156
1157 #define CLN_CLNAMES (1 << 0)
1158 #define CLN_HOST (1 << 1)
1159
1160 static void
1161 cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
1162 struct netbuf *nbuf)
1163 {
1164 if ((cln->transp = transp) != NULL) {
1165 assert(netid == NULL && nbuf == NULL);
1166 cln->netid = transp->xp_netid;
1167 cln->nbuf = svc_getrpccaller(transp);
1168 } else {
1169 cln->netid = netid;
1170 cln->nbuf = nbuf;
1171 }
1172
1173 cln->nconf = NULL;
1174 cln->clnames = NULL;
1175 cln->host = NULL;
1176
1177 cln->flags = 0;
1178 }
1179
1180 void
1181 cln_init(struct cln *cln, SVCXPRT *transp)
1182 {
1183 cln_init_common(cln, transp, NULL, NULL);
1184 }
1185
1186 void
1187 cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf)
1188 {
1189 cln_init_common(cln, NULL, netid, nbuf);
1190 }
1191
1192 void
1193 cln_fini(struct cln *cln)
1194 {
1195 if (cln->nconf != NULL)
1196 freenetconfigent(cln->nconf);
1197
1198 if (cln->clnames != NULL)
1199 netdir_free(cln->clnames, ND_HOSTSERVLIST);
1200
1201 free(cln->host);
1202 }
1203
1204 struct netbuf *
1205 cln_getnbuf(struct cln *cln)
1206 {
1207 return (cln->nbuf);
1208 }
1209
1210 struct nd_hostservlist *
1211 cln_getclientsnames(struct cln *cln)
1212 {
1213 if ((cln->flags & CLN_CLNAMES) == 0) {
1214 /*
1215 * nconf is not needed if we do not have nbuf (see
1216 * cln_gethost() too), so we check for nbuf and in a case it is
1217 * NULL we do not try to get nconf.
1218 */
1219 if (cln->netid != NULL && cln->nbuf != NULL) {
1220 cln->nconf = getnetconfigent(cln->netid);
1221 if (cln->nconf == NULL)
1222 syslog(LOG_ERR, "%s: getnetconfigent failed",
1223 cln->netid);
1224 }
1225
1226 if (cln->nconf != NULL && cln->nbuf != NULL)
1227 (void) __netdir_getbyaddr_nosrv(cln->nconf,
1228 &cln->clnames, cln->nbuf);
1229
1230 cln->flags |= CLN_CLNAMES;
1231 }
1232
1233 return (cln->clnames);
1234 }
1235
1236 /*
1237 * Return B_TRUE if the host is already available at no cost
1238 */
1239 boolean_t
1240 cln_havehost(struct cln *cln)
1241 {
1242 return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0);
1243 }
1244
1245 char *
1246 cln_gethost(struct cln *cln)
1247 {
1248 if (cln_getclientsnames(cln) != NULL)
1249 return (cln->clnames->h_hostservs[0].h_host);
1250
1251 if ((cln->flags & CLN_HOST) == 0) {
1252 if (cln->nconf == NULL || cln->nbuf == NULL) {
1253 cln->host = strdup("(anon)");
1254 } else {
1255 char host[MAXIPADDRLEN];
1256
1257 if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
1258 struct sockaddr_in *sa;
1259
1260 /* LINTED pointer alignment */
1261 sa = (struct sockaddr_in *)(cln->nbuf->buf);
1262 (void) inet_ntoa_r(sa->sin_addr, host);
1263
1264 cln->host = strdup(host);
1265 } else if (strcmp(cln->nconf->nc_protofmly,
1266 NC_INET6) == 0) {
1267 struct sockaddr_in6 *sa;
1268
1269 /* LINTED pointer alignment */
1270 sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
1271 (void) inet_ntop(AF_INET6,
1272 sa->sin6_addr.s6_addr,
1273 host, INET6_ADDRSTRLEN);
1274
1275 cln->host = strdup(host);
1276 } else {
1277 syslog(LOG_ERR, gettext("Client's address is "
1278 "neither IPv4 nor IPv6"));
1279
1280 cln->host = strdup("(anon)");
1281 }
1282 }
1283
1284 cln->flags |= CLN_HOST;
1285 }
1286
1287 return (cln->host);
1288 }
1289
1290 /*
1291 * Check mount requests, add to mounted list if ok
1292 */
1293 static int
1294 mount(struct svc_req *rqstp)
1295 {
1296 SVCXPRT *transp;
1297 int version, vers;
1298 struct fhstatus fhs;
1299 struct mountres3 mountres3;
1300 char fh[FHSIZE3];
1301 int len = FHSIZE3;
1302 char *path, rpath[MAXPATHLEN];
1303 share_t *sh = NULL;
1304 struct cln cln;
1305 char *host = NULL;
1306 int error = 0, lofs_tried = 0, enqueued;
1313 transp = rqstp->rq_xprt;
1314 version = rqstp->rq_vers;
1315 path = NULL;
1316
1317 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
1318 svcerr_decode(transp);
1319 return (EACCES);
1320 }
1321
1322 cln_init(&cln, transp);
1323
1324 /*
1325 * Put off getting the name for the client until we
1326 * need it. This is a performance gain. If we are logging,
1327 * then we don't care about performance and might as well
1328 * get the host name now in case we need to spit out an
1329 * error message.
1330 */
1331 if (verbose) {
1332 DTRACE_PROBE(mountd, name_by_verbose);
1333 if ((host = cln_gethost(&cln)) == NULL) {
1334 /*
1335 * We failed to get a name for the client, even
1336 * 'anon', probably because we ran out of memory.
1337 * In this situation it doesn't make sense to
1338 * allow the mount to succeed.
1339 */
1340 error = EACCES;
1341 goto reply;
1342 }
1343 }
1344
1345 /*
1346 * If the version being used is less than the minimum version,
1347 * the filehandle translation should not be provided to the
1348 * client.
1349 */
1350 if (rejecting || version < mount_vers_min) {
1351 if (verbose)
1352 syslog(LOG_NOTICE, "Rejected mount: %s for %s",
1353 host, path);
1354 error = EACCES;
1355 goto reply;
1356 }
1357
1358 /*
1359 * Trusted Extension doesn't support nfsv2. nfsv2 client
1360 * uses MOUNT protocol v1 and v2. To prevent circumventing
1361 * TX label policy via using nfsv2 client, reject a mount
1362 * request with version less than 3 and log an error.
1363 */
1528 break;
1529
1530 case MOUNTVERS3:
1531 if (!error) {
1532 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
1533 flavor_list;
1534 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
1535 flavor_count;
1536
1537 } else if (error == ENAMETOOLONG)
1538 error = MNT3ERR_NAMETOOLONG;
1539
1540 mountres3.fhs_status = error;
1541 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1542 log_cant_reply_cln(&cln);
1543
1544 audit_status = mountres3.fhs_status;
1545 break;
1546 }
1547
1548 if (cln_havehost(&cln))
1549 host = cln_gethost(&cln);
1550
1551 if (verbose)
1552 syslog(LOG_NOTICE, "MOUNT: %s %s %s",
1553 (host == NULL) ? "unknown host" : host,
1554 error ? "denied" : "mounted", path);
1555
1556 /*
1557 * If we can not create a queue entry, go ahead and do it
1558 * in the context of this thread.
1559 */
1560 enqueued = enqueue_logging_data(host, transp, path, rpath,
1561 audit_status, error);
1562 if (enqueued == FALSE) {
1563 if (host == NULL) {
1564 DTRACE_PROBE(mountd, name_by_in_thread);
1565 host = cln_gethost(&cln);
1566 }
1567
1568 DTRACE_PROBE(mountd, logged_in_thread);
1569 audit_mountd_mount(host, path, audit_status); /* BSM */
1570 if (!error)
1571 mntlist_new(host, rpath); /* add entry to mount list */
1572 }
1573
1574 if (path != NULL)
1575 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
1576
1577 if (sh)
1578 sharefree(sh);
1579
1580 cln_fini(&cln);
1581
1582 return (error);
1583 }
1584
1585 /*
1586 * Determine whether two paths are within the same file system.
1587 * Returns nonzero (true) if paths are the same, zero (false) if
1588 * they are different. If an error occurs, return false.
1589 *
1590 * Use the actual FSID if it's available (via getattrat()); otherwise,
1591 * fall back on st_dev.
1592 *
1593 * With ZFS snapshots, st_dev differs from the regular file system
1958 }
1959 }
1960 } else {
1961 ret = inet_matchaddr(pnb->buf, gr);
1962 if (ret == -1) {
1963 if (errno == EINVAL) {
1964 syslog(LOG_WARNING,
1965 "invalid access list "
1966 "entry: %s", gr);
1967 }
1968 return (-1);
1969 } else if (ret == 1) {
1970 return (response);
1971 }
1972 }
1973
1974 goto next;
1975 }
1976
1977 /*
1978 * No other checks can be performed if client address
1979 * can't be resolved.
1980 */
1981 if ((clnames = cln_getclientsnames(cln)) == NULL)
1982 goto next;
1983
1984 /* Otherwise loop through all client hostname aliases */
1985 for (i = 0; i < clnames->h_cnt; i++) {
1986 char *host = clnames->h_hostservs[i].h_host;
1987
1988 /*
1989 * If the list name begins with a dot then
1990 * do a domain name suffix comparison.
1991 * A single dot matches any name with no
1992 * suffix.
1993 */
1994 if (*gr == '.') {
1995 if (*(gr + 1) == '\0') { /* single dot */
1996 if (strchr(host, '.') == NULL)
1997 return (response);
3208 {
3209 char *host, *path, *remove_path;
3210 char rpath[MAXPATHLEN];
3211 SVCXPRT *transp;
3212 struct cln cln;
3213
3214 transp = rqstp->rq_xprt;
3215 path = NULL;
3216 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
3217 svcerr_decode(transp);
3218 return;
3219 }
3220
3221 cln_init(&cln, transp);
3222
3223 errno = 0;
3224 if (!svc_sendreply(transp, xdr_void, (char *)NULL))
3225 log_cant_reply_cln(&cln);
3226
3227 host = cln_gethost(&cln);
3228 if (host == NULL) {
3229 /*
3230 * Without the hostname we can't do audit or delete
3231 * this host from the mount entries.
3232 */
3233 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3234 return;
3235 }
3236
3237 if (verbose)
3238 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
3239
3240 audit_mountd_umount(host, path);
3241
3242 remove_path = rpath; /* assume we will use the cannonical path */
3243 if (realpath(path, rpath) == NULL) {
3244 if (verbose)
3245 syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
3246 remove_path = path; /* use path provided instead */
3247 }
3248
3249 mntlist_delete(host, remove_path); /* remove from mount list */
3250
3251 cln_fini(&cln);
3252
3253 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3254 }
3255
3256 /*
3257 * Remove all entries for one machine from mounted list
3258 */
3259 static void
3262 SVCXPRT *transp;
3263 char *host;
3264 struct cln cln;
3265
3266 transp = rqstp->rq_xprt;
3267 if (!svc_getargs(transp, xdr_void, NULL)) {
3268 svcerr_decode(transp);
3269 return;
3270 }
3271 /*
3272 * We assume that this call is asynchronous and made via rpcbind
3273 * callit routine. Therefore return control immediately. The error
3274 * causes rpcbind to remain silent, as opposed to every machine
3275 * on the net blasting the requester with a response.
3276 */
3277 svcerr_systemerr(transp);
3278
3279 cln_init(&cln, transp);
3280
3281 host = cln_gethost(&cln);
3282 if (host == NULL) {
3283 /* Can't do anything without the name of the client */
3284 return;
3285 }
3286
3287 /*
3288 * Remove all hosts entries from mount list
3289 */
3290 mntlist_delete_all(host);
3291
3292 if (verbose)
3293 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
3294
3295 cln_fini(&cln);
3296 }
3297
3298 void *
3299 exmalloc(size_t size)
3300 {
3301 void *ret;
3302
3303 if ((ret = malloc(size)) == NULL) {
3304 syslog(LOG_ERR, "Out of memory");
3305 exit(1);
|
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,
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)
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,
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
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 }
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
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
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));
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;
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 */
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
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);
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
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);
|