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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * NETR challenge/response client functions. 28 * 29 * NT_STATUS_INVALID_PARAMETER 30 * NT_STATUS_NO_TRUST_SAM_ACCOUNT 31 * NT_STATUS_ACCESS_DENIED 32 */ 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <strings.h> 37 #include <unistd.h> 38 #include <ctype.h> 39 #include <security/cryptoki.h> 40 #include <security/pkcs11.h> 41 42 #include <smbsrv/libsmb.h> 43 #include <smbsrv/libsmbrdr.h> 44 #include <smbsrv/libsmbns.h> 45 #include <smbsrv/libmlsvc.h> 46 #include <smbsrv/ndl/netlogon.ndl> 47 #include <smbsrv/ntstatus.h> 48 #include <smbsrv/smbinfo.h> 49 #include <smbsrv/netrauth.h> 50 51 #define NETR_SESSKEY_ZEROBUF_SZ 4 52 /* The DES algorithm uses a 56-bit encryption key. */ 53 #define NETR_DESKEY_LEN 7 54 55 int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *, 56 struct netr_authenticator *); 57 DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *); 58 59 static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *); 60 static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *); 61 static int netr_gen_password(BYTE *, BYTE *, BYTE *); 62 63 /* 64 * Shared with netr_logon.c 65 */ 66 netr_info_t netr_global_info; 67 68 /* 69 * netlogon_auth 70 * 71 * This is the core of the NETLOGON authentication protocol. 72 * Do the challenge response authentication. 73 * 74 * Prior to calling this function, an anonymous session to the NETLOGON 75 * pipe on a domain controller(server) should have already been opened. 76 * 77 * Upon a successful NETLOGON credential chain establishment, the 78 * netlogon sequence number will be set to match the kpasswd sequence 79 * number. 80 * 81 */ 82 DWORD 83 netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags) 84 { 85 netr_info_t *netr_info; 86 int rc; 87 DWORD leout_rc[2]; 88 89 netr_info = &netr_global_info; 90 bzero(netr_info, sizeof (netr_info_t)); 91 92 netr_info->flags |= flags; 93 94 rc = smb_getnetbiosname(netr_info->hostname, NETBIOS_NAME_SZ); 95 if (rc != 0) 96 return (NT_STATUS_UNSUCCESSFUL); 97 98 (void) snprintf(netr_info->server, sizeof (netr_info->server), 99 "\\\\%s", server); 100 101 LE_OUT32(&leout_rc[0], random()); 102 LE_OUT32(&leout_rc[1], random()); 103 (void) memcpy(&netr_info->client_challenge, leout_rc, 104 sizeof (struct netr_credential)); 105 106 if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) { 107 rc = netr_server_authenticate2(netr_handle, netr_info); 108 if (rc == 0) { 109 smb_update_netlogon_seqnum(); 110 netr_info->flags |= NETR_FLG_VALID; 111 112 } 113 } 114 115 return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS); 116 } 117 118 /* 119 * netr_open 120 * 121 * Open an anonymous session to the NETLOGON pipe on a domain 122 * controller and bind to the NETR RPC interface. We store the 123 * remote server's native OS type - we may need it due to 124 * differences between versions of Windows. 125 */ 126 int 127 netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle) 128 { 129 char *user = smbrdr_ipc_get_user(); 130 131 if (ndr_rpc_bind(netr_handle, server, domain, user, "NETR") < 0) 132 return (-1); 133 134 return (0); 135 } 136 137 /* 138 * netr_close 139 * 140 * Close a NETLOGON pipe and free the RPC context. 141 */ 142 int 143 netr_close(mlsvc_handle_t *netr_handle) 144 { 145 ndr_rpc_unbind(netr_handle); 146 return (0); 147 } 148 149 /* 150 * netr_server_req_challenge 151 */ 152 static int 153 netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 154 { 155 struct netr_ServerReqChallenge arg; 156 int opnum; 157 158 bzero(&arg, sizeof (struct netr_ServerReqChallenge)); 159 opnum = NETR_OPNUM_ServerReqChallenge; 160 161 arg.servername = (unsigned char *)netr_info->server; 162 arg.hostname = (unsigned char *)netr_info->hostname; 163 164 (void) memcpy(&arg.client_challenge, &netr_info->client_challenge, 165 sizeof (struct netr_credential)); 166 167 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0) 168 return (-1); 169 170 if (arg.status != 0) { 171 ndr_rpc_status(netr_handle, opnum, arg.status); 172 ndr_rpc_release(netr_handle); 173 return (-1); 174 } 175 176 (void) memcpy(&netr_info->server_challenge, &arg.server_challenge, 177 sizeof (struct netr_credential)); 178 179 ndr_rpc_release(netr_handle); 180 return (0); 181 } 182 183 /* 184 * netr_server_authenticate2 185 */ 186 static int 187 netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 188 { 189 struct netr_ServerAuthenticate2 arg; 190 int opnum; 191 int rc; 192 char account_name[NETBIOS_NAME_SZ * 2]; 193 194 bzero(&arg, sizeof (struct netr_ServerAuthenticate2)); 195 opnum = NETR_OPNUM_ServerAuthenticate2; 196 197 (void) snprintf(account_name, sizeof (account_name), "%s$", 198 netr_info->hostname); 199 200 smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n", 201 netr_info->server, account_name, netr_info->hostname); 202 203 arg.servername = (unsigned char *)netr_info->server; 204 arg.account_name = (unsigned char *)account_name; 205 arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 206 arg.hostname = (unsigned char *)netr_info->hostname; 207 arg.negotiate_flags = NETR_NEGOTIATE_BASE_FLAGS; 208 209 if (ndr_rpc_server_os(netr_handle) != NATIVE_OS_WINNT) { 210 arg.negotiate_flags |= NETR_NEGOTIATE_STRONGKEY_FLAG; 211 if (netr_gen_skey128(netr_info) != SMBAUTH_SUCCESS) 212 return (-1); 213 } else { 214 if (netr_gen_skey64(netr_info) != SMBAUTH_SUCCESS) 215 return (-1); 216 } 217 218 if (netr_gen_credentials(netr_info->session_key.key, 219 &netr_info->client_challenge, 0, 220 &netr_info->client_credential) != SMBAUTH_SUCCESS) { 221 return (-1); 222 } 223 224 if (netr_gen_credentials(netr_info->session_key.key, 225 &netr_info->server_challenge, 0, 226 &netr_info->server_credential) != SMBAUTH_SUCCESS) { 227 return (-1); 228 } 229 230 (void) memcpy(&arg.client_credential, &netr_info->client_credential, 231 sizeof (struct netr_credential)); 232 233 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0) 234 return (-1); 235 236 if (arg.status != 0) { 237 ndr_rpc_status(netr_handle, opnum, arg.status); 238 ndr_rpc_release(netr_handle); 239 return (-1); 240 } 241 242 rc = memcmp(&netr_info->server_credential, &arg.server_credential, 243 sizeof (struct netr_credential)); 244 245 ndr_rpc_release(netr_handle); 246 return (rc); 247 } 248 249 /* 250 * netr_gen_skey128 251 * 252 * Generate a 128-bit session key from the client and server challenges. 253 * See "Session-Key Computation" section of MS-NRPC document. 254 */ 255 int 256 netr_gen_skey128(netr_info_t *netr_info) 257 { 258 unsigned char ntlmhash[SMBAUTH_HASH_SZ]; 259 int rc = SMBAUTH_FAILURE; 260 CK_RV rv; 261 CK_MECHANISM mechanism; 262 CK_SESSION_HANDLE hSession; 263 CK_ULONG diglen = MD_DIGEST_LEN; 264 unsigned char md5digest[MD_DIGEST_LEN]; 265 unsigned char zerobuf[NETR_SESSKEY_ZEROBUF_SZ]; 266 267 bzero(ntlmhash, SMBAUTH_HASH_SZ); 268 /* 269 * We should check (netr_info->flags & NETR_FLG_INIT) and use 270 * the appropriate password but it isn't working yet. So we 271 * always use the default one for now. 272 */ 273 bzero(netr_info->password, sizeof (netr_info->password)); 274 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, 275 (char *)netr_info->password, sizeof (netr_info->password)); 276 277 if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') { 278 return (SMBAUTH_FAILURE); 279 } 280 281 rc = smb_auth_ntlm_hash((char *)netr_info->password, ntlmhash); 282 if (rc != SMBAUTH_SUCCESS) 283 return (SMBAUTH_FAILURE); 284 285 bzero(zerobuf, NETR_SESSKEY_ZEROBUF_SZ); 286 287 mechanism.mechanism = CKM_MD5; 288 mechanism.pParameter = 0; 289 mechanism.ulParameterLen = 0; 290 291 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession); 292 if (rv != CKR_OK) 293 return (SMBAUTH_FAILURE); 294 295 rv = C_DigestInit(hSession, &mechanism); 296 if (rv != CKR_OK) 297 goto cleanup; 298 299 rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)zerobuf, 300 NETR_SESSKEY_ZEROBUF_SZ); 301 if (rv != CKR_OK) 302 goto cleanup; 303 304 rv = C_DigestUpdate(hSession, 305 (CK_BYTE_PTR)netr_info->client_challenge.data, NETR_CRED_DATA_SZ); 306 if (rv != CKR_OK) 307 goto cleanup; 308 309 rv = C_DigestUpdate(hSession, 310 (CK_BYTE_PTR)netr_info->server_challenge.data, NETR_CRED_DATA_SZ); 311 if (rv != CKR_OK) 312 goto cleanup; 313 314 rv = C_DigestFinal(hSession, (CK_BYTE_PTR)md5digest, &diglen); 315 if (rv != CKR_OK) 316 goto cleanup; 317 318 rc = smb_auth_hmac_md5(md5digest, diglen, ntlmhash, SMBAUTH_HASH_SZ, 319 netr_info->session_key.key); 320 321 netr_info->session_key.len = NETR_SESSKEY128_SZ; 322 cleanup: 323 (void) C_CloseSession(hSession); 324 return (rc); 325 326 } 327 /* 328 * netr_gen_skey64 329 * 330 * Generate a 64-bit session key from the client and server challenges. 331 * See "Session-Key Computation" section of MS-NRPC document. 332 * 333 * The algorithm is a two stage hash. For the first hash, the input is 334 * the combination of the client and server challenges, the key is 335 * the first 7 bytes of the password. The initial password is formed 336 * using the NT password hash on the local hostname in lower case. 337 * The result is stored in a temporary buffer. 338 * 339 * input: challenge 340 * key: passwd lower 7 bytes 341 * output: intermediate result 342 * 343 * For the second hash, the input is the result of the first hash and 344 * the key is the last 7 bytes of the password. 345 * 346 * input: result of first hash 347 * key: passwd upper 7 bytes 348 * output: session_key 349 * 350 * The final output should be the session key. 351 * 352 * FYI: smb_auth_DES(output, key, input) 353 * 354 * If any difficulties occur using the cryptographic framework, the 355 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 356 * returned. 357 */ 358 int 359 netr_gen_skey64(netr_info_t *netr_info) 360 { 361 unsigned char md4hash[32]; 362 unsigned char buffer[8]; 363 DWORD data[2]; 364 DWORD *client_challenge; 365 DWORD *server_challenge; 366 int rc; 367 DWORD le_data[2]; 368 369 client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge; 370 server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge; 371 bzero(md4hash, 32); 372 373 /* 374 * We should check (netr_info->flags & NETR_FLG_INIT) and use 375 * the appropriate password but it isn't working yet. So we 376 * always use the default one for now. 377 */ 378 bzero(netr_info->password, sizeof (netr_info->password)); 379 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, 380 (char *)netr_info->password, sizeof (netr_info->password)); 381 382 if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') { 383 return (SMBAUTH_FAILURE); 384 } 385 386 rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash); 387 388 if (rc != SMBAUTH_SUCCESS) 389 return (SMBAUTH_FAILURE); 390 391 data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]); 392 data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]); 393 LE_OUT32(&le_data[0], data[0]); 394 LE_OUT32(&le_data[1], data[1]); 395 rc = smb_auth_DES(buffer, 8, md4hash, NETR_DESKEY_LEN, 396 (unsigned char *)le_data, 8); 397 398 if (rc != SMBAUTH_SUCCESS) 399 return (rc); 400 401 netr_info->session_key.len = NETR_SESSKEY64_SZ; 402 rc = smb_auth_DES(netr_info->session_key.key, 403 netr_info->session_key.len, &md4hash[9], NETR_DESKEY_LEN, buffer, 404 8); 405 406 return (rc); 407 } 408 409 /* 410 * netr_gen_credentials 411 * 412 * Generate a set of credentials from a challenge and a session key. 413 * The algorithm is a two stage hash. For the first hash, the 414 * timestamp is added to the challenge and the result is stored in a 415 * temporary buffer: 416 * 417 * input: challenge (including timestamp) 418 * key: session_key 419 * output: intermediate result 420 * 421 * For the second hash, the input is the result of the first hash and 422 * a strange partial key is used: 423 * 424 * input: result of first hash 425 * key: funny partial key 426 * output: credentiails 427 * 428 * The final output should be an encrypted set of credentials. 429 * 430 * FYI: smb_auth_DES(output, key, input) 431 * 432 * If any difficulties occur using the cryptographic framework, the 433 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 434 * returned. 435 */ 436 int 437 netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge, 438 DWORD timestamp, netr_cred_t *out_cred) 439 { 440 unsigned char buffer[8]; 441 DWORD data[2]; 442 DWORD le_data[2]; 443 DWORD *p; 444 int rc; 445 446 p = (DWORD *)(uintptr_t)challenge; 447 data[0] = LE_IN32(&p[0]) + timestamp; 448 data[1] = LE_IN32(&p[1]); 449 450 LE_OUT32(&le_data[0], data[0]); 451 LE_OUT32(&le_data[1], data[1]); 452 453 if (smb_auth_DES(buffer, 8, session_key, NETR_DESKEY_LEN, 454 (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS) 455 return (SMBAUTH_FAILURE); 456 457 rc = smb_auth_DES(out_cred->data, 8, &session_key[NETR_DESKEY_LEN], 458 NETR_DESKEY_LEN, buffer, 8); 459 460 return (rc); 461 } 462 463 /* 464 * netr_server_password_set 465 * 466 * Attempt to change the trust account password for this system. 467 * 468 * Note that this call may legitimately fail if the registry on the 469 * domain controller has been setup to deny attempts to change the 470 * trust account password. In this case we should just continue to 471 * use the original password. 472 * 473 * Possible status values: 474 * NT_STATUS_ACCESS_DENIED 475 */ 476 int 477 netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 478 { 479 struct netr_PasswordSet arg; 480 int opnum; 481 BYTE new_password[NETR_OWF_PASSWORD_SZ]; 482 char account_name[NETBIOS_NAME_SZ * 2]; 483 484 bzero(&arg, sizeof (struct netr_PasswordSet)); 485 opnum = NETR_OPNUM_ServerPasswordSet; 486 487 (void) snprintf(account_name, sizeof (account_name), "%s$", 488 netr_info->hostname); 489 490 arg.servername = (unsigned char *)netr_info->server; 491 arg.account_name = (unsigned char *)account_name; 492 arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 493 arg.hostname = (unsigned char *)netr_info->hostname; 494 495 /* 496 * Set up the client side authenticator. 497 */ 498 if (netr_setup_authenticator(netr_info, &arg.auth, 0) != 499 SMBAUTH_SUCCESS) { 500 return (-1); 501 } 502 503 /* 504 * Generate a new password from the old password. 505 */ 506 if (netr_gen_password(netr_info->session_key.key, 507 netr_info->password, new_password) == SMBAUTH_FAILURE) { 508 return (-1); 509 } 510 511 (void) memcpy(&arg.uas_new_password, &new_password, 512 NETR_OWF_PASSWORD_SZ); 513 514 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0) 515 return (-1); 516 517 if (arg.status != 0) { 518 ndr_rpc_status(netr_handle, opnum, arg.status); 519 ndr_rpc_release(netr_handle); 520 return (-1); 521 } 522 523 /* 524 * Check the returned credentials. The server returns the new 525 * client credential rather than the new server credentiali, 526 * as documented elsewhere. 527 * 528 * Generate the new seed for the credential chain. Increment 529 * the timestamp and add it to the client challenge. Then we 530 * need to copy the challenge to the credential field in 531 * preparation for the next cycle. 532 */ 533 if (netr_validate_chain(netr_info, &arg.auth) == 0) { 534 /* 535 * Save the new password. 536 */ 537 (void) memcpy(netr_info->password, new_password, 538 NETR_OWF_PASSWORD_SZ); 539 } 540 541 ndr_rpc_release(netr_handle); 542 return (0); 543 } 544 545 /* 546 * netr_gen_password 547 * 548 * Generate a new pasword from the old password and the session key. 549 * The algorithm is a two stage hash. The session key is used in the 550 * first hash but only part of the session key is used in the second 551 * hash. 552 * 553 * If any difficulties occur using the cryptographic framework, the 554 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 555 * returned. 556 */ 557 static int 558 netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password) 559 { 560 int rv; 561 562 rv = smb_auth_DES(new_password, 8, session_key, NETR_DESKEY_LEN, 563 old_password, 8); 564 if (rv != SMBAUTH_SUCCESS) 565 return (rv); 566 567 rv = smb_auth_DES(&new_password[8], 8, &session_key[NETR_DESKEY_LEN], 568 NETR_DESKEY_LEN, &old_password[8], 8); 569 return (rv); 570 } 571