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