Bug Summary

File:src/sbin/mountd/mountd.c
Warning:line 1483, column 24
The right operand of '==' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name mountd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/mountd/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/mountd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/mountd/mountd.c
1/* $OpenBSD: mountd.c,v 1.89 2020/08/06 17:57:32 naddy Exp $ */
2/* $NetBSD: mountd.c,v 1.31 1996/02/18 11:57:53 fvdl Exp $ */
3
4/*
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Herb Hasler and Rick Macklem at The University of Guelph.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/types.h>
37#include <sys/ioctl.h>
38#include <sys/mount.h>
39#include <sys/queue.h>
40#include <sys/socket.h>
41#include <sys/stat.h>
42#include <sys/uio.h>
43#include <sys/wait.h>
44#include <syslog.h>
45
46#include <rpc/rpc.h>
47#include <rpc/pmap_clnt.h>
48#include <rpc/pmap_prot.h>
49#include <nfs/rpcv2.h>
50#include <nfs/nfsproto.h>
51
52#include <arpa/inet.h>
53
54#include <ctype.h>
55#include <errno(*__errno()).h>
56#include <grp.h>
57#include <imsg.h>
58#include <netdb.h>
59#include <netgroup.h>
60#include <poll.h>
61#include <pwd.h>
62#include <signal.h>
63#include <stdio.h>
64#include <stdlib.h>
65#include <string.h>
66#include <unistd.h>
67#include <limits.h>
68#include "pathnames.h"
69
70#include <stdarg.h>
71
72#define isterminated(str, size)(memchr((str), '\0', (size)) != ((void *)0)) (memchr((str), '\0', (size)) != NULL((void *)0))
73
74/*
75 * Structures for keeping the mount list and export list
76 */
77struct mountlist {
78 struct mountlist *ml_next;
79 char ml_host[RPCMNT_NAMELEN255+1];
80 char ml_dirp[RPCMNT_PATHLEN1024+1];
81};
82
83struct dirlist {
84 struct dirlist *dp_left;
85 struct dirlist *dp_right;
86 int dp_flag;
87 struct hostlist *dp_hosts; /* List of hosts this dir exported to */
88 char dp_dirp[1]; /* Actually malloc'd to size of dir */
89};
90/* dp_flag bits */
91#define DP_DEFSET0x1 0x1
92#define DP_HOSTSET0x2 0x2
93
94struct exportlist {
95 struct exportlist *ex_next;
96 struct dirlist *ex_dirl;
97 struct dirlist *ex_defdir;
98 int ex_flag;
99 fsid_t ex_fs;
100 char *ex_fsdir;
101};
102/* ex_flag bits */
103#define EX_LINKED0x1 0x1
104
105struct netmsk {
106 in_addr_t nt_net;
107 in_addr_t nt_mask;
108 char *nt_name;
109};
110
111union grouptypes {
112 struct hostent *gt_hostent;
113 struct netmsk gt_net;
114};
115
116struct grouplist {
117 int gr_type;
118 union grouptypes gr_ptr;
119 struct grouplist *gr_next;
120};
121/* Group types */
122#define GT_NULL0x0 0x0
123#define GT_HOST0x1 0x1
124#define GT_NET0x2 0x2
125#define GT_IGNORE0x5 0x5
126
127struct hostlist {
128 int ht_flag; /* Uses DP_xx bits */
129 struct grouplist *ht_grp;
130 struct hostlist *ht_next;
131};
132
133struct fhreturn {
134 int fhr_flag;
135 int fhr_vers;
136 nfsfh_t fhr_fh;
137};
138
139#define IMSG_GETFH_REQ0x0 0x0
140#define IMSG_GETFH_RESP0x1 0x1
141#define IMSG_EXPORT_REQ0x2 0x2
142#define IMSG_EXPORT_RESP0x3 0x3
143#define IMSG_DELEXPORT0x4 0x4
144#define IMSG_MLIST_APPEND0x5 0x5
145#define IMSG_MLIST_OPEN0x6 0x6
146#define IMSG_MLIST_CLOSE0x7 0x7
147#define IMSG_MLIST_WRITE0x8 0x8
148
149struct getfh_resp {
150 fhandle_t gr_fh;
151 int gr_error;
152};
153
154struct export_req {
155 char er_path[MNAMELEN90];
156 struct export_args er_args;
157 struct sockaddr er_addr;
158 struct sockaddr er_mask;
159};
160
161/* Global defs */
162char *add_expdir(struct dirlist **, char *, int);
163void add_dlist(struct dirlist **, struct dirlist *, struct grouplist *, int);
164void add_mlist(char *, char *);
165void check_child(int);
166int check_dirpath(char *);
167int check_options(struct dirlist *);
168int chk_host(struct dirlist *, in_addr_t, int *, int *);
169void del_mlist(char *, char *);
170struct dirlist *dirp_search(struct dirlist *, char *);
171int do_mount(struct exportlist *, struct grouplist *, int, struct xucred *,
172 char *, int);
173int do_opt(char **, char **, struct exportlist *, struct grouplist *,
174 int *, int *, struct xucred *);
175struct exportlist *ex_search(fsid_t *);
176struct exportlist *get_exp(void);
177void free_dir(struct dirlist *);
178void free_exp(struct exportlist *);
179void free_grp(struct grouplist *);
180void free_host(struct hostlist *);
181void new_exportlist(int signo);
182void get_exportlist(void);
183int get_host(char *, struct grouplist *, struct grouplist *);
184int get_num(char *);
185struct hostlist *get_ht(void);
186int get_line(void);
187void get_mountlist(void);
188int get_net(char *, struct netmsk *, int);
189void getexp_err(struct exportlist *, struct grouplist *);
190struct grouplist *get_grp(void);
191void hang_dirp(struct dirlist *, struct grouplist *, struct exportlist *,
192 int);
193void mntsrv(struct svc_req *, SVCXPRT *);
194void nextfield(char **, char **);
195void out_of_mem(void);
196void parsecred(char *, struct xucred *);
197void privchild(int);
198int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *);
199ssize_t recv_imsg(struct imsg *);
200int scan_tree(struct dirlist *, in_addr_t);
201int send_imsg(u_int32_t, void *, u_int16_t);
202void send_umntall(int signo);
203int umntall_each(caddr_t, struct sockaddr_in *);
204int xdr_dir(XDR *, char *);
205int xdr_explist(XDR *, caddr_t);
206int xdr_fhs(XDR *, caddr_t);
207int xdr_mlist(XDR *, caddr_t);
208void mountd_svc_run(void);
209
210struct exportlist *exphead;
211struct mountlist *mlhead;
212struct grouplist *grphead;
213const char *exname;
214struct xucred def_anon = {
215 .cr_uid = (uid_t) -2,
216 .cr_gid = (gid_t) -2,
217 .cr_ngroups = 0,
218 .cr_groups = { 0, }
219};
220int opt_flags;
221/* Bits for above */
222#define OP_MAPROOT0x01 0x01
223#define OP_MAPALL0x02 0x02
224#define OP_MASK0x08 0x08
225#define OP_NET0x10 0x10
226#define OP_ALLDIRS0x40 0x40
227
228struct imsgbuf ibuf;
229int debug = 0;
230
231volatile sig_atomic_t gotchld;
232volatile sig_atomic_t gothup;
233volatile sig_atomic_t gotterm;
234
235/*
236 * Mountd server for NFS mount protocol as described in:
237 * NFS: Network File System Protocol Specification, RFC1094, Appendix A
238 * The optional arguments are the exports file name
239 * default: _PATH_EXPORTS
240 * "-d" to enable debugging
241 */
242int
243main(int argc, char *argv[])
244{
245 SVCXPRT *udptransp, *tcptransp;
246 FILE *pidfile;
247 int c, socks[2];
248
249 while ((c = getopt(argc, argv, "dnr")) != -1)
250 switch (c) {
251 case 'd':
252 debug = 1;
253 break;
254 case 'n':
255 case 'r':
256 /* Compatibility */
257 break;
258 default:
259 fprintf(stderr(&__sF[2]), "usage: mountd [-d] [exportsfile]\n");
260 exit(1);
261 }
262 argc -= optind;
263 argv += optind;
264 grphead = NULL((void *)0);
265 exphead = NULL((void *)0);
266 mlhead = NULL((void *)0);
267
268 if (argc == 1)
269 exname = *argv;
270 else
271 exname = _PATH_EXPORTS"/etc/exports";
272
273 openlog("mountd", LOG_PID0x01, LOG_DAEMON(3<<3));
274 if (debug)
275 fprintf(stderr(&__sF[2]), "Here we go.\n");
276 if (debug == 0) {
277 daemon(0, 0);
278 signal(SIGINT2, SIG_IGN(void (*)(int))1);
279 signal(SIGQUIT3, SIG_IGN(void (*)(int))1);
280 }
281 /* Store pid in file unless mountd is already running */
282 pidfile = fopen(_PATH_MOUNTDPID"/var/run/mountd.pid", "r");
283 if (pidfile != NULL((void *)0)) {
284 if (fscanf(pidfile, "%d\n", &c) > 0 && c > 0) {
285 if (kill(c, 0) == 0) {
286 syslog(LOG_ERR3, "Already running (pid %d)", c);
287 exit(1);
288 }
289 }
290 pidfile = freopen(_PATH_MOUNTDPID"/var/run/mountd.pid", "w", pidfile);
291 } else {
292 pidfile = fopen(_PATH_MOUNTDPID"/var/run/mountd.pid", "w");
293 }
294 if (pidfile) {
295 fprintf(pidfile, "%ld\n", (long)getpid());
296 fclose(pidfile);
297 }
298
299 signal(SIGCHLD20, (void (*)(int)) check_child);
300 signal(SIGHUP1, (void (*)(int)) new_exportlist);
301 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
302
303 if (socketpair(AF_UNIX1, SOCK_STREAM1, PF_UNSPEC0, socks) == -1) {
304 syslog(LOG_ERR3, "socketpair: %m");
305 exit(1);
306 }
307
308 switch (fork()) {
309 case -1:
310 syslog(LOG_ERR3, "fork: %m");
311 exit(1);
312 case 0:
313 close(socks[0]);
314 privchild(socks[1]);
315 }
316
317 close(socks[1]);
318
319 if (pledge("stdio rpath inet dns getpw", NULL((void *)0)) == -1) {
320 syslog(LOG_ERR3, "pledge: %m");
321 exit(1);
322 }
323
324 signal(SIGTERM15, (void (*)(int)) send_umntall);
325 imsg_init(&ibuf, socks[0]);
326 setproctitle("parent");
327
328 if (debug)
329 fprintf(stderr(&__sF[2]), "Getting export list.\n");
330 get_exportlist();
331 if (debug)
332 fprintf(stderr(&__sF[2]), "Getting mount list.\n");
333 get_mountlist();
334
335 if ((udptransp = svcudp_create(RPC_ANYSOCK-1)) == NULL((void *)0) ||
336 (tcptransp = svctcp_create(RPC_ANYSOCK-1, 0, 0)) == NULL((void *)0)) {
337 syslog(LOG_ERR3, "Can't create socket");
338 exit(1);
339 }
340 pmap_unset(RPCPROG_MNT100005, RPCMNT_VER11);
341 pmap_unset(RPCPROG_MNT100005, RPCMNT_VER33);
342 if (!svc_register(udptransp, RPCPROG_MNT100005, RPCMNT_VER11, mntsrv, IPPROTO_UDP17) ||
343 !svc_register(udptransp, RPCPROG_MNT100005, RPCMNT_VER33, mntsrv, IPPROTO_UDP17) ||
344 !svc_register(tcptransp, RPCPROG_MNT100005, RPCMNT_VER11, mntsrv, IPPROTO_TCP6) ||
345 !svc_register(tcptransp, RPCPROG_MNT100005, RPCMNT_VER33, mntsrv, IPPROTO_TCP6)) {
346 syslog(LOG_ERR3, "Can't register mount");
347 exit(1);
348 }
349 mountd_svc_run();
350 syslog(LOG_ERR3, "Mountd died");
351 exit(1);
352}
353
354void
355check_child(int signo)
356{
357 gotchld = 1;
358}
359
360void
361privchild(int sock)
362{
363 struct imsg imsg;
364 struct pollfd pfd[1];
365 struct ufs_args args;
366 struct statfs sfb;
367 struct getfh_resp resp;
368 struct export_req *req;
369 struct mountlist *ml;
370 FILE *fp;
371 char *path;
372 int error, size;
373
374 imsg_init(&ibuf, sock);
375 setproctitle("[priv]");
376 fp = NULL((void *)0);
377
378 for (;;) {
379 if (gothup) {
380 kill(getppid(), SIGHUP1);
381 gothup = 0;
382 }
383
384 pfd[0].fd = ibuf.fd;
385 pfd[0].events = POLLIN0x0001;
386 switch (poll(pfd, 1, INFTIM(-1))) {
387 case -1:
388 if (errno(*__errno()) == EINTR4)
389 continue;
390 syslog(LOG_ERR3, "poll: %m");
391 _exit(1);
392 case 0:
393 continue;
394 }
395 if (pfd[0].revents & POLLHUP0x0010) {
396 syslog(LOG_ERR3, "Socket disconnected");
397 _exit(1);
398 }
399 if (!(pfd[0].revents & POLLIN0x0001))
400 continue;
401
402 switch (imsg_read(&ibuf)) {
403 case -1:
404 syslog(LOG_ERR3, "imsg_read: %m");
405 _exit(1);
406 case 0:
407 syslog(LOG_ERR3, "Socket disconnected");
408 _exit(1);
409 }
410
411 while ((size = imsg_get(&ibuf, &imsg)) != 0) {
412 if (size == -1) {
413 syslog(LOG_ERR3, "imsg_get: %m");
414 _exit(1);
415 }
416 size -= IMSG_HEADER_SIZEsizeof(struct imsg_hdr);
417
418 switch (imsg.hdr.type) {
419 case IMSG_GETFH_REQ0x0:
420 if (size != PATH_MAX1024) {
421 syslog(LOG_ERR3, "Invalid message size");
422 break;
423 }
424 path = imsg.data;
425 if (getfh(path, &resp.gr_fh) == -1)
426 resp.gr_error = errno(*__errno());
427 else
428 resp.gr_error = 0;
429 send_imsg(IMSG_GETFH_RESP0x1, &resp, sizeof(resp));
430 break;
431 case IMSG_EXPORT_REQ0x2:
432 if (size != sizeof(*req)) {
433 syslog(LOG_ERR3, "Invalid message size");
434 break;
435 }
436 req = imsg.data;
437 if (statfs(req->er_path, &sfb) == -1) {
438 error = errno(*__errno());
439 syslog(LOG_ERR3, "statfs: %m");
440 send_imsg(IMSG_EXPORT_RESP0x3, &error,
441 sizeof(error));
442 break;
443 }
444 args.fspec = 0;
445 args.export_info = req->er_args;
446 args.export_info.ex_addr = &req->er_addr;
447 args.export_info.ex_mask = &req->er_mask;
448 if (mount(sfb.f_fstypename, sfb.f_mntonname,
449 sfb.f_flags | MNT_UPDATE0x00010000, &args) == -1) {
450 error = errno(*__errno());
451 syslog(LOG_ERR3, "mount: %m");
452 send_imsg(IMSG_EXPORT_RESP0x3, &error,
453 sizeof(error));
454 break;
455 }
456 error = 0;
457 send_imsg(IMSG_EXPORT_RESP0x3, &error, sizeof(error));
458 break;
459 case IMSG_DELEXPORT0x4:
460 if (size != MNAMELEN90) {
461 syslog(LOG_ERR3, "Invalid message size");
462 break;
463 }
464 path = imsg.data;
465 if (statfs(path, &sfb) == -1) {
466 syslog(LOG_ERR3, "statfs: %m");
467 break;
468 }
469 memset(&args, 0, sizeof(args));
470 args.export_info.ex_flags = MNT_DELEXPORT0x00020000;
471 if (mount(sfb.f_fstypename, sfb.f_mntonname,
472 sfb.f_flags | MNT_UPDATE0x00010000, &args) == -1)
473 syslog(LOG_ERR3, "mount: %m");
474 break;
475 case IMSG_MLIST_APPEND0x5:
476 if (size != sizeof(*ml)) {
477 syslog(LOG_ERR3, "Invalid message size");
478 break;
479 }
480 if (fp != NULL((void *)0))
481 break;
482 ml = imsg.data;
483 if (!isterminated(&ml->ml_host,(memchr((&ml->ml_host), '\0', (sizeof(ml->ml_host))
) != ((void *)0))
484 sizeof(ml->ml_host))(memchr((&ml->ml_host), '\0', (sizeof(ml->ml_host))
) != ((void *)0))
||
485 !isterminated(&ml->ml_dirp,(memchr((&ml->ml_dirp), '\0', (sizeof(ml->ml_dirp))
) != ((void *)0))
486 sizeof(ml->ml_dirp))(memchr((&ml->ml_dirp), '\0', (sizeof(ml->ml_dirp))
) != ((void *)0))
)
487 break;
488 fp = fopen(_PATH_RMOUNTLIST"/var/db/mountdtab", "a");
489 if (fp == NULL((void *)0)) {
490 syslog(LOG_ERR3, "fopen: %s: %m",
491 _PATH_RMOUNTLIST"/var/db/mountdtab");
492 break;
493 }
494 fprintf(fp, "%s %s\n", ml->ml_host,
495 ml->ml_dirp);
496 fclose(fp);
497 fp = NULL((void *)0);
498 break;
499 case IMSG_MLIST_OPEN0x6:
500 if (size != 0) {
501 syslog(LOG_ERR3, "Invalid message size");
502 break;
503 }
504 if (fp != NULL((void *)0))
505 break;
506 fp = fopen(_PATH_RMOUNTLIST"/var/db/mountdtab", "w");
507 if (fp == NULL((void *)0))
508 syslog(LOG_ERR3, "fopen: %s: %m",
509 _PATH_RMOUNTLIST"/var/db/mountdtab");
510 break;
511 case IMSG_MLIST_WRITE0x8:
512 if (size != sizeof(*ml)) {
513 syslog(LOG_ERR3, "Invalid message size");
514 break;
515 }
516 if (fp == NULL((void *)0))
517 break;
518 ml = imsg.data;
519 if (!isterminated(&ml->ml_host,(memchr((&ml->ml_host), '\0', (sizeof(ml->ml_host))
) != ((void *)0))
520 sizeof(ml->ml_host))(memchr((&ml->ml_host), '\0', (sizeof(ml->ml_host))
) != ((void *)0))
||
521 !isterminated(&ml->ml_dirp,(memchr((&ml->ml_dirp), '\0', (sizeof(ml->ml_host))
) != ((void *)0))
522 sizeof(ml->ml_host))(memchr((&ml->ml_dirp), '\0', (sizeof(ml->ml_host))
) != ((void *)0))
)
523 break;
524 fprintf(fp, "%s %s\n", ml->ml_host,
525 ml->ml_dirp);
526 break;
527 case IMSG_MLIST_CLOSE0x7:
528 if (size != 0) {
529 syslog(LOG_ERR3, "Invalid message size");
530 break;
531 }
532 if (fp != NULL((void *)0)) {
533 fclose(fp);
534 fp = NULL((void *)0);
535 }
536 break;
537 default:
538 syslog(LOG_ERR3, "Unexpected message type");
539 break;
540 }
541
542 imsg_free(&imsg);
543 }
544 }
545}
546
547int
548imsg_getfh(char *path, fhandle_t *fh)
549{
550 struct imsg imsg;
551 struct getfh_resp *resp;
552 ssize_t size;
553
554 if (send_imsg(IMSG_GETFH_REQ0x0, path, PATH_MAX1024) == -1)
555 return (-1);
556
557 size = recv_imsg(&imsg);
558 if (size == -1)
559 return (-1);
560 if (imsg.hdr.type != IMSG_GETFH_RESP0x1 || size != sizeof(*resp)) {
561 syslog(LOG_ERR3, "Invalid message");
562 imsg_free(&imsg);
563 errno(*__errno()) = EINVAL22;
564 return (-1);
565 }
566
567 resp = imsg.data;
568 *fh = resp->gr_fh;
569 if (resp->gr_error) {
570 errno(*__errno()) = resp->gr_error;
571 imsg_free(&imsg);
572 return (-1);
573 }
574
575 imsg_free(&imsg);
576 return (0);
577}
578
579int
580imsg_export(const char *dir, struct export_args *args)
581{
582 struct export_req req;
583 struct imsg imsg;
584 ssize_t size;
585
586 if (strlcpy(req.er_path, dir, sizeof(req.er_path)) >=
587 sizeof(req.er_path)) {
588 syslog(LOG_ERR3, "%s: mount dir too long", dir);
589 errno(*__errno()) = EINVAL22;
590 return (-1);
591 }
592
593 req.er_args = *args;
594 if (args->ex_addrlen)
595 req.er_addr = *args->ex_addr;
596 if (args->ex_masklen)
597 req.er_mask = *args->ex_mask;
598
599 if (send_imsg(IMSG_EXPORT_REQ0x2, &req, sizeof(req)) == -1)
600 return (-1);
601
602 size = recv_imsg(&imsg);
603 if (size == -1)
604 return (-1);
605 if (imsg.hdr.type != IMSG_EXPORT_RESP0x3 || size != sizeof(int)) {
606 syslog(LOG_ERR3, "Invalid message");
607 imsg_free(&imsg);
608 errno(*__errno()) = EINVAL22;
609 return (-1);
610 }
611
612 if (*(int *)imsg.data != 0) {
613 errno(*__errno()) = *(int *)imsg.data;
614 imsg_free(&imsg);
615 return (-1);
616 }
617
618 imsg_free(&imsg);
619 return (0);
620}
621
622ssize_t
623recv_imsg(struct imsg *imsg)
624{
625 ssize_t n;
626
627 n = imsg_read(&ibuf);
628 if (n == -1) {
629 syslog(LOG_ERR3, "imsg_read: %m");
630 return (-1);
631 }
632 if (n == 0) {
633 syslog(LOG_ERR3, "Socket disconnected");
634 errno(*__errno()) = EINVAL22;
635 return (-1);
636 }
637
638 n = imsg_get(&ibuf, imsg);
639 if (n == -1) {
640 syslog(LOG_ERR3, "imsg_get: %m");
641 return (-1);
642 }
643 if (n == 0) {
644 syslog(LOG_ERR3, "No messages ready");
645 errno(*__errno()) = EINVAL22;
646 return (-1);
647 }
648
649 return (n - IMSG_HEADER_SIZEsizeof(struct imsg_hdr));
650}
651
652int
653send_imsg(u_int32_t type, void *data, u_int16_t size)
654{
655 if (imsg_compose(&ibuf, type, 0, 0, -1, data, size) == -1) {
656 syslog(LOG_ERR3, "imsg_compose: %m");
657 return (-1);
658 }
659
660 if (imsg_flush(&ibuf) == -1) {
661 syslog(LOG_ERR3, "imsg_flush: %m");
662 return (-1);
663 }
664
665 return (0);
666}
667
668void
669mountd_svc_run(void)
670{
671 struct pollfd *pfd = NULL((void *)0), *newp;
672 nfds_t saved_max_pollfd = 0;
673 int nready, status;
674
675 for (;;) {
676 if (gotchld) {
677 if (waitpid(WAIT_ANY(-1), &status, WNOHANG1) == -1) {
678 syslog(LOG_ERR3, "waitpid: %m");
679 break;
680 }
681 if (WIFEXITED(status)(((status) & 0177) == 0)) {
682 syslog(LOG_ERR3, "Child exited");
683 break;
684 }
685 if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
) {
686 syslog(LOG_ERR3, "Child terminated by signal");
687 break;
688 }
689 gotchld = 0;
690 }
691 if (gothup) {
692 get_exportlist();
693 gothup = 0;
694 }
695 if (gotterm)
696 break;
697 if (svc_max_pollfd > saved_max_pollfd) {
698 newp = reallocarray(pfd, svc_max_pollfd, sizeof(*pfd));
699 if (!newp) {
700 free(pfd);
701 perror("mountd_svc_run: - realloc failed");
702 return;
703 }
704 pfd = newp;
705 saved_max_pollfd = svc_max_pollfd;
706 }
707 memcpy(pfd, svc_pollfd, svc_max_pollfd * sizeof(*pfd));
708
709 nready = poll(pfd, svc_max_pollfd, INFTIM(-1));
710 switch (nready) {
711 case -1:
712 if (errno(*__errno()) == EINTR4)
713 break;
714 perror("mountd_svc_run: - poll failed");
715 free(pfd);
716 return;
717 case 0:
718 break;
719 default:
720 svc_getreq_poll(pfd, nready);
721 break;
722 }
723 }
724
725 (void) clnt_broadcast(RPCPROG_MNT100005, RPCMNT_VER11, RPCMNT_UMNTALL4,
726 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
727 exit(0);
728}
729
730/*
731 * The mount rpc service
732 */
733void
734mntsrv(struct svc_req *rqstp, SVCXPRT *transp)
735{
736 char rpcpath[RPCMNT_PATHLEN1024+1], dirpath[PATH_MAX1024];
737 struct hostent *hp = NULL((void *)0);
738 struct exportlist *ep;
739 sigset_t sighup_mask;
740 int defset, hostset;
741 struct fhreturn fhr;
742 struct dirlist *dp;
743 struct statfs fsb;
744 struct stat stb;
745 in_addr_t saddr;
746 u_short sport;
747 long bad = 0;
748
749 sigemptyset(&sighup_mask);
750 sigaddset(&sighup_mask, SIGHUP1);
751 saddr = transp->xp_raddr.sin_addr.s_addr;
752 sport = ntohs(transp->xp_raddr.sin_port)(__uint16_t)(__builtin_constant_p(transp->xp_raddr.sin_port
) ? (__uint16_t)(((__uint16_t)(transp->xp_raddr.sin_port) &
0xffU) << 8 | ((__uint16_t)(transp->xp_raddr.sin_port
) & 0xff00U) >> 8) : __swap16md(transp->xp_raddr
.sin_port))
;
1
'?' condition is false
753 switch (rqstp->rq_proc) {
2
Control jumps to 'case 1:' at line 758
754 case NULLPROC((unsigned int)0):
755 if (!svc_sendreply(transp, xdr_void, NULL((void *)0)))
756 syslog(LOG_ERR3, "Can't send reply");
757 return;
758 case RPCMNT_MOUNT1:
759 if (debug)
3
Assuming 'debug' is 0
4
Taking false branch
760 fprintf(stderr(&__sF[2]), "Got mount request from %s\n",
761 inet_ntoa(transp->xp_raddr.sin_addr));
762 if (sport >= IPPORT_RESERVED1024) {
5
Assuming 'sport' is < IPPORT_RESERVED
6
Taking false branch
763 syslog(LOG_NOTICE5,
764 "Refused mount RPC from host %s port %d",
765 inet_ntoa(transp->xp_raddr.sin_addr), sport);
766 svcerr_weakauth(transp);
767 return;
768 }
769 if (!svc_getargs(transp, xdr_dir, rpcpath)(*(transp)->xp_ops->xp_getargs)((transp), (xdr_dir), (rpcpath
))
) {
7
Assuming the condition is false
8
Taking false branch
770 svcerr_decode(transp);
771 return;
772 }
773 if (debug)
9
Assuming 'debug' is 0
10
Taking false branch
774 fprintf(stderr(&__sF[2]), "rpcpath: %s\n", rpcpath);
775
776 /*
777 * Get the real pathname and make sure it is a file or
778 * directory that exists.
779 */
780 if (realpath(rpcpath, dirpath) == NULL((void *)0)) {
11
Assuming the condition is false
12
Taking false branch
781 bad = errno(*__errno());
782 if (debug)
783 fprintf(stderr(&__sF[2]), "realpath failed on %s\n",
784 rpcpath);
785 strlcpy(dirpath, rpcpath, sizeof(dirpath));
786 } else if (stat(dirpath, &stb) == -1 ||
13
Assuming the condition is true
787 (!S_ISDIR(stb.st_mode)((stb.st_mode & 0170000) == 0040000) && !S_ISREG(stb.st_mode)((stb.st_mode & 0170000) == 0100000)) ||
788 statfs(dirpath, &fsb) == -1) {
789 if (debug
13.1
'debug' is 0
)
14
Taking false branch
790 fprintf(stderr(&__sF[2]), "stat failed on %s\n", dirpath);
791 bad = ENOENT2; /* We will send error reply later */
792 }
793
794 /* Check in the exports list */
795 sigprocmask(SIG_BLOCK1, &sighup_mask, NULL((void *)0));
796 ep = ex_search(&fsb.f_fsid);
15
Calling 'ex_search'
797 hostset = defset = 0;
798 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
799 ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
800 chk_host(dp, saddr, &defset, &hostset)) ||
801 (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
802 scan_tree(ep->ex_dirl, saddr) == 0))) {
803 if (bad) {
804 if (!svc_sendreply(transp, xdr_long,
805 (caddr_t)&bad))
806 syslog(LOG_ERR3, "Can't send reply");
807 sigprocmask(SIG_UNBLOCK2, &sighup_mask, NULL((void *)0));
808 return;
809 }
810 if (hostset & DP_HOSTSET0x2)
811 fhr.fhr_flag = hostset;
812 else
813 fhr.fhr_flag = defset;
814 fhr.fhr_vers = rqstp->rq_vers;
815 /* Get the file handle */
816 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
817 if (imsg_getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
818 bad = errno(*__errno());
819 syslog(LOG_ERR3, "Can't get fh for %s", dirpath);
820 if (!svc_sendreply(transp, xdr_long,
821 (caddr_t)&bad))
822 syslog(LOG_ERR3, "Can't send reply");
823 sigprocmask(SIG_UNBLOCK2, &sighup_mask, NULL((void *)0));
824 return;
825 }
826 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))
827 syslog(LOG_ERR3, "Can't send reply");
828 if (hp == NULL((void *)0))
829 hp = gethostbyaddr((caddr_t)&saddr,
830 sizeof(saddr), AF_INET2);
831 if (hp)
832 add_mlist(hp->h_name, dirpath);
833 else
834 add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
835 dirpath);
836 if (debug) {
837 fprintf(stderr(&__sF[2]),
838 "Mount successful for %s by %s.\n",
839 dirpath,
840 inet_ntoa(transp->xp_raddr.sin_addr));
841 }
842 } else
843 bad = EACCES13;
844
845 if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad))
846 syslog(LOG_ERR3, "Can't send reply");
847 sigprocmask(SIG_UNBLOCK2, &sighup_mask, NULL((void *)0));
848 return;
849 case RPCMNT_DUMP2:
850 if (!svc_sendreply(transp, xdr_mlist, NULL((void *)0)))
851 syslog(LOG_ERR3, "Can't send reply");
852 return;
853 case RPCMNT_UMOUNT3:
854 if (sport >= IPPORT_RESERVED1024) {
855 svcerr_weakauth(transp);
856 return;
857 }
858 if (!svc_getargs(transp, xdr_dir, dirpath)(*(transp)->xp_ops->xp_getargs)((transp), (xdr_dir), (dirpath
))
) {
859 svcerr_decode(transp);
860 return;
861 }
862 if (!svc_sendreply(transp, xdr_void, NULL((void *)0)))
863 syslog(LOG_ERR3, "Can't send reply");
864 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET2);
865 if (hp)
866 del_mlist(hp->h_name, dirpath);
867 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
868 return;
869 case RPCMNT_UMNTALL4:
870 if (sport >= IPPORT_RESERVED1024) {
871 svcerr_weakauth(transp);
872 return;
873 }
874 if (!svc_sendreply(transp, xdr_void, NULL((void *)0)))
875 syslog(LOG_ERR3, "Can't send reply");
876 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET2);
877 if (hp)
878 del_mlist(hp->h_name, NULL((void *)0));
879 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), NULL((void *)0));
880 return;
881 case RPCMNT_EXPORT5:
882 if (!svc_sendreply(transp, xdr_explist, NULL((void *)0)))
883 syslog(LOG_ERR3, "Can't send reply");
884 return;
885 default:
886 svcerr_noproc(transp);
887 return;
888 }
889}
890
891/*
892 * Xdr conversion for a dirpath string
893 */
894int
895xdr_dir(XDR *xdrsp, char *dirp)
896{
897 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN1024));
898}
899
900/*
901 * Xdr routine to generate file handle reply
902 */
903int
904xdr_fhs(XDR *xdrsp, caddr_t cp)
905{
906 struct fhreturn *fhrp = (struct fhreturn *)cp;
907 long ok = 0, len, auth;
908
909 if (!xdr_long(xdrsp, &ok))
910 return (0);
911 switch (fhrp->fhr_vers) {
912 case 1:
913 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH32));
914 case 3:
915 len = NFSX_V3FH(sizeof (fhandle_t));
916 if (!xdr_long(xdrsp, &len))
917 return (0);
918 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
919 return (0);
920 auth = RPCAUTH_UNIX1;
921 len = 1;
922 if (!xdr_long(xdrsp, &len))
923 return (0);
924 return (xdr_long(xdrsp, &auth));
925 }
926 return (0);
927}
928
929int
930xdr_mlist(XDR *xdrsp, caddr_t cp)
931{
932 int true = 1, false = 0;
933 struct mountlist *mlp;
934 char *strp;
935
936 mlp = mlhead;
937 while (mlp) {
938 if (!xdr_bool(xdrsp, &true))
939 return (0);
940 strp = &mlp->ml_host[0];
941 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN255))
942 return (0);
943 strp = &mlp->ml_dirp[0];
944 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN1024))
945 return (0);
946 mlp = mlp->ml_next;
947 }
948 if (!xdr_bool(xdrsp, &false))
949 return (0);
950 return (1);
951}
952
953/*
954 * Xdr conversion for export list
955 */
956int
957xdr_explist(XDR *xdrsp, caddr_t cp)
958{
959 struct exportlist *ep;
960 int false = 0, putdef;
961 sigset_t sighup_mask;
962
963 sigemptyset(&sighup_mask);
964 sigaddset(&sighup_mask, SIGHUP1);
965 sigprocmask(SIG_BLOCK1, &sighup_mask, NULL((void *)0));
966 ep = exphead;
967 while (ep) {
968 putdef = 0;
969 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
970 goto errout;
971 if (ep->ex_defdir && putdef == 0 && put_exlist(ep->ex_defdir,
972 xdrsp, NULL((void *)0), &putdef))
973 goto errout;
974 ep = ep->ex_next;
975 }
976 sigprocmask(SIG_UNBLOCK2, &sighup_mask, NULL((void *)0));
977 if (!xdr_bool(xdrsp, &false))
978 return (0);
979 return (1);
980errout:
981 sigprocmask(SIG_UNBLOCK2, &sighup_mask, NULL((void *)0));
982 return (0);
983}
984
985/*
986 * Called from xdr_explist() to traverse the tree and export the
987 * directory paths.
988 */
989int
990put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp,
991 int *putdefp)
992{
993 int true = 1, false = 0, gotalldir = 0;
994 struct grouplist *grp;
995 struct hostlist *hp;
996 char *strp;
997
998 if (dp) {
999 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
1000 return (1);
1001 if (!xdr_bool(xdrsp, &true))
1002 return (1);
1003 strp = dp->dp_dirp;
1004 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN1024))
1005 return (1);
1006 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
1007 gotalldir = 1;
1008 *putdefp = 1;
1009 }
1010 if ((dp->dp_flag & DP_DEFSET0x1) == 0 &&
1011 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET0x1) == 0)) {
1012 hp = dp->dp_hosts;
1013 while (hp) {
1014 grp = hp->ht_grp;
1015 if (grp->gr_type == GT_HOST0x1) {
1016 if (!xdr_bool(xdrsp, &true))
1017 return (1);
1018 strp = grp->gr_ptr.gt_hostent->h_name;
1019 if (!xdr_string(xdrsp, &strp,
1020 RPCMNT_NAMELEN255))
1021 return (1);
1022 } else if (grp->gr_type == GT_NET0x2) {
1023 if (!xdr_bool(xdrsp, &true))
1024 return (1);
1025 strp = grp->gr_ptr.gt_net.nt_name;
1026 if (!xdr_string(xdrsp, &strp,
1027 RPCMNT_NAMELEN255))
1028 return (1);
1029 }
1030 hp = hp->ht_next;
1031 if (gotalldir && hp == NULL((void *)0)) {
1032 hp = adp->dp_hosts;
1033 gotalldir = 0;
1034 }
1035 }
1036 }
1037 if (!xdr_bool(xdrsp, &false))
1038 return (1);
1039 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
1040 return (1);
1041 }
1042 return (0);
1043}
1044
1045#define LINESIZ10240 10240
1046char line[LINESIZ10240];
1047FILE *exp_file;
1048
1049void
1050new_exportlist(int signo)
1051{
1052 gothup = 1;
1053
1054}
1055
1056/*
1057 * Get the export list
1058 */
1059void
1060get_exportlist(void)
1061{
1062 int len, has_host, exflags, got_nondir, dirplen = 0, num;
1063 int lookup_failed, num_hosts, i, netgrp;
1064 char *cp, *endcp, *dirp = NULL((void *)0), *hst, *usr, *dom, savedc;
1065 struct exportlist *ep, *ep2;
1066 struct grouplist *grp, *tgrp;
1067 struct exportlist **epp;
1068 struct dirlist *dirhead;
1069 struct statfs fsb, *ofsp, *fsp;
1070 struct hostent *hpe;
1071 struct xucred anon;
1072 struct fsarray {
1073 int exflags;
1074 char *mntonname;
1075 } *fstbl;
1076
1077 /*
1078 * First, get rid of the old list
1079 */
1080 ep = exphead;
1081 while (ep) {
1082 ep2 = ep;
1083 ep = ep->ex_next;
1084 free_exp(ep2);
1085 }
1086 exphead = NULL((void *)0);
1087
1088 grp = grphead;
1089 while (grp) {
1090 tgrp = grp;
1091 grp = grp->gr_next;
1092 free_grp(tgrp);
1093 }
1094 grphead = NULL((void *)0);
1095
1096 /*
1097 * And delete exports that are in the kernel for all local
1098 * file systems.
1099 * XXX: Should know how to handle all local exportable file systems
1100 * instead of just MOUNT_FFS.
1101 */
1102 num = getmntinfo(&ofsp, MNT_NOWAIT2);
1103 if (num == 0 && errno(*__errno()))
1104 syslog(LOG_ERR3, "getmntinfo: %s", strerror(errno(*__errno())));
1105
1106 fsp = ofsp;
1107
1108 fstbl = calloc(num, sizeof (fstbl[0]));
1109 if (fstbl == NULL((void *)0))
1110 out_of_mem();
1111
1112 for (i = 0; i < num; i++) {
1113
1114 if (!strncmp(fsp->f_fstypename, MOUNT_MFS"mfs", MFSNAMELEN16) ||
1115 !strncmp(fsp->f_fstypename, MOUNT_FFS"ffs", MFSNAMELEN16) ||
1116 !strncmp(fsp->f_fstypename, MOUNT_EXT2FS"ext2fs", MFSNAMELEN16) ||
1117 !strncmp(fsp->f_fstypename, MOUNT_MSDOS"msdos", MFSNAMELEN16) ||
1118 !strncmp(fsp->f_fstypename, MOUNT_CD9660"cd9660", MFSNAMELEN16)) {
1119 fstbl[i].exflags = MNT_DELEXPORT0x00020000;
1120 fstbl[i].mntonname = fsp->f_mntonname;
1121 }
1122 fsp++;
1123 }
1124
1125 /*
1126 * Read in the exports file and build the list, calling mount() through
1127 * the privileged child as we go along to push the export rules into
1128 * the kernel.
1129 */
1130 if ((exp_file = fopen(exname, "r")) == NULL((void *)0)) {
1131 syslog(LOG_ERR3, "Can't open %s", exname);
1132 exit(2);
1133 }
1134 dirhead = NULL((void *)0);
1135 while (get_line()) {
1136 if (debug)
1137 fprintf(stderr(&__sF[2]), "Got line %s\n",line);
1138 cp = line;
1139 nextfield(&cp, &endcp);
1140 if (*cp == '#')
1141 goto nextline;
1142
1143 /*
1144 * Set defaults.
1145 */
1146 has_host = FALSE(0);
1147 num_hosts = 0;
1148 lookup_failed = FALSE(0);
1149 anon = def_anon;
1150 exflags = MNT_EXPORTED0x00000100;
1151 got_nondir = 0;
1152 opt_flags = 0;
1153 ep = NULL((void *)0);
1154
1155 /*
1156 * Create new exports list entry
1157 */
1158 len = endcp-cp;
1159 tgrp = grp = get_grp();
1160 while (len > 0) {
1161 if (len > RPCMNT_NAMELEN255) {
1162 getexp_err(ep, tgrp);
1163 goto nextline;
1164 }
1165 if (*cp == '-') {
1166 if (ep == NULL((void *)0)) {
1167 getexp_err(ep, tgrp);
1168 goto nextline;
1169 }
1170 if (debug)
1171 fprintf(stderr(&__sF[2]), "doing opt %s\n", cp);
1172 got_nondir = 1;
1173 if (do_opt(&cp, &endcp, ep, grp, &has_host,
1174 &exflags, &anon)) {
1175 getexp_err(ep, tgrp);
1176 goto nextline;
1177 }
1178 } else if (*cp == '/') {
1179 savedc = *endcp;
1180 *endcp = '\0';
1181 if (check_dirpath(cp) &&
1182 statfs(cp, &fsb) >= 0) {
1183 if (got_nondir) {
1184 syslog(LOG_ERR3, "Dirs must be first");
1185 getexp_err(ep, tgrp);
1186 goto nextline;
1187 }
1188 if (ep) {
1189 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
1190 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
1191 getexp_err(ep, tgrp);
1192 goto nextline;
1193 }
1194 } else {
1195 /*
1196 * See if this directory is already
1197 * in the list.
1198 */
1199 ep = ex_search(&fsb.f_fsid);
1200 if (ep == NULL((void *)0)) {
1201 int len;
1202
1203 ep = get_exp();
1204 ep->ex_fs = fsb.f_fsid;
1205 len = strlen(fsb.f_mntonname) + 1;
1206 ep->ex_fsdir = malloc(len);
1207 if (ep->ex_fsdir)
1208 strlcpy(ep->ex_fsdir,
1209 fsb.f_mntonname, len);
1210 else
1211 out_of_mem();
1212 if (debug)
1213 fprintf(stderr(&__sF[2]),
1214 "Making new ep fs=0x%x,0x%x\n",
1215 fsb.f_fsid.val[0],
1216 fsb.f_fsid.val[1]);
1217 } else if (debug)
1218 fprintf(stderr(&__sF[2]),
1219 "Found ep fs=0x%x,0x%x\n",
1220 fsb.f_fsid.val[0],
1221 fsb.f_fsid.val[1]);
1222 }
1223
1224 /*
1225 * Add dirpath to export mount point.
1226 */
1227 dirp = add_expdir(&dirhead, cp, len);
1228 dirplen = len;
1229 } else {
1230 getexp_err(ep, tgrp);
1231 goto nextline;
1232 }
1233 *endcp = savedc;
1234 } else {
1235 savedc = *endcp;
1236 *endcp = '\0';
1237 got_nondir = 1;
1238 if (ep == NULL((void *)0)) {
1239 getexp_err(ep, tgrp);
1240 goto nextline;
1241 }
1242
1243 /*
1244 * Get the host or netgroup.
1245 */
1246 setnetgrent(cp);
1247 netgrp = getnetgrent((const char **)&hst,
1248 (const char **)&usr, (const char **)&dom);
1249 do {
1250 if (has_host) {
1251 grp->gr_next = get_grp();
1252 grp = grp->gr_next;
1253 } else {
1254 memset(grp, 0, sizeof(*grp));
1255 }
1256 if (netgrp) {
1257 if (hst == NULL((void *)0)) {
1258 syslog(LOG_ERR3,
1259 "NULL hostname in netgroup %s, skipping",
1260 cp);
1261 grp->gr_type = GT_IGNORE0x5;
1262 lookup_failed = TRUE(1);
1263 continue;
1264 } else if (get_host(hst, grp, tgrp)) {
1265 syslog(LOG_ERR3,
1266 "Unknown host (%s) in netgroup %s",
1267 hst, cp);
1268 grp->gr_type = GT_IGNORE0x5;
1269 lookup_failed = TRUE(1);
1270 continue;
1271 }
1272 } else if (get_host(cp, grp, tgrp)) {
1273 syslog(LOG_ERR3,
1274 "Unknown host (%s) in line %s",
1275 cp, line);
1276 grp->gr_type = GT_IGNORE0x5;
1277 lookup_failed = TRUE(1);
1278 continue;
1279 }
1280 has_host = TRUE(1);
1281 num_hosts++;
1282 } while (netgrp && getnetgrent((const char **)&hst,
1283 (const char **)&usr, (const char **)&dom));
1284 endnetgrent();
1285 *endcp = savedc;
1286 }
1287 cp = endcp;
1288 nextfield(&cp, &endcp);
1289 len = endcp - cp;
1290 }
1291 /*
1292 * If the exports list is empty due to unresolvable hostnames
1293 * we throw away the line.
1294 */
1295 if (lookup_failed == TRUE(1) && num_hosts == 0 &&
1296 tgrp->gr_type == GT_IGNORE0x5) {
1297 getexp_err(ep, tgrp);
1298 goto nextline;
1299 }
1300 if (check_options(dirhead)) {
1301 getexp_err(ep, tgrp);
1302 goto nextline;
1303 }
1304 if (!has_host) {
1305 grp->gr_type = GT_HOST0x1;
1306 if (debug)
1307 fprintf(stderr(&__sF[2]), "Adding a default entry\n");
1308 /* add a default group and make the grp list NULL */
1309 hpe = malloc(sizeof(struct hostent));
1310 if (hpe == NULL((void *)0))
1311 out_of_mem();
1312 hpe->h_name = strdup("Default");
1313 if (hpe->h_name == NULL((void *)0))
1314 out_of_mem();
1315 hpe->h_addrtype = AF_INET2;
1316 hpe->h_length = sizeof (u_int32_t);
1317 hpe->h_addr_list = NULL((void *)0);
1318 grp->gr_ptr.gt_hostent = hpe;
1319
1320 /*
1321 * Don't allow a network export coincide with a list of
1322 * host(s) on the same line.
1323 */
1324 } else if ((opt_flags & OP_NET0x10) && tgrp->gr_next) {
1325 getexp_err(ep, tgrp);
1326 goto nextline;
1327 }
1328
1329 /*
1330 * Loop through hosts, pushing the exports into the kernel.
1331 * After loop, tgrp points to the start of the list and
1332 * grp points to the last entry in the list.
1333 */
1334 grp = tgrp;
1335 do {
1336
1337 /*
1338 * remove filesystem from unexport list
1339 * add MNT_DELEXPORT to exflags to clean up
1340 * any old addrlist in the kernel
1341 */
1342
1343 for (i = 0; i < num; i++) {
1344 if ((fstbl[i].mntonname != NULL((void *)0)) &&
1345 (strcmp(fsb.f_mntonname,
1346 fstbl[i].mntonname) == 0) &&
1347 (fstbl[i].exflags & MNT_DELEXPORT0x00020000)) {
1348 exflags |= MNT_DELEXPORT0x00020000;
1349 fstbl[i].exflags = 0;
1350 if (debug)
1351 fprintf(stderr(&__sF[2]), "removing %s %s from unexport list\n", dirp, fstbl[i].mntonname);
1352 }
1353 }
1354
1355 if (debug)
1356 fprintf(stderr(&__sF[2]), "exporting %s\n", dirp);
1357 /*
1358 * Non-zero return indicates an error. Return
1359 * val of 1 means line is invalid (not just entry).
1360 */
1361 i = do_mount(ep, grp, exflags, &anon, dirp, dirplen);
1362 exflags &= ~MNT_DELEXPORT0x00020000;
1363 if (i == 1) {
1364 getexp_err(ep, tgrp);
1365 goto nextline;
1366 } else if (i == 2) {
1367 syslog(LOG_ERR3,
1368 "Bad exports list entry (%s) in line %s",
1369 (grp->gr_type == GT_HOST0x1)
1370 ? grp->gr_ptr.gt_hostent->h_name
1371 : (grp->gr_type == GT_NET0x2)
1372 ? grp->gr_ptr.gt_net.nt_name
1373 : "Unknown", line);
1374 }
1375 } while (grp->gr_next && (grp = grp->gr_next));
1376
1377 /*
1378 * Success. Update the data structures.
1379 */
1380 if (has_host) {
1381 hang_dirp(dirhead, tgrp, ep, opt_flags);
1382 grp->gr_next = grphead;
1383 grphead = tgrp;
1384 } else {
1385 hang_dirp(dirhead, NULL((void *)0), ep,
1386 opt_flags);
1387 free_grp(grp);
1388 }
1389 dirhead = NULL((void *)0);
1390 if ((ep->ex_flag & EX_LINKED0x1) == 0) {
1391 ep2 = exphead;
1392 epp = &exphead;
1393
1394 /*
1395 * Insert in the list in alphabetical order.
1396 */
1397 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
1398 epp = &ep2->ex_next;
1399 ep2 = ep2->ex_next;
1400 }
1401 if (ep2)
1402 ep->ex_next = ep2;
1403 *epp = ep;
1404 ep->ex_flag |= EX_LINKED0x1;
1405 }
1406nextline:
1407 if (dirhead) {
1408 free_dir(dirhead);
1409 dirhead = NULL((void *)0);
1410 }
1411 }
1412
1413 fsp = ofsp;
1414 for (i = 0; i < num; i++, fsp++) {
1415 if ((fstbl[i].exflags & MNT_DELEXPORT0x00020000) == 0)
1416 continue;
1417 if (debug)
1418 fprintf(stderr(&__sF[2]), "unexporting %s %s\n",
1419 fsp->f_mntonname, fstbl[i].mntonname);
1420 send_imsg(IMSG_DELEXPORT0x4, fsp->f_mntonname,
1421 sizeof(fsp->f_mntonname));
1422 }
1423 free(fstbl);
1424 fclose(exp_file);
1425}
1426
1427/*
1428 * Allocate an export list element
1429 */
1430struct exportlist *
1431get_exp(void)
1432{
1433 struct exportlist *ep;
1434
1435 ep = calloc(1, sizeof (struct exportlist));
1436 if (ep == NULL((void *)0))
1437 out_of_mem();
1438 return (ep);
1439}
1440
1441/*
1442 * Allocate a group list element
1443 */
1444struct grouplist *
1445get_grp(void)
1446{
1447 struct grouplist *gp;
1448
1449 gp = calloc(1, sizeof (struct grouplist));
1450 if (gp == NULL((void *)0))
1451 out_of_mem();
1452 return (gp);
1453}
1454
1455/*
1456 * Clean up upon an error in get_exportlist().
1457 */
1458void
1459getexp_err(struct exportlist *ep, struct grouplist *grp)
1460{
1461 struct grouplist *tgrp;
1462
1463 syslog(LOG_ERR3, "Bad exports list line %s", line);
1464 if (ep && (ep->ex_flag & EX_LINKED0x1) == 0)
1465 free_exp(ep);
1466 while (grp) {
1467 tgrp = grp;
1468 grp = grp->gr_next;
1469 free_grp(tgrp);
1470 }
1471}
1472
1473/*
1474 * Search the export list for a matching fs.
1475 */
1476struct exportlist *
1477ex_search(fsid_t *fsid)
1478{
1479 struct exportlist *ep;
1480
1481 ep = exphead;
1482 while (ep) {
16
Loop condition is true. Entering loop body
1483 if (ep->ex_fs.val[0] == fsid->val[0] &&
17
The right operand of '==' is a garbage value
1484 ep->ex_fs.val[1] == fsid->val[1])
1485 return (ep);
1486 ep = ep->ex_next;
1487 }
1488 return (ep);
1489}
1490
1491/*
1492 * Add a directory path to the list.
1493 */
1494char *
1495add_expdir(struct dirlist **dpp, char *cp, int len)
1496{
1497 struct dirlist *dp;
1498
1499 /* do not need +1 because of dp_dirp[1] */
1500 dp = malloc(sizeof (struct dirlist) + len);
1501 if (dp == NULL((void *)0))
1502 out_of_mem();
1503 dp->dp_left = *dpp;
1504 dp->dp_right = NULL((void *)0);
1505 dp->dp_flag = 0;
1506 dp->dp_hosts = NULL((void *)0);
1507 strlcpy(dp->dp_dirp, cp, len + 1);
1508 *dpp = dp;
1509 return (dp->dp_dirp);
1510}
1511
1512/*
1513 * Hang the dir list element off the dirpath binary tree as required
1514 * and update the entry for host.
1515 */
1516void
1517hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep,
1518 int flags)
1519{
1520 struct hostlist *hp;
1521 struct dirlist *dp2;
1522
1523 if (flags & OP_ALLDIRS0x40) {
1524 if (ep->ex_defdir)
1525 free((caddr_t)dp);
1526 else
1527 ep->ex_defdir = dp;
1528 if (grp == NULL((void *)0)) {
1529 ep->ex_defdir->dp_flag |= DP_DEFSET0x1;
1530 } else while (grp) {
1531 hp = get_ht();
1532 hp->ht_grp = grp;
1533 hp->ht_next = ep->ex_defdir->dp_hosts;
1534 ep->ex_defdir->dp_hosts = hp;
1535 grp = grp->gr_next;
1536 }
1537 } else {
1538
1539 /*
1540 * Loop through the directories adding them to the tree.
1541 */
1542 while (dp) {
1543 dp2 = dp->dp_left;
1544 add_dlist(&ep->ex_dirl, dp, grp, flags);
1545 dp = dp2;
1546 }
1547 }
1548}
1549
1550/*
1551 * Traverse the binary tree either updating a node that is already there
1552 * for the new directory or adding the new node.
1553 */
1554void
1555add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp,
1556 int flags)
1557{
1558 struct dirlist *dp;
1559 struct hostlist *hp;
1560 int cmp;
1561
1562 dp = *dpp;
1563 if (dp) {
1564 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
1565 if (cmp > 0) {
1566 add_dlist(&dp->dp_left, newdp, grp, flags);
1567 return;
1568 } else if (cmp < 0) {
1569 add_dlist(&dp->dp_right, newdp, grp, flags);
1570 return;
1571 } else
1572 free((caddr_t)newdp);
1573 } else {
1574 dp = newdp;
1575 dp->dp_left = NULL((void *)0);
1576 *dpp = dp;
1577 }
1578 if (grp) {
1579
1580 /*
1581 * Hang all of the host(s) off of the directory point.
1582 */
1583 do {
1584 hp = get_ht();
1585 hp->ht_grp = grp;
1586 hp->ht_next = dp->dp_hosts;
1587 dp->dp_hosts = hp;
1588 grp = grp->gr_next;
1589 } while (grp);
1590 } else {
1591 dp->dp_flag |= DP_DEFSET0x1;
1592 }
1593}
1594
1595/*
1596 * Search for a dirpath on the export point.
1597 */
1598struct dirlist *
1599dirp_search(struct dirlist *dp, char *dirpath)
1600{
1601 int cmp;
1602
1603 if (dp) {
1604 cmp = strcmp(dp->dp_dirp, dirpath);
1605 if (cmp > 0)
1606 return (dirp_search(dp->dp_left, dirpath));
1607 else if (cmp < 0)
1608 return (dirp_search(dp->dp_right, dirpath));
1609 else
1610 return (dp);
1611 }
1612 return (dp);
1613}
1614
1615/*
1616 * Scan for a host match in a directory tree.
1617 */
1618int
1619chk_host(struct dirlist *dp, in_addr_t saddr, int *defsetp, int *hostsetp)
1620{
1621 struct hostlist *hp;
1622 struct grouplist *grp;
1623 u_int32_t **addrp;
1624
1625 if (dp) {
1626 if (dp->dp_flag & DP_DEFSET0x1)
1627 *defsetp = dp->dp_flag;
1628 hp = dp->dp_hosts;
1629 while (hp) {
1630 grp = hp->ht_grp;
1631 switch (grp->gr_type) {
1632 case GT_HOST0x1:
1633 addrp = (u_int32_t **)
1634 grp->gr_ptr.gt_hostent->h_addr_list;
1635 while (*addrp) {
1636 if (**addrp == saddr) {
1637 *hostsetp = (hp->ht_flag | DP_HOSTSET0x2);
1638 return (1);
1639 }
1640 addrp++;
1641 }
1642 break;
1643 case GT_NET0x2:
1644 if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
1645 grp->gr_ptr.gt_net.nt_net) {
1646 *hostsetp = (hp->ht_flag | DP_HOSTSET0x2);
1647 return (1);
1648 }
1649 break;
1650 }
1651 hp = hp->ht_next;
1652 }
1653 }
1654 return (0);
1655}
1656
1657/*
1658 * Scan tree for a host that matches the address.
1659 */
1660int
1661scan_tree(struct dirlist *dp, in_addr_t saddr)
1662{
1663 int defset, hostset;
1664
1665 if (dp) {
1666 if (scan_tree(dp->dp_left, saddr))
1667 return (1);
1668 if (chk_host(dp, saddr, &defset, &hostset))
1669 return (1);
1670 if (scan_tree(dp->dp_right, saddr))
1671 return (1);
1672 }
1673 return (0);
1674}
1675
1676/*
1677 * Traverse the dirlist tree and free it up.
1678 */
1679void
1680free_dir(struct dirlist *dp)
1681{
1682
1683 if (dp) {
1684 free_dir(dp->dp_left);
1685 free_dir(dp->dp_right);
1686 free_host(dp->dp_hosts);
1687 free((caddr_t)dp);
1688 }
1689}
1690
1691/*
1692 * Parse the option string and update fields.
1693 * Option arguments may either be -<option>=<value> or
1694 * -<option> <value>
1695 */
1696int
1697do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp,
1698 int *has_hostp, int *exflagsp, struct xucred *cr)
1699{
1700 char *cp, *endcp, *cpopt, savedc, savedc2 = 0;
1701 char *cpoptarg, *cpoptend;
1702 int allflag, usedarg;
1703
1704 cpopt = *cpp;
1705 cpopt++;
1706 cp = *endcpp;
1707 savedc = *cp;
1708 *cp = '\0';
1709 while (cpopt && *cpopt) {
1710 allflag = 1;
1711 usedarg = -2;
1712 if ((cpoptend = strchr(cpopt, ','))) {
1713 *cpoptend++ = '\0';
1714 if ((cpoptarg = strchr(cpopt, '=')))
1715 *cpoptarg++ = '\0';
1716 } else {
1717 if ((cpoptarg = strchr(cpopt, '=')))
1718 *cpoptarg++ = '\0';
1719 else {
1720 *cp = savedc;
1721 nextfield(&cp, &endcp);
1722 **endcpp = '\0';
1723 if (endcp > cp && *cp != '-') {
1724 cpoptarg = cp;
1725 savedc2 = *endcp;
1726 *endcp = '\0';
1727 usedarg = 0;
1728 }
1729 }
1730 }
1731 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1732 *exflagsp |= MNT_EXRDONLY0x00000080;
1733 } else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1734 !(allflag = strcmp(cpopt, "mapall")) ||
1735 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1736 usedarg++;
1737 parsecred(cpoptarg, cr);
1738 if (allflag == 0) {
1739 *exflagsp |= MNT_EXPORTANON0x00000400;
1740 opt_flags |= OP_MAPALL0x02;
1741 } else
1742 opt_flags |= OP_MAPROOT0x01;
1743 } else
1744 if (cpoptarg && (!strcmp(cpopt, "mask") ||
1745 !strcmp(cpopt, "m"))) {
1746 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1747 syslog(LOG_ERR3, "Bad mask: %s", cpoptarg);
1748 return (1);
1749 }
1750 usedarg++;
1751 opt_flags |= OP_MASK0x08;
1752 } else if (cpoptarg && (!strcmp(cpopt, "network") ||
1753 !strcmp(cpopt, "n"))) {
1754 if (grp->gr_type != GT_NULL0x0) {
1755 syslog(LOG_ERR3, "Network/host conflict");
1756 return (1);
1757 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1758 syslog(LOG_ERR3, "Bad net: %s", cpoptarg);
1759 return (1);
1760 }
1761 grp->gr_type = GT_NET0x2;
1762 *has_hostp = 1;
1763 usedarg++;
1764 opt_flags |= OP_NET0x10;
1765 } else if (!strcmp(cpopt, "alldirs")) {
1766 opt_flags |= OP_ALLDIRS0x40;
1767 } else {
1768 syslog(LOG_ERR3, "Bad opt %s", cpopt);
1769 return (1);
1770 }
1771 if (usedarg >= 0) {
1772 *endcp = savedc2;
1773 **endcpp = savedc;
1774 if (usedarg > 0) {
1775 *cpp = cp;
1776 *endcpp = endcp;
1777 }
1778 return (0);
1779 }
1780 cpopt = cpoptend;
1781 }
1782 **endcpp = savedc;
1783 return (0);
1784}
1785
1786/*
1787 * Translate a character string to the corresponding list of network
1788 * addresses for a hostname.
1789 */
1790int
1791get_host(char *cp, struct grouplist *grp, struct grouplist *tgrp)
1792{
1793 struct hostent *hp, *nhp, t_host;
1794 struct grouplist *checkgrp;
1795 char **addrp, **naddrp;
1796 struct in_addr saddr;
1797 char *aptr[2];
1798 int i;
1799
1800 if (grp->gr_type != GT_NULL0x0)
1801 return (1);
1802 if ((hp = gethostbyname(cp)) == NULL((void *)0)) {
1803 if (isdigit((unsigned char)*cp)) {
1804 if (inet_aton(cp, &saddr) == 0) {
1805 syslog(LOG_ERR3, "inet_aton failed for %s", cp);
1806 return (1);
1807 }
1808 if ((hp = gethostbyaddr((caddr_t)&saddr.s_addr,
1809 sizeof (saddr.s_addr), AF_INET2)) == NULL((void *)0)) {
1810 hp = &t_host;
1811 hp->h_name = cp;
1812 hp->h_addrtype = AF_INET2;
1813 hp->h_length = sizeof (u_int32_t);
1814 hp->h_addr_list = aptr;
1815 aptr[0] = (char *)&saddr;
1816 aptr[1] = NULL((void *)0);
1817 }
1818 } else {
1819 syslog(LOG_ERR3, "gethostbyname; failed for %s: %s", cp,
1820 hstrerror(h_errno));
1821 return (1);
1822 }
1823 }
1824
1825 /* only insert each host onto the list once */
1826 for (checkgrp = tgrp; checkgrp; checkgrp = checkgrp->gr_next) {
1827 if (checkgrp->gr_type == GT_HOST0x1 &&
1828 checkgrp->gr_ptr.gt_hostent != NULL((void *)0) &&
1829 !strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)) {
1830 grp->gr_type = GT_IGNORE0x5;
1831 return (0);
1832 }
1833 }
1834
1835 grp->gr_type = GT_HOST0x1;
1836 nhp = grp->gr_ptr.gt_hostent = malloc(sizeof(struct hostent));
1837 if (nhp == NULL((void *)0))
1838 out_of_mem();
1839 memcpy(nhp, hp, sizeof(struct hostent));
1840 i = strlen(hp->h_name)+1;
1841 nhp->h_name = malloc(i);
1842 if (nhp->h_name == NULL((void *)0))
1843 out_of_mem();
1844 memcpy(nhp->h_name, hp->h_name, i);
1845 addrp = hp->h_addr_list;
1846 i = 1;
1847 while (*addrp++)
1848 i++;
1849 naddrp = nhp->h_addr_list = reallocarray(NULL((void *)0), i, sizeof(char *));
1850 if (naddrp == NULL((void *)0))
1851 out_of_mem();
1852 addrp = hp->h_addr_list;
1853 while (*addrp) {
1854 *naddrp = malloc(hp->h_length);
1855 if (*naddrp == NULL((void *)0))
1856 out_of_mem();
1857 memcpy(*naddrp, *addrp, hp->h_length);
1858 addrp++;
1859 naddrp++;
1860 }
1861 *naddrp = NULL((void *)0);
1862 if (debug)
1863 fprintf(stderr(&__sF[2]), "got host %s\n", hp->h_name);
1864 return (0);
1865}
1866
1867/*
1868 * Free up an exports list component
1869 */
1870void
1871free_exp(struct exportlist *ep)
1872{
1873
1874 if (ep->ex_defdir) {
1875 free_host(ep->ex_defdir->dp_hosts);
1876 free((caddr_t)ep->ex_defdir);
1877 }
1878 free(ep->ex_fsdir);
1879 free_dir(ep->ex_dirl);
1880 free((caddr_t)ep);
1881}
1882
1883/*
1884 * Free hosts.
1885 */
1886void
1887free_host(struct hostlist *hp)
1888{
1889 struct hostlist *hp2;
1890
1891 while (hp) {
1892 hp2 = hp;
1893 hp = hp->ht_next;
1894 free((caddr_t)hp2);
1895 }
1896}
1897
1898struct hostlist *
1899get_ht(void)
1900{
1901 struct hostlist *hp;
1902
1903 hp = malloc(sizeof (struct hostlist));
1904 if (hp == NULL((void *)0))
1905 out_of_mem();
1906 hp->ht_next = NULL((void *)0);
1907 hp->ht_flag = 0;
1908 return (hp);
1909}
1910
1911/*
1912 * Out of memory, fatal
1913 */
1914void
1915out_of_mem(void)
1916{
1917
1918 syslog(LOG_ERR3, "Out of memory");
1919 exit(2);
1920}
1921
1922/*
1923 * Do the mount syscall with the update flag to push the export info into
1924 * the kernel. Returns 0 on success, 1 for fatal error, and 2 for error
1925 * that only invalidates the specific entry/host.
1926 */
1927int
1928do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
1929 struct xucred *anoncrp, char *dirp, int dirplen)
1930{
1931 struct sockaddr_in sin, imask;
1932 struct export_args args;
1933 char savedc = '\0';
1934 u_int32_t **addrp;
1935 char *cp = NULL((void *)0);
1936 in_addr_t net;
1937 int done;
1938
1939 args.ex_flags = exflags;
1940 args.ex_anon = *anoncrp;
1941 memset(&sin, 0, sizeof(sin));
1942 memset(&imask, 0, sizeof(imask));
1943 sin.sin_family = AF_INET2;
1944 sin.sin_len = sizeof(sin);
1945 imask.sin_family = AF_INET2;
1946 imask.sin_len = sizeof(sin);
1947 if (grp->gr_type == GT_HOST0x1)
1948 addrp = (u_int32_t **)grp->gr_ptr.gt_hostent->h_addr_list;
1949 else
1950 addrp = NULL((void *)0);
1951
1952 done = FALSE(0);
1953 while (!done) {
1954 switch (grp->gr_type) {
1955 case GT_HOST0x1:
1956 args.ex_addr = (struct sockaddr *)&sin;
1957 args.ex_masklen = 0;
1958 if (!addrp) {
1959 args.ex_addrlen = 0;
1960 break;
1961 }
1962 sin.sin_addr.s_addr = **addrp;
1963 args.ex_addrlen = sizeof(sin);
1964 break;
1965 case GT_NET0x2:
1966 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1967 args.ex_addr = (struct sockaddr *)&sin;
1968 args.ex_addrlen = sizeof (sin);
1969 args.ex_mask = (struct sockaddr *)&imask;
1970 args.ex_masklen = sizeof (imask);
1971 if (grp->gr_ptr.gt_net.nt_mask) {
1972 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1973 break;
1974 }
1975 net = ntohl(grp->gr_ptr.gt_net.nt_net)(__uint32_t)(__builtin_constant_p(grp->gr_ptr.gt_net.nt_net
) ? (__uint32_t)(((__uint32_t)(grp->gr_ptr.gt_net.nt_net) &
0xff) << 24 | ((__uint32_t)(grp->gr_ptr.gt_net.nt_net
) & 0xff00) << 8 | ((__uint32_t)(grp->gr_ptr.gt_net
.nt_net) & 0xff0000) >> 8 | ((__uint32_t)(grp->gr_ptr
.gt_net.nt_net) & 0xff000000) >> 24) : __swap32md(grp
->gr_ptr.gt_net.nt_net))
;
1976 if (IN_CLASSA(net)(((u_int32_t)(net) & ((u_int32_t)(0x80000000))) == ((u_int32_t
)(0x00000000)))
)
1977 imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1978 else if (IN_CLASSB(net)(((u_int32_t)(net) & ((u_int32_t)(0xc0000000))) == ((u_int32_t
)(0x80000000)))
)
1979 imask.sin_addr.s_addr = inet_addr("255.255.0.0");
1980 else
1981 imask.sin_addr.s_addr = inet_addr("255.255.255.0");
1982 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1983 break;
1984 case GT_IGNORE0x5:
1985 return (0);
1986 default:
1987 syslog(LOG_ERR3, "Bad grouptype");
1988 if (cp)
1989 *cp = savedc;
1990 return (1);
1991 }
1992
1993 /*
1994 * XXX:
1995 * Maybe I should just use the fsb->f_mntonname path instead
1996 * of looping back up the dirp to the mount point??
1997 * Also, needs to know how to export all types of local
1998 * exportable file systems and not just MOUNT_FFS.
1999 */
2000 while (imsg_export(dirp, &args) == -1) {
2001 if (cp)
2002 *cp-- = savedc;
2003 else
2004 cp = dirp + dirplen - 1;
2005 if (errno(*__errno()) == EPERM1) {
2006 syslog(LOG_ERR3,
2007 "Can't change attributes for %s (%s).\n",
2008 dirp,
2009 (grp->gr_type == GT_HOST0x1)
2010 ?grp->gr_ptr.gt_hostent->h_name
2011 :(grp->gr_type == GT_NET0x2)
2012 ?grp->gr_ptr.gt_net.nt_name
2013 :"Unknown");
2014 return (2);
2015 }
2016 if (opt_flags & OP_ALLDIRS0x40) {
2017#if 0
2018 syslog(LOG_ERR3, "Could not remount %s: %m",
2019 dirp);
2020 return (2);
2021#endif
2022 }
2023 /* back up over the last component */
2024 while (cp > dirp && *cp == '/')
2025 cp--;
2026 while (cp > dirp && *(cp - 1) != '/')
2027 cp--;
2028 if (cp == dirp) {
2029 if (debug)
2030 fprintf(stderr(&__sF[2]), "mnt unsucc\n");
2031 syslog(LOG_ERR3, "Can't export %s: %m", dirp);
2032 return (2);
2033 }
2034 savedc = *cp;
2035 *cp = '\0';
2036 }
2037 if (addrp) {
2038 ++addrp;
2039 if (*addrp == NULL((void *)0))
2040 done = TRUE(1);
2041 } else
2042 done = TRUE(1);
2043 }
2044 if (cp)
2045 *cp = savedc;
2046 return (0);
2047}
2048
2049/*
2050 * Translate a net address.
2051 */
2052int
2053get_net(char *cp, struct netmsk *net, int maskflg)
2054{
2055 struct in_addr inetaddr, inetaddr2;
2056 in_addr_t netaddr;
2057 struct netent *np;
2058 char *name;
2059
2060 if ((netaddr = inet_network(cp)) != INADDR_NONE((u_int32_t)(0xffffffff))) {
2061 inetaddr = inet_makeaddr(netaddr, 0);
2062 /*
2063 * Due to arbitrary subnet masks, you don't know how many
2064 * bits to shift the address to make it into a network,
2065 * however you do know how to make a network address into
2066 * a host with host == 0 and then compare them.
2067 * (What a pest)
2068 */
2069 if (!maskflg) {
2070 setnetent(0);
2071 while ((np = getnetent())) {
2072 inetaddr2 = inet_makeaddr(np->n_net, 0);
2073 if (inetaddr2.s_addr == inetaddr.s_addr)
2074 break;
2075 }
2076 endnetent();
2077 }
2078 } else {
2079 if ((np = getnetbyname(cp)))
2080 inetaddr = inet_makeaddr(np->n_net, 0);
2081 else
2082 return (1);
2083 }
2084 if (maskflg)
2085 net->nt_mask = inetaddr.s_addr;
2086 else {
2087 int len;
2088
2089 if (np)
2090 name = np->n_name;
2091 else
2092 name = inet_ntoa(inetaddr);
2093 len = strlen(name) + 1;
2094 net->nt_name = malloc(len);
2095 if (net->nt_name == NULL((void *)0))
2096 out_of_mem();
2097 strlcpy(net->nt_name, name, len);
2098 net->nt_net = inetaddr.s_addr;
2099 }
2100 return (0);
2101}
2102
2103/*
2104 * Parse out the next white space separated field
2105 */
2106void
2107nextfield(char **cp, char **endcp)
2108{
2109 char *p;
2110
2111 p = *cp;
2112 while (*p == ' ' || *p == '\t')
2113 p++;
2114 if (*p == '\n' || *p == '\0')
2115 *cp = *endcp = p;
2116 else {
2117 *cp = p++;
2118 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
2119 p++;
2120 *endcp = p;
2121 }
2122}
2123
2124/*
2125 * Get an exports file line. Skip over blank lines and handle line
2126 * continuations.
2127 */
2128int
2129get_line(void)
2130{
2131 int totlen, cont_line, len;
2132 char *p, *cp;
2133
2134 /*
2135 * Loop around ignoring blank lines and getting all continuation lines.
2136 */
2137 p = line;
2138 totlen = 0;
2139 do {
2140 if (fgets(p, LINESIZ10240 - totlen, exp_file) == NULL((void *)0))
2141 return (0);
2142 len = strlen(p);
2143 cp = p + len - 1;
2144 cont_line = 0;
2145 while (cp >= p && (*cp == ' ' || *cp == '\t' || *cp == '\n' ||
2146 *cp == '\\')) {
2147 if (*cp == '\\')
2148 cont_line = 1;
2149 cp--;
2150 len--;
2151 }
2152 *++cp = '\0';
2153 if (len > 0) {
2154 totlen += len;
2155 if (totlen >= LINESIZ10240) {
2156 syslog(LOG_ERR3, "Exports line too long");
2157 exit(2);
2158 }
2159 p = cp;
2160 }
2161 } while (totlen == 0 || cont_line);
2162 return (1);
2163}
2164
2165/*
2166 * Parse a description of a credential.
2167 */
2168void
2169parsecred(char *namelist, struct xucred *cr)
2170{
2171 gid_t groups[NGROUPS_MAX16 + 1];
2172 char *name, *names;
2173 struct passwd *pw;
2174 struct group *gr;
2175 int ngroups, cnt;
2176
2177 /*
2178 * Set up the unprivileged user.
2179 */
2180 *cr = def_anon;
2181
2182 /*
2183 * Get the user's password table entry.
2184 */
2185 names = strsep(&namelist, " \t\n");
2186 name = strsep(&names, ":");
2187 if (isdigit((unsigned char)*name) || *name == '-')
2188 pw = getpwuid(atoi(name));
2189 else
2190 pw = getpwnam(name);
2191 /*
2192 * Credentials specified as those of a user.
2193 */
2194 if (names == NULL((void *)0)) {
2195 if (pw == NULL((void *)0)) {
2196 syslog(LOG_ERR3, "Unknown user: %s", name);
2197 return;
2198 }
2199 cr->cr_uid = pw->pw_uid;
2200 ngroups = NGROUPS_MAX16 + 1;
2201 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
2202 syslog(LOG_ERR3, "Too many groups for %s: %m", pw->pw_name);
2203 /*
2204 * compress out duplicate
2205 */
2206 cr->cr_ngroups = ngroups - 1;
2207 cr->cr_gid = groups[0];
2208 for (cnt = 1; cnt < ngroups; cnt++)
2209 cr->cr_groups[cnt - 1] = groups[cnt];
2210 return;
2211 }
2212 /*
2213 * Explicit credential specified as a colon separated list:
2214 * uid:gid:gid:...
2215 */
2216 if (pw != NULL((void *)0))
2217 cr->cr_uid = pw->pw_uid;
2218 else if (isdigit((unsigned char)*name) || *name == '-')
2219 cr->cr_uid = atoi(name);
2220 else {
2221 syslog(LOG_ERR3, "Unknown user: %s", name);
2222 return;
2223 }
2224 cr->cr_ngroups = 0;
2225 while (names != NULL((void *)0) && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX16) {
2226 name = strsep(&names, ":");
2227 if (isdigit((unsigned char)*name) || *name == '-') {
2228 cr->cr_groups[cr->cr_ngroups++] = atoi(name);
2229 } else {
2230 if ((gr = getgrnam(name)) == NULL((void *)0)) {
2231 syslog(LOG_ERR3, "Unknown group: %s", name);
2232 continue;
2233 }
2234 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
2235 }
2236 }
2237 if (names != NULL((void *)0) && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX16)
2238 syslog(LOG_ERR3, "Too many groups");
2239}
2240
2241#define STRSIZ(255 +1024 +50) (RPCMNT_NAMELEN255+RPCMNT_PATHLEN1024+50)
2242/*
2243 * Routines that maintain the remote mounttab
2244 */
2245void
2246get_mountlist(void)
2247{
2248 struct mountlist *mlp, **mlpp;
2249 char *host, *dirp, *cp;
2250 char str[STRSIZ(255 +1024 +50)];
2251 FILE *mlfile;
2252
2253 if ((mlfile = fopen(_PATH_RMOUNTLIST"/var/db/mountdtab", "r")) == NULL((void *)0)) {
2254 syslog(LOG_ERR3, "Can't open %s: %m", _PATH_RMOUNTLIST"/var/db/mountdtab");
2255 return;
2256 }
2257 mlpp = &mlhead;
2258 while (fgets(str, STRSIZ(255 +1024 +50), mlfile) != NULL((void *)0)) {
2259 cp = str;
2260 host = strsep(&cp, " \t\n");
2261 dirp = strsep(&cp, " \t\n");
2262 if (host == NULL((void *)0) || dirp == NULL((void *)0))
2263 continue;
2264 mlp = malloc(sizeof (*mlp));
2265 if (mlp == NULL((void *)0))
2266 out_of_mem();
2267 strlcpy(mlp->ml_host, host, sizeof(mlp->ml_host));
2268 strlcpy(mlp->ml_dirp, dirp, sizeof(mlp->ml_dirp));
2269 mlp->ml_next = NULL((void *)0);
2270 *mlpp = mlp;
2271 mlpp = &mlp->ml_next;
2272 }
2273 fclose(mlfile);
2274}
2275
2276void
2277del_mlist(char *hostp, char *dirp)
2278{
2279 struct mountlist *mlp, **mlpp;
2280 struct mountlist *mlp2;
2281 int fnd = 0;
2282
2283 mlpp = &mlhead;
2284 mlp = mlhead;
2285 while (mlp) {
2286 if (!strcmp(mlp->ml_host, hostp) &&
2287 (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
2288 fnd = 1;
2289 mlp2 = mlp;
2290 *mlpp = mlp = mlp->ml_next;
2291 free((caddr_t)mlp2);
2292 } else {
2293 mlpp = &mlp->ml_next;
2294 mlp = mlp->ml_next;
2295 }
2296 }
2297 if (fnd) {
2298 send_imsg(IMSG_MLIST_OPEN0x6, NULL((void *)0), 0);
2299 mlp = mlhead;
2300 while (mlp) {
2301 send_imsg(IMSG_MLIST_WRITE0x8, mlp, sizeof(*mlp));
2302 mlp = mlp->ml_next;
2303 }
2304 send_imsg(IMSG_MLIST_CLOSE0x7, NULL((void *)0), 0);
2305 }
2306}
2307
2308void
2309add_mlist(char *hostp, char *dirp)
2310{
2311 struct mountlist *mlp, **mlpp;
2312
2313 mlpp = &mlhead;
2314 mlp = mlhead;
2315 while (mlp) {
2316 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
2317 return;
2318 mlpp = &mlp->ml_next;
2319 mlp = mlp->ml_next;
2320 }
2321 mlp = malloc(sizeof (*mlp));
2322 if (mlp == NULL((void *)0))
2323 out_of_mem();
2324 strlcpy(mlp->ml_host, hostp, sizeof(mlp->ml_host));
2325 strlcpy(mlp->ml_dirp, dirp, sizeof(mlp->ml_dirp));
2326 mlp->ml_next = NULL((void *)0);
2327 *mlpp = mlp;
2328 send_imsg(IMSG_MLIST_APPEND0x5, mlp, sizeof(*mlp));
2329}
2330
2331/*
2332 * This function is called via SIGTERM when the system is going down.
2333 * It sends a broadcast RPCMNT_UMNTALL.
2334 */
2335void
2336send_umntall(int signo)
2337{
2338 gotterm = 1;
2339}
2340
2341int
2342umntall_each(caddr_t resultsp, struct sockaddr_in *raddr)
2343{
2344 return (1);
2345}
2346
2347/*
2348 * Free up a group list.
2349 */
2350void
2351free_grp(struct grouplist *grp)
2352{
2353 char **addrp;
2354
2355 if (grp->gr_type == GT_HOST0x1) {
2356 if (grp->gr_ptr.gt_hostent->h_name) {
2357 addrp = grp->gr_ptr.gt_hostent->h_addr_list;
2358 while (addrp && *addrp)
2359 free(*addrp++);
2360 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
2361 free(grp->gr_ptr.gt_hostent->h_name);
2362 }
2363 free((caddr_t)grp->gr_ptr.gt_hostent);
2364 } else if (grp->gr_type == GT_NET0x2) {
2365 free(grp->gr_ptr.gt_net.nt_name);
2366 }
2367 free((caddr_t)grp);
2368}
2369
2370/*
2371 * Check options for consistency.
2372 */
2373int
2374check_options(struct dirlist *dp)
2375{
2376
2377 if (dp == NULL((void *)0))
2378 return (1);
2379 if ((opt_flags & (OP_MAPROOT0x01 | OP_MAPALL0x02)) == (OP_MAPROOT0x01 | OP_MAPALL0x02)) {
2380 syslog(LOG_ERR3, "-mapall and -maproot mutually exclusive");
2381 return (1);
2382 }
2383 if ((opt_flags & OP_MASK0x08) && (opt_flags & OP_NET0x10) == 0) {
2384 syslog(LOG_ERR3, "-mask requires -network");
2385 return (1);
2386 }
2387 if ((opt_flags & OP_ALLDIRS0x40) && dp->dp_left) {
2388 syslog(LOG_ERR3, "-alldirs has multiple directories");
2389 return (1);
2390 }
2391 return (0);
2392}
2393
2394/*
2395 * Check an absolute directory path for any symbolic links. Return true
2396 * if no symbolic links are found.
2397 */
2398int
2399check_dirpath(char *dirp)
2400{
2401 struct stat sb;
2402 int ret = 1;
2403 char *cp;
2404
2405 /* Remove trailing '/' */
2406 cp = dirp + strlen(dirp) - 1;
2407 while (cp > dirp && *cp == '/')
2408 *cp-- = '\0';
2409
2410 cp = dirp + 1;
2411 while (*cp && ret) {
2412 if (*cp == '/') {
2413 *cp = '\0';
2414 if (lstat(dirp, &sb) == -1 || !S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000))
2415 ret = 0;
2416 *cp = '/';
2417 }
2418 cp++;
2419 }
2420 if (lstat(dirp, &sb) == -1 ||
2421 (!S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000) && !S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000)))
2422 ret = 0;
2423 return (ret);
2424}