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.15 (Berkeley) 11/12/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 DEF_NAME "default" 50 51 #define MNT_HOST 0 52 #define MNT_GROUP 1 53 #define MNT_ISO 2 54 55 struct namelist { 56 char name[RPCMNT_NAMELEN+1]; 57 struct namelist *next; 58 }; 59 struct namegrp { 60 char gname[RPCMNT_NAMELEN+1]; 61 struct namegrp *next; 62 struct namelist *names; 63 }; 64 /* 65 * Structures for keeping the mount list and export list 66 */ 67 struct mountlist { 68 struct mountlist *ml_next; 69 char ml_host[RPCMNT_NAMELEN+1]; 70 char ml_dirp[RPCMNT_PATHLEN+1]; 71 }; 72 73 struct exportlist { 74 struct exportlist *ex_next; 75 struct exportlist *ex_prev; 76 struct grouplist *ex_groups; 77 int ex_defset; 78 char ex_dirp[RPCMNT_PATHLEN+1]; 79 }; 80 81 union grouptypes { 82 struct hostent *gt_hostent; 83 struct groupnames *gt_grpname; 84 #ifdef ISO 85 struct sockaddr_iso *gt_isoaddr; 86 #endif 87 }; 88 89 struct grouplist { 90 int type; 91 int exflags; 92 struct ucred anoncr; 93 union grouptypes gr_ptr; 94 struct grouplist *gr_next; 95 }; 96 97 struct al_mnt { 98 struct al_mnt *al_next; 99 fsid_t al_mnted; 100 }; 101 102 struct groupnames { 103 char gn_name[RPCMNT_NAMELEN+1]; 104 struct grouplist *gn_glist; 105 struct groupnames *gn_next; 106 }; 107 108 /* Global defs */ 109 int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist(); 110 void get_exportlist(), send_umntall(), nextfield(), do_opt(); 111 void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp(); 112 void get_group(), get_host(), do_group(); 113 char *realpath(); 114 #ifdef ISO 115 struct iso_addr *iso_addr(); 116 #endif 117 struct exportlist exphead; 118 struct mountlist *mlhead; 119 struct groupnames *grpnames; 120 char exname[MAXPATHLEN]; 121 struct ucred def_anon = { 122 (u_short) 1, 123 (uid_t) -2, 124 1, 125 (gid_t) -2, 126 }; 127 int root_only = 1; 128 extern int errno; 129 struct al_mnt *al_head = (struct al_mnt *)0; 130 #ifdef DEBUG 131 int debug = 1; 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 hpe->h_name = (char *)malloc(sizeof(DEF_NAME)+1); 686 if (hpe->h_name == NULL) { 687 syslog(LOG_ERR,"No more memory: mountd Failed"); 688 exit(2); 689 } 690 strcpy(hpe->h_name,DEF_NAME); 691 hpe->h_addrtype = AF_INET; 692 hpe->h_length = sizeof (u_long); 693 hpe->h_addr_list = INADDR_ANY; 694 tgrp->gr_ptr.gt_hostent = hpe; 695 tgrp->gr_next = ep->ex_groups; 696 ep->ex_groups = tgrp; 697 } 698 } 699 grp = ep->ex_groups; 700 while (grp != NULL) { 701 exflags = grp->exflags; 702 anoncr = grp->anoncr; 703 if (grp->type == MNT_GROUP) { 704 tgrp = grp->gr_ptr.gt_grpname->gn_glist; 705 while(tgrp != NULL) { 706 if (do_mount(ep, tgrp, exflags, &anoncr, 707 dirplen) == FALSE) 708 goto nextline; 709 tgrp = tgrp->gr_next; 710 } 711 } else { 712 if (do_mount(ep, grp, exflags, &anoncr, dirplen) 713 == FALSE) 714 goto nextline; 715 } 716 grp = grp->gr_next; 717 } 718 if (cp) 719 *cp = savedc; 720 if (ep->ex_prev == (struct exportlist *)0) { 721 ep->ex_next = exphead.ex_next; 722 ep->ex_prev = &exphead; 723 if (ep->ex_next != NULL) 724 ep->ex_next->ex_prev = ep; 725 exphead.ex_next = ep; 726 } 727 nextline: 728 ; 729 } 730 fclose(inf); 731 return; 732 err: 733 syslog(LOG_ERR, "No more memory: mountd Failed"); 734 exit(2); 735 } 736 737 do_mount(ep, grp, exflags, anoncrp, dirplen) 738 struct exportlist *ep; 739 struct grouplist *grp; 740 int exflags, dirplen; 741 struct ucred *anoncrp; 742 { 743 int done, found; 744 register u_long **addrp; 745 struct sockaddr_in sin; 746 struct statfs stfsbuf; 747 struct ufs_args args, targs; 748 struct al_mnt *al_mp; 749 char *cp, savedc; 750 751 args.fspec = 0; 752 args.exflags = exflags; 753 args.anon = *anoncrp; 754 sin.sin_family = AF_INET; 755 sin.sin_port = 0; 756 sin.sin_len = sizeof(sin); 757 if (grp->type == MNT_HOST) 758 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 759 done = FALSE; 760 while(!done) { 761 if (grp->type == MNT_HOST) { 762 if (!strcmp(grp->gr_ptr.gt_hostent->h_name, DEF_NAME)) 763 sin.sin_addr.s_addr = INADDR_ANY; 764 else 765 sin.sin_addr.s_addr = **addrp; 766 args.saddr = (struct sockaddr *)&sin; 767 args.slen = sizeof(sin); 768 #ifdef ISO 769 } else if (grp->type == MNT_ISO) { 770 args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 771 args.slen = sizeof (struct sockaddr_iso); 772 #endif /* ISO */ 773 } else { 774 syslog(LOG_ERR, "Bad grouptype"); 775 free_exp(ep); 776 return (FALSE); 777 } 778 if (statfs(ep->ex_dirp, &stfsbuf) < 0) { 779 if (debug) { 780 fprintf(stderr,"statfs failed.\n"); 781 } 782 syslog(LOG_ERR, "Invalid path: %s", ep->ex_dirp); 783 free_exp(ep); 784 return(FALSE); 785 } 786 found = FALSE; 787 for (al_mp = al_head; al_mp && !found; al_mp = al_mp->al_next) 788 if (al_mp->al_mnted.val[0] == stfsbuf.f_fsid.val[0] && 789 al_mp->al_mnted.val[1] == stfsbuf.f_fsid.val[1]) 790 found = TRUE; 791 if (!found) { 792 /* first time for fs, so must send a MNT_DELEXPORT 793 * to clear the old export list held in the kernel 794 * for this fs. 795 */ 796 al_mp = (struct al_mnt *)malloc(sizeof (struct al_mnt)); 797 al_mp->al_mnted = stfsbuf.f_fsid; 798 al_mp->al_next = al_head; 799 al_head = al_mp; 800 targs.fspec = 0; 801 targs.exflags = MNT_DELEXPORT; 802 cp = (char *)0; 803 while (mount(MOUNT_UFS, ep->ex_dirp, 804 stfsbuf.f_flags | MNT_UPDATE, &targs) < 0) { 805 if (debug) { 806 fprintf(stderr, 807 "tried [%s][%d]\n", 808 ep->ex_dirp,errno); 809 } 810 if (cp == NULL) 811 cp = ep->ex_dirp + dirplen - 1; 812 else 813 *cp = savedc; 814 cp--; 815 /* back up over the last component */ 816 while (*cp == '/' && cp > ep->ex_dirp) 817 cp--; 818 while (*(cp - 1) != '/' && cp > ep->ex_dirp) 819 cp--; 820 if (cp == ep->ex_dirp) { 821 if (debug) { 822 fprintf(stderr,"mnt unsucc\n"); 823 } 824 syslog(LOG_ERR, 825 "Can't export %s", ep->ex_dirp); 826 free_exp(ep); 827 return(FALSE); 828 } 829 savedc = *cp; 830 *cp = '\0'; 831 } 832 if (cp != NULL) { 833 *cp = savedc; 834 } 835 } 836 cp = (char *)0; 837 while (mount(MOUNT_UFS, ep->ex_dirp, 838 stfsbuf.f_flags | MNT_UPDATE, &args) < 0) { 839 if (errno == EPERM) { 840 syslog(LOG_ERR, 841 "Can't change attributes for %s.\n", 842 ep->ex_dirp); 843 if (cp != NULL) 844 *cp = savedc; 845 break; 846 } 847 if (cp == NULL) 848 cp = ep->ex_dirp + dirplen - 1; 849 else 850 *cp = savedc; 851 cp--; 852 /* back up over the last component */ 853 while (*cp == '/' && cp > ep->ex_dirp) 854 cp--; 855 while (*(cp - 1) != '/' && cp > ep->ex_dirp) 856 cp--; 857 if (cp == ep->ex_dirp) { 858 if (debug) { 859 fprintf(stderr,"mnt unsucc\n"); 860 } 861 syslog(LOG_ERR, "Can't export %s", ep->ex_dirp); 862 free_exp(ep); 863 return(FALSE); 864 } 865 savedc = *cp; 866 *cp = '\0'; 867 } 868 if (addrp == NULL) 869 done = TRUE; 870 else { 871 ++addrp; 872 if (*addrp == NULL) 873 done = TRUE; 874 } 875 if (cp != NULL) 876 *cp = savedc; 877 } 878 return(TRUE); 879 } 880 881 882 /* 883 * Parse out the next white space separated field 884 */ 885 void 886 nextfield(cp, endcp) 887 char **cp; 888 char **endcp; 889 { 890 register char *p; 891 892 p = *cp; 893 while (*p == ' ' || *p == '\t') 894 p++; 895 if (*p == '\n' || *p == '\0') { 896 *cp = *endcp = p; 897 return; 898 } 899 *cp = p++; 900 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 901 p++; 902 *endcp = p; 903 } 904 905 /* 906 * Parse the option string 907 */ 908 void 909 do_opt(cpopt, ep, exflagsp, cr) 910 register char *cpopt; 911 struct exportlist *ep; 912 int *exflagsp; 913 struct ucred *cr; 914 { 915 register char *cpoptarg, *cpoptend; 916 int allflag; 917 918 while (cpopt && *cpopt) { 919 if (cpoptend = index(cpopt, ',')) 920 *cpoptend++ = '\0'; 921 if (cpoptarg = index(cpopt, '=')) 922 *cpoptarg++ = '\0'; 923 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 924 *exflagsp |= MNT_EXRDONLY; 925 } else if ((!strcmp(cpopt, "root") || !strcmp(cpopt, "r") || 926 !(allflag = strcmp(cpopt, "allanon"))) && cpoptarg) { 927 parsecred(cpoptarg, cr); 928 if (allflag == 0) 929 *exflagsp |= MNT_EXPORTANON; 930 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 931 *exflagsp |= MNT_EXKERB; 932 } else 933 syslog(LOG_ERR, "opt %s ignored for %s", cpopt, 934 ep->ex_dirp); 935 cpopt = cpoptend; 936 } 937 } 938 939 /* 940 * Parse a description of a credential. 941 */ 942 parsecred(namelist, cr) 943 char *namelist; 944 register struct ucred *cr; 945 { 946 register char *name; 947 register int cnt; 948 char *names; 949 struct passwd *pw; 950 struct group *gr; 951 int ngroups, groups[NGROUPS + 1]; 952 953 /* 954 * Set up the unpriviledged user. 955 */ 956 cr->cr_ref = 1; 957 cr->cr_uid = -2; 958 cr->cr_groups[0] = -2; 959 cr->cr_ngroups = 1; 960 /* 961 * Get the user's password table entry. 962 */ 963 names = strsep(&namelist, " \t\n"); 964 name = strsep(&names, ":"); 965 if (isdigit(*name) || *name == '-') 966 pw = getpwuid(atoi(name)); 967 else 968 pw = getpwnam(name); 969 /* 970 * Credentials specified as those of a user. 971 */ 972 if (names == NULL) { 973 if (pw == NULL) { 974 syslog(LOG_ERR, "Unknown user: %s\n", name); 975 return; 976 } 977 cr->cr_uid = pw->pw_uid; 978 ngroups = NGROUPS + 1; 979 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 980 syslog(LOG_ERR, "Too many groups\n"); 981 /* 982 * Convert from int's to gid_t's and compress out duplicate 983 */ 984 cr->cr_ngroups = ngroups - 1; 985 cr->cr_groups[0] = groups[0]; 986 for (cnt = 2; cnt < ngroups; cnt++) 987 cr->cr_groups[cnt - 1] = groups[cnt]; 988 return; 989 } 990 /* 991 * Explicit credential specified as a colon separated list: 992 * uid:gid:gid:... 993 */ 994 if (pw != NULL) 995 cr->cr_uid = pw->pw_uid; 996 else if (isdigit(*name) || *name == '-') 997 cr->cr_uid = atoi(name); 998 else { 999 syslog(LOG_ERR, "Unknown user: %s\n", name); 1000 return; 1001 } 1002 cr->cr_ngroups = 0; 1003 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 1004 name = strsep(&names, ":"); 1005 if (isdigit(*name) || *name == '-') { 1006 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 1007 } else { 1008 if ((gr = getgrnam(name)) == NULL) { 1009 syslog(LOG_ERR, "Unknown group: %s\n", name); 1010 continue; 1011 } 1012 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 1013 } 1014 } 1015 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 1016 syslog(LOG_ERR, "Too many groups\n"); 1017 } 1018 1019 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 1020 /* 1021 * Routines that maintain the remote mounttab 1022 */ 1023 void 1024 get_mountlist() 1025 { 1026 register struct mountlist *mlp, **mlpp; 1027 register char *eos, *dirp; 1028 int len; 1029 char str[STRSIZ]; 1030 FILE *mlfile; 1031 1032 if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) && 1033 ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) { 1034 syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 1035 return; 1036 } 1037 mlpp = &mlhead; 1038 while (fgets(str, STRSIZ, mlfile) != NULL) { 1039 if ((dirp = index(str, '\t')) == NULL && 1040 (dirp = index(str, ' ')) == NULL) 1041 continue; 1042 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1043 len = dirp-str; 1044 if (len > RPCMNT_NAMELEN) 1045 len = RPCMNT_NAMELEN; 1046 bcopy(str, mlp->ml_host, len); 1047 mlp->ml_host[len] = '\0'; 1048 while (*dirp == '\t' || *dirp == ' ') 1049 dirp++; 1050 if ((eos = index(dirp, '\t')) == NULL && 1051 (eos = index(dirp, ' ')) == NULL && 1052 (eos = index(dirp, '\n')) == NULL) 1053 len = strlen(dirp); 1054 else 1055 len = eos-dirp; 1056 if (len > RPCMNT_PATHLEN) 1057 len = RPCMNT_PATHLEN; 1058 bcopy(dirp, mlp->ml_dirp, len); 1059 mlp->ml_dirp[len] = '\0'; 1060 mlp->ml_next = (struct mountlist *)0; 1061 *mlpp = mlp; 1062 mlpp = &mlp->ml_next; 1063 } 1064 fclose(mlfile); 1065 } 1066 1067 void 1068 del_mlist(hostp, dirp) 1069 register char *hostp, *dirp; 1070 { 1071 register struct mountlist *mlp, **mlpp; 1072 FILE *mlfile; 1073 int fnd = 0; 1074 1075 mlpp = &mlhead; 1076 mlp = mlhead; 1077 while (mlp) { 1078 if (!strcmp(mlp->ml_host, hostp) && 1079 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 1080 fnd = 1; 1081 *mlpp = mlp->ml_next; 1082 free((caddr_t)mlp); 1083 } 1084 mlpp = &mlp->ml_next; 1085 mlp = mlp->ml_next; 1086 } 1087 if (fnd) { 1088 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 1089 syslog(LOG_WARNING,"Can't update %s", _PATH_RMOUNTLIST); 1090 return; 1091 } 1092 mlp = mlhead; 1093 while (mlp) { 1094 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1095 mlp = mlp->ml_next; 1096 } 1097 fclose(mlfile); 1098 } 1099 } 1100 1101 void 1102 add_mlist(hostp, dirp) 1103 register char *hostp, *dirp; 1104 { 1105 register struct mountlist *mlp, **mlpp; 1106 FILE *mlfile; 1107 1108 mlpp = &mlhead; 1109 mlp = mlhead; 1110 while (mlp) { 1111 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 1112 return; 1113 mlpp = &mlp->ml_next; 1114 mlp = mlp->ml_next; 1115 } 1116 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1117 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 1118 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 1119 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 1120 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 1121 mlp->ml_next = (struct mountlist *)0; 1122 *mlpp = mlp; 1123 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 1124 syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST); 1125 return; 1126 } 1127 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1128 fclose(mlfile); 1129 } 1130 1131 /* 1132 * This function is called via. SIGTERM when the system is going down. 1133 * It sends a broadcast RPCMNT_UMNTALL. 1134 */ 1135 void 1136 send_umntall() 1137 { 1138 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 1139 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 1140 exit(0); 1141 } 1142 1143 umntall_each(resultsp, raddr) 1144 caddr_t resultsp; 1145 struct sockaddr_in *raddr; 1146 { 1147 return (1); 1148 } 1149 1150 /* 1151 * Free up an exports list component 1152 */ 1153 void 1154 free_exp(ep) 1155 register struct exportlist *ep; 1156 { 1157 register struct grouplist *grp; 1158 struct grouplist *grp2; 1159 1160 grp = ep->ex_groups; 1161 while (grp != NULL) { 1162 grp2 = grp; 1163 grp = grp->gr_next; 1164 free_grp(grp2); 1165 } 1166 free((caddr_t)ep); 1167 } 1168 1169 /* 1170 * Free up a group list. 1171 */ 1172 void 1173 free_grp(grp) 1174 register struct grouplist *grp; 1175 { 1176 register char **addrp; 1177 1178 if (grp->type == MNT_HOST) { 1179 addrp = grp->gr_ptr.gt_hostent->h_addr_list; 1180 while (addrp && *addrp) 1181 free(*addrp++); 1182 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 1183 free(grp->gr_ptr.gt_hostent->h_name); 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