#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"
#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 char *cli_session_setup_get_account(TALLOC_CTX *mem_ctx,
+ const char *principal);
+
+struct cli_credentials *cli_session_creds_init(TALLOC_CTX *mem_ctx,
+ const char *username,
+ const char *domain,
+ const char *realm,
+ const char *password,
+ bool use_kerberos,
+ bool fallback_after_kerberos,
+ bool use_ccache,
+ bool password_is_nt_hash)
+{
+ struct loadparm_context *lp_ctx = NULL;
+ struct cli_credentials *creds = NULL;
+ const char *principal = NULL;
+ char *tmp = NULL;
+ char *p = NULL;
+ bool ok;
-static NTSTATUS smb_bytes_talloc_string(TALLOC_CTX *mem_ctx,
- const uint8_t *hdr,
- char **dest,
- uint8_t *src,
- size_t srclen,
- ssize_t *destlen)
-{
- *destlen = clistr_pull_talloc(mem_ctx,
- (const char *)hdr,
- SVAL(hdr, HDR_FLG2),
- dest,
- (char *)src,
- srclen,
- STR_TERMINATE);
- if (*destlen == -1) {
- return NT_STATUS_NO_MEMORY;
+ creds = cli_credentials_init(mem_ctx);
+ if (creds == NULL) {
+ return NULL;
}
- if (*dest == NULL) {
- *dest = talloc_strdup(mem_ctx, "");
- if (*dest == NULL) {
- return NT_STATUS_NO_MEMORY;
+ lp_ctx = loadparm_init_s3(creds, loadparm_s3_helpers());
+ if (lp_ctx == NULL) {
+ goto fail;
+ }
+ cli_credentials_set_conf(creds, lp_ctx);
+
+ if (username == NULL) {
+ username = "";
+ }
+
+ if (strlen(username) == 0) {
+ if (password != NULL && strlen(password) == 0) {
+ /*
+ * some callers pass "" as no password
+ *
+ * gensec only handles NULL as no password.
+ */
+ password = NULL;
+ }
+ if (password == NULL) {
+ cli_credentials_set_anonymous(creds);
+ return creds;
}
}
- return NT_STATUS_OK;
-}
-/****************************************************************************
- Do an old lanman2 style session setup.
-****************************************************************************/
+ tmp = talloc_strdup(creds, username);
+ if (tmp == NULL) {
+ goto fail;
+ }
+ username = tmp;
-struct cli_session_setup_lanman2_state {
- struct cli_state *cli;
- uint16_t vwv[10];
- const char *user;
-};
+ /* allow for workgroups as part of the username */
+ if ((p = strchr_m(tmp, '\\')) ||
+ (p = strchr_m(tmp, '/')) ||
+ (p = strchr_m(tmp, *lp_winbind_separator()))) {
+ *p = 0;
+ username = p + 1;
+ domain = tmp;
+ }
-static void cli_session_setup_lanman2_done(struct tevent_req *subreq);
+ principal = username;
+ username = cli_session_setup_get_account(creds, principal);
+ if (username == NULL) {
+ goto fail;
+ }
+ ok = strequal(username, principal);
+ if (ok) {
+ /*
+ * Ok still the same, so it's not a principal
+ */
+ principal = NULL;
+ }
-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)
-{
- struct tevent_req *req, *subreq;
- struct cli_session_setup_lanman2_state *state;
- DATA_BLOB lm_response = data_blob_null;
- uint16_t *vwv;
- uint8_t *bytes;
- char *tmp;
- uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
+ if (use_kerberos && fallback_after_kerberos) {
+ cli_credentials_set_kerberos_state(creds,
+ CRED_AUTO_USE_KERBEROS);
+ } else if (use_kerberos) {
+ cli_credentials_set_kerberos_state(creds,
+ CRED_MUST_USE_KERBEROS);
+ } else {
+ cli_credentials_set_kerberos_state(creds,
+ CRED_DONT_USE_KERBEROS);
+ }
- req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_lanman2_state);
- if (req == NULL) {
- return NULL;
+ if (use_ccache) {
+ uint32_t features;
+
+ features = cli_credentials_get_gensec_features(creds);
+ features |= GENSEC_FEATURE_NTLM_CCACHE;
+ cli_credentials_set_gensec_features(creds, features);
+
+ if (password != NULL && strlen(password) == 0) {
+ /*
+ * some callers pass "" as no password
+ *
+ * GENSEC_FEATURE_NTLM_CCACHE only handles
+ * NULL as no password.
+ */
+ password = NULL;
+ }
}
- state->cli = cli;
- state->user = user;
- vwv = state->vwv;
- /*
- * if in share level security then don't send a password now
- */
- if (!(sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
- passlen = 0;
+ ok = cli_credentials_set_username(creds,
+ username,
+ CRED_SPECIFIED);
+ if (!ok) {
+ goto fail;
}
- if (passlen > 0
- && (sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)
- && passlen != 24) {
- /*
- * Encrypted mode needed, and non encrypted password
- * supplied.
- */
- lm_response = data_blob(NULL, 24);
- if (tevent_req_nomem(lm_response.data, req)) {
- return tevent_req_post(req, ev);
+ if (domain != NULL) {
+ ok = cli_credentials_set_domain(creds,
+ domain,
+ CRED_SPECIFIED);
+ if (!ok) {
+ goto fail;
}
+ }
- if (!SMBencrypt(pass, smb1cli_conn_server_challenge(cli->conn),
- (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);
+ if (principal != NULL) {
+ ok = cli_credentials_set_principal(creds,
+ principal,
+ CRED_SPECIFIED);
+ if (!ok) {
+ goto fail;
}
- } else if ((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);
+ }
+
+ if (realm != NULL) {
+ ok = cli_credentials_set_realm(creds,
+ realm,
+ CRED_SPECIFIED);
+ if (!ok) {
+ goto fail;
}
- } else if (passlen > 0) {
- 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, smbXcli_conn_use_unicode(cli->conn), pass, passlen+1,
- &converted_size);
- if (tevent_req_nomem(buf, req)) {
- return tevent_req_post(req, ev);
+ }
+
+ if (password != NULL && strlen(password) > 0) {
+ if (password_is_nt_hash) {
+ struct samr_Password nt_hash;
+ size_t converted;
+
+ converted = strhex_to_str((char *)nt_hash.hash,
+ sizeof(nt_hash.hash),
+ password,
+ strlen(password));
+ if (converted != sizeof(nt_hash.hash)) {
+ goto fail;
+ }
+
+ ok = cli_credentials_set_nt_hash(creds,
+ &nt_hash,
+ CRED_SPECIFIED);
+ if (!ok) {
+ goto fail;
+ }
+ } else {
+ ok = cli_credentials_set_password(creds,
+ password,
+ CRED_SPECIFIED);
+ if (!ok) {
+ goto fail;
+ }
}
- lm_response = data_blob(pass, passlen);
- TALLOC_FREE(buf);
- if (tevent_req_nomem(lm_response.data, req)) {
- return tevent_req_post(req, ev);
+ }
+
+ return creds;
+fail:
+ TALLOC_FREE(creds);
+ 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;
+ char *canon_principal = NULL;
+ char *canon_realm = NULL;
+ const char *target_hostname = NULL;
+ enum credentials_use_kerberos krb5_state;
+ bool try_kerberos = false;
+ bool need_kinit = false;
+ bool auth_requested = true;
+ int ret;
+ bool ok;
+
+ target_hostname = smbXcli_conn_remote_name(cli->conn);
+
+ 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);
- 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, smb1cli_conn_server_session_key(cli->conn));
- SSVAL(vwv+7, 0, lm_response.length);
+ krb5_state = cli_credentials_get_kerberos_state(creds);
- bytes = talloc_array(state, uint8_t, lm_response.length);
- if (tevent_req_nomem(bytes, req)) {
- return tevent_req_post(req, ev);
+ if (krb5_state != CRED_DONT_USE_KERBEROS) {
+ try_kerberos = true;
}
- if (lm_response.length != 0) {
- memcpy(bytes, lm_response.data, lm_response.length);
+
+ if (user_principal == NULL) {
+ try_kerberos = false;
}
- data_blob_free(&lm_response);
- tmp = talloc_strdup_upper(talloc_tos(), user);
- if (tevent_req_nomem(tmp, req)) {
- return tevent_req_post(req, ev);
+ 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;
}
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
- NULL);
- TALLOC_FREE(tmp);
- tmp = talloc_strdup_upper(talloc_tos(), workgroup);
- if (tevent_req_nomem(tmp, req)) {
- return tevent_req_post(req, ev);
+ 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;
}
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
- NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
- if (tevent_req_nomem(bytes, req)) {
- 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 {
+ need_kinit = try_kerberos;
}
- 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);
+ if (!need_kinit) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
}
- tevent_req_set_callback(subreq, cli_session_setup_lanman2_done, req);
- return req;
-}
-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;
- uint8_t *inhdr;
- uint8_t *bytes;
- uint8_t *p;
- NTSTATUS status;
- ssize_t ret;
- uint8_t wct;
- uint16_t *vwv;
+ DBG_INFO("Doing kinit for %s to access %s\n",
+ user_principal, target_hostname);
- 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;
- }
+ /*
+ * TODO: This should be done within the gensec layer
+ * only if required!
+ */
+ setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
+ ret = kerberos_kinit_password_ext(user_principal,
+ pass,
+ 0,
+ 0,
+ 0,
+ NULL,
+ false,
+ false,
+ 0,
+ frame,
+ &canon_principal,
+ &canon_realm,
+ NULL);
+ if (ret != 0) {
+ int dbglvl = DBGLVL_NOTICE;
+
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ dbglvl = DBGLVL_ERR;
+ }
- inhdr = in + NBT_HDR_SIZE;
- p = bytes;
+ 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);
+ }
- cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
+ /*
+ * Ignore the error and hope that NTLM will work
+ */
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_os,
- p,
- bytes+num_bytes-p,
- &ret);
+ ok = cli_credentials_set_principal(creds,
+ canon_principal,
+ CRED_SPECIFIED);
+ if (!ok) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
+ ok = cli_credentials_set_realm(creds,
+ canon_realm,
+ CRED_SPECIFIED);
+ if (!ok) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
}
- p += ret;
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_type,
- p,
- bytes+num_bytes-p,
- &ret);
+ DBG_DEBUG("Successfully authenticated as %s (%s) to access %s using "
+ "Kerberos\n",
+ user_principal,
+ canon_principal,
+ target_hostname);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
+ 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;
+ }
}
- p += ret;
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &cli->server_domain,
- p,
- bytes+num_bytes-p,
- &ret);
+ 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 (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
+ 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;
+ }
}
- p += ret;
- tevent_req_done(req);
+#undef _VALID_STRING
+ return NT_STATUS_OK;
}
-static NTSTATUS cli_session_setup_lanman2_recv(struct tevent_req *req)
+/********************************************************
+ 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(TALLOC_CTX *mem_ctx,
+ const uint8_t *hdr,
+ char **dest,
+ uint8_t *src,
+ size_t srclen,
+ ssize_t *destlen)
{
- return tevent_req_simple_recv_ntstatus(req);
+ *destlen = clistr_pull_talloc(mem_ctx,
+ (const char *)hdr,
+ SVAL(hdr, HDR_FLG2),
+ dest,
+ (char *)src,
+ srclen,
+ STR_TERMINATE);
+ if (*destlen == -1) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (*dest == NULL) {
+ *dest = talloc_strdup(mem_ctx, "");
+ if (*dest == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ return NT_STATUS_OK;
}
/****************************************************************************
bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, /* username */
NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, /* workgroup */
- NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
-
- if (bytes == NULL) {
- TALLOC_FREE(req);
- return NULL;
- }
-
- state->bytes.iov_base = (void *)bytes;
- state->bytes.iov_len = talloc_get_size(bytes);
-
- subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
- 1, &state->bytes);
- if (subreq == NULL) {
- TALLOC_FREE(req);
- return NULL;
- }
- tevent_req_set_callback(subreq, cli_session_setup_guest_done, req);
- *psmbreq = subreq;
- return req;
-}
-
-struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct cli_state *cli)
-{
- struct tevent_req *req, *subreq;
- NTSTATUS status;
-
- req = cli_session_setup_guest_create(mem_ctx, ev, cli, &subreq);
- if (req == NULL) {
- return NULL;
- }
-
- status = smb1cli_req_chain_submit(&subreq, 1);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return tevent_req_post(req, ev);
- }
- return req;
-}
-
-static void cli_session_setup_guest_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cli_session_setup_guest_state *state = tevent_req_data(
- req, struct cli_session_setup_guest_state);
- struct cli_state *cli = state->cli;
- uint32_t num_bytes;
- uint8_t *in;
- uint8_t *inhdr;
- 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;
- }
-
- inhdr = in + NBT_HDR_SIZE;
- p = bytes;
-
- cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &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,
- inhdr,
- &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,
- inhdr,
- &cli->server_domain,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- tevent_req_done(req);
-}
-
-NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
-{
- return tevent_req_simple_recv_ntstatus(req);
-}
-
-/****************************************************************************
- Do a NT1 plaintext session setup.
-****************************************************************************/
-
-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)
-{
- 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_state_get_vc_num(cli));
- SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
- 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, 0));
-
- bytes = talloc_array(state, uint8_t, 0);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), pass, strlen(pass)+1,
- &passlen);
- if (tevent_req_nomem(bytes, req)) {
- return tevent_req_post(req, ev);
- }
- SSVAL(vwv + (smbXcli_conn_use_unicode(cli->conn) ? 8 : 7), 0, passlen);
-
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- user, strlen(user)+1, NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- workgroup, strlen(workgroup)+1, NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- "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, smbXcli_conn_use_unicode(cli->conn),
- 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;
- uint8_t *inhdr;
- 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 (tevent_req_nterror(req, status)) {
- return;
- }
-
- inhdr = in + NBT_HDR_SIZE;
- p = bytes;
-
- cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &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,
- inhdr,
- &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,
- inhdr,
- &cli->server_domain,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
- }
- p += ret;
-
- tevent_req_done(req);
-}
-
-static NTSTATUS cli_session_setup_plain_recv(struct tevent_req *req)
-{
- return tevent_req_simple_recv_ntstatus(req);
-}
-
-/****************************************************************************
- do a NT1 NTLM/LM encrypted session setup - for when extended security
- is not negotiated.
- @param cli client state to create do session setup on
- @param user username
- @param pass *either* cleartext password (passlen !=24) or LM response.
- @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
- @param workgroup The user's domain.
-****************************************************************************/
-
-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)
-{
- 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;
- 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 */
- } else if (passlen != 24) {
- if (lp_client_ntlmv2_auth()) {
- DATA_BLOB server_chal;
- DATA_BLOB names_blob;
-
- server_chal =
- data_blob_const(smb1cli_conn_server_challenge(cli->conn),
- 8);
-
- /*
- * note that the 'workgroup' here is a best
- * guess - we don't know the server's domain
- * at this point. Windows clients also don't
- * use hostname...
- */
- names_blob = NTLMv2_generate_names_blob(
- NULL, NULL, 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)) {
- data_blob_free(&names_blob);
- tevent_req_nterror(
- req, NT_STATUS_ACCESS_DENIED);
- return tevent_req_post(req, ev);
- }
- data_blob_free(&names_blob);
-
- } else {
- uchar nt_hash[16];
- E_md4hash(pass, nt_hash);
-
-#ifdef LANMAN_ONLY
- nt_response = data_blob_null;
-#else
- nt_response = data_blob(NULL, 24);
- if (tevent_req_nomem(nt_response.data, req)) {
- return tevent_req_post(req, ev);
- }
-
- SMBNTencrypt(pass, smb1cli_conn_server_challenge(cli->conn),
- nt_response.data);
-#endif
- /* non encrypted password supplied. Ignore ntpass. */
- if (lp_client_lanman_auth()) {
-
- lm_response = data_blob(NULL, 24);
- if (tevent_req_nomem(lm_response.data, req)) {
- return tevent_req_post(req, ev);
- }
-
- if (!SMBencrypt(pass,
- smb1cli_conn_server_challenge(cli->conn),
- 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);
- }
- } else {
- /*
- * 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);
-#else
- SMBsesskeygen_ntv1(nt_hash, session_key.data);
-#endif
- }
- } else {
- /* pre-encrypted password supplied. Only used for
- security=server, can't do
- 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);
- }
- }
-
-#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);
- }
-
- 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_state_get_vc_num(cli));
- SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
- 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, 0));
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, /* workgroup */
+ NULL);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
- 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 (lm_response.length != 0) {
- memcpy(bytes, lm_response.data, lm_response.length);
- }
- if (nt_response.length != 0) {
- memcpy(bytes + lm_response.length,
- nt_response.data, nt_response.length);
+ if (bytes == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
}
- data_blob_free(&lm_response);
- data_blob_free(&nt_response);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- user, strlen(user)+1, NULL);
+ state->bytes.iov_base = (void *)bytes;
+ state->bytes.iov_len = talloc_get_size(bytes);
- /*
- * 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);
+ subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 0, 13,
+ vwv, 1, &state->bytes);
+ if (subreq == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
}
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
- workgroup_upper, strlen(workgroup_upper)+1,
- NULL);
- TALLOC_FREE(workgroup_upper);
+ tevent_req_set_callback(subreq, cli_session_setup_guest_done, req);
+ *psmbreq = subreq;
+ return req;
+}
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
- bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
- if (tevent_req_nomem(bytes, req)) {
- return tevent_req_post(req, ev);
+struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli)
+{
+ struct tevent_req *req, *subreq;
+ NTSTATUS status;
+
+ req = cli_session_setup_guest_create(mem_ctx, ev, cli, &subreq);
+ if (req == NULL) {
+ return NULL;
}
- subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
- talloc_get_size(bytes), bytes);
- if (tevent_req_nomem(subreq, req)) {
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_session_setup_nt1_done, req);
return req;
}
-static void cli_session_setup_nt1_done(struct tevent_req *subreq)
+static void cli_session_setup_guest_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
- struct cli_session_setup_nt1_state *state = tevent_req_data(
- req, struct cli_session_setup_nt1_state);
+ struct cli_session_setup_guest_state *state = tevent_req_data(
+ req, struct cli_session_setup_guest_state);
struct cli_state *cli = state->cli;
uint32_t num_bytes;
uint8_t *in;
p = bytes;
cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
+ smb1cli_session_set_action(cli->smb1.session, SVAL(vwv+2, 0));
status = smb_bytes_talloc_string(cli,
inhdr,
p,
bytes+num_bytes-p,
&ret);
+
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return;
p,
bytes+num_bytes-p,
&ret);
+
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return;
p,
bytes+num_bytes-p,
&ret);
+
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return;
}
- p += ret;
-
- if (smb1cli_conn_activate_signing(cli->conn, state->session_key, state->response)
- && !smb1cli_conn_check_signing(cli->conn, (uint8_t *)in, 1)) {
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
- }
- if (state->session_key.data) {
- struct smbXcli_session *session = state->cli->smb1.session;
- status = smb1cli_session_set_session_key(session,
- state->session_key);
- if (tevent_req_nterror(req, status)) {
- return;
- }
- }
tevent_req_done(req);
}
-static NTSTATUS cli_session_setup_nt1_recv(struct tevent_req *req)
+NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
{
return tevent_req_simple_recv_ntstatus(req);
}
struct cli_state *cli;
DATA_BLOB blob;
uint16_t max_blob_size;
- uint16_t vwv[12];
- uint8_t *buf;
- DATA_BLOB smb2_blob;
+ DATA_BLOB this_blob;
struct iovec *recv_iov;
NTSTATUS status;
- uint8_t *inbuf;
+ const uint8_t *inbuf;
DATA_BLOB ret_blob;
+
+ char *out_native_os;
+ char *out_native_lm;
};
static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
thistime = MIN(state->blob.length, state->max_blob_size);
- if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
-
- state->smb2_blob.data = state->blob.data;
- state->smb2_blob.length = thistime;
+ state->this_blob.data = state->blob.data;
+ state->this_blob.length = thistime;
- state->blob.data += thistime;
- state->blob.length -= thistime;
+ state->blob.data += thistime;
+ state->blob.length -= thistime;
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
subreq = smb2cli_session_setup_send(state, state->ev,
state->cli->conn,
state->cli->timeout,
SMB2_CAP_DFS, /* in_capabilities */
0, /* in_channel */
0, /* in_previous_session_id */
- &state->smb2_blob);
+ &state->this_blob);
if (subreq == NULL) {
return false;
}
- *psubreq = subreq;
- return true;
- }
-
- SCVAL(state->vwv+0, 0, 0xFF);
- SCVAL(state->vwv+0, 1, 0);
- SSVAL(state->vwv+1, 0, 0);
- SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE);
- SSVAL(state->vwv+3, 0, 2);
- SSVAL(state->vwv+4, 0, 1);
- SIVAL(state->vwv+5, 0, 0);
-
- SSVAL(state->vwv+7, 0, thistime);
-
- SSVAL(state->vwv+8, 0, 0);
- SSVAL(state->vwv+9, 0, 0);
- SIVAL(state->vwv+10, 0,
- cli_session_setup_capabilities(state->cli, CAP_EXTENDED_SECURITY));
-
- state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
- thistime);
- if (state->buf == NULL) {
- return false;
- }
- state->blob.data += thistime;
- state->blob.length -= thistime;
+ } else {
+ uint16_t in_buf_size = 0;
+ uint16_t in_mpx_max = 0;
+ uint16_t in_vc_num = 0;
+ uint32_t in_sess_key = 0;
+ uint32_t in_capabilities = 0;
+ const char *in_native_os = NULL;
+ const char *in_native_lm = NULL;
+
+ in_buf_size = CLI_BUFFER_SIZE;
+ in_mpx_max = smbXcli_conn_max_requests(state->cli->conn);
+ in_vc_num = cli_state_get_vc_num(state->cli);
+ in_sess_key = smb1cli_conn_server_session_key(state->cli->conn);
+ in_capabilities = cli_session_setup_capabilities(state->cli,
+ CAP_EXTENDED_SECURITY);
+ in_native_os = "Unix";
+ in_native_lm = "Samba";
- state->buf = smb_bytes_push_str(state->buf, smbXcli_conn_use_unicode(state->cli->conn),
- "Unix", 5, NULL);
- state->buf = smb_bytes_push_str(state->buf, smbXcli_conn_use_unicode(state->cli->conn),
- "Samba", 6, NULL);
- if (state->buf == NULL) {
- return false;
- }
- subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
- 12, state->vwv,
- talloc_get_size(state->buf), state->buf);
- if (subreq == NULL) {
- return false;
+ /*
+ * For now we keep the same values as before,
+ * we may remove these in a separate commit later.
+ */
+ in_mpx_max = 2;
+ in_vc_num = 1;
+ in_sess_key = 0;
+
+ subreq = smb1cli_session_setup_ext_send(state, state->ev,
+ state->cli->conn,
+ state->cli->timeout,
+ state->cli->smb1.pid,
+ state->cli->smb1.session,
+ in_buf_size,
+ in_mpx_max,
+ in_vc_num,
+ in_sess_key,
+ state->this_blob,
+ in_capabilities,
+ in_native_os,
+ in_native_lm);
+ if (subreq == NULL) {
+ return false;
+ }
}
*psubreq = subreq;
return true;
subreq, struct tevent_req);
struct cli_sesssetup_blob_state *state = tevent_req_data(
req, struct cli_sesssetup_blob_state);
- struct cli_state *cli = state->cli;
- uint8_t wct;
- uint16_t *vwv;
- uint32_t num_bytes;
- uint8_t *bytes;
NTSTATUS status;
- uint8_t *p;
- uint16_t blob_length;
- uint8_t *in;
- uint8_t *inhdr;
- ssize_t ret;
if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
status = smb2cli_session_setup_recv(subreq, state,
&state->recv_iov,
&state->ret_blob);
} else {
- status = cli_smb_recv(subreq, state, &in, 4, &wct, &vwv,
- &num_bytes, &bytes);
- TALLOC_FREE(state->buf);
+ status = smb1cli_session_setup_ext_recv(subreq, state,
+ &state->recv_iov,
+ &state->inbuf,
+ &state->ret_blob,
+ &state->out_native_os,
+ &state->out_native_lm);
}
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)
state->status = status;
- if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
- goto next;
- }
-
- state->inbuf = in;
- inhdr = in + NBT_HDR_SIZE;
- cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
-
- blob_length = SVAL(vwv+3, 0);
- if (blob_length > num_bytes) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
- state->ret_blob = data_blob_const(bytes, blob_length);
-
- p = bytes + blob_length;
-
- status = smb_bytes_talloc_string(cli,
- inhdr,
- &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,
- inhdr,
- &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,
- inhdr,
- &cli->server_domain,
- p,
- bytes+num_bytes-p,
- &ret);
-
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, 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;
}
- p += ret;
-next:
if (state->blob.length != 0) {
/*
* More to send
static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
DATA_BLOB *pblob,
- uint8_t **pinbuf,
+ const uint8_t **pinbuf,
struct iovec **precv_iov)
{
struct cli_sesssetup_blob_state *state = tevent_req_data(
req, struct cli_sesssetup_blob_state);
NTSTATUS status;
- uint8_t *inbuf;
struct iovec *recv_iov;
if (tevent_req_is_nterror(req, &status)) {
TALLOC_FREE(state->cli->smb2.session);
cli_state_set_uid(state->cli, UID_FIELD_INVALID);
+ tevent_req_received(req);
return status;
}
- inbuf = talloc_move(mem_ctx, &state->inbuf);
recv_iov = talloc_move(mem_ctx, &state->recv_iov);
if (pblob != NULL) {
*pblob = state->ret_blob;
}
if (pinbuf != NULL) {
- *pinbuf = inbuf;
+ *pinbuf = state->inbuf;
}
if (precv_iov != NULL) {
*precv_iov = recv_iov;
}
/* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
- return state->status;
-}
-
-#ifdef HAVE_KRB5
-
-/****************************************************************************
- Use in-memory credentials cache
-****************************************************************************/
-
-static void use_in_memory_ccache(void) {
- setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
+ status = state->status;
+ tevent_req_received(req);
+ return status;
}
-#endif /* HAVE_KRB5 */
-
/****************************************************************************
Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
struct auth_generic_state *auth_generic;
bool is_anonymous;
DATA_BLOB blob_in;
- uint8_t *inbuf;
+ const uint8_t *inbuf;
struct iovec *recv_iov;
DATA_BLOB blob_out;
bool local_ready;
static struct tevent_req *cli_session_setup_gensec_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
- const char *user, const char *pass, const char *domain,
- enum credentials_use_kerberos krb5_state,
+ struct cli_credentials *creds,
const char *target_service,
- const char *target_hostname,
- const char *target_principal)
+ const char *target_hostname)
{
struct tevent_req *req;
struct cli_session_setup_gensec_state *state;
NTSTATUS status;
- bool use_spnego_principal = lp_client_use_spnego_principal();
+ const DATA_BLOB *b = NULL;
req = tevent_req_create(mem_ctx, &state,
struct cli_session_setup_gensec_state);
return tevent_req_post(req, ev);
}
- gensec_want_feature(state->auth_generic->gensec_security,
- GENSEC_FEATURE_SESSION_KEY);
- if (cli->use_ccache) {
- gensec_want_feature(state->auth_generic->gensec_security,
- GENSEC_FEATURE_NTLM_CCACHE);
- if (pass != NULL && strlen(pass) == 0) {
- /*
- * some callers pass "" as no password
- *
- * GENSEC_FEATURE_NTLM_CCACHE only handles
- * NULL as no password.
- */
- pass = NULL;
- }
- }
-
- status = auth_generic_set_username(state->auth_generic, user);
- if (tevent_req_nterror(req, status)) {
- return tevent_req_post(req, ev);
- }
-
- status = auth_generic_set_domain(state->auth_generic, domain);
+ status = auth_generic_set_creds(state->auth_generic, creds);
if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}
- if (cli->pw_nt_hash) {
- struct samr_Password nt_hash;
- size_t converted;
- bool ok;
-
- if (pass == NULL) {
- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
- return tevent_req_post(req, ev);
- }
-
- converted = strhex_to_str((char *)nt_hash.hash,
- sizeof(nt_hash.hash),
- pass, strlen(pass));
- if (converted != sizeof(nt_hash.hash)) {
- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
- return tevent_req_post(req, ev);
- }
-
- ok = cli_credentials_set_nt_hash(state->auth_generic->credentials,
- &nt_hash, CRED_SPECIFIED);
- if (!ok) {
- tevent_req_oom(req);
- return tevent_req_post(req, ev);
- }
- } else {
- status = auth_generic_set_password(state->auth_generic, pass);
- if (tevent_req_nterror(req, status)) {
- return tevent_req_post(req, ev);
- }
- }
-
- cli_credentials_set_kerberos_state(state->auth_generic->credentials,
- krb5_state);
-
- if (krb5_state == CRED_DONT_USE_KERBEROS) {
- use_spnego_principal = false;
- }
+ gensec_want_feature(state->auth_generic->gensec_security,
+ GENSEC_FEATURE_SESSION_KEY);
if (target_service != NULL) {
status = gensec_set_target_service(
}
}
- if (target_principal != NULL) {
- status = gensec_set_target_principal(
- state->auth_generic->gensec_security,
- target_principal);
- if (tevent_req_nterror(req, status)) {
- return tevent_req_post(req, ev);
- }
- use_spnego_principal = false;
- } else if (target_service != NULL && target_hostname != NULL) {
- use_spnego_principal = false;
- }
-
- if (use_spnego_principal) {
- const DATA_BLOB *b;
- b = smbXcli_conn_server_gss_blob(cli->conn);
- if (b != NULL) {
- state->blob_in = *b;
- }
+ b = smbXcli_conn_server_gss_blob(cli->conn);
+ if (b != NULL) {
+ state->blob_in = *b;
}
state->is_anonymous = cli_credentials_is_anonymous(state->auth_generic->credentials);
struct cli_session_setup_gensec_state);
NTSTATUS status;
- TALLOC_FREE(state->inbuf);
+ state->inbuf = NULL;
TALLOC_FREE(state->recv_iov);
status = cli_sesssetup_blob_recv(subreq, state, &state->blob_in,
}
if (NT_STATUS_IS_OK(status)) {
+ struct smbXcli_session *session = NULL;
+ bool is_guest = false;
+
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ session = state->cli->smb2.session;
+ } else {
+ session = state->cli->smb1.session;
+ }
+
+ is_guest = smbXcli_session_is_guest(session);
+ if (is_guest) {
+ /*
+ * We can't finish the gensec handshake, we don't
+ * have a negotiated session key.
+ *
+ * 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;
}
cli_session_setup_gensec_local_next(req);
}
+static void cli_session_dump_keys(TALLOC_CTX *mem_ctx,
+ struct smbXcli_session *session,
+ DATA_BLOB session_key)
+{
+ NTSTATUS status;
+ DATA_BLOB sig = data_blob_null;
+ DATA_BLOB app = data_blob_null;
+ DATA_BLOB enc = data_blob_null;
+ DATA_BLOB dec = data_blob_null;
+ uint64_t sid = smb2cli_session_current_id(session);
+
+ status = smb2cli_session_signing_key(session, mem_ctx, &sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ status = smbXcli_session_application_key(session, mem_ctx, &app);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ status = smb2cli_session_encryption_key(session, mem_ctx, &enc);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ status = smb2cli_session_decryption_key(session, mem_ctx, &dec);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ DEBUG(0, ("debug encryption: dumping generated session keys\n"));
+ DEBUGADD(0, ("Session Id "));
+ dump_data(0, (uint8_t*)&sid, sizeof(sid));
+ DEBUGADD(0, ("Session Key "));
+ dump_data(0, session_key.data, session_key.length);
+ DEBUGADD(0, ("Signing Key "));
+ dump_data(0, sig.data, sig.length);
+ DEBUGADD(0, ("App Key "));
+ dump_data(0, app.data, app.length);
+
+ /* In client code, ServerIn is the encryption key */
+
+ DEBUGADD(0, ("ServerIn Key "));
+ dump_data(0, enc.data, enc.length);
+ DEBUGADD(0, ("ServerOut Key "));
+ dump_data(0, dec.data, dec.length);
+
+out:
+ data_blob_clear_free(&sig);
+ data_blob_clear_free(&app);
+ data_blob_clear_free(&enc);
+ data_blob_clear_free(&dec);
+}
+
static void cli_session_setup_gensec_ready(struct tevent_req *req)
{
struct cli_session_setup_gensec_state *state =
}
}
+ if (state->is_anonymous) {
+ /*
+ * Windows server does not set the
+ * SMB2_SESSION_FLAG_IS_NULL flag.
+ *
+ * This fix makes sure we do not try
+ * to verify a signature on the final
+ * session setup response.
+ */
+ tevent_req_done(req);
+ return;
+ }
+
status = gensec_session_key(state->auth_generic->gensec_security,
state, &state->session_key);
if (tevent_req_nterror(req, status)) {
if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
struct smbXcli_session *session = state->cli->smb2.session;
- if (state->is_anonymous) {
- /*
- * Windows server does not set the
- * SMB2_SESSION_FLAG_IS_GUEST nor
- * SMB2_SESSION_FLAG_IS_NULL flag.
- *
- * This fix makes sure we do not try
- * to verify a signature on the final
- * session setup response.
- */
- tevent_req_done(req);
- return;
- }
-
status = smb2cli_session_set_session_key(session,
state->session_key,
state->recv_iov);
if (tevent_req_nterror(req, status)) {
return;
}
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB3_00
+ && lp_debug_encryption())
+ {
+ cli_session_dump_keys(state, session, state->session_key);
+ }
} else {
struct smbXcli_session *session = state->cli->smb1.session;
bool active;
struct cli_session_setup_gensec_state);
NTSTATUS status;
- if (tevent_req_is_nterror(req, &status)) {
- cli_state_set_uid(state->cli, UID_FIELD_INVALID);
- return status;
- }
- return NT_STATUS_OK;
-}
-
-#ifdef HAVE_KRB5
-
-static char *cli_session_setup_get_principal(
- TALLOC_CTX *mem_ctx, const char *spnego_principal,
- const char *remote_name, const char *dest_realm)
-{
- char *principal = NULL;
-
- if (!lp_client_use_spnego_principal() ||
- strequal(spnego_principal, ADS_IGNORE_PRINCIPAL)) {
- spnego_principal = NULL;
- }
- if (spnego_principal != NULL) {
- DEBUG(3, ("cli_session_setup_spnego: using spnego provided "
- "principal %s\n", spnego_principal));
- return talloc_strdup(mem_ctx, spnego_principal);
- }
- if (is_ipaddress(remote_name) ||
- strequal(remote_name, STAR_SMBSERVER)) {
- return NULL;
- }
-
- DEBUG(3, ("cli_session_setup_spnego: using target "
- "hostname not SPNEGO principal\n"));
-
- if (dest_realm) {
- char *realm = strupper_talloc(talloc_tos(), dest_realm);
- if (realm == NULL) {
- return NULL;
- }
- principal = talloc_asprintf(talloc_tos(), "cifs/%s@%s",
- remote_name, realm);
- TALLOC_FREE(realm);
- } else {
- principal = kerberos_get_principal_from_service_hostname(
- talloc_tos(), "cifs", remote_name, lp_realm());
- }
- DEBUG(3, ("cli_session_setup_spnego: guessed server principal=%s\n",
- principal ? principal : "<null>"));
-
- return principal;
+ if (tevent_req_is_nterror(req, &status)) {
+ cli_state_set_uid(state->cli, UID_FIELD_INVALID);
+ return status;
+ }
+ return NT_STATUS_OK;
}
-#endif
static char *cli_session_setup_get_account(TALLOC_CTX *mem_ctx,
const char *principal)
****************************************************************************/
struct cli_session_setup_spnego_state {
- struct tevent_context *ev;
- struct cli_state *cli;
- const char *target_hostname;
- const char *user;
- const char *account;
- const char *pass;
- const char *user_domain;
- const char *dest_realm;
ADS_STATUS result;
};
-#ifdef HAVE_KRB5
-static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq);
-#endif
-
-static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq);
+static void cli_session_setup_spnego_done(struct tevent_req *subreq);
static struct tevent_req *cli_session_setup_spnego_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
- const char *user, const char *pass, const char *user_domain)
+ struct cli_credentials *creds)
{
struct tevent_req *req, *subreq;
struct cli_session_setup_spnego_state *state;
- char *principal = NULL;
- char *OIDs[ASN1_MAX_OIDS];
- int i;
- const char *dest_realm = cli_state_remote_realm(cli);
- const DATA_BLOB *server_blob;
+ const char *target_service = NULL;
+ const char *target_hostname = NULL;
+ NTSTATUS status;
req = tevent_req_create(mem_ctx, &state,
struct cli_session_setup_spnego_state);
if (req == NULL) {
return NULL;
}
- state->ev = ev;
- state->cli = cli;
- state->user = user;
- state->pass = pass;
- state->user_domain = user_domain;
- state->dest_realm = dest_realm;
-
- state->account = cli_session_setup_get_account(state, user);
- if (tevent_req_nomem(state->account, req)) {
- return tevent_req_post(req, ev);
- }
-
- state->target_hostname = smbXcli_conn_remote_name(cli->conn);
- server_blob = smbXcli_conn_server_gss_blob(cli->conn);
-
- DEBUG(3,("Doing spnego session setup (blob length=%lu)\n",
- (unsigned long)server_blob->length));
-
- /* the server might not even do spnego */
- if (server_blob->length == 0) {
- DEBUG(3,("server didn't supply a full spnego negprot\n"));
- goto ntlmssp;
- }
-#if 0
- file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
-#endif
+ target_service = "cifs";
+ target_hostname = smbXcli_conn_remote_name(cli->conn);
- /* 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);
+ status = cli_session_creds_prepare_krb5(cli, creds);
+ if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}
- /* make sure the server understands kerberos */
- for (i=0;OIDs[i];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]);
- }
-
- DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
-
-#ifdef HAVE_KRB5
- /* If password is set we reauthenticate to kerberos server
- * and do not store results */
-
- if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) {
- char *tmp;
-
- tmp = cli_session_setup_get_principal(
- talloc_tos(), principal, state->target_hostname, dest_realm);
- TALLOC_FREE(principal);
- principal = tmp;
-
- if (pass && *pass) {
- int ret;
-
- use_in_memory_ccache();
- ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
-
- if (ret){
- DEBUG(0, ("Kinit for %s to access %s failed: %s\n", user, principal, error_message(ret)));
- TALLOC_FREE(principal);
- if (cli->fallback_after_kerberos)
- goto ntlmssp;
- state->result = ADS_ERROR_KRB5(ret);
- tevent_req_done(req);
- return tevent_req_post(req, ev);
- }
- }
-
- if (principal) {
- subreq = cli_session_setup_gensec_send(
- state, ev, cli,
- state->account, pass, user_domain,
- CRED_MUST_USE_KERBEROS,
- "cifs", state->target_hostname, principal);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(
- subreq, cli_session_setup_spnego_done_krb,
- req);
- return req;
- }
- }
-#endif
+ DBG_INFO("Connect to %s as %s using SPNEGO\n",
+ target_hostname,
+ cli_credentials_get_principal(creds, talloc_tos()));
-ntlmssp:
- subreq = cli_session_setup_gensec_send(
- state, state->ev, state->cli,
- state->account, state->pass, state->user_domain,
- CRED_DONT_USE_KERBEROS,
- "cifs", state->target_hostname, NULL);
+ subreq = cli_session_setup_gensec_send(state, ev, cli, creds,
+ target_service, target_hostname);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(
- subreq, cli_session_setup_spnego_done_ntlmssp, req);
+ subreq, cli_session_setup_spnego_done, req);
return req;
}
-#ifdef HAVE_KRB5
-static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq)
+static void cli_session_setup_spnego_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
- struct cli_session_setup_spnego_state *state = tevent_req_data(
- req, struct cli_session_setup_spnego_state);
NTSTATUS status;
status = cli_session_setup_gensec_recv(subreq);
TALLOC_FREE(subreq);
- state->result = ADS_ERROR_NT(status);
-
- if (ADS_ERR_OK(state->result) ||
- !state->cli->fallback_after_kerberos) {
- tevent_req_done(req);
- return;
- }
-
- subreq = cli_session_setup_gensec_send(
- state, state->ev, state->cli,
- state->account, state->pass, state->user_domain,
- CRED_DONT_USE_KERBEROS,
- "cifs", state->target_hostname, NULL);
- if (tevent_req_nomem(subreq, req)) {
+ if (tevent_req_nterror(req, status)) {
return;
}
- tevent_req_set_callback(subreq, cli_session_setup_spnego_done_ntlmssp,
- req);
-}
-#endif
-
-static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cli_session_setup_spnego_state *state = tevent_req_data(
- req, struct cli_session_setup_spnego_state);
- NTSTATUS status;
- status = cli_session_setup_gensec_recv(subreq);
- TALLOC_FREE(subreq);
- state->result = ADS_ERROR_NT(status);
tevent_req_done(req);
}
{
struct cli_session_setup_spnego_state *state = tevent_req_data(
req, struct cli_session_setup_spnego_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ state->result = ADS_ERROR_NT(status);
+ }
return state->result;
}
-struct cli_session_setup_state {
- uint8_t dummy;
+struct cli_session_setup_creds_state {
+ struct cli_state *cli;
+ DATA_BLOB apassword_blob;
+ DATA_BLOB upassword_blob;
+ DATA_BLOB lm_session_key;
+ DATA_BLOB session_key;
+ char *out_native_os;
+ char *out_native_lm;
+ char *out_primary_domain;
};
-static void cli_session_setup_done_lanman2(struct tevent_req *subreq);
-static void cli_session_setup_done_spnego(struct tevent_req *subreq);
-static void cli_session_setup_done_guest(struct tevent_req *subreq);
-static void cli_session_setup_done_plain(struct tevent_req *subreq);
-static void cli_session_setup_done_nt1(struct tevent_req *subreq);
+static void cli_session_setup_creds_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct cli_session_setup_creds_state *state = tevent_req_data(
+ req, struct cli_session_setup_creds_state);
+
+ if (req_state != TEVENT_REQ_RECEIVED) {
+ return;
+ }
+
+ /*
+ * We only call data_blob_clear() as
+ * some of the blobs point to the same memory.
+ *
+ * We let the talloc hierarchy free the memory.
+ */
+ data_blob_clear(&state->apassword_blob);
+ data_blob_clear(&state->upassword_blob);
+ data_blob_clear(&state->lm_session_key);
+ data_blob_clear(&state->session_key);
+ ZERO_STRUCTP(state);
+}
+
+static void cli_session_setup_creds_done_spnego(struct tevent_req *subreq);
+static void cli_session_setup_creds_done_nt1(struct tevent_req *subreq);
+static void cli_session_setup_creds_done_lm21(struct tevent_req *subreq);
/****************************************************************************
Send a session setup. The username and workgroup is in UNIX character
password is in plaintext, the same should be done.
****************************************************************************/
-struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct cli_state *cli,
- const char *user,
- const char *pass, int passlen,
- const char *ntpass, int ntpasslen,
- const char *workgroup)
+struct tevent_req *cli_session_setup_creds_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ struct cli_credentials *creds)
{
struct tevent_req *req, *subreq;
- struct cli_session_setup_state *state;
- char *p;
- char *user2;
+ struct cli_session_setup_creds_state *state;
uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
+ bool use_spnego = false;
+ int flags = 0;
+ enum credentials_use_kerberos krb5_state;
+ uint32_t gensec_features;
+ const char *username = "";
+ const char *domain = "";
+ DATA_BLOB target_info = data_blob_null;
+ DATA_BLOB challenge = data_blob_null;
+ uint16_t in_buf_size = 0;
+ uint16_t in_mpx_max = 0;
+ uint16_t in_vc_num = 0;
+ uint32_t in_sess_key = 0;
+ const char *in_native_os = NULL;
+ const char *in_native_lm = NULL;
+ NTSTATUS status;
req = tevent_req_create(mem_ctx, &state,
- struct cli_session_setup_state);
+ struct cli_session_setup_creds_state);
if (req == NULL) {
return NULL;
}
+ state->cli = cli;
- if (user) {
- user2 = talloc_strdup(state, user);
- } else {
- user2 = talloc_strdup(state, "");
- }
- if (user2 == NULL) {
- tevent_req_oom(req);
- return tevent_req_post(req, ev);
- }
+ tevent_req_set_cleanup_fn(req, cli_session_setup_creds_cleanup);
- if (!workgroup) {
- workgroup = "";
- }
+ krb5_state = cli_credentials_get_kerberos_state(creds);
+ gensec_features = cli_credentials_get_gensec_features(creds);
- /* allow for workgroups as part of the username */
- if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
- (p=strchr_m(user2,*lp_winbind_separator()))) {
- *p = 0;
- user = p+1;
- if (!strupper_m(user2)) {
- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return tevent_req_post(req, ev);
- }
- workgroup = user2;
+ switch (krb5_state) {
+ case CRED_MUST_USE_KERBEROS:
+ cli->use_kerberos = true;
+ cli->fallback_after_kerberos = false;
+ break;
+ case CRED_AUTO_USE_KERBEROS:
+ cli->use_kerberos = true;
+ cli->fallback_after_kerberos = true;
+ break;
+ case CRED_DONT_USE_KERBEROS:
+ cli->use_kerberos = false;
+ cli->fallback_after_kerberos = false;
+ break;
}
- if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) {
- tevent_req_done(req);
- return tevent_req_post(req, ev);
+ if (gensec_features & GENSEC_FEATURE_NTLM_CCACHE) {
+ cli->use_ccache = true;
+ } else {
+ cli->use_ccache = false;
}
- /* now work out what sort of session setup we are going to
- do. I have split this into separate functions to make the
- flow a bit easier to understand (tridge) */
-
- /* if its an older server then we have to use the older request format */
-
+ /*
+ * Now work out what sort of session setup we are going to
+ * do. I have split this into separate functions to make the flow a bit
+ * easier to understand (tridge).
+ */
if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_NT1) {
- if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
- DEBUG(1, ("Server requested LM password but 'client lanman auth = no'"
- " or 'client ntlmv2 auth = yes'\n"));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return tevent_req_post(req, ev);
- }
-
- if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
- !lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
- " or 'client ntlmv2 auth = yes'\n"));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return tevent_req_post(req, ev);
- }
-
- subreq = cli_session_setup_lanman2_send(
- state, ev, cli, user, pass, passlen, workgroup);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, cli_session_setup_done_lanman2,
- req);
- return req;
+ use_spnego = false;
+ } else if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ use_spnego = true;
+ } else if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) {
+ /*
+ * if the server supports extended security then use SPNEGO
+ * even for anonymous connections.
+ */
+ use_spnego = true;
+ } else {
+ use_spnego = false;
}
- if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ if (use_spnego) {
subreq = cli_session_setup_spnego_send(
- state, ev, cli, user, pass, workgroup);
+ state, ev, cli, creds);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_session_setup_done_spnego,
+ tevent_req_set_callback(subreq, cli_session_setup_creds_done_spnego,
req);
return req;
}
- /* if no user is supplied then we have to do an anonymous connection.
- passwords are ignored */
-
- if (!user || !*user) {
- subreq = cli_session_setup_guest_send(state, ev, cli);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, cli_session_setup_done_guest,
- req);
- return req;
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) {
+ /*
+ * SessionSetupAndX was introduced by LANMAN 1.0. So we skip
+ * this step against older servers.
+ */
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
}
- /* if the server is share level then send a plaintext null
- password at this point. The password is sent in the tree
- connect */
+ if (cli_credentials_is_anonymous(creds)) {
+ /*
+ * Do an anonymous session setup
+ */
+ goto non_spnego_creds_done;
+ }
if ((sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
- subreq = cli_session_setup_plain_send(
- state, ev, cli, user, "", workgroup);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, cli_session_setup_done_plain,
- req);
- return req;
+ /*
+ * Do an anonymous session setup,
+ * the password is passed via the tree connect.
+ */
+ goto non_spnego_creds_done;
+ }
+
+ cli_credentials_get_ntlm_username_domain(creds, state,
+ &username,
+ &domain);
+ if (tevent_req_nomem(username, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (tevent_req_nomem(domain, req)) {
+ return tevent_req_post(req, ev);
}
- /* if the server doesn't support encryption then we have to use
- plaintext. The second password is ignored */
+ DBG_INFO("Connect to %s as %s using NTLM\n", domain, username);
if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
- if (!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
- " or 'client ntlmv2 auth = yes'\n"));
+ bool use_unicode = smbXcli_conn_use_unicode(cli->conn);
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ const char *pw = cli_credentials_get_password(creds);
+ size_t pw_len = 0;
+
+ if (pw == NULL) {
+ pw = "";
+ }
+ pw_len = strlen(pw) + 1;
+
+ if (!lp_client_plaintext_auth()) {
+ DEBUG(1, ("Server requested PLAINTEXT password but "
+ "'client plaintext auth = no'\n"));
tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
return tevent_req_post(req, ev);
}
- subreq = cli_session_setup_plain_send(
- state, ev, cli, user, pass, workgroup);
- if (tevent_req_nomem(subreq, req)) {
+
+ bytes = talloc_array(state, uint8_t, 0);
+ bytes = trans2_bytes_push_str(bytes, use_unicode,
+ pw, pw_len, &bytes_len);
+ if (tevent_req_nomem(bytes, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_session_setup_done_plain,
- req);
- return req;
+
+ if (use_unicode) {
+ /*
+ * CAP_UNICODE, can only be negotiated by NT1.
+ */
+ state->upassword_blob = data_blob_const(bytes,
+ bytes_len);
+ } else {
+ state->apassword_blob = data_blob_const(bytes,
+ bytes_len);
+ }
+
+ goto non_spnego_creds_done;
}
- /* if the server supports extended security then use SPNEGO */
+ challenge = data_blob_const(smb1cli_conn_server_challenge(cli->conn), 8);
- if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) {
- subreq = cli_session_setup_spnego_send(
- state, ev, cli, user, pass, workgroup);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, cli_session_setup_done_spnego,
- req);
- return req;
- } else {
- /* otherwise do a NT1 style session setup */
+ if (smbXcli_conn_protocol(cli->conn) == PROTOCOL_NT1) {
if (lp_client_ntlmv2_auth() && lp_client_use_spnego()) {
/*
- * Don't send an NTLMv2 response without NTLMSSP
- * if we want to use spnego support
+ * Don't send an NTLMv2 response without NTLMSSP if we
+ * want to use spnego support.
*/
DEBUG(1, ("Server does not support EXTENDED_SECURITY "
- " but 'client use spnego = yes"
- " and 'client ntlmv2 auth = yes'\n"));
+ " but 'client use spnego = yes'"
+ " and 'client ntlmv2 auth = yes' is set\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
+ }
+
+ if (lp_client_ntlmv2_auth()) {
+ flags |= CLI_CRED_NTLMv2_AUTH;
+
+ /*
+ * note that the 'domain' here is a best
+ * guess - we don't know the server's domain
+ * at this point. Windows clients also don't
+ * use hostname...
+ */
+ target_info = NTLMv2_generate_names_blob(state,
+ NULL,
+ domain);
+ if (tevent_req_nomem(target_info.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ } else {
+ flags |= CLI_CRED_NTLM_AUTH;
+ if (lp_client_lanman_auth()) {
+ flags |= CLI_CRED_LANMAN_AUTH;
+ }
+ }
+ } else {
+ if (!lp_client_lanman_auth()) {
+ DEBUG(1, ("Server requested user level LM password but "
+ "'client lanman auth = no' is set.\n"));
tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
return tevent_req_post(req, ev);
}
- subreq = cli_session_setup_nt1_send(
- state, ev, cli, user, pass, passlen, ntpass, ntpasslen,
- workgroup);
+ flags |= CLI_CRED_LANMAN_AUTH;
+ }
+
+ status = cli_credentials_get_ntlm_response(creds, state, &flags,
+ challenge, NULL,
+ target_info,
+ &state->apassword_blob,
+ &state->upassword_blob,
+ &state->lm_session_key,
+ &state->session_key);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+non_spnego_creds_done:
+
+ in_buf_size = CLI_BUFFER_SIZE;
+ in_mpx_max = smbXcli_conn_max_requests(cli->conn);
+ in_vc_num = cli_state_get_vc_num(cli);
+ in_sess_key = smb1cli_conn_server_session_key(cli->conn);
+ in_native_os = "Unix";
+ in_native_lm = "Samba";
+
+ if (smbXcli_conn_protocol(cli->conn) == PROTOCOL_NT1) {
+ uint32_t in_capabilities = 0;
+
+ in_capabilities = cli_session_setup_capabilities(cli, 0);
+
+ /*
+ * For now we keep the same values as before,
+ * we may remove these in a separate commit later.
+ */
+ in_mpx_max = 2;
+
+ subreq = smb1cli_session_setup_nt1_send(state, ev,
+ cli->conn,
+ cli->timeout,
+ cli->smb1.pid,
+ cli->smb1.session,
+ in_buf_size,
+ in_mpx_max,
+ in_vc_num,
+ in_sess_key,
+ username,
+ domain,
+ state->apassword_blob,
+ state->upassword_blob,
+ in_capabilities,
+ in_native_os,
+ in_native_lm);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_session_setup_done_nt1,
+ tevent_req_set_callback(subreq, cli_session_setup_creds_done_nt1,
req);
return req;
}
- tevent_req_done(req);
- return tevent_req_post(req, ev);
-}
-
-static void cli_session_setup_done_lanman2(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- NTSTATUS status;
-
- status = cli_session_setup_lanman2_recv(subreq);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return;
+ /*
+ * For now we keep the same values as before,
+ * we may remove these in a separate commit later.
+ */
+ in_mpx_max = 2;
+ in_vc_num = 1;
+
+ subreq = smb1cli_session_setup_lm21_send(state, ev,
+ cli->conn,
+ cli->timeout,
+ cli->smb1.pid,
+ cli->smb1.session,
+ in_buf_size,
+ in_mpx_max,
+ in_vc_num,
+ in_sess_key,
+ username,
+ domain,
+ state->apassword_blob,
+ in_native_os,
+ in_native_lm);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
- tevent_req_done(req);
+ tevent_req_set_callback(subreq, cli_session_setup_creds_done_lm21,
+ req);
+ return req;
}
-static void cli_session_setup_done_spnego(struct tevent_req *subreq)
+static void cli_session_setup_creds_done_spnego(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
tevent_req_done(req);
}
-static void cli_session_setup_done_guest(struct tevent_req *subreq)
+static void cli_session_setup_creds_done_nt1(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
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 = cli_session_setup_guest_recv(subreq);
+ struct iovec *recv_iov = NULL;
+ const uint8_t *inbuf = NULL;
+ bool ok;
+
+ status = smb1cli_session_setup_nt1_recv(subreq, state,
+ &recv_iov,
+ &inbuf,
+ &state->out_native_os,
+ &state->out_native_lm,
+ &state->out_primary_domain);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("NT1 login failed: %s\n", nt_errstr(status)));
tevent_req_nterror(req, status);
return;
}
- tevent_req_done(req);
-}
-
-static void cli_session_setup_done_plain(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- NTSTATUS status;
- status = cli_session_setup_plain_recv(subreq);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
+ 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,
+ state->session_key,
+ state->upassword_blob);
+ if (ok) {
+ ok = smb1cli_conn_check_signing(cli->conn, inbuf, 1);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ }
+
+ if (state->session_key.data) {
+ struct smbXcli_session *session = cli->smb1.session;
+
+ status = smb1cli_session_set_session_key(session,
+ state->session_key);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
tevent_req_done(req);
}
-static void cli_session_setup_done_nt1(struct tevent_req *subreq)
+static void cli_session_setup_creds_done_lm21(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
+ struct cli_session_setup_creds_state *state = tevent_req_data(
+ req, struct cli_session_setup_creds_state);
NTSTATUS status;
- status = cli_session_setup_nt1_recv(subreq);
+ status = smb1cli_session_setup_lm21_recv(subreq, state,
+ &state->out_native_os,
+ &state->out_native_lm);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3, ("cli_session_setup: NT1 session setup "
- "failed: %s\n", nt_errstr(status)));
+ DEBUG(3, ("LM21 login failed: %s\n", nt_errstr(status)));
tevent_req_nterror(req, status);
return;
}
+
+ 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);
}
-NTSTATUS cli_session_setup_recv(struct tevent_req *req)
+NTSTATUS cli_session_setup_creds_recv(struct tevent_req *req)
{
return tevent_req_simple_recv_ntstatus(req);
}
-NTSTATUS cli_session_setup(struct cli_state *cli,
- const char *user,
- const char *pass, int passlen,
- const char *ntpass, int ntpasslen,
- const char *workgroup)
+NTSTATUS cli_session_setup_creds(struct cli_state *cli,
+ struct cli_credentials *creds)
{
struct tevent_context *ev;
struct tevent_req *req;
if (ev == NULL) {
goto fail;
}
- req = cli_session_setup_send(ev, ev, cli, user, pass, passlen,
- ntpass, ntpasslen, workgroup);
+ req = cli_session_setup_creds_send(ev, ev, cli, creds);
if (req == NULL) {
goto fail;
}
if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
- status = cli_session_setup_recv(req);
+ status = cli_session_setup_creds_recv(req);
fail:
TALLOC_FREE(ev);
return status;
}
+NTSTATUS cli_session_setup_anon(struct cli_state *cli)
+{
+ NTSTATUS status;
+ struct cli_credentials *creds = NULL;
+
+ creds = cli_credentials_init_anon(cli);
+ 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.
*****************************************************************************/
SCVAL(state->vwv+1, 0, 0);
SSVAL(state->vwv+2, 0, 0);
- subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv,
+ subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 0, 2, state->vwv,
0, NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
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;
state->bytes.iov_base = (void *)bytes;
state->bytes.iov_len = talloc_get_size(bytes);
- subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 4, vwv,
+ subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 0, 4, vwv,
1, &state->bytes);
if (subreq == NULL) {
TALLOC_FREE(req);
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.
****************************************************************************/
}
state->cli = cli;
- subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
+ subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, 0, NULL, 0, NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
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)) {
/*
}
state->desthost = host;
- } else {
+ } else if (dest_ss != NULL) {
state->desthost = print_canonical_sockaddr(state, dest_ss);
if (tevent_req_nomem(state->desthost, req)) {
return tevent_req_post(req, ev);
}
+ } else {
+ /* No host or dest_ss given. Error out. */
+ tevent_req_error(req, EINVAL);
+ return tevent_req_post(req, ev);
}
subreq = cli_connect_sock_send(state, ev, host, name_type, dest_ss,
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);
if (req == NULL) {
return NULL;
}
- state->ev = ev;
+ state->ev = ev;
+
+ if (signing_state == SMB_SIGNING_IPC_DEFAULT) {
+ state->min_protocol = lp_client_ipc_min_protocol();
+ state->max_protocol = lp_client_ipc_max_protocol();
+ } else {
+ state->min_protocol = lp_client_min_protocol();
+ 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)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_start_connection_connected, req);
+ return req;
+}
+
+static void cli_start_connection_connected(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_start_connection_state *state = tevent_req_data(
+ req, struct cli_start_connection_state);
+ NTSTATUS status;
+
+ status = cli_connect_nb_recv(subreq, &state->cli);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
+ state->cli->timeout,
+ state->min_protocol,
+ state->max_protocol,
+ WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_start_connection_done, req);
+}
+
+static void cli_start_connection_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_start_connection_state *state = tevent_req_data(
+ req, struct cli_start_connection_state);
+ NTSTATUS status;
+
+ status = smbXcli_negprot_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
+ /* Ensure we ask for some initial credits. */
+ smb2cli_conn_set_max_credits(state->cli->conn,
+ DEFAULT_SMB2_MAX_CREDITS);
+ }
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_start_connection_recv(struct tevent_req *req,
+ struct cli_state **output_cli)
+{
+ struct cli_start_connection_state *state = tevent_req_data(
+ req, struct cli_start_connection_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *output_cli = state->cli;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_start_connection(struct cli_state **output_cli,
+ const char *my_name,
+ const char *dest_host,
+ const struct sockaddr_storage *dest_ss, int port,
+ int signing_state, int flags)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_start_connection_send(ev, ev, my_name, dest_host, dest_ss,
+ port, signing_state, flags);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_start_connection_recv(req, output_cli);
+fail:
+ TALLOC_FREE(ev);
+ 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);
+ }
- if (signing_state == SMB_SIGNING_IPC_DEFAULT) {
- state->min_protocol = lp_client_ipc_min_protocol();
- state->max_protocol = lp_client_ipc_max_protocol();
- } else {
- state->min_protocol = lp_client_min_protocol();
- state->max_protocol = lp_client_max_protocol();
+ 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 = cli_connect_nb_send(state, ev, dest_host, dest_ss, port,
- 0x20, my_name, signing_state, flags);
+ subreq = gensec_update_send(state, state->ev,
+ state->es->gensec_security,
+ state->blob_in);
if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ return;
}
- tevent_req_set_callback(subreq, cli_start_connection_connected, req);
- return req;
+ tevent_req_set_callback(subreq, cli_smb1_setup_encryption_local_done, req);
}
-static void cli_start_connection_connected(struct tevent_req *subreq)
+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_start_connection_state *state = tevent_req_data(
- req, struct cli_start_connection_state);
+ 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_connect_nb_recv(subreq, &state->cli);
+ status = gensec_update_recv(subreq, state, &state->blob_out);
TALLOC_FREE(subreq);
- if (tevent_req_nterror(req, status)) {
+ 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;
}
- subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
- state->cli->timeout,
- state->min_protocol,
- state->max_protocol);
+ 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_start_connection_done, req);
+ tevent_req_set_callback(subreq,
+ cli_smb1_setup_encryption_remote_done,
+ req);
}
-static void cli_start_connection_done(struct tevent_req *subreq)
+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_start_connection_state *state = tevent_req_data(
- req, struct cli_start_connection_state);
+ 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 = smbXcli_negprot_recv(subreq);
+ status = cli_smb1_setup_encryption_blob_recv(subreq, state,
+ &state->blob_in,
+ &state->es->enc_ctx_num);
TALLOC_FREE(subreq);
- if (tevent_req_nterror(req, status)) {
+ 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;
}
- if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
- /* Ensure we ask for some initial credits. */
- smb2cli_conn_set_max_credits(state->cli->conn,
- DEFAULT_SMB2_MAX_CREDITS);
+ /*
+ * 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;
}
- tevent_req_done(req);
+ if (state->local_ready && state->remote_ready) {
+ cli_smb1_setup_encryption_ready(req);
+ return;
+ }
+
+ cli_smb1_setup_encryption_local_next(req);
}
-static NTSTATUS cli_start_connection_recv(struct tevent_req *req,
- struct cli_state **output_cli)
+static void cli_smb1_setup_encryption_ready(struct tevent_req *req)
{
- struct cli_start_connection_state *state = tevent_req_data(
- req, struct cli_start_connection_state);
- NTSTATUS status;
+ 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 (tevent_req_is_nterror(req, &status)) {
- return status;
+ if (state->blob_in.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
}
- *output_cli = state->cli;
- return NT_STATUS_OK;
+ 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);
}
-NTSTATUS cli_start_connection(struct cli_state **output_cli,
- const char *my_name,
- const char *dest_host,
- const struct sockaddr_storage *dest_ss, int port,
- int signing_state, int flags)
+static NTSTATUS cli_smb1_setup_encryption_recv(struct tevent_req *req)
{
- struct tevent_context *ev;
- 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_start_connection_send(ev, ev, my_name, dest_host, dest_ss,
- port, signing_state, flags);
+ 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_start_connection_recv(req, output_cli);
-fail:
+ status = cli_smb1_setup_encryption_recv(req);
+ fail:
TALLOC_FREE(ev);
return status;
}
@param port (optional) The destination port (0 for default)
@param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
@param service_type The 'type' of serivice.
- @param user Username, unix string
- @param domain User's domain
- @param password User's password, unencrypted unix string.
+ @param creds The used user credentials
*/
-struct cli_full_connection_state {
+struct cli_full_connection_creds_state {
struct tevent_context *ev;
const char *service;
const char *service_type;
- const char *user;
- const char *domain;
- const char *password;
- int pw_len;
+ struct cli_credentials *creds;
int flags;
struct cli_state *cli;
};
-static int cli_full_connection_state_destructor(
- struct cli_full_connection_state *s);
-static void cli_full_connection_started(struct tevent_req *subreq);
-static void cli_full_connection_sess_set_up(struct tevent_req *subreq);
-static void cli_full_connection_done(struct tevent_req *subreq);
+static int cli_full_connection_creds_state_destructor(
+ struct cli_full_connection_creds_state *s)
+{
+ if (s->cli != NULL) {
+ cli_shutdown(s->cli);
+ s->cli = NULL;
+ }
+ return 0;
+}
+
+static void cli_full_connection_creds_conn_done(struct tevent_req *subreq);
+static void cli_full_connection_creds_sess_start(struct tevent_req *req);
+static void cli_full_connection_creds_sess_done(struct tevent_req *subreq);
+static void cli_full_connection_creds_tcon_start(struct tevent_req *req);
+static void cli_full_connection_creds_tcon_done(struct tevent_req *subreq);
-struct tevent_req *cli_full_connection_send(
+struct tevent_req *cli_full_connection_creds_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev,
const char *my_name, const char *dest_host,
const struct sockaddr_storage *dest_ss, int port,
const char *service, const char *service_type,
- const char *user, const char *domain,
- const char *password, int flags, int signing_state)
+ struct cli_credentials *creds,
+ int flags, int signing_state)
{
struct tevent_req *req, *subreq;
- struct cli_full_connection_state *state;
+ struct cli_full_connection_creds_state *state;
+ enum credentials_use_kerberos krb5_state;
+ uint32_t gensec_features = 0;
req = tevent_req_create(mem_ctx, &state,
- struct cli_full_connection_state);
+ struct cli_full_connection_creds_state);
if (req == NULL) {
return NULL;
}
- talloc_set_destructor(state, cli_full_connection_state_destructor);
+ talloc_set_destructor(state, cli_full_connection_creds_state_destructor);
+
+ flags &= ~CLI_FULL_CONNECTION_USE_KERBEROS;
+ flags &= ~CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+ flags &= ~CLI_FULL_CONNECTION_USE_CCACHE;
+ flags &= ~CLI_FULL_CONNECTION_USE_NT_HASH;
+
+ krb5_state = cli_credentials_get_kerberos_state(creds);
+ switch (krb5_state) {
+ case CRED_MUST_USE_KERBEROS:
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+ flags &= ~CLI_FULL_CONNECTION_DONT_SPNEGO;
+ break;
+ case CRED_AUTO_USE_KERBEROS:
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+ flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+ break;
+ case CRED_DONT_USE_KERBEROS:
+ break;
+ }
+
+ gensec_features = cli_credentials_get_gensec_features(creds);
+ if (gensec_features & GENSEC_FEATURE_NTLM_CCACHE) {
+ flags |= CLI_FULL_CONNECTION_USE_CCACHE;
+ }
state->ev = ev;
state->service = service;
state->service_type = service_type;
- state->user = user;
- state->domain = domain;
- state->password = password;
+ state->creds = creds;
state->flags = flags;
- state->pw_len = state->password ? strlen(state->password)+1 : 0;
- if (state->password == NULL) {
- state->password = "";
- }
-
subreq = cli_start_connection_send(
state, ev, my_name, dest_host, dest_ss, port,
signing_state, flags);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, cli_full_connection_started, req);
+ tevent_req_set_callback(subreq,
+ cli_full_connection_creds_conn_done,
+ req);
return req;
}
-static int cli_full_connection_state_destructor(
- struct cli_full_connection_state *s)
-{
- if (s->cli != NULL) {
- cli_shutdown(s->cli);
- s->cli = NULL;
- }
- return 0;
-}
-
-static void cli_full_connection_started(struct tevent_req *subreq)
+static void cli_full_connection_creds_conn_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
- struct cli_full_connection_state *state = tevent_req_data(
- req, struct cli_full_connection_state);
+ struct cli_full_connection_creds_state *state = tevent_req_data(
+ req, struct cli_full_connection_creds_state);
NTSTATUS status;
status = cli_start_connection_recv(subreq, &state->cli);
if (tevent_req_nterror(req, status)) {
return;
}
- subreq = cli_session_setup_send(
- state, state->ev, state->cli, state->user,
- state->password, state->pw_len, state->password, state->pw_len,
- state->domain);
+
+ cli_full_connection_creds_sess_start(req);
+}
+
+static void cli_full_connection_creds_sess_start(struct tevent_req *req)
+{
+ struct cli_full_connection_creds_state *state = tevent_req_data(
+ req, struct cli_full_connection_creds_state);
+ struct tevent_req *subreq = NULL;
+
+ subreq = cli_session_setup_creds_send(
+ state, state->ev, state->cli, state->creds);
if (tevent_req_nomem(subreq, req)) {
return;
}
- tevent_req_set_callback(subreq, cli_full_connection_sess_set_up, req);
+ tevent_req_set_callback(subreq,
+ cli_full_connection_creds_sess_done,
+ req);
}
-static void cli_full_connection_sess_set_up(struct tevent_req *subreq)
+static void cli_full_connection_creds_sess_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
- struct cli_full_connection_state *state = tevent_req_data(
- req, struct cli_full_connection_state);
+ struct cli_full_connection_creds_state *state = tevent_req_data(
+ req, struct cli_full_connection_creds_state);
NTSTATUS status;
- status = cli_session_setup_recv(subreq);
+ status = cli_session_setup_creds_recv(subreq);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status) &&
state->flags &= ~CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
- subreq = cli_session_setup_send(
- state, state->ev, state->cli, "", "", 0, "", 0,
- state->domain);
- if (tevent_req_nomem(subreq, req)) {
+ state->creds = cli_credentials_init_anon(state);
+ if (tevent_req_nomem(state->creds, req)) {
return;
}
- tevent_req_set_callback(
- subreq, cli_full_connection_sess_set_up, req);
+
+ cli_full_connection_creds_sess_start(req);
return;
}
return;
}
- if (state->service != NULL) {
- subreq = cli_tree_connect_send(
- state, state->ev, state->cli,
- state->service, state->service_type,
- state->password, state->pw_len);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, cli_full_connection_done, req);
+ cli_full_connection_creds_tcon_start(req);
+}
+
+static void cli_full_connection_creds_tcon_start(struct tevent_req *req)
+{
+ struct cli_full_connection_creds_state *state = tevent_req_data(
+ req, struct cli_full_connection_creds_state);
+ struct tevent_req *subreq = NULL;
+ const char *password = NULL;
+
+ if (state->service == NULL) {
+ tevent_req_done(req);
return;
}
- tevent_req_done(req);
+ password = cli_credentials_get_password(state->creds);
+
+ subreq = cli_tree_connect_send(state, state->ev,
+ state->cli,
+ state->service,
+ state->service_type,
+ password);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ cli_full_connection_creds_tcon_done,
+ req);
}
-static void cli_full_connection_done(struct tevent_req *subreq)
+static void cli_full_connection_creds_tcon_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
tevent_req_done(req);
}
-NTSTATUS cli_full_connection_recv(struct tevent_req *req,
+NTSTATUS cli_full_connection_creds_recv(struct tevent_req *req,
struct cli_state **output_cli)
{
- struct cli_full_connection_state *state = tevent_req_data(
- req, struct cli_full_connection_state);
+ struct cli_full_connection_creds_state *state = tevent_req_data(
+ req, struct cli_full_connection_creds_state);
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
return NT_STATUS_OK;
}
-NTSTATUS cli_full_connection(struct cli_state **output_cli,
- const char *my_name,
- const char *dest_host,
- const struct sockaddr_storage *dest_ss, int port,
- const char *service, const char *service_type,
- const char *user, const char *domain,
- const char *password, int flags,
- int signing_state)
+NTSTATUS cli_full_connection_creds(struct cli_state **output_cli,
+ const char *my_name,
+ const char *dest_host,
+ const struct sockaddr_storage *dest_ss, int port,
+ const char *service, const char *service_type,
+ struct cli_credentials *creds,
+ int flags,
+ int signing_state)
{
struct tevent_context *ev;
struct tevent_req *req;
if (ev == NULL) {
goto fail;
}
- req = cli_full_connection_send(
+ req = cli_full_connection_creds_send(
ev, ev, my_name, dest_host, dest_ss, port, service,
- service_type, user, domain, password, flags, signing_state);
+ service_type, creds, flags, signing_state);
if (req == NULL) {
goto fail;
}
if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
- status = cli_full_connection_recv(req, output_cli);
+ status = cli_full_connection_creds_recv(req, output_cli);
fail:
TALLOC_FREE(ev);
return status;
}
+NTSTATUS cli_full_connection(struct cli_state **output_cli,
+ const char *my_name,
+ const char *dest_host,
+ const struct sockaddr_storage *dest_ss, int port,
+ const char *service, const char *service_type,
+ const char *user, const char *domain,
+ const char *password, int flags,
+ int signing_state)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ bool use_kerberos = false;
+ bool fallback_after_kerberos = false;
+ bool use_ccache = false;
+ bool pw_nt_hash = false;
+ struct cli_credentials *creds = NULL;
+
+ if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
+ use_kerberos = true;
+ }
+
+ if (flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) {
+ fallback_after_kerberos = true;
+ }
+
+ if (flags & CLI_FULL_CONNECTION_USE_CCACHE) {
+ use_ccache = true;
+ }
+
+ if (flags & CLI_FULL_CONNECTION_USE_NT_HASH) {
+ pw_nt_hash = true;
+ }
+
+ creds = cli_session_creds_init(frame,
+ user,
+ domain,
+ NULL, /* realm (use default) */
+ password,
+ use_kerberos,
+ fallback_after_kerberos,
+ use_ccache,
+ pw_nt_hash);
+ if (creds == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = cli_full_connection_creds(output_cli, my_name,
+ dest_host, dest_ss, port,
+ service, service_type,
+ creds, flags, signing_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
/****************************************************************************
Send an old style tcon.
****************************************************************************/
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),
return tevent_req_post(req, ev);
}
- subreq = cli_smb_send(state, ev, cli, SMBtcon, 0, 0, NULL,
+ subreq = cli_smb_send(state, ev, cli, SMBtcon, 0, 0, 0, NULL,
talloc_get_size(bytes), bytes);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
NTSTATUS nt_status;
uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
- if (user_info->use_kerberos) {
+ if (get_cmdline_auth_info_use_kerberos(user_info)) {
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",
- user_info->username ? user_info->username : "",
+ get_cmdline_auth_info_username(user_info),
lp_workgroup(),
- user_info->password ? user_info->password : "",
+ get_cmdline_auth_info_password(user_info),
flags,
SMB_SIGNING_DEFAULT);
return cli;
}
-
-/*
- * Return the IP address and workgroup of a master browser on the network, and
- * connect to it.
- */
-
-struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
- const struct user_auth_info *user_info,
- char **pp_workgroup_out)
-{
- struct sockaddr_storage *ip_list;
- struct cli_state *cli;
- int i, count;
- NTSTATUS status;
-
- *pp_workgroup_out = NULL;
-
- DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
-
- /* Go looking for workgroups by broadcasting on the local network */
-
- 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 NULL;
- }
-
- for (i = 0; i < count; i++) {
- char addr[INET6_ADDRSTRLEN];
- 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],
- user_info, pp_workgroup_out);
- if (cli)
- return(cli);
- }
-
- return NULL;
-}