summaryrefslogtreecommitdiff
path: root/source4/auth/credentials/credentials_krb5.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/auth/credentials/credentials_krb5.c')
-rw-r--r--source4/auth/credentials/credentials_krb5.c903
1 files changed, 0 insertions, 903 deletions
diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c
deleted file mode 100644
index 7130e4164d..0000000000
--- a/source4/auth/credentials/credentials_krb5.c
+++ /dev/null
@@ -1,903 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- Handle user credentials (as regards krb5)
-
- Copyright (C) Jelmer Vernooij 2005
- Copyright (C) Tim Potter 2001
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "system/kerberos.h"
-#include "auth/kerberos/kerberos.h"
-#include "auth/credentials/credentials.h"
-#include "auth/credentials/credentials_proto.h"
-#include "auth/credentials/credentials_krb5.h"
-#include "auth/kerberos/kerberos_credentials.h"
-#include "auth/kerberos/kerberos_util.h"
-#include "param/param.h"
-
-_PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred,
- struct loadparm_context *lp_ctx,
- struct smb_krb5_context **smb_krb5_context)
-{
- int ret;
- if (cred->smb_krb5_context) {
- *smb_krb5_context = cred->smb_krb5_context;
- return 0;
- }
-
- ret = smb_krb5_init_context(cred, NULL, lp_ctx,
- &cred->smb_krb5_context);
- if (ret) {
- cred->smb_krb5_context = NULL;
- return ret;
- }
- *smb_krb5_context = cred->smb_krb5_context;
- return 0;
-}
-
-/* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(),
- * otherwise we may still have references to the old smb_krb5_context in a credential cache etc
- */
-_PUBLIC_ NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred,
- struct smb_krb5_context *smb_krb5_context)
-{
- if (smb_krb5_context == NULL) {
- talloc_unlink(cred, cred->smb_krb5_context);
- cred->smb_krb5_context = NULL;
- return NT_STATUS_OK;
- }
-
- if (!talloc_reference(cred, smb_krb5_context)) {
- return NT_STATUS_NO_MEMORY;
- }
- cred->smb_krb5_context = smb_krb5_context;
- return NT_STATUS_OK;
-}
-
-static int cli_credentials_set_from_ccache(struct cli_credentials *cred,
- struct ccache_container *ccache,
- enum credentials_obtained obtained,
- const char **error_string)
-{
-
- krb5_principal princ;
- krb5_error_code ret;
- char *name;
-
- if (cred->ccache_obtained > obtained) {
- return 0;
- }
-
- ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context,
- ccache->ccache, &princ);
-
- if (ret) {
- (*error_string) = talloc_asprintf(cred, "failed to get principal from ccache: %s\n",
- smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
- ret, cred));
- return ret;
- }
-
- ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name);
- if (ret) {
- (*error_string) = talloc_asprintf(cred, "failed to unparse principal from ccache: %s\n",
- smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
- ret, cred));
- return ret;
- }
-
- cli_credentials_set_principal(cred, name, obtained);
-
- free(name);
-
- krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
-
- /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
- cred->ccache_obtained = obtained;
-
- return 0;
-}
-
-/* Free a memory ccache */
-static int free_mccache(struct ccache_container *ccc)
-{
- krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache);
-
- return 0;
-}
-
-/* Free a disk-based ccache */
-static int free_dccache(struct ccache_container *ccc) {
- krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);
-
- return 0;
-}
-
-_PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
- struct loadparm_context *lp_ctx,
- const char *name,
- enum credentials_obtained obtained,
- const char **error_string)
-{
- krb5_error_code ret;
- krb5_principal princ;
- struct ccache_container *ccc;
- if (cred->ccache_obtained > obtained) {
- return 0;
- }
-
- ccc = talloc(cred, struct ccache_container);
- if (!ccc) {
- (*error_string) = error_message(ENOMEM);
- return ENOMEM;
- }
-
- ret = cli_credentials_get_krb5_context(cred, lp_ctx,
- &ccc->smb_krb5_context);
- if (ret) {
- (*error_string) = error_message(ret);
- talloc_free(ccc);
- return ret;
- }
- if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
- talloc_free(ccc);
- (*error_string) = error_message(ENOMEM);
- return ENOMEM;
- }
-
- if (name) {
- ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
- if (ret) {
- (*error_string) = talloc_asprintf(cred, "failed to read krb5 ccache: %s: %s\n",
- name,
- smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
- ret, ccc));
- talloc_free(ccc);
- return ret;
- }
- } else {
- ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
- if (ret) {
- (*error_string) = talloc_asprintf(cred, "failed to read default krb5 ccache: %s\n",
- smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
- ret, ccc));
- talloc_free(ccc);
- return ret;
- }
- }
-
- talloc_set_destructor(ccc, free_dccache);
-
- ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
-
- if (ret == 0) {
- krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
- ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
-
- if (ret) {
- (*error_string) = error_message(ret);
- return ret;
- }
-
- cred->ccache = ccc;
- cred->ccache_obtained = obtained;
- talloc_steal(cred, ccc);
-
- cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
- return 0;
- }
- return 0;
-}
-
-
-static int cli_credentials_new_ccache(struct cli_credentials *cred,
- struct loadparm_context *lp_ctx,
- char *ccache_name,
- struct ccache_container **_ccc,
- const char **error_string)
-{
- bool must_free_cc_name = false;
- krb5_error_code ret;
- struct ccache_container *ccc = talloc(cred, struct ccache_container);
- if (!ccc) {
- return ENOMEM;
- }
-
- ret = cli_credentials_get_krb5_context(cred, lp_ctx,
- &ccc->smb_krb5_context);
- if (ret) {
- talloc_free(ccc);
- (*error_string) = talloc_asprintf(cred, "Failed to get krb5_context: %s",
- error_message(ret));
- return ret;
- }
- if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
- talloc_free(ccc);
- (*error_string) = strerror(ENOMEM);
- return ENOMEM;
- }
-
- if (!ccache_name) {
- must_free_cc_name = true;
-
- if (lpcfg_parm_bool(lp_ctx, NULL, "credentials", "krb5_cc_file", false)) {
- ccache_name = talloc_asprintf(ccc, "FILE:/tmp/krb5_cc_samba_%u_%p",
- (unsigned int)getpid(), ccc);
- } else {
- ccache_name = talloc_asprintf(ccc, "MEMORY:%p",
- ccc);
- }
-
- if (!ccache_name) {
- talloc_free(ccc);
- (*error_string) = strerror(ENOMEM);
- return ENOMEM;
- }
- }
-
- ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name,
- &ccc->ccache);
- if (ret) {
- (*error_string) = talloc_asprintf(cred, "failed to resolve a krb5 ccache (%s): %s\n",
- ccache_name,
- smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
- ret, ccc));
- talloc_free(ccache_name);
- talloc_free(ccc);
- return ret;
- }
-
- if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) {
- talloc_set_destructor(ccc, free_mccache);
- } else {
- talloc_set_destructor(ccc, free_dccache);
- }
-
- if (must_free_cc_name) {
- talloc_free(ccache_name);
- }
-
- *_ccc = ccc;
-
- return 0;
-}
-
-_PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
- struct tevent_context *event_ctx,
- struct loadparm_context *lp_ctx,
- char *ccache_name,
- struct ccache_container **ccc,
- const char **error_string)
-{
- krb5_error_code ret;
- enum credentials_obtained obtained;
-
- if (cred->machine_account_pending) {
- cli_credentials_set_machine_account(cred, lp_ctx);
- }
-
- if (cred->ccache_obtained >= cred->ccache_threshold &&
- cred->ccache_obtained > CRED_UNINITIALISED) {
- time_t lifetime;
- bool expired = false;
- ret = krb5_cc_get_lifetime(cred->ccache->smb_krb5_context->krb5_context,
- cred->ccache->ccache, &lifetime);
- if (ret == KRB5_CC_END) {
- /* If we have a particular ccache set, without
- * an initial ticket, then assume there is a
- * good reason */
- } else if (ret == 0) {
- if (lifetime == 0) {
- DEBUG(3, ("Ticket in credentials cache for %s expired, will refresh\n",
- cli_credentials_get_principal(cred, cred)));
- expired = true;
- } else if (lifetime < 300) {
- DEBUG(3, ("Ticket in credentials cache for %s will shortly expire (%u secs), will refresh\n",
- cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
- expired = true;
- }
- } else {
- (*error_string) = talloc_asprintf(cred, "failed to get ccache lifetime: %s\n",
- smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context,
- ret, cred));
- return ret;
- }
-
- DEBUG(5, ("Ticket in credentials cache for %s will expire in %u secs\n",
- cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
-
- if (!expired) {
- *ccc = cred->ccache;
- return 0;
- }
- }
- if (cli_credentials_is_anonymous(cred)) {
- (*error_string) = "Cannot get anonymous kerberos credentials";
- return EINVAL;
- }
-
- ret = cli_credentials_new_ccache(cred, lp_ctx, ccache_name, ccc, error_string);
- if (ret) {
- return ret;
- }
-
- ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, event_ctx, (*ccc)->ccache, &obtained, error_string);
- if (ret) {
- return ret;
- }
-
- ret = cli_credentials_set_from_ccache(cred, *ccc,
- obtained, error_string);
-
- cred->ccache = *ccc;
- cred->ccache_obtained = cred->principal_obtained;
- if (ret) {
- return ret;
- }
- cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
- return 0;
-}
-
-_PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred,
- struct tevent_context *event_ctx,
- struct loadparm_context *lp_ctx,
- struct ccache_container **ccc,
- const char **error_string)
-{
- return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string);
-}
-
-/* We have good reason to think the ccache in these credentials is invalid - blow it away */
-static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials *cred)
-{
- if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
- talloc_unlink(cred, cred->client_gss_creds);
- cred->client_gss_creds = NULL;
- }
- cred->client_gss_creds_obtained = CRED_UNINITIALISED;
-}
-
-void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred,
- enum credentials_obtained obtained)
-{
- /* If the caller just changed the username/password etc, then
- * any cached credentials are now invalid */
- if (obtained >= cred->client_gss_creds_obtained) {
- if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
- talloc_unlink(cred, cred->client_gss_creds);
- cred->client_gss_creds = NULL;
- }
- cred->client_gss_creds_obtained = CRED_UNINITIALISED;
- }
- /* Now that we know that the data is 'this specified', then
- * don't allow something less 'known' to be returned as a
- * ccache. Ie, if the username is on the command line, we
- * don't want to later guess to use a file-based ccache */
- if (obtained > cred->client_gss_creds_threshold) {
- cred->client_gss_creds_threshold = obtained;
- }
-}
-
-/* We have good reason to think this CCACHE is invalid. Blow it away */
-static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred)
-{
- if (cred->ccache_obtained > CRED_UNINITIALISED) {
- talloc_unlink(cred, cred->ccache);
- cred->ccache = NULL;
- }
- cred->ccache_obtained = CRED_UNINITIALISED;
-
- cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
-}
-
-_PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred,
- enum credentials_obtained obtained)
-{
- /* If the caller just changed the username/password etc, then
- * any cached credentials are now invalid */
- if (obtained >= cred->ccache_obtained) {
- if (cred->ccache_obtained > CRED_UNINITIALISED) {
- talloc_unlink(cred, cred->ccache);
- cred->ccache = NULL;
- }
- cred->ccache_obtained = CRED_UNINITIALISED;
- }
- /* Now that we know that the data is 'this specified', then
- * don't allow something less 'known' to be returned as a
- * ccache. i.e, if the username is on the command line, we
- * don't want to later guess to use a file-based ccache */
- if (obtained > cred->ccache_threshold) {
- cred->ccache_threshold = obtained;
- }
-
- cli_credentials_invalidate_client_gss_creds(cred,
- obtained);
-}
-
-static int free_gssapi_creds(struct gssapi_creds_container *gcc)
-{
- OM_uint32 min_stat, maj_stat;
- maj_stat = gss_release_cred(&min_stat, &gcc->creds);
- return 0;
-}
-
-_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
- struct tevent_context *event_ctx,
- struct loadparm_context *lp_ctx,
- struct gssapi_creds_container **_gcc,
- const char **error_string)
-{
- int ret = 0;
- OM_uint32 maj_stat, min_stat;
- struct gssapi_creds_container *gcc;
- struct ccache_container *ccache;
- gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
- krb5_enctype *etypes = NULL;
-
- if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold &&
- cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
- bool expired = false;
- OM_uint32 lifetime = 0;
- gss_cred_usage_t usage = 0;
- maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds,
- NULL, &lifetime, &usage, NULL);
- if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) {
- DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred)));
- expired = true;
- } else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) {
- DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime));
- expired = true;
- } else if (maj_stat != GSS_S_COMPLETE) {
- *error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
- gssapi_error_string(cred, maj_stat, min_stat, NULL));
- return EINVAL;
- }
- if (expired) {
- cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
- } else {
- DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n",
- cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
-
- *_gcc = cred->client_gss_creds;
- return 0;
- }
- }
-
- ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
- &ccache, error_string);
- if (ret) {
- if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) {
- DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", error_message(ret)));
- } else {
- DEBUG(4, ("Failed to get kerberos credentials: %s\n", error_message(ret)));
- }
- return ret;
- }
-
- gcc = talloc(cred, struct gssapi_creds_container);
- if (!gcc) {
- (*error_string) = error_message(ENOMEM);
- return ENOMEM;
- }
-
- maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
- &gcc->creds);
- if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) {
- /* This CCACHE is no good. Ensure we don't use it again */
- cli_credentials_unconditionally_invalidate_ccache(cred);
-
- /* Now try again to get a ccache */
- ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
- &ccache, error_string);
- if (ret) {
- DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
- return ret;
- }
-
- maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
- &gcc->creds);
-
- }
-
- if (maj_stat) {
- talloc_free(gcc);
- if (min_stat) {
- ret = min_stat;
- } else {
- ret = EINVAL;
- }
- (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret));
- return ret;
- }
-
- /*
- * transfer the enctypes from the smb_krb5_context to the gssapi layer
- *
- * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
- * to configure the enctypes via the krb5.conf.
- *
- * And the gss_init_sec_context() creates it's own krb5_context and
- * the TGS-REQ had all enctypes in it and only the ones configured
- * and used for the AS-REQ, so it wasn't possible to disable the usage
- * of AES keys.
- */
- min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context,
- KRB5_PDU_NONE,
- &etypes);
- if (min_stat == 0) {
- OM_uint32 num_ktypes;
-
- for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);
-
- maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
- num_ktypes,
- (int32_t *) etypes);
- krb5_xfree (etypes);
- if (maj_stat) {
- talloc_free(gcc);
- if (min_stat) {
- ret = min_stat;
- } else {
- ret = EINVAL;
- }
- (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret));
- return ret;
- }
- }
-
- /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
- maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
- GSS_KRB5_CRED_NO_CI_FLAGS_X,
- &empty_buffer);
- if (maj_stat) {
- talloc_free(gcc);
- if (min_stat) {
- ret = min_stat;
- } else {
- ret = EINVAL;
- }
- (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret));
- return ret;
- }
-
- cred->client_gss_creds_obtained = cred->ccache_obtained;
- talloc_set_destructor(gcc, free_gssapi_creds);
- cred->client_gss_creds = gcc;
- *_gcc = gcc;
- return 0;
-}
-
-/**
- Set a gssapi cred_id_t into the credentials system. (Client case)
-
- This grabs the credentials both 'intact' and getting the krb5
- ccache out of it. This routine can be generalised in future for
- the case where we deal with GSSAPI mechs other than krb5.
-
- On sucess, the caller must not free gssapi_cred, as it now belongs
- to the credentials system.
-*/
-
- int cli_credentials_set_client_gss_creds(struct cli_credentials *cred,
- struct loadparm_context *lp_ctx,
- gss_cred_id_t gssapi_cred,
- enum credentials_obtained obtained,
- const char **error_string)
-{
- int ret;
- OM_uint32 maj_stat, min_stat;
- struct ccache_container *ccc;
- struct gssapi_creds_container *gcc;
- if (cred->client_gss_creds_obtained > obtained) {
- return 0;
- }
-
- gcc = talloc(cred, struct gssapi_creds_container);
- if (!gcc) {
- (*error_string) = error_message(ENOMEM);
- return ENOMEM;
- }
-
- ret = cli_credentials_new_ccache(cred, lp_ctx, NULL, &ccc, error_string);
- if (ret != 0) {
- return ret;
- }
-
- maj_stat = gss_krb5_copy_ccache(&min_stat,
- gssapi_cred, ccc->ccache);
- if (maj_stat) {
- if (min_stat) {
- ret = min_stat;
- } else {
- ret = EINVAL;
- }
- if (ret) {
- (*error_string) = error_message(ENOMEM);
- }
- }
-
- if (ret == 0) {
- ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
- }
- cred->ccache = ccc;
- cred->ccache_obtained = obtained;
- if (ret == 0) {
- gcc->creds = gssapi_cred;
- talloc_set_destructor(gcc, free_gssapi_creds);
-
- /* set the clinet_gss_creds_obtained here, as it just
- got set to UNINITIALISED by the calls above */
- cred->client_gss_creds_obtained = obtained;
- cred->client_gss_creds = gcc;
- }
- return ret;
-}
-
-/* Get the keytab (actually, a container containing the krb5_keytab)
- * attached to this context. If this hasn't been done or set before,
- * it will be generated from the password.
- */
-_PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred,
- struct loadparm_context *lp_ctx,
- struct keytab_container **_ktc)
-{
- krb5_error_code ret;
- struct keytab_container *ktc;
- struct smb_krb5_context *smb_krb5_context;
- TALLOC_CTX *mem_ctx;
-
- if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
- cred->username_obtained))) {
- *_ktc = cred->keytab;
- return 0;
- }
-
- if (cli_credentials_is_anonymous(cred)) {
- return EINVAL;
- }
-
- ret = cli_credentials_get_krb5_context(cred, lp_ctx,
- &smb_krb5_context);
- if (ret) {
- return ret;
- }
-
- mem_ctx = talloc_new(cred);
- if (!mem_ctx) {
- return ENOMEM;
- }
-
- ret = smb_krb5_create_memory_keytab(mem_ctx, cred,
- smb_krb5_context, &ktc);
- if (ret) {
- talloc_free(mem_ctx);
- return ret;
- }
-
- cred->keytab_obtained = (MAX(cred->principal_obtained,
- cred->username_obtained));
-
- talloc_steal(cred, ktc);
- cred->keytab = ktc;
- *_ktc = cred->keytab;
- talloc_free(mem_ctx);
- return ret;
-}
-
-/* Given the name of a keytab (presumably in the format
- * FILE:/etc/krb5.keytab), open it and attach it */
-
-_PUBLIC_ int cli_credentials_set_keytab_name(struct cli_credentials *cred,
- struct loadparm_context *lp_ctx,
- const char *keytab_name,
- enum credentials_obtained obtained)
-{
- krb5_error_code ret;
- struct keytab_container *ktc;
- struct smb_krb5_context *smb_krb5_context;
- TALLOC_CTX *mem_ctx;
-
- if (cred->keytab_obtained >= obtained) {
- return 0;
- }
-
- ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
- if (ret) {
- return ret;
- }
-
- mem_ctx = talloc_new(cred);
- if (!mem_ctx) {
- return ENOMEM;
- }
-
- ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context,
- keytab_name, &ktc);
- if (ret) {
- return ret;
- }
-
- cred->keytab_obtained = obtained;
-
- talloc_steal(cred, ktc);
- cred->keytab = ktc;
- talloc_free(mem_ctx);
-
- return ret;
-}
-
-/* Get server gss credentials (in gsskrb5, this means the keytab) */
-
-_PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
- struct loadparm_context *lp_ctx,
- struct gssapi_creds_container **_gcc)
-{
- int ret = 0;
- OM_uint32 maj_stat, min_stat;
- struct gssapi_creds_container *gcc;
- struct keytab_container *ktc;
- struct smb_krb5_context *smb_krb5_context;
- TALLOC_CTX *mem_ctx;
- krb5_principal princ;
- const char *error_string;
- enum credentials_obtained obtained;
-
- mem_ctx = talloc_new(cred);
- if (!mem_ctx) {
- return ENOMEM;
- }
-
- ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
- if (ret) {
- return ret;
- }
-
- ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string);
- if (ret) {
- DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
- error_string));
- talloc_free(mem_ctx);
- return ret;
- }
-
- if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) {
- talloc_free(mem_ctx);
- *_gcc = cred->server_gss_creds;
- return 0;
- }
-
- ret = cli_credentials_get_keytab(cred, lp_ctx, &ktc);
- if (ret) {
- DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
- return ret;
- }
-
- gcc = talloc(cred, struct gssapi_creds_container);
- if (!gcc) {
- talloc_free(mem_ctx);
- return ENOMEM;
- }
-
- /* This creates a GSSAPI cred_id_t with the principal and keytab set */
- maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
- &gcc->creds);
- if (maj_stat) {
- if (min_stat) {
- ret = min_stat;
- } else {
- ret = EINVAL;
- }
- }
- if (ret == 0) {
- cred->server_gss_creds_obtained = cred->keytab_obtained;
- talloc_set_destructor(gcc, free_gssapi_creds);
- cred->server_gss_creds = gcc;
- *_gcc = gcc;
- }
- talloc_free(mem_ctx);
- return ret;
-}
-
-/**
- * Set Kerberos KVNO
- */
-
-_PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred,
- int kvno)
-{
- cred->kvno = kvno;
-}
-
-/**
- * Return Kerberos KVNO
- */
-
-_PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred)
-{
- return cred->kvno;
-}
-
-
-const char *cli_credentials_get_salt_principal(struct cli_credentials *cred)
-{
- return cred->salt_principal;
-}
-
-_PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
-{
- talloc_free(cred->salt_principal);
- cred->salt_principal = talloc_strdup(cred, principal);
-}
-
-/* The 'impersonate_principal' is used to allow one Kerberos principal
- * (and it's associated keytab etc) to impersonate another. The
- * ability to do this is controlled by the KDC, but it is generally
- * permitted to impersonate anyone to yourself. This allows any
- * member of the domain to get the groups of a user. This is also
- * known as S4U2Self */
-
-_PUBLIC_ const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred)
-{
- return cred->impersonate_principal;
-}
-
-/*
- * The 'self_service' is the service principal that
- * represents the same object (by its objectSid)
- * as the client principal (typically our machine account).
- * When trying to impersonate 'impersonate_principal' with
- * S4U2Self.
- */
-_PUBLIC_ const char *cli_credentials_get_self_service(struct cli_credentials *cred)
-{
- return cred->self_service;
-}
-
-_PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred,
- const char *principal,
- const char *self_service)
-{
- talloc_free(cred->impersonate_principal);
- cred->impersonate_principal = talloc_strdup(cred, principal);
- talloc_free(cred->self_service);
- cred->self_service = talloc_strdup(cred, self_service);
- cli_credentials_set_kerberos_state(cred, CRED_MUST_USE_KERBEROS);
-}
-
-/*
- * when impersonating for S4U2proxy we need to set the target principal.
- * Similarly, we may only be authorized to do general impersonation to
- * some particular services.
- *
- * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
- *
- * NULL means that tickets will be obtained for the krbtgt service.
-*/
-
-const char *cli_credentials_get_target_service(struct cli_credentials *cred)
-{
- return cred->target_service;
-}
-
-_PUBLIC_ void cli_credentials_set_target_service(struct cli_credentials *cred, const char *target_service)
-{
- talloc_free(cred->target_service);
- cred->target_service = talloc_strdup(cred, target_service);
-}
-