X-Git-Url: http://git.samba.org/samba.git/?p=nivanova%2Fsamba-autobuild%2F.git;a=blobdiff_plain;f=source3%2Flibsmb%2Fcliconnect.c;h=146fc3d3b47d0726dd97868d78445663009f5e63;hp=ec1ec670acb248269d570a03c132c9f14adbf6fa;hb=8080dbad78edbc26c8ece8ae7f1abc27f0d7afd4;hpb=fa5475ea9e3cbd610ea9d00ce3a84123ea21b394 diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index ec1ec670acb..146fc3d3b47 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -22,33 +22,19 @@ #include "includes.h" #include "libsmb/libsmb.h" -#include "popt_common.h" +#include "auth_info.h" #include "../libcli/auth/libcli_auth.h" #include "../libcli/auth/spnego.h" #include "smb_krb5.h" -#include "../libcli/auth/ntlmssp.h" +#include "../auth/ntlmssp/ntlmssp.h" #include "libads/kerberos_proto.h" #include "krb5_env.h" #include "../lib/util/tevent_ntstatus.h" #include "async_smb.h" #include "libsmb/nmblib.h" -#include "read_smb.h" - -static const struct { - int prot; - const char name[24]; -} prots[10] = { - {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"}, - {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"}, - {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"}, - {PROTOCOL_LANMAN1, "LANMAN1.0"}, - {PROTOCOL_LANMAN2, "LM1.2X002"}, - {PROTOCOL_LANMAN2, "DOS LANMAN2.1"}, - {PROTOCOL_LANMAN2, "LANMAN2.1"}, - {PROTOCOL_LANMAN2, "Samba"}, - {PROTOCOL_NT1, "NT LANMAN 1.0"}, - {PROTOCOL_NT1, "NT LM 0.12"}, -}; +#include "librpc/ndr/libndr.h" +#include "../libcli/smb/smbXcli_base.h" +#include "smb2cli.h" #define STAR_SMBSERVER "*SMBSERVER" @@ -133,16 +119,6 @@ static struct tevent_req *cli_session_setup_lanman2_send( state->user = user; vwv = state->vwv; - /* - * LANMAN servers predate NT status codes and Unicode and - * ignore those smb flags so we must disable the corresponding - * default capabilities that would otherwise cause the Unicode - * and NT Status flags to be set (and even returned by the - * server) - */ - - cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32); - /* * if in share level security then don't send a password now */ @@ -162,7 +138,7 @@ static struct tevent_req *cli_session_setup_lanman2_send( return tevent_req_post(req, ev); } - if (!SMBencrypt(pass, cli->secblob.data, + if (!SMBencrypt(pass, cli_state_server_challenge(cli), (uint8_t *)lm_response.data)) { DEBUG(1, ("Password is > 14 chars in length, and is " "therefore incompatible with Lanman " @@ -205,7 +181,7 @@ static struct tevent_req *cli_session_setup_lanman2_send( SSVAL(vwv+2, 0, CLI_BUFFER_SIZE); SSVAL(vwv+3, 0, 2); SSVAL(vwv+4, 0, 1); - SIVAL(vwv+5, 0, cli->sesskey); + SIVAL(vwv+5, 0, cli_state_server_session_key(cli)); SSVAL(vwv+7, 0, lm_response.length); bytes = talloc_array(state, uint8_t, lm_response.length); @@ -317,9 +293,6 @@ static void cli_session_setup_lanman2_done(struct tevent_req *subreq) } p += ret; - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } status = cli_set_username(cli, state->user); if (tevent_req_nterror(req, status)) { return; @@ -370,18 +343,31 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, const char *use Work out suitable capabilities to offer the server. ****************************************************************************/ -static uint32 cli_session_setup_capabilities(struct cli_state *cli) +static uint32_t cli_session_setup_capabilities(struct cli_state *cli, + uint32_t sesssetup_capabilities) { - uint32 capabilities = CAP_NT_SMBS; + uint32_t client_capabilities = cli_state_capabilities(cli); - if (!cli->force_dos_errors) - capabilities |= CAP_STATUS32; + /* + * We only send capabilities based on the mask for: + * - client only flags + * - flags used in both directions + * + * We do not echo the server only flags. + */ + client_capabilities &= (SMB_CAP_BOTH_MASK | SMB_CAP_CLIENT_MASK); - if (cli->use_level_II_oplocks) - capabilities |= CAP_LEVEL_II_OPLOCKS; + /* + * Session Setup specific flags CAP_DYNAMIC_REAUTH + * and CAP_EXTENDED_SECURITY are passed by the caller. + * We need that in order to do guest logins even if + * CAP_EXTENDED_SECURITY is negotiated. + */ + client_capabilities &= ~(CAP_DYNAMIC_REAUTH|CAP_EXTENDED_SECURITY); + sesssetup_capabilities &= (CAP_DYNAMIC_REAUTH|CAP_EXTENDED_SECURITY); + client_capabilities |= sesssetup_capabilities; - capabilities |= (cli_state_capabilities(cli) & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS)); - return capabilities; + return client_capabilities; } /**************************************************************************** @@ -420,12 +406,12 @@ struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx, SSVAL(vwv+2, 0, CLI_BUFFER_SIZE); SSVAL(vwv+3, 0, 2); SSVAL(vwv+4, 0, cli_state_get_vc_num(cli)); - SIVAL(vwv+5, 0, cli->sesskey); + SIVAL(vwv+5, 0, cli_state_server_session_key(cli)); SSVAL(vwv+7, 0, 0); SSVAL(vwv+8, 0, 0); SSVAL(vwv+9, 0, 0); SSVAL(vwv+10, 0, 0); - SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli)); + SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0)); bytes = talloc_array(state, uint8_t, 0); @@ -545,10 +531,6 @@ static void cli_session_setup_guest_done(struct tevent_req *subreq) } p += ret; - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } - status = cli_set_username(cli, ""); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); @@ -639,12 +621,12 @@ static struct tevent_req *cli_session_setup_plain_send( SSVAL(vwv+2, 0, CLI_BUFFER_SIZE); SSVAL(vwv+3, 0, 2); SSVAL(vwv+4, 0, cli_state_get_vc_num(cli)); - SIVAL(vwv+5, 0, cli->sesskey); + SIVAL(vwv+5, 0, cli_state_server_session_key(cli)); SSVAL(vwv+7, 0, 0); SSVAL(vwv+8, 0, 0); SSVAL(vwv+9, 0, 0); SSVAL(vwv+10, 0, 0); - SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli)); + SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0)); bytes = talloc_array(state, uint8_t, 0); bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), pass, strlen(pass)+1, @@ -756,9 +738,7 @@ static void cli_session_setup_plain_done(struct tevent_req *subreq) if (tevent_req_nterror(req, status)) { return; } - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } + tevent_req_done(req); } @@ -853,11 +833,9 @@ static struct tevent_req *cli_session_setup_nt1_send( DATA_BLOB server_chal; DATA_BLOB names_blob; - server_chal = data_blob(cli->secblob.data, - MIN(cli->secblob.length, 8)); - if (tevent_req_nomem(server_chal.data, req)) { - return tevent_req_post(req, ev); - } + server_chal = + data_blob_const(cli_state_server_challenge(cli), + 8); /* * note that the 'workgroup' here is a best @@ -877,13 +855,11 @@ static struct tevent_req *cli_session_setup_nt1_send( &lm_response, &nt_response, NULL, &session_key)) { data_blob_free(&names_blob); - data_blob_free(&server_chal); tevent_req_nterror( req, NT_STATUS_ACCESS_DENIED); return tevent_req_post(req, ev); } data_blob_free(&names_blob); - data_blob_free(&server_chal); } else { uchar nt_hash[16]; @@ -897,7 +873,7 @@ static struct tevent_req *cli_session_setup_nt1_send( return tevent_req_post(req, ev); } - SMBNTencrypt(pass, cli->secblob.data, + SMBNTencrypt(pass, cli_state_server_challenge(cli), nt_response.data); #endif /* non encrypted password supplied. Ignore ntpass. */ @@ -908,7 +884,8 @@ static struct tevent_req *cli_session_setup_nt1_send( return tevent_req_post(req, ev); } - if (!SMBencrypt(pass,cli->secblob.data, + if (!SMBencrypt(pass, + cli_state_server_challenge(cli), lm_response.data)) { /* * Oops, the LM response is @@ -944,7 +921,6 @@ static struct tevent_req *cli_session_setup_nt1_send( SMBsesskeygen_ntv1(nt_hash, session_key.data); #endif } - cli_temp_set_signing(cli); } else { /* pre-encrypted password supplied. Only used for security=server, can't do @@ -987,12 +963,12 @@ static struct tevent_req *cli_session_setup_nt1_send( SSVAL(vwv+2, 0, CLI_BUFFER_SIZE); SSVAL(vwv+3, 0, 2); SSVAL(vwv+4, 0, cli_state_get_vc_num(cli)); - SIVAL(vwv+5, 0, cli->sesskey); + SIVAL(vwv+5, 0, cli_state_server_session_key(cli)); SSVAL(vwv+7, 0, lm_response.length); SSVAL(vwv+8, 0, nt_response.length); SSVAL(vwv+9, 0, 0); SSVAL(vwv+10, 0, 0); - SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli)); + SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0)); bytes = talloc_array(state, uint8_t, lm_response.length + nt_response.length); @@ -1106,10 +1082,6 @@ static void cli_session_setup_nt1_done(struct tevent_req *subreq) } p += ret; - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } - status = cli_set_username(cli, state->user); if (tevent_req_nterror(req, status)) { return; @@ -1183,6 +1155,9 @@ struct cli_sesssetup_blob_state { uint16_t vwv[12]; uint8_t *buf; + DATA_BLOB smb2_blob; + struct iovec *recv_iov; + NTSTATUS status; char *inbuf; DATA_BLOB ret_blob; @@ -1210,8 +1185,12 @@ static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx, state->blob = blob; state->cli = cli; - usable_space = cli_state_available_size(cli, + if (cli_state_protocol(cli) >= PROTOCOL_SMB2_02) { + usable_space = UINT16_MAX; + } else { + usable_space = cli_state_available_size(cli, BASE_SESSSETUP_BLOB_PACKET_SIZE); + } if (usable_space == 0) { DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small " @@ -1236,6 +1215,32 @@ static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state, struct tevent_req *subreq; uint16_t thistime; + thistime = MIN(state->blob.length, state->max_blob_size); + + if (cli_state_protocol(state->cli) >= PROTOCOL_SMB2_02) { + + state->smb2_blob.data = state->blob.data; + state->smb2_blob.length = thistime; + + state->blob.data += thistime; + state->blob.length -= thistime; + + subreq = smb2cli_session_setup_send(state, state->ev, + state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + 0, /* in_flags */ + SMB2_CAP_DFS, /* in_capabilities */ + 0, /* in_channel */ + NULL, /* in_previous_session */ + &state->smb2_blob); + if (subreq == NULL) { + return false; + } + *psubreq = subreq; + return true; + } + SCVAL(state->vwv+0, 0, 0xFF); SCVAL(state->vwv+0, 1, 0); SSVAL(state->vwv+1, 0, 0); @@ -1244,14 +1249,12 @@ static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state, SSVAL(state->vwv+4, 0, 1); SIVAL(state->vwv+5, 0, 0); - thistime = MIN(state->blob.length, state->max_blob_size); SSVAL(state->vwv+7, 0, thistime); SSVAL(state->vwv+8, 0, 0); SSVAL(state->vwv+9, 0, 0); SIVAL(state->vwv+10, 0, - cli_session_setup_capabilities(state->cli) - | CAP_EXTENDED_SECURITY); + cli_session_setup_capabilities(state->cli, CAP_EXTENDED_SECURITY)); state->buf = (uint8_t *)talloc_memdup(state, state->blob.data, thistime); @@ -1295,8 +1298,15 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq) uint8_t *inbuf; ssize_t ret; - status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, - &num_bytes, &bytes); + if (cli_state_protocol(state->cli) >= PROTOCOL_SMB2_02) { + status = smb2cli_session_setup_recv(subreq, state, + &state->recv_iov, + &state->ret_blob); + } else { + status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, + &num_bytes, &bytes); + TALLOC_FREE(state->buf); + } TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { @@ -1305,7 +1315,10 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq) } state->status = status; - TALLOC_FREE(state->buf); + + if (cli_state_protocol(state->cli) >= PROTOCOL_SMB2_02) { + goto next; + } state->inbuf = (char *)inbuf; cli_state_set_uid(state->cli, SVAL(inbuf, smb_uid)); @@ -1359,10 +1372,7 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq) } p += ret; - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } - +next: if (state->blob.length != 0) { /* * More to send @@ -1380,25 +1390,32 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq) static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *pblob, - char **pinbuf) + char **pinbuf, + struct iovec **precv_iov) { struct cli_sesssetup_blob_state *state = tevent_req_data( req, struct cli_sesssetup_blob_state); NTSTATUS status; char *inbuf; + struct iovec *recv_iov; if (tevent_req_is_nterror(req, &status)) { + TALLOC_FREE(state->cli->smb2.session); cli_state_set_uid(state->cli, UID_FIELD_INVALID); return status; } inbuf = talloc_move(mem_ctx, &state->inbuf); + recv_iov = talloc_move(mem_ctx, &state->recv_iov); if (pblob != NULL) { *pblob = state->ret_blob; } if (pinbuf != NULL) { *pinbuf = inbuf; } + if (precv_iov != NULL) { + *precv_iov = recv_iov; + } /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */ return state->status; } @@ -1444,8 +1461,6 @@ static struct tevent_req *cli_session_setup_kerberos_send( state->cli = cli; state->ads_status = ADS_SUCCESS; - cli_temp_set_signing(cli); - /* * Ok, this is cheating: spnego_gen_krb5_negTokenInit can block if * we have to acquire a ticket. To be fixed later :-) @@ -1466,6 +1481,14 @@ static struct tevent_req *cli_session_setup_kerberos_send( state->negTokenTarg.length); #endif + if (cli_state_protocol(cli) >= PROTOCOL_SMB2_02) { + state->cli->smb2.session = smbXcli_session_create(cli, + cli->conn); + if (tevent_req_nomem(state->cli->smb2.session, req)) { + return tevent_req_post(req, ev); + } + } + subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); @@ -1481,25 +1504,36 @@ static void cli_session_setup_kerberos_done(struct tevent_req *subreq) struct cli_session_setup_kerberos_state *state = tevent_req_data( req, struct cli_session_setup_kerberos_state); char *inbuf = NULL; + struct iovec *recv_iov = NULL; NTSTATUS status; - status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf); + status = cli_sesssetup_blob_recv(subreq, state, + NULL, &inbuf, &recv_iov); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(subreq); tevent_req_nterror(req, status); return; } cli_set_session_key(state->cli, state->session_key_krb5); - if (cli_simple_set_signing(state->cli, state->session_key_krb5, - data_blob_null) - && !cli_check_sign_mac(state->cli, inbuf, 1)) { - TALLOC_FREE(subreq); - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; + if (cli_state_protocol(state->cli) >= PROTOCOL_SMB2_02) { + struct smbXcli_session *session = state->cli->smb2.session; + status = smb2cli_session_update_session_key(session, + state->session_key_krb5, + recv_iov); + if (tevent_req_nterror(req, status)) { + return; + } + } else { + if (cli_simple_set_signing(state->cli, state->session_key_krb5, + data_blob_null) + && !cli_check_sign_mac(state->cli, inbuf, 1)) { + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } } - TALLOC_FREE(subreq); + tevent_req_done(req); } @@ -1590,8 +1624,6 @@ static struct tevent_req *cli_session_setup_ntlmssp_send( talloc_set_destructor( state, cli_session_setup_ntlmssp_state_destructor); - cli_temp_set_signing(cli); - status = ntlmssp_client_start(state, lp_netbios_name(), lp_workgroup(), @@ -1627,6 +1659,14 @@ static struct tevent_req *cli_session_setup_ntlmssp_send( state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL); data_blob_free(&blob_out); + if (cli_state_protocol(cli) >= PROTOCOL_SMB2_02) { + state->cli->smb2.session = smbXcli_session_create(cli, + cli->conn); + if (tevent_req_nomem(state->cli->smb2.session, req)) { + return tevent_req_post(req, ev); + } + } + subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); @@ -1646,11 +1686,12 @@ static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq) req, struct cli_session_setup_ntlmssp_state); DATA_BLOB blob_in, msg_in, blob_out; char *inbuf = NULL; + struct iovec *recv_iov = NULL; bool parse_ret; NTSTATUS status; status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in, - &inbuf); + &inbuf, &recv_iov); TALLOC_FREE(subreq); data_blob_free(&state->blob_out); @@ -1660,7 +1701,6 @@ static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq) state->cli->server_domain = talloc_strdup(state->cli, state->ntlmssp_state->server.netbios_domain); if (state->cli->server_domain == NULL) { - TALLOC_FREE(subreq); tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -1668,15 +1708,23 @@ static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq) cli_set_session_key( state->cli, state->ntlmssp_state->session_key); - if (cli_simple_set_signing( - state->cli, state->ntlmssp_state->session_key, - data_blob_null) - && !cli_check_sign_mac(state->cli, inbuf, 1)) { - TALLOC_FREE(subreq); - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; + if (cli_state_protocol(state->cli) >= PROTOCOL_SMB2_02) { + struct smbXcli_session *session = state->cli->smb2.session; + status = smb2cli_session_update_session_key(session, + state->ntlmssp_state->session_key, + recv_iov); + if (tevent_req_nterror(req, status)) { + return; + } + } else { + if (cli_simple_set_signing( + state->cli, state->ntlmssp_state->session_key, + data_blob_null) + && !cli_check_sign_mac(state->cli, inbuf, 1)) { + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } } - TALLOC_FREE(subreq); TALLOC_FREE(state->ntlmssp_state); tevent_req_done(req); return; @@ -1719,14 +1767,12 @@ static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq) if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - TALLOC_FREE(subreq); TALLOC_FREE(state->ntlmssp_state); tevent_req_nterror(req, status); return; } state->blob_out = spnego_gen_auth(state, blob_out); - TALLOC_FREE(subreq); if (tevent_req_nomem(state->blob_out.data, req)) { return; } @@ -1797,15 +1843,21 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, char *principal = NULL; char *OIDs[ASN1_MAX_OIDS]; int i; - DATA_BLOB blob; + const DATA_BLOB *server_blob; + DATA_BLOB blob = data_blob_null; const char *p = NULL; char *account = NULL; NTSTATUS status; - DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length)); + server_blob = cli_state_server_gss_blob(cli); + if (server_blob) { + blob = data_blob(server_blob->data, server_blob->length); + } + + DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)blob.length)); /* the server might not even do spnego */ - if (cli->secblob.length <= 16) { + if (blob.length == 0) { DEBUG(3,("server didn't supply a full spnego negprot\n")); goto ntlmssp; } @@ -1814,9 +1866,6 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, file_save("negprot.dat", cli->secblob.data, cli->secblob.length); #endif - /* there is 16 bytes of GUID before the real spnego packet starts */ - blob = data_blob(cli->secblob.data+16, cli->secblob.length-16); - /* The server sent us the first part of the SPNEGO exchange in the * negprot reply. It is WRONG to depend on the principal sent in the * negprot reply, but right now we do it. If we don't receive one, @@ -1853,7 +1902,7 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, /* If password is set we reauthenticate to kerberos server * and do not store results */ - if (cli->got_kerberos_mechanism && cli->use_kerberos) { + if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) { ADS_STATUS rc; const char *remote_name = cli_state_remote_name(cli); @@ -1882,56 +1931,30 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, !is_ipaddress(remote_name) && !strequal(STAR_SMBSERVER, remote_name)) { - char *realm = NULL; - char *host = NULL; DEBUG(3,("cli_session_setup_spnego: using target " "hostname not SPNEGO principal\n")); - host = strchr_m(remote_name, '.'); if (dest_realm) { - realm = SMB_STRDUP(dest_realm); - if (!realm) { - return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + char *realm = strupper_talloc(talloc_tos(), dest_realm); + if (realm) { + principal = talloc_asprintf(talloc_tos(), + "cifs/%s@%s", + remote_name, + realm); + TALLOC_FREE(realm); } - strupper_m(realm); } else { - if (host) { - /* DNS name. */ - realm = kerberos_get_realm_from_hostname(remote_name); - } else { - /* NetBIOS name - use our realm. */ - realm = kerberos_get_default_realm_from_ccache(); - } + principal = kerberos_get_principal_from_service_hostname(talloc_tos(), + "cifs", + remote_name); } - if (realm == NULL || *realm == '\0') { - realm = SMB_STRDUP(lp_realm()); - if (!realm) { - return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); - } - strupper_m(realm); - DEBUG(3,("cli_session_setup_spnego: cannot " - "get realm from dest_realm %s, " - "desthost %s. Using default " - "smb.conf realm %s\n", - dest_realm ? dest_realm : "", - remote_name, - realm)); - } - - principal = talloc_asprintf(talloc_tos(), - "cifs/%s@%s", - remote_name, - realm); if (!principal) { - SAFE_FREE(realm); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } DEBUG(3,("cli_session_setup_spnego: guessed " "server principal=%s\n", principal ? principal : "")); - - SAFE_FREE(realm); } if (principal) { @@ -2029,6 +2052,18 @@ NTSTATUS cli_session_setup(struct cli_state *cli, workgroup); } + if (cli_state_protocol(cli) >= PROTOCOL_SMB2_02) { + const char *remote_realm = cli_state_remote_realm(cli); + ADS_STATUS status = cli_session_setup_spnego(cli, user, pass, + workgroup, + remote_realm); + if (!ADS_ERR_OK(status)) { + DEBUG(3, ("SMB2-SPNEGO login failed: %s\n", ads_errstr(status))); + return ads_ntstatus(status); + } + return NT_STATUS_OK; + } + /* if no user is supplied then we have to do an anonymous connection. passwords are ignored */ @@ -2078,10 +2113,6 @@ NTSTATUS cli_session_setup(struct cli_state *cli, } } - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } - return NT_STATUS_OK; } @@ -2234,7 +2265,7 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx, * Non-encrypted passwords - convert to DOS codepage before * encryption. */ - SMBencrypt(pass, cli->secblob.data, p24); + SMBencrypt(pass, cli_state_server_challenge(cli), p24); passlen = 24; pass = (const char *)p24; } else { @@ -2463,6 +2494,21 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share, return status; } +NTSTATUS cli_tree_connect(struct cli_state *cli, const char *share, + const char *dev, const char *pass, int passlen) +{ + cli->share = talloc_strdup(cli, share); + if (!cli->share) { + return NT_STATUS_NO_MEMORY; + } + + if (cli_state_protocol(cli) >= PROTOCOL_SMB2_02) { + return smb2cli_tcon(cli, share); + } + + return cli_tcon_andx(cli, share, dev, pass, passlen); +} + /**************************************************************************** Send a tree disconnect. ****************************************************************************/ @@ -2543,261 +2589,25 @@ fail: return status; } -/**************************************************************************** - Send a negprot command. -****************************************************************************/ - -struct cli_negprot_state { - struct cli_state *cli; -}; - -static void cli_negprot_done(struct tevent_req *subreq); - struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli) -{ - struct tevent_req *req, *subreq; - struct cli_negprot_state *state; - uint8_t *bytes = NULL; - int numprots; - - req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state); - if (req == NULL) { - return NULL; - } - state->cli = cli; - - if (cli_state_protocol(cli) < PROTOCOL_NT1) - cli->use_spnego = False; - - /* setup the protocol strings */ - for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) { - uint8_t c = 2; - if (prots[numprots].prot > cli_state_protocol(cli)) { - break; - } - bytes = (uint8_t *)talloc_append_blob( - state, bytes, data_blob_const(&c, sizeof(c))); - if (tevent_req_nomem(bytes, req)) { - return tevent_req_post(req, ev); - } - bytes = smb_bytes_push_str(bytes, false, - prots[numprots].name, - strlen(prots[numprots].name)+1, - NULL); - if (tevent_req_nomem(bytes, req)) { - return tevent_req_post(req, ev); - } - } - - subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL, - talloc_get_size(bytes), bytes); - - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, cli_negprot_done, req); - return req; -} - -static void cli_negprot_done(struct tevent_req *subreq) + struct cli_state *cli, + enum protocol_types max_protocol) { - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct cli_negprot_state *state = tevent_req_data( - req, struct cli_negprot_state); - struct cli_state *cli = state->cli; - uint8_t wct; - uint16_t *vwv; - uint32_t num_bytes; - uint8_t *bytes; - NTSTATUS status; - uint16_t protnum; - uint8_t *inbuf; - - status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv, - &num_bytes, &bytes); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; - } - - protnum = SVAL(vwv, 0); - - if ((protnum >= ARRAY_SIZE(prots)) - || (prots[protnum].prot > cli_state_protocol(cli))) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - cli->protocol = prots[protnum].prot; - - if ((cli_state_protocol(cli) < PROTOCOL_NT1) && - client_is_signing_mandatory(cli)) { - DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n")); - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - - if (cli_state_protocol(cli) >= PROTOCOL_NT1) { - struct timespec ts; - bool negotiated_smb_signing = false; - - if (wct != 0x11) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - /* NT protocol */ - cli->sec_mode = CVAL(vwv + 1, 0); - cli->max_mux = SVAL(vwv + 1, 1); - cli->max_xmit = IVAL(vwv + 3, 1); - cli->sesskey = IVAL(vwv + 7, 1); - cli->serverzone = SVALS(vwv + 15, 1); - cli->serverzone *= 60; - /* this time arrives in real GMT */ - ts = interpret_long_date(((char *)(vwv+11))+1); - cli->servertime = ts.tv_sec; - cli->secblob = data_blob(bytes, num_bytes); - cli->capabilities = IVAL(vwv + 9, 1); - if (cli_state_capabilities(cli) & CAP_RAW_MODE) { - cli->readbraw_supported = True; - cli->writebraw_supported = True; - } - /* work out if they sent us a workgroup */ - if (!(cli_state_capabilities(cli) & CAP_EXTENDED_SECURITY) && - smb_buflen(inbuf) > 8) { - ssize_t ret; - status = smb_bytes_talloc_string( - cli, (char *)inbuf, &cli->server_domain, - bytes + 8, num_bytes - 8, &ret); - if (tevent_req_nterror(req, status)) { - return; - } - } - - /* - * As signing is slow we only turn it on if either the client or - * the server require it. JRA. - */ - - if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) { - /* Fail if server says signing is mandatory and we don't want to support it. */ - if (!client_is_signing_allowed(cli)) { - DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n")); - tevent_req_nterror(req, - NT_STATUS_ACCESS_DENIED); - return; - } - negotiated_smb_signing = true; - } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) { - /* Fail if client says signing is mandatory and the server doesn't support it. */ - if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) { - DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n")); - tevent_req_nterror(req, - NT_STATUS_ACCESS_DENIED); - return; - } - negotiated_smb_signing = true; - } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) { - negotiated_smb_signing = true; - } - - if (negotiated_smb_signing) { - cli_set_signing_negotiated(cli); - } - - } else if (cli_state_protocol(cli) >= PROTOCOL_LANMAN1) { - if (wct != 0x0D) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - cli->use_spnego = False; - cli->sec_mode = SVAL(vwv + 1, 0); - cli->max_xmit = SVAL(vwv + 2, 0); - cli->max_mux = SVAL(vwv + 3, 0); - cli->sesskey = IVAL(vwv + 6, 0); - cli->serverzone = SVALS(vwv + 10, 0); - cli->serverzone *= 60; - /* this time is converted to GMT by make_unix_date */ - cli->servertime = make_unix_date( - (char *)(vwv + 8), cli->serverzone); - cli->readbraw_supported = ((SVAL(vwv + 5, 0) & 0x1) != 0); - cli->writebraw_supported = ((SVAL(vwv + 5, 0) & 0x2) != 0); - cli->secblob = data_blob(bytes, num_bytes); - } else { - /* the old core protocol */ - cli->use_spnego = False; - cli->sec_mode = 0; - cli->serverzone = get_time_zone(time(NULL)); - cli->max_xmit = 1024; - cli->max_mux = 1; - } - - if (cli->max_xmit < 1024) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - if (cli->max_mux < 1) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE); - - /* a way to force ascii SMB */ - if (cli->force_ascii) { - cli->capabilities &= ~CAP_UNICODE; - } - - tevent_req_done(req); + return smbXcli_negprot_send(mem_ctx, ev, + cli->conn, cli->timeout, + PROTOCOL_CORE, max_protocol); } NTSTATUS cli_negprot_recv(struct tevent_req *req) { - return tevent_req_simple_recv_ntstatus(req); + return smbXcli_negprot_recv(req); } -NTSTATUS cli_negprot(struct cli_state *cli) +NTSTATUS cli_negprot(struct cli_state *cli, enum protocol_types max_protocol) { - TALLOC_CTX *frame = talloc_stackframe(); - struct event_context *ev; - struct tevent_req *req; - NTSTATUS status = NT_STATUS_OK; - - if (cli_has_async_calls(cli)) { - /* - * Can't use sync call while an async call is in flight - */ - status = NT_STATUS_INVALID_PARAMETER; - goto fail; - } - - ev = event_context_init(frame); - if (ev == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - - req = cli_negprot_send(frame, ev, cli); - if (req == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - - if (!tevent_req_poll(req, ev)) { - status = map_nt_error_from_unix(errno); - goto fail; - } - - status = cli_negprot_recv(req); - fail: - TALLOC_FREE(frame); - return status; + return smbXcli_negprot(cli->conn, cli->timeout, + PROTOCOL_CORE, max_protocol); } static NTSTATUS cli_connect_sock(const char *host, int name_type, @@ -2905,6 +2715,8 @@ NTSTATUS cli_connect_nb(const char *host, const struct sockaddr_storage *dest_ss cli = cli_state_create(NULL, fd, desthost, NULL, signing_state, flags); if (cli == NULL) { + close(fd); + fd = -1; goto fail; } @@ -2939,7 +2751,7 @@ NTSTATUS cli_start_connection(struct cli_state **output_cli, return nt_status; } - nt_status = cli_negprot(cli); + nt_status = cli_negprot(cli, PROTOCOL_NT1); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status))); cli_shutdown(cli); @@ -3095,7 +2907,7 @@ struct cli_state *get_ipc_connect(char *server, lp_workgroup(), user_info->password ? user_info->password : "", flags, - Undefined); + SMB_SIGNING_DEFAULT); if (NT_STATUS_IS_OK(nt_status)) { return cli; @@ -3199,7 +3011,7 @@ struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx, if (!NT_STATUS_IS_OK(status)) { DEBUG(99, ("No master browsers responded: %s\n", nt_errstr(status))); - return False; + return NULL; } for (i = 0; i < count; i++) {