From: Greg Hudson Date: Tue, 13 Apr 2010 22:57:34 +0000 (+0000) Subject: Validate and renew should work on non-TGT creds X-Git-Tag: krb5-1.9-beta1~287 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=cc6dc869a5aa8cebc2ec4c081f11c0e116ae591a;p=krb5.git Validate and renew should work on non-TGT creds The validate and renew APIs were using get_cred_from_kdc, which always presents a TGT to get credentials. Instead, they should present the ticket they are trying to validate or renew. This is most easily done with krb5_get_cred_via_tkt(). Move the relevant code into a new file since it now has nothing in common with the other APIs implemented in get_creds.c. ticket: 6699 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23891 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 2fad9e9d9..e25ba669a 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -106,6 +106,7 @@ STLIBOBJS= \ str_conv.o \ tgtname.o \ unparse.o \ + val_renew.o \ valid_times.o \ vfy_increds.o \ vic_opt.o \ @@ -205,6 +206,7 @@ OBJS= $(OUTPRE)addr_comp.$(OBJEXT) \ $(OUTPRE)str_conv.$(OBJEXT) \ $(OUTPRE)tgtname.$(OBJEXT) \ $(OUTPRE)unparse.$(OBJEXT) \ + $(OUTPRE)val_renew.$(OBJEXT) \ $(OUTPRE)valid_times.$(OBJEXT) \ $(OUTPRE)vfy_increds.$(OBJEXT) \ $(OUTPRE)vic_opt.$(OBJEXT) \ @@ -306,6 +308,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/t_ad_fx_armor.c \ $(srcdir)/tgtname.c \ $(srcdir)/unparse.c \ + $(srcdir)/val_renew.c \ $(srcdir)/valid_times.c \ $(srcdir)/vfy_increds.c \ $(srcdir)/vic_opt.c \ diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c index 5b2c1c2fa..396ea7941 100644 --- a/src/lib/krb5/krb/get_creds.c +++ b/src/lib/krb5/krb/get_creds.c @@ -209,154 +209,3 @@ krb5_get_credentials(krb5_context context, krb5_flags options, *out_creds = ncreds; return 0; } - -#define INT_GC_VALIDATE 1 -#define INT_GC_RENEW 2 - -static krb5_error_code -get_credentials_val_renew_core(krb5_context context, krb5_flags options, - krb5_ccache ccache, krb5_creds *in_creds, - krb5_creds **out_creds, int which) -{ - krb5_error_code retval; - krb5_principal tmp; - krb5_creds **tgts = 0; - - switch(which) { - case INT_GC_VALIDATE: - retval = krb5_get_cred_from_kdc_validate(context, ccache, - in_creds, out_creds, &tgts); - break; - case INT_GC_RENEW: - retval = krb5_get_cred_from_kdc_renew(context, ccache, - in_creds, out_creds, &tgts); - break; - default: - /* Should never happen */ - retval = 255; - break; - } - /* - * Callers to krb5_get_cred_blah... must free up tgts even in - * error cases. - */ - if (tgts) krb5_free_tgt_creds(context, tgts); - if (retval) return retval; - - retval = krb5_cc_get_principal(context, ccache, &tmp); - if (retval) return retval; - - retval = krb5_cc_initialize(context, ccache, tmp); - if (retval) return retval; - - retval = krb5_cc_store_cred(context, ccache, *out_creds); - return retval; -} - -krb5_error_code KRB5_CALLCONV -krb5_get_credentials_validate(krb5_context context, krb5_flags options, - krb5_ccache ccache, krb5_creds *in_creds, - krb5_creds **out_creds) -{ - return(get_credentials_val_renew_core(context, options, ccache, - in_creds, out_creds, - INT_GC_VALIDATE)); -} - -krb5_error_code KRB5_CALLCONV -krb5_get_credentials_renew(krb5_context context, krb5_flags options, - krb5_ccache ccache, krb5_creds *in_creds, - krb5_creds **out_creds) -{ - - return(get_credentials_val_renew_core(context, options, ccache, - in_creds, out_creds, - INT_GC_RENEW)); -} - -static krb5_error_code -validate_or_renew_creds(krb5_context context, krb5_creds *creds, - krb5_principal client, krb5_ccache ccache, - char *in_tkt_service, int validate) -{ - krb5_error_code ret; - krb5_creds in_creds; /* only client and server need to be filled in */ - krb5_creds *out_creds = 0; /* for check before dereferencing below */ - krb5_creds **tgts; - - memset(&in_creds, 0, sizeof(krb5_creds)); - - in_creds.server = NULL; - tgts = NULL; - - in_creds.client = client; - - if (in_tkt_service) { - /* this is ugly, because so are the data structures involved. I'm - in the library, so I'm going to manipulate the data structures - directly, otherwise, it will be worse. */ - - if ((ret = krb5_parse_name(context, in_tkt_service, &in_creds.server))) - goto cleanup; - - /* stuff the client realm into the server principal. - realloc if necessary */ - if (in_creds.server->realm.length < in_creds.client->realm.length) - if ((in_creds.server->realm.data = - (char *) realloc(in_creds.server->realm.data, - in_creds.client->realm.length)) == NULL) { - ret = ENOMEM; - goto cleanup; - } - - in_creds.server->realm.length = in_creds.client->realm.length; - memcpy(in_creds.server->realm.data, in_creds.client->realm.data, - in_creds.client->realm.length); - } else { - if ((ret = krb5_build_principal_ext(context, &in_creds.server, - in_creds.client->realm.length, - in_creds.client->realm.data, - KRB5_TGS_NAME_SIZE, - KRB5_TGS_NAME, - in_creds.client->realm.length, - in_creds.client->realm.data, - 0))) - goto cleanup; - } - - if (validate) - ret = krb5_get_cred_from_kdc_validate(context, ccache, - &in_creds, &out_creds, &tgts); - else - ret = krb5_get_cred_from_kdc_renew(context, ccache, - &in_creds, &out_creds, &tgts); - - /* ick. copy the struct contents, free the container */ - if (out_creds) { - *creds = *out_creds; - free(out_creds); - } - -cleanup: - - if (in_creds.server) - krb5_free_principal(context, in_creds.server); - if (tgts) - krb5_free_tgt_creds(context, tgts); - - return(ret); -} - -krb5_error_code KRB5_CALLCONV -krb5_get_validated_creds(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_ccache ccache, char *in_tkt_service) -{ - return(validate_or_renew_creds(context, creds, client, ccache, - in_tkt_service, 1)); -} - -krb5_error_code KRB5_CALLCONV -krb5_get_renewed_creds(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_ccache ccache, char *in_tkt_service) -{ - return(validate_or_renew_creds(context, creds, client, ccache, - in_tkt_service, 0)); -} diff --git a/src/lib/krb5/krb/val_renew.c b/src/lib/krb5/krb/val_renew.c new file mode 100644 index 000000000..46eff99b7 --- /dev/null +++ b/src/lib/krb5/krb/val_renew.c @@ -0,0 +1,194 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * lib/krb5/krb/val_renew.c + * + * Copyright (C) 2010 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Implements the following APIs: + * + * krb5_get_credentials_validate + * krb5_get_credentials_renew + * krb5_get_validated_creds + * krb5_get_renewed_creds + * + * The first two are old but not formally deprecated; the latter two are newer. + */ + +#include "k5-int.h" +#include "int-proto.h" + +/* + * Get a validated or renewed credential matching in_creds, by retrieving a + * matching credential from ccache and renewing or validating it with the + * credential's realm's KDC. kdcopt specifies whether to validate or renew. + * The result is placed in *out_creds. + */ +static krb5_error_code +get_new_creds(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds, + krb5_flags kdcopt, krb5_creds **out_creds) +{ + krb5_error_code code; + krb5_creds old_creds, *new_creds = NULL; + + *out_creds = NULL; + + /* Retrieve an existing cached credential matching in_creds. */ + code = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_SUPPORTED_KTYPES, + in_creds, &old_creds); + if (code != 0) + return code; + + /* Use it to get a new credential from the KDC. */ + code = krb5_get_cred_via_tkt(context, &old_creds, kdcopt, + old_creds.addresses, in_creds, &new_creds); + krb5_free_cred_contents(context, &old_creds); + if (code != 0) + return code; + + *out_creds = new_creds; + return code; +} + +/* + * Core of the older pair of APIs: get a validated or renewed credential + * matching in_creds and reinitialize ccache so that it contains only the new + * credential. + */ +static krb5_error_code +gc_valrenew(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds, + krb5_flags kdcopt, krb5_creds **out_creds) +{ + krb5_error_code code; + krb5_creds *new_creds = NULL; + krb5_principal default_princ = NULL; + + /* Get the validated or renewed credential. */ + code = get_new_creds(context, ccache, in_creds, kdcopt, &new_creds); + if (code != 0) + goto cleanup; + + /* Reinitialize the cache without changing its default principal. */ + code = krb5_cc_get_principal(context, ccache, &default_princ); + if (code != 0) + goto cleanup; + code = krb5_cc_initialize(context, ccache, default_princ); + if (code != 0) + goto cleanup; + + /* Store the validated or renewed cred in the now-empty cache. */ + code = krb5_cc_store_cred(context, ccache, new_creds); + if (code != 0) + goto cleanup; + + *out_creds = new_creds; + new_creds = NULL; + +cleanup: + krb5_free_principal(context, default_princ); + krb5_free_creds(context, new_creds); + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_get_credentials_validate(krb5_context context, krb5_flags options, + krb5_ccache ccache, krb5_creds *in_creds, + krb5_creds **out_creds) +{ + return gc_valrenew(context, ccache, in_creds, KDC_OPT_VALIDATE, out_creds); +} + +krb5_error_code KRB5_CALLCONV +krb5_get_credentials_renew(krb5_context context, krb5_flags options, + krb5_ccache ccache, krb5_creds *in_creds, + krb5_creds **out_creds) +{ + return gc_valrenew(context, ccache, in_creds, KDC_OPT_RENEW, out_creds); +} + +/* + * Core of the newer pair of APIs: get new credentials for in_tkt_service + * (defaults to the TGT of the client's realm) and store them into *out_creds. + */ +static krb5_error_code +get_valrenewed_creds(krb5_context context, krb5_creds *out_creds, + krb5_principal client, krb5_ccache ccache, + char *in_tkt_service, int kdcopt) +{ + krb5_error_code code; + krb5_creds in_creds, *new_creds; + krb5_principal server = NULL; + + if (in_tkt_service != NULL) { + /* Parse in_tkt_service, but use the client's realm. */ + code = krb5_parse_name(context, in_tkt_service, &server); + if (code != 0) + goto cleanup; + krb5_free_data_contents(context, &server->realm); + code = krb5int_copy_data_contents(context, &client->realm, + &server->realm); + if (code != 0) + goto cleanup; + } else { + /* Use the TGT name for the client's realm. */ + code = krb5int_tgtname(context, &client->realm, &client->realm, + &server); + if (code != 0) + goto cleanup; + } + + memset(&in_creds, 0, sizeof(krb5_creds)); + in_creds.client = client; + in_creds.server = server; + + /* Get the validated or renewed credential from the KDC. */ + code = get_new_creds(context, ccache, &in_creds, kdcopt, &new_creds); + if (code != 0) + goto cleanup; + + /* Fill in *out_creds and free the unwanted new_creds container. */ + *out_creds = *new_creds; + free(new_creds); + +cleanup: + krb5_free_principal(context, server); + return code; +} + +krb5_error_code KRB5_CALLCONV +krb5_get_validated_creds(krb5_context context, krb5_creds *creds, + krb5_principal client, krb5_ccache ccache, + char *in_tkt_service) +{ + return get_valrenewed_creds(context, creds, client, ccache, + in_tkt_service, KDC_OPT_VALIDATE); +} + +krb5_error_code KRB5_CALLCONV +krb5_get_renewed_creds(krb5_context context, krb5_creds *creds, + krb5_principal client, krb5_ccache ccache, + char *in_tkt_service) +{ + return get_valrenewed_creds(context, creds, client, ccache, + in_tkt_service, KDC_OPT_RENEW); +}