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 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 387 kgetnetname(char *netname) 388 { 389 return (key_getnetname(netname, CRED())); 390 } 391