Copyright (C) Andrew Tridgell 2001
Copyright (C) Luke Howard 2002-2003
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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#ifdef HAVE_KRB5
-#ifndef HAVE_KRB5_SET_REAL_TIME
-/*
- * This function is not in the Heimdal mainline.
- */
- krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds)
-{
- krb5_error_code ret;
- int32_t sec, usec;
-
- ret = krb5_us_timeofday(context, &sec, &usec);
- if (ret)
- return ret;
-
- context->kdc_sec_offset = seconds - sec;
- context->kdc_usec_offset = microseconds - usec;
-
- return 0;
-}
-#endif
-
-#if defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES) && !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
- 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
-
-#if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS)
-/* HEIMDAL */
- void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr)
-{
- pkaddr->addr_type = KRB5_ADDRESS_INET;
- pkaddr->address.length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
- pkaddr->address.data = (char *)&(((struct sockaddr_in *)paddr)->sin_addr);
-}
-#elif defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS)
-/* MIT */
- void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr)
-{
- pkaddr->addrtype = ADDRTYPE_INET;
- pkaddr->length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
- pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in *)paddr)->sin_addr);
-}
-#else
-#error UNKNOWN_ADDRTYPE
-#endif
-
#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY) && defined(HAVE_KRB5_ENCRYPT_BLOCK)
int create_kerberos_key_from_string(krb5_context context,
krb5_principal host_princ,
DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret)));
return ret;
}
- return krb5_string_to_key_salt(context, enctype, password->data,
- salt, key);
+ ret = krb5_string_to_key_salt(context, enctype, password->data,
+ salt, key);
+ krb5_free_salt(context, salt);
+ return ret;
}
#else
#error UNKNOWN_CREATE_KEY_FUNCTIONS
-#endif
-
-#if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
- krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
- krb5_enctype **enctypes)
-{
- return krb5_get_permitted_enctypes(context, enctypes);
-}
-#elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES)
- krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
- krb5_enctype **enctypes)
-{
- return krb5_get_default_in_tkt_etypes(context, enctypes);
-}
-#else
-#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,
- krb5_keyblock *keyblock)
-{
- return krb5_auth_con_setkey(context, auth_context, keyblock);
-}
-#endif
-
- DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx,
- krb5_ticket *tkt)
-{
- DATA_BLOB auth_data = data_blob(NULL, 0);
-#if defined(HAVE_KRB5_TKT_ENC_PART2)
- if (tkt && tkt->enc_part2
- && tkt->enc_part2->authorization_data
- && tkt->enc_part2->authorization_data[0]
- && tkt->enc_part2->authorization_data[0]->length)
- auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents,
- tkt->enc_part2->authorization_data[0]->length);
-#else
- if (tkt && tkt->ticket.authorization_data && tkt->ticket.authorization_data->len)
- auth_data = data_blob(tkt->ticket.authorization_data->val->ad_data.data,
- tkt->ticket.authorization_data->val->ad_data.length);
-#endif
- return auth_data;
-}
-
- krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt)
-{
-#if defined(HAVE_KRB5_TKT_ENC_PART2)
- return tkt->enc_part2->client;
-#else
- return tkt->client;
-#endif
-}
-
-#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
- void krb5_free_unparsed_name(krb5_context context, char *val)
-{
- SAFE_FREE(val);
-}
#endif
void kerberos_free_data_contents(krb5_context context, krb5_data *pdata)
{
-#if defined(HAVE_KRB5_FREE_DATA_CONTENTS)
if (pdata->data) {
- krb5_free_data_contents(context, pdata);
+ krb5_data_free(pdata);
}
-#else
- SAFE_FREE(pdata->data);
-#endif
-}
-
- void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype)
-{
-#if defined(HAVE_KRB5_KEYBLOCK_IN_CREDS)
- KRB5_KEY_TYPE((&pcreds->keyblock)) = enctype;
-#elif defined(HAVE_KRB5_SESSION_IN_CREDS)
- KRB5_KEY_TYPE((&pcreds->session)) = enctype;
-#else
-#error UNKNOWN_KEYBLOCK_MEMBER_IN_KRB5_CREDS_STRUCT
-#endif
-}
-
- BOOL kerberos_compatible_enctypes(krb5_context context,
- krb5_enctype enctype1,
- krb5_enctype enctype2)
-{
-#if defined(HAVE_KRB5_C_ENCTYPE_COMPARE)
- krb5_boolean similar = 0;
-
- krb5_c_enctype_compare(context, enctype1, enctype2, &similar);
- return similar ? True : False;
-#elif defined(HAVE_KRB5_ENCTYPES_COMPATIBLE_KEYS)
- return krb5_enctypes_compatible_keys(context, enctype1, enctype2) ? True : False;
-#endif
-}
-
-static BOOL ads_cleanup_expired_creds(krb5_context context,
- krb5_ccache ccache,
- krb5_creds *credsp)
-{
- krb5_error_code retval;
- TALLOC_CTX *mem_ctx = talloc_init("ticket expied time");
- if (!mem_ctx) {
- return False;
- }
-
- DEBUG(3, ("Ticket in ccache[%s] expiration %s\n",
- krb5_cc_default_name(context),
- http_timestring(mem_ctx, credsp->times.endtime)));
-
- talloc_free(mem_ctx);
-
- /* we will probably need new tickets if the current ones
- will expire within 10 seconds.
- */
- if (credsp->times.endtime >= (time(NULL) + 10))
- return False;
-
- /* heimdal won't remove creds from a file ccache, and
- perhaps we shouldn't anyway, since internally we
- use memory ccaches, and a FILE one probably means that
- we're using creds obtained outside of our exectuable
- */
- if (StrCaseCmp(krb5_cc_get_type(context, ccache), "FILE") == 0) {
- DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a FILE ccache\n"));
- return False;
- }
-
- retval = krb5_cc_remove_cred(context, ccache, 0, credsp);
- if (retval) {
- DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n",
- error_message(retval)));
- /* If we have an error in this, we want to display it,
- but continue as though we deleted it */
- }
- return True;
-}
-
-/*
- we can't use krb5_mk_req because w2k wants the service to be in a particular format
-*/
-krb5_error_code ads_krb5_mk_req(krb5_context context,
- krb5_auth_context *auth_context,
- const krb5_flags ap_req_options,
- const char *principal,
- krb5_ccache ccache,
- krb5_data *outbuf)
-{
- krb5_error_code retval;
- krb5_principal server;
- krb5_creds * credsp;
- krb5_creds creds;
- krb5_data in_data;
- BOOL creds_ready = False;
-
- TALLOC_CTX *mem_ctx = NULL;
-
- retval = krb5_parse_name(context, principal, &server);
- if (retval) {
- DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
- return retval;
- }
-
- /* obtain ticket & session key */
- ZERO_STRUCT(creds);
- if ((retval = krb5_copy_principal(context, server, &creds.server))) {
- DEBUG(1,("krb5_copy_principal failed (%s)\n",
- error_message(retval)));
- goto cleanup_princ;
- }
-
- if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
- /* This can commonly fail on smbd startup with no ticket in the cache.
- * Report at higher level than 1. */
- DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n",
- error_message(retval)));
- goto cleanup_creds;
- }
-
- while(!creds_ready) {
- if ((retval = krb5_get_credentials(context, 0, ccache,
- &creds, &credsp))) {
- DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
- principal, error_message(retval)));
- goto cleanup_creds;
- }
-
- /* cope with ticket being in the future due to clock skew */
- if ((unsigned)credsp->times.starttime > time(NULL)) {
- time_t t = time(NULL);
- int time_offset =(unsigned)credsp->times.starttime-t;
- DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
- krb5_set_real_time(context, t + time_offset + 1, 0);
- }
-
- if (!ads_cleanup_expired_creds(context, ccache, credsp))
- creds_ready = True;
- }
-
- mem_ctx = talloc_init("ticket expied time");
- if (!mem_ctx) {
- retval = ENOMEM;
- goto cleanup_creds;
- }
- DEBUG(10,("Ticket (%s) in ccache (%s) is valid until: (%s - %d)\n",
- principal, krb5_cc_default_name(context),
- http_timestring(mem_ctx, (unsigned)credsp->times.endtime),
- (unsigned)credsp->times.endtime));
-
- in_data.length = 0;
- retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
- &in_data, credsp, outbuf);
- if (retval) {
- DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n",
- error_message(retval)));
- }
-
- krb5_free_creds(context, credsp);
-
-cleanup_creds:
- krb5_free_cred_contents(context, &creds);
-
-cleanup_princ:
- krb5_free_principal(context, server);
-
- return retval;
}
krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry)
#if defined(HAVE_KRB5_GET_ERROR_STRING) && defined(HAVE_KRB5_FREE_ERROR_STRING)
char *context_error = krb5_get_error_string(context);
- ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error);
- krb5_free_error_string(context, context_error);
-#else
- ret = talloc_strdup(mem_ctx, error_message(code));
-#endif
- return ret;
-}
-
-
-static int smb_krb5_context_destory_1(void *ptr)
-{
- struct smb_krb5_context *ctx = ptr;
- krb5_free_context(ctx->krb5_context);
- return 0;
-}
-
-#ifdef HAVE_KRB5_LOG_CONTROL
-static int smb_krb5_context_destory_2(void *ptr)
-{
- struct smb_krb5_context *ctx = ptr;
-
- /* Otherwise krb5_free_context will try and close what we have already free()ed */
- krb5_set_warn_dest(ctx->krb5_context, NULL);
- krb5_closelog(ctx->krb5_context, ctx->logf);
- smb_krb5_context_destory_1(ptr);
- return 0;
-}
-
-/* We never close down the DEBUG system, and no need to unreference the use */
-static void smb_krb5_debug_close(void *private) {
- return;
-}
-
-static void smb_krb5_debug_wrapper(const char *timestr, const char *msg, void *private)
-{
- DEBUG(3, ("Kerberos: %s\n", msg));
-}
-
-#endif
-
- krb5_error_code smb_krb5_init_context(TALLOC_CTX *parent_ctx,
- struct smb_krb5_context **smb_krb5_context)
-{
- krb5_error_code ret;
- TALLOC_CTX *tmp_ctx;
-
- initialize_krb5_error_table();
-
- *smb_krb5_context = talloc(parent_ctx, struct smb_krb5_context);
- tmp_ctx = talloc_new(*smb_krb5_context);
-
- if (!*smb_krb5_context || !tmp_ctx) {
- talloc_free(*smb_krb5_context);
- talloc_free(tmp_ctx);
- return ENOMEM;
- }
-
- ret = krb5_init_context(&(*smb_krb5_context)->krb5_context);
- if (ret) {
- DEBUG(1,("krb5_init_context failed (%s)\n",
- error_message(ret)));
+ if (context_error) {
+ ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error);
+ krb5_free_error_string(context, context_error);
return ret;
}
-
- talloc_set_destructor(*smb_krb5_context, smb_krb5_context_destory_1);
-
- if (lp_realm() && *lp_realm()) {
- char *upper_realm = strupper_talloc(tmp_ctx, lp_realm());
- if (!upper_realm) {
- DEBUG(1,("gensec_krb5_start: could not uppercase realm: %s\n", lp_realm()));
- return ENOMEM;
- }
- ret = krb5_set_default_realm((*smb_krb5_context)->krb5_context, lp_realm());
- if (ret) {
- DEBUG(1,("krb5_set_default_realm failed (%s)\n",
- smb_get_krb5_error_message((*smb_krb5_context)->krb5_context, ret, tmp_ctx)));
- talloc_free(*smb_krb5_context);
- return ret;
- }
- }
-
-#ifdef HAVE_KRB5_LOG_CONTROL
- /* TODO: Should we have a different name here? */
- ret = krb5_initlog((*smb_krb5_context)->krb5_context, "Samba", &(*smb_krb5_context)->logf);
-
- if (ret) {
- DEBUG(1,("krb5_initlog failed (%s)\n",
- smb_get_krb5_error_message((*smb_krb5_context)->krb5_context, ret, tmp_ctx)));
- talloc_free(*smb_krb5_context);
- return ret;
- }
-
- talloc_set_destructor(*smb_krb5_context, smb_krb5_context_destory_2);
-
- ret = krb5_addlog_func((*smb_krb5_context)->krb5_context, (*smb_krb5_context)->logf, 0 /* min */, -1 /* max */,
- smb_krb5_debug_wrapper, smb_krb5_debug_close, NULL);
- if (ret) {
- DEBUG(1,("krb5_addlog_func failed (%s)\n",
- smb_get_krb5_error_message((*smb_krb5_context)->krb5_context, ret, tmp_ctx)));
- talloc_free(*smb_krb5_context);
- return ret;
- }
- krb5_set_warn_dest((*smb_krb5_context)->krb5_context, (*smb_krb5_context)->logf);
-
-#endif
- talloc_free(tmp_ctx);
- return 0;
+#endif
+ ret = talloc_strdup(mem_ctx, error_message(code));
+ return ret;
}
#endif