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 2001 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35 #pragma ident "%Z%%M% %I% %E% SMI"
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, T_UDATA|T_ADDR,
115 (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, 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)) != 0) {
129 RPCLOG(1, "rtime: t_ksndudata %d\n", error);
130 (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
131 (void) t_kclose(tiptr, 1);
132 return (-1);
133 }
134
135 timo = TIMEVAL_TO_TICK(wait);
136
137 RPCLOG(8, "rtime: timo %x\n", timo);
138 if ((error = t_kspoll(tiptr, timo, READWAIT, &type)) != 0) {
139 RPCLOG(1, "rtime: t_kspoll %d\n", error);
140 (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
141 (void) t_kclose(tiptr, 1);
142 return (-1);
143 }
144
145 if (type == 0) {
146 RPCLOG0(1, "rtime: t_kspoll timed out\n");
147 (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
148 (void) t_kclose(tiptr, 1);
149 return (-1);
150 }
151
152 error = t_krcvudata(tiptr, unitdata, &type, &uderr);
153 if (error != 0) {
154 RPCLOG(1, "rtime: t_krcvudata %d\n", error);
155 (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
156 (void) t_kclose(tiptr, 1);
157 return (-1);
158 }
159
160 if (type == T_UDERR) {
161 if (bcmp(addrp->buf, unitdata->addr.buf,
162 unitdata->addr.len) != 0) {
163 /*
164 * Response comes from some other
165 * destination:
166 * ignore it since it's not related to the
167 * request we just sent out.
168 */
169 (void) t_kfree(tiptr, (char *)unitdata,
170 T_UNITDATA);
171 (void) t_kclose(tiptr, 1);
172 goto again;
173 }
174 }
175
176 if (type != T_DATA) {
177 RPCLOG(1, "rtime: t_krcvudata returned type %d\n",
178 type);
179 (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
180 (void) t_kclose(tiptr, 1);
181 if (retries-- == 0)
182 return (-1);
183 goto again;
184 }
185
186 if (unitdata->udata.len < sizeof (uint32_t)) {
187 RPCLOG(1, "rtime: bad rcvd length %d\n",
188 unitdata->udata.len);
189 (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
190 (void) t_kclose(tiptr, 1);
191 if (retries-- == 0)
192 return (-1);
193 goto again;
194 }
195
196 /* LINTED pointer alignment */
197 thetime = (time_t)ntohl(*(uint32_t *)unitdata->udata.buf);
198 (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
199
200 } else {
201
202 if ((error = t_kalloc(tiptr, T_CALL, T_ADDR,
203 (char **)&server)) != 0) {
204 RPCLOG(1, "rtime: t_kalloc %d\n", error);
205 (void) t_kclose(tiptr, 1);
206 return (-1);
207 }
208
209 server->addr.len = addrp->len;
210 bcopy(addrp->buf, server->addr.buf, server->addr.len);
211
212 if ((error = t_kconnect(tiptr, server, NULL)) != 0) {
213 RPCLOG(1, "rtime: t_kconnect %d\n", error);
214 (void) t_kfree(tiptr, (char *)server, T_CALL);
215 (void) t_kclose(tiptr, 1);
216 return (-1);
217 }
218 (void) t_kfree(tiptr, (char *)server, T_CALL);
219
220 timo = TIMEVAL_TO_TICK(wait);
221
222 RPCLOG(8, "rtime: timo %x\n", timo);
223
224 i = 0;
225 dummy = 0;
226
227 /* now read up to 4 bytes from the TIME server */
228 while (i < sizeof (dummy)) {
229
230 error = t_kspoll(tiptr, timo, READWAIT, &type);
231 if (error != 0) {
232 RPCLOG(1, "rtime: t_kspoll %d\n", error);
233 (void) t_kclose(tiptr, 1);
234 return (-1);
235 }
236
237 if (type == 0) {
238 RPCLOG0(1, "rtime: t_kspoll timed out\n");
239 (void) t_kclose(tiptr, 1);
240 return (-1);
241 }
242
243 error = tli_recv(tiptr, &mp, tiptr->fp->f_flag);
244 if (error != 0) {
245 RPCLOG(1, "rtime: tli_recv %d\n", error);
246 (void) t_kclose(tiptr, 1);
247 return (-1);
248 }
249
250 if (mp->b_datap->db_type != M_DATA) {
251 RPCLOG(1, "rtime: wrong msg type %d\n",
252 mp->b_datap->db_type);
253 RPCLOG(1, "rtime: wrong msg type: read %d"
254 " bytes\n", i);
255 (void) t_kclose(tiptr, 1);
256 freemsg(mp);
257 return (-1);
258 }
259
260 mp2 = mp;
261
262 /*
263 * The outer loop iterates until we reach the end of
264 * the mblk chain.
265 */
266 while (mp2 != NULL) {
267
268 /*
269 * The inner loop iterates until we've gotten
270 * 4 bytes or until the mblk is exhausted.
271 */
272 while (i < sizeof (dummy) &&
273 mp2->b_rptr < mp2->b_wptr) {
274
275 i++;
276
277 /*
278 * We avoid big-endian/little-endian
279 * issues by serializing the result
280 * one byte at a time.
281 */
282 dummy <<= 8;
283 dummy += ((*mp2->b_rptr) & 0xFF);
284
285 mp2->b_rptr++;
286 }
287
288 mp2 = mp2->b_cont;
289 }
290
291 freemsg(mp);
292 }
293
294 thetime = (time_t)dummy;
295 }
296
297 (void) t_kclose(tiptr, 1);
298
299 } else {
300 CLIENT *client;
301 struct timeval timout;
302
303 RPCLOG0(8, "rtime: using new method\n");
304
305 new_again:
306 /*
307 * We talk to rpcbind.
308 */
309 error = clnt_tli_kcreate(synconfig, addrp, (rpcprog_t)RPCBPROG,
310 (rpcvers_t)RPCBVERS, 0, retries, CRED(), &client);
311
312 if (error != 0) {
313 RPCLOG(1,
314 "rtime: clnt_tli_kcreate returned %d\n", error);
315 return (-1);
316 }
317 timout.tv_sec = 60;
318 timout.tv_usec = 0;
319 error = clnt_call(client, RPCBPROC_GETTIME, (xdrproc_t)xdr_void,
320 NULL, (xdrproc_t)xdr_u_int,
321 (caddr_t)&srvtime, timout);
322 thetime = srvtime;
323 auth_destroy(client->cl_auth);
324 clnt_destroy(client);
325 if (error == RPC_UDERROR) {
326 if (retries-- > 0)
327 goto new_again;
328 }
329 if (error != RPC_SUCCESS) {
330 RPCLOG(1, "rtime: time sync clnt_call returned %d\n",
331 error);
332 error = EIO;
333 return (-1);
334 }
335 }
336
337 if (calltype != 0)
338 thetime += TOFFSET;
339
340 RPCLOG(8, "rtime: thetime = %lx\n", thetime);
341
342 if (thetime < WRITTEN) {
343 RPCLOG(1, "rtime: time returned is too far in past %lx",
344 thetime);
345 RPCLOG(1, "rtime: WRITTEN %x", WRITTEN);
346 return (-1);
347 }
348 thetime -= TOFFSET;
349
350 timep->tv_sec = thetime;
351 RPCLOG(8, "rtime: timep->tv_sec = %lx\n", timep->tv_sec);
352 RPCLOG(8, "rtime: machine time = %lx\n", gethrestime_sec());
353 timep->tv_usec = 0;
354 RPCLOG0(8, "rtime: returning success\n");
355 return (0);
356 }
357
358 /*
359 * What is my network name?
360 * WARNING: this gets the network name in sun unix format.
361 * Other operating systems (non-unix) are free to put something else
362 * here.
363 *
364 * Return 0 on success
365 * Return RPC errors (non-zero values) if failed.
366 */
367 enum clnt_stat
kgetnetname(char * netname)368 kgetnetname(char *netname)
369 {
370 return (key_getnetname(netname, CRED()));
371 }
372