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