*/
#include "includes.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "../libcli/auth/spnego.h"
+#include "smb_krb5.h"
+#include "ntlmssp.h"
static const struct {
int prot;
- const char *name;
-} prots[] = {
- {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"},
- {-1,NULL}
+ 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"},
};
-static const char *star_smbserver_name = "*SMBSERVER";
+#define STAR_SMBSERVER "*SMBSERVER"
/**
* Set the user session key for a connection
{
DATA_BLOB session_key = data_blob_null;
DATA_BLOB lm_response = data_blob_null;
+ NTSTATUS status;
fstring pword;
char *p;
/* use the returned vuid from now on */
cli->vuid = SVAL(cli->inbuf,smb_uid);
- fstrcpy(cli->user_name, user);
+ status = cli_set_username(cli, user);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
if (session_key.data) {
/* Have plaintext orginal */
Do a NT1 guest session setup.
****************************************************************************/
-static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
+struct cli_session_setup_guest_state {
+ struct cli_state *cli;
+ uint16_t vwv[16];
+ struct iovec bytes;
+};
+
+static void cli_session_setup_guest_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ struct tevent_req **psmbreq)
{
- char *p;
- uint32 capabilities = cli_session_setup_capabilities(cli);
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_guest_state *state;
+ uint16_t *vwv;
+ uint8_t *bytes;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_guest_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ vwv = state->vwv;
+
+ SCVAL(vwv+0, 0, 0xFF);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
+ SSVAL(vwv+3, 0, 2);
+ SSVAL(vwv+4, 0, cli->pid);
+ SIVAL(vwv+5, 0, cli->sesskey);
+ 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));
+
+ bytes = talloc_array(state, uint8_t, 0);
+
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* username */
+ NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* workgroup */
+ NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
+
+ if (bytes == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ state->bytes.iov_base = (void *)bytes;
+ state->bytes.iov_len = talloc_get_size(bytes);
+
+ subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
+ 1, &state->bytes);
+ if (subreq == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_guest_done, req);
+ *psmbreq = subreq;
+ return req;
+}
- 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);
- SSVAL(cli->outbuf,smb_vwv4,cli->pid);
- SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
- SSVAL(cli->outbuf,smb_vwv7,0);
- SSVAL(cli->outbuf,smb_vwv8,0);
- SIVAL(cli->outbuf,smb_vwv11,capabilities);
- p = smb_buf(cli->outbuf);
- p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
- p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
+struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli)
+{
+ struct tevent_req *req, *subreq;
+ NTSTATUS status;
- 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);
+ req = cli_session_setup_guest_create(mem_ctx, ev, cli, &subreq);
+ if (req == NULL) {
+ return NULL;
}
- cli->vuid = SVAL(cli->inbuf,smb_uid);
+ status = cli_smb_req_send(subreq);
+ if (NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
- p = smb_buf(cli->inbuf);
- p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+static void cli_session_setup_guest_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_guest_state *state = tevent_req_data(
+ req, struct cli_session_setup_guest_state);
+ struct cli_state *cli = state->cli;
+ uint32_t num_bytes;
+ char *inbuf;
+ uint8_t *bytes;
+ uint8_t *p;
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, 0, NULL, NULL, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ inbuf = (char *)cli_smb_inbuf(subreq);
+ p = bytes;
+
+ cli->vuid = SVAL(inbuf, smb_uid);
+
+ p += clistr_pull(inbuf, cli->server_os, (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
+ p += clistr_pull(inbuf, cli->server_type, (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
+ p += clistr_pull(inbuf, cli->server_domain, (char *)p, sizeof(fstring),
+ bytes+num_bytes-p, STR_TERMINATE);
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
}
- fstrcpy(cli->user_name, "");
+ TALLOC_FREE(subreq);
- return NT_STATUS_OK;
+ status = cli_set_username(cli, "");
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
+{
+ 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_session_setup_guest_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_session_setup_guest_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
{
uint32 capabilities = cli_session_setup_capabilities(cli);
char *p;
+ NTSTATUS status;
fstring lanman;
- fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
+ fstr_sprintf( lanman, "Samba %s", samba_version_string());
memset(cli->outbuf, '\0', smb_size);
cli_set_message(cli->outbuf,13,0,True);
cli->vuid = SVAL(cli->inbuf,smb_uid);
p = smb_buf(cli->inbuf);
- p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
- fstrcpy(cli->user_name, user);
-
+ p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
+ -1, STR_TERMINATE);
+ p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
+ -1, STR_TERMINATE);
+ p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
+ -1, STR_TERMINATE);
+ status = cli_set_username(cli, user);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
}
DATA_BLOB session_key = data_blob_null;
NTSTATUS result;
char *p;
+ bool ok;
if (passlen == 0) {
/* do nothing - guest login */
the server's domain at this point. The 'server name' is also
dodgy...
*/
- names_blob = NTLMv2_generate_names_blob(cli->called.name, workgroup);
+ names_blob = NTLMv2_generate_names_blob(NULL, cli->called.name, workgroup);
- if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal,
+ if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass, &server_chal,
&names_blob,
- &lm_response, &nt_response, &session_key)) {
+ &lm_response, &nt_response, NULL, &session_key)) {
data_blob_free(&names_blob);
data_blob_free(&server_chal);
return NT_STATUS_ACCESS_DENIED;
E_deshash(pass, session_key.data);
memset(&session_key.data[8], '\0', 8);
#else
- SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+ SMBsesskeygen_ntv1(nt_hash, session_key.data);
#endif
}
-#ifdef LANMAN_ONLY
- cli_simple_set_signing(cli, session_key, lm_response);
-#else
- cli_simple_set_signing(cli, session_key, nt_response);
-#endif
+ cli_temp_set_signing(cli);
} else {
/* pre-encrypted password supplied. Only used for
security=server, can't do
goto end;
}
+#ifdef LANMAN_ONLY
+ ok = cli_simple_set_signing(cli, session_key, lm_response);
+#else
+ ok = cli_simple_set_signing(cli, session_key, nt_response);
+#endif
+ if (ok) {
+ if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
+ result = NT_STATUS_ACCESS_DENIED;
+ goto end;
+ }
+ }
+
/* use the returned vuid from now on */
cli->vuid = SVAL(cli->inbuf,smb_uid);
p = smb_buf(cli->inbuf);
- p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
- p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
+ -1, STR_TERMINATE);
+ p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
+ -1, STR_TERMINATE);
+ p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
+ -1, STR_TERMINATE);
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
}
- fstrcpy(cli->user_name, user);
+ result = cli_set_username(cli, user);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto end;
+ }
if (session_key.data) {
/* Have plaintext orginal */
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);
NT_STATUS_MORE_PROCESSING_REQUIRED)) {
return blob2;
}
-
+
/* use the returned vuid from now on */
cli->vuid = SVAL(cli->inbuf,smb_uid);
-
+
p = smb_buf(cli->inbuf);
blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
p += blob2.length;
- p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
+ -1, STR_TERMINATE);
/* w2k with kerberos doesn't properly null terminate this field */
- len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
- p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
-
+ len = smb_bufrem(cli->inbuf, p);
+ if (p + len < cli->inbuf + cli->bufsize+SAFETY_MARGIN - 2) {
+ char *end_of_buf = p + len;
+
+ SSVAL(p, len, 0);
+ /* Now it's null terminated. */
+ p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
+ -1, STR_TERMINATE);
+ /*
+ * See if there's another string. If so it's the
+ * server domain (part of the 'standard' Samba
+ * server signature).
+ */
+ if (p < end_of_buf) {
+ p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
+ -1, STR_TERMINATE);
+ }
+ } 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);
+ }
return blob2;
}
#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
-static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob, DATA_BLOB session_key_krb5)
+static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
{
int32 remaining = blob.length;
int32 cur = 0;
send_blob.length = max_blob_size;
remaining -= max_blob_size;
} else {
- DATA_BLOB null_blob = data_blob_null;
-
send_blob.length = remaining;
remaining = 0;
-
- /* This is the last packet in the sequence - turn signing on. */
- cli_simple_set_signing(cli, session_key_krb5, null_blob);
}
send_blob.data = &blob.data[cur];
{
DATA_BLOB negTokenTarg;
DATA_BLOB session_key_krb5;
+ NTSTATUS nt_status;
int rc;
+ cli_temp_set_signing(cli);
+
DEBUG(2,("Doing kerberos session setup\n"));
/* generate the encapsulated kerberos5 ticket */
file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
#endif
- if (!cli_session_setup_blob(cli, negTokenTarg, session_key_krb5)) {
- data_blob_free(&negTokenTarg);
- data_blob_free(&session_key_krb5);
- return ADS_ERROR_NT(cli_nt_error(cli));
+ if (!cli_session_setup_blob(cli, negTokenTarg)) {
+ nt_status = cli_nt_error(cli);
+ goto nt_error;
+ }
+
+ 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;
}
cli_set_session_key(cli, session_key_krb5);
+ if (cli_simple_set_signing(
+ cli, session_key_krb5, data_blob_null)) {
+
+ if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
+ nt_status = NT_STATUS_ACCESS_DENIED;
+ goto nt_error;
+ }
+ }
+
data_blob_free(&negTokenTarg);
data_blob_free(&session_key_krb5);
- if (cli_is_error(cli)) {
- if (NT_STATUS_IS_OK(cli_nt_error(cli))) {
- return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
- }
- }
- return ADS_ERROR_NT(cli_nt_error(cli));
+ return ADS_ERROR_NT(NT_STATUS_OK);
+
+nt_error:
+ data_blob_free(&negTokenTarg);
+ data_blob_free(&session_key_krb5);
+ cli->vuid = 0;
+ return ADS_ERROR_NT(nt_status);
}
#endif /* HAVE_KRB5 */
/* 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) {
}
data_blob_free(&msg1);
}
-
+
if (!blob.length) {
if (NT_STATUS_IS_OK(nt_status)) {
nt_status = NT_STATUS_UNSUCCESSFUL;
if (NT_STATUS_IS_OK(nt_status)) {
- DATA_BLOB key = data_blob(ntlmssp_state->session_key.data,
- ntlmssp_state->session_key.length);
- DATA_BLOB null_blob = data_blob_null;
- bool res;
-
- fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
+ if (cli->server_domain[0] == '\0') {
+ fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
+ }
cli_set_session_key(cli, ntlmssp_state->session_key);
- res = cli_simple_set_signing(cli, key, null_blob);
+ if (cli_simple_set_signing(
+ cli, ntlmssp_state->session_key, data_blob_null)) {
- data_blob_free(&key);
-
- if (res) {
-
- /* 'resign' the last message, so we get the right sequence numbers
- for checking the first reply from the server */
- cli_calculate_sign_mac(cli, cli->outbuf);
-
- if (!cli_check_sign_mac(cli, cli->inbuf)) {
+ if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
nt_status = NT_STATUS_ACCESS_DENIED;
}
}
/****************************************************************************
Do a spnego encrypted session setup.
+
+ user_domain: The shortname of the domain the user/machine is a member of.
+ dest_realm: The realm we're connecting to, if NULL we use our default realm.
****************************************************************************/
ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
- const char *pass, const char *domain)
+ const char *pass, const char *user_domain,
+ const char * dest_realm)
{
- char *principal;
+ char *principal = NULL;
char *OIDs[ASN1_MAX_OIDS];
int i;
- bool got_kerberos_mechanism = False;
DATA_BLOB blob;
+ const char *p = NULL;
+ char *account = NULL;
+ NTSTATUS status;
DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
/* 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 */
+ /* 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,
+ * we try to best guess, then fall back to NTLM. */
if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
data_blob_free(&blob);
return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
/* make sure the server understands kerberos */
for (i=0;OIDs[i];i++) {
- DEBUG(3,("got OID=%s\n", OIDs[i]));
+ if (i == 0)
+ DEBUG(3,("got OID=%s\n", OIDs[i]));
+ else
+ DEBUGADD(3,("got OID=%s\n", OIDs[i]));
if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
strcmp(OIDs[i], OID_KERBEROS5) == 0) {
- got_kerberos_mechanism = True;
+ cli->got_kerberos_mechanism = True;
}
- free(OIDs[i]);
+ talloc_free(OIDs[i]);
}
DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
- if (got_kerberos_mechanism && (principal == NULL)) {
- /*
- * It is WRONG to depend on the principal sent in the negprot
- * reply, but right now we do it. So for safety (don't
- * segfault later) disable Kerberos when no principal was
- * sent. -- VL
- */
- DEBUG(1, ("Kerberos mech was offered, but no principal was "
- "sent, disabling Kerberos\n"));
- cli->use_kerberos = False;
+ status = cli_set_username(cli, user);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ADS_ERROR_NT(status);
}
- fstrcpy(cli->user_name, user);
-
#ifdef HAVE_KRB5
/* If password is set we reauthenticate to kerberos server
* and do not store results */
- if (got_kerberos_mechanism && cli->use_kerberos) {
+ if (cli->got_kerberos_mechanism && cli->use_kerberos) {
ADS_STATUS rc;
if (pass && *pass) {
int ret;
-
+
use_in_memory_ccache();
ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
-
+
if (ret){
- SAFE_FREE(principal);
+ TALLOC_FREE(principal);
DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
if (cli->fallback_after_kerberos)
goto ntlmssp;
return ADS_ERROR_KRB5(ret);
}
}
-
+
/* If we get a bad principal, try to guess it if
we have a valid host NetBIOS name.
*/
if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
- SAFE_FREE(principal);
+ TALLOC_FREE(principal);
}
if (principal == NULL &&
!is_ipaddress(cli->desthost) &&
- !strequal(star_smbserver_name,
+ !strequal(STAR_SMBSERVER,
cli->desthost)) {
char *realm = NULL;
char *machine = NULL;
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
- realm = kerberos_get_default_realm_from_ccache();
+ if (dest_realm) {
+ realm = SMB_STRDUP(dest_realm);
+ strupper_m(realm);
+ } else {
+ realm = kerberos_get_default_realm_from_ccache();
+ }
if (realm && *realm) {
- if (asprintf(&principal, "%s$@%s",
- machine, realm) < 0) {
+ principal = talloc_asprintf(NULL, "%s$@%s",
+ machine, realm);
+ if (!principal) {
SAFE_FREE(machine);
SAFE_FREE(realm);
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
if (principal) {
- rc = cli_session_setup_kerberos(cli, principal, domain);
+ rc = cli_session_setup_kerberos(cli, principal,
+ dest_realm);
if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
- SAFE_FREE(principal);
+ TALLOC_FREE(principal);
return rc;
}
}
}
#endif
- SAFE_FREE(principal);
+ TALLOC_FREE(principal);
ntlmssp:
- return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, user, pass, domain));
+ account = talloc_strdup(talloc_tos(), user);
+ if (!account) {
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ /* when falling back to ntlmssp while authenticating with a machine
+ * account strip off the realm - gd */
+
+ if ((p = strchr_m(user, '@')) != NULL) {
+ account[PTR_DIFF(p,user)] = '\0';
+ }
+
+ return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
}
/****************************************************************************
/* if the server supports extended security then use SPNEGO */
if (cli->capabilities & CAP_EXTENDED_SECURITY) {
- ADS_STATUS status = cli_session_setup_spnego(cli, user, pass, workgroup);
+ ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
+ workgroup, NULL);
if (!ADS_ERR_OK(status)) {
DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
return ads_ntstatus(status);
return False;
}
- cli->cnum = -1;
+ cli->vuid = -1;
return True;
}
Send a tconX.
****************************************************************************/
-bool cli_send_tconX(struct cli_state *cli,
- const char *share, const char *dev, const char *pass, int passlen)
+struct cli_tcon_andx_state {
+ struct cli_state *cli;
+ uint16_t vwv[4];
+ struct iovec bytes;
+};
+
+static void cli_tcon_andx_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *share, const char *dev,
+ const char *pass, int passlen,
+ struct tevent_req **psmbreq)
{
- fstring fullshare, pword;
- char *p;
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+ struct tevent_req *req, *subreq;
+ struct cli_tcon_andx_state *state;
+ fstring pword;
+ uint16_t *vwv;
+ char *tmp = NULL;
+ uint8_t *bytes;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ vwv = state->vwv;
fstrcpy(cli->share, share);
if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
passlen = 1;
pass = "";
- } else if (!pass) {
- DEBUG(1, ("Server not using user level security and no password supplied.\n"));
- return False;
+ } else if (pass == NULL) {
+ DEBUG(1, ("Server not using user level security and no "
+ "password supplied.\n"));
+ goto access_denied;
}
if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
DEBUG(1, ("Server requested LANMAN password "
"(share-level security) but "
"'client lanman auth' is disabled\n"));
- return False;
+ goto access_denied;
}
/*
- * Non-encrypted passwords - convert to DOS codepage before encryption.
+ * Non-encrypted passwords - convert to DOS codepage before
+ * encryption.
*/
passlen = 24;
- SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
+ SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
} else {
- if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
+ if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
+ |NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
+ == 0) {
if (!lp_client_plaintext_auth() && (*pass)) {
DEBUG(1, ("Server requested plaintext "
"password but 'client plaintext "
"auth' is disabled\n"));
- return False;
+ goto access_denied;
}
/*
- * Non-encrypted passwords - convert to DOS codepage before using.
+ * Non-encrypted passwords - convert to DOS codepage
+ * before using.
*/
- passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
-
+ passlen = clistr_push(cli, pword, pass, sizeof(pword),
+ STR_TERMINATE);
+ if (passlen == -1) {
+ DEBUG(1, ("clistr_push(pword) failed\n"));
+ goto access_denied;
+ }
} else {
if (passlen) {
memcpy(pword, pass, passlen);
}
}
- slprintf(fullshare, sizeof(fullshare)-1,
- "\\\\%s\\%s", cli->desthost, share);
+ SCVAL(vwv+0, 0, 0xFF);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
+ SSVAL(vwv+3, 0, passlen);
- cli_set_message(cli->outbuf,4, 0, True);
- SCVAL(cli->outbuf,smb_com,SMBtconX);
- cli_setup_packet(cli);
+ if (passlen) {
+ bytes = (uint8_t *)talloc_memdup(state, pword, passlen);
+ } else {
+ bytes = talloc_array(state, uint8_t, 0);
+ }
- SSVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,TCONX_FLAG_EXTENDED_RESPONSE);
- SSVAL(cli->outbuf,smb_vwv3,passlen);
+ /*
+ * Add the sharename
+ */
+ tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
+ cli->desthost, share);
+ if (tmp == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+ NULL);
+ TALLOC_FREE(tmp);
- p = smb_buf(cli->outbuf);
- if (passlen) {
- memcpy(p,pword,passlen);
+ /*
+ * Add the devicetype
+ */
+ tmp = talloc_strdup_upper(talloc_tos(), dev);
+ if (tmp == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
}
- p += passlen;
- p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
- p += clistr_push(cli, p, dev, -1, STR_TERMINATE |STR_UPPER | STR_ASCII);
+ bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL);
+ TALLOC_FREE(tmp);
- cli_setup_bcc(cli, p);
+ if (bytes == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ state->bytes.iov_base = (void *)bytes;
+ state->bytes.iov_len = talloc_get_size(bytes);
- if (cli_is_error(cli))
- return False;
+ subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 4, vwv,
+ 1, &state->bytes);
+ if (subreq == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, cli_tcon_andx_done, req);
+ *psmbreq = subreq;
+ return req;
+
+ access_denied:
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
+}
- clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
+struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *share, const char *dev,
+ const char *pass, int passlen)
+{
+ struct tevent_req *req, *subreq;
+ NTSTATUS status;
- if (cli->protocol >= PROTOCOL_NT1 &&
- smb_buflen(cli->inbuf) == 3) {
+ req = cli_tcon_andx_create(mem_ctx, ev, cli, share, dev, pass, passlen,
+ &subreq);
+ if (req == NULL) {
+ return NULL;
+ }
+ status = cli_smb_req_send(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void cli_tcon_andx_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ 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 wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes,
+ STR_TERMINATE|STR_ASCII);
+
+ if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
/* almost certainly win95 - enable bug fixes */
cli->win95 = True;
}
-
- /* Make sure that we have the optional support 16-bit field. WCT > 2 */
- /* Avoids issues when connecting to Win9x boxes sharing files */
- cli->dfsroot = False;
- if ( (CVAL(cli->inbuf, smb_wct))>2 && cli->protocol >= PROTOCOL_LANMAN2 )
- cli->dfsroot = (SVAL( cli->inbuf, smb_vwv2 ) & SMB_SHARE_IN_DFS) ? True : False;
+ /*
+ * Make sure that we have the optional support 16-bit field. WCT > 2.
+ * Avoids issues when connecting to Win9x boxes sharing files
+ */
- cli->cnum = SVAL(cli->inbuf,smb_tid);
- return True;
+ cli->dfsroot = false;
+
+ if ((wct > 2) && (cli->protocol >= PROTOCOL_LANMAN2)) {
+ cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
+ }
+
+ cli->cnum = SVAL(inbuf,smb_tid);
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_tcon_andx_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
+ const char *dev, const char *pass, int passlen)
+{
+ 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_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
+ 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_tcon_andx_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
SCVAL(cli->outbuf,smb_com,SMBtdis);
SSVAL(cli->outbuf,smb_tid,cli->cnum);
cli_setup_packet(cli);
-
+
cli_send_smb(cli);
if (!cli_receive_smb(cli))
return False;
-
+
if (cli_is_error(cli)) {
return False;
}
Send a negprot command.
****************************************************************************/
-void cli_negprot_send(struct cli_state *cli)
+void cli_negprot_sendsync(struct cli_state *cli)
{
char *p;
int numprots;
cli_set_message(cli->outbuf,0,0,True);
p = smb_buf(cli->outbuf);
- for (numprots=0;
- prots[numprots].name && prots[numprots].prot<=cli->protocol;
- numprots++) {
+ for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
+ if (prots[numprots].prot > cli->protocol) {
+ break;
+ }
*p++ = 2;
p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
}
Send a negprot command.
****************************************************************************/
-bool cli_negprot(struct cli_state *cli)
+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)
{
- char *p;
+ struct tevent_req *req, *subreq;
+ struct cli_negprot_state *state;
+ uint8_t *bytes = NULL;
int numprots;
- int plength;
+ uint16_t cnum;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
if (cli->protocol < PROTOCOL_NT1)
cli->use_spnego = False;
- memset(cli->outbuf,'\0',smb_size);
-
/* setup the protocol strings */
- for (plength=0,numprots=0;
- prots[numprots].name && prots[numprots].prot<=cli->protocol;
- numprots++)
- plength += strlen(prots[numprots].name)+2;
-
- cli_set_message(cli->outbuf,0,plength,True);
-
- p = smb_buf(cli->outbuf);
- for (numprots=0;
- prots[numprots].name && prots[numprots].prot<=cli->protocol;
- numprots++) {
- *p++ = 2;
- p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
+ for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
+ uint8_t c = 2;
+ if (prots[numprots].prot > cli->protocol) {
+ 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);
+ }
}
- SCVAL(cli->outbuf,smb_com,SMBnegprot);
- cli_setup_packet(cli);
+ cnum = cli->cnum;
- SCVAL(smb_buf(cli->outbuf),0,2);
+ cli->cnum = 0;
+ subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL,
+ talloc_get_size(bytes), bytes);
+ cli->cnum = cnum;
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_negprot_done, req);
+ return req;
+}
- show_msg(cli->inbuf);
+static void cli_negprot_done(struct tevent_req *subreq)
+{
+ 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;
- if (cli_is_error(cli) ||
- ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
- return(False);
+ status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
}
- cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
+ protnum = SVAL(vwv, 0);
- if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
+ if ((protnum >= ARRAY_SIZE(prots))
+ || (prots[protnum].prot > cli->protocol)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ cli->protocol = prots[protnum].prot;
+
+ if ((cli->protocol < 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"));
- return False;
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
}
if (cli->protocol >= PROTOCOL_NT1) {
struct timespec ts;
+ bool negotiated_smb_signing = false;
+
/* NT protocol */
- cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
- cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
- cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
- cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
- cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
+ 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(cli->inbuf+smb_vwv11+1);
+ ts = interpret_long_date(((char *)(vwv+11))+1);
cli->servertime = ts.tv_sec;
- cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
- cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
+ cli->secblob = data_blob(bytes, num_bytes);
+ cli->capabilities = IVAL(vwv + 9, 1);
if (cli->capabilities & CAP_RAW_MODE) {
cli->readbraw_supported = True;
cli->writebraw_supported = True;
/* work out if they sent us a workgroup */
if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
smb_buflen(cli->inbuf) > 8) {
- clistr_pull(cli, cli->server_domain,
- smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
- smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
+ clistr_pull(cli->inbuf, cli->server_domain,
+ bytes+8, sizeof(cli->server_domain),
+ num_bytes-8,
+ STR_UNICODE|STR_NOALIGN);
}
/*
if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
/* Fail if server says signing is mandatory and we don't want to support it. */
- if (!cli->sign_info.allow_smb_signing) {
+ if (!client_is_signing_allowed(cli)) {
DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
- return False;
+ tevent_req_nterror(req,
+ NT_STATUS_ACCESS_DENIED);
+ return;
}
- cli->sign_info.negotiated_smb_signing = True;
- cli->sign_info.mandatory_signing = True;
- } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
+ 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"));
- return False;
+ tevent_req_nterror(req,
+ NT_STATUS_ACCESS_DENIED);
+ return;
}
- cli->sign_info.negotiated_smb_signing = True;
- cli->sign_info.mandatory_signing = True;
+ negotiated_smb_signing = true;
} else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
- cli->sign_info.negotiated_smb_signing = True;
+ negotiated_smb_signing = true;
+ }
+
+ if (negotiated_smb_signing) {
+ cli_set_signing_negotiated(cli);
}
if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
SAFE_FREE(cli->outbuf);
SAFE_FREE(cli->inbuf);
- cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
- cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
- cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE;
+ 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);
+ cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
}
} else if (cli->protocol >= PROTOCOL_LANMAN1) {
cli->use_spnego = False;
- cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
- cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
- cli->max_mux = SVAL(cli->inbuf, smb_vwv3);
- cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
- cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
+ 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 = cli_make_unix_date(cli,cli->inbuf+smb_vwv8);
- cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
- cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
- cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
+ cli->servertime = cli_make_unix_date(
+ cli, (char *)(vwv + 8));
+ 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;
if (getenv("CLI_FORCE_ASCII"))
cli->capabilities &= ~CAP_UNICODE;
- return True;
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_negprot_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_negprot(struct cli_state *cli)
+{
+ 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);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
{
char *p;
int len = 4;
+ char *tmp;
+
+ /* 445 doesn't have session request */
+ if (cli->port == 445)
+ return True;
memcpy(&(cli->calling), calling, sizeof(*calling));
memcpy(&(cli->called ), called , sizeof(*called ));
-
+
/* put in the destination name */
+
+ tmp = name_mangle(talloc_tos(), cli->called.name,
+ cli->called.name_type);
+ if (tmp == NULL) {
+ return false;
+ }
+
p = cli->outbuf+len;
- name_mangle(cli->called .name, p, cli->called .name_type);
- len += name_len(p);
+ memcpy(p, tmp, name_len(tmp));
+ len += name_len(tmp);
+ TALLOC_FREE(tmp);
/* and my name */
- p = cli->outbuf+len;
- name_mangle(cli->calling.name, p, cli->calling.name_type);
- len += name_len(p);
- /* 445 doesn't have session request */
- if (cli->port == 445)
- return True;
+ tmp = name_mangle(talloc_tos(), cli->calling.name,
+ cli->calling.name_type);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ p = cli->outbuf+len;
+ memcpy(p, tmp, name_len(tmp));
+ len += name_len(tmp);
+ TALLOC_FREE(tmp);
/* send a session request (RFC 1002) */
/* setup the packet length
*/
uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
struct in_addr dest_ip;
+ NTSTATUS status;
/* SESSION RETARGET */
putip((char *)&dest_ip,cli->inbuf+4);
in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
- cli->fd = open_socket_out(SOCK_STREAM,
- &cli->dest_ss,
- port,
- LONG_CONNECT_TIMEOUT);
- if (cli->fd == -1)
+ status = open_socket_out(&cli->dest_ss, port,
+ LONG_CONNECT_TIMEOUT, &cli->fd);
+ if (!NT_STATUS_IS_OK(status)) {
return False;
+ }
DEBUG(3,("Retargeted\n"));
return(True);
}
+struct fd_struct {
+ int fd;
+};
+
+static void smb_sock_connected(struct tevent_req *req)
+{
+ struct fd_struct *pfd = tevent_req_callback_data(
+ req, struct fd_struct);
+ int fd;
+ NTSTATUS status;
+
+ status = open_socket_out_defer_recv(req, &fd);
+ if (NT_STATUS_IS_OK(status)) {
+ pfd->fd = fd;
+ }
+}
+
+static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
+ uint16_t *port, int timeout, int *pfd)
+{
+ struct event_context *ev;
+ struct tevent_req *r139, *r445;
+ struct fd_struct *fd139, *fd445;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (*port != 0) {
+ return open_socket_out(pss, *port, timeout, pfd);
+ }
+
+ ev = event_context_init(talloc_tos());
+ if (ev == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fd139 = talloc(ev, struct fd_struct);
+ if (fd139 == NULL) {
+ goto done;
+ }
+ fd139->fd = -1;
+
+ fd445 = talloc(ev, struct fd_struct);
+ if (fd445 == NULL) {
+ goto done;
+ }
+ fd445->fd = -1;
+
+ r445 = open_socket_out_defer_send(ev, ev, timeval_set(0, 0),
+ pss, 445, timeout);
+ r139 = open_socket_out_defer_send(ev, ev, timeval_set(0, 3000),
+ pss, 139, timeout);
+ if ((r445 == NULL) || (r139 == NULL)) {
+ goto done;
+ }
+ tevent_req_set_callback(r445, smb_sock_connected, fd445);
+ tevent_req_set_callback(r139, smb_sock_connected, fd139);
+
+ while ((fd445->fd == -1) && (fd139->fd == -1)
+ && (tevent_req_is_in_progress(r139)
+ || tevent_req_is_in_progress(r445))) {
+ event_loop_once(ev);
+ }
+
+ if ((fd139->fd != -1) && (fd445->fd != -1)) {
+ close(fd139->fd);
+ fd139->fd = -1;
+ }
+
+ if (fd445->fd != -1) {
+ *port = 445;
+ *pfd = fd445->fd;
+ status = NT_STATUS_OK;
+ goto done;
+ }
+ if (fd139->fd != -1) {
+ *port = 139;
+ *pfd = fd139->fd;
+ status = NT_STATUS_OK;
+ goto done;
+ }
+
+ status = open_socket_out_defer_recv(r445, &fd445->fd);
+ done:
+ TALLOC_FREE(ev);
+ return status;
+}
+
/****************************************************************************
Open the client sockets.
****************************************************************************/
/* reasonable default hostname */
if (!host) {
- host = star_smbserver_name;
+ host = STAR_SMBSERVER;
}
fstrcpy(cli->desthost, host);
*p = 0;
}
- if (!dest_ss || is_zero_addr(dest_ss)) {
+ if (!dest_ss || is_zero_addr((struct sockaddr *)dest_ss)) {
NTSTATUS status =resolve_name_list(frame,
cli->desthost,
name_type,
if (getenv("LIBSMB_PROG")) {
cli->fd = sock_exec(getenv("LIBSMB_PROG"));
} else {
- /* try 445 first, then 139 */
- uint16_t port = cli->port?cli->port:445;
- cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ss,
- port, cli->timeout);
- if (cli->fd == -1 && cli->port == 0) {
- port = 139;
- cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ss,
- port, cli->timeout);
- }
- if (cli->fd != -1) {
+ uint16_t port = cli->port;
+ NTSTATUS status;
+ status = open_smb_socket(&cli->dest_ss, &port,
+ cli->timeout, &cli->fd);
+ if (NT_STATUS_IS_OK(status)) {
cli->port = port;
}
}
if (!my_name)
my_name = global_myname();
-
- if (!(cli = cli_initialise())) {
+
+ if (!(cli = cli_initialise_ex(signing_state))) {
return NT_STATUS_NO_MEMORY;
}
-
+
make_nmb_name(&calling, my_name, 0x0);
make_nmb_name(&called , dest_host, 0x20);
- if (cli_set_port(cli, port) != port) {
- cli_shutdown(cli);
- return NT_STATUS_UNSUCCESSFUL;
- }
-
+ cli_set_port(cli, port);
cli_set_timeout(cli, 10000); /* 10 seconds. */
if (dest_ss) {
ss = *dest_ss;
} else {
- zero_addr(&ss);
+ zero_sockaddr(&ss);
}
again:
*p = 0;
goto again;
}
- if (strcmp(called.name, star_smbserver_name)) {
- make_nmb_name(&called , star_smbserver_name, 0x20);
+ if (strcmp(called.name, STAR_SMBSERVER)) {
+ make_nmb_name(&called , STAR_SMBSERVER, 0x20);
goto again;
}
return NT_STATUS_BAD_NETWORK_NAME;
}
- cli_setup_signing_state(cli, signing_state);
-
if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
cli->use_spnego = False;
else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
cli->fallback_after_kerberos = true;
}
- if (!cli_negprot(cli)) {
- DEBUG(1,("failed negprot\n"));
- nt_status = cli_nt_error(cli);
- if (NT_STATUS_IS_OK(nt_status)) {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
+ nt_status = cli_negprot(cli);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
cli_shutdown(cli);
return nt_status;
}
return nt_status;
}
+ cli->use_oplocks = ((flags & CLI_FULL_CONNECTION_OPLOCKS) != 0);
+ cli->use_level_II_oplocks =
+ ((flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) != 0);
+
nt_status = cli_session_setup(cli, user, password, pw_len, password,
pw_len, domain);
if (!NT_STATUS_IS_OK(nt_status)) {
}
if (service) {
- if (!cli_send_tconX(cli, service, service_type, password, pw_len)) {
- nt_status = cli_nt_error(cli);
+ nt_status = cli_tcon_andx(cli, service, service_type, password,
+ pw_len);
+ if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
cli_shutdown(cli);
if (NT_STATUS_IS_OK(nt_status)) {
}
}
- cli_init_creds(cli, user, domain, password);
+ nt_status = cli_init_creds(cli, user, domain, password);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ cli_shutdown(cli);
+ return nt_status;
+ }
*output_cli = cli;
return NT_STATUS_OK;
*/
if(is_ipaddress(desthost)) {
- make_nmb_name(&called, star_smbserver_name, 0x20);
+ make_nmb_name(&called, STAR_SMBSERVER, 0x20);
} else {
make_nmb_name(&called, desthost, 0x20);
}
NTSTATUS status;
struct nmb_name smbservername;
- make_nmb_name(&smbservername, star_smbserver_name, 0x20);
+ make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
/*
* If the name wasn't *SMBSERVER then
{
struct cli_state *cli;
NTSTATUS nt_status;
+ uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
+
+ if (user_info->use_kerberos) {
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+ }
nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
user_info->username ? user_info->username : "",
lp_workgroup(),
user_info->password ? user_info->password : "",
- CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK, Undefined, NULL);
+ flags,
+ Undefined, NULL);
if (NT_STATUS_IS_OK(nt_status)) {
return cli;