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.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)) != NULL) 73 74 /* 75 * Structures for keeping the mount list and export list 76 */ 77 struct mountlist { 78 struct mountlist *ml_next; 79 char ml_host[RPCMNT_NAMELEN+1]; 80 char ml_dirp[RPCMNT_PATHLEN+1]; 81 }; 82 83 struct 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_DEFSET 0x1 92 #define DP_HOSTSET 0x2 93 94 struct 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_LINKED 0x1 104 105 struct netmsk { 106 in_addr_t nt_net; 107 in_addr_t nt_mask; 108 char *nt_name; 109 }; 110 111 union grouptypes { 112 struct hostent *gt_hostent; 113 struct netmsk gt_net; 114 }; 115 116 struct grouplist { 117 int gr_type; 118 union grouptypes gr_ptr; 119 struct grouplist *gr_next; 120 }; 121 /* Group types */ 122 #define GT_NULL 0x0 123 #define GT_HOST 0x1 124 #define GT_NET 0x2 125 #define GT_IGNORE 0x5 126 127 struct hostlist { 128 int ht_flag; /* Uses DP_xx bits */ 129 struct grouplist *ht_grp; 130 struct hostlist *ht_next; 131 }; 132 133 struct fhreturn { 134 int fhr_flag; 135 int fhr_vers; 136 nfsfh_t fhr_fh; 137 }; 138 139 #define IMSG_GETFH_REQ 0x0 140 #define IMSG_GETFH_RESP 0x1 141 #define IMSG_EXPORT_REQ 0x2 142 #define IMSG_EXPORT_RESP 0x3 143 #define IMSG_DELEXPORT 0x4 144 #define IMSG_MLIST_APPEND 0x5 145 #define IMSG_MLIST_OPEN 0x6 146 #define IMSG_MLIST_CLOSE 0x7 147 #define IMSG_MLIST_WRITE 0x8 148 149 struct getfh_resp { 150 fhandle_t gr_fh; 151 int gr_error; 152 }; 153 154 struct export_req { 155 char er_path[MNAMELEN]; 156 struct export_args er_args; 157 struct sockaddr er_addr; 158 struct sockaddr er_mask; 159 }; 160 161 /* Global defs */ 162 char *add_expdir(struct dirlist **, char *, int); 163 void add_dlist(struct dirlist **, struct dirlist *, struct grouplist *, int); 164 void add_mlist(char *, char *); 165 void check_child(int); 166 int check_dirpath(char *); 167 int check_options(struct dirlist *); 168 int chk_host(struct dirlist *, in_addr_t, int *, int *); 169 void del_mlist(char *, char *); 170 struct dirlist *dirp_search(struct dirlist *, char *); 171 int do_mount(struct exportlist *, struct grouplist *, int, struct xucred *, 172 char *, int); 173 int do_opt(char **, char **, struct exportlist *, struct grouplist *, 174 int *, int *, struct xucred *); 175 struct exportlist *ex_search(fsid_t *); 176 struct exportlist *get_exp(void); 177 void free_dir(struct dirlist *); 178 void free_exp(struct exportlist *); 179 void free_grp(struct grouplist *); 180 void free_host(struct hostlist *); 181 void new_exportlist(int signo); 182 void get_exportlist(void); 183 int get_host(char *, struct grouplist *, struct grouplist *); 184 int get_num(char *); 185 struct hostlist *get_ht(void); 186 int get_line(void); 187 void get_mountlist(void); 188 int get_net(char *, struct netmsk *, int); 189 void getexp_err(struct exportlist *, struct grouplist *); 190 struct grouplist *get_grp(void); 191 void hang_dirp(struct dirlist *, struct grouplist *, struct exportlist *, 192 int); 193 void mntsrv(struct svc_req *, SVCXPRT *); 194 void nextfield(char **, char **); 195 void out_of_mem(void); 196 void parsecred(char *, struct xucred *); 197 void privchild(int); 198 int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *); 199 ssize_t recv_imsg(struct imsg *); 200 int scan_tree(struct dirlist *, in_addr_t); 201 int send_imsg(u_int32_t, void *, u_int16_t); 202 void send_umntall(int signo); 203 int umntall_each(caddr_t, struct sockaddr_in *); 204 int xdr_dir(XDR *, char *); 205 int xdr_explist(XDR *, caddr_t); 206 int xdr_fhs(XDR *, caddr_t); 207 int xdr_mlist(XDR *, caddr_t); 208 void mountd_svc_run(void); 209 210 struct exportlist *exphead; 211 struct mountlist *mlhead; 212 struct grouplist *grphead; 213 const char *exname; 214 struct xucred def_anon = { 215 .cr_uid = (uid_t) -2, 216 .cr_gid = (gid_t) -2, 217 .cr_ngroups = 0, 218 .cr_groups = { 0, } 219 }; 220 int opt_flags; 221 /* Bits for above */ 222 #define OP_MAPROOT 0x01 223 #define OP_MAPALL 0x02 224 #define OP_MASK 0x08 225 #define OP_NET 0x10 226 #define OP_ALLDIRS 0x40 227 228 struct imsgbuf ibuf; 229 int debug = 0; 230 231 volatile sig_atomic_t gotchld; 232 volatile sig_atomic_t gothup; 233 volatile 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 */ 242 int 243 main(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, "usage: mountd [-d] [exportsfile]\n"); 260 exit(1); 261 } 262 argc -= optind; 263 argv += optind; 264 grphead = NULL; 265 exphead = NULL; 266 mlhead = NULL; 267 268 if (argc == 1) 269 exname = *argv; 270 else 271 exname = _PATH_EXPORTS; 272 273 openlog("mountd", LOG_PID, LOG_DAEMON); 274 if (debug) 275 fprintf(stderr, "Here we go.\n"); 276 if (debug == 0) { 277 daemon(0, 0); 278 signal(SIGINT, SIG_IGN); 279 signal(SIGQUIT, SIG_IGN); 280 } 281 /* Store pid in file unless mountd is already running */ 282 pidfile = fopen(_PATH_MOUNTDPID, "r"); 283 if (pidfile != NULL) { 284 if (fscanf(pidfile, "%d\n", &c) > 0 && c > 0) { 285 if (kill(c, 0) == 0) { 286 syslog(LOG_ERR, "Already running (pid %d)", c); 287 exit(1); 288 } 289 } 290 pidfile = freopen(_PATH_MOUNTDPID, "w", pidfile); 291 } else { 292 pidfile = fopen(_PATH_MOUNTDPID, "w"); 293 } 294 if (pidfile) { 295 fprintf(pidfile, "%ld\n", (long)getpid()); 296 fclose(pidfile); 297 } 298 299 signal(SIGCHLD, (void (*)(int)) check_child); 300 signal(SIGHUP, (void (*)(int)) new_exportlist); 301 signal(SIGPIPE, SIG_IGN); 302 303 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { 304 syslog(LOG_ERR, "socketpair: %m"); 305 exit(1); 306 } 307 308 switch (fork()) { 309 case -1: 310 syslog(LOG_ERR, "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) == -1) { 320 syslog(LOG_ERR, "pledge: %m"); 321 exit(1); 322 } 323 324 signal(SIGTERM, (void (*)(int)) send_umntall); 325 imsg_init(&ibuf, socks[0]); 326 setproctitle("parent"); 327 328 if (debug) 329 fprintf(stderr, "Getting export list.\n"); 330 get_exportlist(); 331 if (debug) 332 fprintf(stderr, "Getting mount list.\n"); 333 get_mountlist(); 334 335 if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL || 336 (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { 337 syslog(LOG_ERR, "Can't create socket"); 338 exit(1); 339 } 340 pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 341 pmap_unset(RPCPROG_MNT, RPCMNT_VER3); 342 if (!svc_register(udptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP) || 343 !svc_register(udptransp, RPCPROG_MNT, RPCMNT_VER3, mntsrv, IPPROTO_UDP) || 344 !svc_register(tcptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_TCP) || 345 !svc_register(tcptransp, RPCPROG_MNT, RPCMNT_VER3, mntsrv, IPPROTO_TCP)) { 346 syslog(LOG_ERR, "Can't register mount"); 347 exit(1); 348 } 349 mountd_svc_run(); 350 syslog(LOG_ERR, "Mountd died"); 351 exit(1); 352 } 353 354 void 355 check_child(int signo) 356 { 357 gotchld = 1; 358 } 359 360 void 361 privchild(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; 377 378 for (;;) { 379 if (gothup) { 380 kill(getppid(), SIGHUP); 381 gothup = 0; 382 } 383 384 pfd[0].fd = ibuf.fd; 385 pfd[0].events = POLLIN; 386 switch (poll(pfd, 1, INFTIM)) { 387 case -1: 388 if (errno == EINTR) 389 continue; 390 syslog(LOG_ERR, "poll: %m"); 391 _exit(1); 392 case 0: 393 continue; 394 } 395 if (pfd[0].revents & POLLHUP) { 396 syslog(LOG_ERR, "Socket disconnected"); 397 _exit(1); 398 } 399 if (!(pfd[0].revents & POLLIN)) 400 continue; 401 402 switch (imsg_read(&ibuf)) { 403 case -1: 404 syslog(LOG_ERR, "imsg_read: %m"); 405 _exit(1); 406 case 0: 407 syslog(LOG_ERR, "Socket disconnected"); 408 _exit(1); 409 } 410 411 while ((size = imsg_get(&ibuf, &imsg)) != 0) { 412 if (size == -1) { 413 syslog(LOG_ERR, "imsg_get: %m"); 414 _exit(1); 415 } 416 size -= IMSG_HEADER_SIZE; 417 418 switch (imsg.hdr.type) { 419 case IMSG_GETFH_REQ: 420 if (size != PATH_MAX) { 421 syslog(LOG_ERR, "Invalid message size"); 422 break; 423 } 424 path = imsg.data; 425 if (getfh(path, &resp.gr_fh) == -1) 426 resp.gr_error = errno; 427 else 428 resp.gr_error = 0; 429 send_imsg(IMSG_GETFH_RESP, &resp, sizeof(resp)); 430 break; 431 case IMSG_EXPORT_REQ: 432 if (size != sizeof(*req)) { 433 syslog(LOG_ERR, "Invalid message size"); 434 break; 435 } 436 req = imsg.data; 437 if (statfs(req->er_path, &sfb) == -1) { 438 error = errno; 439 syslog(LOG_ERR, "statfs: %m"); 440 send_imsg(IMSG_EXPORT_RESP, &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_UPDATE, &args) == -1) { 450 error = errno; 451 syslog(LOG_ERR, "mount: %m"); 452 send_imsg(IMSG_EXPORT_RESP, &error, 453 sizeof(error)); 454 break; 455 } 456 error = 0; 457 send_imsg(IMSG_EXPORT_RESP, &error, sizeof(error)); 458 break; 459 case IMSG_DELEXPORT: 460 if (size != MNAMELEN) { 461 syslog(LOG_ERR, "Invalid message size"); 462 break; 463 } 464 path = imsg.data; 465 if (statfs(path, &sfb) == -1) { 466 syslog(LOG_ERR, "statfs: %m"); 467 break; 468 } 469 memset(&args, 0, sizeof(args)); 470 args.export_info.ex_flags = MNT_DELEXPORT; 471 if (mount(sfb.f_fstypename, sfb.f_mntonname, 472 sfb.f_flags | MNT_UPDATE, &args) == -1) 473 syslog(LOG_ERR, "mount: %m"); 474 break; 475 case IMSG_MLIST_APPEND: 476 if (size != sizeof(*ml)) { 477 syslog(LOG_ERR, "Invalid message size"); 478 break; 479 } 480 if (fp != NULL) 481 break; 482 ml = imsg.data; 483 if (!isterminated(&ml->ml_host, 484 sizeof(ml->ml_host)) || 485 !isterminated(&ml->ml_dirp, 486 sizeof(ml->ml_dirp))) 487 break; 488 fp = fopen(_PATH_RMOUNTLIST, "a"); 489 if (fp == NULL) { 490 syslog(LOG_ERR, "fopen: %s: %m", 491 _PATH_RMOUNTLIST); 492 break; 493 } 494 fprintf(fp, "%s %s\n", ml->ml_host, 495 ml->ml_dirp); 496 fclose(fp); 497 fp = NULL; 498 break; 499 case IMSG_MLIST_OPEN: 500 if (size != 0) { 501 syslog(LOG_ERR, "Invalid message size"); 502 break; 503 } 504 if (fp != NULL) 505 break; 506 fp = fopen(_PATH_RMOUNTLIST, "w"); 507 if (fp == NULL) 508 syslog(LOG_ERR, "fopen: %s: %m", 509 _PATH_RMOUNTLIST); 510 break; 511 case IMSG_MLIST_WRITE: 512 if (size != sizeof(*ml)) { 513 syslog(LOG_ERR, "Invalid message size"); 514 break; 515 } 516 if (fp == NULL) 517 break; 518 ml = imsg.data; 519 if (!isterminated(&ml->ml_host, 520 sizeof(ml->ml_host)) || 521 !isterminated(&ml->ml_dirp, 522 sizeof(ml->ml_host))) 523 break; 524 fprintf(fp, "%s %s\n", ml->ml_host, 525 ml->ml_dirp); 526 break; 527 case IMSG_MLIST_CLOSE: 528 if (size != 0) { 529 syslog(LOG_ERR, "Invalid message size"); 530 break; 531 } 532 if (fp != NULL) { 533 fclose(fp); 534 fp = NULL; 535 } 536 break; 537 default: 538 syslog(LOG_ERR, "Unexpected message type"); 539 break; 540 } 541 542 imsg_free(&imsg); 543 } 544 } 545 } 546 547 int 548 imsg_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_REQ, path, PATH_MAX) == -1) 555 return (-1); 556 557 size = recv_imsg(&imsg); 558 if (size == -1) 559 return (-1); 560 if (imsg.hdr.type != IMSG_GETFH_RESP || size != sizeof(*resp)) { 561 syslog(LOG_ERR, "Invalid message"); 562 imsg_free(&imsg); 563 errno = EINVAL; 564 return (-1); 565 } 566 567 resp = imsg.data; 568 *fh = resp->gr_fh; 569 if (resp->gr_error) { 570 errno = resp->gr_error; 571 imsg_free(&imsg); 572 return (-1); 573 } 574 575 imsg_free(&imsg); 576 return (0); 577 } 578 579 int 580 imsg_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_ERR, "%s: mount dir too long", dir); 589 errno = EINVAL; 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_REQ, &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_RESP || size != sizeof(int)) { 606 syslog(LOG_ERR, "Invalid message"); 607 imsg_free(&imsg); 608 errno = EINVAL; 609 return (-1); 610 } 611 612 if (*(int *)imsg.data != 0) { 613 errno = *(int *)imsg.data; 614 imsg_free(&imsg); 615 return (-1); 616 } 617 618 imsg_free(&imsg); 619 return (0); 620 } 621 622 ssize_t 623 recv_imsg(struct imsg *imsg) 624 { 625 ssize_t n; 626 627 n = imsg_read(&ibuf); 628 if (n == -1) { 629 syslog(LOG_ERR, "imsg_read: %m"); 630 return (-1); 631 } 632 if (n == 0) { 633 syslog(LOG_ERR, "Socket disconnected"); 634 errno = EINVAL; 635 return (-1); 636 } 637 638 n = imsg_get(&ibuf, imsg); 639 if (n == -1) { 640 syslog(LOG_ERR, "imsg_get: %m"); 641 return (-1); 642 } 643 if (n == 0) { 644 syslog(LOG_ERR, "No messages ready"); 645 errno = EINVAL; 646 return (-1); 647 } 648 649 return (n - IMSG_HEADER_SIZE); 650 } 651 652 int 653 send_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_ERR, "imsg_compose: %m"); 657 return (-1); 658 } 659 660 if (imsg_flush(&ibuf) == -1) { 661 syslog(LOG_ERR, "imsg_flush: %m"); 662 return (-1); 663 } 664 665 return (0); 666 } 667 668 void 669 mountd_svc_run(void) 670 { 671 struct pollfd *pfd = NULL, *newp; 672 nfds_t saved_max_pollfd = 0; 673 int nready, status; 674 675 for (;;) { 676 if (gotchld) { 677 if (waitpid(WAIT_ANY, &status, WNOHANG) == -1) { 678 syslog(LOG_ERR, "waitpid: %m"); 679 break; 680 } 681 if (WIFEXITED(status)) { 682 syslog(LOG_ERR, "Child exited"); 683 break; 684 } 685 if (WIFSIGNALED(status)) { 686 syslog(LOG_ERR, "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); 710 switch (nready) { 711 case -1: 712 if (errno == EINTR) 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_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 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 */ 733 void 734 mntsrv(struct svc_req *rqstp, SVCXPRT *transp) 735 { 736 char rpcpath[RPCMNT_PATHLEN+1], dirpath[PATH_MAX]; 737 struct hostent *hp = NULL; 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, SIGHUP); 751 saddr = transp->xp_raddr.sin_addr.s_addr; 752 sport = ntohs(transp->xp_raddr.sin_port); 753 switch (rqstp->rq_proc) { 754 case NULLPROC: 755 if (!svc_sendreply(transp, xdr_void, NULL)) 756 syslog(LOG_ERR, "Can't send reply"); 757 return; 758 case RPCMNT_MOUNT: 759 if (debug) 760 fprintf(stderr, "Got mount request from %s\n", 761 inet_ntoa(transp->xp_raddr.sin_addr)); 762 if (sport >= IPPORT_RESERVED) { 763 syslog(LOG_NOTICE, 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)) { 770 svcerr_decode(transp); 771 return; 772 } 773 if (debug) 774 fprintf(stderr, "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) { 781 bad = errno; 782 if (debug) 783 fprintf(stderr, "realpath failed on %s\n", 784 rpcpath); 785 strlcpy(dirpath, rpcpath, sizeof(dirpath)); 786 } else if (stat(dirpath, &stb) == -1 || 787 (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) || 788 statfs(dirpath, &fsb) == -1) { 789 if (debug) 790 fprintf(stderr, "stat failed on %s\n", dirpath); 791 bad = ENOENT; /* We will send error reply later */ 792 } 793 794 /* Check in the exports list */ 795 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 796 ep = ex_search(&fsb.f_fsid); 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_ERR, "Can't send reply"); 807 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 808 return; 809 } 810 if (hostset & DP_HOSTSET) 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; 819 syslog(LOG_ERR, "Can't get fh for %s", dirpath); 820 if (!svc_sendreply(transp, xdr_long, 821 (caddr_t)&bad)) 822 syslog(LOG_ERR, "Can't send reply"); 823 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 824 return; 825 } 826 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) 827 syslog(LOG_ERR, "Can't send reply"); 828 if (hp == NULL) 829 hp = gethostbyaddr((caddr_t)&saddr, 830 sizeof(saddr), AF_INET); 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, 838 "Mount successful for %s by %s.\n", 839 dirpath, 840 inet_ntoa(transp->xp_raddr.sin_addr)); 841 } 842 } else 843 bad = EACCES; 844 845 if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 846 syslog(LOG_ERR, "Can't send reply"); 847 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 848 return; 849 case RPCMNT_DUMP: 850 if (!svc_sendreply(transp, xdr_mlist, NULL)) 851 syslog(LOG_ERR, "Can't send reply"); 852 return; 853 case RPCMNT_UMOUNT: 854 if (sport >= IPPORT_RESERVED) { 855 svcerr_weakauth(transp); 856 return; 857 } 858 if (!svc_getargs(transp, xdr_dir, dirpath)) { 859 svcerr_decode(transp); 860 return; 861 } 862 if (!svc_sendreply(transp, xdr_void, NULL)) 863 syslog(LOG_ERR, "Can't send reply"); 864 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 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_UMNTALL: 870 if (sport >= IPPORT_RESERVED) { 871 svcerr_weakauth(transp); 872 return; 873 } 874 if (!svc_sendreply(transp, xdr_void, NULL)) 875 syslog(LOG_ERR, "Can't send reply"); 876 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 877 if (hp) 878 del_mlist(hp->h_name, NULL); 879 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), NULL); 880 return; 881 case RPCMNT_EXPORT: 882 if (!svc_sendreply(transp, xdr_explist, NULL)) 883 syslog(LOG_ERR, "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 */ 894 int 895 xdr_dir(XDR *xdrsp, char *dirp) 896 { 897 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 898 } 899 900 /* 901 * Xdr routine to generate file handle reply 902 */ 903 int 904 xdr_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_V2FH)); 914 case 3: 915 len = NFSX_V3FH; 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_UNIX; 921 len = 1; 922 if (!xdr_long(xdrsp, &len)) 923 return (0); 924 return (xdr_long(xdrsp, &auth)); 925 } 926 return (0); 927 } 928 929 int 930 xdr_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_NAMELEN)) 942 return (0); 943 strp = &mlp->ml_dirp[0]; 944 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 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 */ 956 int 957 xdr_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, SIGHUP); 965 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 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, &putdef)) 973 goto errout; 974 ep = ep->ex_next; 975 } 976 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 977 if (!xdr_bool(xdrsp, &false)) 978 return (0); 979 return (1); 980 errout: 981 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 982 return (0); 983 } 984 985 /* 986 * Called from xdr_explist() to traverse the tree and export the 987 * directory paths. 988 */ 989 int 990 put_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_PATHLEN)) 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_DEFSET) == 0 && 1011 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 1012 hp = dp->dp_hosts; 1013 while (hp) { 1014 grp = hp->ht_grp; 1015 if (grp->gr_type == GT_HOST) { 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_NAMELEN)) 1021 return (1); 1022 } else if (grp->gr_type == GT_NET) { 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_NAMELEN)) 1028 return (1); 1029 } 1030 hp = hp->ht_next; 1031 if (gotalldir && hp == NULL) { 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 LINESIZ 10240 1046 char line[LINESIZ]; 1047 FILE *exp_file; 1048 1049 void 1050 new_exportlist(int signo) 1051 { 1052 gothup = 1; 1053 1054 } 1055 1056 /* 1057 * Get the export list 1058 */ 1059 void 1060 get_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, *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; 1087 1088 grp = grphead; 1089 while (grp) { 1090 tgrp = grp; 1091 grp = grp->gr_next; 1092 free_grp(tgrp); 1093 } 1094 grphead = NULL; 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_NOWAIT); 1103 if (num == 0 && errno) 1104 syslog(LOG_ERR, "getmntinfo: %s", strerror(errno)); 1105 1106 fsp = ofsp; 1107 1108 fstbl = calloc(num, sizeof (fstbl[0])); 1109 if (fstbl == NULL) 1110 out_of_mem(); 1111 1112 for (i = 0; i < num; i++) { 1113 1114 if (!strncmp(fsp->f_fstypename, MOUNT_MFS, MFSNAMELEN) || 1115 !strncmp(fsp->f_fstypename, MOUNT_FFS, MFSNAMELEN) || 1116 !strncmp(fsp->f_fstypename, MOUNT_EXT2FS, MFSNAMELEN) || 1117 !strncmp(fsp->f_fstypename, MOUNT_MSDOS, MFSNAMELEN) || 1118 !strncmp(fsp->f_fstypename, MOUNT_CD9660, MFSNAMELEN)) { 1119 fstbl[i].exflags = MNT_DELEXPORT; 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) { 1131 syslog(LOG_ERR, "Can't open %s", exname); 1132 exit(2); 1133 } 1134 dirhead = NULL; 1135 while (get_line()) { 1136 if (debug) 1137 fprintf(stderr, "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; 1147 num_hosts = 0; 1148 lookup_failed = FALSE; 1149 anon = def_anon; 1150 exflags = MNT_EXPORTED; 1151 got_nondir = 0; 1152 opt_flags = 0; 1153 ep = NULL; 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_NAMELEN) { 1162 getexp_err(ep, tgrp); 1163 goto nextline; 1164 } 1165 if (*cp == '-') { 1166 if (ep == NULL) { 1167 getexp_err(ep, tgrp); 1168 goto nextline; 1169 } 1170 if (debug) 1171 fprintf(stderr, "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_ERR, "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) { 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, 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, 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) { 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) { 1258 syslog(LOG_ERR, 1259 "NULL hostname in netgroup %s, skipping", 1260 cp); 1261 grp->gr_type = GT_IGNORE; 1262 lookup_failed = TRUE; 1263 continue; 1264 } else if (get_host(hst, grp, tgrp)) { 1265 syslog(LOG_ERR, 1266 "Unknown host (%s) in netgroup %s", 1267 hst, cp); 1268 grp->gr_type = GT_IGNORE; 1269 lookup_failed = TRUE; 1270 continue; 1271 } 1272 } else if (get_host(cp, grp, tgrp)) { 1273 syslog(LOG_ERR, 1274 "Unknown host (%s) in line %s", 1275 cp, line); 1276 grp->gr_type = GT_IGNORE; 1277 lookup_failed = TRUE; 1278 continue; 1279 } 1280 has_host = TRUE; 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 && num_hosts == 0 && 1296 tgrp->gr_type == GT_IGNORE) { 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_HOST; 1306 if (debug) 1307 fprintf(stderr, "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) 1311 out_of_mem(); 1312 hpe->h_name = strdup("Default"); 1313 if (hpe->h_name == NULL) 1314 out_of_mem(); 1315 hpe->h_addrtype = AF_INET; 1316 hpe->h_length = sizeof (u_int32_t); 1317 hpe->h_addr_list = NULL; 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_NET) && 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) && 1345 (strcmp(fsb.f_mntonname, 1346 fstbl[i].mntonname) == 0) && 1347 (fstbl[i].exflags & MNT_DELEXPORT)) { 1348 exflags |= MNT_DELEXPORT; 1349 fstbl[i].exflags = 0; 1350 if (debug) 1351 fprintf(stderr, "removing %s %s from unexport list\n", dirp, fstbl[i].mntonname); 1352 } 1353 } 1354 1355 if (debug) 1356 fprintf(stderr, "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_DELEXPORT; 1363 if (i == 1) { 1364 getexp_err(ep, tgrp); 1365 goto nextline; 1366 } else if (i == 2) { 1367 syslog(LOG_ERR, 1368 "Bad exports list entry (%s) in line %s", 1369 (grp->gr_type == GT_HOST) 1370 ? grp->gr_ptr.gt_hostent->h_name 1371 : (grp->gr_type == GT_NET) 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, ep, 1386 opt_flags); 1387 free_grp(grp); 1388 } 1389 dirhead = NULL; 1390 if ((ep->ex_flag & EX_LINKED) == 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_LINKED; 1405 } 1406 nextline: 1407 if (dirhead) { 1408 free_dir(dirhead); 1409 dirhead = NULL; 1410 } 1411 } 1412 1413 fsp = ofsp; 1414 for (i = 0; i < num; i++, fsp++) { 1415 if ((fstbl[i].exflags & MNT_DELEXPORT) == 0) 1416 continue; 1417 if (debug) 1418 fprintf(stderr, "unexporting %s %s\n", 1419 fsp->f_mntonname, fstbl[i].mntonname); 1420 send_imsg(IMSG_DELEXPORT, 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 */ 1430 struct exportlist * 1431 get_exp(void) 1432 { 1433 struct exportlist *ep; 1434 1435 ep = calloc(1, sizeof (struct exportlist)); 1436 if (ep == NULL) 1437 out_of_mem(); 1438 return (ep); 1439 } 1440 1441 /* 1442 * Allocate a group list element 1443 */ 1444 struct grouplist * 1445 get_grp(void) 1446 { 1447 struct grouplist *gp; 1448 1449 gp = calloc(1, sizeof (struct grouplist)); 1450 if (gp == NULL) 1451 out_of_mem(); 1452 return (gp); 1453 } 1454 1455 /* 1456 * Clean up upon an error in get_exportlist(). 1457 */ 1458 void 1459 getexp_err(struct exportlist *ep, struct grouplist *grp) 1460 { 1461 struct grouplist *tgrp; 1462 1463 syslog(LOG_ERR, "Bad exports list line %s", line); 1464 if (ep && (ep->ex_flag & EX_LINKED) == 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 */ 1476 struct exportlist * 1477 ex_search(fsid_t *fsid) 1478 { 1479 struct exportlist *ep; 1480 1481 ep = exphead; 1482 while (ep) { 1483 if (ep->ex_fs.val[0] == fsid->val[0] && 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 */ 1494 char * 1495 add_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) 1502 out_of_mem(); 1503 dp->dp_left = *dpp; 1504 dp->dp_right = NULL; 1505 dp->dp_flag = 0; 1506 dp->dp_hosts = NULL; 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 */ 1516 void 1517 hang_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_ALLDIRS) { 1524 if (ep->ex_defdir) 1525 free((caddr_t)dp); 1526 else 1527 ep->ex_defdir = dp; 1528 if (grp == NULL) { 1529 ep->ex_defdir->dp_flag |= DP_DEFSET; 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 */ 1554 void 1555 add_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; 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_DEFSET; 1592 } 1593 } 1594 1595 /* 1596 * Search for a dirpath on the export point. 1597 */ 1598 struct dirlist * 1599 dirp_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 */ 1618 int 1619 chk_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_DEFSET) 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_HOST: 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_HOSTSET); 1638 return (1); 1639 } 1640 addrp++; 1641 } 1642 break; 1643 case GT_NET: 1644 if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 1645 grp->gr_ptr.gt_net.nt_net) { 1646 *hostsetp = (hp->ht_flag | DP_HOSTSET); 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 */ 1660 int 1661 scan_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 */ 1679 void 1680 free_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 */ 1696 int 1697 do_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_EXRDONLY; 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_EXPORTANON; 1740 opt_flags |= OP_MAPALL; 1741 } else 1742 opt_flags |= OP_MAPROOT; 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_ERR, "Bad mask: %s", cpoptarg); 1748 return (1); 1749 } 1750 usedarg++; 1751 opt_flags |= OP_MASK; 1752 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1753 !strcmp(cpopt, "n"))) { 1754 if (grp->gr_type != GT_NULL) { 1755 syslog(LOG_ERR, "Network/host conflict"); 1756 return (1); 1757 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1758 syslog(LOG_ERR, "Bad net: %s", cpoptarg); 1759 return (1); 1760 } 1761 grp->gr_type = GT_NET; 1762 *has_hostp = 1; 1763 usedarg++; 1764 opt_flags |= OP_NET; 1765 } else if (!strcmp(cpopt, "alldirs")) { 1766 opt_flags |= OP_ALLDIRS; 1767 } else { 1768 syslog(LOG_ERR, "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 */ 1790 int 1791 get_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_NULL) 1801 return (1); 1802 if ((hp = gethostbyname(cp)) == NULL) { 1803 if (isdigit((unsigned char)*cp)) { 1804 if (inet_aton(cp, &saddr) == 0) { 1805 syslog(LOG_ERR, "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_INET)) == NULL) { 1810 hp = &t_host; 1811 hp->h_name = cp; 1812 hp->h_addrtype = AF_INET; 1813 hp->h_length = sizeof (u_int32_t); 1814 hp->h_addr_list = aptr; 1815 aptr[0] = (char *)&saddr; 1816 aptr[1] = NULL; 1817 } 1818 } else { 1819 syslog(LOG_ERR, "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_HOST && 1828 checkgrp->gr_ptr.gt_hostent != NULL && 1829 !strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)) { 1830 grp->gr_type = GT_IGNORE; 1831 return (0); 1832 } 1833 } 1834 1835 grp->gr_type = GT_HOST; 1836 nhp = grp->gr_ptr.gt_hostent = malloc(sizeof(struct hostent)); 1837 if (nhp == NULL) 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) 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, i, sizeof(char *)); 1850 if (naddrp == NULL) 1851 out_of_mem(); 1852 addrp = hp->h_addr_list; 1853 while (*addrp) { 1854 *naddrp = malloc(hp->h_length); 1855 if (*naddrp == NULL) 1856 out_of_mem(); 1857 memcpy(*naddrp, *addrp, hp->h_length); 1858 addrp++; 1859 naddrp++; 1860 } 1861 *naddrp = NULL; 1862 if (debug) 1863 fprintf(stderr, "got host %s\n", hp->h_name); 1864 return (0); 1865 } 1866 1867 /* 1868 * Free up an exports list component 1869 */ 1870 void 1871 free_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 */ 1886 void 1887 free_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 1898 struct hostlist * 1899 get_ht(void) 1900 { 1901 struct hostlist *hp; 1902 1903 hp = malloc(sizeof (struct hostlist)); 1904 if (hp == NULL) 1905 out_of_mem(); 1906 hp->ht_next = NULL; 1907 hp->ht_flag = 0; 1908 return (hp); 1909 } 1910 1911 /* 1912 * Out of memory, fatal 1913 */ 1914 void 1915 out_of_mem(void) 1916 { 1917 1918 syslog(LOG_ERR, "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 */ 1927 int 1928 do_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; 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_INET; 1944 sin.sin_len = sizeof(sin); 1945 imask.sin_family = AF_INET; 1946 imask.sin_len = sizeof(sin); 1947 if (grp->gr_type == GT_HOST) 1948 addrp = (u_int32_t **)grp->gr_ptr.gt_hostent->h_addr_list; 1949 else 1950 addrp = NULL; 1951 1952 done = FALSE; 1953 while (!done) { 1954 switch (grp->gr_type) { 1955 case GT_HOST: 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_NET: 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); 1976 if (IN_CLASSA(net)) 1977 imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 1978 else if (IN_CLASSB(net)) 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_IGNORE: 1985 return (0); 1986 default: 1987 syslog(LOG_ERR, "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 == EPERM) { 2006 syslog(LOG_ERR, 2007 "Can't change attributes for %s (%s).\n", 2008 dirp, 2009 (grp->gr_type == GT_HOST) 2010 ?grp->gr_ptr.gt_hostent->h_name 2011 :(grp->gr_type == GT_NET) 2012 ?grp->gr_ptr.gt_net.nt_name 2013 :"Unknown"); 2014 return (2); 2015 } 2016 if (opt_flags & OP_ALLDIRS) { 2017 #if 0 2018 syslog(LOG_ERR, "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, "mnt unsucc\n"); 2031 syslog(LOG_ERR, "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) 2040 done = TRUE; 2041 } else 2042 done = TRUE; 2043 } 2044 if (cp) 2045 *cp = savedc; 2046 return (0); 2047 } 2048 2049 /* 2050 * Translate a net address. 2051 */ 2052 int 2053 get_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) { 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) 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 */ 2106 void 2107 nextfield(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 */ 2128 int 2129 get_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, LINESIZ - totlen, exp_file) == NULL) 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 >= LINESIZ) { 2156 syslog(LOG_ERR, "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 */ 2168 void 2169 parsecred(char *namelist, struct xucred *cr) 2170 { 2171 gid_t groups[NGROUPS_MAX + 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) { 2195 if (pw == NULL) { 2196 syslog(LOG_ERR, "Unknown user: %s", name); 2197 return; 2198 } 2199 cr->cr_uid = pw->pw_uid; 2200 ngroups = NGROUPS_MAX + 1; 2201 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 2202 syslog(LOG_ERR, "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) 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_ERR, "Unknown user: %s", name); 2222 return; 2223 } 2224 cr->cr_ngroups = 0; 2225 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX) { 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) { 2231 syslog(LOG_ERR, "Unknown group: %s", name); 2232 continue; 2233 } 2234 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 2235 } 2236 } 2237 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX) 2238 syslog(LOG_ERR, "Too many groups"); 2239 } 2240 2241 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 2242 /* 2243 * Routines that maintain the remote mounttab 2244 */ 2245 void 2246 get_mountlist(void) 2247 { 2248 struct mountlist *mlp, **mlpp; 2249 char *host, *dirp, *cp; 2250 char str[STRSIZ]; 2251 FILE *mlfile; 2252 2253 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 2254 syslog(LOG_ERR, "Can't open %s: %m", _PATH_RMOUNTLIST); 2255 return; 2256 } 2257 mlpp = &mlhead; 2258 while (fgets(str, STRSIZ, mlfile) != NULL) { 2259 cp = str; 2260 host = strsep(&cp, " \t\n"); 2261 dirp = strsep(&cp, " \t\n"); 2262 if (host == NULL || dirp == NULL) 2263 continue; 2264 mlp = malloc(sizeof (*mlp)); 2265 if (mlp == NULL) 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; 2270 *mlpp = mlp; 2271 mlpp = &mlp->ml_next; 2272 } 2273 fclose(mlfile); 2274 } 2275 2276 void 2277 del_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_OPEN, NULL, 0); 2299 mlp = mlhead; 2300 while (mlp) { 2301 send_imsg(IMSG_MLIST_WRITE, mlp, sizeof(*mlp)); 2302 mlp = mlp->ml_next; 2303 } 2304 send_imsg(IMSG_MLIST_CLOSE, NULL, 0); 2305 } 2306 } 2307 2308 void 2309 add_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) 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; 2327 *mlpp = mlp; 2328 send_imsg(IMSG_MLIST_APPEND, 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 */ 2335 void 2336 send_umntall(int signo) 2337 { 2338 gotterm = 1; 2339 } 2340 2341 int 2342 umntall_each(caddr_t resultsp, struct sockaddr_in *raddr) 2343 { 2344 return (1); 2345 } 2346 2347 /* 2348 * Free up a group list. 2349 */ 2350 void 2351 free_grp(struct grouplist *grp) 2352 { 2353 char **addrp; 2354 2355 if (grp->gr_type == GT_HOST) { 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_NET) { 2365 free(grp->gr_ptr.gt_net.nt_name); 2366 } 2367 free((caddr_t)grp); 2368 } 2369 2370 /* 2371 * Check options for consistency. 2372 */ 2373 int 2374 check_options(struct dirlist *dp) 2375 { 2376 2377 if (dp == NULL) 2378 return (1); 2379 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 2380 syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 2381 return (1); 2382 } 2383 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2384 syslog(LOG_ERR, "-mask requires -network"); 2385 return (1); 2386 } 2387 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2388 syslog(LOG_ERR, "-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 */ 2398 int 2399 check_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)) 2415 ret = 0; 2416 *cp = '/'; 2417 } 2418 cp++; 2419 } 2420 if (lstat(dirp, &sb) == -1 || 2421 (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode))) 2422 ret = 0; 2423 return (ret); 2424 } 2425