*/
#include "includes.h"
+#include "system/filesys.h"
#include "krb5_samba.h"
#include "lib/util/asn1.h"
+#ifdef HAVE_COM_ERR_H
+#include <com_err.h>
+#endif /* HAVE_COM_ERR_H */
+
#ifndef KRB5_AUTHDATA_WIN2K_PAC
#define KRB5_AUTHDATA_WIN2K_PAC 128
#endif
#error UNKNOWN_ADDRTYPE
#endif
-#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_C_STRING_TO_KEY)
-/* MIT */
-int create_kerberos_key_from_string_direct(krb5_context context,
- krb5_principal host_princ,
- krb5_data *password,
- krb5_keyblock *key,
- krb5_enctype enctype)
+/**
+* @brief Create a keyblock based on input parameters
+*
+* @param context The krb5_context
+* @param host_princ The krb5_principal to use
+* @param salt The optional salt, if omitted, salt is calculated with
+* the provided principal.
+* @param password The krb5_data containing the password
+* @param enctype The krb5_enctype to use for the keyblock generation
+* @param key The returned krb5_keyblock, caller needs to free with
+* krb5_free_keyblock().
+*
+* @return krb5_error_code
+*/
+int smb_krb5_create_key_from_string(krb5_context context,
+ krb5_const_principal host_princ,
+ krb5_data *salt,
+ krb5_data *password,
+ krb5_enctype enctype,
+ krb5_keyblock *key)
{
int ret = 0;
- krb5_data salt;
- ret = krb5_principal2salt(context, host_princ, &salt);
- if (ret) {
- DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
- return ret;
+ if (host_princ == NULL && salt == NULL) {
+ return -1;
}
- ret = krb5_c_string_to_key(context, enctype, password, &salt, key);
- SAFE_FREE(salt.data);
- return ret;
+#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_C_STRING_TO_KEY)
+{/* MIT */
+ krb5_data _salt;
+
+ if (salt == NULL) {
+ ret = krb5_principal2salt(context, host_princ, &_salt);
+ if (ret) {
+ DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+ } else {
+ _salt = *salt;
+ }
+ ret = krb5_c_string_to_key(context, enctype, password, &_salt, key);
+ if (salt == NULL) {
+ SAFE_FREE(_salt.data);
+ }
}
#elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
+{/* Heimdal */
+ krb5_salt _salt;
+
+ if (salt == NULL) {
+ ret = krb5_get_pw_salt(context, host_princ, &_salt);
+ if (ret) {
+ DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+ } else {
+ _salt.saltvalue = *salt;
+ _salt.salttype = KRB5_PW_SALT;
+ }
+
+ ret = krb5_string_to_key_salt(context, enctype, (const char *)password->data, _salt, key);
+ if (salt == NULL) {
+ krb5_free_salt(context, _salt);
+ }
+}
+#else
+#error UNKNOWN_CREATE_KEY_FUNCTIONS
+#endif
+ return ret;
+}
+
+/**
+* @brief Create a salt for a given principal
+*
+* @param context The initialized krb5_context
+* @param host_princ The krb5_principal to create the salt for
+* @param psalt A pointer to a krb5_data struct
+*
+* caller has to free the contents of psalt with kerberos_free_data_contents
+* when function has succeeded
+*
+* @return krb5_error_code, returns 0 on success, error code otherwise
+*/
+
+int smb_krb5_get_pw_salt(krb5_context context,
+ krb5_const_principal host_princ,
+ krb5_data *psalt)
+#if defined(HAVE_KRB5_GET_PW_SALT)
/* Heimdal */
-int create_kerberos_key_from_string_direct(krb5_context context,
- krb5_principal host_princ,
- krb5_data *password,
- krb5_keyblock *key,
- krb5_enctype enctype)
{
int ret;
krb5_salt salt;
ret = krb5_get_pw_salt(context, host_princ, &salt);
if (ret) {
- DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret)));
return ret;
}
- ret = krb5_string_to_key_salt(context, enctype, (const char *)password->data, salt, key);
- krb5_free_salt(context, salt);
+ psalt->data = salt.saltvalue.data;
+ psalt->length = salt.saltvalue.length;
return ret;
}
+#elif defined(HAVE_KRB5_PRINCIPAL2SALT)
+/* MIT */
+{
+ return krb5_principal2salt(context, host_princ, psalt);
+}
#else
-#error UNKNOWN_CREATE_KEY_FUNCTIONS
+#error UNKNOWN_SALT_FUNCTIONS
#endif
#if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
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 (!asn1_load(data, *edata)) goto err;
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err;
+ if (!asn1_read_Integer(data, &edata_type)) goto err;
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;
+ goto err;
}
- asn1_start_tag(data, ASN1_CONTEXT(2));
- asn1_read_OctetString(data, talloc_tos(), &edata_contents);
- asn1_end_tag(data);
- asn1_end_tag(data);
- asn1_end_tag(data);
+ if (!asn1_start_tag(data, ASN1_CONTEXT(2))) goto err;
+ if (!asn1_read_OctetString(data, talloc_tos(), &edata_contents)) goto err;
+ if (!asn1_end_tag(data)) goto err;
+ if (!asn1_end_tag(data)) goto err;
+ if (!asn1_end_tag(data)) goto err;
asn1_free(data);
*edata_out = data_blob_talloc(mem_ctx, edata_contents.data, edata_contents.length);
data_blob_free(&edata_contents);
return true;
+
+ err:
+
+ asn1_free(data);
+ return false;
}
#endif
}
+/*
+ * @brief copy a buffer into a krb5_data struct
+ *
+ * @param[in] p The krb5_data
+ * @param[in] data The data to copy
+ * @param[in] length The length of the data to copy
+ * @return krb5_error_code
+ *
+ * Caller has to free krb5_data with kerberos_free_data_contents().
+ */
+
+krb5_error_code krb5_copy_data_contents(krb5_data *p,
+ const void *data,
+ size_t len)
+{
+#if defined(HAVE_KRB5_DATA_COPY)
+ return krb5_data_copy(p, data, len);
+#else
+ if (len) {
+ p->data = malloc(len);
+ if (p->data == NULL) {
+ return ENOMEM;
+ }
+ memmove(p->data, data, len);
+ } else {
+ p->data = NULL;
+ }
+ p->length = len;
+ p->magic = KV5M_DATA;
+ return 0;
+#endif
+}
+
/*
get a kerberos5 ticket for the given service
*/
bool ret = false;
if (remote) {
+#ifdef HAVE_KRB5_AUTH_CON_GETRECVSUBKEY
+ err = krb5_auth_con_getrecvsubkey(context,
+ auth_context,
+ &skey);
+#else /* HAVE_KRB5_AUTH_CON_GETRECVSUBKEY */
err = krb5_auth_con_getremotesubkey(context,
auth_context, &skey);
+#endif /* HAVE_KRB5_AUTH_CON_GETRECVSUBKEY */
} else {
+#ifdef HAVE_KRB5_AUTH_CON_GETSENDSUBKEY
+ err = krb5_auth_con_getsendsubkey(context,
+ auth_context,
+ &skey);
+#else /* HAVE_KRB5_AUTH_CON_GETSENDSUBKEY */
err = krb5_auth_con_getlocalsubkey(context,
auth_context, &skey);
+#endif /* HAVE_KRB5_AUTH_CON_GETSENDSUBKEY */
}
if (err || skey == NULL) {
}
#endif
+/*
+ * @brief Get talloced string component of a principal
+ *
+ * @param[in] mem_ctx The TALLOC_CTX
+ * @param[in] context The krb5_context
+ * @param[in] principal The principal
+ * @param[in] component The component
+ * @return string component
+ *
+ * Caller must talloc_free if the return value is not NULL.
+ *
+ */
+
+/* caller has to free returned string with talloc_free() */
+char *smb_krb5_principal_get_comp_string(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_const_principal principal,
+ unsigned int component)
+{
+#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
+ return talloc_strdup(mem_ctx, krb5_principal_get_comp_string(context, principal, component));
+#else
+ krb5_data *data;
+
+ if (component >= krb5_princ_size(context, principal)) {
+ return NULL;
+ }
+
+ data = krb5_princ_component(context, principal, component);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return talloc_strndup(mem_ctx, data->data, data->length);
+#endif
+}
+
/* Prototypes */
krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, /* FILE:/tmp/krb5cc_0 */
/**********************************************************************
* Open a krb5 keytab with flags, handles readonly or readwrite access and
- * allows to process non-default keytab names.
+ * allows one to process non-default keytab names.
* @param context krb5_context
* @param keytab_name_req string
* @param write_access bool if writable keytab is required
#define MAX_KEYTAB_NAME_LEN 1100
#endif
-krb5_error_code smb_krb5_open_keytab(krb5_context context,
- const char *keytab_name_req,
- bool write_access,
- krb5_keytab *keytab)
+krb5_error_code smb_krb5_open_keytab_relative(krb5_context context,
+ const char *keytab_name_req,
+ bool write_access,
+ krb5_keytab *keytab)
{
krb5_error_code ret = 0;
TALLOC_CTX *mem_ctx;
goto resolve;
}
- if (keytab_name_req[0] != '/') {
- ret = KRB5_KT_BADNAME;
- goto out;
- }
-
tmp = talloc_asprintf(mem_ctx, "%s:%s", pragma, keytab_name_req);
if (!tmp) {
ret = ENOMEM;
return ret;
}
+krb5_error_code smb_krb5_open_keytab(krb5_context context,
+ const char *keytab_name_req,
+ bool write_access,
+ krb5_keytab *keytab)
+{
+ if (keytab_name_req != NULL) {
+ if (keytab_name_req[0] != '/') {
+ return KRB5_KT_BADNAME;
+ }
+ }
+
+ return smb_krb5_open_keytab_relative(context,
+ keytab_name_req,
+ write_access,
+ keytab);
+}
+
krb5_error_code smb_krb5_keytab_name(TALLOC_CTX *mem_ctx,
krb5_context context,
krb5_keytab keytab,
return ret;
}
+/**
+ * @brief Seek and delete old entries in a keytab based on the passed
+ * principal.
+ *
+ * @param[in] context The KRB5 context to use.
+ *
+ * @param[in] keytab The keytab to operate on.
+ *
+ * @param[in] kvno The kvnco to use.
+ *
+ * @param[in] princ_s The principal as a string to search for.
+ *
+ * @param[in] princ The principal as a krb5_principal to search for.
+ *
+ * @param[in] flush Weather to flush the complete keytab.
+ *
+ * @param[in] keep_old_entries Keep the entry with the previous kvno.
+ *
+ * @retval 0 on Sucess
+ *
+ * @return An appropriate KRB5 error code.
+ */
+krb5_error_code smb_krb5_kt_seek_and_delete_old_entries(krb5_context context,
+ krb5_keytab keytab,
+ krb5_kvno kvno,
+ krb5_enctype enctype,
+ const char *princ_s,
+ krb5_principal princ,
+ bool flush,
+ bool keep_old_entries)
+{
+ krb5_error_code ret;
+ krb5_kt_cursor cursor;
+ krb5_kt_cursor zero_csr;
+ krb5_keytab_entry kt_entry;
+ krb5_keytab_entry zero_kt_entry;
+ char *ktprinc = NULL;
+ krb5_kvno old_kvno = kvno - 1;
+ TALLOC_CTX *tmp_ctx;
+
+ ZERO_STRUCT(cursor);
+ ZERO_STRUCT(zero_csr);
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(zero_kt_entry);
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret == KRB5_KT_END || ret == ENOENT ) {
+ /* no entries */
+ return 0;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ DEBUG(3, (__location__ ": Will try to delete old keytab entries\n"));
+ while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
+ bool name_ok = false;
+ krb5_enctype kt_entry_enctype =
+ smb_get_enctype_from_kt_entry(&kt_entry);
+
+ if (!flush && (princ_s != NULL)) {
+ ret = smb_krb5_unparse_name(tmp_ctx, context,
+ kt_entry.principal,
+ &ktprinc);
+ if (ret) {
+ DEBUG(1, (__location__
+ ": smb_krb5_unparse_name failed "
+ "(%s)\n", error_message(ret)));
+ goto out;
+ }
+
+#ifdef HAVE_KRB5_KT_COMPARE
+ name_ok = krb5_kt_compare(context, &kt_entry,
+ princ, 0, 0);
+#else
+ name_ok = (strcmp(ktprinc, princ_s) == 0);
+#endif
+
+ if (!name_ok) {
+ DEBUG(10, (__location__ ": ignoring keytab "
+ "entry principal %s, kvno = %d\n",
+ ktprinc, kt_entry.vno));
+
+ /* Not a match,
+ * just free this entry and continue. */
+ ret = smb_krb5_kt_free_entry(context,
+ &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1, (__location__
+ ": smb_krb5_kt_free_entry "
+ "failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ TALLOC_FREE(ktprinc);
+ continue;
+ }
+
+ TALLOC_FREE(ktprinc);
+ }
+
+ /*------------------------------------------------------------
+ * Save the entries with kvno - 1. This is what microsoft does
+ * to allow people with existing sessions that have kvno - 1
+ * to still work. Otherwise, when the password for the machine
+ * changes, all kerberizied sessions will 'break' until either
+ * the client reboots or the client's session key expires and
+ * they get a new session ticket with the new kvno.
+ * Some keytab files only store the kvno in 8bits, limit
+ * the compare accordingly.
+ */
+
+ if (!flush && ((kt_entry.vno & 0xff) == (old_kvno & 0xff))) {
+ DEBUG(5, (__location__ ": Saving previous (kvno %d) "
+ "entry for principal: %s.\n",
+ old_kvno, princ_s));
+ continue;
+ }
+
+ if (keep_old_entries) {
+ DEBUG(5, (__location__ ": Saving old (kvno %d) "
+ "entry for principal: %s.\n",
+ kvno, princ_s));
+ continue;
+ }
+
+ if (!flush &&
+ (kt_entry.vno == kvno) &&
+ (kt_entry_enctype != enctype))
+ {
+ DEBUG(5, (__location__ ": Saving entry with kvno [%d] "
+ "enctype [%d] for principal: %s.\n",
+ kvno, kt_entry_enctype, princ_s));
+ continue;
+ }
+
+ DEBUG(5, (__location__ ": Found old entry for principal: %s "
+ "(kvno %d) - trying to remove it.\n",
+ princ_s, kt_entry.vno));
+
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(1, (__location__ ": krb5_kt_end_seq_get() "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
+ if (ret) {
+ DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ DEBUG(5, (__location__ ": removed old entry for principal: "
+ "%s (kvno %d).\n", princ_s, kt_entry.vno));
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(1, (__location__ ": krb5_kt_start_seq() failed "
+ "(%s)\n", error_message(ret)));
+ goto out;
+ }
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ }
+
+out:
+ talloc_free(tmp_ctx);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ if (memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ return ret;
+}
+
+/**
+ * @brief Add a keytab entry for the given principal
+ *
+ * @param[in] context The krb5 context to use.
+ *
+ * @param[in] keytab The keytab to add the entry to.
+ *
+ * @param[in] kvno The kvno to use.
+ *
+ * @param[in] princ_s The principal as a string.
+ *
+ * @param[in] salt_principal The salt principal to salt the password with.
+ * Only needed for keys which support salting.
+ * If no salt is used set no_salt to false and
+ * pass NULL here.
+ *
+ * @param[in] enctype The encryption type of the keytab entry.
+ *
+ * @param[in] password The password of the keytab entry.
+ *
+ * @param[in] no_salt If the password should not be salted. Normally
+ * this is only set to false for encryption types
+ * which do not support salting like RC4.
+ *
+ * @param[in] keep_old_entries Wether to keep or delte old keytab entries.
+ *
+ * @retval 0 on Success
+ *
+ * @return A corresponding KRB5 error code.
+ *
+ * @see smb_krb5_open_keytab()
+ */
+krb5_error_code smb_krb5_kt_add_entry(krb5_context context,
+ krb5_keytab keytab,
+ krb5_kvno kvno,
+ const char *princ_s,
+ const char *salt_principal,
+ krb5_enctype enctype,
+ krb5_data *password,
+ bool no_salt,
+ bool keep_old_entries)
+{
+ krb5_error_code ret;
+ krb5_keytab_entry kt_entry;
+ krb5_principal princ = NULL;
+ krb5_keyblock *keyp;
+
+ ZERO_STRUCT(kt_entry);
+
+ ret = smb_krb5_parse_name(context, princ_s, &princ);
+ if (ret) {
+ DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
+ "failed (%s)\n", princ_s, error_message(ret)));
+ goto out;
+ }
+
+ /* Seek and delete old keytab entries */
+ ret = smb_krb5_kt_seek_and_delete_old_entries(context,
+ keytab,
+ kvno,
+ enctype,
+ princ_s,
+ princ,
+ false,
+ keep_old_entries);
+ if (ret) {
+ goto out;
+ }
+
+ /* If we get here, we have deleted all the old entries with kvno's
+ * not equal to the current kvno-1. */
+
+ keyp = KRB5_KT_KEY(&kt_entry);
+
+ if (no_salt) {
+ KRB5_KEY_DATA(keyp) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
+ if (KRB5_KEY_DATA(keyp) == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ memcpy(KRB5_KEY_DATA(keyp), password->data, password->length);
+ KRB5_KEY_LENGTH(keyp) = password->length;
+ KRB5_KEY_TYPE(keyp) = enctype;
+ } else {
+ krb5_principal salt_princ = NULL;
+
+ /* Now add keytab entries for all encryption types */
+ ret = smb_krb5_parse_name(context, salt_principal, &salt_princ);
+ if (ret) {
+ DBG_WARNING("krb5_parse_name(%s) failed (%s)\n",
+ salt_principal, error_message(ret));
+ goto out;
+ }
+
+ ret = smb_krb5_create_key_from_string(context,
+ salt_princ,
+ NULL,
+ password,
+ enctype,
+ keyp);
+ krb5_free_principal(context, salt_princ);
+ if (ret != 0) {
+ goto out;
+ }
+ }
+
+ kt_entry.principal = princ;
+ kt_entry.vno = kvno;
+
+ DEBUG(3, (__location__ ": adding keytab entry for (%s) with "
+ "encryption type (%d) and version (%d)\n",
+ princ_s, enctype, kt_entry.vno));
+ ret = krb5_kt_add_entry(context, keytab, &kt_entry);
+ krb5_free_keyblock_contents(context, keyp);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1, (__location__ ": adding entry to keytab "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+out:
+ if (princ) {
+ krb5_free_principal(context, princ);
+ }
+
+ return ret;
+}
+
#if defined(HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE) && \
defined(HAVE_KRB5_GET_CREDS_OPT_ALLOC) && \
defined(HAVE_KRB5_GET_CREDS)
#endif /* HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE */
#ifdef HAVE_KRB5_GET_CREDENTIALS_FOR_USER
+
+#if !HAVE_DECL_KRB5_GET_CREDENTIALS_FOR_USER
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
+ krb5_ccache ccache, krb5_creds *in_creds,
+ krb5_data *subject_cert,
+ krb5_creds **out_creds);
+#endif /* !HAVE_DECL_KRB5_GET_CREDENTIALS_FOR_USER */
+
static krb5_error_code smb_krb5_get_credentials_for_user(krb5_context context,
krb5_ccache ccache,
krb5_principal me,
krb5_error_code ret;
krb5_creds in_creds;
-#if !HAVE_DECL_KRB5_GET_CREDENTIALS_FOR_USER
-krb5_error_code KRB5_CALLCONV
-krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
- krb5_ccache ccache, krb5_creds *in_creds,
- krb5_data *subject_cert,
- krb5_creds **out_creds);
-#endif /* !HAVE_DECL_KRB5_GET_CREDENTIALS_FOR_USER */
-
ZERO_STRUCT(in_creds);
if (impersonate_princ) {
char tmp_name[sizeof(SMB_CREDS_KEYTAB)];
krb5_keytab_entry entry;
krb5_keytab keytab;
+ mode_t mask;
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;
}
return code;
}
+#ifndef SAMBA4_USES_HEIMDAL /* MIT */
+ /*
+ * We need to store the principal as returned from the KDC to the
+ * credentials cache. If we don't do that the KRB5 library is not
+ * able to find the tickets it is looking for
+ */
+ principal = my_creds.client;
+#endif
code = krb5_cc_initialize(ctx, cc, principal);
if (code) {
goto done;
return code;
}
+#ifndef SAMBA4_USES_HEIMDAL /* MIT */
+ /*
+ * We need to store the principal as returned from the KDC to the
+ * credentials cache. If we don't do that the KRB5 library is not
+ * able to find the tickets it is looking for
+ */
+ principal = my_creds.client;
+#endif
code = krb5_cc_initialize(ctx, cc, principal);
if (code) {
goto done;
va_list ap;
if (_realm) {
- realm = _realm;
+ realm = discard_const_p(char, _realm);
free_realm = false;
} else {
code = krb5_get_default_realm(context, &realm);
* @param[in] principal The principal
* @return pointer to the realm
*
+ * Caller must free if the return value is not NULL.
+ *
*/
char *smb_krb5_principal_get_realm(krb5_context context,
- krb5_principal principal)
+ krb5_const_principal principal)
{
#ifdef HAVE_KRB5_PRINCIPAL_GET_REALM /* Heimdal */
- return discard_const_p(char, krb5_principal_get_realm(context, principal));
+ return strdup(discard_const_p(char, krb5_principal_get_realm(context, principal)));
#elif defined(krb5_princ_realm) /* MIT */
krb5_data *realm;
- realm = krb5_princ_realm(context, principal);
- return discard_const_p(char, realm->data);
+ realm = discard_const_p(krb5_data,
+ krb5_princ_realm(context, principal));
+ return strndup(realm->data, realm->length);
+#else
+#error UNKNOWN_GET_PRINC_REALM_FUNCTIONS
+#endif
+}
+
+/*
+ * smb_krb5_principal_set_realm
+ *
+ * @brief Get realm of a principal
+ *
+ * @param[in] context The krb5_context
+ * @param[in] principal The principal
+ * @param[in] realm The realm
+ * @return 0 on success, a krb5_error_code on error.
+ *
+ */
+
+krb5_error_code smb_krb5_principal_set_realm(krb5_context context,
+ krb5_principal principal,
+ const char *realm)
+{
+#ifdef HAVE_KRB5_PRINCIPAL_SET_REALM /* Heimdal */
+ return krb5_principal_set_realm(context, principal, realm);
+#elif defined(krb5_princ_realm) && defined(krb5_princ_set_realm) /* MIT */
+ krb5_error_code ret;
+ krb5_data data;
+ krb5_data *old_data;
+
+ old_data = krb5_princ_realm(context, principal);
+
+ ret = krb5_copy_data_contents(&data,
+ realm,
+ strlen(realm));
+ if (ret) {
+ return ret;
+ }
+
+ /* free realm before setting */
+ free(old_data->data);
+
+ krb5_princ_set_realm(context, principal, &data);
+
+ return ret;
#else
- return NULL;
+#error UNKNOWN_PRINC_SET_REALM_FUNCTION
#endif
}
+
/************************************************************************
Routine to get the default realm from the kerberos credentials cache.
Caller must free if the return value is not NULL.
return ret;
}
+
+/**
+* @brief Return the kerberos library setting for "libdefaults:allow_weak_crypto"
+*
+* @param context The krb5_context
+*
+* @return krb5_boolean
+*
+* Function returns true if weak crypto is allowd, false if not
+*/
+
+krb5_boolean smb_krb5_get_allowed_weak_crypto(krb5_context context)
+#if defined(HAVE_KRB5_CONFIG_GET_BOOL_DEFAULT)
+{
+ return krb5_config_get_bool_default(context,
+ NULL,
+ FALSE,
+ "libdefaults",
+ "allow_weak_crypto",
+ NULL);
+}
+#elif defined(HAVE_PROFILE_H) && defined(HAVE_KRB5_GET_PROFILE)
+{
+#include <profile.h>
+ krb5_error_code ret;
+ krb5_boolean ret_default = false;
+ profile_t profile;
+ int ret_profile;
+
+ ret = krb5_get_profile(context,
+ &profile);
+ if (ret) {
+ return ret_default;
+ }
+
+ ret = profile_get_boolean(profile,
+ "libdefaults",
+ "allow_weak_crypto",
+ NULL, /* subsubname */
+ ret_default, /* def_val */
+ &ret_profile /* *ret_default */);
+ if (ret) {
+ return ret_default;
+ }
+
+ profile_release(profile);
+
+ return ret_profile;
+}
+#else
+#error UNKNOWN_KRB5_CONFIG_ROUTINES
+#endif
+
+/**
+* @brief Return the type of a krb5_principal
+*
+* @param context The krb5_context
+* @param principal The const krb5_principal
+*
+* @return integer type of the principal
+*/
+int smb_krb5_principal_get_type(krb5_context context,
+ krb5_const_principal principal)
+{
+#ifdef HAVE_KRB5_PRINCIPAL_GET_TYPE /* Heimdal */
+ return krb5_principal_get_type(context, principal);
+#elif defined(krb5_princ_type) /* MIT */
+ return krb5_princ_type(context, principal);
+#else
+#error UNKNOWN_PRINC_GET_TYPE_FUNCTION
+#endif
+}
+
+/**
+* @brief Set the type of a krb5_principal
+*
+* @param context The krb5_context
+* @param principal The const krb5_principal
+* @param type The principal type
+*
+*/
+void smb_krb5_principal_set_type(krb5_context context,
+ krb5_principal principal,
+ int type)
+{
+#ifdef HAVE_KRB5_PRINCIPAL_SET_TYPE /* Heimdal */
+ krb5_principal_set_type(context, principal, type);
+#elif defined(krb5_princ_type) /* MIT */
+ krb5_princ_type(context, principal) = type;
+#else
+#error UNKNOWN_PRINC_SET_TYPE_FUNCTION
+#endif
+}
+
+/**
+* @brief Generate a krb5 warning, forwarding to com_err
+*
+* @param context The krb5_context
+* @param fmt The message format
+* @param ... The message arguments
+*
+* @return
+*/
+#if !defined(HAVE_KRB5_WARNX)
+krb5_error_code krb5_warnx(krb5_context context, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ com_err_va("kdb_samba", errno, fmt, args);
+ va_end(args);
+
+ return 0;
+}
+#endif
+
#else /* HAVE_KRB5 */
/* this saves a few linking headaches */
int cli_krb5_get_ticket(TALLOC_CTX *mem_ctx,