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