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