/src/samba/auth/ntlmssp/ntlmssp_util.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/Netbios implementation. |
3 | | Version 3.0 |
4 | | handle NLTMSSP, server side |
5 | | |
6 | | Copyright (C) Andrew Tridgell 2001 |
7 | | Copyright (C) Andrew Bartlett 2001-2003 |
8 | | Copyright (C) Andrew Bartlett 2005 (Updated from gensec). |
9 | | |
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 3 of the License, or |
13 | | (at your option) any later version. |
14 | | |
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. |
19 | | |
20 | | You should have received a copy of the GNU General Public License |
21 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
22 | | */ |
23 | | |
24 | | #include "includes.h" |
25 | | #include "auth/gensec/gensec.h" |
26 | | #include "auth/gensec/gensec_internal.h" |
27 | | #include "../auth/ntlmssp/ntlmssp.h" |
28 | | #include "../auth/ntlmssp/ntlmssp_private.h" |
29 | | |
30 | | #include "lib/crypto/gnutls_helpers.h" |
31 | | #include <gnutls/gnutls.h> |
32 | | #include <gnutls/crypto.h> |
33 | | |
34 | | #undef DBGC_CLASS |
35 | 0 | #define DBGC_CLASS DBGC_AUTH |
36 | | |
37 | | static void debug_ntlmssp_flags_raw(int level, uint32_t flags) |
38 | 0 | { |
39 | 0 | #define _PRINT_FLAG_LINE(v) do { \ |
40 | 0 | if (flags & (v)) { \ |
41 | 0 | DEBUGADD(level, (" " #v "\n")); \ |
42 | 0 | } \ |
43 | 0 | } while (0) |
44 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_UNICODE); |
45 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_OEM); |
46 | 0 | _PRINT_FLAG_LINE(NTLMSSP_REQUEST_TARGET); |
47 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_SIGN); |
48 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_SEAL); |
49 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_DATAGRAM); |
50 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_LM_KEY); |
51 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_NETWARE); |
52 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_NTLM); |
53 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_NT_ONLY); |
54 | 0 | _PRINT_FLAG_LINE(NTLMSSP_ANONYMOUS); |
55 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED); |
56 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED); |
57 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL); |
58 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_ALWAYS_SIGN); |
59 | 0 | _PRINT_FLAG_LINE(NTLMSSP_TARGET_TYPE_DOMAIN); |
60 | 0 | _PRINT_FLAG_LINE(NTLMSSP_TARGET_TYPE_SERVER); |
61 | 0 | _PRINT_FLAG_LINE(NTLMSSP_TARGET_TYPE_SHARE); |
62 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY); |
63 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_IDENTIFY); |
64 | 0 | _PRINT_FLAG_LINE(NTLMSSP_REQUEST_NON_NT_SESSION_KEY); |
65 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_TARGET_INFO); |
66 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_VERSION); |
67 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_128); |
68 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_KEY_EXCH); |
69 | 0 | _PRINT_FLAG_LINE(NTLMSSP_NEGOTIATE_56); |
70 | 0 | } |
71 | | |
72 | | /** |
73 | | * Print out the NTLMSSP flags for debugging |
74 | | * @param neg_flags The flags from the packet |
75 | | */ |
76 | | void debug_ntlmssp_flags(uint32_t neg_flags) |
77 | 0 | { |
78 | 0 | DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags)); |
79 | 0 | debug_ntlmssp_flags_raw(4, neg_flags); |
80 | 0 | } |
81 | | |
82 | | NTSTATUS ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, |
83 | | uint32_t flags, const char *name) |
84 | 0 | { |
85 | 0 | uint32_t missing_flags = ntlmssp_state->required_flags; |
86 | |
|
87 | 0 | if (ntlmssp_state->use_ntlmv2) { |
88 | | /* |
89 | | * Using NTLMv2 as a client implies |
90 | | * using NTLMSSP_NEGOTIATE_NTLM2 |
91 | | * (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) |
92 | | * |
93 | | * Note that 'use_ntlmv2' is only set |
94 | | * true in the client case. |
95 | | * |
96 | | * Even if the server has a bug and does not announce |
97 | | * it, we need to assume it's present. |
98 | | * |
99 | | * Note that we also have the flag |
100 | | * in ntlmssp_state->required_flags, |
101 | | * see gensec_ntlmssp_client_start(). |
102 | | * |
103 | | * See bug #12862. |
104 | | */ |
105 | 0 | flags |= NTLMSSP_NEGOTIATE_NTLM2; |
106 | 0 | } |
107 | |
|
108 | 0 | if (flags & NTLMSSP_NEGOTIATE_UNICODE) { |
109 | 0 | ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; |
110 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM; |
111 | 0 | ntlmssp_state->unicode = true; |
112 | 0 | } else { |
113 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE; |
114 | 0 | ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM; |
115 | 0 | ntlmssp_state->unicode = false; |
116 | 0 | } |
117 | | |
118 | | /* |
119 | | * NTLMSSP_NEGOTIATE_NTLM2 (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) |
120 | | * has priority over NTLMSSP_NEGOTIATE_LM_KEY |
121 | | */ |
122 | 0 | if (!(flags & NTLMSSP_NEGOTIATE_NTLM2)) { |
123 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; |
124 | 0 | } |
125 | |
|
126 | 0 | if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { |
127 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; |
128 | 0 | } |
129 | |
|
130 | 0 | if (!(flags & NTLMSSP_NEGOTIATE_LM_KEY)) { |
131 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; |
132 | 0 | } |
133 | |
|
134 | 0 | if (!(flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) { |
135 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN; |
136 | 0 | } |
137 | |
|
138 | 0 | if (!(flags & NTLMSSP_NEGOTIATE_128)) { |
139 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128; |
140 | 0 | } |
141 | |
|
142 | 0 | if (!(flags & NTLMSSP_NEGOTIATE_56)) { |
143 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56; |
144 | 0 | } |
145 | |
|
146 | 0 | if (!(flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { |
147 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH; |
148 | 0 | } |
149 | |
|
150 | 0 | if (!(flags & NTLMSSP_NEGOTIATE_SIGN)) { |
151 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN; |
152 | 0 | } |
153 | |
|
154 | 0 | if (!(flags & NTLMSSP_NEGOTIATE_SEAL)) { |
155 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL; |
156 | 0 | } |
157 | |
|
158 | 0 | if ((flags & NTLMSSP_REQUEST_TARGET)) { |
159 | 0 | ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET; |
160 | 0 | } |
161 | |
|
162 | 0 | missing_flags &= ~ntlmssp_state->neg_flags; |
163 | 0 | if (missing_flags != 0) { |
164 | 0 | HRESULT hres = HRES_SEC_E_UNSUPPORTED_FUNCTION; |
165 | 0 | NTSTATUS status = NT_STATUS(HRES_ERROR_V(hres)); |
166 | 0 | DEBUG(1, ("%s: Got %s flags[0x%08x] " |
167 | 0 | "- possible downgrade detected! " |
168 | 0 | "missing_flags[0x%08x] - %s\n", |
169 | 0 | __func__, name, |
170 | 0 | (unsigned)flags, |
171 | 0 | (unsigned)missing_flags, |
172 | 0 | nt_errstr(status))); |
173 | 0 | debug_ntlmssp_flags_raw(1, missing_flags); |
174 | 0 | DEBUGADD(4, ("neg_flags[0x%08x]\n", |
175 | 0 | (unsigned)ntlmssp_state->neg_flags)); |
176 | 0 | debug_ntlmssp_flags_raw(4, ntlmssp_state->neg_flags); |
177 | 0 | return status; |
178 | 0 | } |
179 | | |
180 | 0 | return NT_STATUS_OK; |
181 | 0 | } |
182 | | |
183 | | /* Does this blob looks like it could be NTLMSSP? */ |
184 | | bool ntlmssp_blob_matches_magic(const DATA_BLOB *blob) |
185 | 0 | { |
186 | 0 | if (blob->length > 8 && memcmp("NTLMSSP\0", blob->data, 8) == 0) { |
187 | 0 | return true; |
188 | 0 | } else { |
189 | 0 | return false; |
190 | 0 | } |
191 | 0 | } |
192 | | |
193 | | const DATA_BLOB ntlmssp_version_blob(void) |
194 | 0 | { |
195 | | /* |
196 | | * This is a simplified version of |
197 | | * |
198 | | * enum ndr_err_code err; |
199 | | * struct ntlmssp_VERSION vers; |
200 | | * |
201 | | * ZERO_STRUCT(vers); |
202 | | * vers.ProductMajorVersion = NTLMSSP_WINDOWS_MAJOR_VERSION_6; |
203 | | * vers.ProductMinorVersion = NTLMSSP_WINDOWS_MINOR_VERSION_1; |
204 | | * vers.ProductBuild = 0; |
205 | | * vers.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; |
206 | | * |
207 | | * err = ndr_push_struct_blob(&version_blob, |
208 | | * ntlmssp_state, |
209 | | * &vers, |
210 | | * (ndr_push_flags_fn_t)ndr_push_ntlmssp_VERSION); |
211 | | * |
212 | | * if (!NDR_ERR_CODE_IS_SUCCESS(err)) { |
213 | | * data_blob_free(&struct_blob); |
214 | | * return NT_STATUS_NO_MEMORY; |
215 | | * } |
216 | | */ |
217 | 0 | static const uint8_t version_buffer[8] = { |
218 | 0 | NTLMSSP_WINDOWS_MAJOR_VERSION_6, |
219 | 0 | NTLMSSP_WINDOWS_MINOR_VERSION_1, |
220 | 0 | 0x00, 0x00, /* product build */ |
221 | 0 | 0x00, 0x00, 0x00, /* reserved */ |
222 | 0 | NTLMSSP_REVISION_W2K3 |
223 | 0 | }; |
224 | |
|
225 | 0 | return data_blob_const(version_buffer, ARRAY_SIZE(version_buffer)); |
226 | 0 | } |
227 | | |
228 | | NTSTATUS ntlmssp_hash_channel_bindings(struct gensec_security *gensec_security, |
229 | | uint8_t cb_hash[16]) |
230 | 0 | { |
231 | 0 | const struct gensec_channel_bindings *cb = |
232 | 0 | gensec_security->channel_bindings; |
233 | 0 | gnutls_hash_hd_t hash_hnd = NULL; |
234 | 0 | uint8_t uint32buf[4]; |
235 | 0 | int rc; |
236 | |
|
237 | 0 | if (cb == NULL) { |
238 | 0 | memset(cb_hash, 0, 16); |
239 | 0 | return NT_STATUS_OK; |
240 | 0 | } |
241 | | |
242 | 0 | GNUTLS_FIPS140_SET_LAX_MODE(); |
243 | 0 | rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5); |
244 | 0 | if (rc < 0) { |
245 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
246 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
247 | 0 | } |
248 | | |
249 | 0 | SIVAL(uint32buf, 0, cb->initiator_addrtype); |
250 | 0 | rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf)); |
251 | 0 | if (rc < 0) { |
252 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
253 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
254 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
255 | 0 | } |
256 | 0 | SIVAL(uint32buf, 0, cb->initiator_address.length); |
257 | 0 | rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf)); |
258 | 0 | if (rc < 0) { |
259 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
260 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
261 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
262 | 0 | } |
263 | 0 | if (cb->initiator_address.length > 0) { |
264 | 0 | rc = gnutls_hash(hash_hnd, |
265 | 0 | cb->initiator_address.data, |
266 | 0 | cb->initiator_address.length); |
267 | 0 | if (rc < 0) { |
268 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
269 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
270 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
271 | 0 | } |
272 | 0 | } |
273 | 0 | SIVAL(uint32buf, 0, cb->acceptor_addrtype); |
274 | 0 | rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf)); |
275 | 0 | if (rc < 0) { |
276 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
277 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
278 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
279 | 0 | } |
280 | 0 | SIVAL(uint32buf, 0, cb->acceptor_address.length); |
281 | 0 | rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf)); |
282 | 0 | if (rc < 0) { |
283 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
284 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
285 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
286 | 0 | } |
287 | 0 | if (cb->acceptor_address.length > 0) { |
288 | 0 | rc = gnutls_hash(hash_hnd, |
289 | 0 | cb->acceptor_address.data, |
290 | 0 | cb->acceptor_address.length); |
291 | 0 | if (rc < 0) { |
292 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
293 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
294 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
295 | 0 | } |
296 | 0 | } |
297 | 0 | SIVAL(uint32buf, 0, cb->application_data.length); |
298 | 0 | rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf)); |
299 | 0 | if (rc < 0) { |
300 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
301 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
302 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
303 | 0 | } |
304 | 0 | if (cb->application_data.length > 0) { |
305 | 0 | rc = gnutls_hash(hash_hnd, |
306 | 0 | cb->application_data.data, |
307 | 0 | cb->application_data.length); |
308 | 0 | if (rc < 0) { |
309 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
310 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
311 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
312 | 0 | } |
313 | 0 | } |
314 | | |
315 | 0 | gnutls_hash_deinit(hash_hnd, cb_hash); |
316 | 0 | GNUTLS_FIPS140_SET_STRICT_MODE(); |
317 | 0 | return NT_STATUS_OK; |
318 | 0 | } |