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