1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/parse.c - Parse strings into krb5_principals */
4 * Copyright 1990,1991,2008,2012 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.
30 * Scan name and allocate a shell principal with enough space in each field.
31 * If enterprise is true, use enterprise principal parsing rules. Return
32 * KRB5_PARSE_MALFORMED if name is malformed. Set *has_realm_out according to
33 * whether name contains a realm separator.
35 static krb5_error_code
36 allocate_princ(krb5_context context, const char *name, krb5_boolean enterprise,
37 krb5_principal *princ_out, krb5_boolean *has_realm_out)
41 krb5_boolean first_at = TRUE;
42 krb5_principal princ = NULL;
43 krb5_data *cur_data, *new_comps;
47 *has_realm_out = FALSE;
49 /* Allocate a starting principal with one component. */
50 princ = k5alloc(sizeof(*princ), &ret);
53 princ->data = k5alloc(sizeof(*princ->data), &ret);
54 if (princ->data == NULL)
56 princ->realm = empty_data();
57 princ->data[0] = empty_data();
60 cur_data = &princ->data[0];
61 for (p = name; *p != '\0'; p++) {
62 if (*p == '/' && !enterprise) {
63 /* Component separator (for non-enterprise principals). We
64 * shouldn't see this in the realm name. */
65 if (cur_data == &princ->realm) {
66 ret = KRB5_PARSE_MALFORMED;
69 new_comps = realloc(princ->data,
70 (princ->length + 1) * sizeof(*princ->data));
71 if (new_comps == NULL) {
75 princ->data = new_comps;
77 cur_data = &princ->data[princ->length - 1];
78 *cur_data = empty_data();
79 } else if (*p == '@' && (!enterprise || !first_at)) {
80 /* Realm separator. In enterprise principals, the first one of
81 * these we see is part of the component. */
82 cur_data = &princ->realm;
84 /* Component or realm character, possibly quoted. Make note if
85 * we're seeing the first '@' in an enterprise principal. */
87 if (*p == '@' && enterprise)
90 /* Quote character can't be the last character of the name. */
92 ret = KRB5_PARSE_MALFORMED;
99 /* Allocate space for each non-empty component and the realm. */
100 for (i = 0; i < princ->length; i++) {
101 if (princ->data[i].length > 0) {
102 princ->data[i].data = k5alloc(princ->data[i].length, &ret);
103 if (princ->data[i].data == NULL)
107 if (princ->realm.length > 0) {
108 princ->realm.data = k5alloc(princ->realm.length, &ret);
109 if (princ->realm.data == NULL)
114 *has_realm_out = (cur_data == &princ->realm);
117 krb5_free_principal(context, princ);
122 * Parse name into princ, assuming that name is correctly formed and that all
123 * principal fields are allocated to the correct length. If enterprise is
124 * true, use enterprise principal parsing rules.
127 parse_name_into_princ(const char *name, krb5_boolean enterprise,
128 krb5_principal princ)
132 krb5_boolean first_at = TRUE;
133 krb5_data *cur_data = princ->data;
134 unsigned int pos = 0;
136 for (p = name; *p != '\0'; p++) {
137 if (*p == '/' && !enterprise) {
138 /* Advance to the next component. */
139 assert(pos == cur_data->length);
140 assert(cur_data != &princ->realm);
141 assert(cur_data - princ->data + 1 < princ->length);
144 } else if (*p == '@' && (!enterprise || !first_at)) {
145 /* Advance to the realm. */
146 assert(pos == cur_data->length);
147 cur_data = &princ->realm;
150 /* Add to the current component or to the realm. */
151 if (*p == '@' && enterprise)
165 assert(pos < cur_data->length);
166 cur_data->data[pos++] = c;
169 assert(pos == cur_data->length);
172 krb5_error_code KRB5_CALLCONV
173 krb5_parse_name_flags(krb5_context context, const char *name,
174 int flags, krb5_principal *principal_out)
177 krb5_principal princ = NULL;
179 krb5_boolean has_realm;
180 krb5_boolean enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE);
181 krb5_boolean require_realm = (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM);
182 krb5_boolean no_realm = (flags & KRB5_PRINCIPAL_PARSE_NO_REALM);
184 *principal_out = NULL;
186 ret = allocate_princ(context, name, enterprise, &princ, &has_realm);
189 parse_name_into_princ(name, enterprise, princ);
192 * If a realm was not found, then use the default realm, unless
193 * KRB5_PRINCIPAL_PARSE_NO_REALM was specified in which case the
194 * realm will be empty.
198 ret = KRB5_PARSE_MALFORMED;
199 krb5_set_error_message(context, ret,
200 _("Principal %s is missing required realm"),
205 ret = krb5_get_default_realm(context, &default_realm);
208 princ->realm = string2data(default_realm);
210 } else if (no_realm) {
211 ret = KRB5_PARSE_MALFORMED;
212 krb5_set_error_message(context, ret,
213 _("Principal %s has realm present"), name);
217 princ->type = (enterprise) ? KRB5_NT_ENTERPRISE_PRINCIPAL :
219 princ->magic = KV5M_PRINCIPAL;
220 *principal_out = princ;
224 krb5_free_principal(context, princ);
228 krb5_error_code KRB5_CALLCONV
229 krb5_parse_name(krb5_context context, const char *name,
230 krb5_principal *principal_out)
232 return krb5_parse_name_flags(context, name, 0, principal_out);