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 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 368 kgetnetname(char *netname) 369 { 370 return (key_getnetname(netname, CRED())); 371 } 372