Print this page
    
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-2667 Wrong error when join domain with wrong password
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
re #12435 rb3958 r10 is added 2 times to panic info
re #12393 rb3935 Kerberos and smbd disagree about who is our AD server
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
          +++ new/usr/src/lib/smbsrv/libmlsvc/common/samlib.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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
       24 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  25   25   */
  26   26  
  27   27  /*
  28   28   * This module provides the high level interface to the SAM RPC
  29   29   * functions.
  30   30   */
  31   31  
  32   32  #include <sys/types.h>
  33   33  #include <sys/isa_defs.h>
  34   34  #include <sys/byteorder.h>
  35   35  
  36   36  #include <alloca.h>
  37   37  
  38   38  #include <smbsrv/libsmb.h>
  39   39  #include <smbsrv/libmlsvc.h>
  40      -#include <smbsrv/ntaccess.h>
       40 +#include <smb/ntaccess.h>
  41   41  #include <lsalib.h>
  42   42  #include <samlib.h>
  43   43  
  44   44  #ifdef _LITTLE_ENDIAN
  45   45  /* little-endian values on little-endian */
  46   46  #define htolel(x)       ((uint32_t)(x))
  47   47  #define letohl(x)       ((uint32_t)(x))
  48   48  #else   /* (BYTE_ORDER == LITTLE_ENDIAN) */
  49   49  /* little-endian values on big-endian (swap) */
  50   50  #define letohl(x)       BSWAP_32(x)
  51   51  #define htolel(x)       BSWAP_32(x)
  52   52  #endif  /* (BYTE_ORDER == LITTLE_ENDIAN) */
  53   53  
  54   54  /*
  55   55   * Valid values for the OEM OWF password encryption.
  56   56   */
  57   57  #define SAM_KEYLEN              16
  58   58  
  59   59  static void samr_fill_userpw(struct samr_user_password *, const char *);
  60   60  static void samr_make_encrypted_password(
  61   61          struct samr_encr_passwd *epw,
  62   62          char *new_pw_clear,
  63   63          uint8_t *crypt_key);
  64   64  
  65   65  
  66   66  /*
  67   67   * Todo: Implement "unjoin" domain, which would use the
  68   68   * sam_remove_trust_account code below.
  69   69   */
  70   70  
  71   71  /*
  72   72   * sam_remove_trust_account
  73   73   *
  74   74   * Attempt to remove the workstation trust account for this system.
  75   75   * Administrator access is required to perform this operation.
  76   76   *
  77   77   * Returns NT status codes.
  78   78   */
  79   79  DWORD
  80   80  sam_remove_trust_account(char *server, char *domain)
  81   81  {
  82   82          char account_name[SMB_SAMACCT_MAXLEN];
  83   83  
  84   84          if (smb_getsamaccount(account_name, SMB_SAMACCT_MAXLEN) != 0)
  85   85                  return (NT_STATUS_INTERNAL_ERROR);
  86   86  
  87   87          return (sam_delete_account(server, domain, account_name));
  88   88  }
  89   89  
  90   90  
  91   91  /*
  92   92   * sam_delete_account
  93   93   *
  94   94   * Attempt to remove an account from the SAM database on the specified
  95   95   * server.
  96   96   *
  97   97   * Returns NT status codes.
  98   98   */
  99   99  DWORD
 100  100  sam_delete_account(char *server, char *domain_name, char *account_name)
 101  101  {
 102  102          mlsvc_handle_t samr_handle;
 103  103          mlsvc_handle_t domain_handle;
 104  104          mlsvc_handle_t user_handle;
 105  105          smb_account_t ainfo;
 106  106          smb_sid_t *sid;
 107  107          DWORD access_mask;
 108  108          DWORD status;
 109  109          int rc;
 110  110          char user[SMB_USERNAME_MAXLEN];
 111  111  
 112  112          smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 113  113  
 114  114          rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
 115  115              &samr_handle);
 116  116          if (rc != 0)
 117  117                  return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 118  118  
 119  119          sid = samr_lookup_domain(&samr_handle, domain_name);
 120  120          if (sid == NULL) {
 121  121                  status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 122  122                  goto out_samr_hdl;
 123  123          }
 124  124  
 125  125          status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
 126  126              (struct samr_sid *)sid, &domain_handle);
 127  127          if (status != NT_STATUS_SUCCESS)
 128  128                  goto out_sid_ptr;
 129  129  
 130  130          status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo);
 131  131          if (status != NT_STATUS_SUCCESS)
 132  132                  goto out_dom_hdl;
 133  133  
 134  134          access_mask = STANDARD_RIGHTS_EXECUTE | DELETE;
 135  135          status = samr_open_user(&domain_handle, access_mask,
 136  136              ainfo.a_rid, &user_handle);
 137  137          if (status != NT_STATUS_SUCCESS)
 138  138                  goto out_dom_hdl;
 139  139  
 140  140          status = samr_delete_user(&user_handle);
 141  141  
 142  142          (void) samr_close_handle(&user_handle);
 143  143  out_dom_hdl:
 144  144          (void) samr_close_handle(&domain_handle);
 145  145  out_sid_ptr:
 146  146          free(sid);
 147  147  out_samr_hdl:
 148  148          (void) samr_close_handle(&samr_handle);
 149  149  
 150  150          return (status);
 151  151  }
 152  152  
 153  153  
 154  154  /*
 155  155   * sam_lookup_name
 156  156   *
 157  157   * Lookup an account name in the SAM database on the specified domain
 158  158   * controller. Provides the account RID on success.
 159  159   *
 160  160   * Returns NT status codes.
 161  161   */
 162  162  DWORD
 163  163  sam_lookup_name(char *server, char *domain_name, char *account_name,
 164  164      DWORD *rid_ret)
 165  165  {
 166  166          mlsvc_handle_t samr_handle;
 167  167          mlsvc_handle_t domain_handle;
 168  168          smb_account_t ainfo;
 169  169          struct samr_sid *domain_sid;
 170  170          int rc;
 171  171          DWORD status;
 172  172          char user[SMB_USERNAME_MAXLEN];
 173  173  
 174  174          smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 175  175  
 176  176          *rid_ret = 0;
 177  177  
 178  178          rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
 179  179              &samr_handle);
 180  180  
 181  181          if (rc != 0)
 182  182                  return (NT_STATUS_OPEN_FAILED);
 183  183  
 184  184          domain_sid = (struct samr_sid *)samr_lookup_domain(&samr_handle,
 185  185              domain_name);
 186  186          if (domain_sid == NULL) {
 187  187                  (void) samr_close_handle(&samr_handle);
 188  188                  return (NT_STATUS_NO_SUCH_DOMAIN);
 189  189          }
 190  190  
 191  191          status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
 192  192              domain_sid, &domain_handle);
 193  193          if (status == NT_STATUS_SUCCESS) {
 194  194                  status = samr_lookup_domain_names(&domain_handle,
 195  195                      account_name, &ainfo);
 196  196                  if (status == NT_STATUS_SUCCESS)
 197  197                          *rid_ret = ainfo.a_rid;
 198  198  
 199  199                  (void) samr_close_handle(&domain_handle);
 200  200          }
 201  201  
 202  202          (void) samr_close_handle(&samr_handle);
 203  203          return (status);
 204  204  }
 205  205  
 206  206  /*
 207  207   * sam_get_local_domains
 208  208   *
 209  209   * Query a remote server to get the list of local domains that it
 210  210   * supports.
 211  211   *
 212  212   * Returns NT status codes.
 213  213   */
 214  214  DWORD
 215  215  sam_get_local_domains(char *server, char *domain_name)
 216  216  {
 217  217          mlsvc_handle_t samr_handle;
 218  218          DWORD status;
 219  219          int rc;
 220  220          char user[SMB_USERNAME_MAXLEN];
 221  221  
 222  222          smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 223  223  
 224  224          rc = samr_open(server, domain_name, user, SAM_ENUM_LOCAL_DOMAIN,
 225  225              &samr_handle);
 226  226          if (rc != 0)
 227  227                  return (NT_STATUS_OPEN_FAILED);
 228  228  
 229  229          status = samr_enum_local_domains(&samr_handle);
 230  230          (void) samr_close_handle(&samr_handle);
 231  231          return (status);
 232  232  }
 233  233  
 234  234  /*
 235  235   * Set the account control flags on some account for which we
 236  236   * have already opened a SAM handle with appropriate rights,
 237  237   * passed in here as sam_handle, along with the new flags.
 238  238   */
 239  239  DWORD
 240  240  netr_set_user_control(
 241  241          mlsvc_handle_t *user_handle,
 242  242          DWORD UserAccountControl)
 243  243  {
 244  244          struct samr_SetUserInfo16 info;
 245  245  
 246  246          info.UserAccountControl = UserAccountControl;
 247  247          return (samr_set_user_info(user_handle, 16, &info));
 248  248  }
 249  249  
 250  250  /*
 251  251   * Set the password on some account, for which we have already
 252  252   * opened a SAM handle with appropriate rights, passed in here
 253  253   * as sam_handle, along with the new password as cleartext.
 254  254   *
 255  255   * This builds a struct SAMPR_USER_INTERNAL5_INFORMATION [MS-SAMR]
 256  256   * containing the new password, encrypted with our session key.
 257  257   */
 258  258  DWORD
 259  259  netr_set_user_password(
 260  260          mlsvc_handle_t *user_handle,
 261  261          char *new_pw_clear)
 262  262  {
 263  263          unsigned char ssn_key[SMBAUTH_HASH_SZ];
 264  264          struct samr_SetUserInfo24 info;
 265  265  
 266  266          if (ndr_rpc_get_ssnkey(user_handle, ssn_key, SMBAUTH_HASH_SZ))
 267  267                  return (NT_STATUS_INTERNAL_ERROR);
 268  268  
 269  269          (void) memset(&info, 0, sizeof (info));
 270  270          samr_make_encrypted_password(&info.encr_pw, new_pw_clear, ssn_key);
 271  271  
 272  272          /* Rather not leave the session key around. */
 273  273          (void) memset(ssn_key, 0, sizeof (ssn_key));
 274  274  
 275  275          return (samr_set_user_info(user_handle, 24, &info));
 276  276  }
 277  277  
 278  278  /*
 279  279   * Change a password like NetUserChangePassword(),
 280  280   * but where we already know which AD server to use,
 281  281   * so we don't request the domain name or search for
 282  282   * an AD server for that domain here.
 283  283   */
 284  284  DWORD
 285  285  netr_change_password(
 286  286          char *server,
 287  287          char *account,
 288  288          char *old_pw_clear,
 289  289          char *new_pw_clear)
 290  290  {
 291  291          struct samr_encr_passwd epw;
 292  292          struct samr_encr_hash old_hash;
 293  293          uint8_t old_nt_hash[SAMR_PWHASH_LEN];
 294  294          uint8_t new_nt_hash[SAMR_PWHASH_LEN];
 295  295          mlsvc_handle_t handle;
 296  296          DWORD status;
 297  297  
 298  298          /*
 299  299           * Create an RPC handle to this server, bound to SAMR.
 300  300           */
 301  301          status = ndr_rpc_bind(&handle, server, "", "", "SAMR");
 302  302          if (status != NT_STATUS_SUCCESS)
 303  303                  return (status);
 304  304  
 305  305          /*
 306  306           * Encrypt the new p/w (plus random filler) with the
 307  307           * old password, and send the old p/w encrypted with
 308  308           * the new p/w hash to prove we know the old p/w.
 309  309           * Details:  [MS-SAMR 3.1.5.10.3]
 310  310           */
 311  311          (void) smb_auth_ntlm_hash(old_pw_clear, old_nt_hash);
 312  312          (void) smb_auth_ntlm_hash(new_pw_clear, new_nt_hash);
 313  313          samr_make_encrypted_password(&epw, new_pw_clear, old_nt_hash);
 314  314  
 315  315          (void) smb_auth_DES(old_hash.data, SAMR_PWHASH_LEN,
 316  316              new_nt_hash, 14, /* key */
 317  317              old_nt_hash, SAMR_PWHASH_LEN);
 318  318  
 319  319          /*
 320  320           * Finally, ready to try the OtW call.
 321  321           */
 322  322          status = samr_change_password(
 323  323              &handle, server, account,
 324  324              &epw, &old_hash);
 325  325  
 326  326          /* Avoid leaving cleartext (or equivalent) around. */
 327  327          (void) memset(old_nt_hash, 0, sizeof (old_nt_hash));
 328  328          (void) memset(new_nt_hash, 0, sizeof (new_nt_hash));
 329  329  
 330  330          ndr_rpc_unbind(&handle);
 331  331          return (status);
 332  332  }
 333  333  
 334  334  /*
 335  335   * Build an encrypted password, as used by samr_set_user_info
 336  336   * and samr_change_password.  Note: This builds the unencrypted
 337  337   * form in one union arm, and encrypts it in the other union arm.
 338  338   */
 339  339  void
 340  340  samr_make_encrypted_password(
 341  341          struct samr_encr_passwd *epw,
 342  342          char *new_pw_clear,
 343  343          uint8_t *crypt_key)
 344  344  {
 345  345          union {
 346  346                  struct samr_user_password u;
 347  347                  struct samr_encr_passwd e;
 348  348          } pwu;
 349  349  
 350  350          samr_fill_userpw(&pwu.u, new_pw_clear);
 351  351  
 352  352          (void) smb_auth_RC4(pwu.e.data, sizeof (pwu.e.data),
 353  353              crypt_key, SAMR_PWHASH_LEN,
 354  354              pwu.e.data, sizeof (pwu.e.data));
 355  355  
 356  356          (void) memcpy(epw->data, pwu.e.data, sizeof (pwu.e.data));
 357  357          (void) memset(pwu.e.data, 0, sizeof (pwu.e.data));
 358  358  }
 359  359  
 360  360  /*
 361  361   * This fills in a samr_user_password (a.k.a. SAMPR_USER_PASSWORD
 362  362   * in the MS Net API) which has the new password "right justified"
 363  363   * in the buffer, and any space on the left filled with random junk
 364  364   * to improve the quality of the encryption that is subsequently
 365  365   * applied to this buffer before it goes over the wire.
 366  366   */
 367  367  static void
 368  368  samr_fill_userpw(struct samr_user_password *upw, const char *new_pw)
 369  369  {
 370  370          smb_wchar_t *pbuf;
 371  371          uint32_t pwlen_bytes;
 372  372          size_t pwlen_wchars;
 373  373  
 374  374          /*
 375  375           * First fill the whole buffer with the random junk.
 376  376           * (Slightly less random when debugging:)
 377  377           */
 378  378  #ifdef DEBUG
 379  379          (void) memset(upw->Buffer, '*', sizeof (upw->Buffer));
 380  380  #else
 381  381          randomize((char *)upw->Buffer, sizeof (upw->Buffer));
 382  382  #endif
 383  383  
 384  384          /*
 385  385           * Now overwrite the last pwlen characters of
 386  386           * that buffer with the password, and set the
 387  387           * length field so the receiving end knows where
 388  388           * the junk ends and the real password starts.
 389  389           */
 390  390          pwlen_wchars = smb_wcequiv_strlen(new_pw) / 2;
 391  391          if (pwlen_wchars > SAMR_USER_PWLEN)
 392  392                  pwlen_wchars = SAMR_USER_PWLEN;
 393  393          pwlen_bytes = pwlen_wchars * 2;
 394  394  
 395  395          pbuf = &upw->Buffer[SAMR_USER_PWLEN - pwlen_wchars];
 396  396          (void) smb_mbstowcs(pbuf, new_pw, pwlen_wchars);
 397  397  
 398  398          /* Yes, this is in Bytes, not wchars. */
 399  399          upw->Length = htolel(pwlen_bytes);
 400  400  }
  
    | 
      ↓ open down ↓ | 
    350 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX