1 /*        $NetBSD: rdate.c,v 1.22 2017/08/26 19:26:32 ginsbach Exp $  */
2 
3 /*
4  * Copyright (c) 1994 Christos Zoulas
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /*
29  * rdate.c: Set the date from the specified host
30  *
31  *        Uses the rfc868 time protocol at socket 37.
32  *        Time is returned as the number of seconds since
33  *        midnight January 1st 1900.
34  */
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __RCSID("$NetBSD: rdate.c,v 1.22 2017/08/26 19:26:32 ginsbach Exp $");
38 #endif /* lint */
39 
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/time.h>
43 
44 #include <netinet/in.h>
45 
46 #include <err.h>
47 #include <netdb.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 #include <util.h>
53 
54 /* seconds from midnight Jan 1900 - 1970 */
55 #define DIFFERENCE 2208988800ULL
56 
57 static    void      usage(void);
58 
59 static void
usage(void)60 usage(void)
61 {
62           (void) fprintf(stderr, "usage: %s [-46aps] host\n", getprogname());
63           (void) fprintf(stderr, "  -4: use IPv4 addresses only\n");
64           (void) fprintf(stderr, "  -6: use IPv6 addresses only\n");
65           (void) fprintf(stderr, "  -a: use adjtime instead of instant change\n");
66           (void) fprintf(stderr, "  -p: just print, don't set\n");
67           (void) fprintf(stderr, "  -s: just set, don't print\n");
68 }
69 
70 int
main(int argc,char * argv[])71 main(int argc, char *argv[])
72 {
73           int             pr = 0, silent = 0, s;
74           int                 slidetime = 0;
75           int                 adjustment;
76           uint32_t  data;
77           time_t          tim;
78           char           *hname;
79           const char     *emsg = NULL;
80           struct addrinfo     hints, *res, *res0;
81           int             c;
82           int                 error;
83           int                 family = AF_UNSPEC;
84 
85           adjustment = 0;
86           while ((c = getopt(argc, argv, "46aps")) != -1)
87                     switch (c) {
88                     case '4':
89                               family = AF_INET;
90                               break;
91 
92                     case '6':
93                               family  = AF_INET6;
94                               break;
95 
96                     case 'a':
97                               slidetime++;
98                               break;
99 
100                     case 'p':
101                               pr++;
102                               break;
103 
104                     case 's':
105                               silent++;
106                               break;
107 
108                     default:
109                               usage();
110                               return 1;
111                     }
112 
113           if (argc - 1 != optind) {
114                     usage();
115                     return 1;
116           }
117           hname = argv[optind];
118 
119           memset(&hints, 0, sizeof (hints));
120           hints.ai_family = family;
121           hints.ai_socktype = SOCK_STREAM;
122           hints.ai_flags = AI_CANONNAME;
123           error = getaddrinfo(hname, "time", &hints, &res0);
124           if (error)
125                     errx(1, "%s: %s", gai_strerror(error), hname);
126 
127           for (res = res0, s = -1; res != NULL; res = res->ai_next) {
128                     s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
129                     if (s < 0) {
130                               emsg = "socket";
131                               continue;
132                     }
133 
134                     if (connect(s, res->ai_addr, res->ai_addrlen)) {
135                               close(s);
136                               s = -1;
137                               emsg = "connect";
138                               continue;
139                     }
140 
141                     break;
142           }
143           if (s < 0)
144                     err(1, "%s", emsg);
145 
146           if (read(s, &data, sizeof(uint32_t)) != sizeof(uint32_t))
147                     err(1, "Could not read data");
148 
149           (void) close(s);
150           tim = ntohl(data) - DIFFERENCE;
151 
152           if (!pr) {
153               struct timeval  tv;
154               if (!slidetime) {
155                         logwtmp("|", "date", "");
156                         tv.tv_sec = tim;
157                         tv.tv_usec = 0;
158                         if (settimeofday(&tv, NULL) == -1)
159                                   err(1, "Could not set time of day");
160                         logwtmp("{", "date", "");
161               } else {
162                         struct timeval tv_current;
163                         if (gettimeofday(&tv_current, NULL) == -1)
164                                   err(1, "Could not get local time of day");
165                         adjustment = tv.tv_sec = tim - tv_current.tv_sec;
166                         tv.tv_usec = 0;
167                         if (adjtime(&tv, NULL) == -1)
168                                   err(1, "Could not adjust time of day");
169               }
170           }
171 
172           if (!silent) {
173                     (void) fputs(ctime(&tim), stdout);
174                     if (slidetime)
175                         (void) fprintf(stdout,
176                                            "%s: adjust local clock by %d seconds\n",
177                                            getprogname(), adjustment);
178           }
179           return 0;
180 }
181