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