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