#ifdef HAVE_KRB5
-#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE
-#define KRB5_KEY_TYPE(k) ((k)->keytype)
+#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE /* Heimdal */
+#define KRB5_KEY_TYPE(k) ((k)->keytype)
#define KRB5_KEY_LENGTH(k) ((k)->keyvalue.length)
#define KRB5_KEY_DATA(k) ((k)->keyvalue.data)
-#else
+#else /* MIT */
#define KRB5_KEY_TYPE(k) ((k)->enctype)
#define KRB5_KEY_LENGTH(k) ((k)->length)
#define KRB5_KEY_DATA(k) ((k)->contents)
krb5_error_code ret;
char *utf8_name;
+ *principal = NULL;
if (push_utf8_allocate(&utf8_name, name) == (size_t)-1) {
return ENOMEM;
}
krb5_error_code ret;
char *utf8_name;
+ *unix_name = NULL;
ret = krb5_unparse_name(context, principal, &utf8_name);
if (ret) {
return ret;
}
#endif
-#if defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES) && !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
+#if !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
+
+#if defined(HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES)
+
+/* With MIT kerberos, we should use krb5_set_default_tgs_enctypes in preference
+ * to krb5_set_default_tgs_ktypes. See
+ * http://lists.samba.org/archive/samba-technical/2006-July/048271.html
+ *
+ * If the MIT libraries are not exporting internal symbols, we will end up in
+ * this branch, which is correct. Otherwise we will continue to use the
+ * internal symbol
+ */
+ krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
+{
+ return krb5_set_default_tgs_enctypes(ctx, enc);
+}
+
+#elif defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES)
+
+/* Heimdal */
krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
{
return krb5_set_default_in_tkt_etypes(ctx, enc);
}
-#endif
+
+#endif /* HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES */
+
+#endif /* HAVE_KRB5_SET_DEFAULT_TGS_KTYPES */
#if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS)
/* HEIMDAL */
return ret;
}
- ret = krb5_string_to_key_salt(context, enctype, password->data, salt, key);
+ ret = krb5_string_to_key_salt(context, enctype, (const char *)password->data, salt, key);
krb5_free_salt(context, salt);
return ret;
}
#error UNKNOWN_GET_ENCTYPES_FUNCTIONS
#endif
- void free_kerberos_etypes(krb5_context context,
- krb5_enctype *enctypes)
-{
-#if defined(HAVE_KRB5_FREE_KTYPES)
- krb5_free_ktypes(context, enctypes);
- return;
-#else
- SAFE_FREE(enctypes);
- return;
-#endif
-}
-
#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context,
krb5_auth_context auth_context,
}
#endif
+BOOL unwrap_edata_ntstatus(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *edata,
+ DATA_BLOB *edata_out)
+{
+ DATA_BLOB edata_contents;
+ ASN1_DATA data;
+ int edata_type;
+
+ if (!edata->length) {
+ return False;
+ }
+
+ asn1_load(&data, *edata);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_read_Integer(&data, &edata_type);
+
+ if (edata_type != KRB5_PADATA_PW_SALT) {
+ DEBUG(0,("edata is not of required type %d but of type %d\n",
+ KRB5_PADATA_PW_SALT, edata_type));
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_start_tag(&data, ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data, &edata_contents);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_free(&data);
+
+ *edata_out = data_blob_talloc(mem_ctx, edata_contents.data, edata_contents.length);
+
+ data_blob_free(&edata_contents);
+
+ return True;
+}
+
+
BOOL unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, DATA_BLOB *unwrapped_pac_data)
{
DATA_BLOB pac_contents;
}
#if !defined(HAVE_KRB5_LOCATE_KDC)
- krb5_error_code krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters)
+
+/* krb5_locate_kdc is an internal MIT symbol. MIT are not yet willing to commit
+ * to a public interface for this functionality, so we have to be able to live
+ * without it if the MIT libraries are hiding their internal symbols.
+ */
+
+#if defined(KRB5_KRBHST_INIT)
+/* Heimdal */
+ krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters)
{
krb5_krbhst_handle hnd;
krb5_krbhst_info *hinfo;
rc = krb5_krbhst_init(ctx, realm->data, KRB5_KRBHST_KDC, &hnd);
if (rc) {
- DEBUG(0, ("krb5_locate_kdc: krb5_krbhst_init failed (%s)\n", error_message(rc)));
+ DEBUG(0, ("smb_krb5_locate_kdc: krb5_krbhst_init failed (%s)\n", error_message(rc)));
return rc;
}
krb5_krbhst_reset(ctx, hnd);
if (!num_kdcs) {
- DEBUG(0, ("krb5_locate_kdc: zero kdcs found !\n"));
+ DEBUG(0, ("smb_krb5_locate_kdc: zero kdcs found !\n"));
krb5_krbhst_free(ctx, hnd);
return -1;
}
sa = SMB_MALLOC_ARRAY( struct sockaddr, num_kdcs );
if (!sa) {
- DEBUG(0, ("krb5_locate_kdc: malloc failed\n"));
+ DEBUG(0, ("smb_krb5_locate_kdc: malloc failed\n"));
krb5_krbhst_free(ctx, hnd);
naddrs = 0;
return -1;
*addr_pp = sa;
return 0;
}
-#endif
+
+#else /* ! defined(KRB5_KRBHST_INIT) */
+
+ krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm,
+ struct sockaddr **addr_pp, int *naddrs, int get_masters)
+{
+ DEBUG(0, ("unable to explicitly locate the KDC on this platform\n"));
+ return KRB5_KDC_UNREACH;
+}
+
+#endif /* KRB5_KRBHST_INIT */
+
+#else /* ! HAVE_KRB5_LOCATE_KDC */
+
+ krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm,
+ struct sockaddr **addr_pp, int *naddrs, int get_masters)
+{
+ return krb5_locate_kdc(ctx, realm, addr_pp, naddrs, get_masters);
+}
+
+#endif /* HAVE_KRB5_LOCATE_KDC */
#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
void krb5_free_unparsed_name(krb5_context context, char *val)
const krb5_flags ap_req_options,
const char *principal,
krb5_ccache ccache,
- krb5_data *outbuf)
+ krb5_data *outbuf,
+ time_t *expire_time)
{
krb5_error_code retval;
krb5_principal server;
}
while (!creds_ready && (i < maxtries)) {
+
if ((retval = krb5_get_credentials(context, 0, ccache,
&creds, &credsp))) {
DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
krb5_set_real_time(context, t + time_offset + 1, 0);
}
- if (!ads_cleanup_expired_creds(context, ccache, credsp))
+ if (!ads_cleanup_expired_creds(context, ccache, credsp)) {
creds_ready = True;
+ }
i++;
}
http_timestring((unsigned)credsp->times.endtime),
(unsigned)credsp->times.endtime));
+ if (expire_time) {
+ *expire_time = (time_t)credsp->times.endtime;
+ }
+
in_data.length = 0;
retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
&in_data, credsp, outbuf);
*/
int cli_krb5_get_ticket(const char *principal, time_t time_offset,
DATA_BLOB *ticket, DATA_BLOB *session_key_krb5,
- uint32 extra_ap_opts, const char *ccname)
+ uint32 extra_ap_opts, const char *ccname,
+ time_t *tgs_expire)
+
{
krb5_error_code retval;
krb5_data packet;
&auth_context,
AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts,
principal,
- ccdef, &packet))) {
+ ccdef, &packet,
+ tgs_expire))) {
goto failed;
}
else
err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
if (err == 0 && skey != NULL) {
- DEBUG(10, ("Got KRB5 session key of length %d\n", KRB5_KEY_LENGTH(skey)));
+ DEBUG(10, ("Got KRB5 session key of length %d\n", (int)KRB5_KEY_LENGTH(skey)));
*session_key = data_blob(KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
static krb5_data kdata;
kdata.data = (char *)krb5_principal_get_comp_string(context, principal, i);
- kdata.length = strlen(kdata.data);
+ kdata.length = strlen((const char *)kdata.data);
return &kdata;
}
#endif
#endif
}
+#ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */
static int get_kvno_from_ap_req(krb5_ap_req *ap_req)
{
#ifdef HAVE_TICKET_POINTER_IN_KRB5_AP_REQ /* MIT */
return ap_req->ticket->enc_part.enctype;
#endif
}
+#endif /* HAVE_KRB5_DECODE_AP_REQ */
static krb5_error_code
get_key_from_keytab(krb5_context context,
return ret;
}
- void smb_krb5_free_ap_req(krb5_context context,
- krb5_ap_req *ap_req)
-{
-#ifdef HAVE_KRB5_FREE_AP_REQ /* MIT */
- krb5_free_ap_req(context, ap_req);
-#elif defined(HAVE_FREE_AP_REQ) /* Heimdal */
- free_AP_REQ(ap_req);
-#else
-#error UNKNOWN_KRB5_AP_REQ_FREE_FUNCTION
-#endif
-}
-
/* Prototypes */
-#if defined(HAVE_DECODE_KRB5_AP_REQ) /* MIT */
-krb5_error_code decode_krb5_ap_req(const krb5_data *code, krb5_ap_req **rep);
-#endif
krb5_error_code smb_krb5_get_keyinfo_from_ap_req(krb5_context context,
const krb5_data *inbuf,
krb5_kvno *kvno,
krb5_enctype *enctype)
{
- krb5_error_code ret;
#ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */
{
+ krb5_error_code ret;
krb5_ap_req ap_req;
ret = krb5_decode_ap_req(context, inbuf, &ap_req);
*kvno = get_kvno_from_ap_req(&ap_req);
*enctype = get_enctype_from_ap_req(&ap_req);
- smb_krb5_free_ap_req(context, &ap_req);
- }
-#elif defined(HAVE_DECODE_KRB5_AP_REQ) /* MIT */
- {
- krb5_ap_req *ap_req = NULL;
-
- ret = decode_krb5_ap_req(inbuf, &ap_req);
- if (ret)
- return ret;
-
- *kvno = get_kvno_from_ap_req(ap_req);
- *enctype = get_enctype_from_ap_req(ap_req);
-
- smb_krb5_free_ap_req(context, ap_req);
+ free_AP_REQ(&ap_req);
+ return 0;
}
-#else
-#error UNKOWN_KRB5_AP_REQ_DECODING_FUNCTION
#endif
- return ret;
+
+ /* Possibly not an appropriate error code. */
+ return KRB5KDC_ERR_BADOPTION;
}
krb5_error_code krb5_rd_req_return_keyblock_from_keytab(krb5_context context,
return ret;
}
+#ifdef KRB5_TICKET_HAS_KEYINFO
+ enctype = (*ticket)->enc_part.enctype;
+ kvno = (*ticket)->enc_part.kvno;
+#else
ret = smb_krb5_get_keyinfo_from_ap_req(context, inbuf, &kvno, &enctype);
if (ret) {
return ret;
}
+#endif
ret = get_key_from_keytab(context,
server,
krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, /* FILE:/tmp/krb5cc_0 */
const char *client_string, /* gd@BER.SUSE.DE */
const char *service_string, /* krbtgt/BER.SUSE.DE@BER.SUSE.DE */
- time_t *new_start_time)
+ time_t *expire_time)
{
krb5_error_code ret;
krb5_context context = NULL;
ret = krb5_cc_store_cred(context, ccache, &creds);
- if (new_start_time) {
- *new_start_time = (time_t) creds.times.renew_till;
+ if (expire_time) {
+ *expire_time = (time_t) creds.times.endtime;
}
krb5_free_cred_contents(context, &creds);
}
} else {
/* build tgt service by default */
- client_realm = krb5_princ_realm(context, client);
+ client_realm = krb5_princ_realm(context, creds_in.client);
+ if (!client_realm) {
+ ret = ENOMEM;
+ goto done;
+ }
ret = krb5_make_principal(context, &creds_in.server, *client_realm, KRB5_TGS_NAME, *client_realm, NULL);
if (ret) {
goto done;
ret = krb5_cc_store_cred(context, ccache, creds);
- if (new_start_time) {
- *new_start_time = (time_t) creds->times.renew_till;
+ if (expire_time) {
+ *expire_time = (time_t) creds->times.endtime;
}
krb5_free_cred_contents(context, &creds_in);
krb5_free_creds(context, creds);
}
#else
-#error No suitable krb5 ticket renew function available
+#error NO_SUITABKE_KRB5_TICKET_RENEW_FUNCTION_AVAILABLE
#endif
return ret;
}
+ krb5_error_code smb_krb5_get_init_creds_opt_alloc(krb5_context context,
+ krb5_get_init_creds_opt **opt)
+{
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
+ /* Heimdal or modern MIT version */
+ return krb5_get_init_creds_opt_alloc(context, opt);
+#else
+ /* Historical MIT version */
+ krb5_get_init_creds_opt *my_opt;
+
+ *opt = NULL;
+
+ if ((my_opt = SMB_MALLOC_P(krb5_get_init_creds_opt)) == NULL) {
+ return ENOMEM;
+ }
+
+ krb5_get_init_creds_opt_init(my_opt);
+
+ *opt = my_opt;
+ return 0;
+#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC */
+}
+
+ void smb_krb5_get_init_creds_opt_free(krb5_context context,
+ krb5_get_init_creds_opt *opt)
+{
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE
+
+#ifdef KRB5_CREDS_OPT_FREE_REQUIRES_CONTEXT
+ /* Modern MIT or Heimdal version */
+ krb5_get_init_creds_opt_free(context, opt);
+#else
+ /* Heimdal version */
+ krb5_get_init_creds_opt_free(opt);
+#endif /* KRB5_CREDS_OPT_FREE_REQUIRES_CONTEXT */
+
+#else /* HAVE_KRB5_GET_INIT_CREDS_OPT_FREE */
+ /* Historical MIT version */
+ SAFE_FREE(opt);
+ opt = NULL;
+#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_FREE */
+}
+
+ krb5_enctype smb_get_enctype_from_kt_entry(const krb5_keytab_entry *kt_entry)
+{
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */
+ return kt_entry->key.enctype;
+#elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK) /* Heimdal */
+ return kt_entry->keyblock.keytype;
+#else
+#error UNKNOWN_KRB5_KEYTAB_ENTRY_KEYBLOCK_FORMAT
+#endif
+}
+
+
+/* caller needs to free etype_s */
+ krb5_error_code smb_krb5_enctype_to_string(krb5_context context,
+ krb5_enctype enctype,
+ char **etype_s)
+{
+#ifdef HAVE_KRB5_ENCTYPE_TO_STRING_WITH_KRB5_CONTEXT_ARG
+ return krb5_enctype_to_string(context, enctype, etype_s); /* Heimdal */
+#elif defined(HAVE_KRB5_ENCTYPE_TO_STRING_WITH_SIZE_T_ARG)
+ char buf[256];
+ krb5_error_code ret = krb5_enctype_to_string(enctype, buf, 256); /* MIT */
+ if (ret) {
+ return ret;
+ }
+ *etype_s = SMB_STRDUP(buf);
+ if (!*etype_s) {
+ return ENOMEM;
+ }
+ return ret;
+#else
+#error UNKNOWN_KRB5_ENCTYPE_TO_STRING_FUNCTION
+#endif
+}
+
+ krb5_error_code smb_krb5_mk_error(krb5_context context,
+ krb5_error_code error_code,
+ const krb5_principal server,
+ krb5_data *reply)
+{
+#ifdef HAVE_SHORT_KRB5_MK_ERROR_INTERFACE /* MIT */
+ /*
+ * The MIT interface is *terrible*.
+ * We have to construct this ourselves...
+ */
+ krb5_error e;
+
+ memset(&e, 0, sizeof(e));
+ krb5_us_timeofday(context, &e.stime, &e.susec);
+ e.server = server;
+#if defined(krb5_err_base)
+ e.error = error_code - krb5_err_base;
+#elif defined(ERROR_TABLE_BASE_krb5)
+ e.error = error_code - ERROR_TABLE_BASE_krb5;
+#else
+ e.error = error_code; /* Almost certainly wrong, but what can we do... ? */
+#endif
+
+ return krb5_mk_error(context, &e, reply);
+#else /* Heimdal. */
+ return krb5_mk_error(context,
+ error_code,
+ NULL,
+ NULL, /* e_data */
+ NULL,
+ server,
+ NULL,
+ NULL,
+ reply);
+#endif
+}
+
#else /* HAVE_KRB5 */
/* this saves a few linking headaches */
int cli_krb5_get_ticket(const char *principal, time_t time_offset,
DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
- const char *ccname)
+ const char *ccname, time_t *tgs_expire)
{
DEBUG(0,("NO KERBEROS SUPPORT\n"));
return 1;