This commit was manufactured by cvs2svn to create tag
[krb5.git] / src / lib / krb5 / krb / parse.c
1 /*
2  * lib/krb5/krb/parse.c
3  *
4  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  * 
26  *
27  * krb5_parse_name() routine.
28  *
29  * Rewritten by Theodore Ts'o to properly handle arbitrary quoted
30  * characters in the principal name.
31  */
32
33 #include "k5-int.h"
34
35 /*
36  * converts a single-string representation of the name to the
37  * multi-part principal format used in the protocols.
38  *
39  * principal will point to allocated storage which should be freed by 
40  * the caller (using krb5_free_principal) after use.
41  * 
42  * Conventions:  / is used to separate components.  If @ is present in the
43  * string, then the rest of the string after it represents the realm name.
44  * Otherwise the local realm name is used.
45  * 
46  * error return:
47  *      KRB5_PARSE_MALFORMED    badly formatted string
48  *
49  * also returns system errors:
50  *      ENOMEM  malloc failed/out of memory
51  *
52  * get_default_realm() is called; it may return other errors.
53  */
54
55 #define REALM_SEP       '@'
56 #define COMPONENT_SEP   '/'
57 #define QUOTECHAR       '\\'
58
59 #define FCOMPNUM        10
60
61
62 /*
63  * May the fleas of a thousand camels infest the ISO, they who think
64  * that arbitrarily large multi-component names are a Good Thing.....
65  */
66 krb5_error_code KRB5_CALLCONV
67 krb5_parse_name(krb5_context context, const char *name, krb5_principal *nprincipal)
68 {
69         register const char     *cp;
70         register char   *q;
71         register int    i,c,size;
72         int             components = 0;
73         const char      *parsed_realm = NULL;
74         int             fcompsize[FCOMPNUM];
75         unsigned int    realmsize = 0;
76         static char     *default_realm = NULL;
77         static int      default_realm_size = 0;
78         char            *tmpdata;
79         krb5_principal  principal;
80         krb5_error_code retval;
81         
82         /*
83          * Pass 1.  Find out how many components there are to the name,
84          * and get string sizes for the first FCOMPNUM components.
85          */
86         size = 0;
87         for (i=0,cp = name; (c = *cp); cp++) {
88                 if (c == QUOTECHAR) {
89                         cp++;
90                         if (!(c = *cp))
91                                 /*
92                                  * QUOTECHAR can't be at the last
93                                  * character of the name!
94                                  */
95                                 return(KRB5_PARSE_MALFORMED);
96                         size++;
97                         continue;
98                 } else if (c == COMPONENT_SEP) {
99                         if (parsed_realm)
100                                 /*
101                                  * Shouldn't see a component separator
102                                  * after we've parsed out the realm name!
103                                  */
104                                 return(KRB5_PARSE_MALFORMED);
105                         if (i < FCOMPNUM) {
106                                 fcompsize[i] = size;
107                         }
108                         size = 0;
109                         i++;
110                 } else if (c == REALM_SEP) {
111                         if (parsed_realm || !*(cp+1)) 
112                                 /*
113                                  * Multiple realm separaters or null
114                                  * realm names are not allowed!
115                                  */
116                                 return(KRB5_PARSE_MALFORMED);
117                         parsed_realm = cp+1;
118                         if (i < FCOMPNUM) {
119                                 fcompsize[i] = size;
120                         }
121                         size = 0;
122                 } else
123                         size++;
124         }
125         if (parsed_realm)
126                 realmsize = size;
127         else if (i < FCOMPNUM) 
128                 fcompsize[i] = size;
129         components = i + 1;
130         /*
131          * Now, we allocate the principal structure and all of its
132          * component pieces
133          */
134         principal = (krb5_principal)malloc(sizeof(krb5_principal_data));
135         if (!principal) {
136                 return(ENOMEM);
137         }
138         principal->data = (krb5_data *) malloc(sizeof(krb5_data) * components);
139         if (!principal->data) {
140             free((char *)principal);
141             return ENOMEM;
142         }
143         principal->length = components;
144         /*
145          * If a realm was not found, then use the defualt realm....
146          */
147         if (!parsed_realm) {
148             if (!default_realm) {
149                 retval = krb5_get_default_realm(context, &default_realm);
150                 if (retval) {
151                     krb5_xfree(principal->data);
152                     krb5_xfree((char *)principal);
153                     return(retval);
154                 }
155                 default_realm_size = strlen(default_realm);
156             }
157             realmsize = default_realm_size;
158         }
159         /*
160          * Pass 2.  Happens only if there were more than FCOMPNUM
161          * component; if this happens, someone should be shot
162          * immediately.  Nevertheless, we will attempt to handle said
163          * case..... <martyred sigh>
164          */
165         if (components >= FCOMPNUM) {
166                 size = 0;
167                 parsed_realm = NULL;
168                 for (i=0,cp = name; (c = *cp); cp++) {
169                         if (c == QUOTECHAR) {
170                                 cp++;
171                                 size++;
172                         } else if (c == COMPONENT_SEP) {
173                                 if (krb5_princ_size(context, principal) > i)
174                                         krb5_princ_component(context, principal, i)->length = size;
175                                 size = 0;
176                                 i++;
177                         } else if (c == REALM_SEP) {
178                                 if (krb5_princ_size(context, principal) > i)
179                                         krb5_princ_component(context, principal, i)->length = size;
180                                 size = 0;
181                                 parsed_realm = cp+1;
182                         } else
183                                 size++;
184                 }
185                 if (parsed_realm)
186                         krb5_princ_realm(context, principal)->length = size;
187                 else
188                         if (krb5_princ_size(context, principal) > i)
189                                 krb5_princ_component(context, principal, i)->length = size;
190                 if (i + 1 != components) {
191 #if !defined(_WIN32) && !defined(macintosh)
192                         fprintf(stderr,
193                                 "Programming error in krb5_parse_name!");
194                         exit(1);
195 #else
196          /* Need to come up with windows error handling mechanism */
197 #endif
198                 }
199         } else {
200                 /*
201                  * If there were fewer than FCOMPSIZE components (the
202                  * usual case), then just copy the sizes to the
203                  * principal structure
204                  */
205                 for (i=0; i < components; i++)
206                         krb5_princ_component(context, principal, i)->length = fcompsize[i];
207         }
208         /*      
209          * Now, we need to allocate the space for the strings themselves.....
210          */
211         tmpdata = malloc(realmsize+1);
212         if (tmpdata == 0) {
213                 krb5_xfree(principal->data);
214                 krb5_xfree(principal);
215                 return ENOMEM;
216         }
217         krb5_princ_set_realm_length(context, principal, realmsize);
218         krb5_princ_set_realm_data(context, principal, tmpdata);
219         for (i=0; i < components; i++) {
220                 char *tmpdata2 =
221                   malloc(krb5_princ_component(context, principal, i)->length + 1);
222                 if (!tmpdata2) {
223                         for (i--; i >= 0; i--)
224                                 krb5_xfree(krb5_princ_component(context, principal, i)->data);
225                         krb5_xfree(krb5_princ_realm(context, principal)->data);
226                         krb5_xfree(principal->data);
227                         krb5_xfree(principal);
228                         return(ENOMEM);
229                 }
230                 krb5_princ_component(context, principal, i)->data = tmpdata2;
231                 krb5_princ_component(context, principal, i)->magic = KV5M_DATA;
232         }
233         
234         /*
235          * Pass 3.  Now we go through the string a *third* time, this
236          * time filling in the krb5_principal structure which we just
237          * allocated.
238          */
239         q = krb5_princ_component(context, principal, 0)->data;
240         for (i=0,cp = name; (c = *cp); cp++) {
241                 if (c == QUOTECHAR) {
242                         cp++;
243                         switch (c = *cp) {
244                         case 'n':
245                                 *q++ = '\n';
246                                 break;
247                         case 't':
248                                 *q++ = '\t';
249                                 break;
250                         case 'b':
251                                 *q++ = '\b';
252                                 break;
253                         case '0':
254                                 *q++ = '\0';
255                                 break;
256                         default:
257                                 *q++ = c;
258                         }
259                 } else if ((c == COMPONENT_SEP) || (c == REALM_SEP)) {
260                         i++;
261                         *q++ = '\0';
262                         if (c == COMPONENT_SEP) 
263                                 q = krb5_princ_component(context, principal, i)->data;
264                         else
265                                 q = krb5_princ_realm(context, principal)->data;
266                 } else
267                         *q++ = c;
268         }
269         *q++ = '\0';
270         if (!parsed_realm)
271                 strcpy(krb5_princ_realm(context, principal)->data, default_realm);
272         /*
273          * Alright, we're done.  Now stuff a pointer to this monstrosity
274          * into the return variable, and let's get out of here.
275          */
276         krb5_princ_type(context, principal) = KRB5_NT_PRINCIPAL;
277         principal->magic = KV5M_PRINCIPAL;
278         principal->realm.magic = KV5M_DATA;
279         *nprincipal = principal;
280         return(0);
281 }
282
283