/* Replaces krb5_build_principal_ext(), with varargs length == 2 (svc, host), ** because I dont't know how to stub varargs. ** Returns krb5_error_code == ENOMEM on alloc error, otherwise ** passes back newly constructed principal, which should be freed by caller. */ krb5_error_code kssl_build_principal_2( /* UPDATE */ krb5_context context, /* OUT */ krb5_principal *princ, /* IN */ int rlen, const char *realm, /* IN */ int slen, const char *svc, /* IN */ int hlen, const char *host) { krb5_data *p_data = NULL; krb5_principal new_p = NULL; char *new_r = NULL; if ((p_data = (krb5_data *)calloc(2, sizeof(krb5_data))) == NULL || (new_p = (krb5_principal)calloc(1, sizeof(krb5_principal_data))) == NULL) goto err; new_p->length = 2; new_p->data = p_data; if ((new_r = calloc(1, rlen + 1)) == NULL) goto err; memcpy(new_r, realm, rlen); krb5_princ_set_realm_length(context, new_p, rlen); krb5_princ_set_realm_data(context, new_p, new_r); if ((new_p->data[0].data = calloc(1, slen + 1)) == NULL) goto err; memcpy(new_p->data[0].data, svc, slen); new_p->data[0].length = slen; if ((new_p->data[1].data = calloc(1, hlen + 1)) == NULL) goto err; memcpy(new_p->data[1].data, host, hlen); new_p->data[1].length = hlen; krb5_princ_type(context, new_p) = KRB5_NT_UNKNOWN; *princ = new_p; return 0; err: if (new_p && new_p[0].data) free(new_p[0].data); if (new_p && new_p[1].data) free(new_p[1].data); if (new_p) free(new_p); if (new_r) free(new_r); return ENOMEM; }
/* * May the fleas of a thousand camels infest the ISO, they who think * that arbitrarily large multi-component names are a Good Thing..... */ static krb5_error_code k5_parse_name(krb5_context context, const char *name, int flags, krb5_principal *nprincipal) { register const char *cp; register char *q; register int i,c,size; int components = 0; const char *parsed_realm = NULL; int fcompsize[FCOMPNUM]; unsigned int realmsize = 0; char *default_realm = NULL; int default_realm_size = 0; char *tmpdata; krb5_principal principal; krb5_error_code retval; unsigned int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE); int first_at; /* * Pass 1. Find out how many components there are to the name, * and get string sizes for the first FCOMPNUM components. For * enterprise principal names (UPNs), there is only a single * component. */ size = 0; for (i=0,cp = name, first_at = 1; (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 && !enterprise) { 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 && (!enterprise || !first_at)) { if (parsed_realm) /* * Multiple realm separaters * not allowed; zero-length realms are. */ return(KRB5_PARSE_MALFORMED); parsed_realm = cp + 1; if (i < FCOMPNUM) { fcompsize[i] = size; } size = 0; } else { if (c == REALM_SEP && enterprise && first_at) first_at = 0; size++; } } if (parsed_realm != NULL) realmsize = size; else if (i < FCOMPNUM) fcompsize[i] = size; components = i + 1; /* * Now, we allocate the principal structure and all of its * component pieces */ principal = (krb5_principal)malloc(sizeof(krb5_principal_data)); if (principal == NULL) { return(ENOMEM); } principal->data = (krb5_data *) malloc(sizeof(krb5_data) * components); if (principal->data == NULL) { krb5_xfree((char *)principal); return ENOMEM; } principal->length = components; /* * If a realm was not found, then use the default realm, unless * KRB5_PRINCIPAL_PARSE_NO_REALM was specified in which case the * realm will be empty. */ if (!parsed_realm) { if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) { krb5_set_error_message(context, KRB5_PARSE_MALFORMED, "Principal %s is missing required realm", name); krb5_xfree(principal->data); krb5_xfree(principal); return KRB5_PARSE_MALFORMED; } if (!default_realm && (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) == 0) { retval = krb5_get_default_realm(context, &default_realm); if (retval) { krb5_xfree(principal->data); krb5_xfree((char *)principal); return(retval); } default_realm_size = strlen(default_realm); } realmsize = default_realm_size; } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) { krb5_set_error_message(context, KRB5_PARSE_MALFORMED, "Principal %s has realm present", name); krb5_xfree(principal->data); krb5_xfree(principal); return KRB5_PARSE_MALFORMED; } /* * 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=0,cp = name; (c = *cp); cp++) { if (c == QUOTECHAR) { cp++; size++; } else if (c == COMPONENT_SEP) { if (krb5_princ_size(context, principal) > i) krb5_princ_component(context, principal, i)->length = size; size = 0; i++; } else if (c == REALM_SEP) { if (krb5_princ_size(context, principal) > i) krb5_princ_component(context, principal, i)->length = size; size = 0; parsed_realm = cp+1; } else size++; } if (parsed_realm) krb5_princ_realm(context, principal)->length = size; else if (krb5_princ_size(context, principal) > i) krb5_princ_component(context, principal, i)->length = size; if (i + 1 != components) { #if !defined(_WIN32) fprintf(stderr, "Programming error in krb5_parse_name!"); #endif assert(i + 1 == components); abort(); } } else { /* * 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++) krb5_princ_component(context, principal, i)->length = fcompsize[i]; } /* * Now, we need to allocate the space for the strings themselves..... */ tmpdata = malloc(realmsize + 1); if (tmpdata == 0) { krb5_xfree(principal->data); krb5_xfree(principal); krb5_xfree(default_realm); return ENOMEM; } krb5_princ_set_realm_length(context, principal, realmsize); krb5_princ_set_realm_data(context, principal, tmpdata); for (i=0; i < components; i++) { char *tmpdata2 = malloc(krb5_princ_component(context, principal, i)->length + 1); if (tmpdata2 == NULL) { for (i--; i >= 0; i--) krb5_xfree(krb5_princ_component(context, principal, i)->data); krb5_xfree(krb5_princ_realm(context, principal)->data); krb5_xfree(principal->data); krb5_xfree(principal); krb5_xfree(default_realm); return(ENOMEM); } krb5_princ_component(context, principal, i)->data = tmpdata2; krb5_princ_component(context, principal, i)->magic = KV5M_DATA; } /* * Pass 3. Now we go through the string a *third* time, this * time filling in the krb5_principal structure which we just * allocated. */ q = krb5_princ_component(context, principal, 0)->data; for (i=0,cp = name, first_at = 1; (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; break; } } else if (c == COMPONENT_SEP && !enterprise) { i++; *q++ = '\0'; q = krb5_princ_component(context, principal, i)->data; } else if (c == REALM_SEP && (!enterprise || !first_at)) { i++; *q++ = '\0'; q = krb5_princ_realm(context, principal)->data; } else { if (c == REALM_SEP && enterprise && first_at) first_at = 0; *q++ = c; } } *q++ = '\0'; if (!parsed_realm) { if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) (krb5_princ_realm(context, principal)->data)[0] = '\0'; else strlcpy(krb5_princ_realm(context, principal)->data, default_realm, realmsize+1); } /* * Alright, we're done. Now stuff a pointer to this monstrosity * into the return variable, and let's get out of here. */ if (enterprise) krb5_princ_type(context, principal) = KRB5_NT_ENTERPRISE_PRINCIPAL; else krb5_princ_type(context, principal) = KRB5_NT_PRINCIPAL; principal->magic = KV5M_PRINCIPAL; principal->realm.magic = KV5M_DATA; *nprincipal = principal; if (default_realm != NULL) krb5_xfree(default_realm); return(0); }