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