#include "includes.h"
#include "libsmb/libsmb.h"
+#include "libsmb/namequery.h"
#include "auth_info.h"
#include "../libcli/auth/libcli_auth.h"
#include "../libcli/auth/spnego.h"
#include "libsmb/nmblib.h"
#include "librpc/ndr/libndr.h"
#include "../libcli/smb/smbXcli_base.h"
+#include "../libcli/smb/smb_seal.h"
#include "lib/param/param.h"
+#include "../libcli/smb/smb2_negotiate_context.h"
+#include "libads/krb5_errs.h"
#define STAR_SMBSERVER "*SMBSERVER"
}
cli_credentials_set_conf(creds, lp_ctx);
- if (domain == NULL) {
- domain = "";
- }
-
if (username == NULL) {
username = "";
}
goto fail;
}
- ok = cli_credentials_set_domain(creds,
- domain,
- CRED_SPECIFIED);
- if (!ok) {
- goto fail;
+ if (domain != NULL) {
+ ok = cli_credentials_set_domain(creds,
+ domain,
+ CRED_SPECIFIED);
+ if (!ok) {
+ goto fail;
+ }
}
if (principal != NULL) {
return NULL;
}
+NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli,
+ struct cli_credentials *creds)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *user_principal = NULL;
+ const char *user_account = NULL;
+ const char *user_domain = NULL;
+ const char *pass = NULL;
+ const char *target_hostname = NULL;
+ const DATA_BLOB *server_blob = NULL;
+ bool got_kerberos_mechanism = false;
+ enum credentials_use_kerberos krb5_state;
+ bool try_kerberos = false;
+ bool need_kinit = false;
+ bool auth_requested = true;
+ int ret;
+
+ target_hostname = smbXcli_conn_remote_name(cli->conn);
+ server_blob = smbXcli_conn_server_gss_blob(cli->conn);
+
+ /* the server might not even do spnego */
+ if (server_blob != NULL && server_blob->length != 0) {
+ char *OIDs[ASN1_MAX_OIDS] = { NULL, };
+ size_t i;
+ bool ok;
+
+ /*
+ * 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.
+ */
+ ok = spnego_parse_negTokenInit(frame,
+ *server_blob,
+ OIDs,
+ NULL,
+ NULL);
+ if (!ok) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (OIDs[0] == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* make sure the server understands kerberos */
+ for (i = 0; OIDs[i] != NULL; 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;
+ break;
+ }
+ }
+ }
+
+ auth_requested = cli_credentials_authentication_requested(creds);
+ if (auth_requested) {
+ errno = 0;
+ user_principal = cli_credentials_get_principal(creds, frame);
+ if (errno != 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ user_account = cli_credentials_get_username(creds);
+ user_domain = cli_credentials_get_domain(creds);
+ pass = cli_credentials_get_password(creds);
+
+ krb5_state = cli_credentials_get_kerberos_state(creds);
+
+ if (krb5_state != CRED_DONT_USE_KERBEROS) {
+ try_kerberos = true;
+ }
+
+ if (user_principal == NULL) {
+ try_kerberos = false;
+ }
+
+ if (target_hostname == NULL) {
+ try_kerberos = false;
+ } else if (is_ipaddress(target_hostname)) {
+ try_kerberos = false;
+ } else if (strequal(target_hostname, "localhost")) {
+ try_kerberos = false;
+ } else if (strequal(target_hostname, STAR_SMBSERVER)) {
+ try_kerberos = false;
+ } else if (!auth_requested) {
+ try_kerberos = false;
+ }
+
+ if (krb5_state == CRED_MUST_USE_KERBEROS && !try_kerberos) {
+ DEBUG(0, ("Kerberos auth with '%s' (%s\\%s) to access "
+ "'%s' not possible\n",
+ user_principal, user_domain, user_account,
+ target_hostname));
+ TALLOC_FREE(frame);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (pass == NULL || strlen(pass) == 0) {
+ need_kinit = false;
+ } else if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ need_kinit = try_kerberos;
+ } else if (!got_kerberos_mechanism) {
+ /*
+ * Most likely the server doesn't support
+ * Kerberos, don't waste time doing a kinit
+ */
+ need_kinit = false;
+ } else {
+ need_kinit = try_kerberos;
+ }
+
+ if (!need_kinit) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+
+ /*
+ * TODO: This should be done within the gensec layer
+ * only if required!
+ */
+ setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
+ ret = kerberos_kinit_password(user_principal, pass,
+ 0 /* no time correction for now */,
+ NULL);
+ if (ret != 0) {
+ int dbglvl = DBGLVL_NOTICE;
+
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ dbglvl = DBGLVL_ERR;
+ }
+
+ DEBUG(dbglvl, ("Kinit for %s to access %s failed: %s\n",
+ user_principal, target_hostname,
+ error_message(ret)));
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ TALLOC_FREE(frame);
+ return krb5_to_nt_status(ret);
+ }
+
+ /*
+ * Ignore the error and hope that NTLM will work
+ */
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cli_state_update_after_sesssetup(struct cli_state *cli,
+ const char *native_os,
+ const char *native_lm,
+ const char *primary_domain)
+{
+#define _VALID_STR(p) ((p) != NULL && (p)[0] != '\0')
+
+ if (!_VALID_STR(cli->server_os) && _VALID_STR(native_os)) {
+ cli->server_os = talloc_strdup(cli, native_os);
+ if (cli->server_os == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (!_VALID_STR(cli->server_type) && _VALID_STR(native_lm)) {
+ cli->server_type = talloc_strdup(cli, native_lm);
+ if (cli->server_type == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (!_VALID_STR(cli->server_domain) && _VALID_STR(primary_domain)) {
+ cli->server_domain = talloc_strdup(cli, primary_domain);
+ if (cli->server_domain == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+#undef _VALID_STRING
+ return NT_STATUS_OK;
+}
+
/********************************************************
Utility function to ensure we always return at least
a valid char * pointer to an empty string for the
subreq, struct tevent_req);
struct cli_sesssetup_blob_state *state = tevent_req_data(
req, struct cli_sesssetup_blob_state);
- struct cli_state *cli = state->cli;
NTSTATUS status;
if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
return;
}
- if (cli->server_os == NULL) {
- cli->server_os = talloc_move(cli, &state->out_native_os);
- }
- if (cli->server_type == NULL) {
- cli->server_type = talloc_move(cli, &state->out_native_lm);
- }
-
state->status = status;
+ status = cli_state_update_after_sesssetup(state->cli,
+ state->out_native_os,
+ state->out_native_lm,
+ NULL);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
if (state->blob.length != 0) {
/*
* More to send
return status;
}
-/****************************************************************************
- Use in-memory credentials cache
-****************************************************************************/
-
-static void use_in_memory_ccache(void) {
- setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
-}
-
/****************************************************************************
Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
* We can't finish the gensec handshake, we don't
* have a negotiated session key.
*
- * So just pretend we are completely done.
+ * So just pretend we are completely done,
+ * we need to continue as anonymous from this point,
+ * as we can't get a session key.
*
* Note that smbXcli_session_is_guest()
* always returns false if we require signing.
*/
state->blob_in = data_blob_null;
state->local_ready = true;
+ state->is_anonymous = true;
}
state->remote_ready = true;
{
struct tevent_req *req, *subreq;
struct cli_session_setup_spnego_state *state;
- const char *user_principal = NULL;
- const char *user_account = NULL;
- const char *user_domain = NULL;
- const char *pass = NULL;
+ const char *target_service = NULL;
const char *target_hostname = NULL;
- const DATA_BLOB *server_blob = NULL;
- enum credentials_use_kerberos krb5_state;
- bool try_kerberos = false;
- bool need_kinit = false;
- bool auth_requested = true;
+ NTSTATUS status;
req = tevent_req_create(mem_ctx, &state,
struct cli_session_setup_spnego_state);
return NULL;
}
+ target_service = "cifs";
target_hostname = smbXcli_conn_remote_name(cli->conn);
- server_blob = smbXcli_conn_server_gss_blob(cli->conn);
-
- /* the server might not even do spnego */
- if (server_blob != NULL && server_blob->length != 0) {
- char *principal = NULL;
- char *OIDs[ASN1_MAX_OIDS];
- int i;
-
- /* 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(state, *server_blob, OIDs,
- &principal, NULL) ||
- OIDs[0] == NULL) {
- state->result = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- tevent_req_done(req);
- return tevent_req_post(req, ev);
- }
- TALLOC_FREE(principal);
-
- /* make sure the server understands kerberos */
- for (i = 0; OIDs[i] != NULL; 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) {
- cli->got_kerberos_mechanism = True;
- }
- talloc_free(OIDs[i]);
- }
- }
-
- auth_requested = cli_credentials_authentication_requested(creds);
- if (auth_requested) {
- user_principal = cli_credentials_get_principal(creds, state);
- if (tevent_req_nomem(user_principal, req)) {
- return tevent_req_post(req, ev);
- }
- }
- user_account = cli_credentials_get_username(creds);
- user_domain = cli_credentials_get_domain(creds);
- pass = cli_credentials_get_password(creds);
-
- krb5_state = cli_credentials_get_kerberos_state(creds);
-
- if (krb5_state != CRED_DONT_USE_KERBEROS) {
- try_kerberos = true;
- }
-
- if (target_hostname == NULL) {
- try_kerberos = false;
- } else if (is_ipaddress(target_hostname)) {
- try_kerberos = false;
- } else if (strequal(target_hostname, "localhost")) {
- try_kerberos = false;
- } else if (strequal(target_hostname, STAR_SMBSERVER)) {
- try_kerberos = false;
- } else if (!auth_requested) {
- try_kerberos = false;
- }
- if (krb5_state == CRED_MUST_USE_KERBEROS && !try_kerberos) {
- DEBUG(0, ("Kerberos auth with '%s' (%s\\%s) to access "
- "'%s' not possible\n",
- user_principal, user_domain, user_account,
- target_hostname));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ status = cli_session_creds_prepare_krb5(cli, creds);
+ if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}
- if (pass == NULL || strlen(pass) == 0) {
- need_kinit = false;
- } else if (krb5_state == CRED_MUST_USE_KERBEROS) {
- need_kinit = try_kerberos;
- } else if (!cli->got_kerberos_mechanism) {
- /*
- * Most likely the server doesn't support
- * Kerberos, don't waste time doing a kinit
- */
- need_kinit = false;
- } else {
- need_kinit = try_kerberos;
- }
-
- if (need_kinit) {
- int ret;
-
- use_in_memory_ccache();
- ret = kerberos_kinit_password(user_principal, pass,
- 0 /* no time correction for now */,
- NULL);
-
- if (ret != 0) {
- DEBUG(0, ("Kinit for %s to access %s failed: %s\n",
- user_principal, target_hostname,
- error_message(ret)));
- if (krb5_state == CRED_MUST_USE_KERBEROS) {
- state->result = ADS_ERROR_KRB5(ret);
- tevent_req_done(req);
- return tevent_req_post(req, ev);
- }
-
- /*
- * Ignore the error and hope that NTLM will work
- */
- ret = 0;
- }
- }
-
subreq = cli_session_setup_gensec_send(state, ev, cli, creds,
- "cifs", target_hostname);
+ target_service, target_hostname);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
return;
}
- if (cli->server_os == NULL) {
- cli->server_os = talloc_move(cli, &state->out_native_os);
- }
- if (cli->server_type == NULL) {
- cli->server_type = talloc_move(cli, &state->out_native_lm);
- }
- if (cli->server_domain == NULL) {
- cli->server_domain = talloc_move(cli, &state->out_primary_domain);
+ status = cli_state_update_after_sesssetup(state->cli,
+ state->out_native_os,
+ state->out_native_lm,
+ state->out_primary_domain);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
ok = smb1cli_conn_activate_signing(cli->conn,
subreq, struct tevent_req);
struct cli_session_setup_creds_state *state = tevent_req_data(
req, struct cli_session_setup_creds_state);
- struct cli_state *cli = state->cli;
NTSTATUS status;
status = smb1cli_session_setup_lm21_recv(subreq, state,
return;
}
- if (cli->server_os == NULL) {
- cli->server_os = talloc_move(cli, &state->out_native_os);
- }
- if (cli->server_type == NULL) {
- cli->server_type = talloc_move(cli, &state->out_native_lm);
+ status = cli_state_update_after_sesssetup(state->cli,
+ state->out_native_os,
+ state->out_native_lm,
+ NULL);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
tevent_req_done(req);
return NT_STATUS_OK;
}
-NTSTATUS cli_session_setup(struct cli_state *cli,
- const char *user,
- const char *pass,
- const char *workgroup)
-{
- NTSTATUS status = NT_STATUS_NO_MEMORY;
- const char *dest_realm = NULL;
- struct cli_credentials *creds = NULL;
-
- /*
- * dest_realm is only valid in the winbindd use case,
- * where we also have the account in that realm.
- */
- dest_realm = cli_state_remote_realm(cli);
-
- creds = cli_session_creds_init(cli,
- user,
- workgroup,
- dest_realm,
- pass,
- cli->use_kerberos,
- cli->fallback_after_kerberos,
- cli->use_ccache,
- cli->pw_nt_hash);
- if (creds == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- status = cli_session_setup_creds(cli, creds);
- TALLOC_FREE(creds);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-/****************************************************************************
- Send a uloggoff.
-*****************************************************************************/
+/****************************************************************************
+ Send a uloggoff.
+*****************************************************************************/
struct cli_ulogoff_state {
struct cli_state *cli;
state->cli = cli;
vwv = state->vwv;
+ TALLOC_FREE(cli->smb1.tcon);
+ cli->smb1.tcon = smbXcli_tcon_create(cli);
+ if (tevent_req_nomem(cli->smb1.tcon, req)) {
+ return tevent_req_post(req, ev);
+ }
+ smb1cli_tcon_set_id(cli->smb1.tcon, UINT16_MAX);
+
cli->share = talloc_strdup(cli, share);
if (!cli->share) {
return NULL;
static struct tevent_req *cli_tree_connect_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
- const char *share, const char *dev, const char *pass, int passlen)
+ const char *share, const char *dev, const char *pass)
{
struct tevent_req *req, *subreq;
struct cli_tree_connect_state *state;
+ int passlen;
+
+ if (pass == NULL) {
+ pass = "";
+ }
+ passlen = strlen(pass) + 1;
req = tevent_req_create(mem_ctx, &state,
struct cli_tree_connect_state);
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
char *unc;
+ TALLOC_FREE(cli->smb2.tcon);
cli->smb2.tcon = smbXcli_tcon_create(cli);
if (tevent_req_nomem(cli->smb2.tcon, req)) {
return tevent_req_post(req, ev);
}
NTSTATUS cli_tree_connect(struct cli_state *cli, const char *share,
- const char *dev, const char *pass, int passlen)
+ const char *dev, const char *pass)
{
struct tevent_context *ev;
struct tevent_req *req;
if (ev == NULL) {
goto fail;
}
- req = cli_tree_connect_send(ev, ev, cli, share, dev, pass, passlen);
+ req = cli_tree_connect_send(ev, ev, cli, share, dev, pass);
if (req == NULL) {
goto fail;
}
return status;
}
+NTSTATUS cli_tree_connect_creds(struct cli_state *cli,
+ const char *share, const char *dev,
+ struct cli_credentials *creds)
+{
+ const char *pw = NULL;
+
+ if (creds != NULL) {
+ pw = cli_credentials_get_password(creds);
+ }
+
+ return cli_tree_connect(cli, share, dev, pw);
+}
+
/****************************************************************************
Send a tree disconnect.
****************************************************************************/
tevent_req_nterror(req, status);
return;
}
- cli_state_set_tid(state->cli, UINT16_MAX);
+ TALLOC_FREE(state->cli->smb1.tcon);
tevent_req_done(req);
}
NTSTATUS status = NT_STATUS_NO_MEMORY;
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- return smb2cli_tdis(cli->conn,
+ status = smb2cli_tdis(cli->conn,
cli->timeout,
cli->smb2.session,
cli->smb2.tcon);
+ if (NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(cli->smb2.tcon);
+ }
+ return status;
}
if (smbXcli_conn_has_async_calls(cli->conn)) {
{
struct tevent_req *req, *subreq;
struct cli_connect_sock_state *state;
- const char *prog;
struct sockaddr_storage *addrs;
unsigned i, num_addrs;
NTSTATUS status;
return NULL;
}
- prog = getenv("LIBSMB_PROG");
- if (prog != NULL) {
- state->fd = sock_exec(prog);
- if (state->fd == -1) {
- status = map_nt_error_from_unix(errno);
- tevent_req_nterror(req, status);
- } else {
- state->port = 0;
- tevent_req_done(req);
- }
- return tevent_req_post(req, ev);
- }
-
if ((pss == NULL) || is_zero_addr(pss)) {
/*
return;
}
- state->cli = cli_state_create(state, fd, state->desthost, NULL,
+ state->cli = cli_state_create(state, fd, state->desthost,
state->signing_state, state->flags);
if (tevent_req_nomem(state->cli, req)) {
close(fd);
state->max_protocol = lp_client_max_protocol();
}
+ if (flags & CLI_FULL_CONNECTION_FORCE_SMB1) {
+ state->max_protocol = MIN(state->max_protocol, PROTOCOL_NT1);
+ }
+
+ if (flags & CLI_FULL_CONNECTION_DISABLE_SMB1) {
+ state->min_protocol = MAX(state->max_protocol, PROTOCOL_SMB2_02);
+ state->max_protocol = MAX(state->max_protocol, PROTOCOL_LATEST);
+ }
+
subreq = cli_connect_nb_send(state, ev, dest_host, dest_ss, port,
0x20, my_name, signing_state, flags);
if (tevent_req_nomem(subreq, req)) {
subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
state->cli->timeout,
state->min_protocol,
- state->max_protocol);
+ state->max_protocol,
+ WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK);
if (tevent_req_nomem(subreq, req)) {
return;
}
return status;
}
+struct cli_smb1_setup_encryption_blob_state {
+ uint16_t setup[1];
+ uint8_t param[4];
+ NTSTATUS status;
+ DATA_BLOB out;
+ uint16_t enc_ctx_id;
+};
+
+static void cli_smb1_setup_encryption_blob_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_smb1_setup_encryption_blob_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const DATA_BLOB in)
+{
+ struct tevent_req *req = NULL;
+ struct cli_smb1_setup_encryption_blob_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_smb1_setup_encryption_blob_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (in.length > CLI_BUFFER_SIZE) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ SSVAL(state->setup+0, 0, TRANSACT2_SETFSINFO);
+ SSVAL(state->param, 0, 0);
+ SSVAL(state->param, 2, SMB_REQUEST_TRANSPORT_ENCRYPTION);
+
+ subreq = smb1cli_trans_send(state, ev, cli->conn,
+ SMBtrans2,
+ 0, 0, /* _flags */
+ 0, 0, /* _flags2 */
+ cli->timeout,
+ cli->smb1.pid,
+ cli->smb1.tcon,
+ cli->smb1.session,
+ NULL, /* pipe_name */
+ 0, /* fid */
+ 0, /* function */
+ 0, /* flags */
+ state->setup, 1, 0,
+ state->param, 4, 2,
+ in.data, in.length, CLI_BUFFER_SIZE);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq,
+ cli_smb1_setup_encryption_blob_done,
+ req);
+
+ return req;
+}
+
+static void cli_smb1_setup_encryption_blob_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cli_smb1_setup_encryption_blob_state *state =
+ tevent_req_data(req,
+ struct cli_smb1_setup_encryption_blob_state);
+ uint8_t *rparam=NULL, *rdata=NULL;
+ uint32_t num_rparam, num_rdata;
+ NTSTATUS status;
+
+ status = smb1cli_trans_recv(subreq, state,
+ NULL, /* recv_flags */
+ NULL, 0, NULL, /* rsetup */
+ &rparam, 0, &num_rparam,
+ &rdata, 0, &num_rdata);
+ TALLOC_FREE(subreq);
+ state->status = status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ status = NT_STATUS_OK;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (num_rparam == 2) {
+ state->enc_ctx_id = SVAL(rparam, 0);
+ }
+ TALLOC_FREE(rparam);
+
+ state->out = data_blob_const(rdata, num_rdata);
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_smb1_setup_encryption_blob_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out,
+ uint16_t *enc_ctx_id)
+{
+ struct cli_smb1_setup_encryption_blob_state *state =
+ tevent_req_data(req,
+ struct cli_smb1_setup_encryption_blob_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ status = state->status;
+
+ *out = state->out;
+ talloc_steal(mem_ctx, out->data);
+
+ *enc_ctx_id = state->enc_ctx_id;
+
+ tevent_req_received(req);
+ return status;
+}
+
+struct cli_smb1_setup_encryption_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ struct smb_trans_enc_state *es;
+ DATA_BLOB blob_in;
+ DATA_BLOB blob_out;
+ bool local_ready;
+ bool remote_ready;
+};
+
+static void cli_smb1_setup_encryption_local_next(struct tevent_req *req);
+static void cli_smb1_setup_encryption_local_done(struct tevent_req *subreq);
+static void cli_smb1_setup_encryption_remote_next(struct tevent_req *req);
+static void cli_smb1_setup_encryption_remote_done(struct tevent_req *subreq);
+static void cli_smb1_setup_encryption_ready(struct tevent_req *req);
+
+static struct tevent_req *cli_smb1_setup_encryption_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ struct cli_credentials *creds)
+{
+ struct tevent_req *req = NULL;
+ struct cli_smb1_setup_encryption_state *state = NULL;
+ struct auth_generic_state *ags = NULL;
+ const DATA_BLOB *b = NULL;
+ bool auth_requested = false;
+ const char *target_service = NULL;
+ const char *target_hostname = NULL;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_smb1_setup_encryption_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->cli = cli;
+
+ auth_requested = cli_credentials_authentication_requested(creds);
+ if (!auth_requested) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ target_service = "cifs";
+ target_hostname = smbXcli_conn_remote_name(cli->conn);
+
+ status = cli_session_creds_prepare_krb5(cli, creds);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->es = talloc_zero(state, struct smb_trans_enc_state);
+ if (tevent_req_nomem(state->es, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = auth_generic_client_prepare(state->es, &ags);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ gensec_want_feature(ags->gensec_security,
+ GENSEC_FEATURE_SIGN);
+ gensec_want_feature(ags->gensec_security,
+ GENSEC_FEATURE_SEAL);
+
+ status = auth_generic_set_creds(ags, creds);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (target_service != NULL) {
+ status = gensec_set_target_service(ags->gensec_security,
+ target_service);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ if (target_hostname != NULL) {
+ status = gensec_set_target_hostname(ags->gensec_security,
+ target_hostname);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ gensec_set_max_update_size(ags->gensec_security,
+ CLI_BUFFER_SIZE);
+
+ b = smbXcli_conn_server_gss_blob(state->cli->conn);
+ if (b != NULL) {
+ state->blob_in = *b;
+ }
+
+ status = auth_generic_client_start(ags, GENSEC_OID_SPNEGO);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * We only need the gensec_security part from here.
+ */
+ state->es->gensec_security = talloc_move(state->es,
+ &ags->gensec_security);
+ TALLOC_FREE(ags);
+
+ cli_smb1_setup_encryption_local_next(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void cli_smb1_setup_encryption_local_next(struct tevent_req *req)
+{
+ struct cli_smb1_setup_encryption_state *state =
+ tevent_req_data(req,
+ struct cli_smb1_setup_encryption_state);
+ struct tevent_req *subreq = NULL;
+
+ if (state->local_ready) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ subreq = gensec_update_send(state, state->ev,
+ state->es->gensec_security,
+ state->blob_in);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_smb1_setup_encryption_local_done, req);
+}
+
+static void cli_smb1_setup_encryption_local_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cli_smb1_setup_encryption_state *state =
+ tevent_req_data(req,
+ struct cli_smb1_setup_encryption_state);
+ NTSTATUS status;
+
+ status = gensec_update_recv(subreq, state, &state->blob_out);
+ TALLOC_FREE(subreq);
+ state->blob_in = data_blob_null;
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
+ {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ state->local_ready = true;
+ }
+
+ /*
+ * We always get NT_STATUS_OK from the server even if it is not ready.
+ * So guess the server is ready when we are ready and already sent
+ * our last blob to the server.
+ */
+ if (state->local_ready && state->blob_out.length == 0) {
+ state->remote_ready = true;
+ }
+
+ if (state->local_ready && state->remote_ready) {
+ cli_smb1_setup_encryption_ready(req);
+ return;
+ }
+
+ cli_smb1_setup_encryption_remote_next(req);
+}
+
+static void cli_smb1_setup_encryption_remote_next(struct tevent_req *req)
+{
+ struct cli_smb1_setup_encryption_state *state =
+ tevent_req_data(req,
+ struct cli_smb1_setup_encryption_state);
+ struct tevent_req *subreq = NULL;
+
+ if (state->remote_ready) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ subreq = cli_smb1_setup_encryption_blob_send(state, state->ev,
+ state->cli, state->blob_out);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ cli_smb1_setup_encryption_remote_done,
+ req);
+}
+
+static void cli_smb1_setup_encryption_remote_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cli_smb1_setup_encryption_state *state =
+ tevent_req_data(req,
+ struct cli_smb1_setup_encryption_state);
+ NTSTATUS status;
+
+ status = cli_smb1_setup_encryption_blob_recv(subreq, state,
+ &state->blob_in,
+ &state->es->enc_ctx_num);
+ TALLOC_FREE(subreq);
+ data_blob_free(&state->blob_out);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
+ {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ /*
+ * We always get NT_STATUS_OK even if the server is not ready.
+ * So guess the server is ready when we are ready and sent
+ * our last blob to the server.
+ */
+ if (state->local_ready) {
+ state->remote_ready = true;
+ }
+
+ if (state->local_ready && state->remote_ready) {
+ cli_smb1_setup_encryption_ready(req);
+ return;
+ }
+
+ cli_smb1_setup_encryption_local_next(req);
+}
+
+static void cli_smb1_setup_encryption_ready(struct tevent_req *req)
+{
+ struct cli_smb1_setup_encryption_state *state =
+ tevent_req_data(req,
+ struct cli_smb1_setup_encryption_state);
+ struct smb_trans_enc_state *es = NULL;
+
+ if (state->blob_in.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (state->blob_out.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ es = talloc_move(state->cli->conn, &state->es);
+ es->enc_on = true;
+ smb1cli_conn_set_encryption(state->cli->conn, es);
+ es = NULL;
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_smb1_setup_encryption_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_smb1_setup_encryption(struct cli_state *cli,
+ struct cli_credentials *creds)
+{
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_smb1_setup_encryption_send(ev, ev, cli, creds);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_smb1_setup_encryption_recv(req);
+ fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+
/**
establishes a connection right up to doing tconX, password specified.
@param output_cli A fully initialised cli structure, non-null only on success
req, struct cli_full_connection_creds_state);
struct tevent_req *subreq = NULL;
const char *password = NULL;
- int pw_len = 0;
if (state->service == NULL) {
tevent_req_done(req);
}
password = cli_credentials_get_password(state->creds);
- if (password == NULL) {
- password = "";
- pw_len = 0;
- } else {
- pw_len = strlen(password) + 1;
- }
subreq = cli_tree_connect_send(state, state->ev,
state->cli,
state->service,
state->service_type,
- password, pw_len);
+ password);
if (tevent_req_nomem(subreq, req)) {
return;
}
return tevent_req_post(req, ev);
}
+ TALLOC_FREE(cli->smb1.tcon);
+ cli->smb1.tcon = smbXcli_tcon_create(cli);
+ if (tevent_req_nomem(cli->smb1.tcon, req)) {
+ return tevent_req_post(req, ev);
+ }
+ smb1cli_tcon_set_id(cli->smb1.tcon, UINT16_MAX);
+
bytes = talloc_array(state, uint8_t, 0);
bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
}
+ flags |= CLI_FULL_CONNECTION_FORCE_SMB1;
+
nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
get_cmdline_auth_info_username(user_info),
lp_workgroup(),