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