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