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