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 * 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.8 (Berkeley) 06/01/90"; 19 #endif not lint 20 21 #include <sys/param.h> 22 #include <sys/ioctl.h> 23 #include <sys/stat.h> 24 #include <sys/file.h> 25 #include <sys/mount.h> 26 #include <sys/socket.h> 27 #include <sys/errno.h> 28 #include <sys/signal.h> 29 #include <stdio.h> 30 #include <string.h> 31 #include <syslog.h> 32 #include <netdb.h> 33 #include <rpc/rpc.h> 34 #include <rpc/pmap_clnt.h> 35 #include <rpc/pmap_prot.h> 36 #include <nfs/rpcv2.h> 37 #include <nfs/nfsv2.h> 38 #include "pathnames.h" 39 40 struct ufid { 41 u_short ufid_len; 42 ino_t ufid_ino; 43 long ufid_gen; 44 }; 45 /* 46 * Structures for keeping the mount list and export list 47 */ 48 struct mountlist { 49 char ml_host[RPCMNT_NAMELEN+1]; 50 char ml_dirp[RPCMNT_PATHLEN+1]; 51 }; 52 53 struct exportlist { 54 struct exportlist *ex_next; 55 struct exportlist *ex_prev; 56 struct grouplist *ex_groups; 57 int ex_rootuid; 58 int ex_exflags; 59 char ex_dirp[RPCMNT_PATHLEN+1]; 60 }; 61 62 struct grouplist { 63 struct grouplist *gr_next; 64 struct hostent *gr_hp; 65 }; 66 67 /* Global defs */ 68 int xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist(); 69 int mntsrv(), get_exportlist(); 70 struct exportlist exphead; 71 int mlfile; 72 char exname[MAXPATHLEN]; 73 int def_rootuid = -2; 74 extern int errno; 75 #ifdef DEBUG 76 int debug = 1; 77 #else 78 int debug = 0; 79 #endif 80 81 /* 82 * Mountd server for NFS mount protocol as described in: 83 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 84 * The optional argument is the exports file name 85 * default: _PATH_EXPORTS 86 */ 87 main(argc, argv) 88 int argc; 89 char *argv[]; 90 { 91 SVCXPRT *transp; 92 93 if (debug == 0) { 94 if (fork()) 95 exit(0); 96 { int s; 97 for (s = 0; s < 10; s++) 98 (void) close(s); 99 } 100 (void) open("/", O_RDONLY); 101 (void) dup2(0, 1); 102 (void) dup2(0, 2); 103 { int tt = open("/dev/tty", O_RDWR); 104 if (tt > 0) { 105 ioctl(tt, TIOCNOTTY, (char *)0); 106 close(tt); 107 } 108 } 109 (void) setpgrp(0, 0); 110 signal(SIGTSTP, SIG_IGN); 111 signal(SIGTTIN, SIG_IGN); 112 signal(SIGTTOU, SIG_IGN); 113 signal(SIGINT, SIG_IGN); 114 signal(SIGQUIT, SIG_IGN); 115 signal(SIGTERM, SIG_IGN); 116 } 117 openlog("mountd:", LOG_PID, LOG_DAEMON); 118 exphead.ex_next = exphead.ex_prev = (struct exportlist *)0; 119 if (argc == 2) { 120 strncpy(exname, argv[1], MAXPATHLEN-1); 121 exname[MAXPATHLEN-1] = '\0'; 122 } else 123 strcpy(exname, _PATH_EXPORTS); 124 get_exportlist(); 125 signal(SIGHUP, get_exportlist); 126 { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 127 if (pidfile != NULL) { 128 fprintf(pidfile, "%d\n", getpid()); 129 fclose(pidfile); 130 } 131 } 132 if ((mlfile = open(_PATH_RMOUNTLIST, (O_RDWR|O_CREAT), 0600)) < 0) { 133 syslog(LOG_ERR, "Can't open mountlist file"); 134 exit(1); 135 } 136 if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 137 syslog(LOG_ERR, "Can't create socket"); 138 exit(1); 139 } 140 pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 141 if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP)) { 142 syslog(LOG_ERR, "Can't register mount"); 143 exit(1); 144 } 145 svc_run(); 146 syslog(LOG_ERR, "Mountd died"); 147 } 148 149 /* 150 * The mount rpc service 151 */ 152 mntsrv(rqstp, transp) 153 register struct svc_req *rqstp; 154 register SVCXPRT *transp; 155 { 156 register struct grouplist *grp; 157 register u_long **addrp; 158 register struct exportlist *ep; 159 struct mountlist ml; 160 nfsv2fh_t nfh; 161 struct authunix_parms *ucr; 162 struct stat stb; 163 struct hostent *hp; 164 u_long saddr; 165 char dirpath[RPCMNT_PATHLEN+1]; 166 int ok = 0; 167 int bad = ENOENT; 168 int omask; 169 uid_t uid = -2; 170 171 /* Get authorization */ 172 switch (rqstp->rq_cred.oa_flavor) { 173 case AUTH_UNIX: 174 ucr = (struct authunix_parms *)rqstp->rq_clntcred; 175 uid = ucr->aup_uid; 176 break; 177 case AUTH_NULL: 178 default: 179 break; 180 } 181 182 saddr = transp->xp_raddr.sin_addr.s_addr; 183 hp = (struct hostent *)0; 184 switch (rqstp->rq_proc) { 185 case NULLPROC: 186 if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 187 syslog(LOG_ERR, "Can't send reply"); 188 return; 189 case RPCMNT_MOUNT: 190 if (uid != 0) { 191 svcerr_weakauth(transp); 192 return; 193 } 194 if (!svc_getargs(transp, xdr_dir, dirpath)) { 195 svcerr_decode(transp); 196 return; 197 } 198 199 /* Check to see if it's a valid dirpath */ 200 if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) != 201 S_IFDIR) { 202 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 203 syslog(LOG_ERR, "Can't send reply"); 204 return; 205 } 206 207 /* Check in the exports list */ 208 omask = sigblock(sigmask(SIGHUP)); 209 ep = exphead.ex_next; 210 while (ep != NULL) { 211 if (!strcmp(ep->ex_dirp, dirpath)) { 212 grp = ep->ex_groups; 213 if (grp == NULL) 214 break; 215 216 /* Check for a host match */ 217 addrp = (u_long **)grp->gr_hp->h_addr_list; 218 for (;;) { 219 if (**addrp == saddr) 220 break; 221 if (*++addrp == NULL) 222 if (grp = grp->gr_next) { 223 addrp = (u_long **) 224 grp->gr_hp->h_addr_list; 225 } else { 226 bad = EACCES; 227 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 228 syslog(LOG_ERR, "Can't send reply"); 229 sigsetmask(omask); 230 return; 231 } 232 } 233 hp = grp->gr_hp; 234 break; 235 } 236 ep = ep->ex_next; 237 } 238 sigsetmask(omask); 239 if (ep == NULL) { 240 bad = EACCES; 241 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 242 syslog(LOG_ERR, "Can't send reply"); 243 return; 244 } 245 246 /* Get the file handle */ 247 bzero((caddr_t)&nfh, sizeof(nfh)); 248 if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 249 bad = errno; 250 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 251 syslog(LOG_ERR, "Can't send reply"); 252 return; 253 } 254 #ifdef notnow 255 nfh.fh_generic.fh_fid.fid_gen = htonl(nfh.fh_generic.fh_fid.fid_gen); 256 #endif 257 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 258 syslog(LOG_ERR, "Can't send reply"); 259 if (hp == NULL) 260 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 261 if (hp) { 262 if (!fnd_mnt(hp->h_name, dirpath)) { 263 strcpy(ml.ml_host, hp->h_name); 264 strcpy(ml.ml_dirp, dirpath); 265 write(mlfile, (caddr_t)&ml, sizeof(ml)); 266 } 267 } 268 return; 269 case RPCMNT_DUMP: 270 if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0)) 271 syslog(LOG_ERR, "Can't send reply"); 272 return; 273 case RPCMNT_UMOUNT: 274 if (uid != 0) { 275 svcerr_weakauth(transp); 276 return; 277 } 278 if (!svc_getargs(transp, xdr_dir, dirpath)) { 279 svcerr_decode(transp); 280 return; 281 } 282 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 283 if (hp && fnd_mnt(hp->h_name, dirpath)) { 284 ml.ml_host[0] = '\0'; 285 write(mlfile, (caddr_t)&ml, sizeof(ml)); 286 } 287 if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 288 syslog(LOG_ERR, "Can't send reply"); 289 return; 290 case RPCMNT_UMNTALL: 291 if (uid != 0) { 292 svcerr_weakauth(transp); 293 return; 294 } 295 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 296 if (hp) { 297 lseek(mlfile, (off_t)0, L_SET); 298 while (read(mlfile, (caddr_t)&ml, sizeof(ml)) == 299 sizeof(ml)) { 300 if (!strcmp(hp->h_name, ml.ml_host)) { 301 lseek(mlfile, (off_t)-sizeof(ml), 302 L_INCR); 303 ml.ml_host[0] = '\0'; 304 write(mlfile, (caddr_t)&ml, sizeof(ml)); 305 } 306 } 307 } 308 if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) 309 syslog(LOG_ERR, "Can't send reply"); 310 return; 311 case RPCMNT_EXPORT: 312 if (!svc_sendreply(transp, xdr_explist, (caddr_t)0)) 313 syslog(LOG_ERR, "Can't send reply"); 314 return; 315 default: 316 svcerr_noproc(transp); 317 return; 318 } 319 } 320 321 /* 322 * Xdr conversion for a dirpath string 323 */ 324 xdr_dir(xdrsp, dirp) 325 XDR *xdrsp; 326 char *dirp; 327 { 328 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 329 } 330 331 /* 332 * Xdr routine to generate fhstatus 333 */ 334 xdr_fhs(xdrsp, nfh) 335 XDR *xdrsp; 336 nfsv2fh_t *nfh; 337 { 338 int ok = 0; 339 340 if (!xdr_long(xdrsp, &ok)) 341 return (0); 342 return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 343 } 344 345 xdr_mlist(xdrsp, cp) 346 XDR *xdrsp; 347 caddr_t cp; 348 { 349 struct mountlist ml; 350 int true = 1; 351 int false = 0; 352 char *strp; 353 354 lseek(mlfile, (off_t)0, L_SET); 355 while (read(mlfile, (caddr_t)&ml, sizeof(ml)) == sizeof(ml)) { 356 if (ml.ml_host[0] != '\0') { 357 if (!xdr_bool(xdrsp, &true)) 358 return (0); 359 strp = &ml.ml_host[0]; 360 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 361 return (0); 362 strp = &ml.ml_dirp[0]; 363 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 364 return (0); 365 } 366 } 367 if (!xdr_bool(xdrsp, &false)) 368 return (0); 369 return (1); 370 } 371 372 /* 373 * Xdr conversion for export list 374 */ 375 xdr_explist(xdrsp, cp) 376 XDR *xdrsp; 377 caddr_t cp; 378 { 379 register struct exportlist *ep; 380 register struct grouplist *grp; 381 int true = 1; 382 int false = 0; 383 char *strp; 384 int omask; 385 386 omask = sigblock(sigmask(SIGHUP)); 387 ep = exphead.ex_next; 388 while (ep != NULL) { 389 if (!xdr_bool(xdrsp, &true)) 390 goto errout; 391 strp = &ep->ex_dirp[0]; 392 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 393 goto errout; 394 grp = ep->ex_groups; 395 while (grp != NULL) { 396 if (!xdr_bool(xdrsp, &true)) 397 goto errout; 398 strp = grp->gr_hp->h_name; 399 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 400 goto errout; 401 grp = grp->gr_next; 402 } 403 if (!xdr_bool(xdrsp, &false)) 404 goto errout; 405 ep = ep->ex_next; 406 } 407 sigsetmask(omask); 408 if (!xdr_bool(xdrsp, &false)) 409 return (0); 410 return (1); 411 errout: 412 sigsetmask(omask); 413 return (0); 414 } 415 416 #define LINESIZ 10240 417 char line[LINESIZ]; 418 419 /* 420 * Get the export list 421 */ 422 get_exportlist() 423 { 424 register struct hostent *hp, *nhp; 425 register char **addrp, **naddrp; 426 register int i; 427 register struct grouplist *grp, *grp2; 428 register struct exportlist *ep, *ep2; 429 struct ufs_args args; 430 FILE *inf; 431 char *cp, *endcp; 432 char savedc; 433 int len; 434 int rootuid, exflags; 435 436 /* 437 * First, get rid of the old list 438 */ 439 ep = exphead.ex_next; 440 while (ep != NULL) { 441 grp = ep->ex_groups; 442 while (grp != NULL) { 443 addrp = grp->gr_hp->h_addr_list; 444 while (*addrp) 445 free(*addrp++); 446 free((caddr_t)grp->gr_hp->h_addr_list); 447 free(grp->gr_hp->h_name); 448 free((caddr_t)grp->gr_hp); 449 grp2 = grp; 450 grp = grp->gr_next; 451 free((caddr_t)grp2); 452 } 453 ep2 = ep; 454 ep = ep->ex_next; 455 free((caddr_t)ep2); 456 } 457 458 /* 459 * Read in the exports file and build the list, calling 460 * exportfs() as we go along 461 */ 462 exphead.ex_next = exphead.ex_prev = (struct exportlist *)0; 463 if ((inf = fopen(exname, "r")) == NULL) { 464 syslog(LOG_ERR, "Can't open %s", exname); 465 exit(2); 466 } 467 while (fgets(line, LINESIZ, inf)) { 468 exflags = MNT_EXPORTED; 469 rootuid = def_rootuid; 470 cp = line; 471 nextfield(&cp, &endcp); 472 len = endcp-cp; 473 if (len <= RPCMNT_PATHLEN && len > 0) { 474 ep = (struct exportlist *)malloc(sizeof(*ep)); 475 ep->ex_next = ep->ex_prev = (struct exportlist *)0; 476 ep->ex_groups = (struct grouplist *)0; 477 bcopy(cp, ep->ex_dirp, len); 478 ep->ex_dirp[len] = '\0'; 479 } else 480 goto err; 481 cp = endcp; 482 nextfield(&cp, &endcp); 483 len = endcp-cp; 484 while (len > 0) { 485 savedc = *endcp; 486 *endcp = '\0'; 487 if (len <= RPCMNT_NAMELEN) { 488 if (*cp == '-') { 489 cp++; 490 switch (*cp) { 491 case 'o': 492 exflags |= MNT_EXRDONLY; 493 break; 494 case 'r': 495 if (*++cp == '=') 496 rootuid = atoi(++cp); 497 break; 498 default: 499 syslog(LOG_WARNING, 500 "Bad -%c option in %s", 501 *cp, exname); 502 break; 503 }; 504 } else if (hp = gethostbyname(cp)) { 505 grp = (struct grouplist *) 506 malloc(sizeof(struct grouplist)); 507 if (grp == NULL) 508 goto err; 509 nhp = grp->gr_hp = (struct hostent *) 510 malloc(sizeof(struct hostent)); 511 if (nhp == NULL) 512 goto err; 513 bcopy((caddr_t)hp, (caddr_t)nhp, 514 sizeof(struct hostent)); 515 i = strlen(hp->h_name)+1; 516 nhp->h_name = (char *)malloc(i); 517 if (nhp->h_name == NULL) 518 goto err; 519 bcopy(hp->h_name, nhp->h_name, i); 520 addrp = hp->h_addr_list; 521 i = 1; 522 while (*addrp++) 523 i++; 524 naddrp = nhp->h_addr_list = (char **) 525 malloc(i*sizeof(char *)); 526 if (naddrp == NULL) 527 goto err; 528 addrp = hp->h_addr_list; 529 while (*addrp) { 530 *naddrp = (char *) 531 malloc(hp->h_length); 532 bcopy(*addrp, *naddrp, 533 hp->h_length); 534 addrp++; 535 naddrp++; 536 } 537 *naddrp = (char *)0; 538 grp->gr_next = ep->ex_groups; 539 ep->ex_groups = grp; 540 } 541 } 542 cp = endcp; 543 *cp = savedc; 544 nextfield(&cp, &endcp); 545 len = endcp-cp; 546 } 547 args.fspec = 0; 548 args.exflags = exflags; 549 args.exroot = rootuid; 550 if (mount(MOUNT_UFS, ep->ex_dirp, MNT_UPDATE, &args) < 0) { 551 syslog(LOG_WARNING, "Can't export %s", ep->ex_dirp); 552 free((caddr_t)ep); 553 } else { 554 ep->ex_rootuid = rootuid; 555 ep->ex_exflags = exflags; 556 ep->ex_next = exphead.ex_next; 557 ep->ex_prev = &exphead; 558 if (ep->ex_next != NULL) 559 ep->ex_next->ex_prev = ep; 560 exphead.ex_next = ep; 561 } 562 } 563 fclose(inf); 564 return; 565 err: 566 syslog(LOG_ERR, "Bad Exports File, mountd Failed"); 567 exit(2); 568 } 569 570 /* 571 * Parse out the next white space separated field 572 */ 573 nextfield(cp, endcp) 574 char **cp; 575 char **endcp; 576 { 577 register char *p; 578 579 p = *cp; 580 while (*p == ' ' || *p == '\t') 581 p++; 582 if (*p == '\n' || *p == '\0') { 583 *cp = *endcp = p; 584 return; 585 } 586 *cp = p++; 587 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 588 p++; 589 *endcp = p; 590 } 591 592 /* 593 * Search the remote mounts file for a match. 594 * Iff found 595 * - set file offset to record and return TRUE 596 * else 597 * - set file offset to an unused record if found or eof otherwise 598 * and return FALSE 599 */ 600 fnd_mnt(host, dirp) 601 char *host; 602 char *dirp; 603 { 604 struct mountlist ml; 605 off_t off, pos; 606 607 off = -1; 608 pos = 0; 609 lseek(mlfile, (off_t)0, L_SET); 610 while (read(mlfile, (caddr_t)&ml, sizeof(ml)) == sizeof(ml)) { 611 if (!strcmp(host, ml.ml_host) && !strcmp(dirp, ml.ml_dirp)) { 612 lseek(mlfile, (off_t)-sizeof(ml), L_INCR); 613 return (TRUE); 614 } else if (ml.ml_host[0] == '\0') { 615 off = pos; 616 } 617 pos += sizeof(ml); 618 } 619 if (off != -1) 620 lseek(mlfile, off, L_SET); 621 else 622 lseek(mlfile, (off_t)0, L_XTND); 623 return (FALSE); 624 } 625