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