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