4 * Copyright 1990,1991,2008 by the Massachusetts Institute of Technology.
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.
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.
27 * krb5_parse_name() routine.
29 * Rewritten by Theodore Ts'o to properly handle arbitrary quoted
30 * characters in the principal name.
37 * converts a single-string representation of the name to the
38 * multi-part principal format used in the protocols.
40 * principal will point to allocated storage which should be freed by
41 * the caller (using krb5_free_principal) after use.
43 * Conventions: / is used to separate components. If @ is present in the
44 * string, then the rest of the string after it represents the realm name.
45 * Otherwise the local realm name is used.
48 * KRB5_PARSE_MALFORMED badly formatted string
50 * also returns system errors:
51 * ENOMEM malloc failed/out of memory
53 * get_default_realm() is called; it may return other errors.
57 #define COMPONENT_SEP '/'
58 #define QUOTECHAR '\\'
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.....
66 static krb5_error_code
67 k5_parse_name(krb5_context context, const char *name,
68 int flags, krb5_principal *nprincipal)
70 register const char *cp;
72 register int i,c,size;
74 const char *parsed_realm = NULL;
75 int fcompsize[FCOMPNUM];
76 unsigned int realmsize = 0;
77 char *default_realm = NULL;
78 int default_realm_size = 0;
80 krb5_principal principal;
81 krb5_error_code retval;
82 unsigned int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE);
88 * Pass 1. Find out how many components there are to the name,
89 * and get string sizes for the first FCOMPNUM components. For
90 * enterprise principal names (UPNs), there is only a single
94 for (i=0,cp = name, first_at = 1; (c = *cp); cp++) {
99 * QUOTECHAR can't be at the last
100 * character of the name!
102 return(KRB5_PARSE_MALFORMED);
105 } else if (c == COMPONENT_SEP && !enterprise) {
108 * Shouldn't see a component separator
109 * after we've parsed out the realm name!
111 return(KRB5_PARSE_MALFORMED);
117 } else if (c == REALM_SEP && (!enterprise || !first_at)) {
120 * Multiple realm separaters
121 * not allowed; zero-length realms are.
123 return(KRB5_PARSE_MALFORMED);
124 parsed_realm = cp + 1;
130 if (c == REALM_SEP && enterprise && first_at)
136 if (parsed_realm != NULL)
138 else if (i < FCOMPNUM)
142 * Now, we allocate the principal structure and all of its
145 principal = (krb5_principal)malloc(sizeof(krb5_principal_data));
146 if (principal == NULL) {
149 principal->data = (krb5_data *) malloc(sizeof(krb5_data) * components);
150 if (principal->data == NULL) {
154 principal->length = components;
157 * If a realm was not found, then use the default realm, unless
158 * KRB5_PRINCIPAL_PARSE_NO_REALM was specified in which case the
159 * realm will be empty.
162 if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) {
163 krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
164 "Principal %s is missing required realm", name);
165 free(principal->data);
167 return KRB5_PARSE_MALFORMED;
169 if (!default_realm && (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) == 0) {
170 retval = krb5_get_default_realm(context, &default_realm);
172 free(principal->data);
176 default_realm_size = strlen(default_realm);
178 realmsize = default_realm_size;
179 } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
180 krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
181 "Principal %s has realm present", name);
182 free(principal->data);
184 return KRB5_PARSE_MALFORMED;
188 * Pass 2. Happens only if there were more than FCOMPNUM
189 * component; if this happens, someone should be shot
190 * immediately. Nevertheless, we will attempt to handle said
191 * case..... <martyred sigh>
193 if (components >= FCOMPNUM) {
196 for (i=0,cp = name; (c = *cp); cp++) {
197 if (c == QUOTECHAR) {
200 } else if (c == COMPONENT_SEP) {
201 if (krb5_princ_size(context, principal) > i)
202 krb5_princ_component(context, principal, i)->length = size;
205 } else if (c == REALM_SEP) {
206 if (krb5_princ_size(context, principal) > i)
207 krb5_princ_component(context, principal, i)->length = size;
214 krb5_princ_realm(context, principal)->length = size;
216 if (krb5_princ_size(context, principal) > i)
217 krb5_princ_component(context, principal, i)->length = size;
218 if (i + 1 != components) {
221 "Programming error in krb5_parse_name!");
223 assert(i + 1 == components);
228 * If there were fewer than FCOMPSIZE components (the
229 * usual case), then just copy the sizes to the
230 * principal structure
232 for (i=0; i < components; i++)
233 krb5_princ_component(context, principal, i)->length = fcompsize[i];
236 * Now, we need to allocate the space for the strings themselves.....
238 tmpdata = malloc(realmsize + 1);
240 free(principal->data);
245 krb5_princ_set_realm_length(context, principal, realmsize);
246 krb5_princ_set_realm_data(context, principal, tmpdata);
247 for (i=0; i < components; i++) {
249 malloc(krb5_princ_component(context, principal, i)->length + 1);
250 if (tmpdata2 == NULL) {
251 for (i--; i >= 0; i--)
252 free(krb5_princ_component(context, principal, i)->data);
253 free(krb5_princ_realm(context, principal)->data);
254 free(principal->data);
259 krb5_princ_component(context, principal, i)->data = tmpdata2;
260 krb5_princ_component(context, principal, i)->magic = KV5M_DATA;
264 * Pass 3. Now we go through the string a *third* time, this
265 * time filling in the krb5_principal structure which we just
268 q = krb5_princ_component(context, principal, 0)->data;
269 for (i=0,cp = name, first_at = 1; (c = *cp); cp++) {
270 if (c == QUOTECHAR) {
289 } else if (c == COMPONENT_SEP && !enterprise) {
292 q = krb5_princ_component(context, principal, i)->data;
293 } else if (c == REALM_SEP && (!enterprise || !first_at)) {
296 q = krb5_princ_realm(context, principal)->data;
298 if (c == REALM_SEP && enterprise && first_at)
306 if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM)
307 (krb5_princ_realm(context, principal)->data)[0] = '\0';
309 strlcpy(krb5_princ_realm(context, principal)->data, default_realm, realmsize+1);
312 * Alright, we're done. Now stuff a pointer to this monstrosity
313 * into the return variable, and let's get out of here.
316 krb5_princ_type(context, principal) = KRB5_NT_ENTERPRISE_PRINCIPAL;
318 krb5_princ_type(context, principal) = KRB5_NT_PRINCIPAL;
319 principal->magic = KV5M_PRINCIPAL;
320 principal->realm.magic = KV5M_DATA;
321 *nprincipal = principal;
323 if (default_realm != NULL)
329 krb5_error_code KRB5_CALLCONV
330 krb5_parse_name(krb5_context context, const char *name, krb5_principal *nprincipal)
332 return k5_parse_name(context, name, 0, nprincipal);
335 krb5_error_code KRB5_CALLCONV
336 krb5_parse_name_flags(krb5_context context, const char *name,
337 int flags, krb5_principal *nprincipal)
339 return k5_parse_name(context, name, flags, nprincipal);