Print this page
    
NEX-5260 smbd segfaults while running smbtorture:rpc.lsa.lookupnames
NEX-5261 smbd segfaults while running smbtorture:rpc.winreg
NEX-5262 smbd segfaults while running smbtorture:rpc.samba3
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c
          +++ new/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.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 (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  24   25   */
  25   26  
  26   27  /*
  27   28   * Windows Registry RPC (WINREG) server-side interface.
  28   29   *
  29   30   * The registry is a database with a hierarchical structure similar to
  30   31   * a file system, with keys in place of directories and values in place
  31   32   * of files.  The top level keys are known as root keys and each key can
  32   33   * contain subkeys and values.  As with directories and sub-directories,
  33   34   * the terms key and subkey are used interchangeably.  Values, analogous
  34   35   * to files, contain data.
  35   36   *
  36   37   * A specific subkey can be identifies by its fully qualified name (FQN),
  37   38   * which is analogous to a file system path.  In the registry, the key
  38   39   * separator is the '\' character, which is reserved and cannot appear
  39   40   * in key or value names.  Registry names are case-insensitive.
  40   41   *
  41   42   * For example:  HKEY_LOCAL_MACHINE\System\CurrentControlSet
  42   43   *
  43   44   * The HKEY_LOCAL_MACHINE root key contains a subkey called System, and
  44   45   * System contains a subkey called CurrentControlSet.
  45   46   *
  46   47   * The WINREG RPC interface returns Win32 error codes.
  47   48   */
  48   49  
  49   50  #include <sys/utsname.h>
  50   51  #include <strings.h>
  51   52  
  52   53  #include <smbsrv/libsmb.h>
  53   54  #include <smbsrv/nmpipes.h>
  54   55  #include <smbsrv/libmlsvc.h>
  55   56  #include <smbsrv/ndl/winreg.ndl>
  56   57  
  57   58  /*
  58   59   * List of supported registry keys (case-insensitive).
  59   60   */
  60   61  static char *winreg_keys[] = {
  61   62          "HKLM",
  62   63          "HKU",
  63   64          "HKLM\\SOFTWARE",
  64   65          "HKLM\\SYSTEM",
  65   66          "System",
  66   67          "CurrentControlSet",
  67   68          "SunOS",
  68   69          "Solaris",
  69   70          "System\\CurrentControlSet\\Services\\Eventlog",
  70   71          "System\\CurrentControlSet\\Control\\ProductOptions",
  71   72          "SOFTWARE",
  72   73          "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
  73   74  };
  74   75  
  75   76  static char *winreg_eventlog = "System\\CurrentControlSet\\Services\\Eventlog";
  76   77  
  77   78  static char *winreg_log[] = {
  78   79          "Application",
  79   80          "Security",
  80   81          "System",
  81   82          "smbd",
  82   83          "smbrdr"
  83   84  };
  84   85  
  85   86  typedef struct winreg_subkey {
  86   87          list_node_t sk_lnd;
  87   88          ndr_hdid_t sk_handle;
  88   89          char sk_name[MAXPATHLEN];
  89   90          boolean_t sk_predefined;
  90   91  } winreg_subkey_t;
  91   92  
  92   93  typedef struct winreg_keylist {
  93   94          list_t kl_list;
  94   95          int kl_count;
  95   96  } winreg_keylist_t;
  96   97  
  97   98  static winreg_keylist_t winreg_keylist;
  98   99  static mutex_t winreg_mutex;
  99  100  
 100  101  static void winreg_add_predefined(const char *);
 101  102  static ndr_hdid_t *winreg_alloc_id(ndr_xa_t *, const char *);
 102  103  static void winreg_dealloc_id(ndr_xa_t *, ndr_hdid_t *);
 103  104  static boolean_t winreg_key_has_subkey(const char *);
 104  105  static char *winreg_enum_subkey(ndr_xa_t *, const char *, uint32_t);
 105  106  static char *winreg_lookup_value(const char *);
 106  107  static uint32_t winreg_sd_format(smb_sd_t *);
 107  108  uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *);
 108  109  
 109  110  static int winreg_s_OpenHKCR(void *, ndr_xa_t *);
 110  111  static int winreg_s_OpenHKCU(void *, ndr_xa_t *);
 111  112  static int winreg_s_OpenHKLM(void *, ndr_xa_t *);
 112  113  static int winreg_s_OpenHKPD(void *, ndr_xa_t *);
 113  114  static int winreg_s_OpenHKU(void *, ndr_xa_t *);
 114  115  static int winreg_s_OpenHKCC(void *, ndr_xa_t *);
 115  116  static int winreg_s_OpenHKDD(void *, ndr_xa_t *);
 116  117  static int winreg_s_OpenHKPT(void *, ndr_xa_t *);
 117  118  static int winreg_s_OpenHKPN(void *, ndr_xa_t *);
 118  119  static int winreg_s_OpenHK(void *, ndr_xa_t *, const char *);
 119  120  static int winreg_s_Close(void *, ndr_xa_t *);
 120  121  static int winreg_s_CreateKey(void *, ndr_xa_t *);
 121  122  static int winreg_s_DeleteKey(void *, ndr_xa_t *);
 122  123  static int winreg_s_DeleteValue(void *, ndr_xa_t *);
 123  124  static int winreg_s_EnumKey(void *, ndr_xa_t *);
 124  125  static int winreg_s_EnumValue(void *, ndr_xa_t *);
 125  126  static int winreg_s_FlushKey(void *, ndr_xa_t *);
 126  127  static int winreg_s_GetKeySec(void *, ndr_xa_t *);
 127  128  static int winreg_s_NotifyChange(void *, ndr_xa_t *);
 128  129  static int winreg_s_OpenKey(void *, ndr_xa_t *);
 129  130  static int winreg_s_QueryKey(void *, ndr_xa_t *);
 130  131  static int winreg_s_QueryValue(void *, ndr_xa_t *);
 131  132  static int winreg_s_SetKeySec(void *, ndr_xa_t *);
 132  133  static int winreg_s_CreateValue(void *, ndr_xa_t *);
 133  134  static int winreg_s_Shutdown(void *, ndr_xa_t *);
 134  135  static int winreg_s_AbortShutdown(void *, ndr_xa_t *);
 135  136  static int winreg_s_GetVersion(void *, ndr_xa_t *);
 136  137  
 137  138  static ndr_stub_table_t winreg_stub_table[] = {
 138  139          { winreg_s_OpenHKCR,    WINREG_OPNUM_OpenHKCR },
 139  140          { winreg_s_OpenHKCU,    WINREG_OPNUM_OpenHKCU },
 140  141          { winreg_s_OpenHKLM,    WINREG_OPNUM_OpenHKLM },
 141  142          { winreg_s_OpenHKPD,    WINREG_OPNUM_OpenHKPD },
 142  143          { winreg_s_OpenHKU,     WINREG_OPNUM_OpenHKUsers },
 143  144          { winreg_s_Close,       WINREG_OPNUM_Close },
 144  145          { winreg_s_CreateKey,   WINREG_OPNUM_CreateKey },
 145  146          { winreg_s_DeleteKey,   WINREG_OPNUM_DeleteKey },
 146  147          { winreg_s_DeleteValue, WINREG_OPNUM_DeleteValue },
 147  148          { winreg_s_EnumKey,     WINREG_OPNUM_EnumKey },
 148  149          { winreg_s_EnumValue,   WINREG_OPNUM_EnumValue },
 149  150          { winreg_s_FlushKey,    WINREG_OPNUM_FlushKey },
 150  151          { winreg_s_GetKeySec,   WINREG_OPNUM_GetKeySec },
 151  152          { winreg_s_NotifyChange,        WINREG_OPNUM_NotifyChange },
 152  153          { winreg_s_OpenKey,     WINREG_OPNUM_OpenKey },
 153  154          { winreg_s_QueryKey,    WINREG_OPNUM_QueryKey },
 154  155          { winreg_s_QueryValue,  WINREG_OPNUM_QueryValue },
 155  156          { winreg_s_SetKeySec,   WINREG_OPNUM_SetKeySec },
 156  157          { winreg_s_CreateValue, WINREG_OPNUM_CreateValue },
 157  158          { winreg_s_Shutdown,    WINREG_OPNUM_Shutdown },
 158  159          { winreg_s_AbortShutdown,       WINREG_OPNUM_AbortShutdown },
 159  160          { winreg_s_GetVersion,  WINREG_OPNUM_GetVersion },
 160  161          { winreg_s_OpenHKCC,    WINREG_OPNUM_OpenHKCC },
 161  162          { winreg_s_OpenHKDD,    WINREG_OPNUM_OpenHKDD },
 162  163          { winreg_s_OpenHKPT,    WINREG_OPNUM_OpenHKPT },
 163  164          { winreg_s_OpenHKPN,    WINREG_OPNUM_OpenHKPN },
 164  165          {0}
 165  166  };
 166  167  
 167  168  static ndr_service_t winreg_service = {
 168  169          "Winreg",                       /* name */
 169  170          "Windows Registry",             /* desc */
 170  171          "\\winreg",                     /* endpoint */
 171  172          PIPE_WINREG,                    /* sec_addr_port */
 172  173          "338cd001-2244-31f1-aaaa-900038001003", 1,      /* abstract */
 173  174          NDR_TRANSFER_SYNTAX_UUID,               2,      /* transfer */
 174  175          0,                              /* no bind_instance_size */
 175  176          0,                              /* no bind_req() */
 176  177          0,                              /* no unbind_and_close() */
 177  178          0,                              /* use generic_call_stub() */
 178  179          &TYPEINFO(winreg_interface),    /* interface ti */
 179  180          winreg_stub_table               /* stub_table */
 180  181  };
 181  182  
 182  183  static char winreg_sysname[SYS_NMLN];
 183  184  static char winreg_sysver[SMB_VERSTR_LEN];
 184  185  
 185  186  /*
 186  187   * winreg_initialize
 187  188   *
 188  189   * Initialize and register the WINREG RPC interface with the RPC runtime
 189  190   * library. It must be called in order to use either the client side
 190  191   * or the server side functions.
 191  192   */
 192  193  void
 193  194  winreg_initialize(void)
 194  195  {
 195  196          smb_version_t version;
 196  197          struct utsname name;
 197  198          char subkey[MAXPATHLEN];
 198  199          char *sysname;
 199  200          int i;
 200  201  
 201  202          (void) mutex_lock(&winreg_mutex);
 202  203  
 203  204          list_create(&winreg_keylist.kl_list, sizeof (winreg_subkey_t),
 204  205              offsetof(winreg_subkey_t, sk_lnd));
 205  206          winreg_keylist.kl_count = 0;
 206  207  
 207  208          for (i = 0; i < sizeof (winreg_keys)/sizeof (winreg_keys[0]); ++i)
 208  209                  winreg_add_predefined(winreg_keys[i]);
 209  210  
 210  211          for (i = 0; i < sizeof (winreg_log)/sizeof (winreg_log[0]); ++i) {
 211  212                  (void) snprintf(subkey, MAXPATHLEN, "%s", winreg_log[i]);
 212  213                  winreg_add_predefined(subkey);
 213  214  
 214  215                  (void) snprintf(subkey, MAXPATHLEN, "%s\\%s",
 215  216                      winreg_eventlog, winreg_log[i]);
 216  217                  winreg_add_predefined(subkey);
 217  218  
 218  219                  (void) snprintf(subkey, MAXPATHLEN, "%s\\%s\\%s",
 219  220                      winreg_eventlog, winreg_log[i], winreg_log[i]);
 220  221                  winreg_add_predefined(subkey);
 221  222          }
 222  223  
 223  224          (void) mutex_unlock(&winreg_mutex);
 224  225  
 225  226          if (uname(&name) < 0)
 226  227                  sysname = "Solaris";
 227  228          else
 228  229                  sysname = name.sysname;
 229  230  
 230  231          (void) strlcpy(winreg_sysname, sysname, SYS_NMLN);
 231  232  
 232  233          smb_config_get_version(&version);
 233  234          (void) snprintf(winreg_sysver, SMB_VERSTR_LEN, "%d.%d",
 234  235              version.sv_major, version.sv_minor);
 235  236  
 236  237          (void) ndr_svc_register(&winreg_service);
 237  238  }
 238  239  
 239  240  static void
 240  241  winreg_add_predefined(const char *subkey)
 241  242  {
 242  243          winreg_subkey_t *key;
 243  244  
 244  245          if ((key = malloc(sizeof (winreg_subkey_t))) != NULL) {
 245  246                  bzero(key, sizeof (winreg_subkey_t));
 246  247                  (void) strlcpy(key->sk_name, subkey, MAXPATHLEN);
 247  248                  key->sk_predefined = B_TRUE;
 248  249  
 249  250                  list_insert_tail(&winreg_keylist.kl_list, key);
 250  251                  ++winreg_keylist.kl_count;
 251  252          }
 252  253  }
 253  254  
 254  255  static int
 255  256  winreg_s_OpenHKCR(void *arg, ndr_xa_t *mxa)
 256  257  {
 257  258          return (winreg_s_OpenHK(arg, mxa, "HKCR"));
 258  259  }
 259  260  
 260  261  static int
 261  262  winreg_s_OpenHKCU(void *arg, ndr_xa_t *mxa)
 262  263  {
 263  264          return (winreg_s_OpenHK(arg, mxa, "HKCU"));
 264  265  }
 265  266  
 266  267  static int
 267  268  winreg_s_OpenHKLM(void *arg, ndr_xa_t *mxa)
 268  269  {
 269  270          return (winreg_s_OpenHK(arg, mxa, "HKLM"));
 270  271  }
 271  272  
 272  273  static int
 273  274  winreg_s_OpenHKPD(void *arg, ndr_xa_t *mxa)
 274  275  {
 275  276          return (winreg_s_OpenHK(arg, mxa, "HKPD"));
 276  277  }
 277  278  
 278  279  static int
 279  280  winreg_s_OpenHKU(void *arg, ndr_xa_t *mxa)
 280  281  {
 281  282          return (winreg_s_OpenHK(arg, mxa, "HKU"));
 282  283  }
 283  284  
 284  285  static int
 285  286  winreg_s_OpenHKCC(void *arg, ndr_xa_t *mxa)
 286  287  {
 287  288          return (winreg_s_OpenHK(arg, mxa, "HKCC"));
 288  289  }
 289  290  
 290  291  static int
 291  292  winreg_s_OpenHKDD(void *arg, ndr_xa_t *mxa)
 292  293  {
 293  294          return (winreg_s_OpenHK(arg, mxa, "HKDD"));
 294  295  }
 295  296  
 296  297  static int
 297  298  winreg_s_OpenHKPT(void *arg, ndr_xa_t *mxa)
 298  299  {
 299  300          return (winreg_s_OpenHK(arg, mxa, "HKPT"));
 300  301  }
 301  302  
 302  303  static int
 303  304  winreg_s_OpenHKPN(void *arg, ndr_xa_t *mxa)
 304  305  {
 305  306          return (winreg_s_OpenHK(arg, mxa, "HKPN"));
 306  307  }
 307  308  
 308  309  /*
 309  310   * winreg_s_OpenHK
 310  311   *
 311  312   * Common code to open root HKEYs.
 312  313   */
 313  314  static int
 314  315  winreg_s_OpenHK(void *arg, ndr_xa_t *mxa, const char *hkey)
 315  316  {
 316  317          struct winreg_OpenHKCR *param = arg;
 317  318          ndr_hdid_t *id;
 318  319  
 319  320          (void) mutex_lock(&winreg_mutex);
 320  321  
 321  322          if ((id = winreg_alloc_id(mxa, hkey)) == NULL) {
 322  323                  bzero(¶m->handle, sizeof (winreg_handle_t));
 323  324                  param->status = ERROR_ACCESS_DENIED;
 324  325          } else {
 325  326                  bcopy(id, ¶m->handle, sizeof (winreg_handle_t));
 326  327                  param->status = ERROR_SUCCESS;
 327  328          }
 328  329  
 329  330          (void) mutex_unlock(&winreg_mutex);
 330  331          return (NDR_DRC_OK);
 331  332  }
 332  333  
 333  334  /*
 334  335   * winreg_s_Close
 335  336   *
 336  337   * This is a request to close the WINREG interface specified by the
 337  338   * handle. We don't track handles (yet), so just zero out the handle
 338  339   * and return NDR_DRC_OK. Setting the handle to zero appears to be
 339  340   * standard behaviour.
 340  341   */
 341  342  static int
 342  343  winreg_s_Close(void *arg, ndr_xa_t *mxa)
 343  344  {
 344  345          struct winreg_Close *param = arg;
 345  346          ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
 346  347  
 347  348          (void) mutex_lock(&winreg_mutex);
 348  349          winreg_dealloc_id(mxa, id);
 349  350          (void) mutex_unlock(&winreg_mutex);
 350  351  
 351  352          bzero(¶m->result_handle, sizeof (winreg_handle_t));
 352  353          param->status = ERROR_SUCCESS;
 353  354          return (NDR_DRC_OK);
 354  355  }
 355  356  
 356  357  static ndr_hdid_t *
 357  358  winreg_alloc_id(ndr_xa_t *mxa, const char *key)
 358  359  {
 359  360          ndr_handle_t    *hd;
 360  361          ndr_hdid_t      *id;
 361  362          char            *data;
 362  363  
 363  364          if ((data = strdup(key)) == NULL)
 364  365                  return (NULL);
 365  366  
 366  367          if ((id = ndr_hdalloc(mxa, data)) == NULL) {
 367  368                  free(data);
 368  369                  return (NULL);
 369  370          }
 370  371  
 371  372          if ((hd = ndr_hdlookup(mxa, id)) != NULL)
 372  373                  hd->nh_data_free = free;
 373  374  
 374  375          return (id);
 375  376  }
 376  377  
 377  378  static void
 378  379  winreg_dealloc_id(ndr_xa_t *mxa, ndr_hdid_t *id)
 379  380  {
 380  381          ndr_handle_t *hd;
 381  382  
 382  383          if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
 383  384                  free(hd->nh_data);
 384  385                  hd->nh_data = NULL;
 385  386          }
 386  387  
 387  388          ndr_hdfree(mxa, id);
 388  389  }
 389  390  
 390  391  /*
 391  392   * winreg_s_CreateKey
 392  393   */
 393  394  static int
 394  395  winreg_s_CreateKey(void *arg, ndr_xa_t *mxa)
 395  396  {
 396  397          struct winreg_CreateKey *param = arg;
 397  398          ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
 398  399          ndr_handle_t *hd;
 399  400          winreg_subkey_t *key;
 400  401          char *subkey;
 401  402          DWORD *action;
 402  403  
 403  404          subkey = (char *)param->subkey.str;
 404  405  
 405  406          if (!ndr_is_admin(mxa) || (subkey == NULL)) {
 406  407                  bzero(param, sizeof (struct winreg_CreateKey));
 407  408                  param->status = ERROR_ACCESS_DENIED;
 408  409                  return (NDR_DRC_OK);
 409  410          }
 410  411  
 411  412          (void) mutex_lock(&winreg_mutex);
 412  413  
 413  414          hd = ndr_hdlookup(mxa, id);
 414  415          if (hd == NULL) {
 415  416                  (void) mutex_unlock(&winreg_mutex);
 416  417                  bzero(param, sizeof (struct winreg_CreateKey));
 417  418                  param->status = ERROR_INVALID_HANDLE;
 418  419                  return (NDR_DRC_OK);
 419  420          }
 420  421  
 421  422          if ((action = NDR_NEW(mxa, DWORD)) == NULL) {
 422  423                  (void) mutex_unlock(&winreg_mutex);
 423  424                  bzero(param, sizeof (struct winreg_CreateKey));
 424  425                  param->status = ERROR_NOT_ENOUGH_MEMORY;
 425  426                  return (NDR_DRC_OK);
 426  427          }
 427  428  
 428  429          if (list_is_empty(&winreg_keylist.kl_list))
 429  430                  goto new_key;
 430  431  
 431  432          /*
 432  433           * Check for an existing key.
 433  434           */
 434  435          key = list_head(&winreg_keylist.kl_list);
 435  436          do {
 436  437                  if (strcasecmp(subkey, key->sk_name) == 0) {
 437  438                          bcopy(&key->sk_handle, ¶m->result_handle,
 438  439                              sizeof (winreg_handle_t));
 439  440  
 440  441                          (void) mutex_unlock(&winreg_mutex);
 441  442                          *action = WINREG_ACTION_EXISTING_KEY;
 442  443                          param->action = action;
 443  444                          param->status = ERROR_SUCCESS;
 444  445                          return (NDR_DRC_OK);
 445  446                  }
 446  447          } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
 447  448  
 448  449  new_key:
 449  450          /*
 450  451           * Create a new key.
 451  452           */
 452  453          if ((id = winreg_alloc_id(mxa, subkey)) == NULL)
 453  454                  goto no_memory;
 454  455  
 455  456          if ((key = malloc(sizeof (winreg_subkey_t))) == NULL) {
 456  457                  winreg_dealloc_id(mxa, id);
 457  458                  goto no_memory;
 458  459          }
 459  460  
 460  461          bcopy(id, &key->sk_handle, sizeof (ndr_hdid_t));
 461  462          (void) strlcpy(key->sk_name, subkey, MAXPATHLEN);
 462  463          key->sk_predefined = B_FALSE;
 463  464          list_insert_tail(&winreg_keylist.kl_list, key);
 464  465          ++winreg_keylist.kl_count;
 465  466  
 466  467          bcopy(id, ¶m->result_handle, sizeof (winreg_handle_t));
 467  468  
 468  469          (void) mutex_unlock(&winreg_mutex);
 469  470          *action = WINREG_ACTION_NEW_KEY;
 470  471          param->action = action;
 471  472          param->status = ERROR_SUCCESS;
 472  473          return (NDR_DRC_OK);
 473  474  
 474  475  no_memory:
 475  476          (void) mutex_unlock(&winreg_mutex);
 476  477          bzero(param, sizeof (struct winreg_CreateKey));
 477  478          param->status = ERROR_NOT_ENOUGH_MEMORY;
 478  479          return (NDR_DRC_OK);
 479  480  }
 480  481  
 481  482  /*
 482  483   * winreg_s_DeleteKey
 483  484   */
 484  485  static int
 485  486  winreg_s_DeleteKey(void *arg, ndr_xa_t *mxa)
 486  487  {
 487  488          struct winreg_DeleteKey *param = arg;
 488  489          ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
 489  490          winreg_subkey_t *key;
 490  491          char *subkey;
 491  492  
 492  493          subkey = (char *)param->subkey.str;
 493  494  
 494  495          if (!ndr_is_admin(mxa) || (subkey == NULL)) {
 495  496                  param->status = ERROR_ACCESS_DENIED;
 496  497                  return (NDR_DRC_OK);
 497  498          }
 498  499  
 499  500          (void) mutex_lock(&winreg_mutex);
 500  501  
 501  502          if ((ndr_hdlookup(mxa, id) == NULL) ||
 502  503              list_is_empty(&winreg_keylist.kl_list) ||
 503  504              winreg_key_has_subkey(subkey)) {
 504  505                  (void) mutex_unlock(&winreg_mutex);
 505  506                  param->status = ERROR_ACCESS_DENIED;
 506  507                  return (NDR_DRC_OK);
 507  508          }
 508  509  
 509  510          key = list_head(&winreg_keylist.kl_list);
 510  511          do {
 511  512                  if (strcasecmp(subkey, key->sk_name) == 0) {
 512  513                          if (key->sk_predefined == B_TRUE) {
 513  514                                  /* Predefined keys cannot be deleted */
 514  515                                  break;
 515  516                          }
 516  517  
 517  518                          list_remove(&winreg_keylist.kl_list, key);
 518  519                          --winreg_keylist.kl_count;
 519  520                          winreg_dealloc_id(mxa, &key->sk_handle);
 520  521                          free(key);
 521  522  
 522  523                          (void) mutex_unlock(&winreg_mutex);
 523  524                          param->status = ERROR_SUCCESS;
 524  525                          return (NDR_DRC_OK);
 525  526                  }
 526  527          } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
 527  528  
 528  529          (void) mutex_unlock(&winreg_mutex);
 529  530          param->status = ERROR_ACCESS_DENIED;
 530  531          return (NDR_DRC_OK);
 531  532  }
 532  533  
 533  534  /*
 534  535   * Call with the winreg_mutex held.
 535  536   */
 536  537  static boolean_t
 537  538  winreg_key_has_subkey(const char *subkey)
 538  539  {
 539  540          winreg_subkey_t *key;
 540  541          int keylen;
 541  542  
 542  543          if (list_is_empty(&winreg_keylist.kl_list))
 543  544                  return (B_FALSE);
 544  545  
 545  546          keylen = strlen(subkey);
 546  547  
 547  548          key = list_head(&winreg_keylist.kl_list);
 548  549          do {
 549  550                  if (strncasecmp(subkey, key->sk_name, keylen) == 0) {
 550  551                          /*
 551  552                           * Potential match.  If sk_name is longer than
 552  553                           * subkey, then sk_name is a subkey of our key.
 553  554                           */
 554  555                          if (keylen < strlen(key->sk_name))
 555  556                                  return (B_TRUE);
 556  557                  }
 557  558          } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
 558  559  
 559  560          return (B_FALSE);
 560  561  }
 561  562  
 562  563  /*
 563  564   * Call with the winreg_mutex held.
 564  565   */
 565  566  static char *
 566  567  winreg_enum_subkey(ndr_xa_t *mxa, const char *subkey, uint32_t index)
 567  568  {
 568  569          winreg_subkey_t *key;
 569  570          char *entry;
 570  571          char *p;
 571  572          int subkeylen;
 572  573          int count = 0;
 573  574  
 574  575          if (subkey == NULL)
 575  576                  return (NULL);
 576  577  
 577  578          if (list_is_empty(&winreg_keylist.kl_list))
 578  579                  return (NULL);
 579  580  
 580  581          subkeylen = strlen(subkey);
 581  582  
 582  583          for (key = list_head(&winreg_keylist.kl_list);
 583  584              key != NULL; key = list_next(&winreg_keylist.kl_list, key)) {
 584  585                  if (strncasecmp(subkey, key->sk_name, subkeylen) == 0) {
 585  586                          p = key->sk_name + subkeylen;
 586  587  
 587  588                          if ((*p != '\\') || (*p == '\0')) {
 588  589                                  /*
 589  590                                   * Not the same subkey or an exact match.
 590  591                                   * We're looking for children of subkey.
 591  592                                   */
 592  593                                  continue;
 593  594                          }
 594  595  
 595  596                          ++p;
 596  597  
 597  598                          if (count < index) {
 598  599                                  ++count;
 599  600                                  continue;
 600  601                          }
 601  602  
 602  603                          if ((entry = NDR_STRDUP(mxa, p)) == NULL)
 603  604                                  return (NULL);
 604  605  
 605  606                          if ((p = strchr(entry, '\\')) != NULL)
 606  607                                  *p = '\0';
 607  608  
 608  609                          return (entry);
 609  610                  }
 610  611          }
 611  612  
 612  613          return (NULL);
 613  614  }
 614  615  
 615  616  /*
 616  617   * winreg_s_DeleteValue
 617  618   */
 618  619  /*ARGSUSED*/
 619  620  static int
 620  621  winreg_s_DeleteValue(void *arg, ndr_xa_t *mxa)
 621  622  {
 622  623          struct winreg_DeleteValue *param = arg;
 623  624  
 624  625          param->status = ERROR_ACCESS_DENIED;
 625  626          return (NDR_DRC_OK);
 626  627  }
 627  628  
 628  629  /*
 629  630   * winreg_s_EnumKey
 630  631   */
 631  632  static int
 632  633  winreg_s_EnumKey(void *arg, ndr_xa_t *mxa)
 633  634  {
 634  635          struct winreg_EnumKey *param = arg;
 635  636          ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
 636  637          ndr_handle_t *hd;
 637  638          char *subkey;
 638  639          char *name = NULL;
 639  640  
 640  641          (void) mutex_lock(&winreg_mutex);
 641  642  
 642  643          if ((hd = ndr_hdlookup(mxa, id)) != NULL)
 643  644                  name = hd->nh_data;
 644  645  
 645  646          if (hd == NULL || name == NULL) {
 646  647                  (void) mutex_unlock(&winreg_mutex);
 647  648                  bzero(param, sizeof (struct winreg_EnumKey));
 648  649                  param->status = ERROR_NO_MORE_ITEMS;
 649  650                  return (NDR_DRC_OK);
 650  651          }
 651  652  
 652  653          subkey = winreg_enum_subkey(mxa, name, param->index);
 653  654          if (subkey == NULL) {
 654  655                  (void) mutex_unlock(&winreg_mutex);
 655  656                  bzero(param, sizeof (struct winreg_EnumKey));
 656  657                  param->status = ERROR_NO_MORE_ITEMS;
 657  658                  return (NDR_DRC_OK);
 658  659          }
 659  660  
 660  661          if (NDR_MSTRING(mxa, subkey, (ndr_mstring_t *)¶m->name_out) == -1) {
 661  662                  (void) mutex_unlock(&winreg_mutex);
 662  663                  bzero(param, sizeof (struct winreg_EnumKey));
 663  664                  param->status = ERROR_NOT_ENOUGH_MEMORY;
 664  665                  return (NDR_DRC_OK);
 665  666          }
 666  667  
 667  668          (void) mutex_unlock(&winreg_mutex);
 668  669  
 669  670          /*
 670  671           * This request requires that the length includes the null.
 671  672           */
 672  673          param->name_out.length = param->name_out.allosize;
 673  674          param->status = ERROR_SUCCESS;
 674  675          return (NDR_DRC_OK);
 675  676  }
 676  677  
 677  678  /*
 678  679   * winreg_s_EnumValue
 679  680   */
 680  681  static int
 681  682  winreg_s_EnumValue(void *arg, ndr_xa_t *mxa)
 682  683  {
 683  684          struct winreg_EnumValue *param = arg;
 684  685          ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
 685  686  
 686  687          if (ndr_hdlookup(mxa, id) == NULL) {
 687  688                  bzero(param, sizeof (struct winreg_EnumValue));
 688  689                  param->status = ERROR_NO_MORE_ITEMS;
 689  690                  return (NDR_DRC_OK);
 690  691          }
 691  692  
 692  693          bzero(param, sizeof (struct winreg_EnumValue));
 693  694          param->status = ERROR_NO_MORE_ITEMS;
 694  695          return (NDR_DRC_OK);
 695  696  }
 696  697  
 697  698  /*
 698  699   * winreg_s_FlushKey
 699  700   *
 700  701   * Flush the attributes associated with the specified open key to disk.
 701  702   */
 702  703  static int
 703  704  winreg_s_FlushKey(void *arg, ndr_xa_t *mxa)
 704  705  {
 705  706          struct winreg_FlushKey *param = arg;
 706  707          ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
 707  708  
 708  709          if (ndr_hdlookup(mxa, id) == NULL)
 709  710                  param->status = ERROR_INVALID_HANDLE;
 710  711          else
 711  712                  param->status = ERROR_SUCCESS;
 712  713  
 713  714          return (NDR_DRC_OK);
 714  715  }
 715  716  
 716  717  /*
 717  718   * winreg_s_GetKeySec
 718  719   */
 719  720  static int
 720  721  winreg_s_GetKeySec(void *arg, ndr_xa_t *mxa)
 721  722  {
 722  723          static struct winreg_secdesc    error_sd;
 723  724          struct winreg_GetKeySec         *param = arg;
 724  725          struct winreg_value             *sd_buf;
 725  726          smb_sd_t                        sd;
 726  727          uint32_t                        sd_len;
 727  728          uint32_t                        status;
 728  729  
 729  730          bzero(&sd, sizeof (smb_sd_t));
 730  731  
 731  732          if ((status = winreg_sd_format(&sd)) != ERROR_SUCCESS)
 732  733                  goto winreg_getkeysec_error;
 733  734  
 734  735          sd_len = smb_sd_len(&sd, SMB_ALL_SECINFO);
 735  736          sd_buf = NDR_MALLOC(mxa, sd_len + sizeof (struct winreg_value));
 736  737  
 737  738          param->sd = NDR_MALLOC(mxa, sizeof (struct winreg_secdesc));
 738  739          if ((param->sd == NULL) || (sd_buf == NULL)) {
 739  740                  status = ERROR_NOT_ENOUGH_MEMORY;
 740  741                  goto winreg_getkeysec_error;
 741  742          }
 742  743  
 743  744          param->sd->sd_len = sd_len;
 744  745          param->sd->sd_size = sd_len;
 745  746          param->sd->sd_buf = sd_buf;
 746  747  
 747  748          sd_buf->vc_first_is = 0;
 748  749          sd_buf->vc_length_is = sd_len;
 749  750          param->status = srvsvc_sd_set_relative(&sd, sd_buf->value);
 750  751  
 751  752          smb_sd_term(&sd);
 752  753          return (NDR_DRC_OK);
 753  754  
 754  755  winreg_getkeysec_error:
 755  756          smb_sd_term(&sd);
 756  757          bzero(param, sizeof (struct winreg_GetKeySec));
 757  758          param->sd = &error_sd;
 758  759          param->status = status;
 759  760          return (NDR_DRC_OK);
 760  761  }
 761  762  
 762  763  static uint32_t
 763  764  winreg_sd_format(smb_sd_t *sd)
 764  765  {
 765  766          smb_fssd_t      fs_sd;
 766  767          acl_t           *acl;
 767  768          uint32_t        status = ERROR_SUCCESS;
 768  769  
 769  770          if (acl_fromtext("owner@:rwxpdDaARWcCos::allow", &acl) != 0)
 770  771                  return (ERROR_NOT_ENOUGH_MEMORY);
 771  772  
 772  773          smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR);
 773  774          fs_sd.sd_uid = 0;
 774  775          fs_sd.sd_gid = 0;
 775  776          fs_sd.sd_zdacl = acl;
 776  777          fs_sd.sd_zsacl = NULL;
 777  778  
 778  779          if (smb_sd_fromfs(&fs_sd, sd) != NT_STATUS_SUCCESS)
 779  780                  status = ERROR_ACCESS_DENIED;
 780  781          smb_fssd_term(&fs_sd);
 781  782          return (status);
 782  783  }
 783  784  
 784  785  /*
 785  786   * winreg_s_NotifyChange
 786  787   */
 787  788  static int
 788  789  winreg_s_NotifyChange(void *arg, ndr_xa_t *mxa)
 789  790  {
 790  791          struct winreg_NotifyChange *param = arg;
 791  792  
 792  793          if (ndr_is_admin(mxa))
 793  794                  param->status = ERROR_SUCCESS;
 794  795          else
 795  796                  param->status = ERROR_ACCESS_DENIED;
 796  797  
 797  798          return (NDR_DRC_OK);
 798  799  }
 799  800  
 800  801  /*
 801  802   * winreg_s_OpenKey
 802  803   *
 803  804   * This is a request to open a windows registry key.
 804  805   * If we recognize the key, we return a handle.
 805  806   *
 806  807   * Returns:
 807  808   *      ERROR_SUCCESS           Valid handle returned.
 808  809   *      ERROR_FILE_NOT_FOUND    No key or unable to allocate a handle.
 809  810   */
 810  811  static int
 811  812  winreg_s_OpenKey(void *arg, ndr_xa_t *mxa)
 812  813  {
 813  814          struct winreg_OpenKey *param = arg;
 814  815          ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
 815  816          ndr_handle_t *hd;
 816  817          char *subkey = (char *)param->name.str;
 817  818          winreg_subkey_t *key;
 818  819  
 819  820          (void) mutex_lock(&winreg_mutex);
 820  821  
 821  822          if (subkey == NULL || *subkey == '\0') {
 822  823                  if ((hd = ndr_hdlookup(mxa, id)) != NULL)
 823  824                          subkey = hd->nh_data;
 824  825          }
 825  826  
 826  827          id = NULL;
 827  828  
 828  829          if (subkey == NULL || list_is_empty(&winreg_keylist.kl_list)) {
 829  830                  (void) mutex_unlock(&winreg_mutex);
 830  831                  bzero(¶m->result_handle, sizeof (winreg_handle_t));
 831  832                  param->status = ERROR_FILE_NOT_FOUND;
 832  833                  return (NDR_DRC_OK);
 833  834          }
 834  835  
 835  836          key = list_head(&winreg_keylist.kl_list);
 836  837          do {
 837  838                  if (strcasecmp(subkey, key->sk_name) == 0) {
 838  839                          if (key->sk_predefined == B_TRUE)
 839  840                                  id = winreg_alloc_id(mxa, subkey);
 840  841                          else
 841  842                                  id = &key->sk_handle;
 842  843  
 843  844                          if (id == NULL)
 844  845                                  break;
 845  846  
 846  847                          bcopy(id, ¶m->result_handle,
 847  848                              sizeof (winreg_handle_t));
 848  849  
 849  850                          (void) mutex_unlock(&winreg_mutex);
 850  851                          param->status = ERROR_SUCCESS;
 851  852                          return (NDR_DRC_OK);
 852  853                  }
 853  854          } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
 854  855  
 855  856          (void) mutex_unlock(&winreg_mutex);
 856  857          bzero(¶m->result_handle, sizeof (winreg_handle_t));
 857  858          param->status = ERROR_FILE_NOT_FOUND;
 858  859          return (NDR_DRC_OK);
 859  860  }
 860  861  
 861  862  /*
 862  863   * winreg_s_QueryKey
 863  864   */
 864  865  /*ARGSUSED*/
 865  866  static int
 866  867  winreg_s_QueryKey(void *arg, ndr_xa_t *mxa)
 867  868  {
 868  869          struct winreg_QueryKey *param = arg;
 869  870          int rc;
 870  871          winreg_string_t *name;
 871  872  
 872  873          name = (winreg_string_t *)¶m->name;
 873  874          bzero(param, sizeof (struct winreg_QueryKey));
 874  875  
 875  876          if ((name = NDR_NEW(mxa, winreg_string_t)) != NULL)
 876  877                  rc = NDR_MSTRING(mxa, "", (ndr_mstring_t *)name);
 877  878  
 878  879          if ((name == NULL) || (rc != 0)) {
 879  880                  bzero(param, sizeof (struct winreg_QueryKey));
 880  881                  param->status = ERROR_NOT_ENOUGH_MEMORY;
 881  882                  return (NDR_DRC_OK);
 882  883          }
 883  884  
 884  885          param->status = ERROR_SUCCESS;
 885  886          return (NDR_DRC_OK);
 886  887  }
 887  888  
 888  889  /*
 889  890   * winreg_s_QueryValue
 890  891   *
 891  892   * This is a request to get the value associated with a specified name.
 892  893   *
 893  894   * Returns:
 894  895   *      ERROR_SUCCESS           Value returned.
 895  896   *      ERROR_FILE_NOT_FOUND    PrimaryModule is not supported.
 896  897   *      ERROR_CANTREAD          No such name or memory problem.
 897  898   */
 898  899  static int
 899  900  winreg_s_QueryValue(void *arg, ndr_xa_t *mxa)
  
    | 
      ↓ open down ↓ | 
    866 lines elided | 
    
      ↑ open up ↑ | 
  
 900  901  {
 901  902          struct winreg_QueryValue *param = arg;
 902  903          struct winreg_value *pv;
 903  904          char *name;
 904  905          char *value;
 905  906          DWORD slen;
 906  907          DWORD msize;
 907  908  
 908  909          name = (char *)param->value_name.str;
 909  910  
 910      -        if (strcasecmp(name, "PrimaryModule") == 0) {
      911 +        if (name == NULL ||
      912 +            strcasecmp(name, "PrimaryModule") == 0) {
 911  913                  param->status = ERROR_FILE_NOT_FOUND;
 912  914                  return (NDR_DRC_OK);
 913  915          }
 914  916  
 915  917          if ((value = winreg_lookup_value(name)) == NULL) {
 916  918                  param->status = ERROR_CANTREAD;
 917  919                  return (NDR_DRC_OK);
 918  920          }
 919  921  
 920  922          slen = smb_wcequiv_strlen(value) + sizeof (smb_wchar_t);
 921  923          msize = sizeof (struct winreg_value) + slen;
 922  924  
 923  925          param->value = (struct winreg_value *)NDR_MALLOC(mxa, msize);
 924  926          param->type = NDR_NEW(mxa, DWORD);
 925  927          param->value_size = NDR_NEW(mxa, DWORD);
 926  928          param->value_size_total = NDR_NEW(mxa, DWORD);
 927  929  
 928  930          if (param->value == NULL || param->type == NULL ||
 929  931              param->value_size == NULL || param->value_size_total == NULL) {
 930  932                  param->status = ERROR_CANTREAD;
 931  933                  return (NDR_DRC_OK);
 932  934          }
 933  935  
 934  936          bzero(param->value, msize);
 935  937          pv = param->value;
 936  938          pv->vc_first_is = 0;
 937  939          pv->vc_length_is = slen;
 938  940          /*LINTED E_BAD_PTR_CAST_ALIGN*/
 939  941          (void) ndr_mbstowcs(NULL, (smb_wchar_t *)pv->value, value, slen);
 940  942  
 941  943          *param->type = 1;
 942  944          *param->value_size = slen;
 943  945          *param->value_size_total = slen;
 944  946  
 945  947          param->status = ERROR_SUCCESS;
 946  948          return (NDR_DRC_OK);
 947  949  }
 948  950  
 949  951  /*
 950  952   * Lookup a name in the registry and return the associated value.
 951  953   * Our registry is a case-insensitive, name-value pair table.
 952  954   *
 953  955   * Windows ProductType: WinNT, ServerNT, LanmanNT.
 954  956   *      Windows NT4.0 workstation: WinNT
 955  957   *      Windows NT4.0 server:      ServerNT
 956  958   *
 957  959   * If LanmanNT is used here, Windows 2000 sends LsarQueryInfoPolicy
 958  960   * with info level 6, which we don't support.  If we use ServerNT
 959  961   * (as reported by NT4.0 Server) Windows 2000 send requests for
 960  962   * levels 3 and 5, which are support.
 961  963   *
 962  964   * On success, returns a pointer to the value.  Otherwise returns
 963  965   * a null pointer.
 964  966   */
 965  967  static char *
 966  968  winreg_lookup_value(const char *name)
 967  969  {
 968  970          static struct registry {
 969  971                  char *name;
 970  972                  char *value;
 971  973          } registry[] = {
 972  974                  { "SystemRoot",         "C:\\" },
 973  975                  { "CurrentVersion",     winreg_sysver },
 974  976                  { "ProductType",        "ServerNT" },
 975  977                  { "Sources",            winreg_sysname }, /* product name */
 976  978                  { "EventMessageFile",   "C:\\windows\\system32\\eventlog.dll" }
 977  979          };
 978  980  
 979  981          int i;
 980  982  
 981  983          for (i = 0; i < sizeof (registry)/sizeof (registry[0]); ++i) {
 982  984                  if (strcasecmp(registry[i].name, name) == 0)
 983  985                          return (registry[i].value);
 984  986          }
 985  987  
 986  988          return (NULL);
 987  989  }
 988  990  
 989  991  /*
 990  992   * winreg_s_SetKeySec
 991  993   */
 992  994  /*ARGSUSED*/
 993  995  static int
 994  996  winreg_s_SetKeySec(void *arg, ndr_xa_t *mxa)
 995  997  {
 996  998          struct winreg_SetKeySec *param = arg;
 997  999  
 998 1000          param->status = ERROR_ACCESS_DENIED;
 999 1001          return (NDR_DRC_OK);
1000 1002  }
1001 1003  
1002 1004  /*
1003 1005   * winreg_s_CreateValue
1004 1006   */
1005 1007  /*ARGSUSED*/
1006 1008  static int
1007 1009  winreg_s_CreateValue(void *arg, ndr_xa_t *mxa)
1008 1010  {
1009 1011          struct winreg_CreateValue *param = arg;
1010 1012  
1011 1013          param->status = ERROR_ACCESS_DENIED;
1012 1014          return (NDR_DRC_OK);
1013 1015  }
1014 1016  
1015 1017  /*
1016 1018   * winreg_s_Shutdown
1017 1019   *
1018 1020   * Attempt to shutdown or reboot the system: access denied.
1019 1021   */
1020 1022  /*ARGSUSED*/
1021 1023  static int
1022 1024  winreg_s_Shutdown(void *arg, ndr_xa_t *mxa)
1023 1025  {
1024 1026          struct winreg_Shutdown *param = arg;
1025 1027  
1026 1028          param->status = ERROR_ACCESS_DENIED;
1027 1029          return (NDR_DRC_OK);
1028 1030  }
1029 1031  
1030 1032  /*
1031 1033   * winreg_s_AbortShutdown
1032 1034   *
1033 1035   * Abort a shutdown request.
1034 1036   */
1035 1037  static int
1036 1038  winreg_s_AbortShutdown(void *arg, ndr_xa_t *mxa)
1037 1039  {
1038 1040          struct winreg_AbortShutdown *param = arg;
1039 1041  
1040 1042          if (ndr_is_admin(mxa))
1041 1043                  param->status = ERROR_SUCCESS;
1042 1044          else
1043 1045                  param->status = ERROR_ACCESS_DENIED;
1044 1046  
1045 1047          return (NDR_DRC_OK);
1046 1048  }
1047 1049  
1048 1050  /*
1049 1051   * winreg_s_GetVersion
1050 1052   *
1051 1053   * Return the windows registry version.  The current version is 5.
1052 1054   * This call is usually made prior to enumerating or querying registry
1053 1055   * keys or values.
1054 1056   */
1055 1057  /*ARGSUSED*/
1056 1058  static int
1057 1059  winreg_s_GetVersion(void *arg, ndr_xa_t *mxa)
1058 1060  {
1059 1061          struct winreg_GetVersion *param = arg;
1060 1062  
1061 1063          param->version = 5;
1062 1064          param->status = ERROR_SUCCESS;
1063 1065          return (NDR_DRC_OK);
1064 1066  }
  
    | 
      ↓ open down ↓ | 
    144 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX