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