aboutsummaryrefslogtreecommitdiff
path: root/src/lib/krb5
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/krb5')
-rw-r--r--src/lib/krb5/krb/parse.c310
-rw-r--r--src/lib/krb5/krb/unparse.c153
2 files changed, 315 insertions, 148 deletions
diff --git a/src/lib/krb5/krb/parse.c b/src/lib/krb5/krb/parse.c
index c647e1f..de25f2e 100644
--- a/src/lib/krb5/krb/parse.c
+++ b/src/lib/krb5/krb/parse.c
@@ -8,6 +8,9 @@
* <krb5/copyright.h>.
*
* 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 <krb5/libos-proto.h>
/*
- 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..... <martyred sigh>
+ */
+ 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 36fd9c2..d16a2c5 100644
--- a/src/lib/krb5/krb/unparse.c
+++ b/src/lib/krb5/krb/unparse.c
@@ -8,6 +8,10 @@
* <krb5/copyright.h>.
*
* 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 <stdio.h>
#include <krb5/copyright.h>
-
#include <krb5/krb5.h>
#include <krb5/ext-proto.h>
/*
- 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));
+}
+
+