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


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * NETR SamLogon and SamLogoff RPC client functions.
  29  */
  30 
  31 #include <stdio.h>
  32 #include <strings.h>
  33 #include <stdlib.h>
  34 #include <time.h>
  35 #include <alloca.h>
  36 #include <unistd.h>
  37 #include <netdb.h>
  38 #include <thread.h>
  39 

  40 #include <smbsrv/libsmb.h>
  41 #include <smbsrv/libmlrpc.h>
  42 #include <smbsrv/libmlsvc.h>
  43 #include <smbsrv/ndl/netlogon.ndl>
  44 #include <smbsrv/netrauth.h>
  45 #include <smbsrv/smbinfo.h>
  46 #include <smbsrv/smb_token.h>
  47 #include <mlsvc.h>
  48 
  49 #define NETLOGON_ATTEMPTS       2
  50 
  51 static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *);
  52 static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
  53     smb_logon_t *, smb_token_t *);
  54 static void netr_invalidate_chain(void);
  55 static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *,
  56     struct netr_logon_info1 *);
  57 static void netr_network_samlogon(ndr_heap_t *, netr_info_t *,
  58     smb_logon_t *, struct netr_logon_info2 *);
  59 static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
  60     netr_logon_id_t *);
  61 static boolean_t netr_isadmin(struct netr_validation_info3 *);
  62 static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
  63     smb_ids_t *);
  64 static uint32_t netr_setup_token_info3(struct netr_validation_info3 *,
  65     smb_token_t *);
  66 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
  67     smb_token_t *);
  68 
  69 /*
  70  * Shared with netr_auth.c
  71  */
  72 extern netr_info_t netr_global_info;
  73 
  74 static mutex_t netlogon_mutex;
  75 static cond_t netlogon_cv;
  76 static boolean_t netlogon_busy = B_FALSE;
  77 static boolean_t netlogon_abort = B_FALSE;
  78 
  79 /*
  80  * Helper for Kerberos authentication
  81  */
  82 uint32_t
  83 smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len)
  84 {
  85         struct krb5_validation_info info;
  86         ndr_buf_t *nbuf;

  87         uint32_t status = NT_STATUS_NO_MEMORY;
  88         int rc;
  89 
  90         bzero(&info, sizeof (info));
  91 
  92         /* Need to keep this until we're done with &info */
  93         nbuf = ndr_buf_init(&TYPEINFO(netr_interface));
  94         if (nbuf == NULL)
  95                 goto out;
  96 
  97         rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC,
  98             NETR_OPNUM_decode_krb5_pac, data, len, &info);
  99         if (rc != NDR_DRC_OK) {
 100                 status = RPC_NT_PROTOCOL_ERROR;
 101                 goto out;
 102         }
 103 
 104         status = netr_setup_token_info3(&info.info3, token);
 105 
 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         token->tkn_user.i_sid = smb_sid_splice(domsid,
 128             info3->UserId);
 129         if (token->tkn_user.i_sid == NULL)
 130                 goto errout;
 131 
 132         token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
 133             info3->PrimaryGroupId);
 134         if (token->tkn_primary_grp.i_sid == NULL)
 135                 goto errout;
 136 
 137         if (info3->EffectiveName.str) {
 138                 token->tkn_account_name =
 139                     strdup((char *)info3->EffectiveName.str);
 140                 if (token->tkn_account_name == NULL)
 141                         goto errout;
 142         }
 143 
 144         if (info3->LogonDomainName.str) {
 145                 token->tkn_domain_name =
 146                     strdup((char *)info3->LogonDomainName.str);
 147                 if (token->tkn_domain_name == NULL)
 148                         goto errout;
 149         }
 150 
 151         return (netr_setup_token_wingrps(info3, token));
 152 errout:
 153         return (NT_STATUS_INSUFF_SERVER_RESOURCES);














 154 }
 155 
 156 /*
 157  * Abort impending domain logon requests.
 158  */
 159 void
 160 smb_logon_abort(void)
 161 {
 162         (void) mutex_lock(&netlogon_mutex);
 163         if (netlogon_busy && !netlogon_abort)
 164                 syslog(LOG_DEBUG, "logon abort");
 165         netlogon_abort = B_TRUE;
 166         (void) cond_broadcast(&netlogon_cv);
 167         (void) mutex_unlock(&netlogon_mutex);
 168 }
 169 
 170 /*
 171  * This is the entry point for authenticating domain users.
 172  *
 173  * If we are not going to attempt to authenticate the user,
 174  * this function must return without updating the status.
 175  *
 176  * If the user is successfully authenticated, we build an
 177  * access token and the status will be NT_STATUS_SUCCESS.
 178  * Otherwise, the token contents are invalid.





 179  */

 180 void
 181 smb_logon_domain(smb_logon_t *user_info, smb_token_t *token)
 182 {

 183         uint32_t        status;
 184         int             i;
 185 
 186         if (user_info->lg_secmode != SMB_SECMODE_DOMAIN)
 187                 return;
 188 
 189         if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL)
 190                 return;
 191 
 192         for (i = 0; i < NETLOGON_ATTEMPTS; ++i) {







 193                 (void) mutex_lock(&netlogon_mutex);
 194                 while (netlogon_busy && !netlogon_abort)
 195                         (void) cond_wait(&netlogon_cv, &netlogon_mutex);
 196 
 197                 if (netlogon_abort) {
 198                         (void) mutex_unlock(&netlogon_mutex);
 199                         user_info->lg_status = NT_STATUS_REQUEST_ABORTED;
 200                         return;
 201                 }
 202 
 203                 netlogon_busy = B_TRUE;
 204                 (void) mutex_unlock(&netlogon_mutex);
 205 
 206                 status = netlogon_logon(user_info, token);
 207 
 208                 (void) mutex_lock(&netlogon_mutex);
 209                 netlogon_busy = B_FALSE;
 210                 if (netlogon_abort)
 211                         status = NT_STATUS_REQUEST_ABORTED;
 212                 (void) cond_signal(&netlogon_cv);
 213                 (void) mutex_unlock(&netlogon_mutex);
 214 
 215                 if (status != NT_STATUS_CANT_ACCESS_DOMAIN_INFO)








 216                         break;


 217         }

 218 

 219         if (status != NT_STATUS_SUCCESS)
 220                 syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain,
 221                     user_info->lg_e_username, xlate_nt_status(status));
 222 
 223         user_info->lg_status = status;
 224 }
 225 








 226 static uint32_t
 227 netlogon_logon(smb_logon_t *user_info, smb_token_t *token)
 228 {
 229         char resource_domain[SMB_PI_MAX_DOMAIN];
 230         char server[MAXHOSTNAMELEN];
 231         mlsvc_handle_t netr_handle;
 232         smb_domainex_t di;
 233         uint32_t status;
 234         int retries = 0;
 235 
 236         (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
 237 
 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);



 243         }
 244 
 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);
 249 
 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();
 257                 }
 258 

 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);
 263 
 264                         if (status != 0) {


 265                                 (void) netr_close(&netr_handle);
 266                                 return (NT_STATUS_LOGON_FAILURE);
 267                         }
 268 
 269                         netr_global_info.flags |= NETR_FLG_VALID;
 270                 }
 271 
 272                 status = netr_server_samlogon(&netr_handle,
 273                     &netr_global_info, di.d_dci.dc_name, user_info, token);
 274 









 275                 (void) netr_close(&netr_handle);
 276         } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3);
 277 
 278         if (retries >= 3)
 279                 status = NT_STATUS_LOGON_FAILURE;
 280 


























































 281         return (status);
 282 }
 283 
 284 static uint32_t
 285 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
 286     netr_info_t *netr_info, smb_token_t *token)
 287 {
 288         char *username, *domain;
 289         unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
 290         smb_sid_t *domsid;
 291         uint32_t status;
 292         char nbdomain[NETBIOS_NAME_SZ];
 293 
 294         domsid = (smb_sid_t *)info3->LogonDomainId;
 295 
 296         token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
 297         if (token->tkn_user.i_sid == NULL)
 298                 return (NT_STATUS_NO_MEMORY);
 299 
 300         token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,


 305         username = (info3->EffectiveName.str)
 306             ? (char *)info3->EffectiveName.str : user_info->lg_e_username;
 307 
 308         if (info3->LogonDomainName.str) {
 309                 domain = (char *)info3->LogonDomainName.str;
 310         } else if (*user_info->lg_e_domain != '\0') {
 311                 domain = user_info->lg_e_domain;
 312         } else {
 313                 (void) smb_getdomainname(nbdomain, sizeof (nbdomain));
 314                 domain = nbdomain;
 315         }
 316 
 317         if (username)
 318                 token->tkn_account_name = strdup(username);
 319         if (domain)
 320                 token->tkn_domain_name = strdup(domain);
 321 
 322         if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
 323                 return (NT_STATUS_NO_MEMORY);
 324 




 325         status = netr_setup_token_wingrps(info3, token);
 326         if (status != NT_STATUS_SUCCESS)
 327                 return (status);
 328 
 329         /*
 330          * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
 331          * session key obtained in the NETLOGON credential chain.
 332          * An 8 byte session key is zero extended to 16 bytes. This 16 byte
 333          * key is the key to the RC4 algorithm. The RC4 byte stream is
 334          * exclusively ored with the 16 byte UserSessionKey to recover
 335          * the the clear form.
 336          */
 337         if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
 338                 return (NT_STATUS_NO_MEMORY);
 339         token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
 340         bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
 341         bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
 342         bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val,
 343             SMBAUTH_SESSION_KEY_SZ);
 344         rand_hash((unsigned char *)token->tkn_ssnkey.val,


 694             MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
 695         identity->logon_id.LowPart = logon_id;
 696         identity->logon_id.HighPart = 0;
 697 
 698         ndr_heap_mkvcs(heap, user_info->lg_domain,
 699             (ndr_vcstr_t *)&identity->domain_name);
 700 
 701         ndr_heap_mkvcs(heap, user_info->lg_username,
 702             (ndr_vcstr_t *)&identity->username);
 703 
 704         /*
 705          * Some systems prefix the client workstation name with \\.
 706          * It doesn't seem to make any difference whether it's there
 707          * or not.
 708          */
 709         ndr_heap_mkvcs(heap, user_info->lg_workstation,
 710             (ndr_vcstr_t *)&identity->workstation);
 711 }
 712 
 713 /*
 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
 721  */
 722 static uint32_t
 723 netr_setup_token_wingrps(struct netr_validation_info3 *info3,
 724     smb_token_t *token)
 725 {
 726         smb_ids_t tkn_grps;
 727         uint32_t status;
 728 
 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);
 735                 return (status);
 736         }
 737 
 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         if (netr_isadmin(info3))
 745                 token->tkn_flags |= SMB_ATF_ADMIN;
 746 
 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);
 752 
 753         return (status);
 754 }
 755 
 756 /*
 757  * Converts groups information in the returned structure by domain controller
 758  * (info3) to an internal representation (gids)
 759  */
 760 static uint32_t
 761 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
 762 {
 763         smb_sid_t *domain_sid;
 764         smb_id_t *ids;
 765         int i, total_cnt;
 766 
 767         if ((i = info3->GroupCount) == 0)
 768                 i++;
 769         i += info3->SidCount;
 770 
 771         total_cnt = gids->i_cnt + i;


 793                 if (ids->i_sid == NULL)
 794                         return (NT_STATUS_NO_MEMORY);
 795 
 796                 ids->i_attrs = 0x7;
 797                 gids->i_cnt++;
 798                 ids++;
 799         }
 800 
 801         /* Add the extra SIDs */
 802         for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
 803                 ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
 804                 if (ids->i_sid == NULL)
 805                         return (NT_STATUS_NO_MEMORY);
 806 
 807                 ids->i_attrs = info3->ExtraSids[i].attributes;
 808         }
 809 
 810         return (NT_STATUS_SUCCESS);
 811 }
 812 































 813 /*
 814  * Determines if the given user is the domain Administrator or a
 815  * member of Domain Admins
 816  */
 817 static boolean_t
 818 netr_isadmin(struct netr_validation_info3 *info3)
 819 {
 820         smb_domain_t di;
 821         int i;
 822 
 823         if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di))
 824                 return (B_FALSE);
 825 
 826         if (di.di_type != SMB_DOMAIN_PRIMARY)
 827                 return (B_FALSE);
 828 
 829         if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
 830             (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS))
 831                 return (B_TRUE);
 832 


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * NETR SamLogon and SamLogoff RPC client functions.
  29  */
  30 
  31 #include <stdio.h>
  32 #include <strings.h>
  33 #include <stdlib.h>
  34 #include <time.h>
  35 #include <alloca.h>
  36 #include <unistd.h>
  37 #include <netdb.h>
  38 #include <thread.h>
  39 
  40 #include <libmlrpc/libmlrpc.h>
  41 #include <smbsrv/libsmb.h>

  42 #include <smbsrv/libmlsvc.h>
  43 #include <smbsrv/ndl/netlogon.ndl>
  44 #include <smbsrv/netrauth.h>
  45 #include <smbsrv/smbinfo.h>
  46 #include <smbsrv/smb_token.h>
  47 #include <mlsvc.h>
  48 
  49 static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *, smb_domainex_t *);


  50 static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
  51     smb_logon_t *, smb_token_t *);
  52 static void netr_invalidate_chain(void);
  53 static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *,
  54     struct netr_logon_info1 *);
  55 static void netr_network_samlogon(ndr_heap_t *, netr_info_t *,
  56     smb_logon_t *, struct netr_logon_info2 *);
  57 static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
  58     netr_logon_id_t *);
  59 static boolean_t netr_isadmin(struct netr_validation_info3 *);
  60 static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
  61     smb_ids_t *);
  62 static uint32_t netr_setup_krb5res_groups(struct krb5_validation_info *,
  63     smb_ids_t *);
  64 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
  65     smb_token_t *);
  66 
  67 /*
  68  * Shared with netr_auth.c
  69  */
  70 extern netr_info_t netr_global_info;
  71 
  72 static mutex_t netlogon_mutex;
  73 static cond_t netlogon_cv;
  74 static boolean_t netlogon_busy = B_FALSE;
  75 static boolean_t netlogon_abort = B_FALSE;
  76 
  77 /*
  78  * Helper for Kerberos authentication
  79  */
  80 uint32_t
  81 smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len)
  82 {
  83         struct krb5_validation_info info;
  84         ndr_buf_t *nbuf;
  85         smb_sid_t *domsid;
  86         uint32_t status = NT_STATUS_NO_MEMORY;
  87         int rc;
  88 
  89         bzero(&info, sizeof (info));
  90 
  91         /* Need to keep this until we're done with &info */
  92         nbuf = ndr_buf_init(&TYPEINFO(netr_interface));
  93         if (nbuf == NULL)
  94                 goto out;
  95 
  96         rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC,
  97             NETR_OPNUM_decode_krb5_pac, data, len, &info);
  98         if (rc != NDR_DRC_OK) {
  99                 status = RPC_NT_PROTOCOL_ERROR;
 100                 goto out;
 101         }
 102 
 103         /*
 104          * Copy the decoded info into the token,
 105          * similar to netr_setup_token()











 106          */
 107         domsid = (smb_sid_t *)info.info3.LogonDomainId;




 108 


 109         token->tkn_user.i_sid = smb_sid_splice(domsid,
 110             info.info3.UserId);
 111         if (token->tkn_user.i_sid == NULL)
 112                 goto out;
 113 
 114         token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
 115             info.info3.PrimaryGroupId);
 116         if (token->tkn_primary_grp.i_sid == NULL)
 117                 goto out;
 118 
 119         if (info.info3.EffectiveName.str) {
 120                 token->tkn_account_name =
 121                     strdup((char *)info.info3.EffectiveName.str);
 122                 if (token->tkn_account_name == NULL)
 123                         goto out;
 124         }
 125 
 126         if (info.info3.LogonDomainName.str) {
 127                 token->tkn_domain_name =
 128                     strdup((char *)info.info3.LogonDomainName.str);
 129                 if (token->tkn_domain_name == NULL)
 130                         goto out;
 131         }
 132 
 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);
 150 }
 151 
 152 /*
 153  * Abort impending domain logon requests.
 154  */
 155 void
 156 smb_logon_abort(void)
 157 {
 158         (void) mutex_lock(&netlogon_mutex);
 159         if (netlogon_busy && !netlogon_abort)
 160                 syslog(LOG_DEBUG, "logon abort");
 161         netlogon_abort = B_TRUE;
 162         (void) cond_broadcast(&netlogon_cv);
 163         (void) mutex_unlock(&netlogon_mutex);
 164 }
 165 
 166 /*
 167  * This is the entry point for authenticating domain users.
 168  *
 169  * If we are not going to attempt to authenticate the user,
 170  * this function must return without updating the status.
 171  *
 172  * If the user is successfully authenticated, we build an
 173  * access token and the status will be NT_STATUS_SUCCESS.
 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.
 180  */
 181 int smb_netr_logon_retries = 3;
 182 void
 183 smb_logon_domain(smb_logon_t *user_info, smb_token_t *token)
 184 {
 185         smb_domainex_t  di;
 186         uint32_t        status;
 187         int             retries = smb_netr_logon_retries;
 188 
 189         if (user_info->lg_secmode != SMB_SECMODE_DOMAIN)
 190                 return;
 191 
 192         if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL)
 193                 return;
 194 
 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 
 203                 (void) mutex_lock(&netlogon_mutex);
 204                 while (netlogon_busy && !netlogon_abort)
 205                         (void) cond_wait(&netlogon_cv, &netlogon_mutex);
 206 
 207                 if (netlogon_abort) {
 208                         (void) mutex_unlock(&netlogon_mutex);
 209                         status = NT_STATUS_REQUEST_ABORTED;
 210                         goto out;
 211                 }
 212 
 213                 netlogon_busy = B_TRUE;
 214                 (void) mutex_unlock(&netlogon_mutex);
 215 
 216                 status = netlogon_logon(user_info, token, &di);
 217 
 218                 (void) mutex_lock(&netlogon_mutex);
 219                 netlogon_busy = B_FALSE;
 220                 if (netlogon_abort)
 221                         status = NT_STATUS_REQUEST_ABORTED;
 222                 (void) cond_signal(&netlogon_cv);
 223                 (void) mutex_unlock(&netlogon_mutex);
 224 
 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;
 234                         break;
 235                 default:
 236                         goto out;
 237                 }
 238         }
 239 
 240 out:
 241         if (status != NT_STATUS_SUCCESS)
 242                 syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain,
 243                     user_info->lg_e_username, xlate_nt_status(status));

 244         user_info->lg_status = status;
 245 }
 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  */
 255 static uint32_t
 256 netlogon_logon(smb_logon_t *user_info, smb_token_t *token, smb_domainex_t *di)
 257 {

 258         char server[MAXHOSTNAMELEN];
 259         mlsvc_handle_t netr_handle;

 260         uint32_t status;
 261         boolean_t did_reauth = B_FALSE;
 262 
 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         }
 274 
 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();
 282         }
 283 
 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);
 294 
 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);
 300                 }
 301 
 302                 netr_global_info.flags |= NETR_FLG_VALID;
 303         }
 304 
 305         status = netr_server_samlogon(&netr_handle,
 306             &netr_global_info, di->d_dci.dc_name, user_info, token);
 307 
 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;
 313                 }
 314                 status = NT_STATUS_DOMAIN_TRUST_INCONSISTENT;
 315         }
 316 
 317         (void) netr_close(&netr_handle);

 318 
 319         return (status);
 320 }
 321 
 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;
 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 
 380         return (status);
 381 }
 382 
 383 static uint32_t
 384 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
 385     netr_info_t *netr_info, smb_token_t *token)
 386 {
 387         char *username, *domain;
 388         unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
 389         smb_sid_t *domsid;
 390         uint32_t status;
 391         char nbdomain[NETBIOS_NAME_SZ];
 392 
 393         domsid = (smb_sid_t *)info3->LogonDomainId;
 394 
 395         token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
 396         if (token->tkn_user.i_sid == NULL)
 397                 return (NT_STATUS_NO_MEMORY);
 398 
 399         token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,


 404         username = (info3->EffectiveName.str)
 405             ? (char *)info3->EffectiveName.str : user_info->lg_e_username;
 406 
 407         if (info3->LogonDomainName.str) {
 408                 domain = (char *)info3->LogonDomainName.str;
 409         } else if (*user_info->lg_e_domain != '\0') {
 410                 domain = user_info->lg_e_domain;
 411         } else {
 412                 (void) smb_getdomainname(nbdomain, sizeof (nbdomain));
 413                 domain = nbdomain;
 414         }
 415 
 416         if (username)
 417                 token->tkn_account_name = strdup(username);
 418         if (domain)
 419                 token->tkn_domain_name = strdup(domain);
 420 
 421         if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
 422                 return (NT_STATUS_NO_MEMORY);
 423 
 424         status = netr_setup_domain_groups(info3, &token->tkn_win_grps);
 425         if (status != NT_STATUS_SUCCESS)
 426                 return (status);
 427 
 428         status = netr_setup_token_wingrps(info3, token);
 429         if (status != NT_STATUS_SUCCESS)
 430                 return (status);
 431 
 432         /*
 433          * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
 434          * session key obtained in the NETLOGON credential chain.
 435          * An 8 byte session key is zero extended to 16 bytes. This 16 byte
 436          * key is the key to the RC4 algorithm. The RC4 byte stream is
 437          * exclusively ored with the 16 byte UserSessionKey to recover
 438          * the the clear form.
 439          */
 440         if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
 441                 return (NT_STATUS_NO_MEMORY);
 442         token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
 443         bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
 444         bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
 445         bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val,
 446             SMBAUTH_SESSION_KEY_SZ);
 447         rand_hash((unsigned char *)token->tkn_ssnkey.val,


 797             MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
 798         identity->logon_id.LowPart = logon_id;
 799         identity->logon_id.HighPart = 0;
 800 
 801         ndr_heap_mkvcs(heap, user_info->lg_domain,
 802             (ndr_vcstr_t *)&identity->domain_name);
 803 
 804         ndr_heap_mkvcs(heap, user_info->lg_username,
 805             (ndr_vcstr_t *)&identity->username);
 806 
 807         /*
 808          * Some systems prefix the client workstation name with \\.
 809          * It doesn't seem to make any difference whether it's there
 810          * or not.
 811          */
 812         ndr_heap_mkvcs(heap, user_info->lg_workstation,
 813             (ndr_vcstr_t *)&identity->workstation);
 814 }
 815 
 816 /*
 817  * Add local and well-known group membership to the given
 818  * token.  Called after domain groups have been added.





 819  */
 820 static uint32_t
 821 netr_setup_token_wingrps(struct netr_validation_info3 *info3,
 822     smb_token_t *token)
 823 {

 824         uint32_t status;
 825 
 826         status = smb_sam_usr_groups(token->tkn_user.i_sid,
 827             &token->tkn_win_grps);
 828         if (status != NT_STATUS_SUCCESS)



 829                 return (status);

 830 






 831         if (netr_isadmin(info3))
 832                 token->tkn_flags |= SMB_ATF_ADMIN;
 833 
 834         status = smb_wka_token_groups(token->tkn_flags, &token->tkn_win_grps);




 835 
 836         return (status);
 837 }
 838 
 839 /*
 840  * Converts groups information in the returned structure by domain controller
 841  * (info3) to an internal representation (gids)
 842  */
 843 static uint32_t
 844 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
 845 {
 846         smb_sid_t *domain_sid;
 847         smb_id_t *ids;
 848         int i, total_cnt;
 849 
 850         if ((i = info3->GroupCount) == 0)
 851                 i++;
 852         i += info3->SidCount;
 853 
 854         total_cnt = gids->i_cnt + i;


 876                 if (ids->i_sid == NULL)
 877                         return (NT_STATUS_NO_MEMORY);
 878 
 879                 ids->i_attrs = 0x7;
 880                 gids->i_cnt++;
 881                 ids++;
 882         }
 883 
 884         /* Add the extra SIDs */
 885         for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
 886                 ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
 887                 if (ids->i_sid == NULL)
 888                         return (NT_STATUS_NO_MEMORY);
 889 
 890                 ids->i_attrs = info3->ExtraSids[i].attributes;
 891         }
 892 
 893         return (NT_STATUS_SUCCESS);
 894 }
 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 
 927 /*
 928  * Determines if the given user is the domain Administrator or a
 929  * member of Domain Admins
 930  */
 931 static boolean_t
 932 netr_isadmin(struct netr_validation_info3 *info3)
 933 {
 934         smb_domain_t di;
 935         int i;
 936 
 937         if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di))
 938                 return (B_FALSE);
 939 
 940         if (di.di_type != SMB_DOMAIN_PRIMARY)
 941                 return (B_FALSE);
 942 
 943         if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
 944             (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS))
 945                 return (B_TRUE);
 946