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.
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.
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]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28 * NT Lan Manager Security Support Provider (NTLMSSP)
30 * Based on information from the "Davenport NTLM" page:
31 * http://davenport.sourceforge.net/ntlm.html
46 #include <sys/types.h>
48 #include <sys/byteorder.h>
49 #include <sys/socket.h>
50 #include <sys/fcntl.h>
52 #include <netinet/in.h>
53 #include <netinet/tcp.h>
54 #include <arpa/inet.h>
56 #include <netsmb/smb.h>
57 #include <netsmb/smb_lib.h>
58 #include <netsmb/mchain.h>
62 #include "smb_crypt.h"
69 /* A shorter alias for a crazy long name from [MS-NLMP] */
70 #define NTLMSSP_NEGOTIATE_NTLM2 \
71 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
73 typedef struct ntlmssp_state
{
75 char *ss_target_name
; /* Primary domain or server name */
76 struct mbuf
*ss_target_info
;
77 uchar_t ss_kxkey
[NTLM_HASH_SZ
];
81 * So called "security buffer".
82 * A lot like an RPC string.
90 static const char ntlmssp_id
[ID_SZ
] = "NTLMSSP";
93 ntlm_rand_ssn_key(struct smb_ctx
*ctx
,
94 ntlmssp_state_t
*ssp_st
, struct mbdata
*ek_mbp
);
97 * Get a "security buffer" (header part)
100 md_get_sb_hdr(struct mbdata
*mbp
, struct sec_buf
*sb
)
104 (void) md_get_uint16le(mbp
, &sb
->sb_length
);
105 (void) md_get_uint16le(mbp
, &sb
->sb_maxlen
);
106 err
= md_get_uint32le(mbp
, &sb
->sb_offset
);
112 * Get a "security buffer" (data part), where
113 * the data is delivered as an mbuf.
116 md_get_sb_data(struct mbdata
*mbp
, struct sec_buf
*sb
, struct mbuf
**mp
)
118 struct mbdata tmp_mb
;
122 * Setup tmp_mb to point to the start of the header.
123 * This is a dup ref - do NOT free it.
125 mb_initm(&tmp_mb
, mbp
->mb_top
);
127 /* Skip data up to the offset. */
128 err
= md_get_mem(&tmp_mb
, NULL
, sb
->sb_offset
, MB_MSYSTEM
);
132 /* Get the data (as an mbuf). */
133 err
= md_get_mbuf(&tmp_mb
, sb
->sb_maxlen
, mp
);
139 * Put a "security buffer" (header part)
142 mb_put_sb_hdr(struct mbdata
*mbp
, struct sec_buf
*sb
)
146 (void) mb_put_uint16le(mbp
, sb
->sb_length
);
147 (void) mb_put_uint16le(mbp
, sb
->sb_maxlen
);
148 err
= mb_put_uint32le(mbp
, sb
->sb_offset
);
154 * Put a "security buffer" (data part), where
155 * the data is an mbuf. Note: consumes m.
158 mb_put_sb_data(struct mbdata
*mbp
, struct sec_buf
*sb
, struct mbuf
*m
)
163 sb
->sb_offset
= cnt0
= mbp
->mb_count
;
165 err
= mb_put_mbuf(mbp
, m
);
166 sb
->sb_maxlen
= sb
->sb_length
= mbp
->mb_count
- cnt0
;
172 * Put a "security buffer" (data part), where
173 * the data is a string (OEM or unicode).
175 * The string is NOT null terminated.
178 mb_put_sb_string(struct mbdata
*mbp
, struct sec_buf
*sb
,
179 const char *str
, int unicode
)
182 struct mbdata tmp_mb
;
184 bzero(&tmp_mb
, sizeof (tmp_mb
));
186 if (str
!= NULL
&& *str
!= '\0') {
188 * Put the string into a temp. mbuf,
189 * then chop off the null terminator
190 * before appending to caller's mbp.
192 err
= mb_init(&tmp_mb
);
195 err
= mb_put_string(&tmp_mb
, str
, unicode
);
199 trim
= (unicode
) ? 2 : 1;
200 if (tmp_mb
.mb_cur
->m_len
< trim
)
202 tmp_mb
.mb_cur
->m_len
-= trim
;
205 err
= mb_put_sb_data(mbp
, sb
, tmp_mb
.mb_top
);
207 * Note: tmp_mb.mb_top (if any) is consumed,
208 * so do NOT free it (no mb_done)
214 * Build a Type 1 message
216 * This message has a header section containing offsets to
217 * data later in the message. We use the common trick of
218 * building it in two parts and then concatenatening.
221 ntlmssp_put_type1(struct ssp_ctx
*sp
, struct mbdata
*out_mb
)
227 struct sec_buf h_cldom
;
228 struct sec_buf h_wksta
;
230 struct mbdata mb2
; /* 2nd part */
232 struct smb_ctx
*ctx
= sp
->smb_ctx
;
233 ntlmssp_state_t
*ssp_st
= sp
->sp_private
;
235 if ((err
= mb_init(&mb2
)) != 0)
237 mb2
.mb_count
= sizeof (hdr
);
240 * The initial negotiation flags represent the union of all
241 * options we support. The server selects from these.
242 * See: [MS-NLMP 2.2.2.5 NEGOTIATE]
245 NTLMSSP_NEGOTIATE_UNICODE
|
246 NTLMSSP_NEGOTIATE_OEM
|
247 NTLMSSP_REQUEST_TARGET
|
248 NTLMSSP_NEGOTIATE_SIGN
|
249 NTLMSSP_NEGOTIATE_SEAL
|
250 /* NTLMSSP_NEGOTIATE_LM_KEY (never) */
251 NTLMSSP_NEGOTIATE_NTLM
|
252 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
253 NTLMSSP_NEGOTIATE_NTLM2
|
254 NTLMSSP_NEGOTIATE_128
|
255 NTLMSSP_NEGOTIATE_KEY_EXCH
|
256 NTLMSSP_NEGOTIATE_56
;
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
;
263 bcopy(ntlmssp_id
, &hdr
.h_id
, ID_SZ
);
264 hdr
.h_type
= NTLMSSP_MSGTYPE_NEGOTIATE
;
265 hdr
.h_flags
= ssp_st
->ss_flags
;
268 * We could put the client domain, client name strings
269 * here, (always in OEM format, upper-case), and set
270 * NTLMSSP_NEGOTIATE_OEM_..._SUPPLIED, but Windows
271 * leaves these NULL so let's do the same.
273 (void) mb_put_sb_string(&mb2
, &hdr
.h_cldom
, NULL
, 0);
274 (void) mb_put_sb_string(&mb2
, &hdr
.h_wksta
, NULL
, 0);
277 * Marshal the header (in LE order)
278 * then concatenate the 2nd part.
280 (void) mb_put_mem(out_mb
, &hdr
.h_id
, ID_SZ
, MB_MSYSTEM
);
281 (void) mb_put_uint32le(out_mb
, hdr
.h_type
);
282 (void) mb_put_uint32le(out_mb
, hdr
.h_flags
);
283 (void) mb_put_sb_hdr(out_mb
, &hdr
.h_cldom
);
284 (void) mb_put_sb_hdr(out_mb
, &hdr
.h_wksta
);
286 err
= mb_put_mbuf(out_mb
, mb2
.mb_top
);
292 * Parse a Type 2 message
295 ntlmssp_get_type2(struct ssp_ctx
*sp
, struct mbdata
*in_mb
)
300 struct sec_buf h_target_name
;
302 uint8_t h_challenge
[8];
303 uint32_t h_context
[2]; /* optional */
304 struct sec_buf h_target_info
; /* optional */
306 struct mbdata top_mb
, tmp_mb
;
309 int min_hdr_sz
= offsetof(struct type2hdr
, h_context
);
310 struct smb_ctx
*ctx
= sp
->smb_ctx
;
311 ntlmssp_state_t
*ssp_st
= sp
->sp_private
;
314 if (m_totlen(in_mb
->mb_top
) < min_hdr_sz
) {
320 * Save the mbdata pointers before we consume anything.
321 * Careful to NOT free this (would be dup. free)
322 * We use this below to find data based on offsets
323 * from the start of the header.
327 /* Parse the fixed size header stuff. */
328 bzero(&hdr
, sizeof (hdr
));
329 (void) md_get_mem(in_mb
, &hdr
.h_id
, ID_SZ
, MB_MSYSTEM
);
330 (void) md_get_uint32le(in_mb
, &hdr
.h_type
);
331 if (hdr
.h_type
!= NTLMSSP_MSGTYPE_CHALLENGE
) {
335 (void) md_get_sb_hdr(in_mb
, &hdr
.h_target_name
);
336 (void) md_get_uint32le(in_mb
, &hdr
.h_flags
);
337 (void) md_get_mem(in_mb
, &hdr
.h_challenge
, NTLM_CHAL_SZ
, MB_MSYSTEM
);
340 * Save flags, server challenge for later.
342 ssp_st
->ss_flags
= hdr
.h_flags
;
343 bcopy(&hdr
.h_challenge
, ctx
->ct_srv_chal
, NTLM_CHAL_SZ
);
346 * Turn off flags that might have been given but
347 * that we don't want to send with authenticate.
349 uc
= hdr
.h_flags
& NTLMSSP_NEGOTIATE_UNICODE
;
350 ssp_st
->ss_flags
&= ~NTLMSSP_NEGOTIATE_VERSION
;
353 * Now find out if the optional parts are there.
355 if ((m_totlen(top_mb
.mb_top
) > sizeof (hdr
)) &&
356 (hdr
.h_target_name
.sb_offset
>= sizeof (hdr
))) {
357 (void) md_get_uint32le(in_mb
, &hdr
.h_context
[0]);
358 (void) md_get_uint32le(in_mb
, &hdr
.h_context
[1]);
359 (void) md_get_sb_hdr(in_mb
, &hdr
.h_target_info
);
363 * Get the target name string. (Server name or
364 * Primary domain name.) First get a copy of the
365 * data from the offset/length indicated in the
366 * security buffer header; then parse the string.
368 err
= md_get_sb_data(&top_mb
, &hdr
.h_target_name
, &m
);
371 mb_initm(&tmp_mb
, m
);
372 err
= md_get_string(&tmp_mb
, &ssp_st
->ss_target_name
, uc
);
376 * Get the target info blob, if present.
378 if (hdr
.h_target_info
.sb_offset
>= sizeof (hdr
)) {
379 err
= md_get_sb_data(&top_mb
, &hdr
.h_target_info
,
380 &ssp_st
->ss_target_info
);
390 * Build a Type 3 message
392 * This message has a header section containing offsets to
393 * data later in the message. We use the common trick of
394 * building it in two parts and then concatenatening.
397 ntlmssp_put_type3(struct ssp_ctx
*sp
, struct mbdata
*out_mb
)
402 struct sec_buf h_lm_resp
;
403 struct sec_buf h_nt_resp
;
404 struct sec_buf h_domain
;
405 struct sec_buf h_user
;
406 struct sec_buf h_wksta
;
407 struct sec_buf h_ssn_key
;
409 /* Version struct (ommitted) */
410 uchar_t h_mic
[NTLM_HASH_SZ
];
412 struct mbdata lm_mbc
; /* LM response */
413 struct mbdata nt_mbc
; /* NT response */
414 struct mbdata ti_mbc
; /* target info */
415 struct mbdata ek_mbc
; /* encrypted session key */
416 struct mbdata mb2
; /* payload */
418 struct smb_ctx
*ctx
= sp
->smb_ctx
;
419 ntlmssp_state_t
*ssp_st
= sp
->sp_private
;
422 bzero(&hdr
, sizeof (hdr
));
423 bzero(&lm_mbc
, sizeof (lm_mbc
));
424 bzero(&nt_mbc
, sizeof (nt_mbc
));
425 bzero(&ti_mbc
, sizeof (ti_mbc
));
426 bzero(&ek_mbc
, sizeof (ek_mbc
));
427 bzero(&mb2
, sizeof (mb2
));
430 * Fill in the NTLMSSP header, etc.
432 if ((err
= mb_init(&mb2
)) != 0)
434 mb2
.mb_count
= sizeof (hdr
);
435 uc
= ssp_st
->ss_flags
& NTLMSSP_NEGOTIATE_UNICODE
;
437 bcopy(ntlmssp_id
, &hdr
.h_id
, ID_SZ
);
438 hdr
.h_type
= NTLMSSP_MSGTYPE_AUTHENTICATE
;
439 hdr
.h_flags
= ssp_st
->ss_flags
;
442 * Put the NTLMv2/LMv2 or NTLM/LM (v1) responses,
443 * and compute the session key, etc.
445 if (ctx
->ct_authflags
& SMB_AT_ANON
) {
447 * We're setting up a NULL session, meaning
448 * the lm_mbc, nt_mbc parts remain empty.
449 * Let's add the "anon" flag (hint).
450 * As there is no session key, disable the
451 * fancy session key stuff.
453 hdr
.h_flags
|= NTLMSSP_NEGOTIATE_NULL_SESSION
;
454 ssp_st
->ss_flags
&= ~(
455 NTLMSSP_NEGOTIATE_NTLM2
|
456 NTLMSSP_NEGOTIATE_KEY_EXCH
);
458 } else if (ctx
->ct_authflags
& SMB_AT_NTLM2
) {
462 err
= ntlm_build_target_info(ctx
,
463 ssp_st
->ss_target_info
, &ti_mbc
);
466 err
= ntlm_put_v2_responses(ctx
, &ti_mbc
,
470 /* The "key exg. key" is the session base key */
471 memcpy(ssp_st
->ss_kxkey
, ctx
->ct_ssn_key
, NTLM_HASH_SZ
);
473 } else if (ssp_st
->ss_flags
& NTLMSSP_NEGOTIATE_NTLM2
) {
475 * Doing NTLM ("v1x") which is NTLM with
476 * "Extended Session Security"
478 err
= ntlm_put_v1x_responses(ctx
,
482 /* Compute the "Key exchange key". */
483 ntlm2_kxkey(ctx
, &lm_mbc
, ssp_st
->ss_kxkey
);
486 * Doing plain old NTLM (and LM if enabled)
488 err
= ntlm_put_v1_responses(ctx
,
492 /* The "key exg. key" is the session base key */
493 memcpy(ssp_st
->ss_kxkey
, ctx
->ct_ssn_key
, NTLM_HASH_SZ
);
497 * Compute the "Exported Session Key" and (possibly)
498 * the "Encrypted Random Sesion Key".
499 * [MS-NLMP 3.1.5.1.2]
501 if (ssp_st
->ss_flags
& NTLMSSP_NEGOTIATE_KEY_EXCH
) {
502 err
= ntlm_rand_ssn_key(ctx
, ssp_st
, &ek_mbc
);
506 /* ExportedSessionKey is the KeyExchangeKey */
507 memcpy(ctx
->ct_ssn_key
, ssp_st
->ss_kxkey
, NTLM_HASH_SZ
);
508 /* EncryptedRandomSessionKey remains NULL */
511 err
= mb_put_sb_data(&mb2
, &hdr
.h_lm_resp
, lm_mbc
.mb_top
);
512 lm_mbc
.mb_top
= NULL
; /* consumed */
515 err
= mb_put_sb_data(&mb2
, &hdr
.h_nt_resp
, nt_mbc
.mb_top
);
516 nt_mbc
.mb_top
= NULL
; /* consumed */
521 * Put the "target" (domain), user, workstation
523 err
= mb_put_sb_string(&mb2
, &hdr
.h_domain
, ctx
->ct_domain
, uc
);
526 err
= mb_put_sb_string(&mb2
, &hdr
.h_user
, ctx
->ct_user
, uc
);
529 err
= mb_put_sb_string(&mb2
, &hdr
.h_wksta
, ctx
->ct_locname
, uc
);
534 * Put the "Encrypted Random Session Key", if any.
535 * (ek_mbc.mb_top may be NULL)
537 err
= mb_put_sb_data(&mb2
, &hdr
.h_ssn_key
, ek_mbc
.mb_top
);
538 ek_mbc
.mb_top
= NULL
; /* consumed (if any) */
543 * Marshal the header (in LE order)
544 * then concatenate the 2nd part.
546 (void) mb_put_mem(out_mb
, &hdr
.h_id
, ID_SZ
, MB_MSYSTEM
);
547 (void) mb_put_uint32le(out_mb
, hdr
.h_type
);
549 (void) mb_put_sb_hdr(out_mb
, &hdr
.h_lm_resp
);
550 (void) mb_put_sb_hdr(out_mb
, &hdr
.h_nt_resp
);
552 (void) mb_put_sb_hdr(out_mb
, &hdr
.h_domain
);
553 (void) mb_put_sb_hdr(out_mb
, &hdr
.h_user
);
554 (void) mb_put_sb_hdr(out_mb
, &hdr
.h_wksta
);
556 (void) mb_put_sb_hdr(out_mb
, &hdr
.h_ssn_key
);
557 (void) mb_put_uint32le(out_mb
, hdr
.h_flags
);
559 /* Put zeros for the MIC - filled in later */
560 pmic
= mb_reserve(out_mb
, NTLM_HASH_SZ
);
562 /* Put the payload. */
563 err
= mb_put_mbuf(out_mb
, mb2
.mb_top
);
564 mb2
.mb_top
= NULL
; /* consumed */
567 * Compute the MIC and stuff that in...
568 * The MIC is apparently optional.
583 * Helper for ntlmssp_put_type3 when doing key exchange.
585 * "ExportedSessionKey" is what we give to the "application"
586 * layer, which in here means the MAC key for SMB signing.
587 * With "key exchange", we replace the ExportedSessionKey
588 * with random data and send that (encrypted) to the peer.
593 ntlmssp_state_t
*ssp_st
,
594 struct mbdata
*ek_mbp
)
597 uchar_t
*encr_ssn_key
;
600 if ((err
= mb_init(ek_mbp
)) != 0)
602 encr_ssn_key
= mb_reserve(ek_mbp
, NTLM_HASH_SZ
);
604 /* Set "ExportedSessionKey to NONCE(16) */
605 (void) smb_get_urandom(ctx
->ct_ssn_key
, NTLM_HASH_SZ
);
607 /* Set "EncryptedRandomSessionKey" to RC4(...) */
608 err
= smb_encrypt_RC4(encr_ssn_key
, NTLM_HASH_SZ
,
609 ssp_st
->ss_kxkey
, NTLM_HASH_SZ
,
610 ctx
->ct_ssn_key
, NTLM_HASH_SZ
);
618 * Called after successful authentication.
619 * Setup the MAC key for signing.
622 ntlmssp_final(struct ssp_ctx
*sp
)
624 struct smb_ctx
*ctx
= sp
->smb_ctx
;
628 * MAC_key is just the session key, but
629 * Only on the first successful auth.
631 if ((ctx
->ct_hflags2
& SMB_FLAGS2_SECURITY_SIGNATURE
) &&
632 (ctx
->ct_mackey
== NULL
)) {
633 ctx
->ct_mackeylen
= NTLM_HASH_SZ
;
634 ctx
->ct_mackey
= malloc(ctx
->ct_mackeylen
);
635 if (ctx
->ct_mackey
== NULL
) {
636 ctx
->ct_mackeylen
= 0;
640 memcpy(ctx
->ct_mackey
, ctx
->ct_ssn_key
, NTLM_HASH_SZ
);
642 * Apparently, the server used seq. no. zero
643 * for our previous message, so next is two.
645 ctx
->ct_mac_seqno
= 2;
655 * See ssp.c: ssp_ctx_next_token
658 ntlmssp_next_token(struct ssp_ctx
*sp
, struct mbdata
*in_mb
,
659 struct mbdata
*out_mb
)
663 if (out_mb
== NULL
) {
664 /* final call on successful auth. */
665 err
= ntlmssp_final(sp
);
669 /* Will build an ouptut token. */
670 err
= mb_init(out_mb
);
675 * When called with in_mb == NULL, it means
676 * this is the first call for this session,
677 * so put a Type 1 (initialize) token.
680 err
= ntlmssp_put_type1(sp
, out_mb
);
685 * This is not the first call, so
686 * parse the response token we received.
687 * It should be a Type 2 (challenge).
688 * Then put a Type 3 (authenticate)
690 err
= ntlmssp_get_type2(sp
, in_mb
);
694 err
= ntlmssp_put_type3(sp
, out_mb
);
698 DPRINT("ret: %d", err
);
703 * ntlmssp_ctx_destroy
705 * Destroy mechanism-specific data.
708 ntlmssp_destroy(struct ssp_ctx
*sp
)
710 ntlmssp_state_t
*ssp_st
;
712 ssp_st
= sp
->sp_private
;
713 if (ssp_st
!= NULL
) {
714 sp
->sp_private
= NULL
;
715 free(ssp_st
->ss_target_name
);
716 m_freem(ssp_st
->ss_target_info
);
724 * Initialize a new NTLMSSP client context.
727 ntlmssp_init_client(struct ssp_ctx
*sp
)
729 ntlmssp_state_t
*ssp_st
;
731 if ((sp
->smb_ctx
->ct_authflags
&
732 (SMB_AT_NTLM2
| SMB_AT_NTLM1
| SMB_AT_ANON
)) == 0) {
733 DPRINT("No NTLM authflags");
737 ssp_st
= calloc(1, sizeof (*ssp_st
));
741 sp
->sp_nexttok
= ntlmssp_next_token
;
742 sp
->sp_destroy
= ntlmssp_destroy
;
743 sp
->sp_private
= ssp_st
;