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