Path: blob/main/crypto/krb5/src/clients/ksu/ccache.c
34907 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/*2* Copyright (c) 1994 by the University of Southern California3*4* EXPORT OF THIS SOFTWARE from the United States of America may5* require a specific license from the United States Government.6* It is the responsibility of any person or organization contemplating7* export to obtain such a license before exporting.8*9* WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute10* this software and its documentation in source and binary forms is11* hereby granted, provided that any documentation or other materials12* related to such distribution or use acknowledge that the software13* was developed by the University of Southern California.14*15* DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The16* University of Southern California MAKES NO REPRESENTATIONS OR17* WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not18* limitation, the University of Southern California MAKES NO19* REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY20* PARTICULAR PURPOSE. The University of Southern21* California shall not be held liable for any liability nor for any22* direct, indirect, or consequential damages with respect to any23* claim by the user or distributor of the ksu software.24*25* KSU was written by: Ari Medvinsky, [email protected]26*/2728#include "ksu.h"29#include "k5-base64.h"30#include "adm_proto.h"31#include <sys/types.h>32#include <sys/stat.h>3334/******************************************************************35krb5_cache_copy3637gets rid of any expired tickets in the secondary cache,38copies the default cache into the secondary cache,3940************************************************************************/4142static void43free_creds_list(krb5_context context, krb5_creds **list)44{45size_t i;4647if (list == NULL)48return;49for (i = 0; list[i]; i++)50krb5_free_creds(context, list[i]);51free(list);52}5354void show_credential(krb5_context, krb5_creds *, krb5_ccache);5556/* modifies only the cc_other, the algorithm may look a bit funny,57but I had to do it this way, since remove function did not come58with k5 beta 3 release.59*/6061krb5_error_code62krb5_ccache_copy(krb5_context context, krb5_ccache cc_def,63krb5_principal target_principal, krb5_ccache cc_target,64krb5_boolean restrict_creds, krb5_principal primary_principal,65krb5_boolean *stored)66{67krb5_error_code retval=0;68krb5_creds ** cc_def_creds_arr = NULL;69krb5_creds ** cc_other_creds_arr = NULL;7071if (ks_ccache_is_initialized(context, cc_def)) {72retval = krb5_get_nonexp_tkts(context, cc_def, &cc_def_creds_arr);73if (retval)74goto cleanup;75}7677retval = krb5_cc_initialize(context, cc_target, target_principal);78if (retval)79goto cleanup;8081if (restrict_creds) {82retval = krb5_store_some_creds(context, cc_target, cc_def_creds_arr,83cc_other_creds_arr, primary_principal,84stored);85} else {86*stored = krb5_find_princ_in_cred_list(context, cc_def_creds_arr,87primary_principal);88retval = krb5_store_all_creds(context, cc_target, cc_def_creds_arr,89cc_other_creds_arr);90}9192cleanup:93free_creds_list(context, cc_def_creds_arr);94free_creds_list(context, cc_other_creds_arr);95return retval;96}979899krb5_error_code100krb5_store_all_creds(krb5_context context, krb5_ccache cc,101krb5_creds **creds_def, krb5_creds **creds_other)102{103104int i = 0;105krb5_error_code retval = 0;106krb5_creds ** temp_creds= NULL;107108109if ((creds_def == NULL) && (creds_other == NULL))110return 0;111112if ((creds_def == NULL) && (creds_other != NULL))113temp_creds = creds_other;114115if ((creds_def != NULL) && (creds_other == NULL))116temp_creds = creds_def;117118119if (temp_creds){120while(temp_creds[i]){121if ((retval= krb5_cc_store_cred(context, cc,122temp_creds[i]))){123return retval;124}125i++;126}127}128else { /* both arrays have elements in them */129130return KRB5KRB_ERR_GENERIC;131132/************ while(creds_other[i]){133cmp = FALSE;134j = 0;135while(creds_def[j]){136cmp = compare_creds(creds_other[i],creds_def[j]);137138if( cmp == TRUE) break;139140j++;141}142if (cmp == FALSE){143if (retval= krb5_cc_store_cred(context, cc,144creds_other[i])){145return retval;146}147}148i ++;149}150151i=0;152while(creds_def[i]){153if (retval= krb5_cc_store_cred(context, cc,154creds_def[i])){155return retval;156}157i++;158}159160**************/161}162return 0;163}164165krb5_boolean166compare_creds(krb5_context context, krb5_creds *cred1, krb5_creds *cred2)167{168krb5_boolean retval;169170retval = krb5_principal_compare (context, cred1->client, cred2->client);171172if (retval == TRUE)173retval = krb5_principal_compare (context, cred1->server, cred2->server);174175return retval;176}177178krb5_error_code179krb5_get_nonexp_tkts(krb5_context context, krb5_ccache cc,180krb5_creds ***creds_array)181{182183krb5_creds creds, temp_tktq, temp_tkt;184krb5_creds **temp_creds = NULL;185krb5_error_code retval=0;186krb5_cc_cursor cur;187int count = 0;188int chunk_count = 1;189190temp_creds = xcalloc(CHUNK, sizeof(*temp_creds));191memset(&temp_tktq, 0, sizeof(temp_tktq));192memset(&temp_tkt, 0, sizeof(temp_tkt));193memset(&creds, 0, sizeof(creds));194195/* initialize the cursor */196retval = krb5_cc_start_seq_get(context, cc, &cur);197if (retval)198goto cleanup;199200while (!(retval = krb5_cc_next_cred(context, cc, &cur, &creds))){201202if (!krb5_is_config_principal(context, creds.server) &&203(retval = krb5_check_exp(context, creds.times))){204krb5_free_cred_contents(context, &creds);205if (retval != KRB5KRB_AP_ERR_TKT_EXPIRED){206goto cleanup;207}208if (auth_debug){209fprintf(stderr,"krb5_ccache_copy: CREDS EXPIRED:\n");210fputs(" Valid starting Expires Service principal\n",stdout);211show_credential(context, &creds, cc);212fprintf(stderr,"\n");213}214}215else { /* these credentials didn't expire */216retval = krb5_copy_creds(context, &creds, &temp_creds[count]);217krb5_free_cred_contents(context, &creds);218temp_creds[count+1] = NULL;219if (retval)220goto cleanup;221count ++;222223if (count == (chunk_count * CHUNK -1)){224chunk_count ++;225226temp_creds = xrealloc(temp_creds,227chunk_count * CHUNK *228sizeof(*temp_creds));229}230}231232}233234temp_creds[count] = NULL;235*creds_array = temp_creds;236temp_creds = NULL;237238if (retval == KRB5_CC_END) {239retval = krb5_cc_end_seq_get(context, cc, &cur);240}241242cleanup:243free_creds_list(context, temp_creds);244return retval;245}246247krb5_error_code248krb5_check_exp(krb5_context context, krb5_ticket_times tkt_time)249{250krb5_error_code retval =0;251krb5_timestamp currenttime;252253if ((retval = krb5_timeofday (context, ¤ttime))){254return retval;255}256if (auth_debug){257fprintf(stderr,"krb5_check_exp: the krb5_clockskew is %d \n",258context->clockskew);259260fprintf(stderr,"krb5_check_exp: currenttime - endtime %d \n",261ts_delta(currenttime, tkt_time.endtime));262263}264265if (ts_after(currenttime, ts_incr(tkt_time.endtime, context->clockskew))) {266retval = KRB5KRB_AP_ERR_TKT_EXPIRED ;267return retval;268}269270return 0;271}272273char *274flags_string(krb5_creds *cred)275{276static char buf[32];277int i = 0;278279if (cred->ticket_flags & TKT_FLG_FORWARDABLE)280buf[i++] = 'F';281if (cred->ticket_flags & TKT_FLG_FORWARDED)282buf[i++] = 'f';283if (cred->ticket_flags & TKT_FLG_PROXIABLE)284buf[i++] = 'P';285if (cred->ticket_flags & TKT_FLG_PROXY)286buf[i++] = 'p';287if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)288buf[i++] = 'D';289if (cred->ticket_flags & TKT_FLG_POSTDATED)290buf[i++] = 'd';291if (cred->ticket_flags & TKT_FLG_INVALID)292buf[i++] = 'i';293if (cred->ticket_flags & TKT_FLG_RENEWABLE)294buf[i++] = 'R';295if (cred->ticket_flags & TKT_FLG_INITIAL)296buf[i++] = 'I';297if (cred->ticket_flags & TKT_FLG_HW_AUTH)298buf[i++] = 'H';299if (cred->ticket_flags & TKT_FLG_PRE_AUTH)300buf[i++] = 'A';301buf[i] = '\0';302return(buf);303}304305void306printtime(krb5_timestamp ts)307{308char fmtbuf[18], fill = ' ';309310if (!krb5_timestamp_to_sfstring(ts, fmtbuf, sizeof(fmtbuf), &fill))311printf("%s", fmtbuf);312}313314void315show_credential(krb5_context context, krb5_creds *cred, krb5_ccache cc)316{317krb5_error_code retval;318char *name = NULL, *sname = NULL, *defname = NULL, *flags;319int first = 1;320krb5_principal princ = NULL;321int show_flags =1;322323retval = krb5_unparse_name(context, cred->client, &name);324if (retval) {325com_err(prog_name, retval, _("while unparsing client name"));326goto cleanup;327}328retval = krb5_unparse_name(context, cred->server, &sname);329if (retval) {330com_err(prog_name, retval, _("while unparsing server name"));331goto cleanup;332}333334if ((retval = krb5_cc_get_principal(context, cc, &princ))) {335com_err(prog_name, retval, _("while retrieving principal name"));336goto cleanup;337}338if ((retval = krb5_unparse_name(context, princ, &defname))) {339com_err(prog_name, retval, _("while unparsing principal name"));340goto cleanup;341}342343if (!cred->times.starttime)344cred->times.starttime = cred->times.authtime;345346printtime(cred->times.starttime);347putchar(' '); putchar(' ');348printtime(cred->times.endtime);349putchar(' '); putchar(' ');350351printf("%s\n", sname);352353if (strcmp(name, defname)) {354printf(_("\tfor client %s"), name);355first = 0;356}357358if (cred->times.renew_till) {359if (first)360fputs("\t",stdout);361else362fputs(", ",stdout);363fputs(_("renew until "), stdout);364printtime(cred->times.renew_till);365}366if (show_flags) {367flags = flags_string(cred);368if (flags && *flags) {369if (first)370fputs("\t",stdout);371else372fputs(", ",stdout);373printf(_("Flags: %s"), flags);374first = 0;375}376}377putchar('\n');378379cleanup:380free(name);381free(sname);382free(defname);383krb5_free_principal(context, princ);384}385386/* Create a random string suitable for a filename extension. */387krb5_error_code388gen_sym(krb5_context context, char **sym_out)389{390krb5_error_code retval;391char bytes[6], *p, *sym;392krb5_data data = make_data(bytes, sizeof(bytes));393394*sym_out = NULL;395retval = krb5_c_random_make_octets(context, &data);396if (retval)397return retval;398sym = k5_base64_encode(data.data, data.length);399if (sym == NULL)400return ENOMEM;401/* Tweak the output alphabet just a bit. */402while ((p = strchr(sym, '/')) != NULL)403*p = '_';404while ((p = strchr(sym, '+')) != NULL)405*p = '-';406*sym_out = sym;407return 0;408}409410krb5_error_code411krb5_ccache_overwrite(krb5_context context, krb5_ccache ccs, krb5_ccache cct,412krb5_principal primary_principal)413{414krb5_error_code retval=0;415krb5_principal defprinc = NULL, princ;416krb5_creds ** ccs_creds_arr = NULL;417418if (ks_ccache_is_initialized(context, ccs)) {419retval = krb5_get_nonexp_tkts(context, ccs, &ccs_creds_arr);420if (retval)421goto cleanup;422}423424retval = krb5_cc_get_principal(context, cct, &defprinc);425princ = (retval == 0) ? defprinc : primary_principal;426retval = krb5_cc_initialize(context, cct, princ);427if (retval)428goto cleanup;429430retval = krb5_store_all_creds(context, cct, ccs_creds_arr, NULL);431432cleanup:433free_creds_list(context, ccs_creds_arr);434krb5_free_principal(context, defprinc);435return retval;436}437438krb5_error_code439krb5_store_some_creds(krb5_context context, krb5_ccache cc,440krb5_creds **creds_def, krb5_creds **creds_other,441krb5_principal prst, krb5_boolean *stored)442{443444int i = 0;445krb5_error_code retval = 0;446krb5_creds ** temp_creds= NULL;447krb5_boolean temp_stored = FALSE;448449450if ((creds_def == NULL) && (creds_other == NULL))451return 0;452453if ((creds_def == NULL) && (creds_other != NULL))454temp_creds = creds_other;455456if ((creds_def != NULL) && (creds_other == NULL))457temp_creds = creds_def;458459460if (temp_creds){461while(temp_creds[i]){462if (krb5_principal_compare(context,463temp_creds[i]->client,464prst)== TRUE) {465466if ((retval = krb5_cc_store_cred(context,467cc,temp_creds[i]))){468return retval;469}470temp_stored = TRUE;471}472473i++;474}475}476else { /* both arrays have elements in them */477return KRB5KRB_ERR_GENERIC;478}479480*stored = temp_stored;481return 0;482}483484krb5_error_code485krb5_ccache_filter(krb5_context context, krb5_ccache cc, krb5_principal prst)486{487488krb5_error_code retval=0;489krb5_principal temp_principal = NULL;490krb5_creds ** cc_creds_arr = NULL;491const char * cc_name;492krb5_boolean stored;493494if (!ks_ccache_is_initialized(context, cc))495return 0;496497if (auth_debug) {498cc_name = krb5_cc_get_name(context, cc);499fprintf(stderr, "putting cache %s through a filter for -z option\n",500cc_name);501}502503retval = krb5_get_nonexp_tkts(context, cc, &cc_creds_arr);504if (retval)505goto cleanup;506507retval = krb5_cc_get_principal(context, cc, &temp_principal);508if (retval)509goto cleanup;510511retval = krb5_cc_initialize(context, cc, temp_principal);512if (retval)513goto cleanup;514515retval = krb5_store_some_creds(context, cc, cc_creds_arr, NULL, prst,516&stored);517518cleanup:519free_creds_list(context, cc_creds_arr);520krb5_free_principal(context, temp_principal);521return retval;522}523524krb5_boolean525krb5_find_princ_in_cred_list(krb5_context context, krb5_creds **creds_list,526krb5_principal princ)527{528529int i = 0;530krb5_boolean temp_stored = FALSE;531532if (creds_list){533while(creds_list[i]){534if (krb5_principal_compare(context,535creds_list[i]->client,536princ)== TRUE){537temp_stored = TRUE;538break;539}540541i++;542}543}544545return temp_stored;546}547548krb5_error_code549krb5_find_princ_in_cache(krb5_context context, krb5_ccache cc,550krb5_principal princ, krb5_boolean *found)551{552krb5_error_code retval = 0;553krb5_creds ** creds_list = NULL;554555if (ks_ccache_is_initialized(context, cc)) {556retval = krb5_get_nonexp_tkts(context, cc, &creds_list);557if (retval)558goto cleanup;559}560561*found = krb5_find_princ_in_cred_list(context, creds_list, princ);562563cleanup:564free_creds_list(context, creds_list);565return retval;566}567568krb5_boolean569ks_ccache_name_is_initialized(krb5_context context, const char *cctag)570{571krb5_boolean result;572krb5_ccache cc;573574if (krb5_cc_resolve(context, cctag, &cc) != 0)575return FALSE;576result = ks_ccache_is_initialized(context, cc);577krb5_cc_close(context, cc);578579return result;580}581582krb5_boolean583ks_ccache_is_initialized(krb5_context context, krb5_ccache cc)584{585krb5_principal princ;586krb5_error_code retval;587588if (cc == NULL)589return FALSE;590591retval = krb5_cc_get_principal(context, cc, &princ);592if (retval == 0)593krb5_free_principal(context, princ);594595return retval == 0;596}597598599