amq.c revision 50366
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.3 1999/01/13 20:03:56 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.3 1999/01/13 20:03:56 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#ifdef ENABLE_AMQ_MOUNT 341 while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:pP:TU")) != -1) 342#else 343 while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:pP:TU")) != -1) 344#endif 345 switch (opt_ch) { 346 case 'f': 347 flush_flag = 1; 348 nodefault = 1; 349 break; 350 351 case 'h': 352 def_server = optarg; 353 break; 354 355 case 'l': 356 amq_logfile = optarg; 357 nodefault = 1; 358 break; 359 360 case 'm': 361 minfo_flag = 1; 362 nodefault = 1; 363 break; 364 365 case 'p': 366 getpid_flag = 1; 367 nodefault = 1; 368 break; 369 370 case 's': 371 stats_flag = 1; 372 nodefault = 1; 373 break; 374 375 case 'u': 376 unmount_flag = 1; 377 nodefault = 1; 378 break; 379 380 case 'v': 381 getvers_flag = 1; 382 nodefault = 1; 383 break; 384 385 case 'x': 386 xlog_optstr = optarg; 387 nodefault = 1; 388 break; 389 390 case 'D': 391 debug_opts = optarg; 392 nodefault = 1; 393 break; 394 395 case 'M': 396 mount_map = optarg; 397 nodefault = 1; 398 break; 399 400 case 'P': 401 amd_program_number = atoi(optarg); 402 break; 403 404 case 'T': 405 use_tcp_flag = 1; 406 break; 407 408 case 'U': 409 use_udp_flag = 1; 410 break; 411 412 default: 413 errs = 1; 414 break; 415 } 416 417 if (optind == argc) { 418 if (unmount_flag) 419 errs = 1; 420 } 421 if (errs) { 422 show_usage: 423 fprintf(stderr, "\ 424Usage: %s [-h host] [[-f] [-m] [-p] [-v] [-s]] | [[-u] directory ...]]\n\ 425\t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts] [-M mapent]\n\ 426\t[-P prognum] [-T] [-U]\n", am_get_progname()); 427 exit(1); 428 } 429 430 /* set use_udp and use_tcp flags both to on if none are defined */ 431 if (!use_tcp_flag && !use_udp_flag) 432 use_tcp_flag = use_udp_flag = 1; 433 434#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) 435 /* 436 * Figure out root server of cluster 437 */ 438 if (def_server == localhost) 439 server = cluster_server(); 440 else 441#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ 442 server = def_server; 443 444 /* 445 * Get address of server 446 */ 447 if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) { 448 fprintf(stderr, "%s: Can't get address of %s\n", 449 am_get_progname(), server); 450 exit(1); 451 } 452 memset(&server_addr, 0, sizeof server_addr); 453 server_addr.sin_family = AF_INET; 454 if (hp) { 455 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr, 456 sizeof(server_addr.sin_addr)); 457 } else { 458 /* fake "localhost" */ 459 server_addr.sin_addr.s_addr = htonl(0x7f000001); 460 } 461 462 /* 463 * Create RPC endpoint 464 */ 465 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */ 466 tv.tv_usec = 0; 467 468#ifdef HAVE_TRANSPORT_TYPE_TLI 469 clnt = get_secure_amd_client(server, &tv, &s); 470 if (!clnt && use_tcp_flag) /* try tcp first */ 471 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp"); 472 if (!clnt && use_udp_flag) { /* try udp next */ 473 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp"); 474 /* if ok, set timeout (valid for connectionless transports only) */ 475 if (clnt) 476 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv); 477 } 478#else /* not HAVE_TRANSPORT_TYPE_TLI */ 479 480 /* first check if remote portmapper is up */ 481 cs = pmap_ping(&server_addr); 482 if (cs == RPC_TIMEDOUT) { 483 fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n", 484 am_get_progname(), server, clnt_sperrno(cs)); 485 exit(1); 486 } 487 488 /* portmapper exists: get remote amd info from it */ 489 if (!clnt && use_tcp_flag) { /* try tcp first */ 490 s = RPC_ANYSOCK; 491 clnt = clnttcp_create(&server_addr, amd_program_number, 492 AMQ_VERSION, &s, 0, 0); 493 } 494 if (!clnt && use_udp_flag) { /* try udp next */ 495 /* XXX: do we need to close(s) ? */ 496 s = privsock(SOCK_DGRAM); 497 clnt = clntudp_create(&server_addr, amd_program_number, 498 AMQ_VERSION, tv, &s); 499 } 500#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 501 if (!clnt) { 502 fprintf(stderr, "%s: ", am_get_progname()); 503 clnt_pcreateerror(server); 504 exit(1); 505 } 506 507 /* 508 * Control debugging 509 */ 510 if (debug_opts) { 511 int *rc; 512 amq_setopt opt; 513 opt.as_opt = AMOPT_DEBUG; 514 opt.as_str = debug_opts; 515 rc = amqproc_setopt_1(&opt, clnt); 516 if (rc && *rc < 0) { 517 fprintf(stderr, "%s: daemon not compiled for debug\n", 518 am_get_progname()); 519 errs = 1; 520 } else if (!rc || *rc > 0) { 521 fprintf(stderr, "%s: debug setting for \"%s\" failed\n", 522 am_get_progname(), debug_opts); 523 errs = 1; 524 } 525 } 526 527 /* 528 * Control logging 529 */ 530 if (xlog_optstr) { 531 int *rc; 532 amq_setopt opt; 533 opt.as_opt = AMOPT_XLOG; 534 opt.as_str = xlog_optstr; 535 rc = amqproc_setopt_1(&opt, clnt); 536 if (!rc || *rc) { 537 fprintf(stderr, "%s: setting log level to \"%s\" failed\n", 538 am_get_progname(), xlog_optstr); 539 errs = 1; 540 } 541 } 542 543 /* 544 * Control log file 545 */ 546 if (amq_logfile) { 547 int *rc; 548 amq_setopt opt; 549 opt.as_opt = AMOPT_LOGFILE; 550 opt.as_str = amq_logfile; 551 rc = amqproc_setopt_1(&opt, clnt); 552 if (!rc || *rc) { 553 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", 554 am_get_progname(), amq_logfile); 555 errs = 1; 556 } 557 } 558 559 /* 560 * Flush map cache 561 */ 562 if (flush_flag) { 563 int *rc; 564 amq_setopt opt; 565 opt.as_opt = AMOPT_FLUSHMAPC; 566 opt.as_str = ""; 567 rc = amqproc_setopt_1(&opt, clnt); 568 if (!rc || *rc) { 569 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", 570 am_get_progname(), server); 571 errs = 1; 572 } 573 } 574 575 /* 576 * Mount info 577 */ 578 if (minfo_flag) { 579 int dummy; 580 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt); 581 if (ml) { 582 int mwid = 0, dwid = 0, twid = 0; 583 show_mi(ml, Calc, &mwid, &dwid, &twid); 584 mwid++; 585 dwid++; 586 twid++; 587 show_mi(ml, Full, &mwid, &dwid, &twid); 588 589 } else { 590 fprintf(stderr, "%s: amd on %s cannot provide mount info\n", 591 am_get_progname(), server); 592 } 593 } 594 595 /* 596 * Mount map 597 */ 598 if (mount_map) { 599 int *rc; 600 do { 601 rc = amqproc_mount_1(&mount_map, clnt); 602 } while (rc && *rc < 0); 603 if (!rc || *rc > 0) { 604 if (rc) 605 errno = *rc; 606 else 607 errno = ETIMEDOUT; 608 fprintf(stderr, "%s: could not start new ", am_get_progname()); 609 perror("automount point"); 610 } 611 } 612 613 /* 614 * Get Version 615 */ 616 if (getvers_flag) { 617 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt); 618 if (spp && *spp) { 619 fputs(*spp, stdout); 620 XFREE(*spp); 621 } else { 622 fprintf(stderr, "%s: failed to get version information\n", 623 am_get_progname()); 624 errs = 1; 625 } 626 } 627 628 /* 629 * Get PID of amd 630 */ 631 if (getpid_flag) { 632 int *ip = amqproc_getpid_1((voidp) 0, clnt); 633 if (ip && *ip) { 634 printf("%d\n", *ip); 635 } else { 636 fprintf(stderr, "%s: failed to get PID of amd\n", am_get_progname()); 637 errs = 1; 638 } 639 } 640 641 /* 642 * Apply required operation to all remaining arguments 643 */ 644 if (optind < argc) { 645 do { 646 char *fs = argv[optind++]; 647 if (unmount_flag) { 648 /* 649 * Unmount request 650 */ 651 amqproc_umnt_1(&fs, clnt); 652 } else { 653 /* 654 * Stats request 655 */ 656 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt); 657 if (mtp) { 658 amq_mount_tree *mt = *mtp; 659 if (mt) { 660 int mwid = 0, dwid = 0, twid = 0; 661 show_mt(mt, Calc, &mwid, &dwid, &twid); 662 mwid++; 663 dwid++, twid++; 664 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n", 665 dwid, dwid, "What"); 666 show_mt(mt, Stats, &mwid, &dwid, &twid); 667 } else { 668 fprintf(stderr, "%s: %s not automounted\n", am_get_progname(), fs); 669 } 670 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp); 671 } else { 672 fprintf(stderr, "%s: ", am_get_progname()); 673 clnt_perror(clnt, server); 674 errs = 1; 675 } 676 } 677 } while (optind < argc); 678 679 } else if (unmount_flag) { 680 goto show_usage; 681 682 } else if (stats_flag) { 683 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt); 684 if (ms) { 685 show_ms(ms); 686 } else { 687 fprintf(stderr, "%s: ", am_get_progname()); 688 clnt_perror(clnt, server); 689 errs = 1; 690 } 691 692 } else if (!nodefault) { 693 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt); 694 if (mlp) { 695 enum show_opt e = Calc; 696 int mwid = 0, dwid = 0, pwid = 0; 697 while (e != ShowDone) { 698 int i; 699 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) { 700 show_mt(mlp->amq_mount_tree_list_val[i], 701 e, &mwid, &dwid, &pwid); 702 } 703 mwid++; 704 dwid++, pwid++; 705 if (e == Calc) 706 e = Short; 707 else if (e == Short) 708 e = ShowDone; 709 } 710 711 } else { 712 fprintf(stderr, "%s: ", am_get_progname()); 713 clnt_perror(clnt, server); 714 errs = 1; 715 } 716 } 717 exit(errs); 718 return errs; /* should never reach here */ 719} 720 721 722#ifdef HAVE_TRANSPORT_TYPE_TLI 723 724/* 725 * How to bind to reserved ports. 726 * TLI handle (socket) and port version. 727 */ 728/* defined here so that it does not have to resolve it with libamu.a */ 729static int 730amq_bind_resv_port(int td, u_short *pp) 731{ 732 int rc = -1, port; 733 struct t_bind *treq, *tret; 734 struct sockaddr_in *sin; 735 736 treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); 737 if (!treq) { 738 plog(XLOG_ERROR, "t_alloc 1"); 739 return -1; 740 } 741 tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); 742 if (!tret) { 743 t_free((char *) treq, T_BIND); 744 plog(XLOG_ERROR, "t_alloc 2"); 745 return -1; 746 } 747 memset((char *) treq->addr.buf, 0, treq->addr.len); 748 sin = (struct sockaddr_in *) treq->addr.buf; 749 sin->sin_family = AF_INET; 750 treq->qlen = 0; 751 treq->addr.len = treq->addr.maxlen; 752 errno = EADDRINUSE; 753 port = IPPORT_RESERVED; 754 755 do { 756 --port; 757 sin->sin_port = htons(port); 758 rc = t_bind(td, treq, tret); 759 if (rc < 0) { 760 } else { 761 if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0) 762 break; 763 else 764 t_unbind(td); 765 } 766 } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2); 767 768 if (pp) { 769 if (rc == 0) 770 *pp = port; 771 else 772 plog(XLOG_ERROR, "could not t_bind to any reserved port"); 773 } 774 t_free((char *) tret, T_BIND); 775 t_free((char *) treq, T_BIND); 776 return rc; 777} 778 779 780/* 781 * Create a secure rpc client attached to the amd daemon. 782 */ 783static CLIENT * 784get_secure_amd_client(char *host, struct timeval *tv, int *sock) 785{ 786 CLIENT *client; 787 struct netbuf nb; 788 struct netconfig *nc, *pm_nc; 789 struct sockaddr_in sin; 790 791 792 nb.maxlen = sizeof(sin); 793 nb.buf = (char *) &sin; 794 795 /* 796 * Ensure that remote portmapper is alive 797 * (must use connectionless netconfig). 798 */ 799 if ((pm_nc = getnetconfigent(NC_UDP)) != NULL) { 800 enum clnt_stat cs; 801 802 cs = rpcb_rmtcall(pm_nc, 803 host, 804 amd_program_number, 805 AMQ_VERSION, 806 AMQPROC_NULL, 807 (XDRPROC_T_TYPE) xdr_void, 808 NULL, 809 (XDRPROC_T_TYPE) xdr_void, 810 NULL, 811 *tv, 812 NULL); 813 if (cs == RPC_TIMEDOUT) { 814 fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n", 815 am_get_progname(), host, clnt_sperrno(cs)); 816 exit(1); 817 } 818 } 819 820 /* 821 * First transport type to try: TCP 822 */ 823 if (use_tcp_flag) { 824 /* Find amd address on TCP */ 825 nc = getnetconfigent(NC_TCP); 826 if (!nc) { 827 fprintf(stderr, "getnetconfig for tcp failed: %s\n", nc_sperror()); 828 goto tryudp; 829 } 830 831 if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) { 832 /* 833 * don't print error messages here, since amd might legitimately 834 * serve udp only 835 */ 836 goto tryudp; 837 } 838 /* Create privileged TCP socket */ 839 *sock = t_open(nc->nc_device, O_RDWR, 0); 840 841 if (*sock < 0) { 842 fprintf(stderr, "t_open %s: %m\n", nc->nc_device); 843 goto tryudp; 844 } 845 if (amq_bind_resv_port(*sock, (u_short *) 0) < 0) 846 goto tryudp; 847 848 client = clnt_vc_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0); 849 if (!client) { 850 fprintf(stderr, "clnt_vc_create failed"); 851 t_close(*sock); 852 goto tryudp; 853 } 854 /* tcp succeeded */ 855 return client; 856 } 857 858tryudp: 859 /* 860 * TCP failed so try UDP 861 */ 862 if (use_udp_flag) { 863 /* find amd address on UDP */ 864 nc = getnetconfigent(NC_UDP); 865 if (!nc) { 866 fprintf(stderr, "getnetconfig for udp failed: %s\n", nc_sperror()); 867 return NULL; 868 } 869 if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) { 870 fprintf(stderr, "%s\n", 871 clnt_spcreateerror("couldn't get amd address on udp")); 872 return NULL; 873 } 874 /* create privileged UDP socket */ 875 *sock = t_open(nc->nc_device, O_RDWR, 0); 876 877 if (*sock < 0) { 878 fprintf(stderr, "t_open %s: %m\n", nc->nc_device); 879 return NULL; /* neither tcp not udp succeeded */ 880 } 881 if (amq_bind_resv_port(*sock, (u_short *) 0) < 0) 882 return NULL; 883 884 client = clnt_dg_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0); 885 if (!client) { 886 fprintf(stderr, "clnt_dg_create failed\n"); 887 t_close(*sock); 888 return NULL; /* neither tcp not udp succeeded */ 889 } 890 if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) { 891 fprintf(stderr, "clnt_control CLSET_RETRY_TIMEOUT for udp failed\n"); 892 clnt_destroy(client); 893 return NULL; /* neither tcp not udp succeeded */ 894 } 895 /* udp succeeded */ 896 return client; 897 } 898 899 /* should never get here */ 900 return NULL; 901} 902 903#else /* not HAVE_TRANSPORT_TYPE_TLI */ 904 905/* 906 * inetresport creates a datagram socket and attempts to bind it to a 907 * secure port. 908 * returns: The bound socket, or -1 to indicate an error. 909 */ 910static int 911inetresport(int ty) 912{ 913 int alport; 914 struct sockaddr_in addr; 915 int fd; 916 917 /* Use internet address family */ 918 addr.sin_family = AF_INET; 919 addr.sin_addr.s_addr = INADDR_ANY; 920 if ((fd = socket(AF_INET, ty, 0)) < 0) 921 return -1; 922 923 for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) { 924 addr.sin_port = htons((u_short) alport); 925 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) 926 return fd; 927 if (errno != EADDRINUSE) { 928 close(fd); 929 return -1; 930 } 931 } 932 close(fd); 933 errno = EAGAIN; 934 return -1; 935} 936 937 938/* 939 * Privsock() calls inetresport() to attempt to bind a socket to a secure 940 * port. If inetresport() fails, privsock returns a magic socket number which 941 * indicates to RPC that it should make its own socket. 942 * returns: A privileged socket # or RPC_ANYSOCK. 943 */ 944static int 945privsock(int ty) 946{ 947 int sock = inetresport(ty); 948 949 if (sock < 0) { 950 errno = 0; 951 /* Couldn't get a secure port, let RPC make an insecure one */ 952 sock = RPC_ANYSOCK; 953 } 954 return sock; 955} 956 957#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 958