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