client connect/disconnect routines
Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Andrew Bartlett 2001-2003
+ Copyright (C) Volker Lendecke 2011
+ Copyright (C) Jeremy Allison 2011
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
*/
#include "includes.h"
+#include "libsmb/libsmb.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 "../lib/util/tevent_ntstatus.h"
+#include "async_smb.h"
+#include "libsmb/nmblib.h"
+#include "read_smb.h"
static const struct {
int prot;
#define STAR_SMBSERVER "*SMBSERVER"
+/********************************************************
+ Utility function to ensure we always return at least
+ a valid char * pointer to an empty string for the
+ cli->server_os, cli->server_type and cli->server_domain
+ strings.
+*******************************************************/
+
+static NTSTATUS smb_bytes_talloc_string(struct cli_state *cli,
+ char *inbuf,
+ char **dest,
+ uint8_t *src,
+ size_t srclen,
+ ssize_t *destlen)
+{
+ *destlen = clistr_pull_talloc(cli,
+ inbuf,
+ SVAL(inbuf, smb_flg2),
+ dest,
+ (char *)src,
+ srclen,
+ STR_TERMINATE);
+ if (*destlen == -1) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (*dest == NULL) {
+ *dest = talloc_strdup(cli, "");
+ if (*dest == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
/**
* Set the user session key for a connection
* @param cli The cli structure to add it too
Do an old lanman2 style session setup.
****************************************************************************/
-static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
- const char *user,
- const char *pass, size_t passlen,
- const char *workgroup)
+struct cli_session_setup_lanman2_state {
+ struct cli_state *cli;
+ uint16_t vwv[10];
+ const char *user;
+};
+
+static void cli_session_setup_lanman2_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_lanman2_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *workgroup)
{
- DATA_BLOB session_key = data_blob_null;
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_lanman2_state *state;
DATA_BLOB lm_response = data_blob_null;
- NTSTATUS status;
- fstring pword;
- char *p;
+ uint16_t *vwv;
+ uint8_t *bytes;
+ char *tmp;
- if (passlen > sizeof(pword)-1) {
- return NT_STATUS_INVALID_PARAMETER;
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_lanman2_state);
+ if (req == NULL) {
+ return NULL;
}
+ state->cli = cli;
+ 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) */
+ /*
+ * 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 */
- if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
+ /*
+ * if in share level security then don't send a password now
+ */
+ if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
passlen = 0;
+ }
- if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
- /* Encrypted mode needed, and non encrypted password supplied. */
+ if (passlen > 0
+ && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)
+ && passlen != 24) {
+ /*
+ * Encrypted mode needed, and non encrypted password
+ * supplied.
+ */
lm_response = data_blob(NULL, 24);
- if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
- DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
- return NT_STATUS_ACCESS_DENIED;
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
}
- } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
- /* Encrypted mode needed, and encrypted password supplied. */
+
+ if (!SMBencrypt(pass, cli->secblob.data,
+ (uint8_t *)lm_response.data)) {
+ DEBUG(1, ("Password is > 14 chars in length, and is "
+ "therefore incompatible with Lanman "
+ "authentication\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
+ }
+ } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)
+ && passlen == 24) {
+ /*
+ * Encrypted mode needed, and encrypted password
+ * supplied.
+ */
lm_response = data_blob(pass, passlen);
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
} else if (passlen > 0) {
- /* Plaintext mode needed, assume plaintext supplied. */
- passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
+ uint8_t *buf;
+ size_t converted_size;
+ /*
+ * Plaintext mode needed, assume plaintext supplied.
+ */
+ buf = talloc_array(talloc_tos(), uint8_t, 0);
+ buf = smb_bytes_push_str(buf, cli_ucs2(cli), pass, passlen+1,
+ &converted_size);
+ if (tevent_req_nomem(buf, req)) {
+ return tevent_req_post(req, ev);
+ }
lm_response = data_blob(pass, passlen);
+ TALLOC_FREE(buf);
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ 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, 1);
+ SIVAL(vwv+5, 0, cli->sesskey);
+ SSVAL(vwv+7, 0, lm_response.length);
+
+ bytes = talloc_array(state, uint8_t, lm_response.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
}
+ if (lm_response.length != 0) {
+ memcpy(bytes, lm_response.data, lm_response.length);
+ }
+ data_blob_free(&lm_response);
- /* send a session setup command */
- memset(cli->outbuf,'\0',smb_size);
- cli_set_message(cli->outbuf,10, 0, True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
- cli_setup_packet(cli);
+ tmp = talloc_strdup_upper(talloc_tos(), user);
+ if (tevent_req_nomem(tmp, req)) {
+ return tevent_req_post(req, ev);
+ }
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+ NULL);
+ TALLOC_FREE(tmp);
- SCVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
- SSVAL(cli->outbuf,smb_vwv3,2);
- SSVAL(cli->outbuf,smb_vwv4,1);
- SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
- SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
+ tmp = talloc_strdup_upper(talloc_tos(), workgroup);
+ if (tevent_req_nomem(tmp, req)) {
+ return tevent_req_post(req, ev);
+ }
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+ 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);
- p = smb_buf(cli->outbuf);
- memcpy(p,lm_response.data,lm_response.length);
- p += lm_response.length;
- p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
- p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
- if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
- return cli_nt_error(cli);
+ subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 10, vwv,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_session_setup_lanman2_done, req);
+ return req;
+}
- show_msg(cli->inbuf);
+static void cli_session_setup_lanman2_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_lanman2_state *state = tevent_req_data(
+ req, struct cli_session_setup_lanman2_state);
+ struct cli_state *cli = state->cli;
+ uint32_t num_bytes;
+ uint8_t *in;
+ char *inbuf;
+ uint8_t *bytes;
+ uint8_t *p;
+ NTSTATUS status;
+ ssize_t ret;
+ uint8_t wct;
+ uint16_t *vwv;
- if (cli_is_error(cli)) {
- return cli_nt_error(cli);
+ status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
- /* use the returned vuid from now on */
- cli->vuid = SVAL(cli->inbuf,smb_uid);
- status = cli_set_username(cli, user);
+ inbuf = (char *)in;
+ p = bytes;
+
+ cli->vuid = SVAL(inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ tevent_req_nterror(req, status);
+ return;
}
+ p += ret;
- if (session_key.data) {
- /* Have plaintext orginal */
- cli_set_session_key(cli, session_key);
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
+ p += ret;
- return NT_STATUS_OK;
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ 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;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_session_setup_lanman2_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ 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) {
+ goto fail;
+ }
+ req = cli_session_setup_lanman2_send(frame, ev, cli, user, pass, passlen,
+ workgroup);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_session_setup_lanman2_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
}
/****************************************************************************
struct cli_session_setup_guest_state {
struct cli_state *cli;
- uint16_t vwv[16];
+ uint16_t vwv[13];
struct iovec bytes;
};
uint8_t *bytes;
uint8_t *p;
NTSTATUS status;
+ ssize_t ret;
+ uint8_t wct;
+ uint16_t *vwv;
- status = cli_smb_recv(subreq, state, &in, 0, NULL, NULL,
+ status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
&num_bytes, &bytes);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
p = bytes;
cli->vuid = SVAL(inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
- 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);
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
status = cli_session_setup_guest_recv(req);
fail:
TALLOC_FREE(frame);
- if (!NT_STATUS_IS_OK(status)) {
- cli_set_error(cli, status);
- }
return status;
}
Do a NT1 plaintext session setup.
****************************************************************************/
-static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
- const char *user, const char *pass,
- const char *workgroup)
+struct cli_session_setup_plain_state {
+ struct cli_state *cli;
+ uint16_t vwv[13];
+ const char *user;
+};
+
+static void cli_session_setup_plain_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_plain_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *user, const char *pass, const char *workgroup)
{
- uint32 capabilities = cli_session_setup_capabilities(cli);
- char *p;
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_plain_state *state;
+ uint16_t *vwv;
+ uint8_t *bytes;
+ size_t passlen;
+ char *version;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_plain_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ state->user = user;
+ 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), pass, strlen(pass)+1,
+ &passlen);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ SSVAL(vwv + (cli_ucs2(cli) ? 8 : 7), 0, passlen);
+
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ user, strlen(user)+1, NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ workgroup, strlen(workgroup)+1, NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ "Unix", 5, NULL);
+
+ version = talloc_asprintf(talloc_tos(), "Samba %s",
+ samba_version_string());
+ if (tevent_req_nomem(version, req)){
+ return tevent_req_post(req, ev);
+ }
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ version, strlen(version)+1, NULL);
+ TALLOC_FREE(version);
+
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_plain_done, req);
+ return req;
+}
+
+static void cli_session_setup_plain_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_plain_state *state = tevent_req_data(
+ req, struct cli_session_setup_plain_state);
+ struct cli_state *cli = state->cli;
+ uint32_t num_bytes;
+ uint8_t *in;
+ char *inbuf;
+ uint8_t *bytes;
+ uint8_t *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);
- SSVAL(cli->outbuf,smb_vwv4,cli->pid);
- SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
- 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)));
- }
- else {
- /* For ucs2 passwords clistr_push calls ucs2_align, which causes
- * the space taken by the unicode password to be one byte too
- * long (as we're on an odd byte boundary here). Reduce the
- * count by 1 to cope with this. Fixes smbclient against NetApp
- * servers which can't cope. Fix from
- * bryan.kolodziej@allenlund.com in bug #3840.
- */
- 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);
+ ssize_t ret;
+ uint8_t wct;
+ uint16_t *vwv;
+
+ status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
- 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);
- p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
+ inbuf = (char *)in;
+ p = bytes;
- if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
- return cli_nt_error(cli);
+ cli->vuid = SVAL(inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
+ p += ret;
- show_msg(cli->inbuf);
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
- if (cli_is_error(cli)) {
- return cli_nt_error(cli);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
- 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);
- 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;
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = cli_set_username(cli, state->user);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
}
+ tevent_req_done(req);
+}
- return NT_STATUS_OK;
+static NTSTATUS cli_session_setup_plain_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS cli_session_setup_plain(struct cli_state *cli,
+ const char *user, const char *pass,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ 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) {
+ goto fail;
+ }
+ req = cli_session_setup_plain_send(frame, ev, cli, user, pass,
+ workgroup);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_session_setup_plain_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
}
/****************************************************************************
@param workgroup The user's domain.
****************************************************************************/
-static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
- const char *pass, size_t passlen,
- const char *ntpass, size_t ntpasslen,
- const char *workgroup)
+struct cli_session_setup_nt1_state {
+ struct cli_state *cli;
+ uint16_t vwv[13];
+ DATA_BLOB response;
+ DATA_BLOB session_key;
+ const char *user;
+};
+
+static void cli_session_setup_nt1_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_nt1_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *ntpass, size_t ntpasslen,
+ const char *workgroup)
{
- uint32 capabilities = cli_session_setup_capabilities(cli);
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_nt1_state *state;
DATA_BLOB lm_response = data_blob_null;
DATA_BLOB nt_response = data_blob_null;
DATA_BLOB session_key = data_blob_null;
- NTSTATUS result;
- char *p;
- bool ok;
+ uint16_t *vwv;
+ uint8_t *bytes;
+ char *workgroup_upper;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_nt1_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ state->user = user;
+ vwv = state->vwv;
if (passlen == 0) {
/* do nothing - guest login */
if (lp_client_ntlmv2_auth()) {
DATA_BLOB server_chal;
DATA_BLOB names_blob;
- server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
- /* note that the 'workgroup' here is a best guess - we don't know
- the server's domain at this point. The 'server name' is also
- dodgy...
- */
- names_blob = NTLMv2_generate_names_blob(NULL, cli->called.name, workgroup);
+ 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);
+ }
+
+ /*
+ * note that the 'workgroup' here is a best
+ * guess - we don't know the server's domain
+ * at this point. The 'server name' is also
+ * dodgy...
+ */
+ names_blob = NTLMv2_generate_names_blob(
+ NULL, cli->called.name, workgroup);
+
+ if (tevent_req_nomem(names_blob.data, req)) {
+ return tevent_req_post(req, ev);
+ }
- if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass, &server_chal,
- &names_blob,
- &lm_response, &nt_response, NULL, &session_key)) {
+ if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass,
+ &server_chal, &names_blob,
+ &lm_response, &nt_response,
+ NULL, &session_key)) {
data_blob_free(&names_blob);
data_blob_free(&server_chal);
- return NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(
+ req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
}
data_blob_free(&names_blob);
data_blob_free(&server_chal);
nt_response = data_blob_null;
#else
nt_response = data_blob(NULL, 24);
- SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
+ if (tevent_req_nomem(nt_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ SMBNTencrypt(pass, cli->secblob.data,
+ nt_response.data);
#endif
/* non encrypted password supplied. Ignore ntpass. */
if (lp_client_lanman_auth()) {
+
lm_response = data_blob(NULL, 24);
- if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
- /* Oops, the LM response is invalid, just put
- the NT response there instead */
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (!SMBencrypt(pass,cli->secblob.data,
+ lm_response.data)) {
+ /*
+ * Oops, the LM response is
+ * invalid, just put the NT
+ * response there instead
+ */
data_blob_free(&lm_response);
- lm_response = data_blob(nt_response.data, nt_response.length);
+ lm_response = data_blob(
+ nt_response.data,
+ nt_response.length);
}
} else {
- /* LM disabled, place NT# in LM field instead */
- lm_response = data_blob(nt_response.data, nt_response.length);
+ /*
+ * LM disabled, place NT# in LM field
+ * instead
+ */
+ lm_response = data_blob(
+ nt_response.data, nt_response.length);
+ }
+
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
}
session_key = data_blob(NULL, 16);
+ if (tevent_req_nomem(session_key.data, req)) {
+ return tevent_req_post(req, ev);
+ }
#ifdef LANMAN_ONLY
E_deshash(pass, session_key.data);
memset(&session_key.data[8], '\0', 8);
signing because we don't have original key */
lm_response = data_blob(pass, passlen);
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
nt_response = data_blob(ntpass, ntpasslen);
+ if (tevent_req_nomem(nt_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
}
- /* send a session setup command */
- memset(cli->outbuf,'\0',smb_size);
+#ifdef LANMAN_ONLY
+ state->response = data_blob_talloc(
+ state, lm_response.data, lm_response.length);
+#else
+ state->response = data_blob_talloc(
+ state, nt_response.data, nt_response.length);
+#endif
+ if (tevent_req_nomem(state->response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
- cli_set_message(cli->outbuf,13,0,True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
- cli_setup_packet(cli);
+ if (session_key.data) {
+ state->session_key = data_blob_talloc(
+ state, session_key.data, session_key.length);
+ if (tevent_req_nomem(state->session_key.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+ data_blob_free(&session_key);
+
+ 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, 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));
- 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,lm_response.length);
- SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
- SIVAL(cli->outbuf,smb_vwv11,capabilities);
- p = smb_buf(cli->outbuf);
- if (lm_response.length) {
- memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
+ bytes = talloc_array(state, uint8_t,
+ lm_response.length + nt_response.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
}
- if (nt_response.length) {
- memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
+ if (lm_response.length != 0) {
+ memcpy(bytes, lm_response.data, lm_response.length);
}
- p += clistr_push(cli, p, user, -1, STR_TERMINATE);
+ if (nt_response.length != 0) {
+ memcpy(bytes + lm_response.length,
+ nt_response.data, nt_response.length);
+ }
+ data_blob_free(&lm_response);
+ data_blob_free(&nt_response);
- /* Upper case here might help some NTLMv2 implementations */
- p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ user, strlen(user)+1, NULL);
- if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
- result = cli_nt_error(cli);
- goto end;
+ /*
+ * Upper case here might help some NTLMv2 implementations
+ */
+ workgroup_upper = talloc_strdup_upper(talloc_tos(), workgroup);
+ if (tevent_req_nomem(workgroup_upper, req)) {
+ return tevent_req_post(req, ev);
}
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ workgroup_upper, strlen(workgroup_upper)+1,
+ NULL);
+ TALLOC_FREE(workgroup_upper);
- /* show_msg(cli->inbuf); */
+ 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 (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
- if (cli_is_error(cli)) {
- result = cli_nt_error(cli);
- goto end;
+ subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_session_setup_nt1_done, req);
+ return req;
+}
-#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;
- }
+static void cli_session_setup_nt1_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_nt1_state *state = tevent_req_data(
+ req, struct cli_session_setup_nt1_state);
+ struct cli_state *cli = state->cli;
+ uint32_t num_bytes;
+ uint8_t *in;
+ char *inbuf;
+ uint8_t *bytes;
+ uint8_t *p;
+ NTSTATUS status;
+ ssize_t ret;
+ uint8_t wct;
+ uint16_t *vwv;
+
+ status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
- /* use the returned vuid from now on */
- cli->vuid = SVAL(cli->inbuf,smb_uid);
+ inbuf = (char *)in;
+ p = bytes;
- p = smb_buf(cli->inbuf);
- 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);
+ cli->vuid = SVAL(inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
}
- result = cli_set_username(cli, user);
- if (!NT_STATUS_IS_OK(result)) {
- goto end;
+ status = cli_set_username(cli, state->user);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
-
- if (session_key.data) {
+ if (cli_simple_set_signing(cli, state->session_key, state->response)
+ && !cli_check_sign_mac(cli, (char *)in, 1)) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ if (state->session_key.data) {
/* Have plaintext orginal */
- cli_set_session_key(cli, session_key);
+ cli_set_session_key(cli, state->session_key);
}
+ tevent_req_done(req);
+}
- result = NT_STATUS_OK;
-end:
- data_blob_free(&lm_response);
- data_blob_free(&nt_response);
- data_blob_free(&session_key);
- return result;
+static NTSTATUS cli_session_setup_nt1_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *ntpass, size_t ntpasslen,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ 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) {
+ goto fail;
+ }
+ req = cli_session_setup_nt1_send(frame, ev, cli, user, pass, passlen,
+ ntpass, ntpasslen, workgroup);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_session_setup_nt1_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
}
/* The following is calculated from :
MIN(cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE, 0xFFFF);
if (!cli_sesssetup_blob_next(state, &subreq)) {
- tevent_req_nomem(NULL, req);
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
uint8_t *p;
uint16_t blob_length;
uint8_t *inbuf;
+ ssize_t ret;
- status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv,
+ status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv,
&num_bytes, &bytes);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)
state->inbuf = (char *)inbuf;
cli->vuid = SVAL(state->inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
blob_length = SVAL(vwv+3, 0);
if (blob_length > num_bytes) {
p = bytes + blob_length;
- 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);
+ status = smb_bytes_talloc_string(cli,
+ (char *)inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ (char *)inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ (char *)inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
* More to send
*/
if (!cli_sesssetup_blob_next(state, &subreq)) {
- tevent_req_nomem(NULL, req);
+ tevent_req_oom(req);
return;
}
tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
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)
+ const char *principal)
{
struct tevent_req *req, *subreq;
struct cli_session_setup_kerberos_state *state;
cli_temp_set_signing(cli);
/*
- * Ok, this is cheated: spnego_gen_negTokenTarg can block if
+ * Ok, this is cheating: spnego_gen_krb5_negTokenInit can block if
* we have to acquire a ticket. To be fixed later :-)
*/
- rc = spnego_gen_negTokenTarg(principal, 0, &state->negTokenTarg,
+ 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",
+ "spnego_gen_krb5_negTokenInit failed: %s\n",
error_message(rc)));
state->ads_status = ADS_ERROR_KRB5(rc);
tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
}
static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
- const char *principal,
- const char *workgroup)
+ const char *principal)
{
struct tevent_context *ev;
struct tevent_req *req;
if (ev == NULL) {
goto fail;
}
- req = cli_session_setup_kerberos_send(ev, ev, cli, principal,
- workgroup);
+ req = cli_session_setup_kerberos_send(ev, ev, cli, principal);
if (req == NULL) {
goto fail;
}
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);
cli_temp_set_signing(cli);
status = ntlmssp_client_start(state,
- global_myname(),
+ lp_netbios_name(),
lp_workgroup(),
lp_client_ntlmv2_auth(),
&state->ntlmssp_state);
goto fail;
}
- state->blob_out = gen_negTokenInit(OID_NTLMSSP, blob_out);
+ state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
data_blob_free(&blob_out);
subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
if (NT_STATUS_IS_OK(status)) {
if (state->cli->server_domain[0] == '\0') {
- fstrcpy(state->cli->server_domain,
- state->ntlmssp_state->server.netbios_domain);
+ TALLOC_FREE(state->cli->server_domain);
+ 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;
+ }
}
cli_set_session_key(
state->cli, state->ntlmssp_state->session_key);
&& 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(blob_in, &msg_in,
+ parse_ret = spnego_parse_challenge(state, blob_in, &msg_in,
&tmp_blob);
data_blob_free(&tmp_blob);
} else {
- parse_ret = spnego_parse_auth_response(blob_in, status,
+ parse_ret = spnego_parse_auth_response(state, blob_in, status,
OID_NTLMSSP, &msg_in);
}
state->turn += 1;
return;
}
- state->blob_out = spnego_gen_auth(blob_out);
+ state->blob_out = spnego_gen_auth(state, blob_out);
TALLOC_FREE(subreq);
if (tevent_req_nomem(state->blob_out.data, req)) {
return;
status = cli_session_setup_ntlmssp_recv(req);
fail:
TALLOC_FREE(ev);
- if (!NT_STATUS_IS_OK(status)) {
- cli_set_error(cli, status);
- }
return status;
}
* 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, NULL)) {
+ 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);
}
status = cli_set_username(cli, user);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(principal);
return ADS_ERROR_NT(status);
}
}
}
- /* 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);
}
!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) {
- /* We had a '.' in the name. */
- 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);
+ if (!realm) {
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
strupper_m(realm);
} else {
if (host) {
}
}
- if (realm && *realm) {
- if (host) {
- /* DNS name. */
- principal = talloc_asprintf(talloc_tos(),
- "cifs/%s@%s",
- cli->desthost,
- realm);
- } else {
- /* NetBIOS name, use machine account. */
- principal = talloc_asprintf(talloc_tos(),
- "%s$@%s",
- machine,
- realm);
- }
- if (!principal) {
- SAFE_FREE(machine);
- SAFE_FREE(realm);
+ if (realm == NULL || *realm == '\0') {
+ realm = SMB_STRDUP(lp_realm());
+ if (!realm) {
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
- DEBUG(3,("cli_session_setup_spnego: guessed "
- "server principal=%s\n",
- principal ? principal : "<null>"));
+ 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 : "<null>",
+ cli->desthost,
+ realm));
+ }
+
+ principal = talloc_asprintf(talloc_tos(),
+ "cifs/%s@%s",
+ cli->desthost,
+ realm);
+ if (!principal) {
+ SAFE_FREE(realm);
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
- SAFE_FREE(machine);
+ DEBUG(3,("cli_session_setup_spnego: guessed "
+ "server principal=%s\n",
+ principal ? principal : "<null>"));
+
SAFE_FREE(realm);
}
if (principal) {
- rc = cli_session_setup_kerberos(cli, principal,
- dest_realm);
+ rc = cli_session_setup_kerberos(cli, principal);
if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
TALLOC_FREE(principal);
return rc;
const char *workgroup)
{
char *p;
- fstring user2;
+ char *user2;
if (user) {
- fstrcpy(user2, user);
+ user2 = talloc_strdup(talloc_tos(), user);
} else {
- user2[0] ='\0';
+ user2 = talloc_strdup(talloc_tos(), "");
+ }
+ if (user2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
if (!workgroup) {
(p=strchr_m(user2,*lp_winbind_separator()))) {
*p = 0;
user = p+1;
+ strupper_m(user2);
workgroup = user2;
}
if (cli->protocol < PROTOCOL_NT1) {
if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
- DEBUG(1, ("Server requested LM password but 'client lanman auth'"
- " is disabled\n"));
+ DEBUG(1, ("Server requested LM password but 'client lanman auth = no'"
+ " or 'client ntlmv2 auth = yes'\n"));
return NT_STATUS_ACCESS_DENIED;
}
if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested plaintext password but "
- "'client plaintext auth' is disabled\n"));
+ DEBUG(1, ("Server requested LM password but 'client plaintext auth = no'"
+ " or 'client ntlmv2 auth = yes'\n"));
return NT_STATUS_ACCESS_DENIED;
}
connect */
if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
- return cli_session_setup_plaintext(cli, user, "", workgroup);
+ return cli_session_setup_plain(cli, user, "", workgroup);
/* if the server doesn't support encryption then we have to use
plaintext. The second password is ignored */
if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
if (!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested plaintext password but "
- "'client plaintext auth' is disabled\n"));
+ DEBUG(1, ("Server requested LM password but 'client plaintext auth = no'"
+ " or 'client ntlmv2 auth = yes'\n"));
return NT_STATUS_ACCESS_DENIED;
}
- return cli_session_setup_plaintext(cli, user, pass, workgroup);
+ return cli_session_setup_plain(cli, user, pass, workgroup);
}
/* if the server supports extended security then use SPNEGO */
struct cli_ulogoff_state {
struct cli_state *cli;
- uint16_t vwv[2];
+ uint16_t vwv[3];
};
static void cli_ulogoff_done(struct tevent_req *subreq);
status = cli_ulogoff_recv(req);
fail:
TALLOC_FREE(ev);
- if (!NT_STATUS_IS_OK(status)) {
- cli_set_error(cli, status);
- }
return status;
}
{
struct tevent_req *req, *subreq;
struct cli_tcon_andx_state *state;
- fstring pword;
+ uint8_t p24[24];
uint16_t *vwv;
char *tmp = NULL;
uint8_t *bytes;
state->cli = cli;
vwv = state->vwv;
- fstrcpy(cli->share, share);
+ cli->share = talloc_strdup(cli, share);
+ if (!cli->share) {
+ return NULL;
+ }
/* in user level security don't send a password now */
if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
if (!lp_client_lanman_auth()) {
DEBUG(1, ("Server requested LANMAN password "
"(share-level security) but "
- "'client lanman auth' is disabled\n"));
+ "'client lanman auth = no' or 'client ntlmv2 auth = yes'\n"));
goto access_denied;
}
* Non-encrypted passwords - convert to DOS codepage before
* encryption.
*/
+ SMBencrypt(pass, cli->secblob.data, p24);
passlen = 24;
- SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
+ pass = (const char *)p24;
} else {
if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
== 0) {
+ char *tmp_pass;
+
if (!lp_client_plaintext_auth() && (*pass)) {
DEBUG(1, ("Server requested plaintext "
- "password but 'client plaintext "
- "auth' is disabled\n"));
+ "password but "
+ "'client lanman auth = no' or 'client ntlmv2 auth = yes'\n"));
goto access_denied;
}
* Non-encrypted passwords - convert to DOS codepage
* before using.
*/
- passlen = clistr_push(cli, pword, pass, sizeof(pword),
- STR_TERMINATE);
- if (passlen == -1) {
- DEBUG(1, ("clistr_push(pword) failed\n"));
- goto access_denied;
+ tmp_pass = talloc_array(talloc_tos(), char, 128);
+ if (tmp_pass == NULL) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return tevent_req_post(req, ev);
}
- } else {
- if (passlen) {
- memcpy(pword, pass, passlen);
+ passlen = clistr_push(cli,
+ tmp_pass,
+ pass,
+ talloc_get_size(tmp_pass),
+ STR_TERMINATE);
+ if (passlen == -1) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return tevent_req_post(req, ev);
}
+ pass = tmp_pass;
}
}
SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
SSVAL(vwv+3, 0, passlen);
- if (passlen) {
- bytes = (uint8_t *)talloc_memdup(state, pword, passlen);
+ if (passlen && pass) {
+ bytes = (uint8_t *)talloc_memdup(state, pass, passlen);
} else {
bytes = talloc_array(state, uint8_t, 0);
}
inbuf = (char *)in;
- clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes,
- STR_TERMINATE|STR_ASCII);
+ if (num_bytes) {
+ if (clistr_pull_talloc(cli,
+ inbuf,
+ SVAL(inbuf, smb_flg2),
+ &cli->dev,
+ bytes,
+ num_bytes,
+ STR_TERMINATE|STR_ASCII) == -1) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ } else {
+ cli->dev = talloc_strdup(cli, "");
+ if (cli->dev == NULL) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ }
if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
/* almost certainly win95 - enable bug fixes */
status = cli_tcon_andx_recv(req);
fail:
TALLOC_FREE(frame);
- if (!NT_STATUS_IS_OK(status)) {
- cli_set_error(cli, status);
- }
return status;
}
status = cli_tdis_recv(req);
fail:
TALLOC_FREE(ev);
- if (!NT_STATUS_IS_OK(status)) {
- cli_set_error(cli, status);
- }
return status;
}
Send a negprot command.
****************************************************************************/
-void cli_negprot_sendsync(struct cli_state *cli)
-{
- char *p;
- int numprots;
-
- if (cli->protocol < PROTOCOL_NT1)
- cli->use_spnego = False;
-
- memset(cli->outbuf,'\0',smb_size);
-
- /* setup the protocol strings */
- cli_set_message(cli->outbuf,0,0,True);
-
- p = smb_buf(cli->outbuf);
- 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);
- }
-
- SCVAL(cli->outbuf,smb_com,SMBnegprot);
- cli_setup_bcc(cli, p);
- cli_setup_packet(cli);
-
- SCVAL(smb_buf(cli->outbuf),0,2);
-
- cli_send_smb(cli);
-}
-
-/****************************************************************************
- Send a negprot command.
-****************************************************************************/
-
struct cli_negprot_state {
struct cli_state *cli;
};
}
/* work out if they sent us a workgroup */
if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
- smb_buflen(cli->inbuf) > 8) {
- clistr_pull(cli->inbuf, cli->server_domain,
- bytes+8, sizeof(cli->server_domain),
- num_bytes-8,
- STR_UNICODE|STR_NOALIGN);
+ 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;
+ }
}
/*
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;
}
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);
status = cli_negprot_recv(req);
fail:
TALLOC_FREE(frame);
- if (!NT_STATUS_IS_OK(status)) {
- cli_set_error(cli, status);
- }
return status;
}
-/****************************************************************************
- Send a session request. See rfc1002.txt 4.3 and 4.3.2.
-****************************************************************************/
-
-bool cli_session_request(struct cli_state *cli,
- struct nmb_name *calling, struct nmb_name *called)
-{
- 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;
- memcpy(p, tmp, name_len(tmp));
- len += name_len(tmp);
- TALLOC_FREE(tmp);
-
- /* and my name */
-
- 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
- * Remove four bytes from the length count, since the length
- * field in the NBT Session Service header counts the number
- * of bytes which follow. The cli_send_smb() function knows
- * about this and accounts for those four bytes.
- * CRH.
- */
- len -= 4;
- _smb_setlen(cli->outbuf,len);
- SCVAL(cli->outbuf,0,0x81);
-
- cli_send_smb(cli);
- DEBUG(5,("Sent session request\n"));
-
- if (!cli_receive_smb(cli))
- return False;
-
- if (CVAL(cli->inbuf,0) == 0x84) {
- /* C. Hoch 9/14/95 Start */
- /* For information, here is the response structure.
- * We do the byte-twiddling to for portability.
- struct RetargetResponse{
- unsigned char type;
- unsigned char flags;
- int16 length;
- int32 ip_addr;
- int16 port;
- };
- */
- 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);
-
- 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"));
-
- set_socket_options(cli->fd, lp_socket_options());
-
- /* Try again */
- {
- static int depth;
- bool ret;
- if (depth > 4) {
- DEBUG(0,("Retarget recursion - failing\n"));
- return False;
- }
- depth++;
- ret = cli_session_request(cli, calling, called);
- depth--;
- return ret;
- }
- } /* C. Hoch 9/14/95 End */
-
- if (CVAL(cli->inbuf,0) != 0x82) {
- /* This is the wrong place to put the error... JRA. */
- cli->rap_error = CVAL(cli->inbuf,4);
- return False;
- }
- return(True);
-}
-
-struct fd_struct {
- int fd;
-};
-
-static void smb_sock_connected(struct tevent_req *req)
+static NTSTATUS cli_connect_sock(const char *host, int name_type,
+ const struct sockaddr_storage *pss,
+ const char *myname, uint16_t port,
+ int sec_timeout, int *pfd, uint16_t *pport)
{
- struct fd_struct *pfd = tevent_req_callback_data(
- req, struct fd_struct);
- int fd;
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *prog;
+ unsigned int i, num_addrs;
+ const char **called_names;
+ const char **calling_names;
+ int *called_types;
NTSTATUS status;
+ int fd;
- 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) {
+ prog = getenv("LIBSMB_PROG");
+ if (prog != NULL) {
+ fd = sock_exec(prog);
+ if (fd == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ port = 0;
goto done;
}
- fd139->fd = -1;
- fd445 = talloc(ev, struct fd_struct);
- if (fd445 == NULL) {
- goto done;
+ if ((pss == NULL) || is_zero_addr(pss)) {
+ struct sockaddr_storage *addrs;
+ status = resolve_name_list(talloc_tos(), host, name_type,
+ &addrs, &num_addrs);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ pss = addrs;
+ } else {
+ num_addrs = 1;
}
- 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;
+ called_names = talloc_array(talloc_tos(), const char *, num_addrs);
+ if (called_names == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
- 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);
+ called_types = talloc_array(talloc_tos(), int, num_addrs);
+ if (called_types == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
-
- if ((fd139->fd != -1) && (fd445->fd != -1)) {
- close(fd139->fd);
- fd139->fd = -1;
+ calling_names = talloc_array(talloc_tos(), const char *, num_addrs);
+ if (calling_names == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
-
- if (fd445->fd != -1) {
- *port = 445;
- *pfd = fd445->fd;
- status = NT_STATUS_OK;
- goto done;
+ for (i=0; i<num_addrs; i++) {
+ called_names[i] = host;
+ called_types[i] = name_type;
+ calling_names[i] = myname;
}
- if (fd139->fd != -1) {
- *port = 139;
- *pfd = fd139->fd;
- status = NT_STATUS_OK;
- goto done;
+ status = smbsock_any_connect(pss, called_names, called_types,
+ calling_names, NULL, num_addrs, port,
+ sec_timeout, &fd, NULL, &port);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
}
-
- status = open_socket_out_defer_recv(r445, &fd445->fd);
- done:
- TALLOC_FREE(ev);
+ set_socket_options(fd, lp_socket_options());
+done:
+ *pfd = fd;
+ *pport = port;
+ status = NT_STATUS_OK;
+fail:
+ TALLOC_FREE(frame);
return status;
}
-/****************************************************************************
- Open the client sockets.
-****************************************************************************/
-
-NTSTATUS cli_connect(struct cli_state *cli,
- const char *host,
- struct sockaddr_storage *dest_ss)
-
+NTSTATUS cli_connect_nb(const char *host, struct sockaddr_storage *pss,
+ uint16_t port, int name_type, const char *myname,
+ int signing_state, struct cli_state **pcli)
{
- int name_type = 0x20;
TALLOC_CTX *frame = talloc_stackframe();
- unsigned int num_addrs = 0;
- unsigned int i = 0;
- struct sockaddr_storage *ss_arr = NULL;
- char *p = NULL;
+ struct cli_state *cli;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ int fd = -1;
+ char *desthost;
+ char *p;
+ socklen_t length;
+ int ret;
- /* reasonable default hostname */
- if (!host) {
- host = STAR_SMBSERVER;
+ desthost = talloc_strdup(talloc_tos(), host);
+ if (desthost == NULL) {
+ goto fail;
}
- fstrcpy(cli->desthost, host);
-
- /* allow hostnames of the form NAME#xx and do a netbios lookup */
- if ((p = strchr(cli->desthost, '#'))) {
+ p = strchr(host, '#');
+ if (p != NULL) {
name_type = strtol(p+1, NULL, 16);
- *p = 0;
- }
-
- if (!dest_ss || is_zero_addr((struct sockaddr *)dest_ss)) {
- NTSTATUS status =resolve_name_list(frame,
- cli->desthost,
- name_type,
- &ss_arr,
- &num_addrs);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(frame);
- return NT_STATUS_BAD_NETWORK_NAME;
- }
- } else {
- num_addrs = 1;
- ss_arr = TALLOC_P(frame, struct sockaddr_storage);
- if (!ss_arr) {
- TALLOC_FREE(frame);
- return NT_STATUS_NO_MEMORY;
+ host = talloc_strndup(talloc_tos(), host, p - host);
+ if (host == NULL) {
+ goto fail;
}
- *ss_arr = *dest_ss;
}
- for (i = 0; i < num_addrs; i++) {
- cli->dest_ss = ss_arr[i];
- if (getenv("LIBSMB_PROG")) {
- cli->fd = sock_exec(getenv("LIBSMB_PROG"));
- } else {
- 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 (cli->fd == -1) {
- char addr[INET6_ADDRSTRLEN];
- print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
- DEBUG(2,("Error connecting to %s (%s)\n",
- dest_ss?addr:host,strerror(errno)));
- } else {
- /* Exit from loop on first connection. */
- break;
- }
+ cli = cli_initialise_ex(signing_state);
+ if (cli == NULL) {
+ goto fail;
}
+ cli->desthost = talloc_move(cli, &desthost);
- if (cli->fd == -1) {
- TALLOC_FREE(frame);
- return map_nt_error_from_unix(errno);
+ status = cli_connect_sock(host, name_type, pss, myname, port, 20, &fd,
+ &port);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_shutdown(cli);
+ goto fail;
}
+ cli->fd = fd;
+ cli->port = port;
- if (dest_ss) {
- *dest_ss = cli->dest_ss;
+ length = sizeof(cli->dest_ss);
+ ret = getpeername(fd, (struct sockaddr *)(void *)&cli->dest_ss,
+ &length);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ cli_shutdown(cli);
+ goto fail;
}
- set_socket_options(cli->fd, lp_socket_options());
+ if (pss != NULL) {
+ *pss = cli->dest_ss;
+ }
+ *pcli = cli;
+ status = NT_STATUS_OK;
+fail:
TALLOC_FREE(frame);
- return NT_STATUS_OK;
+ return status;
}
/**
@param dest_host The netbios name of the remote host
@param dest_ss (optional) The the destination IP, NULL for name based lookup
@param port (optional) The destination port (0 for default)
- @param retry bool. Did this connection fail with a retryable error ?
-
*/
NTSTATUS cli_start_connection(struct cli_state **output_cli,
const char *my_name,
const char *dest_host,
struct sockaddr_storage *dest_ss, int port,
- int signing_state, int flags,
- bool *retry)
+ int signing_state, int flags)
{
NTSTATUS nt_status;
- struct nmb_name calling;
- struct nmb_name called;
struct cli_state *cli;
- struct sockaddr_storage ss;
- if (retry)
- *retry = False;
-
- if (!my_name)
- my_name = global_myname();
-
- 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);
-
- cli_set_port(cli, port);
- cli_set_timeout(cli, 10000); /* 10 seconds. */
-
- if (dest_ss) {
- ss = *dest_ss;
- } else {
- zero_sockaddr(&ss);
- }
-
-again:
-
- DEBUG(3,("Connecting to host=%s\n", dest_host));
-
- nt_status = cli_connect(cli, dest_host, &ss);
+ nt_status = cli_connect_nb(dest_host, dest_ss, port, 0x20, my_name,
+ signing_state, &cli);
if (!NT_STATUS_IS_OK(nt_status)) {
- char addr[INET6_ADDRSTRLEN];
- print_sockaddr(addr, sizeof(addr), &ss);
- DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
- nmb_namestr(&called), addr, nt_errstr(nt_status) ));
- cli_shutdown(cli);
+ DEBUG(10, ("cli_connect_nb failed: %s\n",
+ nt_errstr(nt_status)));
return nt_status;
}
- if (retry)
- *retry = True;
-
- if (!cli_session_request(cli, &calling, &called)) {
- char *p;
- DEBUG(1,("session request to %s failed (%s)\n",
- called.name, cli_errstr(cli)));
- if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
- *p = 0;
- goto again;
- }
- if (strcmp(called.name, STAR_SMBSERVER)) {
- make_nmb_name(&called , STAR_SMBSERVER, 0x20);
- goto again;
- }
- return NT_STATUS_BAD_NETWORK_NAME;
- }
-
if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
cli->use_spnego = False;
else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
@param user Username, unix string
@param domain User's domain
@param password User's password, unencrypted unix string.
- @param retry bool. Did this connection fail with a retryable error ?
*/
NTSTATUS cli_full_connection(struct cli_state **output_cli,
const char *service, const char *service_type,
const char *user, const char *domain,
const char *password, int flags,
- int signing_state,
- bool *retry)
+ int signing_state)
{
NTSTATUS nt_status;
struct cli_state *cli = NULL;
nt_status = cli_start_connection(&cli, my_name, dest_host,
dest_ss, port, signing_state,
- flags, retry);
+ flags);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
return NT_STATUS_OK;
}
-/****************************************************************************
- Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
-****************************************************************************/
-
-bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
- struct sockaddr_storage *pdest_ss)
-{
- struct nmb_name calling, called;
-
- make_nmb_name(&calling, srchost, 0x0);
-
- /*
- * If the called name is an IP address
- * then use *SMBSERVER immediately.
- */
-
- if(is_ipaddress(desthost)) {
- make_nmb_name(&called, STAR_SMBSERVER, 0x20);
- } else {
- make_nmb_name(&called, desthost, 0x20);
- }
-
- if (!cli_session_request(*ppcli, &calling, &called)) {
- NTSTATUS status;
- struct nmb_name smbservername;
-
- make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
-
- /*
- * If the name wasn't *SMBSERVER then
- * try with *SMBSERVER if the first name fails.
- */
-
- if (nmb_name_equal(&called, &smbservername)) {
-
- /*
- * The name used was *SMBSERVER, don't bother with another name.
- */
-
- DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
-with error %s.\n", desthost, cli_errstr(*ppcli) ));
- return False;
- }
-
- /* Try again... */
- cli_shutdown(*ppcli);
-
- *ppcli = cli_initialise();
- if (!*ppcli) {
- /* Out of memory... */
- return False;
- }
-
- status = cli_connect(*ppcli, desthost, pdest_ss);
- if (!NT_STATUS_IS_OK(status) ||
- !cli_session_request(*ppcli, &calling, &smbservername)) {
- DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
-name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
- return False;
- }
- }
-
- return True;
-}
-
/****************************************************************************
Send an old style tcon.
****************************************************************************/
const char *service, const char *pass, const char *dev,
uint16 *max_xmit, uint16 *tid)
{
- char *p;
+ struct tevent_req *req;
+ uint16_t *ret_vwv;
+ uint8_t *bytes;
+ NTSTATUS status;
if (!lp_client_plaintext_auth() && (*pass)) {
DEBUG(1, ("Server requested plaintext password but 'client "
return NT_STATUS_ACCESS_DENIED;
}
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
-
- cli_set_message(cli->outbuf, 0, 0, True);
- SCVAL(cli->outbuf,smb_com,SMBtcon);
- cli_setup_packet(cli);
-
- p = smb_buf(cli->outbuf);
- *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
- *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
- *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
-
- cli_setup_bcc(cli, p);
-
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
- }
-
- if (cli_is_error(cli)) {
- return cli_nt_error(cli);
+ bytes = talloc_array(talloc_tos(), uint8_t, 0);
+ bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ service, strlen(service)+1, NULL);
+ bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ pass, strlen(pass)+1, NULL);
+ bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ dev, strlen(dev)+1, NULL);
+
+ status = cli_smb(talloc_tos(), cli, SMBtcon, 0, 0, NULL,
+ talloc_get_size(bytes), bytes, &req,
+ 2, NULL, &ret_vwv, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- *max_xmit = SVAL(cli->inbuf, smb_vwv0);
- *tid = SVAL(cli->inbuf, smb_vwv1);
+ *max_xmit = SVAL(ret_vwv + 0, 0);
+ *tid = SVAL(ret_vwv + 1, 0);
return NT_STATUS_OK;
}
lp_workgroup(),
user_info->password ? user_info->password : "",
flags,
- Undefined, NULL);
+ Undefined);
if (NT_STATUS_IS_OK(nt_status)) {
return cli;
*/
struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
- struct ip_service *mb_ip,
+ struct sockaddr_storage *mb_ip,
const struct user_auth_info *user_info,
char **pp_workgroup_out)
{
*pp_workgroup_out = NULL;
- print_sockaddr(addr, sizeof(addr), &mb_ip->ss);
+ print_sockaddr(addr, sizeof(addr), mb_ip);
DEBUG(99, ("Looking up name of master browser %s\n",
addr));
* the original wildcard query as the first choice and fall back to
* MSBROWSE if the wildcard query fails.
*/
- if (!name_status_find("*", 0, 0x1d, &mb_ip->ss, name) &&
- !name_status_find(MSBROWSE, 1, 0x1d, &mb_ip->ss, name)) {
+ if (!name_status_find("*", 0, 0x1d, mb_ip, name) &&
+ !name_status_find(MSBROWSE, 1, 0x1d, mb_ip, name)) {
DEBUG(99, ("Could not retrieve name status for %s\n",
addr));
const struct user_auth_info *user_info,
char **pp_workgroup_out)
{
- struct ip_service *ip_list;
+ struct sockaddr_storage *ip_list;
struct cli_state *cli;
int i, count;
+ NTSTATUS status;
*pp_workgroup_out = NULL;
/* Go looking for workgroups by broadcasting on the local network */
- if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
- &count))) {
- DEBUG(99, ("No master browsers responded\n"));
+ status = name_resolve_bcast(MSBROWSE, 1, talloc_tos(),
+ &ip_list, &count);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(99, ("No master browsers responded: %s\n",
+ nt_errstr(status)));
return False;
}
for (i = 0; i < count; i++) {
char addr[INET6_ADDRSTRLEN];
- print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
+ print_sockaddr(addr, sizeof(addr), &ip_list[i]);
DEBUG(99, ("Found master browser %s\n", addr));
cli = get_ipc_connect_master_ip(ctx, &ip_list[i],