No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / krb5 / transited.c
blob50b98d63ea1b6a08d42b2e820e203cb609aa4c5c
1 /*
2 * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "krb5_locl.h"
36 __RCSID("$Heimdal: transited.c 21745 2007-07-31 16:11:25Z lha $"
37 "$NetBSD$");
39 /* this is an attempt at one of the most horrible `compression'
40 schemes that has ever been invented; it's so amazingly brain-dead
41 that words can not describe it, and all this just to save a few
42 silly bytes */
44 struct tr_realm {
45 char *realm;
46 unsigned leading_space:1;
47 unsigned leading_slash:1;
48 unsigned trailing_dot:1;
49 struct tr_realm *next;
52 static void
53 free_realms(struct tr_realm *r)
55 struct tr_realm *p;
56 while(r){
57 p = r;
58 r = r->next;
59 free(p->realm);
60 free(p);
64 static int
65 make_path(krb5_context context, struct tr_realm *r,
66 const char *from, const char *to)
68 const char *p;
69 struct tr_realm *path = r->next;
70 struct tr_realm *tmp;
72 if(strlen(from) < strlen(to)){
73 const char *str;
74 str = from;
75 from = to;
76 to = str;
79 if(strcmp(from + strlen(from) - strlen(to), to) == 0){
80 p = from;
81 while(1){
82 p = strchr(p, '.');
83 if(p == NULL) {
84 krb5_clear_error_string (context);
85 return KRB5KDC_ERR_POLICY;
87 p++;
88 if(strcmp(p, to) == 0)
89 break;
90 tmp = calloc(1, sizeof(*tmp));
91 if(tmp == NULL){
92 krb5_set_error_string (context, "malloc: out of memory");
93 return ENOMEM;
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_string (context, "malloc: out of memory");
101 return ENOMEM;;
104 }else if(strncmp(from, to, strlen(to)) == 0){
105 p = from + strlen(from);
106 while(1){
107 while(p >= from && *p != '/') p--;
108 if(p == from) {
109 r->next = path; /* XXX */
110 return KRB5KDC_ERR_POLICY;
112 if(strncmp(to, from, p - from) == 0)
113 break;
114 tmp = calloc(1, sizeof(*tmp));
115 if(tmp == NULL){
116 krb5_set_error_string (context, "malloc: out of memory");
117 return ENOMEM;
119 tmp->next = path;
120 path = tmp;
121 path->realm = malloc(p - from + 1);
122 if(path->realm == NULL){
123 r->next = path; /* XXX */
124 krb5_set_error_string (context, "malloc: out of memory");
125 return ENOMEM;
127 memcpy(path->realm, from, p - from);
128 path->realm[p - from] = '\0';
129 p--;
131 } else {
132 krb5_clear_error_string (context);
133 return KRB5KDC_ERR_POLICY;
135 r->next = path;
137 return 0;
140 static int
141 make_paths(krb5_context context,
142 struct tr_realm *realms, const char *client_realm,
143 const char *server_realm)
145 struct tr_realm *r;
146 int ret;
147 const char *prev_realm = client_realm;
148 const char *next_realm = NULL;
149 for(r = realms; r; r = r->next){
150 /* it *might* be that you can have more than one empty
151 component in a row, at least that's how I interpret the
152 "," exception in 1510 */
153 if(r->realm[0] == '\0'){
154 while(r->next && r->next->realm[0] == '\0')
155 r = r->next;
156 if(r->next)
157 next_realm = r->next->realm;
158 else
159 next_realm = server_realm;
160 ret = make_path(context, r, prev_realm, next_realm);
161 if(ret){
162 free_realms(realms);
163 return ret;
166 prev_realm = r->realm;
168 return 0;
171 static int
172 expand_realms(krb5_context context,
173 struct tr_realm *realms, const char *client_realm)
175 struct tr_realm *r;
176 const char *prev_realm = NULL;
177 for(r = realms; r; r = r->next){
178 if(r->trailing_dot){
179 char *tmp;
180 size_t len;
182 if(prev_realm == NULL)
183 prev_realm = client_realm;
185 len = strlen(r->realm) + strlen(prev_realm) + 1;
187 tmp = realloc(r->realm, len);
188 if(tmp == NULL){
189 free_realms(realms);
190 krb5_set_error_string (context, "malloc: out of memory");
191 return ENOMEM;
193 r->realm = tmp;
194 strlcat(r->realm, prev_realm, len);
195 }else if(r->leading_slash && !r->leading_space && prev_realm){
196 /* yet another exception: if you use x500-names, the
197 leading realm doesn't have to be "quoted" with a space */
198 char *tmp;
199 size_t len = strlen(r->realm) + strlen(prev_realm) + 1;
201 tmp = malloc(len);
202 if(tmp == NULL){
203 free_realms(realms);
204 krb5_set_error_string (context, "malloc: out of memory");
205 return ENOMEM;
207 strlcpy(tmp, prev_realm, len);
208 strlcat(tmp, r->realm, len);
209 free(r->realm);
210 r->realm = tmp;
212 prev_realm = r->realm;
214 return 0;
217 static struct tr_realm *
218 make_realm(char *realm)
220 struct tr_realm *r;
221 char *p, *q;
222 int quote = 0;
223 r = calloc(1, sizeof(*r));
224 if(r == NULL){
225 free(realm);
226 return NULL;
228 r->realm = realm;
229 for(p = q = r->realm; *p; p++){
230 if(p == r->realm && *p == ' '){
231 r->leading_space = 1;
232 continue;
234 if(q == r->realm && *p == '/')
235 r->leading_slash = 1;
236 if(quote){
237 *q++ = *p;
238 quote = 0;
239 continue;
241 if(*p == '\\'){
242 quote = 1;
243 continue;
245 if(p[0] == '.' && p[1] == '\0')
246 r->trailing_dot = 1;
247 *q++ = *p;
249 *q = '\0';
250 return r;
253 static struct tr_realm*
254 append_realm(struct tr_realm *head, struct tr_realm *r)
256 struct tr_realm *p;
257 if(head == NULL){
258 r->next = NULL;
259 return r;
261 p = head;
262 while(p->next) p = p->next;
263 p->next = r;
264 return head;
267 static int
268 decode_realms(krb5_context context,
269 const char *tr, int length, struct tr_realm **realms)
271 struct tr_realm *r = NULL;
273 char *tmp;
274 int quote = 0;
275 const char *start = tr;
276 int i;
278 for(i = 0; i < length; i++){
279 if(quote){
280 quote = 0;
281 continue;
283 if(tr[i] == '\\'){
284 quote = 1;
285 continue;
287 if(tr[i] == ','){
288 tmp = malloc(tr + i - start + 1);
289 if(tmp == NULL){
290 krb5_set_error_string (context, "malloc: out of memory");
291 return ENOMEM;
293 memcpy(tmp, start, tr + i - start);
294 tmp[tr + i - start] = '\0';
295 r = make_realm(tmp);
296 if(r == NULL){
297 free_realms(*realms);
298 krb5_set_error_string (context, "malloc: out of memory");
299 return ENOMEM;
301 *realms = append_realm(*realms, r);
302 start = tr + i + 1;
305 tmp = malloc(tr + i - start + 1);
306 if(tmp == NULL){
307 free(*realms);
308 krb5_set_error_string (context, "malloc: out of memory");
309 return ENOMEM;
311 memcpy(tmp, start, tr + i - start);
312 tmp[tr + i - start] = '\0';
313 r = make_realm(tmp);
314 if(r == NULL){
315 free_realms(*realms);
316 krb5_set_error_string (context, "malloc: out of memory");
317 return ENOMEM;
319 *realms = append_realm(*realms, r);
321 return 0;
325 krb5_error_code KRB5_LIB_FUNCTION
326 krb5_domain_x500_decode(krb5_context context,
327 krb5_data tr, char ***realms, int *num_realms,
328 const char *client_realm, const char *server_realm)
330 struct tr_realm *r = NULL;
331 struct tr_realm *p, **q;
332 int ret;
334 if(tr.length == 0) {
335 *realms = NULL;
336 *num_realms = 0;
337 return 0;
340 /* split string in components */
341 ret = decode_realms(context, tr.data, tr.length, &r);
342 if(ret)
343 return ret;
345 /* apply prefix rule */
346 ret = expand_realms(context, r, client_realm);
347 if(ret)
348 return ret;
350 ret = make_paths(context, r, client_realm, server_realm);
351 if(ret)
352 return ret;
354 /* remove empty components and count realms */
355 q = &r;
356 *num_realms = 0;
357 for(p = r; p; ){
358 if(p->realm[0] == '\0'){
359 free(p->realm);
360 *q = p->next;
361 free(p);
362 p = *q;
363 }else{
364 q = &p->next;
365 p = p->next;
366 (*num_realms)++;
369 if (*num_realms < 0 || *num_realms + 1 > UINT_MAX/sizeof(**realms))
370 return ERANGE;
373 char **R;
374 R = malloc((*num_realms + 1) * sizeof(*R));
375 if (R == NULL)
376 return ENOMEM;
377 *realms = R;
378 while(r){
379 *R++ = r->realm;
380 p = r->next;
381 free(r);
382 r = p;
385 return 0;
388 krb5_error_code KRB5_LIB_FUNCTION
389 krb5_domain_x500_encode(char **realms, int num_realms, krb5_data *encoding)
391 char *s = NULL;
392 int len = 0;
393 int i;
394 krb5_data_zero(encoding);
395 if (num_realms == 0)
396 return 0;
397 for(i = 0; i < num_realms; i++){
398 len += strlen(realms[i]);
399 if(realms[i][0] == '/')
400 len++;
402 len += num_realms - 1;
403 s = malloc(len + 1);
404 if (s == NULL)
405 return ENOMEM;
406 *s = '\0';
407 for(i = 0; i < num_realms; i++){
408 if(i && i < num_realms - 1)
409 strlcat(s, ",", len + 1);
410 if(realms[i][0] == '/')
411 strlcat(s, " ", len + 1);
412 strlcat(s, realms[i], len + 1);
414 encoding->data = s;
415 encoding->length = strlen(s);
416 return 0;
419 krb5_error_code KRB5_LIB_FUNCTION
420 krb5_check_transited(krb5_context context,
421 krb5_const_realm client_realm,
422 krb5_const_realm server_realm,
423 krb5_realm *realms,
424 int num_realms,
425 int *bad_realm)
427 char **tr_realms;
428 char **p;
429 int i;
431 if(num_realms == 0)
432 return 0;
434 tr_realms = krb5_config_get_strings(context, NULL,
435 "capaths",
436 client_realm,
437 server_realm,
438 NULL);
439 for(i = 0; i < num_realms; i++) {
440 for(p = tr_realms; p && *p; p++) {
441 if(strcmp(*p, realms[i]) == 0)
442 break;
444 if(p == NULL || *p == NULL) {
445 krb5_config_free_strings(tr_realms);
446 krb5_set_error_string (context, "no transit through realm %s",
447 realms[i]);
448 if(bad_realm)
449 *bad_realm = i;
450 return KRB5KRB_AP_ERR_ILL_CR_TKT;
453 krb5_config_free_strings(tr_realms);
454 return 0;
457 krb5_error_code KRB5_LIB_FUNCTION
458 krb5_check_transited_realms(krb5_context context,
459 const char *const *realms,
460 int num_realms,
461 int *bad_realm)
463 int i;
464 int ret = 0;
465 char **bad_realms = krb5_config_get_strings(context, NULL,
466 "libdefaults",
467 "transited_realms_reject",
468 NULL);
469 if(bad_realms == NULL)
470 return 0;
472 for(i = 0; i < num_realms; i++) {
473 char **p;
474 for(p = bad_realms; *p; p++)
475 if(strcmp(*p, realms[i]) == 0) {
476 krb5_set_error_string (context, "no transit through realm %s",
477 *p);
478 ret = KRB5KRB_AP_ERR_ILL_CR_TKT;
479 if(bad_realm)
480 *bad_realm = i;
481 break;
484 krb5_config_free_strings(bad_realms);
485 return ret;
488 #if 0
490 main(int argc, char **argv)
492 krb5_data x;
493 char **r;
494 int num, i;
495 x.data = argv[1];
496 x.length = strlen(x.data);
497 if(domain_expand(x, &r, &num, argv[2], argv[3]))
498 exit(1);
499 for(i = 0; i < num; i++)
500 printf("%s\n", r[i]);
501 return 0;
503 #endif