amq.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: amq.c,v 5.2.2.1 1992/02/09 15:09:16 jsp beta $ 42 * 43 */ 44 45/* 46 * Automounter query tool 47 */ 48 49#ifndef lint 50char copyright[] = "\ 51@(#)Copyright (c) 1997-1998 Erez Zadok\n\ 52@(#)Copyright (c) 1990 Jan-Simon Pendry\n\ 53@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\ 54@(#)Copyright (c) 1990 The Regents of the University of California.\n\ 55@(#)All rights reserved.\n"; 56#if __GNUC__ < 2 57static char rcsid[] = "$Id: amq.c,v 6.0 1997-1998/01/01 15:09:16 ezk $"; 58static char sccsid[] = "%W% (Berkeley) %G%"; 59#endif /* __GNUC__ < 2 */ 60#endif /* not lint */ 61 62#ifdef HAVE_CONFIG_H 63# include <config.h> 64#endif /* HAVE_CONFIG_H */ 65#include <am_defs.h> 66#include <amq.h> 67 68/* locals */ 69char *progname; 70static int flush_flag; 71static int minfo_flag; 72static int getpid_flag; 73static int unmount_flag; 74static int stats_flag; 75static int getvers_flag; 76static int amd_program_number = AMQ_PROGRAM; 77static int use_tcp_flag, use_udp_flag; 78static char *debug_opts; 79static char *amq_logfile; 80static char *mount_map; 81static char *xlog_optstr; 82static char localhost[] = "localhost"; 83static char *def_server = localhost; 84 85/* externals */ 86extern int optind; 87extern char *optarg; 88 89/* forward decalrations */ 90#ifdef HAVE_TRANSPORT_TYPE_TLI 91static CLIENT *get_secure_amd_client(char *host, struct timeval *tv, int *sock); 92static int amq_bind_resv_port(int td, u_short *pp); 93#else /* not HAVE_TRANSPORT_TYPE_TLI */ 94static int privsock(int ty); 95#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 96 97/* dummy variables */ 98char hostname[MAXHOSTNAMELEN]; 99int orig_umask, foreground, debug_flags; 100pid_t mypid; 101serv_state amd_state; 102 103/* structures */ 104enum show_opt { 105 Full, Stats, Calc, Short, ShowDone 106}; 107 108 109/* 110 * If (e) is Calc then just calculate the sizes 111 * Otherwise display the mount node on stdout 112 */ 113static void 114show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid) 115{ 116 switch (e) { 117 case Calc: 118 { 119 int mw = strlen(mt->mt_mountinfo); 120 int dw = strlen(mt->mt_directory); 121 int tw = strlen(mt->mt_type); 122 if (mw > *mwid) 123 *mwid = mw; 124 if (dw > *dwid) 125 *dwid = dw; 126 if (tw > *twid) 127 *twid = tw; 128 } 129 break; 130 131 case Full: 132 { 133 struct tm *tp = localtime((time_t *) &mt->mt_mounttime); 134 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", 135 *dwid, *dwid, 136 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ 137 *twid, *twid, 138 mt->mt_type, 139 *mwid, *mwid, 140 mt->mt_mountinfo, 141 mt->mt_mountpoint, 142 143 mt->mt_mountuid, 144 mt->mt_getattr, 145 mt->mt_lookup, 146 mt->mt_readdir, 147 mt->mt_readlink, 148 mt->mt_statfs, 149 150 tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, 151 tp->tm_mon + 1, tp->tm_mday, 152 tp->tm_hour, tp->tm_min, tp->tm_sec); 153 } 154 break; 155 156 case Stats: 157 { 158 struct tm *tp = localtime((time_t *) &mt->mt_mounttime); 159 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", 160 *dwid, *dwid, 161 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ 162 163 mt->mt_mountuid, 164 mt->mt_getattr, 165 mt->mt_lookup, 166 mt->mt_readdir, 167 mt->mt_readlink, 168 mt->mt_statfs, 169 170 tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, 171 tp->tm_mon + 1, tp->tm_mday, 172 tp->tm_hour, tp->tm_min, tp->tm_sec); 173 } 174 break; 175 176 case Short: 177 { 178 printf("%-*.*s %-*.*s %-*.*s %s\n", 179 *dwid, *dwid, 180 *mt->mt_directory ? mt->mt_directory : "/", 181 *twid, *twid, 182 mt->mt_type, 183 *mwid, *mwid, 184 mt->mt_mountinfo, 185 mt->mt_mountpoint); 186 } 187 break; 188 189 default: 190 break; 191 } 192} 193 194/* 195 * Display a mount tree. 196 */ 197static void 198show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid) 199{ 200 while (mt) { 201 show_mti(mt, e, mwid, dwid, pwid); 202 show_mt(mt->mt_next, e, mwid, dwid, pwid); 203 mt = mt->mt_child; 204 } 205} 206 207static void 208show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid) 209{ 210 int i; 211 212 switch (e) { 213 214 case Calc: 215 { 216 for (i = 0; i < ml->amq_mount_info_list_len; i++) { 217 amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; 218 int mw = strlen(mi->mi_mountinfo); 219 int dw = strlen(mi->mi_mountpt); 220 int tw = strlen(mi->mi_type); 221 if (mw > *mwid) 222 *mwid = mw; 223 if (dw > *dwid) 224 *dwid = dw; 225 if (tw > *twid) 226 *twid = tw; 227 } 228 } 229 break; 230 231 case Full: 232 { 233 for (i = 0; i < ml->amq_mount_info_list_len; i++) { 234 amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; 235 printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s", 236 *mwid, *mwid, mi->mi_mountinfo, 237 *dwid, *dwid, mi->mi_mountpt, 238 *twid, *twid, mi->mi_type, 239 mi->mi_refc, mi->mi_fserver, 240 mi->mi_up > 0 ? "up" : 241 mi->mi_up < 0 ? "starting" : "down"); 242 if (mi->mi_error > 0) { 243 extern int sys_nerr; 244 if (mi->mi_error < sys_nerr) 245 printf(" (%s)", sys_errlist[mi->mi_error]); 246 else 247 printf(" (Error %d)", mi->mi_error); 248 } else if (mi->mi_error < 0) { 249 fputs(" (in progress)", stdout); 250 } 251 fputc('\n', stdout); 252 } 253 } 254 break; 255 256 default: 257 break; 258 } 259} 260 261 262/* 263 * Display general mount statistics 264 */ 265static void 266show_ms(amq_mount_stats *ms) 267{ 268 printf("\ 269requests stale mount mount unmount\n\ 270deferred fhandles ok failed failed\n\ 271%-9d %-9d %-9d %-9d %-9d\n", 272 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr); 273} 274 275 276#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) 277static char * 278cluster_server(void) 279{ 280 struct cct_entry *cp; 281 282 if (cnodeid() == 0) { 283 /* 284 * Not clustered 285 */ 286 return def_server; 287 } 288 while (cp = getccent()) 289 if (cp->cnode_type == 'r') 290 return cp->cnode_name; 291 292 return def_server; 293} 294#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ 295 296 297/* 298 * MAIN 299 */ 300int 301main(int argc, char *argv[]) 302{ 303 int opt_ch; 304 int errs = 0; 305 char *server; 306 struct sockaddr_in server_addr; 307 int s; /* to pass the Amd security check, we must use a priv port */ 308 CLIENT *clnt = NULL; 309 struct hostent *hp; 310 int nodefault = 0; 311 struct timeval tv; 312#ifndef HAVE_TRANSPORT_TYPE_TLI 313 enum clnt_stat cs; 314#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 315 316 317 /* 318 * Compute program name 319 */ 320 if (argv[0]) { 321 progname = strrchr(argv[0], '/'); 322 if (progname && progname[1]) 323 progname++; 324 else 325 progname = argv[0]; 326 } 327 if (!progname) 328 progname = "amq"; 329 330 /* 331 * Parse arguments 332 */ 333 while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:pP:TU")) != EOF) 334 switch (opt_ch) { 335 case 'f': 336 flush_flag = 1; 337 nodefault = 1; 338 break; 339 340 case 'h': 341 def_server = optarg; 342 break; 343 344 case 'l': 345 amq_logfile = optarg; 346 nodefault = 1; 347 break; 348 349 case 'm': 350 minfo_flag = 1; 351 nodefault = 1; 352 break; 353 354 case 'p': 355 getpid_flag = 1; 356 nodefault = 1; 357 break; 358 359 case 's': 360 stats_flag = 1; 361 nodefault = 1; 362 break; 363 364 case 'u': 365 unmount_flag = 1; 366 nodefault = 1; 367 break; 368 369 case 'v': 370 getvers_flag = 1; 371 nodefault = 1; 372 break; 373 374 case 'x': 375 xlog_optstr = optarg; 376 nodefault = 1; 377 break; 378 379 case 'D': 380 debug_opts = optarg; 381 nodefault = 1; 382 break; 383 384 case 'M': 385 mount_map = optarg; 386 nodefault = 1; 387 break; 388 389 case 'P': 390 amd_program_number = atoi(optarg); 391 break; 392 393 case 'T': 394 use_tcp_flag = 1; 395 break; 396 397 case 'U': 398 use_udp_flag = 1; 399 break; 400 401 default: 402 errs = 1; 403 break; 404 } 405 406 if (optind == argc) { 407 if (unmount_flag) 408 errs = 1; 409 } 410 if (errs) { 411 show_usage: 412 fprintf(stderr, "\ 413Usage: %s [-h host] [[-f] [-m] [-p] [-v] [-s]] | [[-u] directory ...]]\n\ 414\t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts] [-M mapent]\n\ 415\t[-P prognum] [-T] [-U]\n", progname); 416 exit(1); 417 } 418 419 /* set use_udp and use_tcp flags both to on if none are defined */ 420 if (!use_tcp_flag && !use_udp_flag) 421 use_tcp_flag = use_udp_flag = 1; 422 423#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) 424 /* 425 * Figure out root server of cluster 426 */ 427 if (def_server == localhost) 428 server = cluster_server(); 429 else 430#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ 431 server = def_server; 432 433 /* 434 * Get address of server 435 */ 436 if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) { 437 fprintf(stderr, "%s: Can't get address of %s\n", progname, server); 438 exit(1); 439 } 440 memset(&server_addr, 0, sizeof server_addr); 441 server_addr.sin_family = AF_INET; 442 if (hp) { 443 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr, 444 sizeof(server_addr.sin_addr)); 445 } else { 446 /* fake "localhost" */ 447 server_addr.sin_addr.s_addr = htonl(0x7f000001); 448 } 449 450 /* 451 * Create RPC endpoint 452 */ 453 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */ 454 tv.tv_usec = 0; 455 456#ifdef HAVE_TRANSPORT_TYPE_TLI 457 clnt = get_secure_amd_client(server, &tv, &s); 458 if (!clnt && use_tcp_flag) /* try tcp first */ 459 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp"); 460 if (!clnt && use_udp_flag) { /* try udp next */ 461 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp"); 462 /* if ok, set timeout (valid for connectionless transports only) */ 463 if (clnt) 464 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv); 465 } 466#else /* not HAVE_TRANSPORT_TYPE_TLI */ 467 468 /* first check if remote portmapper is up */ 469 cs = pmap_ping(&server_addr); 470 if (cs == RPC_TIMEDOUT) { 471 fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n", 472 progname, server, clnt_sperrno(cs)); 473 exit(1); 474 } 475 476 /* portmapper exists: get remote amd info from it */ 477 if (!clnt && use_tcp_flag) { /* try tcp first */ 478 s = RPC_ANYSOCK; 479 clnt = clnttcp_create(&server_addr, amd_program_number, 480 AMQ_VERSION, &s, 0, 0); 481 } 482 if (!clnt && use_udp_flag) { /* try udp next */ 483 /* XXX: do we need to close(s) ? */ 484 s = privsock(SOCK_DGRAM); 485 clnt = clntudp_create(&server_addr, amd_program_number, 486 AMQ_VERSION, tv, &s); 487 } 488#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 489 if (!clnt) { 490 fprintf(stderr, "%s: ", progname); 491 clnt_pcreateerror(server); 492 exit(1); 493 } 494 495 /* 496 * Control debugging 497 */ 498 if (debug_opts) { 499 int *rc; 500 amq_setopt opt; 501 opt.as_opt = AMOPT_DEBUG; 502 opt.as_str = debug_opts; 503 rc = amqproc_setopt_1(&opt, clnt); 504 if (rc && *rc < 0) { 505 fprintf(stderr, "%s: daemon not compiled for debug\n", progname); 506 errs = 1; 507 } else if (!rc || *rc > 0) { 508 fprintf(stderr, "%s: debug setting for \"%s\" failed\n", progname, debug_opts); 509 errs = 1; 510 } 511 } 512 513 /* 514 * Control logging 515 */ 516 if (xlog_optstr) { 517 int *rc; 518 amq_setopt opt; 519 opt.as_opt = AMOPT_XLOG; 520 opt.as_str = xlog_optstr; 521 rc = amqproc_setopt_1(&opt, clnt); 522 if (!rc || *rc) { 523 fprintf(stderr, "%s: setting log level to \"%s\" failed\n", progname, xlog_optstr); 524 errs = 1; 525 } 526 } 527 528 /* 529 * Control log file 530 */ 531 if (amq_logfile) { 532 int *rc; 533 amq_setopt opt; 534 opt.as_opt = AMOPT_LOGFILE; 535 opt.as_str = amq_logfile; 536 rc = amqproc_setopt_1(&opt, clnt); 537 if (!rc || *rc) { 538 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", progname, amq_logfile); 539 errs = 1; 540 } 541 } 542 543 /* 544 * Flush map cache 545 */ 546 if (flush_flag) { 547 int *rc; 548 amq_setopt opt; 549 opt.as_opt = AMOPT_FLUSHMAPC; 550 opt.as_str = ""; 551 rc = amqproc_setopt_1(&opt, clnt); 552 if (!rc || *rc) { 553 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", progname, server); 554 errs = 1; 555 } 556 } 557 558 /* 559 * Mount info 560 */ 561 if (minfo_flag) { 562 int dummy; 563 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt); 564 if (ml) { 565 int mwid = 0, dwid = 0, twid = 0; 566 show_mi(ml, Calc, &mwid, &dwid, &twid); 567 mwid++; 568 dwid++; 569 twid++; 570 show_mi(ml, Full, &mwid, &dwid, &twid); 571 572 } else { 573 fprintf(stderr, "%s: amd on %s cannot provide mount info\n", progname, server); 574 } 575 } 576 577 /* 578 * Mount map 579 */ 580 if (mount_map) { 581 int *rc; 582 do { 583 rc = amqproc_mount_1(&mount_map, clnt); 584 } while (rc && *rc < 0); 585 if (!rc || *rc > 0) { 586 if (rc) 587 errno = *rc; 588 else 589 errno = ETIMEDOUT; 590 fprintf(stderr, "%s: could not start new ", progname); 591 perror("autmount point"); 592 } 593 } 594 595 /* 596 * Get Version 597 */ 598 if (getvers_flag) { 599 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt); 600 if (spp && *spp) { 601 fputs(*spp, stdout); 602 XFREE(*spp); 603 } else { 604 fprintf(stderr, "%s: failed to get version information\n", progname); 605 errs = 1; 606 } 607 } 608 609 /* 610 * Get PID of amd 611 */ 612 if (getpid_flag) { 613 int *ip = amqproc_getpid_1((voidp) 0, clnt); 614 if (ip && *ip) { 615 printf("%d\n", *ip); 616 } else { 617 fprintf(stderr, "%s: failed to get PID of amd\n", progname); 618 errs = 1; 619 } 620 } 621 622 /* 623 * Apply required operation to all remaining arguments 624 */ 625 if (optind < argc) { 626 do { 627 char *fs = argv[optind++]; 628 if (unmount_flag) { 629 /* 630 * Unmount request 631 */ 632 amqproc_umnt_1(&fs, clnt); 633 } else { 634 /* 635 * Stats request 636 */ 637 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt); 638 if (mtp) { 639 amq_mount_tree *mt = *mtp; 640 if (mt) { 641 int mwid = 0, dwid = 0, twid = 0; 642 show_mt(mt, Calc, &mwid, &dwid, &twid); 643 mwid++; 644 dwid++, twid++; 645 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n", 646 dwid, dwid, "What"); 647 show_mt(mt, Stats, &mwid, &dwid, &twid); 648 } else { 649 fprintf(stderr, "%s: %s not automounted\n", progname, fs); 650 } 651 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp); 652 } else { 653 fprintf(stderr, "%s: ", progname); 654 clnt_perror(clnt, server); 655 errs = 1; 656 } 657 } 658 } while (optind < argc); 659 660 } else if (unmount_flag) { 661 goto show_usage; 662 663 } else if (stats_flag) { 664 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt); 665 if (ms) { 666 show_ms(ms); 667 } else { 668 fprintf(stderr, "%s: ", progname); 669 clnt_perror(clnt, server); 670 errs = 1; 671 } 672 673 } else if (!nodefault) { 674 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt); 675 if (mlp) { 676 enum show_opt e = Calc; 677 int mwid = 0, dwid = 0, pwid = 0; 678 while (e != ShowDone) { 679 int i; 680 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) { 681 show_mt(mlp->amq_mount_tree_list_val[i], 682 e, &mwid, &dwid, &pwid); 683 } 684 mwid++; 685 dwid++, pwid++; 686 if (e == Calc) 687 e = Short; 688 else if (e == Short) 689 e = ShowDone; 690 } 691 692 } else { 693 fprintf(stderr, "%s: ", progname); 694 clnt_perror(clnt, server); 695 errs = 1; 696 } 697 } 698 exit(errs); 699 return errs; /* should never reache here */ 700} 701 702 703#ifdef HAVE_TRANSPORT_TYPE_TLI 704 705/* 706 * How to bind to reserved ports. 707 * TLI handle (socket) and port version. 708 */ 709/* defined here so that it does not have to resolve it with libamu.a */ 710static int 711amq_bind_resv_port(int td, u_short *pp) 712{ 713 int rc = -1, port; 714 struct t_bind *treq, *tret; 715 struct sockaddr_in *sin; 716 717 treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); 718 if (!treq) { 719 plog(XLOG_ERROR, "t_alloc 1"); 720 return -1; 721 } 722 tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); 723 if (!tret) { 724 t_free((char *) treq, T_BIND); 725 plog(XLOG_ERROR, "t_alloc 2"); 726 return -1; 727 } 728 memset((char *) treq->addr.buf, 0, treq->addr.len); 729 sin = (struct sockaddr_in *) treq->addr.buf; 730 sin->sin_family = AF_INET; 731 treq->qlen = 0; 732 treq->addr.len = treq->addr.maxlen; 733 errno = EADDRINUSE; 734 port = IPPORT_RESERVED; 735 736 do { 737 --port; 738 sin->sin_port = htons(port); 739 rc = t_bind(td, treq, tret); 740 if (rc < 0) { 741 } else { 742 if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0) 743 break; 744 else 745 t_unbind(td); 746 } 747 } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2); 748 749 if (pp) { 750 if (rc == 0) 751 *pp = port; 752 else 753 plog(XLOG_ERROR, "could not t_bind to any reserved port"); 754 } 755 t_free((char *) tret, T_BIND); 756 t_free((char *) treq, T_BIND); 757 return rc; 758} 759 760 761/* 762 * Create a secure rpc client attached to the amd daemon. 763 */ 764static CLIENT * 765get_secure_amd_client(char *host, struct timeval *tv, int *sock) 766{ 767 CLIENT *client; 768 struct netbuf nb; 769 struct netconfig *nc, *pm_nc; 770 struct sockaddr_in sin; 771 772 773 nb.maxlen = sizeof(sin); 774 nb.buf = (char *) &sin; 775 776 /* 777 * Ensure that remote portmapper is alive 778 * (must use connectionless netconfig). 779 */ 780 if ((pm_nc = getnetconfigent(NC_UDP)) != NULL) { 781 enum clnt_stat cs; 782 783 cs = rpcb_rmtcall(pm_nc, 784 host, 785 amd_program_number, 786 AMQ_VERSION, 787 AMQPROC_NULL, 788 (XDRPROC_T_TYPE) xdr_void, 789 NULL, 790 (XDRPROC_T_TYPE) xdr_void, 791 NULL, 792 *tv, 793 NULL); 794 if (cs == RPC_TIMEDOUT) { 795 fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n", 796 progname, host, clnt_sperrno(cs)); 797 exit(1); 798 } 799 } 800 801 /* 802 * First transport type to try: TCP 803 */ 804 if (use_tcp_flag) { 805 /* Find amd address on TCP */ 806 nc = getnetconfigent(NC_TCP); 807 if (!nc) { 808 fprintf(stderr, "getnetconfig for tcp failed: %s\n", nc_sperror()); 809 goto tryudp; 810 } 811 812 if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) { 813 /* 814 * don't pring error messages here, since amd might legitimately 815 * serve udp only 816 */ 817 goto tryudp; 818 } 819 /* Create priviledged TCP socket */ 820 *sock = t_open(nc->nc_device, O_RDWR, 0); 821 822 if (*sock < 0) { 823 fprintf(stderr, "t_open %s: %m\n", nc->nc_device); 824 goto tryudp; 825 } 826 if (amq_bind_resv_port(*sock, (u_short *) 0) < 0) 827 goto tryudp; 828 829 client = clnt_vc_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0); 830 if (!client) { 831 fprintf(stderr, "clnt_vc_create failed"); 832 t_close(*sock); 833 goto tryudp; 834 } 835 /* tcp succeeded */ 836 return client; 837 } 838 839tryudp: 840 /* 841 * TCP failed so try UDP 842 */ 843 if (use_udp_flag) { 844 /* find amd address on UDP */ 845 nc = getnetconfigent(NC_UDP); 846 if (!nc) { 847 fprintf(stderr, "getnetconfig for udp failed: %s\n", nc_sperror()); 848 return NULL; 849 } 850 if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) { 851 fprintf(stderr, "%s\n", 852 clnt_spcreateerror("couldn't get amd address on udp")); 853 return NULL; 854 } 855 /* create priviledged UDP socket */ 856 *sock = t_open(nc->nc_device, O_RDWR, 0); 857 858 if (*sock < 0) { 859 fprintf(stderr, "t_open %s: %m\n", nc->nc_device); 860 return NULL; /* neither tcp not udp succeeded */ 861 } 862 if (amq_bind_resv_port(*sock, (u_short *) 0) < 0) 863 return NULL; 864 865 client = clnt_dg_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0); 866 if (!client) { 867 fprintf(stderr, "clnt_dg_create failed\n"); 868 t_close(*sock); 869 return NULL; /* neither tcp not udp succeeded */ 870 } 871 if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) { 872 fprintf(stderr, "clnt_control CLSET_RETRY_TIMEOUT for udp failed\n"); 873 clnt_destroy(client); 874 return NULL; /* neither tcp not udp succeeded */ 875 } 876 /* udp succeeded */ 877 return client; 878 } 879 880 /* should never get here */ 881 return NULL; 882} 883 884#else /* not HAVE_TRANSPORT_TYPE_TLI */ 885 886/* 887 * inetresport creates a datagram socket and attempts to bind it to a 888 * secure port. 889 * returns: The bound socket, or -1 to indicate an error. 890 */ 891static int 892inetresport(int ty) 893{ 894 int alport; 895 struct sockaddr_in addr; 896 int fd; 897 898 /* Use internet address family */ 899 addr.sin_family = AF_INET; 900 addr.sin_addr.s_addr = INADDR_ANY; 901 if ((fd = socket(AF_INET, ty, 0)) < 0) 902 return -1; 903 904 for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) { 905 addr.sin_port = htons((u_short) alport); 906 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) 907 return fd; 908 if (errno != EADDRINUSE) { 909 close(fd); 910 return -1; 911 } 912 } 913 close(fd); 914 errno = EAGAIN; 915 return -1; 916} 917 918 919/* 920 * Privsock() calls inetresport() to attempt to bind a socket to a secure 921 * port. If inetresport() fails, privsock returns a magic socket number which 922 * indicates to RPC that it should make its own socket. 923 * returns: A privileged socket # or RPC_ANYSOCK. 924 */ 925static int 926privsock(int ty) 927{ 928 int sock = inetresport(ty); 929 930 if (sock < 0) { 931 errno = 0; 932 /* Couldn't get a secure port, let RPC make an insecure one */ 933 sock = RPC_ANYSOCK; 934 } 935 return sock; 936} 937 938#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 939