fixmount.c revision 41145
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 acknowledgement: 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.2 1998/08/23 22:52:08 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 */ 90char *progname; 91char hostname[MAXHOSTNAMELEN]; 92int orig_umask, foreground, debug_flags; 93pid_t mypid; 94serv_state amd_state; 95 96void 97usage(void) 98{ 99 fprintf(stderr, "usage: fixmount [-adervAqf] [-h hostname] host ...\n"); 100 exit(1); 101} 102 103 104/* 105 * Check hostname against other name and its IP address 106 */ 107int 108is_same_host(char *name1, char *name2, struct in_addr addr2) 109{ 110 if (strcasecmp(name1, name2) == 0) { 111 return 1; 112 } else if (addr2.s_addr == INADDR_NONE) { 113 return 0; 114 } else { 115 static char lasthost[MAXHOSTNAMELEN] = ""; 116 static struct in_addr addr1; 117 struct hostent *he; 118 119 /* 120 * To save nameserver lookups, and because this function 121 * is typically called repeatedly on the same names, 122 * cache the last lookup result and reuse it if possible. 123 */ 124 if (strcasecmp(name1, lasthost) == 0) { 125 return (addr1.s_addr == addr2.s_addr); 126 } else if (!(he = gethostbyname(name1))) { 127 return 0; 128 } else { 129 strncpy(lasthost, name1, sizeof(lasthost) - 1); 130 memcpy(&addr1, he->h_addr, sizeof(addr1)); 131 return (addr1.s_addr == addr2.s_addr); 132 } 133 } 134} 135 136 137/* 138 * Print the binary tree in inorder so that output is sorted. 139 */ 140void 141print_dump(mountlist mp) 142{ 143 if (mp == NULL) 144 return; 145 if (is_same_host(mp->ml_hostname, thishost, thisaddr)) { 146 switch (type) { 147 case ALL: 148 printf("%s:%s\n", mp->ml_hostname, mp->ml_directory); 149 break; 150 case DIRS: 151 printf("%s\n", mp->ml_directory); 152 break; 153 default: 154 printf("%s\n", mp->ml_hostname); 155 break; 156 }; 157 } 158 if (mp->ml_next) 159 print_dump(mp->ml_next); 160} 161 162 163/* 164 * remove entry from remote rmtab 165 */ 166int 167remove_mount(CLIENT *client, char *host, mountlist ml, int fixit) 168{ 169 enum clnt_stat estat; 170 struct timeval tv; 171 char *pathp = dir_path; 172 173 strncpy(dir_path, ml->ml_directory, sizeof(dir_path)); 174 175 if (!fixit) { 176 printf("%s: bogus mount %s:%s\n", host, ml->ml_hostname, ml->ml_directory); 177 fflush(stdout); 178 } else { 179 printf("%s: removing %s:%s\n", host, ml->ml_hostname, ml->ml_directory); 180 fflush(stdout); 181 182 tv.tv_sec = CALL_TIMEOUT; 183 tv.tv_usec = 0; 184 185 if ((estat = clnt_call(client, 186 MOUNTPROC_UMNT, 187 (XDRPROC_T_TYPE) xdr_dirpath, 188 (char *) &pathp, 189 (XDRPROC_T_TYPE) xdr_void, 190 (char *) 0, 191 tv)) != RPC_SUCCESS) { 192 fprintf(stderr, "%s:%s MOUNTPROC_UMNT: ", 193 host, ml->ml_directory); 194 clnt_perrno(estat); 195 fflush(stderr); 196 return -1; 197 } 198 } 199 return 0; 200} 201 202 203/* 204 * fix mount list on remote host 205 */ 206void 207fix_rmtab(CLIENT *client, char *host, mountlist mp, int fixit, int force) 208{ 209 mountlist p; 210 struct hostent *he; 211 struct in_addr hostaddr; 212 213 /* 214 * Obtain remote address for comparisons 215 */ 216 if ((he = gethostbyname(host))) { 217 memcpy(&hostaddr, he->h_addr, sizeof(hostaddr)); 218 } else { 219 hostaddr.s_addr = INADDR_NONE; 220 } 221 222 for (p = mp; p; p = p->ml_next) { 223 if (is_same_host(p->ml_hostname, thishost, thisaddr)) { 224 if (force || !fixmount_check_mount(host, hostaddr, p->ml_directory)) 225 remove_mount(client, host, p, fixit); 226 } 227 } 228} 229 230 231/* 232 * remove all entries from remote rmtab 233 */ 234int 235remove_all(CLIENT *client, char *host) 236{ 237 enum clnt_stat estat; 238 struct timeval tv; 239 240 printf("%s: removing ALL\n", host); 241 fflush(stdout); 242 243 tv.tv_sec = CALL_TIMEOUT; 244 tv.tv_usec = 0; 245 246 if ((estat = clnt_call(client, 247 MOUNTPROC_UMNTALL, 248 (XDRPROC_T_TYPE) xdr_void, 249 (char *) 0, 250 (XDRPROC_T_TYPE) xdr_void, 251 (char *) 0, 252 tv)) != RPC_SUCCESS) { 253 /* 254 * RPC_SYSTEMERROR is returned even if all went well 255 */ 256 if (estat != RPC_SYSTEMERROR) { 257 fprintf(stderr, "%s MOUNTPROC_UMNTALL: ", host); 258 clnt_perrno(estat); 259 fflush(stderr); 260 return -1; 261 } 262 } 263 264 return 0; 265} 266 267 268/* 269 * This command queries the NFS mount daemon for it's mount list and/or 270 * it's exports list and prints them out. 271 * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" 272 * for detailed information on the protocol. 273 */ 274int 275main(int argc, char *argv[]) 276{ 277 AUTH *auth; 278 CLIENT *client; 279 char *host; 280 enum clnt_stat estat; 281 exports exp; 282 extern char *optarg; 283 extern int optind; 284 groups grp; 285 int ch; 286 int force = 0; 287 int morethanone; 288 register int rpcs = 0; 289 struct timeval tv; 290 291 while ((ch = getopt(argc, argv, "adervAqfh:")) != -1) 292 switch ((char) ch) { 293 294 case 'a': 295 if (type == 0) { 296 type = ALL; 297 rpcs |= DODUMP; 298 } else 299 usage(); 300 break; 301 302 case 'd': 303 if (type == 0) { 304 type = DIRS; 305 rpcs |= DODUMP; 306 } else 307 usage(); 308 break; 309 310 case 'e': 311 rpcs |= DOEXPORTS; 312 break; 313 314 case 'r': 315 rpcs |= DOREMOVE; 316 break; 317 318 case 'A': 319 rpcs |= DOREMALL; 320 break; 321 322 case 'v': 323 rpcs |= DOVERIFY; 324 break; 325 326 case 'q': 327 quiet = 1; 328 break; 329 330 case 'f': 331 force = 1; 332 break; 333 334 case 'h': 335 strncpy(thishost, optarg, sizeof(thishost)); 336 thishost[sizeof(thishost) - 1] = '\0'; 337 break; 338 339 case '?': 340 default: 341 usage(); 342 } 343 344 if (optind == argc) 345 usage(); 346 347 if (rpcs == 0) 348 rpcs = DODUMP; 349 350 if (!*thishost) { 351 struct hostent *he; 352 353 if (gethostname(thishost, sizeof(thishost)) < 0) { 354 perror("gethostname"); 355 exit(1); 356 } 357 thishost[sizeof(thishost) - 1] = '\0'; 358 359 /* 360 * We need the hostname as it appears to the other side's 361 * mountd, so get our own hostname by reverse address 362 * resolution. 363 */ 364 if (!(he = gethostbyname(thishost))) { 365 fprintf(stderr, "gethostbyname failed on %s\n", 366 thishost); 367 exit(1); 368 } 369 memcpy(&thisaddr, he->h_addr, sizeof(thisaddr)); 370 if (!(he = gethostbyaddr((char *) &thisaddr, sizeof(thisaddr), 371 he->h_addrtype))) { 372 fprintf(stderr, "gethostbyaddr failed on %s\n", 373 inet_ntoa(thisaddr)); 374 exit(1); 375 } 376 strncpy(thishost, he->h_name, sizeof(thishost)); 377 thishost[sizeof(thishost) - 1] = '\0'; 378 } else { 379 thisaddr.s_addr = INADDR_NONE; 380 } 381 382 if (!(auth = authunix_create_default())) { 383 fprintf(stderr, "couldn't create authentication handle\n"); 384 exit(1); 385 } 386 morethanone = (optind + 1 < argc); 387 388 for (; optind < argc; optind++) { 389 390 host = argv[optind]; 391 tv.tv_sec = CREATE_TIMEOUT; 392 tv.tv_usec = 0; 393 394 if (!(client = clnt_create_timeout(host, &tv))) 395 continue; 396 397 client->cl_auth = auth; 398 tv.tv_sec = CALL_TIMEOUT; 399 tv.tv_usec = 0; 400 401 if (rpcs & (DODUMP | DOREMOVE | DOVERIFY)) 402 if ((estat = clnt_call(client, 403 MOUNTPROC_DUMP, 404 (XDRPROC_T_TYPE) xdr_void, 405 (char *) 0, 406 (XDRPROC_T_TYPE) xdr_mountlist, 407 (char *) &mntdump, 408 tv)) != RPC_SUCCESS) { 409 fprintf(stderr, "%s: MOUNTPROC_DUMP: ", host); 410 clnt_perrno(estat); 411 fflush(stderr); 412 mntdump = NULL; 413 goto next; 414 } 415 if (rpcs & DOEXPORTS) 416 if ((estat = clnt_call(client, 417 MOUNTPROC_EXPORT, 418 (XDRPROC_T_TYPE) xdr_void, 419 (char *) 0, 420 (XDRPROC_T_TYPE) xdr_exports, 421 (char *) &mntexports, 422 tv)) != RPC_SUCCESS) { 423 fprintf(stderr, "%s: MOUNTPROC_EXPORT: ", host); 424 clnt_perrno(estat); 425 fflush(stderr); 426 mntexports = NULL; 427 goto next; 428 } 429 430 /* Now just print out the results */ 431 if ((rpcs & (DODUMP | DOEXPORTS)) && 432 morethanone) { 433 printf(">>> %s <<<\n", host); 434 fflush(stdout); 435 } 436 437 if (rpcs & DODUMP) { 438 print_dump(mntdump); 439 } 440 441 if (rpcs & DOEXPORTS) { 442 exp = mntexports; 443 while (exp) { 444 printf("%-35s", exp->ex_dir); 445 grp = exp->ex_groups; 446 if (grp == NULL) { 447 printf("Everyone\n"); 448 } else { 449 while (grp) { 450 printf("%s ", grp->gr_name); 451 grp = grp->gr_next; 452 } 453 printf("\n"); 454 } 455 exp = exp->ex_next; 456 } 457 } 458 459 if (rpcs & DOVERIFY) 460 fix_rmtab(client, host, mntdump, 0, force); 461 462 if (rpcs & DOREMOVE) 463 fix_rmtab(client, host, mntdump, 1, force); 464 465 if (rpcs & DOREMALL) 466 remove_all(client, host); 467 468 next: 469 if (mntdump) 470 (void) clnt_freeres(client, 471 (XDRPROC_T_TYPE) xdr_mountlist, 472 (char *) &mntdump); 473 if (mntexports) 474 (void) clnt_freeres(client, 475 (XDRPROC_T_TYPE) xdr_exports, 476 (char *) &mntexports); 477 478 clnt_destroy(client); 479 } 480 exit(0); 481 return 0; /* should never reach here */ 482} 483 484 485RETSIGTYPE 486create_timeout(int sig) 487{ 488 signal(SIGALRM, SIG_DFL); 489 longjmp(before_rpc, 1); 490} 491 492 493#ifndef HAVE_TRANSPORT_TYPE_TLI 494/* 495 * inetresport creates a datagram socket and attempts to bind it to a 496 * secure port. 497 * returns: The bound socket, or -1 to indicate an error. 498 */ 499static int 500inetresport(int ty) 501{ 502 int alport; 503 struct sockaddr_in addr; 504 int fd; 505 506 /* Use internet address family */ 507 addr.sin_family = AF_INET; 508 addr.sin_addr.s_addr = INADDR_ANY; 509 if ((fd = socket(AF_INET, ty, 0)) < 0) 510 return -1; 511 512 for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) { 513 addr.sin_port = htons((u_short) alport); 514 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) 515 return fd; 516 if (errno != EADDRINUSE) { 517 close(fd); 518 return -1; 519 } 520 } 521 close(fd); 522 errno = EAGAIN; 523 return -1; 524} 525 526 527/* 528 * Privsock() calls inetresport() to attempt to bind a socket to a secure 529 * port. If inetresport() fails, privsock returns a magic socket number which 530 * indicates to RPC that it should make its own socket. 531 * returns: A privileged socket # or RPC_ANYSOCK. 532 */ 533static int 534privsock(int ty) 535{ 536 int sock = inetresport(ty); 537 538 if (sock < 0) { 539 errno = 0; 540 /* Couldn't get a secure port, let RPC make an insecure one */ 541 sock = RPC_ANYSOCK; 542 } 543 return sock; 544} 545#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 546 547 548static CLIENT * 549clnt_create_timeout(char *host, struct timeval *tvp) 550{ 551 CLIENT *clnt; 552 struct sockaddr_in host_addr; 553 struct hostent *hp; 554#ifndef HAVE_TRANSPORT_TYPE_TLI 555 int s; 556#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 557 558 if (setjmp(before_rpc)) { 559 if (!quiet) { 560 fprintf(stderr, "%s: ", host); 561 clnt_perrno(RPC_TIMEDOUT); 562 fprintf(stderr, "\n"); 563 fflush(stderr); 564 } 565 return NULL; 566 } 567 signal(SIGALRM, create_timeout); 568 ualarm(tvp->tv_sec * 1000000 + tvp->tv_usec, 0); 569 570 /* 571 * Get address of host 572 */ 573 if ((hp = gethostbyname(host)) == 0 && !STREQ(host, localhost)) { 574 fprintf(stderr, "can't get address of %s\n", host); 575 return NULL; 576 } 577 memset(&host_addr, 0, sizeof host_addr); 578 host_addr.sin_family = AF_INET; 579 if (hp) { 580 memmove((voidp) &host_addr.sin_addr, (voidp) hp->h_addr, 581 sizeof(host_addr.sin_addr)); 582 } else { 583 /* fake "localhost" */ 584 host_addr.sin_addr.s_addr = htonl(0x7f000001); 585 } 586 587#ifdef HAVE_TRANSPORT_TYPE_TLI 588 /* try TCP first (in case return data is large), then UDP */ 589 clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "tcp"); 590 if (!clnt) 591 clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "udp"); 592#else /* not HAVE_TRANSPORT_TYPE_TLI */ 593 s = RPC_ANYSOCK; 594 clnt = clnttcp_create(&host_addr, MOUNTPROG, MOUNTVERS, &s, 0, 0); 595 if (!clnt) { 596 /* XXX: do we need to close(s) ? */ 597 s = privsock(SOCK_DGRAM); 598 clnt = clntudp_create(&host_addr, MOUNTPROG, MOUNTVERS, *tvp, &s); 599 } 600#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 601 602 if (!clnt) { 603 ualarm(0, 0); 604 if (!quiet) { 605 clnt_pcreateerror(host); 606 fflush(stderr); 607 } 608 return NULL; 609 } 610 611 ualarm(0, 0); 612 return clnt; 613} 614