/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- free_realms
- make_path
- make_paths
- expand_realms
- make_realm
- append_realm
- decode_realms
- krb5_domain_x500_decode
- krb5_domain_x500_encode
- krb5_check_transited
- krb5_check_transited_realms
- main
1 /*
2 * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "krb5_locl.h"
35
36 RCSID("$Id$");
37
38 /* this is an attempt at one of the most horrible `compression'
39 schemes that has ever been invented; it's so amazingly brain-dead
40 that words can not describe it, and all this just to save a few
41 silly bytes */
42
43 struct tr_realm {
44 char *realm;
45 unsigned leading_space:1;
46 unsigned leading_slash:1;
47 unsigned trailing_dot:1;
48 struct tr_realm *next;
49 };
50
51 static void
52 free_realms(struct tr_realm *r)
/* [<][>][^][v][top][bottom][index][help] */
53 {
54 struct tr_realm *p;
55 while(r){
56 p = r;
57 r = r->next;
58 free(p->realm);
59 free(p);
60 }
61 }
62
63 static int
64 make_path(krb5_context context, struct tr_realm *r,
/* [<][>][^][v][top][bottom][index][help] */
65 const char *from, const char *to)
66 {
67 const char *p;
68 struct tr_realm *path = r->next;
69 struct tr_realm *tmp;
70
71 if(strlen(from) < strlen(to)){
72 const char *str;
73 str = from;
74 from = to;
75 to = str;
76 }
77
78 if(strcmp(from + strlen(from) - strlen(to), to) == 0){
79 p = from;
80 while(1){
81 p = strchr(p, '.');
82 if(p == NULL) {
83 krb5_clear_error_message (context);
84 return KRB5KDC_ERR_POLICY;
85 }
86 p++;
87 if(strcmp(p, to) == 0)
88 break;
89 tmp = calloc(1, sizeof(*tmp));
90 if(tmp == NULL){
91 krb5_set_error_message(context, ENOMEM,
92 N_("malloc: out of memory", ""));
93 return ENOMEM;
94 }
95 tmp->next = path;
96 path = tmp;
97 path->realm = strdup(p);
98 if(path->realm == NULL){
99 r->next = path; /* XXX */
100 krb5_set_error_message(context, ENOMEM,
101 N_("malloc: out of memory", ""));
102 return ENOMEM;;
103 }
104 }
105 }else if(strncmp(from, to, strlen(to)) == 0){
106 p = from + strlen(from);
107 while(1){
108 while(p >= from && *p != '/') p--;
109 if(p == from) {
110 r->next = path; /* XXX */
111 return KRB5KDC_ERR_POLICY;
112 }
113 if(strncmp(to, from, p - from) == 0)
114 break;
115 tmp = calloc(1, sizeof(*tmp));
116 if(tmp == NULL){
117 krb5_set_error_message(context, ENOMEM,
118 N_("malloc: out of memory", ""));
119 return ENOMEM;
120 }
121 tmp->next = path;
122 path = tmp;
123 path->realm = malloc(p - from + 1);
124 if(path->realm == NULL){
125 r->next = path; /* XXX */
126 krb5_set_error_message(context, ENOMEM,
127 N_("malloc: out of memory", ""));
128 return ENOMEM;
129 }
130 memcpy(path->realm, from, p - from);
131 path->realm[p - from] = '\0';
132 p--;
133 }
134 } else {
135 krb5_clear_error_message (context);
136 return KRB5KDC_ERR_POLICY;
137 }
138 r->next = path;
139
140 return 0;
141 }
142
143 static int
144 make_paths(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
145 struct tr_realm *realms, const char *client_realm,
146 const char *server_realm)
147 {
148 struct tr_realm *r;
149 int ret;
150 const char *prev_realm = client_realm;
151 const char *next_realm = NULL;
152 for(r = realms; r; r = r->next){
153 /* it *might* be that you can have more than one empty
154 component in a row, at least that's how I interpret the
155 "," exception in 1510 */
156 if(r->realm[0] == '\0'){
157 while(r->next && r->next->realm[0] == '\0')
158 r = r->next;
159 if(r->next)
160 next_realm = r->next->realm;
161 else
162 next_realm = server_realm;
163 ret = make_path(context, r, prev_realm, next_realm);
164 if(ret){
165 free_realms(realms);
166 return ret;
167 }
168 }
169 prev_realm = r->realm;
170 }
171 return 0;
172 }
173
174 static int
175 expand_realms(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
176 struct tr_realm *realms, const char *client_realm)
177 {
178 struct tr_realm *r;
179 const char *prev_realm = NULL;
180 for(r = realms; r; r = r->next){
181 if(r->trailing_dot){
182 char *tmp;
183 size_t len;
184
185 if(prev_realm == NULL)
186 prev_realm = client_realm;
187
188 len = strlen(r->realm) + strlen(prev_realm) + 1;
189
190 tmp = realloc(r->realm, len);
191 if(tmp == NULL){
192 free_realms(realms);
193 krb5_set_error_message(context, ENOMEM,
194 N_("malloc: out of memory", ""));
195 return ENOMEM;
196 }
197 r->realm = tmp;
198 strlcat(r->realm, prev_realm, len);
199 }else if(r->leading_slash && !r->leading_space && prev_realm){
200 /* yet another exception: if you use x500-names, the
201 leading realm doesn't have to be "quoted" with a space */
202 char *tmp;
203 size_t len = strlen(r->realm) + strlen(prev_realm) + 1;
204
205 tmp = malloc(len);
206 if(tmp == NULL){
207 free_realms(realms);
208 krb5_set_error_message(context, ENOMEM,
209 N_("malloc: out of memory", ""));
210 return ENOMEM;
211 }
212 strlcpy(tmp, prev_realm, len);
213 strlcat(tmp, r->realm, len);
214 free(r->realm);
215 r->realm = tmp;
216 }
217 prev_realm = r->realm;
218 }
219 return 0;
220 }
221
222 static struct tr_realm *
223 make_realm(char *realm)
/* [<][>][^][v][top][bottom][index][help] */
224 {
225 struct tr_realm *r;
226 char *p, *q;
227 int quote = 0;
228 r = calloc(1, sizeof(*r));
229 if(r == NULL){
230 free(realm);
231 return NULL;
232 }
233 r->realm = realm;
234 for(p = q = r->realm; *p; p++){
235 if(p == r->realm && *p == ' '){
236 r->leading_space = 1;
237 continue;
238 }
239 if(q == r->realm && *p == '/')
240 r->leading_slash = 1;
241 if(quote){
242 *q++ = *p;
243 quote = 0;
244 continue;
245 }
246 if(*p == '\\'){
247 quote = 1;
248 continue;
249 }
250 if(p[0] == '.' && p[1] == '\0')
251 r->trailing_dot = 1;
252 *q++ = *p;
253 }
254 *q = '\0';
255 return r;
256 }
257
258 static struct tr_realm*
259 append_realm(struct tr_realm *head, struct tr_realm *r)
/* [<][>][^][v][top][bottom][index][help] */
260 {
261 struct tr_realm *p;
262 if(head == NULL){
263 r->next = NULL;
264 return r;
265 }
266 p = head;
267 while(p->next) p = p->next;
268 p->next = r;
269 return head;
270 }
271
272 static int
273 decode_realms(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
274 const char *tr, int length, struct tr_realm **realms)
275 {
276 struct tr_realm *r = NULL;
277
278 char *tmp;
279 int quote = 0;
280 const char *start = tr;
281 int i;
282
283 for(i = 0; i < length; i++){
284 if(quote){
285 quote = 0;
286 continue;
287 }
288 if(tr[i] == '\\'){
289 quote = 1;
290 continue;
291 }
292 if(tr[i] == ','){
293 tmp = malloc(tr + i - start + 1);
294 if(tmp == NULL){
295 krb5_set_error_message(context, ENOMEM,
296 N_("malloc: out of memory", ""));
297 return ENOMEM;
298 }
299 memcpy(tmp, start, tr + i - start);
300 tmp[tr + i - start] = '\0';
301 r = make_realm(tmp);
302 if(r == NULL){
303 free_realms(*realms);
304 krb5_set_error_message(context, ENOMEM,
305 N_("malloc: out of memory", ""));
306 return ENOMEM;
307 }
308 *realms = append_realm(*realms, r);
309 start = tr + i + 1;
310 }
311 }
312 tmp = malloc(tr + i - start + 1);
313 if(tmp == NULL){
314 free(*realms);
315 krb5_set_error_message(context, ENOMEM,
316 N_("malloc: out of memory", ""));
317 return ENOMEM;
318 }
319 memcpy(tmp, start, tr + i - start);
320 tmp[tr + i - start] = '\0';
321 r = make_realm(tmp);
322 if(r == NULL){
323 free_realms(*realms);
324 krb5_set_error_message(context, ENOMEM,
325 N_("malloc: out of memory", ""));
326 return ENOMEM;
327 }
328 *realms = append_realm(*realms, r);
329
330 return 0;
331 }
332
333
334 krb5_error_code KRB5_LIB_FUNCTION
335 krb5_domain_x500_decode(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
336 krb5_data tr, char ***realms, unsigned int *num_realms,
337 const char *client_realm, const char *server_realm)
338 {
339 struct tr_realm *r = NULL;
340 struct tr_realm *p, **q;
341 int ret;
342
343 if(tr.length == 0) {
344 *realms = NULL;
345 *num_realms = 0;
346 return 0;
347 }
348
349 /* split string in components */
350 ret = decode_realms(context, tr.data, tr.length, &r);
351 if(ret)
352 return ret;
353
354 /* apply prefix rule */
355 ret = expand_realms(context, r, client_realm);
356 if(ret)
357 return ret;
358
359 ret = make_paths(context, r, client_realm, server_realm);
360 if(ret)
361 return ret;
362
363 /* remove empty components and count realms */
364 q = &r;
365 *num_realms = 0;
366 for(p = r; p; ){
367 if(p->realm[0] == '\0'){
368 free(p->realm);
369 *q = p->next;
370 free(p);
371 p = *q;
372 }else{
373 q = &p->next;
374 p = p->next;
375 (*num_realms)++;
376 }
377 }
378 if (*num_realms < 0 || *num_realms + 1 > UINT_MAX/sizeof(**realms))
379 return ERANGE;
380
381 {
382 char **R;
383 R = malloc((*num_realms + 1) * sizeof(*R));
384 if (R == NULL)
385 return ENOMEM;
386 *realms = R;
387 while(r){
388 *R++ = r->realm;
389 p = r->next;
390 free(r);
391 r = p;
392 }
393 }
394 return 0;
395 }
396
397 krb5_error_code KRB5_LIB_FUNCTION
398 krb5_domain_x500_encode(char **realms, unsigned int num_realms,
/* [<][>][^][v][top][bottom][index][help] */
399 krb5_data *encoding)
400 {
401 char *s = NULL;
402 int len = 0;
403 unsigned int i;
404 krb5_data_zero(encoding);
405 if (num_realms == 0)
406 return 0;
407 for(i = 0; i < num_realms; i++){
408 len += strlen(realms[i]);
409 if(realms[i][0] == '/')
410 len++;
411 }
412 len += num_realms - 1;
413 s = malloc(len + 1);
414 if (s == NULL)
415 return ENOMEM;
416 *s = '\0';
417 for(i = 0; i < num_realms; i++){
418 if(i && i < num_realms - 1)
419 strlcat(s, ",", len + 1);
420 if(realms[i][0] == '/')
421 strlcat(s, " ", len + 1);
422 strlcat(s, realms[i], len + 1);
423 }
424 encoding->data = s;
425 encoding->length = strlen(s);
426 return 0;
427 }
428
429 krb5_error_code KRB5_LIB_FUNCTION
430 krb5_check_transited(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
431 krb5_const_realm client_realm,
432 krb5_const_realm server_realm,
433 krb5_realm *realms,
434 unsigned int num_realms,
435 int *bad_realm)
436 {
437 char **tr_realms;
438 char **p;
439 int i;
440
441 if(num_realms == 0)
442 return 0;
443
444 tr_realms = krb5_config_get_strings(context, NULL,
445 "capaths",
446 client_realm,
447 server_realm,
448 NULL);
449 for(i = 0; i < num_realms; i++) {
450 for(p = tr_realms; p && *p; p++) {
451 if(strcmp(*p, realms[i]) == 0)
452 break;
453 }
454 if(p == NULL || *p == NULL) {
455 krb5_config_free_strings(tr_realms);
456 krb5_set_error_message (context, KRB5KRB_AP_ERR_ILL_CR_TKT,
457 N_("no transit allowed "
458 "through realm %s", ""),
459 realms[i]);
460 if(bad_realm)
461 *bad_realm = i;
462 return KRB5KRB_AP_ERR_ILL_CR_TKT;
463 }
464 }
465 krb5_config_free_strings(tr_realms);
466 return 0;
467 }
468
469 krb5_error_code KRB5_LIB_FUNCTION
470 krb5_check_transited_realms(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
471 const char *const *realms,
472 unsigned int num_realms,
473 int *bad_realm)
474 {
475 int i;
476 int ret = 0;
477 char **bad_realms = krb5_config_get_strings(context, NULL,
478 "libdefaults",
479 "transited_realms_reject",
480 NULL);
481 if(bad_realms == NULL)
482 return 0;
483
484 for(i = 0; i < num_realms; i++) {
485 char **p;
486 for(p = bad_realms; *p; p++)
487 if(strcmp(*p, realms[i]) == 0) {
488 ret = KRB5KRB_AP_ERR_ILL_CR_TKT;
489 krb5_set_error_message (context, ret,
490 N_("no transit allowed "
491 "through realm %s", ""),
492 *p);
493 if(bad_realm)
494 *bad_realm = i;
495 break;
496 }
497 }
498 krb5_config_free_strings(bad_realms);
499 return ret;
500 }
501
502 #if 0
503 int
504 main(int argc, char **argv)
/* [<][>][^][v][top][bottom][index][help] */
505 {
506 krb5_data x;
507 char **r;
508 int num, i;
509 x.data = argv[1];
510 x.length = strlen(x.data);
511 if(domain_expand(x, &r, &num, argv[2], argv[3]))
512 exit(1);
513 for(i = 0; i < num; i++)
514 printf("%s\n", r[i]);
515 return 0;
516 }
517 #endif
518