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