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