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