From 5c6dd5e800b879efdce3bbc3a16f32c5e78b4917 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 15 May 2005 23:42:11 +0000 Subject: r6800: A big GENSEC update: Finally remove the distinction between 'krb5' and 'ms_krb5'. We now don't do kerberos stuff twice on failure. The solution to this is slightly more general than perhaps was really required (as this is a special case), but it works, and I'm happy with the cleanup I achived in the process. All modules have been updated to supply a NULL-terminated list of OIDs. In that process, SPNEGO code has been generalised, as I realised that two of the functions should have been identical in behaviour. Over in the actual modules, I have worked to remove the 'kinit' code from gensec_krb5, and placed it in kerberos/kerberos_util.c. The GSSAPI module has been extended to use this, so no longer requires a manual kinit at the command line. It will soon loose the requirement for a on-disk keytab too. The general kerberos code has also been updated to move from error_message() to our routine which gets the Heimdal error string (which may be much more useful) when available. Andrew Bartlett (This used to be commit 0101728d8e2ed9419eb31fe95047944a718ba135) --- source4/auth/kerberos/kerberos.h | 5 ++ source4/auth/kerberos/kerberos.mk | 1 + source4/auth/kerberos/kerberos_util.c | 120 ++++++++++++++++++++++++++++++++ source4/auth/kerberos/kerberos_verify.c | 9 +-- 4 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 source4/auth/kerberos/kerberos_util.c (limited to 'source4/auth/kerberos') diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h index 4daf0ea07a..ec7df4c2f1 100644 --- a/source4/auth/kerberos/kerberos.h +++ b/source4/auth/kerberos/kerberos.h @@ -95,5 +95,10 @@ BOOL kerberos_compatible_enctypes(krb5_context context, krb5_enctype enctype1, k void kerberos_free_data_contents(krb5_context context, krb5_data *pdata); krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry); char *smb_get_krb5_error_message(krb5_context context, krb5_error_code code, TALLOC_CTX *mem_ctx); +NTSTATUS kinit_to_ccache(TALLOC_CTX *parent_ctx, + struct cli_credentials *credentials, + krb5_context context, + krb5_ccache *ccache, + const char **ccache_name); #endif /* HAVE_KRB5 */ diff --git a/source4/auth/kerberos/kerberos.mk b/source4/auth/kerberos/kerberos.mk index a43e6bb517..38c8862747 100644 --- a/source4/auth/kerberos/kerberos.mk +++ b/source4/auth/kerberos/kerberos.mk @@ -5,6 +5,7 @@ INIT_OBJ_FILES = auth/kerberos/kerberos.o ADD_OBJ_FILES = \ auth/kerberos/clikrb5.o \ auth/kerberos/kerberos_verify.o \ + auth/kerberos/kerberos_util.o \ auth/kerberos/gssapi_parse.o # End SUBSYSTEM KERBEROS ################################# diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c new file mode 100644 index 0000000000..55975b2594 --- /dev/null +++ b/source4/auth/kerberos/kerberos_util.c @@ -0,0 +1,120 @@ +/* + Unix SMB/CIFS implementation. + + Kerberos utility functions for GENSEC + + Copyright (C) Andrew Bartlett 2004 + + 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 + (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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "system/kerberos.h" +#include "system/time.h" +#include "system/network.h" +#include "auth/kerberos/kerberos.h" +#include "auth/auth.h" + +struct ccache_container { + krb5_context krb5_context; + krb5_ccache ccache; +} ccache_container; + +#if 0 +static int free_ccache(void *ptr) { + struct ccache_container *ccc = ptr; + /* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */ + krb5_cc_close(ccc->krb5_context, ccc->ccache); + + return 0; +} +#endif + +/** + * Return a freshly allocated ccache (destroyed by destructor on child + * of parent_ctx), for a given set of client credentials + */ + + NTSTATUS kinit_to_ccache(TALLOC_CTX *parent_ctx, + struct cli_credentials *credentials, + krb5_context context, + krb5_ccache *ccache, + const char **ccache_name) +{ + krb5_error_code ret; + const char *password; + char *ccache_string; + time_t kdc_time = 0; + struct ccache_container *mem_ctx = talloc(parent_ctx, struct ccache_container); + + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + + password = cli_credentials_get_password(credentials); + + /* this string should be unique */ + ccache_string = talloc_asprintf(mem_ctx, "MEMORY:%s_%s", + cli_credentials_get_principal(credentials, mem_ctx), + generate_random_str(mem_ctx, 16)); + + ret = krb5_cc_resolve(context, ccache_string, ccache); + if (ret) { + DEBUG(1,("failed to generate a new krb5 keytab (%s): %s\n", + ccache_string, + error_message(ret))); + talloc_free(mem_ctx); + return NT_STATUS_INTERNAL_ERROR; + } + + mem_ctx->krb5_context = context; + mem_ctx->ccache = *ccache; + +#if 0 + talloc_set_destructor(mem_ctx, free_ccache); +#endif + ret = kerberos_kinit_password_cc(context, *ccache, + cli_credentials_get_principal(credentials, mem_ctx), + password, NULL, &kdc_time); + + /* cope with ticket being in the future due to clock skew */ + if ((unsigned)kdc_time > time(NULL)) { + time_t t = time(NULL); + int time_offset =(unsigned)kdc_time-t; + DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset)); + krb5_set_real_time(context, t + time_offset + 1, 0); + } + + if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { + DEBUG(1,("kinit for %s failed (%s)\n", + cli_credentials_get_principal(credentials, mem_ctx), + smb_get_krb5_error_message(context, + ret, mem_ctx))); + talloc_free(mem_ctx); + return NT_STATUS_TIME_DIFFERENCE_AT_DC; + } + if (ret) { + DEBUG(1,("kinit for %s failed (%s)\n", + cli_credentials_get_principal(credentials, mem_ctx), + smb_get_krb5_error_message(context, + ret, mem_ctx))); + talloc_free(mem_ctx); + return NT_STATUS_WRONG_PASSWORD; + } + *ccache_name = ccache_string; + + return NT_STATUS_OK; +} diff --git a/source4/auth/kerberos/kerberos_verify.c b/source4/auth/kerberos/kerberos_verify.c index 927b12d454..0497e3effa 100644 --- a/source4/auth/kerberos/kerberos_verify.c +++ b/source4/auth/kerberos/kerberos_verify.c @@ -93,7 +93,8 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex /* Generate the list of principal names which we expect * clients might want to use for authenticating to the file - * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */ + * service. We allow name$,{host,service}/{name,fqdn,name.REALM}. + * (where service is specified by the caller) */ my_name = lp_netbios_name(); @@ -103,9 +104,9 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm()); asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm()); asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm()); - asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm()); - asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm()); - asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()); + asprintf(&valid_princ_formats[4], "%s/%s@%s", service, my_name, lp_realm()); + asprintf(&valid_princ_formats[5], "%s/%s@%s", service, my_fqdn, lp_realm()); + asprintf(&valid_princ_formats[6], "%s/%s.%s@%s", service, my_name, lp_realm(), lp_realm()); ZERO_STRUCT(kt_entry); ZERO_STRUCT(kt_cursor); -- cgit