Print this page
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
SUP-513 Unable to join AD domain (fix lint)
SUP-513 Unable to join AD domain (with NtlmMinSeverSec set in the registry)
Implement "Extended Session Security" and "Key Exchange" in NTLMSSP
re #12739 rb4271 AD join with lmauth_level=2 fails
re #12394 rb3934 Even NULL sessions should use SPNEGO
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libsmbfs/smb/ntlmssp.c
+++ new/usr/src/lib/libsmbfs/smb/ntlmssp.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
25 25 */
26 26
27 27 /*
28 28 * NT Lan Manager Security Support Provider (NTLMSSP)
29 29 *
30 30 * Based on information from the "Davenport NTLM" page:
31 31 * http://davenport.sourceforge.net/ntlm.html
32 32 */
33 33
34 34
35 35 #include <errno.h>
36 36 #include <stdio.h>
37 37 #include <stddef.h>
38 38 #include <stdlib.h>
39 39 #include <unistd.h>
40 40 #include <strings.h>
41 41 #include <netdb.h>
42 42 #include <libintl.h>
43 43 #include <xti.h>
44 44 #include <assert.h>
45 45
46 46 #include <sys/types.h>
47 47 #include <sys/time.h>
48 48 #include <sys/byteorder.h>
49 49 #include <sys/socket.h>
50 50 #include <sys/fcntl.h>
51 51
52 52 #include <netinet/in.h>
53 53 #include <netinet/tcp.h>
54 54 #include <arpa/inet.h>
55 55
56 56 #include <netsmb/smb.h>
57 57 #include <netsmb/smb_lib.h>
58 58 #include <netsmb/mchain.h>
59 59
|
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
60 60 #include "private.h"
61 61 #include "charsets.h"
62 62 #include "smb_crypt.h"
63 63 #include "spnego.h"
64 64 #include "derparse.h"
65 65 #include "ssp.h"
66 66 #include "ntlm.h"
67 67 #include "ntlmssp.h"
68 68
69 69 /* A shorter alias for a crazy long name from [MS-NLMP] */
70 -#define NTLMSSP_NEGOTIATE_NTLM2 \
70 +#define NTLMSSP_NEGOTIATE_ESS \
71 71 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
72 72
73 73 typedef struct ntlmssp_state {
74 74 uint32_t ss_flags;
75 75 char *ss_target_name; /* Primary domain or server name */
76 76 struct mbuf *ss_target_info;
77 + uchar_t ss_ssnkey[NTLM_HASH_SZ];
77 78 uchar_t ss_kxkey[NTLM_HASH_SZ];
78 79 } ntlmssp_state_t;
79 80
80 81 /*
81 82 * So called "security buffer".
82 83 * A lot like an RPC string.
83 84 */
84 85 struct sec_buf {
85 86 uint16_t sb_length;
86 87 uint16_t sb_maxlen;
87 88 uint32_t sb_offset;
88 89 };
89 90 #define ID_SZ 8
90 91 static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
91 92
92 93 static int
93 -ntlm_rand_ssn_key(struct smb_ctx *ctx,
94 - ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
94 +ntlm_rand_ssn_key(ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
95 95
96 96 /*
97 97 * Get a "security buffer" (header part)
98 98 */
99 99 static int
100 100 md_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
101 101 {
102 102 int err;
103 103
104 104 (void) md_get_uint16le(mbp, &sb->sb_length);
105 105 (void) md_get_uint16le(mbp, &sb->sb_maxlen);
106 106 err = md_get_uint32le(mbp, &sb->sb_offset);
107 107
108 108 return (err);
109 109 }
110 110
111 111 /*
112 112 * Get a "security buffer" (data part), where
113 113 * the data is delivered as an mbuf.
114 114 */
115 115 static int
116 116 md_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp)
117 117 {
118 118 struct mbdata tmp_mb;
119 119 int err;
120 120
121 121 /*
122 122 * Setup tmp_mb to point to the start of the header.
123 123 * This is a dup ref - do NOT free it.
124 124 */
125 125 mb_initm(&tmp_mb, mbp->mb_top);
126 126
127 127 /* Skip data up to the offset. */
128 128 err = md_get_mem(&tmp_mb, NULL, sb->sb_offset, MB_MSYSTEM);
129 129 if (err)
130 130 return (err);
131 131
132 132 /* Get the data (as an mbuf). */
133 133 err = md_get_mbuf(&tmp_mb, sb->sb_maxlen, mp);
134 134
135 135 return (err);
136 136 }
137 137
138 138 /*
139 139 * Put a "security buffer" (header part)
140 140 */
141 141 static int
142 142 mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
143 143 {
144 144 int err;
145 145
146 146 (void) mb_put_uint16le(mbp, sb->sb_length);
147 147 (void) mb_put_uint16le(mbp, sb->sb_maxlen);
148 148 err = mb_put_uint32le(mbp, sb->sb_offset);
149 149
150 150 return (err);
151 151 }
152 152
153 153 /*
154 154 * Put a "security buffer" (data part), where
155 155 * the data is an mbuf. Note: consumes m.
156 156 */
157 157 static int
158 158 mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
159 159 {
160 160 int cnt0;
161 161 int err = 0;
162 162
163 163 sb->sb_offset = cnt0 = mbp->mb_count;
164 164 if (m != NULL)
165 165 err = mb_put_mbuf(mbp, m);
166 166 sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0;
167 167
168 168 return (err);
169 169 }
170 170
171 171 /*
172 172 * Put a "security buffer" (data part), where
173 173 * the data is a string (OEM or unicode).
174 174 *
175 175 * The string is NOT null terminated.
176 176 */
177 177 static int
178 178 mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb,
179 179 const char *str, int unicode)
180 180 {
181 181 int err, trim;
182 182 struct mbdata tmp_mb;
183 183
184 184 bzero(&tmp_mb, sizeof (tmp_mb));
185 185
186 186 if (str != NULL && *str != '\0') {
187 187 /*
188 188 * Put the string into a temp. mbuf,
189 189 * then chop off the null terminator
190 190 * before appending to caller's mbp.
191 191 */
192 192 err = mb_init(&tmp_mb);
193 193 if (err)
194 194 return (err);
195 195 err = mb_put_string(&tmp_mb, str, unicode);
196 196 if (err)
197 197 return (err);
198 198
199 199 trim = (unicode) ? 2 : 1;
200 200 if (tmp_mb.mb_cur->m_len < trim)
201 201 trim = 0;
202 202 tmp_mb.mb_cur->m_len -= trim;
203 203 }
204 204
205 205 err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top);
206 206 /*
207 207 * Note: tmp_mb.mb_top (if any) is consumed,
208 208 * so do NOT free it (no mb_done)
209 209 */
210 210 return (err);
211 211 }
212 212
213 213 /*
214 214 * Build a Type 1 message
215 215 *
216 216 * This message has a header section containing offsets to
217 217 * data later in the message. We use the common trick of
218 218 * building it in two parts and then concatenatening.
219 219 */
220 220 int
221 221 ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
222 222 {
223 223 struct type1hdr {
224 224 char h_id[ID_SZ];
225 225 uint32_t h_type;
226 226 uint32_t h_flags;
227 227 struct sec_buf h_cldom;
228 228 struct sec_buf h_wksta;
229 229 } hdr;
230 230 struct mbdata mb2; /* 2nd part */
231 231 int err;
232 232 struct smb_ctx *ctx = sp->smb_ctx;
233 233 ntlmssp_state_t *ssp_st = sp->sp_private;
234 234
235 235 if ((err = mb_init(&mb2)) != 0)
236 236 return (err);
237 237 mb2.mb_count = sizeof (hdr);
238 238
239 239 /*
240 240 * The initial negotiation flags represent the union of all
241 241 * options we support. The server selects from these.
|
↓ open down ↓ |
137 lines elided |
↑ open up ↑ |
242 242 * See: [MS-NLMP 2.2.2.5 NEGOTIATE]
243 243 */
244 244 ssp_st->ss_flags =
245 245 NTLMSSP_NEGOTIATE_UNICODE |
246 246 NTLMSSP_NEGOTIATE_OEM |
247 247 NTLMSSP_REQUEST_TARGET |
248 248 NTLMSSP_NEGOTIATE_SIGN |
249 249 NTLMSSP_NEGOTIATE_SEAL |
250 250 /* NTLMSSP_NEGOTIATE_LM_KEY (never) */
251 251 NTLMSSP_NEGOTIATE_NTLM |
252 - /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
253 - NTLMSSP_NEGOTIATE_NTLM2 |
252 + NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
253 + NTLMSSP_NEGOTIATE_ESS |
254 254 NTLMSSP_NEGOTIATE_128 |
255 255 NTLMSSP_NEGOTIATE_KEY_EXCH |
256 256 NTLMSSP_NEGOTIATE_56;
257 257
258 - if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
259 - ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
260 - ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
261 - }
258 + if ((ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED) == 0)
259 + ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
262 260
263 261 bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
264 262 hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
265 263 hdr.h_flags = ssp_st->ss_flags;
266 264
267 265 /*
268 266 * We could put the client domain, client name strings
269 267 * here, (always in OEM format, upper-case), and set
270 268 * NTLMSSP_NEGOTIATE_OEM_..._SUPPLIED, but Windows
271 269 * leaves these NULL so let's do the same.
272 270 */
273 271 (void) mb_put_sb_string(&mb2, &hdr.h_cldom, NULL, 0);
274 272 (void) mb_put_sb_string(&mb2, &hdr.h_wksta, NULL, 0);
275 273
276 274 /*
277 275 * Marshal the header (in LE order)
278 276 * then concatenate the 2nd part.
279 277 */
280 278 (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
281 279 (void) mb_put_uint32le(out_mb, hdr.h_type);
282 280 (void) mb_put_uint32le(out_mb, hdr.h_flags);
283 281 (void) mb_put_sb_hdr(out_mb, &hdr.h_cldom);
284 282 (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
285 283
286 284 err = mb_put_mbuf(out_mb, mb2.mb_top);
287 285
288 286 return (err);
289 287 }
290 288
291 289 /*
292 290 * Parse a Type 2 message
293 291 */
294 292 int
295 293 ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
296 294 {
297 295 struct type2hdr {
298 296 char h_id[ID_SZ];
299 297 uint32_t h_type;
300 298 struct sec_buf h_target_name;
301 299 uint32_t h_flags;
302 300 uint8_t h_challenge[8];
303 301 uint32_t h_context[2]; /* optional */
304 302 struct sec_buf h_target_info; /* optional */
305 303 } hdr;
306 304 struct mbdata top_mb, tmp_mb;
307 305 struct mbuf *m;
308 306 int err, uc;
309 307 int min_hdr_sz = offsetof(struct type2hdr, h_context);
310 308 struct smb_ctx *ctx = sp->smb_ctx;
311 309 ntlmssp_state_t *ssp_st = sp->sp_private;
312 310 char *buf = NULL;
313 311
314 312 if (m_totlen(in_mb->mb_top) < min_hdr_sz) {
315 313 err = EBADRPC;
316 314 goto out;
317 315 }
318 316
319 317 /*
320 318 * Save the mbdata pointers before we consume anything.
321 319 * Careful to NOT free this (would be dup. free)
322 320 * We use this below to find data based on offsets
323 321 * from the start of the header.
324 322 */
325 323 top_mb = *in_mb;
326 324
327 325 /* Parse the fixed size header stuff. */
328 326 bzero(&hdr, sizeof (hdr));
329 327 (void) md_get_mem(in_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
330 328 (void) md_get_uint32le(in_mb, &hdr.h_type);
331 329 if (hdr.h_type != NTLMSSP_MSGTYPE_CHALLENGE) {
332 330 err = EPROTO;
333 331 goto out;
334 332 }
335 333 (void) md_get_sb_hdr(in_mb, &hdr.h_target_name);
336 334 (void) md_get_uint32le(in_mb, &hdr.h_flags);
337 335 (void) md_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ, MB_MSYSTEM);
338 336
339 337 /*
340 338 * Save flags, server challenge for later.
341 339 */
342 340 ssp_st->ss_flags = hdr.h_flags;
343 341 bcopy(&hdr.h_challenge, ctx->ct_srv_chal, NTLM_CHAL_SZ);
344 342
345 343 /*
346 344 * Turn off flags that might have been given but
347 345 * that we don't want to send with authenticate.
348 346 */
349 347 uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE;
350 348 ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_VERSION;
351 349
352 350 /*
353 351 * Now find out if the optional parts are there.
354 352 */
355 353 if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) &&
356 354 (hdr.h_target_name.sb_offset >= sizeof (hdr))) {
357 355 (void) md_get_uint32le(in_mb, &hdr.h_context[0]);
358 356 (void) md_get_uint32le(in_mb, &hdr.h_context[1]);
359 357 (void) md_get_sb_hdr(in_mb, &hdr.h_target_info);
360 358 }
361 359
362 360 /*
363 361 * Get the target name string. (Server name or
364 362 * Primary domain name.) First get a copy of the
365 363 * data from the offset/length indicated in the
366 364 * security buffer header; then parse the string.
367 365 */
368 366 err = md_get_sb_data(&top_mb, &hdr.h_target_name, &m);
369 367 if (err)
370 368 goto out;
371 369 mb_initm(&tmp_mb, m);
372 370 err = md_get_string(&tmp_mb, &ssp_st->ss_target_name, uc);
373 371 mb_done(&tmp_mb);
374 372
375 373 /*
376 374 * Get the target info blob, if present.
377 375 */
378 376 if (hdr.h_target_info.sb_offset >= sizeof (hdr)) {
379 377 err = md_get_sb_data(&top_mb, &hdr.h_target_info,
380 378 &ssp_st->ss_target_info);
381 379 }
382 380
383 381 out:
384 382 if (buf != NULL)
385 383 free(buf);
386 384
387 385 return (err);
388 386 }
389 387
390 388 /*
391 389 * Build a Type 3 message
392 390 *
393 391 * This message has a header section containing offsets to
394 392 * data later in the message. We use the common trick of
395 393 * building it in two parts and then concatenatening.
396 394 */
397 395 int
398 396 ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
399 397 {
400 398 struct type3hdr {
401 399 char h_id[ID_SZ];
402 400 uint32_t h_type;
403 401 struct sec_buf h_lm_resp;
404 402 struct sec_buf h_nt_resp;
405 403 struct sec_buf h_domain;
406 404 struct sec_buf h_user;
407 405 struct sec_buf h_wksta;
408 406 struct sec_buf h_ssn_key;
409 407 uint32_t h_flags;
410 408 /* Version struct (ommitted) */
411 409 uchar_t h_mic[NTLM_HASH_SZ];
412 410 } hdr;
413 411 struct mbdata lm_mbc; /* LM response */
414 412 struct mbdata nt_mbc; /* NT response */
415 413 struct mbdata ti_mbc; /* target info */
416 414 struct mbdata ek_mbc; /* encrypted session key */
417 415 struct mbdata mb2; /* payload */
418 416 int err, uc;
419 417 struct smb_ctx *ctx = sp->smb_ctx;
420 418 ntlmssp_state_t *ssp_st = sp->sp_private;
421 419 uchar_t *pmic;
422 420
423 421 bzero(&hdr, sizeof (hdr));
424 422 bzero(&lm_mbc, sizeof (lm_mbc));
425 423 bzero(&nt_mbc, sizeof (nt_mbc));
426 424 bzero(&ti_mbc, sizeof (ti_mbc));
427 425 bzero(&ek_mbc, sizeof (ek_mbc));
428 426 bzero(&mb2, sizeof (mb2));
429 427
430 428 /*
431 429 * Fill in the NTLMSSP header, etc.
432 430 */
433 431 if ((err = mb_init(&mb2)) != 0)
434 432 goto out;
435 433 mb2.mb_count = sizeof (hdr);
436 434 uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
437 435
438 436 bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
439 437 hdr.h_type = NTLMSSP_MSGTYPE_AUTHENTICATE;
|
↓ open down ↓ |
168 lines elided |
↑ open up ↑ |
440 438 hdr.h_flags = ssp_st->ss_flags;
441 439
442 440 /*
443 441 * Put the NTLMv2/LMv2 or NTLM/LM (v1) responses,
444 442 * and compute the session key, etc.
445 443 */
446 444 if (ctx->ct_authflags & SMB_AT_ANON) {
447 445 /*
448 446 * We're setting up a NULL session, meaning
449 447 * the lm_mbc, nt_mbc parts remain empty.
450 - * Let's add the "anon" flag (hint).
451 - * As there is no session key, disable the
452 - * fancy session key stuff.
448 + * Let's add the "anon" flag (hint), and
449 + * as we have no OWF hashes, we can't use
450 + * "extended session security" (_ESS).
451 + * The SessionBaseKey is all zeros, so
452 + * the KeyExchangeKey is too. Otherwise
453 + * this is like NTLMv2/LMv2
453 454 */
454 - hdr.h_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
455 - ssp_st->ss_flags &= ~(
456 - NTLMSSP_NEGOTIATE_NTLM2 |
457 - NTLMSSP_NEGOTIATE_KEY_EXCH);
455 + ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
456 + ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ESS;
457 + hdr.h_flags = ssp_st->ss_flags;
458 458 err = 0;
459 + /* KeyExchangeKey = SessionBaseKey = (zeros) */
460 + memset(ssp_st->ss_ssnkey, 0, NTLM_HASH_SZ);
461 + memset(ssp_st->ss_kxkey, 0, NTLM_HASH_SZ);
459 462 } else if (ctx->ct_authflags & SMB_AT_NTLM2) {
460 463 /*
461 464 * Doing NTLMv2/LMv2
462 465 */
463 466 err = ntlm_build_target_info(ctx,
464 467 ssp_st->ss_target_info, &ti_mbc);
465 468 if (err)
466 469 goto out;
467 470 err = ntlm_put_v2_responses(ctx, &ti_mbc,
468 - &lm_mbc, &nt_mbc);
471 + &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
469 472 if (err)
470 473 goto out;
471 - /* The "key exg. key" is the session base key */
472 - memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
473 -
474 - } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_NTLM2) {
474 + /* KeyExchangeKey = SessionBaseKey (v2) */
475 + memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
476 + } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_ESS) {
475 477 /*
476 478 * Doing NTLM ("v1x") which is NTLM with
477 479 * "Extended Session Security"
478 480 */
479 481 err = ntlm_put_v1x_responses(ctx,
480 - &lm_mbc, &nt_mbc);
482 + &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
481 483 if (err)
482 484 goto out;
483 - /* Compute the "Key exchange key". */
484 - ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_kxkey);
485 + /*
486 + * "v1x computes the KeyExchangeKey from both the
487 + * server and client nonce and (v1) SessionBaseKey.
488 + */
489 + ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_ssnkey,
490 + ssp_st->ss_kxkey);
485 491 } else {
486 492 /*
487 493 * Doing plain old NTLM (and LM if enabled)
488 494 */
489 495 err = ntlm_put_v1_responses(ctx,
490 - &lm_mbc, &nt_mbc);
496 + &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
491 497 if (err)
492 498 goto out;
493 - /* The "key exg. key" is the session base key */
494 - memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
499 + /* KeyExchangeKey = SessionBaseKey (v1) */
500 + memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
495 501 }
496 502
497 503 /*
498 - * Compute the "Exported Session Key" and (possibly)
499 - * the "Encrypted Random Sesion Key".
500 - * [MS-NLMP 3.1.5.1.2]
504 + * Compute the "ExportedSessionKey" and (possibly) the
505 + * "EncryptedRandomSesionKey". [MS-NLMP 3.1.5.1.2]
501 506 */
502 507 if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
503 - err = ntlm_rand_ssn_key(ctx, ssp_st, &ek_mbc);
508 + err = ntlm_rand_ssn_key(ssp_st, &ek_mbc);
504 509 if (err)
505 510 goto out;
506 511 } else {
507 512 /* ExportedSessionKey is the KeyExchangeKey */
508 - memcpy(ctx->ct_ssn_key, ssp_st->ss_kxkey, NTLM_HASH_SZ);
513 + memcpy(ssp_st->ss_ssnkey, ssp_st->ss_kxkey, NTLM_HASH_SZ);
509 514 /* EncryptedRandomSessionKey remains NULL */
510 515 }
511 516
512 517 err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
513 518 lm_mbc.mb_top = NULL; /* consumed */
514 519 if (err)
515 520 goto out;
516 521 err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top);
517 522 nt_mbc.mb_top = NULL; /* consumed */
518 523 if (err)
519 524 goto out;
520 525
521 526 /*
522 527 * Put the "target" (domain), user, workstation
523 528 */
524 529 err = mb_put_sb_string(&mb2, &hdr.h_domain, ctx->ct_domain, uc);
525 530 if (err)
526 531 goto out;
527 532 err = mb_put_sb_string(&mb2, &hdr.h_user, ctx->ct_user, uc);
528 533 if (err)
529 534 goto out;
530 535 err = mb_put_sb_string(&mb2, &hdr.h_wksta, ctx->ct_locname, uc);
531 536 if (err)
532 537 goto out;
533 538
534 539 /*
535 540 * Put the "Encrypted Random Session Key", if any.
536 541 * (ek_mbc.mb_top may be NULL)
537 542 */
538 543 err = mb_put_sb_data(&mb2, &hdr.h_ssn_key, ek_mbc.mb_top);
539 544 ek_mbc.mb_top = NULL; /* consumed (if any) */
540 545 if (err)
541 546 goto out;
542 547
543 548 /*
544 549 * Marshal the header (in LE order)
545 550 * then concatenate the 2nd part.
546 551 */
547 552 (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
548 553 (void) mb_put_uint32le(out_mb, hdr.h_type);
549 554
550 555 (void) mb_put_sb_hdr(out_mb, &hdr.h_lm_resp);
551 556 (void) mb_put_sb_hdr(out_mb, &hdr.h_nt_resp);
552 557
553 558 (void) mb_put_sb_hdr(out_mb, &hdr.h_domain);
554 559 (void) mb_put_sb_hdr(out_mb, &hdr.h_user);
555 560 (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
556 561
557 562 (void) mb_put_sb_hdr(out_mb, &hdr.h_ssn_key);
558 563 (void) mb_put_uint32le(out_mb, hdr.h_flags);
559 564
560 565 /* Put zeros for the MIC - filled in later */
561 566 pmic = mb_reserve(out_mb, NTLM_HASH_SZ);
562 567
563 568 /* Put the payload. */
564 569 err = mb_put_mbuf(out_mb, mb2.mb_top);
565 570 mb2.mb_top = NULL; /* consumed */
566 571
567 572 /*
568 573 * Compute the MIC and stuff that in...
569 574 * The MIC is apparently optional.
570 575 */
571 576 (void) pmic;
572 577
573 578 out:
574 579 mb_done(&mb2);
575 580 mb_done(&lm_mbc);
576 581 mb_done(&nt_mbc);
577 582 mb_done(&ti_mbc);
578 583 mb_done(&ek_mbc);
579 584
580 585 return (err);
581 586 }
582 587
|
↓ open down ↓ |
64 lines elided |
↑ open up ↑ |
583 588 /*
584 589 * Helper for ntlmssp_put_type3 when doing key exchange.
585 590 *
586 591 * "ExportedSessionKey" is what we give to the "application"
587 592 * layer, which in here means the MAC key for SMB signing.
588 593 * With "key exchange", we replace the ExportedSessionKey
589 594 * with random data and send that (encrypted) to the peer.
590 595 */
591 596 static int
592 597 ntlm_rand_ssn_key(
593 - struct smb_ctx *ctx,
594 598 ntlmssp_state_t *ssp_st,
595 599 struct mbdata *ek_mbp)
596 600 {
597 601
598 602 uchar_t *encr_ssn_key;
599 603 int err;
600 604
601 605 if ((err = mb_init(ek_mbp)) != 0)
602 606 return (err);
603 607 encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ);
604 608
605 609 /* Set "ExportedSessionKey to NONCE(16) */
606 - (void) smb_get_urandom(ctx->ct_ssn_key, NTLM_HASH_SZ);
610 + (void) smb_get_urandom(ssp_st->ss_ssnkey, NTLM_HASH_SZ);
607 611
608 612 /* Set "EncryptedRandomSessionKey" to RC4(...) */
609 613 err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ,
610 614 ssp_st->ss_kxkey, NTLM_HASH_SZ,
611 - ctx->ct_ssn_key, NTLM_HASH_SZ);
615 + ssp_st->ss_ssnkey, NTLM_HASH_SZ);
612 616
613 617 return (err);
614 618 }
615 619
616 620 /*
617 621 * ntlmssp_final
618 622 *
619 623 * Called after successful authentication.
620 - * Setup the MAC key for signing.
624 + * Save the session key.
621 625 */
622 626 int
623 627 ntlmssp_final(struct ssp_ctx *sp)
624 628 {
625 629 struct smb_ctx *ctx = sp->smb_ctx;
630 + ntlmssp_state_t *ssp_st = sp->sp_private;
626 631 int err = 0;
627 632
628 633 /*
629 - * MAC_key is just the session key, but
630 - * Only on the first successful auth.
634 + * Update/save the session key.
631 635 */
632 - if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
633 - (ctx->ct_mackey == NULL)) {
634 - ctx->ct_mackeylen = NTLM_HASH_SZ;
635 - ctx->ct_mackey = malloc(ctx->ct_mackeylen);
636 - if (ctx->ct_mackey == NULL) {
637 - ctx->ct_mackeylen = 0;
638 - err = ENOMEM;
639 - goto out;
640 - }
641 - memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
642 - /*
643 - * Apparently, the server used seq. no. zero
644 - * for our previous message, so next is two.
645 - */
646 - ctx->ct_mac_seqno = 2;
636 + if (ctx->ct_ssnkey_buf != NULL) {
637 + free(ctx->ct_ssnkey_buf);
638 + ctx->ct_ssnkey_buf = NULL;
647 639 }
640 + ctx->ct_ssnkey_buf = malloc(NTLM_HASH_SZ);
641 + if (ctx->ct_ssnkey_buf == NULL) {
642 + err = ENOMEM;
643 + goto out;
644 + }
645 + ctx->ct_ssnkey_len = NTLM_HASH_SZ;
646 + memcpy(ctx->ct_ssnkey_buf, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
648 647
649 648 out:
650 649 return (err);
651 650 }
652 651
653 652 /*
654 653 * ntlmssp_next_token
655 654 *
656 655 * See ssp.c: ssp_ctx_next_token
657 656 */
658 657 int
659 658 ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
660 659 struct mbdata *out_mb)
661 660 {
662 661 int err;
663 662
664 663 if (out_mb == NULL) {
665 664 /* final call on successful auth. */
666 665 err = ntlmssp_final(sp);
667 666 goto out;
668 667 }
669 668
670 669 /* Will build an ouptut token. */
671 670 err = mb_init(out_mb);
672 671 if (err)
673 672 goto out;
674 673
675 674 /*
676 675 * When called with in_mb == NULL, it means
677 676 * this is the first call for this session,
678 677 * so put a Type 1 (initialize) token.
679 678 */
680 679 if (in_mb == NULL) {
681 680 err = ntlmssp_put_type1(sp, out_mb);
682 681 goto out;
683 682 }
684 683
685 684 /*
686 685 * This is not the first call, so
687 686 * parse the response token we received.
688 687 * It should be a Type 2 (challenge).
689 688 * Then put a Type 3 (authenticate)
690 689 */
691 690 err = ntlmssp_get_type2(sp, in_mb);
692 691 if (err)
693 692 goto out;
694 693
695 694 err = ntlmssp_put_type3(sp, out_mb);
696 695
697 696 out:
698 697 if (err)
699 698 DPRINT("ret: %d", err);
700 699 return (err);
701 700 }
702 701
703 702 /*
704 703 * ntlmssp_ctx_destroy
705 704 *
706 705 * Destroy mechanism-specific data.
707 706 */
708 707 void
709 708 ntlmssp_destroy(struct ssp_ctx *sp)
710 709 {
711 710 ntlmssp_state_t *ssp_st;
712 711
713 712 ssp_st = sp->sp_private;
714 713 if (ssp_st != NULL) {
715 714 sp->sp_private = NULL;
716 715 free(ssp_st->ss_target_name);
717 716 m_freem(ssp_st->ss_target_info);
718 717 free(ssp_st);
719 718 }
720 719 }
|
↓ open down ↓ |
63 lines elided |
↑ open up ↑ |
721 720
722 721 /*
723 722 * ntlmssp_init_clnt
724 723 *
725 724 * Initialize a new NTLMSSP client context.
726 725 */
727 726 int
728 727 ntlmssp_init_client(struct ssp_ctx *sp)
729 728 {
730 729 ntlmssp_state_t *ssp_st;
730 + smb_ctx_t *ctx = sp->smb_ctx;
731 731
732 - if ((sp->smb_ctx->ct_authflags &
732 + if ((ctx->ct_authflags &
733 733 (SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
734 734 DPRINT("No NTLM authflags");
735 735 return (EINVAL);
736 736 }
737 737
738 + /* Get the client nonce. */
739 + (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
740 +
738 741 ssp_st = calloc(1, sizeof (*ssp_st));
739 742 if (ssp_st == NULL)
740 743 return (ENOMEM);
741 744
742 745 sp->sp_nexttok = ntlmssp_next_token;
743 746 sp->sp_destroy = ntlmssp_destroy;
744 747 sp->sp_private = ssp_st;
745 748
746 749 return (0);
747 750 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX