2 Unix SMB/CIFS implementation.
4 User credentials handling
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
8 Copyright (C) Stefan Metzmacher 2005
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "lib/ldb/include/ldb.h"
27 #include "librpc/gen_ndr/ndr_samr.h" /* for struct samrPassword */
28 #include "lib/crypto/crypto.h"
30 void cli_credentials_get_ntlm_username_domain(struct cli_credentials
*cred
, TALLOC_CTX
*mem_ctx
,
31 const char **username
,
34 if (cred
->principal_obtained
> cred
->username_obtained
) {
35 *domain
= talloc_strdup(mem_ctx
, "");
36 *username
= cli_credentials_get_principal(cred
, mem_ctx
);
38 *domain
= cli_credentials_get_domain(cred
);
39 *username
= cli_credentials_get_username(cred
);
43 NTSTATUS
cli_credentials_get_ntlm_response(struct cli_credentials
*cred
, TALLOC_CTX
*mem_ctx
,
45 DATA_BLOB challenge
, DATA_BLOB target_info
,
46 DATA_BLOB
*_lm_response
, DATA_BLOB
*_nt_response
,
47 DATA_BLOB
*_lm_session_key
, DATA_BLOB
*_session_key
)
49 const char *user
, *domain
;
50 DATA_BLOB lm_response
, nt_response
;
51 DATA_BLOB lm_session_key
, session_key
;
52 const struct samr_Password
*nt_hash
;
53 lm_session_key
= data_blob(NULL
, 0);
55 nt_hash
= cli_credentials_get_nt_hash(cred
, mem_ctx
);
57 cli_credentials_get_ntlm_username_domain(cred
, mem_ctx
, &user
, &domain
);
59 /* If we are sending a username@realm login (see function
60 * above), then we will not send LM, it will not be
62 if (cred
->principal_obtained
> cred
->username_obtained
) {
63 *flags
= *flags
& ~CLI_CRED_LANMAN_AUTH
;
66 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
67 if (cred
->machine_account
) {
68 *flags
= *flags
& ~CLI_CRED_LANMAN_AUTH
;
72 static const uint8_t zeros
[16];
73 /* do nothing - blobs are zero length */
75 /* session key is all zeros */
76 session_key
= data_blob_talloc(mem_ctx
, zeros
, 16);
77 lm_session_key
= data_blob_talloc(mem_ctx
, zeros
, 16);
79 lm_response
= data_blob(NULL
, 0);
80 nt_response
= data_blob(NULL
, 0);
82 /* not doing NTLM2 without a password */
83 *flags
&= ~CLI_CRED_NTLM2
;
84 } else if (*flags
& CLI_CRED_NTLMv2_AUTH
) {
86 if (!target_info
.length
) {
87 /* be lazy, match win2k - we can't do NTLMv2 without it */
88 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
89 return NT_STATUS_INVALID_PARAMETER
;
92 /* TODO: if the remote server is standalone, then we should replace 'domain'
93 with the server name as supplied above */
95 if (!SMBNTLMv2encrypt_hash(mem_ctx
,
98 nt_hash
->hash
, &challenge
,
100 &lm_response
, &nt_response
,
101 NULL
, &session_key
)) {
102 return NT_STATUS_NO_MEMORY
;
105 /* LM Key is incompatible... */
106 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
107 } else if (*flags
& CLI_CRED_NTLM2
) {
108 struct MD5Context md5_session_nonce_ctx
;
109 uint8_t session_nonce
[16];
110 uint8_t session_nonce_hash
[16];
111 uint8_t user_session_key
[16];
113 lm_response
= data_blob_talloc(mem_ctx
, NULL
, 24);
114 generate_random_buffer(lm_response
.data
, 8);
115 memset(lm_response
.data
+8, 0, 16);
117 memcpy(session_nonce
, challenge
.data
, 8);
118 memcpy(&session_nonce
[8], lm_response
.data
, 8);
120 MD5Init(&md5_session_nonce_ctx
);
121 MD5Update(&md5_session_nonce_ctx
, challenge
.data
, 8);
122 MD5Update(&md5_session_nonce_ctx
, lm_response
.data
, 8);
123 MD5Final(session_nonce_hash
, &md5_session_nonce_ctx
);
125 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
126 DEBUG(5, ("challenge is: \n"));
127 dump_data(5, session_nonce_hash
, 8);
129 nt_response
= data_blob_talloc(mem_ctx
, NULL
, 24);
130 SMBOWFencrypt(nt_hash
->hash
,
134 session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
136 SMBsesskeygen_ntv1(nt_hash
->hash
, user_session_key
);
137 hmac_md5(user_session_key
, session_nonce
, sizeof(session_nonce
), session_key
.data
);
138 dump_data_pw("NTLM2 session key:\n", session_key
.data
, session_key
.length
);
140 /* LM Key is incompatible... */
141 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
143 nt_response
= data_blob_talloc(mem_ctx
, NULL
, 24);
144 SMBOWFencrypt(nt_hash
->hash
, challenge
.data
,
147 session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
148 SMBsesskeygen_ntv1(nt_hash
->hash
, session_key
.data
);
149 dump_data_pw("NT session key:\n", session_key
.data
, session_key
.length
);
151 /* lanman auth is insecure, it may be disabled.
152 We may also not have a password */
153 if (*flags
& CLI_CRED_LANMAN_AUTH
) {
154 const char *password
;
155 password
= cli_credentials_get_password(cred
);
157 lm_response
= nt_response
;
160 lm_response
= data_blob_talloc(mem_ctx
, NULL
, 24);
161 if (!SMBencrypt(password
,challenge
.data
,
163 /* If the LM password was too long (and therefore the LM hash being
164 of the first 14 chars only), don't send it.
166 We don't have any better options but to send the NT response
168 data_blob_free(&lm_response
);
169 lm_response
= nt_response
;
170 /* LM Key is incompatible with 'long' passwords */
171 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
173 E_deshash(password
, lm_hash
);
174 lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
175 memcpy(lm_session_key
.data
, lm_hash
, 8);
176 memset(&lm_session_key
.data
[8], '\0', 8);
178 if (!(*flags
& CLI_CRED_NTLM_AUTH
)) {
179 session_key
= lm_session_key
;
184 /* LM Key is incompatible... */
185 lm_response
= nt_response
;
186 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
190 *_lm_response
= lm_response
;
193 *_nt_response
= nt_response
;
195 if (_lm_session_key
) {
196 *_lm_session_key
= lm_session_key
;
199 *_session_key
= session_key
;