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 2021 Tintri by DDN, Inc. All rights reserved.
25 * Copyright 2023 RackTop Systems, Inc.
26 */
27
28 /*
29 * NETR challenge/response client functions.
30 *
31 * NT_STATUS_INVALID_PARAMETER
32 * NT_STATUS_NO_TRUST_SAM_ACCOUNT
33 * NT_STATUS_ACCESS_DENIED
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <strings.h>
39 #include <unistd.h>
40 #include <ctype.h>
41 #include <security/cryptoki.h>
42 #include <security/pkcs11.h>
43
44 #include <smbsrv/libsmb.h>
45 #include <smbsrv/libsmbns.h>
46 #include <smbsrv/libmlsvc.h>
47 #include <mlsvc.h>
48 #include <smbsrv/ndl/netlogon.ndl>
49 #include <smbsrv/smbinfo.h>
50 #include <smbsrv/netrauth.h>
51
52 #define NETR_SESSKEY_ZEROBUF_SZ 4
53 /* The DES algorithm uses a 56-bit encryption key. */
54 #define NETR_DESKEY_LEN 7
55
56 int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *,
57 struct netr_authenticator *);
58 DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *);
59
60 static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *);
61 static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *);
62 static int netr_gen_password(BYTE *, BYTE *, BYTE *);
63
64 /*
65 * Shared with netr_logon.c
66 */
67 netr_info_t netr_global_info = {
68 .use_secure_rpc = B_TRUE,
69 .use_logon_ex = B_TRUE
70 };
71 extern ndr_auth_ctx_t netr_ssp_ctx;
72
73 /*
74 * These flags control various parts of NetLogon RPC messages.
75 * The default is 0 - setting a bit disables some feature.
76 * They are set in smbd/netlogon_flags in svc:/network/smb/server.
77 * These are set when smbd starts. Changing them requires
78 * restarting smbd.
79 *
80 * These shouldn't be confused with either SamLogonEx's ExtraFlags,
81 * or NetrServerAuthenticate's negotiate_flags.
82 *
83 * DISABLE_SECURE_RPC causes Netlogon to use unauthenticated RPC.
84 * Note that the underlying transport is still authenticated and signed.
85 *
86 * DISABLE_RESP_VERIF instructs RPC authentication to ignore failures
87 * when verifying responses.
88 *
89 * DISABLE_SAMLOGONEX causes Netlogon to always use SamLogon, which
90 * makes use of Netlogon Authenticators.
91 *
92 * DISABLE_SEALING causes Netlogon to use Signing (integrity) instead of
93 * Sealing (privacy).
94 */
95 #define NETR_CFG_DISABLE_SECURE_RPC 0x00000001
96 #define NETR_CFG_DISABLE_RESP_VERIF 0x00000002
97 #define NETR_CFG_DISABLE_SAMLOGONEX 0x00000004
98 #define NETR_CFG_DISABLE_SEALING 0x00000008
99
100 void
netlogon_init_global(uint32_t flags)101 netlogon_init_global(uint32_t flags)
102 {
103 netr_global_info.use_secure_rpc =
104 ((flags & NETR_CFG_DISABLE_SECURE_RPC) == 0);
105 netr_ssp_ctx.auth_verify_resp =
106 ((flags & NETR_CFG_DISABLE_RESP_VERIF) == 0);
107 netr_global_info.use_logon_ex =
108 ((flags & NETR_CFG_DISABLE_SAMLOGONEX) == 0);
109 if ((flags & NETR_CFG_DISABLE_SEALING) != 0)
110 netr_ssp_ctx.auth_level = NDR_C_AUTHN_LEVEL_PKT_INTEGRITY;
111 }
112
113 /*
114 * AES-CFB8 has the odd property that 1/256 keys will encrypt
115 * a full block of 0s to all 0s. In order to mitigate this, Windows DCs
116 * now reject Challenges and Credentials where "none of the first 5 bytes
117 * are unique" (i.e. [MS-NRPC] 3.1.4.1 "Session-Key Negotiation" Step 7).
118 * This detects that condition so that we can avoid having our connection
119 * rejected unexpectedly.
120 *
121 * I've interpreted this condition as 'amongst the first 5 bytes,
122 * at least one must appear exactly once'.
123 *
124 * NOTE: Win2012r2 seems to only reject challenges whose first 5 bytes are 0.
125 */
126 boolean_t
passes_dc_mitigation(uint8_t * buf)127 passes_dc_mitigation(uint8_t *buf)
128 {
129 int i, j;
130
131 for (i = 0; i < 5; i++) {
132 for (j = 0; j < 5; j++) {
133 if (i != j && buf[i] == buf[j])
134 break;
135 }
136
137 /* if this byte didn't match any other byte, this passes */
138 if (j == 5)
139 return (B_TRUE);
140 }
141
142 /* None of the bytes were unique - the check fails */
143 return (B_FALSE);
144 }
145
146 /*
147 * netlogon_auth
148 *
149 * This is the core of the NETLOGON authentication protocol.
150 * Do the challenge response authentication.
151 *
152 * Prior to calling this function, an anonymous session to the NETLOGON
153 * pipe on a domain controller(server) should have already been opened.
154 *
155 * Upon a successful NETLOGON credential chain establishment, the
156 * netlogon sequence number will be set to match the kpasswd sequence
157 * number.
158 *
159 */
160 DWORD
netlogon_auth(char * server,char * domain,DWORD flags)161 netlogon_auth(char *server, char *domain, DWORD flags)
162 {
163 mlsvc_handle_t netr_handle;
164 netr_info_t *netr_info;
165 int rc;
166 DWORD leout_rc[2];
167 boolean_t retry;
168 DWORD status;
169
170 /*
171 * [MS-NRPC] 3.1.4.1 "Session-Key Negotiation"
172 * Negotiation happens on an 'unprotected RPC channel'
173 * (no RPC-level auth).
174 */
175 status = netr_open(server, domain, &netr_handle);
176
177 if (status != 0) {
178 syslog(LOG_ERR, "netlogon_auth remote open failed (%s)",
179 xlate_nt_status(status));
180 return (status);
181 }
182
183 netr_info = &netr_global_info;
184 bzero(&netr_info->session_key, sizeof (netr_info->session_key));
185 bzero(&netr_info->rpc_seal_key, sizeof (netr_info->rpc_seal_key));
186 netr_info->flags = flags;
187
188 rc = smb_getnetbiosname(netr_info->hostname, NETBIOS_NAME_SZ);
189 if (rc != 0)
190 goto errout;
191
192 /* server is our DC. Note: normally an FQDN. */
193 (void) snprintf(netr_info->server, sizeof (netr_info->server),
194 "\\\\%s", server);
195
196 /*
197 * Domain (FQDN and NetBIOS) Name needed for Netlogon SSP-based
198 * Secure RPC.
199 */
200 rc = smb_getdomainname(netr_info->nb_domain,
201 sizeof (netr_info->nb_domain));
202 if (rc != 0)
203 goto errout;
204
205 rc = smb_getfqdomainname(netr_info->fqdn_domain,
206 sizeof (netr_info->fqdn_domain));
207 if (rc != 0)
208 goto errout;
209
210 /*
211 * [MS-NRPC] 3.1.4.1 "Session-Key Negotiation" Step 7
212 * Windows DCs will reject negotiate attempts if none of the first
213 * 5 bytes of the Challenge are unique.
214 * Keep retrying until we've generated one that satisfies this.
215 */
216 do {
217 retry = B_FALSE;
218 LE_OUT32(&leout_rc[0], arc4random());
219 LE_OUT32(&leout_rc[1], arc4random());
220 (void) memcpy(&netr_info->client_challenge, leout_rc,
221 sizeof (struct netr_credential));
222
223 if (!passes_dc_mitigation(netr_info->client_challenge.data))
224 retry = B_TRUE;
225 } while (retry);
226
227 if ((rc = netr_server_req_challenge(&netr_handle, netr_info)) == 0) {
228 rc = netr_server_authenticate2(&netr_handle, netr_info);
229 if (rc == 0) {
230 /*
231 * TODO: (later) When joining a domain using a
232 * pre-created machine account, should do:
233 * netr_server_password_set(&netr_handle, netr_info);
234 * Nexenta issue 11960
235 */
236 smb_update_netlogon_seqnum();
237 netr_info->flags |= NETR_FLG_VALID;
238
239 }
240 }
241
242 errout:
243 (void) netr_close(&netr_handle);
244
245 return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS);
246 }
247
248 /*
249 * netr_open
250 *
251 * Open an anonymous session to the NETLOGON pipe on a domain controller
252 * and bind to the NETR RPC interface.
253 *
254 * We store the remote server information, which is used to drive Windows
255 * version specific behavior.
256 *
257 * Returns 0 or NT status
258 */
259 DWORD
netr_open(char * server,char * domain,mlsvc_handle_t * netr_handle)260 netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle)
261 {
262 char user[SMB_USERNAME_MAXLEN];
263 DWORD status;
264
265 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
266
267 status = ndr_rpc_bind(netr_handle, server, domain, user, "NETR");
268
269 return (status);
270 }
271
272 uint32_t auth_context_id = 1;
273
274 DWORD
netr_open_secure(char * server,char * domain,mlsvc_handle_t * netr_handle)275 netr_open_secure(char *server, char *domain, mlsvc_handle_t *netr_handle)
276 {
277 char user[SMB_USERNAME_MAXLEN];
278 DWORD status;
279
280 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
281
282 /*
283 * If the server doesn't support SECURE_RPC_FLAG, or we've disabled
284 * secure rpc (netr_global_info.use_secure_rpc), then SECURE_RPC_FLAG
285 * won't be in the set of negotiated flags. Don't use SecureRPC if
286 * that's the case.
287 */
288 if ((netr_global_info.nego_flags & NETR_NEGO_SECURE_RPC_FLAG) != 0) {
289 netr_ssp_ctx.auth_context_id = auth_context_id++;
290 status = ndr_rpc_bind_secure(netr_handle, server, domain, user,
291 "NETR", &netr_ssp_ctx);
292 } else {
293 status = ndr_rpc_bind(netr_handle, server, domain, user,
294 "NETR");
295 }
296
297 return (status);
298 }
299
300 /*
301 * netr_close
302 *
303 * Close a NETLOGON pipe and free the RPC context.
304 */
305 int
netr_close(mlsvc_handle_t * netr_handle)306 netr_close(mlsvc_handle_t *netr_handle)
307 {
308 ndr_rpc_unbind(netr_handle);
309 return (0);
310 }
311
312 /*
313 * netr_server_req_challenge
314 */
315 static int
netr_server_req_challenge(mlsvc_handle_t * netr_handle,netr_info_t * netr_info)316 netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
317 {
318 struct netr_ServerReqChallenge arg;
319 int opnum;
320
321 bzero(&arg, sizeof (struct netr_ServerReqChallenge));
322 opnum = NETR_OPNUM_ServerReqChallenge;
323
324 arg.servername = (unsigned char *)netr_info->server;
325 arg.hostname = (unsigned char *)netr_info->hostname;
326
327 (void) memcpy(&arg.client_challenge, &netr_info->client_challenge,
328 sizeof (struct netr_credential));
329
330 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0)
331 return (-1);
332
333 if (arg.status != 0) {
334 ndr_rpc_status(netr_handle, opnum, arg.status);
335 ndr_rpc_release(netr_handle);
336 return (-1);
337 }
338
339 (void) memcpy(&netr_info->server_challenge, &arg.server_challenge,
340 sizeof (struct netr_credential));
341
342 ndr_rpc_release(netr_handle);
343 return (0);
344 }
345
346 uint32_t netr_server_auth2_flags =
347 NETR_NEGO_BASE_FLAGS |
348 NETR_NEGO_STRONGKEY_FLAG |
349 NETR_NEGO_SECURE_RPC_FLAG;
350
351 /*
352 * netr_server_authenticate2
353 */
354 static int
netr_server_authenticate2(mlsvc_handle_t * netr_handle,netr_info_t * netr_info)355 netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
356 {
357 struct netr_ServerAuthenticate2 arg;
358 /* sizeof netr_info->hostname, + 1 for the '$' */
359 char account_name[(NETBIOS_NAME_SZ * 2) + 1];
360 int opnum;
361 int rc;
362 int i;
363
364 bzero(&arg, sizeof (struct netr_ServerAuthenticate2));
365 opnum = NETR_OPNUM_ServerAuthenticate2;
366
367 (void) snprintf(account_name, sizeof (account_name), "%s$",
368 netr_info->hostname);
369
370 smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n",
371 netr_info->server, account_name, netr_info->hostname);
372
373 arg.servername = (unsigned char *)netr_info->server;
374 arg.account_name = (unsigned char *)account_name;
375 arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
376 arg.hostname = (unsigned char *)netr_info->hostname;
377 arg.negotiate_flags = netr_server_auth2_flags;
378
379 /*
380 * If we've disabled SecureRPC, remove it from our negotiate_flags
381 * so that the returned flags don't include it. We won't later use
382 * SecureRPC if the returned flags don't include the flag.
383 */
384 if (!netr_global_info.use_secure_rpc)
385 arg.negotiate_flags &= ~NETR_NEGO_SECURE_RPC_FLAG;
386
387 if (arg.negotiate_flags & NETR_NEGO_STRONGKEY_FLAG) {
388 if (netr_gen_skey128(netr_info) != SMBAUTH_SUCCESS)
389 return (-1);
390 } else {
391 if (netr_gen_skey64(netr_info) != SMBAUTH_SUCCESS)
392 return (-1);
393 }
394
395 /*
396 * Calculate the 'XorKey' used to derive certain Netlogon SSP keys.
397 * This is used in [MS-NRPC] 3.3.4.2 "The Netlogon Signature Token".
398 */
399 for (i = 0; i < netr_info->session_key.len; i++)
400 netr_info->rpc_seal_key.key[i] =
401 netr_info->session_key.key[i] ^ 0xf0;
402 netr_info->rpc_seal_key.len = netr_info->session_key.len;
403
404 /*
405 * We can't 'fiddle' with anything here to prevent getting bitten by
406 * ClientStoredCredential-based mitigations.
407 *
408 * If we're using SamLogonEx, we won't use authenticators unless
409 * some other NetLogon command is implemented and used.
410 */
411 if (netr_gen_credentials(netr_info->session_key.key,
412 &netr_info->client_challenge, 0,
413 &netr_info->client_credential, B_FALSE) != SMBAUTH_SUCCESS) {
414 return (-1);
415 }
416
417 if (netr_gen_credentials(netr_info->session_key.key,
418 &netr_info->server_challenge, 0,
419 &netr_info->server_credential, B_FALSE) != SMBAUTH_SUCCESS) {
420 return (-1);
421 }
422
423 (void) memcpy(&arg.client_credential, &netr_info->client_credential,
424 sizeof (struct netr_credential));
425
426 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0)
427 return (-1);
428
429 if (arg.status != 0) {
430 ndr_rpc_status(netr_handle, opnum, arg.status);
431 ndr_rpc_release(netr_handle);
432 return (-1);
433 }
434
435 /* The server returns the intersection of our flags and their flags. */
436 netr_info->nego_flags = arg.negotiate_flags;
437
438 rc = memcmp(&netr_info->server_credential, &arg.server_credential,
439 sizeof (struct netr_credential));
440
441 ndr_rpc_release(netr_handle);
442 return (rc);
443 }
444
445 /*
446 * netr_gen_skey128
447 *
448 * Generate a 128-bit session key from the client and server challenges.
449 * See "Session-Key Computation" section of MS-NRPC document.
450 */
451 int
netr_gen_skey128(netr_info_t * netr_info)452 netr_gen_skey128(netr_info_t *netr_info)
453 {
454 unsigned char ntlmhash[SMBAUTH_HASH_SZ];
455 int rc = SMBAUTH_FAILURE;
456 CK_RV rv;
457 CK_MECHANISM mechanism;
458 CK_SESSION_HANDLE hSession;
459 CK_ULONG diglen = MD_DIGEST_LEN;
460 unsigned char md5digest[MD_DIGEST_LEN];
461 unsigned char zerobuf[NETR_SESSKEY_ZEROBUF_SZ];
462
463 bzero(ntlmhash, SMBAUTH_HASH_SZ);
464 /*
465 * We should check (netr_info->flags & NETR_FLG_INIT) and use
466 * the appropriate password but it isn't working yet. So we
467 * always use the default one for now.
468 */
469 bzero(netr_info->password, sizeof (netr_info->password));
470 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD,
471 (char *)netr_info->password, sizeof (netr_info->password));
472
473 if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') {
474 return (SMBAUTH_FAILURE);
475 }
476
477 rc = smb_auth_ntlm_hash((char *)netr_info->password, ntlmhash);
478 if (rc != SMBAUTH_SUCCESS) {
479 explicit_bzero(&netr_info->password,
480 sizeof (netr_info->password));
481 return (SMBAUTH_FAILURE);
482 }
483
484 bzero(zerobuf, NETR_SESSKEY_ZEROBUF_SZ);
485
486 mechanism.mechanism = CKM_MD5;
487 mechanism.pParameter = 0;
488 mechanism.ulParameterLen = 0;
489
490 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
491 if (rv != CKR_OK) {
492 rc = SMBAUTH_FAILURE;
493 goto errout;
494 }
495
496 rv = C_DigestInit(hSession, &mechanism);
497 if (rv != CKR_OK)
498 goto cleanup;
499
500 rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)zerobuf,
501 NETR_SESSKEY_ZEROBUF_SZ);
502 if (rv != CKR_OK)
503 goto cleanup;
504
505 rv = C_DigestUpdate(hSession,
506 (CK_BYTE_PTR)netr_info->client_challenge.data, NETR_CRED_DATA_SZ);
507 if (rv != CKR_OK)
508 goto cleanup;
509
510 rv = C_DigestUpdate(hSession,
511 (CK_BYTE_PTR)netr_info->server_challenge.data, NETR_CRED_DATA_SZ);
512 if (rv != CKR_OK)
513 goto cleanup;
514
515 rv = C_DigestFinal(hSession, (CK_BYTE_PTR)md5digest, &diglen);
516 if (rv != CKR_OK)
517 goto cleanup;
518
519 rc = smb_auth_hmac_md5(md5digest, diglen, ntlmhash, SMBAUTH_HASH_SZ,
520 netr_info->session_key.key);
521
522 netr_info->session_key.len = NETR_SESSKEY128_SZ;
523 cleanup:
524 (void) C_CloseSession(hSession);
525
526 errout:
527 explicit_bzero(&netr_info->password, sizeof (netr_info->password));
528 explicit_bzero(ntlmhash, sizeof (ntlmhash));
529
530 return (rc);
531
532 }
533 /*
534 * netr_gen_skey64
535 *
536 * Generate a 64-bit session key from the client and server challenges.
537 * See "Session-Key Computation" section of MS-NRPC document.
538 *
539 * The algorithm is a two stage hash. For the first hash, the input is
540 * the combination of the client and server challenges, the key is
541 * the first 7 bytes of the password. The initial password is formed
542 * using the NT password hash on the local hostname in lower case.
543 * The result is stored in a temporary buffer.
544 *
545 * input: challenge
546 * key: passwd lower 7 bytes
547 * output: intermediate result
548 *
549 * For the second hash, the input is the result of the first hash and
550 * the key is the last 7 bytes of the password.
551 *
552 * input: result of first hash
553 * key: passwd upper 7 bytes
554 * output: session_key
555 *
556 * The final output should be the session key.
557 *
558 * FYI: smb_auth_DES(output, key, input)
559 *
560 * If any difficulties occur using the cryptographic framework, the
561 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
562 * returned.
563 */
564 int
netr_gen_skey64(netr_info_t * netr_info)565 netr_gen_skey64(netr_info_t *netr_info)
566 {
567 unsigned char md4hash[32];
568 unsigned char buffer[8];
569 DWORD data[2];
570 DWORD *client_challenge;
571 DWORD *server_challenge;
572 int rc;
573 DWORD le_data[2];
574
575 client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge;
576 server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge;
577 bzero(md4hash, 32);
578
579 /*
580 * We should check (netr_info->flags & NETR_FLG_INIT) and use
581 * the appropriate password but it isn't working yet. So we
582 * always use the default one for now.
583 */
584 bzero(netr_info->password, sizeof (netr_info->password));
585 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD,
586 (char *)netr_info->password, sizeof (netr_info->password));
587
588 if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') {
589 return (SMBAUTH_FAILURE);
590 }
591
592 rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash);
593
594 if (rc != SMBAUTH_SUCCESS) {
595 rc = SMBAUTH_FAILURE;
596 goto out;
597 }
598
599 data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]);
600 data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]);
601 LE_OUT32(&le_data[0], data[0]);
602 LE_OUT32(&le_data[1], data[1]);
603 rc = smb_auth_DES(buffer, 8, md4hash, NETR_DESKEY_LEN,
604 (unsigned char *)le_data, 8);
605
606 if (rc != SMBAUTH_SUCCESS)
607 goto out;
608
609 netr_info->session_key.len = NETR_SESSKEY64_SZ;
610 rc = smb_auth_DES(netr_info->session_key.key,
611 netr_info->session_key.len, &md4hash[9], NETR_DESKEY_LEN, buffer,
612 8);
613
614 out:
615 explicit_bzero(&netr_info->password, sizeof (netr_info->password));
616 explicit_bzero(md4hash, sizeof (md4hash));
617 explicit_bzero(buffer, sizeof (buffer));
618 return (rc);
619 }
620
621 /*
622 * netr_gen_credentials
623 *
624 * Generate a set of credentials from a challenge and a session key.
625 * The algorithm is a two stage hash. For the first hash, the
626 * timestamp is added to the challenge and the result is stored in a
627 * temporary buffer:
628 *
629 * input: challenge (including timestamp)
630 * key: session_key
631 * output: intermediate result
632 *
633 * For the second hash, the input is the result of the first hash and
634 * a strange partial key is used:
635 *
636 * input: result of first hash
637 * key: funny partial key
638 * output: credentiails
639 *
640 * The final output should be an encrypted set of credentials.
641 *
642 * FYI: smb_auth_DES(output, key, input)
643 *
644 * If any difficulties occur using the cryptographic framework, the
645 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
646 * returned.
647 */
648 int
netr_gen_credentials(BYTE * session_key,netr_cred_t * challenge,DWORD timestamp,netr_cred_t * out_cred,boolean_t retry)649 netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge,
650 DWORD timestamp, netr_cred_t *out_cred, boolean_t retry)
651 {
652 unsigned char buffer[8];
653 DWORD data[2];
654 DWORD le_data[2];
655 DWORD *p;
656 int rc;
657
658 p = (DWORD *)(uintptr_t)challenge;
659 data[0] = LE_IN32(&p[0]) + timestamp;
660 data[1] = LE_IN32(&p[1]);
661
662 LE_OUT32(&le_data[0], data[0]);
663 LE_OUT32(&le_data[1], data[1]);
664
665 if (smb_auth_DES(buffer, 8, session_key, NETR_DESKEY_LEN,
666 (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS)
667 return (SMBAUTH_FAILURE);
668
669 rc = smb_auth_DES(out_cred->data, 8, &session_key[NETR_DESKEY_LEN],
670 NETR_DESKEY_LEN, buffer, 8);
671
672 /*
673 * [MS-NRPC] 3.1.4.6 "Calling Methods Requiring Session-Key
674 * Establishment" Step 6
675 *
676 * Windows DCs will reject authenticators if none of the first
677 * 5 bytes of the ClientStoredCredential are unique.
678 * Keep retrying until we've generated one that satisfies this,
679 * but only if the caller can handle retries.
680 */
681 if (retry && !passes_dc_mitigation(out_cred->data))
682 return (SMBAUTH_RETRY);
683
684 return (rc);
685 }
686
687 /*
688 * netr_server_password_set
689 *
690 * Attempt to change the trust account password for this system.
691 *
692 * Note that this call may legitimately fail if the registry on the
693 * domain controller has been setup to deny attempts to change the
694 * trust account password. In this case we should just continue to
695 * use the original password.
696 *
697 * Possible status values:
698 * NT_STATUS_ACCESS_DENIED
699 */
700 int
netr_server_password_set(mlsvc_handle_t * netr_handle,netr_info_t * netr_info)701 netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
702 {
703 struct netr_PasswordSet arg;
704 int opnum;
705 BYTE new_password[NETR_OWF_PASSWORD_SZ];
706 char account_name[NETBIOS_NAME_SZ * 2];
707
708 bzero(&arg, sizeof (struct netr_PasswordSet));
709 opnum = NETR_OPNUM_ServerPasswordSet;
710
711 (void) snprintf(account_name, sizeof (account_name), "%s$",
712 netr_info->hostname);
713
714 arg.servername = (unsigned char *)netr_info->server;
715 arg.account_name = (unsigned char *)account_name;
716 arg.sec_chan_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
717 arg.hostname = (unsigned char *)netr_info->hostname;
718
719 /*
720 * Set up the client side authenticator.
721 */
722 if (netr_setup_authenticator(netr_info, &arg.auth, 0) !=
723 SMBAUTH_SUCCESS) {
724 return (-1);
725 }
726
727 /*
728 * Generate a new password from the old password.
729 */
730 if (netr_gen_password(netr_info->session_key.key,
731 netr_info->password, new_password) == SMBAUTH_FAILURE) {
732 return (-1);
733 }
734
735 (void) memcpy(&arg.owf_password, &new_password,
736 NETR_OWF_PASSWORD_SZ);
737
738 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0)
739 return (-1);
740
741 if (arg.status != 0) {
742 ndr_rpc_status(netr_handle, opnum, arg.status);
743 ndr_rpc_release(netr_handle);
744 return (-1);
745 }
746
747 /*
748 * Check the returned credentials. The server returns the new
749 * client credential rather than the new server credentiali,
750 * as documented elsewhere.
751 *
752 * Generate the new seed for the credential chain. Increment
753 * the timestamp and add it to the client challenge. Then we
754 * need to copy the challenge to the credential field in
755 * preparation for the next cycle.
756 */
757 if (netr_validate_chain(netr_info, &arg.auth) == 0) {
758 /*
759 * Save the new password.
760 */
761 (void) memcpy(netr_info->password, new_password,
762 NETR_OWF_PASSWORD_SZ);
763 }
764
765 ndr_rpc_release(netr_handle);
766 return (0);
767 }
768
769 /*
770 * netr_gen_password
771 *
772 * Generate a new pasword from the old password and the session key.
773 * The algorithm is a two stage hash. The session key is used in the
774 * first hash but only part of the session key is used in the second
775 * hash.
776 *
777 * If any difficulties occur using the cryptographic framework, the
778 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
779 * returned.
780 */
781 static int
netr_gen_password(BYTE * session_key,BYTE * old_password,BYTE * new_password)782 netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password)
783 {
784 int rv;
785
786 rv = smb_auth_DES(new_password, 8, session_key, NETR_DESKEY_LEN,
787 old_password, 8);
788 if (rv != SMBAUTH_SUCCESS)
789 return (rv);
790
791 rv = smb_auth_DES(&new_password[8], 8, &session_key[NETR_DESKEY_LEN],
792 NETR_DESKEY_LEN, &old_password[8], 8);
793 return (rv);
794 }
795
796 /*
797 * Todo: need netr_server_password_set2()
798 * used by "unsecure join". (NX 11960)
799 */
800