X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Flibsmb%2Fcliconnect.c;h=65f6924a688ddcb7f306bc321226ec6525658083;hb=f13404e27b00f826a11684e69cff82ae0023fc91;hp=112143ca9661a4f73a71277d0dc39b4b4c076da3;hpb=04f8c229de7ffad5f4ec1a0bb68c2c8b4ccf4e15;p=samba.git diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 112143ca966..65f6924a688 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -3,25 +3,30 @@ client connect/disconnect routines Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Andrew Bartlett 2001-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 the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "includes.h" +#include "popt_common.h" #include "../libcli/auth/libcli_auth.h" #include "../libcli/auth/spnego.h" #include "smb_krb5.h" +#include "../libcli/auth/ntlmssp.h" +#include "libads/kerberos_proto.h" +#include "krb5_env.h" +#include "async_smb.h" static const struct { int prot; @@ -104,7 +109,7 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, cli_set_message(cli->outbuf,10, 0, True); SCVAL(cli->outbuf,smb_com,SMBsesssetupX); cli_setup_packet(cli); - + SCVAL(cli->outbuf,smb_vwv0,0xFF); SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit); SSVAL(cli->outbuf,smb_vwv3,2); @@ -130,7 +135,7 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, if (cli_is_error(cli)) { return cli_nt_error(cli); } - + /* use the returned vuid from now on */ cli->vuid = SVAL(cli->inbuf,smb_uid); status = cli_set_username(cli, user); @@ -263,19 +268,21 @@ static void cli_session_setup_guest_done(struct tevent_req *subreq) req, struct cli_session_setup_guest_state); struct cli_state *cli = state->cli; uint32_t num_bytes; + uint8_t *in; char *inbuf; uint8_t *bytes; uint8_t *p; NTSTATUS status; - status = cli_smb_recv(subreq, 0, NULL, NULL, &num_bytes, &bytes); + status = cli_smb_recv(subreq, state, &in, 0, NULL, NULL, + &num_bytes, &bytes); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(subreq); tevent_req_nterror(req, status); return; } - inbuf = (char *)cli_smb_inbuf(subreq); + inbuf = (char *)in; p = bytes; cli->vuid = SVAL(inbuf, smb_uid); @@ -291,8 +298,6 @@ static void cli_session_setup_guest_done(struct tevent_req *subreq) cli->is_samba = True; } - TALLOC_FREE(subreq); - status = cli_set_username(cli, ""); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); @@ -359,14 +364,14 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli, char *p; NTSTATUS status; fstring lanman; - + fstr_sprintf( lanman, "Samba %s", samba_version_string()); memset(cli->outbuf, '\0', smb_size); cli_set_message(cli->outbuf,13,0,True); SCVAL(cli->outbuf,smb_com,SMBsesssetupX); cli_setup_packet(cli); - + SCVAL(cli->outbuf,smb_vwv0,0xFF); SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE); SSVAL(cli->outbuf,smb_vwv3,2); @@ -375,9 +380,9 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli, SSVAL(cli->outbuf,smb_vwv8,0); SIVAL(cli->outbuf,smb_vwv11,capabilities); p = smb_buf(cli->outbuf); - + /* check wether to send the ASCII or UNICODE version of the password */ - + if ( (capabilities & CAP_UNICODE) == 0 ) { p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */ SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf))); @@ -393,7 +398,7 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli, p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */ SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1); } - + p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */ p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE); @@ -403,9 +408,9 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli, if (!cli_send_smb(cli) || !cli_receive_smb(cli)) { return cli_nt_error(cli); } - + show_msg(cli->inbuf); - + if (cli_is_error(cli)) { return cli_nt_error(cli); } @@ -524,7 +529,7 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user, cli_set_message(cli->outbuf,13,0,True); SCVAL(cli->outbuf,smb_com,SMBsesssetupX); cli_setup_packet(cli); - + SCVAL(cli->outbuf,smb_vwv0,0xFF); SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE); SSVAL(cli->outbuf,smb_vwv3,2); @@ -574,7 +579,7 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user, /* use the returned vuid from now on */ cli->vuid = SVAL(cli->inbuf,smb_uid); - + p = smb_buf(cli->inbuf); p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE); @@ -605,172 +610,212 @@ end: return result; } -/**************************************************************************** - Send a extended security session setup blob -****************************************************************************/ +/* The following is calculated from : + * (smb_size-4) = 35 + * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() ) + * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at + * end of packet. + */ -static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob) -{ - uint32 capabilities = cli_session_setup_capabilities(cli); - char *p; +#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22) - capabilities |= CAP_EXTENDED_SECURITY; +struct cli_sesssetup_blob_state { + struct tevent_context *ev; + struct cli_state *cli; + DATA_BLOB blob; + uint16_t max_blob_size; + uint16_t vwv[12]; + uint8_t *buf; - /* send a session setup command */ - memset(cli->outbuf,'\0',smb_size); + NTSTATUS status; + char *inbuf; + DATA_BLOB ret_blob; +}; - cli_set_message(cli->outbuf,12,0,True); - SCVAL(cli->outbuf,smb_com,SMBsesssetupX); +static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state, + struct tevent_req **psubreq); +static void cli_sesssetup_blob_done(struct tevent_req *subreq); - cli_setup_packet(cli); +static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + DATA_BLOB blob) +{ + struct tevent_req *req, *subreq; + struct cli_sesssetup_blob_state *state; - SCVAL(cli->outbuf,smb_vwv0,0xFF); - SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE); - SSVAL(cli->outbuf,smb_vwv3,2); - SSVAL(cli->outbuf,smb_vwv4,1); - SIVAL(cli->outbuf,smb_vwv5,0); - SSVAL(cli->outbuf,smb_vwv7,blob.length); - SIVAL(cli->outbuf,smb_vwv10,capabilities); - p = smb_buf(cli->outbuf); - memcpy(p, blob.data, blob.length); - p += blob.length; - p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE); - p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE); - cli_setup_bcc(cli, p); - return cli_send_smb(cli); -} + req = tevent_req_create(mem_ctx, &state, + struct cli_sesssetup_blob_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->blob = blob; + state->cli = cli; -/**************************************************************************** - Send a extended security session setup blob, returning a reply blob. -****************************************************************************/ + if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) { + DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small " + "(was %u, need minimum %u)\n", + (unsigned int)cli->max_xmit, + BASE_SESSSETUP_BLOB_PACKET_SIZE)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + state->max_blob_size = + MIN(cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE, 0xFFFF); + + if (!cli_sesssetup_blob_next(state, &subreq)) { + tevent_req_nomem(NULL, req); + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req); + return req; +} -static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli) +static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state, + struct tevent_req **psubreq) { - DATA_BLOB blob2 = data_blob_null; - char *p; - size_t len; + struct tevent_req *subreq; + uint16_t thistime; + + SCVAL(state->vwv+0, 0, 0xFF); + SCVAL(state->vwv+0, 1, 0); + SSVAL(state->vwv+1, 0, 0); + SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE); + SSVAL(state->vwv+3, 0, 2); + 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); + + state->buf = (uint8_t *)talloc_memdup(state, state->blob.data, + thistime); + if (state->buf == NULL) { + return false; + } + state->blob.data += thistime; + state->blob.length -= thistime; - if (!cli_receive_smb(cli)) - return blob2; + state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli), + "Unix", 5, NULL); + state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli), + "Samba", 6, NULL); + if (state->buf == NULL) { + return false; + } + subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0, + 12, state->vwv, + talloc_get_size(state->buf), state->buf); + if (subreq == NULL) { + return false; + } + *psubreq = subreq; + return true; +} - show_msg(cli->inbuf); +static void cli_sesssetup_blob_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_sesssetup_blob_state *state = tevent_req_data( + req, struct cli_sesssetup_blob_state); + struct cli_state *cli = state->cli; + uint8_t wct; + uint16_t *vwv; + uint32_t num_bytes; + uint8_t *bytes; + NTSTATUS status; + uint8_t *p; + uint16_t blob_length; + uint8_t *inbuf; - if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli), - NT_STATUS_MORE_PROCESSING_REQUIRED)) { - return blob2; + status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv, + &num_bytes, &bytes); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status) + && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_nterror(req, status); + return; } - /* use the returned vuid from now on */ - cli->vuid = SVAL(cli->inbuf,smb_uid); + state->status = status; + TALLOC_FREE(state->buf); - p = smb_buf(cli->inbuf); + state->inbuf = (char *)inbuf; + cli->vuid = SVAL(state->inbuf, smb_uid); - blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3)); + blob_length = SVAL(vwv+3, 0); + if (blob_length > num_bytes) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + state->ret_blob = data_blob_const(bytes, blob_length); - p += blob2.length; - p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring), - -1, STR_TERMINATE); + p = bytes + blob_length; - /* w2k with kerberos doesn't properly null terminate this field */ - len = smb_bufrem(cli->inbuf, p); - if (p + len < cli->inbuf + cli->bufsize+SAFETY_MARGIN - 2) { - char *end_of_buf = p + len; + p += clistr_pull(state->inbuf, cli->server_os, + (char *)p, sizeof(fstring), + bytes+num_bytes-p, STR_TERMINATE); + p += clistr_pull(state->inbuf, cli->server_type, + (char *)p, sizeof(fstring), + bytes+num_bytes-p, STR_TERMINATE); + p += clistr_pull(state->inbuf, cli->server_domain, + (char *)p, sizeof(fstring), + bytes+num_bytes-p, STR_TERMINATE); - SSVAL(p, len, 0); - /* Now it's null terminated. */ - p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring), - -1, STR_TERMINATE); + if (strstr(cli->server_type, "Samba")) { + cli->is_samba = True; + } + + if (state->blob.length != 0) { /* - * See if there's another string. If so it's the - * server domain (part of the 'standard' Samba - * server signature). + * More to send */ - if (p < end_of_buf) { - p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring), - -1, STR_TERMINATE); + if (!cli_sesssetup_blob_next(state, &subreq)) { + tevent_req_nomem(NULL, req); + return; } - } else { - /* - * No room to null terminate so we can't see if there - * is another string (server_domain) afterwards. - */ - p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring), - len, 0); + tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req); + return; } - return blob2; + tevent_req_done(req); } -#ifdef HAVE_KRB5 -/**************************************************************************** - Send a extended security session setup blob, returning a reply blob. -****************************************************************************/ - -/* The following is calculated from : - * (smb_size-4) = 35 - * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() ) - * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at - * end of packet. - */ - -#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22) - -static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob) +static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + DATA_BLOB *pblob, + char **pinbuf) { - int32 remaining = blob.length; - int32 cur = 0; - DATA_BLOB send_blob = data_blob_null; - int32 max_blob_size = 0; - DATA_BLOB receive_blob = data_blob_null; + struct cli_sesssetup_blob_state *state = tevent_req_data( + req, struct cli_sesssetup_blob_state); + NTSTATUS status; + char *inbuf; - if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) { - DEBUG(0,("cli_session_setup_blob: cli->max_xmit too small " - "(was %u, need minimum %u)\n", - (unsigned int)cli->max_xmit, - BASE_SESSSETUP_BLOB_PACKET_SIZE)); - cli_set_nt_error(cli, NT_STATUS_INVALID_PARAMETER); - return False; + if (tevent_req_is_nterror(req, &status)) { + state->cli->vuid = 0; + return status; } - max_blob_size = cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE; - - while ( remaining > 0) { - if (remaining >= max_blob_size) { - send_blob.length = max_blob_size; - remaining -= max_blob_size; - } else { - send_blob.length = remaining; - remaining = 0; - } - - send_blob.data = &blob.data[cur]; - cur += send_blob.length; - - DEBUG(10, ("cli_session_setup_blob: Remaining (%u) sending (%u) current (%u)\n", - (unsigned int)remaining, - (unsigned int)send_blob.length, - (unsigned int)cur )); - - if (!cli_session_setup_blob_send(cli, send_blob)) { - DEBUG(0, ("cli_session_setup_blob: send failed\n")); - return False; - } - - receive_blob = cli_session_setup_blob_receive(cli); - data_blob_free(&receive_blob); - - if (cli_is_error(cli) && - !NT_STATUS_EQUAL( cli_get_nt_error(cli), - NT_STATUS_MORE_PROCESSING_REQUIRED)) { - DEBUG(0, ("cli_session_setup_blob: receive failed " - "(%s)\n", nt_errstr(cli_get_nt_error(cli)))); - cli->vuid = 0; - return False; - } + inbuf = talloc_move(mem_ctx, &state->inbuf); + if (pblob != NULL) { + *pblob = state->ret_blob; } - - return True; + if (pinbuf != NULL) { + *pinbuf = inbuf; + } + /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */ + return state->status; } +#ifdef HAVE_KRB5 + /**************************************************************************** Use in-memory credentials cache ****************************************************************************/ @@ -783,187 +828,367 @@ static void use_in_memory_ccache(void) { Do a spnego/kerberos encrypted session setup. ****************************************************************************/ -static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup) -{ +struct cli_session_setup_kerberos_state { + struct cli_state *cli; DATA_BLOB negTokenTarg; DATA_BLOB session_key_krb5; - NTSTATUS nt_status; - int rc; + ADS_STATUS ads_status; +}; - cli_temp_set_signing(cli); +static void cli_session_setup_kerberos_done(struct tevent_req *subreq); + +static struct tevent_req *cli_session_setup_kerberos_send( + TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, + const char *principal, const char *workgroup) +{ + struct tevent_req *req, *subreq; + struct cli_session_setup_kerberos_state *state; + int rc; DEBUG(2,("Doing kerberos session setup\n")); - /* generate the encapsulated kerberos5 ticket */ - rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0, NULL); + req = tevent_req_create(mem_ctx, &state, + struct cli_session_setup_kerberos_state); + if (req == NULL) { + return NULL; + } + 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 :-) + */ + rc = spnego_gen_krb5_negTokenInit(state, principal, 0, &state->negTokenTarg, + &state->session_key_krb5, 0, NULL); if (rc) { - DEBUG(1, ("cli_session_setup_kerberos: spnego_gen_negTokenTarg failed: %s\n", - error_message(rc))); - return ADS_ERROR_KRB5(rc); + DEBUG(1, ("cli_session_setup_kerberos: " + "spnego_gen_krb5_negTokenInit failed: %s\n", + error_message(rc))); + state->ads_status = ADS_ERROR_KRB5(rc); + tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL); + return tevent_req_post(req, ev); } #if 0 - file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length); + file_save("negTokenTarg.dat", state->negTokenTarg.data, + state->negTokenTarg.length); #endif - if (!cli_session_setup_blob(cli, negTokenTarg)) { - nt_status = cli_nt_error(cli); - goto nt_error; + subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } + tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req); + return req; +} - if (cli_is_error(cli)) { - nt_status = cli_nt_error(cli); - if (NT_STATUS_IS_OK(nt_status)) { - nt_status = NT_STATUS_UNSUCCESSFUL; - } - goto nt_error; - } +static void cli_session_setup_kerberos_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_session_setup_kerberos_state *state = tevent_req_data( + req, struct cli_session_setup_kerberos_state); + char *inbuf = NULL; + NTSTATUS status; - cli_set_session_key(cli, session_key_krb5); + status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; + } - if (cli_simple_set_signing( - cli, session_key_krb5, data_blob_null)) { + cli_set_session_key(state->cli, state->session_key_krb5); - if (!cli_check_sign_mac(cli, cli->inbuf, 1)) { - nt_status = NT_STATUS_ACCESS_DENIED; - goto nt_error; - } + 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; } + TALLOC_FREE(subreq); + tevent_req_done(req); +} - data_blob_free(&negTokenTarg); - data_blob_free(&session_key_krb5); +static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req) +{ + struct cli_session_setup_kerberos_state *state = tevent_req_data( + req, struct cli_session_setup_kerberos_state); + NTSTATUS status; - return ADS_ERROR_NT(NT_STATUS_OK); + if (tevent_req_is_nterror(req, &status)) { + return ADS_ERROR_NT(status); + } + return state->ads_status; +} -nt_error: - data_blob_free(&negTokenTarg); - data_blob_free(&session_key_krb5); - cli->vuid = 0; - return ADS_ERROR_NT(nt_status); +static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, + const char *principal, + const char *workgroup) +{ + struct tevent_context *ev; + struct tevent_req *req; + ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + + if (cli_has_async_calls(cli)) { + return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } + ev = tevent_context_init(talloc_tos()); + if (ev == NULL) { + goto fail; + } + req = cli_session_setup_kerberos_send(ev, ev, cli, principal, + workgroup); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll(req, ev)) { + status = ADS_ERROR_SYSTEM(errno); + goto fail; + } + status = cli_session_setup_kerberos_recv(req); +fail: + TALLOC_FREE(ev); + return status; } #endif /* HAVE_KRB5 */ - /**************************************************************************** Do a spnego/NTLMSSP encrypted session setup. ****************************************************************************/ -static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, - const char *pass, const char *domain) -{ +struct cli_session_setup_ntlmssp_state { + struct tevent_context *ev; + struct cli_state *cli; struct ntlmssp_state *ntlmssp_state; - NTSTATUS nt_status; - int turn = 1; - DATA_BLOB msg1; - DATA_BLOB blob = data_blob_null; - DATA_BLOB blob_in = data_blob_null; - DATA_BLOB blob_out = data_blob_null; + int turn; + DATA_BLOB blob_out; +}; - cli_temp_set_signing(cli); +static int cli_session_setup_ntlmssp_state_destructor( + struct cli_session_setup_ntlmssp_state *state) +{ + if (state->ntlmssp_state != NULL) { + TALLOC_FREE(state->ntlmssp_state); + } + return 0; +} - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) { - return nt_status; +static void cli_session_setup_ntlmssp_done(struct tevent_req *req); + +static struct tevent_req *cli_session_setup_ntlmssp_send( + TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, + const char *user, const char *pass, const char *domain) +{ + struct tevent_req *req, *subreq; + struct cli_session_setup_ntlmssp_state *state; + NTSTATUS status; + DATA_BLOB blob_out; + const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL}; + + req = tevent_req_create(mem_ctx, &state, + struct cli_session_setup_ntlmssp_state); + if (req == NULL) { + return NULL; } - ntlmssp_want_feature(ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY); + state->ev = ev; + state->cli = cli; + state->turn = 1; - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) { - return nt_status; + state->ntlmssp_state = NULL; + talloc_set_destructor( + state, cli_session_setup_ntlmssp_state_destructor); + + cli_temp_set_signing(cli); + + status = ntlmssp_client_start(state, + global_myname(), + lp_workgroup(), + lp_client_ntlmv2_auth(), + &state->ntlmssp_state); + if (!NT_STATUS_IS_OK(status)) { + goto fail; } - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) { - return nt_status; + ntlmssp_want_feature(state->ntlmssp_state, + NTLMSSP_FEATURE_SESSION_KEY); + if (cli->use_ccache) { + ntlmssp_want_feature(state->ntlmssp_state, + NTLMSSP_FEATURE_CCACHE); } - if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) { - return nt_status; + status = ntlmssp_set_username(state->ntlmssp_state, user); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + status = ntlmssp_set_domain(state->ntlmssp_state, domain); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + status = ntlmssp_set_password(state->ntlmssp_state, pass); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + status = ntlmssp_update(state->ntlmssp_state, data_blob_null, + &blob_out); + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + goto fail; } - do { - nt_status = ntlmssp_update(ntlmssp_state, - blob_in, &blob_out); - data_blob_free(&blob_in); - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) { - 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 */ - if (!cli_session_setup_blob_send(cli, msg1)) { - DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n")); - nt_status = NT_STATUS_UNSUCCESSFUL; - } else { - blob = cli_session_setup_blob_receive(cli); - - nt_status = cli_nt_error(cli); - if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) { - if (cli->smb_rw_error == SMB_READ_BAD_SIG) { - nt_status = NT_STATUS_ACCESS_DENIED; - } else { - nt_status = NT_STATUS_UNSUCCESSFUL; - } - } - } - data_blob_free(&msg1); - } + state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL); + data_blob_free(&blob_out); - 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; - /* 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 { - if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP, - &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)); + subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req); + return req; +fail: + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); +} - data_blob_free(&blob_in); +static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_session_setup_ntlmssp_state *state = tevent_req_data( + req, struct cli_session_setup_ntlmssp_state); + DATA_BLOB blob_in, msg_in, blob_out; + char *inbuf = NULL; + bool parse_ret; + NTSTATUS status; - if (NT_STATUS_IS_OK(nt_status)) { + status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in, + &inbuf); + TALLOC_FREE(subreq); + data_blob_free(&state->blob_out); - if (cli->server_domain[0] == '\0') { - fstrcpy(cli->server_domain, ntlmssp_state->server_domain); + if (NT_STATUS_IS_OK(status)) { + if (state->cli->server_domain[0] == '\0') { + fstrcpy(state->cli->server_domain, + state->ntlmssp_state->server.netbios_domain); } - cli_set_session_key(cli, ntlmssp_state->session_key); + cli_set_session_key( + state->cli, state->ntlmssp_state->session_key); if (cli_simple_set_signing( - cli, ntlmssp_state->session_key, data_blob_null)) { + 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; + } + TALLOC_FREE(subreq); + TALLOC_FREE(state->ntlmssp_state); + tevent_req_done(req); + return; + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_nterror(req, status); + return; + } - if (!cli_check_sign_mac(cli, cli->inbuf, 1)) { - nt_status = NT_STATUS_ACCESS_DENIED; - } + if (blob_in.length == 0) { + tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL); + return; + } + + if ((state->turn == 1) + && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + DATA_BLOB tmp_blob = data_blob_null; + /* the server might give us back two challenges */ + parse_ret = spnego_parse_challenge(state, blob_in, &msg_in, + &tmp_blob); + data_blob_free(&tmp_blob); + } else { + parse_ret = spnego_parse_auth_response(state, blob_in, status, + OID_NTLMSSP, &msg_in); + } + state->turn += 1; + + if (!parse_ret) { + DEBUG(3,("Failed to parse auth response\n")); + if (NT_STATUS_IS_OK(status) + || NT_STATUS_EQUAL(status, + NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_nterror( + req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; } } - /* we have a reference conter on ntlmssp_state, if we are signing - then the state will be kept by the signing engine */ + status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out); - ntlmssp_end(&ntlmssp_state); + 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; + } - if (!NT_STATUS_IS_OK(nt_status)) { - cli->vuid = 0; + state->blob_out = spnego_gen_auth(state, blob_out); + TALLOC_FREE(subreq); + if (tevent_req_nomem(state->blob_out.data, req)) { + return; + } + + subreq = cli_sesssetup_blob_send(state, state->ev, state->cli, + state->blob_out); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req); +} + +static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req) +{ + struct cli_session_setup_ntlmssp_state *state = tevent_req_data( + req, struct cli_session_setup_ntlmssp_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + state->cli->vuid = 0; + return status; + } + return NT_STATUS_OK; +} + +static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, + const char *user, + const char *pass, + const char *domain) +{ + struct tevent_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if (cli_has_async_calls(cli)) { + return NT_STATUS_INVALID_PARAMETER; + } + ev = tevent_context_init(talloc_tos()); + if (ev == NULL) { + goto fail; + } + req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain); + if (req == NULL) { + goto fail; } - return nt_status; + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + status = cli_session_setup_ntlmssp_recv(req); +fail: + TALLOC_FREE(ev); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** @@ -1004,7 +1229,8 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, * 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, * we try to best guess, then fall back to NTLM. */ - if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) { + if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &principal, NULL) || + OIDs[0] == NULL) { data_blob_free(&blob); return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); } @@ -1027,6 +1253,7 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, status = cli_set_username(cli, user); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(principal); return ADS_ERROR_NT(status); } @@ -1052,10 +1279,9 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, } } - /* If we get a bad principal, try to guess it if - we have a valid host NetBIOS name. + /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us */ - if (strequal(principal, ADS_IGNORE_PRINCIPAL)) { + if (!lp_client_use_spnego_principal() || strequal(principal, ADS_IGNORE_PRINCIPAL)) { TALLOC_FREE(principal); } @@ -1064,33 +1290,30 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, !strequal(STAR_SMBSERVER, cli->desthost)) { char *realm = NULL; - char *machine = NULL; char *host = NULL; - DEBUG(3,("cli_session_setup_spnego: got a " - "bad server principal, trying to guess ...\n")); + DEBUG(3,("cli_session_setup_spnego: using target " + "hostname not SPNEGO principal\n")); host = strchr_m(cli->desthost, '.'); - if (host) { - machine = SMB_STRNDUP(cli->desthost, - host - cli->desthost); - } else { - machine = SMB_STRDUP(cli->desthost); - } - if (machine == NULL) { - return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); - } - if (dest_realm) { realm = SMB_STRDUP(dest_realm); strupper_m(realm); } else { - realm = kerberos_get_default_realm_from_ccache(); + if (host) { + /* DNS name. */ + realm = kerberos_get_realm_from_hostname(cli->desthost); + } else { + /* NetBIOS name - use our realm. */ + realm = kerberos_get_default_realm_from_ccache(); + } } + if (realm && *realm) { - principal = talloc_asprintf(NULL, "%s$@%s", - machine, realm); + principal = talloc_asprintf(talloc_tos(), + "cifs/%s@%s", + cli->desthost, + realm); if (!principal) { - SAFE_FREE(machine); SAFE_FREE(realm); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } @@ -1098,7 +1321,6 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, "server principal=%s\n", principal ? principal : "")); } - SAFE_FREE(machine); SAFE_FREE(realm); } @@ -1251,25 +1473,88 @@ NTSTATUS cli_session_setup(struct cli_state *cli, Send a uloggoff. *****************************************************************************/ -bool cli_ulogoff(struct cli_state *cli) +struct cli_ulogoff_state { + struct cli_state *cli; + uint16_t vwv[3]; +}; + +static void cli_ulogoff_done(struct tevent_req *subreq); + +struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli) { - memset(cli->outbuf,'\0',smb_size); - cli_set_message(cli->outbuf,2,0,True); - SCVAL(cli->outbuf,smb_com,SMBulogoffX); - cli_setup_packet(cli); - SSVAL(cli->outbuf,smb_vwv0,0xFF); - SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */ + struct tevent_req *req, *subreq; + struct cli_ulogoff_state *state; - cli_send_smb(cli); - if (!cli_receive_smb(cli)) - return False; + req = tevent_req_create(mem_ctx, &state, struct cli_ulogoff_state); + if (req == NULL) { + return NULL; + } + state->cli = cli; - if (cli_is_error(cli)) { - return False; + SCVAL(state->vwv+0, 0, 0xFF); + SCVAL(state->vwv+1, 0, 0); + SSVAL(state->vwv+2, 0, 0); + + subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv, + 0, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_ulogoff_done, req); + return req; +} + +static void cli_ulogoff_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_ulogoff_state *state = tevent_req_data( + req, struct cli_ulogoff_state); + NTSTATUS status; + + status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; } + state->cli->vuid = -1; + tevent_req_done(req); +} - cli->vuid = -1; - return True; +NTSTATUS cli_ulogoff_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +NTSTATUS cli_ulogoff(struct cli_state *cli) +{ + struct tevent_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if (cli_has_async_calls(cli)) { + return NT_STATUS_INVALID_PARAMETER; + } + ev = tevent_context_init(talloc_tos()); + if (ev == NULL) { + goto fail; + } + req = cli_ulogoff_send(ev, ev, cli); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + status = cli_ulogoff_recv(req); +fail: + TALLOC_FREE(ev); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** @@ -1298,6 +1583,8 @@ struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx, char *tmp = NULL; uint8_t *bytes; + *psmbreq = NULL; + req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state); if (req == NULL) { return NULL; @@ -1433,6 +1720,9 @@ struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx, if (req == NULL) { return NULL; } + if (subreq == NULL) { + return req; + } status = cli_smb_req_send(subreq); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); @@ -1448,20 +1738,24 @@ static void cli_tcon_andx_done(struct tevent_req *subreq) struct cli_tcon_andx_state *state = tevent_req_data( req, struct cli_tcon_andx_state); struct cli_state *cli = state->cli; - char *inbuf = (char *)cli_smb_inbuf(subreq); + uint8_t *in; + char *inbuf; uint8_t wct; uint16_t *vwv; uint32_t num_bytes; uint8_t *bytes; NTSTATUS status; - status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes); + status = cli_smb_recv(subreq, state, &in, 0, &wct, &vwv, + &num_bytes, &bytes); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(subreq); tevent_req_nterror(req, status); return; } + inbuf = (char *)in; + clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes, STR_TERMINATE|STR_ASCII); @@ -1536,24 +1830,83 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share, Send a tree disconnect. ****************************************************************************/ -bool cli_tdis(struct cli_state *cli) +struct cli_tdis_state { + struct cli_state *cli; +}; + +static void cli_tdis_done(struct tevent_req *subreq); + +struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli) { - memset(cli->outbuf,'\0',smb_size); - cli_set_message(cli->outbuf,0,0,True); - SCVAL(cli->outbuf,smb_com,SMBtdis); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + struct tevent_req *req, *subreq; + struct cli_tdis_state *state; - cli_send_smb(cli); - if (!cli_receive_smb(cli)) - return False; + req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state); + if (req == NULL) { + return NULL; + } + state->cli = cli; - if (cli_is_error(cli)) { - return False; + subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } + tevent_req_set_callback(subreq, cli_tdis_done, req); + return req; +} - cli->cnum = -1; - return True; +static void cli_tdis_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_tdis_state *state = tevent_req_data( + req, struct cli_tdis_state); + NTSTATUS status; + + status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + state->cli->cnum = -1; + tevent_req_done(req); +} + +NTSTATUS cli_tdis_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +NTSTATUS cli_tdis(struct cli_state *cli) +{ + struct tevent_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + if (cli_has_async_calls(cli)) { + return NT_STATUS_INVALID_PARAMETER; + } + ev = tevent_context_init(talloc_tos()); + if (ev == NULL) { + goto fail; + } + req = cli_tdis_send(ev, ev, cli); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + status = cli_tdis_recv(req); +fail: + TALLOC_FREE(ev); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** @@ -1667,10 +2020,13 @@ static void cli_negprot_done(struct tevent_req *subreq) uint8_t *bytes; NTSTATUS status; uint16_t protnum; + uint8_t *inbuf; - status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes); + status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv, + &num_bytes, &bytes); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(subreq); + tevent_req_nterror(req, status); return; } @@ -1756,6 +2112,11 @@ static void cli_negprot_done(struct tevent_req *subreq) SAFE_FREE(cli->inbuf); cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN); cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN); + if (!cli->outbuf || !cli->inbuf) { + tevent_req_nterror(req, + NT_STATUS_NO_MEMORY); + return; + } cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE; } @@ -1768,8 +2129,8 @@ static void cli_negprot_done(struct tevent_req *subreq) cli->serverzone = SVALS(vwv + 10, 0); cli->serverzone *= 60; /* this time is converted to GMT by make_unix_date */ - cli->servertime = cli_make_unix_date( - cli, (char *)(vwv + 8)); + 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); @@ -1844,6 +2205,7 @@ bool cli_session_request(struct cli_state *cli, { char *p; int len = 4; + int namelen = 0; char *tmp; /* 445 doesn't have session request */ @@ -1862,8 +2224,11 @@ bool cli_session_request(struct cli_state *cli, } p = cli->outbuf+len; - memcpy(p, tmp, name_len(tmp)); - len += name_len(tmp); + namelen = name_len((unsigned char *)tmp, talloc_get_size(tmp)); + if (namelen > 0) { + memcpy(p, tmp, namelen); + len += namelen; + } TALLOC_FREE(tmp); /* and my name */ @@ -1875,8 +2240,11 @@ bool cli_session_request(struct cli_state *cli, } p = cli->outbuf+len; - memcpy(p, tmp, name_len(tmp)); - len += name_len(tmp); + namelen = name_len((unsigned char *)tmp, talloc_get_size(tmp)); + if (namelen > 0) { + memcpy(p, tmp, namelen); + len += namelen; + } TALLOC_FREE(tmp); /* send a session request (RFC 1002) */ @@ -2209,6 +2577,9 @@ again: cli->use_kerberos) { cli->fallback_after_kerberos = true; } + if (flags & CLI_FULL_CONNECTION_USE_CCACHE) { + cli->use_ccache = true; + } nt_status = cli_negprot(cli); if (!NT_STATUS_IS_OK(nt_status)) {