Bug Summary

File:src/sbin/mountd/mountd.c
Warning:line 1469, 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.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mountd.c -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 -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -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/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/mountd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -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/scan/2024-01-11-140451-98009-1 -x c /usr/src/sbin/mountd/mountd.c
1/* $OpenBSD: mountd.c,v 1.91 2023/03/02 16:58:43 millert 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, WNOHANG0x01) == -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 int defset, hostset;
740 struct fhreturn fhr;
741 struct dirlist *dp;
742 struct statfs fsb;
743 struct stat stb;
744 in_addr_t saddr;
745 u_short sport;
746 long bad = 0;
747
748 saddr = transp->xp_raddr.sin_addr.s_addr;
749 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
750 switch (rqstp->rq_proc) {
2
Control jumps to 'case 1:' at line 755
751 case NULLPROC((unsigned int)0):
752 if (!svc_sendreply(transp, xdr_void, NULL((void *)0)))
753 syslog(LOG_ERR3, "Can't send reply");
754 return;
755 case RPCMNT_MOUNT1:
756 if (debug)
3
Assuming 'debug' is 0
4
Taking false branch
757 fprintf(stderr(&__sF[2]), "Got mount request from %s\n",
758 inet_ntoa(transp->xp_raddr.sin_addr));
759 if (sport >= IPPORT_RESERVED1024) {
5
Assuming 'sport' is < IPPORT_RESERVED
6
Taking false branch
760 syslog(LOG_NOTICE5,
761 "Refused mount RPC from host %s port %d",
762 inet_ntoa(transp->xp_raddr.sin_addr), sport);
763 svcerr_weakauth(transp);
764 return;
765 }
766 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
767 svcerr_decode(transp);
768 return;
769 }
770 if (debug)
9
Assuming 'debug' is 0
10
Taking false branch
771 fprintf(stderr(&__sF[2]), "rpcpath: %s\n", rpcpath);
772
773 /*
774 * Get the real pathname and make sure it is a file or
775 * directory that exists.
776 */
777 if (realpath(rpcpath, dirpath) == NULL((void *)0)) {
11
Assuming the condition is true
12
Taking true branch
778 bad = errno(*__errno());
779 if (debug
12.1
'debug' is 0
)
13
Taking false branch
780 fprintf(stderr(&__sF[2]), "realpath failed on %s\n",
781 rpcpath);
782 strlcpy(dirpath, rpcpath, sizeof(dirpath));
783 } else if (stat(dirpath, &stb) == -1 ||
784 (!S_ISDIR(stb.st_mode)((stb.st_mode & 0170000) == 0040000) && !S_ISREG(stb.st_mode)((stb.st_mode & 0170000) == 0100000)) ||
785 statfs(dirpath, &fsb) == -1) {
786 if (debug)
787 fprintf(stderr(&__sF[2]), "stat failed on %s\n", dirpath);
788 bad = ENOENT2; /* We will send error reply later */
789 }
790
791 /* Check in the exports list */
792 ep = bad ? NULL((void *)0) : ex_search(&fsb.f_fsid);
14
Assuming 'bad' is 0
15
'?' condition is false
16
Calling 'ex_search'
793 hostset = defset = 0;
794 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
795 ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
796 chk_host(dp, saddr, &defset, &hostset)) ||
797 (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
798 scan_tree(ep->ex_dirl, saddr) == 0))) {
799 if (bad) {
800 if (!svc_sendreply(transp, xdr_long,
801 (caddr_t)&bad))
802 syslog(LOG_ERR3, "Can't send reply");
803 return;
804 }
805 if (hostset & DP_HOSTSET0x2)
806 fhr.fhr_flag = hostset;
807 else
808 fhr.fhr_flag = defset;
809 fhr.fhr_vers = rqstp->rq_vers;
810 /* Get the file handle */
811 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
812 if (imsg_getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
813 bad = errno(*__errno());
814 syslog(LOG_ERR3, "Can't get fh for %s", dirpath);
815 if (!svc_sendreply(transp, xdr_long,
816 (caddr_t)&bad))
817 syslog(LOG_ERR3, "Can't send reply");
818 return;
819 }
820 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))
821 syslog(LOG_ERR3, "Can't send reply");
822 if (hp == NULL((void *)0))
823 hp = gethostbyaddr((caddr_t)&saddr,
824 sizeof(saddr), AF_INET2);
825 if (hp)
826 add_mlist(hp->h_name, dirpath);
827 else
828 add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
829 dirpath);
830 if (debug) {
831 fprintf(stderr(&__sF[2]),
832 "Mount successful for %s by %s.\n",
833 dirpath,
834 inet_ntoa(transp->xp_raddr.sin_addr));
835 }
836 } else
837 bad = EACCES13;
838
839 if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad))
840 syslog(LOG_ERR3, "Can't send reply");
841 return;
842 case RPCMNT_DUMP2:
843 if (!svc_sendreply(transp, xdr_mlist, NULL((void *)0)))
844 syslog(LOG_ERR3, "Can't send reply");
845 return;
846 case RPCMNT_UMOUNT3:
847 if (sport >= IPPORT_RESERVED1024) {
848 svcerr_weakauth(transp);
849 return;
850 }
851 if (!svc_getargs(transp, xdr_dir, dirpath)(*(transp)->xp_ops->xp_getargs)((transp), (xdr_dir), (dirpath
))
) {
852 svcerr_decode(transp);
853 return;
854 }
855 if (!svc_sendreply(transp, xdr_void, NULL((void *)0)))
856 syslog(LOG_ERR3, "Can't send reply");
857 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET2);
858 if (hp)
859 del_mlist(hp->h_name, dirpath);
860 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
861 return;
862 case RPCMNT_UMNTALL4:
863 if (sport >= IPPORT_RESERVED1024) {
864 svcerr_weakauth(transp);
865 return;
866 }
867 if (!svc_sendreply(transp, xdr_void, NULL((void *)0)))
868 syslog(LOG_ERR3, "Can't send reply");
869 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET2);
870 if (hp)
871 del_mlist(hp->h_name, NULL((void *)0));
872 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), NULL((void *)0));
873 return;
874 case RPCMNT_EXPORT5:
875 if (!svc_sendreply(transp, xdr_explist, NULL((void *)0)))
876 syslog(LOG_ERR3, "Can't send reply");
877 return;
878 default:
879 svcerr_noproc(transp);
880 return;
881 }
882}
883
884/*
885 * Xdr conversion for a dirpath string
886 */
887int
888xdr_dir(XDR *xdrsp, char *dirp)
889{
890 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN1024));
891}
892
893/*
894 * Xdr routine to generate file handle reply
895 */
896int
897xdr_fhs(XDR *xdrsp, caddr_t cp)
898{
899 struct fhreturn *fhrp = (struct fhreturn *)cp;
900 long ok = 0, len, auth;
901
902 if (!xdr_long(xdrsp, &ok))
903 return (0);
904 switch (fhrp->fhr_vers) {
905 case 1:
906 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH32));
907 case 3:
908 len = NFSX_V3FH(sizeof (fhandle_t));
909 if (!xdr_long(xdrsp, &len))
910 return (0);
911 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
912 return (0);
913 auth = RPCAUTH_UNIX1;
914 len = 1;
915 if (!xdr_long(xdrsp, &len))
916 return (0);
917 return (xdr_long(xdrsp, &auth));
918 }
919 return (0);
920}
921
922int
923xdr_mlist(XDR *xdrsp, caddr_t cp)
924{
925 int true = 1, false = 0;
926 struct mountlist *mlp;
927 char *strp;
928
929 mlp = mlhead;
930 while (mlp) {
931 if (!xdr_bool(xdrsp, &true))
932 return (0);
933 strp = &mlp->ml_host[0];
934 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN255))
935 return (0);
936 strp = &mlp->ml_dirp[0];
937 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN1024))
938 return (0);
939 mlp = mlp->ml_next;
940 }
941 if (!xdr_bool(xdrsp, &false))
942 return (0);
943 return (1);
944}
945
946/*
947 * Xdr conversion for export list
948 */
949int
950xdr_explist(XDR *xdrsp, caddr_t cp)
951{
952 struct exportlist *ep;
953 int false = 0, putdef;
954
955 ep = exphead;
956 while (ep) {
957 putdef = 0;
958 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
959 goto errout;
960 if (ep->ex_defdir && putdef == 0 && put_exlist(ep->ex_defdir,
961 xdrsp, NULL((void *)0), &putdef))
962 goto errout;
963 ep = ep->ex_next;
964 }
965 if (!xdr_bool(xdrsp, &false))
966 return (0);
967 return (1);
968errout:
969 return (0);
970}
971
972/*
973 * Called from xdr_explist() to traverse the tree and export the
974 * directory paths.
975 */
976int
977put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp,
978 int *putdefp)
979{
980 int true = 1, false = 0, gotalldir = 0;
981 struct grouplist *grp;
982 struct hostlist *hp;
983 char *strp;
984
985 if (dp) {
986 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
987 return (1);
988 if (!xdr_bool(xdrsp, &true))
989 return (1);
990 strp = dp->dp_dirp;
991 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN1024))
992 return (1);
993 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
994 gotalldir = 1;
995 *putdefp = 1;
996 }
997 if ((dp->dp_flag & DP_DEFSET0x1) == 0 &&
998 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET0x1) == 0)) {
999 hp = dp->dp_hosts;
1000 while (hp) {
1001 grp = hp->ht_grp;
1002 if (grp->gr_type == GT_HOST0x1) {
1003 if (!xdr_bool(xdrsp, &true))
1004 return (1);
1005 strp = grp->gr_ptr.gt_hostent->h_name;
1006 if (!xdr_string(xdrsp, &strp,
1007 RPCMNT_NAMELEN255))
1008 return (1);
1009 } else if (grp->gr_type == GT_NET0x2) {
1010 if (!xdr_bool(xdrsp, &true))
1011 return (1);
1012 strp = grp->gr_ptr.gt_net.nt_name;
1013 if (!xdr_string(xdrsp, &strp,
1014 RPCMNT_NAMELEN255))
1015 return (1);
1016 }
1017 hp = hp->ht_next;
1018 if (gotalldir && hp == NULL((void *)0)) {
1019 hp = adp->dp_hosts;
1020 gotalldir = 0;
1021 }
1022 }
1023 }
1024 if (!xdr_bool(xdrsp, &false))
1025 return (1);
1026 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
1027 return (1);
1028 }
1029 return (0);
1030}
1031
1032#define LINESIZ10240 10240
1033char line[LINESIZ10240];
1034FILE *exp_file;
1035
1036void
1037new_exportlist(int signo)
1038{
1039 gothup = 1;
1040}
1041
1042/*
1043 * Get the export list
1044 */
1045void
1046get_exportlist(void)
1047{
1048 int len, has_host, exflags, got_nondir, dirplen = 0, num;
1049 int lookup_failed, num_hosts, i, netgrp;
1050 char *cp, *endcp, *dirp = NULL((void *)0), *hst, *usr, *dom, savedc;
1051 struct exportlist *ep, *ep2;
1052 struct grouplist *grp, *tgrp;
1053 struct exportlist **epp;
1054 struct dirlist *dirhead;
1055 struct statfs fsb, *ofsp, *fsp;
1056 struct hostent *hpe;
1057 struct xucred anon;
1058 struct fsarray {
1059 int exflags;
1060 char *mntonname;
1061 } *fstbl;
1062
1063 /*
1064 * First, get rid of the old list
1065 */
1066 ep = exphead;
1067 while (ep) {
1068 ep2 = ep;
1069 ep = ep->ex_next;
1070 free_exp(ep2);
1071 }
1072 exphead = NULL((void *)0);
1073
1074 grp = grphead;
1075 while (grp) {
1076 tgrp = grp;
1077 grp = grp->gr_next;
1078 free_grp(tgrp);
1079 }
1080 grphead = NULL((void *)0);
1081
1082 /*
1083 * And delete exports that are in the kernel for all local
1084 * file systems.
1085 * XXX: Should know how to handle all local exportable file systems
1086 * instead of just MOUNT_FFS.
1087 */
1088 num = getmntinfo(&ofsp, MNT_NOWAIT2);
1089 if (num == 0 && errno(*__errno()))
1090 syslog(LOG_ERR3, "getmntinfo: %s", strerror(errno(*__errno())));
1091
1092 fsp = ofsp;
1093
1094 fstbl = calloc(num, sizeof (fstbl[0]));
1095 if (fstbl == NULL((void *)0))
1096 out_of_mem();
1097
1098 for (i = 0; i < num; i++) {
1099
1100 if (!strncmp(fsp->f_fstypename, MOUNT_MFS"mfs", MFSNAMELEN16) ||
1101 !strncmp(fsp->f_fstypename, MOUNT_FFS"ffs", MFSNAMELEN16) ||
1102 !strncmp(fsp->f_fstypename, MOUNT_EXT2FS"ext2fs", MFSNAMELEN16) ||
1103 !strncmp(fsp->f_fstypename, MOUNT_MSDOS"msdos", MFSNAMELEN16) ||
1104 !strncmp(fsp->f_fstypename, MOUNT_CD9660"cd9660", MFSNAMELEN16)) {
1105 fstbl[i].exflags = MNT_DELEXPORT0x00020000;
1106 fstbl[i].mntonname = fsp->f_mntonname;
1107 }
1108 fsp++;
1109 }
1110
1111 /*
1112 * Read in the exports file and build the list, calling mount() through
1113 * the privileged child as we go along to push the export rules into
1114 * the kernel.
1115 */
1116 if ((exp_file = fopen(exname, "r")) == NULL((void *)0)) {
1117 syslog(LOG_ERR3, "Can't open %s", exname);
1118 exit(2);
1119 }
1120 dirhead = NULL((void *)0);
1121 while (get_line()) {
1122 if (debug)
1123 fprintf(stderr(&__sF[2]), "Got line %s\n",line);
1124 cp = line;
1125 nextfield(&cp, &endcp);
1126 if (*cp == '#')
1127 goto nextline;
1128
1129 /*
1130 * Set defaults.
1131 */
1132 has_host = FALSE(0);
1133 num_hosts = 0;
1134 lookup_failed = FALSE(0);
1135 anon = def_anon;
1136 exflags = MNT_EXPORTED0x00000100;
1137 got_nondir = 0;
1138 opt_flags = 0;
1139 ep = NULL((void *)0);
1140
1141 /*
1142 * Create new exports list entry
1143 */
1144 len = endcp-cp;
1145 tgrp = grp = get_grp();
1146 while (len > 0) {
1147 if (len > RPCMNT_NAMELEN255) {
1148 getexp_err(ep, tgrp);
1149 goto nextline;
1150 }
1151 if (*cp == '-') {
1152 if (ep == NULL((void *)0)) {
1153 getexp_err(ep, tgrp);
1154 goto nextline;
1155 }
1156 if (debug)
1157 fprintf(stderr(&__sF[2]), "doing opt %s\n", cp);
1158 got_nondir = 1;
1159 if (do_opt(&cp, &endcp, ep, grp, &has_host,
1160 &exflags, &anon)) {
1161 getexp_err(ep, tgrp);
1162 goto nextline;
1163 }
1164 } else if (*cp == '/') {
1165 savedc = *endcp;
1166 *endcp = '\0';
1167 if (check_dirpath(cp) &&
1168 statfs(cp, &fsb) >= 0) {
1169 if (got_nondir) {
1170 syslog(LOG_ERR3, "Dirs must be first");
1171 getexp_err(ep, tgrp);
1172 goto nextline;
1173 }
1174 if (ep) {
1175 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
1176 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
1177 getexp_err(ep, tgrp);
1178 goto nextline;
1179 }
1180 } else {
1181 /*
1182 * See if this directory is already
1183 * in the list.
1184 */
1185 ep = ex_search(&fsb.f_fsid);
1186 if (ep == NULL((void *)0)) {
1187 int len;
1188
1189 ep = get_exp();
1190 ep->ex_fs = fsb.f_fsid;
1191 len = strlen(fsb.f_mntonname) + 1;
1192 ep->ex_fsdir = malloc(len);
1193 if (ep->ex_fsdir)
1194 strlcpy(ep->ex_fsdir,
1195 fsb.f_mntonname, len);
1196 else
1197 out_of_mem();
1198 if (debug)
1199 fprintf(stderr(&__sF[2]),
1200 "Making new ep fs=0x%x,0x%x\n",
1201 fsb.f_fsid.val[0],
1202 fsb.f_fsid.val[1]);
1203 } else if (debug)
1204 fprintf(stderr(&__sF[2]),
1205 "Found ep fs=0x%x,0x%x\n",
1206 fsb.f_fsid.val[0],
1207 fsb.f_fsid.val[1]);
1208 }
1209
1210 /*
1211 * Add dirpath to export mount point.
1212 */
1213 dirp = add_expdir(&dirhead, cp, len);
1214 dirplen = len;
1215 } else {
1216 getexp_err(ep, tgrp);
1217 goto nextline;
1218 }
1219 *endcp = savedc;
1220 } else {
1221 savedc = *endcp;
1222 *endcp = '\0';
1223 got_nondir = 1;
1224 if (ep == NULL((void *)0)) {
1225 getexp_err(ep, tgrp);
1226 goto nextline;
1227 }
1228
1229 /*
1230 * Get the host or netgroup.
1231 */
1232 setnetgrent(cp);
1233 netgrp = getnetgrent((const char **)&hst,
1234 (const char **)&usr, (const char **)&dom);
1235 do {
1236 if (has_host) {
1237 grp->gr_next = get_grp();
1238 grp = grp->gr_next;
1239 } else {
1240 memset(grp, 0, sizeof(*grp));
1241 }
1242 if (netgrp) {
1243 if (hst == NULL((void *)0)) {
1244 syslog(LOG_ERR3,
1245 "NULL hostname in netgroup %s, skipping",
1246 cp);
1247 grp->gr_type = GT_IGNORE0x5;
1248 lookup_failed = TRUE(1);
1249 continue;
1250 } else if (get_host(hst, grp, tgrp)) {
1251 syslog(LOG_ERR3,
1252 "Unknown host (%s) in netgroup %s",
1253 hst, cp);
1254 grp->gr_type = GT_IGNORE0x5;
1255 lookup_failed = TRUE(1);
1256 continue;
1257 }
1258 } else if (get_host(cp, grp, tgrp)) {
1259 syslog(LOG_ERR3,
1260 "Unknown host (%s) in line %s",
1261 cp, line);
1262 grp->gr_type = GT_IGNORE0x5;
1263 lookup_failed = TRUE(1);
1264 continue;
1265 }
1266 has_host = TRUE(1);
1267 num_hosts++;
1268 } while (netgrp && getnetgrent((const char **)&hst,
1269 (const char **)&usr, (const char **)&dom));
1270 endnetgrent();
1271 *endcp = savedc;
1272 }
1273 cp = endcp;
1274 nextfield(&cp, &endcp);
1275 len = endcp - cp;
1276 }
1277 /*
1278 * If the exports list is empty due to unresolvable hostnames
1279 * we throw away the line.
1280 */
1281 if (lookup_failed == TRUE(1) && num_hosts == 0 &&
1282 tgrp->gr_type == GT_IGNORE0x5) {
1283 getexp_err(ep, tgrp);
1284 goto nextline;
1285 }
1286 if (check_options(dirhead)) {
1287 getexp_err(ep, tgrp);
1288 goto nextline;
1289 }
1290 if (!has_host) {
1291 grp->gr_type = GT_HOST0x1;
1292 if (debug)
1293 fprintf(stderr(&__sF[2]), "Adding a default entry\n");
1294 /* add a default group and make the grp list NULL */
1295 hpe = malloc(sizeof(struct hostent));
1296 if (hpe == NULL((void *)0))
1297 out_of_mem();
1298 hpe->h_name = strdup("Default");
1299 if (hpe->h_name == NULL((void *)0))
1300 out_of_mem();
1301 hpe->h_addrtype = AF_INET2;
1302 hpe->h_length = sizeof (u_int32_t);
1303 hpe->h_addr_list = NULL((void *)0);
1304 grp->gr_ptr.gt_hostent = hpe;
1305
1306 /*
1307 * Don't allow a network export coincide with a list of
1308 * host(s) on the same line.
1309 */
1310 } else if ((opt_flags & OP_NET0x10) && tgrp->gr_next) {
1311 getexp_err(ep, tgrp);
1312 goto nextline;
1313 }
1314
1315 /*
1316 * Loop through hosts, pushing the exports into the kernel.
1317 * After loop, tgrp points to the start of the list and
1318 * grp points to the last entry in the list.
1319 */
1320 grp = tgrp;
1321 do {
1322
1323 /*
1324 * remove filesystem from unexport list
1325 * add MNT_DELEXPORT to exflags to clean up
1326 * any old addrlist in the kernel
1327 */
1328
1329 for (i = 0; i < num; i++) {
1330 if ((fstbl[i].mntonname != NULL((void *)0)) &&
1331 (strcmp(fsb.f_mntonname,
1332 fstbl[i].mntonname) == 0) &&
1333 (fstbl[i].exflags & MNT_DELEXPORT0x00020000)) {
1334 exflags |= MNT_DELEXPORT0x00020000;
1335 fstbl[i].exflags = 0;
1336 if (debug)
1337 fprintf(stderr(&__sF[2]), "removing %s %s from unexport list\n", dirp, fstbl[i].mntonname);
1338 }
1339 }
1340
1341 if (debug)
1342 fprintf(stderr(&__sF[2]), "exporting %s\n", dirp);
1343 /*
1344 * Non-zero return indicates an error. Return
1345 * val of 1 means line is invalid (not just entry).
1346 */
1347 i = do_mount(ep, grp, exflags, &anon, dirp, dirplen);
1348 exflags &= ~MNT_DELEXPORT0x00020000;
1349 if (i == 1) {
1350 getexp_err(ep, tgrp);
1351 goto nextline;
1352 } else if (i == 2) {
1353 syslog(LOG_ERR3,
1354 "Bad exports list entry (%s) in line %s",
1355 (grp->gr_type == GT_HOST0x1)
1356 ? grp->gr_ptr.gt_hostent->h_name
1357 : (grp->gr_type == GT_NET0x2)
1358 ? grp->gr_ptr.gt_net.nt_name
1359 : "Unknown", line);
1360 }
1361 } while (grp->gr_next && (grp = grp->gr_next));
1362
1363 /*
1364 * Success. Update the data structures.
1365 */
1366 if (has_host) {
1367 hang_dirp(dirhead, tgrp, ep, opt_flags);
1368 grp->gr_next = grphead;
1369 grphead = tgrp;
1370 } else {
1371 hang_dirp(dirhead, NULL((void *)0), ep,
1372 opt_flags);
1373 free_grp(grp);
1374 }
1375 dirhead = NULL((void *)0);
1376 if ((ep->ex_flag & EX_LINKED0x1) == 0) {
1377 ep2 = exphead;
1378 epp = &exphead;
1379
1380 /*
1381 * Insert in the list in alphabetical order.
1382 */
1383 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
1384 epp = &ep2->ex_next;
1385 ep2 = ep2->ex_next;
1386 }
1387 if (ep2)
1388 ep->ex_next = ep2;
1389 *epp = ep;
1390 ep->ex_flag |= EX_LINKED0x1;
1391 }
1392nextline:
1393 if (dirhead) {
1394 free_dir(dirhead);
1395 dirhead = NULL((void *)0);
1396 }
1397 }
1398
1399 fsp = ofsp;
1400 for (i = 0; i < num; i++, fsp++) {
1401 if ((fstbl[i].exflags & MNT_DELEXPORT0x00020000) == 0)
1402 continue;
1403 if (debug)
1404 fprintf(stderr(&__sF[2]), "unexporting %s %s\n",
1405 fsp->f_mntonname, fstbl[i].mntonname);
1406 send_imsg(IMSG_DELEXPORT0x4, fsp->f_mntonname,
1407 sizeof(fsp->f_mntonname));
1408 }
1409 free(fstbl);
1410 fclose(exp_file);
1411}
1412
1413/*
1414 * Allocate an export list element
1415 */
1416struct exportlist *
1417get_exp(void)
1418{
1419 struct exportlist *ep;
1420
1421 ep = calloc(1, sizeof (struct exportlist));
1422 if (ep == NULL((void *)0))
1423 out_of_mem();
1424 return (ep);
1425}
1426
1427/*
1428 * Allocate a group list element
1429 */
1430struct grouplist *
1431get_grp(void)
1432{
1433 struct grouplist *gp;
1434
1435 gp = calloc(1, sizeof (struct grouplist));
1436 if (gp == NULL((void *)0))
1437 out_of_mem();
1438 return (gp);
1439}
1440
1441/*
1442 * Clean up upon an error in get_exportlist().
1443 */
1444void
1445getexp_err(struct exportlist *ep, struct grouplist *grp)
1446{
1447 struct grouplist *tgrp;
1448
1449 syslog(LOG_ERR3, "Bad exports list line %s", line);
1450 if (ep && (ep->ex_flag & EX_LINKED0x1) == 0)
1451 free_exp(ep);
1452 while (grp) {
1453 tgrp = grp;
1454 grp = grp->gr_next;
1455 free_grp(tgrp);
1456 }
1457}
1458
1459/*
1460 * Search the export list for a matching fs.
1461 */
1462struct exportlist *
1463ex_search(fsid_t *fsid)
1464{
1465 struct exportlist *ep;
1466
1467 ep = exphead;
1468 while (ep) {
1469 if (ep->ex_fs.val[0] == fsid->val[0] &&
17
The right operand of '==' is a garbage value
1470 ep->ex_fs.val[1] == fsid->val[1])
1471 return (ep);
1472 ep = ep->ex_next;
1473 }
1474 return (ep);
1475}
1476
1477/*
1478 * Add a directory path to the list.
1479 */
1480char *
1481add_expdir(struct dirlist **dpp, char *cp, int len)
1482{
1483 struct dirlist *dp;
1484
1485 /* do not need +1 because of dp_dirp[1] */
1486 dp = malloc(sizeof (struct dirlist) + len);
1487 if (dp == NULL((void *)0))
1488 out_of_mem();
1489 dp->dp_left = *dpp;
1490 dp->dp_right = NULL((void *)0);
1491 dp->dp_flag = 0;
1492 dp->dp_hosts = NULL((void *)0);
1493 strlcpy(dp->dp_dirp, cp, len + 1);
1494 *dpp = dp;
1495 return (dp->dp_dirp);
1496}
1497
1498/*
1499 * Hang the dir list element off the dirpath binary tree as required
1500 * and update the entry for host.
1501 */
1502void
1503hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep,
1504 int flags)
1505{
1506 struct hostlist *hp;
1507 struct dirlist *dp2;
1508
1509 if (flags & OP_ALLDIRS0x40) {
1510 if (ep->ex_defdir)
1511 free((caddr_t)dp);
1512 else
1513 ep->ex_defdir = dp;
1514 if (grp == NULL((void *)0)) {
1515 ep->ex_defdir->dp_flag |= DP_DEFSET0x1;
1516 } else while (grp) {
1517 hp = get_ht();
1518 hp->ht_grp = grp;
1519 hp->ht_next = ep->ex_defdir->dp_hosts;
1520 ep->ex_defdir->dp_hosts = hp;
1521 grp = grp->gr_next;
1522 }
1523 } else {
1524
1525 /*
1526 * Loop through the directories adding them to the tree.
1527 */
1528 while (dp) {
1529 dp2 = dp->dp_left;
1530 add_dlist(&ep->ex_dirl, dp, grp, flags);
1531 dp = dp2;
1532 }
1533 }
1534}
1535
1536/*
1537 * Traverse the binary tree either updating a node that is already there
1538 * for the new directory or adding the new node.
1539 */
1540void
1541add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp,
1542 int flags)
1543{
1544 struct dirlist *dp;
1545 struct hostlist *hp;
1546 int cmp;
1547
1548 dp = *dpp;
1549 if (dp) {
1550 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
1551 if (cmp > 0) {
1552 add_dlist(&dp->dp_left, newdp, grp, flags);
1553 return;
1554 } else if (cmp < 0) {
1555 add_dlist(&dp->dp_right, newdp, grp, flags);
1556 return;
1557 } else
1558 free((caddr_t)newdp);
1559 } else {
1560 dp = newdp;
1561 dp->dp_left = NULL((void *)0);
1562 *dpp = dp;
1563 }
1564 if (grp) {
1565
1566 /*
1567 * Hang all of the host(s) off of the directory point.
1568 */
1569 do {
1570 hp = get_ht();
1571 hp->ht_grp = grp;
1572 hp->ht_next = dp->dp_hosts;
1573 dp->dp_hosts = hp;
1574 grp = grp->gr_next;
1575 } while (grp);
1576 } else {
1577 dp->dp_flag |= DP_DEFSET0x1;
1578 }
1579}
1580
1581/*
1582 * Search for a dirpath on the export point.
1583 */
1584struct dirlist *
1585dirp_search(struct dirlist *dp, char *dirpath)
1586{
1587 int cmp;
1588
1589 if (dp) {
1590 cmp = strcmp(dp->dp_dirp, dirpath);
1591 if (cmp > 0)
1592 return (dirp_search(dp->dp_left, dirpath));
1593 else if (cmp < 0)
1594 return (dirp_search(dp->dp_right, dirpath));
1595 else
1596 return (dp);
1597 }
1598 return (dp);
1599}
1600
1601/*
1602 * Scan for a host match in a directory tree.
1603 */
1604int
1605chk_host(struct dirlist *dp, in_addr_t saddr, int *defsetp, int *hostsetp)
1606{
1607 struct hostlist *hp;
1608 struct grouplist *grp;
1609 u_int32_t **addrp;
1610
1611 if (dp) {
1612 if (dp->dp_flag & DP_DEFSET0x1)
1613 *defsetp = dp->dp_flag;
1614 hp = dp->dp_hosts;
1615 while (hp) {
1616 grp = hp->ht_grp;
1617 switch (grp->gr_type) {
1618 case GT_HOST0x1:
1619 addrp = (u_int32_t **)
1620 grp->gr_ptr.gt_hostent->h_addr_list;
1621 while (*addrp) {
1622 if (**addrp == saddr) {
1623 *hostsetp = (hp->ht_flag | DP_HOSTSET0x2);
1624 return (1);
1625 }
1626 addrp++;
1627 }
1628 break;
1629 case GT_NET0x2:
1630 if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
1631 grp->gr_ptr.gt_net.nt_net) {
1632 *hostsetp = (hp->ht_flag | DP_HOSTSET0x2);
1633 return (1);
1634 }
1635 break;
1636 }
1637 hp = hp->ht_next;
1638 }
1639 }
1640 return (0);
1641}
1642
1643/*
1644 * Scan tree for a host that matches the address.
1645 */
1646int
1647scan_tree(struct dirlist *dp, in_addr_t saddr)
1648{
1649 int defset, hostset;
1650
1651 if (dp) {
1652 if (scan_tree(dp->dp_left, saddr))
1653 return (1);
1654 if (chk_host(dp, saddr, &defset, &hostset))
1655 return (1);
1656 if (scan_tree(dp->dp_right, saddr))
1657 return (1);
1658 }
1659 return (0);
1660}
1661
1662/*
1663 * Traverse the dirlist tree and free it up.
1664 */
1665void
1666free_dir(struct dirlist *dp)
1667{
1668
1669 if (dp) {
1670 free_dir(dp->dp_left);
1671 free_dir(dp->dp_right);
1672 free_host(dp->dp_hosts);
1673 free((caddr_t)dp);
1674 }
1675}
1676
1677/*
1678 * Parse the option string and update fields.
1679 * Option arguments may either be -<option>=<value> or
1680 * -<option> <value>
1681 */
1682int
1683do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp,
1684 int *has_hostp, int *exflagsp, struct xucred *cr)
1685{
1686 char *cp, *endcp, *cpopt, savedc, savedc2 = 0;
1687 char *cpoptarg, *cpoptend;
1688 int allflag, usedarg;
1689
1690 cpopt = *cpp;
1691 cpopt++;
1692 cp = *endcpp;
1693 savedc = *cp;
1694 *cp = '\0';
1695 while (cpopt && *cpopt) {
1696 allflag = 1;
1697 usedarg = -2;
1698 if ((cpoptend = strchr(cpopt, ','))) {
1699 *cpoptend++ = '\0';
1700 if ((cpoptarg = strchr(cpopt, '=')))
1701 *cpoptarg++ = '\0';
1702 } else {
1703 if ((cpoptarg = strchr(cpopt, '=')))
1704 *cpoptarg++ = '\0';
1705 else {
1706 *cp = savedc;
1707 nextfield(&cp, &endcp);
1708 **endcpp = '\0';
1709 if (endcp > cp && *cp != '-') {
1710 cpoptarg = cp;
1711 savedc2 = *endcp;
1712 *endcp = '\0';
1713 usedarg = 0;
1714 }
1715 }
1716 }
1717 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1718 *exflagsp |= MNT_EXRDONLY0x00000080;
1719 } else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1720 !(allflag = strcmp(cpopt, "mapall")) ||
1721 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1722 usedarg++;
1723 parsecred(cpoptarg, cr);
1724 if (allflag == 0) {
1725 *exflagsp |= MNT_EXPORTANON0x00000400;
1726 opt_flags |= OP_MAPALL0x02;
1727 } else
1728 opt_flags |= OP_MAPROOT0x01;
1729 } else
1730 if (cpoptarg && (!strcmp(cpopt, "mask") ||
1731 !strcmp(cpopt, "m"))) {
1732 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1733 syslog(LOG_ERR3, "Bad mask: %s", cpoptarg);
1734 return (1);
1735 }
1736 usedarg++;
1737 opt_flags |= OP_MASK0x08;
1738 } else if (cpoptarg && (!strcmp(cpopt, "network") ||
1739 !strcmp(cpopt, "n"))) {
1740 if (grp->gr_type != GT_NULL0x0) {
1741 syslog(LOG_ERR3, "Network/host conflict");
1742 return (1);
1743 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1744 syslog(LOG_ERR3, "Bad net: %s", cpoptarg);
1745 return (1);
1746 }
1747 grp->gr_type = GT_NET0x2;
1748 *has_hostp = 1;
1749 usedarg++;
1750 opt_flags |= OP_NET0x10;
1751 } else if (!strcmp(cpopt, "alldirs")) {
1752 opt_flags |= OP_ALLDIRS0x40;
1753 } else {
1754 syslog(LOG_ERR3, "Bad opt %s", cpopt);
1755 return (1);
1756 }
1757 if (usedarg >= 0) {
1758 *endcp = savedc2;
1759 **endcpp = savedc;
1760 if (usedarg > 0) {
1761 *cpp = cp;
1762 *endcpp = endcp;
1763 }
1764 return (0);
1765 }
1766 cpopt = cpoptend;
1767 }
1768 **endcpp = savedc;
1769 return (0);
1770}
1771
1772/*
1773 * Translate a character string to the corresponding list of network
1774 * addresses for a hostname.
1775 */
1776int
1777get_host(char *cp, struct grouplist *grp, struct grouplist *tgrp)
1778{
1779 struct hostent *hp, *nhp, t_host;
1780 struct grouplist *checkgrp;
1781 char **addrp, **naddrp;
1782 struct in_addr saddr;
1783 char *aptr[2];
1784 int i;
1785
1786 if (grp->gr_type != GT_NULL0x0)
1787 return (1);
1788 if ((hp = gethostbyname(cp)) == NULL((void *)0)) {
1789 if (isdigit((unsigned char)*cp)) {
1790 if (inet_aton(cp, &saddr) == 0) {
1791 syslog(LOG_ERR3, "inet_aton failed for %s", cp);
1792 return (1);
1793 }
1794 if ((hp = gethostbyaddr((caddr_t)&saddr.s_addr,
1795 sizeof (saddr.s_addr), AF_INET2)) == NULL((void *)0)) {
1796 hp = &t_host;
1797 hp->h_name = cp;
1798 hp->h_addrtype = AF_INET2;
1799 hp->h_length = sizeof (u_int32_t);
1800 hp->h_addr_list = aptr;
1801 aptr[0] = (char *)&saddr;
1802 aptr[1] = NULL((void *)0);
1803 }
1804 } else {
1805 syslog(LOG_ERR3, "gethostbyname; failed for %s: %s", cp,
1806 hstrerror(h_errno));
1807 return (1);
1808 }
1809 }
1810
1811 /* only insert each host onto the list once */
1812 for (checkgrp = tgrp; checkgrp; checkgrp = checkgrp->gr_next) {
1813 if (checkgrp->gr_type == GT_HOST0x1 &&
1814 checkgrp->gr_ptr.gt_hostent != NULL((void *)0) &&
1815 !strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)) {
1816 grp->gr_type = GT_IGNORE0x5;
1817 return (0);
1818 }
1819 }
1820
1821 grp->gr_type = GT_HOST0x1;
1822 nhp = grp->gr_ptr.gt_hostent = malloc(sizeof(struct hostent));
1823 if (nhp == NULL((void *)0))
1824 out_of_mem();
1825 memcpy(nhp, hp, sizeof(struct hostent));
1826 i = strlen(hp->h_name)+1;
1827 nhp->h_name = malloc(i);
1828 if (nhp->h_name == NULL((void *)0))
1829 out_of_mem();
1830 memcpy(nhp->h_name, hp->h_name, i);
1831 addrp = hp->h_addr_list;
1832 i = 1;
1833 while (*addrp++)
1834 i++;
1835 naddrp = nhp->h_addr_list = reallocarray(NULL((void *)0), i, sizeof(char *));
1836 if (naddrp == NULL((void *)0))
1837 out_of_mem();
1838 addrp = hp->h_addr_list;
1839 while (*addrp) {
1840 *naddrp = malloc(hp->h_length);
1841 if (*naddrp == NULL((void *)0))
1842 out_of_mem();
1843 memcpy(*naddrp, *addrp, hp->h_length);
1844 addrp++;
1845 naddrp++;
1846 }
1847 *naddrp = NULL((void *)0);
1848 if (debug)
1849 fprintf(stderr(&__sF[2]), "got host %s\n", hp->h_name);
1850 return (0);
1851}
1852
1853/*
1854 * Free up an exports list component
1855 */
1856void
1857free_exp(struct exportlist *ep)
1858{
1859
1860 if (ep->ex_defdir) {
1861 free_host(ep->ex_defdir->dp_hosts);
1862 free((caddr_t)ep->ex_defdir);
1863 }
1864 free(ep->ex_fsdir);
1865 free_dir(ep->ex_dirl);
1866 free((caddr_t)ep);
1867}
1868
1869/*
1870 * Free hosts.
1871 */
1872void
1873free_host(struct hostlist *hp)
1874{
1875 struct hostlist *hp2;
1876
1877 while (hp) {
1878 hp2 = hp;
1879 hp = hp->ht_next;
1880 free((caddr_t)hp2);
1881 }
1882}
1883
1884struct hostlist *
1885get_ht(void)
1886{
1887 struct hostlist *hp;
1888
1889 hp = malloc(sizeof (struct hostlist));
1890 if (hp == NULL((void *)0))
1891 out_of_mem();
1892 hp->ht_next = NULL((void *)0);
1893 hp->ht_flag = 0;
1894 return (hp);
1895}
1896
1897/*
1898 * Out of memory, fatal
1899 */
1900void
1901out_of_mem(void)
1902{
1903
1904 syslog(LOG_ERR3, "Out of memory");
1905 exit(2);
1906}
1907
1908/*
1909 * Do the mount syscall with the update flag to push the export info into
1910 * the kernel. Returns 0 on success, 1 for fatal error, and 2 for error
1911 * that only invalidates the specific entry/host.
1912 */
1913int
1914do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
1915 struct xucred *anoncrp, char *dirp, int dirplen)
1916{
1917 struct sockaddr_in sin, imask;
1918 struct export_args args;
1919 char savedc = '\0';
1920 u_int32_t **addrp;
1921 char *cp = NULL((void *)0);
1922 in_addr_t net;
1923 int done;
1924
1925 args.ex_flags = exflags;
1926 args.ex_anon = *anoncrp;
1927 memset(&sin, 0, sizeof(sin));
1928 memset(&imask, 0, sizeof(imask));
1929 sin.sin_family = AF_INET2;
1930 sin.sin_len = sizeof(sin);
1931 imask.sin_family = AF_INET2;
1932 imask.sin_len = sizeof(sin);
1933 if (grp->gr_type == GT_HOST0x1)
1934 addrp = (u_int32_t **)grp->gr_ptr.gt_hostent->h_addr_list;
1935 else
1936 addrp = NULL((void *)0);
1937
1938 done = FALSE(0);
1939 while (!done) {
1940 switch (grp->gr_type) {
1941 case GT_HOST0x1:
1942 args.ex_addr = (struct sockaddr *)&sin;
1943 args.ex_masklen = 0;
1944 if (!addrp) {
1945 args.ex_addrlen = 0;
1946 break;
1947 }
1948 sin.sin_addr.s_addr = **addrp;
1949 args.ex_addrlen = sizeof(sin);
1950 break;
1951 case GT_NET0x2:
1952 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1953 args.ex_addr = (struct sockaddr *)&sin;
1954 args.ex_addrlen = sizeof (sin);
1955 args.ex_mask = (struct sockaddr *)&imask;
1956 args.ex_masklen = sizeof (imask);
1957 if (grp->gr_ptr.gt_net.nt_mask) {
1958 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1959 break;
1960 }
1961 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))
;
1962 if (IN_CLASSA(net)(((u_int32_t)(net) & ((u_int32_t)(0x80000000))) == ((u_int32_t
)(0x00000000)))
)
1963 imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1964 else if (IN_CLASSB(net)(((u_int32_t)(net) & ((u_int32_t)(0xc0000000))) == ((u_int32_t
)(0x80000000)))
)
1965 imask.sin_addr.s_addr = inet_addr("255.255.0.0");
1966 else
1967 imask.sin_addr.s_addr = inet_addr("255.255.255.0");
1968 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1969 break;
1970 case GT_IGNORE0x5:
1971 return (0);
1972 default:
1973 syslog(LOG_ERR3, "Bad grouptype");
1974 if (cp)
1975 *cp = savedc;
1976 return (1);
1977 }
1978
1979 /*
1980 * XXX:
1981 * Maybe I should just use the fsb->f_mntonname path instead
1982 * of looping back up the dirp to the mount point??
1983 * Also, needs to know how to export all types of local
1984 * exportable file systems and not just MOUNT_FFS.
1985 */
1986 while (imsg_export(dirp, &args) == -1) {
1987 if (cp)
1988 *cp-- = savedc;
1989 else
1990 cp = dirp + dirplen - 1;
1991 if (errno(*__errno()) == EPERM1) {
1992 syslog(LOG_ERR3,
1993 "Can't change attributes for %s (%s).\n",
1994 dirp,
1995 (grp->gr_type == GT_HOST0x1)
1996 ?grp->gr_ptr.gt_hostent->h_name
1997 :(grp->gr_type == GT_NET0x2)
1998 ?grp->gr_ptr.gt_net.nt_name
1999 :"Unknown");
2000 return (2);
2001 }
2002 if (opt_flags & OP_ALLDIRS0x40) {
2003#if 0
2004 syslog(LOG_ERR3, "Could not remount %s: %m",
2005 dirp);
2006 return (2);
2007#endif
2008 }
2009 /* back up over the last component */
2010 while (cp > dirp && *cp == '/')
2011 cp--;
2012 while (cp > dirp && *(cp - 1) != '/')
2013 cp--;
2014 if (cp == dirp) {
2015 if (debug)
2016 fprintf(stderr(&__sF[2]), "mnt unsucc\n");
2017 syslog(LOG_ERR3, "Can't export %s: %m", dirp);
2018 return (2);
2019 }
2020 savedc = *cp;
2021 *cp = '\0';
2022 }
2023 if (addrp) {
2024 ++addrp;
2025 if (*addrp == NULL((void *)0))
2026 done = TRUE(1);
2027 } else
2028 done = TRUE(1);
2029 }
2030 if (cp)
2031 *cp = savedc;
2032 return (0);
2033}
2034
2035/*
2036 * Translate a net address.
2037 */
2038int
2039get_net(char *cp, struct netmsk *net, int maskflg)
2040{
2041 struct in_addr inetaddr, inetaddr2;
2042 in_addr_t netaddr;
2043 struct netent *np;
2044 char *name;
2045
2046 if ((netaddr = inet_network(cp)) != INADDR_NONE((u_int32_t)(0xffffffff))) {
2047 inetaddr = inet_makeaddr(netaddr, 0);
2048 /*
2049 * Due to arbitrary subnet masks, you don't know how many
2050 * bits to shift the address to make it into a network,
2051 * however you do know how to make a network address into
2052 * a host with host == 0 and then compare them.
2053 * (What a pest)
2054 */
2055 if (!maskflg) {
2056 setnetent(0);
2057 while ((np = getnetent())) {
2058 inetaddr2 = inet_makeaddr(np->n_net, 0);
2059 if (inetaddr2.s_addr == inetaddr.s_addr)
2060 break;
2061 }
2062 endnetent();
2063 }
2064 } else {
2065 if ((np = getnetbyname(cp)))
2066 inetaddr = inet_makeaddr(np->n_net, 0);
2067 else
2068 return (1);
2069 }
2070 if (maskflg)
2071 net->nt_mask = inetaddr.s_addr;
2072 else {
2073 int len;
2074
2075 if (np)
2076 name = np->n_name;
2077 else
2078 name = inet_ntoa(inetaddr);
2079 len = strlen(name) + 1;
2080 net->nt_name = malloc(len);
2081 if (net->nt_name == NULL((void *)0))
2082 out_of_mem();
2083 strlcpy(net->nt_name, name, len);
2084 net->nt_net = inetaddr.s_addr;
2085 }
2086 return (0);
2087}
2088
2089/*
2090 * Parse out the next white space separated field
2091 */
2092void
2093nextfield(char **cp, char **endcp)
2094{
2095 char *p;
2096
2097 p = *cp;
2098 while (*p == ' ' || *p == '\t')
2099 p++;
2100 if (*p == '\n' || *p == '\0')
2101 *cp = *endcp = p;
2102 else {
2103 *cp = p++;
2104 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
2105 p++;
2106 *endcp = p;
2107 }
2108}
2109
2110/*
2111 * Get an exports file line. Skip over blank lines and handle line
2112 * continuations.
2113 */
2114int
2115get_line(void)
2116{
2117 int totlen, cont_line, len;
2118 char *p, *cp;
2119
2120 /*
2121 * Loop around ignoring blank lines and getting all continuation lines.
2122 */
2123 p = line;
2124 totlen = 0;
2125 do {
2126 if (fgets(p, LINESIZ10240 - totlen, exp_file) == NULL((void *)0))
2127 return (0);
2128 len = strlen(p);
2129 cp = p + len - 1;
2130 cont_line = 0;
2131 while (cp >= p && (*cp == ' ' || *cp == '\t' || *cp == '\n' ||
2132 *cp == '\\')) {
2133 if (*cp == '\\')
2134 cont_line = 1;
2135 cp--;
2136 len--;
2137 }
2138 *++cp = '\0';
2139 if (len > 0) {
2140 totlen += len;
2141 if (totlen >= LINESIZ10240) {
2142 syslog(LOG_ERR3, "Exports line too long");
2143 exit(2);
2144 }
2145 p = cp;
2146 }
2147 } while (totlen == 0 || cont_line);
2148 return (1);
2149}
2150
2151/*
2152 * Parse a description of a credential.
2153 */
2154void
2155parsecred(char *namelist, struct xucred *cr)
2156{
2157 gid_t groups[NGROUPS_MAX16 + 1];
2158 char *name, *names;
2159 struct passwd *pw;
2160 struct group *gr;
2161 int ngroups, cnt;
2162
2163 /*
2164 * Set up the unprivileged user.
2165 */
2166 *cr = def_anon;
2167
2168 /*
2169 * Get the user's password table entry.
2170 */
2171 names = strsep(&namelist, " \t\n");
2172 name = strsep(&names, ":");
2173 if (isdigit((unsigned char)*name) || *name == '-')
2174 pw = getpwuid(atoi(name));
2175 else
2176 pw = getpwnam(name);
2177 /*
2178 * Credentials specified as those of a user.
2179 */
2180 if (names == NULL((void *)0)) {
2181 if (pw == NULL((void *)0)) {
2182 syslog(LOG_ERR3, "Unknown user: %s", name);
2183 return;
2184 }
2185 cr->cr_uid = pw->pw_uid;
2186 ngroups = NGROUPS_MAX16 + 1;
2187 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
2188 syslog(LOG_ERR3, "Too many groups for %s: %m", pw->pw_name);
2189 /*
2190 * compress out duplicate
2191 */
2192 cr->cr_ngroups = ngroups - 1;
2193 cr->cr_gid = groups[0];
2194 for (cnt = 1; cnt < ngroups; cnt++)
2195 cr->cr_groups[cnt - 1] = groups[cnt];
2196 return;
2197 }
2198 /*
2199 * Explicit credential specified as a colon separated list:
2200 * uid:gid:gid:...
2201 */
2202 if (pw != NULL((void *)0))
2203 cr->cr_uid = pw->pw_uid;
2204 else if (isdigit((unsigned char)*name) || *name == '-')
2205 cr->cr_uid = atoi(name);
2206 else {
2207 syslog(LOG_ERR3, "Unknown user: %s", name);
2208 return;
2209 }
2210 cr->cr_ngroups = 0;
2211 while (names != NULL((void *)0) && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX16) {
2212 name = strsep(&names, ":");
2213 if (isdigit((unsigned char)*name) || *name == '-') {
2214 cr->cr_groups[cr->cr_ngroups++] = atoi(name);
2215 } else {
2216 if ((gr = getgrnam(name)) == NULL((void *)0)) {
2217 syslog(LOG_ERR3, "Unknown group: %s", name);
2218 continue;
2219 }
2220 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
2221 }
2222 }
2223 if (names != NULL((void *)0) && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX16)
2224 syslog(LOG_ERR3, "Too many groups");
2225}
2226
2227#define STRSIZ(255 +1024 +50) (RPCMNT_NAMELEN255+RPCMNT_PATHLEN1024+50)
2228/*
2229 * Routines that maintain the remote mounttab
2230 */
2231void
2232get_mountlist(void)
2233{
2234 struct mountlist *mlp, **mlpp;
2235 char *host, *dirp, *cp;
2236 char str[STRSIZ(255 +1024 +50)];
2237 FILE *mlfile;
2238
2239 if ((mlfile = fopen(_PATH_RMOUNTLIST"/var/db/mountdtab", "r")) == NULL((void *)0)) {
2240 syslog(LOG_ERR3, "Can't open %s: %m", _PATH_RMOUNTLIST"/var/db/mountdtab");
2241 return;
2242 }
2243 mlpp = &mlhead;
2244 while (fgets(str, STRSIZ(255 +1024 +50), mlfile) != NULL((void *)0)) {
2245 cp = str;
2246 host = strsep(&cp, " \t\n");
2247 dirp = strsep(&cp, " \t\n");
2248 if (host == NULL((void *)0) || dirp == NULL((void *)0))
2249 continue;
2250 mlp = malloc(sizeof (*mlp));
2251 if (mlp == NULL((void *)0))
2252 out_of_mem();
2253 strlcpy(mlp->ml_host, host, sizeof(mlp->ml_host));
2254 strlcpy(mlp->ml_dirp, dirp, sizeof(mlp->ml_dirp));
2255 mlp->ml_next = NULL((void *)0);
2256 *mlpp = mlp;
2257 mlpp = &mlp->ml_next;
2258 }
2259 fclose(mlfile);
2260}
2261
2262void
2263del_mlist(char *hostp, char *dirp)
2264{
2265 struct mountlist *mlp, **mlpp;
2266 struct mountlist *mlp2;
2267 int fnd = 0;
2268
2269 mlpp = &mlhead;
2270 mlp = mlhead;
2271 while (mlp) {
2272 if (!strcmp(mlp->ml_host, hostp) &&
2273 (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
2274 fnd = 1;
2275 mlp2 = mlp;
2276 *mlpp = mlp = mlp->ml_next;
2277 free((caddr_t)mlp2);
2278 } else {
2279 mlpp = &mlp->ml_next;
2280 mlp = mlp->ml_next;
2281 }
2282 }
2283 if (fnd) {
2284 send_imsg(IMSG_MLIST_OPEN0x6, NULL((void *)0), 0);
2285 mlp = mlhead;
2286 while (mlp) {
2287 send_imsg(IMSG_MLIST_WRITE0x8, mlp, sizeof(*mlp));
2288 mlp = mlp->ml_next;
2289 }
2290 send_imsg(IMSG_MLIST_CLOSE0x7, NULL((void *)0), 0);
2291 }
2292}
2293
2294void
2295add_mlist(char *hostp, char *dirp)
2296{
2297 struct mountlist *mlp, **mlpp;
2298
2299 mlpp = &mlhead;
2300 mlp = mlhead;
2301 while (mlp) {
2302 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
2303 return;
2304 mlpp = &mlp->ml_next;
2305 mlp = mlp->ml_next;
2306 }
2307 mlp = malloc(sizeof (*mlp));
2308 if (mlp == NULL((void *)0))
2309 out_of_mem();
2310 strlcpy(mlp->ml_host, hostp, sizeof(mlp->ml_host));
2311 strlcpy(mlp->ml_dirp, dirp, sizeof(mlp->ml_dirp));
2312 mlp->ml_next = NULL((void *)0);
2313 *mlpp = mlp;
2314 send_imsg(IMSG_MLIST_APPEND0x5, mlp, sizeof(*mlp));
2315}
2316
2317/*
2318 * This function is called via SIGTERM when the system is going down.
2319 * It sends a broadcast RPCMNT_UMNTALL.
2320 */
2321void
2322send_umntall(int signo)
2323{
2324 gotterm = 1;
2325}
2326
2327int
2328umntall_each(caddr_t resultsp, struct sockaddr_in *raddr)
2329{
2330 return (1);
2331}
2332
2333/*
2334 * Free up a group list.
2335 */
2336void
2337free_grp(struct grouplist *grp)
2338{
2339 char **addrp;
2340
2341 if (grp->gr_type == GT_HOST0x1) {
2342 if (grp->gr_ptr.gt_hostent->h_name) {
2343 addrp = grp->gr_ptr.gt_hostent->h_addr_list;
2344 while (addrp && *addrp)
2345 free(*addrp++);
2346 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
2347 free(grp->gr_ptr.gt_hostent->h_name);
2348 }
2349 free((caddr_t)grp->gr_ptr.gt_hostent);
2350 } else if (grp->gr_type == GT_NET0x2) {
2351 free(grp->gr_ptr.gt_net.nt_name);
2352 }
2353 free((caddr_t)grp);
2354}
2355
2356/*
2357 * Check options for consistency.
2358 */
2359int
2360check_options(struct dirlist *dp)
2361{
2362
2363 if (dp == NULL((void *)0))
2364 return (1);
2365 if ((opt_flags & (OP_MAPROOT0x01 | OP_MAPALL0x02)) == (OP_MAPROOT0x01 | OP_MAPALL0x02)) {
2366 syslog(LOG_ERR3, "-mapall and -maproot mutually exclusive");
2367 return (1);
2368 }
2369 if ((opt_flags & OP_MASK0x08) && (opt_flags & OP_NET0x10) == 0) {
2370 syslog(LOG_ERR3, "-mask requires -network");
2371 return (1);
2372 }
2373 if ((opt_flags & OP_ALLDIRS0x40) && dp->dp_left) {
2374 syslog(LOG_ERR3, "-alldirs has multiple directories");
2375 return (1);
2376 }
2377 return (0);
2378}
2379
2380/*
2381 * Check an absolute directory path for any symbolic links. Return true
2382 * if no symbolic links are found.
2383 */
2384int
2385check_dirpath(char *dirp)
2386{
2387 struct stat sb;
2388 int ret = 1;
2389 char *cp;
2390
2391 /* Remove trailing '/' */
2392 cp = dirp + strlen(dirp) - 1;
2393 while (cp > dirp && *cp == '/')
2394 *cp-- = '\0';
2395
2396 cp = dirp + 1;
2397 while (*cp && ret) {
2398 if (*cp == '/') {
2399 *cp = '\0';
2400 if (lstat(dirp, &sb) == -1 || !S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000))
2401 ret = 0;
2402 *cp = '/';
2403 }
2404 cp++;
2405 }
2406 if (lstat(dirp, &sb) == -1 ||
2407 (!S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000) && !S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000)))
2408 ret = 0;
2409 return (ret);
2410}