Remove bogus sys_nerr defines
[dragonfly.git] / contrib / amd / amq / amq.c
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: src/contrib/amd/amq/amq.c,v 1.5 1999/09/15 05:45:14 obrien Exp $
43  * $DragonFly: src/contrib/amd/amq/amq.c,v 1.3 2004/01/23 19:49:35 joerg Exp $
44  *
45  */
46
47 /*
48  * Automounter query tool
49  */
50
51 #ifndef lint
52 char copyright[] = "\
53 @(#)Copyright (c) 1997-1999 Erez Zadok\n\
54 @(#)Copyright (c) 1990 Jan-Simon Pendry\n\
55 @(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
56 @(#)Copyright (c) 1990 The Regents of the University of California.\n\
57 @(#)All rights reserved.\n";
58 #if __GNUC__ < 2
59 static char rcsid[] = "$Id: amq.c,v 1.6 1999/09/08 23:36:40 ezk Exp $";
60 static char sccsid[] = "%W% (Berkeley) %G%";
61 #endif /* __GNUC__ < 2 */
62 #endif /* not lint */
63
64 #ifdef HAVE_CONFIG_H
65 # include <config.h>
66 #endif /* HAVE_CONFIG_H */
67 #include <am_defs.h>
68 #include <amq.h>
69
70 /* locals */
71 static int flush_flag;
72 static int minfo_flag;
73 static int getpid_flag;
74 static int unmount_flag;
75 static int stats_flag;
76 static int getvers_flag;
77 static int amd_program_number = AMQ_PROGRAM;
78 static int use_tcp_flag, use_udp_flag;
79 static char *debug_opts;
80 static char *amq_logfile;
81 static char *mount_map;
82 static char *xlog_optstr;
83 static char localhost[] = "localhost";
84 static char *def_server = localhost;
85
86 /* externals */
87 extern int optind;
88 extern char *optarg;
89
90 /* forward declarations */
91 #ifdef HAVE_TRANSPORT_TYPE_TLI
92 static CLIENT *get_secure_amd_client(char *host, struct timeval *tv, int *sock);
93 static int amq_bind_resv_port(int td, u_short *pp);
94 #else /* not HAVE_TRANSPORT_TYPE_TLI */
95 static int privsock(int ty);
96 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
97
98 /* structures */
99 enum show_opt {
100   Full, Stats, Calc, Short, ShowDone
101 };
102
103
104 /*
105  * If (e) is Calc then just calculate the sizes
106  * Otherwise display the mount node on stdout
107  */
108 static void
109 show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid)
110 {
111   switch (e) {
112   case Calc:
113     {
114       int mw = strlen(mt->mt_mountinfo);
115       int dw = strlen(mt->mt_directory);
116       int tw = strlen(mt->mt_type);
117       if (mw > *mwid)
118         *mwid = mw;
119       if (dw > *dwid)
120         *dwid = dw;
121       if (tw > *twid)
122         *twid = tw;
123     }
124   break;
125
126   case Full:
127     {
128       struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
129       printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
130              *dwid, *dwid,
131              *mt->mt_directory ? mt->mt_directory : "/",        /* XXX */
132              *twid, *twid,
133              mt->mt_type,
134              *mwid, *mwid,
135              mt->mt_mountinfo,
136              mt->mt_mountpoint,
137
138              mt->mt_mountuid,
139              mt->mt_getattr,
140              mt->mt_lookup,
141              mt->mt_readdir,
142              mt->mt_readlink,
143              mt->mt_statfs,
144
145              tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
146              tp->tm_mon + 1, tp->tm_mday,
147              tp->tm_hour, tp->tm_min, tp->tm_sec);
148     }
149   break;
150
151   case Stats:
152     {
153       struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
154       printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
155              *dwid, *dwid,
156              *mt->mt_directory ? mt->mt_directory : "/",        /* XXX */
157
158              mt->mt_mountuid,
159              mt->mt_getattr,
160              mt->mt_lookup,
161              mt->mt_readdir,
162              mt->mt_readlink,
163              mt->mt_statfs,
164
165              tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
166              tp->tm_mon + 1, tp->tm_mday,
167              tp->tm_hour, tp->tm_min, tp->tm_sec);
168     }
169   break;
170
171   case Short:
172     {
173       printf("%-*.*s %-*.*s %-*.*s %s\n",
174              *dwid, *dwid,
175              *mt->mt_directory ? mt->mt_directory : "/",
176              *twid, *twid,
177              mt->mt_type,
178              *mwid, *mwid,
179              mt->mt_mountinfo,
180              mt->mt_mountpoint);
181     }
182   break;
183
184   default:
185     break;
186   }
187 }
188
189 /*
190  * Display a mount tree.
191  */
192 static void
193 show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid)
194 {
195   while (mt) {
196     show_mti(mt, e, mwid, dwid, pwid);
197     show_mt(mt->mt_next, e, mwid, dwid, pwid);
198     mt = mt->mt_child;
199   }
200 }
201
202 static void
203 show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid)
204 {
205   int i;
206
207   switch (e) {
208
209   case Calc:
210     {
211       for (i = 0; i < ml->amq_mount_info_list_len; i++) {
212         amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
213         int mw = strlen(mi->mi_mountinfo);
214         int dw = strlen(mi->mi_mountpt);
215         int tw = strlen(mi->mi_type);
216         if (mw > *mwid)
217           *mwid = mw;
218         if (dw > *dwid)
219           *dwid = dw;
220         if (tw > *twid)
221           *twid = tw;
222       }
223     }
224   break;
225
226   case Full:
227     {
228       for (i = 0; i < ml->amq_mount_info_list_len; i++) {
229         amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
230         printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
231                *mwid, *mwid, mi->mi_mountinfo,
232                *dwid, *dwid, mi->mi_mountpt,
233                *twid, *twid, mi->mi_type,
234                mi->mi_refc, mi->mi_fserver,
235                mi->mi_up > 0 ? "up" :
236                mi->mi_up < 0 ? "starting" : "down");
237         if (mi->mi_error > 0) {
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  */
263 static void
264 show_ms(amq_mount_stats *ms)
265 {
266   printf("\
267 requests  stale     mount     mount     unmount\n\
268 deferred  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)
275 static char *
276 cluster_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  */
298 int
299 main(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, "\
419 Usage: %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 */
733 static int
734 amq_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  */
787 static CLIENT *
788 get_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
862 tryudp:
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  */
914 static int
915 inetresport(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  */
948 static int
949 privsock(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 */