fixmount.c revision 38495
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 5.2.2.2 1992/05/31 16:35:45 jsp 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] = ""; 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:")) != EOF) 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 358 /* 359 * We need the hostname as it appears to the other side's 360 * mountd, so get our own hostname by reverse address 361 * resolution. 362 */ 363 if (!(he = gethostbyname(thishost))) { 364 fprintf(stderr, "gethostbyname failed on %s\n", 365 thishost); 366 exit(1); 367 } 368 memcpy(&thisaddr, he->h_addr, sizeof(thisaddr)); 369 if (!(he = gethostbyaddr((char *) &thisaddr, sizeof(thisaddr), 370 he->h_addrtype))) { 371 fprintf(stderr, "gethostbyaddr failed on %s\n", 372 inet_ntoa(thisaddr)); 373 exit(1); 374 } 375 strncpy(thishost, he->h_name, sizeof(thishost)); 376 thishost[sizeof(thishost) - 1] = '\0'; 377 } else { 378 thisaddr.s_addr = INADDR_NONE; 379 } 380 381 if (!(auth = authunix_create_default())) { 382 fprintf(stderr, "couldn't create authentication handle\n"); 383 exit(1); 384 } 385 morethanone = (optind + 1 < argc); 386 387 for (; optind < argc; optind++) { 388 389 host = argv[optind]; 390 tv.tv_sec = CREATE_TIMEOUT; 391 tv.tv_usec = 0; 392 393 if (!(client = clnt_create_timeout(host, &tv))) 394 continue; 395 396 client->cl_auth = auth; 397 tv.tv_sec = CALL_TIMEOUT; 398 tv.tv_usec = 0; 399 400 if (rpcs & (DODUMP | DOREMOVE | DOVERIFY)) 401 if ((estat = clnt_call(client, 402 MOUNTPROC_DUMP, 403 (XDRPROC_T_TYPE) xdr_void, 404 (char *) 0, 405 (XDRPROC_T_TYPE) xdr_mountlist, 406 (char *) &mntdump, 407 tv)) != RPC_SUCCESS) { 408 fprintf(stderr, "%s: MOUNTPROC_DUMP: ", host); 409 clnt_perrno(estat); 410 fflush(stderr); 411 mntdump = NULL; 412 goto next; 413 } 414 if (rpcs & DOEXPORTS) 415 if ((estat = clnt_call(client, 416 MOUNTPROC_EXPORT, 417 (XDRPROC_T_TYPE) xdr_void, 418 (char *) 0, 419 (XDRPROC_T_TYPE) xdr_exports, 420 (char *) &mntexports, 421 tv)) != RPC_SUCCESS) { 422 fprintf(stderr, "%s: MOUNTPROC_EXPORT: ", host); 423 clnt_perrno(estat); 424 fflush(stderr); 425 mntexports = NULL; 426 goto next; 427 } 428 429 /* Now just print out the results */ 430 if ((rpcs & (DODUMP | DOEXPORTS)) && 431 morethanone) { 432 printf(">>> %s <<<\n", host); 433 fflush(stdout); 434 } 435 436 if (rpcs & DODUMP) { 437 print_dump(mntdump); 438 } 439 440 if (rpcs & DOEXPORTS) { 441 exp = mntexports; 442 while (exp) { 443 printf("%-35s", exp->ex_dir); 444 grp = exp->ex_groups; 445 if (grp == NULL) { 446 printf("Everyone\n"); 447 } else { 448 while (grp) { 449 printf("%s ", grp->gr_name); 450 grp = grp->gr_next; 451 } 452 printf("\n"); 453 } 454 exp = exp->ex_next; 455 } 456 } 457 458 if (rpcs & DOVERIFY) 459 fix_rmtab(client, host, mntdump, 0, force); 460 461 if (rpcs & DOREMOVE) 462 fix_rmtab(client, host, mntdump, 1, force); 463 464 if (rpcs & DOREMALL) 465 remove_all(client, host); 466 467 next: 468 if (mntdump) 469 (void) clnt_freeres(client, 470 (XDRPROC_T_TYPE) xdr_mountlist, 471 (char *) &mntdump); 472 if (mntexports) 473 (void) clnt_freeres(client, 474 (XDRPROC_T_TYPE) xdr_exports, 475 (char *) &mntexports); 476 477 clnt_destroy(client); 478 } 479 exit(0); 480 return 0; /* should never reach here */ 481} 482 483 484RETSIGTYPE 485create_timeout(int sig) 486{ 487 signal(SIGALRM, SIG_DFL); 488 longjmp(before_rpc, 1); 489} 490 491 492#ifndef HAVE_TRANSPORT_TYPE_TLI 493/* 494 * inetresport creates a datagram socket and attempts to bind it to a 495 * secure port. 496 * returns: The bound socket, or -1 to indicate an error. 497 */ 498static int 499inetresport(int ty) 500{ 501 int alport; 502 struct sockaddr_in addr; 503 int fd; 504 505 /* Use internet address family */ 506 addr.sin_family = AF_INET; 507 addr.sin_addr.s_addr = INADDR_ANY; 508 if ((fd = socket(AF_INET, ty, 0)) < 0) 509 return -1; 510 511 for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) { 512 addr.sin_port = htons((u_short) alport); 513 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) 514 return fd; 515 if (errno != EADDRINUSE) { 516 close(fd); 517 return -1; 518 } 519 } 520 close(fd); 521 errno = EAGAIN; 522 return -1; 523} 524 525 526/* 527 * Privsock() calls inetresport() to attempt to bind a socket to a secure 528 * port. If inetresport() fails, privsock returns a magic socket number which 529 * indicates to RPC that it should make its own socket. 530 * returns: A privileged socket # or RPC_ANYSOCK. 531 */ 532static int 533privsock(int ty) 534{ 535 int sock = inetresport(ty); 536 537 if (sock < 0) { 538 errno = 0; 539 /* Couldn't get a secure port, let RPC make an insecure one */ 540 sock = RPC_ANYSOCK; 541 } 542 return sock; 543} 544#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 545 546 547static CLIENT * 548clnt_create_timeout(char *host, struct timeval *tvp) 549{ 550 CLIENT *clnt; 551 struct sockaddr_in host_addr; 552 struct hostent *hp; 553#ifndef HAVE_TRANSPORT_TYPE_TLI 554 int s; 555#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 556 557 if (setjmp(before_rpc)) { 558 if (!quiet) { 559 fprintf(stderr, "%s: ", host); 560 clnt_perrno(RPC_TIMEDOUT); 561 fprintf(stderr, "\n"); 562 fflush(stderr); 563 } 564 return NULL; 565 } 566 signal(SIGALRM, create_timeout); 567 ualarm(tvp->tv_sec * 1000000 + tvp->tv_usec, 0); 568 569 /* 570 * Get address of host 571 */ 572 if ((hp = gethostbyname(host)) == 0 && !STREQ(host, localhost)) { 573 fprintf(stderr, "can't get address of %s\n", host); 574 return NULL; 575 } 576 memset(&host_addr, 0, sizeof host_addr); 577 host_addr.sin_family = AF_INET; 578 if (hp) { 579 memmove((voidp) &host_addr.sin_addr, (voidp) hp->h_addr, 580 sizeof(host_addr.sin_addr)); 581 } else { 582 /* fake "localhost" */ 583 host_addr.sin_addr.s_addr = htonl(0x7f000001); 584 } 585 586#ifdef HAVE_TRANSPORT_TYPE_TLI 587 /* try TCP first (in case return data is large), then UDP */ 588 clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "tcp"); 589 if (!clnt) 590 clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "udp"); 591#else /* not HAVE_TRANSPORT_TYPE_TLI */ 592 s = RPC_ANYSOCK; 593 clnt = clnttcp_create(&host_addr, MOUNTPROG, MOUNTVERS, &s, 0, 0); 594 if (!clnt) { 595 /* XXX: do we need to close(s) ? */ 596 s = privsock(SOCK_DGRAM); 597 clnt = clntudp_create(&host_addr, MOUNTPROG, MOUNTVERS, *tvp, &s); 598 } 599#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 600 601 if (!clnt) { 602 ualarm(0, 0); 603 if (!quiet) { 604 clnt_pcreateerror(host); 605 fflush(stderr); 606 } 607 return NULL; 608 } 609 610 ualarm(0, 0); 611 return clnt; 612} 613