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