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