1 /* $OpenBSD: mountd.c,v 1.97 2025/01/16 12:48:45 kn 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 struct hostlist *get_ht(void); 185 int get_line(void); 186 void get_mountlist(void); 187 int get_net(char *, struct netmsk *, int); 188 void getexp_err(struct exportlist *, struct grouplist *); 189 struct grouplist *get_grp(void); 190 void hang_dirp(struct dirlist *, struct grouplist *, struct exportlist *, 191 int); 192 void mntsrv(struct svc_req *, SVCXPRT *); 193 void nextfield(char **, char **); 194 void out_of_mem(void); 195 void parsecred(char *, struct xucred *); 196 void privchild(int); 197 int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *); 198 ssize_t recv_imsg(struct imsg *); 199 int scan_tree(struct dirlist *, in_addr_t); 200 int send_imsg(u_int32_t, void *, u_int16_t); 201 void send_umntall(int signo); 202 int umntall_each(caddr_t, struct sockaddr_in *); 203 int xdr_dir(XDR *, char *); 204 int xdr_explist(XDR *, caddr_t); 205 int xdr_fhs(XDR *, caddr_t); 206 int xdr_mlist(XDR *, caddr_t); 207 void mountd_svc_run(void); 208 209 struct exportlist *exphead; 210 struct mountlist *mlhead; 211 struct grouplist *grphead; 212 const char *exname; 213 struct xucred def_anon = { 214 .cr_uid = (uid_t) -2, 215 .cr_gid = (gid_t) -2, 216 .cr_ngroups = 0, 217 .cr_groups = { 0, } 218 }; 219 int opt_flags; 220 /* Bits for above */ 221 #define OP_MAPROOT 0x01 222 #define OP_MAPALL 0x02 223 #define OP_MASK 0x08 224 #define OP_NET 0x10 225 #define OP_ALLDIRS 0x40 226 227 struct imsgbuf ibuf; 228 int debug = 0; 229 230 volatile sig_atomic_t gotchld; 231 volatile sig_atomic_t gothup; 232 volatile sig_atomic_t gotterm; 233 234 /* 235 * Mountd server for NFS mount protocol as described in: 236 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 237 * The optional arguments are the exports file name 238 * default: _PATH_EXPORTS 239 * "-d" to enable debugging 240 */ 241 int 242 main(int argc, char *argv[]) 243 { 244 SVCXPRT *udptransp, *tcptransp; 245 FILE *pidfile; 246 int c, socks[2]; 247 248 while ((c = getopt(argc, argv, "dnr")) != -1) 249 switch (c) { 250 case 'd': 251 debug = 1; 252 break; 253 case 'n': 254 case 'r': 255 /* Compatibility */ 256 break; 257 default: 258 fprintf(stderr, "usage: mountd [-d] [exportsfile]\n"); 259 exit(1); 260 } 261 argc -= optind; 262 argv += optind; 263 grphead = NULL; 264 exphead = NULL; 265 mlhead = NULL; 266 267 if (argc == 1) 268 exname = *argv; 269 else 270 exname = _PATH_EXPORTS; 271 272 openlog("mountd", LOG_PID, LOG_DAEMON); 273 if (debug) 274 fprintf(stderr, "Here we go.\n"); 275 if (debug == 0) { 276 daemon(0, 0); 277 signal(SIGINT, SIG_IGN); 278 signal(SIGQUIT, SIG_IGN); 279 } 280 /* Store pid in file unless mountd is already running */ 281 pidfile = fopen(_PATH_MOUNTDPID, "r"); 282 if (pidfile != NULL) { 283 if (fscanf(pidfile, "%d\n", &c) > 0 && c > 0) { 284 if (kill(c, 0) == 0) { 285 syslog(LOG_ERR, "Already running (pid %d)", c); 286 exit(1); 287 } 288 } 289 pidfile = freopen(_PATH_MOUNTDPID, "w", pidfile); 290 } else { 291 pidfile = fopen(_PATH_MOUNTDPID, "w"); 292 } 293 if (pidfile) { 294 fprintf(pidfile, "%ld\n", (long)getpid()); 295 fclose(pidfile); 296 } 297 298 signal(SIGCHLD, (void (*)(int)) check_child); 299 signal(SIGHUP, (void (*)(int)) new_exportlist); 300 signal(SIGPIPE, SIG_IGN); 301 302 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { 303 syslog(LOG_ERR, "socketpair: %m"); 304 exit(1); 305 } 306 307 switch (fork()) { 308 case -1: 309 syslog(LOG_ERR, "fork: %m"); 310 exit(1); 311 case 0: 312 close(socks[0]); 313 privchild(socks[1]); 314 } 315 316 close(socks[1]); 317 318 if (pledge("stdio rpath inet dns getpw", NULL) == -1) { 319 syslog(LOG_ERR, "pledge: %m"); 320 exit(1); 321 } 322 323 signal(SIGTERM, (void (*)(int)) send_umntall); 324 if (imsgbuf_init(&ibuf, socks[0]) == -1) { 325 syslog(LOG_ERR, "imsgbuf_init: %m"); 326 exit(1); 327 } 328 setproctitle("parent"); 329 330 if (debug) 331 fprintf(stderr, "Getting export list.\n"); 332 get_exportlist(); 333 if (debug) 334 fprintf(stderr, "Getting mount list.\n"); 335 get_mountlist(); 336 337 if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL || 338 (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { 339 syslog(LOG_ERR, "Can't create socket"); 340 exit(1); 341 } 342 pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 343 pmap_unset(RPCPROG_MNT, RPCMNT_VER3); 344 if (!svc_register(udptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP) || 345 !svc_register(udptransp, RPCPROG_MNT, RPCMNT_VER3, mntsrv, IPPROTO_UDP) || 346 !svc_register(tcptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_TCP) || 347 !svc_register(tcptransp, RPCPROG_MNT, RPCMNT_VER3, mntsrv, IPPROTO_TCP)) { 348 syslog(LOG_ERR, "Can't register mount"); 349 exit(1); 350 } 351 mountd_svc_run(); 352 syslog(LOG_ERR, "Mountd died"); 353 exit(1); 354 } 355 356 void 357 check_child(int signo) 358 { 359 gotchld = 1; 360 } 361 362 void 363 privchild(int sock) 364 { 365 struct imsg imsg; 366 struct pollfd pfd[1]; 367 struct ufs_args args; 368 struct statfs sfb; 369 struct getfh_resp resp; 370 struct export_req *req; 371 struct mountlist *ml; 372 FILE *fp; 373 char *path; 374 int error, size; 375 376 if (unveil("/", "r") == -1) { 377 syslog(LOG_ERR, "unveil /: %m"); 378 _exit(1); 379 } 380 if (unveil(_PATH_RMOUNTLIST, "rwc") == -1) { 381 syslog(LOG_ERR, "unveil %s: %m", _PATH_RMOUNTLIST); 382 _exit(1); 383 } 384 if (unveil(NULL, NULL) == -1) { 385 syslog(LOG_ERR, "unveil: %m"); 386 _exit(1); 387 } 388 389 if (imsgbuf_init(&ibuf, sock) == -1) { 390 syslog(LOG_ERR, "imsgbuf_init: %m"); 391 _exit(1); 392 } 393 setproctitle("[priv]"); 394 fp = NULL; 395 396 for (;;) { 397 if (gothup) { 398 kill(getppid(), SIGHUP); 399 gothup = 0; 400 } 401 402 pfd[0].fd = ibuf.fd; 403 pfd[0].events = POLLIN; 404 switch (poll(pfd, 1, INFTIM)) { 405 case -1: 406 if (errno == EINTR) 407 continue; 408 syslog(LOG_ERR, "poll: %m"); 409 _exit(1); 410 case 0: 411 continue; 412 } 413 if (pfd[0].revents & POLLHUP) { 414 syslog(LOG_ERR, "Socket disconnected"); 415 _exit(1); 416 } 417 if (!(pfd[0].revents & POLLIN)) 418 continue; 419 420 switch (imsgbuf_read(&ibuf)) { 421 case -1: 422 syslog(LOG_ERR, "imsgbuf_read: %m"); 423 _exit(1); 424 case 0: 425 syslog(LOG_ERR, "Socket disconnected"); 426 _exit(1); 427 } 428 429 while ((size = imsg_get(&ibuf, &imsg)) != 0) { 430 if (size == -1) { 431 syslog(LOG_ERR, "imsg_get: %m"); 432 _exit(1); 433 } 434 size -= IMSG_HEADER_SIZE; 435 436 switch (imsg.hdr.type) { 437 case IMSG_GETFH_REQ: 438 if (size != PATH_MAX) { 439 syslog(LOG_ERR, "Invalid message size"); 440 break; 441 } 442 path = imsg.data; 443 if (getfh(path, &resp.gr_fh) == -1) 444 resp.gr_error = errno; 445 else 446 resp.gr_error = 0; 447 send_imsg(IMSG_GETFH_RESP, &resp, sizeof(resp)); 448 break; 449 case IMSG_EXPORT_REQ: 450 if (size != sizeof(*req)) { 451 syslog(LOG_ERR, "Invalid message size"); 452 break; 453 } 454 req = imsg.data; 455 if (statfs(req->er_path, &sfb) == -1) { 456 error = errno; 457 syslog(LOG_ERR, "statfs: %m"); 458 send_imsg(IMSG_EXPORT_RESP, &error, 459 sizeof(error)); 460 break; 461 } 462 args.fspec = 0; 463 args.export_info = req->er_args; 464 args.export_info.ex_addr = &req->er_addr; 465 args.export_info.ex_mask = &req->er_mask; 466 if (mount(sfb.f_fstypename, sfb.f_mntonname, 467 sfb.f_flags | MNT_UPDATE, &args) == -1) { 468 error = errno; 469 syslog(LOG_ERR, "mount: %m"); 470 send_imsg(IMSG_EXPORT_RESP, &error, 471 sizeof(error)); 472 break; 473 } 474 error = 0; 475 send_imsg(IMSG_EXPORT_RESP, &error, sizeof(error)); 476 break; 477 case IMSG_DELEXPORT: 478 if (size != MNAMELEN) { 479 syslog(LOG_ERR, "Invalid message size"); 480 break; 481 } 482 path = imsg.data; 483 if (statfs(path, &sfb) == -1) { 484 syslog(LOG_ERR, "statfs: %m"); 485 break; 486 } 487 memset(&args, 0, sizeof(args)); 488 args.export_info.ex_flags = MNT_DELEXPORT; 489 if (mount(sfb.f_fstypename, sfb.f_mntonname, 490 sfb.f_flags | MNT_UPDATE, &args) == -1) 491 syslog(LOG_ERR, "mount: %m"); 492 break; 493 case IMSG_MLIST_APPEND: 494 if (size != sizeof(*ml)) { 495 syslog(LOG_ERR, "Invalid message size"); 496 break; 497 } 498 if (fp != NULL) 499 break; 500 ml = imsg.data; 501 if (!isterminated(&ml->ml_host, 502 sizeof(ml->ml_host)) || 503 !isterminated(&ml->ml_dirp, 504 sizeof(ml->ml_dirp))) 505 break; 506 fp = fopen(_PATH_RMOUNTLIST, "a"); 507 if (fp == NULL) { 508 syslog(LOG_ERR, "fopen: %s: %m", 509 _PATH_RMOUNTLIST); 510 break; 511 } 512 fprintf(fp, "%s %s\n", ml->ml_host, 513 ml->ml_dirp); 514 fclose(fp); 515 fp = NULL; 516 break; 517 case IMSG_MLIST_OPEN: 518 if (size != 0) { 519 syslog(LOG_ERR, "Invalid message size"); 520 break; 521 } 522 if (fp != NULL) 523 break; 524 fp = fopen(_PATH_RMOUNTLIST, "w"); 525 if (fp == NULL) 526 syslog(LOG_ERR, "fopen: %s: %m", 527 _PATH_RMOUNTLIST); 528 break; 529 case IMSG_MLIST_WRITE: 530 if (size != sizeof(*ml)) { 531 syslog(LOG_ERR, "Invalid message size"); 532 break; 533 } 534 if (fp == NULL) 535 break; 536 ml = imsg.data; 537 if (!isterminated(&ml->ml_host, 538 sizeof(ml->ml_host)) || 539 !isterminated(&ml->ml_dirp, 540 sizeof(ml->ml_host))) 541 break; 542 fprintf(fp, "%s %s\n", ml->ml_host, 543 ml->ml_dirp); 544 break; 545 case IMSG_MLIST_CLOSE: 546 if (size != 0) { 547 syslog(LOG_ERR, "Invalid message size"); 548 break; 549 } 550 if (fp != NULL) { 551 fclose(fp); 552 fp = NULL; 553 } 554 break; 555 default: 556 syslog(LOG_ERR, "Unexpected message type"); 557 break; 558 } 559 560 imsg_free(&imsg); 561 } 562 } 563 } 564 565 int 566 imsg_getfh(char *path, fhandle_t *fh) 567 { 568 struct imsg imsg; 569 struct getfh_resp *resp; 570 ssize_t size; 571 572 if (send_imsg(IMSG_GETFH_REQ, path, PATH_MAX) == -1) 573 return (-1); 574 575 size = recv_imsg(&imsg); 576 if (size == -1) 577 return (-1); 578 if (imsg.hdr.type != IMSG_GETFH_RESP || size != sizeof(*resp)) { 579 syslog(LOG_ERR, "Invalid message"); 580 imsg_free(&imsg); 581 errno = EINVAL; 582 return (-1); 583 } 584 585 resp = imsg.data; 586 *fh = resp->gr_fh; 587 if (resp->gr_error) { 588 errno = resp->gr_error; 589 imsg_free(&imsg); 590 return (-1); 591 } 592 593 imsg_free(&imsg); 594 return (0); 595 } 596 597 int 598 imsg_export(const char *dir, struct export_args *args) 599 { 600 struct export_req req; 601 struct imsg imsg; 602 ssize_t size; 603 604 if (strlcpy(req.er_path, dir, sizeof(req.er_path)) >= 605 sizeof(req.er_path)) { 606 syslog(LOG_ERR, "%s: mount dir too long", dir); 607 errno = EINVAL; 608 return (-1); 609 } 610 611 req.er_args = *args; 612 if (args->ex_addrlen) 613 req.er_addr = *args->ex_addr; 614 if (args->ex_masklen) 615 req.er_mask = *args->ex_mask; 616 617 if (send_imsg(IMSG_EXPORT_REQ, &req, sizeof(req)) == -1) 618 return (-1); 619 620 size = recv_imsg(&imsg); 621 if (size == -1) 622 return (-1); 623 if (imsg.hdr.type != IMSG_EXPORT_RESP || size != sizeof(int)) { 624 syslog(LOG_ERR, "Invalid message"); 625 imsg_free(&imsg); 626 errno = EINVAL; 627 return (-1); 628 } 629 630 if (*(int *)imsg.data != 0) { 631 errno = *(int *)imsg.data; 632 imsg_free(&imsg); 633 return (-1); 634 } 635 636 imsg_free(&imsg); 637 return (0); 638 } 639 640 ssize_t 641 recv_imsg(struct imsg *imsg) 642 { 643 while (1) { 644 switch (imsg_get(&ibuf, imsg)) { 645 case -1: 646 syslog(LOG_ERR, "imsg_get: %m"); 647 return (-1); 648 case 0: 649 break; 650 default: 651 return (imsg_get_len(imsg)); 652 } 653 654 switch (imsgbuf_read(&ibuf)) { 655 case -1: 656 syslog(LOG_ERR, "imsgbuf_read: %m"); 657 return (-1); 658 case 0: 659 syslog(LOG_ERR, "Socket disconnected"); 660 errno = EINVAL; 661 return (-1); 662 } 663 } 664 } 665 666 int 667 send_imsg(u_int32_t type, void *data, u_int16_t size) 668 { 669 if (imsg_compose(&ibuf, type, 0, 0, -1, data, size) == -1) { 670 syslog(LOG_ERR, "imsg_compose: %m"); 671 return (-1); 672 } 673 674 if (imsgbuf_flush(&ibuf) == -1) { 675 syslog(LOG_ERR, "imsgbuf_flush: %m"); 676 return (-1); 677 } 678 679 return (0); 680 } 681 682 void 683 mountd_svc_run(void) 684 { 685 struct pollfd *pfd = NULL, *newp; 686 nfds_t saved_max_pollfd = 0; 687 int nready, status; 688 689 for (;;) { 690 if (gotchld) { 691 if (waitpid(WAIT_ANY, &status, WNOHANG) == -1) { 692 syslog(LOG_ERR, "waitpid: %m"); 693 break; 694 } 695 if (WIFEXITED(status)) { 696 syslog(LOG_ERR, "Child exited"); 697 break; 698 } 699 if (WIFSIGNALED(status)) { 700 syslog(LOG_ERR, "Child terminated by signal"); 701 break; 702 } 703 gotchld = 0; 704 } 705 if (gothup) { 706 get_exportlist(); 707 gothup = 0; 708 } 709 if (gotterm) 710 break; 711 if (svc_max_pollfd > saved_max_pollfd) { 712 newp = reallocarray(pfd, svc_max_pollfd, sizeof(*pfd)); 713 if (!newp) { 714 free(pfd); 715 perror("mountd_svc_run: - realloc failed"); 716 return; 717 } 718 pfd = newp; 719 saved_max_pollfd = svc_max_pollfd; 720 } 721 memcpy(pfd, svc_pollfd, svc_max_pollfd * sizeof(*pfd)); 722 723 nready = poll(pfd, svc_max_pollfd, INFTIM); 724 switch (nready) { 725 case -1: 726 if (errno == EINTR) 727 break; 728 perror("mountd_svc_run: - poll failed"); 729 free(pfd); 730 return; 731 case 0: 732 break; 733 default: 734 svc_getreq_poll(pfd, nready); 735 break; 736 } 737 } 738 739 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 740 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 741 exit(0); 742 } 743 744 /* 745 * The mount rpc service 746 */ 747 void 748 mntsrv(struct svc_req *rqstp, SVCXPRT *transp) 749 { 750 char rpcpath[RPCMNT_PATHLEN+1], dirpath[PATH_MAX]; 751 struct hostent *hp = NULL; 752 struct exportlist *ep; 753 int defset, hostset; 754 struct fhreturn fhr; 755 struct dirlist *dp; 756 struct statfs fsb; 757 struct stat stb; 758 in_addr_t saddr; 759 u_short sport; 760 long bad = 0; 761 762 saddr = transp->xp_raddr.sin_addr.s_addr; 763 sport = ntohs(transp->xp_raddr.sin_port); 764 switch (rqstp->rq_proc) { 765 case NULLPROC: 766 if (!svc_sendreply(transp, xdr_void, NULL)) 767 syslog(LOG_ERR, "Can't send reply"); 768 return; 769 case RPCMNT_MOUNT: 770 if (debug) 771 fprintf(stderr, "Got mount request from %s\n", 772 inet_ntoa(transp->xp_raddr.sin_addr)); 773 if (sport >= IPPORT_RESERVED) { 774 syslog(LOG_NOTICE, 775 "Refused mount RPC from host %s port %d", 776 inet_ntoa(transp->xp_raddr.sin_addr), sport); 777 svcerr_weakauth(transp); 778 return; 779 } 780 if (!svc_getargs(transp, xdr_dir, rpcpath)) { 781 svcerr_decode(transp); 782 return; 783 } 784 if (debug) 785 fprintf(stderr, "rpcpath: %s\n", rpcpath); 786 787 /* 788 * Get the real pathname and make sure it is a file or 789 * directory that exists. 790 */ 791 if (realpath(rpcpath, dirpath) == NULL) { 792 bad = errno; 793 if (debug) 794 fprintf(stderr, "realpath failed on %s\n", 795 rpcpath); 796 strlcpy(dirpath, rpcpath, sizeof(dirpath)); 797 } else if (stat(dirpath, &stb) == -1 || 798 (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) || 799 statfs(dirpath, &fsb) == -1) { 800 if (debug) 801 fprintf(stderr, "stat failed on %s\n", dirpath); 802 bad = ENOENT; /* We will send error reply later */ 803 } 804 805 /* Check in the exports list */ 806 ep = bad ? NULL : ex_search(&fsb.f_fsid); 807 hostset = defset = 0; 808 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 809 ((dp = dirp_search(ep->ex_dirl, dirpath)) && 810 chk_host(dp, saddr, &defset, &hostset)) || 811 (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 812 scan_tree(ep->ex_dirl, saddr) == 0))) { 813 if (bad) { 814 if (!svc_sendreply(transp, xdr_long, 815 (caddr_t)&bad)) 816 syslog(LOG_ERR, "Can't send reply"); 817 return; 818 } 819 if (hostset & DP_HOSTSET) 820 fhr.fhr_flag = hostset; 821 else 822 fhr.fhr_flag = defset; 823 fhr.fhr_vers = rqstp->rq_vers; 824 /* Get the file handle */ 825 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 826 if (imsg_getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 827 bad = errno; 828 syslog(LOG_ERR, "Can't get fh for %s", dirpath); 829 if (!svc_sendreply(transp, xdr_long, 830 (caddr_t)&bad)) 831 syslog(LOG_ERR, "Can't send reply"); 832 return; 833 } 834 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) 835 syslog(LOG_ERR, "Can't send reply"); 836 if (hp == NULL) 837 hp = gethostbyaddr((caddr_t)&saddr, 838 sizeof(saddr), AF_INET); 839 if (hp) 840 add_mlist(hp->h_name, dirpath); 841 else 842 add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 843 dirpath); 844 if (debug) { 845 fprintf(stderr, 846 "Mount successful for %s by %s.\n", 847 dirpath, 848 inet_ntoa(transp->xp_raddr.sin_addr)); 849 } 850 } else 851 bad = EACCES; 852 853 if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 854 syslog(LOG_ERR, "Can't send reply"); 855 return; 856 case RPCMNT_DUMP: 857 if (!svc_sendreply(transp, xdr_mlist, NULL)) 858 syslog(LOG_ERR, "Can't send reply"); 859 return; 860 case RPCMNT_UMOUNT: 861 if (sport >= IPPORT_RESERVED) { 862 svcerr_weakauth(transp); 863 return; 864 } 865 if (!svc_getargs(transp, xdr_dir, dirpath)) { 866 svcerr_decode(transp); 867 return; 868 } 869 if (!svc_sendreply(transp, xdr_void, NULL)) 870 syslog(LOG_ERR, "Can't send reply"); 871 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 872 if (hp) 873 del_mlist(hp->h_name, dirpath); 874 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 875 return; 876 case RPCMNT_UMNTALL: 877 if (sport >= IPPORT_RESERVED) { 878 svcerr_weakauth(transp); 879 return; 880 } 881 if (!svc_sendreply(transp, xdr_void, NULL)) 882 syslog(LOG_ERR, "Can't send reply"); 883 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 884 if (hp) 885 del_mlist(hp->h_name, NULL); 886 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), NULL); 887 return; 888 case RPCMNT_EXPORT: 889 if (!svc_sendreply(transp, xdr_explist, NULL)) 890 syslog(LOG_ERR, "Can't send reply"); 891 return; 892 default: 893 svcerr_noproc(transp); 894 return; 895 } 896 } 897 898 /* 899 * Xdr conversion for a dirpath string 900 */ 901 int 902 xdr_dir(XDR *xdrsp, char *dirp) 903 { 904 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 905 } 906 907 /* 908 * Xdr routine to generate file handle reply 909 */ 910 int 911 xdr_fhs(XDR *xdrsp, caddr_t cp) 912 { 913 struct fhreturn *fhrp = (struct fhreturn *)cp; 914 long ok = 0, len, auth; 915 916 if (!xdr_long(xdrsp, &ok)) 917 return (0); 918 switch (fhrp->fhr_vers) { 919 case 1: 920 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 921 case 3: 922 len = NFSX_V3FH; 923 if (!xdr_long(xdrsp, &len)) 924 return (0); 925 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 926 return (0); 927 auth = RPCAUTH_UNIX; 928 len = 1; 929 if (!xdr_long(xdrsp, &len)) 930 return (0); 931 return (xdr_long(xdrsp, &auth)); 932 } 933 return (0); 934 } 935 936 int 937 xdr_mlist(XDR *xdrsp, caddr_t cp) 938 { 939 int true = 1, false = 0; 940 struct mountlist *mlp; 941 char *strp; 942 943 mlp = mlhead; 944 while (mlp) { 945 if (!xdr_bool(xdrsp, &true)) 946 return (0); 947 strp = &mlp->ml_host[0]; 948 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 949 return (0); 950 strp = &mlp->ml_dirp[0]; 951 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 952 return (0); 953 mlp = mlp->ml_next; 954 } 955 if (!xdr_bool(xdrsp, &false)) 956 return (0); 957 return (1); 958 } 959 960 /* 961 * Xdr conversion for export list 962 */ 963 int 964 xdr_explist(XDR *xdrsp, caddr_t cp) 965 { 966 struct exportlist *ep; 967 int false = 0, putdef; 968 969 ep = exphead; 970 while (ep) { 971 putdef = 0; 972 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 973 goto errout; 974 if (ep->ex_defdir && putdef == 0 && put_exlist(ep->ex_defdir, 975 xdrsp, NULL, &putdef)) 976 goto errout; 977 ep = ep->ex_next; 978 } 979 if (!xdr_bool(xdrsp, &false)) 980 return (0); 981 return (1); 982 errout: 983 return (0); 984 } 985 986 /* 987 * Called from xdr_explist() to traverse the tree and export the 988 * directory paths. 989 */ 990 int 991 put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, 992 int *putdefp) 993 { 994 int true = 1, false = 0, gotalldir = 0; 995 struct grouplist *grp; 996 struct hostlist *hp; 997 char *strp; 998 999 if (dp) { 1000 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 1001 return (1); 1002 if (!xdr_bool(xdrsp, &true)) 1003 return (1); 1004 strp = dp->dp_dirp; 1005 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 1006 return (1); 1007 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 1008 gotalldir = 1; 1009 *putdefp = 1; 1010 } 1011 if ((dp->dp_flag & DP_DEFSET) == 0 && 1012 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 1013 hp = dp->dp_hosts; 1014 while (hp) { 1015 grp = hp->ht_grp; 1016 if (grp->gr_type == GT_HOST) { 1017 if (!xdr_bool(xdrsp, &true)) 1018 return (1); 1019 strp = grp->gr_ptr.gt_hostent->h_name; 1020 if (!xdr_string(xdrsp, &strp, 1021 RPCMNT_NAMELEN)) 1022 return (1); 1023 } else if (grp->gr_type == GT_NET) { 1024 if (!xdr_bool(xdrsp, &true)) 1025 return (1); 1026 strp = grp->gr_ptr.gt_net.nt_name; 1027 if (!xdr_string(xdrsp, &strp, 1028 RPCMNT_NAMELEN)) 1029 return (1); 1030 } 1031 hp = hp->ht_next; 1032 if (gotalldir && hp == NULL) { 1033 hp = adp->dp_hosts; 1034 gotalldir = 0; 1035 } 1036 } 1037 } 1038 if (!xdr_bool(xdrsp, &false)) 1039 return (1); 1040 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 1041 return (1); 1042 } 1043 return (0); 1044 } 1045 1046 #define LINESIZ 10240 1047 char line[LINESIZ]; 1048 FILE *exp_file; 1049 1050 void 1051 new_exportlist(int signo) 1052 { 1053 gothup = 1; 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 maxgroups, 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 maxgroups = ngroups = NGROUPS_MAX + 1; 2201 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) == -1) { 2202 syslog(LOG_ERR, "Too many groups for %s: %m", pw->pw_name); 2203 /* Truncate group list */ 2204 ngroups = maxgroups; 2205 } 2206 /* 2207 * compress out duplicate 2208 */ 2209 cr->cr_ngroups = ngroups - 1; 2210 cr->cr_gid = groups[0]; 2211 for (cnt = 1; cnt < ngroups; cnt++) 2212 cr->cr_groups[cnt - 1] = groups[cnt]; 2213 return; 2214 } 2215 /* 2216 * Explicit credential specified as a colon separated list: 2217 * uid:gid:gid:... 2218 */ 2219 if (pw != NULL) 2220 cr->cr_uid = pw->pw_uid; 2221 else if (isdigit((unsigned char)*name) || *name == '-') 2222 cr->cr_uid = atoi(name); 2223 else { 2224 syslog(LOG_ERR, "Unknown user: %s", name); 2225 return; 2226 } 2227 cr->cr_ngroups = 0; 2228 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX) { 2229 name = strsep(&names, ":"); 2230 if (isdigit((unsigned char)*name) || *name == '-') { 2231 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 2232 } else { 2233 if ((gr = getgrnam(name)) == NULL) { 2234 syslog(LOG_ERR, "Unknown group: %s", name); 2235 continue; 2236 } 2237 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 2238 } 2239 } 2240 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX) 2241 syslog(LOG_ERR, "Too many groups"); 2242 } 2243 2244 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 2245 /* 2246 * Routines that maintain the remote mounttab 2247 */ 2248 void 2249 get_mountlist(void) 2250 { 2251 struct mountlist *mlp, **mlpp; 2252 char *host, *dirp, *cp; 2253 char str[STRSIZ]; 2254 FILE *mlfile; 2255 2256 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 2257 syslog(LOG_ERR, "Can't open %s: %m", _PATH_RMOUNTLIST); 2258 return; 2259 } 2260 mlpp = &mlhead; 2261 while (fgets(str, STRSIZ, mlfile) != NULL) { 2262 cp = str; 2263 host = strsep(&cp, " \t\n"); 2264 dirp = strsep(&cp, " \t\n"); 2265 if (host == NULL || dirp == NULL) 2266 continue; 2267 mlp = malloc(sizeof (*mlp)); 2268 if (mlp == NULL) 2269 out_of_mem(); 2270 strlcpy(mlp->ml_host, host, sizeof(mlp->ml_host)); 2271 strlcpy(mlp->ml_dirp, dirp, sizeof(mlp->ml_dirp)); 2272 mlp->ml_next = NULL; 2273 *mlpp = mlp; 2274 mlpp = &mlp->ml_next; 2275 } 2276 fclose(mlfile); 2277 } 2278 2279 void 2280 del_mlist(char *hostp, char *dirp) 2281 { 2282 struct mountlist *mlp, **mlpp; 2283 struct mountlist *mlp2; 2284 int fnd = 0; 2285 2286 mlpp = &mlhead; 2287 mlp = mlhead; 2288 while (mlp) { 2289 if (!strcmp(mlp->ml_host, hostp) && 2290 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 2291 fnd = 1; 2292 mlp2 = mlp; 2293 *mlpp = mlp = mlp->ml_next; 2294 free((caddr_t)mlp2); 2295 } else { 2296 mlpp = &mlp->ml_next; 2297 mlp = mlp->ml_next; 2298 } 2299 } 2300 if (fnd) { 2301 send_imsg(IMSG_MLIST_OPEN, NULL, 0); 2302 mlp = mlhead; 2303 while (mlp) { 2304 send_imsg(IMSG_MLIST_WRITE, mlp, sizeof(*mlp)); 2305 mlp = mlp->ml_next; 2306 } 2307 send_imsg(IMSG_MLIST_CLOSE, NULL, 0); 2308 } 2309 } 2310 2311 void 2312 add_mlist(char *hostp, char *dirp) 2313 { 2314 struct mountlist *mlp, **mlpp; 2315 2316 mlpp = &mlhead; 2317 mlp = mlhead; 2318 while (mlp) { 2319 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 2320 return; 2321 mlpp = &mlp->ml_next; 2322 mlp = mlp->ml_next; 2323 } 2324 mlp = malloc(sizeof (*mlp)); 2325 if (mlp == NULL) 2326 out_of_mem(); 2327 strlcpy(mlp->ml_host, hostp, sizeof(mlp->ml_host)); 2328 strlcpy(mlp->ml_dirp, dirp, sizeof(mlp->ml_dirp)); 2329 mlp->ml_next = NULL; 2330 *mlpp = mlp; 2331 send_imsg(IMSG_MLIST_APPEND, mlp, sizeof(*mlp)); 2332 } 2333 2334 /* 2335 * This function is called via SIGTERM when the system is going down. 2336 * It sends a broadcast RPCMNT_UMNTALL. 2337 */ 2338 void 2339 send_umntall(int signo) 2340 { 2341 gotterm = 1; 2342 } 2343 2344 int 2345 umntall_each(caddr_t resultsp, struct sockaddr_in *raddr) 2346 { 2347 return (1); 2348 } 2349 2350 /* 2351 * Free up a group list. 2352 */ 2353 void 2354 free_grp(struct grouplist *grp) 2355 { 2356 char **addrp; 2357 2358 if (grp->gr_type == GT_HOST) { 2359 if (grp->gr_ptr.gt_hostent->h_name) { 2360 addrp = grp->gr_ptr.gt_hostent->h_addr_list; 2361 while (addrp && *addrp) 2362 free(*addrp++); 2363 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 2364 free(grp->gr_ptr.gt_hostent->h_name); 2365 } 2366 free((caddr_t)grp->gr_ptr.gt_hostent); 2367 } else if (grp->gr_type == GT_NET) { 2368 free(grp->gr_ptr.gt_net.nt_name); 2369 } 2370 free((caddr_t)grp); 2371 } 2372 2373 /* 2374 * Check options for consistency. 2375 */ 2376 int 2377 check_options(struct dirlist *dp) 2378 { 2379 2380 if (dp == NULL) 2381 return (1); 2382 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 2383 syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 2384 return (1); 2385 } 2386 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2387 syslog(LOG_ERR, "-mask requires -network"); 2388 return (1); 2389 } 2390 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2391 syslog(LOG_ERR, "-alldirs has multiple directories"); 2392 return (1); 2393 } 2394 return (0); 2395 } 2396 2397 /* 2398 * Check an absolute directory path for any symbolic links. Return true 2399 * if no symbolic links are found. 2400 */ 2401 int 2402 check_dirpath(char *dirp) 2403 { 2404 struct stat sb; 2405 int ret = 1; 2406 char *cp; 2407 2408 /* Remove trailing '/' */ 2409 cp = dirp + strlen(dirp) - 1; 2410 while (cp > dirp && *cp == '/') 2411 *cp-- = '\0'; 2412 2413 cp = dirp + 1; 2414 while (*cp && ret) { 2415 if (*cp == '/') { 2416 *cp = '\0'; 2417 if (lstat(dirp, &sb) == -1 || !S_ISDIR(sb.st_mode)) 2418 ret = 0; 2419 *cp = '/'; 2420 } 2421 cp++; 2422 } 2423 if (lstat(dirp, &sb) == -1 || 2424 (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode))) 2425 ret = 0; 2426 return (ret); 2427 } 2428