Print this page
    
NEX-18708 Domain logons may get STATUS_ACCESS_DENIED
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
1575 untangle libmlrpc from SMB server
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9106 SMB should support "Resource SID Compression"
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-4272 Allow authenticating computer accounts
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3080 SMB1 signing problem with Kerberos auth.
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-2225 Unable to join NexentaStor to 2008 AD
NEX-1810 extended security Kerberos (inbound)
re #7126 rb4153 smbd panic with missing negotiate challenge
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c
          +++ new/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.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   * NETR SamLogon and SamLogoff RPC client functions.
  29   29   */
  30   30  
  31   31  #include <stdio.h>
  32   32  #include <strings.h>
  33   33  #include <stdlib.h>
  34   34  #include <time.h>
  35   35  #include <alloca.h>
  36   36  #include <unistd.h>
  37   37  #include <netdb.h>
  38   38  #include <thread.h>
  39   39  
       40 +#include <libmlrpc/libmlrpc.h>
  40   41  #include <smbsrv/libsmb.h>
  41      -#include <smbsrv/libmlrpc.h>
  42   42  #include <smbsrv/libmlsvc.h>
  43   43  #include <smbsrv/ndl/netlogon.ndl>
  44   44  #include <smbsrv/netrauth.h>
  45   45  #include <smbsrv/smbinfo.h>
  46   46  #include <smbsrv/smb_token.h>
  47   47  #include <mlsvc.h>
  48   48  
  49      -#define NETLOGON_ATTEMPTS       2
  50      -
  51      -static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *);
       49 +static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *, smb_domainex_t *);
  52   50  static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
  53   51      smb_logon_t *, smb_token_t *);
  54   52  static void netr_invalidate_chain(void);
  55   53  static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *,
  56   54      struct netr_logon_info1 *);
  57   55  static void netr_network_samlogon(ndr_heap_t *, netr_info_t *,
  58   56      smb_logon_t *, struct netr_logon_info2 *);
  59   57  static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
  60   58      netr_logon_id_t *);
  61   59  static boolean_t netr_isadmin(struct netr_validation_info3 *);
  62   60  static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
  63   61      smb_ids_t *);
  64      -static uint32_t netr_setup_token_info3(struct netr_validation_info3 *,
  65      -    smb_token_t *);
       62 +static uint32_t netr_setup_krb5res_groups(struct krb5_validation_info *,
       63 +    smb_ids_t *);
  66   64  static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
  67   65      smb_token_t *);
  68   66  
  69   67  /*
  70   68   * Shared with netr_auth.c
  71   69   */
  72   70  extern netr_info_t netr_global_info;
  73   71  
  74   72  static mutex_t netlogon_mutex;
  75   73  static cond_t netlogon_cv;
  76   74  static boolean_t netlogon_busy = B_FALSE;
  
    | 
      ↓ open down ↓ | 
    1 lines elided | 
    
      ↑ open up ↑ | 
  
  77   75  static boolean_t netlogon_abort = B_FALSE;
  78   76  
  79   77  /*
  80   78   * Helper for Kerberos authentication
  81   79   */
  82   80  uint32_t
  83   81  smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len)
  84   82  {
  85   83          struct krb5_validation_info info;
  86   84          ndr_buf_t *nbuf;
       85 +        smb_sid_t *domsid;
  87   86          uint32_t status = NT_STATUS_NO_MEMORY;
  88   87          int rc;
  89   88  
  90   89          bzero(&info, sizeof (info));
  91   90  
  92   91          /* Need to keep this until we're done with &info */
  93   92          nbuf = ndr_buf_init(&TYPEINFO(netr_interface));
  94   93          if (nbuf == NULL)
  95   94                  goto out;
  96   95  
  97   96          rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC,
  98   97              NETR_OPNUM_decode_krb5_pac, data, len, &info);
  99   98          if (rc != NDR_DRC_OK) {
 100   99                  status = RPC_NT_PROTOCOL_ERROR;
 101  100                  goto out;
 102  101          }
 103  102  
 104      -        status = netr_setup_token_info3(&info.info3, token);
      103 +        /*
      104 +         * Copy the decoded info into the token,
      105 +         * similar to netr_setup_token()
      106 +         */
      107 +        domsid = (smb_sid_t *)info.info3.LogonDomainId;
 105  108  
 106      -        /* Deal with the "resource groups"? */
 107      -
 108      -
 109      -out:
 110      -        if (nbuf != NULL)
 111      -                ndr_buf_fini(nbuf);
 112      -
 113      -        return (status);
 114      -}
 115      -
 116      -/*
 117      - * Code factored out of netr_setup_token()
 118      - */
 119      -static uint32_t
 120      -netr_setup_token_info3(struct netr_validation_info3 *info3,
 121      -    smb_token_t *token)
 122      -{
 123      -        smb_sid_t *domsid;
 124      -
 125      -        domsid = (smb_sid_t *)info3->LogonDomainId;
 126      -
 127  109          token->tkn_user.i_sid = smb_sid_splice(domsid,
 128      -            info3->UserId);
      110 +            info.info3.UserId);
 129  111          if (token->tkn_user.i_sid == NULL)
 130      -                goto errout;
      112 +                goto out;
 131  113  
 132  114          token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
 133      -            info3->PrimaryGroupId);
      115 +            info.info3.PrimaryGroupId);
 134  116          if (token->tkn_primary_grp.i_sid == NULL)
 135      -                goto errout;
      117 +                goto out;
 136  118  
 137      -        if (info3->EffectiveName.str) {
      119 +        if (info.info3.EffectiveName.str) {
 138  120                  token->tkn_account_name =
 139      -                    strdup((char *)info3->EffectiveName.str);
      121 +                    strdup((char *)info.info3.EffectiveName.str);
 140  122                  if (token->tkn_account_name == NULL)
 141      -                        goto errout;
      123 +                        goto out;
 142  124          }
 143  125  
 144      -        if (info3->LogonDomainName.str) {
      126 +        if (info.info3.LogonDomainName.str) {
 145  127                  token->tkn_domain_name =
 146      -                    strdup((char *)info3->LogonDomainName.str);
      128 +                    strdup((char *)info.info3.LogonDomainName.str);
 147  129                  if (token->tkn_domain_name == NULL)
 148      -                        goto errout;
      130 +                        goto out;
 149  131          }
 150  132  
 151      -        return (netr_setup_token_wingrps(info3, token));
 152      -errout:
 153      -        return (NT_STATUS_INSUFF_SERVER_RESOURCES);
      133 +        status = netr_setup_domain_groups(&info.info3, &token->tkn_win_grps);
      134 +        if (status != NT_STATUS_SUCCESS)
      135 +                goto out;
      136 +
      137 +        if (info.rg_rid_cnt != 0) {
      138 +                status = netr_setup_krb5res_groups(&info, &token->tkn_win_grps);
      139 +                if (status != NT_STATUS_SUCCESS)
      140 +                        goto out;
      141 +        }
      142 +
      143 +        status = netr_setup_token_wingrps(&info.info3, token);
      144 +
      145 +out:
      146 +        if (nbuf != NULL)
      147 +                ndr_buf_fini(nbuf);
      148 +
      149 +        return (status);
 154  150  }
 155  151  
 156  152  /*
 157  153   * Abort impending domain logon requests.
 158  154   */
 159  155  void
 160  156  smb_logon_abort(void)
 161  157  {
 162  158          (void) mutex_lock(&netlogon_mutex);
 163  159          if (netlogon_busy && !netlogon_abort)
 164  160                  syslog(LOG_DEBUG, "logon abort");
 165  161          netlogon_abort = B_TRUE;
 166  162          (void) cond_broadcast(&netlogon_cv);
 167  163          (void) mutex_unlock(&netlogon_mutex);
 168  164  }
  
    | 
      ↓ open down ↓ | 
    5 lines elided | 
    
      ↑ open up ↑ | 
  
 169  165  
 170  166  /*
 171  167   * This is the entry point for authenticating domain users.
 172  168   *
 173  169   * If we are not going to attempt to authenticate the user,
 174  170   * this function must return without updating the status.
 175  171   *
 176  172   * If the user is successfully authenticated, we build an
 177  173   * access token and the status will be NT_STATUS_SUCCESS.
 178  174   * Otherwise, the token contents are invalid.
      175 + *
      176 + * This will retry a few times for errors indicating that the
      177 + * current DC might have gone off-line or become too busy etc.
      178 + * With such errors, smb_ddiscover_bad_dc is called and then
      179 + * the smb_domain_getinfo call here waits for new DC info.
 179  180   */
      181 +int smb_netr_logon_retries = 3;
 180  182  void
 181  183  smb_logon_domain(smb_logon_t *user_info, smb_token_t *token)
 182  184  {
      185 +        smb_domainex_t  di;
 183  186          uint32_t        status;
 184      -        int             i;
      187 +        int             retries = smb_netr_logon_retries;
 185  188  
 186  189          if (user_info->lg_secmode != SMB_SECMODE_DOMAIN)
 187  190                  return;
 188  191  
 189  192          if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL)
 190  193                  return;
 191  194  
 192      -        for (i = 0; i < NETLOGON_ATTEMPTS; ++i) {
      195 +        while (--retries > 0) {
      196 +
      197 +                if (!smb_domain_getinfo(&di)) {
      198 +                        syslog(LOG_ERR, "logon DC getinfo failed");
      199 +                        status = NT_STATUS_NO_LOGON_SERVERS;
      200 +                        goto out;
      201 +                }
      202 +
 193  203                  (void) mutex_lock(&netlogon_mutex);
 194  204                  while (netlogon_busy && !netlogon_abort)
 195  205                          (void) cond_wait(&netlogon_cv, &netlogon_mutex);
 196  206  
 197  207                  if (netlogon_abort) {
 198  208                          (void) mutex_unlock(&netlogon_mutex);
 199      -                        user_info->lg_status = NT_STATUS_REQUEST_ABORTED;
 200      -                        return;
      209 +                        status = NT_STATUS_REQUEST_ABORTED;
      210 +                        goto out;
 201  211                  }
 202  212  
 203  213                  netlogon_busy = B_TRUE;
 204  214                  (void) mutex_unlock(&netlogon_mutex);
 205  215  
 206      -                status = netlogon_logon(user_info, token);
      216 +                status = netlogon_logon(user_info, token, &di);
 207  217  
 208  218                  (void) mutex_lock(&netlogon_mutex);
 209  219                  netlogon_busy = B_FALSE;
 210  220                  if (netlogon_abort)
 211  221                          status = NT_STATUS_REQUEST_ABORTED;
 212  222                  (void) cond_signal(&netlogon_cv);
 213  223                  (void) mutex_unlock(&netlogon_mutex);
 214  224  
 215      -                if (status != NT_STATUS_CANT_ACCESS_DOMAIN_INFO)
      225 +                switch (status) {
      226 +                case NT_STATUS_BAD_NETWORK_PATH:
      227 +                case NT_STATUS_BAD_NETWORK_NAME:
      228 +                case RPC_NT_SERVER_TOO_BUSY:
      229 +                        /*
      230 +                         * May retry with a new DC, or if we're
      231 +                         * out of retries, will return...
      232 +                         */
      233 +                        status = NT_STATUS_NO_LOGON_SERVERS;
 216  234                          break;
      235 +                default:
      236 +                        goto out;
      237 +                }
 217  238          }
 218  239  
      240 +out:
 219  241          if (status != NT_STATUS_SUCCESS)
 220  242                  syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain,
 221  243                      user_info->lg_e_username, xlate_nt_status(status));
 222      -
 223  244          user_info->lg_status = status;
 224  245  }
 225  246  
      247 +/*
      248 + * Run a netr_server_samlogon call, dealing with the possible need to
      249 + * re-establish the NetLogon credential chain.  If that fails, return
      250 + * NT_STATUS_DOMAIN_TRUST_INCONSISTENT indicating the machine account
      251 + * needs it's password reset (or whatever).  Other errors are from the
      252 + * netr_server_samlogon() call including the many possibilities listed
      253 + * above that function.
      254 + */
 226  255  static uint32_t
 227      -netlogon_logon(smb_logon_t *user_info, smb_token_t *token)
      256 +netlogon_logon(smb_logon_t *user_info, smb_token_t *token, smb_domainex_t *di)
 228  257  {
 229      -        char resource_domain[SMB_PI_MAX_DOMAIN];
 230  258          char server[MAXHOSTNAMELEN];
 231  259          mlsvc_handle_t netr_handle;
 232      -        smb_domainex_t di;
 233  260          uint32_t status;
 234      -        int retries = 0;
      261 +        boolean_t did_reauth = B_FALSE;
 235  262  
 236      -        (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
      263 +        /*
      264 +         * This netr_open call does the work to connect to the DC,
      265 +         * get the IPC share, open the named pipe, RPC bind, etc.
      266 +         */
      267 +        status = netr_open(di->d_dci.dc_name, di->d_primary.di_nbname,
      268 +            &netr_handle);
      269 +        if (status != 0) {
      270 +                syslog(LOG_ERR, "netlogon remote open failed (%s)",
      271 +                    xlate_nt_status(status));
      272 +                return (status);
      273 +        }
 237  274  
 238      -        /* Avoid interfering with DC discovery. */
 239      -        if (smb_ddiscover_wait() != 0 ||
 240      -            !smb_domain_getinfo(&di)) {
 241      -                netr_invalidate_chain();
 242      -                return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
      275 +        if (di->d_dci.dc_name[0] != '\0' &&
      276 +            (*netr_global_info.server != '\0')) {
      277 +                (void) snprintf(server, sizeof (server),
      278 +                    "\\\\%s", di->d_dci.dc_name);
      279 +                if (strncasecmp(netr_global_info.server,
      280 +                    server, strlen(server)) != 0)
      281 +                        netr_invalidate_chain();
 243  282          }
 244  283  
 245      -        do {
 246      -                if (netr_open(di.d_dci.dc_name, di.d_primary.di_nbname,
 247      -                    &netr_handle) != 0)
 248      -                        return (NT_STATUS_OPEN_FAILED);
      284 +reauth:
      285 +        if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
      286 +            !smb_match_netlogon_seqnum()) {
      287 +                /*
      288 +                 * This does netr_server_req_challenge() and
      289 +                 * netr_server_authenticate2(), updating the
      290 +                 * current netlogon sequence number.
      291 +                 */
      292 +                status = netlogon_auth(di->d_dci.dc_name, &netr_handle,
      293 +                    NETR_FLG_NULL);
 249  294  
 250      -                if (di.d_dci.dc_name[0] != '\0' &&
 251      -                    (*netr_global_info.server != '\0')) {
 252      -                        (void) snprintf(server, sizeof (server),
 253      -                            "\\\\%s", di.d_dci.dc_name);
 254      -                        if (strncasecmp(netr_global_info.server,
 255      -                            server, strlen(server)) != 0)
 256      -                                netr_invalidate_chain();
      295 +                if (status != 0) {
      296 +                        syslog(LOG_ERR, "netlogon remote auth failed (%s)",
      297 +                            xlate_nt_status(status));
      298 +                        (void) netr_close(&netr_handle);
      299 +                        return (NT_STATUS_DOMAIN_TRUST_INCONSISTENT);
 257  300                  }
 258  301  
 259      -                if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
 260      -                    !smb_match_netlogon_seqnum()) {
 261      -                        status = netlogon_auth(di.d_dci.dc_name, &netr_handle,
 262      -                            NETR_FLG_NULL);
      302 +                netr_global_info.flags |= NETR_FLG_VALID;
      303 +        }
 263  304  
 264      -                        if (status != 0) {
 265      -                                (void) netr_close(&netr_handle);
 266      -                                return (NT_STATUS_LOGON_FAILURE);
 267      -                        }
      305 +        status = netr_server_samlogon(&netr_handle,
      306 +            &netr_global_info, di->d_dci.dc_name, user_info, token);
 268  307  
 269      -                        netr_global_info.flags |= NETR_FLG_VALID;
      308 +        if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
      309 +                if (!did_reauth) {
      310 +                        /* Call netlogon_auth() again, just once. */
      311 +                        did_reauth = B_TRUE;
      312 +                        goto reauth;
 270  313                  }
      314 +                status = NT_STATUS_DOMAIN_TRUST_INCONSISTENT;
      315 +        }
 271  316  
 272      -                status = netr_server_samlogon(&netr_handle,
 273      -                    &netr_global_info, di.d_dci.dc_name, user_info, token);
      317 +        (void) netr_close(&netr_handle);
 274  318  
 275      -                (void) netr_close(&netr_handle);
 276      -        } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3);
      319 +        return (status);
      320 +}
 277  321  
 278      -        if (retries >= 3)
 279      -                status = NT_STATUS_LOGON_FAILURE;
      322 +/*
      323 + * Helper for mlsvc_netlogon
      324 + *
      325 + * Call netlogon_auth with appropriate locks etc.
      326 + * Serialize like smb_logon_domain does for
      327 + * netlogon_logon / netlogon_auth
      328 + */
      329 +uint32_t
      330 +smb_netlogon_check(char *server, char *domain)
      331 +{
      332 +        mlsvc_handle_t netr_handle;
      333 +        uint32_t        status;
 280  334  
      335 +        (void) mutex_lock(&netlogon_mutex);
      336 +        while (netlogon_busy)
      337 +                (void) cond_wait(&netlogon_cv, &netlogon_mutex);
      338 +
      339 +        netlogon_busy = B_TRUE;
      340 +        (void) mutex_unlock(&netlogon_mutex);
      341 +
      342 +        /*
      343 +         * This section like netlogon_logon(), but only does
      344 +         * one pass and no netr_server_samlogon call.
      345 +         */
      346 +
      347 +        status = netr_open(server, domain,
      348 +            &netr_handle);
      349 +        if (status != 0) {
      350 +                syslog(LOG_ERR, "netlogon remote open failed (%s)",
      351 +                    xlate_nt_status(status));
      352 +                goto unlock_out;
      353 +        }
      354 +
      355 +        if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
      356 +            !smb_match_netlogon_seqnum()) {
      357 +                /*
      358 +                 * This does netr_server_req_challenge() and
      359 +                 * netr_server_authenticate2(), updating the
      360 +                 * current netlogon sequence number.
      361 +                 */
      362 +                status = netlogon_auth(server, &netr_handle,
      363 +                    NETR_FLG_NULL);
      364 +                if (status != 0) {
      365 +                        syslog(LOG_ERR, "netlogon remote auth failed (%s)",
      366 +                            xlate_nt_status(status));
      367 +                } else {
      368 +                        netr_global_info.flags |= NETR_FLG_VALID;
      369 +                }
      370 +        }
      371 +
      372 +        (void) netr_close(&netr_handle);
      373 +
      374 +unlock_out:
      375 +        (void) mutex_lock(&netlogon_mutex);
      376 +        netlogon_busy = B_FALSE;
      377 +        (void) cond_signal(&netlogon_cv);
      378 +        (void) mutex_unlock(&netlogon_mutex);
      379 +
 281  380          return (status);
 282  381  }
 283  382  
 284  383  static uint32_t
 285  384  netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
 286  385      netr_info_t *netr_info, smb_token_t *token)
 287  386  {
 288  387          char *username, *domain;
 289  388          unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
 290  389          smb_sid_t *domsid;
 291  390          uint32_t status;
 292  391          char nbdomain[NETBIOS_NAME_SZ];
 293  392  
 294  393          domsid = (smb_sid_t *)info3->LogonDomainId;
 295  394  
 296  395          token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
 297  396          if (token->tkn_user.i_sid == NULL)
 298  397                  return (NT_STATUS_NO_MEMORY);
 299  398  
 300  399          token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
 301  400              info3->PrimaryGroupId);
 302  401          if (token->tkn_primary_grp.i_sid == NULL)
 303  402                  return (NT_STATUS_NO_MEMORY);
 304  403  
 305  404          username = (info3->EffectiveName.str)
 306  405              ? (char *)info3->EffectiveName.str : user_info->lg_e_username;
 307  406  
 308  407          if (info3->LogonDomainName.str) {
 309  408                  domain = (char *)info3->LogonDomainName.str;
 310  409          } else if (*user_info->lg_e_domain != '\0') {
 311  410                  domain = user_info->lg_e_domain;
 312  411          } else {
 313  412                  (void) smb_getdomainname(nbdomain, sizeof (nbdomain));
 314  413                  domain = nbdomain;
  
    | 
      ↓ open down ↓ | 
    24 lines elided | 
    
      ↑ open up ↑ | 
  
 315  414          }
 316  415  
 317  416          if (username)
 318  417                  token->tkn_account_name = strdup(username);
 319  418          if (domain)
 320  419                  token->tkn_domain_name = strdup(domain);
 321  420  
 322  421          if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
 323  422                  return (NT_STATUS_NO_MEMORY);
 324  423  
      424 +        status = netr_setup_domain_groups(info3, &token->tkn_win_grps);
      425 +        if (status != NT_STATUS_SUCCESS)
      426 +                return (status);
      427 +
 325  428          status = netr_setup_token_wingrps(info3, token);
 326  429          if (status != NT_STATUS_SUCCESS)
 327  430                  return (status);
 328  431  
 329  432          /*
 330  433           * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
 331  434           * session key obtained in the NETLOGON credential chain.
 332  435           * An 8 byte session key is zero extended to 16 bytes. This 16 byte
 333  436           * key is the key to the RC4 algorithm. The RC4 byte stream is
 334  437           * exclusively ored with the 16 byte UserSessionKey to recover
 335  438           * the the clear form.
 336  439           */
 337  440          if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
 338  441                  return (NT_STATUS_NO_MEMORY);
 339  442          token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
 340  443          bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
 341  444          bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
 342  445          bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val,
 343  446              SMBAUTH_SESSION_KEY_SZ);
 344  447          rand_hash((unsigned char *)token->tkn_ssnkey.val,
 345  448              SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ);
 346  449  
 347  450          return (NT_STATUS_SUCCESS);
 348  451  }
 349  452  
 350  453  /*
 351  454   * netr_server_samlogon
 352  455   *
 353  456   * NetrServerSamLogon RPC: interactive or network. It is assumed that
 354  457   * we have already authenticated with the PDC. If everything works,
 355  458   * we build a user info structure and return it, where the caller will
 356  459   * probably build an access token.
 357  460   *
 358  461   * Returns an NT status. There are numerous possibilities here.
 359  462   * For example:
 360  463   *      NT_STATUS_INVALID_INFO_CLASS
 361  464   *      NT_STATUS_INVALID_PARAMETER
 362  465   *      NT_STATUS_ACCESS_DENIED
 363  466   *      NT_STATUS_PASSWORD_MUST_CHANGE
 364  467   *      NT_STATUS_NO_SUCH_USER
 365  468   *      NT_STATUS_WRONG_PASSWORD
 366  469   *      NT_STATUS_LOGON_FAILURE
 367  470   *      NT_STATUS_ACCOUNT_RESTRICTION
 368  471   *      NT_STATUS_INVALID_LOGON_HOURS
 369  472   *      NT_STATUS_INVALID_WORKSTATION
 370  473   *      NT_STATUS_INTERNAL_ERROR
 371  474   *      NT_STATUS_PASSWORD_EXPIRED
 372  475   *      NT_STATUS_ACCOUNT_DISABLED
 373  476   */
 374  477  uint32_t
 375  478  netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info,
 376  479      char *server, smb_logon_t *user_info, smb_token_t *token)
 377  480  {
 378  481          struct netr_SamLogon arg;
 379  482          struct netr_authenticator auth;
 380  483          struct netr_authenticator ret_auth;
 381  484          struct netr_logon_info1 info1;
 382  485          struct netr_logon_info2 info2;
 383  486          struct netr_validation_info3 *info3;
 384  487          ndr_heap_t *heap;
 385  488          int opnum;
 386  489          int rc, len;
 387  490          uint32_t status;
 388  491  
 389  492          bzero(&arg, sizeof (struct netr_SamLogon));
 390  493          opnum = NETR_OPNUM_SamLogon;
 391  494  
 392  495          /*
 393  496           * Should we get the server and hostname from netr_info?
 394  497           */
 395  498  
 396  499          len = strlen(server) + 4;
 397  500          arg.servername = ndr_rpc_malloc(netr_handle, len);
 398  501          arg.hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ);
 399  502          if (arg.servername == NULL || arg.hostname == NULL) {
 400  503                  ndr_rpc_release(netr_handle);
 401  504                  return (NT_STATUS_INTERNAL_ERROR);
 402  505          }
 403  506  
 404  507          (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
 405  508          if (smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ) != 0) {
 406  509                  ndr_rpc_release(netr_handle);
 407  510                  return (NT_STATUS_INTERNAL_ERROR);
 408  511          }
 409  512  
 410  513          rc = netr_setup_authenticator(netr_info, &auth, &ret_auth);
 411  514          if (rc != SMBAUTH_SUCCESS) {
 412  515                  ndr_rpc_release(netr_handle);
 413  516                  return (NT_STATUS_INTERNAL_ERROR);
 414  517          }
 415  518  
 416  519          arg.auth = &auth;
 417  520          arg.ret_auth = &ret_auth;
 418  521          arg.validation_level = NETR_VALIDATION_LEVEL3;
 419  522          arg.logon_info.logon_level = user_info->lg_level;
 420  523          arg.logon_info.switch_value = user_info->lg_level;
 421  524  
 422  525          heap = ndr_rpc_get_heap(netr_handle);
 423  526  
 424  527          switch (user_info->lg_level) {
 425  528          case NETR_INTERACTIVE_LOGON:
 426  529                  netr_setup_identity(heap, user_info, &info1.identity);
 427  530                  netr_interactive_samlogon(netr_info, user_info, &info1);
 428  531                  arg.logon_info.ru.info1 = &info1;
 429  532                  break;
 430  533  
 431  534          case NETR_NETWORK_LOGON:
 432  535                  if (user_info->lg_challenge_key.len < 8 ||
 433  536                      user_info->lg_challenge_key.val == NULL) {
 434  537                          ndr_rpc_release(netr_handle);
 435  538                          return (NT_STATUS_INVALID_PARAMETER);
 436  539                  }
 437  540                  netr_setup_identity(heap, user_info, &info2.identity);
 438  541                  netr_network_samlogon(heap, netr_info, user_info, &info2);
 439  542                  arg.logon_info.ru.info2 = &info2;
 440  543                  break;
 441  544  
 442  545          default:
 443  546                  ndr_rpc_release(netr_handle);
 444  547                  return (NT_STATUS_INVALID_PARAMETER);
 445  548          }
 446  549  
 447  550          rc = ndr_rpc_call(netr_handle, opnum, &arg);
 448  551          if (rc != 0) {
 449  552                  bzero(netr_info, sizeof (netr_info_t));
 450  553                  status = NT_STATUS_INVALID_PARAMETER;
 451  554          } else if (arg.status != 0) {
 452  555                  status = NT_SC_VALUE(arg.status);
 453  556  
 454  557                  /*
 455  558                   * We need to validate the chain even though we have
 456  559                   * a non-zero status. If the status is ACCESS_DENIED
 457  560                   * this will trigger a new credential chain. However,
 458  561                   * a valid credential is returned with some status
 459  562                   * codes; for example, WRONG_PASSWORD.
 460  563                   */
 461  564                  (void) netr_validate_chain(netr_info, arg.ret_auth);
 462  565          } else {
 463  566                  status = netr_validate_chain(netr_info, arg.ret_auth);
 464  567                  if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
 465  568                          ndr_rpc_release(netr_handle);
 466  569                          return (status);
 467  570                  }
 468  571  
 469  572                  info3 = arg.ru.info3;
 470  573                  status = netr_setup_token(info3, user_info, netr_info, token);
 471  574          }
 472  575  
 473  576          ndr_rpc_release(netr_handle);
 474  577          return (status);
 475  578  }
 476  579  
 477  580  /*
 478  581   * netr_interactive_samlogon
 479  582   *
 480  583   * Set things up for an interactive SamLogon. Copy the NT and LM
 481  584   * passwords to the logon structure and hash them with the session
 482  585   * key.
 483  586   */
 484  587  static void
 485  588  netr_interactive_samlogon(netr_info_t *netr_info, smb_logon_t *user_info,
 486  589      struct netr_logon_info1 *info1)
 487  590  {
 488  591          BYTE key[NETR_OWF_PASSWORD_SZ];
 489  592  
 490  593          (void) memcpy(&info1->lm_owf_password,
 491  594              user_info->lg_lm_password.val, sizeof (netr_owf_password_t));
 492  595  
 493  596          (void) memcpy(&info1->nt_owf_password,
 494  597              user_info->lg_nt_password.val, sizeof (netr_owf_password_t));
 495  598  
 496  599          (void) memset(key, 0, NETR_OWF_PASSWORD_SZ);
 497  600          (void) memcpy(key, netr_info->session_key.key,
 498  601              netr_info->session_key.len);
 499  602  
 500  603          rand_hash((unsigned char *)&info1->lm_owf_password,
 501  604              NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
 502  605  
 503  606          rand_hash((unsigned char *)&info1->nt_owf_password,
 504  607              NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
 505  608  }
 506  609  
 507  610  /*
 508  611   * netr_network_samlogon
 509  612   *
 510  613   * Set things up for a network SamLogon.  We provide a copy of the random
 511  614   * challenge, that we sent to the client, to the domain controller.  This
 512  615   * is the key that the client will have used to encrypt the NT and LM
 513  616   * passwords.  Note that Windows 9x clients may not provide both passwords.
 514  617   */
 515  618  /*ARGSUSED*/
 516  619  static void
 517  620  netr_network_samlogon(ndr_heap_t *heap, netr_info_t *netr_info,
 518  621      smb_logon_t *user_info, struct netr_logon_info2 *info2)
 519  622  {
 520  623          uint32_t len;
 521  624  
 522  625          if (user_info->lg_challenge_key.len >= 8 &&
 523  626              user_info->lg_challenge_key.val != 0) {
 524  627                  bcopy(user_info->lg_challenge_key.val,
 525  628                      info2->lm_challenge.data, 8);
 526  629          } else {
 527  630                  bzero(info2->lm_challenge.data, 8);
 528  631          }
 529  632  
 530  633          if ((len = user_info->lg_nt_password.len) != 0) {
 531  634                  ndr_heap_mkvcb(heap, user_info->lg_nt_password.val, len,
 532  635                      (ndr_vcbuf_t *)&info2->nt_response);
 533  636          } else {
 534  637                  bzero(&info2->nt_response, sizeof (netr_vcbuf_t));
 535  638          }
 536  639  
 537  640          if ((len = user_info->lg_lm_password.len) != 0) {
 538  641                  ndr_heap_mkvcb(heap, user_info->lg_lm_password.val, len,
 539  642                      (ndr_vcbuf_t *)&info2->lm_response);
 540  643          } else {
 541  644                  bzero(&info2->lm_response, sizeof (netr_vcbuf_t));
 542  645          }
 543  646  }
 544  647  
 545  648  /*
 546  649   * netr_setup_authenticator
 547  650   *
 548  651   * Set up the request and return authenticators. A new credential is
 549  652   * generated from the session key, the current client credential and
 550  653   * the current time, i.e.
 551  654   *
 552  655   *              NewCredential = Cred(SessionKey, OldCredential, time);
 553  656   *
 554  657   * The timestamp, which is used as a random seed, is stored in both
 555  658   * the request and return authenticators.
 556  659   *
 557  660   * If any difficulties occur using the cryptographic framework, the
 558  661   * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
 559  662   * returned.
 560  663   */
 561  664  int
 562  665  netr_setup_authenticator(netr_info_t *netr_info,
 563  666      struct netr_authenticator *auth, struct netr_authenticator *ret_auth)
 564  667  {
 565  668          bzero(auth, sizeof (struct netr_authenticator));
 566  669  
 567  670          netr_info->timestamp = time(0);
 568  671          auth->timestamp = netr_info->timestamp;
 569  672  
 570  673          if (netr_gen_credentials(netr_info->session_key.key,
 571  674              &netr_info->client_credential,
 572  675              netr_info->timestamp,
 573  676              (netr_cred_t *)&auth->credential) != SMBAUTH_SUCCESS)
 574  677                  return (SMBAUTH_FAILURE);
 575  678  
 576  679          if (ret_auth) {
 577  680                  bzero(ret_auth, sizeof (struct netr_authenticator));
 578  681                  ret_auth->timestamp = netr_info->timestamp;
 579  682          }
 580  683  
 581  684          return (SMBAUTH_SUCCESS);
 582  685  }
 583  686  
 584  687  /*
 585  688   * Validate the returned credentials and update the credential chain.
 586  689   * The server returns an updated client credential rather than a new
 587  690   * server credential.  The server uses (timestamp + 1) when generating
 588  691   * the credential.
 589  692   *
 590  693   * Generate the new seed for the credential chain. The new seed is
 591  694   * formed by adding (timestamp + 1) to the current client credential.
 592  695   * The only quirk is the uint32_t style addition.
 593  696   *
 594  697   * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a
 595  698   * NULL pointer. The Authenticator field of the SamLogon response packet
 596  699   * sent by the Samba 3 PDC always return NULL pointer if the received
 597  700   * SamLogon request is not immediately followed by the ServerReqChallenge
 598  701   * and ServerAuthenticate2 requests.
 599  702   *
 600  703   * Returns NT_STATUS_SUCCESS if the server returned a valid credential.
 601  704   * Otherwise we retirm NT_STATUS_UNSUCCESSFUL.
 602  705   */
 603  706  uint32_t
 604  707  netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth)
 605  708  {
 606  709          netr_cred_t cred;
 607  710          uint32_t result = NT_STATUS_SUCCESS;
 608  711          uint32_t *dwp;
 609  712  
 610  713          ++netr_info->timestamp;
 611  714  
 612  715          if (netr_gen_credentials(netr_info->session_key.key,
 613  716              &netr_info->client_credential,
 614  717              netr_info->timestamp, &cred) != SMBAUTH_SUCCESS)
 615  718                  return (NT_STATUS_INTERNAL_ERROR);
 616  719  
 617  720          if (&auth->credential == 0) {
 618  721                  /*
 619  722                   * If the validation fails, destroy the credential chain.
 620  723                   * This should trigger a new authentication chain.
 621  724                   */
 622  725                  bzero(netr_info, sizeof (netr_info_t));
 623  726                  return (NT_STATUS_INSUFFICIENT_LOGON_INFO);
 624  727          }
 625  728  
 626  729          result = memcmp(&cred, &auth->credential, sizeof (netr_cred_t));
 627  730          if (result != 0) {
 628  731                  /*
 629  732                   * If the validation fails, destroy the credential chain.
 630  733                   * This should trigger a new authentication chain.
 631  734                   */
 632  735                  bzero(netr_info, sizeof (netr_info_t));
 633  736                  result = NT_STATUS_UNSUCCESSFUL;
 634  737          } else {
 635  738                  /*
 636  739                   * Otherwise generate the next step in the chain.
 637  740                   */
 638  741                  /*LINTED E_BAD_PTR_CAST_ALIGN*/
 639  742                  dwp = (uint32_t *)&netr_info->client_credential;
 640  743                  dwp[0] += netr_info->timestamp;
 641  744  
 642  745                  netr_info->flags |= NETR_FLG_VALID;
 643  746          }
 644  747  
 645  748          return (result);
 646  749  }
 647  750  
 648  751  /*
 649  752   * netr_invalidate_chain
 650  753   *
 651  754   * Mark the credential chain as invalid so that it will be recreated
 652  755   * on the next attempt.
 653  756   */
 654  757  static void
 655  758  netr_invalidate_chain(void)
 656  759  {
 657  760          netr_global_info.flags &= ~NETR_FLG_VALID;
 658  761  }
 659  762  
 660  763  /*
 661  764   * netr_setup_identity
 662  765   *
 663  766   * Set up the client identity information. All of this information is
 664  767   * specifically related to the client user and workstation attempting
 665  768   * to access this system. It may not be in our primary domain.
 666  769   *
 667  770   * I don't know what logon_id is, it seems to be a unique identifier.
 668  771   * Increment it before each use.
 669  772   */
 670  773  static void
 671  774  netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info,
 672  775      netr_logon_id_t *identity)
 673  776  {
 674  777          static mutex_t logon_id_mutex;
 675  778          static uint32_t logon_id;
 676  779  
 677  780          (void) mutex_lock(&logon_id_mutex);
 678  781  
 679  782          if (logon_id == 0)
 680  783                  logon_id = 0xDCD0;
 681  784  
 682  785          ++logon_id;
 683  786          user_info->lg_logon_id = logon_id;
 684  787  
 685  788          (void) mutex_unlock(&logon_id_mutex);
 686  789  
 687  790          /*
 688  791           * [MS-APDS] 3.1.5.2 "NTLM Network Logon" says to set
 689  792           * ParameterControl to the 'E' + 'K' bits.  Those are:
 690  793           * (1 << 5) | (1 << 11), a.k.a
 691  794           */
 692  795          identity->parameter_control =
 693  796              MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
 694  797              MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
 695  798          identity->logon_id.LowPart = logon_id;
 696  799          identity->logon_id.HighPart = 0;
 697  800  
 698  801          ndr_heap_mkvcs(heap, user_info->lg_domain,
 699  802              (ndr_vcstr_t *)&identity->domain_name);
 700  803  
 701  804          ndr_heap_mkvcs(heap, user_info->lg_username,
 702  805              (ndr_vcstr_t *)&identity->username);
 703  806  
  
    | 
      ↓ open down ↓ | 
    369 lines elided | 
    
      ↑ open up ↑ | 
  
 704  807          /*
 705  808           * Some systems prefix the client workstation name with \\.
 706  809           * It doesn't seem to make any difference whether it's there
 707  810           * or not.
 708  811           */
 709  812          ndr_heap_mkvcs(heap, user_info->lg_workstation,
 710  813              (ndr_vcstr_t *)&identity->workstation);
 711  814  }
 712  815  
 713  816  /*
 714      - * Sets up domain, local and well-known group membership for the given
 715      - * token. Two assumptions have been made here:
 716      - *
 717      - *   a) token already contains a valid user SID so that group
 718      - *      memberships can be established
 719      - *
 720      - *   b) token belongs to a domain user
      817 + * Add local and well-known group membership to the given
      818 + * token.  Called after domain groups have been added.
 721  819   */
 722  820  static uint32_t
 723  821  netr_setup_token_wingrps(struct netr_validation_info3 *info3,
 724  822      smb_token_t *token)
 725  823  {
 726      -        smb_ids_t tkn_grps;
 727  824          uint32_t status;
 728  825  
 729      -        tkn_grps.i_cnt = 0;
 730      -        tkn_grps.i_ids = NULL;
 731      -
 732      -        status = netr_setup_domain_groups(info3, &tkn_grps);
 733      -        if (status != NT_STATUS_SUCCESS) {
 734      -                smb_ids_free(&tkn_grps);
      826 +        status = smb_sam_usr_groups(token->tkn_user.i_sid,
      827 +            &token->tkn_win_grps);
      828 +        if (status != NT_STATUS_SUCCESS)
 735  829                  return (status);
 736      -        }
 737  830  
 738      -        status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps);
 739      -        if (status != NT_STATUS_SUCCESS) {
 740      -                smb_ids_free(&tkn_grps);
 741      -                return (status);
 742      -        }
 743      -
 744  831          if (netr_isadmin(info3))
 745  832                  token->tkn_flags |= SMB_ATF_ADMIN;
 746  833  
 747      -        status = smb_wka_token_groups(token->tkn_flags, &tkn_grps);
 748      -        if (status == NT_STATUS_SUCCESS)
 749      -                token->tkn_win_grps = tkn_grps;
 750      -        else
 751      -                smb_ids_free(&tkn_grps);
      834 +        status = smb_wka_token_groups(token->tkn_flags, &token->tkn_win_grps);
 752  835  
 753  836          return (status);
 754  837  }
 755  838  
 756  839  /*
 757  840   * Converts groups information in the returned structure by domain controller
 758  841   * (info3) to an internal representation (gids)
 759  842   */
 760  843  static uint32_t
 761  844  netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
 762  845  {
 763  846          smb_sid_t *domain_sid;
 764  847          smb_id_t *ids;
 765  848          int i, total_cnt;
 766  849  
 767  850          if ((i = info3->GroupCount) == 0)
 768  851                  i++;
 769  852          i += info3->SidCount;
 770  853  
 771  854          total_cnt = gids->i_cnt + i;
 772  855  
 773  856          gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
 774  857          if (gids->i_ids == NULL)
 775  858                  return (NT_STATUS_NO_MEMORY);
 776  859  
 777  860          domain_sid = (smb_sid_t *)info3->LogonDomainId;
 778  861  
 779  862          ids = gids->i_ids + gids->i_cnt;
 780  863          for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) {
 781  864                  ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid);
 782  865                  if (ids->i_sid == NULL)
 783  866                          return (NT_STATUS_NO_MEMORY);
 784  867  
 785  868                  ids->i_attrs = info3->GroupIds[i].attributes;
 786  869          }
 787  870  
 788  871          if (info3->GroupCount == 0) {
 789  872                  /*
 790  873                   * if there's no global group should add the primary group.
 791  874                   */
 792  875                  ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId);
 793  876                  if (ids->i_sid == NULL)
 794  877                          return (NT_STATUS_NO_MEMORY);
 795  878  
 796  879                  ids->i_attrs = 0x7;
 797  880                  gids->i_cnt++;
 798  881                  ids++;
 799  882          }
 800  883  
 801  884          /* Add the extra SIDs */
 802  885          for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
  
    | 
      ↓ open down ↓ | 
    41 lines elided | 
    
      ↑ open up ↑ | 
  
 803  886                  ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
 804  887                  if (ids->i_sid == NULL)
 805  888                          return (NT_STATUS_NO_MEMORY);
 806  889  
 807  890                  ids->i_attrs = info3->ExtraSids[i].attributes;
 808  891          }
 809  892  
 810  893          return (NT_STATUS_SUCCESS);
 811  894  }
 812  895  
      896 +/*
      897 + * Converts additional "resource" groups (from krb5_validation_info)
      898 + * into the internal representation (gids), appending to the list
      899 + * already put in place by netr_setup_domain_groups().
      900 + */
      901 +static uint32_t netr_setup_krb5res_groups(struct krb5_validation_info *info,
      902 +    smb_ids_t *gids)
      903 +{
      904 +        smb_sid_t *domain_sid;
      905 +        smb_id_t *ids;
      906 +        int i, total_cnt;
      907 +
      908 +        total_cnt = gids->i_cnt + info->rg_rid_cnt;
      909 +
      910 +        gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
      911 +        if (gids->i_ids == NULL)
      912 +                return (NT_STATUS_NO_MEMORY);
      913 +
      914 +        domain_sid = (smb_sid_t *)info->rg_dom_sid;
      915 +
      916 +        ids = gids->i_ids + gids->i_cnt;
      917 +        for (i = 0; i < info->rg_rid_cnt; i++, gids->i_cnt++, ids++) {
      918 +                ids->i_sid = smb_sid_splice(domain_sid, info->rg_rids[i].rid);
      919 +                if (ids->i_sid == NULL)
      920 +                        return (NT_STATUS_NO_MEMORY);
      921 +                ids->i_attrs = info->rg_rids[i].attributes;
      922 +        }
      923 +
      924 +        return (0);
      925 +}
      926 +
 813  927  /*
 814  928   * Determines if the given user is the domain Administrator or a
 815  929   * member of Domain Admins
 816  930   */
 817  931  static boolean_t
 818  932  netr_isadmin(struct netr_validation_info3 *info3)
 819  933  {
 820  934          smb_domain_t di;
 821  935          int i;
 822  936  
 823  937          if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di))
 824  938                  return (B_FALSE);
 825  939  
 826  940          if (di.di_type != SMB_DOMAIN_PRIMARY)
 827  941                  return (B_FALSE);
 828  942  
 829  943          if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
 830  944              (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS))
 831  945                  return (B_TRUE);
 832  946  
 833  947          for (i = 0; i < info3->GroupCount; i++)
 834  948                  if (info3->GroupIds[i].rid == DOMAIN_GROUP_RID_ADMINS)
 835  949                          return (B_TRUE);
 836  950  
 837  951          return (B_FALSE);
 838  952  }
  
    | 
      ↓ open down ↓ | 
    16 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX