From 1a56ea6a655b191ea2ecde21c57efe746d64c378 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Fri, 2 Jan 2009 01:40:41 +0000 Subject: [PATCH] Rewrite walk_rtree.c to handle hierarchical traversal better and to be less convoluted. Update test cases. ticket: 5947 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@21659 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb5/krb/Makefile.in | 6 +- src/lib/krb5/krb/walk_rtree.c | 763 +++++++++++++++++++------------- src/lib/krb5/krb/walktree-tests | 8 + 3 files changed, 468 insertions(+), 309 deletions(-) diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index ce161666b..1a204dfd2 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -294,7 +294,7 @@ clean-unix:: clean-libobjs COMERRLIB=$(TOPLIBD)/libcom_err.a T_WALK_RTREE_OBJS= t_walk_rtree.o walk_rtree.o tgtname.o unparse.o \ - free_rtree.o bld_pr_ext.o + free_rtree.o bld_pr_ext.o copy_data.o T_KERB_OBJS= t_kerb.o conv_princ.o unparse.o set_realm.o str_conv.o @@ -351,8 +351,8 @@ check-unix:: $(TEST_PROGS) $(RUN_SETUP) $(VALGRIND) ./t_ser $(RUN_SETUP) $(VALGRIND) ./t_deltat $(RUN_SETUP) $(VALGRIND) sh $(srcdir)/transit-tests - : known to fail "http://krbdev.mit.edu/rt/Ticket/Display.html?id=5947" - -$(RUN_SETUP) $(VALGRIND) sh $(srcdir)/walktree-tests + KRB5_CONFIG=$(srcdir)/t_krb5.conf ; export KRB5_CONFIG ;\ + $(RUN_SETUP) $(VALGRIND) sh $(srcdir)/walktree-tests clean:: $(RM) $(OUTPRE)t_walk_rtree$(EXEEXT) $(OUTPRE)t_walk_rtree.$(OBJEXT) \ diff --git a/src/lib/krb5/krb/walk_rtree.c b/src/lib/krb5/krb/walk_rtree.c index b1b2627c8..4cebce526 100644 --- a/src/lib/krb5/krb/walk_rtree.c +++ b/src/lib/krb5/krb/walk_rtree.c @@ -1,14 +1,14 @@ /* * lib/krb5/krb/walk_rtree.c * - * Copyright 1990,1991,2008 by the Massachusetts Institute of Technology. + * Copyright 1990,1991,2008,2009 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. - * + * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright @@ -22,11 +22,104 @@ * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. - * * * krb5_walk_realm_tree() + * + * internal function, used by krb5_get_cred_from_kdc() */ +#include "k5-int.h" +#include "int-proto.h" + +/* + * Structure to help with finding the common suffix between client and + * server realm during hierarchical traversal. + */ +struct hstate { + char *str; + size_t len; + char *tail; + char *dot; +}; + +static krb5_error_code +rtree_capath_tree( + krb5_context context, + const krb5_data *client, + const krb5_data *server, + char **vals, + krb5_principal **tree); + +static krb5_error_code +rtree_capath_vals( + krb5_context context, + const krb5_data *client, + const krb5_data *server, + char ***vals); + +static krb5_error_code +rtree_hier_tree( + krb5_context context, + const krb5_data *client, + const krb5_data *server, + krb5_principal **rettree, + int sep); + +static krb5_error_code +rtree_hier_realms( + krb5_context context, + const krb5_data *client, + const krb5_data *server, + krb5_data **realms, + size_t *nrealms, + int sep); + +static krb5_error_code +rtree_hier_tweens( + krb5_context context, + struct hstate *realm, + krb5_data **tweens, + size_t *ntweens, + int dotail, + int sep); + +static void +adjtail(struct hstate *c, struct hstate *s, int sep); + +static void +comtail(struct hstate *c, struct hstate *s, int sep); + +krb5_error_code +krb5_walk_realm_tree( + krb5_context context, + const krb5_data *client, + const krb5_data *server, + krb5_principal **tree, + int realm_sep) +{ + krb5_error_code retval = 0; + char **capvals; + + if (client->data == NULL || server->data == NULL) + return KRB5_NO_TKT_IN_RLM; + + if (client->length == server->length && + memcmp(client->data, server->data, server->length) == 0) { + return KRB5_NO_TKT_IN_RLM; + } + retval = rtree_capath_vals(context, client, server, &capvals); + if (retval) + return retval; + + if (capvals != NULL) { + retval = rtree_capath_tree(context, client, server, capvals, tree); + return retval; + } + + retval = rtree_hier_tree(context, client, server, tree, realm_sep); + return retval; +} + /* ANL - Modified to allow Configurable Authentication Paths. * This modification removes the restriction on the choice of realm * names, i.e. they nolonger have to be hierarchical. This @@ -52,8 +145,8 @@ * NERSC.GOV = ES.NET * PNL.GOV = ES.NET * ES.NET = . - * HAL.COM = K5.MOON - * HAL.COM = K5.JUPITER + * HAL.COM = K5.MOON + * HAL.COM = K5.JUPITER * } * NERSC.GOV = { * ANL.GOV = ES.NET @@ -62,7 +155,7 @@ * ANL.GOV = ES.NET * } * ES.NET = { - * ANL.GOV = . + * ANL.GOV = . * } * HAL.COM = { * ANL.GOV = K5.JUPITER @@ -82,326 +175,384 @@ * will work together. * DEE - 5/23/95 */ -#include "k5-int.h" -#include "int-proto.h" -/* internal function, used by krb5_get_cred_from_kdc() */ +/* + * Build a tree given a set of profile values retrieved by + * walk_rtree_capath_vals(). + */ +static krb5_error_code +rtree_capath_tree( + krb5_context context, + const krb5_data *client, + const krb5_data *server, + char **vals, + krb5_principal **rettree) +{ + krb5_error_code retval = 0; + unsigned int nvals, nlinks, nprincs, i; + krb5_data srcrealm, dstrealm; + krb5_principal *tree, *pprinc; -#ifndef min -#define min(x,y) ((x) < (y) ? (x) : (y)) -#define max(x,y) ((x) > (y) ? (x) : (y)) -#endif + *rettree = NULL; + tree = pprinc = NULL; + for (nvals = 0; vals[nvals] != NULL; nvals++) + ; + if (vals[0] != NULL && *vals[0] == '.') { + nlinks = 0; + } else { + nlinks = nvals; + } + nprincs = nlinks + 2; + tree = calloc(nprincs + 1, sizeof(krb5_principal)); + if (tree == NULL) { + retval = ENOMEM; + goto error; + } + for (i = 0; i < nprincs + 1; i++) + tree[i] = NULL; + /* Invariant: PPRINC points one past end of list. */ + pprinc = &tree[0]; + /* Local TGS name */ + retval = krb5_tgtname(context, client, client, pprinc++); + if (retval) goto error; + srcrealm = *client; + for (i = 0; i < nlinks; i++) { + dstrealm.data = vals[i]; + dstrealm.length = strcspn(vals[i], "\t "); + retval = krb5_tgtname(context, &dstrealm, &srcrealm, pprinc++); + if (retval) goto error; + srcrealm = dstrealm; + } + retval = krb5_tgtname(context, server, &srcrealm, pprinc++); + if (retval) goto error; + *rettree = tree; + +error: + profile_free_list(vals); + if (retval) { + while (pprinc != NULL && pprinc > &tree[0]) { + /* krb5_free_principal() correctly handles null input */ + krb5_free_principal(context, *--pprinc); + *pprinc = NULL; + } + free(tree); + } + return retval; +} /* - * xxx The following function is very confusing to read and probably - * is buggy. It should be documented better. Here is what I've - * learned about it doing a quick bug fixing walk through. The - * function takes a client and server realm name and returns the set - * of realms (in a field called tree) that you need to get tickets in - * in order to get from the source realm to the destination realm. It - * takes a realm separater character (normally ., but presumably there - * for all those X.500 realms) . There are two modes it runs in: the - * ANL krb5.conf mode and the hierarchy mode. The ANL mode is - * fairly obvious. The hierarchy mode looks for common components in - * both the client and server realms. In general, the pointer scp and - * ccp are used to walk through the client and server realms. The - * com_sdot and com_cdot pointers point to (I think) the beginning of - * the common part of the realm names. I.E. strcmp(com_cdot, - * com_sdot) ==0 is roughly an invarient. However, there are cases - * where com_sdot and com_cdot are set to point before the start of - * the client or server strings. I think this only happens when there - * are no common components. --hartmans 2002/03/14 + * Get realm list from "capaths" section of the profile. Deliberately + * returns success but leaves VALS null if profile_get_values() fails + * by not finding anything. */ +static krb5_error_code +rtree_capath_vals( + krb5_context context, + const krb5_data *client, + const krb5_data *server, + char ***vals) +{ + krb5_error_code retval = 0; + /* null-terminated realm names */ + char *clientz = NULL, *serverz = NULL; + const char *key[4]; -krb5_error_code -krb5_walk_realm_tree(krb5_context context, const krb5_data *client, const krb5_data *server, krb5_principal **tree, int realm_branch_char) + *vals = NULL; + + clientz = calloc(client->length + 1, 1); + if (clientz == NULL) { + retval = ENOMEM; + goto error; + } + memcpy(clientz, client->data, client->length); + + serverz = calloc(server->length + 1, 1); + if (clientz == NULL) { + retval = ENOMEM; + goto error; + } + memcpy(serverz, server->data, server->length); + + key[0] = "capaths"; + key[1] = clientz; + key[2] = serverz; + key[3] = NULL; + retval = profile_get_values(context->profile, key, vals); + switch (retval) { + case PROF_NO_SECTION: + case PROF_NO_RELATION: + /* + * Not found; don't return an error. + */ + retval = 0; + break; + default: + break; + } +error: + free(clientz); + free(serverz); + return retval; +} + +/* + * Build tree by hierarchical traversal. + */ +static krb5_error_code +rtree_hier_tree( + krb5_context context, + const krb5_data *client, + const krb5_data *server, + krb5_principal **rettree, + int sep) { krb5_error_code retval; - krb5_principal *rettree; - register char *ccp, *scp; - register char *prevccp = 0, *prevscp = 0; - char *com_sdot = 0, *com_cdot = 0; - register int i, links = 0; - int clen, slen = -1; - krb5_data tmpcrealm, tmpsrealm; - int nocommon = 1; - - const char *cap_names[4]; - char *cap_client, *cap_server; - char **cap_nodes; - krb5_error_code cap_code; - -#ifdef DEBUG_REFERRALS - printf("krb5_walk_realm_tree starting\n"); - printf(" client is %s\n",client->data); - printf(" server is %s\n",server->data); -#endif - - if (!(client->data &&server->data)) - return KRB5_NO_TKT_IN_RLM; - if ((cap_client = (char *)malloc(client->length + 1)) == NULL) - return ENOMEM; - strncpy(cap_client, client->data, client->length); - cap_client[client->length] = '\0'; - if ((cap_server = (char *)malloc(server->length + 1)) == NULL) { - krb5_xfree(cap_client); - return ENOMEM; + krb5_data *realms; + const krb5_data *dstrealm, *srcrealm; + krb5_principal *tree, *pprinc; + size_t nrealms, nprincs, i; + + *rettree = NULL; + retval = rtree_hier_realms(context, client, server, + &realms, &nrealms, sep); + if (retval) + return retval; + nprincs = nrealms; + pprinc = tree = calloc(nprincs + 1, sizeof(krb5_principal)); + if (tree == NULL) { + retval = ENOMEM; + goto error; } - strncpy(cap_server, server->data, server->length); - cap_server[server->length] = '\0'; - cap_names[0] = "capaths"; - cap_names[1] = cap_client; - cap_names[2] = cap_server; - cap_names[3] = 0; - cap_code = profile_get_values(context->profile, cap_names, &cap_nodes); - krb5_xfree(cap_client); /* done with client string */ - cap_names[1] = 0; - if (cap_code == 0) { /* found a path, so lets use it */ - links = 0; - if (*cap_nodes[0] != '.') { /* a link of . means direct */ - while(cap_nodes[links]) { - links++; - } - } - if (cap_nodes[links] != NULL) - krb5_xfree(cap_nodes[links]); - - cap_nodes[links] = cap_server; /* put server on end of list */ - /* this simplifies the code later and make */ - /* cleanup eaiser as well */ - links++; /* count the null entry at end */ - } else { /* no path use hierarchical method */ - krb5_xfree(cap_server); /* failed, don't need server string */ - cap_names[2] = 0; - - clen = client->length; - slen = server->length; - - for (com_cdot = ccp = client->data + clen - 1, - com_sdot = scp = server->data + slen - 1; - clen && slen && *ccp == *scp ; - ccp--, scp--, clen--, slen--) { - if (*ccp == realm_branch_char) { - com_cdot = ccp; - com_sdot = scp; - nocommon = 0; - } - } + for (i = 0; i < nrealms; i++) + tree[i] = NULL; + srcrealm = client; + for (i = 0; i < nrealms; i++) { + dstrealm = &realms[i]; + retval = krb5_tgtname(context, dstrealm, srcrealm, pprinc++); + if (retval) goto error; + srcrealm = dstrealm; + } + *rettree = tree; + return 0; +error: + while (pprinc != NULL && pprinc > tree) { + krb5_free_principal(context, *--pprinc); + *pprinc = NULL; + } + free(tree); + return retval; +} - /* ccp, scp point to common root. - com_cdot, com_sdot point to common components. */ - /* handle case of one ran out */ - if (!clen) { - /* construct path from client to server, down the tree */ - if (!slen) - /* in the same realm--this means there is no ticket - in this realm. */ - return KRB5_NO_TKT_IN_RLM; - if (*scp == realm_branch_char) { - /* one is a subdomain of the other */ - com_cdot = client->data; - com_sdot = scp; - nocommon = 0; - } /* else normal case of two sharing parents */ - } - if (!slen) { - /* construct path from client to server, up the tree */ - if (*ccp == realm_branch_char) { - /* one is a subdomain of the other */ - com_sdot = server->data; - com_cdot = ccp; - nocommon = 0; - } /* else normal case of two sharing parents */ - } - /* determine #links to/from common ancestor */ - if (nocommon) - links = 1; - else - links = 2; - /* if no common ancestor, artificially set up common root at the last - component, then join with special code */ - for (ccp = client->data; ccp < com_cdot; ccp++) { - if (*ccp == realm_branch_char) { - links++; - if (nocommon) - prevccp = ccp; - } - } +/* + * Construct list of realms between client and server. + */ +static krb5_error_code +rtree_hier_realms( + krb5_context context, + const krb5_data *client, + const krb5_data *server, + krb5_data **realms, + size_t *nrealms, + int sep) +{ + krb5_error_code retval; + struct hstate c, s; + krb5_data *ctweens, *stweens, *twp, *r, *rp; + size_t nctween, nstween; - for (scp = server->data; scp < com_sdot; scp++) { - if (*scp == realm_branch_char) { - links++; - if (nocommon) - prevscp = scp; - } - } - if (nocommon) { - if (prevccp) - com_cdot = prevccp; - if (prevscp) - com_sdot = prevscp; - - if(com_cdot == client->data + client->length -1) - com_cdot = client->data - 1 ; - if(com_sdot == server->data + server->length -1) - com_sdot = server->data - 1 ; - } - } /* end of if use hierarchical method */ + r = rp = NULL; + c.str = client->data; + c.len = client->length; + c.dot = c.tail = NULL; + s.str = server->data; + s.len = server->length; + s.dot = s.tail = NULL; + + comtail(&c, &s, sep); + adjtail(&c, &s, sep); + + retval = rtree_hier_tweens(context, &c, &ctweens, &nctween, 1, sep); + if (retval) goto error; + retval = rtree_hier_tweens(context, &s, &stweens, &nstween, 0, sep); + if (retval) goto error; - if (!(rettree = (krb5_principal *)calloc(links+2, - sizeof(krb5_principal)))) { - return ENOMEM; + *nrealms = nctween + nstween; + rp = r = calloc(*nrealms, sizeof(krb5_data)); + if (r == NULL) { + retval = ENOMEM; + goto error; } - i = 1; - if ((retval = krb5_tgtname(context, client, client, &rettree[0]))) { - krb5_xfree(rettree); - return retval; + /* Copy client realm "tweens" forward. */ + for (twp = ctweens; twp < &ctweens[nctween]; twp++) { + retval = krb5int_copy_data_contents(context, twp, rp++); + if (retval) goto error; } - links--; /* dont count the null entry on end */ - if (cap_code == 0) { /* found a path above */ - tmpcrealm.data = client->data; - tmpcrealm.length = client->length; - while( i-1 <= links) { - - tmpsrealm.data = cap_nodes[i-1]; - /* don't count trailing whitespace from profile_get */ - tmpsrealm.length = strcspn(cap_nodes[i-1],"\t "); - if ((retval = krb5_tgtname(context, - &tmpsrealm, - &tmpcrealm, - &rettree[i]))) { - while (i) { - krb5_free_principal(context, rettree[i-1]); - i--; - } - krb5_xfree(rettree); - /* cleanup the cap_nodes from profile_get */ - for (i = 0; i<=links; i++) { - krb5_xfree(cap_nodes[i]); - } - krb5_xfree((char *)cap_nodes); - return retval; - } - tmpcrealm.data = tmpsrealm.data; - tmpcrealm.length = tmpsrealm.length; - i++; - } - /* cleanup the cap_nodes from profile_get last one has server */ - for (i = 0; i<=links; i++) { - krb5_xfree(cap_nodes[i]); - } - krb5_xfree((char *)cap_nodes); - } else { /* if not cap then use hierarchical method */ - for (prevccp = ccp = client->data; - ccp <= com_cdot; - ccp++) { - if (*ccp != realm_branch_char) - continue; - ++ccp; /* advance past dot */ - tmpcrealm.data = prevccp; - tmpcrealm.length = client->length - - (prevccp - client->data); - tmpsrealm.data = ccp; - tmpsrealm.length = client->length - - (ccp - client->data); - if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, - &rettree[i]))) { - while (i) { - krb5_free_principal(context, rettree[i-1]); - i--; - } - krb5_xfree(rettree); - return retval; - } - prevccp = ccp; - i++; - } - if (nocommon) { - tmpcrealm.data = com_cdot + 1; - tmpcrealm.length = client->length - - (com_cdot + 1 - client->data); - tmpsrealm.data = com_sdot + 1; - tmpsrealm.length = server->length - - (com_sdot + 1 - server->data); - if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, - &rettree[i]))) { - while (i) { - krb5_free_principal(context, rettree[i-1]); - i--; - } - krb5_xfree(rettree); - return retval; - } - i++; + /* Copy server realm "tweens" backward. */ + for (twp = &stweens[nstween]; twp-- > stweens;) { + krb5int_copy_data_contents(context, twp, rp++); + if (retval) goto error; + } +error: + if (retval) { + *nrealms = 0; + while (rp > r) { + krb5_free_data_contents(context, --rp); } + free(r); + r = NULL; + } + free(ctweens); + free(stweens); + *realms = r; + return retval; +} - for (prevscp = com_sdot + 1, scp = com_sdot - 1; - scp > server->data; - scp--) { - if (*scp != realm_branch_char) - continue; - if (scp - 1 < server->data) - break; /* XXX only if . starts realm? */ - tmpcrealm.data = prevscp; - tmpcrealm.length = server->length - - (prevscp - server->data); - tmpsrealm.data = scp + 1; - tmpsrealm.length = server->length - - (scp + 1 - server->data); - if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, - &rettree[i]))) { - while (i) { - krb5_free_principal(context, rettree[i-1]); - i--; - } - krb5_xfree(rettree); - return retval; - } - prevscp = scp + 1; - i++; - } - if (slen && com_sdot >= server->data) { - /* only necessary if building down tree from ancestor or client */ - /* however, we can get here if we have only one component - in the server realm name, hence we make sure we found a component - separator there... */ - tmpcrealm.data = prevscp; - tmpcrealm.length = server->length - - (prevscp - server->data); - if ((retval = krb5_tgtname(context, server, &tmpcrealm, - &rettree[i]))) { - while (i) { - krb5_free_principal(context, rettree[i-1]); - i--; - } - krb5_xfree(rettree); - return retval; - } +/* + * Build a list of realms between a given realm and the common + * suffix. The original realm is included, but the "tail" is only + * included if DOTAIL is true. + * + * Warning: This function intentionally aliases memory. Caller must + * make copies as needed and not call krb5_free_data_contents, etc. + */ +static krb5_error_code +rtree_hier_tweens( + krb5_context context, + struct hstate *realm, + krb5_data **tweens, + size_t *ntweens, + int dotail, + int sep) +{ + char *p, *r, *rtail, *lp; + size_t rlen, n; + krb5_data *tws, *ntws; + + r = realm->str; + rlen = realm->len; + rtail = realm->tail; + *tweens = ntws = tws = NULL; + *ntweens = n = 0; + + for (lp = p = r; p < &r[rlen]; p++) { + if (*p != sep && &p[1] != &r[rlen]) + continue; + if (lp == rtail && !dotail) + break; + ntws = realloc(tws, (n + 1) * sizeof(krb5_data)); + if (ntws == NULL) { + free(tws); + return ENOMEM; } + tws = ntws; + tws[n].data = lp; + tws[n].length = &r[rlen] - lp; + n++; + if (lp == rtail) + break; + lp = &p[1]; } - *tree = rettree; - -#ifdef DEBUG_REFERRALS - printf("krb5_walk_realm_tree ending; tree (length %d) is:\n",links); - for(i=0;ilength;n++) - printf("%s<%.*s>",(n>0)?"/":"",p->data[n].length,p->data[n].data); - printf("@<%.*s> (length %d, type %d)\n",p->realm.length,p->realm.data, - p->length, p->type); + int cfull, sfull; + char *cp, *sp; + + cp = c->tail; + sp = s->tail; + if (cp == NULL || sp == NULL) + return; + /* + * Is it a full component? Yes, if it's the beginning of the + * string or there's a separator to the left. + * + * The index of -1 is valid because it only gets evaluated if the + * pointer is not at the beginning of the string. + */ + cfull = (cp == c->str || cp[-1] == sep); + sfull = (sp == s->str || sp[-1] == sep); + /* + * If they're both full components, we're done. + */ + if (cfull && sfull) { + return; + } else if (c->dot != NULL && s->dot != NULL) { + cp = c->dot + 1; + sp = s->dot + 1; + /* + * Out of bounds? Can only happen if there are trailing dots. + */ + if (cp >= &c->str[c->len] || sp >= &s->str[s->len]) { + cp = sp = NULL; + } + } else { + cp = sp = NULL; + } + c->tail = cp; + s->tail = sp; +} + +/* + * Find common suffix of C and S. + * + * C->TAIL and S->TAIL will point to the respective suffixes. C->DOT + * and S->DOT will point to the nearest instances of SEP to the right + * of the start of each suffix. Caller must initialize TAIL and DOT + * pointers to null. + */ +static void +comtail(struct hstate *c, struct hstate *s, int sep) +{ + char *cp, *sp, *cdot, *sdot; + + if (c->len == 0 || s->len == 0) + return; + + cdot = sdot = NULL; + /* + * ANSI/ISO C allows a pointer one past the end but not one + * before the beginning of an array. + */ + cp = &c->str[c->len]; + sp = &s->str[s->len]; + /* + * Set CP and SP to point to the common suffix of each string. + * When we run into separators (dots, unless someone has a X.500 + * style realm), keep pointers to the latest pair. + */ + while (cp > c->str && sp > s->str) { + if (*--cp != *--sp) { + /* + * Didn't match, so most recent match is one byte to the + * right (or not at all). + */ + cp++; + sp++; + break; + } + /* + * Keep track of matching dots. + */ + if (*cp == sep) { + cdot = cp; + sdot = sp; + } + } + /* No match found at all. */ + if (cp == &c->str[c->len]) + return; + c->tail = cp; + s->tail = sp; + c->dot = cdot; + s->dot = sdot; } -#endif diff --git a/src/lib/krb5/krb/walktree-tests b/src/lib/krb5/krb/walktree-tests index 99561c547..17f6eae11 100644 --- a/src/lib/krb5/krb/walktree-tests +++ b/src/lib/krb5/krb/walktree-tests @@ -68,4 +68,12 @@ eval $check set A.EXAMPLE.COM EXAMPLE.COM "A.EXAMPLE.COM@A.EXAMPLE.COM EXAMPLE.COM@A.EXAMPLE.COM" eval $check +echo CAPATH test +set ATHENA.MIT.EDU KERBEROS.COM "ATHENA.MIT.EDU@ATHENA.MIT.EDU KERBEROS.COM@ATHENA.MIT.EDU" +eval $check + +echo CAPATH test +set LCS.MIT.EDU KABLOOEY.KERBEROS.COM "LCS.MIT.EDU@LCS.MIT.EDU ATHENA.MIT.EDU@LCS.MIT.EDU KERBEROS.COM@ATHENA.MIT.EDU KABLOOEY.KERBEROS.COM@KERBEROS.COM" +eval $check + exit $err -- 2.26.2