1 /* $NetBSD: mountd.c,v 1.84 2003/05/16 14:03:31 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Herb Hasler and Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 40 /* 41 * XXX The ISO support can't possibly work.. 42 */ 43 44 #include <sys/cdefs.h> 45 #ifndef lint 46 __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\ 47 The Regents of the University of California. All rights reserved.\n"); 48 #endif /* not lint */ 49 50 #ifndef lint 51 #if 0 52 static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 53 #else 54 __RCSID("$NetBSD: mountd.c,v 1.84 2003/05/16 14:03:31 christos Exp $"); 55 #endif 56 #endif /* not lint */ 57 58 #include <sys/param.h> 59 #include <sys/file.h> 60 #include <sys/ioctl.h> 61 #include <sys/mount.h> 62 #include <sys/socket.h> 63 #include <sys/stat.h> 64 #include <syslog.h> 65 #include <sys/ucred.h> 66 67 #include <rpc/rpc.h> 68 #include <rpc/pmap_clnt.h> 69 #include <rpc/pmap_prot.h> 70 #include <rpcsvc/mount.h> 71 #ifdef ISO 72 #include <netiso/iso.h> 73 #endif 74 #include <nfs/rpcv2.h> 75 #include <nfs/nfsproto.h> 76 #include <nfs/nfs.h> 77 #include <nfs/nfsmount.h> 78 79 #include <ufs/ufs/ufsmount.h> 80 #include <isofs/cd9660/cd9660_mount.h> 81 #include <msdosfs/msdosfsmount.h> 82 #include <adosfs/adosfs.h> 83 84 #include <arpa/inet.h> 85 86 #include <ctype.h> 87 #include <errno.h> 88 #include <grp.h> 89 #include <netdb.h> 90 #include <pwd.h> 91 #include <netgroup.h> 92 #include <signal.h> 93 #include <stdio.h> 94 #include <stdlib.h> 95 #include <string.h> 96 #include <unistd.h> 97 #include <netgroup.h> 98 #include <err.h> 99 #include <util.h> 100 #include "pathnames.h" 101 #ifdef KERBEROS 102 #include <kerberosIV/krb.h> 103 #include "kuid.h" 104 #endif 105 106 #ifdef IPSEC 107 #include <netinet6/ipsec.h> 108 #ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */ 109 #undef IPSEC 110 #endif 111 #include "ipsec.h" 112 #endif 113 114 #include <stdarg.h> 115 116 /* 117 * Structures for keeping the mount list and export list 118 */ 119 struct mountlist { 120 struct mountlist *ml_next; 121 char ml_host[RPCMNT_NAMELEN + 1]; 122 char ml_dirp[RPCMNT_PATHLEN + 1]; 123 int ml_flag;/* XXX more flags (same as dp_flag) */ 124 }; 125 126 struct dirlist { 127 struct dirlist *dp_left; 128 struct dirlist *dp_right; 129 int dp_flag; 130 struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 131 char dp_dirp[1]; /* Actually malloc'd to size of dir */ 132 }; 133 /* dp_flag bits */ 134 #define DP_DEFSET 0x1 135 #define DP_HOSTSET 0x2 136 #define DP_KERB 0x4 137 #define DP_NORESMNT 0x8 138 139 struct exportlist { 140 struct exportlist *ex_next; 141 struct dirlist *ex_dirl; 142 struct dirlist *ex_defdir; 143 int ex_flag; 144 fsid_t ex_fs; 145 char *ex_fsdir; 146 char *ex_indexfile; 147 }; 148 /* ex_flag bits */ 149 #define EX_LINKED 0x1 150 151 struct netmsk { 152 struct sockaddr_storage nt_net; 153 int nt_len; 154 char *nt_name; 155 }; 156 157 union grouptypes { 158 struct addrinfo *gt_addrinfo; 159 struct netmsk gt_net; 160 #ifdef ISO 161 struct sockaddr_iso *gt_isoaddr; 162 #endif 163 }; 164 165 struct grouplist { 166 int gr_type; 167 union grouptypes gr_ptr; 168 struct grouplist *gr_next; 169 }; 170 /* Group types */ 171 #define GT_NULL 0x0 172 #define GT_HOST 0x1 173 #define GT_NET 0x2 174 #define GT_ISO 0x4 175 176 struct hostlist { 177 int ht_flag;/* Uses DP_xx bits */ 178 struct grouplist *ht_grp; 179 struct hostlist *ht_next; 180 }; 181 182 struct fhreturn { 183 int fhr_flag; 184 int fhr_vers; 185 nfsfh_t fhr_fh; 186 }; 187 188 /* Global defs */ 189 static char *add_expdir __P((struct dirlist **, char *, int)); 190 static void add_dlist __P((struct dirlist **, struct dirlist *, 191 struct grouplist *, int)); 192 static void add_mlist __P((char *, char *, int)); 193 static int check_dirpath __P((const char *, size_t, char *)); 194 static int check_options __P((const char *, size_t, struct dirlist *)); 195 static int chk_host __P((struct dirlist *, struct sockaddr *, int *, int *)); 196 static int del_mlist __P((char *, char *, struct sockaddr *)); 197 static struct dirlist *dirp_search __P((struct dirlist *, char *)); 198 static int do_mount __P((const char *, size_t, struct exportlist *, 199 struct grouplist *, int, struct uucred *, char *, int, struct statfs *)); 200 static int do_opt __P((const char *, size_t, char **, char **, 201 struct exportlist *, struct grouplist *, int *, int *, struct uucred *)); 202 static struct exportlist *ex_search __P((fsid_t *)); 203 static int parse_directory __P((const char *, size_t, struct grouplist *, 204 int, char *, struct exportlist **, struct statfs *)); 205 static int parse_host_netgroup __P((const char *, size_t, struct exportlist *, 206 struct grouplist *, char *, int *, struct grouplist **)); 207 static struct exportlist *get_exp __P((void)); 208 static void free_dir __P((struct dirlist *)); 209 static void free_exp __P((struct exportlist *)); 210 static void free_grp __P((struct grouplist *)); 211 static void free_host __P((struct hostlist *)); 212 static void get_exportlist __P((int)); 213 static int get_host __P((const char *, size_t, const char *, 214 struct grouplist *)); 215 static struct hostlist *get_ht __P((void)); 216 static void get_mountlist __P((void)); 217 static int get_net __P((char *, struct netmsk *, int)); 218 static void free_exp_grp __P((struct exportlist *, struct grouplist *)); 219 static struct grouplist *get_grp __P((void)); 220 static void hang_dirp __P((struct dirlist *, struct grouplist *, 221 struct exportlist *, int)); 222 static void mntsrv __P((struct svc_req *, SVCXPRT *)); 223 static void nextfield __P((char **, char **)); 224 static void parsecred __P((char *, struct uucred *)); 225 static int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); 226 static int scan_tree __P((struct dirlist *, struct sockaddr *)); 227 static void send_umntall __P((int)); 228 static int umntall_each __P((caddr_t, struct sockaddr_in *)); 229 static int xdr_dir __P((XDR *, char *)); 230 static int xdr_explist __P((XDR *, caddr_t)); 231 static int xdr_fhs __P((XDR *, caddr_t)); 232 static int xdr_mlist __P((XDR *, caddr_t)); 233 static void *emalloc __P((size_t)); 234 static char *estrdup __P((const char *)); 235 static int bitcmp __P((void *, void *, int)); 236 static int netpartcmp __P((struct sockaddr *, struct sockaddr *, int)); 237 static int sacmp __P((struct sockaddr *, struct sockaddr *)); 238 static int allones __P((struct sockaddr_storage *, int)); 239 static int countones __P((struct sockaddr *)); 240 #ifdef ISO 241 static int get_isoaddr __P((const char *, size_t, char *, struct grouplist *)); 242 #endif 243 static struct exportlist *exphead; 244 static struct mountlist *mlhead; 245 static struct grouplist *grphead; 246 static char *exname; 247 static struct uucred def_anon = { 248 1, 249 (uid_t) -2, 250 (gid_t) -2, 251 0, 252 {} 253 }; 254 255 static int opt_flags; 256 static int have_v6 = 1; 257 #ifdef NI_WITHSCOPEID 258 static const int ninumeric = NI_NUMERICHOST | NI_WITHSCOPEID; 259 #else 260 static const int ninumeric = NI_NUMERICHOST; 261 #endif 262 263 /* Bits for above */ 264 #define OP_MAPROOT 0x001 265 #define OP_MAPALL 0x002 266 #define OP_KERB 0x004 267 #define OP_MASK 0x008 268 #define OP_NET 0x010 269 #define OP_ISO 0x020 270 #define OP_ALLDIRS 0x040 271 #define OP_NORESPORT 0x080 272 #define OP_NORESMNT 0x100 273 #define OP_MASKLEN 0x200 274 275 static int debug = 0; 276 #if 0 277 static void SYSLOG __P((int, const char *,...)); 278 #endif 279 int main __P((int, char *[])); 280 281 /* 282 * Mountd server for NFS mount protocol as described in: 283 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 284 * The optional arguments are the exports file name 285 * default: _PATH_EXPORTS 286 * "-d" to enable debugging 287 * and "-n" to allow nonroot mount. 288 */ 289 int 290 main(argc, argv) 291 int argc; 292 char **argv; 293 { 294 SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; 295 struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 296 int udpsock, tcpsock, udp6sock, tcp6sock; 297 int xcreated = 0, s; 298 int c, one = 1; 299 int maxrec = RPC_MAXDATASIZE; 300 #ifdef IPSEC 301 char *policy = NULL; 302 #define ADDOPTS "P:" 303 #else 304 #define ADDOPTS 305 #endif 306 307 while ((c = getopt(argc, argv, "dnr" ADDOPTS)) != -1) 308 switch (c) { 309 #ifdef IPSEC 310 case 'P': 311 if (ipsecsetup_test(policy = optarg)) 312 errx(1, "Invalid ipsec policy `%s'", policy); 313 break; 314 #endif 315 case 'd': 316 debug = 1; 317 break; 318 /* Compatibility */ 319 case 'n': 320 case 'r': 321 break; 322 default: 323 fprintf(stderr, "Usage: %s [-d]" 324 #ifdef IPSEC 325 " [-P ipsec policy]" 326 #endif 327 " [export_file]\n", getprogname()); 328 exit(1); 329 }; 330 argc -= optind; 331 argv += optind; 332 grphead = NULL; 333 exphead = NULL; 334 mlhead = NULL; 335 if (argc == 1) 336 exname = *argv; 337 else 338 exname = _PATH_EXPORTS; 339 openlog("mountd", LOG_PID, LOG_DAEMON); 340 341 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 342 if (s < 0) 343 have_v6 = 0; 344 else 345 close(s); 346 347 if (debug) 348 (void)fprintf(stderr, "Getting export list.\n"); 349 get_exportlist(0); 350 if (debug) 351 (void)fprintf(stderr, "Getting mount list.\n"); 352 get_mountlist(); 353 if (debug) 354 (void)fprintf(stderr, "Here we go.\n"); 355 if (debug == 0) { 356 daemon(0, 0); 357 (void)signal(SIGINT, SIG_IGN); 358 (void)signal(SIGQUIT, SIG_IGN); 359 } 360 (void)signal(SIGHUP, get_exportlist); 361 (void)signal(SIGTERM, send_umntall); 362 pidfile(NULL); 363 364 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 365 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 366 367 udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 368 tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 369 udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 370 tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 371 372 /* 373 * We're doing host-based access checks here, so don't allow 374 * v4-in-v6 to confuse things. The kernel will disable it 375 * by default on NFS sockets too. 376 */ 377 if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, 378 IPV6_V6ONLY, &one, sizeof one) < 0){ 379 syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 380 exit(1); 381 } 382 if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, 383 IPV6_V6ONLY, &one, sizeof one) < 0){ 384 syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 385 exit(1); 386 } 387 388 udpconf = getnetconfigent("udp"); 389 tcpconf = getnetconfigent("tcp"); 390 udp6conf = getnetconfigent("udp6"); 391 tcp6conf = getnetconfigent("tcp6"); 392 393 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 394 395 if (udpsock != -1 && udpconf != NULL) { 396 bindresvport(udpsock, NULL); 397 #ifdef IPSEC 398 if (policy) 399 ipsecsetup(AF_INET, udpsock, policy); 400 #endif 401 udptransp = svc_dg_create(udpsock, 0, 0); 402 if (udptransp != NULL) { 403 if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, 404 mntsrv, udpconf) || 405 !svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, 406 mntsrv, udpconf)) 407 syslog(LOG_WARNING, "can't register UDP service"); 408 else 409 xcreated++; 410 } else 411 syslog(LOG_WARNING, "can't create UDP service"); 412 413 } 414 415 if (tcpsock != -1 && tcpconf != NULL) { 416 bindresvport(tcpsock, NULL); 417 #ifdef IPSEC 418 if (policy) 419 ipsecsetup(AF_INET, tcpsock, policy); 420 #endif 421 listen(tcpsock, SOMAXCONN); 422 tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, 423 RPC_MAXDATASIZE); 424 if (tcptransp != NULL) { 425 if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, 426 mntsrv, tcpconf) || 427 !svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, 428 mntsrv, tcpconf)) 429 syslog(LOG_WARNING, "can't register TCP service"); 430 else 431 xcreated++; 432 } else 433 syslog(LOG_WARNING, "can't create TCP service"); 434 435 } 436 437 if (udp6sock != -1 && udp6conf != NULL) { 438 bindresvport(udp6sock, NULL); 439 #ifdef IPSEC 440 if (policy) 441 ipsecsetup(AF_INET6, tcpsock, policy); 442 #endif 443 udp6transp = svc_dg_create(udp6sock, 0, 0); 444 if (udp6transp != NULL) { 445 if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, 446 mntsrv, udp6conf) || 447 !svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, 448 mntsrv, udp6conf)) 449 syslog(LOG_WARNING, "can't register UDP6 service"); 450 else 451 xcreated++; 452 } else 453 syslog(LOG_WARNING, "can't create UDP6 service"); 454 455 } 456 457 if (tcp6sock != -1 && tcp6conf != NULL) { 458 bindresvport(tcp6sock, NULL); 459 #ifdef IPSEC 460 if (policy) 461 ipsecsetup(AF_INET6, tcpsock, policy); 462 #endif 463 listen(tcp6sock, SOMAXCONN); 464 tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, 465 RPC_MAXDATASIZE); 466 if (tcp6transp != NULL) { 467 if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, 468 mntsrv, tcp6conf) || 469 !svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, 470 mntsrv, tcp6conf)) 471 syslog(LOG_WARNING, "can't register TCP6 service"); 472 else 473 xcreated++; 474 } else 475 syslog(LOG_WARNING, "can't create TCP6 service"); 476 477 } 478 479 if (xcreated == 0) { 480 syslog(LOG_ERR, "could not create any services"); 481 exit(1); 482 } 483 484 #ifdef KERBEROS 485 kuidinit(); 486 #endif 487 svc_run(); 488 syslog(LOG_ERR, "Mountd died"); 489 exit(1); 490 } 491 492 /* 493 * The mount rpc service 494 */ 495 void 496 mntsrv(rqstp, transp) 497 struct svc_req *rqstp; 498 SVCXPRT *transp; 499 { 500 struct exportlist *ep; 501 struct dirlist *dp; 502 struct fhreturn fhr; 503 struct stat stb; 504 struct statfs fsb; 505 struct addrinfo *ai; 506 char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 507 int lookup_failed = 1; 508 struct sockaddr *saddr; 509 u_short sport; 510 char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 511 long bad = EACCES; 512 int defset, hostset, ret; 513 sigset_t sighup_mask; 514 struct sockaddr_in6 *sin6; 515 struct sockaddr_in *sin; 516 517 (void)sigemptyset(&sighup_mask); 518 (void)sigaddset(&sighup_mask, SIGHUP); 519 saddr = svc_getrpccaller(transp)->buf; 520 switch (saddr->sa_family) { 521 case AF_INET6: 522 sin6 = (struct sockaddr_in6 *)saddr; 523 sport = ntohs(sin6->sin6_port); 524 break; 525 case AF_INET: 526 sin = (struct sockaddr_in *)saddr; 527 sport = ntohs(sin->sin_port); 528 break; 529 default: 530 syslog(LOG_ERR, "request from unknown address family"); 531 return; 532 } 533 lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 534 NULL, 0, 0); 535 if (getnameinfo(saddr, saddr->sa_len, numerichost, 536 sizeof numerichost, NULL, 0, ninumeric) != 0) 537 strlcpy(numerichost, "?", sizeof(numerichost)); 538 ai = NULL; 539 #ifdef KERBEROS 540 kuidreset(); 541 #endif 542 ret = 0; 543 switch (rqstp->rq_proc) { 544 case NULLPROC: 545 if (!svc_sendreply(transp, xdr_void, NULL)) 546 syslog(LOG_ERR, "Can't send reply"); 547 return; 548 case MOUNTPROC_MNT: 549 if (debug) 550 fprintf(stderr, 551 "got mount request from %s\n", numerichost); 552 if (!svc_getargs(transp, xdr_dir, rpcpath)) { 553 if (debug) 554 fprintf(stderr, "-> garbage args\n"); 555 svcerr_decode(transp); 556 return; 557 } 558 if (debug) 559 fprintf(stderr, 560 "-> rpcpath: %s\n", rpcpath); 561 /* 562 * Get the real pathname and make sure it is a file or 563 * directory that exists. 564 */ 565 if (realpath(rpcpath, dirpath) == 0 || 566 stat(dirpath, &stb) < 0 || 567 (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) || 568 statfs(dirpath, &fsb) < 0) { 569 (void)chdir("/"); /* Just in case realpath doesn't */ 570 if (debug) 571 (void)fprintf(stderr, "-> stat failed on %s\n", 572 dirpath); 573 if (!svc_sendreply(transp, xdr_long, (caddr_t) &bad)) 574 syslog(LOG_ERR, "Can't send reply"); 575 return; 576 } 577 if (debug) 578 fprintf(stderr, 579 "-> dirpath: %s\n", dirpath); 580 /* Check in the exports list */ 581 (void)sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 582 ep = ex_search(&fsb.f_fsid); 583 hostset = defset = 0; 584 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, 585 &hostset) || ((dp = dirp_search(ep->ex_dirl, dirpath)) && 586 chk_host(dp, saddr, &defset, &hostset)) || 587 (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 588 scan_tree(ep->ex_dirl, saddr) == 0))) { 589 if (sport >= IPPORT_RESERVED && 590 !(hostset & DP_NORESMNT)) { 591 syslog(LOG_NOTICE, 592 "Refused mount RPC from host %s port %d", 593 numerichost, sport); 594 svcerr_weakauth(transp); 595 goto out; 596 } 597 if (hostset & DP_HOSTSET) 598 fhr.fhr_flag = hostset; 599 else 600 fhr.fhr_flag = defset; 601 fhr.fhr_vers = rqstp->rq_vers; 602 /* Get the file handle */ 603 (void)memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 604 if (getfh(dirpath, (fhandle_t *) &fhr.fhr_fh) < 0) { 605 bad = errno; 606 syslog(LOG_ERR, "Can't get fh for %s", dirpath); 607 if (!svc_sendreply(transp, xdr_long, 608 (char *)&bad)) 609 syslog(LOG_ERR, "Can't send reply"); 610 goto out; 611 } 612 if (!svc_sendreply(transp, xdr_fhs, (char *) &fhr)) 613 syslog(LOG_ERR, "Can't send reply"); 614 if (!lookup_failed) 615 add_mlist(host, dirpath, hostset); 616 else 617 add_mlist(numerichost, dirpath, hostset); 618 if (debug) 619 (void)fprintf(stderr, "Mount successful.\n"); 620 } else { 621 if (!svc_sendreply(transp, xdr_long, (caddr_t) &bad)) 622 syslog(LOG_ERR, "Can't send reply"); 623 } 624 out: 625 (void)sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 626 return; 627 case MOUNTPROC_DUMP: 628 if (!svc_sendreply(transp, xdr_mlist, NULL)) 629 syslog(LOG_ERR, "Can't send reply"); 630 return; 631 case MOUNTPROC_UMNT: 632 if (!svc_getargs(transp, xdr_dir, dirpath)) { 633 svcerr_decode(transp); 634 return; 635 } 636 if (!lookup_failed) 637 ret = del_mlist(host, dirpath, saddr); 638 ret |= del_mlist(numerichost, dirpath, saddr); 639 if (ret) { 640 svcerr_weakauth(transp); 641 return; 642 } 643 if (!svc_sendreply(transp, xdr_void, NULL)) 644 syslog(LOG_ERR, "Can't send reply"); 645 return; 646 case MOUNTPROC_UMNTALL: 647 if (!lookup_failed) 648 ret = del_mlist(host, NULL, saddr); 649 ret |= del_mlist(numerichost, NULL, saddr); 650 if (ret) { 651 svcerr_weakauth(transp); 652 return; 653 } 654 if (!svc_sendreply(transp, xdr_void, NULL)) 655 syslog(LOG_ERR, "Can't send reply"); 656 return; 657 case MOUNTPROC_EXPORT: 658 case MOUNTPROC_EXPORTALL: 659 if (!svc_sendreply(transp, xdr_explist, NULL)) 660 syslog(LOG_ERR, "Can't send reply"); 661 return; 662 663 #ifdef KERBEROS 664 case MOUNTPROC_KUIDMAP: 665 case MOUNTPROC_KUIDUMAP: 666 case MOUNTPROC_KUIDPURGE: 667 case MOUNTPROC_KUIDUPURGE: 668 kuidops(rqstp, transp); 669 return; 670 #endif 671 672 default: 673 svcerr_noproc(transp); 674 return; 675 } 676 } 677 678 /* 679 * Xdr conversion for a dirpath string 680 */ 681 static int 682 xdr_dir(xdrsp, dirp) 683 XDR *xdrsp; 684 char *dirp; 685 { 686 687 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 688 } 689 690 /* 691 * Xdr routine to generate file handle reply 692 */ 693 static int 694 xdr_fhs(xdrsp, cp) 695 XDR *xdrsp; 696 caddr_t cp; 697 { 698 struct fhreturn *fhrp = (struct fhreturn *) cp; 699 long ok = 0, len, auth; 700 701 if (!xdr_long(xdrsp, &ok)) 702 return (0); 703 switch (fhrp->fhr_vers) { 704 case 1: 705 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 706 case 3: 707 len = NFSX_V3FH; 708 if (!xdr_long(xdrsp, &len)) 709 return (0); 710 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 711 return (0); 712 if (fhrp->fhr_flag & DP_KERB) 713 auth = RPCAUTH_KERB4; 714 else 715 auth = RPCAUTH_UNIX; 716 len = 1; 717 if (!xdr_long(xdrsp, &len)) 718 return (0); 719 return (xdr_long(xdrsp, &auth)); 720 }; 721 return (0); 722 } 723 724 int 725 xdr_mlist(xdrsp, cp) 726 XDR *xdrsp; 727 caddr_t cp; 728 { 729 struct mountlist *mlp; 730 int true = 1; 731 int false = 0; 732 char *strp; 733 734 mlp = mlhead; 735 while (mlp) { 736 if (!xdr_bool(xdrsp, &true)) 737 return (0); 738 strp = &mlp->ml_host[0]; 739 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 740 return (0); 741 strp = &mlp->ml_dirp[0]; 742 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 743 return (0); 744 mlp = mlp->ml_next; 745 } 746 if (!xdr_bool(xdrsp, &false)) 747 return (0); 748 return (1); 749 } 750 751 /* 752 * Xdr conversion for export list 753 */ 754 int 755 xdr_explist(xdrsp, cp) 756 XDR *xdrsp; 757 caddr_t cp; 758 { 759 struct exportlist *ep; 760 int false = 0; 761 int putdef; 762 sigset_t sighup_mask; 763 764 (void)sigemptyset(&sighup_mask); 765 (void)sigaddset(&sighup_mask, SIGHUP); 766 (void)sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 767 ep = exphead; 768 while (ep) { 769 putdef = 0; 770 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 771 goto errout; 772 if (ep->ex_defdir && putdef == 0 && 773 put_exlist(ep->ex_defdir, xdrsp, NULL, &putdef)) 774 goto errout; 775 ep = ep->ex_next; 776 } 777 (void)sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 778 if (!xdr_bool(xdrsp, &false)) 779 return (0); 780 return (1); 781 errout: 782 (void)sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 783 return (0); 784 } 785 786 /* 787 * Called from xdr_explist() to traverse the tree and export the 788 * directory paths. Assumes SIGHUP has already been masked. 789 */ 790 int 791 put_exlist(dp, xdrsp, adp, putdefp) 792 struct dirlist *dp; 793 XDR *xdrsp; 794 struct dirlist *adp; 795 int *putdefp; 796 { 797 struct grouplist *grp; 798 struct hostlist *hp; 799 int true = 1; 800 int false = 0; 801 int gotalldir = 0; 802 char *strp; 803 804 if (dp) { 805 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 806 return (1); 807 if (!xdr_bool(xdrsp, &true)) 808 return (1); 809 strp = dp->dp_dirp; 810 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 811 return (1); 812 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 813 gotalldir = 1; 814 *putdefp = 1; 815 } 816 if ((dp->dp_flag & DP_DEFSET) == 0 && 817 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 818 hp = dp->dp_hosts; 819 while (hp) { 820 grp = hp->ht_grp; 821 if (grp->gr_type == GT_HOST) { 822 if (!xdr_bool(xdrsp, &true)) 823 return (1); 824 strp = 825 grp->gr_ptr.gt_addrinfo->ai_canonname; 826 if (!xdr_string(xdrsp, &strp, 827 RPCMNT_NAMELEN)) 828 return (1); 829 } else if (grp->gr_type == GT_NET) { 830 if (!xdr_bool(xdrsp, &true)) 831 return (1); 832 strp = grp->gr_ptr.gt_net.nt_name; 833 if (!xdr_string(xdrsp, &strp, 834 RPCMNT_NAMELEN)) 835 return (1); 836 } 837 hp = hp->ht_next; 838 if (gotalldir && hp == NULL) { 839 hp = adp->dp_hosts; 840 gotalldir = 0; 841 } 842 } 843 } 844 if (!xdr_bool(xdrsp, &false)) 845 return (1); 846 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 847 return (1); 848 } 849 return (0); 850 } 851 852 static int 853 parse_host_netgroup(line, lineno, ep, tgrp, cp, has_host, grp) 854 const char *line; 855 size_t lineno; 856 struct exportlist *ep; 857 struct grouplist *tgrp; 858 char *cp; 859 int *has_host; 860 struct grouplist **grp; 861 { 862 const char *hst, *usr, *dom; 863 int netgrp; 864 865 if (ep == NULL) { 866 syslog(LOG_ERR, "\"%s\", line %ld: No current export", 867 line, (unsigned long)lineno); 868 return 0; 869 } 870 setnetgrent(cp); 871 netgrp = getnetgrent(&hst, &usr, &dom); 872 do { 873 if (*has_host) { 874 (*grp)->gr_next = get_grp(); 875 *grp = (*grp)->gr_next; 876 } 877 if (netgrp) { 878 if (hst == NULL) { 879 syslog(LOG_ERR, 880 "\"%s\", line %ld: No host in netgroup %s", 881 line, (unsigned long)lineno, cp); 882 goto bad; 883 } 884 if (get_host(line, lineno, hst, *grp)) 885 goto bad; 886 } else if (get_host(line, lineno, cp, *grp)) 887 goto bad; 888 *has_host = TRUE; 889 } while (netgrp && getnetgrent(&hst, &usr, &dom)); 890 891 endnetgrent(); 892 return 1; 893 bad: 894 endnetgrent(); 895 return 0; 896 897 } 898 899 static int 900 parse_directory(line, lineno, tgrp, got_nondir, cp, ep, fsp) 901 const char *line; 902 size_t lineno; 903 struct grouplist *tgrp; 904 int got_nondir; 905 char *cp; 906 struct exportlist **ep; 907 struct statfs *fsp; 908 { 909 if (!check_dirpath(line, lineno, cp)) 910 return 0; 911 912 if (statfs(cp, fsp) == -1) { 913 syslog(LOG_ERR, "\"%s\", line %ld: statfs for `%s' failed: %m", 914 line, (unsigned long)lineno, cp); 915 return 0; 916 } 917 918 if (got_nondir) { 919 syslog(LOG_ERR, 920 "\"%s\", line %ld: Directories must precede files", 921 line, (unsigned long)lineno); 922 return 0; 923 } 924 if (*ep) { 925 if ((*ep)->ex_fs.val[0] != fsp->f_fsid.val[0] || 926 (*ep)->ex_fs.val[1] != fsp->f_fsid.val[1]) { 927 syslog(LOG_ERR, 928 "\"%s\", line %ld: filesystem ids disagree", 929 line, (unsigned long)lineno); 930 return 0; 931 } 932 } else { 933 /* 934 * See if this directory is already 935 * in the list. 936 */ 937 *ep = ex_search(&fsp->f_fsid); 938 if (*ep == NULL) { 939 *ep = get_exp(); 940 (*ep)->ex_fs = fsp->f_fsid; 941 (*ep)->ex_fsdir = estrdup(fsp->f_mntonname); 942 if (debug) 943 (void)fprintf(stderr, 944 "Making new ep fs=0x%x,0x%x\n", 945 fsp->f_fsid.val[0], fsp->f_fsid.val[1]); 946 } else { 947 if (debug) 948 (void)fprintf(stderr, 949 "Found ep fs=0x%x,0x%x\n", 950 fsp->f_fsid.val[0], fsp->f_fsid.val[1]); 951 } 952 } 953 954 return 1; 955 } 956 957 958 /* 959 * Get the export list 960 */ 961 /* ARGSUSED */ 962 void 963 get_exportlist(n) 964 int n; 965 { 966 struct exportlist *ep, *ep2; 967 struct grouplist *grp, *tgrp; 968 struct exportlist **epp; 969 struct dirlist *dirhead; 970 struct statfs fsb, *fsp; 971 struct addrinfo *ai; 972 struct uucred anon; 973 char *cp, *endcp, *dirp, savedc; 974 int has_host, exflags, got_nondir, dirplen, num, i; 975 FILE *exp_file; 976 char *line; 977 size_t lineno = 0, len; 978 979 980 /* 981 * First, get rid of the old list 982 */ 983 ep = exphead; 984 while (ep) { 985 ep2 = ep; 986 ep = ep->ex_next; 987 free_exp(ep2); 988 } 989 exphead = NULL; 990 991 dirp = NULL; 992 dirplen = 0; 993 grp = grphead; 994 while (grp) { 995 tgrp = grp; 996 grp = grp->gr_next; 997 free_grp(tgrp); 998 } 999 grphead = NULL; 1000 1001 /* 1002 * And delete exports that are in the kernel for all local 1003 * file systems. 1004 * XXX: Should know how to handle all local exportable file systems 1005 * instead of just MOUNT_FFS. 1006 */ 1007 num = getmntinfo(&fsp, MNT_NOWAIT); 1008 for (i = 0; i < num; i++) { 1009 union { 1010 struct ufs_args ua; 1011 struct iso_args ia; 1012 struct mfs_args ma; 1013 struct msdosfs_args da; 1014 struct adosfs_args aa; 1015 } targs; 1016 1017 if (!strncmp(fsp->f_fstypename, MOUNT_MFS, MFSNAMELEN) || 1018 !strncmp(fsp->f_fstypename, MOUNT_FFS, MFSNAMELEN) || 1019 !strncmp(fsp->f_fstypename, MOUNT_EXT2FS, MFSNAMELEN) || 1020 !strncmp(fsp->f_fstypename, MOUNT_MSDOS, MFSNAMELEN) || 1021 !strncmp(fsp->f_fstypename, MOUNT_ADOSFS, MFSNAMELEN) || 1022 !strncmp(fsp->f_fstypename, MOUNT_NULL, MFSNAMELEN) || 1023 !strncmp(fsp->f_fstypename, MOUNT_UMAP, MFSNAMELEN) || 1024 !strncmp(fsp->f_fstypename, MOUNT_UNION, MFSNAMELEN) || 1025 !strncmp(fsp->f_fstypename, MOUNT_CD9660, MFSNAMELEN) || 1026 !strncmp(fsp->f_fstypename, MOUNT_NTFS, MFSNAMELEN)) { 1027 bzero((char *) &targs, sizeof(targs)); 1028 targs.ua.fspec = NULL; 1029 targs.ua.export.ex_flags = MNT_DELEXPORT; 1030 if (mount(fsp->f_fstypename, fsp->f_mntonname, 1031 fsp->f_flags | MNT_UPDATE, &targs) == -1) 1032 syslog(LOG_ERR, "Can't delete exports for %s", 1033 fsp->f_mntonname); 1034 } 1035 fsp++; 1036 } 1037 1038 /* 1039 * Read in the exports file and build the list, calling 1040 * mount() as we go along to push the export rules into the kernel. 1041 */ 1042 if ((exp_file = fopen(exname, "r")) == NULL) { 1043 syslog(LOG_ERR, "Can't open %s: %m", exname); 1044 exit(2); 1045 } 1046 dirhead = NULL; 1047 while ((line = fparseln(exp_file, &len, &lineno, NULL, 0)) != NULL) { 1048 if (debug) 1049 (void)fprintf(stderr, "Got line %s\n", line); 1050 cp = line; 1051 nextfield(&cp, &endcp); 1052 if (cp == endcp) 1053 goto nextline; /* skip empty line */ 1054 /* 1055 * Set defaults. 1056 */ 1057 has_host = FALSE; 1058 anon = def_anon; 1059 exflags = MNT_EXPORTED; 1060 got_nondir = 0; 1061 opt_flags = 0; 1062 ep = NULL; 1063 1064 /* 1065 * Create new exports list entry 1066 */ 1067 len = endcp - cp; 1068 tgrp = grp = get_grp(); 1069 while (len > 0) { 1070 if (len > RPCMNT_NAMELEN) { 1071 *endcp = '\0'; 1072 syslog(LOG_ERR, 1073 "\"%s\", line %ld: name `%s' is too long", 1074 line, (unsigned long)lineno, cp); 1075 goto badline; 1076 } 1077 switch (*cp) { 1078 case '-': 1079 /* 1080 * Option 1081 */ 1082 if (ep == NULL) { 1083 syslog(LOG_ERR, 1084 "\"%s\", line %ld: No current export list", 1085 line, (unsigned long)lineno); 1086 goto badline; 1087 } 1088 if (debug) 1089 (void)fprintf(stderr, "doing opt %s\n", 1090 cp); 1091 got_nondir = 1; 1092 if (do_opt(line, lineno, &cp, &endcp, ep, grp, 1093 &has_host, &exflags, &anon)) 1094 goto badline; 1095 break; 1096 1097 case '/': 1098 /* 1099 * Directory 1100 */ 1101 savedc = *endcp; 1102 *endcp = '\0'; 1103 1104 if (!parse_directory(line, lineno, tgrp, 1105 got_nondir, cp, &ep, &fsb)) 1106 goto badline; 1107 /* 1108 * Add dirpath to export mount point. 1109 */ 1110 dirp = add_expdir(&dirhead, cp, len); 1111 dirplen = len; 1112 1113 *endcp = savedc; 1114 break; 1115 1116 default: 1117 /* 1118 * Host or netgroup. 1119 */ 1120 savedc = *endcp; 1121 *endcp = '\0'; 1122 1123 if (!parse_host_netgroup(line, lineno, ep, 1124 tgrp, cp, &has_host, &grp)) 1125 goto badline; 1126 1127 got_nondir = 1; 1128 1129 *endcp = savedc; 1130 break; 1131 } 1132 1133 cp = endcp; 1134 nextfield(&cp, &endcp); 1135 len = endcp - cp; 1136 } 1137 if (check_options(line, lineno, dirhead)) 1138 goto badline; 1139 1140 if (!has_host) { 1141 grp->gr_type = GT_HOST; 1142 if (debug) 1143 (void)fprintf(stderr, 1144 "Adding a default entry\n"); 1145 /* add a default group and make the grp list NULL */ 1146 ai = emalloc(sizeof(struct addrinfo)); 1147 ai->ai_flags = 0; 1148 ai->ai_family = AF_INET; /* XXXX */ 1149 ai->ai_socktype = SOCK_DGRAM; 1150 /* setting the length to 0 will match anything */ 1151 ai->ai_addrlen = 0; 1152 ai->ai_flags = AI_CANONNAME; 1153 ai->ai_canonname = estrdup("Default"); 1154 ai->ai_addr = NULL; 1155 ai->ai_next = NULL; 1156 grp->gr_ptr.gt_addrinfo = ai; 1157 1158 } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1159 /* 1160 * Don't allow a network export coincide with a list of 1161 * host(s) on the same line. 1162 */ 1163 syslog(LOG_ERR, 1164 "\"%s\", line %ld: Mixed exporting of networks and hosts is disallowed", 1165 line, (unsigned long)lineno); 1166 goto badline; 1167 } 1168 /* 1169 * Loop through hosts, pushing the exports into the kernel. 1170 * After loop, tgrp points to the start of the list and 1171 * grp points to the last entry in the list. 1172 */ 1173 grp = tgrp; 1174 do { 1175 if (do_mount(line, lineno, ep, grp, exflags, &anon, 1176 dirp, dirplen, &fsb)) 1177 goto badline; 1178 } while (grp->gr_next && (grp = grp->gr_next)); 1179 1180 /* 1181 * Success. Update the data structures. 1182 */ 1183 if (has_host) { 1184 hang_dirp(dirhead, tgrp, ep, opt_flags); 1185 grp->gr_next = grphead; 1186 grphead = tgrp; 1187 } else { 1188 hang_dirp(dirhead, NULL, ep, opt_flags); 1189 free_grp(grp); 1190 } 1191 dirhead = NULL; 1192 if ((ep->ex_flag & EX_LINKED) == 0) { 1193 ep2 = exphead; 1194 epp = &exphead; 1195 1196 /* 1197 * Insert in the list in alphabetical order. 1198 */ 1199 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 1200 epp = &ep2->ex_next; 1201 ep2 = ep2->ex_next; 1202 } 1203 if (ep2) 1204 ep->ex_next = ep2; 1205 *epp = ep; 1206 ep->ex_flag |= EX_LINKED; 1207 } 1208 goto nextline; 1209 badline: 1210 free_exp_grp(ep, grp); 1211 nextline: 1212 if (dirhead) { 1213 free_dir(dirhead); 1214 dirhead = NULL; 1215 } 1216 free(line); 1217 } 1218 (void)fclose(exp_file); 1219 } 1220 1221 /* 1222 * Allocate an export list element 1223 */ 1224 static struct exportlist * 1225 get_exp() 1226 { 1227 struct exportlist *ep; 1228 1229 ep = emalloc(sizeof(struct exportlist)); 1230 (void)memset(ep, 0, sizeof(struct exportlist)); 1231 return (ep); 1232 } 1233 1234 /* 1235 * Allocate a group list element 1236 */ 1237 static struct grouplist * 1238 get_grp() 1239 { 1240 struct grouplist *gp; 1241 1242 gp = emalloc(sizeof(struct grouplist)); 1243 (void)memset(gp, 0, sizeof(struct grouplist)); 1244 return (gp); 1245 } 1246 1247 /* 1248 * Clean up upon an error in get_exportlist(). 1249 */ 1250 static void 1251 free_exp_grp(ep, grp) 1252 struct exportlist *ep; 1253 struct grouplist *grp; 1254 { 1255 struct grouplist *tgrp; 1256 1257 if (ep && (ep->ex_flag & EX_LINKED) == 0) 1258 free_exp(ep); 1259 while (grp) { 1260 tgrp = grp; 1261 grp = grp->gr_next; 1262 free_grp(tgrp); 1263 } 1264 } 1265 1266 /* 1267 * Search the export list for a matching fs. 1268 */ 1269 static struct exportlist * 1270 ex_search(fsid) 1271 fsid_t *fsid; 1272 { 1273 struct exportlist *ep; 1274 1275 ep = exphead; 1276 while (ep) { 1277 if (ep->ex_fs.val[0] == fsid->val[0] && 1278 ep->ex_fs.val[1] == fsid->val[1]) 1279 return (ep); 1280 ep = ep->ex_next; 1281 } 1282 return (ep); 1283 } 1284 1285 /* 1286 * Add a directory path to the list. 1287 */ 1288 static char * 1289 add_expdir(dpp, cp, len) 1290 struct dirlist **dpp; 1291 char *cp; 1292 int len; 1293 { 1294 struct dirlist *dp; 1295 1296 dp = emalloc(sizeof(struct dirlist) + len); 1297 dp->dp_left = *dpp; 1298 dp->dp_right = NULL; 1299 dp->dp_flag = 0; 1300 dp->dp_hosts = NULL; 1301 (void)strcpy(dp->dp_dirp, cp); 1302 *dpp = dp; 1303 return (dp->dp_dirp); 1304 } 1305 1306 /* 1307 * Hang the dir list element off the dirpath binary tree as required 1308 * and update the entry for host. 1309 */ 1310 void 1311 hang_dirp(dp, grp, ep, flags) 1312 struct dirlist *dp; 1313 struct grouplist *grp; 1314 struct exportlist *ep; 1315 int flags; 1316 { 1317 struct hostlist *hp; 1318 struct dirlist *dp2; 1319 1320 if (flags & OP_ALLDIRS) { 1321 if (ep->ex_defdir) 1322 free(dp); 1323 else 1324 ep->ex_defdir = dp; 1325 if (grp == NULL) { 1326 ep->ex_defdir->dp_flag |= DP_DEFSET; 1327 if (flags & OP_KERB) 1328 ep->ex_defdir->dp_flag |= DP_KERB; 1329 if (flags & OP_NORESMNT) 1330 ep->ex_defdir->dp_flag |= DP_NORESMNT; 1331 } else 1332 while (grp) { 1333 hp = get_ht(); 1334 if (flags & OP_KERB) 1335 hp->ht_flag |= DP_KERB; 1336 if (flags & OP_NORESMNT) 1337 hp->ht_flag |= DP_NORESMNT; 1338 hp->ht_grp = grp; 1339 hp->ht_next = ep->ex_defdir->dp_hosts; 1340 ep->ex_defdir->dp_hosts = hp; 1341 grp = grp->gr_next; 1342 } 1343 } else { 1344 1345 /* 1346 * Loop through the directories adding them to the tree. 1347 */ 1348 while (dp) { 1349 dp2 = dp->dp_left; 1350 add_dlist(&ep->ex_dirl, dp, grp, flags); 1351 dp = dp2; 1352 } 1353 } 1354 } 1355 1356 /* 1357 * Traverse the binary tree either updating a node that is already there 1358 * for the new directory or adding the new node. 1359 */ 1360 static void 1361 add_dlist(dpp, newdp, grp, flags) 1362 struct dirlist **dpp; 1363 struct dirlist *newdp; 1364 struct grouplist *grp; 1365 int flags; 1366 { 1367 struct dirlist *dp; 1368 struct hostlist *hp; 1369 int cmp; 1370 1371 dp = *dpp; 1372 if (dp) { 1373 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1374 if (cmp > 0) { 1375 add_dlist(&dp->dp_left, newdp, grp, flags); 1376 return; 1377 } else if (cmp < 0) { 1378 add_dlist(&dp->dp_right, newdp, grp, flags); 1379 return; 1380 } else 1381 free(newdp); 1382 } else { 1383 dp = newdp; 1384 dp->dp_left = NULL; 1385 *dpp = dp; 1386 } 1387 if (grp) { 1388 1389 /* 1390 * Hang all of the host(s) off of the directory point. 1391 */ 1392 do { 1393 hp = get_ht(); 1394 if (flags & OP_KERB) 1395 hp->ht_flag |= DP_KERB; 1396 if (flags & OP_NORESMNT) 1397 hp->ht_flag |= DP_NORESMNT; 1398 hp->ht_grp = grp; 1399 hp->ht_next = dp->dp_hosts; 1400 dp->dp_hosts = hp; 1401 grp = grp->gr_next; 1402 } while (grp); 1403 } else { 1404 dp->dp_flag |= DP_DEFSET; 1405 if (flags & OP_KERB) 1406 dp->dp_flag |= DP_KERB; 1407 if (flags & OP_NORESMNT) 1408 dp->dp_flag |= DP_NORESMNT; 1409 } 1410 } 1411 1412 /* 1413 * Search for a dirpath on the export point. 1414 */ 1415 static struct dirlist * 1416 dirp_search(dp, dirp) 1417 struct dirlist *dp; 1418 char *dirp; 1419 { 1420 int cmp; 1421 1422 if (dp) { 1423 cmp = strcmp(dp->dp_dirp, dirp); 1424 if (cmp > 0) 1425 return (dirp_search(dp->dp_left, dirp)); 1426 else if (cmp < 0) 1427 return (dirp_search(dp->dp_right, dirp)); 1428 else 1429 return (dp); 1430 } 1431 return (dp); 1432 } 1433 1434 /* 1435 * Some helper functions for netmasks. They all assume masks in network 1436 * order (big endian). 1437 */ 1438 static int 1439 bitcmp(void *dst, void *src, int bitlen) 1440 { 1441 int i; 1442 u_int8_t *p1 = dst, *p2 = src; 1443 u_int8_t bitmask; 1444 int bytelen, bitsleft; 1445 1446 bytelen = bitlen / 8; 1447 bitsleft = bitlen % 8; 1448 1449 if (debug) { 1450 printf("comparing:\n"); 1451 for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++) 1452 printf("%02x", p1[i]); 1453 printf("\n"); 1454 for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++) 1455 printf("%02x", p2[i]); 1456 printf("\n"); 1457 } 1458 1459 for (i = 0; i < bytelen; i++) { 1460 if (*p1 != *p2) 1461 return 1; 1462 p1++; 1463 p2++; 1464 } 1465 1466 for (i = 0; i < bitsleft; i++) { 1467 bitmask = 1 << (7 - i); 1468 if ((*p1 & bitmask) != (*p2 & bitmask)) 1469 return 1; 1470 } 1471 1472 return 0; 1473 } 1474 1475 static int 1476 netpartcmp(struct sockaddr *s1, struct sockaddr *s2, int bitlen) 1477 { 1478 void *src, *dst; 1479 1480 if (s1->sa_family != s2->sa_family) 1481 return 1; 1482 1483 switch (s1->sa_family) { 1484 case AF_INET: 1485 src = &((struct sockaddr_in *)s1)->sin_addr; 1486 dst = &((struct sockaddr_in *)s2)->sin_addr; 1487 if (bitlen > sizeof(((struct sockaddr_in *)s1)->sin_addr) * 8) 1488 return 1; 1489 break; 1490 case AF_INET6: 1491 src = &((struct sockaddr_in6 *)s1)->sin6_addr; 1492 dst = &((struct sockaddr_in6 *)s2)->sin6_addr; 1493 if (((struct sockaddr_in6 *)s1)->sin6_scope_id != 1494 ((struct sockaddr_in6 *)s2)->sin6_scope_id) 1495 return 1; 1496 if (bitlen > sizeof(((struct sockaddr_in6 *)s1)->sin6_addr) * 8) 1497 return 1; 1498 break; 1499 default: 1500 return 1; 1501 } 1502 1503 return bitcmp(src, dst, bitlen); 1504 } 1505 1506 static int 1507 allones(struct sockaddr_storage *ssp, int bitlen) 1508 { 1509 u_int8_t *p; 1510 int bytelen, bitsleft, i; 1511 int zerolen; 1512 1513 switch (ssp->ss_family) { 1514 case AF_INET: 1515 p = (u_int8_t *)&((struct sockaddr_in *)ssp)->sin_addr; 1516 zerolen = sizeof (((struct sockaddr_in *)ssp)->sin_addr); 1517 break; 1518 case AF_INET6: 1519 p = (u_int8_t *)&((struct sockaddr_in6 *)ssp)->sin6_addr; 1520 zerolen = sizeof (((struct sockaddr_in6 *)ssp)->sin6_addr); 1521 break; 1522 default: 1523 return -1; 1524 } 1525 1526 memset(p, 0, zerolen); 1527 1528 bytelen = bitlen / 8; 1529 bitsleft = bitlen % 8; 1530 1531 if (bytelen > zerolen) 1532 return -1; 1533 1534 for (i = 0; i < bytelen; i++) 1535 *p++ = 0xff; 1536 1537 for (i = 0; i < bitsleft; i++) 1538 *p |= 1 << (7 - i); 1539 1540 return 0; 1541 } 1542 1543 static int 1544 countones(struct sockaddr *sa) 1545 { 1546 void *mask; 1547 int i, bits = 0, bytelen; 1548 u_int8_t *p; 1549 1550 switch (sa->sa_family) { 1551 case AF_INET: 1552 mask = (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr; 1553 bytelen = 4; 1554 break; 1555 case AF_INET6: 1556 mask = (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr; 1557 bytelen = 16; 1558 break; 1559 default: 1560 return 0; 1561 } 1562 1563 p = mask; 1564 1565 for (i = 0; i < bytelen; i++, p++) { 1566 if (*p != 0xff) { 1567 for (bits = 0; bits < 8; bits++) { 1568 if (!(*p & (1 << (7 - bits)))) 1569 break; 1570 } 1571 break; 1572 } 1573 } 1574 1575 return (i * 8 + bits); 1576 } 1577 1578 static int 1579 sacmp(struct sockaddr *sa1, struct sockaddr *sa2) 1580 { 1581 void *p1, *p2; 1582 int len; 1583 1584 if (sa1->sa_family != sa2->sa_family) 1585 return 1; 1586 1587 switch (sa1->sa_family) { 1588 case AF_INET: 1589 p1 = &((struct sockaddr_in *)sa1)->sin_addr; 1590 p2 = &((struct sockaddr_in *)sa2)->sin_addr; 1591 len = 4; 1592 break; 1593 case AF_INET6: 1594 p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr; 1595 p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr; 1596 len = 16; 1597 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 1598 ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 1599 return 1; 1600 break; 1601 default: 1602 return 1; 1603 } 1604 1605 return memcmp(p1, p2, len); 1606 } 1607 1608 /* 1609 * Scan for a host match in a directory tree. 1610 */ 1611 static int 1612 chk_host(dp, saddr, defsetp, hostsetp) 1613 struct dirlist *dp; 1614 struct sockaddr *saddr; 1615 int *defsetp; 1616 int *hostsetp; 1617 { 1618 struct hostlist *hp; 1619 struct grouplist *grp; 1620 struct addrinfo *ai; 1621 1622 if (dp) { 1623 if (dp->dp_flag & DP_DEFSET) 1624 *defsetp = dp->dp_flag; 1625 hp = dp->dp_hosts; 1626 while (hp) { 1627 grp = hp->ht_grp; 1628 switch (grp->gr_type) { 1629 case GT_HOST: 1630 ai = grp->gr_ptr.gt_addrinfo; 1631 for (; ai; ai = ai->ai_next) { 1632 if (!sacmp(ai->ai_addr, saddr)) { 1633 *hostsetp = 1634 (hp->ht_flag | DP_HOSTSET); 1635 return (1); 1636 } 1637 } 1638 break; 1639 case GT_NET: 1640 if (!netpartcmp(saddr, 1641 (struct sockaddr *) 1642 &grp->gr_ptr.gt_net.nt_net, 1643 grp->gr_ptr.gt_net.nt_len)) { 1644 *hostsetp = (hp->ht_flag | DP_HOSTSET); 1645 return (1); 1646 } 1647 break; 1648 }; 1649 hp = hp->ht_next; 1650 } 1651 } 1652 return (0); 1653 } 1654 1655 /* 1656 * Scan tree for a host that matches the address. 1657 */ 1658 static int 1659 scan_tree(dp, saddr) 1660 struct dirlist *dp; 1661 struct sockaddr *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 static void 1680 free_dir(dp) 1681 struct dirlist *dp; 1682 { 1683 1684 if (dp) { 1685 free_dir(dp->dp_left); 1686 free_dir(dp->dp_right); 1687 free_host(dp->dp_hosts); 1688 free(dp); 1689 } 1690 } 1691 1692 /* 1693 * Parse the option string and update fields. 1694 * Option arguments may either be -<option>=<value> or 1695 * -<option> <value> 1696 */ 1697 static int 1698 do_opt(line, lineno, cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1699 const char *line; 1700 size_t lineno; 1701 char **cpp, **endcpp; 1702 struct exportlist *ep; 1703 struct grouplist *grp; 1704 int *has_hostp; 1705 int *exflagsp; 1706 struct uucred *cr; 1707 { 1708 char *cpoptarg, *cpoptend; 1709 char *cp, *endcp, *cpopt, savedc, savedc2; 1710 int allflag, usedarg; 1711 1712 cpopt = *cpp; 1713 cpopt++; 1714 cp = *endcpp; 1715 savedc = *cp; 1716 *cp = '\0'; 1717 while (cpopt && *cpopt) { 1718 allflag = 1; 1719 usedarg = -2; 1720 savedc2 = '\0'; 1721 if ((cpoptend = strchr(cpopt, ',')) != NULL) { 1722 *cpoptend++ = '\0'; 1723 if ((cpoptarg = strchr(cpopt, '=')) != NULL) 1724 *cpoptarg++ = '\0'; 1725 } else { 1726 if ((cpoptarg = strchr(cpopt, '=')) != NULL) 1727 *cpoptarg++ = '\0'; 1728 else { 1729 *cp = savedc; 1730 nextfield(&cp, &endcp); 1731 **endcpp = '\0'; 1732 if (endcp > cp && *cp != '-') { 1733 cpoptarg = cp; 1734 savedc2 = *endcp; 1735 *endcp = '\0'; 1736 usedarg = 0; 1737 } 1738 } 1739 } 1740 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1741 *exflagsp |= MNT_EXRDONLY; 1742 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1743 !(allflag = strcmp(cpopt, "mapall")) || 1744 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1745 usedarg++; 1746 parsecred(cpoptarg, cr); 1747 if (allflag == 0) { 1748 *exflagsp |= MNT_EXPORTANON; 1749 opt_flags |= OP_MAPALL; 1750 } else 1751 opt_flags |= OP_MAPROOT; 1752 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 1753 *exflagsp |= MNT_EXKERB; 1754 opt_flags |= OP_KERB; 1755 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1756 !strcmp(cpopt, "m"))) { 1757 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1758 syslog(LOG_ERR, 1759 "\"%s\", line %ld: Bad mask: %s", 1760 line, (unsigned long)lineno, cpoptarg); 1761 return (1); 1762 } 1763 usedarg++; 1764 opt_flags |= OP_MASK; 1765 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1766 !strcmp(cpopt, "n"))) { 1767 if (strchr(cpoptarg, '/') != NULL) { 1768 if (debug) 1769 fprintf(stderr, "setting OP_MASKLEN\n"); 1770 opt_flags |= OP_MASKLEN; 1771 } 1772 if (grp->gr_type != GT_NULL) { 1773 syslog(LOG_ERR, 1774 "\"%s\", line %ld: Network/host conflict", 1775 line, (unsigned long)lineno); 1776 return (1); 1777 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1778 syslog(LOG_ERR, 1779 "\"%s\", line %ld: Bad net: %s", 1780 line, (unsigned long)lineno, cpoptarg); 1781 return (1); 1782 } 1783 grp->gr_type = GT_NET; 1784 *has_hostp = 1; 1785 usedarg++; 1786 opt_flags |= OP_NET; 1787 } else if (!strcmp(cpopt, "alldirs")) { 1788 opt_flags |= OP_ALLDIRS; 1789 } else if (!strcmp(cpopt, "noresvmnt")) { 1790 opt_flags |= OP_NORESMNT; 1791 } else if (!strcmp(cpopt, "noresvport")) { 1792 opt_flags |= OP_NORESPORT; 1793 *exflagsp |= MNT_EXNORESPORT; 1794 } else if (!strcmp(cpopt, "public")) { 1795 *exflagsp |= (MNT_EXNORESPORT | MNT_EXPUBLIC); 1796 opt_flags |= OP_NORESPORT; 1797 } else if (!strcmp(cpopt, "webnfs")) { 1798 *exflagsp |= (MNT_EXNORESPORT | MNT_EXPUBLIC | 1799 MNT_EXRDONLY | MNT_EXPORTANON); 1800 opt_flags |= (OP_MAPALL | OP_NORESPORT); 1801 } else if (cpoptarg && !strcmp(cpopt, "index")) { 1802 ep->ex_indexfile = strdup(cpoptarg); 1803 #ifdef ISO 1804 } else if (cpoptarg && !strcmp(cpopt, "iso")) { 1805 if (get_isoaddr(line, lineno, cpoptarg, grp)) 1806 return (1); 1807 *has_hostp = 1; 1808 usedarg++; 1809 opt_flags |= OP_ISO; 1810 #endif /* ISO */ 1811 } else { 1812 syslog(LOG_ERR, 1813 "\"%s\", line %ld: Bad opt %s", 1814 line, (unsigned long)lineno, cpopt); 1815 return (1); 1816 } 1817 if (usedarg >= 0) { 1818 *endcp = savedc2; 1819 **endcpp = savedc; 1820 if (usedarg > 0) { 1821 *cpp = cp; 1822 *endcpp = endcp; 1823 } 1824 return (0); 1825 } 1826 cpopt = cpoptend; 1827 } 1828 **endcpp = savedc; 1829 return (0); 1830 } 1831 1832 /* 1833 * Translate a character string to the corresponding list of network 1834 * addresses for a hostname. 1835 */ 1836 static int 1837 get_host(line, lineno, cp, grp) 1838 const char *line; 1839 size_t lineno; 1840 const char *cp; 1841 struct grouplist *grp; 1842 { 1843 struct addrinfo *ai, hints; 1844 int ecode; 1845 char host[NI_MAXHOST]; 1846 1847 if (grp->gr_type != GT_NULL) { 1848 syslog(LOG_ERR, 1849 "\"%s\", line %ld: Bad netgroup type for ip host %s", 1850 line, (unsigned long)lineno, cp); 1851 return (1); 1852 } 1853 memset(&hints, 0, sizeof hints); 1854 hints.ai_flags = AI_CANONNAME; 1855 hints.ai_protocol = IPPROTO_UDP; 1856 ecode = getaddrinfo(cp, NULL, &hints, &ai); 1857 if (ecode != 0) { 1858 syslog(LOG_ERR, "\"%s\", line %ld: can't get address info for " 1859 "host %s", 1860 line, (long)lineno, cp); 1861 return 1; 1862 } 1863 grp->gr_type = GT_HOST; 1864 grp->gr_ptr.gt_addrinfo = ai; 1865 while (ai != NULL) { 1866 if (ai->ai_canonname == NULL) { 1867 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1868 sizeof host, NULL, 0, ninumeric) != 0) 1869 strlcpy(host, "?", sizeof(host)); 1870 ai->ai_canonname = estrdup(host); 1871 ai->ai_flags |= AI_CANONNAME; 1872 } else 1873 ai->ai_flags &= ~AI_CANONNAME; 1874 if (debug) 1875 (void)fprintf(stderr, "got host %s\n", ai->ai_canonname); 1876 ai = ai->ai_next; 1877 } 1878 return (0); 1879 } 1880 1881 /* 1882 * Free up an exports list component 1883 */ 1884 static void 1885 free_exp(ep) 1886 struct exportlist *ep; 1887 { 1888 1889 if (ep->ex_defdir) { 1890 free_host(ep->ex_defdir->dp_hosts); 1891 free(ep->ex_defdir); 1892 } 1893 if (ep->ex_fsdir) 1894 free(ep->ex_fsdir); 1895 if (ep->ex_indexfile) 1896 free(ep->ex_indexfile); 1897 free_dir(ep->ex_dirl); 1898 free(ep); 1899 } 1900 1901 /* 1902 * Free hosts. 1903 */ 1904 static void 1905 free_host(hp) 1906 struct hostlist *hp; 1907 { 1908 struct hostlist *hp2; 1909 1910 while (hp) { 1911 hp2 = hp; 1912 hp = hp->ht_next; 1913 free(hp2); 1914 } 1915 } 1916 1917 static struct hostlist * 1918 get_ht() 1919 { 1920 struct hostlist *hp; 1921 1922 hp = emalloc(sizeof(struct hostlist)); 1923 hp->ht_next = NULL; 1924 hp->ht_flag = 0; 1925 return (hp); 1926 } 1927 1928 #ifdef ISO 1929 /* 1930 * Translate an iso address. 1931 */ 1932 static int 1933 get_isoaddr(line, lineno, cp, grp) 1934 const char *line; 1935 size_t lineno; 1936 char *cp; 1937 struct grouplist *grp; 1938 { 1939 struct iso_addr *isop; 1940 struct sockaddr_iso *isoaddr; 1941 1942 if (grp->gr_type != GT_NULL) { 1943 syslog(LOG_ERR, 1944 "\"%s\", line %ld: Bad netgroup type for iso addr %s", 1945 line, (unsigned long)lineno, cp); 1946 return (1); 1947 } 1948 if ((isop = iso_addr(cp)) == NULL) { 1949 syslog(LOG_ERR, 1950 "\"%s\", line %ld: Bad iso addr %s", 1951 line, (unsigned long)lineno, cp); 1952 return (1); 1953 } 1954 isoaddr = emalloc(sizeof(struct sockaddr_iso)); 1955 (void)memset(isoaddr, 0, sizeof(struct sockaddr_iso)); 1956 (void)memcpy(&isoaddr->siso_addr, isop, sizeof(struct iso_addr)); 1957 isoaddr->siso_len = sizeof(struct sockaddr_iso); 1958 isoaddr->siso_family = AF_ISO; 1959 grp->gr_type = GT_ISO; 1960 grp->gr_ptr.gt_isoaddr = isoaddr; 1961 return (0); 1962 } 1963 #endif /* ISO */ 1964 1965 /* 1966 * error checked malloc and strdup 1967 */ 1968 static void * 1969 emalloc(n) 1970 size_t n; 1971 { 1972 void *ptr = malloc(n); 1973 1974 if (ptr == NULL) { 1975 syslog(LOG_ERR, "%m"); 1976 exit(2); 1977 } 1978 return ptr; 1979 } 1980 1981 static char * 1982 estrdup(s) 1983 const char *s; 1984 { 1985 char *n = strdup(s); 1986 1987 if (n == NULL) { 1988 syslog(LOG_ERR, "%m"); 1989 exit(2); 1990 } 1991 return n; 1992 } 1993 1994 /* 1995 * Do the mount syscall with the update flag to push the export info into 1996 * the kernel. 1997 */ 1998 static int 1999 do_mount(line, lineno, ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 2000 const char *line; 2001 size_t lineno; 2002 struct exportlist *ep; 2003 struct grouplist *grp; 2004 int exflags; 2005 struct uucred *anoncrp; 2006 char *dirp; 2007 int dirplen; 2008 struct statfs *fsb; 2009 { 2010 struct sockaddr *addrp; 2011 struct sockaddr_storage ss; 2012 struct addrinfo *ai; 2013 int addrlen; 2014 char *cp = NULL; 2015 int done; 2016 char savedc = '\0'; 2017 union { 2018 struct ufs_args ua; 2019 struct iso_args ia; 2020 struct mfs_args ma; 2021 struct msdosfs_args da; 2022 struct adosfs_args aa; 2023 } args; 2024 2025 args.ua.fspec = 0; 2026 args.ua.export.ex_flags = exflags; 2027 args.ua.export.ex_anon = *anoncrp; 2028 args.ua.export.ex_indexfile = ep->ex_indexfile; 2029 if (grp->gr_type == GT_HOST) { 2030 ai = grp->gr_ptr.gt_addrinfo; 2031 addrp = ai->ai_addr; 2032 addrlen = ai->ai_addrlen; 2033 } else 2034 addrp = NULL; 2035 done = FALSE; 2036 while (!done) { 2037 switch (grp->gr_type) { 2038 case GT_HOST: 2039 if (addrp != NULL && addrp->sa_family == AF_INET6 && 2040 have_v6 == 0) 2041 goto skip; 2042 args.ua.export.ex_addr = addrp; 2043 args.ua.export.ex_addrlen = addrlen; 2044 args.ua.export.ex_masklen = 0; 2045 break; 2046 case GT_NET: 2047 args.ua.export.ex_addr = (struct sockaddr *) 2048 &grp->gr_ptr.gt_net.nt_net; 2049 if (args.ua.export.ex_addr->sa_family == AF_INET6 && 2050 have_v6 == 0) 2051 goto skip; 2052 args.ua.export.ex_addrlen = 2053 args.ua.export.ex_addr->sa_len; 2054 memset(&ss, 0, sizeof ss); 2055 ss.ss_family = args.ua.export.ex_addr->sa_family; 2056 ss.ss_len = args.ua.export.ex_addr->sa_len; 2057 if (allones(&ss, grp->gr_ptr.gt_net.nt_len) != 0) { 2058 syslog(LOG_ERR, 2059 "\"%s\", line %ld: Bad network flag", 2060 line, (unsigned long)lineno); 2061 if (cp) 2062 *cp = savedc; 2063 return (1); 2064 } 2065 args.ua.export.ex_mask = (struct sockaddr *)&ss; 2066 args.ua.export.ex_masklen = ss.ss_len; 2067 break; 2068 #ifdef ISO 2069 case GT_ISO: 2070 args.ua.export.ex_addr = 2071 (struct sockaddr *) grp->gr_ptr.gt_isoaddr; 2072 args.ua.export.ex_addrlen = 2073 sizeof(struct sockaddr_iso); 2074 args.ua.export.ex_masklen = 0; 2075 break; 2076 #endif /* ISO */ 2077 default: 2078 syslog(LOG_ERR, "\"%s\", line %ld: Bad netgroup type", 2079 line, (unsigned long)lineno); 2080 if (cp) 2081 *cp = savedc; 2082 return (1); 2083 }; 2084 2085 /* 2086 * XXX: 2087 * Maybe I should just use the fsb->f_mntonname path instead 2088 * of looping back up the dirp to the mount point?? 2089 * Also, needs to know how to export all types of local 2090 * exportable file systems and not just MOUNT_FFS. 2091 */ 2092 while (mount(fsb->f_fstypename, dirp, 2093 fsb->f_flags | MNT_UPDATE, &args) == -1) { 2094 if (cp) 2095 *cp-- = savedc; 2096 else 2097 cp = dirp + dirplen - 1; 2098 if (errno == EPERM) { 2099 syslog(LOG_ERR, 2100 "\"%s\", line %ld: Can't change attributes for %s to %s: %m", 2101 line, (unsigned long)lineno, 2102 dirp, (grp->gr_type == GT_HOST) ? 2103 grp->gr_ptr.gt_addrinfo->ai_canonname : 2104 (grp->gr_type == GT_NET) ? 2105 grp->gr_ptr.gt_net.nt_name : 2106 "Unknown"); 2107 return (1); 2108 } 2109 if (opt_flags & OP_ALLDIRS) { 2110 syslog(LOG_ERR, 2111 "\"%s\", line %ld: Could not remount %s: %m", 2112 line, (unsigned long)lineno, 2113 dirp); 2114 return (1); 2115 } 2116 /* back up over the last component */ 2117 while (*cp == '/' && cp > dirp) 2118 cp--; 2119 while (*(cp - 1) != '/' && cp > dirp) 2120 cp--; 2121 if (cp == dirp) { 2122 if (debug) 2123 (void)fprintf(stderr, "mnt unsucc\n"); 2124 syslog(LOG_ERR, 2125 "\"%s\", line %ld: Can't export %s: %m", 2126 line, (unsigned long)lineno, dirp); 2127 return (1); 2128 } 2129 savedc = *cp; 2130 *cp = '\0'; 2131 } 2132 skip: 2133 if (addrp) { 2134 ai = ai->ai_next; 2135 if (ai == NULL) 2136 done = TRUE; 2137 else { 2138 addrp = ai->ai_addr; 2139 addrlen = ai->ai_addrlen; 2140 } 2141 } else 2142 done = TRUE; 2143 } 2144 if (cp) 2145 *cp = savedc; 2146 return (0); 2147 } 2148 2149 /* 2150 * Translate a net address. 2151 */ 2152 static int 2153 get_net(cp, net, maskflg) 2154 char *cp; 2155 struct netmsk *net; 2156 int maskflg; 2157 { 2158 struct netent *np; 2159 char *name, *p, *prefp; 2160 struct sockaddr_in sin, *sinp; 2161 struct sockaddr *sa; 2162 struct addrinfo hints, *ai = NULL; 2163 char netname[NI_MAXHOST]; 2164 long preflen; 2165 int ecode; 2166 2167 (void)memset(&sin, 0, sizeof(sin)); 2168 if ((opt_flags & OP_MASKLEN) && !maskflg) { 2169 p = strchr(cp, '/'); 2170 *p = '\0'; 2171 prefp = p + 1; 2172 } 2173 2174 if ((np = getnetbyname(cp)) != NULL) { 2175 sin.sin_family = AF_INET; 2176 sin.sin_len = sizeof sin; 2177 sin.sin_addr = inet_makeaddr(np->n_net, 0); 2178 sa = (struct sockaddr *)&sin; 2179 } else if (isdigit(*cp)) { 2180 memset(&hints, 0, sizeof hints); 2181 hints.ai_family = AF_UNSPEC; 2182 hints.ai_flags = AI_NUMERICHOST; 2183 if (getaddrinfo(cp, NULL, &hints, &ai) != 0) { 2184 /* 2185 * If getaddrinfo() failed, try the inet4 network 2186 * notation with less than 3 dots. 2187 */ 2188 sin.sin_family = AF_INET; 2189 sin.sin_len = sizeof sin; 2190 sin.sin_addr = inet_makeaddr(inet_network(cp),0); 2191 if (debug) 2192 fprintf(stderr, "get_net: v4 addr %x\n", 2193 sin.sin_addr.s_addr); 2194 sa = (struct sockaddr *)&sin; 2195 } else 2196 sa = ai->ai_addr; 2197 } else if (isxdigit(*cp) || *cp == ':') { 2198 memset(&hints, 0, sizeof hints); 2199 hints.ai_family = AF_UNSPEC; 2200 hints.ai_flags = AI_NUMERICHOST; 2201 if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 2202 sa = ai->ai_addr; 2203 else 2204 goto fail; 2205 } else 2206 goto fail; 2207 2208 /* 2209 * Only allow /pref notation for v6 addresses. 2210 */ 2211 if (sa->sa_family == AF_INET6 && (!(opt_flags & OP_MASKLEN) || maskflg)) 2212 return 1; 2213 2214 ecode = getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2215 NULL, 0, ninumeric); 2216 if (ecode != 0) 2217 goto fail; 2218 2219 if (maskflg) 2220 net->nt_len = countones(sa); 2221 else { 2222 if (opt_flags & OP_MASKLEN) { 2223 errno = 0; 2224 preflen = strtol(prefp, NULL, 10); 2225 if (preflen == LONG_MIN && errno == ERANGE) 2226 goto fail; 2227 net->nt_len = (int)preflen; 2228 *p = '/'; 2229 } 2230 2231 if (np) 2232 name = np->n_name; 2233 else { 2234 if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2235 NULL, 0, ninumeric) != 0) 2236 strlcpy(netname, "?", sizeof(netname)); 2237 name = netname; 2238 } 2239 net->nt_name = estrdup(name); 2240 memcpy(&net->nt_net, sa, sa->sa_len); 2241 } 2242 2243 if (!maskflg && sa->sa_family == AF_INET && 2244 !(opt_flags & (OP_MASK|OP_MASKLEN))) { 2245 sinp = (struct sockaddr_in *)sa; 2246 if (IN_CLASSA(sinp->sin_addr.s_addr)) 2247 net->nt_len = 8; 2248 else if (IN_CLASSB(sinp->sin_addr.s_addr)) 2249 net->nt_len = 16; 2250 else if (IN_CLASSC(sinp->sin_addr.s_addr)) 2251 net->nt_len = 24; 2252 else if (IN_CLASSD(sinp->sin_addr.s_addr)) 2253 net->nt_len = 28; 2254 else 2255 net->nt_len = 32; /* XXX */ 2256 } 2257 2258 if (ai) 2259 freeaddrinfo(ai); 2260 return 0; 2261 2262 fail: 2263 if (ai) 2264 freeaddrinfo(ai); 2265 return 1; 2266 } 2267 2268 /* 2269 * Parse out the next white space separated field 2270 */ 2271 static void 2272 nextfield(cp, endcp) 2273 char **cp; 2274 char **endcp; 2275 { 2276 char *p; 2277 2278 p = *cp; 2279 while (*p == ' ' || *p == '\t') 2280 p++; 2281 if (*p == '\n' || *p == '\0') 2282 *cp = *endcp = p; 2283 else { 2284 *cp = p++; 2285 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 2286 p++; 2287 *endcp = p; 2288 } 2289 } 2290 2291 /* 2292 * Parse a description of a credential. 2293 */ 2294 static void 2295 parsecred(namelist, cr) 2296 char *namelist; 2297 struct uucred *cr; 2298 { 2299 char *name; 2300 int cnt; 2301 char *names; 2302 struct passwd *pw; 2303 struct group *gr; 2304 int ngroups, groups[NGROUPS + 1]; 2305 2306 /* 2307 * Set up the unprivileged user. 2308 */ 2309 *cr = def_anon; 2310 /* 2311 * Get the user's password table entry. 2312 */ 2313 names = strsep(&namelist, " \t\n"); 2314 name = strsep(&names, ":"); 2315 if (isdigit(*name) || *name == '-') 2316 pw = getpwuid(atoi(name)); 2317 else 2318 pw = getpwnam(name); 2319 /* 2320 * Credentials specified as those of a user. 2321 */ 2322 if (names == NULL) { 2323 if (pw == NULL) { 2324 syslog(LOG_ERR, "Unknown user: %s", name); 2325 return; 2326 } 2327 cr->cr_uid = pw->pw_uid; 2328 ngroups = NGROUPS + 1; 2329 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 2330 syslog(LOG_ERR, "Too many groups"); 2331 /* 2332 * Convert from int's to gid_t's and compress out duplicate 2333 */ 2334 cr->cr_ngroups = ngroups - 1; 2335 cr->cr_gid = groups[0]; 2336 for (cnt = 1; cnt < ngroups; cnt++) 2337 cr->cr_groups[cnt - 1] = groups[cnt]; 2338 return; 2339 } 2340 /* 2341 * Explicit credential specified as a colon separated list: 2342 * uid:gid:gid:... 2343 */ 2344 if (pw != NULL) 2345 cr->cr_uid = pw->pw_uid; 2346 else if (isdigit(*name) || *name == '-') 2347 cr->cr_uid = atoi(name); 2348 else { 2349 syslog(LOG_ERR, "Unknown user: %s", name); 2350 return; 2351 } 2352 cr->cr_ngroups = 0; 2353 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 2354 name = strsep(&names, ":"); 2355 if (isdigit(*name) || *name == '-') { 2356 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 2357 } else { 2358 if ((gr = getgrnam(name)) == NULL) { 2359 syslog(LOG_ERR, "Unknown group: %s", name); 2360 continue; 2361 } 2362 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 2363 } 2364 } 2365 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 2366 syslog(LOG_ERR, "Too many groups"); 2367 } 2368 2369 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 2370 /* 2371 * Routines that maintain the remote mounttab 2372 */ 2373 static void 2374 get_mountlist() 2375 { 2376 struct mountlist *mlp, **mlpp; 2377 char *host, *dirp, *cp; 2378 char str[STRSIZ]; 2379 FILE *mlfile; 2380 2381 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 2382 syslog(LOG_ERR, "Can't open %s: %m", _PATH_RMOUNTLIST); 2383 return; 2384 } 2385 mlpp = &mlhead; 2386 while (fgets(str, STRSIZ, mlfile) != NULL) { 2387 cp = str; 2388 host = strsep(&cp, " \t\n"); 2389 dirp = strsep(&cp, " \t\n"); 2390 if (host == NULL || dirp == NULL) 2391 continue; 2392 mlp = emalloc(sizeof(*mlp)); 2393 (void)strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 2394 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2395 (void)strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2396 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2397 mlp->ml_next = NULL; 2398 *mlpp = mlp; 2399 mlpp = &mlp->ml_next; 2400 } 2401 (void)fclose(mlfile); 2402 } 2403 2404 static int 2405 del_mlist(hostp, dirp, saddr) 2406 char *hostp, *dirp; 2407 struct sockaddr *saddr; 2408 { 2409 struct mountlist *mlp, **mlpp; 2410 struct mountlist *mlp2; 2411 u_short sport; 2412 FILE *mlfile; 2413 int fnd = 0, ret = 0; 2414 char host[NI_MAXHOST]; 2415 2416 switch (saddr->sa_family) { 2417 case AF_INET6: 2418 sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 2419 break; 2420 case AF_INET: 2421 sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 2422 break; 2423 default: 2424 return -1; 2425 } 2426 mlpp = &mlhead; 2427 mlp = mlhead; 2428 while (mlp) { 2429 if (!strcmp(mlp->ml_host, hostp) && 2430 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 2431 if (!(mlp->ml_flag & DP_NORESMNT) && 2432 sport >= IPPORT_RESERVED) { 2433 if (getnameinfo(saddr, saddr->sa_len, host, 2434 sizeof host, NULL, 0, ninumeric) != 0) 2435 strlcpy(host, "?", sizeof(host)); 2436 syslog(LOG_NOTICE, 2437 "Umount request for %s:%s from %s refused\n", 2438 mlp->ml_host, mlp->ml_dirp, host); 2439 ret = -1; 2440 goto cont; 2441 } 2442 fnd = 1; 2443 mlp2 = mlp; 2444 *mlpp = mlp = mlp->ml_next; 2445 free(mlp2); 2446 } else { 2447 cont: 2448 mlpp = &mlp->ml_next; 2449 mlp = mlp->ml_next; 2450 } 2451 } 2452 if (fnd) { 2453 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 2454 syslog(LOG_ERR, "Can't update %s: %m", 2455 _PATH_RMOUNTLIST); 2456 return ret; 2457 } 2458 mlp = mlhead; 2459 while (mlp) { 2460 (void)fprintf(mlfile, "%s %s\n", mlp->ml_host, 2461 mlp->ml_dirp); 2462 mlp = mlp->ml_next; 2463 } 2464 (void)fclose(mlfile); 2465 } 2466 return ret; 2467 } 2468 2469 static void 2470 add_mlist(hostp, dirp, flags) 2471 char *hostp, *dirp; 2472 int flags; 2473 { 2474 struct mountlist *mlp, **mlpp; 2475 FILE *mlfile; 2476 2477 mlpp = &mlhead; 2478 mlp = mlhead; 2479 while (mlp) { 2480 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 2481 return; 2482 mlpp = &mlp->ml_next; 2483 mlp = mlp->ml_next; 2484 } 2485 mlp = emalloc(sizeof(*mlp)); 2486 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 2487 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2488 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2489 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2490 mlp->ml_flag = flags; 2491 mlp->ml_next = NULL; 2492 *mlpp = mlp; 2493 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 2494 syslog(LOG_ERR, "Can't update %s: %m", _PATH_RMOUNTLIST); 2495 return; 2496 } 2497 (void)fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2498 (void)fclose(mlfile); 2499 } 2500 2501 /* 2502 * This function is called via. SIGTERM when the system is going down. 2503 * It sends a broadcast RPCMNT_UMNTALL. 2504 */ 2505 /* ARGSUSED */ 2506 static void 2507 send_umntall(n) 2508 int n; 2509 { 2510 (void)clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 2511 xdr_void, NULL, xdr_void, NULL, (resultproc_t)umntall_each); 2512 exit(0); 2513 } 2514 2515 static int 2516 umntall_each(resultsp, raddr) 2517 caddr_t resultsp; 2518 struct sockaddr_in *raddr; 2519 { 2520 return (1); 2521 } 2522 2523 /* 2524 * Free up a group list. 2525 */ 2526 static void 2527 free_grp(grp) 2528 struct grouplist *grp; 2529 { 2530 2531 if (grp->gr_type == GT_HOST) { 2532 if (grp->gr_ptr.gt_addrinfo != NULL) 2533 freeaddrinfo(grp->gr_ptr.gt_addrinfo); 2534 } else if (grp->gr_type == GT_NET) { 2535 if (grp->gr_ptr.gt_net.nt_name) 2536 free(grp->gr_ptr.gt_net.nt_name); 2537 } 2538 #ifdef ISO 2539 else if (grp->gr_type == GT_ISO) 2540 free(grp->gr_ptr.gt_isoaddr); 2541 #endif 2542 free(grp); 2543 } 2544 2545 #if 0 2546 static void 2547 SYSLOG(int pri, const char *fmt,...) 2548 { 2549 va_list ap; 2550 2551 va_start(ap, fmt); 2552 2553 if (debug) 2554 vfprintf(stderr, fmt, ap); 2555 else 2556 vsyslog(pri, fmt, ap); 2557 2558 va_end(ap); 2559 } 2560 #endif 2561 2562 /* 2563 * Check options for consistency. 2564 */ 2565 static int 2566 check_options(line, lineno, dp) 2567 const char *line; 2568 size_t lineno; 2569 struct dirlist *dp; 2570 { 2571 2572 if (dp == NULL) { 2573 syslog(LOG_ERR, 2574 "\"%s\", line %ld: missing directory list", 2575 line, (unsigned long)lineno); 2576 return (1); 2577 } 2578 if ((opt_flags & (OP_MAPROOT|OP_MAPALL)) == (OP_MAPROOT|OP_MAPALL) || 2579 (opt_flags & (OP_MAPROOT|OP_KERB)) == (OP_MAPROOT|OP_KERB) || 2580 (opt_flags & (OP_MAPALL|OP_KERB)) == (OP_MAPALL|OP_KERB)) { 2581 syslog(LOG_ERR, 2582 "\"%s\", line %ld: -mapall, -maproot and -kerb mutually exclusive", 2583 line, (unsigned long)lineno); 2584 return (1); 2585 } 2586 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2587 syslog(LOG_ERR, "\"%s\", line %ld: -mask requires -net", 2588 line, (unsigned long)lineno); 2589 return (1); 2590 } 2591 if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN) != 0) { 2592 syslog(LOG_ERR, "\"%s\", line %ld: /pref and -mask mutually" 2593 " exclusive", 2594 line, (unsigned long)lineno); 2595 return (1); 2596 } 2597 if ((opt_flags & (OP_NET|OP_ISO)) == (OP_NET|OP_ISO)) { 2598 syslog(LOG_ERR, 2599 "\"%s\", line %ld: -net and -iso mutually exclusive", 2600 line, (unsigned long)lineno); 2601 return (1); 2602 } 2603 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2604 syslog(LOG_ERR, 2605 "\"%s\", line %ld: -alldir has multiple directories", 2606 line, (unsigned long)lineno); 2607 return (1); 2608 } 2609 return (0); 2610 } 2611 2612 /* 2613 * Check an absolute directory path for any symbolic links. Return true 2614 * if no symbolic links are found. 2615 */ 2616 static int 2617 check_dirpath(line, lineno, dirp) 2618 const char *line; 2619 size_t lineno; 2620 char *dirp; 2621 { 2622 char *cp; 2623 struct stat sb; 2624 char *file = ""; 2625 2626 for (cp = dirp + 1; *cp; cp++) { 2627 if (*cp == '/') { 2628 *cp = '\0'; 2629 if (lstat(dirp, &sb) == -1) 2630 goto bad; 2631 if (!S_ISDIR(sb.st_mode)) 2632 goto bad1; 2633 *cp = '/'; 2634 } 2635 } 2636 2637 cp = NULL; 2638 if (lstat(dirp, &sb) == -1) 2639 goto bad; 2640 2641 if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) { 2642 file = " file or a"; 2643 goto bad1; 2644 } 2645 2646 return 1; 2647 2648 bad: 2649 syslog(LOG_ERR, 2650 "\"%s\", line %ld: lstat for `%s' failed: %m", 2651 line, (unsigned long)lineno, dirp); 2652 if (cp) 2653 *cp = '/'; 2654 return 0; 2655 2656 bad1: 2657 syslog(LOG_ERR, 2658 "\"%s\", line %ld: `%s' is not a%s directory", 2659 line, (unsigned long)lineno, dirp, file); 2660 if (cp) 2661 *cp = '/'; 2662 return 0; 2663 } 2664