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 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[NETBIOS_NAME_SZ * 2]; 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_dc, di.d_primary.di_nbname, &netr_handle) 247 != 0) 248 return (NT_STATUS_OPEN_FAILED); 249 250 if (di.d_dc && (*netr_global_info.server != '\0')) { 251 (void) snprintf(server, sizeof (server), 252 "\\\\%s", di.d_dc); 253 if (strncasecmp(netr_global_info.server, 254 server, strlen(server)) != 0) 255 netr_invalidate_chain(); 256 } 257 258 if ((netr_global_info.flags & NETR_FLG_VALID) == 0 || 259 !smb_match_netlogon_seqnum()) { 260 status = netlogon_auth(di.d_dc, &netr_handle, 261 NETR_FLG_NULL); 262 263 if (status != 0) { 264 (void) netr_close(&netr_handle); 265 return (NT_STATUS_LOGON_FAILURE); 266 } 267 268 netr_global_info.flags |= NETR_FLG_VALID; 269 } 270 271 status = netr_server_samlogon(&netr_handle, 272 &netr_global_info, di.d_dc, user_info, token); 273 274 (void) netr_close(&netr_handle); 275 } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3); 276 277 if (retries >= 3) 278 status = NT_STATUS_LOGON_FAILURE; 279 280 return (status); 281 } 282 283 static uint32_t 284 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info, 285 netr_info_t *netr_info, smb_token_t *token) 286 { 287 char *username, *domain; 288 unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ]; 289 smb_sid_t *domsid; 290 uint32_t status; 291 char nbdomain[NETBIOS_NAME_SZ]; 292 293 domsid = (smb_sid_t *)info3->LogonDomainId; 294 295 token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId); 296 if (token->tkn_user.i_sid == NULL) 297 return (NT_STATUS_NO_MEMORY); 298 299 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid, 300 info3->PrimaryGroupId); 301 if (token->tkn_primary_grp.i_sid == NULL) 302 return (NT_STATUS_NO_MEMORY); 303 304 username = (info3->EffectiveName.str) 305 ? (char *)info3->EffectiveName.str : user_info->lg_e_username; 306 307 if (info3->LogonDomainName.str) { 308 domain = (char *)info3->LogonDomainName.str; 309 } else if (*user_info->lg_e_domain != '\0') { 310 domain = user_info->lg_e_domain; 311 } else { 312 (void) smb_getdomainname(nbdomain, sizeof (nbdomain)); 313 domain = nbdomain; 314 } 315 316 if (username) 317 token->tkn_account_name = strdup(username); 318 if (domain) 319 token->tkn_domain_name = strdup(domain); 320 321 if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL) 322 return (NT_STATUS_NO_MEMORY); 323 324 status = netr_setup_token_wingrps(info3, token); 325 if (status != NT_STATUS_SUCCESS) 326 return (status); 327 328 /* 329 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the 330 * session key obtained in the NETLOGON credential chain. 331 * An 8 byte session key is zero extended to 16 bytes. This 16 byte 332 * key is the key to the RC4 algorithm. The RC4 byte stream is 333 * exclusively ored with the 16 byte UserSessionKey to recover 334 * the the clear form. 335 */ 336 if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL) 337 return (NT_STATUS_NO_MEMORY); 338 token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ; 339 bzero(rc4key, SMBAUTH_SESSION_KEY_SZ); 340 bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len); 341 bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val, 342 SMBAUTH_SESSION_KEY_SZ); 343 rand_hash((unsigned char *)token->tkn_ssnkey.val, 344 SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ); 345 346 return (NT_STATUS_SUCCESS); 347 } 348 349 /* 350 * netr_server_samlogon 351 * 352 * NetrServerSamLogon RPC: interactive or network. It is assumed that 353 * we have already authenticated with the PDC. If everything works, 354 * we build a user info structure and return it, where the caller will 355 * probably build an access token. 356 * 357 * Returns an NT status. There are numerous possibilities here. 358 * For example: 359 * NT_STATUS_INVALID_INFO_CLASS 360 * NT_STATUS_INVALID_PARAMETER 361 * NT_STATUS_ACCESS_DENIED 362 * NT_STATUS_PASSWORD_MUST_CHANGE 363 * NT_STATUS_NO_SUCH_USER 364 * NT_STATUS_WRONG_PASSWORD 365 * NT_STATUS_LOGON_FAILURE 366 * NT_STATUS_ACCOUNT_RESTRICTION 367 * NT_STATUS_INVALID_LOGON_HOURS 368 * NT_STATUS_INVALID_WORKSTATION 369 * NT_STATUS_INTERNAL_ERROR 370 * NT_STATUS_PASSWORD_EXPIRED 371 * NT_STATUS_ACCOUNT_DISABLED 372 */ 373 uint32_t 374 netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info, 375 char *server, smb_logon_t *user_info, smb_token_t *token) 376 { 377 struct netr_SamLogon arg; 378 struct netr_authenticator auth; 379 struct netr_authenticator ret_auth; 380 struct netr_logon_info1 info1; 381 struct netr_logon_info2 info2; 382 struct netr_validation_info3 *info3; 383 ndr_heap_t *heap; 384 int opnum; 385 int rc, len; 386 uint32_t status; 387 388 bzero(&arg, sizeof (struct netr_SamLogon)); 389 opnum = NETR_OPNUM_SamLogon; 390 391 /* 392 * Should we get the server and hostname from netr_info? 393 */ 394 395 len = strlen(server) + 4; 396 arg.servername = ndr_rpc_malloc(netr_handle, len); 397 arg.hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ); 398 if (arg.servername == NULL || arg.hostname == NULL) { 399 ndr_rpc_release(netr_handle); 400 return (NT_STATUS_INTERNAL_ERROR); 401 } 402 403 (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 404 if (smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ) != 0) { 405 ndr_rpc_release(netr_handle); 406 return (NT_STATUS_INTERNAL_ERROR); 407 } 408 409 rc = netr_setup_authenticator(netr_info, &auth, &ret_auth); 410 if (rc != SMBAUTH_SUCCESS) { 411 ndr_rpc_release(netr_handle); 412 return (NT_STATUS_INTERNAL_ERROR); 413 } 414 415 arg.auth = &auth; 416 arg.ret_auth = &ret_auth; 417 arg.validation_level = NETR_VALIDATION_LEVEL3; 418 arg.logon_info.logon_level = user_info->lg_level; 419 arg.logon_info.switch_value = user_info->lg_level; 420 421 heap = ndr_rpc_get_heap(netr_handle); 422 423 switch (user_info->lg_level) { 424 case NETR_INTERACTIVE_LOGON: 425 netr_setup_identity(heap, user_info, &info1.identity); 426 netr_interactive_samlogon(netr_info, user_info, &info1); 427 arg.logon_info.ru.info1 = &info1; 428 break; 429 430 case NETR_NETWORK_LOGON: 431 if (user_info->lg_challenge_key.len < 8 || 432 user_info->lg_challenge_key.val == NULL) { 433 ndr_rpc_release(netr_handle); 434 return (NT_STATUS_INVALID_PARAMETER); 435 } 436 netr_setup_identity(heap, user_info, &info2.identity); 437 netr_network_samlogon(heap, netr_info, user_info, &info2); 438 arg.logon_info.ru.info2 = &info2; 439 break; 440 441 default: 442 ndr_rpc_release(netr_handle); 443 return (NT_STATUS_INVALID_PARAMETER); 444 } 445 446 rc = ndr_rpc_call(netr_handle, opnum, &arg); 447 if (rc != 0) { 448 bzero(netr_info, sizeof (netr_info_t)); 449 status = NT_STATUS_INVALID_PARAMETER; 450 } else if (arg.status != 0) { 451 status = NT_SC_VALUE(arg.status); 452 453 /* 454 * We need to validate the chain even though we have 455 * a non-zero status. If the status is ACCESS_DENIED 456 * this will trigger a new credential chain. However, 457 * a valid credential is returned with some status 458 * codes; for example, WRONG_PASSWORD. 459 */ 460 (void) netr_validate_chain(netr_info, arg.ret_auth); 461 } else { 462 status = netr_validate_chain(netr_info, arg.ret_auth); 463 if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) { 464 ndr_rpc_release(netr_handle); 465 return (status); 466 } 467 468 info3 = arg.ru.info3; 469 status = netr_setup_token(info3, user_info, netr_info, token); 470 } 471 472 ndr_rpc_release(netr_handle); 473 return (status); 474 } 475 476 /* 477 * netr_interactive_samlogon 478 * 479 * Set things up for an interactive SamLogon. Copy the NT and LM 480 * passwords to the logon structure and hash them with the session 481 * key. 482 */ 483 static void 484 netr_interactive_samlogon(netr_info_t *netr_info, smb_logon_t *user_info, 485 struct netr_logon_info1 *info1) 486 { 487 BYTE key[NETR_OWF_PASSWORD_SZ]; 488 489 (void) memcpy(&info1->lm_owf_password, 490 user_info->lg_lm_password.val, sizeof (netr_owf_password_t)); 491 492 (void) memcpy(&info1->nt_owf_password, 493 user_info->lg_nt_password.val, sizeof (netr_owf_password_t)); 494 495 (void) memset(key, 0, NETR_OWF_PASSWORD_SZ); 496 (void) memcpy(key, netr_info->session_key.key, 497 netr_info->session_key.len); 498 499 rand_hash((unsigned char *)&info1->lm_owf_password, 500 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ); 501 502 rand_hash((unsigned char *)&info1->nt_owf_password, 503 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ); 504 } 505 506 /* 507 * netr_network_samlogon 508 * 509 * Set things up for a network SamLogon. We provide a copy of the random 510 * challenge, that we sent to the client, to the domain controller. This 511 * is the key that the client will have used to encrypt the NT and LM 512 * passwords. Note that Windows 9x clients may not provide both passwords. 513 */ 514 /*ARGSUSED*/ 515 static void 516 netr_network_samlogon(ndr_heap_t *heap, netr_info_t *netr_info, 517 smb_logon_t *user_info, struct netr_logon_info2 *info2) 518 { 519 uint32_t len; 520 521 if (user_info->lg_challenge_key.len >= 8 && 522 user_info->lg_challenge_key.val != 0) { 523 bcopy(user_info->lg_challenge_key.val, 524 info2->lm_challenge.data, 8); 525 } else { 526 bzero(info2->lm_challenge.data, 8); 527 } 528 529 if ((len = user_info->lg_nt_password.len) != 0) { 530 ndr_heap_mkvcb(heap, user_info->lg_nt_password.val, len, 531 (ndr_vcbuf_t *)&info2->nt_response); 532 } else { 533 bzero(&info2->nt_response, sizeof (netr_vcbuf_t)); 534 } 535 536 if ((len = user_info->lg_lm_password.len) != 0) { 537 ndr_heap_mkvcb(heap, user_info->lg_lm_password.val, len, 538 (ndr_vcbuf_t *)&info2->lm_response); 539 } else { 540 bzero(&info2->lm_response, sizeof (netr_vcbuf_t)); 541 } 542 } 543 544 /* 545 * netr_setup_authenticator 546 * 547 * Set up the request and return authenticators. A new credential is 548 * generated from the session key, the current client credential and 549 * the current time, i.e. 550 * 551 * NewCredential = Cred(SessionKey, OldCredential, time); 552 * 553 * The timestamp, which is used as a random seed, is stored in both 554 * the request and return authenticators. 555 * 556 * If any difficulties occur using the cryptographic framework, the 557 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 558 * returned. 559 */ 560 int 561 netr_setup_authenticator(netr_info_t *netr_info, 562 struct netr_authenticator *auth, struct netr_authenticator *ret_auth) 563 { 564 bzero(auth, sizeof (struct netr_authenticator)); 565 566 netr_info->timestamp = time(0); 567 auth->timestamp = netr_info->timestamp; 568 569 if (netr_gen_credentials(netr_info->session_key.key, 570 &netr_info->client_credential, 571 netr_info->timestamp, 572 (netr_cred_t *)&auth->credential) != SMBAUTH_SUCCESS) 573 return (SMBAUTH_FAILURE); 574 575 if (ret_auth) { 576 bzero(ret_auth, sizeof (struct netr_authenticator)); 577 ret_auth->timestamp = netr_info->timestamp; 578 } 579 580 return (SMBAUTH_SUCCESS); 581 } 582 583 /* 584 * Validate the returned credentials and update the credential chain. 585 * The server returns an updated client credential rather than a new 586 * server credential. The server uses (timestamp + 1) when generating 587 * the credential. 588 * 589 * Generate the new seed for the credential chain. The new seed is 590 * formed by adding (timestamp + 1) to the current client credential. 591 * The only quirk is the uint32_t style addition. 592 * 593 * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a 594 * NULL pointer. The Authenticator field of the SamLogon response packet 595 * sent by the Samba 3 PDC always return NULL pointer if the received 596 * SamLogon request is not immediately followed by the ServerReqChallenge 597 * and ServerAuthenticate2 requests. 598 * 599 * Returns NT_STATUS_SUCCESS if the server returned a valid credential. 600 * Otherwise we retirm NT_STATUS_UNSUCCESSFUL. 601 */ 602 uint32_t 603 netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth) 604 { 605 netr_cred_t cred; 606 uint32_t result = NT_STATUS_SUCCESS; 607 uint32_t *dwp; 608 609 ++netr_info->timestamp; 610 611 if (netr_gen_credentials(netr_info->session_key.key, 612 &netr_info->client_credential, 613 netr_info->timestamp, &cred) != SMBAUTH_SUCCESS) 614 return (NT_STATUS_INTERNAL_ERROR); 615 616 if (&auth->credential == 0) { 617 /* 618 * If the validation fails, destroy the credential chain. 619 * This should trigger a new authentication chain. 620 */ 621 bzero(netr_info, sizeof (netr_info_t)); 622 return (NT_STATUS_INSUFFICIENT_LOGON_INFO); 623 } 624 625 result = memcmp(&cred, &auth->credential, sizeof (netr_cred_t)); 626 if (result != 0) { 627 /* 628 * If the validation fails, destroy the credential chain. 629 * This should trigger a new authentication chain. 630 */ 631 bzero(netr_info, sizeof (netr_info_t)); 632 result = NT_STATUS_UNSUCCESSFUL; 633 } else { 634 /* 635 * Otherwise generate the next step in the chain. 636 */ 637 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 638 dwp = (uint32_t *)&netr_info->client_credential; 639 dwp[0] += netr_info->timestamp; 640 641 netr_info->flags |= NETR_FLG_VALID; 642 } 643 644 return (result); 645 } 646 647 /* 648 * netr_invalidate_chain 649 * 650 * Mark the credential chain as invalid so that it will be recreated 651 * on the next attempt. 652 */ 653 static void 654 netr_invalidate_chain(void) 655 { 656 netr_global_info.flags &= ~NETR_FLG_VALID; 657 } 658 659 /* 660 * netr_setup_identity 661 * 662 * Set up the client identity information. All of this information is 663 * specifically related to the client user and workstation attempting 664 * to access this system. It may not be in our primary domain. 665 * 666 * I don't know what logon_id is, it seems to be a unique identifier. 667 * Increment it before each use. 668 */ 669 static void 670 netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info, 671 netr_logon_id_t *identity) 672 { 673 static mutex_t logon_id_mutex; 674 static uint32_t logon_id; 675 676 (void) mutex_lock(&logon_id_mutex); 677 678 if (logon_id == 0) 679 logon_id = 0xDCD0; 680 681 ++logon_id; 682 user_info->lg_logon_id = logon_id; 683 684 (void) mutex_unlock(&logon_id_mutex); 685 686 /* 687 * [MS-APDS] 3.1.5.2 "NTLM Network Logon" says to set 688 * ParameterControl to the 'E' + 'K' bits. Those are: 689 * (1 << 5) | (1 << 11), a.k.a 690 */ 691 identity->parameter_control = 692 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | 693 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT; 694 identity->logon_id.LowPart = logon_id; 695 identity->logon_id.HighPart = 0; 696 697 ndr_heap_mkvcs(heap, user_info->lg_domain, 698 (ndr_vcstr_t *)&identity->domain_name); 699 700 ndr_heap_mkvcs(heap, user_info->lg_username, 701 (ndr_vcstr_t *)&identity->username); 702 703 /* 704 * Some systems prefix the client workstation name with \\. 705 * It doesn't seem to make any difference whether it's there 706 * or not. 707 */ 708 ndr_heap_mkvcs(heap, user_info->lg_workstation, 709 (ndr_vcstr_t *)&identity->workstation); 710 } 711 712 /* 713 * Sets up domain, local and well-known group membership for the given 714 * token. Two assumptions have been made here: 715 * 716 * a) token already contains a valid user SID so that group 717 * memberships can be established 718 * 719 * b) token belongs to a domain user 720 */ 721 static uint32_t 722 netr_setup_token_wingrps(struct netr_validation_info3 *info3, 723 smb_token_t *token) 724 { 725 smb_ids_t tkn_grps; 726 uint32_t status; 727 728 tkn_grps.i_cnt = 0; 729 tkn_grps.i_ids = NULL; 730 731 status = netr_setup_domain_groups(info3, &tkn_grps); 732 if (status != NT_STATUS_SUCCESS) { 733 smb_ids_free(&tkn_grps); 734 return (status); 735 } 736 737 status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps); 738 if (status != NT_STATUS_SUCCESS) { 739 smb_ids_free(&tkn_grps); 740 return (status); 741 } 742 743 if (netr_isadmin(info3)) 744 token->tkn_flags |= SMB_ATF_ADMIN; 745 746 status = smb_wka_token_groups(token->tkn_flags, &tkn_grps); 747 if (status == NT_STATUS_SUCCESS) 748 token->tkn_win_grps = tkn_grps; 749 else 750 smb_ids_free(&tkn_grps); 751 752 return (status); 753 } 754 755 /* 756 * Converts groups information in the returned structure by domain controller 757 * (info3) to an internal representation (gids) 758 */ 759 static uint32_t 760 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids) 761 { 762 smb_sid_t *domain_sid; 763 smb_id_t *ids; 764 int i, total_cnt; 765 766 if ((i = info3->GroupCount) == 0) 767 i++; 768 i += info3->SidCount; 769 770 total_cnt = gids->i_cnt + i; 771 772 gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t)); 773 if (gids->i_ids == NULL) 774 return (NT_STATUS_NO_MEMORY); 775 776 domain_sid = (smb_sid_t *)info3->LogonDomainId; 777 778 ids = gids->i_ids + gids->i_cnt; 779 for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) { 780 ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid); 781 if (ids->i_sid == NULL) 782 return (NT_STATUS_NO_MEMORY); 783 784 ids->i_attrs = info3->GroupIds[i].attributes; 785 } 786 787 if (info3->GroupCount == 0) { 788 /* 789 * if there's no global group should add the primary group. 790 */ 791 ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId); 792 if (ids->i_sid == NULL) 793 return (NT_STATUS_NO_MEMORY); 794 795 ids->i_attrs = 0x7; 796 gids->i_cnt++; 797 ids++; 798 } 799 800 /* Add the extra SIDs */ 801 for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) { 802 ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid); 803 if (ids->i_sid == NULL) 804 return (NT_STATUS_NO_MEMORY); 805 806 ids->i_attrs = info3->ExtraSids[i].attributes; 807 } 808 809 return (NT_STATUS_SUCCESS); 810 } 811 812 /* 813 * Determines if the given user is the domain Administrator or a 814 * member of Domain Admins 815 */ 816 static boolean_t 817 netr_isadmin(struct netr_validation_info3 *info3) 818 { 819 smb_domain_t di; 820 int i; 821 822 if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di)) 823 return (B_FALSE); 824 825 if (di.di_type != SMB_DOMAIN_PRIMARY) 826 return (B_FALSE); 827 828 if ((info3->UserId == DOMAIN_USER_RID_ADMIN) || 829 (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS)) 830 return (B_TRUE); 831 832 for (i = 0; i < info3->GroupCount; i++) 833 if (info3->GroupIds[i].rid == DOMAIN_GROUP_RID_ADMINS) 834 return (B_TRUE); 835 836 return (B_FALSE); 837 } 838