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