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