diff options
Diffstat (limited to 'src/lib/krb5')
67 files changed, 1051 insertions, 574 deletions
diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c index a827ca6083e8..889460989f70 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.c +++ b/src/lib/krb5/asn.1/asn1_k_encode.c @@ -158,8 +158,7 @@ static asn1_error_code encode_kerberos_time(asn1buf *buf, const void *p, taginfo *rettag, size_t *len_out) { - /* Range checking for time_t vs krb5_timestamp? */ - time_t val = *(krb5_timestamp *)p; + time_t val = ts2tt(*(krb5_timestamp *)p); rettag->asn1class = UNIVERSAL; rettag->construction = PRIMITIVE; rettag->tagnum = ASN1_GENERALTIME; diff --git a/src/lib/krb5/ccache/Makefile.in b/src/lib/krb5/ccache/Makefile.in index 5ac870728d9d..f84cf793e0db 100644 --- a/src/lib/krb5/ccache/Makefile.in +++ b/src/lib/krb5/ccache/Makefile.in @@ -34,6 +34,7 @@ STLIBOBJS= \ ccdefops.o \ ccmarshal.o \ ccselect.o \ + ccselect_hostname.o \ ccselect_k5identity.o \ ccselect_realm.o \ cc_dir.o \ @@ -52,6 +53,7 @@ OBJS= $(OUTPRE)ccbase.$(OBJEXT) \ $(OUTPRE)ccdefops.$(OBJEXT) \ $(OUTPRE)ccmarshal.$(OBJEXT) \ $(OUTPRE)ccselect.$(OBJEXT) \ + $(OUTPRE)ccselect_hostname.$(OBJEXT) \ $(OUTPRE)ccselect_k5identity.$(OBJEXT) \ $(OUTPRE)ccselect_realm.$(OBJEXT) \ $(OUTPRE)cc_dir.$(OBJEXT) \ @@ -70,6 +72,7 @@ SRCS= $(srcdir)/ccbase.c \ $(srcdir)/ccdefops.c \ $(srcdir)/ccmarshal.c \ $(srcdir)/ccselect.c \ + $(srcdir)/ccselect_hostname.c \ $(srcdir)/ccselect_k5identity.c \ $(srcdir)/ccselect_realm.c \ $(srcdir)/cc_dir.c \ diff --git a/src/lib/krb5/ccache/cc-int.h b/src/lib/krb5/ccache/cc-int.h index ee9b5e0e97a1..d920367cea97 100644 --- a/src/lib/krb5/ccache/cc-int.h +++ b/src/lib/krb5/ccache/cc-int.h @@ -124,6 +124,10 @@ krb5_error_code krb5int_fcc_new_unique(krb5_context context, char *template, krb5_ccache *id); krb5_error_code +ccselect_hostname_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +krb5_error_code ccselect_realm_initvt(krb5_context context, int maj_ver, int min_ver, krb5_plugin_vtable vtable); diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c index a889e67b4492..b621ed33b3e7 100644 --- a/src/lib/krb5/ccache/cc_kcm.c +++ b/src/lib/krb5/ccache/cc_kcm.c @@ -32,7 +32,7 @@ /* * This cache type contacts a daemon for each cache operation, using Heimdal's - * KCM protocol. On OS X, the preferred transport is Mach RPC; on other + * KCM protocol. On macOS, the preferred transport is Mach RPC; on other * Unix-like platforms or if the daemon is not available via RPC, Unix domain * sockets are used instead. */ @@ -360,7 +360,7 @@ kcmio_connect(krb5_context context, struct kcmio **io_out) return ENOMEM; io->fd = -1; - /* Try Mach RPC (OS X only), then fall back to Unix domain sockets */ + /* Try Mach RPC (macOS only), then fall back to Unix domain sockets */ ret = kcmio_mach_connect(context, io); if (ret) ret = kcmio_unix_socket_connect(context, io); diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c index 4fe3f0d6f1f2..fba710b1b651 100644 --- a/src/lib/krb5/ccache/cc_keyring.c +++ b/src/lib/krb5/ccache/cc_keyring.c @@ -751,7 +751,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id) for (;;) { if (krcc_next_cred(context, id, &cursor, &creds) != 0) break; - if (creds.times.endtime > endtime) + if (ts_after(creds.times.endtime, endtime)) endtime = creds.times.endtime; krb5_free_cred_contents(context, &creds); } @@ -765,7 +765,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id) /* Setting the timeout to zero would reset the timeout, so we set it to one * second instead if creds are already expired. */ - timeout = (endtime > now) ? endtime - now : 1; + timeout = ts_after(endtime, now) ? ts_delta(endtime, now) : 1; (void)keyctl_set_timeout(data->cache_id, timeout); } @@ -1316,8 +1316,10 @@ krcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds) if (ret) goto errout; - if (creds->times.endtime > now) - (void)keyctl_set_timeout(cred_key, creds->times.endtime - now); + if (ts_after(creds->times.endtime, now)) { + (void)keyctl_set_timeout(cred_key, + ts_delta(creds->times.endtime, now)); + } update_keyring_expiration(context, id); @@ -1680,8 +1682,8 @@ static void krcc_update_change_time(krcc_data *data) { krb5_timestamp now_time = time(NULL); - data->changetime = (data->changetime >= now_time) ? - data->changetime + 1 : now_time; + data->changetime = ts_after(now_time, data->changetime) ? + now_time : ts_incr(data->changetime, 1); } /* diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c index 0354575c5c16..c5425eb3ae7a 100644 --- a/src/lib/krb5/ccache/cc_memory.c +++ b/src/lib/krb5/ccache/cc_memory.c @@ -720,8 +720,8 @@ static void update_mcc_change_time(krb5_mcc_data *d) { krb5_timestamp now_time = time(NULL); - d->changetime = (d->changetime >= now_time) ? - d->changetime + 1 : now_time; + d->changetime = ts_after(now_time, d->changetime) ? + now_time : ts_incr(d->changetime, 1); } static krb5_error_code KRB5_CALLCONV diff --git a/src/lib/krb5/ccache/cc_mslsa.c b/src/lib/krb5/ccache/cc_mslsa.c index 7a8047023716..c741a5099ae6 100644 --- a/src/lib/krb5/ccache/cc_mslsa.c +++ b/src/lib/krb5/ccache/cc_mslsa.c @@ -1553,6 +1553,7 @@ krb5_lcc_resolve (krb5_context context, krb5_ccache *id, const char *residual) data->LogonHandle = LogonHandle; data->PackageId = PackageId; data->princ = NULL; + data->flags = 0; data->cc_name = (char *)malloc(strlen(residual)+1); if (data->cc_name == NULL) { diff --git a/src/lib/krb5/ccache/cc_retr.c b/src/lib/krb5/ccache/cc_retr.c index 1314d24bd68d..e8a20fe36001 100644 --- a/src/lib/krb5/ccache/cc_retr.c +++ b/src/lib/krb5/ccache/cc_retr.c @@ -46,11 +46,11 @@ static krb5_boolean times_match(const krb5_ticket_times *t1, const krb5_ticket_times *t2) { if (t1->renew_till) { - if (t1->renew_till > t2->renew_till) + if (ts_after(t1->renew_till, t2->renew_till)) return FALSE; /* this one expires too late */ } if (t1->endtime) { - if (t1->endtime > t2->endtime) + if (ts_after(t1->endtime, t2->endtime)) return FALSE; /* this one expires too late */ } /* only care about expiration on a times_match */ @@ -211,7 +211,6 @@ krb5_cc_retrieve_cred_seq (krb5_context context, krb5_ccache id, int pref; } fetched, best; int have_creds = 0; - krb5_flags oflags = 0; #define fetchcreds (fetched.creds) kret = krb5_cc_start_seq_get(context, id, &cursor); diff --git a/src/lib/krb5/ccache/ccapi/stdcc_util.c b/src/lib/krb5/ccache/ccapi/stdcc_util.c index 9f44af3d087c..6092ee432222 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc_util.c +++ b/src/lib/krb5/ccache/ccapi/stdcc_util.c @@ -16,8 +16,8 @@ #include <malloc.h> #endif +#include "k5-int.h" #include "stdcc_util.h" -#include "krb5.h" #ifdef _WIN32 /* it's part of krb5.h everywhere else */ #include "kv5m_err.h" #endif @@ -321,10 +321,10 @@ copy_cc_cred_union_to_krb5_creds (krb5_context in_context, keyblock_contents = NULL; /* copy times */ - out_creds->times.authtime = cv5->authtime + offset_seconds; - out_creds->times.starttime = cv5->starttime + offset_seconds; - out_creds->times.endtime = cv5->endtime + offset_seconds; - out_creds->times.renew_till = cv5->renew_till + offset_seconds; + out_creds->times.authtime = ts_incr(cv5->authtime, offset_seconds); + out_creds->times.starttime = ts_incr(cv5->starttime, offset_seconds); + out_creds->times.endtime = ts_incr(cv5->endtime, offset_seconds); + out_creds->times.renew_till = ts_incr(cv5->renew_till, offset_seconds); out_creds->is_skey = cv5->is_skey; out_creds->ticket_flags = cv5->ticket_flags; @@ -451,11 +451,11 @@ copy_krb5_creds_to_cc_cred_union (krb5_context in_context, cv5->keyblock.data = keyblock_data; keyblock_data = NULL; - cv5->authtime = in_creds->times.authtime - offset_seconds; - cv5->starttime = in_creds->times.starttime - offset_seconds; - cv5->endtime = in_creds->times.endtime - offset_seconds; - cv5->renew_till = in_creds->times.renew_till - offset_seconds; - cv5->is_skey = in_creds->is_skey; + cv5->authtime = ts_incr(in_creds->times.authtime, -offset_seconds); + cv5->starttime = ts_incr(in_creds->times.starttime, -offset_seconds); + cv5->endtime = ts_incr(in_creds->times.endtime, -offset_seconds); + cv5->renew_till = ts_incr(in_creds->times.renew_till, -offset_seconds); + cv5->is_skey = in_creds->is_skey; cv5->ticket_flags = in_creds->ticket_flags; if (in_creds->ticket.data) { @@ -732,10 +732,10 @@ void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest) err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); if (err) return; #endif - dest->times.authtime = src->authtime + offset_seconds; - dest->times.starttime = src->starttime + offset_seconds; - dest->times.endtime = src->endtime + offset_seconds; - dest->times.renew_till = src->renew_till + offset_seconds; + dest->times.authtime = ts_incr(src->authtime, offset_seconds); + dest->times.starttime = ts_incr(src->starttime, offset_seconds); + dest->times.endtime = ts_incr(src->endtime, offset_seconds); + dest->times.renew_till = ts_incr(src->renew_till, offset_seconds); dest->is_skey = src->is_skey; dest->ticket_flags = src->ticket_flags; @@ -804,10 +804,10 @@ void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu) err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); if (err) return; #endif - c->authtime = creds->times.authtime - offset_seconds; - c->starttime = creds->times.starttime - offset_seconds; - c->endtime = creds->times.endtime - offset_seconds; - c->renew_till = creds->times.renew_till - offset_seconds; + c->authtime = ts_incr(creds->times.authtime, -offset_seconds); + c->starttime = ts_incr(creds->times.starttime, -offset_seconds); + c->endtime = ts_incr(creds->times.endtime, -offset_seconds); + c->renew_till = ts_incr(creds->times.renew_till, -offset_seconds); c->is_skey = creds->is_skey; c->ticket_flags = creds->ticket_flags; @@ -925,11 +925,11 @@ times_match(t1, t2) register const krb5_ticket_times *t2; { if (t1->renew_till) { - if (t1->renew_till > t2->renew_till) + if (ts_after(t1->renew_till, t2->renew_till)) return FALSE; /* this one expires too late */ } if (t1->endtime) { - if (t1->endtime > t2->endtime) + if (ts_after(t1->endtime, t2->endtime)) return FALSE; /* this one expires too late */ } /* only care about expiration on a times_match */ diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c index c31a3f5f0b87..506a27c1b969 100644 --- a/src/lib/krb5/ccache/cccursor.c +++ b/src/lib/krb5/ccache/cccursor.c @@ -159,7 +159,7 @@ krb5_cccol_last_change_time(krb5_context context, ret = krb5_cccol_cursor_next(context, c, &ccache); if (ccache) { ret = krb5_cc_last_change_time(context, ccache, &last_time); - if (!ret && last_time > max_change_time) { + if (!ret && ts_after(last_time, max_change_time)) { max_change_time = last_time; } ret = 0; @@ -230,14 +230,37 @@ save_first_error(krb5_context context, krb5_error_code code, k5_save_ctx_error(context, code, errsave); } +/* Return 0 if cache contains any non-config credentials. Return KRB5_CC_END + * if it does not, or another error if we failed to read through it. */ +static krb5_error_code +has_content(krb5_context context, krb5_ccache cache) +{ + krb5_error_code ret; + krb5_boolean found = FALSE; + krb5_cc_cursor cache_cursor; + krb5_creds creds; + + ret = krb5_cc_start_seq_get(context, cache, &cache_cursor); + if (ret) + return ret; + while (!found) { + ret = krb5_cc_next_cred(context, cache, &cache_cursor, &creds); + if (ret) + break; + if (!krb5_is_config_principal(context, creds.server)) + found = TRUE; + krb5_free_cred_contents(context, &creds); + } + krb5_cc_end_seq_get(context, cache, &cache_cursor); + return ret; +} + krb5_error_code KRB5_CALLCONV krb5_cccol_have_content(krb5_context context) { krb5_error_code ret; krb5_cccol_cursor col_cursor; - krb5_cc_cursor cache_cursor; krb5_ccache cache; - krb5_creds creds; krb5_boolean found = FALSE; struct errinfo errsave = EMPTY_ERRINFO; const char *defname; @@ -252,24 +275,10 @@ krb5_cccol_have_content(krb5_context context) save_first_error(context, ret, &errsave); if (ret || cache == NULL) break; - - ret = krb5_cc_start_seq_get(context, cache, &cache_cursor); + ret = has_content(context, cache); save_first_error(context, ret, &errsave); - if (ret) { - krb5_cc_close(context, cache); - continue; - } - while (!found) { - ret = krb5_cc_next_cred(context, cache, &cache_cursor, &creds); - save_first_error(context, ret, &errsave); - if (ret) - break; - - if (!krb5_is_config_principal(context, creds.server)) - found = TRUE; - krb5_free_cred_contents(context, &creds); - } - krb5_cc_end_seq_get(context, cache, &cache_cursor); + if (!ret) + found = TRUE; krb5_cc_close(context, cache); } krb5_cccol_cursor_free(context, &col_cursor); diff --git a/src/lib/krb5/ccache/ccmarshal.c b/src/lib/krb5/ccache/ccmarshal.c index bd6d309d1d4e..ae634ccab0d2 100644 --- a/src/lib/krb5/ccache/ccmarshal.c +++ b/src/lib/krb5/ccache/ccmarshal.c @@ -100,8 +100,8 @@ * second value when reading it. */ -#include "k5-input.h" #include "cc-int.h" +#include "k5-input.h" /* Read a 16-bit integer in host byte order for versions 1 and 2, or in * big-endian byte order for later versions.*/ diff --git a/src/lib/krb5/ccache/ccselect.c b/src/lib/krb5/ccache/ccselect.c index 2f3071a272a2..6c360e1002ec 100644 --- a/src/lib/krb5/ccache/ccselect.c +++ b/src/lib/krb5/ccache/ccselect.c @@ -71,6 +71,11 @@ load_modules(krb5_context context) if (ret != 0) goto cleanup; + ret = k5_plugin_register(context, PLUGIN_INTERFACE_CCSELECT, "hostname", + ccselect_hostname_initvt); + if (ret != 0) + goto cleanup; + ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_CCSELECT, &modules); if (ret != 0) goto cleanup; @@ -115,14 +120,6 @@ cleanup: return ret; } -static krb5_error_code -choose(krb5_context context, struct ccselect_module_handle *h, - krb5_principal server, krb5_ccache *cache_out, - krb5_principal *princ_out) -{ - return h->vt.choose(context, h->data, server, cache_out, princ_out); -} - krb5_error_code KRB5_CALLCONV krb5_cc_select(krb5_context context, krb5_principal server, krb5_ccache *cache_out, krb5_principal *princ_out) @@ -132,6 +129,8 @@ krb5_cc_select(krb5_context context, krb5_principal server, struct ccselect_module_handle **hp, *h; krb5_ccache cache; krb5_principal princ; + krb5_principal srvcp = NULL; + char **fbrealms = NULL; *cache_out = NULL; *princ_out = NULL; @@ -139,7 +138,27 @@ krb5_cc_select(krb5_context context, krb5_principal server, if (context->ccselect_handles == NULL) { ret = load_modules(context); if (ret) - return ret; + goto cleanup; + } + + /* Try to use the fallback host realm for the server if there is no + * authoritative realm. */ + if (krb5_is_referral_realm(&server->realm) && + server->type == KRB5_NT_SRV_HST && server->length == 2) { + ret = krb5_get_fallback_host_realm(context, &server->data[1], + &fbrealms); + if (ret) + goto cleanup; + + /* Make a copy with the first fallback realm. */ + ret = krb5_copy_principal(context, server, &srvcp); + if (ret) + goto cleanup; + ret = krb5_set_principal_realm(context, srvcp, fbrealms[0]); + if (ret) + goto cleanup; + + server = srvcp; } /* Consult authoritative modules first, then heuristic ones. */ @@ -149,26 +168,31 @@ krb5_cc_select(krb5_context context, krb5_principal server, h = *hp; if (h->priority != priority) continue; - ret = choose(context, h, server, &cache, &princ); + ret = h->vt.choose(context, h->data, server, &cache, &princ); if (ret == 0) { TRACE_CCSELECT_MODCHOICE(context, h->vt.name, server, cache, princ); *cache_out = cache; *princ_out = princ; - return 0; + goto cleanup; } else if (ret == KRB5_CC_NOTFOUND) { TRACE_CCSELECT_MODNOTFOUND(context, h->vt.name, server, princ); *princ_out = princ; - return ret; + goto cleanup; } else if (ret != KRB5_PLUGIN_NO_HANDLE) { TRACE_CCSELECT_MODFAIL(context, h->vt.name, ret, server); - return ret; + goto cleanup; } } } TRACE_CCSELECT_NOTFOUND(context, server); - return KRB5_CC_NOTFOUND; + ret = KRB5_CC_NOTFOUND; + +cleanup: + krb5_free_principal(context, srvcp); + krb5_free_host_realm(context, fbrealms); + return ret; } void diff --git a/src/lib/krb5/ccache/ccselect_hostname.c b/src/lib/krb5/ccache/ccselect_hostname.c new file mode 100644 index 000000000000..475cfabaefd7 --- /dev/null +++ b/src/lib/krb5/ccache/ccselect_hostname.c @@ -0,0 +1,146 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/ccache/ccselect_hostname.c - hostname ccselect module */ +/* + * Copyright (C) 2017 by Red Hat, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "k5-int.h" +#include "cc-int.h" +#include <ctype.h> +#include <krb5/ccselect_plugin.h> + +/* Swap a and b, using tmp as an intermediate. */ +#define SWAP(a, b, tmp) \ + tmp = a; \ + a = b; \ + b = tmp; + +static krb5_error_code +hostname_init(krb5_context context, krb5_ccselect_moddata *data_out, + int *priority_out) +{ + *data_out = NULL; + *priority_out = KRB5_CCSELECT_PRIORITY_HEURISTIC; + return 0; +} + +static krb5_error_code +hostname_choose(krb5_context context, krb5_ccselect_moddata data, + krb5_principal server, krb5_ccache *ccache_out, + krb5_principal *princ_out) +{ + krb5_error_code ret; + char *p, *host = NULL; + size_t hostlen; + krb5_cccol_cursor col_cursor; + krb5_ccache ccache, tmp_ccache, best_ccache = NULL; + krb5_principal princ, tmp_princ, best_princ = NULL; + krb5_data domain; + + *ccache_out = NULL; + *princ_out = NULL; + + if (server->type != KRB5_NT_SRV_HST || server->length < 2) + return KRB5_PLUGIN_NO_HANDLE; + + /* Compute upper-case hostname. */ + hostlen = server->data[1].length; + host = k5memdup0(server->data[1].data, hostlen, &ret); + if (host == NULL) + return ret; + for (p = host; *p != '\0'; p++) { + if (islower(*p)) + *p = toupper(*p); + } + + /* Scan the collection for a cache with a client principal whose realm is + * the longest tail of the server hostname. */ + ret = krb5_cccol_cursor_new(context, &col_cursor); + if (ret) + goto done; + + for (ret = krb5_cccol_cursor_next(context, col_cursor, &ccache); + ret == 0 && ccache != NULL; + ret = krb5_cccol_cursor_next(context, col_cursor, &ccache)) { + ret = krb5_cc_get_principal(context, ccache, &princ); + if (ret) { + krb5_cc_close(context, ccache); + break; + } + + /* Check for a longer match than we have. */ + domain = make_data(host, hostlen); + while (best_princ == NULL || + best_princ->realm.length < domain.length) { + if (data_eq(princ->realm, domain)) { + SWAP(best_ccache, ccache, tmp_ccache); + SWAP(best_princ, princ, tmp_princ); + break; + } + + /* Try the next parent domain. */ + p = memchr(domain.data, '.', domain.length); + if (p == NULL) + break; + domain = make_data(p + 1, hostlen - (p + 1 - host)); + } + + if (ccache != NULL) + krb5_cc_close(context, ccache); + krb5_free_principal(context, princ); + } + + krb5_cccol_cursor_free(context, &col_cursor); + + if (best_ccache != NULL) { + *ccache_out = best_ccache; + *princ_out = best_princ; + } else { + ret = KRB5_PLUGIN_NO_HANDLE; + } + +done: + free(host); + return ret; +} + +krb5_error_code +ccselect_hostname_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_ccselect_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_ccselect_vtable)vtable; + vt->name = "hostname"; + vt->init = hostname_init; + vt->choose = hostname_choose; + return 0; +} diff --git a/src/lib/krb5/ccache/deps b/src/lib/krb5/ccache/deps index 9cd2e00d456c..6732f75548ce 100644 --- a/src/lib/krb5/ccache/deps +++ b/src/lib/krb5/ccache/deps @@ -78,6 +78,17 @@ ccselect.so ccselect.po $(OUTPRE)ccselect.$(OBJEXT): \ $(top_srcdir)/include/krb5/ccselect_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ cc-int.h ccselect.c +ccselect_hostname.so ccselect_hostname.po $(OUTPRE)ccselect_hostname.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ + $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ + $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ + $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ + $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/ccselect_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h cc-int.h ccselect_hostname.c ccselect_k5identity.so ccselect_k5identity.po $(OUTPRE)ccselect_k5identity.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c index 6a42f267df7d..091f2c43fa3a 100644 --- a/src/lib/krb5/keytab/kt_file.c +++ b/src/lib/krb5/keytab/kt_file.c @@ -264,9 +264,11 @@ more_recent(const krb5_keytab_entry *k1, const krb5_keytab_entry *k2) * limitations (8-bit kvno storage), pre-1.14 kadmin protocol limitations * (8-bit kvno marshalling), or KDB limitations (16-bit kvno storage). */ - if (k1->timestamp >= k2->timestamp && k1->vno < 128 && k2->vno > 240) + if (!ts_after(k2->timestamp, k1->timestamp) && + k1->vno < 128 && k2->vno > 240) return TRUE; - if (k1->timestamp <= k2->timestamp && k1->vno > 240 && k2->vno < 128) + if (!ts_after(k1->timestamp, k2->timestamp) && + k1->vno > 240 && k2->vno < 128) return FALSE; /* Otherwise do a simple version comparison. */ @@ -357,7 +359,7 @@ krb5_ktfile_get_entry(krb5_context context, krb5_keytab id, } - if (kvno == IGNORE_VNO) { + if (kvno == IGNORE_VNO || new_entry.vno == IGNORE_VNO) { /* If this entry is more recent (or the first match), free the * current and keep the new. Otherwise, free the new. */ if (cur_entry.principal == NULL || diff --git a/src/lib/krb5/keytab/kt_memory.c b/src/lib/krb5/keytab/kt_memory.c index e89fdcb4dc99..8824adf50826 100644 --- a/src/lib/krb5/keytab/kt_memory.c +++ b/src/lib/krb5/keytab/kt_memory.c @@ -403,7 +403,7 @@ krb5_mkt_get_entry(krb5_context context, krb5_keytab id, continue; } - if (kvno == IGNORE_VNO) { + if (kvno == IGNORE_VNO || entry->vno == IGNORE_VNO) { if (match == NULL) match = entry; else if (entry->vno > match->vno) diff --git a/src/lib/krb5/keytab/kt_srvtab.c b/src/lib/krb5/keytab/kt_srvtab.c index caa0158ecc2b..bbfaadfc298c 100644 --- a/src/lib/krb5/keytab/kt_srvtab.c +++ b/src/lib/krb5/keytab/kt_srvtab.c @@ -205,7 +205,7 @@ krb5_ktsrvtab_get_entry(krb5_context context, krb5_keytab id, krb5_const_princip while ((kerror = krb5_ktsrvint_read_entry(context, id, &ent)) == 0) { ent.key.enctype = enctype; if (krb5_principal_compare(context, principal, ent.principal)) { - if (kvno == IGNORE_VNO) { + if (kvno == IGNORE_VNO || ent.vno == IGNORE_VNO) { if (!best_entry.principal || (best_entry.vno < ent.vno)) { krb5_kt_free_entry(context, &best_entry); best_entry = ent; diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 0fe02a95d09e..55f82b147d8c 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -364,6 +364,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/t_in_ccache.c \ $(srcdir)/t_response_items.c \ $(srcdir)/t_sname_match.c \ + $(srcdir)/t_valid_times.c \ $(srcdir)/t_vfy_increds.c # Someday, when we have a "maintainer mode", do this right: @@ -457,9 +458,12 @@ t_response_items: t_response_items.o response_items.o $(KRB5_BASE_DEPLIBS) t_sname_match: t_sname_match.o sname_match.o $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o $@ t_sname_match.o sname_match.o $(KRB5_BASE_LIBS) +t_valid_times: t_valid_times.o valid_times.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ t_valid_times.o valid_times.o $(KRB5_BASE_LIBS) + TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \ - t_in_ccache t_cc_config t_copy_context \ - t_princ t_etypes t_vfy_increds t_response_items t_sname_match + t_in_ccache t_cc_config t_copy_context t_princ t_etypes t_vfy_increds \ + t_response_items t_sname_match t_valid_times check-unix: $(TEST_PROGS) $(RUN_TEST_LOCAL_CONF) ./t_kerb \ @@ -496,6 +500,7 @@ check-unix: $(TEST_PROGS) $(RUN_TEST) ./t_response_items $(RUN_TEST) ./t_copy_context $(RUN_TEST) ./t_sname_match + $(RUN_TEST) ./t_valid_times check-pytests: t_expire_warn t_vfy_increds $(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS) @@ -522,8 +527,9 @@ clean: $(OUTPRE)t_ad_fx_armor$(EXEEXT) $(OUTPRE)t_ad_fx_armor.$(OBJEXT) \ $(OUTPRE)t_vfy_increds$(EXEEXT) $(OUTPRE)t_vfy_increds.$(OBJEXT) \ $(OUTPRE)t_response_items$(EXEEXT) \ - $(OUTPRE)t_response_items.$(OBJEXT) $(OUTPRE)t_sname_match$(EXEEXT) \ - $(OUTPRE)t_sname_match.$(OBJEXT) \ + $(OUTPRE)t_response_items.$(OBJEXT) \ + $(OUTPRE)t_sname_match$(EXEEXT) $(OUTPRE)t_sname_match.$(OBJEXT) \ + $(OUTPRE)t_valid_times$(EXEEXT) $(OUTPRE)t_valid_times.$(OBJECT) \ $(OUTPRE)t_parse_host_string$(EXEEXT) \ $(OUTPRE)t_parse_host_string.$(OBJEXT) diff --git a/src/lib/krb5/krb/deltat.c b/src/lib/krb5/krb/deltat.c index 2c8b90b54ce3..6e6616e99ff8 100644 --- a/src/lib/krb5/krb/deltat.c +++ b/src/lib/krb5/krb/deltat.c @@ -72,7 +72,6 @@ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #include "k5-int.h" @@ -153,7 +152,7 @@ static int mylex(int *intp, struct param *tmv); static int yyparse(struct param *); -#line 157 "deltat.c" /* yacc.c:339 */ +#line 156 "deltat.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus @@ -197,10 +196,10 @@ extern int yydebug; typedef union YYSTYPE YYSTYPE; union YYSTYPE { -#line 129 "x-deltat.y" /* yacc.c:355 */ +#line 128 "x-deltat.y" /* yacc.c:355 */ int val; -#line 204 "deltat.c" /* yacc.c:355 */ +#line 203 "deltat.c" /* yacc.c:355 */ }; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 @@ -214,7 +213,7 @@ int yyparse (struct param *tmv); /* Copy the second part of user declarations. */ -#line 218 "deltat.c" /* yacc.c:358 */ +#line 217 "deltat.c" /* yacc.c:358 */ #ifdef short # undef short @@ -512,9 +511,9 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 143, 143, 144, 144, 145, 145, 146, 146, 147, - 148, 150, 151, 152, 153, 154, 155, 156, 157, 162, - 163, 166, 167, 170, 171 + 0, 142, 142, 143, 143, 144, 144, 145, 145, 146, + 147, 149, 150, 151, 152, 153, 154, 155, 156, 161, + 162, 165, 166, 169, 170 }; #endif @@ -1310,93 +1309,93 @@ yyreduce: switch (yyn) { case 6: -#line 145 "x-deltat.y" /* yacc.c:1646 */ +#line 144 "x-deltat.y" /* yacc.c:1646 */ { (yyval.val) = - (yyvsp[0].val); } -#line 1316 "deltat.c" /* yacc.c:1646 */ +#line 1315 "deltat.c" /* yacc.c:1646 */ break; case 9: -#line 147 "x-deltat.y" /* yacc.c:1646 */ +#line 146 "x-deltat.y" /* yacc.c:1646 */ { (yyval.val) = (yyvsp[0].val); } -#line 1322 "deltat.c" /* yacc.c:1646 */ +#line 1321 "deltat.c" /* yacc.c:1646 */ break; case 10: -#line 148 "x-deltat.y" /* yacc.c:1646 */ +#line 147 "x-deltat.y" /* yacc.c:1646 */ { YYERROR; } -#line 1328 "deltat.c" /* yacc.c:1646 */ +#line 1327 "deltat.c" /* yacc.c:1646 */ break; case 11: -#line 150 "x-deltat.y" /* yacc.c:1646 */ +#line 149 "x-deltat.y" /* yacc.c:1646 */ { DO ((yyvsp[-2].val), 0, 0, (yyvsp[0].val)); } -#line 1334 "deltat.c" /* yacc.c:1646 */ +#line 1333 "deltat.c" /* yacc.c:1646 */ break; case 12: -#line 151 "x-deltat.y" /* yacc.c:1646 */ +#line 150 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, (yyvsp[-2].val), 0, (yyvsp[0].val)); } -#line 1340 "deltat.c" /* yacc.c:1646 */ +#line 1339 "deltat.c" /* yacc.c:1646 */ break; case 13: -#line 152 "x-deltat.y" /* yacc.c:1646 */ +#line 151 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, 0, (yyvsp[-2].val), (yyvsp[0].val)); } -#line 1346 "deltat.c" /* yacc.c:1646 */ +#line 1345 "deltat.c" /* yacc.c:1646 */ break; case 14: -#line 153 "x-deltat.y" /* yacc.c:1646 */ +#line 152 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, 0, 0, (yyvsp[-1].val)); } -#line 1352 "deltat.c" /* yacc.c:1646 */ +#line 1351 "deltat.c" /* yacc.c:1646 */ break; case 15: -#line 154 "x-deltat.y" /* yacc.c:1646 */ +#line 153 "x-deltat.y" /* yacc.c:1646 */ { DO ((yyvsp[-6].val), (yyvsp[-4].val), (yyvsp[-2].val), (yyvsp[0].val)); } -#line 1358 "deltat.c" /* yacc.c:1646 */ +#line 1357 "deltat.c" /* yacc.c:1646 */ break; case 16: -#line 155 "x-deltat.y" /* yacc.c:1646 */ +#line 154 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, (yyvsp[-4].val), (yyvsp[-2].val), (yyvsp[0].val)); } -#line 1364 "deltat.c" /* yacc.c:1646 */ +#line 1363 "deltat.c" /* yacc.c:1646 */ break; case 17: -#line 156 "x-deltat.y" /* yacc.c:1646 */ +#line 155 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, (yyvsp[-2].val), (yyvsp[0].val), 0); } -#line 1370 "deltat.c" /* yacc.c:1646 */ +#line 1369 "deltat.c" /* yacc.c:1646 */ break; case 18: -#line 157 "x-deltat.y" /* yacc.c:1646 */ +#line 156 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, 0, 0, (yyvsp[0].val)); } -#line 1376 "deltat.c" /* yacc.c:1646 */ +#line 1375 "deltat.c" /* yacc.c:1646 */ break; case 20: -#line 163 "x-deltat.y" /* yacc.c:1646 */ +#line 162 "x-deltat.y" /* yacc.c:1646 */ { if (HOUR_NOT_OK((yyvsp[-2].val))) YYERROR; DO_SUM((yyval.val), (yyvsp[-2].val) * 3600, (yyvsp[0].val)); } -#line 1383 "deltat.c" /* yacc.c:1646 */ +#line 1382 "deltat.c" /* yacc.c:1646 */ break; case 22: -#line 167 "x-deltat.y" /* yacc.c:1646 */ +#line 166 "x-deltat.y" /* yacc.c:1646 */ { if (MIN_NOT_OK((yyvsp[-2].val))) YYERROR; DO_SUM((yyval.val), (yyvsp[-2].val) * 60, (yyvsp[0].val)); } -#line 1390 "deltat.c" /* yacc.c:1646 */ +#line 1389 "deltat.c" /* yacc.c:1646 */ break; case 23: -#line 170 "x-deltat.y" /* yacc.c:1646 */ +#line 169 "x-deltat.y" /* yacc.c:1646 */ { (yyval.val) = 0; } -#line 1396 "deltat.c" /* yacc.c:1646 */ +#line 1395 "deltat.c" /* yacc.c:1646 */ break; -#line 1400 "deltat.c" /* yacc.c:1646 */ +#line 1399 "deltat.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1624,7 +1623,7 @@ yyreturn: #endif return yyresult; } -#line 173 "x-deltat.y" /* yacc.c:1906 */ +#line 172 "x-deltat.y" /* yacc.c:1906 */ #ifdef __GNUC__ diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps index 6919eaf717aa..f78b47e766e1 100644 --- a/src/lib/krb5/krb/deps +++ b/src/lib/krb5/krb/deps @@ -1236,8 +1236,15 @@ t_walk_rtree.so t_walk_rtree.po $(OUTPRE)t_walk_rtree.$(OBJEXT): \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ t_walk_rtree.c t_kerb.so t_kerb.po $(OUTPRE)t_kerb.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \ - t_kerb.c + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h t_kerb.c t_ser.so t_ser.po $(OUTPRE)t_ser.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ @@ -1283,14 +1290,14 @@ t_pac.so t_pac.po $(OUTPRE)t_pac.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ t_parse_host_string.so t_parse_host_string.po $(OUTPRE)t_parse_host_string.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ - $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ - $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ - $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ - $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ - $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ - $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - t_parse_host_string.c + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-cmocka.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h t_parse_host_string.c t_princ.so t_princ.po $(OUTPRE)t_princ.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ @@ -1389,6 +1396,17 @@ t_sname_match.so t_sname_match.po $(OUTPRE)t_sname_match.$(OBJEXT): \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ t_sname_match.c +t_valid_times.so t_valid_times.po $(OUTPRE)t_valid_times.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ + $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ + $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ + $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ + $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + int-proto.h t_valid_times.c t_vfy_increds.so t_vfy_increds.po $(OUTPRE)t_vfy_increds.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ diff --git a/src/lib/krb5/krb/fwd_tgt.c b/src/lib/krb5/krb/fwd_tgt.c index a217d4c24001..87f63b6bc4c8 100644 --- a/src/lib/krb5/krb/fwd_tgt.c +++ b/src/lib/krb5/krb/fwd_tgt.c @@ -37,8 +37,9 @@ /* Get a TGT for use at the remote host */ krb5_error_code KRB5_CALLCONV krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, - char *rhost, krb5_principal client, krb5_principal server, - krb5_ccache cc, int forwardable, krb5_data *outbuf) + const char *rhost, krb5_principal client, + krb5_principal server, krb5_ccache cc, int forwardable, + krb5_data *outbuf) /* Should forwarded TGT also be forwardable? */ { krb5_replay_data replaydata; @@ -48,8 +49,8 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, krb5_creds creds, tgt; krb5_creds *pcreds; krb5_flags kdcoptions; - int close_cc = 0; - int free_rhost = 0; + krb5_ccache defcc = NULL; + char *def_rhost = NULL; krb5_enctype enctype = 0; krb5_keyblock *session_key; krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; @@ -58,9 +59,9 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, memset(&tgt, 0, sizeof(creds)); if (cc == 0) { - if ((retval = krb5int_cc_default(context, &cc))) + if ((retval = krb5int_cc_default(context, &defcc))) goto errout; - close_cc = 1; + cc = defcc; } retval = krb5_auth_con_getkey (context, auth_context, &session_key); if (retval) @@ -131,11 +132,11 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, goto errout; } - rhost = k5memdup0(server->data[1].data, server->data[1].length, - &retval); - if (rhost == NULL) + def_rhost = k5memdup0(server->data[1].data, server->data[1].length, + &retval); + if (def_rhost == NULL) goto errout; - free_rhost = 1; + rhost = def_rhost; } retval = k5_os_hostaddr(context, rhost, &addrs); @@ -176,10 +177,9 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, errout: if (addrs) krb5_free_addresses(context, addrs); - if (close_cc) - krb5_cc_close(context, cc); - if (free_rhost) - free(rhost); + if (defcc) + krb5_cc_close(context, defcc); + free(def_rhost); krb5_free_cred_contents(context, &creds); krb5_free_cred_contents(context, &tgt); return retval; diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c index 4c0a1a46120a..5b9bb9573e27 100644 --- a/src/lib/krb5/krb/gc_via_tkt.c +++ b/src/lib/krb5/krb/gc_via_tkt.c @@ -287,26 +287,27 @@ krb5int_process_tgs_reply(krb5_context context, retval = KRB5_KDCREP_MODIFIED; if ((in_cred->times.endtime != 0) && - (dec_rep->enc_part2->times.endtime > in_cred->times.endtime)) + ts_after(dec_rep->enc_part2->times.endtime, in_cred->times.endtime)) retval = KRB5_KDCREP_MODIFIED; if ((kdcoptions & KDC_OPT_RENEWABLE) && (in_cred->times.renew_till != 0) && - (dec_rep->enc_part2->times.renew_till > in_cred->times.renew_till)) + ts_after(dec_rep->enc_part2->times.renew_till, + in_cred->times.renew_till)) retval = KRB5_KDCREP_MODIFIED; if ((kdcoptions & KDC_OPT_RENEWABLE_OK) && (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) && (in_cred->times.endtime != 0) && - (dec_rep->enc_part2->times.renew_till > in_cred->times.endtime)) + ts_after(dec_rep->enc_part2->times.renew_till, in_cred->times.endtime)) retval = KRB5_KDCREP_MODIFIED; if (retval != 0) goto cleanup; if (!in_cred->times.starttime && - !in_clock_skew(dec_rep->enc_part2->times.starttime, - timestamp)) { + !ts_within(dec_rep->enc_part2->times.starttime, timestamp, + context->clockskew)) { retval = KRB5_KDCREP_SKEW; goto cleanup; } diff --git a/src/lib/krb5/krb/gen_save_subkey.c b/src/lib/krb5/krb/gen_save_subkey.c index 61f36aa3665f..bc2c46d30c22 100644 --- a/src/lib/krb5/krb/gen_save_subkey.c +++ b/src/lib/krb5/krb/gen_save_subkey.c @@ -38,7 +38,8 @@ k5_generate_and_save_subkey(krb5_context context, to guarantee randomness, but to make it less likely that multiple sessions could pick the same subkey. */ struct { - krb5_int32 sec, usec; + krb5_timestamp sec; + krb5_int32 usec; } rnd_data; krb5_data d; krb5_error_code retval; diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c index 110abeb2b1bd..69900adfa046 100644 --- a/src/lib/krb5/krb/get_creds.c +++ b/src/lib/krb5/krb/get_creds.c @@ -576,14 +576,6 @@ step_referrals(krb5_context context, krb5_tkt_creds_context ctx) } if (ctx->referral_count == 1) { - /* Cache the referral TGT only if it's from the local realm. - * Make sure to note the associated authdata, if any. */ - code = krb5_copy_authdata(context, ctx->authdata, - &ctx->reply_creds->authdata); - if (code != 0) - return code; - (void) krb5_cc_store_cred(context, ctx->ccache, ctx->reply_creds); - /* The authdata in this TGT will be copied into subsequent TGTs or the * final credentials, so we don't need to request it again. */ krb5_free_authdata(context, ctx->in_creds->authdata); @@ -816,7 +808,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx, return code; /* Check if the TGT is expired before bothering the KDC with it. */ - if (now > tgt->times.endtime) { + if (ts_after(now, tgt->times.endtime)) { krb5_free_creds(context, tgt); return KRB5KRB_AP_ERR_TKT_EXPIRED; } @@ -934,8 +926,9 @@ step_get_tgt(krb5_context context, krb5_tkt_creds_context ctx) /* See where we wound up on the path (or off it). */ path_realm = find_realm_in_path(context, ctx, tgt_realm); if (path_realm != NULL) { - /* We got a realm on the expected path, so we can cache it. */ - (void) krb5_cc_store_cred(context, ctx->ccache, ctx->cur_tgt); + /* Only cache the TGT if we asked for it, to avoid duplicates. */ + if (path_realm == ctx->next_realm) + (void)krb5_cc_store_cred(context, ctx->ccache, ctx->cur_tgt); if (path_realm == ctx->last_realm) { /* We received a TGT for the target realm. */ TRACE_TKT_CREDS_TARGET_TGT(context, ctx->cur_tgt->server); diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index 54badbbc32f8..47a00bf2c702 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -40,24 +40,6 @@ static krb5_error_code sort_krb5_padata_sequence(krb5_context context, krb5_pa_data **padata); /* - * This function performs 32 bit bounded addition so we can generate - * lifetimes without overflowing krb5_int32 - */ -static krb5_int32 -krb5int_addint32 (krb5_int32 x, krb5_int32 y) -{ - if ((x > 0) && (y > (KRB5_INT32_MAX - x))) { - /* sum will be be greater than KRB5_INT32_MAX */ - return KRB5_INT32_MAX; - } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) { - /* sum will be less than KRB5_INT32_MIN */ - return KRB5_INT32_MIN; - } - - return x + y; -} - -/* * Decrypt the AS reply in ctx, populating ctx->reply->enc_part2. If * strengthen_key is not null, combine it with the reply key as specified in * RFC 6113 section 5.4.3. Place the key used in *key_out. @@ -267,28 +249,28 @@ verify_as_reply(krb5_context context, (request->from != 0) && (request->from != as_reply->enc_part2->times.starttime)) || ((request->till != 0) && - (as_reply->enc_part2->times.endtime > request->till)) + ts_after(as_reply->enc_part2->times.endtime, request->till)) || ((request->kdc_options & KDC_OPT_RENEWABLE) && (request->rtime != 0) && - (as_reply->enc_part2->times.renew_till > request->rtime)) + ts_after(as_reply->enc_part2->times.renew_till, request->rtime)) || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) && !(request->kdc_options & KDC_OPT_RENEWABLE) && (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && (request->till != 0) && - (as_reply->enc_part2->times.renew_till > request->till)) + ts_after(as_reply->enc_part2->times.renew_till, request->till)) ) { return KRB5_KDCREP_MODIFIED; } if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) { - time_offset = as_reply->enc_part2->times.authtime - time_now; + time_offset = ts_delta(as_reply->enc_part2->times.authtime, time_now); retval = krb5_set_time_offsets(context, time_offset, 0); if (retval) return retval; } else { if ((request->from == 0) && - (labs(as_reply->enc_part2->times.starttime - time_now) - > context->clockskew)) + !ts_within(as_reply->enc_part2->times.starttime, time_now, + context->clockskew)) return (KRB5_KDCREP_SKEW); } return 0; @@ -583,7 +565,7 @@ krb5_init_creds_free(krb5_context context, k5_response_items_free(ctx->rctx.items); free(ctx->in_tkt_service); zapfree(ctx->gakpw.storage.data, ctx->gakpw.storage.length); - k5_preauth_request_context_fini(context); + k5_preauth_request_context_fini(context, ctx); krb5_free_error(context, ctx->err_reply); krb5_free_pa_data(context, ctx->err_padata); krb5_free_cred_contents(context, &ctx->cred); @@ -593,7 +575,9 @@ krb5_init_creds_free(krb5_context context, krb5_free_data(context, ctx->inner_request_body); krb5_free_data(context, ctx->encoded_previous_request); krb5int_fast_free_state(context, ctx->fast_state); - krb5_free_pa_data(context, ctx->preauth_to_use); + krb5_free_pa_data(context, ctx->optimistic_padata); + krb5_free_pa_data(context, ctx->method_padata); + krb5_free_pa_data(context, ctx->more_padata); krb5_free_data_contents(context, &ctx->salt); krb5_free_data_contents(context, &ctx->s2kparams); krb5_free_keyblock_contents(context, &ctx->as_key); @@ -760,23 +744,6 @@ k5_init_creds_current_time(krb5_context context, krb5_init_creds_context ctx, } } -/* Choose a random nonce for ctx->request. */ -static krb5_error_code -pick_nonce(krb5_context context, krb5_init_creds_context ctx) -{ - krb5_error_code code = 0; - unsigned char random_buf[4]; - krb5_data random_data = make_data(random_buf, 4); - - /* We incorrectly encode this as signed, so make sure we use an unsigned - * value to avoid interoperability issues. */ - code = krb5_c_random_make_octets(context, &random_data); - if (code != 0) - return code; - ctx->request->nonce = 0x7fffffff & load_32_n(random_buf); - return 0; -} - /* Set the timestamps for ctx->request based on the desired lifetimes. */ static krb5_error_code set_request_times(krb5_context context, krb5_init_creds_context ctx) @@ -790,16 +757,16 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx) return code; /* Omit request start time unless the caller explicitly asked for one. */ - from = krb5int_addint32(now, ctx->start_time); + from = ts_incr(now, ctx->start_time); if (ctx->start_time != 0) ctx->request->from = from; - ctx->request->till = krb5int_addint32(from, ctx->tkt_life); + ctx->request->till = ts_incr(from, ctx->tkt_life); if (ctx->renew_life > 0) { /* Don't ask for a smaller renewable time than the lifetime. */ - ctx->request->rtime = krb5int_addint32(from, ctx->renew_life); - if (ctx->request->rtime < ctx->request->till) + ctx->request->rtime = ts_incr(from, ctx->renew_life); + if (ts_after(ctx->request->till, ctx->request->rtime)) ctx->request->rtime = ctx->request->till; ctx->request->kdc_options &= ~KDC_OPT_RENEWABLE_OK; } else { @@ -809,6 +776,31 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx) return 0; } +static void +read_allowed_preauth_type(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_error_code ret; + krb5_data config; + char *tmp, *p; + krb5_ccache in_ccache = k5_gic_opt_get_in_ccache(ctx->opt); + + ctx->allowed_preauth_type = KRB5_PADATA_NONE; + if (in_ccache == NULL) + return; + memset(&config, 0, sizeof(config)); + if (krb5_cc_get_config(context, in_ccache, ctx->request->server, + KRB5_CC_CONF_PA_TYPE, &config) != 0) + return; + tmp = k5memdup0(config.data, config.length, &ret); + krb5_free_data_contents(context, &config); + if (tmp == NULL) + return; + ctx->allowed_preauth_type = strtol(tmp, &p, 10); + if (p == NULL || *p != '\0') + ctx->allowed_preauth_type = KRB5_PADATA_NONE; + free(tmp); +} + /** * Throw away any pre-authentication realm state and begin with a * unauthenticated or optimistically authenticated request. If fast_upgrade is @@ -820,11 +812,15 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, { krb5_error_code code = 0; - krb5_free_pa_data(context, ctx->preauth_to_use); + krb5_free_pa_data(context, ctx->optimistic_padata); + krb5_free_pa_data(context, ctx->method_padata); + krb5_free_pa_data(context, ctx->more_padata); krb5_free_pa_data(context, ctx->err_padata); krb5_free_error(context, ctx->err_reply); - ctx->preauth_to_use = ctx->err_padata = NULL; + ctx->optimistic_padata = ctx->method_padata = ctx->more_padata = NULL; + ctx->err_padata = NULL; ctx->err_reply = NULL; + ctx->selected_preauth_type = KRB5_PADATA_NONE; krb5int_fast_free_state(context, ctx->fast_state); ctx->fast_state = NULL; @@ -834,14 +830,14 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, if (fast_upgrade) ctx->fast_state->fast_state_flags |= KRB5INT_FAST_DO_FAST; - k5_preauth_request_context_fini(context); - k5_preauth_request_context_init(context); + k5_preauth_request_context_fini(context, ctx); + k5_preauth_request_context_init(context, ctx); krb5_free_data(context, ctx->outer_request_body); ctx->outer_request_body = NULL; if (ctx->opt->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) { code = make_preauth_list(context, ctx->opt->preauth_list, ctx->opt->preauth_list_length, - &ctx->preauth_to_use); + &ctx->optimistic_padata); if (code) goto cleanup; } @@ -867,6 +863,11 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, &ctx->outer_request_body); if (code != 0) goto cleanup; + + /* Read the allowed preauth type for this server principal from the input + * ccache, if the application supplied one. */ + read_allowed_preauth_type(context, ctx); + cleanup: return code; } @@ -1172,31 +1173,6 @@ init_creds_validate_reply(krb5_context context, return 0; } -static void -read_allowed_preauth_type(krb5_context context, krb5_init_creds_context ctx) -{ - krb5_error_code ret; - krb5_data config; - char *tmp, *p; - krb5_ccache in_ccache = k5_gic_opt_get_in_ccache(ctx->opt); - - ctx->allowed_preauth_type = KRB5_PADATA_NONE; - if (in_ccache == NULL) - return; - memset(&config, 0, sizeof(config)); - if (krb5_cc_get_config(context, in_ccache, ctx->request->server, - KRB5_CC_CONF_PA_TYPE, &config) != 0) - return; - tmp = k5memdup0(config.data, config.length, &ret); - krb5_free_data_contents(context, &config); - if (tmp == NULL) - return; - ctx->allowed_preauth_type = strtol(tmp, &p, 10); - if (p == NULL || *p != '\0') - ctx->allowed_preauth_type = KRB5_PADATA_NONE; - free(tmp); -} - static krb5_error_code save_selected_preauth_type(krb5_context context, krb5_ccache ccache, krb5_init_creds_context ctx) @@ -1313,6 +1289,9 @@ init_creds_step_request(krb5_context context, krb5_data *out) { krb5_error_code code; + krb5_preauthtype pa_type; + struct errinfo save = EMPTY_ERRINFO; + uint32_t rcode = (ctx->err_reply == NULL) ? 0 : ctx->err_reply->error; if (ctx->loopcount >= MAX_IN_TKT_LOOPS) { code = KRB5_GET_IN_TKT_LOOP; @@ -1320,7 +1299,7 @@ init_creds_step_request(krb5_context context, } /* RFC 6113 requires a new nonce for the inner request on each try. */ - code = pick_nonce(context, ctx); + code = k5_generate_nonce(context, &ctx->request->nonce); if (code != 0) goto cleanup; @@ -1335,11 +1314,6 @@ init_creds_step_request(krb5_context context, if (code) goto cleanup; - /* Read the allowed patype for this server principal from the in_ccache, - * if the application supplied one. */ - read_allowed_preauth_type(context, ctx); - ctx->selected_preauth_type = KRB5_PADATA_NONE; - /* * Read cached preauth configuration data for this server principal from * the in_ccache, if the application supplied one, and delete any that was @@ -1348,32 +1322,65 @@ init_creds_step_request(krb5_context context, read_cc_config_in_data(context, ctx); clear_cc_config_out_data(context, ctx); - if (ctx->err_reply == NULL) { - /* Either our first attempt, or retrying after KDC_ERR_PREAUTH_REQUIRED - * or KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. */ - code = k5_preauth(context, ctx, ctx->preauth_to_use, - ctx->preauth_required, &ctx->request->padata, - &ctx->selected_preauth_type); - if (code != 0) - goto cleanup; - } else { - if (ctx->preauth_to_use != NULL) { - /* - * Retry after an error other than PREAUTH_NEEDED, - * using ctx->err_padata to figure out what to change. - */ - code = k5_preauth_tryagain(context, ctx, ctx->preauth_to_use, - &ctx->request->padata); - } else { - /* No preauth supplied, so can't query the plugins. */ - code = KRB5KRB_ERR_GENERIC; + ctx->request->padata = NULL; + if (ctx->optimistic_padata != NULL) { + /* Our first attempt, using an optimistic padata list. */ + TRACE_INIT_CREDS_PREAUTH_OPTIMISTIC(context); + code = k5_preauth(context, ctx, ctx->optimistic_padata, TRUE, + &ctx->request->padata, &ctx->selected_preauth_type); + krb5_free_pa_data(context, ctx->optimistic_padata); + ctx->optimistic_padata = NULL; + if (code) { + /* Make an unauthenticated request, and possibly try again using + * the same mechanisms as we tried optimistically. */ + k5_reset_preauth_types_tried(ctx); + krb5_clear_error_message(context); + code = 0; } - if (code != 0) { - /* couldn't come up with anything better */ + } if (ctx->more_padata != NULL) { + /* Continuing after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. */ + TRACE_INIT_CREDS_PREAUTH_MORE(context, ctx->selected_preauth_type); + code = k5_preauth(context, ctx, ctx->more_padata, TRUE, + &ctx->request->padata, &pa_type); + } else if (rcode == KDC_ERR_PREAUTH_FAILED) { + /* Report the KDC-side failure code if we can't try another mech. */ + code = KRB5KDC_ERR_PREAUTH_FAILED; + } else if (rcode && rcode != KDC_ERR_PREAUTH_REQUIRED) { + /* Retrying after an error (possibly mechanism-specific), using error + * padata to figure out what to change. */ + TRACE_INIT_CREDS_PREAUTH_TRYAGAIN(context, ctx->err_reply->error, + ctx->selected_preauth_type); + code = k5_preauth_tryagain(context, ctx, ctx->selected_preauth_type, + ctx->err_reply, ctx->err_padata, + &ctx->request->padata); + if (code) { + krb5_clear_error_message(context); code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5; + } + } + /* Don't continue after a keyboard interrupt. */ + if (code == KRB5_LIBOS_PWDINTR) + goto cleanup; + if (code) { + /* See if we can try a different preauth mech before giving up. */ + k5_save_ctx_error(context, code, &save); + ctx->selected_preauth_type = KRB5_PADATA_NONE; + } + + if (ctx->request->padata == NULL && ctx->method_padata != NULL) { + /* Retrying after KDC_ERR_PREAUTH_REQUIRED, or trying again with a + * different mechanism after a failure. */ + TRACE_INIT_CREDS_PREAUTH(context); + code = k5_preauth(context, ctx, ctx->method_padata, TRUE, + &ctx->request->padata, &ctx->selected_preauth_type); + if (code) { + if (save.code != 0) + code = k5_restore_ctx_error(context, &save); goto cleanup; } } + if (ctx->request->padata == NULL) + TRACE_INIT_CREDS_PREAUTH_NONE(context); /* Remember when we sent this request (after any preauth delay). */ ctx->request_time = time(NULL); @@ -1382,8 +1389,6 @@ init_creds_step_request(krb5_context context, krb5_free_data(context, ctx->encoded_previous_request); ctx->encoded_previous_request = NULL; } - if (ctx->request->padata) - ctx->sent_nontrivial_preauth = TRUE; if (ctx->enc_pa_rep_permitted) { code = add_padata(&ctx->request->padata, KRB5_ENCPADATA_REQ_ENC_PA_REP, NULL, 0); @@ -1411,6 +1416,7 @@ init_creds_step_request(krb5_context context, cleanup: krb5_free_pa_data(context, ctx->request->padata); ctx->request->padata = NULL; + k5_clear_error(&save); return code; } @@ -1438,7 +1444,7 @@ note_req_timestamp(krb5_context context, krb5_init_creds_context ctx, if (k5_time_with_offset(0, 0, &now, &usec) != 0) return; - ctx->pa_offset = kdc_time - now; + ctx->pa_offset = ts_delta(kdc_time, now); ctx->pa_offset_usec = kdc_usec - usec; ctx->pa_offset_state = (ctx->fast_state->armor_key != NULL) ? AUTH_OFFSET : UNAUTH_OFFSET; @@ -1463,6 +1469,18 @@ is_referral(krb5_context context, krb5_error *err, krb5_principal client) return !krb5_realm_compare(context, err->client, client); } +/* Transfer error padata to method data in ctx and sort it according to + * configuration. */ +static krb5_error_code +accept_method_data(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_free_pa_data(context, ctx->method_padata); + ctx->method_padata = ctx->err_padata; + ctx->err_padata = NULL; + return sort_krb5_padata_sequence(context, &ctx->request->client->realm, + ctx->method_padata); +} + static krb5_error_code init_creds_step_reply(krb5_context context, krb5_init_creds_context ctx, @@ -1492,8 +1510,9 @@ init_creds_step_reply(krb5_context context, ctx->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL; if (ctx->err_reply != NULL) { + krb5_free_pa_data(context, ctx->more_padata); krb5_free_pa_data(context, ctx->err_padata); - ctx->err_padata = NULL; + ctx->more_padata = ctx->err_padata = NULL; code = krb5int_fast_process_error(context, ctx->fast_state, &ctx->err_reply, &ctx->err_padata, &retry); @@ -1508,7 +1527,7 @@ init_creds_step_reply(krb5_context context, ctx->restarted = TRUE; code = restart_init_creds_loop(context, ctx, TRUE); } else if (!ctx->restarted && reply_code == KDC_ERR_PREAUTH_FAILED && - !ctx->sent_nontrivial_preauth) { + ctx->selected_preauth_type == KRB5_PADATA_NONE) { /* The KDC didn't like our informational padata (probably a pre-1.7 * MIT krb5 KDC). Retry without it. */ ctx->enc_pa_rep_permitted = FALSE; @@ -1519,23 +1538,30 @@ init_creds_step_reply(krb5_context context, * FAST upgrade. */ ctx->restarted = FALSE; code = restart_init_creds_loop(context, ctx, FALSE); - } else if ((reply_code == KDC_ERR_MORE_PREAUTH_DATA_REQUIRED || - reply_code == KDC_ERR_PREAUTH_REQUIRED) && retry) { - /* reset the list of preauth types to try */ - k5_reset_preauth_types_tried(context); - krb5_free_pa_data(context, ctx->preauth_to_use); - ctx->preauth_to_use = ctx->err_padata; - ctx->err_padata = NULL; + } else if (reply_code == KDC_ERR_PREAUTH_REQUIRED && retry) { note_req_timestamp(context, ctx, ctx->err_reply->stime, ctx->err_reply->susec); - /* This will trigger a new call to k5_preauth(). */ - krb5_free_error(context, ctx->err_reply); - ctx->err_reply = NULL; - code = sort_krb5_padata_sequence(context, - &ctx->request->client->realm, - ctx->preauth_to_use); - ctx->preauth_required = TRUE; - + code = accept_method_data(context, ctx); + } else if (reply_code == KDC_ERR_PREAUTH_FAILED && retry) { + note_req_timestamp(context, ctx, ctx->err_reply->stime, + ctx->err_reply->susec); + if (ctx->method_padata == NULL) { + /* Optimistic preauth failed on the KDC. Allow all mechanisms + * to be tried again using method data. */ + k5_reset_preauth_types_tried(ctx); + } else { + /* Don't try again with the mechanism that failed. */ + code = k5_preauth_note_failed(ctx, ctx->selected_preauth_type); + if (code) + goto cleanup; + } + ctx->selected_preauth_type = KRB5_PADATA_NONE; + /* Accept or update method data if the KDC sent it. */ + if (ctx->err_padata != NULL) + code = accept_method_data(context, ctx); + } else if (reply_code == KDC_ERR_MORE_PREAUTH_DATA_REQUIRED && retry) { + ctx->more_padata = ctx->err_padata; + ctx->err_padata = NULL; } else if (canon_flag && is_referral(context, ctx->err_reply, ctx->request->client)) { TRACE_INIT_CREDS_REFERRAL(context, &ctx->err_reply->client->realm); @@ -1548,14 +1574,13 @@ init_creds_step_reply(krb5_context context, goto cleanup; /* Reset per-realm negotiation state. */ ctx->restarted = FALSE; - ctx->sent_nontrivial_preauth = FALSE; ctx->enc_pa_rep_permitted = TRUE; code = restart_init_creds_loop(context, ctx, FALSE); } else { - if (retry) { + if (retry && ctx->selected_preauth_type != KRB5_PADATA_NONE) { code = 0; } else { - /* error + no hints = give up */ + /* error + no hints (or no preauth mech) = give up */ code = (krb5_error_code)reply_code + ERROR_TABLE_BASE_krb5; } } @@ -1573,7 +1598,6 @@ init_creds_step_reply(krb5_context context, goto cleanup; /* process any preauth data in the as_reply */ - k5_reset_preauth_types_tried(context); code = krb5int_fast_process_response(context, ctx->fast_state, ctx->reply, &strengthen_key); if (code != 0) @@ -1658,7 +1682,7 @@ init_creds_step_reply(krb5_context context, k5_prependmsg(context, code, _("Failed to store credentials")); } - k5_preauth_request_context_fini(context); + k5_preauth_request_context_fini(context, ctx); /* success */ ctx->complete = TRUE; @@ -1685,7 +1709,7 @@ krb5_init_creds_step(krb5_context context, krb5_data *realm, unsigned int *flags) { - krb5_error_code code = 0, code2; + krb5_error_code code, code2; *flags = 0; @@ -1698,6 +1722,10 @@ krb5_init_creds_step(krb5_context context, if (ctx->complete) return EINVAL; + code = k5_preauth_check_context(context, ctx); + if (code) + return code; + if (in->length != 0) { code = init_creds_step_reply(context, ctx, in); if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) { @@ -1806,7 +1834,8 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out, krb5_creds *creds) { int i; - krb5_int32 starttime; + krb5_timestamp starttime; + krb5_deltat lifetime; krb5_get_init_creds_opt *opt; krb5_error_code retval; @@ -1838,7 +1867,8 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out, if (retval) goto cleanup; if (creds->times.starttime) starttime = creds->times.starttime; - krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime); + lifetime = ts_delta(creds->times.endtime, starttime); + krb5_get_init_creds_opt_set_tkt_life(opt, lifetime); } *out = opt; return 0; diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c index 3be44d5cd756..ccbe1a65fa5a 100644 --- a/src/lib/krb5/krb/gic_opt.c +++ b/src/lib/krb5/krb/gic_opt.c @@ -12,7 +12,7 @@ #include <TargetConditionals.h> #endif -/* Match struct packing of krb5_get_init_creds_opt on MacOS X. */ +/* Match struct packing of krb5_get_init_creds_opt on macOS. */ #if TARGET_OS_MAC #pragma pack(push,2) #endif diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c index 6f3a29f2c423..3565a7c4c77a 100644 --- a/src/lib/krb5/krb/gic_pwd.c +++ b/src/lib/krb5/krb/gic_pwd.c @@ -211,7 +211,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, if (ret != 0) return; if (!is_last_req && - (pw_exp < now || (pw_exp - now) > 7 * 24 * 60 * 60)) + (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60)) return; if (!prompter) @@ -221,7 +221,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, if (ret != 0) return; - delta = pw_exp - now; + delta = ts_delta(pw_exp, now); if (delta < 3600) { snprintf(banner, sizeof(banner), _("Warning: Your password will expire in less than one hour " diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h index 38c01c775b6f..fe769685ba09 100644 --- a/src/lib/krb5/krb/init_creds_ctx.h +++ b/src/lib/krb5/krb/init_creds_ctx.h @@ -6,6 +6,8 @@ #include "k5-json.h" #include "int-proto.h" +typedef struct krb5_preauth_req_context_st *krb5_preauth_req_context; + struct krb5_responder_context_st { k5_response_items *items; }; @@ -48,7 +50,9 @@ struct _krb5_init_creds_context { krb5_data *inner_request_body; /**< For preauth */ krb5_data *encoded_previous_request; struct krb5int_fast_request_state *fast_state; - krb5_pa_data **preauth_to_use; + krb5_pa_data **optimistic_padata; /* from gic options */ + krb5_pa_data **method_padata; /* from PREAUTH_REQUIRED or PREAUTH_FAILED */ + krb5_pa_data **more_padata; /* from MORE_PREAUTH_DATA_REQUIRED */ krb5_boolean default_salt; krb5_data salt; krb5_data s2kparams; @@ -56,8 +60,6 @@ struct _krb5_init_creds_context { krb5_enctype etype; krb5_boolean enc_pa_rep_permitted; krb5_boolean restarted; - krb5_boolean sent_nontrivial_preauth; - krb5_boolean preauth_required; struct krb5_responder_context_st rctx; krb5_preauthtype selected_preauth_type; krb5_preauthtype allowed_preauth_type; @@ -67,6 +69,7 @@ struct _krb5_init_creds_context { krb5_timestamp pa_offset; krb5_int32 pa_offset_usec; enum { NO_OFFSET = 0, UNAUTH_OFFSET, AUTH_OFFSET } pa_offset_state; + krb5_preauth_req_context preauth_reqctx; }; krb5_error_code diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c index cf226fdbabc0..4246c5dd274f 100644 --- a/src/lib/krb5/krb/init_ctx.c +++ b/src/lib/krb5/krb/init_ctx.c @@ -139,7 +139,8 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags, krb5_context ctx = 0; krb5_error_code retval; struct { - krb5_int32 now, now_usec; + krb5_timestamp now; + krb5_int32 now_usec; long pid; } seed_data; krb5_data seed; diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h index 6da74858e210..cda9010e34a3 100644 --- a/src/lib/krb5/krb/int-proto.h +++ b/src/lib/krb5/krb/int-proto.h @@ -83,8 +83,6 @@ krb5int_construct_matching_creds(krb5_context context, krb5_flags options, krb5_creds *in_creds, krb5_creds *mcreds, krb5_flags *fields); -#define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew) - #define IS_TGS_PRINC(p) ((p)->length == 2 && \ data_eq_string((p)->data[0], KRB5_TGS_NAME)) @@ -102,6 +100,9 @@ krb5_get_cred_via_tkt_ext(krb5_context context, krb5_creds *tkt, krb5_keyblock **out_subkey); krb5_error_code +k5_generate_nonce(krb5_context context, int32_t *out); + +krb5_error_code k5_make_tgs_req(krb5_context context, struct krb5int_fast_request_state *, krb5_creds *tkt, krb5_flags kdcoptions, krb5_address *const *address, krb5_pa_data **in_padata, @@ -187,7 +188,8 @@ k5_preauth(krb5_context context, krb5_init_creds_context ctx, krb5_error_code k5_preauth_tryagain(krb5_context context, krb5_init_creds_context ctx, - krb5_pa_data **in_padata, krb5_pa_data ***padata_out); + krb5_preauthtype pa_type, krb5_error *err, + krb5_pa_data **err_padata, krb5_pa_data ***padata_out); void k5_init_preauth_context(krb5_context context); @@ -196,17 +198,25 @@ void k5_free_preauth_context(krb5_context context); void -k5_reset_preauth_types_tried(krb5_context context); +k5_reset_preauth_types_tried(krb5_init_creds_context ctx); + +krb5_error_code +k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type); void k5_preauth_prepare_request(krb5_context context, krb5_get_init_creds_opt *opt, krb5_kdc_req *request); void -k5_preauth_request_context_init(krb5_context context); +k5_preauth_request_context_init(krb5_context context, + krb5_init_creds_context ctx); void -k5_preauth_request_context_fini(krb5_context context); +k5_preauth_request_context_fini(krb5_context context, + krb5_init_creds_context ctx); + +krb5_error_code +k5_preauth_check_context(krb5_context context, krb5_init_creds_context ctx); krb5_error_code k5_response_items_new(k5_response_items **ri_out); diff --git a/src/lib/krb5/krb/mk_req.c b/src/lib/krb5/krb/mk_req.c index 542ef6d4aee5..162c05b5cbd9 100644 --- a/src/lib/krb5/krb/mk_req.c +++ b/src/lib/krb5/krb/mk_req.c @@ -48,8 +48,9 @@ krb5_error_code KRB5_CALLCONV krb5_mk_req(krb5_context context, krb5_auth_context *auth_context, - krb5_flags ap_req_options, char *service, char *hostname, - krb5_data *in_data, krb5_ccache ccache, krb5_data *outbuf) + krb5_flags ap_req_options, const char *service, + const char *hostname, krb5_data *in_data, krb5_ccache ccache, + krb5_data *outbuf) { krb5_error_code retval; krb5_principal server; diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c index 9098927b5acf..0eb19e6bb464 100644 --- a/src/lib/krb5/krb/pac.c +++ b/src/lib/krb5/krb/pac.c @@ -378,7 +378,7 @@ k5_time_to_seconds_since_1970(int64_t ntTime, krb5_timestamp *elapsedSeconds) abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime; - if (abstime > KRB5_INT32_MAX) + if (abstime > UINT32_MAX) return ERANGE; *elapsedSeconds = abstime; @@ -436,8 +436,7 @@ k5_pac_validate_client(krb5_context context, pac_princname_length % 2) return ERANGE; - ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2, - &pac_princname, NULL); + ret = k5_utf16le_to_utf8(p, pac_princname_length, &pac_princname); if (ret != 0) return ret; @@ -792,8 +791,8 @@ mspac_verify(krb5_context kcontext, * If the above verification failed, don't fail the whole authentication, * just don't mark the PAC as verified. A checksum mismatch can occur if * the PAC was copied from a cross-realm TGT by an ignorant KDC, and Apple - * Mac OS X Server Open Directory (as of 10.6) generates PACs with no - * server checksum at all. + * macOS Server Open Directory (as of 10.6) generates PACs with no server + * checksum at all. */ return 0; } diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c index d40df45f99e8..c94899c96a79 100644 --- a/src/lib/krb5/krb/pac_sign.c +++ b/src/lib/krb5/krb/pac_sign.c @@ -38,8 +38,8 @@ k5_insert_client_info(krb5_context context, krb5_error_code ret; krb5_data client_info; char *princ_name_utf8 = NULL; - unsigned char *princ_name_ucs2 = NULL, *p; - size_t princ_name_ucs2_len = 0; + unsigned char *princ_name_utf16 = NULL, *p; + size_t princ_name_utf16_len = 0; uint64_t nt_authtime; /* If we already have a CLIENT_INFO buffer, then just validate it */ @@ -54,13 +54,12 @@ k5_insert_client_info(krb5_context context, if (ret != 0) goto cleanup; - ret = krb5int_utf8s_to_ucs2les(princ_name_utf8, - &princ_name_ucs2, - &princ_name_ucs2_len); + ret = k5_utf8_to_utf16le(princ_name_utf8, &princ_name_utf16, + &princ_name_utf16_len); if (ret != 0) goto cleanup; - client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_ucs2_len; + client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_utf16_len; client_info.data = NULL; ret = k5_pac_add_buffer(context, pac, KRB5_PAC_CLIENT_INFO, @@ -75,16 +74,16 @@ k5_insert_client_info(krb5_context context, store_64_le(nt_authtime, p); p += 8; - /* copy in number of UCS-2 characters in principal name */ - store_16_le(princ_name_ucs2_len, p); + /* copy in number of UTF-16 bytes in principal name */ + store_16_le(princ_name_utf16_len, p); p += 2; /* copy in principal name */ - memcpy(p, princ_name_ucs2, princ_name_ucs2_len); + memcpy(p, princ_name_utf16, princ_name_utf16_len); cleanup: - if (princ_name_ucs2 != NULL) - free(princ_name_ucs2); + if (princ_name_utf16 != NULL) + free(princ_name_utf16); krb5_free_unparsed_name(context, princ_name_utf8); return ret; diff --git a/src/lib/krb5/krb/plugin.c b/src/lib/krb5/krb/plugin.c index 7d64b7c7eda9..31aaf661d9af 100644 --- a/src/lib/krb5/krb/plugin.c +++ b/src/lib/krb5/krb/plugin.c @@ -57,7 +57,10 @@ const char *interface_names[] = { "hostrealm", "audit", "tls", - "kdcauthdata" + "kdcauthdata", + "certauth", + "kadm5_auth", + "kdcpolicy", }; /* Return the context's interface structure for id, or NULL if invalid. */ diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index ca26fb0e3fa5..6b96fa135e1a 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -46,14 +46,18 @@ typedef struct { struct krb5_clpreauth_vtable_st vt; krb5_clpreauth_moddata data; - krb5_clpreauth_modreq req; } *clpreauth_handle; struct krb5_preauth_context_st { - krb5_preauthtype *tried; clpreauth_handle *handles; }; +struct krb5_preauth_req_context_st { + krb5_context orig_context; + krb5_preauthtype *failed; + krb5_clpreauth_modreq *modreqs; +}; + /* Release the memory used by a list of handles. */ static void free_handles(krb5_context context, clpreauth_handle *handles) @@ -71,21 +75,44 @@ free_handles(krb5_context context, clpreauth_handle *handles) free(handles); } -/* Find the handle in handles which can process pa_type. */ -static clpreauth_handle -find_module(clpreauth_handle *handles, krb5_preauthtype pa_type) +/* Return an index into handles which can process pa_type, or -1 if none is + * found found. */ +static int +search_module_list(clpreauth_handle *handles, krb5_preauthtype pa_type) { - clpreauth_handle *hp, h; - krb5_preauthtype *tp; + clpreauth_handle h; + int i, j; - for (hp = handles; *hp != NULL; hp++) { - h = *hp; - for (tp = h->vt.pa_type_list; *tp != 0; tp++) { - if (*tp == pa_type) - return h; + for (i = 0; handles[i] != NULL; i++) { + h = handles[i]; + for (j = 0; h->vt.pa_type_list[j] != 0; j++) { + if (h->vt.pa_type_list[j] == pa_type) + return i; } } - return FALSE; + return -1; +} + +/* Find the handle which can process pa_type, or NULL if none is found. On + * success, set *modreq_out to the corresponding per-request module data. */ +static clpreauth_handle +find_module(krb5_context context, krb5_init_creds_context ctx, + krb5_preauthtype pa_type, krb5_clpreauth_modreq *modreq_out) +{ + krb5_preauth_context pctx = context->preauth_context; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + int i; + + *modreq_out = NULL; + if (pctx == NULL || reqctx == NULL) + return NULL; + + i = search_module_list(pctx->handles, pa_type); + if (i == -1) + return NULL; + + *modreq_out = reqctx->modreqs[i]; + return pctx->handles[i]; } /* Initialize the preauth state for a krb5 context. */ @@ -93,7 +120,8 @@ void k5_init_preauth_context(krb5_context context) { krb5_plugin_initvt_fn *modules = NULL, *mod; - clpreauth_handle *list = NULL, h, h2; + clpreauth_handle *list = NULL, h; + int i; size_t count; krb5_preauthtype *tp; @@ -140,9 +168,10 @@ k5_init_preauth_context(krb5_context context) /* Check for a preauth type conflict with an existing module. */ for (tp = h->vt.pa_type_list; *tp != 0; tp++) { - h2 = find_module(list, *tp); - if (h2 != NULL) { - TRACE_PREAUTH_CONFLICT(context, h->vt.name, h2->vt.name, *tp); + i = search_module_list(list, *tp); + if (i != -1) { + TRACE_PREAUTH_CONFLICT(context, h->vt.name, list[i]->vt.name, + *tp); break; } } @@ -161,10 +190,9 @@ k5_init_preauth_context(krb5_context context) list[count] = NULL; /* Place the constructed preauth context into the krb5 context. */ - context->preauth_context = malloc(sizeof(struct krb5_preauth_context_st)); + context->preauth_context = malloc(sizeof(*context->preauth_context)); if (context->preauth_context == NULL) goto cleanup; - context->preauth_context->tried = NULL; context->preauth_context->handles = list; list = NULL; @@ -173,22 +201,35 @@ cleanup: free_handles(context, list); } -/* - * Reset the memory of which preauth types we have already tried, because we - * are entering a new phase of padata processing (such as the padata in an - * AS-REP). - */ +/* Reset the memory of which preauth types we have already tried. */ void -k5_reset_preauth_types_tried(krb5_context context) +k5_reset_preauth_types_tried(krb5_init_creds_context ctx) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; - if (pctx == NULL) + if (reqctx == NULL) return; - free(pctx->tried); - pctx->tried = NULL; + free(reqctx->failed); + reqctx->failed = NULL; } +/* Add pa_type to the list of types which has previously failed. */ +krb5_error_code +k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type) +{ + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + krb5_preauthtype *newptr; + size_t i; + + for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++); + newptr = realloc(reqctx->failed, (i + 2) * sizeof(*newptr)); + if (newptr == NULL) + return ENOMEM; + reqctx->failed = newptr; + reqctx->failed[i] = pa_type; + reqctx->failed[i + 1] = 0; + return 0; +} /* Free the per-krb5_context preauth_context. This means clearing any * plugin-specific context which may have been created, and then @@ -196,11 +237,10 @@ k5_reset_preauth_types_tried(krb5_context context) void k5_free_preauth_context(krb5_context context) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_context pctx = context->preauth_context; if (pctx == NULL) return; - free(pctx->tried); free_handles(context, pctx->handles); free(pctx); context->preauth_context = NULL; @@ -209,10 +249,13 @@ k5_free_preauth_context(krb5_context context) /* Initialize the per-AS-REQ context. This means calling the client_req_init * function to give the plugin a chance to allocate a per-request context. */ void -k5_preauth_request_context_init(krb5_context context) +k5_preauth_request_context_init(krb5_context context, + krb5_init_creds_context ctx) { - struct krb5_preauth_context_st *pctx = context->preauth_context; - clpreauth_handle *hp, h; + krb5_preauth_context pctx = context->preauth_context; + clpreauth_handle h; + krb5_preauth_req_context reqctx; + size_t count, i; if (pctx == NULL) { k5_init_preauth_context(context); @@ -220,30 +263,63 @@ k5_preauth_request_context_init(krb5_context context) if (pctx == NULL) return; } - k5_reset_preauth_types_tried(context); - for (hp = pctx->handles; *hp != NULL; hp++) { - h = *hp; + + reqctx = calloc(1, sizeof(*reqctx)); + if (reqctx == NULL) + return; + reqctx->orig_context = context; + + /* Create an array of per-request module data objects corresponding to the + * preauth context's array of handles. */ + for (count = 0; pctx->handles[count] != NULL; count++); + reqctx->modreqs = calloc(count, sizeof(*reqctx->modreqs)); + for (i = 0; i < count; i++) { + h = pctx->handles[i]; if (h->vt.request_init != NULL) - h->vt.request_init(context, h->data, &h->req); + h->vt.request_init(context, h->data, &reqctx->modreqs[i]); } + ctx->preauth_reqctx = reqctx; } /* Free the per-AS-REQ context. This means clearing any request-specific * context which the plugin may have created. */ void -k5_preauth_request_context_fini(krb5_context context) +k5_preauth_request_context_fini(krb5_context context, + krb5_init_creds_context ctx) { - struct krb5_preauth_context_st *pctx = context->preauth_context; - clpreauth_handle *hp, h; + krb5_preauth_context pctx = context->preauth_context; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + size_t i; + clpreauth_handle h; - if (pctx == NULL) + if (reqctx == NULL) return; - for (hp = pctx->handles; *hp != NULL; hp++) { - h = *hp; - if (h->req != NULL && h->vt.request_fini != NULL) - h->vt.request_fini(context, h->data, h->req); - h->req = NULL; + if (reqctx->orig_context == context && pctx != NULL) { + for (i = 0; pctx->handles[i] != NULL; i++) { + h = pctx->handles[i]; + if (reqctx->modreqs[i] != NULL && h->vt.request_fini != NULL) + h->vt.request_fini(context, h->data, reqctx->modreqs[i]); + } + } else { + TRACE_PREAUTH_WRONG_CONTEXT(context); + } + free(reqctx->modreqs); + free(reqctx->failed); + free(reqctx); + ctx->preauth_reqctx = NULL; +} + +krb5_error_code +k5_preauth_check_context(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + + if (reqctx != NULL && reqctx->orig_context != context) { + k5_setmsg(context, EINVAL, + _("krb5_init_creds calls must use same library context")); + return EINVAL; } + return 0; } /* Return 1 if pa_type is a real preauthentication mechanism according to the @@ -259,6 +335,7 @@ clpreauth_is_real(krb5_context context, clpreauth_handle h, static krb5_error_code clpreauth_prep_questions(krb5_context context, clpreauth_handle h, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *req, krb5_data *req_body, @@ -266,35 +343,35 @@ clpreauth_prep_questions(krb5_context context, clpreauth_handle h, { if (h->vt.prep_questions == NULL) return 0; - return h->vt.prep_questions(context, h->data, h->req, opt, cb, rock, req, + return h->vt.prep_questions(context, h->data, modreq, opt, cb, rock, req, req_body, prev_req, pa_data); } static krb5_error_code clpreauth_process(krb5_context context, clpreauth_handle h, - krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, - krb5_clpreauth_rock rock, krb5_kdc_req *req, - krb5_data *req_body, krb5_data *prev_req, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_kdc_req *req, krb5_data *req_body, krb5_data *prev_req, krb5_pa_data *pa_data, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***pa_data_out) { - return h->vt.process(context, h->data, h->req, opt, cb, rock, req, + return h->vt.process(context, h->data, modreq, opt, cb, rock, req, req_body, prev_req, pa_data, prompter, prompter_data, pa_data_out); } static krb5_error_code clpreauth_tryagain(krb5_context context, clpreauth_handle h, - krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, - krb5_clpreauth_rock rock, krb5_kdc_req *req, - krb5_data *req_body, krb5_data *prev_req, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_kdc_req *req, krb5_data *req_body, krb5_data *prev_req, krb5_preauthtype pa_type, krb5_error *error, krb5_pa_data **error_padata, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***pa_data_out) { if (h->vt.tryagain == NULL) return 0; - return h->vt.tryagain(context, h->data, h->req, opt, cb, rock, req, + return h->vt.tryagain(context, h->data, modreq, opt, cb, rock, req, req_body, prev_req, pa_type, error, error_padata, prompter, prompter_data, pa_data_out); } @@ -420,7 +497,7 @@ responder_get_answer(krb5_context context, krb5_clpreauth_rock rock, krb5_init_creds_context ctx = (krb5_init_creds_context)rock; /* Don't let plugins get the raw password. */ - if (question && strcmp(KRB5_RESPONDER_QUESTION_PASSWORD, question) == 0) + if (strcmp(KRB5_RESPONDER_QUESTION_PASSWORD, question) == 0) return NULL; return k5_response_items_get_answer(ctx->rctx.items, question); } @@ -495,7 +572,7 @@ void k5_preauth_prepare_request(krb5_context context, krb5_get_init_creds_opt *opt, krb5_kdc_req *req) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_context pctx = context->preauth_context; clpreauth_handle *hp, h; krb5_enctype *ep; @@ -548,28 +625,17 @@ pa_type_allowed(krb5_init_creds_context ctx, krb5_preauthtype pa_type) pa_type == ctx->allowed_preauth_type; } -/* - * If pa_type has already been tried as a real preauth type for this - * authentication, return true. Otherwise ass pa_type to the list of tried - * types and return false. - */ +/* Return true if pa_type previously failed during this authentication. */ static krb5_boolean -already_tried(krb5_context context, krb5_preauthtype pa_type) +previously_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type) { - struct krb5_preauth_context_st *pctx = context->preauth_context; - size_t count; - krb5_preauthtype *newptr; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + size_t i; - for (count = 0; pctx->tried != NULL && pctx->tried[count] != 0; count++) { - if (pctx->tried[count] == pa_type) + for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++) { + if (reqctx->failed[i] == pa_type) return TRUE; } - newptr = realloc(pctx->tried, (count + 2) * sizeof(*newptr)); - if (newptr == NULL) - return FALSE; - pctx->tried = newptr; - pctx->tried[count] = pa_type; - pctx->tried[count + 1] = ENCTYPE_NULL; return FALSE; } @@ -580,16 +646,13 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, krb5_pa_data ***out_pa_list, int *out_pa_list_size, krb5_preauthtype *out_type) { - struct krb5_preauth_context_st *pctx = context->preauth_context; struct errinfo save = EMPTY_ERRINFO; krb5_pa_data *pa, **pa_ptr, **mod_pa; krb5_error_code ret = 0; + krb5_clpreauth_modreq modreq; clpreauth_handle h; int real, i; - if (pctx == NULL) - return ENOENT; - /* Process all informational padata types, then the first real preauth type * we succeed on. */ for (real = 0; real <= 1; real++) { @@ -598,17 +661,17 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, /* Restrict real mechanisms to the chosen one if we have one. */ if (real && !pa_type_allowed(ctx, pa->pa_type)) continue; - h = find_module(pctx->handles, pa->pa_type); + h = find_module(context, ctx, pa->pa_type, &modreq); if (h == NULL) continue; /* Make sure this type is for the current pass. */ if (clpreauth_is_real(context, h, pa->pa_type) != real) continue; - /* Only try a real mechanism once per authentication. */ - if (real && already_tried(context, pa->pa_type)) + /* Don't try a real mechanism again after failure. */ + if (real && previously_failed(ctx, pa->pa_type)) continue; mod_pa = NULL; - ret = clpreauth_process(context, h, ctx->opt, &callbacks, + ret = clpreauth_process(context, h, modreq, ctx->opt, &callbacks, (krb5_clpreauth_rock)ctx, ctx->request, ctx->inner_request_body, ctx->encoded_previous_request, pa, @@ -625,6 +688,9 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, } free(mod_pa); } + /* Don't continue to try mechanisms after a keyboard interrupt. */ + if (ret == KRB5_LIBOS_PWDINTR) + goto cleanup; if (ret == 0 && real) { /* Stop now and record which real padata type we answered. */ *out_type = pa->pa_type; @@ -633,6 +699,12 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, /* Save the first error we get from a real preauth type. */ k5_save_ctx_error(context, ret, &save); } + if (real && ret) { + /* Don't try this mechanism again for this authentication. */ + ret = k5_preauth_note_failed(ctx, pa->pa_type); + if (ret) + goto cleanup; + } } } @@ -850,45 +922,54 @@ add_s4u_x509_user_padata(krb5_context context, krb5_s4u_userid *userid, } /* - * If one of the modules can adjust its AS_REQ data using the contents of the - * err_reply, return 0. If it's the sort of correction which requires that we - * ask the user another question, we let the calling application deal with it. + * If the module for pa_type can adjust its AS_REQ data using the contents of + * err and err_padata, return 0 with *padata_out set to a padata list for the + * next request. If it's the sort of correction which requires that we ask the + * user another question, we let the calling application deal with it. */ krb5_error_code k5_preauth_tryagain(krb5_context context, krb5_init_creds_context ctx, - krb5_pa_data **in_padata, krb5_pa_data ***padata_out) + krb5_preauthtype pa_type, krb5_error *err, + krb5_pa_data **err_padata, krb5_pa_data ***padata_out) { - struct krb5_preauth_context_st *pctx = context->preauth_context; krb5_error_code ret; krb5_pa_data **mod_pa; + krb5_clpreauth_modreq modreq; clpreauth_handle h; - int i; + int count; *padata_out = NULL; - if (pctx == NULL) - return KRB5KRB_ERR_GENERIC; - TRACE_PREAUTH_TRYAGAIN_INPUT(context, in_padata); + TRACE_PREAUTH_TRYAGAIN_INPUT(context, pa_type, err_padata); - for (i = 0; in_padata[i] != NULL; i++) { - h = find_module(pctx->handles, in_padata[i]->pa_type); - if (h == NULL) - continue; - mod_pa = NULL; - ret = clpreauth_tryagain(context, h, ctx->opt, &callbacks, - (krb5_clpreauth_rock)ctx, ctx->request, - ctx->inner_request_body, - ctx->encoded_previous_request, - in_padata[i]->pa_type, - ctx->err_reply, ctx->err_padata, - ctx->prompter, ctx->prompter_data, &mod_pa); - if (ret == 0 && mod_pa != NULL) { - TRACE_PREAUTH_TRYAGAIN_OUTPUT(context, mod_pa); - *padata_out = mod_pa; - return 0; - } + h = find_module(context, ctx, pa_type, &modreq); + if (h == NULL) + return KRB5KRB_ERR_GENERIC; + mod_pa = NULL; + ret = clpreauth_tryagain(context, h, modreq, ctx->opt, &callbacks, + (krb5_clpreauth_rock)ctx, ctx->request, + ctx->inner_request_body, + ctx->encoded_previous_request, pa_type, err, + err_padata, ctx->prompter, ctx->prompter_data, + &mod_pa); + TRACE_PREAUTH_TRYAGAIN(context, h->vt.name, pa_type, ret); + if (!ret && mod_pa == NULL) + ret = KRB5KRB_ERR_GENERIC; + if (ret) { + k5_preauth_note_failed(ctx, pa_type); + return ret; } - return KRB5KRB_ERR_GENERIC; + + for (count = 0; mod_pa[count] != NULL; count++); + ret = copy_cookie(context, err_padata, &mod_pa, &count); + if (ret) { + krb5_free_pa_data(context, mod_pa); + return ret; + } + + TRACE_PREAUTH_TRYAGAIN_OUTPUT(context, mod_pa); + *padata_out = mod_pa; + return 0; } /* Compile the set of response items for in_padata by invoke each module's @@ -897,9 +978,9 @@ static krb5_error_code fill_response_items(krb5_context context, krb5_init_creds_context ctx, krb5_pa_data **in_padata) { - struct krb5_preauth_context_st *pctx = context->preauth_context; krb5_error_code ret; krb5_pa_data *pa; + krb5_clpreauth_modreq modreq; clpreauth_handle h; int i; @@ -908,11 +989,11 @@ fill_response_items(krb5_context context, krb5_init_creds_context ctx, pa = in_padata[i]; if (!pa_type_allowed(ctx, pa->pa_type)) continue; - h = find_module(pctx->handles, pa->pa_type); + h = find_module(context, ctx, pa->pa_type, &modreq); if (h == NULL) continue; - ret = clpreauth_prep_questions(context, h, ctx->opt, &callbacks, - (krb5_clpreauth_rock)ctx, + ret = clpreauth_prep_questions(context, h, modreq, ctx->opt, + &callbacks, (krb5_clpreauth_rock)ctx, ctx->request, ctx->inner_request_body, ctx->encoded_previous_request, pa); if (ret) @@ -1004,7 +1085,7 @@ krb5_preauth_supply_preauth_data(krb5_context context, krb5_get_init_creds_opt *opt, const char *attr, const char *value) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_context pctx = context->preauth_context; clpreauth_handle *hp, h; krb5_error_code ret; diff --git a/src/lib/krb5/krb/preauth_ec.c b/src/lib/krb5/krb/preauth_ec.c index b1978336a063..c1aa9090fb6c 100644 --- a/src/lib/krb5/krb/preauth_ec.c +++ b/src/lib/krb5/krb/preauth_ec.c @@ -58,6 +58,8 @@ ec_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_keyblock *challenge_key = NULL, *armor_key, *as_key; armor_key = cb->fast_armor(context, rock); + if (armor_key == NULL) + return ENOENT; retval = cb->get_as_key(context, rock, &as_key); if (retval == 0 && padata->length) { krb5_enc_data *enc = NULL; diff --git a/src/lib/krb5/krb/send_tgs.c b/src/lib/krb5/krb/send_tgs.c index f6fdf68d4725..e43a5cc5b135 100644 --- a/src/lib/krb5/krb/send_tgs.c +++ b/src/lib/krb5/krb/send_tgs.c @@ -28,6 +28,25 @@ #include "int-proto.h" #include "fast.h" +/* Choose a random nonce for an AS or TGS request. */ +krb5_error_code +k5_generate_nonce(krb5_context context, int32_t *out) +{ + krb5_error_code ret; + unsigned char random_buf[4]; + krb5_data random_data = make_data(random_buf, 4); + + *out = 0; + + /* We and Heimdal incorrectly encode nonces as signed, so make sure we use + * a non-negative value to avoid interoperability issues. */ + ret = krb5_c_random_make_octets(context, &random_data); + if (ret) + return ret; + *out = 0x7FFFFFFF & load_32_n(random_buf); + return 0; +} + /* Construct an AP-REQ message for a TGS request. */ static krb5_error_code tgs_construct_ap_req(krb5_context context, krb5_data *checksum_data, @@ -156,10 +175,13 @@ k5_make_tgs_req(krb5_context context, req.till = desired->times.endtime ? desired->times.endtime : tgt->times.endtime; req.rtime = desired->times.renew_till; + ret = k5_generate_nonce(context, &req.nonce); + if (ret) + return ret; + *nonce_out = req.nonce; ret = krb5_timeofday(context, &time_now); if (ret) return ret; - *nonce_out = req.nonce = (krb5_int32)time_now; *timestamp_out = time_now; req.addresses = (krb5_address **)addrs; diff --git a/src/lib/krb5/krb/sendauth.c b/src/lib/krb5/krb/sendauth.c index f7e6777411aa..149e25dd7362 100644 --- a/src/lib/krb5/krb/sendauth.c +++ b/src/lib/krb5/krb/sendauth.c @@ -131,22 +131,21 @@ krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, This isn't strong cryptographically; the point here is not to guarantee randomness, but to make it less likely that multiple sessions could pick the same subkey. */ - char rnd_data[1024]; + struct sockaddr_storage rnd_data; GETPEERNAME_ARG3_TYPE len2; - krb5_data d; - d.length = sizeof (rnd_data); - d.data = rnd_data; - len2 = sizeof (rnd_data); - if (getpeername (*(int*)fd, (GETPEERNAME_ARG2_TYPE *) rnd_data, - &len2) == 0) { + krb5_data d = make_data(&rnd_data, sizeof(rnd_data)); + + len2 = sizeof(rnd_data); + if (getpeername(*(int *)fd, ss2sa(&rnd_data), &len2) == 0) { d.length = len2; - (void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); + (void)krb5_c_random_add_entropy( + context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); } - len2 = sizeof (rnd_data); - if (getsockname (*(int*)fd, (GETSOCKNAME_ARG2_TYPE *) rnd_data, - &len2) == 0) { + len2 = sizeof(rnd_data); + if (getsockname(*(int *)fd, ss2sa(&rnd_data), &len2) == 0) { d.length = len2; - (void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); + (void)krb5_c_random_add_entropy( + context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); } } diff --git a/src/lib/krb5/krb/str_conv.c b/src/lib/krb5/krb/str_conv.c index 3ab7eacac1c0..f0a2ae20bab5 100644 --- a/src/lib/krb5/krb/str_conv.c +++ b/src/lib/krb5/krb/str_conv.c @@ -207,7 +207,7 @@ krb5_error_code KRB5_CALLCONV krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen) { size_t ret; - time_t timestamp2 = timestamp; + time_t timestamp2 = ts2tt(timestamp); struct tm tmbuf; const char *fmt = "%c"; /* This is to get around gcc -Wall warning that the year returned might be two digits */ @@ -229,7 +229,7 @@ krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen struct tm *tmp; size_t i; size_t ndone; - time_t timestamp2 = timestamp; + time_t timestamp2 = ts2tt(timestamp); struct tm tmbuf; static const char * const sftime_format_table[] = { diff --git a/src/lib/krb5/krb/t_expire_warn.py b/src/lib/krb5/krb/t_expire_warn.py index e021379ab1cf..aed39e3995ab 100755 --- a/src/lib/krb5/krb/t_expire_warn.py +++ b/src/lib/krb5/krb/t_expire_warn.py @@ -39,15 +39,10 @@ realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '3 days', 'days']) output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0']) if output: fail('Unexpected output for noexpire') -output = realm.run(['./t_expire_warn', 'minutes', 'pass', '0']) -if ' less than one hour on ' not in output: - fail('Expected warning not seen for minutes') -output = realm.run(['./t_expire_warn', 'hours', 'pass', '0']) -if ' hours on ' not in output: - fail('Expected warning not seen for hours') -output = realm.run(['./t_expire_warn', 'days', 'pass', '0']) -if ' days on ' not in output: - fail('Expected warning not seen for days') +realm.run(['./t_expire_warn', 'minutes', 'pass', '0'], + expected_msg=' less than one hour on ') +realm.run(['./t_expire_warn', 'hours', 'pass', '0'], expected_msg=' hours on ') +realm.run(['./t_expire_warn', 'days', 'pass', '0'], expected_msg=' days on ') # Check for expected expire callback behavior. These tests are # carefully agnostic about whether the KDC supports last_req fields, diff --git a/src/lib/krb5/krb/t_kerb.c b/src/lib/krb5/krb/t_kerb.c index 60cfb5b15115..74ac14d9ab64 100644 --- a/src/lib/krb5/krb/t_kerb.c +++ b/src/lib/krb5/krb/t_kerb.c @@ -5,16 +5,8 @@ */ #include "autoconf.h" -#include "krb5.h" -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> +#include "k5-int.h" #include <time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> #include "com_err.h" @@ -37,7 +29,7 @@ test_string_to_timestamp(krb5_context ctx, char *ktime) com_err("krb5_string_to_timestamp", retval, 0); return; } - t = (time_t) timestamp; + t = ts2tt(timestamp); printf("Parsed time was %s", ctime(&t)); } diff --git a/src/lib/krb5/krb/t_parse_host_string.c b/src/lib/krb5/krb/t_parse_host_string.c index 76dd20f817b0..001b77389555 100644 --- a/src/lib/krb5/krb/t_parse_host_string.c +++ b/src/lib/krb5/krb/t_parse_host_string.c @@ -31,10 +31,7 @@ */ #include "k5-int.h" -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <cmocka.h> +#include "k5-cmocka.h" #include <malloc.h> /* Call k5_parse_host_string() and check the result against the expected code, diff --git a/src/lib/krb5/krb/t_valid_times.c b/src/lib/krb5/krb/t_valid_times.c new file mode 100644 index 000000000000..1b469ffc252f --- /dev/null +++ b/src/lib/krb5/krb/t_valid_times.c @@ -0,0 +1,109 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/krb/t_valid_times.c - test program for krb5int_validate_times() */ +/* + * Copyright (C) 2017 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "k5-int.h" +#include "int-proto.h" + +#define BOUNDARY (uint32_t)INT32_MIN + +int +main() +{ + krb5_error_code ret; + krb5_context context; + krb5_ticket_times times = { 0, 0, 0, 0 }; + + ret = krb5_init_context(&context); + assert(!ret); + + /* Current time is within authtime and end time. */ + ret = krb5_set_debugging_time(context, 1000, 0); + times.authtime = 500; + times.endtime = 1500; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime, but within clock skew. */ + times.starttime = 1100; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime by more than clock skew. */ + times.starttime = 1400; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_NYV); + + /* Current time is after end time, but within clock skew. */ + times.starttime = 500; + times.endtime = 800; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is after end time by more than clock skew. */ + times.endtime = 600; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED); + + /* Current time is within starttime and endtime; current time and + * endtime are across y2038 boundary. */ + ret = krb5_set_debugging_time(context, BOUNDARY - 100, 0); + assert(!ret); + times.starttime = BOUNDARY - 200; + times.endtime = BOUNDARY + 500; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime, but by less than clock skew. */ + times.starttime = BOUNDARY + 100; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime by more than clock skew. */ + times.starttime = BOUNDARY + 250; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_NYV); + + /* Current time is after endtime, but by less than clock skew. */ + ret = krb5_set_debugging_time(context, BOUNDARY + 100, 0); + assert(!ret); + times.starttime = BOUNDARY - 1000; + times.endtime = BOUNDARY - 100; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is after endtime by more than clock skew. */ + times.endtime = BOUNDARY - 300; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED); + + return 0; +} diff --git a/src/lib/krb5/krb/valid_times.c b/src/lib/krb5/krb/valid_times.c index d63122183eff..294761a882c5 100644 --- a/src/lib/krb5/krb/valid_times.c +++ b/src/lib/krb5/krb/valid_times.c @@ -47,10 +47,10 @@ krb5int_validate_times(krb5_context context, krb5_ticket_times *times) else starttime = times->authtime; - if (starttime - currenttime > context->clockskew) + if (ts_after(starttime, ts_incr(currenttime, context->clockskew))) return KRB5KRB_AP_ERR_TKT_NYV; /* ticket not yet valid */ - if ((currenttime - times->endtime) > context->clockskew) + if (ts_after(currenttime, ts_incr(times->endtime, context->clockskew))) return KRB5KRB_AP_ERR_TKT_EXPIRED; /* ticket expired */ return 0; diff --git a/src/lib/krb5/krb/vfy_increds.c b/src/lib/krb5/krb/vfy_increds.c index 9786d63b5cb1..b4878ba3852e 100644 --- a/src/lib/krb5/krb/vfy_increds.c +++ b/src/lib/krb5/krb/vfy_increds.c @@ -120,7 +120,7 @@ get_vfy_cred(krb5_context context, krb5_creds *creds, krb5_principal server, ret = krb5_timeofday(context, &in_creds.times.endtime); if (ret) goto cleanup; - in_creds.times.endtime += 5*60; + in_creds.times.endtime = ts_incr(in_creds.times.endtime, 5 * 60); ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds); if (ret) goto cleanup; diff --git a/src/lib/krb5/krb/x-deltat.y b/src/lib/krb5/krb/x-deltat.y index f9cc2bb46959..da11b88077aa 100644 --- a/src/lib/krb5/krb/x-deltat.y +++ b/src/lib/krb5/krb/x-deltat.y @@ -44,7 +44,6 @@ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #include "k5-int.h" diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in index efa82e22f35e..5d2fcb5be8fa 100644 --- a/src/lib/krb5/os/Makefile.in +++ b/src/lib/krb5/os/Makefile.in @@ -225,7 +225,7 @@ check-unix-locate: t_locate_kdc $(RUN_TEST) ./t_locate_kdc $(LOCREALM); \ else \ echo '*** WARNING: skipped t_locate_kdc test: known DNS name not found'; \ - echo 'Skipped t_locate_kdc test: known DNS name found' >> $(SKIPTESTS); \ + echo 'Skipped t_locate_kdc test: known DNS name not found' >> $(SKIPTESTS); \ fi; \ else \ echo '*** WARNING: skipped t_locate_kdc test: OFFLINE'; \ diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c index df63b14faa56..11552ef42c08 100644 --- a/src/lib/krb5/os/accessor.c +++ b/src/lib/krb5/os/accessor.c @@ -30,11 +30,14 @@ /* If this trick gets used elsewhere, move it to k5-platform.h. */ #ifndef DESIGNATED_INITIALIZERS -#define DESIGNATED_INITIALIZERS \ - /* ANSI/ISO C 1999 supports this... */ \ - (__STDC_VERSION__ >= 199901L \ - /* ...as does GCC, since version 2.something. */ \ - || (!defined __cplusplus && __GNUC__ >= 3)) +/* ANSI/ISO C 1999 supports this... */ +#if __STDC_VERSION__ >= 199901L \ + /* ...as does GCC, since version 2.something. */ \ + || (!defined __cplusplus && __GNUC__ >= 3) +#define DESIGNATED_INITIALIZERS 1 +#else +#define DESIGNATED_INITIALIZERS 0 +#endif #endif krb5_error_code KRB5_CALLCONV diff --git a/src/lib/krb5/os/c_ustime.c b/src/lib/krb5/os/c_ustime.c index 871d72183007..f69f2ea4c332 100644 --- a/src/lib/krb5/os/c_ustime.c +++ b/src/lib/krb5/os/c_ustime.c @@ -29,7 +29,10 @@ k5_mutex_t krb5int_us_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER; -struct time_now { krb5_int32 sec, usec; }; +struct time_now { + krb5_timestamp sec; + krb5_int32 usec; +}; #if defined(_WIN32) @@ -73,7 +76,7 @@ get_time_now(struct time_now *n) static struct time_now last_time; krb5_error_code -krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds) +krb5_crypto_us_timeofday(krb5_timestamp *seconds, krb5_int32 *microseconds) { struct time_now now; krb5_error_code err; @@ -102,17 +105,17 @@ krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds) putting now.sec in the past. But don't just use '<' because we need to properly handle the case where the administrator intentionally adjusted time backwards. */ - if ((now.sec == last_time.sec-1) || - ((now.sec == last_time.sec) && (now.usec <= last_time.usec))) { + if (now.sec == ts_incr(last_time.sec, -1) || + (now.sec == last_time.sec && !ts_after(last_time.usec, now.usec))) { /* Correct 'now' to be exactly one microsecond later than 'last_time'. Note that _because_ we perform this hack, 'now' may be _earlier_ than 'last_time', even though the system time is monotonically increasing. */ now.sec = last_time.sec; - now.usec = ++last_time.usec; + now.usec = ts_incr(last_time.usec, 1); if (now.usec >= 1000000) { - ++now.sec; + now.sec = ts_incr(now.sec, 1); now.usec = 0; } } diff --git a/src/lib/krb5/os/dnsglue.c b/src/lib/krb5/os/dnsglue.c index 1a259b399eba..e29066d74bc5 100644 --- a/src/lib/krb5/os/dnsglue.c +++ b/src/lib/krb5/os/dnsglue.c @@ -73,7 +73,7 @@ static int initparse(struct krb5int_dns_state *); #if defined(__APPLE__) -/* Use the OS X interfaces dns_open, dns_search, and dns_free. */ +/* Use the macOS interfaces dns_open, dns_search, and dns_free. */ #define DECLARE_HANDLE(h) dns_handle_t h #define INIT_HANDLE(h) ((h = dns_open(NULL)) != NULL) #define SEARCH(h, n, c, t, a, l) dns_search(h, n, c, t, a, l, NULL, NULL) diff --git a/src/lib/krb5/os/dnsglue.h b/src/lib/krb5/os/dnsglue.h index 27147a6cab51..e7844049db72 100644 --- a/src/lib/krb5/os/dnsglue.h +++ b/src/lib/krb5/os/dnsglue.h @@ -33,9 +33,9 @@ * BIND 4 doesn't have the ns_initparse() API, so we need to do some * manual parsing via the HEADER struct. BIND 8 does have * ns_initparse(), but has enums for the various protocol constants - * rather than the BIND 4 macros. BIND 9 (at least on Mac OS X - * Panther) appears to disable res_nsearch() if BIND_8_COMPAT is - * defined (which is necessary to obtain the HEADER struct). + * rather than the BIND 4 macros. BIND 9 (at least on macOS 10.3) + * appears to disable res_nsearch() if BIND_8_COMPAT is defined + * (which is necessary to obtain the HEADER struct). * * We use ns_initparse() if available at all, and never define * BIND_8_COMPAT. If there is no ns_initparse(), we do manual parsing @@ -167,15 +167,16 @@ struct srv_dns_entry { char *host; }; -krb5_error_code krb5int_make_srv_query_realm(const krb5_data *realm, - const char *service, - const char *protocol, - struct srv_dns_entry **answers); +krb5_error_code +krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm, + const char *service, const char *protocol, + struct srv_dns_entry **answers); + void krb5int_free_srv_dns_data(struct srv_dns_entry *); krb5_error_code -k5_make_uri_query(const krb5_data *realm, const char *service, - struct srv_dns_entry **answers); +k5_make_uri_query(krb5_context context, const krb5_data *realm, + const char *service, struct srv_dns_entry **answers); #endif /* KRB5_DNS_LOOKUP */ #endif /* !defined(KRB5_DNSGLUE_H) */ diff --git a/src/lib/krb5/os/dnssrv.c b/src/lib/krb5/os/dnssrv.c index 76f5b63a1774..d66a8f99a0af 100644 --- a/src/lib/krb5/os/dnssrv.c +++ b/src/lib/krb5/os/dnssrv.c @@ -104,8 +104,8 @@ place_srv_entry(struct srv_dns_entry **head, struct srv_dns_entry *new) /* Query the URI RR, collecting weight, priority, and target. */ krb5_error_code -k5_make_uri_query(const krb5_data *realm, const char *service, - struct srv_dns_entry **answers) +k5_make_uri_query(krb5_context context, const krb5_data *realm, + const char *service, struct srv_dns_entry **answers) { const unsigned char *p = NULL, *base = NULL; char host[MAXDNAME]; @@ -121,6 +121,8 @@ k5_make_uri_query(const krb5_data *realm, const char *service, if (ret) return 0; + TRACE_DNS_URI_SEND(context, host); + size = krb5int_dns_init(&ds, host, C_IN, T_URI); if (size < 0) goto out; @@ -148,6 +150,7 @@ k5_make_uri_query(const krb5_data *realm, const char *service, goto out; } + TRACE_DNS_URI_ANS(context, uri->host, uri->priority, uri->weight); place_srv_entry(&head, uri); } @@ -165,9 +168,8 @@ out: */ krb5_error_code -krb5int_make_srv_query_realm(const krb5_data *realm, - const char *service, - const char *protocol, +krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm, + const char *service, const char *protocol, struct srv_dns_entry **answers) { const unsigned char *p = NULL, *base = NULL; @@ -192,9 +194,7 @@ krb5int_make_srv_query_realm(const krb5_data *realm, if (ret) return 0; -#ifdef TEST - fprintf(stderr, "sending DNS SRV query for %s\n", host); -#endif + TRACE_DNS_SRV_SEND(context, host); size = krb5int_dns_init(&ds, host, C_IN, T_SRV); if (size < 0) @@ -239,6 +239,8 @@ krb5int_make_srv_query_realm(const krb5_data *realm, goto out; } + TRACE_DNS_SRV_ANS(context, srv->host, srv->port, srv->priority, + srv->weight); place_srv_entry(&head, srv); } diff --git a/src/lib/krb5/os/expand_path.c b/src/lib/krb5/os/expand_path.c index a8a14f4bb28b..61fb234594e6 100644 --- a/src/lib/krb5/os/expand_path.c +++ b/src/lib/krb5/os/expand_path.c @@ -351,7 +351,7 @@ expand_null(krb5_context context, PTYPE param, const char *postfix, char **ret) return 0; } -static const struct token { +static const struct { const char *tok; PTYPE param; const char *postfix; diff --git a/src/lib/krb5/os/genaddrs.c b/src/lib/krb5/os/genaddrs.c index 5ef7af5a339f..c818fdb6d79d 100644 --- a/src/lib/krb5/os/genaddrs.c +++ b/src/lib/krb5/os/genaddrs.c @@ -79,8 +79,8 @@ krb5_auth_con_genaddrs(krb5_context context, krb5_auth_context auth_context, int ssize = sizeof(struct sockaddr_storage); if ((flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) || (flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR)) { - if ((retval = getsockname(fd, (GETSOCKNAME_ARG2_TYPE *) &lsaddr, - &ssize))) + retval = getsockname(fd, ss2sa(&lsaddr), &ssize); + if (retval) return retval; if (cvtaddr (&lsaddr, &laddrs)) { @@ -99,8 +99,8 @@ krb5_auth_con_genaddrs(krb5_context context, krb5_auth_context auth_context, int ssize = sizeof(struct sockaddr_storage); if ((flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) || (flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR)) { - if ((retval = getpeername(fd, (GETPEERNAME_ARG2_TYPE *) &rsaddr, - &ssize))) + retval = getpeername(fd, ss2sa(&rsaddr), &ssize); + if (retval) return errno; if (cvtaddr (&rsaddr, &raddrs)) { diff --git a/src/lib/krb5/os/hostaddr.c b/src/lib/krb5/os/hostaddr.c index 22f6ad6d48b9..d7a4a763012d 100644 --- a/src/lib/krb5/os/hostaddr.c +++ b/src/lib/krb5/os/hostaddr.c @@ -83,12 +83,12 @@ k5_os_hostaddr(krb5_context context, const char *name, switch (aip->ai_addr->sa_family) { case AF_INET: addrlen = sizeof (struct in_addr); - ptr = &((struct sockaddr_in *)aip->ai_addr)->sin_addr; + ptr = &sa2sin(aip->ai_addr)->sin_addr; atype = ADDRTYPE_INET; break; case AF_INET6: addrlen = sizeof (struct in6_addr); - ptr = &((struct sockaddr_in6 *)aip->ai_addr)->sin6_addr; + ptr = &sa2sin6(aip->ai_addr)->sin6_addr; atype = ADDRTYPE_INET6; break; default: diff --git a/src/lib/krb5/os/localaddr.c b/src/lib/krb5/os/localaddr.c index 9f7765254467..58443f6e354a 100644 --- a/src/lib/krb5/os/localaddr.c +++ b/src/lib/krb5/os/localaddr.c @@ -181,11 +181,11 @@ is_loopback_address(struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: { - struct sockaddr_in *s4 = (struct sockaddr_in *)sa; + struct sockaddr_in *s4 = sa2sin(sa); return s4->sin_addr.s_addr == htonl(INADDR_LOOPBACK); } case AF_INET6: { - struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa; + struct sockaddr_in6 *s6 = sa2sin6(sa); return IN6_IS_ADDR_LOOPBACK(&s6->sin6_addr); } default: @@ -239,16 +239,17 @@ printifaddr(struct ifaddrs *ifp) #include <stdlib.h> static int -addr_eq (const struct sockaddr *s1, const struct sockaddr *s2) +addr_eq (struct sockaddr *s1, struct sockaddr *s2) { if (s1->sa_family != s2->sa_family) return 0; -#define CMPTYPE(T,F) (!memcmp(&((const T*)s1)->F,&((const T*)s2)->F,sizeof(((const T*)s1)->F))) switch (s1->sa_family) { case AF_INET: - return CMPTYPE (struct sockaddr_in, sin_addr); + return !memcmp(&sa2sin(s1)->sin_addr, &sa2sin(s2)->sin_addr, + sizeof(sa2sin(s1)->sin_addr)); case AF_INET6: - return CMPTYPE (struct sockaddr_in6, sin6_addr); + return !memcmp(&sa2sin6(s1)->sin6_addr, &sa2sin6(s2)->sin6_addr, + sizeof(sa2sin6(s1)->sin6_addr)); default: /* Err on side of duplicate listings. */ return 0; @@ -861,6 +862,9 @@ get_ifreq_array(char **bufp, size_t *np, int s) int numifs = -1; #endif + *bufp = NULL; + *np = 0; + /* At least on NetBSD, an ifreq can hold an IPv4 address, but isn't big enough for an IPv6 or ethernet address. So add a little more space. */ @@ -937,9 +941,9 @@ foreach_localaddr (/*@null@*/ void *data, #endif { struct ifreq *ifr, ifreq, *ifr2; - int s, code; + int s; char *buf = 0; - size_t size, n, i, j; + size_t n, i, j; int retval = 0; #ifdef LINUX_IPV6_HACK struct linux_ipv6_addr_list *linux_ipv6_addrs = get_linux_ipv6_addrs (); @@ -1183,14 +1187,14 @@ add_addr (void *P_data, struct sockaddr *a) #ifdef HAVE_NETINET_IN_H case AF_INET: address = make_addr (ADDRTYPE_INET, sizeof (struct in_addr), - &((const struct sockaddr_in *) a)->sin_addr); + &sa2sin(a)->sin_addr); if (address == NULL) data->mem_err++; break; case AF_INET6: { - const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) a; + const struct sockaddr_in6 *in = sa2sin6(a); if (IN6_IS_ADDR_LINKLOCAL (&in->sin6_addr)) break; diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c index 014ec6ecb902..b9edecc7a910 100644 --- a/src/lib/krb5/os/locate_kdc.c +++ b/src/lib/krb5/os/locate_kdc.c @@ -313,14 +313,16 @@ krb5_locate_srv_conf(krb5_context context, const krb5_data *realm, #ifdef KRB5_DNS_LOOKUP static krb5_error_code -locate_srv_dns_1(const krb5_data *realm, const char *service, - const char *protocol, struct serverlist *serverlist) +locate_srv_dns_1(krb5_context context, const krb5_data *realm, + const char *service, const char *protocol, + struct serverlist *serverlist) { struct srv_dns_entry *head = NULL, *entry = NULL; krb5_error_code code = 0; k5_transport transport; - code = krb5int_make_srv_query_realm(realm, service, protocol, &head); + code = krb5int_make_srv_query_realm(context, realm, service, protocol, + &head); if (code) return 0; @@ -598,9 +600,10 @@ parse_uri_fields(const char *uri, k5_transport *transport_out, * and transport type. Problematic entries are skipped. */ static krb5_error_code -locate_uri(const krb5_data *realm, const char *req_service, - struct serverlist *serverlist, k5_transport req_transport, - int default_port, krb5_boolean master_only) +locate_uri(krb5_context context, const krb5_data *realm, + const char *req_service, struct serverlist *serverlist, + k5_transport req_transport, int default_port, + krb5_boolean master_only) { krb5_error_code ret; k5_transport transport, host_trans; @@ -609,7 +612,7 @@ locate_uri(const krb5_data *realm, const char *req_service, const char *host_field, *path; int port, def_port, master; - ret = k5_make_uri_query(realm, req_service, &answers); + ret = k5_make_uri_query(context, realm, req_service, &answers); if (ret || answers == NULL) return ret; @@ -688,10 +691,11 @@ dns_locate_server_uri(krb5_context context, const krb5_data *realm, return 0; } - ret = locate_uri(realm, svcname, serverlist, transport, def_port, + ret = locate_uri(context, realm, svcname, serverlist, transport, def_port, find_master); - if (ret) - Tprintf("dns URI lookup returned error %d\n", ret); + + if (serverlist->nservers == 0) + TRACE_DNS_URI_NOTFOUND(context); return ret; } @@ -729,16 +733,15 @@ dns_locate_server_srv(krb5_context context, const krb5_data *realm, } code = 0; - if (transport == UDP || transport == TCP_OR_UDP) { - code = locate_srv_dns_1(realm, dnsname, "_udp", serverlist); - if (code) - Tprintf("dns udp lookup returned error %d\n", code); - } - if ((transport == TCP || transport == TCP_OR_UDP) && code == 0) { - code = locate_srv_dns_1(realm, dnsname, "_tcp", serverlist); - if (code) - Tprintf("dns tcp lookup returned error %d\n", code); - } + if (transport == UDP || transport == TCP_OR_UDP) + code = locate_srv_dns_1(context, realm, dnsname, "_udp", serverlist); + + if ((transport == TCP || transport == TCP_OR_UDP) && code == 0) + code = locate_srv_dns_1(context, realm, dnsname, "_tcp", serverlist); + + if (serverlist->nservers == 0) + TRACE_DNS_SRV_NOTFOUND(context); + return code; } #endif /* KRB5_DNS_LOOKUP */ diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c index fffe0262f6bb..e8bc0ad6e2f5 100644 --- a/src/lib/krb5/os/sendto_kdc.c +++ b/src/lib/krb5/os/sendto_kdc.c @@ -253,7 +253,7 @@ cm_get_ssflags(struct select_state *selstate, int fd) struct pollfd *pfd = find_pollfd(selstate, fd); /* - * OS X sets POLLHUP without POLLOUT on connection error. Catch this as + * macOS sets POLLHUP without POLLOUT on connection error. Catch this as * well as other error events such as POLLNVAL, but only if POLLIN and * POLLOUT aren't set, as we can get POLLHUP along with POLLIN with TCP * data still to be read. @@ -1372,8 +1372,7 @@ get_endtime(time_ms endtime, struct conn_state *conns) struct conn_state *state; for (state = conns; state != NULL; state = state->next) { - if (state->addr.transport == TCP && - (state->state == READING || state->state == WRITING) && + if ((state->state == READING || state->state == WRITING) && state->endtime > endtime) endtime = state->endtime; } diff --git a/src/lib/krb5/os/t_locate_kdc.c b/src/lib/krb5/os/t_locate_kdc.c index 6414b8e92d79..7a53c842a80e 100644 --- a/src/lib/krb5/os/t_locate_kdc.c +++ b/src/lib/krb5/os/t_locate_kdc.c @@ -127,7 +127,7 @@ main (int argc, char *argv[]) break; case LOOKUP_DNS: - err = locate_srv_dns_1(&realm, "_kerberos", "_udp", &sl); + err = locate_srv_dns_1(ctx, &realm, "_kerberos", "_udp", &sl); break; case LOOKUP_WHATEVER: diff --git a/src/lib/krb5/os/timeofday.c b/src/lib/krb5/os/timeofday.c index fddb1214296f..d4e36b1c7572 100644 --- a/src/lib/krb5/os/timeofday.c +++ b/src/lib/krb5/os/timeofday.c @@ -60,7 +60,7 @@ krb5_check_clockskew(krb5_context context, krb5_timestamp date) retval = krb5_timeofday(context, ¤ttime); if (retval) return retval; - if (!(labs((date)-currenttime) < context->clockskew)) + if (!ts_within(date, currenttime, context->clockskew)) return KRB5KRB_AP_ERR_SKEW; return 0; diff --git a/src/lib/krb5/os/toffset.c b/src/lib/krb5/os/toffset.c index 456193a41aed..4bbcdde52812 100644 --- a/src/lib/krb5/os/toffset.c +++ b/src/lib/krb5/os/toffset.c @@ -40,14 +40,15 @@ krb5_error_code KRB5_CALLCONV krb5_set_real_time(krb5_context context, krb5_timestamp seconds, krb5_int32 microseconds) { krb5_os_context os_ctx = &context->os_context; - krb5_int32 sec, usec; + krb5_timestamp sec; + krb5_int32 usec; krb5_error_code retval; retval = krb5_crypto_us_timeofday(&sec, &usec); if (retval) return retval; - os_ctx->time_offset = seconds - sec; + os_ctx->time_offset = ts_delta(seconds, sec); os_ctx->usec_offset = (microseconds > -1) ? microseconds - usec : 0; os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) | diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c index 83c8d4db876a..e97ce5fe5d66 100644 --- a/src/lib/krb5/os/trace.c +++ b/src/lib/krb5/os/trace.c @@ -173,7 +173,7 @@ trace_format(krb5_context context, const char *fmt, va_list ap) p = va_arg(ap, const char *); if (p == NULL && len != 0) k5_buf_add(&buf, "(null)"); - else + else if (p != NULL) buf_add_printable_len(&buf, p, len); } else if (strcmp(tmpbuf, "hexlenstr") == 0) { len = va_arg(ap, size_t); @@ -340,7 +340,8 @@ krb5int_trace(krb5_context context, const char *fmt, ...) va_list ap; krb5_trace_info info; char *str = NULL, *msg = NULL; - krb5_int32 sec, usec; + krb5_timestamp sec; + krb5_int32 usec; if (context == NULL || context->trace_callback == NULL) return; @@ -350,7 +351,7 @@ krb5int_trace(krb5_context context, const char *fmt, ...) goto cleanup; if (krb5_crypto_us_timeofday(&sec, &usec) != 0) goto cleanup; - if (asprintf(&msg, "[%d] %d.%d: %s\n", (int) getpid(), (int) sec, + if (asprintf(&msg, "[%d] %u.%d: %s\n", (int) getpid(), (unsigned int) sec, (int) usec, str) < 0) goto cleanup; info.message = msg; diff --git a/src/lib/krb5/os/ustime.c b/src/lib/krb5/os/ustime.c index 056357683456..a80fdf68ca48 100644 --- a/src/lib/krb5/os/ustime.c +++ b/src/lib/krb5/os/ustime.c @@ -40,7 +40,8 @@ krb5_error_code k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec, krb5_timestamp *time_out, krb5_int32 *usec_out) { - krb5_int32 sec, usec; + krb5_timestamp sec; + krb5_int32 usec; krb5_error_code retval; retval = krb5_crypto_us_timeofday(&sec, &usec); @@ -49,13 +50,13 @@ k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec, usec += offset_usec; if (usec > 1000000) { usec -= 1000000; - sec++; + sec = ts_incr(sec, 1); } if (usec < 0) { usec += 1000000; - sec--; + sec = ts_incr(sec, -1); } - sec += offset; + sec = ts_incr(sec, offset); *time_out = sec; *usec_out = usec; diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c index c4d2c744da40..1e0cb22c94e2 100644 --- a/src/lib/krb5/rcache/rc_dfl.c +++ b/src/lib/krb5/rcache/rc_dfl.c @@ -93,12 +93,11 @@ cmp(krb5_donot_replay *old, krb5_donot_replay *new1, krb5_deltat t) } static int -alive(krb5_int32 mytime, krb5_donot_replay *new1, krb5_deltat t) +alive(krb5_timestamp mytime, krb5_donot_replay *new1, krb5_deltat t) { if (mytime == 0) return CMP_HOHUM; /* who cares? */ - /* I hope we don't have to worry about overflow */ - if (new1->ctime + t < mytime) + if (ts_after(mytime, ts_incr(new1->ctime, t))) return CMP_EXPIRED; return CMP_HOHUM; } @@ -130,7 +129,7 @@ struct authlist static int rc_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep, - krb5_int32 now, krb5_boolean fromfile) + krb5_timestamp now, krb5_boolean fromfile) { struct dfl_data *t = (struct dfl_data *)id->data; unsigned int rephash; @@ -517,7 +516,7 @@ errout: free(rep->server); if (rep->msghash) free(rep->msghash); - rep->client = rep->server = 0; + rep->client = rep->server = rep->msghash = NULL; return retval; } @@ -537,7 +536,7 @@ krb5_rc_dfl_recover_locked(krb5_context context, krb5_rcache id) krb5_error_code retval; long max_size; int expired_entries = 0; - krb5_int32 now; + krb5_timestamp now; if ((retval = krb5_rc_io_open(context, &t->d, t->name))) { return retval; @@ -707,7 +706,7 @@ krb5_rc_dfl_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep) { krb5_error_code ret; struct dfl_data *t; - krb5_int32 now; + krb5_timestamp now; ret = krb5_timeofday(context, &now); if (ret) @@ -763,7 +762,7 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id) struct authlist **qt; struct authlist *r; struct authlist *rt; - krb5_int32 now; + krb5_timestamp now; if (krb5_timestamp(context, &now)) now = 0; diff --git a/src/lib/krb5/rcache/ser_rc.c b/src/lib/krb5/rcache/ser_rc.c index 556af21e5e48..5c537f08a1cc 100644 --- a/src/lib/krb5/rcache/ser_rc.c +++ b/src/lib/krb5/rcache/ser_rc.c @@ -72,7 +72,7 @@ krb5_rcache_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep) * krb5_int32 for KV5M_RCACHE */ required = sizeof(krb5_int32) * 3; - if (rcache->ops && rcache->ops->type) + if (rcache->ops) required += (strlen(rcache->ops->type)+1); /* diff --git a/src/lib/krb5/rcache/t_replay.c b/src/lib/krb5/rcache/t_replay.c index db273ec2f221..b99cdf1abb8e 100644 --- a/src/lib/krb5/rcache/t_replay.c +++ b/src/lib/krb5/rcache/t_replay.c @@ -110,7 +110,7 @@ store(krb5_context ctx, char *rcspec, char *client, char *server, char *msg, krb5_donot_replay rep; krb5_data d; - if (now_timestamp > 0) + if (now_timestamp != 0) krb5_set_debugging_time(ctx, now_timestamp, now_usec); if ((retval = krb5_rc_resolve_full(ctx, &rc, rcspec))) goto cleanup; @@ -221,13 +221,13 @@ main(int argc, char **argv) msg = (**argv) ? *argv : NULL; argc--; argv++; if (!argc) usage(progname); - timestamp = (krb5_timestamp) atol(*argv); + timestamp = (krb5_timestamp) atoll(*argv); argc--; argv++; if (!argc) usage(progname); usec = (krb5_int32) atol(*argv); argc--; argv++; if (!argc) usage(progname); - now_timestamp = (krb5_timestamp) atol(*argv); + now_timestamp = (krb5_timestamp) atoll(*argv); argc--; argv++; if (!argc) usage(progname); now_usec = (krb5_int32) atol(*argv); @@ -249,7 +249,7 @@ main(int argc, char **argv) rcspec = *argv; argc--; argv++; if (!argc) usage(progname); - now_timestamp = (krb5_timestamp) atol(*argv); + now_timestamp = (krb5_timestamp) atoll(*argv); argc--; argv++; if (!argc) usage(progname); now_usec = (krb5_int32) atol(*argv); diff --git a/src/lib/krb5/unicode/ure/ure.c b/src/lib/krb5/unicode/ure/ure.c index d1cfd8af945e..23a03d94ffa2 100644 --- a/src/lib/krb5/unicode/ure/ure.c +++ b/src/lib/krb5/unicode/ure/ure.c @@ -421,7 +421,7 @@ _ure_prop_list(ucs2_t *pp, unsigned long limit, unsigned long *mask, b->error = _URE_INVALID_PROPERTY; } - if (n != 0) + if (b->error == _URE_OK && n != 0) m |= cclass_flags[n]; /* |