1 /* $OpenBSD: rdate.c,v 1.37 2023/01/04 13:00:11 jsg Exp $ */
2 /* $NetBSD: rdate.c,v 1.4 1996/03/16 12:37:45 pk Exp $ */
3
4 /*
5 * Copyright (c) 1994 Christos Zoulas
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * rdate.c: Set the date from the specified host
31 *
32 * Time is returned as the number of seconds since
33 * midnight January 1st 1900.
34 */
35
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <sys/wait.h>
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <ctype.h>
43 #include <err.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <time.h>
47
48 /* there are systems without libutil; for portability */
49 #ifndef NO_UTIL
50 #include <util.h>
51 #else
52 #define logwtmp(a,b,c)
53 #endif
54
55 void rfc868time_client(const char *, int, struct timeval *, struct timeval *, int);
56 void ntp_client(const char *, int, struct timeval *, struct timeval *, int);
57
58 extern char *__progname;
59 __dead void usage(void);
60
61 struct {
62 char message[2048];
63 struct timeval new;
64 struct timeval adjust;
65 } pdata;
66
67 __dead void
usage(void)68 usage(void)
69 {
70 (void) fprintf(stderr, "usage: %s [-46acnopsv] host\n", __progname);
71 exit(1);
72 }
73
74 int
main(int argc,char ** argv)75 main(int argc, char **argv)
76 {
77 int pr = 0, silent = 0, ntp = 1, verbose = 0;
78 int slidetime = 0, corrleaps = 0;
79 char *hname;
80 int c, p[2], pid;
81 int family = PF_UNSPEC;
82
83 while ((c = getopt(argc, argv, "46psanocv")) != -1) {
84 switch (c) {
85 case '4':
86 family = PF_INET;
87 break;
88
89 case '6':
90 family = PF_INET6;
91 break;
92
93 case 'p':
94 pr = 1;
95 break;
96
97 case 's':
98 silent = 1;
99 break;
100
101 case 'a':
102 slidetime = 1;
103 break;
104
105 case 'n':
106 ntp = 1;
107 break;
108
109 case 'o':
110 ntp = 0;
111 break;
112
113 case 'c':
114 corrleaps = 1;
115 break;
116
117 case 'v':
118 verbose = 1;
119 break;
120
121 default:
122 usage();
123 }
124 }
125 if (argc - 1 != optind)
126 usage();
127 hname = argv[optind];
128
129 /*
130 * Privilege separation increases safety, with a slight reduction
131 * in precision because the time values have to return over a pipe.
132 */
133 if (pipe(p) == -1)
134 err(1, "pipe");
135 switch ((pid = fork())) {
136 case -1:
137 err(1, "fork");
138 break;
139 case 0:
140 if (pledge("stdio inet dns", NULL) == -1)
141 err(1, "pledge");
142
143 close(p[0]); /* read side of pipe */
144 dup2(p[1], STDIN_FILENO);
145 if (p[1] != STDIN_FILENO)
146 close(p[1]);
147 dup2(STDIN_FILENO, STDOUT_FILENO);
148 dup2(STDOUT_FILENO, STDERR_FILENO);
149 setvbuf(stdout, NULL, _IOFBF, 0);
150 setvbuf(stderr, NULL, _IOFBF, 0);
151
152 if (ntp)
153 ntp_client(hname, family, &pdata.new,
154 &pdata.adjust, corrleaps);
155 else
156 rfc868time_client(hname, family, &pdata.new,
157 &pdata.adjust, corrleaps);
158
159 if (write(STDOUT_FILENO, &pdata, sizeof pdata) != sizeof pdata)
160 exit(1);
161 exit(0);
162 }
163
164 if (pledge("stdio rpath wpath settime", NULL) == -1)
165 err(1, "pledge");
166
167 close(p[1]); /* write side of pipe */
168 if (read(p[0], &pdata, sizeof pdata) < 1)
169 err(1, "child did not collect time");
170 if (waitpid(pid, NULL, 0) == -1)
171 err(1, "waitpid");
172
173 /*
174 * A viable timestamp from the child contains no message.
175 */
176 if (pdata.message[0]) {
177 pdata.message[sizeof(pdata.message)- 1] = '\0';
178 write(STDERR_FILENO, pdata.message, strlen(pdata.message));
179 exit(1);
180 }
181
182 if (!pr) {
183 if (!slidetime) {
184 logwtmp("|", "date", "");
185 if (settimeofday(&pdata.new, NULL) == -1)
186 err(1, "Could not set time of day");
187 logwtmp("{", "date", "");
188 } else {
189 if (adjtime(&pdata.adjust, NULL) == -1)
190 err(1, "Could not adjust time of day");
191 }
192 }
193
194 if (pledge("stdio rpath", NULL) == -1)
195 err(1, "pledge");
196
197 if (!silent) {
198 struct tm *ltm;
199 char buf[80];
200 time_t tim = pdata.new.tv_sec;
201 double adjsec;
202
203 ltm = localtime(&tim);
204 (void) strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y\n", ltm);
205 (void) fputs(buf, stdout);
206
207 adjsec = pdata.adjust.tv_sec + pdata.adjust.tv_usec / 1.0e6;
208
209 if (slidetime || verbose) {
210 if (ntp)
211 (void) fprintf(stdout,
212 "%s: adjust local clock by %.6f seconds\n",
213 __progname, adjsec);
214 else
215 (void) fprintf(stdout,
216 "%s: adjust local clock by %lld seconds\n",
217 __progname, (long long)pdata.adjust.tv_sec);
218 }
219 }
220
221 return 0;
222 }
223