summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2016-12-08 12:11:45 +0100
committerAndreas Schneider <asn@cryptomilk.org>2016-12-19 09:48:24 +0100
commita579151ee7a613b11d66a56938e7d894bd4e89a6 (patch)
treef66df6917f667b975d1b708e9c343798c494d76b
parentb17543a584f0919b7491bcfc3cd20cf47a9beed1 (diff)
downloadsamba-a579151ee7a613b11d66a56938e7d894bd4e89a6.tar.gz
s3:libsmb: split out a cli_session_creds_prepare_krb5() function
This can be used temporarily to do the required kinit if we use kerberos and the password has been specified. In future this should be done in the gensec layer on demand, but there's more work attached to doing it in the gensec_gse module. Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org>
-rw-r--r--source3/libsmb/cliconnect.c284
-rw-r--r--source3/libsmb/proto.h2
2 files changed, 157 insertions, 129 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 559712e1b5e..189c9d9c414 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -219,6 +219,154 @@ fail:
return NULL;
}
+NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli,
+ struct cli_credentials *creds)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *user_principal = NULL;
+ const char *user_account = NULL;
+ const char *user_domain = NULL;
+ const char *pass = NULL;
+ const char *target_hostname = NULL;
+ const DATA_BLOB *server_blob = NULL;
+ enum credentials_use_kerberos krb5_state;
+ bool try_kerberos = false;
+ bool need_kinit = false;
+ bool auth_requested = true;
+ int ret;
+
+ target_hostname = smbXcli_conn_remote_name(cli->conn);
+ if (!cli->got_kerberos_mechanism) {
+ server_blob = smbXcli_conn_server_gss_blob(cli->conn);
+ }
+
+ /* the server might not even do spnego */
+ if (server_blob != NULL && server_blob->length != 0) {
+ char *OIDs[ASN1_MAX_OIDS] = { NULL, };
+ size_t i;
+ bool ok;
+
+ /*
+ * The server sent us the first part of the SPNEGO exchange in the
+ * negprot reply. It is WRONG to depend on the principal sent in the
+ * negprot reply, but right now we do it. If we don't receive one,
+ * we try to best guess, then fall back to NTLM.
+ */
+ ok = spnego_parse_negTokenInit(frame,
+ *server_blob,
+ OIDs,
+ NULL,
+ NULL);
+ if (!ok) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (OIDs[0] == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* make sure the server understands kerberos */
+ for (i = 0; OIDs[i] != NULL; i++) {
+ if (i == 0) {
+ DEBUG(3,("got OID=%s\n", OIDs[i]));
+ } else {
+ DEBUGADD(3,("got OID=%s\n", OIDs[i]));
+ }
+
+ if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
+ strcmp(OIDs[i], OID_KERBEROS5) == 0) {
+ cli->got_kerberos_mechanism = true;
+ break;
+ }
+ }
+ }
+
+ auth_requested = cli_credentials_authentication_requested(creds);
+ if (auth_requested) {
+ user_principal = cli_credentials_get_principal(creds, frame);
+ if (user_principal == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ user_account = cli_credentials_get_username(creds);
+ user_domain = cli_credentials_get_domain(creds);
+ pass = cli_credentials_get_password(creds);
+
+ krb5_state = cli_credentials_get_kerberos_state(creds);
+
+ if (krb5_state != CRED_DONT_USE_KERBEROS) {
+ try_kerberos = true;
+ }
+
+ if (target_hostname == NULL) {
+ try_kerberos = false;
+ } else if (is_ipaddress(target_hostname)) {
+ try_kerberos = false;
+ } else if (strequal(target_hostname, "localhost")) {
+ try_kerberos = false;
+ } else if (strequal(target_hostname, STAR_SMBSERVER)) {
+ try_kerberos = false;
+ } else if (!auth_requested) {
+ try_kerberos = false;
+ }
+
+ if (krb5_state == CRED_MUST_USE_KERBEROS && !try_kerberos) {
+ DEBUG(0, ("Kerberos auth with '%s' (%s\\%s) to access "
+ "'%s' not possible\n",
+ user_principal, user_domain, user_account,
+ target_hostname));
+ TALLOC_FREE(frame);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (pass == NULL || strlen(pass) == 0) {
+ need_kinit = false;
+ } else if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ need_kinit = try_kerberos;
+ } else if (!cli->got_kerberos_mechanism) {
+ /*
+ * Most likely the server doesn't support
+ * Kerberos, don't waste time doing a kinit
+ */
+ need_kinit = false;
+ } else {
+ need_kinit = try_kerberos;
+ }
+
+ if (!need_kinit) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+
+ /*
+ * TODO: This should be done within the gensec layer
+ * only if required!
+ */
+ setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
+ ret = kerberos_kinit_password(user_principal, pass,
+ 0 /* no time correction for now */,
+ NULL);
+ if (ret != 0) {
+ DEBUG(0, ("Kinit for %s to access %s failed: %s\n",
+ user_principal, target_hostname,
+ error_message(ret)));
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ TALLOC_FREE(frame);
+ return krb5_to_nt_status(ret);
+ }
+
+ /*
+ * Ignore the error and hope that NTLM will work
+ */
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
/********************************************************
Utility function to ensure we always return at least
a valid char * pointer to an empty string for the
@@ -689,14 +837,6 @@ static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
}
/****************************************************************************
- Use in-memory credentials cache
-****************************************************************************/
-
-static void use_in_memory_ccache(void) {
- setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
-}
-
-/****************************************************************************
Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
@@ -1089,16 +1229,9 @@ static struct tevent_req *cli_session_setup_spnego_send(
{
struct tevent_req *req, *subreq;
struct cli_session_setup_spnego_state *state;
- const char *user_principal = NULL;
- const char *user_account = NULL;
- const char *user_domain = NULL;
- const char *pass = NULL;
+ const char *target_service = NULL;
const char *target_hostname = NULL;
- const DATA_BLOB *server_blob = NULL;
- enum credentials_use_kerberos krb5_state;
- bool try_kerberos = false;
- bool need_kinit = false;
- bool auth_requested = true;
+ NTSTATUS status;
req = tevent_req_create(mem_ctx, &state,
struct cli_session_setup_spnego_state);
@@ -1106,123 +1239,16 @@ static struct tevent_req *cli_session_setup_spnego_send(
return NULL;
}
+ target_service = "cifs";
target_hostname = smbXcli_conn_remote_name(cli->conn);
- server_blob = smbXcli_conn_server_gss_blob(cli->conn);
-
- /* the server might not even do spnego */
- if (server_blob != NULL && server_blob->length != 0) {
- char *principal = NULL;
- char *OIDs[ASN1_MAX_OIDS];
- int i;
-
- /* The server sent us the first part of the SPNEGO exchange in the
- * negprot reply. It is WRONG to depend on the principal sent in the
- * negprot reply, but right now we do it. If we don't receive one,
- * we try to best guess, then fall back to NTLM. */
- if (!spnego_parse_negTokenInit(state, *server_blob, OIDs,
- &principal, NULL) ||
- OIDs[0] == NULL) {
- state->result = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- tevent_req_done(req);
- return tevent_req_post(req, ev);
- }
- TALLOC_FREE(principal);
-
- /* make sure the server understands kerberos */
- for (i = 0; OIDs[i] != NULL; i++) {
- if (i == 0) {
- DEBUG(3,("got OID=%s\n", OIDs[i]));
- } else {
- DEBUGADD(3,("got OID=%s\n", OIDs[i]));
- }
-
- if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
- strcmp(OIDs[i], OID_KERBEROS5) == 0) {
- cli->got_kerberos_mechanism = True;
- }
- talloc_free(OIDs[i]);
- }
- }
- auth_requested = cli_credentials_authentication_requested(creds);
- if (auth_requested) {
- user_principal = cli_credentials_get_principal(creds, state);
- if (tevent_req_nomem(user_principal, req)) {
- return tevent_req_post(req, ev);
- }
- }
- user_account = cli_credentials_get_username(creds);
- user_domain = cli_credentials_get_domain(creds);
- pass = cli_credentials_get_password(creds);
-
- krb5_state = cli_credentials_get_kerberos_state(creds);
-
- if (krb5_state != CRED_DONT_USE_KERBEROS) {
- try_kerberos = true;
- }
-
- if (target_hostname == NULL) {
- try_kerberos = false;
- } else if (is_ipaddress(target_hostname)) {
- try_kerberos = false;
- } else if (strequal(target_hostname, "localhost")) {
- try_kerberos = false;
- } else if (strequal(target_hostname, STAR_SMBSERVER)) {
- try_kerberos = false;
- } else if (!auth_requested) {
- try_kerberos = false;
- }
-
- if (krb5_state == CRED_MUST_USE_KERBEROS && !try_kerberos) {
- DEBUG(0, ("Kerberos auth with '%s' (%s\\%s) to access "
- "'%s' not possible\n",
- user_principal, user_domain, user_account,
- target_hostname));
- tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
- return tevent_req_post(req, ev);
- }
-
- if (pass == NULL || strlen(pass) == 0) {
- need_kinit = false;
- } else if (krb5_state == CRED_MUST_USE_KERBEROS) {
- need_kinit = try_kerberos;
- } else if (!cli->got_kerberos_mechanism) {
- /*
- * Most likely the server doesn't support
- * Kerberos, don't waste time doing a kinit
- */
- need_kinit = false;
- } else {
- need_kinit = try_kerberos;
- }
-
- if (need_kinit) {
- int ret;
-
- use_in_memory_ccache();
- ret = kerberos_kinit_password(user_principal, pass,
- 0 /* no time correction for now */,
- NULL);
-
- if (ret != 0) {
- DEBUG(0, ("Kinit for %s to access %s failed: %s\n",
- user_principal, target_hostname,
- error_message(ret)));
- if (krb5_state == CRED_MUST_USE_KERBEROS) {
- state->result = ADS_ERROR_KRB5(ret);
- tevent_req_done(req);
- return tevent_req_post(req, ev);
- }
-
- /*
- * Ignore the error and hope that NTLM will work
- */
- ret = 0;
- }
+ status = cli_session_creds_prepare_krb5(cli, creds);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);;
}
subreq = cli_session_setup_gensec_send(state, ev, cli, creds,
- "cifs", target_hostname);
+ target_service, target_hostname);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index e1cd185f101..290183cee8e 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -43,6 +43,8 @@ struct cli_credentials *cli_session_creds_init(TALLOC_CTX *mem_ctx,
bool fallback_after_kerberos,
bool use_ccache,
bool password_is_nt_hash);
+NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli,
+ struct cli_credentials *creds);
struct tevent_req *cli_session_setup_creds_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,