void E_md5hash(const uint8_t salt[16], const uint8_t nthash[16], uint8_t hash_out[16])
{
- struct MD5Context tctx;
+ MD5_CTX tctx;
MD5Init(&tctx);
MD5Update(&tctx, salt, 16);
MD5Update(&tctx, nthash, 16);
bool E_deshash(const char *passwd, uint8_t p16[16])
{
- bool ret = true;
- char dospwd[256];
- ZERO_STRUCT(dospwd);
+ bool ret;
+ uint8_t dospwd[14];
+ TALLOC_CTX *frame = talloc_stackframe();
- /* Password must be converted to DOS charset - null terminated, uppercase. */
- push_string(dospwd, passwd, sizeof(dospwd), STR_ASCII|STR_UPPER|STR_TERMINATE);
+ size_t converted_size;
- /* Only the first 14 chars are considered, password need not be null terminated. */
- E_P16((const uint8_t *)dospwd, p16);
+ char *tmpbuf;
- if (strlen(dospwd) > 14) {
- ret = false;
+ ZERO_STRUCT(dospwd);
+
+ tmpbuf = strupper_talloc(frame, passwd);
+ if (tmpbuf == NULL) {
+ /* Too many callers don't check this result, we need to fill in the buffer with something */
+ strlcpy((char *)dospwd, passwd ? passwd : "", sizeof(dospwd));
+ E_P16(dospwd, p16);
+ talloc_free(frame);
+ return false;
}
ZERO_STRUCT(dospwd);
+ ret = convert_string_error(CH_UNIX, CH_DOS, tmpbuf, strlen(tmpbuf), dospwd, sizeof(dospwd), &converted_size);
+ talloc_free(frame);
+
+ /* Only the first 14 chars are considered, password need not
+ * be null terminated. We do this in the error and success
+ * case to avoid returning a fixed 'password' buffer, but
+ * callers should not use it when E_deshash returns false */
+
+ E_P16((const uint8_t *)dospwd, p16);
+
+ ZERO_STRUCT(dospwd);
+
return ret;
}
/* Does both the NTLMv2 owfs of a user's password */
bool ntv2_owf_gen(const uint8_t owf[16],
const char *user_in, const char *domain_in,
- bool upper_case_domain, /* Transform the domain into UPPER case */
uint8_t kr_buf[16])
{
smb_ucs2_t *user;
return false;
}
- if (upper_case_domain) {
- domain_in = strupper_talloc(mem_ctx, domain_in);
- if (domain_in == NULL) {
- talloc_free(mem_ctx);
- return false;
- }
- }
-
ret = push_ucs2_talloc(mem_ctx, &user, user_in, &user_byte_len );
if (!ret) {
DEBUG(0, ("push_uss2_talloc() for user failed)\n"));
/* Does the des encryption. */
-void SMBNTencrypt_hash(const uint8_t nt_hash[16], uint8_t *c8, uint8_t *p24)
+void SMBNTencrypt_hash(const uint8_t nt_hash[16], const uint8_t *c8, uint8_t *p24)
{
uint8_t p21[21];
/* Does the NT MD4 hash then des encryption. Plaintext version of the above. */
-void SMBNTencrypt(const char *passwd, uint8_t *c8, uint8_t *p24)
+void SMBNTencrypt(const char *passwd, const uint8_t *c8, uint8_t *p24)
{
uint8_t nt_hash[16];
E_md4hash(passwd, nt_hash);
{
DATA_BLOB names_blob = data_blob_talloc(mem_ctx, NULL, 0);
- msrpc_gen(mem_ctx, &names_blob,
- "aaa",
- MsvAvNbDomainName, domain,
- MsvAvNbComputerName, hostname,
- MsvAvEOL, "");
+ /* Deliberately ignore return here.. */
+ if (hostname != NULL) {
+ (void)msrpc_gen(mem_ctx, &names_blob,
+ "aaa",
+ MsvAvNbDomainName, domain,
+ MsvAvNbComputerName, hostname,
+ MsvAvEOL, "");
+ } else {
+ (void)msrpc_gen(mem_ctx, &names_blob,
+ "aa",
+ MsvAvNbDomainName, domain,
+ MsvAvEOL, "");
+ }
return names_blob;
}
-static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, const DATA_BLOB *names_blob)
+static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx,
+ NTTIME nttime,
+ const DATA_BLOB *names_blob)
{
uint8_t client_chal[8];
DATA_BLOB response = data_blob(NULL, 0);
uint8_t long_date[8];
- NTTIME nttime;
-
- unix_to_nt_time(&nttime, time(NULL));
generate_random_buffer(client_chal, sizeof(client_chal));
/* See http://www.ubiqx.org/cifs/SMB.html#SMB.8.5 */
- msrpc_gen(mem_ctx, &response, "ddbbdb",
+ /* Deliberately ignore return here.. */
+ (void)msrpc_gen(mem_ctx, &response, "ddbbdb",
0x00000101, /* Header */
0, /* 'Reserved' */
long_date, 8, /* Timestamp */
static DATA_BLOB NTLMv2_generate_response(TALLOC_CTX *out_mem_ctx,
const uint8_t ntlm_v2_hash[16],
const DATA_BLOB *server_chal,
+ NTTIME nttime,
const DATA_BLOB *names_blob)
{
uint8_t ntlmv2_response[16];
/* NTLMv2 */
/* generate some data to pass into the response function - including
the hostname and domain name of the server */
- ntlmv2_client_data = NTLMv2_generate_client_data(mem_ctx, names_blob);
+ ntlmv2_client_data = NTLMv2_generate_client_data(mem_ctx, nttime, names_blob);
/* Given that data, and the challenge from the server, generate a response */
SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &ntlmv2_client_data, ntlmv2_response);
bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx,
const char *user, const char *domain, const uint8_t nt_hash[16],
const DATA_BLOB *server_chal,
+ const NTTIME *server_timestamp,
const DATA_BLOB *names_blob,
DATA_BLOB *lm_response, DATA_BLOB *nt_response,
DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
the username and domain.
This prevents username swapping during the auth exchange
*/
- if (!ntv2_owf_gen(nt_hash, user, domain, true, ntlm_v2_hash)) {
+ if (!ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash)) {
return false;
}
if (nt_response) {
+ const NTTIME *nttime = server_timestamp;
+ NTTIME _now = 0;
+
+ if (nttime == NULL) {
+ struct timeval tv_now = timeval_current();
+ _now = timeval_to_nttime(&tv_now);
+ nttime = &_now;
+ }
+
*nt_response = NTLMv2_generate_response(mem_ctx,
- ntlm_v2_hash, server_chal,
+ ntlm_v2_hash,
+ server_chal,
+ *nttime,
names_blob);
if (user_session_key) {
*user_session_key = data_blob_talloc(mem_ctx, NULL, 16);
/* LMv2 */
if (lm_response) {
- *lm_response = LMv2_generate_response(mem_ctx,
- ntlm_v2_hash, server_chal);
+ if (server_timestamp != NULL) {
+ *lm_response = data_blob_talloc_zero(mem_ctx, 24);
+ } else {
+ *lm_response = LMv2_generate_response(mem_ctx,
+ ntlm_v2_hash,
+ server_chal);
+ }
if (lm_session_key) {
*lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
E_md4hash(password, nt_hash);
return SMBNTLMv2encrypt_hash(mem_ctx,
- user, domain, nt_hash, server_chal, names_blob,
+ user, domain, nt_hash,
+ server_chal, NULL, names_blob,
lm_response, nt_response, lm_session_key, user_session_key);
}
bool encode_pw_buffer(uint8_t buffer[516], const char *password, int string_flags)
{
uint8_t new_pw[512];
- size_t new_pw_len;
+ ssize_t new_pw_len;
/* the incoming buffer can be any alignment. */
string_flags |= STR_NOALIGN;
new_pw_len = push_string(new_pw,
password,
sizeof(new_pw), string_flags);
+ if (new_pw_len == -1) {
+ return false;
+ }
memcpy(&buffer[512 - new_pw_len], new_pw, new_pw_len);
&in_buffer[512 - byte_len],
byte_len,
(void *)pp_new_pwrd,
- new_pw_len,
- false)) {
+ new_pw_len)) {
DEBUG(0, ("decode_pw_buffer: failed to convert incoming password\n"));
return false;
}
void encode_or_decode_arc4_passwd_buffer(unsigned char pw_buf[532], const DATA_BLOB *psession_key)
{
- struct MD5Context tctx;
+ MD5_CTX tctx;
unsigned char key_out[16];
/* Confounder is last 16 bytes. */
struct wkssvc_PasswordBuffer **pwd_buf)
{
uint8_t buffer[516];
- struct MD5Context ctx;
+ MD5_CTX ctx;
struct wkssvc_PasswordBuffer *my_pwd_buf = NULL;
DATA_BLOB confounded_session_key;
int confounder_len = 8;
char **pwd)
{
uint8_t buffer[516];
- struct MD5Context ctx;
+ MD5_CTX ctx;
size_t pwd_len;
DATA_BLOB confounded_session_key;
*pwd = NULL;
if (!pwd_buf) {
- return WERR_BAD_PASSWORD;
+ return WERR_INVALID_PASSWORD;
}
if (session_key->length != 16) {
DEBUG(10,("invalid session key\n"));
- return WERR_BAD_PASSWORD;
+ return WERR_INVALID_PASSWORD;
}
confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
if (!decode_pw_buffer(mem_ctx, buffer, pwd, &pwd_len, CH_UTF16)) {
data_blob_free(&confounded_session_key);
- return WERR_BAD_PASSWORD;
+ return WERR_INVALID_PASSWORD;
}
data_blob_free(&confounded_session_key);