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