1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2014 Gary Mills
24 * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 * Copyright (c) 2018, Joyent, Inc.
27 */
28
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31
32 /*
33 * Portions of this source code were derived from Berkeley 4.3 BSD
34 * under license from the Regents of the University of California.
35 */
36
37 /*
38 * Miscellaneous support routines for kernel implentation of AUTH_DES
39 */
40
41 /*
42 * rtime - get time from remote machine
43 *
44 * sets time, obtaining value from host
45 * on the udp/time socket. Since timeserver returns
46 * with time of day in seconds since Jan 1, 1900, must
47 * subtract 86400(365*70 + 17) to get time
48 * since Jan 1, 1970, which is what get/settimeofday
49 * uses.
50 */
51 #include <sys/param.h>
52 #include <sys/types.h>
53 #include <sys/time.h>
54 #include <sys/systm.h>
55 #include <sys/errno.h>
56 #include <sys/proc.h>
57 #include <sys/user.h>
58 #include <sys/socket.h>
59 #include <sys/sysmacros.h>
60 #include <netinet/in.h>
61 #include <rpc/rpc.h>
62 #include <sys/stream.h>
63 #include <sys/strsubr.h>
64 #include <sys/cred.h>
65 #include <sys/utsname.h>
66 #include <sys/vnode.h>
67 #include <sys/file.h>
68 #include <sys/uio.h>
69 #include <sys/systeminfo.h>
70 #include <rpc/rpcb_prot.h>
71 #include <sys/cmn_err.h>
72
73 #define TOFFSET ((uint32_t)86400 * (365 * 70 + (70 / 4)))
74 #define WRITTEN ((uint32_t)86400 * (365 * 86 + (86 / 4)))
75
76 #define NC_INET "inet" /* XXX */
77
78 int
rtime(struct knetconfig * synconfig,struct netbuf * addrp,int calltype,struct timeval * timep,struct timeval * wait)79 rtime(struct knetconfig *synconfig, struct netbuf *addrp, int calltype,
80 struct timeval *timep, struct timeval *wait)
81 {
82 int error;
83 int timo;
84 time_t thetime;
85 int32_t srvtime;
86 uint32_t dummy;
87 struct t_kunitdata *unitdata;
88 struct t_call *server;
89 TIUSER *tiptr;
90 int type;
91 int uderr;
92 int i;
93 int retries;
94 mblk_t *mp;
95 mblk_t *mp2;
96
97 retries = 5;
98 if (calltype == 0) {
99 again:
100 RPCLOG0(8, "rtime: using old method\n");
101 if ((error = t_kopen(NULL, synconfig->knc_rdev,
102 FREAD|FWRITE, &tiptr, CRED())) != 0) {
103 RPCLOG(1, "rtime: t_kopen %d\n", error);
104 return (-1);
105 }
106
107 if ((error = t_kbind(tiptr, NULL, NULL)) != 0) {
108 (void) t_kclose(tiptr, 1);
109 RPCLOG(1, "rtime: t_kbind %d\n", error);
110 return (-1);
111 }
112
113 if (synconfig->knc_semantics == NC_TPI_CLTS) {
114 if ((error = t_kalloc(tiptr, T_UNITDATA,
115 T_UDATA|T_ADDR, (char **)&unitdata)) != 0) {
116 RPCLOG(1, "rtime: t_kalloc %d\n", error);
117 (void) t_kclose(tiptr, 1);
118 return (-1);
119 }
120
121 unitdata->addr.len = addrp->len;
122 bcopy(addrp->buf, unitdata->addr.buf,
123 unitdata->addr.len);
124
125 dummy = 0;
126 unitdata->udata.buf = (caddr_t)&dummy;
127 unitdata->udata.len = sizeof (dummy);
128
129 if ((error = t_ksndudata(tiptr, unitdata, NULL)) !=
130 0) {
131 RPCLOG(1, "rtime: t_ksndudata %d\n", error);
132 (void) t_kfree(tiptr, (char *)unitdata,
133 T_UNITDATA);
134 (void) t_kclose(tiptr, 1);
135 return (-1);
136 }
137
138 timo = TIMEVAL_TO_TICK(wait);
139
140 RPCLOG(8, "rtime: timo %x\n", timo);
141 if ((error = t_kspoll(tiptr, timo, READWAIT,
142 &type)) != 0) {
143 RPCLOG(1, "rtime: t_kspoll %d\n", error);
144 (void) t_kfree(tiptr, (char *)unitdata,
145 T_UNITDATA);
146 (void) t_kclose(tiptr, 1);
147 return (-1);
148 }
149
150 if (type == 0) {
151 RPCLOG0(1, "rtime: t_kspoll timed out\n");
152 (void) t_kfree(tiptr, (char *)unitdata,
153 T_UNITDATA);
154 (void) t_kclose(tiptr, 1);
155 return (-1);
156 }
157
158 error = t_krcvudata(tiptr, unitdata, &type, &uderr);
159 if (error != 0) {
160 RPCLOG(1, "rtime: t_krcvudata %d\n", error);
161 (void) t_kfree(tiptr, (char *)unitdata,
162 T_UNITDATA);
163 (void) t_kclose(tiptr, 1);
164 if (error == EBADMSG && retries-- > 0)
165 goto again;
166 return (-1);
167 }
168
169 if (type == T_UDERR) {
170 if (bcmp(addrp->buf, unitdata->addr.buf,
171 unitdata->addr.len) != 0) {
172 /*
173 * Response comes from some other
174 * destination:
175 * ignore it since it's not related to the
176 * request we just sent out.
177 */
178 (void) t_kfree(tiptr, (char *)unitdata,
179 T_UNITDATA);
180 (void) t_kclose(tiptr, 1);
181 goto again;
182 }
183 }
184
185 if (type != T_DATA) {
186 RPCLOG(1,
187 "rtime: t_krcvudata returned type %d\n",
188 type);
189 (void) t_kfree(tiptr, (char *)unitdata,
190 T_UNITDATA);
191 (void) t_kclose(tiptr, 1);
192 if (retries-- == 0)
193 return (-1);
194 goto again;
195 }
196
197 if (unitdata->udata.len < sizeof (uint32_t)) {
198 RPCLOG(1, "rtime: bad rcvd length %d\n",
199 unitdata->udata.len);
200 (void) t_kfree(tiptr, (char *)unitdata,
201 T_UNITDATA);
202 (void) t_kclose(tiptr, 1);
203 if (retries-- == 0)
204 return (-1);
205 goto again;
206 }
207
208 thetime = (time_t)ntohl(
209 /* LINTED pointer alignment */
210 *(uint32_t *)unitdata->udata.buf);
211 (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
212
213 } else {
214
215 if ((error = t_kalloc(tiptr, T_CALL, T_ADDR,
216 (char **)&server)) != 0) {
217 RPCLOG(1, "rtime: t_kalloc %d\n", error);
218 (void) t_kclose(tiptr, 1);
219 return (-1);
220 }
221
222 server->addr.len = addrp->len;
223 bcopy(addrp->buf, server->addr.buf, server->addr.len);
224
225 if ((error = t_kconnect(tiptr, server, NULL)) != 0) {
226 RPCLOG(1, "rtime: t_kconnect %d\n", error);
227 (void) t_kfree(tiptr, (char *)server, T_CALL);
228 (void) t_kclose(tiptr, 1);
229 return (-1);
230 }
231 (void) t_kfree(tiptr, (char *)server, T_CALL);
232
233 timo = TIMEVAL_TO_TICK(wait);
234
235 RPCLOG(8, "rtime: timo %x\n", timo);
236
237 i = 0;
238 dummy = 0;
239
240 /* now read up to 4 bytes from the TIME server */
241 while (i < sizeof (dummy)) {
242
243 error = t_kspoll(tiptr, timo, READWAIT, &type);
244 if (error != 0) {
245 RPCLOG(1, "rtime: t_kspoll %d\n",
246 error);
247 (void) t_kclose(tiptr, 1);
248 return (-1);
249 }
250
251 if (type == 0) {
252 RPCLOG0(1,
253 "rtime: t_kspoll timed out\n");
254 (void) t_kclose(tiptr, 1);
255 return (-1);
256 }
257
258 error = tli_recv(tiptr, &mp,
259 tiptr->fp->f_flag);
260 if (error != 0) {
261 RPCLOG(1, "rtime: tli_recv %d\n",
262 error);
263 (void) t_kclose(tiptr, 1);
264 return (-1);
265 }
266
267 if (mp->b_datap->db_type != M_DATA) {
268 RPCLOG(1, "rtime: wrong msg type %d\n",
269 mp->b_datap->db_type);
270 RPCLOG(1,
271 "rtime: wrong msg type: read %d"
272 " bytes\n", i);
273 (void) t_kclose(tiptr, 1);
274 freemsg(mp);
275 return (-1);
276 }
277
278 mp2 = mp;
279
280 /*
281 * The outer loop iterates until we reach the
282 * end of the mblk chain.
283 */
284 while (mp2 != NULL) {
285
286 /*
287 * The inner loop iterates until
288 * we've gotten 4 bytes or until
289 * the mblk is exhausted.
290 */
291 while (i < sizeof (dummy) &&
292 mp2->b_rptr < mp2->b_wptr) {
293
294 i++;
295
296 /*
297 * We avoid big-endian/little-endian
298 * issues by serializing the result
299 * one byte at a time.
300 */
301 dummy <<= 8;
302 dummy += ((*mp2->b_rptr) &
303 0xFF);
304
305 mp2->b_rptr++;
306 }
307
308 mp2 = mp2->b_cont;
309 }
310
311 freemsg(mp);
312 }
313
314 thetime = (time_t)dummy;
315 }
316
317 (void) t_kclose(tiptr, 1);
318
319 } else {
320 CLIENT *client;
321 struct timeval timout;
322
323 RPCLOG0(8, "rtime: using new method\n");
324
325 new_again:
326 /*
327 * We talk to rpcbind.
328 */
329 error = clnt_tli_kcreate(synconfig, addrp, (rpcprog_t)RPCBPROG,
330 (rpcvers_t)RPCBVERS, 0, retries, CRED(), &client);
331
332 if (error != 0) {
333 RPCLOG(1,
334 "rtime: clnt_tli_kcreate returned %d\n", error);
335 return (-1);
336 }
337 timout.tv_sec = 60;
338 timout.tv_usec = 0;
339 error = clnt_call(client, RPCBPROC_GETTIME, (xdrproc_t)xdr_void,
340 NULL, (xdrproc_t)xdr_u_int,
341 (caddr_t)&srvtime, timout);
342 thetime = srvtime;
343 auth_destroy(client->cl_auth);
344 clnt_destroy(client);
345 if (error == RPC_UDERROR) {
346 if (retries-- > 0)
347 goto new_again;
348 }
349 if (error != RPC_SUCCESS) {
350 RPCLOG(1, "rtime: time sync clnt_call returned %d\n",
351 error);
352 error = EIO;
353 return (-1);
354 }
355 }
356
357 if (calltype != 0)
358 thetime += TOFFSET;
359
360 RPCLOG(8, "rtime: thetime = %lx\n", thetime);
361
362 if (thetime < WRITTEN) {
363 RPCLOG(1, "rtime: time returned is too far in past %lx",
364 thetime);
365 RPCLOG(1, "rtime: WRITTEN %x", WRITTEN);
366 return (-1);
367 }
368 thetime -= TOFFSET;
369
370 timep->tv_sec = thetime;
371 RPCLOG(8, "rtime: timep->tv_sec = %lx\n", timep->tv_sec);
372 RPCLOG(8, "rtime: machine time = %lx\n", gethrestime_sec());
373 timep->tv_usec = 0;
374 RPCLOG0(8, "rtime: returning success\n");
375 return (0);
376 }
377
378 /*
379 * What is my network name?
380 * WARNING: this gets the network name in sun unix format.
381 * Other operating systems (non-unix) are free to put something else
382 * here.
383 *
384 * Return 0 on success
385 * Return RPC errors (non-zero values) if failed.
386 */
387 enum clnt_stat
kgetnetname(char * netname)388 kgetnetname(char *netname)
389 {
390 return (key_getnetname(netname, CRED()));
391 }
392