/src/krb5/src/lib/krb5/krb/unparse.c
Line | Count | Source |
1 | | /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | | /* lib/krb5/krb/unparse.c */ |
3 | | /* |
4 | | * Copyright 1990, 2008 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 | | /* |
28 | | * krb5_unparse_name() routine |
29 | | * |
30 | | * Rewritten by Theodore Ts'o to properly unparse principal names |
31 | | * which have the component or realm separator as part of one of their |
32 | | * components. |
33 | | */ |
34 | | |
35 | | |
36 | | #include "k5-int.h" |
37 | | #include <stdio.h> |
38 | | |
39 | | /* |
40 | | * converts the multi-part principal format used in the protocols to a |
41 | | * single-string representation of the name. |
42 | | * |
43 | | * The name returned is in allocated storage and should be freed by |
44 | | * the caller when finished. |
45 | | * |
46 | | * Conventions: / is used to separate components; @ is used to |
47 | | * separate the realm from the rest of the name. If '/', '@', or '\0' |
48 | | * appear in any the component, they will be representing using |
49 | | * backslash encoding. ("\/", "\@", or '\0', respectively) |
50 | | * |
51 | | * returns error |
52 | | * KRB_PARSE_MALFORMED principal is invalid (does not contain |
53 | | * at least 2 components) |
54 | | * also returns system errors |
55 | | * ENOMEM unable to allocate memory for string |
56 | | */ |
57 | | |
58 | 16.9k | #define REALM_SEP '@' |
59 | 37.1k | #define COMPONENT_SEP '/' |
60 | | |
61 | | static int |
62 | | component_length_quoted(const krb5_data *src, int flags) |
63 | 5.84k | { |
64 | 5.84k | const char *cp = src->data; |
65 | 5.84k | int length = src->length; |
66 | 5.84k | int j; |
67 | 5.84k | int size = length; |
68 | | |
69 | 5.84k | if ((flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) == 0) { |
70 | 5.02k | int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) && |
71 | 0 | !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT); |
72 | | |
73 | 20.8k | for (j = 0; j < length; j++,cp++) |
74 | 15.8k | if ((!no_realm && *cp == REALM_SEP) || |
75 | 15.4k | *cp == COMPONENT_SEP || |
76 | 15.0k | *cp == '\0' || *cp == '\\' || *cp == '\t' || |
77 | 12.7k | *cp == '\n' || *cp == '\b') |
78 | 4.99k | size++; |
79 | 5.02k | } |
80 | | |
81 | 5.84k | return size; |
82 | 5.84k | } |
83 | | |
84 | | static int |
85 | | copy_component_quoting(char *dest, const krb5_data *src, int flags) |
86 | 5.84k | { |
87 | 5.84k | int j; |
88 | 5.84k | const char *cp = src->data; |
89 | 5.84k | char *q = dest; |
90 | 5.84k | int length = src->length; |
91 | | |
92 | 5.84k | if (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) { |
93 | 823 | if (src->length > 0) |
94 | 823 | memcpy(dest, src->data, src->length); |
95 | 823 | return src->length; |
96 | 823 | } |
97 | | |
98 | 20.8k | for (j=0; j < length; j++,cp++) { |
99 | 15.8k | int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) && |
100 | 0 | !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT); |
101 | | |
102 | 15.8k | switch (*cp) { |
103 | 406 | case REALM_SEP: |
104 | 406 | if (no_realm) { |
105 | 0 | *q++ = *cp; |
106 | 0 | break; |
107 | 0 | } |
108 | 794 | case COMPONENT_SEP: |
109 | 1.31k | case '\\': |
110 | 1.31k | *q++ = '\\'; |
111 | 1.31k | *q++ = *cp; |
112 | 1.31k | break; |
113 | 1.37k | case '\t': |
114 | 1.37k | *q++ = '\\'; |
115 | 1.37k | *q++ = 't'; |
116 | 1.37k | break; |
117 | 496 | case '\n': |
118 | 496 | *q++ = '\\'; |
119 | 496 | *q++ = 'n'; |
120 | 496 | break; |
121 | 1.41k | case '\b': |
122 | 1.41k | *q++ = '\\'; |
123 | 1.41k | *q++ = 'b'; |
124 | 1.41k | break; |
125 | 389 | case '\0': |
126 | 389 | *q++ = '\\'; |
127 | 389 | *q++ = '0'; |
128 | 389 | break; |
129 | 10.8k | default: |
130 | 10.8k | *q++ = *cp; |
131 | 15.8k | } |
132 | 15.8k | } |
133 | 5.02k | return q - dest; |
134 | 5.02k | } |
135 | | |
136 | | static krb5_error_code |
137 | | k5_unparse_name(krb5_context context, krb5_const_principal principal, |
138 | | int flags, char **name, unsigned int *size) |
139 | 992 | { |
140 | 992 | char *q; |
141 | 992 | krb5_int32 i; |
142 | 992 | unsigned int totalsize = 0; |
143 | 992 | char *default_realm = NULL; |
144 | 992 | krb5_error_code ret = 0; |
145 | | |
146 | 992 | if (!principal || !name) |
147 | 0 | return KRB5_PARSE_MALFORMED; |
148 | | |
149 | 992 | if (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) { |
150 | | /* omit realm if local realm */ |
151 | 0 | krb5_principal_data p; |
152 | |
|
153 | 0 | ret = krb5_get_default_realm(context, &default_realm); |
154 | 0 | if (ret != 0) |
155 | 0 | goto cleanup; |
156 | | |
157 | 0 | p.realm = string2data(default_realm); |
158 | |
|
159 | 0 | if (krb5_realm_compare(context, &p, principal)) |
160 | 0 | flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM; |
161 | 0 | } |
162 | | |
163 | 992 | if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) { |
164 | 711 | totalsize += component_length_quoted(&principal->realm, flags); |
165 | 711 | totalsize++; /* This is for the separator */ |
166 | 711 | } |
167 | | |
168 | 6.12k | for (i = 0; i < principal->length; i++) { |
169 | 5.13k | totalsize += component_length_quoted(&principal->data[i], flags); |
170 | 5.13k | totalsize++; /* This is for the separator */ |
171 | 5.13k | } |
172 | 992 | if (principal->length == 0) |
173 | 0 | totalsize++; |
174 | | |
175 | | /* |
176 | | * Allocate space for the ascii string; if space has been |
177 | | * provided, use it, realloc'ing it if necessary. |
178 | | * |
179 | | * We need only n-1 separators for n components, but we need |
180 | | * an extra byte for the NUL at the end. |
181 | | */ |
182 | 992 | if (size) { |
183 | 0 | if (*name && (*size < totalsize)) { |
184 | 0 | *name = realloc(*name, totalsize); |
185 | 0 | } else { |
186 | 0 | *name = malloc(totalsize); |
187 | 0 | } |
188 | 0 | *size = totalsize; |
189 | 992 | } else { |
190 | 992 | *name = malloc(totalsize); |
191 | 992 | } |
192 | | |
193 | 992 | if (!*name) { |
194 | 0 | ret = ENOMEM; |
195 | 0 | goto cleanup; |
196 | 0 | } |
197 | | |
198 | 992 | q = *name; |
199 | | |
200 | 6.12k | for (i = 0; i < principal->length; i++) { |
201 | 5.13k | q += copy_component_quoting(q, &principal->data[i], flags); |
202 | 5.13k | *q++ = COMPONENT_SEP; |
203 | 5.13k | } |
204 | | |
205 | 992 | if (i > 0) |
206 | 992 | q--; /* Back up last component separator */ |
207 | 992 | if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) { |
208 | 711 | *q++ = REALM_SEP; |
209 | 711 | q += copy_component_quoting(q, &principal->realm, flags); |
210 | 711 | } |
211 | 992 | *q++ = '\0'; |
212 | | |
213 | 992 | cleanup: |
214 | 992 | if (default_realm != NULL) |
215 | 0 | krb5_free_default_realm(context, default_realm); |
216 | | |
217 | 992 | return ret; |
218 | 992 | } |
219 | | |
220 | | krb5_error_code KRB5_CALLCONV |
221 | | krb5_unparse_name(krb5_context context, krb5_const_principal principal, |
222 | | char **name) |
223 | 440 | { |
224 | 440 | if (name != NULL) /* name == NULL will return error from _ext */ |
225 | 440 | *name = NULL; |
226 | | |
227 | 440 | return k5_unparse_name(context, principal, 0, name, NULL); |
228 | 440 | } |
229 | | |
230 | | krb5_error_code KRB5_CALLCONV |
231 | | krb5_unparse_name_ext(krb5_context context, krb5_const_principal principal, |
232 | | char **name, unsigned int *size) |
233 | 0 | { |
234 | 0 | return k5_unparse_name(context, principal, 0, name, size); |
235 | 0 | } |
236 | | |
237 | | krb5_error_code KRB5_CALLCONV |
238 | | krb5_unparse_name_flags(krb5_context context, krb5_const_principal principal, |
239 | | int flags, char **name) |
240 | 552 | { |
241 | 552 | if (name != NULL) |
242 | 552 | *name = NULL; |
243 | 552 | return k5_unparse_name(context, principal, flags, name, NULL); |
244 | 552 | } |
245 | | |
246 | | krb5_error_code KRB5_CALLCONV |
247 | | krb5_unparse_name_flags_ext(krb5_context context, krb5_const_principal principal, |
248 | | int flags, char **name, unsigned int *size) |
249 | 0 | { |
250 | 0 | return k5_unparse_name(context, principal, flags, name, size); |
251 | 0 | } |