*/
#include "includes.h"
+#include "system/filesys.h"
#include "krb5_samba.h"
-#include "librpc/gen_ndr/krb5pac.h"
#include "lib/util/asn1.h"
#ifndef KRB5_AUTHDATA_WIN2K_PAC
krb5_ccache ccdef = NULL;
krb5_auth_context auth_context = NULL;
krb5_enctype enc_types[] = {
+#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+#endif
+#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+#endif
ENCTYPE_ARCFOUR_HMAC,
ENCTYPE_DES_CBC_MD5,
ENCTYPE_DES_CBC_CRC,
krb5_context context = NULL;
krb5_ccache ccache = NULL;
krb5_principal client = NULL;
- krb5_creds creds, creds_in, *creds_out = NULL;
+ krb5_creds creds, creds_in;
ZERO_STRUCT(creds);
ZERO_STRUCT(creds_in);
done:
krb5_free_cred_contents(context, &creds_in);
-
- if (creds_out) {
- krb5_free_creds(context, creds_out);
- } else {
- krb5_free_cred_contents(context, &creds);
- }
+ krb5_free_cred_contents(context, &creds);
if (client) {
krb5_free_principal(context, client);
krb5_error_code ret;
krb5_creds *creds = NULL;
- *out_creds = NULL;
+ if (out_creds != NULL) {
+ *out_creds = NULL;
+ }
if (impersonate_princ) {
#ifdef HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE /* Heimdal */
return ret;
}
-/*
- * smb_krb5_get_creds
- *
- * @brief Get krb5 credentials for a server
- *
- * @param[in] server_s The string name of the service
- * @param[in] time_offset The offset to the KDCs time in seconds (optional)
- * @param[in] cc The krb5 credential cache string name (optional)
- * @param[in] impersonate_princ_s The string principal name to impersonate (optional)
- * @param[out] creds_p The returned krb5_creds structure
- * @return krb5_error_code
- *
- */
-krb5_error_code smb_krb5_get_creds(const char *server_s,
- time_t time_offset,
- const char *cc,
- const char *impersonate_princ_s,
- krb5_creds **creds_p)
+krb5_error_code smb_krb5_keyblock_init_contents(krb5_context context,
+ krb5_enctype enctype,
+ const void *data,
+ size_t length,
+ krb5_keyblock *key)
{
- krb5_error_code ret;
- krb5_context context = NULL;
- krb5_principal me = NULL;
- krb5_principal server = NULL;
- krb5_principal impersonate_princ = NULL;
- krb5_creds *creds = NULL;
- krb5_ccache ccache = NULL;
+#if defined(HAVE_KRB5_KEYBLOCK_INIT)
+ return krb5_keyblock_init(context, enctype, data, length, key);
+#else
+ memset(key, 0, sizeof(krb5_keyblock));
+ KRB5_KEY_DATA(key) = SMB_MALLOC(length);
+ if (NULL == KRB5_KEY_DATA(key)) {
+ return ENOMEM;
+ }
+ memcpy(KRB5_KEY_DATA(key), data, length);
+ KRB5_KEY_LENGTH(key) = length;
+ KRB5_KEY_TYPE(key) = enctype;
+ return 0;
+#endif
+}
+
+/*
+ simulate a kinit, putting the tgt in the given credentials cache.
+ Orignally by remus@snapserver.com
- *creds_p = NULL;
+ This version is built to use a keyblock, rather than needing the
+ original password.
- initialize_krb5_error_table();
- ret = krb5_init_context(&context);
- if (ret) {
+ The impersonate_principal is the principal if NULL, or the principal
+ to impersonate
+
+ The target_service defaults to the krbtgt if NULL, but could be
+ kpasswd/realm or the local service (if we are doing s4u2self)
+*/
+krb5_error_code kerberos_kinit_keyblock_cc(krb5_context ctx, krb5_ccache cc,
+ krb5_principal principal,
+ krb5_keyblock *keyblock,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time)
+{
+ krb5_error_code code = 0;
+ krb5_creds my_creds;
+ mode_t mask;
+
+#if defined(HAVE_KRB5_GET_INIT_CREDS_KEYBLOCK)
+ code = krb5_get_init_creds_keyblock(ctx, &my_creds, principal,
+ keyblock, 0, target_service,
+ krb_options);
+#elif defined(HAVE_KRB5_GET_INIT_CREDS_KEYTAB)
+{
+#define SMB_CREDS_KEYTAB "MEMORY:tmp_smb_creds_XXXXXX"
+ char tmp_name[sizeof(SMB_CREDS_KEYTAB)];
+ krb5_keytab_entry entry;
+ krb5_keytab keytab;
+
+ memset(&entry, 0, sizeof(entry));
+ entry.principal = principal;
+ *(KRB5_KT_KEY(&entry)) = *keyblock;
+
+ memcpy(tmp_name, SMB_CREDS_KEYTAB, sizeof(SMB_CREDS_KEYTAB));
+ mask = umask(S_IRWXO | S_IRWXG);
+ mktemp(tmp_name);
+ umask(mask);
+ if (tmp_name[0] == 0) {
+ return KRB5_KT_BADNAME;
+ }
+ code = krb5_kt_resolve(ctx, tmp_name, &keytab);
+ if (code) {
+ return code;
+ }
+
+ code = krb5_kt_add_entry(ctx, keytab, &entry);
+ if (code) {
+ (void)krb5_kt_close(ctx, keytab);
goto done;
}
- if (time_offset != 0) {
- krb5_set_real_time(context, time(NULL) + time_offset, 0);
+ code = krb5_get_init_creds_keytab(ctx, &my_creds, principal,
+ keytab, 0, target_service,
+ krb_options);
+ (void)krb5_kt_close(ctx, keytab);
+}
+#else
+#error krb5_get_init_creds_keyblock not available!
+#endif
+ if (code) {
+ return code;
}
- ret = krb5_cc_resolve(context, cc ? cc :
- krb5_cc_default_name(context), &ccache);
- if (ret) {
+ code = krb5_cc_initialize(ctx, cc, principal);
+ if (code) {
goto done;
}
- ret = krb5_cc_get_principal(context, ccache, &me);
- if (ret) {
+ code = krb5_cc_store_cred(ctx, cc, &my_creds);
+ if (code) {
goto done;
}
- ret = smb_krb5_parse_name(context, server_s, &server);
- if (ret) {
- goto done;
+ if (expire_time) {
+ *expire_time = (time_t) my_creds.times.endtime;
}
- if (impersonate_princ_s) {
- ret = smb_krb5_parse_name(context, impersonate_princ_s,
- &impersonate_princ);
- if (ret) {
- goto done;
- }
+ if (kdc_time) {
+ *kdc_time = (time_t) my_creds.times.starttime;
}
- ret = smb_krb5_get_credentials(context, ccache,
- me, server, impersonate_princ,
- &creds);
- if (ret) {
+ code = 0;
+done:
+ krb5_free_cred_contents(ctx, &my_creds);
+ return code;
+}
+
+krb5_error_code kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc,
+ krb5_principal principal,
+ const char *password,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time)
+{
+ krb5_error_code code = 0;
+ krb5_creds my_creds;
+
+ code = krb5_get_init_creds_password(ctx, &my_creds, principal,
+ password, NULL, NULL, 0,
+ target_service, krb_options);
+ if (code) {
+ return code;
+ }
+
+ code = krb5_cc_initialize(ctx, cc, principal);
+ if (code) {
goto done;
}
- ret = krb5_cc_store_cred(context, ccache, creds);
- if (ret) {
+ code = krb5_cc_store_cred(ctx, cc, &my_creds);
+ if (code) {
goto done;
}
- if (creds_p) {
- *creds_p = creds;
+ if (expire_time) {
+ *expire_time = (time_t) my_creds.times.endtime;
}
- DEBUG(1,("smb_krb5_get_creds: got ticket for %s\n",
- server_s));
+ if (kdc_time) {
+ *kdc_time = (time_t) my_creds.times.starttime;
+ }
- if (impersonate_princ_s) {
- char *client = NULL;
+ code = 0;
+done:
+ krb5_free_cred_contents(ctx, &my_creds);
+ return code;
+}
- ret = smb_krb5_unparse_name(talloc_tos(), context, creds->client, &client);
- if (ret) {
- goto done;
+#ifdef SAMBA4_USES_HEIMDAL
+/*
+ simulate a kinit, putting the tgt in the given credentials cache.
+ Orignally by remus@snapserver.com
+
+ The impersonate_principal is the principal
+
+ The self_service, should be the local service (for S4U2Self if
+ impersonate_principal is given).
+
+ The target_service defaults to the krbtgt if NULL, but could be
+ kpasswd/realm or a remote service (for S4U2Proxy)
+
+*/
+krb5_error_code kerberos_kinit_s4u2_cc(krb5_context ctx,
+ krb5_ccache store_cc,
+ krb5_principal init_principal,
+ const char *init_password,
+ krb5_principal impersonate_principal,
+ const char *self_service,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time)
+{
+ krb5_error_code code = 0;
+ krb5_get_creds_opt options;
+ krb5_principal store_principal;
+ krb5_creds store_creds;
+ krb5_creds *s4u2self_creds;
+ Ticket s4u2self_ticket;
+ size_t s4u2self_ticketlen;
+ krb5_creds *s4u2proxy_creds;
+ krb5_principal self_princ;
+ bool s4u2proxy;
+ krb5_principal target_princ;
+ krb5_ccache tmp_cc;
+ const char *self_realm;
+ krb5_principal blacklist_principal = NULL;
+ krb5_principal whitelist_principal = NULL;
+
+ code = krb5_get_init_creds_password(ctx, &store_creds,
+ init_principal,
+ init_password,
+ NULL, NULL,
+ 0,
+ NULL,
+ krb_options);
+ if (code != 0) {
+ return code;
+ }
+
+ store_principal = init_principal;
+
+ /*
+ * We are trying S4U2Self now:
+ *
+ * As we do not want to expose our TGT in the
+ * krb5_ccache, which is also holds the impersonated creds.
+ *
+ * Some low level krb5/gssapi function might use the TGT
+ * identity and let the client act as our machine account.
+ *
+ * We need to avoid that and use a temporary krb5_ccache
+ * in order to pass our TGT to the krb5_get_creds() function.
+ */
+ code = krb5_cc_new_unique(ctx, NULL, NULL, &tmp_cc);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+
+ code = krb5_cc_initialize(ctx, tmp_cc, store_creds.client);
+ if (code != 0) {
+ krb5_cc_destroy(ctx, tmp_cc);
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+
+ code = krb5_cc_store_cred(ctx, tmp_cc, &store_creds);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ /*
+ * we need to remember the client principal of our
+ * TGT and make sure the KDC does not return this
+ * in the impersonated tickets. This can happen
+ * if the KDC does not support S4U2Self and S4U2Proxy.
+ */
+ blacklist_principal = store_creds.client;
+ store_creds.client = NULL;
+ krb5_free_cred_contents(ctx, &store_creds);
+
+ /*
+ * Check if we also need S4U2Proxy or if S4U2Self is
+ * enough in order to get a ticket for the target.
+ */
+ if (target_service == NULL) {
+ s4u2proxy = false;
+ } else if (strcmp(target_service, self_service) == 0) {
+ s4u2proxy = false;
+ } else {
+ s4u2proxy = true;
+ }
+
+ /*
+ * For S4U2Self we need our own service principal,
+ * which belongs to our own realm (available on
+ * our client principal).
+ */
+ self_realm = krb5_principal_get_realm(ctx, init_principal);
+
+ code = krb5_parse_name(ctx, self_service, &self_princ);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_principal_set_realm(ctx, self_princ, self_realm);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_free_principal(ctx, self_princ);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds_opt_alloc(ctx, &options);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_free_principal(ctx, self_princ);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ if (s4u2proxy) {
+ /*
+ * If we want S4U2Proxy, we need the forwardable flag
+ * on the S4U2Self ticket.
+ */
+ krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
+ }
+
+ code = krb5_get_creds_opt_set_impersonate(ctx, options,
+ impersonate_principal);
+ if (code != 0) {
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_free_principal(ctx, self_princ);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds(ctx, options, tmp_cc,
+ self_princ, &s4u2self_creds);
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, self_princ);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ if (!s4u2proxy) {
+ krb5_cc_destroy(ctx, tmp_cc);
+
+ /*
+ * Now make sure we store the impersonated principal
+ * and creds instead of the TGT related stuff
+ * in the krb5_ccache of the caller.
+ */
+ code = krb5_copy_creds_contents(ctx, s4u2self_creds,
+ &store_creds);
+ krb5_free_creds(ctx, s4u2self_creds);
+ if (code != 0) {
+ return code;
}
- DEBUGADD(1,("smb_krb5_get_creds: using S4U2SELF impersonation as %s\n",
- client));
- TALLOC_FREE(client);
+
+ /*
+ * It's important to store the principal the KDC
+ * returned, as otherwise the caller would not find
+ * the S4U2Self ticket in the krb5_ccache lookup.
+ */
+ store_principal = store_creds.client;
+ goto store;
}
- done:
- if (!context) {
- return ret;
+ /*
+ * We are trying S4U2Proxy:
+ *
+ * We need the ticket from the S4U2Self step
+ * and our TGT in order to get the delegated ticket.
+ */
+ code = decode_Ticket((const uint8_t *)s4u2self_creds->ticket.data,
+ s4u2self_creds->ticket.length,
+ &s4u2self_ticket,
+ &s4u2self_ticketlen);
+ if (code != 0) {
+ krb5_free_creds(ctx, s4u2self_creds);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
}
- if (creds && ret) {
- krb5_free_creds(context, creds);
+ /*
+ * we need to remember the client principal of the
+ * S4U2Self stage and as it needs to match the one we
+ * will get for the S4U2Proxy stage. We need this
+ * in order to detect KDCs which does not support S4U2Proxy.
+ */
+ whitelist_principal = s4u2self_creds->client;
+ s4u2self_creds->client = NULL;
+ krb5_free_creds(ctx, s4u2self_creds);
+
+ /*
+ * For S4U2Proxy we also got a target service principal,
+ * which also belongs to our own realm (available on
+ * our client principal).
+ */
+ code = krb5_parse_name(ctx, target_service, &target_princ);
+ if (code != 0) {
+ free_Ticket(&s4u2self_ticket);
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_principal_set_realm(ctx, target_princ, self_realm);
+ if (code != 0) {
+ free_Ticket(&s4u2self_ticket);
+ krb5_free_principal(ctx, target_princ);
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds_opt_alloc(ctx, &options);
+ if (code != 0) {
+ free_Ticket(&s4u2self_ticket);
+ krb5_free_principal(ctx, target_princ);
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
+ krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_CONSTRAINED_DELEGATION);
+
+ code = krb5_get_creds_opt_set_ticket(ctx, options, &s4u2self_ticket);
+ free_Ticket(&s4u2self_ticket);
+ if (code != 0) {
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, target_princ);
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds(ctx, options, tmp_cc,
+ target_princ, &s4u2proxy_creds);
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, target_princ);
+ krb5_cc_destroy(ctx, tmp_cc);
+ if (code != 0) {
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ return code;
}
- if (server) {
- krb5_free_principal(context, server);
+
+ /*
+ * Now make sure we store the impersonated principal
+ * and creds instead of the TGT related stuff
+ * in the krb5_ccache of the caller.
+ */
+ code = krb5_copy_creds_contents(ctx, s4u2proxy_creds,
+ &store_creds);
+ krb5_free_creds(ctx, s4u2proxy_creds);
+ if (code != 0) {
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ return code;
+ }
+
+ /*
+ * It's important to store the principal the KDC
+ * returned, as otherwise the caller would not find
+ * the S4U2Self ticket in the krb5_ccache lookup.
+ */
+ store_principal = store_creds.client;
+
+ store:
+ if (blacklist_principal &&
+ krb5_principal_compare(ctx, store_creds.client, blacklist_principal)) {
+ char *sp = NULL;
+ char *ip = NULL;
+
+ code = krb5_unparse_name(ctx, blacklist_principal, &sp);
+ if (code != 0) {
+ sp = NULL;
+ }
+ code = krb5_unparse_name(ctx, impersonate_principal, &ip);
+ if (code != 0) {
+ ip = NULL;
+ }
+ DEBUG(1, ("kerberos_kinit_password_cc: "
+ "KDC returned self principal[%s] while impersonating [%s]\n",
+ sp?sp:"<no memory>",
+ ip?ip:"<no memory>"));
+
+ SAFE_FREE(sp);
+ SAFE_FREE(ip);
+
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_free_cred_contents(ctx, &store_creds);
+ return KRB5_FWD_BAD_PRINCIPAL;
}
- if (me) {
- krb5_free_principal(context, me);
+ if (blacklist_principal) {
+ krb5_free_principal(ctx, blacklist_principal);
}
- if (impersonate_princ) {
- krb5_free_principal(context, impersonate_princ);
+
+ if (whitelist_principal &&
+ !krb5_principal_compare(ctx, store_creds.client, whitelist_principal)) {
+ char *sp = NULL;
+ char *ep = NULL;
+
+ code = krb5_unparse_name(ctx, store_creds.client, &sp);
+ if (code != 0) {
+ sp = NULL;
+ }
+ code = krb5_unparse_name(ctx, whitelist_principal, &ep);
+ if (code != 0) {
+ ep = NULL;
+ }
+ DEBUG(1, ("kerberos_kinit_password_cc: "
+ "KDC returned wrong principal[%s] we expected [%s]\n",
+ sp?sp:"<no memory>",
+ ep?ep:"<no memory>"));
+
+ SAFE_FREE(sp);
+ SAFE_FREE(ep);
+
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_cred_contents(ctx, &store_creds);
+ return KRB5_FWD_BAD_PRINCIPAL;
}
- if (ccache) {
- krb5_cc_close(context, ccache);
+ if (whitelist_principal) {
+ krb5_free_principal(ctx, whitelist_principal);
}
- krb5_free_context(context);
- return ret;
+ code = krb5_cc_initialize(ctx, store_cc, store_principal);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+
+ code = krb5_cc_store_cred(ctx, store_cc, &store_creds);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+
+ if (expire_time) {
+ *expire_time = (time_t) store_creds.times.endtime;
+ }
+
+ if (kdc_time) {
+ *kdc_time = (time_t) store_creds.times.starttime;
+ }
+
+ krb5_free_cred_contents(ctx, &store_creds);
+
+ return 0;
+}
+#endif
+
+#if !defined(HAVE_KRB5_MAKE_PRINCIPAL) && defined(HAVE_KRB5_BUILD_PRINCIPAL_ALLOC_VA)
+krb5_error_code smb_krb5_make_principal(krb5_context context,
+ krb5_principal *principal,
+ const char *_realm, ...)
+{
+ krb5_error_code code;
+ bool free_realm;
+ char *realm;
+ va_list ap;
+
+ if (_realm) {
+ realm = _realm;
+ free_realm = false;
+ } else {
+ code = krb5_get_default_realm(context, &realm);
+ if (code) {
+ return code;
+ }
+ free_realm = true;
+ }
+
+ va_start(ap, _realm);
+ code = krb5_build_principal_alloc_va(context, principal,
+ strlen(realm), realm,
+ ap);
+ va_end(ap);
+
+ if (free_realm) {
+ krb5_free_default_realm(context, realm);
+ }
+
+ return code;
+}
+#endif
+
+#if !defined(HAVE_KRB5_CC_GET_LIFETIME) && defined(HAVE_KRB5_CC_RETRIEVE_CRED)
+/**
+ * @brief Get the lifetime of the initial ticket in the cache.
+ *
+ * @param[in] context The kerberos context.
+ *
+ * @param[in] id The credential cache to get the ticket lifetime.
+ *
+ * @param[out] t A pointer to a time value to store the lifetime.
+ *
+ * @return 0 on success, a krb5_error_code on error.
+ */
+krb5_error_code smb_krb5_cc_get_lifetime(krb5_context context,
+ krb5_ccache id,
+ time_t *t)
+{
+ krb5_cc_cursor cursor;
+ krb5_error_code kerr;
+ krb5_creds cred;
+ krb5_timestamp now;
+
+ *t = 0;
+
+ kerr = krb5_timeofday(context, &now);
+ if (kerr) {
+ return kerr;
+ }
+
+ kerr = krb5_cc_start_seq_get(context, id, &cursor);
+ if (kerr) {
+ return kerr;
+ }
+
+ while ((kerr = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) {
+#ifndef HAVE_FLAGS_IN_KRB5_CREDS
+ if (cred.ticket_flags & TKT_FLG_INITIAL) {
+#else
+ if (cred.flags.b.initial) {
+#endif
+ if (now < cred.times.endtime) {
+ *t = (time_t) (cred.times.endtime - now);
+ }
+ krb5_free_cred_contents(context, &cred);
+ break;
+ }
+ krb5_free_cred_contents(context, &cred);
+ }
+
+ krb5_cc_end_seq_get(context, id, &cursor);
+
+ return kerr;
+}
+#endif /* HAVE_KRB5_CC_GET_LIFETIME */
+
+#if !defined(HAVE_KRB5_FREE_CHECKSUM_CONTENTS) && defined(HAVE_FREE_CHECKSUM)
+void smb_krb5_free_checksum_contents(krb5_context ctx, krb5_checksum *cksum)
+{
+ free_Checksum(cksum);
+}
+#endif
+
+krb5_error_code smb_krb5_make_pac_checksum(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pac_data,
+ krb5_context context,
+ const krb5_keyblock *keyblock,
+ uint32_t *sig_type,
+ DATA_BLOB *sig_blob)
+{
+ krb5_error_code ret;
+ krb5_checksum cksum;
+#if defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CREATE_CHECKSUM)
+ krb5_crypto crypto;
+
+
+ ret = krb5_crypto_init(context,
+ keyblock,
+ 0,
+ &crypto);
+ if (ret) {
+ DEBUG(0,("krb5_crypto_init() failed: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ return ret;
+ }
+ ret = krb5_create_checksum(context,
+ crypto,
+ KRB5_KU_OTHER_CKSUM,
+ 0,
+ pac_data->data,
+ pac_data->length,
+ &cksum);
+ if (ret) {
+ DEBUG(2, ("PAC Verification failed: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ }
+
+ krb5_crypto_destroy(context, crypto);
+
+ if (ret) {
+ return ret;
+ }
+
+ *sig_type = cksum.cksumtype;
+ *sig_blob = data_blob_talloc(mem_ctx,
+ cksum.checksum.data,
+ cksum.checksum.length);
+#elif defined(HAVE_KRB5_C_MAKE_CHECKSUM)
+ krb5_data input;
+
+ input.data = (char *)pac_data->data;
+ input.length = pac_data->length;
+
+ ret = krb5_c_make_checksum(context,
+ 0,
+ keyblock,
+ KRB5_KEYUSAGE_APP_DATA_CKSUM,
+ &input,
+ &cksum);
+ if (ret) {
+ DEBUG(2, ("PAC Verification failed: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ return ret;
+ }
+
+ *sig_type = cksum.checksum_type;
+ *sig_blob = data_blob_talloc(mem_ctx,
+ cksum.contents,
+ cksum.length);
+
+#else
+#error krb5_create_checksum or krb5_c_make_checksum not available
+#endif /* HAVE_KRB5_C_MAKE_CHECKSUM */
+ smb_krb5_free_checksum_contents(context, &cksum);
+
+ return 0;
}
+
/*
* smb_krb5_principal_get_realm
*