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 }