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 }