#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 "../libcli/smb/smbXcli_base.h"
#include "../libcli/smb/smb_seal.h"
#include "lib/param/param.h"
+#include "../libcli/smb/smb2_negotiate_context.h"
+#include "libads/krb5_errs.h"
#define STAR_SMBSERVER "*SMBSERVER"
const char *pass = NULL;
const char *target_hostname = NULL;
const DATA_BLOB *server_blob = NULL;
+ bool got_kerberos_mechanism = false;
enum credentials_use_kerberos krb5_state;
bool try_kerberos = false;
bool need_kinit = false;
int ret;
target_hostname = smbXcli_conn_remote_name(cli->conn);
- if (!cli->got_kerberos_mechanism) {
- server_blob = smbXcli_conn_server_gss_blob(cli->conn);
- }
+ server_blob = smbXcli_conn_server_gss_blob(cli->conn);
/* the server might not even do spnego */
if (server_blob != NULL && server_blob->length != 0) {
if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
strcmp(OIDs[i], OID_KERBEROS5) == 0) {
- cli->got_kerberos_mechanism = true;
+ got_kerberos_mechanism = true;
break;
}
}
auth_requested = cli_credentials_authentication_requested(creds);
if (auth_requested) {
+ errno = 0;
user_principal = cli_credentials_get_principal(creds, frame);
- if (user_principal == NULL) {
+ if (errno != 0) {
TALLOC_FREE(frame);
return NT_STATUS_NO_MEMORY;
}
try_kerberos = true;
}
+ if (user_principal == NULL) {
+ try_kerberos = false;
+ }
+
if (target_hostname == NULL) {
try_kerberos = false;
} else if (is_ipaddress(target_hostname)) {
need_kinit = false;
} else if (krb5_state == CRED_MUST_USE_KERBEROS) {
need_kinit = try_kerberos;
- } else if (!cli->got_kerberos_mechanism) {
+ } else if (!got_kerberos_mechanism) {
/*
* Most likely the server doesn't support
* Kerberos, don't waste time doing a kinit
0 /* no time correction for now */,
NULL);
if (ret != 0) {
- DEBUG(0, ("Kinit for %s to access %s failed: %s\n",
- user_principal, target_hostname,
- error_message(ret)));
+ int dbglvl = DBGLVL_NOTICE;
+
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ dbglvl = DBGLVL_ERR;
+ }
+
+ DEBUG(dbglvl, ("Kinit for %s to access %s failed: %s\n",
+ user_principal, target_hostname,
+ error_message(ret)));
if (krb5_state == CRED_MUST_USE_KERBEROS) {
TALLOC_FREE(frame);
return krb5_to_nt_status(ret);
return NT_STATUS_OK;
}
+NTSTATUS cli_state_update_after_negprot(struct cli_state *cli)
+{
+ static const struct {
+ enum protocol_types proto;
+ const char *name;
+ } protos[] = {
+ {PROTOCOL_SMB3_11, "SMB3_11"},
+ {PROTOCOL_SMB3_10, "SMB3_10"},
+ {PROTOCOL_SMB3_02, "SMB3_02"},
+ {PROTOCOL_SMB3_00, "SMB3_00"},
+ {PROTOCOL_SMB2_24, "SMB2_24"},
+ {PROTOCOL_SMB2_22, "SMB2_22"},
+ {PROTOCOL_SMB2_10, "SMB2_10"},
+ {PROTOCOL_SMB2_02, "SMB2_02"},
+ {PROTOCOL_NT1, "NT1"},
+ {PROTOCOL_LANMAN2, "LANMAN2"},
+ {PROTOCOL_LANMAN1, "LANMAN1"},
+ {PROTOCOL_CORE, "CORE"},
+ {PROTOCOL_COREPLUS, "COREPLUS"},
+ {PROTOCOL_NONE, "NONE"},
+ {PROTOCOL_DEFAULT, "DEFAULT"},
+ };
+ enum protocol_types protocol;
+ const char *proto_name = NULL;
+ size_t i;
+
+ protocol = smbXcli_conn_protocol(cli->conn);
+
+ if (protocol >= PROTOCOL_SMB2_02) {
+ /* Ensure we ask for some initial credits. */
+ smb2cli_conn_set_max_credits(cli->conn, DEFAULT_SMB2_MAX_CREDITS);
+ }
+
+ for (i=0; i < ARRAY_SIZE(protos); i++) {
+ if (protos[i].proto == protocol) {
+ proto_name = protos[i].name;
+ break;
+ }
+ }
+
+ cli->server_os = talloc_asprintf(cli, "%s Server", proto_name);
+ if (cli->server_os == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli->server_type = talloc_asprintf(cli, "%s",
+ smbXcli_conn_remote_name(cli->conn));
+ if (cli->server_type == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ 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(native_os)) {
+ cli->server_os = talloc_strdup(cli, native_os);
+ if (cli->server_os == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (_VALID_STR(native_lm)) {
+ cli->server_type = talloc_strdup(cli, native_lm);
+ if (cli->server_type == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (_VALID_STR(primary_domain)) {
+ cli->server_domain = talloc_strdup(cli, primary_domain);
+ if (cli->server_domain == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+#undef _VALID_STRING
+ return NT_STATUS_OK;
+}
+
/********************************************************
Utility function to ensure we always return at least
a valid char * pointer to an empty string for the
subreq, struct tevent_req);
struct cli_sesssetup_blob_state *state = tevent_req_data(
req, struct cli_sesssetup_blob_state);
- struct cli_state *cli = state->cli;
NTSTATUS status;
if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
return;
}
- if (cli->server_os == NULL) {
- cli->server_os = talloc_move(cli, &state->out_native_os);
- }
- if (cli->server_type == NULL) {
- cli->server_type = talloc_move(cli, &state->out_native_lm);
- }
-
state->status = status;
+ status = cli_state_update_after_sesssetup(state->cli,
+ state->out_native_os,
+ state->out_native_lm,
+ NULL);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
if (state->blob.length != 0) {
/*
* More to send
* We can't finish the gensec handshake, we don't
* have a negotiated session key.
*
- * So just pretend we are completely done.
+ * So just pretend we are completely done,
+ * we need to continue as anonymous from this point,
+ * as we can't get a session key.
*
* Note that smbXcli_session_is_guest()
* always returns false if we require signing.
*/
state->blob_in = data_blob_null;
state->local_ready = true;
+ state->is_anonymous = true;
}
state->remote_ready = true;
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 =
tevent_req_data(req,
struct cli_session_setup_gensec_state);
- const char *server_domain = NULL;
NTSTATUS status;
if (state->blob_in.length != 0) {
return;
}
- /*
- * gensec_ntlmssp_server_domain() returns NULL
- * if NTLMSSP is not used.
- *
- * We can remove this later
- * and leave the server domain empty for SMB2 and above
- * in future releases.
- */
- server_domain = gensec_ntlmssp_server_domain(
- state->auth_generic->gensec_security);
-
- if (state->cli->server_domain[0] == '\0' && server_domain != NULL) {
- TALLOC_FREE(state->cli->server_domain);
- state->cli->server_domain = talloc_strdup(state->cli,
- server_domain);
- if (state->cli->server_domain == NULL) {
- tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
- return;
- }
- }
-
if (state->is_anonymous) {
/*
* Windows server does not set the
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;
return NULL;
}
p = strchr_m(account, '@');
- if (p != NULL) {
+ if (0 && p != NULL) {
*p = '\0';
}
return account;
status = cli_session_creds_prepare_krb5(cli, creds);
if (tevent_req_nterror(req, status)) {
- return tevent_req_post(req, ev);;
+ return tevent_req_post(req, ev);
}
subreq = cli_session_setup_gensec_send(state, ev, cli, creds,
return;
}
- if (cli->server_os == NULL) {
- cli->server_os = talloc_move(cli, &state->out_native_os);
- }
- if (cli->server_type == NULL) {
- cli->server_type = talloc_move(cli, &state->out_native_lm);
- }
- if (cli->server_domain == NULL) {
- cli->server_domain = talloc_move(cli, &state->out_primary_domain);
+ status = cli_state_update_after_sesssetup(state->cli,
+ state->out_native_os,
+ state->out_native_lm,
+ state->out_primary_domain);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
ok = smb1cli_conn_activate_signing(cli->conn,
subreq, struct tevent_req);
struct cli_session_setup_creds_state *state = tevent_req_data(
req, struct cli_session_setup_creds_state);
- struct cli_state *cli = state->cli;
NTSTATUS status;
status = smb1cli_session_setup_lm21_recv(subreq, state,
return;
}
- if (cli->server_os == NULL) {
- cli->server_os = talloc_move(cli, &state->out_native_os);
- }
- if (cli->server_type == NULL) {
- cli->server_type = talloc_move(cli, &state->out_native_lm);
+ status = cli_state_update_after_sesssetup(state->cli,
+ state->out_native_os,
+ state->out_native_lm,
+ NULL);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
tevent_req_done(req);
return NT_STATUS_OK;
}
-NTSTATUS cli_session_setup(struct cli_state *cli,
- const char *user,
- const char *pass,
- const char *workgroup)
-{
- NTSTATUS status = NT_STATUS_NO_MEMORY;
- const char *dest_realm = NULL;
- struct cli_credentials *creds = NULL;
-
- /*
- * dest_realm is only valid in the winbindd use case,
- * where we also have the account in that realm.
- */
- dest_realm = cli_state_remote_realm(cli);
-
- creds = cli_session_creds_init(cli,
- user,
- workgroup,
- dest_realm,
- pass,
- cli->use_kerberos,
- cli->fallback_after_kerberos,
- cli->use_ccache,
- cli->pw_nt_hash);
- if (creds == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- status = cli_session_setup_creds(cli, creds);
- TALLOC_FREE(creds);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
/****************************************************************************
Send a uloggoff.
*****************************************************************************/
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;
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);
tevent_req_nterror(req, status);
return;
}
- cli_state_set_tid(state->cli, UINT16_MAX);
+ TALLOC_FREE(state->cli->smb1.tcon);
tevent_req_done(req);
}
NTSTATUS status = NT_STATUS_NO_MEMORY;
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- return smb2cli_tdis(cli->conn,
+ status = smb2cli_tdis(cli->conn,
cli->timeout,
cli->smb2.session,
cli->smb2.tcon);
+ if (NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(cli->smb2.tcon);
+ }
+ return status;
}
if (smbXcli_conn_has_async_calls(cli->conn)) {
{
struct tevent_req *req, *subreq;
struct cli_connect_sock_state *state;
- const char *prog;
struct sockaddr_storage *addrs;
unsigned i, num_addrs;
NTSTATUS status;
return NULL;
}
- prog = getenv("LIBSMB_PROG");
- if (prog != NULL) {
- state->fd = sock_exec(prog);
- if (state->fd == -1) {
- status = map_nt_error_from_unix(errno);
- tevent_req_nterror(req, status);
- } else {
- state->port = 0;
- tevent_req_done(req);
- }
- return tevent_req_post(req, ev);
- }
-
if ((pss == NULL) || is_zero_addr(pss)) {
/*
return;
}
- state->cli = cli_state_create(state, fd, state->desthost, NULL,
+ state->cli = cli_state_create(state, fd, state->desthost,
state->signing_state, state->flags);
if (tevent_req_nomem(state->cli, req)) {
close(fd);
state->max_protocol = lp_client_max_protocol();
}
+ if (flags & CLI_FULL_CONNECTION_FORCE_SMB1) {
+ state->max_protocol = MIN(state->max_protocol, PROTOCOL_NT1);
+ }
+
+ if (flags & CLI_FULL_CONNECTION_DISABLE_SMB1) {
+ state->min_protocol = MAX(state->max_protocol, PROTOCOL_SMB2_02);
+ state->max_protocol = MAX(state->max_protocol, PROTOCOL_LATEST);
+ }
+
subreq = cli_connect_nb_send(state, ev, dest_host, dest_ss, port,
0x20, my_name, signing_state, flags);
if (tevent_req_nomem(subreq, req)) {
subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
state->cli->timeout,
state->min_protocol,
- state->max_protocol);
+ state->max_protocol,
+ WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK);
if (tevent_req_nomem(subreq, req)) {
return;
}
return;
}
- 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);
+ status = cli_state_update_after_negprot(state->cli);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
tevent_req_done(req);
struct auth_generic_state *ags = NULL;
const DATA_BLOB *b = NULL;
bool auth_requested = false;
- enum credentials_use_kerberos krb5_state;
- const char *mech_oid = NULL;
const char *target_service = NULL;
const char *target_hostname = NULL;
NTSTATUS status;
target_service = "cifs";
target_hostname = smbXcli_conn_remote_name(cli->conn);
- krb5_state = cli_credentials_get_kerberos_state(creds);
- if (krb5_state == CRED_MUST_USE_KERBEROS) {
- mech_oid = GENSEC_OID_SPNEGO;
-
- b = smbXcli_conn_server_gss_blob(state->cli->conn);
- if (b != NULL) {
- state->blob_in = *b;
- }
-
- status = cli_session_creds_prepare_krb5(cli, creds);
- if (tevent_req_nterror(req, status)) {
- return tevent_req_post(req, ev);
- }
- } else {
- /*
- * Be compatible with the <= 4.5 client code,
- * which used raw NTLMSSP unless kerberos
- * was forced.
- *
- * We need to check with the oldest server implementation
- * if we can remove this and always use
- * GENSEC_OID_SPNEGO.
- */
- mech_oid = GENSEC_OID_NTLMSSP;
+ 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);
gensec_set_max_update_size(ags->gensec_security,
CLI_BUFFER_SIZE);
- status = auth_generic_client_start(ags, mech_oid);
+ 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);
}
return tevent_req_post(req, ev);
}
+ TALLOC_FREE(cli->smb1.tcon);
+ cli->smb1.tcon = smbXcli_tcon_create(cli);
+ if (tevent_req_nomem(cli->smb1.tcon, req)) {
+ return tevent_req_post(req, ev);
+ }
+ smb1cli_tcon_set_id(cli->smb1.tcon, UINT16_MAX);
+
bytes = talloc_array(state, uint8_t, 0);
bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
}
+ flags |= CLI_FULL_CONNECTION_FORCE_SMB1;
+
nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
get_cmdline_auth_info_username(user_info),
lp_workgroup(),