From bda7aac0a05d43e53de0dbede6b6b54a2e578ad9 Mon Sep 17 00:00:00 2001 From: Theodore Tso Date: Mon, 15 Oct 1990 16:57:46 +0000 Subject: [PATCH] Rewritten to allow for principals with components that contain component or realm separators. This is down by supporting backquoting. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@1253 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb5/krb/parse.c | 310 +++++++++++++++++++++++++------------ src/lib/krb5/krb/unparse.c | 153 ++++++++++++------ 2 files changed, 315 insertions(+), 148 deletions(-) diff --git a/src/lib/krb5/krb/parse.c b/src/lib/krb5/krb/parse.c index c647e1f9d..de25f2e09 100644 --- a/src/lib/krb5/krb/parse.c +++ b/src/lib/krb5/krb/parse.c @@ -8,6 +8,9 @@ * . * * krb5_parse_name() routine. + * + * Rewritten by Theodore Ts'o to properly handle arbitrary quoted + * characters in the principal name. */ #if !defined(lint) && !defined(SABER) @@ -22,122 +25,223 @@ static char rcsid_parse_c [] = #include /* - converts a single-string representation of the name to the multi-part - principal format used in the protocols. - - *principal will point to allocated storage which should be freed by - the caller (using krb5_free_principal) after use. - - Conventions: / is used to separate components. If @ is present in the - string, then the rest of the string after it represents the realm name. - Otherwise the local realm name is used. - - returns system errors XXX + * converts a single-string representation of the name to the + * multi-part principal format used in the protocols. + * + * principal will point to allocated storage which should be freed by + * the caller (using krb5_free_principal) after use. + * + * Conventions: / is used to separate components. If @ is present in the + * string, then the rest of the string after it represents the realm name. + * Otherwise the local realm name is used. + * + * returns system errors XXX */ #define REALM_SEP '@' #define COMPONENT_SEP '/' +#define QUOTECHAR '\\' #define MAXRLMSZ 256 /* XXX! */ +#define FCOMPNUM 2 -static char * -strsave(string) -const char *string; -{ - register char *cp; - cp = malloc(strlen(string)+1); - if (cp) - (void) strcpy(cp, string); - return(cp); -} +/* + * May the fleas of a thousand camels infest the ISO, they who think + * that arbitrarily large multi-component names are a Good Thing..... + */ krb5_error_code -krb5_parse_name(name, principal) -const register char *name; -krb5_principal *principal; +krb5_parse_name(name, nprincipal) + const char *name; + krb5_principal *nprincipal; { - const register char *realmptr, *cp, *endcomponent; - register char *realmname; - krb5_principal retprinc; - int ncomponents; - register int i; - krb5_error_code retval; - - realmptr = index(name, REALM_SEP); - if (realmptr) - realmname = strsave(realmptr+1); - else { - realmptr = name + strlen(name); - realmname = malloc(MAXRLMSZ); - if (!realmname) - return(ENOMEM); - if (retval = krb5_get_default_realm(MAXRLMSZ, realmname)) { - xfree(realmname); - return(retval); + register const char *cp; + register char *q; + register i,c,size; + int components = 0; + const char *parsed_realm = NULL; + int fcompsize[FCOMPNUM]; + char default_realm[512]; + krb5_data **principal; + krb5_error_code retval; + + /* + * Pass 1. Find out how many components there are to the name, + * and get string sizes for the first FCOMPNUM components. + */ + size = 0; + for (i=1,cp = name; c = *cp; cp++) { + if (c == QUOTECHAR) { + cp++; + if (!(c = *cp)) + /* + * QUOTECHAR can't be at the last + * character of the name! + */ + return(KRB5_PARSE_MALFORMED); + size++; + continue; + } else if (c == COMPONENT_SEP) { + if (parsed_realm) + /* + * Shouldn't see a component separator + * after we've parsed out the realm name! + */ + return(KRB5_PARSE_MALFORMED); + if (i < FCOMPNUM) { + fcompsize[i] = size; + } + size = 0; + i++; + } else if (c == REALM_SEP) { + if (!*(cp+1)) + /* + * Null Realm names are not allowed! + */ + return(KRB5_PARSE_MALFORMED); + parsed_realm = cp+1; + if (i < FCOMPNUM) { + fcompsize[i] = size; + } + size = 0; + } else + size++; } - } - - /* count components, but only up to 1st @ */ - for (ncomponents = 1, cp = name; - cp < realmptr && (cp = index(cp, COMPONENT_SEP)) && cp < realmptr; - ncomponents++, cp++); - - /* +1 for realm, +1 for null pointer at end */ - retprinc = (krb5_data **) calloc(ncomponents+2, sizeof(krb5_data *)); - if (!retprinc) { - xfree(realmname); - return(ENOMEM); - } - retprinc[ncomponents+1] = 0; - for (i = 0; i <= ncomponents; i++) { - if (!(retprinc[i] = (krb5_data *) malloc(sizeof(krb5_data)))) { - for (i--; i >= 0; i--) - xfree(retprinc[i]); - xfree(retprinc); - xfree(realmname); - return(ENOMEM); + if (parsed_realm) + fcompsize[0] = size; + else if (i < FCOMPNUM) + fcompsize[i] = size; + components = i; + /* + * Now, we allocate the principal structure and all of its + * component pieces + */ + principal = (krb5_principal) + malloc(sizeof(krb5_data *) * (components+2)); + if (!principal) { + return(ENOMEM); } - } - retprinc[0]->length = strlen(realmname); - retprinc[0]->data = realmname; - - /* cp points to the beginning of the current component, - endcomponent points to the end of the current component divider or - is beyond the realm divider, or is null (no more component - dividers). - */ - - /* XXX this is broken */ - for (ncomponents = 1, cp = name, - endcomponent = index(name, COMPONENT_SEP); - cp && cp <= realmptr; - ncomponents++) { - - if (endcomponent && endcomponent < realmptr) { - retprinc[ncomponents]->length = endcomponent - cp; + for (i = 0; i <= components; i++) { + if (!(principal[i] = + (krb5_data *) malloc(sizeof(krb5_data)))) { + for (i--; i >= 0; i--) + xfree(principal[i]); + xfree(principal); + return (ENOMEM); + } + } + principal[components+1] = NULL; + /* + * If a realm was not found, then we need to find the defualt + * realm.... + */ + if (!parsed_realm) { + retval = krb5_get_default_realm(sizeof(default_realm), + default_realm); + if (retval) + return(retval); + principal[0]->length = fcompsize[0] = strlen(default_realm); + } + /* + * Pass 2. Happens only if there were more than FCOMPNUM + * component; if this happens, someone should be shot + * immediately. Nevertheless, we will attempt to handle said + * case..... + */ + if (components >= FCOMPNUM) { + size = 0; + parsed_realm = NULL; + for (i=1,cp = name; c = *cp; cp++) { + if (c == QUOTECHAR) { + cp++; + size++; + } else if (c == COMPONENT_SEP) { + principal[i]->length = size; + size = 0; + i++; + } else if (c == REALM_SEP) { + principal[i]->length = size; + size = 0; + parsed_realm = cp+1; + } else + size++; + } + if (parsed_realm) + principal[0]->length = size; + else + principal[i]->length = size; + if (i != components) { + fprintf(stderr, + "Programming error in krb5_parse_name!"); + exit(1); + } } else { - retprinc[ncomponents]->length = realmptr - cp; + /* + * If there were fewer than FCOMPSIZE components (the + * usual case), then just copy the sizes to the + * principal structure + */ + for (i=0; i <= components; i++) + principal[i]->length = fcompsize[i]; + } + /* + * Now, we need to allocate the space for the strings themselves..... + */ + for (i=0; i <= components; i++) { + if (!(principal[i]->data = malloc(principal[i]->length + 1))) { + for (i--; i >= 0; i--) + xfree(principal[i]->data); + for (i=0; i <= components; i++) + xfree(principal[i]); + xfree(principal); + return(ENOMEM); + } } - if (!(retprinc[ncomponents]->data = - malloc(retprinc[ncomponents]->length+1))) { - /* ut oh...clean up */ - xfree(retprinc[ncomponents]); - for (ncomponents--; ncomponents >= 0; ncomponents--) { - xfree(retprinc[ncomponents]->data); - xfree(retprinc[ncomponents]); - } - xfree(retprinc); - return(ENOMEM); + + /* + * Pass 3. Now we go through the string a *third* time, this + * time filling in the krb5_principal structure which we just + * allocated. + */ + q = principal[1]->data; + for (i=1,cp = name; c = *cp; cp++) { + if (c == QUOTECHAR) { + cp++; + switch (c = *cp) { + case 'n': + *q++ = '\n'; + break; + case 't': + *q++ = '\t'; + break; + case 'b': + *q++ = '\b'; + break; + case '0': + *q++ = '\0'; + break; + default: + *q++ = c; + } + } else if ((c == COMPONENT_SEP) || (c == REALM_SEP)) { + i++; + *q++ = '\0'; + if (c == COMPONENT_SEP) + q = principal[i]->data; + else + q = principal[0]->data; + } else + *q++ = c; } - strncpy(retprinc[ncomponents]->data, cp, - retprinc[ncomponents]->length); - retprinc[ncomponents]->data[retprinc[ncomponents]->length] = '\0'; - if (endcomponent) { - cp = endcomponent + 1; /* move past divider */ - endcomponent = index(cp, COMPONENT_SEP); - } else - cp = 0; - } - *principal = retprinc; - return 0; + *q++ = '\0'; + if (!parsed_realm) + strcpy(principal[0]->data, default_realm); + /* + * Alright, we're done. Now stuff a pointer to this monstrosity + * into the return variable, and let's get out of here. + */ + *nprincipal = principal; + return(0); } + + diff --git a/src/lib/krb5/krb/unparse.c b/src/lib/krb5/krb/unparse.c index 36fd9c2d0..d16a2c52b 100644 --- a/src/lib/krb5/krb/unparse.c +++ b/src/lib/krb5/krb/unparse.c @@ -8,6 +8,10 @@ * . * * krb5_unparse_name() routine + * + * Rewritten by Theodore Ts'o to propoerly unparse principal names + * which have the component or realm separator as part of one of their + * components. */ #if !defined(lint) && !defined(SABER) @@ -15,68 +19,127 @@ static char rcsid_unparse_c[] = "$Id$"; #endif /* !lint & !SABER */ +#include #include - #include #include /* - converts the multi-part - principal format used in the protocols to a single-string representation - of the name. - - the name returned is in allocated storage and should be freed by the caller - when finished. - - Conventions: / is used to separate components; @ is used to separate - the realm from the rest of the name. If any component besides the realm has - a / or @ in it, an error is returned. - - returns system errors XXX + * converts the multi-part principal format used in the protocols to a + * single-string representation of the name. + * + * The name returned is in allocated storage and should be freed by + * the caller when finished. + * + * Conventions: / is used to separate components; @ is used to + * separate the realm from the rest of the name. If '/', '@', or '\0' + * appear in any the component, they will be representing using + * backslash encoding. ("\/", "\@", or '\0', respectively) + * + * returns system errors XXX */ #define REALM_SEP '@' #define COMPONENT_SEP '/' -#define REALM_SEP_STRING "@" -#define COMPONENT_SEP_STRING "/" krb5_error_code -krb5_unparse_name(principal, name) +krb5_unparse_name_ext(principal, name, size) const krb5_principal principal; register char **name; +int *size; { - register char *cp; - register int i; - int totalsize = 0; - - if (!principal[0] || !principal[1]) - return KRB5_PARSE_MALFORMED; - /* check for invalid elements of components; don't need to check - realm, which is first component */ - for (i = 1; principal[i]; i++) { - for (cp = principal[i]->data; - cp < principal[i]->data + principal[i]->length; cp++) - if (*cp == REALM_SEP || *cp == COMPONENT_SEP) - return KRB5_PARSE_ILLCHAR; - totalsize += principal[i]->length + 1; /* + 1 for separator */ - } - totalsize += principal[0]->length; /* no +1 since we need only n-1 seps - for n components */ - - *name = malloc(totalsize+1); /* room for null */ - if (!*name) - return ENOMEM; + register char *cp, *q; + register int i,j; + register int totalsize = 0; + int length; - (void) bzero(*name, totalsize+1); + if (!principal[0] || !principal[1]) + return KRB5_PARSE_MALFORMED; + for (i = 0; principal[i]; i++) { + cp = principal[i]->data; + length = principal[i]->length; + for (j=0; j < length; j++,cp++) + if (*cp == REALM_SEP || *cp == COMPONENT_SEP || + *cp == '\0' || *cp == '\\' || *cp == '\t') + totalsize += 2; + else + totalsize++; + totalsize++; /* This is for the separator */ + } - for (i = 1; principal[i]; i++) { - strncat(*name, principal[i]->data, principal[i]->length); - if (principal[i+1]) /* don't append sep to last elt */ - strcat(*name, COMPONENT_SEP_STRING); - } + /* + * we need only n-1 seps for n components, but we need an + * extra byte for the NULL at the end + */ + if (*name) { + if (*size < (totalsize)) { + *size = totalsize; + *name = realloc(*name, totalsize); + } + } else { + *name = malloc(totalsize); /* room for null */ + *size = totalsize; + } + + if (!*name) + return ENOMEM; - strcat(*name, REALM_SEP_STRING); - strncat(*name, principal[0]->data, principal[0]->length); + q = *name; + + for (i = 1; principal[i]; i++) { + cp = principal[i]->data; + length = principal[i]->length; + for (j=0; j < length; j++,cp++) { + switch (*cp) { + case COMPONENT_SEP: + case REALM_SEP: + case '\t': + case '\\': + *q++ = '\\'; + *q++ = *cp; + break; + case '\0': + *q++ = '\\'; + *q++ = '0'; + break; + default: + *q++ = *cp; + } + } + *q++ = COMPONENT_SEP; + } + q--; /* Back up last component separator */ + *q++ = REALM_SEP; + + cp = principal[0]->data; + length = principal[0]->length; + for (j=0; j < length; j++,cp++) { + switch (*cp) { + case COMPONENT_SEP: + case REALM_SEP: + *q++ = '\\'; + *q++ = *cp; + break; + case '\0': + *q++ = '\\'; + *q++ = '0'; + break; + default: + *q++ = *cp; + } + } + *q++ = '\0'; + return 0; } + +krb5_error_code +krb5_unparse_name(principal, name) +const krb5_principal principal; +register char **name; +{ + return(krb5_unparse_name_ext(principal, name, NULL)); +} + + -- 2.26.2