1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * 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 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 char copyright[] = 13 "@(#) Copyright (c) 1989 Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif not lint 16 17 #ifndef lint 18 static char sccsid[] = "@(#)mountd.c 5.17 (Berkeley) 11/14/91"; 19 #endif not lint 20 21 #include <pwd.h> 22 #include <grp.h> 23 #include <unistd.h> 24 #include <stdlib.h> 25 #include <fcntl.h> 26 #include <sys/param.h> 27 #include <sys/ioctl.h> 28 #include <sys/stat.h> 29 #include <sys/file.h> 30 #include <sys/ucred.h> 31 #include <sys/mount.h> 32 #include <sys/socket.h> 33 #include <sys/errno.h> 34 #include <sys/signal.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <syslog.h> 38 #include <netdb.h> 39 #include <rpc/rpc.h> 40 #include <rpc/pmap_clnt.h> 41 #include <rpc/pmap_prot.h> 42 #ifdef ISO 43 #include <netiso/iso.h> 44 #endif 45 #include <nfs/rpcv2.h> 46 #include <nfs/nfsv2.h> 47 #include "pathnames.h" 48 49 #define MNT_HOST 0 50 #define MNT_GROUP 1 51 #define MNT_ISO 2 52 53 struct namelist { 54 char name[RPCMNT_NAMELEN+1]; 55 struct namelist *next; 56 }; 57 struct namegrp { 58 char gname[RPCMNT_NAMELEN+1]; 59 struct namegrp *next; 60 struct namelist *names; 61 }; 62 /* 63 * Structures for keeping the mount list and export list 64 */ 65 struct mountlist { 66 struct mountlist *ml_next; 67 char ml_host[RPCMNT_NAMELEN+1]; 68 char ml_dirp[RPCMNT_PATHLEN+1]; 69 }; 70 71 struct exportlist { 72 struct exportlist *ex_next; 73 struct exportlist *ex_prev; 74 struct grouplist *ex_groups; 75 int ex_defset; 76 char ex_dirp[RPCMNT_PATHLEN+1]; 77 }; 78 79 union grouptypes { 80 struct hostent *gt_hostent; 81 struct groupnames *gt_grpname; 82 #ifdef ISO 83 struct sockaddr_iso *gt_isoaddr; 84 #endif 85 }; 86 87 struct grouplist { 88 int type; 89 int exflags; 90 struct ucred anoncr; 91 union grouptypes gr_ptr; 92 struct grouplist *gr_next; 93 }; 94 95 struct al_mnt { 96 struct al_mnt *al_next; 97 fsid_t al_mnted; 98 }; 99 100 struct groupnames { 101 char gn_name[RPCMNT_NAMELEN+1]; 102 struct grouplist *gn_glist; 103 struct groupnames *gn_next; 104 }; 105 106 /* Global defs */ 107 int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist(); 108 void get_exportlist(), send_umntall(), nextfield(), do_opt(); 109 void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp(); 110 void get_group(), get_host(), do_group(); 111 char *realpath(); 112 #ifdef ISO 113 struct iso_addr *iso_addr(); 114 #endif 115 struct exportlist exphead; 116 struct mountlist *mlhead; 117 struct groupnames *grpnames; 118 char exname[MAXPATHLEN]; 119 struct ucred def_anon = { 120 (u_short) 1, 121 (uid_t) -2, 122 1, 123 (gid_t) -2, 124 }; 125 int root_only = 1; 126 extern int errno; 127 struct al_mnt *al_head = (struct al_mnt *)0; 128 #ifdef DEBUG 129 int debug = 1; 130 void SYSLOG __P((int, const char *, ...)); 131 #define syslog SYSLOG 132 #else 133 int debug = 0; 134 #endif 135 136 /* 137 * Mountd server for NFS mount protocol as described in: 138 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 139 * The optional arguments are the exports file name 140 * default: _PATH_EXPORTS 141 * and "-n" to allow nonroot mount. 142 */ 143 main(argc, argv) 144 int argc; 145 char **argv; 146 { 147 SVCXPRT *transp; 148 int c; 149 extern int optind; 150 extern char *optarg; 151 152 while ((c = getopt(argc, argv, "n")) != EOF) 153 switch (c) { 154 case 'n': 155 root_only = 0; 156 break; 157 default: 158 fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); 159 exit(1); 160 }; 161 argc -= optind; 162 argv += optind; 163 grpnames = (struct groupnames *)0; 164 exphead.ex_next = exphead.ex_prev = (struct exportlist *)0; 165 mlhead = (struct mountlist *)0; 166 if (argc == 1) { 167 strncpy(exname, *argv, MAXPATHLEN-1); 168 exname[MAXPATHLEN-1] = '\0'; 169 } else 170 strcpy(exname, _PATH_EXPORTS); 171 openlog("mountd:", LOG_PID, LOG_DAEMON); 172 if (debug) 173 fprintf(stderr,"Getting export list.\n"); 174 get_exportlist(); 175 if (debug) 176 fprintf(stderr,"Getting mount list.\n"); 177 get_mountlist(); 178 if (debug) 179 fprintf(stderr,"Here we go.\n"); 180 if (debug == 0) { 181 daemon(0, 0); 182 signal(SIGINT, SIG_IGN); 183 signal(SIGQUIT, SIG_IGN); 184 } 185 signal(SIGHUP, get_exportlist); 186 signal(SIGTERM, send_umntall); 187 { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 188 if (pidfile != NULL) { 189 fprintf(pidfile, "%d\n", getpid()); 190 fclose(pidfile); 191 } 192 } 193 if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 194 syslog(LOG_ERR, "Can't create socket"); 195 exit(1); 196 } 197 pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 198 if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 199 IPPROTO_UDP)) { 200 syslog(LOG_ERR, "Can't register mount"); 201 exit(1); 202 } 203 svc_run(); 204 syslog(LOG_ERR, "Mountd died"); 205 exit(1); 206 } 207 208 /* 209 * The mount rpc service 210 */ 211 mntsrv(rqstp, transp) 212 register struct svc_req *rqstp; 213 register SVCXPRT *transp; 214 { 215 register struct grouplist *grp; 216 register u_long **addrp; 217 register struct exportlist *ep; 218 nfsv2fh_t nfh; 219 struct authunix_parms *ucr; 220 struct stat stb; 221 struct hostent *hp; 222 u_long saddr; 223 char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 224 int bad = ENOENT; 225 int found, matched; 226 int omask; 227 uid_t uid = -2; 228 229 /* Get authorization */ 230 switch (rqstp->rq_cred.oa_flavor) { 231 case AUTH_UNIX: 232 ucr = (struct authunix_parms *)rqstp->rq_clntcred; 233 uid = ucr->aup_uid; 234 break; 235 case AUTH_NULL: 236 default: 237 break; 238 } 239 240 saddr = transp->xp_raddr.sin_addr.s_addr; 241 hp = (struct hostent *)0; 242 switch (rqstp->rq_proc) { 243 case NULLPROC: 244 if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 245 syslog(LOG_ERR, "Can't send reply"); 246 return; 247 case RPCMNT_MOUNT: 248 if ((uid != 0 && root_only) || uid == -2) { 249 svcerr_weakauth(transp); 250 return; 251 } 252 if (!svc_getargs(transp, xdr_dir, rpcpath)) { 253 svcerr_decode(transp); 254 return; 255 } 256 257 /* 258 * Get the real pathname and make sure it is a directory 259 * that exists. 260 */ 261 if (realpath(rpcpath, dirpath) == 0 || stat(dirpath, &stb) < 0 262 || (stb.st_mode&S_IFMT) != S_IFDIR) { 263 chdir("/"); /* Just in case realpath doesn't */ 264 if (debug) 265 fprintf(stderr,"stat failed on %s\n",dirpath); 266 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 267 syslog(LOG_ERR, "Can't send reply"); 268 return; 269 } 270 271 /* Check in the exports list */ 272 omask = sigblock(sigmask(SIGHUP)); 273 ep = exphead.ex_next; 274 found = FALSE; 275 matched = FALSE; 276 while (ep != NULL && !found && !matched) { 277 struct grouplist *tgrp; 278 if (debug) 279 fprintf(stderr,"dirp=[%s]\n",ep->ex_dirp); 280 if (!strcmp(ep->ex_dirp, dirpath)) { 281 if (ep->ex_defset) 282 grp = (struct grouplist *)0; 283 else 284 grp = ep->ex_groups; 285 if (grp == NULL) { 286 if (debug) 287 fprintf(stderr,"grp is null\n"); 288 found = TRUE; 289 } 290 while (grp && !found) { 291 matched = TRUE; 292 if (debug) 293 fprintf(stderr,"type = [%d]\n",grp->type); 294 if (grp->type == MNT_GROUP) { 295 tgrp = grp->gr_ptr.gt_grpname->gn_glist; 296 if (tgrp) 297 addrp = (u_long **) 298 tgrp->gr_ptr.gt_hostent->h_addr_list; 299 while(tgrp && !found) { 300 if (debug) 301 fprintf(stderr, "cmp [%d] [%d]\n", 302 **addrp,saddr); 303 if (**addrp == saddr) { 304 found = TRUE; 305 hp = tgrp->gr_ptr.gt_hostent; 306 break; 307 } 308 if (*++addrp == NULL) { 309 tgrp = tgrp->gr_next; 310 if (tgrp == NULL) 311 break; 312 addrp = (u_long **)tgrp-> 313 gr_ptr.gt_hostent->h_addr_list; 314 } 315 } 316 } else if (grp->type == MNT_HOST) { 317 addrp = (u_long **) 318 grp->gr_ptr.gt_hostent->h_addr_list; 319 while (*addrp) { 320 if (debug) 321 fprintf(stderr, "cmp [%d] [%d]\n", 322 **addrp,saddr); 323 if (**addrp == saddr) { 324 found = TRUE; 325 hp = grp->gr_ptr.gt_hostent; 326 break; 327 } 328 addrp++; 329 } 330 } 331 grp = grp->gr_next; 332 } 333 } 334 ep = ep->ex_next; 335 } 336 if (!found) { 337 bad = EACCES; 338 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 339 syslog(LOG_ERR, "Can't send reply"); 340 sigsetmask(omask); 341 return; 342 } else { 343 /* Get the file handle */ 344 bzero((caddr_t)&nfh, sizeof(nfh)); 345 if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 346 bad = errno; 347 fprintf(stderr, 348 "Couldn't get file handle for %s.\n", 349 dirpath); 350 if (!svc_sendreply(transp, xdr_long, 351 (caddr_t)&bad)) 352 syslog(LOG_ERR, "Can't send reply"); 353 sigsetmask(omask); 354 return; 355 } 356 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 357 syslog(LOG_ERR, "Can't send reply"); 358 if (hp == NULL) 359 hp = gethostbyaddr((caddr_t)&saddr, 360 sizeof(saddr), AF_INET); 361 if (hp) 362 add_mlist(hp->h_name, dirpath); 363 else 364 add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 365 dirpath); 366 if (debug) 367 fprintf(stderr,"Mount successfull.\n"); 368 } 369 sigsetmask(omask); 370 return; 371 case RPCMNT_DUMP: 372 if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0)) 373 syslog(LOG_ERR, "Can't send reply"); 374 return; 375 case RPCMNT_UMOUNT: 376 if ((uid != 0 && root_only) || uid == -2) { 377 svcerr_weakauth(transp); 378 return; 379 } 380 if (!svc_getargs(transp, xdr_dir, dirpath)) { 381 svcerr_decode(transp); 382 return; 383 } 384 if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 385 syslog(LOG_ERR, "Can't send reply"); 386 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 387 if (hp) 388 del_mlist(hp->h_name, dirpath); 389 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 390 return; 391 case RPCMNT_UMNTALL: 392 if ((uid != 0 && root_only) || uid == -2) { 393 svcerr_weakauth(transp); 394 return; 395 } 396 if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 397 syslog(LOG_ERR, "Can't send reply"); 398 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 399 if (hp) 400 del_mlist(hp->h_name, (char *)0); 401 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0); 402 return; 403 case RPCMNT_EXPORT: 404 if (!svc_sendreply(transp, xdr_explist, (caddr_t)0)) 405 syslog(LOG_ERR, "Can't send reply"); 406 return; 407 default: 408 svcerr_noproc(transp); 409 return; 410 } 411 } 412 413 /* 414 * Xdr conversion for a dirpath string 415 */ 416 xdr_dir(xdrsp, dirp) 417 XDR *xdrsp; 418 char *dirp; 419 { 420 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 421 } 422 423 /* 424 * Xdr routine to generate fhstatus 425 */ 426 xdr_fhs(xdrsp, nfh) 427 XDR *xdrsp; 428 nfsv2fh_t *nfh; 429 { 430 int ok = 0; 431 432 if (!xdr_long(xdrsp, &ok)) 433 return (0); 434 return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 435 } 436 437 xdr_mlist(xdrsp, cp) 438 XDR *xdrsp; 439 caddr_t cp; 440 { 441 register struct mountlist *mlp; 442 int true = 1; 443 int false = 0; 444 char *strp; 445 446 mlp = mlhead; 447 while (mlp) { 448 if (!xdr_bool(xdrsp, &true)) 449 return (0); 450 strp = &mlp->ml_host[0]; 451 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 452 return (0); 453 strp = &mlp->ml_dirp[0]; 454 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 455 return (0); 456 mlp = mlp->ml_next; 457 } 458 if (!xdr_bool(xdrsp, &false)) 459 return (0); 460 return (1); 461 } 462 463 /* 464 * Xdr conversion for export list 465 */ 466 xdr_explist(xdrsp, cp) 467 XDR *xdrsp; 468 caddr_t cp; 469 { 470 register struct exportlist *ep; 471 register struct grouplist *grp, *tgrp; 472 int true = 1; 473 int false = 0; 474 char *strp; 475 int omask; 476 477 omask = sigblock(sigmask(SIGHUP)); 478 ep = exphead.ex_next; 479 while (ep != NULL) { 480 if (!xdr_bool(xdrsp, &true)) 481 goto errout; 482 strp = &ep->ex_dirp[0]; 483 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 484 goto errout; 485 grp = ep->ex_groups; 486 while (grp != NULL) { 487 if (grp->type == MNT_GROUP) { 488 tgrp = grp->gr_ptr.gt_grpname->gn_glist; 489 while (tgrp) { 490 if (!xdr_bool(xdrsp, &true)) 491 goto errout; 492 strp = tgrp->gr_ptr.gt_hostent->h_name; 493 if (!xdr_string(xdrsp, &strp, 494 RPCMNT_NAMELEN)) 495 goto errout; 496 tgrp = tgrp->gr_next; 497 } 498 } else if (grp->type == MNT_HOST) { 499 if (!xdr_bool(xdrsp, &true)) 500 goto errout; 501 strp = grp->gr_ptr.gt_hostent->h_name; 502 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 503 goto errout; 504 } 505 grp = grp->gr_next; 506 } 507 if (!xdr_bool(xdrsp, &false)) 508 goto errout; 509 ep = ep->ex_next; 510 } 511 sigsetmask(omask); 512 if (!xdr_bool(xdrsp, &false)) 513 return (0); 514 return (1); 515 errout: 516 sigsetmask(omask); 517 return (0); 518 } 519 520 #define LINESIZ 10240 521 char line[LINESIZ]; 522 523 /* 524 * Get the export list 525 */ 526 void 527 get_exportlist() 528 { 529 struct grouplist *grp, *tgrp; 530 struct al_mnt *al_mp, *t_almp; 531 register struct exportlist *ep, *ep2; 532 struct groupnames *t_gn, *t_gn2; 533 struct ucred anoncr; 534 FILE *inf; 535 char *cp, *endcp; 536 char savedc; 537 int len, dirplen, def_set; 538 int exflags; 539 540 /* 541 * First, get rid of the old list 542 */ 543 ep = exphead.ex_next; 544 while (ep != NULL) { 545 ep2 = ep; 546 ep = ep->ex_next; 547 free_exp(ep2); 548 } 549 exphead.ex_next = exphead.ex_prev = (struct exportlist *)0; 550 551 t_gn = grpnames; 552 while(t_gn != NULL) { 553 t_gn2 = t_gn; 554 t_gn = t_gn->gn_next; 555 free_grp(t_gn2); 556 } 557 grpnames = (struct groupnames *)0; 558 559 al_mp = al_head; 560 while (al_mp) { 561 t_almp = al_mp; 562 al_mp = al_mp->al_next; 563 free((caddr_t)t_almp); 564 } 565 al_head = (struct al_mnt *)0; 566 567 /* 568 * Read in the exports file and build the list, calling 569 * mount() as we go along to push the export rules into the kernel. 570 */ 571 if ((inf = fopen(exname, "r")) == NULL) { 572 syslog(LOG_ERR, "Can't open %s", exname); 573 exit(2); 574 } 575 while (fgets(line, LINESIZ, inf)) { 576 def_set = TRUE; 577 if (debug) 578 fprintf(stderr,"Got line %s\n",line); 579 cp = line; 580 nextfield(&cp, &endcp); 581 if (*cp == '#') 582 goto nextline; 583 if (*cp != '/') { 584 /* create group listing of names */ 585 get_group(cp, ep); 586 goto nextline; 587 } 588 exflags = MNT_EXPORTED; 589 anoncr = def_anon; 590 591 /* 592 * Create new exports list entry 593 */ 594 len = endcp-cp; 595 if (len <= RPCMNT_PATHLEN && len > 0) { 596 /* 597 * See if this directory is already in the list. 598 */ 599 ep = exphead.ex_next; 600 while (ep) { 601 if (!strcmp(ep->ex_dirp, cp)) 602 break; 603 ep = ep->ex_next; 604 } 605 if (ep == (struct exportlist *)0) { 606 ep = (struct exportlist *)malloc(sizeof(*ep)); 607 if (ep == NULL) 608 goto err; 609 ep->ex_next = (struct exportlist *)0; 610 ep->ex_prev = (struct exportlist *)0; 611 ep->ex_groups = (struct grouplist *)0; 612 ep->ex_defset = FALSE; 613 bcopy(cp, ep->ex_dirp, len); 614 ep->ex_dirp[len] = '\0'; 615 } 616 dirplen = len; 617 if (debug) 618 fprintf(stderr, "Making new ep. [%s]\n", 619 ep->ex_dirp); 620 } else { 621 syslog(LOG_ERR, "Bad Exports File line: %s\n", line); 622 goto nextline; 623 } 624 cp = endcp; 625 nextfield(&cp, &endcp); 626 len = endcp-cp; 627 while (len > 0) { 628 savedc = *endcp; 629 *endcp = '\0'; 630 if (len > RPCMNT_NAMELEN) 631 goto more; 632 if (*cp == '-') { 633 do_opt(cp + 1, ep, &exflags, &anoncr); 634 exflags |= MNT_EXPORTED; 635 def_set = TRUE; 636 if (debug) 637 fprintf(stderr, "got r=%d, ex=%d\n", 638 anoncr.cr_uid,exflags); 639 goto more; 640 } else { 641 def_set = FALSE; 642 if (*cp == '$') { 643 do_group(cp + 1, endcp, &grp); 644 grp->type = MNT_GROUP; 645 } else { 646 get_host(cp, endcp, ep, &grp); 647 } 648 if (grp != NULL) { 649 grp->exflags = exflags; 650 grp->anoncr = anoncr; 651 grp->gr_next = ep->ex_groups; 652 ep->ex_groups = grp; 653 } 654 } 655 more: 656 cp = endcp; 657 *cp = savedc; 658 nextfield(&cp, &endcp); 659 len = endcp - cp; 660 } 661 if (def_set == TRUE) { 662 if (ep->ex_defset == TRUE) 663 syslog(LOG_ERR, "Default specified again dir:%s\n", 664 ep->ex_dirp); 665 else { 666 struct hostent *hpe; 667 668 ep->ex_defset = TRUE; 669 if (debug) 670 fprintf(stderr,"Adding a default entry\n"); 671 /* add a default group and make the grp list NULL */ 672 hpe = (struct hostent *)malloc(sizeof(struct hostent)); 673 if (hpe == NULL) { 674 syslog(LOG_ERR,"No more memory: mountd Failed"); 675 exit(2); 676 } 677 tgrp = (struct grouplist *) 678 malloc(sizeof(struct grouplist)); 679 if (tgrp == NULL) { 680 syslog(LOG_ERR,"No more memory: mountd Failed"); 681 exit(2); 682 } 683 tgrp->anoncr = anoncr; 684 tgrp->exflags = exflags; 685 tgrp->type = MNT_HOST; 686 hpe->h_name = (char *)0; 687 hpe->h_addrtype = AF_INET; 688 hpe->h_length = sizeof (u_long); 689 hpe->h_addr_list = (char **)0; 690 tgrp->gr_ptr.gt_hostent = hpe; 691 tgrp->gr_next = ep->ex_groups; 692 ep->ex_groups = tgrp; 693 } 694 } 695 grp = ep->ex_groups; 696 while (grp != NULL) { 697 exflags = grp->exflags; 698 anoncr = grp->anoncr; 699 if (grp->type == MNT_GROUP) { 700 tgrp = grp->gr_ptr.gt_grpname->gn_glist; 701 while(tgrp != NULL) { 702 if (do_mount(ep, tgrp, exflags, &anoncr, 703 dirplen) == FALSE) 704 goto nextline; 705 tgrp = tgrp->gr_next; 706 } 707 } else { 708 if (do_mount(ep, grp, exflags, &anoncr, dirplen) 709 == FALSE) 710 goto nextline; 711 } 712 grp = grp->gr_next; 713 } 714 if (cp) 715 *cp = savedc; 716 if (ep->ex_prev == (struct exportlist *)0) { 717 ep->ex_next = exphead.ex_next; 718 ep->ex_prev = &exphead; 719 if (ep->ex_next != NULL) 720 ep->ex_next->ex_prev = ep; 721 exphead.ex_next = ep; 722 } 723 nextline: 724 ; 725 } 726 fclose(inf); 727 return; 728 err: 729 syslog(LOG_ERR, "No more memory: mountd Failed"); 730 exit(2); 731 } 732 733 do_mount(ep, grp, exflags, anoncrp, dirplen) 734 struct exportlist *ep; 735 struct grouplist *grp; 736 int exflags, dirplen; 737 struct ucred *anoncrp; 738 { 739 int done, found; 740 register u_long **addrp; 741 struct sockaddr_in sin; 742 struct statfs stfsbuf; 743 struct ufs_args args, targs; 744 struct al_mnt *al_mp; 745 char *cp, savedc; 746 747 args.fspec = 0; 748 args.exflags = exflags; 749 args.anon = *anoncrp; 750 sin.sin_family = AF_INET; 751 sin.sin_port = 0; 752 sin.sin_len = sizeof(sin); 753 if (grp->type == MNT_HOST) 754 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 755 done = FALSE; 756 while(!done) { 757 if (grp->type == MNT_HOST) { 758 if (grp->gr_ptr.gt_hostent->h_name) 759 sin.sin_addr.s_addr = **addrp; 760 else 761 sin.sin_addr.s_addr = INADDR_ANY; 762 args.saddr = (struct sockaddr *)&sin; 763 args.slen = sizeof(sin); 764 #ifdef ISO 765 } else if (grp->type == MNT_ISO) { 766 args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 767 args.slen = sizeof (struct sockaddr_iso); 768 #endif /* ISO */ 769 } else { 770 syslog(LOG_ERR, "Bad grouptype"); 771 free_exp(ep); 772 return (FALSE); 773 } 774 if (statfs(ep->ex_dirp, &stfsbuf) < 0) { 775 if (debug) { 776 fprintf(stderr,"statfs failed.\n"); 777 } 778 syslog(LOG_ERR, "Invalid path: %s", ep->ex_dirp); 779 free_exp(ep); 780 return(FALSE); 781 } 782 found = FALSE; 783 for (al_mp = al_head; al_mp && !found; al_mp = al_mp->al_next) 784 if (al_mp->al_mnted.val[0] == stfsbuf.f_fsid.val[0] && 785 al_mp->al_mnted.val[1] == stfsbuf.f_fsid.val[1]) 786 found = TRUE; 787 if (!found) { 788 /* first time for fs, so must send a MNT_DELEXPORT 789 * to clear the old export list held in the kernel 790 * for this fs. 791 */ 792 al_mp = (struct al_mnt *)malloc(sizeof (struct al_mnt)); 793 al_mp->al_mnted = stfsbuf.f_fsid; 794 al_mp->al_next = al_head; 795 al_head = al_mp; 796 targs.fspec = 0; 797 targs.exflags = MNT_DELEXPORT; 798 cp = (char *)0; 799 while (mount(MOUNT_UFS, ep->ex_dirp, 800 stfsbuf.f_flags | MNT_UPDATE, &targs) < 0) { 801 if (debug) { 802 fprintf(stderr, 803 "tried [%s][%d]\n", 804 ep->ex_dirp,errno); 805 } 806 if (cp == NULL) 807 cp = ep->ex_dirp + dirplen - 1; 808 else 809 *cp = savedc; 810 cp--; 811 /* back up over the last component */ 812 while (*cp == '/' && cp > ep->ex_dirp) 813 cp--; 814 while (*(cp - 1) != '/' && cp > ep->ex_dirp) 815 cp--; 816 if (cp == ep->ex_dirp) { 817 if (debug) { 818 fprintf(stderr,"mnt unsucc\n"); 819 } 820 syslog(LOG_ERR, 821 "Can't export %s", ep->ex_dirp); 822 free_exp(ep); 823 return(FALSE); 824 } 825 savedc = *cp; 826 *cp = '\0'; 827 } 828 if (cp != NULL) { 829 *cp = savedc; 830 } 831 } 832 cp = (char *)0; 833 while (mount(MOUNT_UFS, ep->ex_dirp, 834 stfsbuf.f_flags | MNT_UPDATE, &args) < 0) { 835 if (errno == EPERM) { 836 syslog(LOG_ERR, 837 "Can't change attributes for %s.\n", 838 ep->ex_dirp); 839 if (cp != NULL) 840 *cp = savedc; 841 break; 842 } 843 if (cp == NULL) 844 cp = ep->ex_dirp + dirplen - 1; 845 else 846 *cp = savedc; 847 cp--; 848 /* back up over the last component */ 849 while (*cp == '/' && cp > ep->ex_dirp) 850 cp--; 851 while (*(cp - 1) != '/' && cp > ep->ex_dirp) 852 cp--; 853 if (cp == ep->ex_dirp) { 854 if (debug) { 855 fprintf(stderr,"mnt unsucc\n"); 856 } 857 syslog(LOG_ERR, "Can't export %s", ep->ex_dirp); 858 free_exp(ep); 859 return(FALSE); 860 } 861 savedc = *cp; 862 *cp = '\0'; 863 } 864 if (addrp == NULL) 865 done = TRUE; 866 else { 867 ++addrp; 868 if (*addrp == NULL) 869 done = TRUE; 870 } 871 if (cp != NULL) 872 *cp = savedc; 873 } 874 return(TRUE); 875 } 876 877 878 /* 879 * Parse out the next white space separated field 880 */ 881 void 882 nextfield(cp, endcp) 883 char **cp; 884 char **endcp; 885 { 886 register char *p; 887 888 p = *cp; 889 while (*p == ' ' || *p == '\t') 890 p++; 891 if (*p == '\n' || *p == '\0') { 892 *cp = *endcp = p; 893 return; 894 } 895 *cp = p++; 896 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 897 p++; 898 *endcp = p; 899 } 900 901 /* 902 * Parse the option string 903 */ 904 void 905 do_opt(cpopt, ep, exflagsp, cr) 906 register char *cpopt; 907 struct exportlist *ep; 908 int *exflagsp; 909 struct ucred *cr; 910 { 911 register char *cpoptarg, *cpoptend; 912 int allflag = 1; 913 914 while (cpopt && *cpopt) { 915 if (cpoptend = index(cpopt, ',')) 916 *cpoptend++ = '\0'; 917 if (cpoptarg = index(cpopt, '=')) 918 *cpoptarg++ = '\0'; 919 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 920 *exflagsp |= MNT_EXRDONLY; 921 } else if ((!strcmp(cpopt, "root") || !strcmp(cpopt, "r") || 922 !(allflag = strcmp(cpopt, "allanon"))) && cpoptarg) { 923 parsecred(cpoptarg, cr); 924 if (allflag == 0) 925 *exflagsp |= MNT_EXPORTANON; 926 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 927 *exflagsp |= MNT_EXKERB; 928 } else 929 syslog(LOG_ERR, "opt %s ignored for %s", cpopt, 930 ep->ex_dirp); 931 cpopt = cpoptend; 932 } 933 } 934 935 /* 936 * Parse a description of a credential. 937 */ 938 parsecred(namelist, cr) 939 char *namelist; 940 register struct ucred *cr; 941 { 942 register char *name; 943 register int cnt; 944 char *names; 945 struct passwd *pw; 946 struct group *gr; 947 int ngroups, groups[NGROUPS + 1]; 948 949 /* 950 * Set up the unpriviledged user. 951 */ 952 cr->cr_ref = 1; 953 cr->cr_uid = -2; 954 cr->cr_groups[0] = -2; 955 cr->cr_ngroups = 1; 956 /* 957 * Get the user's password table entry. 958 */ 959 names = strsep(&namelist, " \t\n"); 960 name = strsep(&names, ":"); 961 if (isdigit(*name) || *name == '-') 962 pw = getpwuid(atoi(name)); 963 else 964 pw = getpwnam(name); 965 /* 966 * Credentials specified as those of a user. 967 */ 968 if (names == NULL) { 969 if (pw == NULL) { 970 syslog(LOG_ERR, "Unknown user: %s\n", name); 971 return; 972 } 973 cr->cr_uid = pw->pw_uid; 974 ngroups = NGROUPS + 1; 975 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 976 syslog(LOG_ERR, "Too many groups\n"); 977 /* 978 * Convert from int's to gid_t's and compress out duplicate 979 */ 980 cr->cr_ngroups = ngroups - 1; 981 cr->cr_groups[0] = groups[0]; 982 for (cnt = 2; cnt < ngroups; cnt++) 983 cr->cr_groups[cnt - 1] = groups[cnt]; 984 return; 985 } 986 /* 987 * Explicit credential specified as a colon separated list: 988 * uid:gid:gid:... 989 */ 990 if (pw != NULL) 991 cr->cr_uid = pw->pw_uid; 992 else if (isdigit(*name) || *name == '-') 993 cr->cr_uid = atoi(name); 994 else { 995 syslog(LOG_ERR, "Unknown user: %s\n", name); 996 return; 997 } 998 cr->cr_ngroups = 0; 999 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 1000 name = strsep(&names, ":"); 1001 if (isdigit(*name) || *name == '-') { 1002 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 1003 } else { 1004 if ((gr = getgrnam(name)) == NULL) { 1005 syslog(LOG_ERR, "Unknown group: %s\n", name); 1006 continue; 1007 } 1008 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 1009 } 1010 } 1011 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 1012 syslog(LOG_ERR, "Too many groups\n"); 1013 } 1014 1015 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 1016 /* 1017 * Routines that maintain the remote mounttab 1018 */ 1019 void 1020 get_mountlist() 1021 { 1022 register struct mountlist *mlp, **mlpp; 1023 register char *eos, *dirp; 1024 int len; 1025 char str[STRSIZ]; 1026 FILE *mlfile; 1027 1028 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 1029 syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 1030 return; 1031 } 1032 mlpp = &mlhead; 1033 while (fgets(str, STRSIZ, mlfile) != NULL) { 1034 if ((dirp = index(str, '\t')) == NULL && 1035 (dirp = index(str, ' ')) == NULL) 1036 continue; 1037 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1038 len = dirp-str; 1039 if (len > RPCMNT_NAMELEN) 1040 len = RPCMNT_NAMELEN; 1041 bcopy(str, mlp->ml_host, len); 1042 mlp->ml_host[len] = '\0'; 1043 while (*dirp == '\t' || *dirp == ' ') 1044 dirp++; 1045 if ((eos = index(dirp, '\t')) == NULL && 1046 (eos = index(dirp, ' ')) == NULL && 1047 (eos = index(dirp, '\n')) == NULL) 1048 len = strlen(dirp); 1049 else 1050 len = eos-dirp; 1051 if (len > RPCMNT_PATHLEN) 1052 len = RPCMNT_PATHLEN; 1053 bcopy(dirp, mlp->ml_dirp, len); 1054 mlp->ml_dirp[len] = '\0'; 1055 mlp->ml_next = (struct mountlist *)0; 1056 *mlpp = mlp; 1057 mlpp = &mlp->ml_next; 1058 } 1059 fclose(mlfile); 1060 } 1061 1062 void 1063 del_mlist(hostp, dirp) 1064 register char *hostp, *dirp; 1065 { 1066 register struct mountlist *mlp, **mlpp; 1067 struct mountlist *mlp2; 1068 FILE *mlfile; 1069 int fnd = 0; 1070 1071 mlpp = &mlhead; 1072 mlp = mlhead; 1073 while (mlp) { 1074 if (!strcmp(mlp->ml_host, hostp) && 1075 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 1076 fnd = 1; 1077 mlp2 = mlp; 1078 *mlpp = mlp = mlp->ml_next; 1079 free((caddr_t)mlp2); 1080 } else { 1081 mlpp = &mlp->ml_next; 1082 mlp = mlp->ml_next; 1083 } 1084 } 1085 if (fnd) { 1086 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 1087 syslog(LOG_WARNING,"Can't update %s", _PATH_RMOUNTLIST); 1088 return; 1089 } 1090 mlp = mlhead; 1091 while (mlp) { 1092 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1093 mlp = mlp->ml_next; 1094 } 1095 fclose(mlfile); 1096 } 1097 } 1098 1099 void 1100 add_mlist(hostp, dirp) 1101 register char *hostp, *dirp; 1102 { 1103 register struct mountlist *mlp, **mlpp; 1104 FILE *mlfile; 1105 1106 mlpp = &mlhead; 1107 mlp = mlhead; 1108 while (mlp) { 1109 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 1110 return; 1111 mlpp = &mlp->ml_next; 1112 mlp = mlp->ml_next; 1113 } 1114 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1115 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 1116 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 1117 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 1118 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 1119 mlp->ml_next = (struct mountlist *)0; 1120 *mlpp = mlp; 1121 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 1122 syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST); 1123 return; 1124 } 1125 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1126 fclose(mlfile); 1127 } 1128 1129 /* 1130 * This function is called via. SIGTERM when the system is going down. 1131 * It sends a broadcast RPCMNT_UMNTALL. 1132 */ 1133 void 1134 send_umntall() 1135 { 1136 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 1137 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 1138 exit(0); 1139 } 1140 1141 umntall_each(resultsp, raddr) 1142 caddr_t resultsp; 1143 struct sockaddr_in *raddr; 1144 { 1145 return (1); 1146 } 1147 1148 /* 1149 * Free up an exports list component 1150 */ 1151 void 1152 free_exp(ep) 1153 register struct exportlist *ep; 1154 { 1155 register struct grouplist *grp; 1156 struct grouplist *grp2; 1157 1158 grp = ep->ex_groups; 1159 while (grp != NULL) { 1160 grp2 = grp; 1161 grp = grp->gr_next; 1162 free_grp(grp2); 1163 } 1164 free((caddr_t)ep); 1165 } 1166 1167 /* 1168 * Free up a group list. 1169 */ 1170 void 1171 free_grp(grp) 1172 register struct grouplist *grp; 1173 { 1174 register char **addrp; 1175 1176 if (grp->type == MNT_HOST) { 1177 if (grp->gr_ptr.gt_hostent->h_name) { 1178 addrp = grp->gr_ptr.gt_hostent->h_addr_list; 1179 while (addrp && *addrp) 1180 free(*addrp++); 1181 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 1182 free(grp->gr_ptr.gt_hostent->h_name); 1183 } 1184 free((caddr_t)grp->gr_ptr.gt_hostent); 1185 } 1186 #ifdef ISO 1187 else if (grp->type == MNT_ISO) 1188 free((caddr_t)grp->gr_ptr.gt_isoaddr); 1189 #endif 1190 free((caddr_t)grp); 1191 } 1192 1193 void 1194 get_group(line, ep) 1195 char *line; 1196 struct export_list *ep; 1197 { 1198 int done; 1199 struct grouplist *grp; 1200 struct groupnames *t_gn; 1201 char *cp, *endcp, savedc; 1202 1203 cp = line; 1204 nextfield(&cp, &endcp); 1205 savedc = *endcp; 1206 *endcp = NULL; 1207 if (*(endcp-1) == '=') { 1208 *(endcp-1) = NULL; 1209 } 1210 /* check to see if this group exists already */ 1211 t_gn = grpnames; 1212 while(t_gn != NULL) { 1213 if (strcmp(t_gn->gn_name,cp) == 0) { 1214 syslog(LOG_ERR,"Group redifined, second ignored."); 1215 return; 1216 } 1217 t_gn = t_gn->gn_next; 1218 } 1219 1220 /* make a new group list entry */ 1221 t_gn = (struct groupnames *)malloc(sizeof(struct groupnames)); 1222 if (t_gn == NULL) { 1223 syslog(LOG_ERR,"Group: Couldn't Malloc."); 1224 exit(2); 1225 } 1226 strcpy(t_gn->gn_name,cp); 1227 t_gn->gn_next = grpnames; 1228 grpnames = t_gn; 1229 t_gn->gn_glist = NULL; 1230 *endcp = savedc; 1231 cp = endcp; 1232 done = FALSE; 1233 while(!done) { 1234 nextfield(&cp, &endcp); 1235 if (cp == endcp) 1236 done = TRUE; 1237 else { 1238 savedc = *endcp; 1239 *endcp = NULL; 1240 if (strcmp(cp, "=")) { 1241 /* add to group list */ 1242 get_host(cp, endcp, ep, &grp); 1243 if (grp != NULL) { 1244 grp->gr_next = t_gn->gn_glist; 1245 t_gn->gn_glist = grp; 1246 } 1247 } 1248 *endcp = savedc; 1249 cp = endcp; 1250 } 1251 } 1252 } 1253 1254 void 1255 get_host(cp, endcp, ep, gp) 1256 char *cp, *endcp; 1257 struct exportlist *ep; 1258 struct grouplist **gp; 1259 { 1260 register struct hostent *hp, *nhp; 1261 register struct grouplist *grp; 1262 register char **addrp, **naddrp; 1263 struct hostent t_host; 1264 int i; 1265 u_long saddr; 1266 char *aptr[2]; 1267 #ifdef ISO 1268 struct iso_addr *isop; 1269 struct sockaddr_iso *isoaddr; 1270 #endif 1271 1272 if (isdigit(*cp)) { 1273 saddr = inet_addr(cp); 1274 if (saddr == -1) { 1275 syslog(LOG_ERR, 1276 "Bad Exports File, %s: %s", cp, 1277 "inet_addr failed, ignored"); 1278 *gp = NULL; 1279 return; 1280 } 1281 hp = &t_host; 1282 hp->h_name = cp; 1283 hp->h_addrtype = AF_INET; 1284 hp->h_length = sizeof (u_long); 1285 hp->h_addr_list = aptr; 1286 aptr[0] = (char *)&saddr; 1287 aptr[1] = (char *)0; 1288 #ifdef ISO 1289 } else if (!strncmp(cp, "iso=", 4)) { 1290 if ((isop = iso_addr(cp + 4)) == NULL) { 1291 syslog(LOG_ERR, 1292 "Bad Exports File, %s: %s", cp, 1293 "iso_addr failed, ignored"); 1294 *gp = NULL; 1295 return; 1296 } 1297 isoaddr = (struct sockaddr_iso *) 1298 malloc(sizeof (struct sockaddr_iso)); 1299 if (isoaddr == NULL) 1300 goto err1; 1301 bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 1302 bcopy((caddr_t)isop, (caddr_t)isoaddr->siso_addr, 1303 sizeof (struct iso_addr)); 1304 isoaddr->siso_len = sizeof (struct sockaddr_iso); 1305 isoaddr->siso_family = AF_ISO; 1306 grp = (struct grouplist *) 1307 malloc(sizeof(struct grouplist)); 1308 if (grp == NULL) 1309 goto err1; 1310 grp->type = MNT_ISO; 1311 grp->gr_ptr.gt_isoaddr = isoaddr; 1312 *gp = grp; 1313 return; 1314 #endif /* ISO */ 1315 } else if ((hp = gethostbyname(cp)) == NULL) { 1316 syslog(LOG_ERR, "Bad Exports File, %s: %s", 1317 cp, "Gethostbyname failed, ignored"); 1318 *gp = NULL; 1319 return; 1320 } 1321 grp = (struct grouplist *) 1322 malloc(sizeof(struct grouplist)); 1323 if (grp == NULL) 1324 goto err1; 1325 grp->type = MNT_HOST; 1326 nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 1327 malloc(sizeof(struct hostent)); 1328 if (nhp == NULL) 1329 goto err1; 1330 bcopy((caddr_t)hp, (caddr_t)nhp, 1331 sizeof(struct hostent)); 1332 i = strlen(hp->h_name)+1; 1333 nhp->h_name = (char *)malloc(i); 1334 if (nhp->h_name == NULL) 1335 goto err1; 1336 bcopy(hp->h_name, nhp->h_name, i); 1337 addrp = hp->h_addr_list; 1338 i = 1; 1339 while (*addrp++) 1340 i++; 1341 naddrp = nhp->h_addr_list = (char **) 1342 malloc(i*sizeof(char *)); 1343 if (naddrp == NULL) 1344 goto err1; 1345 addrp = hp->h_addr_list; 1346 while (*addrp) { 1347 *naddrp = (char *) 1348 malloc(hp->h_length); 1349 if (*naddrp == NULL) 1350 goto err1; 1351 bcopy(*addrp, *naddrp, 1352 hp->h_length); 1353 addrp++; 1354 naddrp++; 1355 } 1356 *naddrp = (char *)0; 1357 *gp = grp; 1358 return; 1359 err1: 1360 syslog(LOG_ERR, "No more memory: mountd Failed"); 1361 exit(2); 1362 } 1363 1364 void 1365 do_group(cp, endcp, gp) 1366 char *cp, *endcp; 1367 struct grouplist **gp; 1368 { 1369 int found; 1370 struct groupnames *t_gn; 1371 1372 t_gn = grpnames; 1373 found = FALSE; 1374 while((t_gn != NULL) && !found) { 1375 if(strcmp(t_gn->gn_name,cp) == 0) { 1376 found = TRUE; 1377 *gp = (struct grouplist *) 1378 malloc(sizeof(struct grouplist)); 1379 if (*gp == NULL) { 1380 syslog(LOG_ERR,"No more memory: mountd Failed"); 1381 exit(2); 1382 } 1383 (*gp)->gr_ptr.gt_grpname = (struct groupnames *) 1384 malloc(sizeof(struct groupnames)); 1385 if ((*gp)->gr_ptr.gt_grpname == NULL) { 1386 syslog(LOG_ERR,"No more memory: mountd Failed"); 1387 exit(2); 1388 } 1389 (*gp)->gr_ptr.gt_grpname->gn_glist = t_gn->gn_glist; 1390 return; 1391 } 1392 t_gn = t_gn->gn_next; 1393 } 1394 *gp = NULL; 1395 } 1396 1397 /* 1398 * char *realpath(const char *path, char resolved_path[MAXPATHLEN]) 1399 * 1400 * find the real name of path, by removing all ".", ".." 1401 * and symlink components. 1402 * 1403 * Jan-Simon Pendry, September 1991. 1404 */ 1405 char * 1406 realpath(path, resolved) 1407 char *path; 1408 char resolved[MAXPATHLEN]; 1409 { 1410 int d = open(".", O_RDONLY); 1411 int rootd = 0; 1412 char *p, *q; 1413 struct stat stb; 1414 char wbuf[MAXPATHLEN]; 1415 1416 strcpy(resolved, path); 1417 1418 if (d < 0) 1419 return 0; 1420 1421 loop:; 1422 q = strrchr(resolved, '/'); 1423 if (q) { 1424 p = q + 1; 1425 if (q == resolved) 1426 q = "/"; 1427 else { 1428 do 1429 --q; 1430 while (q > resolved && *q == '/'); 1431 q[1] = '\0'; 1432 q = resolved; 1433 } 1434 if (chdir(q) < 0) 1435 goto out; 1436 } else 1437 p = resolved; 1438 1439 if (lstat(p, &stb) == 0) { 1440 if (S_ISLNK(stb.st_mode)) { 1441 int n = readlink(p, resolved, MAXPATHLEN); 1442 if (n < 0) 1443 goto out; 1444 resolved[n] = '\0'; 1445 goto loop; 1446 } 1447 if (S_ISDIR(stb.st_mode)) { 1448 if (chdir(p) < 0) 1449 goto out; 1450 p = ""; 1451 } 1452 } 1453 1454 strcpy(wbuf, p); 1455 if (getcwd(resolved, MAXPATHLEN) == 0) 1456 goto out; 1457 if (resolved[0] == '/' && resolved[1] == '\0') 1458 rootd = 1; 1459 1460 if (*wbuf) { 1461 if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { 1462 errno = ENAMETOOLONG; 1463 goto out; 1464 } 1465 if (rootd == 0) 1466 strcat(resolved, "/"); 1467 strcat(resolved, wbuf); 1468 } 1469 1470 if (fchdir(d) < 0) 1471 goto out; 1472 (void) close(d); 1473 1474 return resolved; 1475 1476 out:; 1477 (void) close(d); 1478 return 0; 1479 } 1480 1481 #ifdef DEBUG 1482 void 1483 SYSLOG(int pri, const char *fmt, ...) 1484 { 1485 va_list ap; 1486 1487 va_start(ap, fmt); 1488 vfprintf(stderr, fmt, ap); 1489 va_end(ap); 1490 } 1491 #endif /* DEBUG */ 1492