Print this page
    
7127  remove -Wno-missing-braces from Makefile.uts
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/gssapi/mechs/dummy/dmech.c
          +++ new/usr/src/uts/common/gssapi/mechs/dummy/dmech.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License, Version 1.0 only
   6    6   * (the "License").  You may not use this file except in compliance
   7    7   * with the License.
   8    8   *
   9    9   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10   10   * or http://www.opensolaris.org/os/licensing.
  11   11   * See the License for the specific language governing permissions
  12   12   * and limitations under the License.
  13   13   *
  14   14   * When distributing Covered Code, include this CDDL HEADER in each
  15   15   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16   16   * If applicable, add the following below this CDDL HEADER, with the
  17   17   * fields enclosed by brackets "[]" replaced with your own identifying
  18   18   * information: Portions Copyright [yyyy] [name of copyright owner]
  19   19   *
  20   20   * CDDL HEADER END
  21   21   */
  22   22  /*
  23   23   * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
  26   26   */
  27   27  
  28   28  /*
  29   29   * A module that implements a dummy security mechanism.
  30   30   * It's mainly used to test GSS-API application. Multiple tokens
  31   31   * exchanged during security context establishment can be
  32   32   * specified through dummy_mech.conf located in /etc.
  33   33   */
  34   34  
  35   35  #include <sys/types.h>
  36   36  #include <sys/modctl.h>
  37   37  #include <sys/errno.h>
  38   38  #include <gssapiP_dummy.h>
  39   39  #include <gssapi_err_generic.h>
  40   40  #include <mechglueP.h>
  41   41  #include <gssapi/kgssapi_defs.h>
  42   42  #include <sys/debug.h>
  43   43  
  44   44  #ifdef DUMMY_MECH_DEBUG
  45   45  /*
  46   46   * Kernel kgssd module debugging aid. The global variable "dummy_mech_log"
  47   47   * is a bit mask which allows various types of debugging messages
  48   48   * to be printed out.
  49   49   *
  50   50   *       dummy_mech_log & 1  will cause actual failures to be printed.
  51   51   *       dummy_mech_log & 2  will cause informational messages to be
  52   52   *                       printed on the client side of kgssd.
  53   53   *       dummy_mech_log & 4  will cause informational messages to be
  54   54   *                       printed on the server side of kgssd.
  55   55   *       dummy_mech_log & 8  will cause informational messages to be
  56   56   *                       printed on both client and server side of kgssd.
  57   57   */
  58   58  
  59   59  uint_t dummy_mech_log = 1;
  60   60  #endif
  61   61  
  62   62  /* Local defines */
  63   63  #define MAGIC_TOKEN_NUMBER 12345
  64   64  /* private routines for dummy_mechanism */
  65   65  static gss_buffer_desc make_dummy_token_msg(void *data, int datalen);
  66   66  
  67   67  static int der_length_size(int);
  68   68  
  69   69  static void der_write_length(unsigned char **, int);
  70   70  static int der_read_length(unsigned char **, int *);
  71   71  static int g_token_size(gss_OID mech, unsigned int body_size);
  72   72  static void g_make_token_header(gss_OID mech, int body_size,
  73   73                                  unsigned char **buf, int tok_type);
  74   74  static int g_verify_token_header(gss_OID mech, int *body_size,
  75   75                                  unsigned char **buf_in, int tok_type,
  76   76                                  int toksize);
  77   77  
  78   78  /* private global variables */
  79   79  static int dummy_token_nums;
  80   80  
  81   81  /*
  82   82   * This OID:
  83   83   * { iso(1) org(3) internet(6) dod(1) private(4) enterprises(1) sun(42)
  84   84   * products(2) gssapi(26) mechtypes(1) dummy(2) }
  85   85   */
  86   86  
  87   87  static struct gss_config dummy_mechanism =
  88   88          {{10, "\053\006\001\004\001\052\002\032\001\002"},
  89   89          NULL,   /* context */
  90   90          NULL,   /* next */
  91   91          TRUE,   /* uses_kmod */
  92   92          dummy_gss_unseal,
  93   93          dummy_gss_delete_sec_context,
  94   94          dummy_gss_seal,
  95   95          dummy_gss_import_sec_context,
  96   96          dummy_gss_sign,
  97   97          dummy_gss_verify
  98   98  };
  99   99  
 100  100  static gss_mechanism
 101  101  gss_mech_initialize()
 102  102  {
 103  103          dprintf("Entering gss_mech_initialize\n");
 104  104  
 105  105          if (dummy_token_nums == 0)
 106  106                  dummy_token_nums = 1;
 107  107  
 108  108          dprintf("Leaving gss_mech_initialize\n");
 109  109          return (&dummy_mechanism);
 110  110  }
 111  111  
 112  112  /*
 113  113   * Clean up after a failed mod_install()
 114  114   */
 115  115  static void
 116  116  gss_mech_fini()
 117  117  {
 118  118          /* Nothing to do */
 119  119  }
 120  120  
 121  121  
 122  122  /*
  
    | 
      ↓ open down ↓ | 
    122 lines elided | 
    
      ↑ open up ↑ | 
  
 123  123   * Module linkage information for the kernel.
 124  124   */
 125  125  extern struct mod_ops mod_miscops;
 126  126  
 127  127  static struct modlmisc modlmisc = {
 128  128          &mod_miscops, "in-kernel dummy GSS mechanism"
 129  129  };
 130  130  
 131  131  static struct modlinkage modlinkage = {
 132  132          MODREV_1,
 133      -        (void *)&modlmisc,
 134      -        NULL
      133 +        { (void *)&modlmisc, NULL }
 135  134  };
 136  135  
 137  136  static int dummy_fini_code = EBUSY;
 138  137  
 139  138  int
 140  139  _init()
 141  140  {
 142  141          int retval;
 143  142          gss_mechanism mech, tmp;
 144  143  
 145  144          mech = gss_mech_initialize();
 146  145  
 147  146          mutex_enter(&__kgss_mech_lock);
 148  147          tmp = __kgss_get_mechanism(&mech->mech_type);
 149  148          if (tmp != NULL) {
 150  149                  DUMMY_MECH_LOG0(8,
 151  150                          "dummy GSS mechanism: mechanism already in table.\n");
 152  151                  if (tmp->uses_kmod == TRUE) {
 153  152                          DUMMY_MECH_LOG0(8, "dummy GSS mechanism: mechanism "
 154  153                                  "table supports kernel operations!\n");
 155  154                  }
 156  155                  /*
 157  156                   * keep us loaded, but let us be unloadable. This
 158  157                   * will give the developer time to trouble shoot
 159  158                   */
 160  159                  dummy_fini_code = 0;
 161  160          } else {
 162  161                  __kgss_add_mechanism(mech);
 163  162                  ASSERT(__kgss_get_mechanism(&mech->mech_type) == mech);
 164  163          }
 165  164          mutex_exit(&__kgss_mech_lock);
 166  165  
 167  166          if ((retval = mod_install(&modlinkage)) != 0)
 168  167                  gss_mech_fini();        /* clean up */
 169  168  
 170  169          return (retval);
 171  170  }
 172  171  
 173  172  int
 174  173  _fini()
 175  174  {
 176  175          int ret = dummy_fini_code;
 177  176  
 178  177          if (ret == 0) {
 179  178                  ret = (mod_remove(&modlinkage));
 180  179          }
 181  180          return (ret);
 182  181  }
 183  182  
 184  183  int
 185  184  _info(struct modinfo *modinfop)
 186  185  {
 187  186          return (mod_info(&modlinkage, modinfop));
 188  187  }
 189  188  
 190  189  
 191  190  /*ARGSUSED*/
 192  191  static OM_uint32
 193  192  dummy_gss_sign(context, minor_status, context_handle,
 194  193                  qop_req, message_buffer, message_token,
 195  194                  gssd_ctx_verifier)
 196  195          void *context;
 197  196          OM_uint32 *minor_status;
 198  197          gss_ctx_id_t context_handle;
 199  198          int qop_req;
 200  199          gss_buffer_t message_buffer;
 201  200          gss_buffer_t message_token;
 202  201          OM_uint32 gssd_ctx_verifier;
 203  202  {
 204  203          dummy_gss_ctx_id_rec    *ctx;
 205  204          char token_string[] = "dummy_gss_sign";
 206  205  
 207  206          dprintf("Entering gss_sign\n");
 208  207  
 209  208          if (context_handle == GSS_C_NO_CONTEXT)
 210  209                  return (GSS_S_NO_CONTEXT);
 211  210          ctx = (dummy_gss_ctx_id_rec *) context_handle;
 212  211          ASSERT(ctx->established == 1);
 213  212          ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER);
 214  213  
 215  214          *message_token = make_dummy_token_msg(
 216  215                                  token_string, strlen(token_string));
 217  216  
 218  217          dprintf("Leaving gss_sign\n");
 219  218          return (GSS_S_COMPLETE);
 220  219  }
 221  220  
 222  221  /*ARGSUSED*/
 223  222  static OM_uint32
 224  223          dummy_gss_verify(context, minor_status, context_handle,
 225  224                  message_buffer, token_buffer, qop_state,
 226  225                  gssd_ctx_verifier)
 227  226          void *context;
 228  227          OM_uint32 *minor_status;
 229  228          gss_ctx_id_t context_handle;
 230  229          gss_buffer_t message_buffer;
 231  230          gss_buffer_t token_buffer;
 232  231          int *qop_state;
 233  232          OM_uint32 gssd_ctx_verifier;
 234  233  {
 235  234          unsigned char *ptr;
 236  235          int bodysize;
 237  236          int err;
 238  237          dummy_gss_ctx_id_rec    *ctx;
 239  238  
 240  239          dprintf("Entering gss_verify\n");
 241  240  
 242  241          if (context_handle == GSS_C_NO_CONTEXT)
 243  242                  return (GSS_S_NO_CONTEXT);
 244  243  
 245  244          ctx = (dummy_gss_ctx_id_rec *) context_handle;
 246  245          ASSERT(ctx->established == 1);
 247  246          ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER);
 248  247          /* Check for defective input token. */
 249  248  
 250  249          ptr = (unsigned char *) token_buffer->value;
 251  250          if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize,
 252  251                                          &ptr, 0,
 253  252                                          token_buffer->length)) {
 254  253                  *minor_status = err;
 255  254                  return (GSS_S_DEFECTIVE_TOKEN);
 256  255          }
 257  256  
 258  257          *qop_state = GSS_C_QOP_DEFAULT;
 259  258  
 260  259          dprintf("Leaving gss_verify\n");
 261  260          return (GSS_S_COMPLETE);
 262  261  }
 263  262  
 264  263  /*ARGSUSED*/
 265  264  static OM_uint32
 266  265  dummy_gss_seal(context, minor_status, context_handle, conf_req_flag,
 267  266                  qop_req, input_message_buffer, conf_state,
 268  267                  output_message_buffer, gssd_ctx_verifier)
 269  268          void *context;
 270  269          OM_uint32 *minor_status;
 271  270          gss_ctx_id_t context_handle;
 272  271          int conf_req_flag;
 273  272          int qop_req;
 274  273          gss_buffer_t input_message_buffer;
 275  274          int *conf_state;
 276  275          gss_buffer_t output_message_buffer;
 277  276          OM_uint32 gssd_ctx_verifier;
 278  277  {
 279  278          gss_buffer_desc output;
 280  279          dummy_gss_ctx_id_rec    *ctx;
 281  280          dprintf("Entering gss_seal\n");
 282  281  
 283  282          if (context_handle == GSS_C_NO_CONTEXT)
 284  283                  return (GSS_S_NO_CONTEXT);
 285  284          ctx = (dummy_gss_ctx_id_rec *) context_handle;
 286  285          ASSERT(ctx->established == 1);
 287  286          ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER);
 288  287          /* Copy the input message to output message */
 289  288          output = make_dummy_token_msg(
 290  289                  input_message_buffer->value, input_message_buffer->length);
 291  290  
 292  291          if (conf_state)
 293  292                  *conf_state = 1;
 294  293  
 295  294          *output_message_buffer = output;
 296  295  
 297  296          dprintf("Leaving gss_seal\n");
 298  297          return (GSS_S_COMPLETE);
 299  298  }
 300  299  
 301  300  /*ARGSUSED*/
 302  301  static OM_uint32
 303  302  dummy_gss_unseal(context, minor_status, context_handle,
 304  303                  input_message_buffer, output_message_buffer,
 305  304                  conf_state, qop_state, gssd_ctx_verifier)
 306  305          void *context;
 307  306          OM_uint32 *minor_status;
 308  307          gss_ctx_id_t context_handle;
 309  308          gss_buffer_t input_message_buffer;
 310  309          gss_buffer_t output_message_buffer;
 311  310          int *conf_state;
 312  311          int *qop_state;
 313  312          OM_uint32 gssd_ctx_verifier;
 314  313  {
 315  314          gss_buffer_desc output;
 316  315          dummy_gss_ctx_id_rec    *ctx;
 317  316          unsigned char *ptr;
 318  317          int bodysize;
 319  318          int err;
 320  319  
 321  320          dprintf("Entering gss_unseal\n");
 322  321  
 323  322          if (context_handle == GSS_C_NO_CONTEXT)
 324  323                  return (GSS_S_NO_CONTEXT);
 325  324  
 326  325          ctx = (dummy_gss_ctx_id_rec *) context_handle;
 327  326          ASSERT(ctx->established == 1);
 328  327          ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER);
 329  328  
 330  329          ptr = (unsigned char *) input_message_buffer->value;
 331  330          if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize,
 332  331                                          &ptr, 0,
 333  332                                          input_message_buffer->length)) {
 334  333                  *minor_status = err;
 335  334                  return (GSS_S_DEFECTIVE_TOKEN);
 336  335          }
 337  336          output.length = bodysize;
 338  337          output.value = (void *)MALLOC(output.length);
 339  338          (void) memcpy(output.value, ptr, output.length);
 340  339  
 341  340          *output_message_buffer = output;
 342  341          *qop_state = GSS_C_QOP_DEFAULT;
 343  342  
 344  343          if (conf_state)
 345  344                  *conf_state = 1;
 346  345  
 347  346          dprintf("Leaving gss_unseal\n");
 348  347          return (GSS_S_COMPLETE);
 349  348  }
 350  349  
 351  350  /*ARGSUSED*/
 352  351  OM_uint32
 353  352          dummy_gss_import_sec_context(ct, minor_status, interprocess_token,
 354  353                                          context_handle)
 355  354  void *ct;
 356  355  OM_uint32 *minor_status;
 357  356  gss_buffer_t interprocess_token;
 358  357  gss_ctx_id_t *context_handle;
 359  358  {
 360  359          unsigned char *ptr;
 361  360          int bodysize;
 362  361          int err;
 363  362  
 364  363          /* Assume that we got ctx from the interprocess token. */
 365  364          dummy_gss_ctx_id_t ctx;
 366  365  
 367  366          dprintf("Entering import_sec_context\n");
 368  367          ptr = (unsigned char *) interprocess_token->value;
 369  368          if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize,
 370  369                                          &ptr, 0,
 371  370                                          interprocess_token->length)) {
 372  371                  *minor_status = err;
 373  372                  return (GSS_S_DEFECTIVE_TOKEN);
 374  373          }
 375  374          ctx = (dummy_gss_ctx_id_t)MALLOC(sizeof (dummy_gss_ctx_id_rec));
 376  375          ctx->token_number = MAGIC_TOKEN_NUMBER;
 377  376          ctx->established = 1;
 378  377  
 379  378          *context_handle = (gss_ctx_id_t)ctx;
 380  379  
 381  380          dprintf("Leaving import_sec_context\n");
 382  381          return (GSS_S_COMPLETE);
 383  382  }
 384  383  
 385  384  /*ARGSUSED*/
 386  385  static OM_uint32
 387  386  dummy_gss_delete_sec_context(ct, minor_status,
 388  387                          context_handle, output_token,
 389  388                          gssd_ctx_verifier)
 390  389  void *ct;
 391  390  OM_uint32 *minor_status;
 392  391  gss_ctx_id_t *context_handle;
 393  392  gss_buffer_t output_token;
 394  393  OM_uint32 gssd_ctx_verifier;
 395  394  {
 396  395          dummy_gss_ctx_id_t ctx;
 397  396  
 398  397          dprintf("Entering delete_sec_context\n");
 399  398  
 400  399          /* Make the length to 0, so the output token is not sent to peer */
 401  400          if (output_token) {
 402  401                  output_token->length = 0;
 403  402                  output_token->value = NULL;
 404  403          }
 405  404  
 406  405          if (*context_handle == GSS_C_NO_CONTEXT) {
 407  406                  *minor_status = 0;
 408  407                  return (GSS_S_COMPLETE);
 409  408          }
 410  409  
 411  410          ctx = (dummy_gss_ctx_id_rec *) *context_handle;
 412  411          ASSERT(ctx->established == 1);
 413  412          ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER);
 414  413  
 415  414          FREE(ctx, sizeof (dummy_gss_ctx_id_rec));
 416  415          *context_handle = GSS_C_NO_CONTEXT;
 417  416  
 418  417          dprintf("Leaving delete_sec_context\n");
 419  418          return (GSS_S_COMPLETE);
 420  419  }
 421  420  
 422  421  static int
 423  422  der_length_size(int length)
 424  423  {
 425  424          if (length < (1<<7))
 426  425                  return (1);
 427  426          else if (length < (1<<8))
 428  427                  return (2);
 429  428          else if (length < (1<<16))
 430  429                  return (3);
 431  430          else if (length < (1<<24))
 432  431                  return (4);
 433  432          else
 434  433                  return (5);
 435  434  }
 436  435  
 437  436  static void
 438  437  der_write_length(unsigned char ** buf, int length)
 439  438  {
 440  439          if (length < (1<<7)) {
 441  440                  *(*buf)++ = (unsigned char) length;
 442  441          } else {
 443  442                  *(*buf)++ = (unsigned char) (der_length_size(length)+127);
 444  443                  if (length >= (1<<24))
 445  444                          *(*buf)++ = (unsigned char) (length>>24);
 446  445                  if (length >= (1<<16))
 447  446                          *(*buf)++ = (unsigned char) ((length>>16)&0xff);
 448  447                  if (length >= (1<<8))
 449  448                          *(*buf)++ = (unsigned char) ((length>>8)&0xff);
 450  449                  *(*buf)++ = (unsigned char) (length&0xff);
 451  450          }
 452  451  }
 453  452  
 454  453  static int
 455  454  der_read_length(buf, bufsize)
 456  455  unsigned char **buf;
 457  456  int *bufsize;
 458  457  {
 459  458          unsigned char sf;
 460  459          int ret;
 461  460  
 462  461          if (*bufsize < 1)
 463  462                  return (-1);
 464  463          sf = *(*buf)++;
 465  464          (*bufsize)--;
 466  465          if (sf & 0x80) {
 467  466                  if ((sf &= 0x7f) > ((*bufsize)-1))
 468  467                          return (-1);
 469  468                  if (sf > DUMMY_SIZE_OF_INT)
 470  469                          return (-1);
 471  470                  ret = 0;
 472  471                  for (; sf; sf--) {
 473  472                          ret = (ret<<8) + (*(*buf)++);
 474  473                          (*bufsize)--;
 475  474                  }
 476  475          } else {
 477  476                  ret = sf;
 478  477          }
 479  478  
 480  479          return (ret);
 481  480  }
 482  481  
 483  482  static int
 484  483  g_token_size(mech, body_size)
 485  484          gss_OID mech;
 486  485          unsigned int body_size;
 487  486  {
 488  487          /* set body_size to sequence contents size */
 489  488          body_size += 4 + (int)mech->length;     /* NEED overflow check */
 490  489          return (1 + der_length_size(body_size) + body_size);
 491  490  }
 492  491  
 493  492  static void
 494  493  g_make_token_header(mech, body_size, buf, tok_type)
 495  494          gss_OID mech;
 496  495          int body_size;
 497  496          unsigned char **buf;
 498  497          int tok_type;
 499  498  {
 500  499          *(*buf)++ = 0x60;
 501  500          der_write_length(buf, 4 + mech->length + body_size);
 502  501          *(*buf)++ = 0x06;
 503  502          *(*buf)++ = (unsigned char) mech->length;
 504  503          TWRITE_STR(*buf, mech->elements, ((int)mech->length));
 505  504          *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
 506  505          *(*buf)++ = (unsigned char) (tok_type&0xff);
 507  506  }
 508  507  
 509  508  static int
 510  509  g_verify_token_header(mech, body_size, buf_in, tok_type, toksize)
 511  510          gss_OID mech;
 512  511          int *body_size;
 513  512          unsigned char **buf_in;
 514  513          int tok_type;
 515  514          int toksize;
 516  515  {
 517  516          unsigned char *buf = *buf_in;
 518  517          int seqsize;
 519  518          gss_OID_desc toid;
 520  519          int ret = 0;
 521  520  
 522  521          if ((toksize -= 1) < 0)
 523  522                  return (G_BAD_TOK_HEADER);
 524  523          if (*buf++ != 0x60)
 525  524                  return (G_BAD_TOK_HEADER);
 526  525  
 527  526          if ((seqsize = der_read_length(&buf, &toksize)) < 0)
 528  527                  return (G_BAD_TOK_HEADER);
 529  528  
 530  529          if (seqsize != toksize)
 531  530                  return (G_BAD_TOK_HEADER);
 532  531  
 533  532          if ((toksize -= 1) < 0)
 534  533                  return (G_BAD_TOK_HEADER);
 535  534          if (*buf++ != 0x06)
 536  535                  return (G_BAD_TOK_HEADER);
 537  536  
 538  537          if ((toksize -= 1) < 0)
 539  538                  return (G_BAD_TOK_HEADER);
 540  539          toid.length = *buf++;
 541  540  
 542  541          if ((toksize -= toid.length) < 0)
 543  542                  return (G_BAD_TOK_HEADER);
 544  543          toid.elements = buf;
 545  544          buf += toid.length;
 546  545  
 547  546          if (! g_OID_equal(&toid, mech))
 548  547                  ret = G_WRONG_MECH;
 549  548  
 550  549          /*
 551  550           * G_WRONG_MECH is not returned immediately because it's more important
 552  551           * to return G_BAD_TOK_HEADER if the token header is in fact bad
 553  552           */
 554  553  
 555  554          if ((toksize -= 2) < 0)
 556  555                  return (G_BAD_TOK_HEADER);
 557  556  
 558  557          if ((*buf++ != ((tok_type>>8)&0xff)) ||
 559  558              (*buf++ != (tok_type&0xff)))
 560  559                  return (G_BAD_TOK_HEADER);
 561  560  
 562  561          if (!ret) {
 563  562                  *buf_in = buf;
 564  563                  *body_size = toksize;
 565  564          }
 566  565  
 567  566          return (ret);
 568  567  }
 569  568  
 570  569  static gss_buffer_desc
 571  570  make_dummy_token_msg(void *data, int dataLen)
 572  571  {
 573  572          gss_buffer_desc buffer;
 574  573          int tlen;
 575  574          unsigned char *t;
 576  575          unsigned char *ptr;
 577  576  
 578  577          if (data == NULL) {
 579  578                  buffer.length = 0;
 580  579                  buffer.value = NULL;
 581  580                  return (buffer);
 582  581          }
 583  582  
 584  583          tlen = g_token_size((gss_OID)gss_mech_dummy, dataLen);
 585  584          t = (unsigned char *) MALLOC(tlen);
 586  585          ptr = t;
 587  586  
 588  587          g_make_token_header((gss_OID)gss_mech_dummy, dataLen, &ptr, 0);
 589  588          (void) memcpy(ptr, data, dataLen);
 590  589  
 591  590          buffer.length = tlen;
 592  591          buffer.value = (void *) t;
 593  592          return (buffer);
 594  593  }
  
    | 
      ↓ open down ↓ | 
    450 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX