17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
2261961e0fSrobinson
237c478bd9Sstevel@tonic-gate /*
24*e8031f0aSraf * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2561961e0fSrobinson * Use is subject to license terms.
26*e8031f0aSraf */
27*e8031f0aSraf
28*e8031f0aSraf /*
297c478bd9Sstevel@tonic-gate * This module contains the private function __rpc_get_time_offset()
307c478bd9Sstevel@tonic-gate * which will return the difference in seconds between the local system's
317c478bd9Sstevel@tonic-gate * notion of time and a remote server's notion of time. This must be
327c478bd9Sstevel@tonic-gate * possible without calling any functions that may invoke the name
337c478bd9Sstevel@tonic-gate * service. (netdir_getbyxxx, getXbyY, etc). The function is used in the
347c478bd9Sstevel@tonic-gate * synchronize call of the authdes code to synchronize clocks between
357c478bd9Sstevel@tonic-gate * NIS+ clients and their servers.
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate * Note to minimize the amount of duplicate code, portions of the
387c478bd9Sstevel@tonic-gate * synchronize() function were folded into this code, and the synchronize
397c478bd9Sstevel@tonic-gate * call becomes simply a wrapper around this function. Further, if this
407c478bd9Sstevel@tonic-gate * function is called with a timehost it *DOES* recurse to the name
417c478bd9Sstevel@tonic-gate * server so don't use it in that mode if you are doing name service code.
427c478bd9Sstevel@tonic-gate *
437c478bd9Sstevel@tonic-gate * Side effects :
447c478bd9Sstevel@tonic-gate * When called a client handle to a RPCBIND process is created
457c478bd9Sstevel@tonic-gate * and destroyed. Two strings "netid" and "uaddr" are malloc'd
467c478bd9Sstevel@tonic-gate * and returned. The SIGALRM processing is modified only if
477c478bd9Sstevel@tonic-gate * needed to deal with TCP connections.
487c478bd9Sstevel@tonic-gate */
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
517c478bd9Sstevel@tonic-gate
52*e8031f0aSraf #include "mt.h"
537c478bd9Sstevel@tonic-gate #include <stdio.h>
547c478bd9Sstevel@tonic-gate #include <stdlib.h>
557c478bd9Sstevel@tonic-gate #include <unistd.h>
567c478bd9Sstevel@tonic-gate #include <syslog.h>
577c478bd9Sstevel@tonic-gate #include <netdir.h>
587c478bd9Sstevel@tonic-gate #include <string.h>
5961961e0fSrobinson #include <strings.h>
607c478bd9Sstevel@tonic-gate #include <netconfig.h>
617c478bd9Sstevel@tonic-gate #include <netdb.h>
627c478bd9Sstevel@tonic-gate #include <signal.h>
637c478bd9Sstevel@tonic-gate #include <sys/errno.h>
647c478bd9Sstevel@tonic-gate #include <sys/poll.h>
657c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
667c478bd9Sstevel@tonic-gate #include <rpc/nettype.h>
677c478bd9Sstevel@tonic-gate #undef NIS
687c478bd9Sstevel@tonic-gate #include <rpcsvc/nis.h>
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate extern void __nis_netconfig2ep(struct netconfig *, endpoint *);
727c478bd9Sstevel@tonic-gate extern bool_t __nis_netconfig_matches_ep(struct netconfig *, endpoint *);
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate #ifdef TESTING
757c478bd9Sstevel@tonic-gate #define msg(x) printf("ERROR: %s\n", x)
767c478bd9Sstevel@tonic-gate /* #define msg(x) syslog(LOG_ERR, "%s", x) */
777c478bd9Sstevel@tonic-gate #else
787c478bd9Sstevel@tonic-gate #define msg(x)
797c478bd9Sstevel@tonic-gate #endif
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate static int saw_alarm = 0;
827c478bd9Sstevel@tonic-gate
8361961e0fSrobinson /* ARGSUSED */
847c478bd9Sstevel@tonic-gate static void
alarm_hndler(int s)8561961e0fSrobinson alarm_hndler(int s)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate saw_alarm = 1;
887c478bd9Sstevel@tonic-gate }
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate * The internet time server defines the epoch to be Jan 1, 1900
927c478bd9Sstevel@tonic-gate * whereas UNIX defines it to be Jan 1, 1970. To adjust the result
937c478bd9Sstevel@tonic-gate * from internet time-service time, into UNIX time we subtract the
947c478bd9Sstevel@tonic-gate * following offset :
957c478bd9Sstevel@tonic-gate */
967c478bd9Sstevel@tonic-gate #define NYEARS (1970 - 1900)
977c478bd9Sstevel@tonic-gate #define TOFFSET ((uint_t)60*60*24*(365*NYEARS + (NYEARS/4)))
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate * free_eps()
1017c478bd9Sstevel@tonic-gate *
1027c478bd9Sstevel@tonic-gate * Free the strings that were strduped into the eps structure.
1037c478bd9Sstevel@tonic-gate */
1047c478bd9Sstevel@tonic-gate static void
free_eps(endpoint eps[],int num)1057c478bd9Sstevel@tonic-gate free_eps(endpoint eps[], int num)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate int i;
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate for (i = 0; i < num; i++) {
1107c478bd9Sstevel@tonic-gate free(eps[i].uaddr);
1117c478bd9Sstevel@tonic-gate free(eps[i].proto);
1127c478bd9Sstevel@tonic-gate free(eps[i].family);
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate * get_server()
1187c478bd9Sstevel@tonic-gate *
1197c478bd9Sstevel@tonic-gate * This function constructs a nis_server structure description for the
1207c478bd9Sstevel@tonic-gate * indicated hostname.
1217c478bd9Sstevel@tonic-gate */
1227c478bd9Sstevel@tonic-gate static nis_server *
get_server(char * host,nis_server * srv,endpoint eps[],int maxep)1237c478bd9Sstevel@tonic-gate get_server(char *host, nis_server *srv, endpoint eps[], int maxep)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate int num_ep = 0, i;
1267c478bd9Sstevel@tonic-gate struct netconfig *nc;
1277c478bd9Sstevel@tonic-gate void *nch;
1287c478bd9Sstevel@tonic-gate struct nd_hostserv hs;
1297c478bd9Sstevel@tonic-gate struct nd_addrlist *addrs;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate if (! host)
1327c478bd9Sstevel@tonic-gate return (NULL);
1337c478bd9Sstevel@tonic-gate hs.h_host = host;
1347c478bd9Sstevel@tonic-gate hs.h_serv = "rpcbind";
1357c478bd9Sstevel@tonic-gate nch = setnetconfig();
1367c478bd9Sstevel@tonic-gate while (nc = getnetconfig(nch)) {
1377c478bd9Sstevel@tonic-gate if ((nc->nc_flag & NC_VISIBLE) == 0)
1387c478bd9Sstevel@tonic-gate continue;
1397c478bd9Sstevel@tonic-gate if (! netdir_getbyname(nc, &hs, &addrs)) {
1407c478bd9Sstevel@tonic-gate for (i = 0; (i < (addrs->n_cnt)) && (num_ep < maxep);
1417c478bd9Sstevel@tonic-gate i++, num_ep++) {
1427c478bd9Sstevel@tonic-gate eps[num_ep].uaddr =
1437c478bd9Sstevel@tonic-gate taddr2uaddr(nc, &(addrs->n_addrs[i]));
1447c478bd9Sstevel@tonic-gate __nis_netconfig2ep(nc, &(eps[num_ep]));
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate netdir_free((char *)addrs, ND_ADDRLIST);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate }
14961961e0fSrobinson (void) endnetconfig(nch);
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate srv->name = (nis_name) host;
1527c478bd9Sstevel@tonic-gate srv->ep.ep_len = num_ep;
1537c478bd9Sstevel@tonic-gate srv->ep.ep_val = eps;
1547c478bd9Sstevel@tonic-gate srv->key_type = NIS_PK_NONE;
1557c478bd9Sstevel@tonic-gate srv->pkey.n_bytes = NULL;
1567c478bd9Sstevel@tonic-gate srv->pkey.n_len = 0;
1577c478bd9Sstevel@tonic-gate return (srv);
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate #define MEP(ep, prot) (strcasecmp(ep.proto, prot) == 0)
1617c478bd9Sstevel@tonic-gate #define MAX_ENDPOINTS 32
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate * __rpc_get_time_offset()
1657c478bd9Sstevel@tonic-gate *
1667c478bd9Sstevel@tonic-gate * This function uses a nis_server structure to contact the a remote
1677c478bd9Sstevel@tonic-gate * machine (as named in that structure) and returns the offset in time
1687c478bd9Sstevel@tonic-gate * between that machine and this one. This offset is returned in seconds
1697c478bd9Sstevel@tonic-gate * and may be positive or negative.
1707c478bd9Sstevel@tonic-gate *
1717c478bd9Sstevel@tonic-gate * The first time through, a lot of fiddling is done with the netconfig
1727c478bd9Sstevel@tonic-gate * stuff to find a suitable transport. The function is very aggressive
1737c478bd9Sstevel@tonic-gate * about choosing UDP or at worst TCP if it can. This is because
1747c478bd9Sstevel@tonic-gate * those transports support both the RCPBIND call and the internet
1757c478bd9Sstevel@tonic-gate * time service.
1767c478bd9Sstevel@tonic-gate *
1777c478bd9Sstevel@tonic-gate * Once through, *uaddr is set to the universal address of
1787c478bd9Sstevel@tonic-gate * the machine and *netid is set to the local netid for the transport
1797c478bd9Sstevel@tonic-gate * that uaddr goes with. On the second call, the netconfig stuff
1807c478bd9Sstevel@tonic-gate * is skipped and the uaddr/netid pair are used to fetch the netconfig
1817c478bd9Sstevel@tonic-gate * structure and to then contact the machine for the time.
1827c478bd9Sstevel@tonic-gate *
1837c478bd9Sstevel@tonic-gate * td = "server" - "client"
1847c478bd9Sstevel@tonic-gate */
1857c478bd9Sstevel@tonic-gate int
__rpc_get_time_offset(struct timeval * td,nis_server * srv,char * thost,char ** uaddr,char ** netid)1867c478bd9Sstevel@tonic-gate __rpc_get_time_offset(struct timeval *td, nis_server *srv,
1877c478bd9Sstevel@tonic-gate char *thost, char **uaddr, char **netid)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate CLIENT *clnt; /* Client handle */
1907c478bd9Sstevel@tonic-gate struct netbuf *addr = 0; /* address */
1917c478bd9Sstevel@tonic-gate void *nc_handle; /* Netconfig "state" */
1927c478bd9Sstevel@tonic-gate struct netconfig *nc; /* Various handles */
1937c478bd9Sstevel@tonic-gate endpoint *ep; /* useful endpoints */
1947c478bd9Sstevel@tonic-gate char *useua = NULL, /* uaddr of selected xp */
1957c478bd9Sstevel@tonic-gate *useid = NULL; /* netid of selected xp */
1967c478bd9Sstevel@tonic-gate int epl, i; /* counters */
1977c478bd9Sstevel@tonic-gate enum clnt_stat status; /* result of clnt_call */
1987c478bd9Sstevel@tonic-gate uint_t thetime;
1997c478bd9Sstevel@tonic-gate ulong_t delta;
2007c478bd9Sstevel@tonic-gate int needfree = 0;
2017c478bd9Sstevel@tonic-gate struct timeval tv;
2027c478bd9Sstevel@tonic-gate int rtime_fd = -1, time_valid, flag = 0;
2037c478bd9Sstevel@tonic-gate int a1, a2, a3, a4;
2047c478bd9Sstevel@tonic-gate char ut[INET6_ADDRSTRLEN];
2057c478bd9Sstevel@tonic-gate char ipuaddr[INET6_ADDRSTRLEN];
2067c478bd9Sstevel@tonic-gate endpoint teps[MAX_ENDPOINTS],
2077c478bd9Sstevel@tonic-gate *epcand[MAX_ENDPOINTS],
2087c478bd9Sstevel@tonic-gate *nonipcand[MAX_ENDPOINTS],
2097c478bd9Sstevel@tonic-gate supplied;
2107c478bd9Sstevel@tonic-gate uint32_t epc, nonip;
2117c478bd9Sstevel@tonic-gate nis_server tsrv;
2127c478bd9Sstevel@tonic-gate void (*oldsig)() = NULL; /* old alarm handler */
2137c478bd9Sstevel@tonic-gate char *dot = NULL; /* tmp pointer */
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate nc = NULL;
2187c478bd9Sstevel@tonic-gate td->tv_sec = 0;
2197c478bd9Sstevel@tonic-gate td->tv_usec = 0;
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /*
2227c478bd9Sstevel@tonic-gate * First check to see if we need to find and address for this
2237c478bd9Sstevel@tonic-gate * server.
2247c478bd9Sstevel@tonic-gate */
2257c478bd9Sstevel@tonic-gate if (*uaddr == NULL) {
2267c478bd9Sstevel@tonic-gate if ((srv != NULL) && (thost != NULL)) {
2277c478bd9Sstevel@tonic-gate msg("both timehost and srv pointer used!");
2287c478bd9Sstevel@tonic-gate return (0);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate if (! srv) {
2317c478bd9Sstevel@tonic-gate srv = get_server(thost, &tsrv, teps, 32);
2327c478bd9Sstevel@tonic-gate if (! srv) {
2337c478bd9Sstevel@tonic-gate msg("unable to contruct server data.");
2347c478bd9Sstevel@tonic-gate return (0);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate needfree = 1; /* need to free data in endpoints */
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate nc_handle = (void *) setnetconfig();
2407c478bd9Sstevel@tonic-gate if (! nc_handle) {
2417c478bd9Sstevel@tonic-gate msg("unable to get netconfig info.");
2427c478bd9Sstevel@tonic-gate if (needfree)
2437c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
2447c478bd9Sstevel@tonic-gate return (0);
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate ep = srv->ep.ep_val;
2487c478bd9Sstevel@tonic-gate epl = srv->ep.ep_len;
2497c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (epcand)/sizeof (epcand[0]); i++) {
2507c478bd9Sstevel@tonic-gate epcand[i] = 0;
2517c478bd9Sstevel@tonic-gate nonipcand[i] = 0;
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate epc = 0;
2547c478bd9Sstevel@tonic-gate nonip = 0;
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate * Build the list of endpoint candidates. We prefer transports
2587c478bd9Sstevel@tonic-gate * that we know are IP, but let /etc/netconfig determine the
2597c478bd9Sstevel@tonic-gate * ordering among the IP transports.
2607c478bd9Sstevel@tonic-gate *
2617c478bd9Sstevel@tonic-gate * Note: We assume that the endpoint 'proto' field contains
2627c478bd9Sstevel@tonic-gate * the netid of the transport.
2637c478bd9Sstevel@tonic-gate */
2647c478bd9Sstevel@tonic-gate while ((nc = getnetconfig(nc_handle)) != NULL) {
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /* Is it a visible transport ? */
2677c478bd9Sstevel@tonic-gate if ((nc->nc_flag & NC_VISIBLE) == 0)
2687c478bd9Sstevel@tonic-gate continue;
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate /* Check against the end points */
2717c478bd9Sstevel@tonic-gate for (i = 0; i < epl; i++) {
2727c478bd9Sstevel@tonic-gate if (__nis_netconfig_matches_ep(nc, &(ep[i]))) {
2737c478bd9Sstevel@tonic-gate if (MEP(ep[i], "udp") ||
2747c478bd9Sstevel@tonic-gate MEP(ep[i], "udp6") ||
2757c478bd9Sstevel@tonic-gate MEP(ep[i], "tcp") ||
2767c478bd9Sstevel@tonic-gate MEP(ep[i], "tcp6")) {
2777c478bd9Sstevel@tonic-gate epcand[epc++] = &(ep[i]);
2787c478bd9Sstevel@tonic-gate } else {
2797c478bd9Sstevel@tonic-gate nonipcand[nonip++] = &ep[i];
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate break;
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate
28661961e0fSrobinson (void) endnetconfig(nc_handle);
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate * epcand[] now contains the candidate transports. If there
2907c478bd9Sstevel@tonic-gate * were non-IP transports as well, add them to the end of the
2917c478bd9Sstevel@tonic-gate * candidate list.
2927c478bd9Sstevel@tonic-gate */
2937c478bd9Sstevel@tonic-gate for (i = 0; i < nonip; i++) {
2947c478bd9Sstevel@tonic-gate epcand[epc++] = nonipcand[i];
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate if (epc == 0) {
2987c478bd9Sstevel@tonic-gate msg("no acceptable transport endpoints.");
2997c478bd9Sstevel@tonic-gate if (needfree)
3007c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
3017c478bd9Sstevel@tonic-gate return (0);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate } else {
3047c478bd9Sstevel@tonic-gate /* Caller supplied a uaddr. Fake an endpoint. */
3057c478bd9Sstevel@tonic-gate if (*netid != 0) {
3067c478bd9Sstevel@tonic-gate supplied.proto = *netid;
3077c478bd9Sstevel@tonic-gate /* Is it one of the known IP transports ? */
3087c478bd9Sstevel@tonic-gate if (strcmp("udp", supplied.proto) &&
3097c478bd9Sstevel@tonic-gate strcmp("udp6", supplied.proto) &&
3107c478bd9Sstevel@tonic-gate strcmp("tcp", supplied.proto) &&
3117c478bd9Sstevel@tonic-gate strcmp("tcp6", supplied.proto)) {
3127c478bd9Sstevel@tonic-gate /* No, it's not */
3137c478bd9Sstevel@tonic-gate nonip = 1;
3147c478bd9Sstevel@tonic-gate } else {
3157c478bd9Sstevel@tonic-gate nonip = 0;
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate } else {
3187c478bd9Sstevel@tonic-gate supplied.proto = (strchr(*uaddr, ':') != 0) ?
3197c478bd9Sstevel@tonic-gate "udp6" : "udp";
3207c478bd9Sstevel@tonic-gate nonip = 0;
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate supplied.uaddr = *uaddr;
3237c478bd9Sstevel@tonic-gate supplied.family = (strchr(*uaddr, ':') != 0) ?
3247c478bd9Sstevel@tonic-gate "inet6" : "inet";
3257c478bd9Sstevel@tonic-gate epcand[0] = &supplied;
3267c478bd9Sstevel@tonic-gate epc = 1;
3277c478bd9Sstevel@tonic-gate nonip = 0;
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate nc = 0;
3317c478bd9Sstevel@tonic-gate clnt = 0;
3327c478bd9Sstevel@tonic-gate status = RPC_FAILED; /* Anything except RPC_SUCCESS */
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate /*
3357c478bd9Sstevel@tonic-gate * Loop over the endpoint candidates. Defer error reporting (except
3367c478bd9Sstevel@tonic-gate * for the netconfig entry) until we've looked at all candidates.
3377c478bd9Sstevel@tonic-gate */
3387c478bd9Sstevel@tonic-gate for (i = 0; i < epc; i++) {
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate if (nc != 0)
3417c478bd9Sstevel@tonic-gate freenetconfigent(nc);
3427c478bd9Sstevel@tonic-gate nc = getnetconfigent(epcand[i]->proto);
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate if (nc == 0) {
3457c478bd9Sstevel@tonic-gate msg("unable to locate netconfig info for netid.");
3467c478bd9Sstevel@tonic-gate if (needfree)
3477c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
3487c478bd9Sstevel@tonic-gate return (0);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate /*
3527c478bd9Sstevel@tonic-gate * Add the appropriate port number to the uaddr
3537c478bd9Sstevel@tonic-gate */
3547c478bd9Sstevel@tonic-gate useua = epcand[i]->uaddr;
3557c478bd9Sstevel@tonic-gate useid = epcand[i]->proto;
3567c478bd9Sstevel@tonic-gate if (strcasecmp(nc->nc_protofmly, NC_INET) == 0) {
35761961e0fSrobinson (void) sscanf(useua,
35861961e0fSrobinson "%d.%d.%d.%d.", &a1, &a2, &a3, &a4);
35961961e0fSrobinson (void) sprintf(ipuaddr, "%d.%d.%d.%d.0.111",
36061961e0fSrobinson a1, a2, a3, a4);
3617c478bd9Sstevel@tonic-gate useua = &ipuaddr[0];
3627c478bd9Sstevel@tonic-gate } else if (strcasecmp(nc->nc_protofmly, NC_INET6) == 0) {
3637c478bd9Sstevel@tonic-gate size_t len;
3647c478bd9Sstevel@tonic-gate char *port = ".0.111";
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate if (strlen(useua) >= sizeof (ipuaddr)) {
3677c478bd9Sstevel@tonic-gate freenetconfigent(nc);
3687c478bd9Sstevel@tonic-gate if (needfree)
3697c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
3707c478bd9Sstevel@tonic-gate return (0);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate
37361961e0fSrobinson (void) strcpy(ipuaddr, useua);
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate /* get the IPv6 address out of the uaddr */
3767c478bd9Sstevel@tonic-gate if ((dot = strrchr(ipuaddr, '.')) != 0) {
3777c478bd9Sstevel@tonic-gate *dot = '\0';
3787c478bd9Sstevel@tonic-gate if ((dot = strrchr(ipuaddr, '.')) != 0)
3797c478bd9Sstevel@tonic-gate *dot = '\0';
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate if (dot == 0 ||
3837c478bd9Sstevel@tonic-gate (len = strlen(ipuaddr))+strlen(port) >=
3847c478bd9Sstevel@tonic-gate sizeof (ipuaddr)) {
3857c478bd9Sstevel@tonic-gate freenetconfigent(nc);
3867c478bd9Sstevel@tonic-gate if (needfree)
3877c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
3887c478bd9Sstevel@tonic-gate return (0);
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate /* now put in 0.111 */
39261961e0fSrobinson (void) strcat(ipuaddr + len, port);
3937c478bd9Sstevel@tonic-gate useua = ipuaddr;
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate * Create the client handle to rpcbind. Note we always try
3987c478bd9Sstevel@tonic-gate * version 3 since that is the earliest version that supports
3997c478bd9Sstevel@tonic-gate * the RPCB_GETTIME call. Also it is the version that comes
4007c478bd9Sstevel@tonic-gate * standard with SVR4. Since most everyone supports TCP/IP
4017c478bd9Sstevel@tonic-gate * we could consider trying the rtime call first.
4027c478bd9Sstevel@tonic-gate */
4037c478bd9Sstevel@tonic-gate if (clnt != 0)
4047c478bd9Sstevel@tonic-gate clnt_destroy(clnt);
4057c478bd9Sstevel@tonic-gate clnt = __nis_clnt_create(RPC_ANYFD, nc, useua, 0, 0, RPCBPROG,
4067c478bd9Sstevel@tonic-gate RPCBVERS, 0, 0);
4077c478bd9Sstevel@tonic-gate if (! clnt)
4087c478bd9Sstevel@tonic-gate continue;
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate tv.tv_sec = 5;
4117c478bd9Sstevel@tonic-gate tv.tv_usec = 0;
4127c478bd9Sstevel@tonic-gate time_valid = 0;
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate status = clnt_call(clnt, RPCBPROC_GETTIME, xdr_void, NULL,
4157c478bd9Sstevel@tonic-gate xdr_u_int, (char *)&thetime, tv);
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate * The only error we check for is anything but success. In
4187c478bd9Sstevel@tonic-gate * fact we could have seen PROGMISMATCH if talking to a 4.1
4197c478bd9Sstevel@tonic-gate * machine (pmap v2) or TIMEDOUT if the net was busy.
4207c478bd9Sstevel@tonic-gate */
4217c478bd9Sstevel@tonic-gate if (status == RPC_SUCCESS)
4227c478bd9Sstevel@tonic-gate break;
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate if (status == RPC_SUCCESS) {
4277c478bd9Sstevel@tonic-gate time_valid = 1;
4287c478bd9Sstevel@tonic-gate } else if (clnt == 0) {
4297c478bd9Sstevel@tonic-gate msg("unable to create client handle to rpcbind.");
4307c478bd9Sstevel@tonic-gate freenetconfigent(nc);
4317c478bd9Sstevel@tonic-gate if (needfree)
4327c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
4337c478bd9Sstevel@tonic-gate return (0);
4347c478bd9Sstevel@tonic-gate } else {
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate /*
4377c478bd9Sstevel@tonic-gate * Try the timeservice port. This presumably only exists
4387c478bd9Sstevel@tonic-gate * for IP transports, so we ignore the non-IP ones.
4397c478bd9Sstevel@tonic-gate */
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate for (i = 0; i < epc-nonip; i++) {
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate /*
4447c478bd9Sstevel@tonic-gate * Convert PMAP address into timeservice address
4457c478bd9Sstevel@tonic-gate * We take advantage of the fact that we "know" what
4467c478bd9Sstevel@tonic-gate * a universal address looks like for inet transports.
4477c478bd9Sstevel@tonic-gate *
4487c478bd9Sstevel@tonic-gate * We also know that the internet timeservice is always
4497c478bd9Sstevel@tonic-gate * listening on port 37.
4507c478bd9Sstevel@tonic-gate */
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate if (nc != 0)
4537c478bd9Sstevel@tonic-gate freenetconfigent(nc);
4547c478bd9Sstevel@tonic-gate nc = getnetconfigent(epcand[i]->proto);
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate if (nc == 0) {
4577c478bd9Sstevel@tonic-gate msg("no netconfig info for netid.");
4587c478bd9Sstevel@tonic-gate if (needfree)
4597c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
4607c478bd9Sstevel@tonic-gate return (0);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate useua = epcand[i]->uaddr;
4647c478bd9Sstevel@tonic-gate useid = epcand[i]->proto;
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate if (strcasecmp(nc->nc_protofmly, NC_INET) == 0) {
46761961e0fSrobinson (void) sscanf(useua,
4687c478bd9Sstevel@tonic-gate "%d.%d.%d.%d.", &a1, &a2, &a3, &a4);
46961961e0fSrobinson (void) sprintf(ut, "%d.%d.%d.%d.0.37",
4707c478bd9Sstevel@tonic-gate a1, a2, a3, a4);
4717c478bd9Sstevel@tonic-gate } else if (strcasecmp(nc->nc_protofmly, NC_INET6) ==
4727c478bd9Sstevel@tonic-gate 0) {
4737c478bd9Sstevel@tonic-gate size_t len;
4747c478bd9Sstevel@tonic-gate char *port = ".0.37";
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate if (strlen(useua) >= sizeof (ut)) {
4777c478bd9Sstevel@tonic-gate goto error;
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate
48061961e0fSrobinson (void) strcpy(ut, useua);
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate /* get the IPv6 address out of the uaddr */
4837c478bd9Sstevel@tonic-gate if ((dot = strrchr(ut, '.')) != 0) {
4847c478bd9Sstevel@tonic-gate *dot = '\0';
4857c478bd9Sstevel@tonic-gate if ((dot = strrchr(ut, '.')) != 0)
4867c478bd9Sstevel@tonic-gate *dot = '\0';
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate if (dot == 0) {
4907c478bd9Sstevel@tonic-gate goto error;
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate if ((len = strlen(ut))+strlen(port) >=
4947c478bd9Sstevel@tonic-gate sizeof (ut)) {
4957c478bd9Sstevel@tonic-gate goto error;
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate
49861961e0fSrobinson (void) strcat(ut + len, port);
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate }
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate addr = uaddr2taddr(nc, ut);
5037c478bd9Sstevel@tonic-gate if (! addr) {
5047c478bd9Sstevel@tonic-gate msg("timeservice uaddr to taddr failed.");
5057c478bd9Sstevel@tonic-gate goto error;
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate rtime_fd = t_open(nc->nc_device, O_RDWR, NULL);
5097c478bd9Sstevel@tonic-gate if (rtime_fd == -1) {
5107c478bd9Sstevel@tonic-gate msg("unable to open fd to network.");
5117c478bd9Sstevel@tonic-gate goto error;
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate if (t_bind(rtime_fd, NULL, NULL) < 0) {
5157c478bd9Sstevel@tonic-gate msg("unable to bind an endpoint to fd.");
5167c478bd9Sstevel@tonic-gate goto error;
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate /*
5207c478bd9Sstevel@tonic-gate * Now depending on whether or not we're talking to
5217c478bd9Sstevel@tonic-gate * UDP we set a timeout or not.
5227c478bd9Sstevel@tonic-gate */
5237c478bd9Sstevel@tonic-gate if (nc->nc_semantics == NC_TPI_CLTS) {
5247c478bd9Sstevel@tonic-gate struct t_unitdata tu_data;
5257c478bd9Sstevel@tonic-gate struct pollfd pfd;
5267c478bd9Sstevel@tonic-gate int res;
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate tu_data.addr = *addr;
5297c478bd9Sstevel@tonic-gate tu_data.udata.buf = (char *)&thetime;
5307c478bd9Sstevel@tonic-gate tu_data.udata.len = (uint_t)sizeof (thetime);
5317c478bd9Sstevel@tonic-gate tu_data.udata.maxlen = tu_data.udata.len;
5327c478bd9Sstevel@tonic-gate tu_data.opt.len = 0;
5337c478bd9Sstevel@tonic-gate tu_data.opt.maxlen = 0;
5347c478bd9Sstevel@tonic-gate if (t_sndudata(rtime_fd, &tu_data) == -1) {
5357c478bd9Sstevel@tonic-gate msg("udp : t_sndudata failed.");
5367c478bd9Sstevel@tonic-gate goto error;
5377c478bd9Sstevel@tonic-gate }
5387c478bd9Sstevel@tonic-gate pfd.fd = rtime_fd;
5397c478bd9Sstevel@tonic-gate pfd.events =
5407c478bd9Sstevel@tonic-gate POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND;
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate do {
5437c478bd9Sstevel@tonic-gate res = poll(&pfd, 1, 10000);
5447c478bd9Sstevel@tonic-gate } while (res < 0);
5457c478bd9Sstevel@tonic-gate if ((res <= 0) || (pfd.revents & POLLNVAL))
5467c478bd9Sstevel@tonic-gate goto error;
5477c478bd9Sstevel@tonic-gate if (t_rcvudata(rtime_fd, &tu_data, &flag) <
5487c478bd9Sstevel@tonic-gate 0) {
5497c478bd9Sstevel@tonic-gate msg("t_rvcdata failed on udp trpt.");
5507c478bd9Sstevel@tonic-gate goto error;
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate time_valid = 1;
5537c478bd9Sstevel@tonic-gate } else {
5547c478bd9Sstevel@tonic-gate struct t_call sndcall;
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate sndcall.addr = *addr;
5577c478bd9Sstevel@tonic-gate sndcall.opt.len = sndcall.opt.maxlen = 0;
5587c478bd9Sstevel@tonic-gate sndcall.udata.len = sndcall.udata.maxlen = 0;
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate oldsig = (void (*)())signal(SIGALRM,
5617c478bd9Sstevel@tonic-gate alarm_hndler);
5627c478bd9Sstevel@tonic-gate saw_alarm = 0; /* global tracking the alarm */
56361961e0fSrobinson (void) alarm(20); /* only wait 20 seconds */
5647c478bd9Sstevel@tonic-gate if (t_connect(rtime_fd, &sndcall, NULL) ==
5657c478bd9Sstevel@tonic-gate -1) {
5667c478bd9Sstevel@tonic-gate msg("connect tcp endpoint failedd.");
5677c478bd9Sstevel@tonic-gate goto error;
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate if (saw_alarm) {
5707c478bd9Sstevel@tonic-gate msg("alarm caught it; unreachable.");
5717c478bd9Sstevel@tonic-gate goto error;
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate if (t_rcv(rtime_fd, (char *)&thetime,
5747c478bd9Sstevel@tonic-gate (uint_t)sizeof (thetime), &flag) !=
5757c478bd9Sstevel@tonic-gate (uint_t)sizeof (thetime)) {
5767c478bd9Sstevel@tonic-gate if (saw_alarm) {
5777c478bd9Sstevel@tonic-gate /*EMPTY*/
5787c478bd9Sstevel@tonic-gate msg("timed out TCP call.");
5797c478bd9Sstevel@tonic-gate } else {
5807c478bd9Sstevel@tonic-gate /*EMPTY*/
5817c478bd9Sstevel@tonic-gate msg("wrong size results");
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate goto error;
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate time_valid = 1;
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate if (time_valid) {
5887c478bd9Sstevel@tonic-gate thetime = ntohl(thetime);
5897c478bd9Sstevel@tonic-gate /* adjust to UNIX time */
5907c478bd9Sstevel@tonic-gate thetime = thetime - TOFFSET;
5917c478bd9Sstevel@tonic-gate } else
5927c478bd9Sstevel@tonic-gate thetime = 0;
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate error:
5977c478bd9Sstevel@tonic-gate /*
5987c478bd9Sstevel@tonic-gate * clean up our allocated data structures.
5997c478bd9Sstevel@tonic-gate */
6007c478bd9Sstevel@tonic-gate if (addr)
6017c478bd9Sstevel@tonic-gate netdir_free((char *)(addr), ND_ADDR);
6027c478bd9Sstevel@tonic-gate
6037c478bd9Sstevel@tonic-gate if (rtime_fd != -1)
6047c478bd9Sstevel@tonic-gate (void) t_close(rtime_fd);
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate if (clnt)
6077c478bd9Sstevel@tonic-gate clnt_destroy(clnt);
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate if (nc)
6107c478bd9Sstevel@tonic-gate freenetconfigent(nc);
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate if (oldsig) {
61361961e0fSrobinson (void) alarm(0); /* reset that alarm if its outstanding */
61461961e0fSrobinson (void) signal(SIGALRM, oldsig);
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate /*
6187c478bd9Sstevel@tonic-gate * note, don't free uaddr strings until after we've made a
6197c478bd9Sstevel@tonic-gate * copy of them.
6207c478bd9Sstevel@tonic-gate */
6217c478bd9Sstevel@tonic-gate if (time_valid) {
6227c478bd9Sstevel@tonic-gate if (! *netid) {
6237c478bd9Sstevel@tonic-gate *netid = strdup(useid);
6247c478bd9Sstevel@tonic-gate if (! *netid) {
6257c478bd9Sstevel@tonic-gate msg("__rpc_get_time_offset: strdup failed.");
6267c478bd9Sstevel@tonic-gate if (needfree)
6277c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
6287c478bd9Sstevel@tonic-gate return (0);
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate
6317c478bd9Sstevel@tonic-gate *uaddr = strdup(useua);
6327c478bd9Sstevel@tonic-gate if (! *uaddr) {
6337c478bd9Sstevel@tonic-gate msg("__rpc_get_time_offset: strdup failed.");
6347c478bd9Sstevel@tonic-gate if (*netid)
6357c478bd9Sstevel@tonic-gate free(*netid);
6367c478bd9Sstevel@tonic-gate if (needfree)
6377c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
6387c478bd9Sstevel@tonic-gate return (0);
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate
64261961e0fSrobinson (void) gettimeofday(&tv, 0);
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate /* Round to the nearest second */
6457c478bd9Sstevel@tonic-gate tv.tv_sec += (tv.tv_sec > 500000) ? 1 : 0;
6467c478bd9Sstevel@tonic-gate delta = (thetime > tv.tv_sec) ? thetime - tv.tv_sec :
6477c478bd9Sstevel@tonic-gate tv.tv_sec - thetime;
6487c478bd9Sstevel@tonic-gate td->tv_sec = (thetime < tv.tv_sec) ? - delta : delta;
6497c478bd9Sstevel@tonic-gate td->tv_usec = 0;
6507c478bd9Sstevel@tonic-gate } else {
6517c478bd9Sstevel@tonic-gate /*EMPTY*/
6527c478bd9Sstevel@tonic-gate msg("unable to get the server's time.");
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate if (needfree)
6567c478bd9Sstevel@tonic-gate free_eps(teps, tsrv.ep.ep_len);
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate return (time_valid);
6597c478bd9Sstevel@tonic-gate }
660