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