1 /* 2 * CDDL HEADER START 3 * 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 2012 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_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 * Abort impending domain logon requests. 79 */ 80 void 81 smb_logon_abort(void) 82 { 83 (void) mutex_lock(&netlogon_mutex); 84 if (netlogon_busy && !netlogon_abort) 85 syslog(LOG_DEBUG, "logon abort"); 86 netlogon_abort = B_TRUE; 87 (void) cond_broadcast(&netlogon_cv); 88 (void) mutex_unlock(&netlogon_mutex); 89 } 90 91 /* 92 * This is the entry point for authenticating domain users. 93 * 94 * If we are not going to attempt to authenticate the user, 95 * this function must return without updating the status. 96 * 97 * If the user is successfully authenticated, we build an 98 * access token and the status will be NT_STATUS_SUCCESS. 99 * Otherwise, the token contents are invalid. 100 */ 101 void 102 smb_logon_domain(smb_logon_t *user_info, smb_token_t *token) 103 { 104 uint32_t status; 105 int i; 106 107 if (user_info->lg_secmode != SMB_SECMODE_DOMAIN) 108 return; 109 110 if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL) 111 return; 112 113 for (i = 0; i < NETLOGON_ATTEMPTS; ++i) { 114 (void) mutex_lock(&netlogon_mutex); 115 while (netlogon_busy && !netlogon_abort) 116 (void) cond_wait(&netlogon_cv, &netlogon_mutex); 117 118 if (netlogon_abort) { 119 (void) mutex_unlock(&netlogon_mutex); 120 user_info->lg_status = NT_STATUS_REQUEST_ABORTED; 121 return; 122 } 123 124 netlogon_busy = B_TRUE; 125 (void) mutex_unlock(&netlogon_mutex); 126 127 status = netlogon_logon(user_info, token); 128 129 (void) mutex_lock(&netlogon_mutex); 130 netlogon_busy = B_FALSE; 131 if (netlogon_abort) 132 status = NT_STATUS_REQUEST_ABORTED; 133 (void) cond_signal(&netlogon_cv); 134 (void) mutex_unlock(&netlogon_mutex); 135 136 if (status != NT_STATUS_CANT_ACCESS_DOMAIN_INFO) 137 break; 138 } 139 140 if (status != NT_STATUS_SUCCESS) 141 syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain, 142 user_info->lg_e_username, xlate_nt_status(status)); 143 144 user_info->lg_status = status; 145 } 146 147 static uint32_t 148 netlogon_logon(smb_logon_t *user_info, smb_token_t *token) 149 { 150 char resource_domain[SMB_PI_MAX_DOMAIN]; 151 char server[NETBIOS_NAME_SZ * 2]; 152 mlsvc_handle_t netr_handle; 153 smb_domainex_t di; 154 uint32_t status; 155 int retries = 0; 156 157 (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN); 158 159 /* Avoid interfering with DC discovery. */ 160 if (smb_ddiscover_wait() != 0 || 161 !smb_domain_getinfo(&di)) { 162 netr_invalidate_chain(); 163 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 164 } 165 166 do { 167 if (netr_open(di.d_dc, di.d_primary.di_nbname, &netr_handle) 168 != 0) 169 return (NT_STATUS_OPEN_FAILED); 170 171 if (di.d_dc && (*netr_global_info.server != '\0')) { 172 (void) snprintf(server, sizeof (server), 173 "\\\\%s", di.d_dc); 174 if (strncasecmp(netr_global_info.server, 175 server, strlen(server)) != 0) 176 netr_invalidate_chain(); 177 } 178 179 if ((netr_global_info.flags & NETR_FLG_VALID) == 0 || 180 !smb_match_netlogon_seqnum()) { 181 status = netlogon_auth(di.d_dc, &netr_handle, 182 NETR_FLG_NULL); 183 184 if (status != 0) { 185 (void) netr_close(&netr_handle); 186 return (NT_STATUS_LOGON_FAILURE); 187 } 188 189 netr_global_info.flags |= NETR_FLG_VALID; 190 } 191 192 status = netr_server_samlogon(&netr_handle, 193 &netr_global_info, di.d_dc, user_info, token); 194 195 (void) netr_close(&netr_handle); 196 } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3); 197 198 if (retries >= 3) 199 status = NT_STATUS_LOGON_FAILURE; 200 201 return (status); 202 } 203 204 static uint32_t 205 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info, 206 netr_info_t *netr_info, smb_token_t *token) 207 { 208 char *username, *domain; 209 unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ]; 210 smb_sid_t *domsid; 211 uint32_t status; 212 char nbdomain[NETBIOS_NAME_SZ]; 213 214 domsid = (smb_sid_t *)info3->LogonDomainId; 215 216 token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId); 217 if (token->tkn_user.i_sid == NULL) 218 return (NT_STATUS_NO_MEMORY); 219 220 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid, 221 info3->PrimaryGroupId); 222 if (token->tkn_primary_grp.i_sid == NULL) 223 return (NT_STATUS_NO_MEMORY); 224 225 username = (info3->EffectiveName.str) 226 ? (char *)info3->EffectiveName.str : user_info->lg_e_username; 227 228 if (info3->LogonDomainName.str) { 229 domain = (char *)info3->LogonDomainName.str; 230 } else if (*user_info->lg_e_domain != '\0') { 231 domain = user_info->lg_e_domain; 232 } else { 233 (void) smb_getdomainname(nbdomain, sizeof (nbdomain)); 234 domain = nbdomain; 235 } 236 237 if (username) 238 token->tkn_account_name = strdup(username); 239 if (domain) 240 token->tkn_domain_name = strdup(domain); 241 242 if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL) 243 return (NT_STATUS_NO_MEMORY); 244 245 status = netr_setup_token_wingrps(info3, token); 246 if (status != NT_STATUS_SUCCESS) 247 return (status); 248 249 /* 250 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the 251 * session key obtained in the NETLOGON credential chain. 252 * An 8 byte session key is zero extended to 16 bytes. This 16 byte 253 * key is the key to the RC4 algorithm. The RC4 byte stream is 254 * exclusively ored with the 16 byte UserSessionKey to recover 255 * the the clear form. 256 */ 257 if ((token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL) 258 return (NT_STATUS_NO_MEMORY); 259 bzero(rc4key, SMBAUTH_SESSION_KEY_SZ); 260 bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len); 261 bcopy(info3->UserSessionKey.data, token->tkn_session_key, 262 SMBAUTH_SESSION_KEY_SZ); 263 rand_hash((unsigned char *)token->tkn_session_key, 264 SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ); 265 266 return (NT_STATUS_SUCCESS); 267 } 268 269 /* 270 * netr_server_samlogon 271 * 272 * NetrServerSamLogon RPC: interactive or network. It is assumed that 273 * we have already authenticated with the PDC. If everything works, 274 * we build a user info structure and return it, where the caller will 275 * probably build an access token. 276 * 277 * Returns an NT status. There are numerous possibilities here. 278 * For example: 279 * NT_STATUS_INVALID_INFO_CLASS 280 * NT_STATUS_INVALID_PARAMETER 281 * NT_STATUS_ACCESS_DENIED 282 * NT_STATUS_PASSWORD_MUST_CHANGE 283 * NT_STATUS_NO_SUCH_USER 284 * NT_STATUS_WRONG_PASSWORD 285 * NT_STATUS_LOGON_FAILURE 286 * NT_STATUS_ACCOUNT_RESTRICTION 287 * NT_STATUS_INVALID_LOGON_HOURS 288 * NT_STATUS_INVALID_WORKSTATION 289 * NT_STATUS_INTERNAL_ERROR 290 * NT_STATUS_PASSWORD_EXPIRED 291 * NT_STATUS_ACCOUNT_DISABLED 292 */ 293 uint32_t 294 netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info, 295 char *server, smb_logon_t *user_info, smb_token_t *token) 296 { 297 struct netr_SamLogon arg; 298 struct netr_authenticator auth; 299 struct netr_authenticator ret_auth; 300 struct netr_logon_info1 info1; 301 struct netr_logon_info2 info2; 302 struct netr_validation_info3 *info3; 303 ndr_heap_t *heap; 304 int opnum; 305 int rc, len; 306 uint32_t status; 307 308 bzero(&arg, sizeof (struct netr_SamLogon)); 309 opnum = NETR_OPNUM_SamLogon; 310 311 /* 312 * Should we get the server and hostname from netr_info? 313 */ 314 315 len = strlen(server) + 4; 316 arg.servername = ndr_rpc_malloc(netr_handle, len); 317 arg.hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ); 318 if (arg.servername == NULL || arg.hostname == NULL) { 319 ndr_rpc_release(netr_handle); 320 return (NT_STATUS_INTERNAL_ERROR); 321 } 322 323 (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 324 if (smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ) != 0) { 325 ndr_rpc_release(netr_handle); 326 return (NT_STATUS_INTERNAL_ERROR); 327 } 328 329 rc = netr_setup_authenticator(netr_info, &auth, &ret_auth); 330 if (rc != SMBAUTH_SUCCESS) { 331 ndr_rpc_release(netr_handle); 332 return (NT_STATUS_INTERNAL_ERROR); 333 } 334 335 arg.auth = &auth; 336 arg.ret_auth = &ret_auth; 337 arg.validation_level = NETR_VALIDATION_LEVEL3; 338 arg.logon_info.logon_level = user_info->lg_level; 339 arg.logon_info.switch_value = user_info->lg_level; 340 341 heap = ndr_rpc_get_heap(netr_handle); 342 343 switch (user_info->lg_level) { 344 case NETR_INTERACTIVE_LOGON: 345 netr_setup_identity(heap, user_info, &info1.identity); 346 netr_interactive_samlogon(netr_info, user_info, &info1); 347 arg.logon_info.ru.info1 = &info1; 348 break; 349 350 case NETR_NETWORK_LOGON: 351 if (user_info->lg_challenge_key.len < 8 || 352 user_info->lg_challenge_key.val == NULL) { 353 ndr_rpc_release(netr_handle); 354 return (NT_STATUS_INVALID_PARAMETER); 355 } 356 netr_setup_identity(heap, user_info, &info2.identity); 357 netr_network_samlogon(heap, netr_info, user_info, &info2); 358 arg.logon_info.ru.info2 = &info2; 359 break; 360 361 default: 362 ndr_rpc_release(netr_handle); 363 return (NT_STATUS_INVALID_PARAMETER); 364 } 365 366 rc = ndr_rpc_call(netr_handle, opnum, &arg); 367 if (rc != 0) { 368 bzero(netr_info, sizeof (netr_info_t)); 369 status = NT_STATUS_INVALID_PARAMETER; 370 } else if (arg.status != 0) { 371 status = NT_SC_VALUE(arg.status); 372 373 /* 374 * We need to validate the chain even though we have 375 * a non-zero status. If the status is ACCESS_DENIED 376 * this will trigger a new credential chain. However, 377 * a valid credential is returned with some status 378 * codes; for example, WRONG_PASSWORD. 379 */ 380 (void) netr_validate_chain(netr_info, arg.ret_auth); 381 } else { 382 status = netr_validate_chain(netr_info, arg.ret_auth); 383 if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) { 384 ndr_rpc_release(netr_handle); 385 return (status); 386 } 387 388 info3 = arg.ru.info3; 389 status = netr_setup_token(info3, user_info, netr_info, token); 390 } 391 392 ndr_rpc_release(netr_handle); 393 return (status); 394 } 395 396 /* 397 * netr_interactive_samlogon 398 * 399 * Set things up for an interactive SamLogon. Copy the NT and LM 400 * passwords to the logon structure and hash them with the session 401 * key. 402 */ 403 static void 404 netr_interactive_samlogon(netr_info_t *netr_info, smb_logon_t *user_info, 405 struct netr_logon_info1 *info1) 406 { 407 BYTE key[NETR_OWF_PASSWORD_SZ]; 408 409 (void) memcpy(&info1->lm_owf_password, 410 user_info->lg_lm_password.val, sizeof (netr_owf_password_t)); 411 412 (void) memcpy(&info1->nt_owf_password, 413 user_info->lg_nt_password.val, sizeof (netr_owf_password_t)); 414 415 (void) memset(key, 0, NETR_OWF_PASSWORD_SZ); 416 (void) memcpy(key, netr_info->session_key.key, 417 netr_info->session_key.len); 418 419 rand_hash((unsigned char *)&info1->lm_owf_password, 420 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ); 421 422 rand_hash((unsigned char *)&info1->nt_owf_password, 423 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ); 424 } 425 426 /* 427 * netr_network_samlogon 428 * 429 * Set things up for a network SamLogon. We provide a copy of the random 430 * challenge, that we sent to the client, to the domain controller. This 431 * is the key that the client will have used to encrypt the NT and LM 432 * passwords. Note that Windows 9x clients may not provide both passwords. 433 */ 434 /*ARGSUSED*/ 435 static void 436 netr_network_samlogon(ndr_heap_t *heap, netr_info_t *netr_info, 437 smb_logon_t *user_info, struct netr_logon_info2 *info2) 438 { 439 uint32_t len; 440 441 if (user_info->lg_challenge_key.len >= 8 && 442 user_info->lg_challenge_key.val != 0) { 443 bcopy(user_info->lg_challenge_key.val, 444 info2->lm_challenge.data, 8); 445 } else { 446 bzero(info2->lm_challenge.data, 8); 447 } 448 449 if ((len = user_info->lg_nt_password.len) != 0) { 450 ndr_heap_mkvcb(heap, user_info->lg_nt_password.val, len, 451 (ndr_vcbuf_t *)&info2->nt_response); 452 } else { 453 bzero(&info2->nt_response, sizeof (netr_vcbuf_t)); 454 } 455 456 if ((len = user_info->lg_lm_password.len) != 0) { 457 ndr_heap_mkvcb(heap, user_info->lg_lm_password.val, len, 458 (ndr_vcbuf_t *)&info2->lm_response); 459 } else { 460 bzero(&info2->lm_response, sizeof (netr_vcbuf_t)); 461 } 462 } 463 464 /* 465 * netr_setup_authenticator 466 * 467 * Set up the request and return authenticators. A new credential is 468 * generated from the session key, the current client credential and 469 * the current time, i.e. 470 * 471 * NewCredential = Cred(SessionKey, OldCredential, time); 472 * 473 * The timestamp, which is used as a random seed, is stored in both 474 * the request and return authenticators. 475 * 476 * If any difficulties occur using the cryptographic framework, the 477 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 478 * returned. 479 */ 480 int 481 netr_setup_authenticator(netr_info_t *netr_info, 482 struct netr_authenticator *auth, struct netr_authenticator *ret_auth) 483 { 484 bzero(auth, sizeof (struct netr_authenticator)); 485 486 netr_info->timestamp = time(0); 487 auth->timestamp = netr_info->timestamp; 488 489 if (netr_gen_credentials(netr_info->session_key.key, 490 &netr_info->client_credential, 491 netr_info->timestamp, 492 (netr_cred_t *)&auth->credential) != SMBAUTH_SUCCESS) 493 return (SMBAUTH_FAILURE); 494 495 if (ret_auth) { 496 bzero(ret_auth, sizeof (struct netr_authenticator)); 497 ret_auth->timestamp = netr_info->timestamp; 498 } 499 500 return (SMBAUTH_SUCCESS); 501 } 502 503 /* 504 * Validate the returned credentials and update the credential chain. 505 * The server returns an updated client credential rather than a new 506 * server credential. The server uses (timestamp + 1) when generating 507 * the credential. 508 * 509 * Generate the new seed for the credential chain. The new seed is 510 * formed by adding (timestamp + 1) to the current client credential. 511 * The only quirk is the uint32_t style addition. 512 * 513 * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a 514 * NULL pointer. The Authenticator field of the SamLogon response packet 515 * sent by the Samba 3 PDC always return NULL pointer if the received 516 * SamLogon request is not immediately followed by the ServerReqChallenge 517 * and ServerAuthenticate2 requests. 518 * 519 * Returns NT_STATUS_SUCCESS if the server returned a valid credential. 520 * Otherwise we retirm NT_STATUS_UNSUCCESSFUL. 521 */ 522 uint32_t 523 netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth) 524 { 525 netr_cred_t cred; 526 uint32_t result = NT_STATUS_SUCCESS; 527 uint32_t *dwp; 528 529 ++netr_info->timestamp; 530 531 if (netr_gen_credentials(netr_info->session_key.key, 532 &netr_info->client_credential, 533 netr_info->timestamp, &cred) != SMBAUTH_SUCCESS) 534 return (NT_STATUS_INTERNAL_ERROR); 535 536 if (&auth->credential == 0) { 537 /* 538 * If the validation fails, destroy the credential chain. 539 * This should trigger a new authentication chain. 540 */ 541 bzero(netr_info, sizeof (netr_info_t)); 542 return (NT_STATUS_INSUFFICIENT_LOGON_INFO); 543 } 544 545 result = memcmp(&cred, &auth->credential, sizeof (netr_cred_t)); 546 if (result != 0) { 547 /* 548 * If the validation fails, destroy the credential chain. 549 * This should trigger a new authentication chain. 550 */ 551 bzero(netr_info, sizeof (netr_info_t)); 552 result = NT_STATUS_UNSUCCESSFUL; 553 } else { 554 /* 555 * Otherwise generate the next step in the chain. 556 */ 557 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 558 dwp = (uint32_t *)&netr_info->client_credential; 559 dwp[0] += netr_info->timestamp; 560 561 netr_info->flags |= NETR_FLG_VALID; 562 } 563 564 return (result); 565 } 566 567 /* 568 * netr_invalidate_chain 569 * 570 * Mark the credential chain as invalid so that it will be recreated 571 * on the next attempt. 572 */ 573 static void 574 netr_invalidate_chain(void) 575 { 576 netr_global_info.flags &= ~NETR_FLG_VALID; 577 } 578 579 /* 580 * netr_setup_identity 581 * 582 * Set up the client identity information. All of this information is 583 * specifically related to the client user and workstation attempting 584 * to access this system. It may not be in our primary domain. 585 * 586 * I don't know what logon_id is, it seems to be a unique identifier. 587 * Increment it before each use. 588 */ 589 static void 590 netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info, 591 netr_logon_id_t *identity) 592 { 593 static mutex_t logon_id_mutex; 594 static uint32_t logon_id; 595 596 (void) mutex_lock(&logon_id_mutex); 597 598 if (logon_id == 0) 599 logon_id = 0xDCD0; 600 601 ++logon_id; 602 user_info->lg_logon_id = logon_id; 603 604 (void) mutex_unlock(&logon_id_mutex); 605 606 identity->parameter_control = 0; 607 identity->logon_id.LowPart = logon_id; 608 identity->logon_id.HighPart = 0; 609 610 ndr_heap_mkvcs(heap, user_info->lg_domain, 611 (ndr_vcstr_t *)&identity->domain_name); 612 613 ndr_heap_mkvcs(heap, user_info->lg_username, 614 (ndr_vcstr_t *)&identity->username); 615 616 /* 617 * Some systems prefix the client workstation name with \\. 618 * It doesn't seem to make any difference whether it's there 619 * or not. 620 */ 621 ndr_heap_mkvcs(heap, user_info->lg_workstation, 622 (ndr_vcstr_t *)&identity->workstation); 623 } 624 625 /* 626 * Sets up domain, local and well-known group membership for the given 627 * token. Two assumptions have been made here: 628 * 629 * a) token already contains a valid user SID so that group 630 * memberships can be established 631 * 632 * b) token belongs to a domain user 633 */ 634 static uint32_t 635 netr_setup_token_wingrps(struct netr_validation_info3 *info3, 636 smb_token_t *token) 637 { 638 smb_ids_t tkn_grps; 639 uint32_t status; 640 641 tkn_grps.i_cnt = 0; 642 tkn_grps.i_ids = NULL; 643 644 status = netr_setup_domain_groups(info3, &tkn_grps); 645 if (status != NT_STATUS_SUCCESS) { 646 smb_ids_free(&tkn_grps); 647 return (status); 648 } 649 650 status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps); 651 if (status != NT_STATUS_SUCCESS) { 652 smb_ids_free(&tkn_grps); 653 return (status); 654 } 655 656 if (netr_isadmin(info3)) 657 token->tkn_flags |= SMB_ATF_ADMIN; 658 659 status = smb_wka_token_groups(token->tkn_flags, &tkn_grps); 660 if (status == NT_STATUS_SUCCESS) 661 token->tkn_win_grps = tkn_grps; 662 else 663 smb_ids_free(&tkn_grps); 664 665 return (status); 666 } 667 668 /* 669 * Converts groups information in the returned structure by domain controller 670 * (info3) to an internal representation (gids) 671 */ 672 static uint32_t 673 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids) 674 { 675 smb_sid_t *domain_sid; 676 smb_id_t *ids; 677 int i, total_cnt; 678 679 if ((i = info3->GroupCount) == 0) 680 i++; 681 i += info3->SidCount; 682 683 total_cnt = gids->i_cnt + i; 684 685 gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t)); 686 if (gids->i_ids == NULL) 687 return (NT_STATUS_NO_MEMORY); 688 689 domain_sid = (smb_sid_t *)info3->LogonDomainId; 690 691 ids = gids->i_ids + gids->i_cnt; 692 for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) { 693 ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid); 694 if (ids->i_sid == NULL) 695 return (NT_STATUS_NO_MEMORY); 696 697 ids->i_attrs = info3->GroupIds[i].attributes; 698 } 699 700 if (info3->GroupCount == 0) { 701 /* 702 * if there's no global group should add the primary group. 703 */ 704 ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId); 705 if (ids->i_sid == NULL) 706 return (NT_STATUS_NO_MEMORY); 707 708 ids->i_attrs = 0x7; 709 gids->i_cnt++; 710 ids++; 711 } 712 713 /* Add the extra SIDs */ 714 for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) { 715 ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid); 716 if (ids->i_sid == NULL) 717 return (NT_STATUS_NO_MEMORY); 718 719 ids->i_attrs = info3->ExtraSids[i].attributes; 720 } 721 722 return (NT_STATUS_SUCCESS); 723 } 724 725 /* 726 * Determines if the given user is the domain Administrator or a 727 * member of Domain Admins 728 */ 729 static boolean_t 730 netr_isadmin(struct netr_validation_info3 *info3) 731 { 732 smb_domain_t di; 733 int i; 734 735 if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di)) 736 return (B_FALSE); 737 738 if (di.di_type != SMB_DOMAIN_PRIMARY) 739 return (B_FALSE); 740 741 if ((info3->UserId == DOMAIN_USER_RID_ADMIN) || 742 (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS)) 743 return (B_TRUE); 744 745 for (i = 0; i < info3->GroupCount; i++) 746 if (info3->GroupIds[i].rid == DOMAIN_GROUP_RID_ADMINS) 747 return (B_TRUE); 748 749 return (B_FALSE); 750 } 751