diff options
Diffstat (limited to 'source3/libsmb')
-rw-r--r-- | source3/libsmb/asn1.c | 21 | ||||
-rw-r--r-- | source3/libsmb/cliconnect.c | 313 | ||||
-rw-r--r-- | source3/libsmb/clientgen.c | 18 | ||||
-rw-r--r-- | source3/libsmb/clikrb5.c | 2 | ||||
-rw-r--r-- | source3/libsmb/clispnego.c | 336 | ||||
-rw-r--r-- | source3/libsmb/errormap.c | 2 | ||||
-rw-r--r-- | source3/libsmb/ntlmssp.c | 492 | ||||
-rw-r--r-- | source3/libsmb/smbencrypt.c | 111 |
8 files changed, 531 insertions, 764 deletions
diff --git a/source3/libsmb/asn1.c b/source3/libsmb/asn1.c index 09d4fbb6c9..333d157905 100644 --- a/source3/libsmb/asn1.c +++ b/source3/libsmb/asn1.c @@ -240,9 +240,7 @@ BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag) uint8 b; struct nesting *nesting; - if (!asn1_read_uint8(data, &b)) - return False; - + asn1_read_uint8(data, &b); if (b != tag) { data->has_error = True; return False; @@ -253,18 +251,13 @@ BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag) return False; } - if (!asn1_read_uint8(data, &b)) { - return False; - } - + asn1_read_uint8(data, &b); if (b & 0x80) { int n = b & 0x7f; - if (!asn1_read_uint8(data, &b)) - return False; + asn1_read_uint8(data, &b); nesting->taglen = b; while (n > 1) { - if (!asn1_read_uint8(data, &b)) - return False; + asn1_read_uint8(data, &b); nesting->taglen = (nesting->taglen << 8) | b; n--; } @@ -411,11 +404,7 @@ BOOL asn1_check_enumerated(ASN1_DATA *data, int v) if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False; asn1_read_uint8(data, &b); asn1_end_tag(data); - - if (v != b) - data->has_error = False; - - return !data->has_error; + return !data->has_error && (v == b); } /* write an enumarted value to the stream */ diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 487b184dd6..389b7a1733 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2,7 +2,7 @@ Unix SMB/CIFS implementation. client connect/disconnect routines Copyright (C) Andrew Tridgell 1994-1998 - Copyright (C) Andrew Barteltt 2001-2003 + Copyright (C) Andrew Barteltt 2001-2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -45,7 +45,7 @@ static const struct { ****************************************************************************/ static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user, - const char *pass, size_t passlen, const char *workgroup) + const char *pass, int passlen, const char *workgroup) { fstring pword; char *p; @@ -228,7 +228,7 @@ static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user, return True; } -static void set_signing_on_cli (struct cli_state *cli, uint8 user_session_key[16], DATA_BLOB response) +static void set_signing_on_cli (struct cli_state *cli, const char* pass, uint8 response[24]) { uint8 zero_sig[8]; ZERO_STRUCT(zero_sig); @@ -242,18 +242,12 @@ static void set_signing_on_cli (struct cli_state *cli, uint8 user_session_key[16 DEBUG(3, ("smb signing enabled!\n")); cli->sign_info.use_smb_signing = True; - cli_calculate_mac_key(cli, user_session_key, response); + cli_calculate_mac_key(cli, pass, response); } else { DEBUG(5, ("smb signing NOT enabled!\n")); } } -static void set_cli_session_key (struct cli_state *cli, DATA_BLOB session_key) -{ - memcpy(cli->user_session_key, session_key.data, MIN(session_key.length, sizeof(cli->user_session_key))); -} - - static void set_temp_signing_on_cli(struct cli_state *cli) { if (cli->sign_info.negotiated_smb_signing) @@ -271,54 +265,37 @@ static void set_temp_signing_on_cli(struct cli_state *cli) ****************************************************************************/ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, - const char *pass, size_t passlen, - const char *ntpass, size_t ntpasslen, + const char *pass, int passlen, + const char *ntpass, int ntpasslen, const char *workgroup) { uint32 capabilities = cli_session_setup_capabilities(cli); - DATA_BLOB lm_response = data_blob(NULL, 0); - DATA_BLOB nt_response = data_blob(NULL, 0); - DATA_BLOB session_key = data_blob(NULL, 0); - BOOL ret = False; + uchar pword[24]; + uchar ntpword[24]; char *p; + BOOL have_plaintext = False; - if (passlen != 24) { - if (lp_client_ntlmv2_auth()) { - DATA_BLOB server_chal; - - server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8)); - - if (!SMBNTLMv2encrypt(user, workgroup, pass, server_chal, - &lm_response, &nt_response, &session_key)) { - data_blob_free(&server_chal); - return False; - } - data_blob_free(&server_chal); - - } else { - uchar nt_hash[16]; - E_md4hash(pass, nt_hash); - - /* non encrypted password supplied. Ignore ntpass. */ - if (lp_client_lanman_auth()) { - lm_response = data_blob(NULL, 24); - SMBencrypt(pass,cli->secblob.data,lm_response.data); - } + if (passlen > sizeof(pword) || ntpasslen > sizeof(ntpword)) + return False; - nt_response = data_blob(NULL, 24); - SMBNTencrypt(pass,cli->secblob.data,nt_response.data); - session_key = data_blob(NULL, 16); - SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); - } + if (passlen != 24) { + /* non encrypted password supplied. Ignore ntpass. */ + passlen = 24; + ntpasslen = 24; + SMBencrypt(pass,cli->secblob.data,pword); + SMBNTencrypt(pass,cli->secblob.data,ntpword); + have_plaintext = True; set_temp_signing_on_cli(cli); } else { /* pre-encrypted password supplied. Only used for security=server, can't do signing becouse we don't have oringial key */ - - lm_response = data_blob(pass, passlen); - nt_response = data_blob(ntpass, ntpasslen); + memcpy(pword, pass, 24); + if (ntpasslen == 24) + memcpy(ntpword, ntpass, 24); + else + ZERO_STRUCT(ntpword); } /* send a session setup command */ @@ -333,33 +310,28 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, SSVAL(cli->outbuf,smb_vwv3,2); SSVAL(cli->outbuf,smb_vwv4,cli->pid); SIVAL(cli->outbuf,smb_vwv5,cli->sesskey); - SSVAL(cli->outbuf,smb_vwv7,lm_response.length); - SSVAL(cli->outbuf,smb_vwv8,nt_response.length); + SSVAL(cli->outbuf,smb_vwv7,passlen); + SSVAL(cli->outbuf,smb_vwv8,ntpasslen); SIVAL(cli->outbuf,smb_vwv11,capabilities); p = smb_buf(cli->outbuf); - if (lm_response.length) { - memcpy(p,lm_response.data, lm_response.length); p += lm_response.length; - } - if (nt_response.length) { - memcpy(p,nt_response.data, nt_response.length); p += nt_response.length; - } + memcpy(p,pword,passlen); p += passlen; + memcpy(p,ntpword,ntpasslen); p += ntpasslen; p += clistr_push(cli, p, user, -1, STR_TERMINATE); p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE); p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE); cli_setup_bcc(cli, p); - if (!cli_send_smb(cli) || !cli_receive_smb(cli)) { - ret = False; - goto end; - } + if (!cli_send_smb(cli)) + return False; + + if (!cli_receive_smb(cli)) + return False; show_msg(cli->inbuf); - if (cli_is_error(cli)) { - ret = False; - goto end; - } + if (cli_is_error(cli)) + return False; /* use the returned vuid from now on */ cli->vuid = SVAL(cli->inbuf,smb_uid); @@ -371,16 +343,11 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, fstrcpy(cli->user_name, user); - if (session_key.data) { + if (have_plaintext) { /* Have plaintext orginal */ - set_cli_session_key(cli, session_key); - set_signing_on_cli(cli, session_key.data, nt_response); + set_signing_on_cli(cli, pass, ntpword); } - -end: - data_blob_free(&lm_response); - data_blob_free(&nt_response); - data_blob_free(&session_key); + return True; } @@ -392,9 +359,11 @@ static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob) { uint32 capabilities = cli_session_setup_capabilities(cli); char *p; - DATA_BLOB blob2 = data_blob(NULL, 0); + DATA_BLOB blob2; uint32 len; + blob2 = data_blob(NULL, 0); + capabilities |= CAP_EXTENDED_SECURITY; /* send a session setup command */ @@ -451,13 +420,6 @@ static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob) #ifdef HAVE_KRB5 /**************************************************************************** - Use in-memory credentials cache -****************************************************************************/ -static void use_in_memory_ccache() { - setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1); -} - -/**************************************************************************** Do a spnego/kerberos encrypted session setup. ****************************************************************************/ @@ -494,87 +456,126 @@ static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *princi static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, const char *pass, const char *workgroup) { - struct ntlmssp_client_state *ntlmssp_state; - NTSTATUS nt_status; - int turn = 1; - DATA_BLOB msg1; - DATA_BLOB blob; - DATA_BLOB blob_in = data_blob(NULL, 0); - DATA_BLOB blob_out; + DATA_BLOB msg1, struct_blob; + DATA_BLOB blob, chal1, chal2, auth, challenge_blob; + uint8 challenge[8]; + uint8 nthash[24], lmhash[24], sess_key[16]; + uint32 neg_flags, chal_flags, ntlmssp_command, unkn1, unkn2; + pstring server_domain; /* FIX THIS, SHOULD be UCS2-LE */ + + neg_flags = NTLMSSP_NEGOTIATE_UNICODE | + NTLMSSP_NEGOTIATE_128 | + NTLMSSP_NEGOTIATE_NTLM | + NTLMSSP_REQUEST_TARGET; + + memset(sess_key, 0, 16); + + DEBUG(10, ("sending NTLMSSP_NEGOTIATE\n")); + + /* generate the ntlmssp negotiate packet */ + msrpc_gen(&blob, "CddAA", + "NTLMSSP", + NTLMSSP_NEGOTIATE, + neg_flags, + workgroup, + cli->calling.name); + DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n", + neg_flags, workgroup, cli->calling.name)); + /* and wrap it in a SPNEGO wrapper */ + msg1 = gen_negTokenInit(OID_NTLMSSP, blob); + data_blob_free(&blob); - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) { + /* now send that blob on its way */ + blob = cli_session_setup_blob(cli, msg1); + + data_blob_free(&msg1); + + if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) return False; - } - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) { +#if 0 + file_save("chal.dat", blob.data, blob.length); +#endif + + /* the server gives us back two challenges */ + if (!spnego_parse_challenge(blob, &chal1, &chal2)) { + DEBUG(3,("Failed to parse challenges\n")); return False; } - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, workgroup))) { - return False; + + data_blob_free(&blob); + + /* + * Ok, chal1 and chal2 are actually two identical copies of + * the NTLMSSP Challenge BLOB, and they contain, encoded in them + * the challenge to use. + */ + + if (!msrpc_parse(&chal1, "CdUdbddB", + "NTLMSSP", + &ntlmssp_command, + &server_domain, + &chal_flags, + &challenge_blob, 8, + &unkn1, &unkn2, + &struct_blob)) { + DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n")); + return False; } - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) { + + if (ntlmssp_command != NTLMSSP_CHALLENGE) { + DEBUG(0, ("NTLMSSP Response != NTLMSSP_CHALLENGE. Got %0X\n", + ntlmssp_command)); return False; } + + DEBUG(10, ("Challenge:\n")); + dump_data(10, challenge_blob.data, 8); - ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth(); - - do { - nt_status = ntlmssp_client_update(ntlmssp_state, - blob_in, &blob_out); - data_blob_free(&blob_in); - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - if (turn == 1) { - /* and wrap it in a SPNEGO wrapper */ - msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out); - } else { - /* wrap it in SPNEGO */ - msg1 = spnego_gen_auth(blob_out); - } - - /* now send that blob on its way */ - blob = cli_session_setup_blob(cli, msg1); - data_blob_free(&msg1); - nt_status = cli_nt_error(cli); - } - - if (!blob.length) { - if (NT_STATUS_IS_OK(nt_status)) { - nt_status = NT_STATUS_UNSUCCESSFUL; - } - } else if ((turn == 1) && - NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - DATA_BLOB tmp_blob = data_blob(NULL, 0); - /* the server might give us back two challenges */ - if (!spnego_parse_challenge(blob, &blob_in, - &tmp_blob)) { - DEBUG(3,("Failed to parse challenges\n")); - nt_status = NT_STATUS_INVALID_PARAMETER; - } - data_blob_free(&tmp_blob); - } else { - /* the server might give us back two challenges */ - if (!spnego_parse_auth_response(blob, nt_status, - &blob_in)) { - DEBUG(3,("Failed to parse auth response\n")); - if (NT_STATUS_IS_OK(nt_status) - || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) - nt_status = NT_STATUS_INVALID_PARAMETER; - } - } - data_blob_free(&blob); - data_blob_free(&blob_out); - turn++; - } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)); + /* encrypt the password with the challenge which is in the blob */ + memcpy(challenge, challenge_blob.data, 8); + SMBencrypt(pass, challenge,lmhash); + SMBNTencrypt(pass, challenge,nthash); + data_blob_free(&challenge_blob); - if (NT_STATUS_IS_OK(nt_status)) { - set_cli_session_key(cli, ntlmssp_state->session_key); - } +#if 0 + file_save("nthash.dat", nthash, 24); + file_save("lmhash.dat", lmhash, 24); + file_save("chal1.dat", chal1.data, chal1.length); +#endif + + data_blob_free(&chal1); + data_blob_free(&chal2); + + /* this generates the actual auth packet */ + msrpc_gen(&blob, "CdBBUUUBd", + "NTLMSSP", + NTLMSSP_AUTH, + lmhash, 24, + nthash, 24, + workgroup, + user, + cli->calling.name, + sess_key, 0, + neg_flags); + + /* wrap it in SPNEGO */ + auth = spnego_gen_auth(blob); + + data_blob_free(&blob); - if (!NT_STATUS_IS_OK(ntlmssp_client_end(&ntlmssp_state))) { + /* now send the auth packet and we should be done */ + blob = cli_session_setup_blob(cli, auth); + + data_blob_free(&auth); + data_blob_free(&blob); + + if (cli_is_error(cli)) return False; - } - return (NT_STATUS_IS_OK(nt_status)); + set_signing_on_cli(cli, pass, nthash); + + return True; } /**************************************************************************** @@ -627,21 +628,6 @@ static BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user, fstrcpy(cli->user_name, user); #ifdef HAVE_KRB5 - /* If password is set we reauthenticate to kerberos server - * and do not store results */ - - if (*pass) { - int ret; - - use_in_memory_ccache(); - ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */); - - if (ret){ - DEBUG(0, ("Kinit failed: %s\n", error_message(ret))); - return False; - } - } - if (got_kerberos_mechanism && cli->use_kerberos) { return cli_session_setup_kerberos(cli, principal, workgroup); } @@ -956,10 +942,7 @@ BOOL cli_negprot(struct cli_state *cli) smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN); } - if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)) - cli->sign_info.negotiated_smb_signing = True; - - if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && cli->sign_info.allow_smb_signing) + if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) cli->sign_info.negotiated_smb_signing = True; } else if (cli->protocol >= PROTOCOL_LANMAN1) { diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 9598f4ac96..ed1286d627 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -114,14 +114,9 @@ BOOL cli_receive_smb(struct cli_state *cli) cli->smb_rw_error = smb_read_error; close(cli->fd); cli->fd = -1; - return ret; } - if (!cli_check_sign_mac(cli)) { - DEBUG(0, ("SMB Signiture verification failed on incoming packet!\n")); - return False; - }; - return True; + return ret; } /**************************************************************************** @@ -251,10 +246,8 @@ struct cli_state *cli_initialise(struct cli_state *cli) cli->outbuf = (char *)malloc(cli->bufsize); cli->inbuf = (char *)malloc(cli->bufsize); cli->oplock_handler = cli_oplock_ack; - - cli->use_spnego = lp_client_use_spnego(); - - cli->capabilities = CAP_UNICODE | CAP_STATUS32; + if (lp_use_spnego()) + cli->use_spnego = True; /* Set the CLI_FORCE_DOSERR environment variable to test client routines using DOS errors instead of STATUS32 @@ -262,8 +255,9 @@ struct cli_state *cli_initialise(struct cli_state *cli) if (getenv("CLI_FORCE_DOSERR")) cli->force_dos_errors = True; - if (lp_client_signing()) - cli->sign_info.allow_smb_signing = True; + /* A way to attempt to force SMB signing */ + if (getenv("CLI_FORCE_SMB_SIGNING")) + cli->sign_info.negotiated_smb_signing = True; if (!cli->outbuf || !cli->inbuf) goto error; diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index e380d80bcc..203d9d874b 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/libsmb/clikrb5.c @@ -278,7 +278,6 @@ DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset) ENCTYPE_ARCFOUR_HMAC, #endif ENCTYPE_DES_CBC_MD5, - ENCTYPE_DES_CBC_CRC, ENCTYPE_NULL}; retval = krb5_init_context(&context); @@ -325,6 +324,7 @@ failed: return data_blob(NULL, 0); } + #else /* HAVE_KRB5 */ /* this saves a few linking headaches */ DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset) diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index e93f1855dd..3e28baa417 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/libsmb/clispnego.c @@ -345,7 +345,7 @@ DATA_BLOB spnego_gen_negTokenTarg(const char *principal, int time_offset) /* parse a spnego NTLMSSP challenge packet giving two security blobs */ -BOOL spnego_parse_challenge(const DATA_BLOB blob, +BOOL spnego_parse_challenge(DATA_BLOB blob, DATA_BLOB *chal1, DATA_BLOB *chal2) { BOOL ret; @@ -387,7 +387,7 @@ BOOL spnego_parse_challenge(const DATA_BLOB blob, /* - generate a SPNEGO auth packet. This will contain the encrypted passwords + generate a SPNEGO NTLMSSP auth packet. This will contain the encrypted passwords */ DATA_BLOB spnego_gen_auth(DATA_BLOB blob) { @@ -412,7 +412,7 @@ DATA_BLOB spnego_gen_auth(DATA_BLOB blob) } /* - parse a SPNEGO auth packet. This contains the encrypted passwords + parse a SPNEGO NTLMSSP auth packet. This contains the encrypted passwords */ BOOL spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth) { @@ -447,11 +447,11 @@ DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply, NTSTATUS nt_status) uint8 negResult; if (NT_STATUS_IS_OK(nt_status)) { - negResult = SPNEGO_NEG_RESULT_ACCEPT; + negResult = SPNGEO_NEG_RESULT_ACCEPT; } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - negResult = SPNEGO_NEG_RESULT_INCOMPLETE; + negResult = SPNGEO_NEG_RESULT_INCOMPLETE; } else { - negResult = SPNEGO_NEG_RESULT_REJECT; + negResult = SPNGEO_NEG_RESULT_REJECT; } ZERO_STRUCT(data); @@ -461,8 +461,7 @@ DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply, NTSTATUS nt_status) asn1_push_tag(&data, ASN1_CONTEXT(0)); asn1_write_enumerated(&data, negResult); asn1_pop_tag(&data); - - if (negResult == SPNEGO_NEG_RESULT_INCOMPLETE) { + if (negResult == SPNGEO_NEG_RESULT_INCOMPLETE) { asn1_push_tag(&data,ASN1_CONTEXT(1)); asn1_write_OID(&data, OID_NTLMSSP); asn1_pop_tag(&data); @@ -481,50 +480,297 @@ DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply, NTSTATUS nt_status) } /* - parse a SPNEGO NTLMSSP auth packet. This contains the encrypted passwords -*/ -BOOL spnego_parse_auth_response(DATA_BLOB blob, NTSTATUS nt_status, - DATA_BLOB *auth) + this is a tiny msrpc packet generator. I am only using this to + avoid tying this code to a particular varient of our rpc code. This + generator is not general enough for all our rpc needs, its just + enough for the spnego/ntlmssp code + + format specifiers are: + + U = unicode string (input is unix string) + a = address (input is BOOL unicode, char *unix_string) + (1 byte type, 1 byte length, unicode/ASCII string, all inline) + A = ASCII string (input is unix string) + B = data blob (pointer + length) + b = data blob in header (pointer + length) + D + d = word (4 bytes) + C = constant ascii string + */ +BOOL msrpc_gen(DATA_BLOB *blob, + const char *format, ...) { - ASN1_DATA data; - uint8 negResult; - - if (NT_STATUS_IS_OK(nt_status)) { - negResult = SPNEGO_NEG_RESULT_ACCEPT; - } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - negResult = SPNEGO_NEG_RESULT_INCOMPLETE; - } else { - negResult = SPNEGO_NEG_RESULT_REJECT; + int i, n; + va_list ap; + char *s; + uint8 *b; + int head_size=0, data_size=0; + int head_ofs, data_ofs; + BOOL unicode; + + /* first scan the format to work out the header and body size */ + va_start(ap, format); + for (i=0; format[i]; i++) { + switch (format[i]) { + case 'U': + s = va_arg(ap, char *); + head_size += 8; + data_size += str_charnum(s) * 2; + break; + case 'A': + s = va_arg(ap, char *); + head_size += 8; + data_size += str_ascii_charnum(s); + break; + case 'a': + unicode = va_arg(ap, BOOL); + n = va_arg(ap, int); + s = va_arg(ap, char *); + if (unicode) { + data_size += (str_charnum(s) * 2) + 4; + } else { + data_size += (str_ascii_charnum(s)) + 4; + } + break; + case 'B': + b = va_arg(ap, uint8 *); + head_size += 8; + data_size += va_arg(ap, int); + break; + case 'b': + b = va_arg(ap, uint8 *); + head_size += va_arg(ap, int); + break; + case 'd': + n = va_arg(ap, int); + head_size += 4; + break; + case 'C': + s = va_arg(ap, char *); + head_size += str_charnum(s) + 1; + break; + } } - - asn1_load(&data, blob); - asn1_start_tag(&data, ASN1_CONTEXT(1)); - asn1_start_tag(&data, ASN1_SEQUENCE(0)); - asn1_start_tag(&data, ASN1_CONTEXT(0)); - asn1_check_enumerated(&data, negResult); - asn1_end_tag(&data); - - if (negResult == SPNEGO_NEG_RESULT_INCOMPLETE) { - asn1_start_tag(&data,ASN1_CONTEXT(1)); - asn1_check_OID(&data, OID_NTLMSSP); - asn1_end_tag(&data); - - asn1_start_tag(&data,ASN1_CONTEXT(2)); - asn1_read_OctetString(&data, auth); - asn1_end_tag(&data); + va_end(ap); + + /* allocate the space, then scan the format again to fill in the values */ + *blob = data_blob(NULL, head_size + data_size); + + head_ofs = 0; + data_ofs = head_size; + + va_start(ap, format); + for (i=0; format[i]; i++) { + switch (format[i]) { + case 'U': + s = va_arg(ap, char *); + n = str_charnum(s); + SSVAL(blob->data, head_ofs, n*2); head_ofs += 2; + SSVAL(blob->data, head_ofs, n*2); head_ofs += 2; + SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4; + push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN); + data_ofs += n*2; + break; + case 'A': + s = va_arg(ap, char *); + n = str_ascii_charnum(s); + SSVAL(blob->data, head_ofs, n); head_ofs += 2; + SSVAL(blob->data, head_ofs, n); head_ofs += 2; + SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4; + push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN); + data_ofs += n; + break; + case 'a': + unicode = va_arg(ap, BOOL); + n = va_arg(ap, int); + SSVAL(blob->data, data_ofs, n); data_ofs += 2; + s = va_arg(ap, char *); + if (unicode) { + n = str_charnum(s); + SSVAL(blob->data, data_ofs, n*2); data_ofs += 2; + if (0 < n) { + push_string(NULL, blob->data+data_ofs, s, n*2, + STR_UNICODE|STR_NOALIGN); + } + data_ofs += n*2; + } else { + n = str_ascii_charnum(s); + SSVAL(blob->data, data_ofs, n); data_ofs += 2; + if (0 < n) { + push_string(NULL, blob->data+data_ofs, s, n, + STR_ASCII|STR_NOALIGN); + } + data_ofs += n; + } + break; + + case 'B': + b = va_arg(ap, uint8 *); + n = va_arg(ap, int); + SSVAL(blob->data, head_ofs, n); head_ofs += 2; + SSVAL(blob->data, head_ofs, n); head_ofs += 2; + SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4; + memcpy(blob->data+data_ofs, b, n); + data_ofs += n; + break; + case 'd': + n = va_arg(ap, int); + SIVAL(blob->data, head_ofs, n); head_ofs += 4; + break; + case 'b': + b = va_arg(ap, uint8 *); + n = va_arg(ap, int); + memcpy(blob->data + head_ofs, b, n); + head_ofs += n; + break; + case 'C': + s = va_arg(ap, char *); + head_ofs += push_string(NULL, blob->data+head_ofs, s, -1, + STR_ASCII|STR_TERMINATE); + break; + } } + va_end(ap); - asn1_end_tag(&data); - asn1_end_tag(&data); + return True; +} - if (data.has_error) { - DEBUG(3,("spnego_parse_auth_response failed at %d\n", (int)data.ofs)); - asn1_free(&data); - data_blob_free(auth); - return False; + +/* + this is a tiny msrpc packet parser. This the the partner of msrpc_gen + + format specifiers are: + + U = unicode string (output is unix string) + A = ascii string + B = data blob + b = data blob in header + d = word (4 bytes) + C = constant ascii string + */ +BOOL msrpc_parse(DATA_BLOB *blob, + const char *format, ...) +{ + int i; + va_list ap; + char **ps, *s; + DATA_BLOB *b; + int head_ofs = 0; + uint16 len1, len2; + uint32 ptr; + uint32 *v; + pstring p; + + va_start(ap, format); + for (i=0; format[i]; i++) { + switch (format[i]) { + case 'U': + len1 = SVAL(blob->data, head_ofs); head_ofs += 2; + len2 = SVAL(blob->data, head_ofs); head_ofs += 2; + ptr = IVAL(blob->data, head_ofs); head_ofs += 4; + /* make sure its in the right format - be strict */ + if (len1 != len2 || (len1&1) || ptr + len1 > blob->length) { + return False; + } + ps = va_arg(ap, char **); + pull_string(NULL, p, blob->data + ptr, -1, len1, + STR_UNICODE|STR_NOALIGN); + (*ps) = strdup(p); + break; + case 'A': + len1 = SVAL(blob->data, head_ofs); head_ofs += 2; + len2 = SVAL(blob->data, head_ofs); head_ofs += 2; + ptr = IVAL(blob->data, head_ofs); head_ofs += 4; + + /* make sure its in the right format - be strict */ + if (len1 != len2 || ptr + len1 > blob->length) { + return False; + } + ps = va_arg(ap, char **); + if (0 < len1) { + pull_string(NULL, p, blob->data + ptr, -1, + len1, STR_ASCII|STR_NOALIGN); + (*ps) = strdup(p); + } else { + (*ps) = NULL; + } + break; + case 'B': + len1 = SVAL(blob->data, head_ofs); head_ofs += 2; + len2 = SVAL(blob->data, head_ofs); head_ofs += 2; + ptr = IVAL(blob->data, head_ofs); head_ofs += 4; + /* make sure its in the right format - be strict */ + if (len1 != len2 || ptr + len1 > blob->length) { + return False; + } + b = (DATA_BLOB *)va_arg(ap, void *); + *b = data_blob(blob->data + ptr, len1); + break; + case 'b': + b = (DATA_BLOB *)va_arg(ap, void *); + len1 = va_arg(ap, unsigned); + *b = data_blob(blob->data + head_ofs, len1); + head_ofs += len1; + break; + case 'd': + v = va_arg(ap, uint32 *); + *v = IVAL(blob->data, head_ofs); head_ofs += 4; + break; + case 'C': + s = va_arg(ap, char *); + head_ofs += pull_string(NULL, p, blob->data+head_ofs, sizeof(p), + blob->length - head_ofs, + STR_ASCII|STR_TERMINATE); + if (strcmp(s, p) != 0) { + return False; + } + break; + } } + va_end(ap); - asn1_free(&data); return True; } +/** + * Print out the NTLMSSP flags for debugging + */ + +void debug_ntlmssp_flags(uint32 neg_flags) +{ + DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags)); + + if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_OEM) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n")); + if (neg_flags & NTLMSSP_REQUEST_TARGET) + DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_SIGN) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_SEAL) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_NTLM) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n")); + if (neg_flags & NTLMSSP_CHAL_TARGET_INFO) + DEBUGADD(4, (" NTLMSSP_CHAL_TARGET_INFO\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_128) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n")); + if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) + DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n")); +} + diff --git a/source3/libsmb/errormap.c b/source3/libsmb/errormap.c index 8ee5ee3d31..09340caccd 100644 --- a/source3/libsmb/errormap.c +++ b/source3/libsmb/errormap.c @@ -1410,7 +1410,7 @@ static const struct { /***************************************************************************** convert a dos eclas/ecode to a NT status32 code *****************************************************************************/ -NTSTATUS dos_to_ntstatus(uint8 eclass, uint32 ecode) +NTSTATUS dos_to_ntstatus(int eclass, int ecode) { int i; if (eclass == 0 && ecode == 0) return NT_STATUS_OK; diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c index e4398dad17..5b608e0a7a 100644 --- a/source3/libsmb/ntlmssp.c +++ b/source3/libsmb/ntlmssp.c @@ -24,53 +24,11 @@ #include "includes.h" /** - * Print out the NTLMSSP flags for debugging - * @param neg_flags The flags from the packet - */ - -void debug_ntlmssp_flags(uint32 neg_flags) -{ - DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags)); - - if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_OEM) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n")); - if (neg_flags & NTLMSSP_REQUEST_TARGET) - DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_SIGN) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_SEAL) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NTLM) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n")); - if (neg_flags & NTLMSSP_CHAL_TARGET_INFO) - DEBUGADD(4, (" NTLMSSP_CHAL_TARGET_INFO\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_128) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n")); - if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) - DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n")); -} - -/** - * Default challenge generation code. + * Default challange generation code. * */ + static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state) { static uchar chal[8]; @@ -79,17 +37,71 @@ static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state) return chal; } -/** - * Determine correct target name flags for reply, given server role - * and negoitated falgs - * - * @param ntlmssp_state NTLMSSP State - * @param neg_flags The flags from the packet - * @param chal_flags The flags to be set in the reply packet - * @return The 'target name' string. - */ +NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state) +{ + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_init("NTLMSSP context"); + + *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state)); + if (!*ntlmssp_state) { + DEBUG(0,("ntlmssp_start: talloc failed!\n")); + talloc_destroy(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + + ZERO_STRUCTP(*ntlmssp_state); + + (*ntlmssp_state)->mem_ctx = mem_ctx; + (*ntlmssp_state)->get_challenge = get_challenge; + + (*ntlmssp_state)->get_global_myname = global_myname; + (*ntlmssp_state)->get_domain = lp_workgroup; + (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */ + + return NT_STATUS_OK; +} + +NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state) +{ + TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx; + + data_blob_free(&(*ntlmssp_state)->chal); + data_blob_free(&(*ntlmssp_state)->lm_resp); + data_blob_free(&(*ntlmssp_state)->nt_resp); + + SAFE_FREE((*ntlmssp_state)->user); + SAFE_FREE((*ntlmssp_state)->domain); + SAFE_FREE((*ntlmssp_state)->workstation); + + talloc_destroy(mem_ctx); + *ntlmssp_state = NULL; + return NT_STATUS_OK; +} + +NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, + DATA_BLOB request, DATA_BLOB *reply) +{ + uint32 ntlmssp_command; + *reply = data_blob(NULL, 0); + + if (!msrpc_parse(&request, "Cd", + "NTLMSSP", + &ntlmssp_command)) { + + return NT_STATUS_LOGON_FAILURE; + } + + if (ntlmssp_command == NTLMSSP_NEGOTIATE) { + return ntlmssp_negotiate(ntlmssp_state, request, reply); + } else if (ntlmssp_command == NTLMSSP_AUTH) { + return ntlmssp_auth(ntlmssp_state, request, reply); + } else { + return NT_STATUS_LOGON_FAILURE; + } +} -static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state, +static const char *ntlmssp_target_name(NTLMSSP_STATE *ntlmssp_state, uint32 neg_flags, uint32 *chal_flags) { if (neg_flags & NTLMSSP_REQUEST_TARGET) { @@ -107,17 +119,8 @@ static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state, } } -/** - * Next state function for the Negotiate packet - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB - * @param request The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors or MORE_PROCESSING_REQUIRED if a reply is sent. - */ - -static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, - const DATA_BLOB request, DATA_BLOB *reply) +NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state, + DATA_BLOB request, DATA_BLOB *reply) { DATA_BLOB struct_blob; fstring dnsname, dnsdomname; @@ -137,7 +140,7 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, &neg_flags, &cliname, &domname)) { - return NT_STATUS_INVALID_PARAMETER; + return NT_STATUS_LOGON_FAILURE; } SAFE_FREE(cliname); @@ -216,22 +219,11 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, data_blob_free(&struct_blob); - ntlmssp_state->expected_state = NTLMSSP_AUTH; - return NT_STATUS_MORE_PROCESSING_REQUIRED; } -/** - * Next state function for the Authenticate packet - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB - * @param request The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, - const DATA_BLOB request, DATA_BLOB *reply) +NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state, + DATA_BLOB request, DATA_BLOB *reply) { DATA_BLOB sess_key; uint32 ntlmssp_command, neg_flags; @@ -268,7 +260,7 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, &ntlmssp_state->workstation, &sess_key, &neg_flags)) { - return NT_STATUS_INVALID_PARAMETER; + return NT_STATUS_LOGON_FAILURE; } data_blob_free(&sess_key); @@ -287,343 +279,3 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, return nt_status; } - -/** - * Create an NTLMSSP state machine - * - * @param ntlmssp_state NTLMSSP State, allocated by this funciton - */ - -NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state) -{ - TALLOC_CTX *mem_ctx; - - mem_ctx = talloc_init("NTLMSSP context"); - - *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state)); - if (!*ntlmssp_state) { - DEBUG(0,("ntlmssp_server_start: talloc failed!\n")); - talloc_destroy(mem_ctx); - return NT_STATUS_NO_MEMORY; - } - - ZERO_STRUCTP(*ntlmssp_state); - - (*ntlmssp_state)->mem_ctx = mem_ctx; - (*ntlmssp_state)->get_challenge = get_challenge; - - (*ntlmssp_state)->get_global_myname = global_myname; - (*ntlmssp_state)->get_domain = lp_workgroup; - (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */ - - (*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE; - - return NT_STATUS_OK; -} - -/** - * End an NTLMSSP state machine - * - * @param ntlmssp_state NTLMSSP State, free()ed by this funciton - */ - -NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state) -{ - TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx; - - data_blob_free(&(*ntlmssp_state)->chal); - data_blob_free(&(*ntlmssp_state)->lm_resp); - data_blob_free(&(*ntlmssp_state)->nt_resp); - - SAFE_FREE((*ntlmssp_state)->user); - SAFE_FREE((*ntlmssp_state)->domain); - SAFE_FREE((*ntlmssp_state)->workstation); - - talloc_destroy(mem_ctx); - *ntlmssp_state = NULL; - return NT_STATUS_OK; -} - -/** - * Next state function for the NTLMSSP state machine - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB - * @param request The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK. - */ - -NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, - const DATA_BLOB request, DATA_BLOB *reply) -{ - uint32 ntlmssp_command; - *reply = data_blob(NULL, 0); - - if (!msrpc_parse(&request, "Cd", - "NTLMSSP", - &ntlmssp_command)) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (ntlmssp_command != ntlmssp_state->expected_state) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (ntlmssp_command == NTLMSSP_NEGOTIATE) { - return ntlmssp_server_negotiate(ntlmssp_state, request, reply); - } else if (ntlmssp_command == NTLMSSP_AUTH) { - return ntlmssp_server_auth(ntlmssp_state, request, reply); - } else { - return NT_STATUS_INVALID_PARAMETER; - } -} - -/********************************************************************* - Client side NTLMSSP -*********************************************************************/ - -/** - * Next state function for the Initial packet - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB. reply.data must be NULL - * @param request The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_state, - DATA_BLOB reply, DATA_BLOB *next_request) -{ - if (ntlmssp_state->unicode) { - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; - } - - /* generate the ntlmssp negotiate packet */ - msrpc_gen(next_request, "CddAA", - "NTLMSSP", - NTLMSSP_NEGOTIATE, - ntlmssp_state->neg_flags, - ntlmssp_state->get_domain(), - ntlmssp_state->get_global_myname()); - - return NT_STATUS_MORE_PROCESSING_REQUIRED; -} - -/** - * Next state function for the Challenge Packet. Generate an auth packet. - * - * @param ntlmssp_state NTLMSSP State - * @param request The request, as a DATA_BLOB. reply.data must be NULL - * @param request The reply, as an allocated DATA_BLOB, caller to free. - * @return Errors or NT_STATUS_OK. - */ - -static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_state, - const DATA_BLOB reply, DATA_BLOB *next_request) -{ - uint32 chal_flags, ntlmssp_command, unkn1, unkn2; - DATA_BLOB server_domain_blob; - DATA_BLOB challenge_blob; - DATA_BLOB struct_blob; - char *server_domain; - const char *chal_parse_string; - const char *auth_gen_string; - DATA_BLOB lm_response = data_blob(NULL, 0); - DATA_BLOB nt_response = data_blob(NULL, 0); - DATA_BLOB session_key = data_blob(NULL, 0); - uint8 datagram_sess_key[16]; - - ZERO_STRUCT(datagram_sess_key); - - if (!msrpc_parse(&reply, "CdBd", - "NTLMSSP", - &ntlmssp_command, - &server_domain_blob, - &chal_flags)) { - DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - data_blob_free(&server_domain_blob); - - if (chal_flags & NTLMSSP_NEGOTIATE_UNICODE) { - chal_parse_string = "CdUdbddB"; - auth_gen_string = "CdBBUUUBd"; - ntlmssp_state->unicode = True; - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE; - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM; - } else if (chal_flags & NTLMSSP_NEGOTIATE_OEM) { - chal_parse_string = "CdAdbddB"; - auth_gen_string = "CdBBAAABd"; - ntlmssp_state->unicode = False; - ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE; - ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM; - } else { - return NT_STATUS_INVALID_PARAMETER; - } - - if (!msrpc_parse(&reply, chal_parse_string, - "NTLMSSP", - &ntlmssp_command, - &server_domain, - &chal_flags, - &challenge_blob, 8, - &unkn1, &unkn2, - &struct_blob)) { - DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - SAFE_FREE(server_domain); - data_blob_free(&struct_blob); - - if (challenge_blob.length != 8) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (ntlmssp_state->use_ntlmv2) { - - /* TODO: if the remote server is standalone, then we should replace 'domain' - with the server name as supplied above */ - - if (!SMBNTLMv2encrypt(ntlmssp_state->user, - ntlmssp_state->domain, - ntlmssp_state->password, challenge_blob, - &lm_response, &nt_response, &session_key)) { - data_blob_free(&challenge_blob); - return NT_STATUS_NO_MEMORY; - } - } else { - uchar nt_hash[16]; - E_md4hash(ntlmssp_state->password, nt_hash); - - /* non encrypted password supplied. Ignore ntpass. */ - if (lp_client_lanman_auth()) { - lm_response = data_blob(NULL, 24); - SMBencrypt(ntlmssp_state->password,challenge_blob.data, - lm_response.data); - } - - nt_response = data_blob(NULL, 24); - SMBNTencrypt(ntlmssp_state->password,challenge_blob.data, - nt_response.data); - session_key = data_blob(NULL, 16); - SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); - } - - data_blob_free(&challenge_blob); - - /* this generates the actual auth packet */ - if (!msrpc_gen(next_request, auth_gen_string, - "NTLMSSP", - NTLMSSP_AUTH, - lm_response.data, lm_response.length, - nt_response.data, nt_response.length, - ntlmssp_state->domain, - ntlmssp_state->user, - ntlmssp_state->get_global_myname(), - datagram_sess_key, 0, - ntlmssp_state->neg_flags)) { - - data_blob_free(&lm_response); - data_blob_free(&nt_response); - data_blob_free(&session_key); - return NT_STATUS_NO_MEMORY; - } - - data_blob_free(&lm_response); - data_blob_free(&nt_response); - - ntlmssp_state->session_key = session_key; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; -} - -NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state) -{ - TALLOC_CTX *mem_ctx; - - mem_ctx = talloc_init("NTLMSSP Client context"); - - *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state)); - if (!*ntlmssp_state) { - DEBUG(0,("ntlmssp_server_start: talloc failed!\n")); - talloc_destroy(mem_ctx); - return NT_STATUS_NO_MEMORY; - } - - ZERO_STRUCTP(*ntlmssp_state); - - (*ntlmssp_state)->mem_ctx = mem_ctx; - - (*ntlmssp_state)->get_global_myname = global_myname; - (*ntlmssp_state)->get_domain = lp_workgroup; - - (*ntlmssp_state)->unicode = True; - - (*ntlmssp_state)->neg_flags = - NTLMSSP_NEGOTIATE_128 | - NTLMSSP_NEGOTIATE_NTLM | - NTLMSSP_REQUEST_TARGET; - - return NT_STATUS_OK; -} - -NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state) -{ - TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx; - - data_blob_free(&(*ntlmssp_state)->session_key); - talloc_destroy(mem_ctx); - *ntlmssp_state = NULL; - return NT_STATUS_OK; -} - -NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state, - DATA_BLOB reply, DATA_BLOB *next_request) -{ - uint32 ntlmssp_command; - *next_request = data_blob(NULL, 0); - - if (!reply.length) { - return ntlmssp_client_initial(ntlmssp_state, reply, next_request); - } - - if (!msrpc_parse(&reply, "Cd", - "NTLMSSP", - &ntlmssp_command)) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (ntlmssp_command == NTLMSSP_CHALLENGE) { - return ntlmssp_client_challenge(ntlmssp_state, reply, next_request); - } - return NT_STATUS_INVALID_PARAMETER; -} - -NTSTATUS ntlmssp_set_username(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *user) -{ - ntlmssp_state->user = talloc_strdup(ntlmssp_state->mem_ctx, user); - if (!ntlmssp_state->user) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -NTSTATUS ntlmssp_set_password(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *password) -{ - ntlmssp_state->password = talloc_strdup(ntlmssp_state->mem_ctx, password); - if (!ntlmssp_state->password) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} - -NTSTATUS ntlmssp_set_domain(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *domain) -{ - ntlmssp_state->domain = talloc_strdup(ntlmssp_state->mem_ctx, domain); - if (!ntlmssp_state->domain) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index aa9391325f..a57a98e3ea 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/libsmb/smbencrypt.c @@ -5,7 +5,6 @@ Modified by Jeremy Allison 1995. Copyright (C) Jeremy Allison 1995-2000. Copyright (C) Luke Kennethc Casson Leighton 1996-2000. - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -295,64 +294,6 @@ void SMBsesskeygen_ntv1(const uchar kr[16], #endif } -DATA_BLOB NTLMv2_generate_response(uchar ntlm_v2_hash[16], - DATA_BLOB server_chal, size_t client_chal_length) -{ - uchar ntlmv2_response[16]; - DATA_BLOB ntlmv2_client_data; - DATA_BLOB final_response; - - /* NTLMv2 */ - - /* We also get to specify some random data */ - ntlmv2_client_data = data_blob(NULL, client_chal_length); - generate_random_buffer(ntlmv2_client_data.data, ntlmv2_client_data.length, False); - - /* Given that data, and the challenge from the server, generate a response */ - SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, ntlmv2_client_data, ntlmv2_response); - - /* put it into nt_response, for the code below to put into the packet */ - final_response = data_blob(NULL, ntlmv2_client_data.length + sizeof(ntlmv2_response)); - memcpy(final_response.data, ntlmv2_response, sizeof(ntlmv2_response)); - /* after the first 16 bytes is the random data we generated above, so the server can verify us with it */ - memcpy(final_response.data + sizeof(ntlmv2_response), ntlmv2_client_data.data, ntlmv2_client_data.length); - data_blob_free(&ntlmv2_client_data); - - return final_response; -} - -BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password, - const DATA_BLOB server_chal, - DATA_BLOB *lm_response, DATA_BLOB *nt_response, - DATA_BLOB *session_key) -{ - uchar nt_hash[16]; - uchar ntlm_v2_hash[16]; - E_md4hash(password, nt_hash); - - /* We don't use the NT# directly. Instead we use it mashed up with - the username and domain. - This prevents username swapping during the auth exchange - */ - if (!ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash)) { - return False; - } - - *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, 64 /* pick a number, > 8 */); - - /* LMv2 */ - - *lm_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, 8); - - *session_key = data_blob(NULL, 16); - - /* The NTLMv2 calculations also provide a session key, for signing etc later */ - /* use only the first 16 bytes of nt_response for session key */ - SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, session_key->data); - - return True; -} - /*********************************************************** encode a password buffer. The caller gets to figure out what to put in it. @@ -421,20 +362,20 @@ BOOL decode_pw_buffer(char in_buffer[516], char *new_pwrd, SMB signing - setup the MAC key. ************************************************************/ -void cli_calculate_mac_key(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response) +void cli_calculate_mac_key(struct cli_state *cli, const char *ntpasswd, const uchar resp[24]) { - - memcpy(&cli->sign_info.mac_key[0], user_session_key, 16); - memcpy(&cli->sign_info.mac_key[16],response.data, MIN(response.length, 40 - 16)); - cli->sign_info.mac_key_len = MIN(response.length + 16, 40); + /* Get first 16 bytes. */ + E_md4hash(ntpasswd,&cli->sign_info.mac_key[0]); + memcpy(&cli->sign_info.mac_key[16],resp,24); + cli->sign_info.mac_key_len = 40; cli->sign_info.use_smb_signing = True; /* These calls are INCONPATIBLE with SMB signing */ cli->readbraw_supported = False; - cli->writebraw_supported = False; + cli->writebraw_supported = False; /* Reset the sequence number in case we had a previous (aborted) attempt */ - cli->sign_info.send_seq_num = 2; + cli->sign_info.send_seq_num = 0; } /*********************************************************** @@ -470,47 +411,9 @@ void cli_caclulate_sign_mac(struct cli_state *cli) MD5Final(calc_md5_mac, &md5_ctx); memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8); - /* cli->outbuf[smb_ss_field+2]=0; Uncomment this to test if the remote server actually verifies signitures...*/ cli->sign_info.send_seq_num++; cli->sign_info.reply_seq_num = cli->sign_info.send_seq_num; cli->sign_info.send_seq_num++; } - -/*********************************************************** - SMB signing - check a MAC sent by server. -************************************************************/ - -BOOL cli_check_sign_mac(struct cli_state *cli) -{ - unsigned char calc_md5_mac[16]; - unsigned char server_sent_mac[8]; - struct MD5Context md5_ctx; - - if (cli->sign_info.temp_smb_signing) { - return True; - } - - if (!cli->sign_info.use_smb_signing) { - return True; - } - - /* - * Firstly put the sequence number into the first 4 bytes. - * and zero out the next 4 bytes. - */ - - memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac)); - - SIVAL(cli->inbuf, smb_ss_field, cli->sign_info.reply_seq_num); - SIVAL(cli->inbuf, smb_ss_field + 4, 0); - - /* Calculate the 16 byte MAC and place first 8 bytes into the field. */ - MD5Init(&md5_ctx); - MD5Update(&md5_ctx, cli->sign_info.mac_key, cli->sign_info.mac_key_len); - MD5Update(&md5_ctx, cli->inbuf + 4, smb_len(cli->inbuf)); - MD5Final(calc_md5_mac, &md5_ctx); - - return (memcmp(server_sent_mac, calc_md5_mac, 8) == 0); -} |