summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsmbfs
diff options
context:
space:
mode:
authorGordon Ross <gwr@nexenta.com>2013-07-16 22:10:42 -0400
committerGordon Ross <gwr@nexenta.com>2014-11-12 14:29:11 -0500
commit85e6b6747d07050e01ec91acef2453655821f9ab (patch)
treeb2531706b2e44cbeaad4a5b157ddffbae7e8406f /usr/src/lib/libsmbfs
parentfd75ca8de430ee0ba5ce650efee0ac0b85ed43e9 (diff)
downloadillumos-joyent-85e6b6747d07050e01ec91acef2453655821f9ab.tar.gz
5308 Unable to join AD domain (with NtlmMinSeverSec set in the registry)
Reviewed by: Bayard Bell <bayard.bell@nexenta.com> Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Thomas Keiser <thomas.keiser@nexenta.com> Reviewed by: Albert Lee <trisk@nexenta.com> Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src/lib/libsmbfs')
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h5
-rw-r--r--usr/src/lib/libsmbfs/smb/connect.c95
-rw-r--r--usr/src/lib/libsmbfs/smb/crypt.c99
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c8
-rw-r--r--usr/src/lib/libsmbfs/smb/negprot.c34
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.c178
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.h11
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.c257
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.h15
-rw-r--r--usr/src/lib/libsmbfs/smb/smb_crypt.h19
-rw-r--r--usr/src/lib/libsmbfs/smb/ssnsetup.c73
11 files changed, 538 insertions, 256 deletions
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
index 02eb6106c2..c1dc6886ac 100644
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
@@ -33,8 +33,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_LIB_H_
@@ -115,10 +115,11 @@ struct smb_ctx {
/* Strings from the SMB negotiate response. */
char *ct_srv_OS;
char *ct_srv_LM;
+ uint32_t ct_clnt_caps;
/* NTLM auth. stuff */
uchar_t ct_clnonce[NTLM_CHAL_SZ];
- uchar_t ct_ntlm_chal[NTLM_CHAL_SZ];
+ uchar_t ct_srv_chal[NTLM_CHAL_SZ];
char ct_password[SMBIOC_MAX_NAME];
/* See ssp.c */
diff --git a/usr/src/lib/libsmbfs/smb/connect.c b/usr/src/lib/libsmbfs/smb/connect.c
index d0f4e2b228..c2ccc3361d 100644
--- a/usr/src/lib/libsmbfs/smb/connect.c
+++ b/usr/src/lib/libsmbfs/smb/connect.c
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -460,76 +461,68 @@ smb_iod_connect(smb_ctx_t *ctx)
}
/*
- * SMB Negotiate Protocol and
- * SMB Session Setup, one of 3 ways:
- * NULL session
- * Extended security,
- * NTLM (v2, v1)
- *
+ * Do SMB Negotiate Protocol.
+ */
+ err = smb_negprot(ctx, &blob);
+ if (err)
+ goto out;
+
+ /*
* Empty user name means an explicit request for
- * NULL session setup. No fall-back logic here.
- *
- * For NULL session, don't offer extended security.
- * That's a lot simpler than dealing with NTLMSSP.
+ * NULL session setup, which is a special case.
+ * If negotiate determined that we want to do
+ * SMB signing, we have to turn that off for a
+ * NULL session. [MS-SMB 3.3.5.3].
*/
if (ctx->ct_user[0] == '\0') {
- ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
- err = smb_negprot(ctx, &blob);
- if (err)
- goto out;
- err = smb_ssnsetup_null(ctx);
- } else {
- /*
- * Do SMB Negotiate Protocol.
- */
- err = smb_negprot(ctx, &blob);
- if (err)
- goto out;
+ /* Null user should have null domain too. */
+ ctx->ct_domain[0] = '\0';
+ ctx->ct_authflags = SMB_AT_ANON;
+ ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY;
+ ctx->ct_vcflags &= ~SMBV_WILL_SIGN;
+ }
+ /*
+ * Do SMB Session Setup (authenticate)
+ *
+ * If the server negotiated extended security,
+ * run the SPNEGO state machine, otherwise do
+ * one of the old-style variants.
+ */
+ if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
+ err = smb_ssnsetup_spnego(ctx, &blob);
+ } else {
/*
- * Do SMB Session Setup (authenticate)
- *
- * If the server negotiated extended security,
- * run the SPNEGO state machine.
+ * Server did NOT negotiate extended security.
+ * Try NTLMv2, NTLMv1, or ANON (if enabled).
*/
- if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
- err = smb_ssnsetup_spnego(ctx, &blob);
+ if (ctx->ct_authflags & SMB_AT_NTLM2) {
+ err = smb_ssnsetup_ntlm2(ctx);
+ } else if (ctx->ct_authflags & SMB_AT_NTLM1) {
+ err = smb_ssnsetup_ntlm1(ctx);
+ } else if (ctx->ct_authflags & SMB_AT_ANON) {
+ err = smb_ssnsetup_null(ctx);
} else {
/*
- * Server did NOT negotiate extended security.
- * Try NTLMv2, NTLMv1 (if enabled).
+ * Don't return EAUTH, because a new
+ * password prompt will not help.
*/
- if ((ctx->ct_authflags &
- (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
- /*
- * Don't return EAUTH, because a
- * new password will not help.
- */
- DPRINT("No NTLM authflags");
- err = ENOTSUP;
- goto out;
- }
- if (ctx->ct_authflags & SMB_AT_NTLM2)
- err = smb_ssnsetup_ntlm2(ctx);
- else
- err = EAUTH;
- if (err == EAUTH && 0 !=
- (ctx->ct_authflags & SMB_AT_NTLM1))
- err = smb_ssnsetup_ntlm1(ctx);
+ DPRINT("No NTLM authflags");
+ err = ENOTSUP;
}
}
- /* Tell library code we have a session. */
- ctx->ct_flags |= SMBCF_RESOLVED | SMBCF_SSNACTIVE;
-
out:
mb_done(&blob);
if (err) {
close(ctx->ct_tran_fd);
ctx->ct_tran_fd = -1;
- } else
+ } else {
+ /* Tell library code we have a session. */
+ ctx->ct_flags |= SMBCF_SSNACTIVE;
DPRINT("tran_fd = %d", ctx->ct_tran_fd);
+ }
return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/crypt.c b/usr/src/lib/libsmbfs/smb/crypt.c
index ea1d7e6dd1..13569c1b8c 100644
--- a/usr/src/lib/libsmbfs/smb/crypt.c
+++ b/usr/src/lib/libsmbfs/smb/crypt.c
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -29,7 +30,7 @@
*
* Some code copied from the server: libsmb smb_crypt.c
* with minor changes, i.e. errno.h return values.
- * XXX: Move this to a common library (later).
+ * XXX: Later, make the server use these.
*/
#include <sys/types.h>
@@ -67,13 +68,21 @@ smb_encrypt_DES(uchar_t *Result, int ResultLen,
int K, D;
int k, d;
- /* Calculate proper number of iterations */
+ /*
+ * Calculate proper number of iterations.
+ * Known call cases include:
+ * ResultLen=16, KeyLen=14, DataLen=8
+ * ResultLen=24, KeyLen=21, DataLen=8
+ * ResultLen=16, KeyLen=14, DataLen=16
+ */
K = KeyLen / 7;
D = DataLen / 8;
-
- if (ResultLen < (K * 8 * D)) {
+ if ((KeyLen % 7) || (DataLen % 8))
+ return (EINVAL);
+ if (K == 0 || D == 0)
+ return (EINVAL);
+ if (ResultLen < (K * 8))
return (EINVAL);
- }
/*
* Use SUNW convenience function to initialize the cryptoki
@@ -88,7 +97,10 @@ smb_encrypt_DES(uchar_t *Result, int ResultLen,
return (ENOTSUP);
}
- for (k = 0; k < K; k++) {
+ for (d = k = 0; k < K; k++, d++) {
+ /* Cycle the input again, as necessary. */
+ if (d == D)
+ d = 0;
smb_initlmkey(des_key, &Key[k * 7]);
rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
des_key, 8, &hKey);
@@ -102,18 +114,18 @@ smb_encrypt_DES(uchar_t *Result, int ResultLen,
error = EIO;
goto exit_encrypt;
}
- ciphertext_len = DataLen;
- for (d = 0; d < D; d++) {
- /* Read in the data and encrypt this portion */
- rv = C_EncryptUpdate(hSession,
- (CK_BYTE_PTR)Data + (d * 8), 8,
- &Result[(k * (8 * D)) + (d * 8)],
- &ciphertext_len);
- if (rv != CKR_OK) {
- error = EIO;
- goto exit_encrypt;
- }
+ ciphertext_len = 8;
+
+ /* Read in the data and encrypt this portion */
+ rv = C_EncryptUpdate(hSession,
+ (CK_BYTE_PTR)Data + (d * 8), 8,
+ (CK_BYTE_PTR)Result + (k * 8),
+ &ciphertext_len);
+ if (rv != CKR_OK) {
+ error = EIO;
+ goto exit_encrypt;
}
+
(void) C_DestroyObject(hSession, hKey);
}
goto exit_session;
@@ -149,6 +161,59 @@ smb_initlmkey(uchar_t *keyout, const uchar_t *keyin)
}
/*
+ * CKM_RC4
+ */
+int
+smb_encrypt_RC4(uchar_t *Result, int ResultLen,
+ const uchar_t *Key, int KeyLen,
+ const uchar_t *Data, int DataLen)
+{
+ CK_RV rv;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE hKey;
+ CK_SESSION_HANDLE hSession;
+ CK_ULONG ciphertext_len;
+ int error = EIO;
+
+ /*
+ * Use SUNW convenience function to initialize the cryptoki
+ * library, and open a session with a slot that supports
+ * the mechanism we plan on using.
+ */
+ mechanism.mechanism = CKM_RC4;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+ rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
+ if (rv != CKR_OK) {
+ return (ENOTSUP);
+ }
+
+ rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
+ Key, KeyLen, &hKey);
+ if (rv != CKR_OK)
+ goto exit_session;
+
+ /* Initialize the encryption operation in the session */
+ rv = C_EncryptInit(hSession, &mechanism, hKey);
+ if (rv != CKR_OK)
+ goto exit_encrypt;
+
+ ciphertext_len = ResultLen;
+ rv = C_EncryptUpdate(hSession,
+ (CK_BYTE_PTR)Data, DataLen,
+ (CK_BYTE_PTR)Result, &ciphertext_len);
+ if (rv == CKR_OK)
+ error = 0;
+
+exit_encrypt:
+ (void) C_DestroyObject(hSession, hKey);
+exit_session:
+ (void) C_CloseSession(hSession);
+
+ return (error);
+}
+
+/*
* Get some random bytes from /dev/urandom
*
* There may be a preferred way to call this via libpkcs11
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index 81e4241aa5..e68213b6ef 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -1121,13 +1121,7 @@ smb_ctx_resolve(struct smb_ctx *ctx)
* check for a keychain entry.
* XXX: Only for auth NTLM?
*/
- if (ctx->ct_user[0] == '\0') {
- /*
- * No user name (anonymous session).
- * The minauth checks do not apply.
- */
- ctx->ct_authflags = SMB_AT_ANON;
- } else {
+ if (ctx->ct_user[0] != '\0') {
/*
* Have a user name.
* If we don't have a p/w yet,
diff --git a/usr/src/lib/libsmbfs/smb/negprot.c b/usr/src/lib/libsmbfs/smb/negprot.c
index 9345cd8c47..770b742c44 100644
--- a/usr/src/lib/libsmbfs/smb/negprot.c
+++ b/usr/src/lib/libsmbfs/smb/negprot.c
@@ -32,11 +32,11 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
* SMB Negotiate Protocol, and related.
- * Copied from the driver: smb_smb.c
*/
#include <errno.h>
@@ -66,6 +66,7 @@
#include <netsmb/smb_dev.h>
#include "charsets.h"
+#include "smb_crypt.h"
#include "private.h"
/*
@@ -87,6 +88,13 @@ static struct smb_dialect smb_dialects[] = {
#define SMB_DIALECT_MAX \
(sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
+static const uint32_t smb_clnt_caps_mask =
+ SMB_CAP_UNICODE |
+ SMB_CAP_LARGE_FILES |
+ SMB_CAP_NT_SMBS |
+ SMB_CAP_STATUS32 |
+ SMB_CAP_EXT_SECURITY;
+
/*
* SMB Negotiate Protocol
* Based on code from the driver: smb_smb.c
@@ -118,9 +126,16 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
* if we find out it doesn't. Need to do this because
* some servers reject all non-Unicode requests.
*/
- ctx->ct_hflags = SMB_FLAGS_CASELESS;
- ctx->ct_hflags2 = SMB_FLAGS2_KNOWS_LONG_NAMES |
- SMB_FLAGS2_ERR_STATUS | SMB_FLAGS2_UNICODE;
+ ctx->ct_hflags =
+ SMB_FLAGS_CASELESS |
+ SMB_FLAGS_CANONICAL_PATHNAMES;
+ ctx->ct_hflags2 =
+ SMB_FLAGS2_KNOWS_LONG_NAMES |
+ SMB_FLAGS2_KNOWS_EAS |
+ /* SMB_FLAGS2_IS_LONG_NAME |? */
+ /* EXT_SEC (see below) */
+ SMB_FLAGS2_ERR_STATUS |
+ SMB_FLAGS2_UNICODE;
/*
* Sould we offer extended security?
@@ -362,7 +377,7 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
err = EBADRPC;
goto errout;
}
- err = md_get_mem(mbp, ctx->ct_ntlm_chal,
+ err = md_get_mem(mbp, ctx->ct_srv_chal,
NTLM_CHAL_SZ, MB_MSYSTEM);
/*
* Server domain follows (ignored)
@@ -423,6 +438,15 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
is->is_rxmax = len;
is->is_wxmax = len;
+ /*
+ * Most of the "capability" bits we offer in session setup
+ * are just copied from those offered by the server.
+ */
+ ctx->ct_clnt_caps = sv->sv_caps & smb_clnt_caps_mask;
+
+ /* Get the client nonce. */
+ (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
+
return (0);
errout:
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c
index bee189561e..9f08a2eaca 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.c
+++ b/usr/src/lib/libsmbfs/smb/ntlm.c
@@ -34,6 +34,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -62,10 +63,11 @@
/*
* ntlm_compute_lm_hash
*
- * Compute an LM hash given a password
+ * Given a password, compute the LM hash.
+ * a.k.a. ResponseKeyLM in [MS-NLMP]
*
* Output:
- * hash: 16-byte "LanMan" (LM) hash.
+ * hash: 16-byte "LanMan" (LM) hash (normally ctx->ct_lmhash)
* Inputs:
* ucpw: User's password, upper-case UTF-8 string.
*
@@ -102,10 +104,11 @@ ntlm_compute_lm_hash(uchar_t *hash, const char *pass)
/*
* ntlm_compute_nt_hash
*
- * Compute an NT hash given a password in UTF-8.
+ * Given a password, compute the NT hash.
+ * a.k.a. the ResponseKeyNT in [MS-NLMP]
*
* Output:
- * hash: 16-byte "NT" hash.
+ * hash: 16-byte "NT" hash (normally ctx->ct_nthash)
* Inputs:
* upw: User's password, mixed-case UCS-2LE.
* pwlen: Size (in bytes) of upw
@@ -134,6 +137,7 @@ ntlm_compute_nt_hash(uchar_t *hash, const char *pass)
/*
* ntlm_v1_response
+ * a.k.a. DESL() in [MS-NLMP]
*
* Create an LM response from the given LM hash and challenge,
* or an NTLM repsonse from a given NTLM hash and challenge.
@@ -194,32 +198,103 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
return (err);
/*
- * Compute the LM response, derived
- * from the challenge and the ASCII
- * password (if authflags allow).
+ * Compute the NTLM response, derived from
+ * the challenge and the NT hash (a.k.a ResponseKeyNT)
+ */
+ err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
+ if (err)
+ return (err);
+ bzero(ntresp, NTLM_V1_RESP_SZ);
+ err = ntlm_v1_response(ntresp, ctx->ct_nthash,
+ ctx->ct_srv_chal, NTLM_CHAL_SZ);
+
+ /*
+ * Compute the LM response, derived from
+ * the challenge and the ASCII password.
+ * Per. [MS-NLMP 3.3.1] if NoLmResponse,
+ * send the NT response for both NT+LM.
*/
err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
if (err)
return (err);
- bzero(lmresp, NTLM_V1_RESP_SZ);
+ memcpy(lmresp, ntresp, NTLM_V1_RESP_SZ);
if (ctx->ct_authflags & SMB_AT_LM1) {
/* They asked to send the LM hash too. */
err = ntlm_v1_response(lmresp, ctx->ct_lmhash,
- ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+ ctx->ct_srv_chal, NTLM_CHAL_SZ);
if (err)
return (err);
}
/*
- * Compute the NTLM response, derived from
- * the challenge and the NT hash.
+ * Compute the session key
+ */
+ ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+
+ return (err);
+}
+
+/*
+ * Compute both the LM(v1x) response and the NTLM(v1x) response,
+ * and put them in the mbdata chains passed. "v1x" here refers to
+ * NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY used with NTLMSSP,
+ * also known by its shorter alias NTLMSSP_NEGOTIATE_NTLM2.
+ * [MS-NLMP 3.3.1]
+ *
+ * This allocates mbuf chains in the output args (caller frees).
+ */
+int
+ntlm_put_v1x_responses(struct smb_ctx *ctx,
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+{
+ MD5_CTX context;
+ uchar_t challenges[2 * NTLM_CHAL_SZ];
+ uchar_t digest[NTLM_HASH_SZ];
+ uchar_t *lmresp, *ntresp;
+ int err;
+
+ /* Get mbuf chain for the LM response. */
+ if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0)
+ return (err);
+
+ /* Get mbuf chain for the NT response. */
+ if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0)
+ return (err);
+
+ /*
+ * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
+ */
+ memcpy(challenges, ctx->ct_srv_chal, NTLM_CHAL_SZ);
+ memcpy(challenges + NTLM_CHAL_SZ, ctx->ct_clnonce, NTLM_CHAL_SZ);
+
+ /*
+ * digest = MD5(challenges)
+ */
+ MD5Init(&context);
+ MD5Update(&context, challenges, sizeof (challenges));
+ MD5Final(digest, &context);
+
+ /*
+ * Compute the NTLM response, derived from the
+ * NT hash (a.k.a ResponseKeyNT) and the first
+ * 8 bytes of the MD5 digest of the challenges.
*/
err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
if (err)
return (err);
bzero(ntresp, NTLM_V1_RESP_SZ);
err = ntlm_v1_response(ntresp, ctx->ct_nthash,
- ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+ digest, NTLM_CHAL_SZ);
+
+ /*
+ * With "Extended Session Security", the LM response
+ * is simply the client challenge (nonce) padded out.
+ */
+ err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
+ if (err)
+ return (err);
+ bzero(lmresp, NTLM_V1_RESP_SZ);
+ memcpy(lmresp, ctx->ct_clnonce, NTLM_CHAL_SZ);
/*
* Compute the session key
@@ -410,22 +485,22 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
uchar_t v2hash[NTLM_HASH_SZ];
struct mbuf *tim = ti_mbp->mb_top;
- if ((err = mb_init(lm_mbp)) != 0)
- return (err);
- if ((err = mb_init(nt_mbp)) != 0)
- return (err);
-
/*
* Convert the user name to upper-case, as
* that's what's used when computing LMv2
* and NTLMv2 responses. Note that the
* domain name is NOT upper-cased!
*/
+ if (ctx->ct_user[0] == '\0')
+ return (EINVAL);
ucuser = utf8_str_toupper(ctx->ct_user);
- if (ucuser == NULL) {
- err = ENOMEM;
+ if (ucuser == NULL)
+ return (ENOMEM);
+
+ if ((err = mb_init(lm_mbp)) != 0)
+ goto out;
+ if ((err = mb_init(nt_mbp)) != 0)
goto out;
- }
/*
* Compute the NTLMv2 hash
@@ -444,10 +519,9 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
* 1: 16-byte response hash
* 2: Client nonce
*/
- lmresp = (uchar_t *)lm_mbp->mb_pos;
- mb_put_mem(lm_mbp, NULL, NTLM_HASH_SZ, MB_MSYSTEM);
+ lmresp = mb_reserve(lm_mbp, NTLM_HASH_SZ);
err = ntlm_v2_resp_hash(lmresp,
- v2hash, ctx->ct_ntlm_chal,
+ v2hash, ctx->ct_srv_chal,
ctx->ct_clnonce, NTLM_CHAL_SZ);
if (err)
goto out;
@@ -462,10 +536,9 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
* 1: 16-byte response hash
* 2: "target info." blob
*/
- ntresp = (uchar_t *)nt_mbp->mb_pos;
- mb_put_mem(nt_mbp, NULL, NTLM_HASH_SZ, MB_MSYSTEM);
+ ntresp = mb_reserve(nt_mbp, NTLM_HASH_SZ);
err = ntlm_v2_resp_hash(ntresp,
- v2hash, ctx->ct_ntlm_chal,
+ v2hash, ctx->ct_srv_chal,
(uchar_t *)tim->m_data, tim->m_len);
if (err)
goto out;
@@ -533,14 +606,6 @@ ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names,
return (err);
/*
- * Construct the client nonce by getting
- * some random data from /dev/urandom
- */
- err = smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
- if (err)
- goto out;
-
- /*
* Get the "NT time" for the target info header.
*/
(void) gettimeofday(&now, 0);
@@ -583,3 +648,48 @@ out:
free(ucdom);
return (err);
}
+
+/*
+ * Build the MAC key (for SMB signing)
+ */
+int
+ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp)
+{
+ struct mbuf *m;
+ size_t len;
+ char *p;
+
+ /*
+ * MAC_key = concat(session_key, nt_response)
+ */
+ m = ntresp_mbp->mb_top;
+ len = NTLM_HASH_SZ + m->m_len;
+ if ((p = malloc(len)) == NULL)
+ return (ENOMEM);
+ ctx->ct_mackeylen = len;
+ ctx->ct_mackey = p;
+ memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
+ memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
+
+ return (0);
+}
+
+/*
+ * Helper for ntlmssp_put_type3 - Build the "key exchange key"
+ * used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2.
+ * HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7]))
+ */
+void
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
+{
+ uchar_t data[NTLM_HASH_SZ];
+ uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *);
+
+ /* concat(ServerChallenge, LmResponse[0..7]) */
+ memcpy(data, ctx->ct_srv_chal, NTLM_CHAL_SZ);
+ memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ);
+
+ /* HMAC_MD5(SessionBaseKey, concat(...)) */
+ HMACT64(kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ,
+ data, NTLM_HASH_SZ);
+}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.h b/usr/src/lib/libsmbfs/smb/ntlm.h
index e8eae559e9..447033b516 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.h
+++ b/usr/src/lib/libsmbfs/smb/ntlm.h
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NTLM_H
@@ -59,7 +60,17 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
struct mbdata *lm_mbp, struct mbdata *nt_mbp);
int
+ntlm_put_v1x_responses(struct smb_ctx *ctx,
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+
+int
ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+int
+ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp);
+
+void
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey);
+
#endif /* _NTLM_H */
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c
index 5766ec835c..f39fa594ec 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.c
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c
@@ -20,8 +20,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -59,16 +59,22 @@
#include "private.h"
#include "charsets.h"
+#include "smb_crypt.h"
#include "spnego.h"
#include "derparse.h"
#include "ssp.h"
#include "ntlm.h"
#include "ntlmssp.h"
+/* A shorter alias for a crazy long name from [MS-NLMP] */
+#define NTLMSSP_NEGOTIATE_NTLM2 \
+ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
+
typedef struct ntlmssp_state {
uint32_t ss_flags;
- char *ss_target_name;
+ char *ss_target_name; /* Primary domain or server name */
struct mbuf *ss_target_info;
+ uchar_t ss_kxkey[NTLM_HASH_SZ];
} ntlmssp_state_t;
/*
@@ -83,6 +89,10 @@ struct sec_buf {
#define ID_SZ 8
static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
+static int
+ntlm_rand_ssn_key(struct smb_ctx *ctx,
+ ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
+
/*
* Get a "security buffer" (header part)
*/
@@ -147,10 +157,12 @@ mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
static int
mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
{
- int cnt0, err;
+ int cnt0;
+ int err = 0;
sb->sb_offset = cnt0 = mbp->mb_count;
- err = mb_put_mbuf(mbp, m);
+ if (m != NULL)
+ err = mb_put_mbuf(mbp, m);
sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0;
return (err);
@@ -164,31 +176,35 @@ mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
*/
static int
mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb,
- const char *s, int unicode)
+ const char *str, int unicode)
{
int err, trim;
struct mbdata tmp_mb;
- /*
- * Put the string into a temp. mbuf,
- * then chop off the null terminator
- * before appending to caller's mbp.
- */
- err = mb_init(&tmp_mb);
- if (err)
- return (err);
- err = mb_put_string(&tmp_mb, s, unicode);
- if (err)
- return (err);
+ bzero(&tmp_mb, sizeof (tmp_mb));
- trim = (unicode) ? 2 : 1;
- if (tmp_mb.mb_cur->m_len < trim)
- return (EFAULT);
- tmp_mb.mb_cur->m_len -= trim;
+ if (str != NULL && *str != '\0') {
+ /*
+ * Put the string into a temp. mbuf,
+ * then chop off the null terminator
+ * before appending to caller's mbp.
+ */
+ err = mb_init(&tmp_mb);
+ if (err)
+ return (err);
+ err = mb_put_string(&tmp_mb, str, unicode);
+ if (err)
+ return (err);
+
+ trim = (unicode) ? 2 : 1;
+ if (tmp_mb.mb_cur->m_len < trim)
+ trim = 0;
+ tmp_mb.mb_cur->m_len -= trim;
+ }
err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top);
/*
- * Note: tmp_mb.mb_top is consumed,
+ * Note: tmp_mb.mb_top (if any) is consumed,
* so do NOT free it (no mb_done)
*/
return (err);
@@ -215,60 +231,47 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
int err;
struct smb_ctx *ctx = sp->smb_ctx;
ntlmssp_state_t *ssp_st = sp->sp_private;
- char *ucdom = NULL;
- char *ucwks = NULL;
if ((err = mb_init(&mb2)) != 0)
return (err);
mb2.mb_count = sizeof (hdr);
/*
- * Initialize the negotiation flags, and
- * save what we sent. For reference:
- * [MS-NLMP] spec. (also ntlmssp.h)
+ * The initial negotiation flags represent the union of all
+ * options we support. The server selects from these.
+ * See: [MS-NLMP 2.2.2.5 NEGOTIATE]
*/
ssp_st->ss_flags =
+ NTLMSSP_NEGOTIATE_UNICODE |
+ NTLMSSP_NEGOTIATE_OEM |
NTLMSSP_REQUEST_TARGET |
+ NTLMSSP_NEGOTIATE_SIGN |
+ NTLMSSP_NEGOTIATE_SEAL |
+ /* NTLMSSP_NEGOTIATE_LM_KEY (never) */
NTLMSSP_NEGOTIATE_NTLM |
- NTLMSSP_NEGOTIATE_TARGET_INFO |
+ /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
+ NTLMSSP_NEGOTIATE_NTLM2 |
NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_56;
- if (ctx->ct_hflags2 & SMB_FLAGS2_UNICODE)
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_UNICODE;
- else
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_OEM;
-
if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
}
- if (ctx->ct_authflags & SMB_AT_NTLM2)
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
- if (ctx->ct_authflags & SMB_AT_NTLM1)
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
-
bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
- hdr.h_type = 1; /* Type 1 */
+ hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
hdr.h_flags = ssp_st->ss_flags;
/*
- * Put the client domain, client name strings.
- * These are always in OEM format, upper-case.
+ * We could put the client domain, client name strings
+ * here, (always in OEM format, upper-case), and set
+ * NTLMSSP_NEGOTIATE_OEM_..._SUPPLIED, but Windows
+ * leaves these NULL so let's do the same.
*/
- ucdom = utf8_str_toupper(ctx->ct_domain);
- ucwks = utf8_str_toupper(ctx->ct_locname);
- if (ucdom == NULL || ucwks == NULL) {
- err = ENOMEM;
- goto out;
- }
- err = mb_put_sb_string(&mb2, &hdr.h_cldom, ucdom, 0);
- if (err)
- goto out;
- err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwks, 0);
- if (err)
- goto out;
+ (void) mb_put_sb_string(&mb2, &hdr.h_cldom, NULL, 0);
+ (void) mb_put_sb_string(&mb2, &hdr.h_wksta, NULL, 0);
/*
* Marshal the header (in LE order)
@@ -282,10 +285,6 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
err = mb_put_mbuf(out_mb, mb2.mb_top);
-out:
- free(ucdom);
- free(ucwks);
-
return (err);
}
@@ -329,7 +328,7 @@ ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
bzero(&hdr, sizeof (hdr));
(void) md_get_mem(in_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
(void) md_get_uint32le(in_mb, &hdr.h_type);
- if (hdr.h_type != 2) {
+ if (hdr.h_type != NTLMSSP_MSGTYPE_CHALLENGE) {
err = EPROTO;
goto out;
}
@@ -338,11 +337,17 @@ ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
(void) md_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ, MB_MSYSTEM);
/*
- * Save flags, challenge for later.
+ * Save flags, server challenge for later.
*/
ssp_st->ss_flags = hdr.h_flags;
+ bcopy(&hdr.h_challenge, ctx->ct_srv_chal, NTLM_CHAL_SZ);
+
+ /*
+ * Turn off flags that might have been given but
+ * that we don't want to send with authenticate.
+ */
uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE;
- bcopy(&hdr.h_challenge, ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_VERSION;
/*
* Now find out if the optional parts are there.
@@ -355,8 +360,9 @@ ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
}
/*
- * Get the target name string. First get a copy of
- * the data from the offset/length indicated in the
+ * Get the target name string. (Server name or
+ * Primary domain name.) First get a copy of the
+ * data from the offset/length indicated in the
* security buffer header; then parse the string.
*/
err = md_get_sb_data(&top_mb, &hdr.h_target_name, &m);
@@ -401,19 +407,24 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
struct sec_buf h_wksta;
struct sec_buf h_ssn_key;
uint32_t h_flags;
+ /* Version struct (ommitted) */
+ uchar_t h_mic[NTLM_HASH_SZ];
} hdr;
struct mbdata lm_mbc; /* LM response */
struct mbdata nt_mbc; /* NT response */
struct mbdata ti_mbc; /* target info */
+ struct mbdata ek_mbc; /* encrypted session key */
struct mbdata mb2; /* payload */
int err, uc;
struct smb_ctx *ctx = sp->smb_ctx;
ntlmssp_state_t *ssp_st = sp->sp_private;
+ uchar_t *pmic;
bzero(&hdr, sizeof (hdr));
bzero(&lm_mbc, sizeof (lm_mbc));
bzero(&nt_mbc, sizeof (nt_mbc));
bzero(&ti_mbc, sizeof (ti_mbc));
+ bzero(&ek_mbc, sizeof (ek_mbc));
bzero(&mb2, sizeof (mb2));
/*
@@ -425,27 +436,78 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
- hdr.h_type = 3; /* Type 3 */
+ hdr.h_type = NTLMSSP_MSGTYPE_AUTHENTICATE;
hdr.h_flags = ssp_st->ss_flags;
/*
- * Put the LMv2,NTLMv2 responses, or
- * possibly LM, NTLM (v1) responses.
+ * Put the NTLMv2/LMv2 or NTLM/LM (v1) responses,
+ * and compute the session key, etc.
*/
- if (ctx->ct_authflags & SMB_AT_NTLM2) {
- /* Build the NTLMv2 "target info" blob. */
+ if (ctx->ct_authflags & SMB_AT_ANON) {
+ /*
+ * We're setting up a NULL session, meaning
+ * the lm_mbc, nt_mbc parts remain empty.
+ * Let's add the "anon" flag (hint).
+ * As there is no session key, disable the
+ * fancy session key stuff.
+ */
+ hdr.h_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
+ ssp_st->ss_flags &= ~(
+ NTLMSSP_NEGOTIATE_NTLM2 |
+ NTLMSSP_NEGOTIATE_KEY_EXCH);
+ err = 0;
+ } else if (ctx->ct_authflags & SMB_AT_NTLM2) {
+ /*
+ * Doing NTLMv2/LMv2
+ */
err = ntlm_build_target_info(ctx,
ssp_st->ss_target_info, &ti_mbc);
if (err)
goto out;
err = ntlm_put_v2_responses(ctx, &ti_mbc,
&lm_mbc, &nt_mbc);
+ if (err)
+ goto out;
+ /* The "key exg. key" is the session base key */
+ memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
+
+ } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ /*
+ * Doing NTLM ("v1x") which is NTLM with
+ * "Extended Session Security"
+ */
+ err = ntlm_put_v1x_responses(ctx,
+ &lm_mbc, &nt_mbc);
+ if (err)
+ goto out;
+ /* Compute the "Key exchange key". */
+ ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_kxkey);
} else {
+ /*
+ * Doing plain old NTLM (and LM if enabled)
+ */
err = ntlm_put_v1_responses(ctx,
&lm_mbc, &nt_mbc);
+ if (err)
+ goto out;
+ /* The "key exg. key" is the session base key */
+ memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
+ }
+
+ /*
+ * Compute the "Exported Session Key" and (possibly)
+ * the "Encrypted Random Sesion Key".
+ * [MS-NLMP 3.1.5.1.2]
+ */
+ if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ err = ntlm_rand_ssn_key(ctx, ssp_st, &ek_mbc);
+ if (err)
+ goto out;
+ } else {
+ /* ExportedSessionKey is the KeyExchangeKey */
+ memcpy(ctx->ct_ssn_key, ssp_st->ss_kxkey, NTLM_HASH_SZ);
+ /* EncryptedRandomSessionKey remains NULL */
}
- if (err)
- goto out;
err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
lm_mbc.mb_top = NULL; /* consumed */
@@ -470,12 +532,13 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
goto out;
/*
- * Put the "Random Session Key". We don't set
- * NTLMSSP_NEGOTIATE_KEY_EXCH, so it's empty.
- * (In-line mb_put_sb_data here.)
+ * Put the "Encrypted Random Session Key", if any.
+ * (ek_mbc.mb_top may be NULL)
*/
- hdr.h_ssn_key.sb_maxlen = hdr.h_ssn_key.sb_length = 0;
- hdr.h_ssn_key.sb_offset = mb2.mb_count;
+ err = mb_put_sb_data(&mb2, &hdr.h_ssn_key, ek_mbc.mb_top);
+ ek_mbc.mb_top = NULL; /* consumed (if any) */
+ if (err)
+ goto out;
/*
* Marshal the header (in LE order)
@@ -494,14 +557,58 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
(void) mb_put_sb_hdr(out_mb, &hdr.h_ssn_key);
(void) mb_put_uint32le(out_mb, hdr.h_flags);
+ /* Put zeros for the MIC - filled in later */
+ pmic = mb_reserve(out_mb, NTLM_HASH_SZ);
+
+ /* Put the payload. */
err = mb_put_mbuf(out_mb, mb2.mb_top);
mb2.mb_top = NULL; /* consumed */
+ /*
+ * Compute the MIC and stuff that in...
+ * The MIC is apparently optional.
+ */
+ (void) pmic;
+
out:
mb_done(&mb2);
mb_done(&lm_mbc);
mb_done(&nt_mbc);
mb_done(&ti_mbc);
+ mb_done(&ek_mbc);
+
+ return (err);
+}
+
+/*
+ * Helper for ntlmssp_put_type3 when doing key exchange.
+ *
+ * "ExportedSessionKey" is what we give to the "application"
+ * layer, which in here means the MAC key for SMB signing.
+ * With "key exchange", we replace the ExportedSessionKey
+ * with random data and send that (encrypted) to the peer.
+ */
+static int
+ntlm_rand_ssn_key(
+ struct smb_ctx *ctx,
+ ntlmssp_state_t *ssp_st,
+ struct mbdata *ek_mbp)
+{
+
+ uchar_t *encr_ssn_key;
+ int err;
+
+ if ((err = mb_init(ek_mbp)) != 0)
+ return (err);
+ encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ);
+
+ /* Set "ExportedSessionKey to NONCE(16) */
+ (void) smb_get_urandom(ctx->ct_ssn_key, NTLM_HASH_SZ);
+
+ /* Set "EncryptedRandomSessionKey" to RC4(...) */
+ err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ,
+ ssp_st->ss_kxkey, NTLM_HASH_SZ,
+ ctx->ct_ssn_key, NTLM_HASH_SZ);
return (err);
}
@@ -623,9 +730,9 @@ ntlmssp_init_client(struct ssp_ctx *sp)
ntlmssp_state_t *ssp_st;
if ((sp->smb_ctx->ct_authflags &
- (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
+ (SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
DPRINT("No NTLM authflags");
- return (ENOTSUP);
+ return (EINVAL);
}
ssp_st = calloc(1, sizeof (*ssp_st));
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.h b/usr/src/lib/libsmbfs/smb/ntlmssp.h
index 591b1ab088..5f3e09ac0d 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.h
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.h
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NTLMSSP_H
@@ -37,6 +38,14 @@
*/
/*
+ * NTLMSSP Message Types
+ * [MS-NLMP] sec. 2.2.1
+ */
+#define NTLMSSP_MSGTYPE_NEGOTIATE 1
+#define NTLMSSP_MSGTYPE_CHALLENGE 2
+#define NTLMSSP_MSGTYPE_AUTHENTICATE 3
+
+/*
* NTLMSSP Negotiate Flags
* [MS-NLMP] sec. 2.2.2.5
*/
@@ -48,13 +57,13 @@
#define NTLMSSP_NEGOTIATE_SEAL 0x00000020
#define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040
#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080
-/* reserved 0x00000100 */
+/* reserved (netware) 0x00000100 */
#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
#define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400
-/* old anonymous_session (ignored by servers) 0x00000800 */
+#define NTLMSSP_NEGOTIATE_NULL_SESSION 0x00000800
#define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000
#define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000
-/* reserved 0x00004000 */
+/* reserved (local caller) 0x00004000 */
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000
#define NTLMSSP_TARGET_TYPE_SERVER 0x00020000
diff --git a/usr/src/lib/libsmbfs/smb/smb_crypt.h b/usr/src/lib/libsmbfs/smb/smb_crypt.h
index 15005ddab6..a3ebd69e22 100644
--- a/usr/src/lib/libsmbfs/smb/smb_crypt.h
+++ b/usr/src/lib/libsmbfs/smb/smb_crypt.h
@@ -33,17 +33,36 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
+#ifndef _SMB_CRYPT_H
+#define _SMB_CRYPT_H
+
/*
* Various crypto stuff.
* from the driver: smb_crypt.c
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
int
smb_encrypt_DES(uchar_t *Result, int ResultLen,
const uchar_t *Key, int KeyLen,
const uchar_t *Data, int DataLen);
int
+smb_encrypt_RC4(uchar_t *Result, int ResultLen,
+ const uchar_t *Key, int KeyLen,
+ const uchar_t *Data, int DataLen);
+
+int
smb_get_urandom(void *data, size_t dlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_CRYPT_H */
diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c
index 03f92dc62c..68e7ce1337 100644
--- a/usr/src/lib/libsmbfs/smb/ssnsetup.c
+++ b/usr/src/lib/libsmbfs/smb/ssnsetup.c
@@ -32,11 +32,11 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
* SMB Session Setup, and related.
- * Copied from the driver: smb_smb.c
*/
#include <errno.h>
@@ -88,7 +88,7 @@ smb_ssnsetup_null(struct smb_ctx *ctx)
uint32_t ntstatus;
uint16_t action = 0;
- if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
/* Should not get here with... */
err = EINVAL;
goto out;
@@ -118,7 +118,7 @@ smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
uint32_t ntstatus;
uint16_t action = 0;
- if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
/* Should not get here with... */
err = EINVAL;
goto out;
@@ -133,30 +133,11 @@ smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
if (err)
goto out;
- /*
- * If we negotiated signing, compute the MAC key
- * and start signing messages, but only on the
- * first non-null session login.
- */
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
+ if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
(ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- struct mbuf *m = nt_mbc.mb_top;
- char *p;
-
- /*
- * MAC_key = concat(session_key, nt_response)
- */
- ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
+ err = ntlm_build_mac_key(ctx, &nt_mbc);
+ if (err)
goto out;
- }
- p = ctx->ct_mackey;
- memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
- memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
-
/* OK, start signing! */
ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
}
@@ -187,7 +168,7 @@ smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
uint32_t ntstatus;
uint16_t action = 0;
- if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
/* Should not get here with... */
err = EINVAL;
goto out;
@@ -208,30 +189,11 @@ smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
if (err)
goto out;
- /*
- * If we negotiated signing, compute the MAC key
- * and start signing messages, but only on the
- * first non-null session login.
- */
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
+ if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
(ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- struct mbuf *m = nt_mbc.mb_top;
- char *p;
-
- /*
- * MAC_key = concat(session_key, nt_response)
- */
- ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
+ err = ntlm_build_mac_key(ctx, &nt_mbc);
+ if (err)
goto out;
- }
- p = ctx->ct_mackey;
- memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
- memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
-
/* OK, start signing! */
ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
}
@@ -334,20 +296,7 @@ smb__ssnsetup(struct smb_ctx *ctx,
uint16_t bc, len1, len2, sblen;
uint8_t wc;
- /*
- * Some of the "capability" bits we offer will be copied
- * from those offered by the server, with a mask applied.
- * This is the mask of capabilies copied from the server.
- * Some others get special handling below.
- */
- static const uint32_t caps_mask =
- SMB_CAP_UNICODE |
- SMB_CAP_LARGE_FILES |
- SMB_CAP_NT_SMBS |
- SMB_CAP_STATUS32 |
- SMB_CAP_EXT_SECURITY;
-
- caps = ctx->ct_sopt.sv_caps & caps_mask;
+ caps = ctx->ct_clnt_caps;
uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);