fixmount.c revision 42633
1/* 2 * Copyright (c) 1997-1998 Erez Zadok 3 * Copyright (c) 1990 Jan-Simon Pendry 4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry at Imperial College, London. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgment: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * %W% (Berkeley) %G% 40 * 41 * $Id: fixmount.c,v 1.3 1998/11/14 03:13:31 obrien Exp $ 42 * 43 */ 44 45#ifdef HAVE_CONFIG_H 46# include <config.h> 47#endif /* HAVE_CONFIG_H */ 48#include <am_defs.h> 49 50#define CREATE_TIMEOUT 2 /* seconds */ 51#define CALL_TIMEOUT 5 /* seconds */ 52 53#ifndef INADDR_NONE 54# define INADDR_NONE 0xffffffff 55#endif /* not INADDR_NONE */ 56 57/* Constant defs */ 58#define ALL 1 59#define DIRS 2 60 61#define DODUMP 0x1 62#define DOEXPORTS 0x2 63#define DOREMOVE 0x4 64#define DOVERIFY 0x8 65#define DOREMALL 0x10 66 67extern int fixmount_check_mount(char *host, struct in_addr hostaddr, char *path); 68 69static char dir_path[NFS_MAXPATHLEN]; 70static char localhost[] = "localhost"; 71static char thishost[MAXHOSTNAMELEN + 1] = ""; 72static exports mntexports; 73static int quiet = 0; 74static int type = 0; 75static jmp_buf before_rpc; 76static mountlist mntdump; 77static struct in_addr thisaddr; 78static CLIENT *clnt_create_timeout(char *, struct timeval *); 79 80RETSIGTYPE create_timeout(int); 81int is_same_host(char *, char *, struct in_addr); 82int main(int, char *[]); 83int remove_all(CLIENT *, char *); 84int remove_mount(CLIENT *, char *, mountlist, int); 85void fix_rmtab(CLIENT *, char *, mountlist, int, int); 86void print_dump(mountlist); 87void usage(void); 88 89/* dummy variables */ 90#if 0 91char *progname; 92char hostname[MAXHOSTNAMELEN]; 93pid_t mypid; 94serv_state amd_state; 95int foreground, orig_umask; 96int debug_flags; 97#endif 98 99void 100usage(void) 101{ 102 fprintf(stderr, "usage: fixmount [-adervAqf] [-h hostname] host ...\n"); 103 exit(1); 104} 105 106 107/* 108 * Check hostname against other name and its IP address 109 */ 110int 111is_same_host(char *name1, char *name2, struct in_addr addr2) 112{ 113 if (strcasecmp(name1, name2) == 0) { 114 return 1; 115 } else if (addr2.s_addr == INADDR_NONE) { 116 return 0; 117 } else { 118 static char lasthost[MAXHOSTNAMELEN] = ""; 119 static struct in_addr addr1; 120 struct hostent *he; 121 122 /* 123 * To save nameserver lookups, and because this function 124 * is typically called repeatedly on the same names, 125 * cache the last lookup result and reuse it if possible. 126 */ 127 if (strcasecmp(name1, lasthost) == 0) { 128 return (addr1.s_addr == addr2.s_addr); 129 } else if (!(he = gethostbyname(name1))) { 130 return 0; 131 } else { 132 strncpy(lasthost, name1, sizeof(lasthost) - 1); 133 memcpy(&addr1, he->h_addr, sizeof(addr1)); 134 return (addr1.s_addr == addr2.s_addr); 135 } 136 } 137} 138 139 140/* 141 * Print the binary tree in inorder so that output is sorted. 142 */ 143void 144print_dump(mountlist mp) 145{ 146 if (mp == NULL) 147 return; 148 if (is_same_host(mp->ml_hostname, thishost, thisaddr)) { 149 switch (type) { 150 case ALL: 151 printf("%s:%s\n", mp->ml_hostname, mp->ml_directory); 152 break; 153 case DIRS: 154 printf("%s\n", mp->ml_directory); 155 break; 156 default: 157 printf("%s\n", mp->ml_hostname); 158 break; 159 }; 160 } 161 if (mp->ml_next) 162 print_dump(mp->ml_next); 163} 164 165 166/* 167 * remove entry from remote rmtab 168 */ 169int 170remove_mount(CLIENT *client, char *host, mountlist ml, int fixit) 171{ 172 enum clnt_stat estat; 173 struct timeval tv; 174 char *pathp = dir_path; 175 176 strncpy(dir_path, ml->ml_directory, sizeof(dir_path)); 177 178 if (!fixit) { 179 printf("%s: bogus mount %s:%s\n", host, ml->ml_hostname, ml->ml_directory); 180 fflush(stdout); 181 } else { 182 printf("%s: removing %s:%s\n", host, ml->ml_hostname, ml->ml_directory); 183 fflush(stdout); 184 185 tv.tv_sec = CALL_TIMEOUT; 186 tv.tv_usec = 0; 187 188 if ((estat = clnt_call(client, 189 MOUNTPROC_UMNT, 190 (XDRPROC_T_TYPE) xdr_dirpath, 191 (char *) &pathp, 192 (XDRPROC_T_TYPE) xdr_void, 193 (char *) 0, 194 tv)) != RPC_SUCCESS) { 195 fprintf(stderr, "%s:%s MOUNTPROC_UMNT: ", 196 host, ml->ml_directory); 197 clnt_perrno(estat); 198 fflush(stderr); 199 return -1; 200 } 201 } 202 return 0; 203} 204 205 206/* 207 * fix mount list on remote host 208 */ 209void 210fix_rmtab(CLIENT *client, char *host, mountlist mp, int fixit, int force) 211{ 212 mountlist p; 213 struct hostent *he; 214 struct in_addr hostaddr; 215 216 /* 217 * Obtain remote address for comparisons 218 */ 219 if ((he = gethostbyname(host))) { 220 memcpy(&hostaddr, he->h_addr, sizeof(hostaddr)); 221 } else { 222 hostaddr.s_addr = INADDR_NONE; 223 } 224 225 for (p = mp; p; p = p->ml_next) { 226 if (is_same_host(p->ml_hostname, thishost, thisaddr)) { 227 if (force || !fixmount_check_mount(host, hostaddr, p->ml_directory)) 228 remove_mount(client, host, p, fixit); 229 } 230 } 231} 232 233 234/* 235 * remove all entries from remote rmtab 236 */ 237int 238remove_all(CLIENT *client, char *host) 239{ 240 enum clnt_stat estat; 241 struct timeval tv; 242 243 printf("%s: removing ALL\n", host); 244 fflush(stdout); 245 246 tv.tv_sec = CALL_TIMEOUT; 247 tv.tv_usec = 0; 248 249 if ((estat = clnt_call(client, 250 MOUNTPROC_UMNTALL, 251 (XDRPROC_T_TYPE) xdr_void, 252 (char *) 0, 253 (XDRPROC_T_TYPE) xdr_void, 254 (char *) 0, 255 tv)) != RPC_SUCCESS) { 256 /* 257 * RPC_SYSTEMERROR is returned even if all went well 258 */ 259 if (estat != RPC_SYSTEMERROR) { 260 fprintf(stderr, "%s MOUNTPROC_UMNTALL: ", host); 261 clnt_perrno(estat); 262 fflush(stderr); 263 return -1; 264 } 265 } 266 267 return 0; 268} 269 270 271/* 272 * This command queries the NFS mount daemon for it's mount list and/or 273 * it's exports list and prints them out. 274 * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" 275 * for detailed information on the protocol. 276 */ 277int 278main(int argc, char *argv[]) 279{ 280 AUTH *auth; 281 CLIENT *client; 282 char *host; 283 enum clnt_stat estat; 284 exports exp; 285 extern char *optarg; 286 extern int optind; 287 groups grp; 288 int ch; 289 int force = 0; 290 int morethanone; 291 register int rpcs = 0; 292 struct timeval tv; 293 294 while ((ch = getopt(argc, argv, "adervAqfh:")) != -1) 295 switch ((char) ch) { 296 297 case 'a': 298 if (type == 0) { 299 type = ALL; 300 rpcs |= DODUMP; 301 } else 302 usage(); 303 break; 304 305 case 'd': 306 if (type == 0) { 307 type = DIRS; 308 rpcs |= DODUMP; 309 } else 310 usage(); 311 break; 312 313 case 'e': 314 rpcs |= DOEXPORTS; 315 break; 316 317 case 'r': 318 rpcs |= DOREMOVE; 319 break; 320 321 case 'A': 322 rpcs |= DOREMALL; 323 break; 324 325 case 'v': 326 rpcs |= DOVERIFY; 327 break; 328 329 case 'q': 330 quiet = 1; 331 break; 332 333 case 'f': 334 force = 1; 335 break; 336 337 case 'h': 338 strncpy(thishost, optarg, sizeof(thishost)); 339 thishost[sizeof(thishost) - 1] = '\0'; 340 break; 341 342 case '?': 343 default: 344 usage(); 345 } 346 347 if (optind == argc) 348 usage(); 349 350 if (rpcs == 0) 351 rpcs = DODUMP; 352 353 if (!*thishost) { 354 struct hostent *he; 355 356 if (gethostname(thishost, sizeof(thishost)) < 0) { 357 perror("gethostname"); 358 exit(1); 359 } 360 thishost[sizeof(thishost) - 1] = '\0'; 361 362 /* 363 * We need the hostname as it appears to the other side's 364 * mountd, so get our own hostname by reverse address 365 * resolution. 366 */ 367 if (!(he = gethostbyname(thishost))) { 368 fprintf(stderr, "gethostbyname failed on %s\n", 369 thishost); 370 exit(1); 371 } 372 memcpy(&thisaddr, he->h_addr, sizeof(thisaddr)); 373 if (!(he = gethostbyaddr((char *) &thisaddr, sizeof(thisaddr), 374 he->h_addrtype))) { 375 fprintf(stderr, "gethostbyaddr failed on %s\n", 376 inet_ntoa(thisaddr)); 377 exit(1); 378 } 379 strncpy(thishost, he->h_name, sizeof(thishost)); 380 thishost[sizeof(thishost) - 1] = '\0'; 381 } else { 382 thisaddr.s_addr = INADDR_NONE; 383 } 384 385 if (!(auth = authunix_create_default())) { 386 fprintf(stderr, "couldn't create authentication handle\n"); 387 exit(1); 388 } 389 morethanone = (optind + 1 < argc); 390 391 for (; optind < argc; optind++) { 392 393 host = argv[optind]; 394 tv.tv_sec = CREATE_TIMEOUT; 395 tv.tv_usec = 0; 396 397 if (!(client = clnt_create_timeout(host, &tv))) 398 continue; 399 400 client->cl_auth = auth; 401 tv.tv_sec = CALL_TIMEOUT; 402 tv.tv_usec = 0; 403 404 if (rpcs & (DODUMP | DOREMOVE | DOVERIFY)) 405 if ((estat = clnt_call(client, 406 MOUNTPROC_DUMP, 407 (XDRPROC_T_TYPE) xdr_void, 408 (char *) 0, 409 (XDRPROC_T_TYPE) xdr_mountlist, 410 (char *) &mntdump, 411 tv)) != RPC_SUCCESS) { 412 fprintf(stderr, "%s: MOUNTPROC_DUMP: ", host); 413 clnt_perrno(estat); 414 fflush(stderr); 415 mntdump = NULL; 416 goto next; 417 } 418 if (rpcs & DOEXPORTS) 419 if ((estat = clnt_call(client, 420 MOUNTPROC_EXPORT, 421 (XDRPROC_T_TYPE) xdr_void, 422 (char *) 0, 423 (XDRPROC_T_TYPE) xdr_exports, 424 (char *) &mntexports, 425 tv)) != RPC_SUCCESS) { 426 fprintf(stderr, "%s: MOUNTPROC_EXPORT: ", host); 427 clnt_perrno(estat); 428 fflush(stderr); 429 mntexports = NULL; 430 goto next; 431 } 432 433 /* Now just print out the results */ 434 if ((rpcs & (DODUMP | DOEXPORTS)) && 435 morethanone) { 436 printf(">>> %s <<<\n", host); 437 fflush(stdout); 438 } 439 440 if (rpcs & DODUMP) { 441 print_dump(mntdump); 442 } 443 444 if (rpcs & DOEXPORTS) { 445 exp = mntexports; 446 while (exp) { 447 printf("%-35s", exp->ex_dir); 448 grp = exp->ex_groups; 449 if (grp == NULL) { 450 printf("Everyone\n"); 451 } else { 452 while (grp) { 453 printf("%s ", grp->gr_name); 454 grp = grp->gr_next; 455 } 456 printf("\n"); 457 } 458 exp = exp->ex_next; 459 } 460 } 461 462 if (rpcs & DOVERIFY) 463 fix_rmtab(client, host, mntdump, 0, force); 464 465 if (rpcs & DOREMOVE) 466 fix_rmtab(client, host, mntdump, 1, force); 467 468 if (rpcs & DOREMALL) 469 remove_all(client, host); 470 471 next: 472 if (mntdump) 473 (void) clnt_freeres(client, 474 (XDRPROC_T_TYPE) xdr_mountlist, 475 (char *) &mntdump); 476 if (mntexports) 477 (void) clnt_freeres(client, 478 (XDRPROC_T_TYPE) xdr_exports, 479 (char *) &mntexports); 480 481 clnt_destroy(client); 482 } 483 exit(0); 484 return 0; /* should never reach here */ 485} 486 487 488RETSIGTYPE 489create_timeout(int sig) 490{ 491 signal(SIGALRM, SIG_DFL); 492 longjmp(before_rpc, 1); 493} 494 495 496#ifndef HAVE_TRANSPORT_TYPE_TLI 497/* 498 * inetresport creates a datagram socket and attempts to bind it to a 499 * secure port. 500 * returns: The bound socket, or -1 to indicate an error. 501 */ 502static int 503inetresport(int ty) 504{ 505 int alport; 506 struct sockaddr_in addr; 507 int fd; 508 509 /* Use internet address family */ 510 addr.sin_family = AF_INET; 511 addr.sin_addr.s_addr = INADDR_ANY; 512 if ((fd = socket(AF_INET, ty, 0)) < 0) 513 return -1; 514 515 for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) { 516 addr.sin_port = htons((u_short) alport); 517 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) 518 return fd; 519 if (errno != EADDRINUSE) { 520 close(fd); 521 return -1; 522 } 523 } 524 close(fd); 525 errno = EAGAIN; 526 return -1; 527} 528 529 530/* 531 * Privsock() calls inetresport() to attempt to bind a socket to a secure 532 * port. If inetresport() fails, privsock returns a magic socket number which 533 * indicates to RPC that it should make its own socket. 534 * returns: A privileged socket # or RPC_ANYSOCK. 535 */ 536static int 537privsock(int ty) 538{ 539 int sock = inetresport(ty); 540 541 if (sock < 0) { 542 errno = 0; 543 /* Couldn't get a secure port, let RPC make an insecure one */ 544 sock = RPC_ANYSOCK; 545 } 546 return sock; 547} 548#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 549 550 551static CLIENT * 552clnt_create_timeout(char *host, struct timeval *tvp) 553{ 554 CLIENT *clnt; 555 struct sockaddr_in host_addr; 556 struct hostent *hp; 557#ifndef HAVE_TRANSPORT_TYPE_TLI 558 int s; 559#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 560 561 if (setjmp(before_rpc)) { 562 if (!quiet) { 563 fprintf(stderr, "%s: ", host); 564 clnt_perrno(RPC_TIMEDOUT); 565 fprintf(stderr, "\n"); 566 fflush(stderr); 567 } 568 return NULL; 569 } 570 signal(SIGALRM, create_timeout); 571 ualarm(tvp->tv_sec * 1000000 + tvp->tv_usec, 0); 572 573 /* 574 * Get address of host 575 */ 576 if ((hp = gethostbyname(host)) == 0 && !STREQ(host, localhost)) { 577 fprintf(stderr, "can't get address of %s\n", host); 578 return NULL; 579 } 580 memset(&host_addr, 0, sizeof host_addr); 581 host_addr.sin_family = AF_INET; 582 if (hp) { 583 memmove((voidp) &host_addr.sin_addr, (voidp) hp->h_addr, 584 sizeof(host_addr.sin_addr)); 585 } else { 586 /* fake "localhost" */ 587 host_addr.sin_addr.s_addr = htonl(0x7f000001); 588 } 589 590#ifdef HAVE_TRANSPORT_TYPE_TLI 591 /* try TCP first (in case return data is large), then UDP */ 592 clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "tcp"); 593 if (!clnt) 594 clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "udp"); 595#else /* not HAVE_TRANSPORT_TYPE_TLI */ 596 s = RPC_ANYSOCK; 597 clnt = clnttcp_create(&host_addr, MOUNTPROG, MOUNTVERS, &s, 0, 0); 598 if (!clnt) { 599 /* XXX: do we need to close(s) ? */ 600 s = privsock(SOCK_DGRAM); 601 clnt = clntudp_create(&host_addr, MOUNTPROG, MOUNTVERS, *tvp, &s); 602 } 603#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 604 605 if (!clnt) { 606 ualarm(0, 0); 607 if (!quiet) { 608 clnt_pcreateerror(host); 609 fflush(stderr); 610 } 611 return NULL; 612 } 613 614 ualarm(0, 0); 615 return clnt; 616} 617