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