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