Rewritten to allow for principals with components that contain component
authorTheodore Tso <tytso@mit.edu>
Mon, 15 Oct 1990 16:57:46 +0000 (16:57 +0000)
committerTheodore Tso <tytso@mit.edu>
Mon, 15 Oct 1990 16:57:46 +0000 (16:57 +0000)
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
src/lib/krb5/krb/unparse.c

index c647e1f9de0e51c410034ea586980fe1debcf745..de25f2e0989604127d53a2dade73f2fd64137bd5 100644 (file)
@@ -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);
 }
+
+
index 36fd9c2d01201442ba8312f4679ae0266d26a814..d16a2c52bacc5f1c0d6ba6882b6e4008c9d9cd64 100644 (file)
@@ -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));
+}
+
+