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