etc/services - sync with NetBSD-8
[minix.git] / crypto / external / bsd / heimdal / dist / lib / krb5 / transited.c
blob0ebc5ca9f9fa21773f146432a063e8155e96dfa2
1 /* $NetBSD: transited.c,v 1.1.1.2 2014/04/24 12:45:51 pettai Exp $ */
3 /*
4 * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include "krb5_locl.h"
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 */
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;
51 static void
52 free_realms(struct tr_realm *r)
54 struct tr_realm *p;
55 while(r){
56 p = r;
57 r = r->next;
58 free(p->realm);
59 free(p);
63 static int
64 make_path(krb5_context context, struct tr_realm *r,
65 const char *from, const char *to)
67 struct tr_realm *tmp;
68 const char *p;
70 if(strlen(from) < strlen(to)){
71 const char *str;
72 str = from;
73 from = to;
74 to = str;
77 if(strcmp(from + strlen(from) - strlen(to), to) == 0){
78 p = from;
79 while(1){
80 p = strchr(p, '.');
81 if(p == NULL) {
82 krb5_clear_error_message (context);
83 return KRB5KDC_ERR_POLICY;
85 p++;
86 if(strcmp(p, to) == 0)
87 break;
88 tmp = calloc(1, sizeof(*tmp));
89 if(tmp == NULL)
90 return krb5_enomem(context);
91 tmp->next = r->next;
92 r->next = tmp;
93 tmp->realm = strdup(p);
94 if(tmp->realm == NULL){
95 r->next = tmp->next;
96 free(tmp);
97 return krb5_enomem(context);
100 }else if(strncmp(from, to, strlen(to)) == 0){
101 p = from + strlen(from);
102 while(1){
103 while(p >= from && *p != '/') p--;
104 if(p == from)
105 return KRB5KDC_ERR_POLICY;
107 if(strncmp(to, from, p - from) == 0)
108 break;
109 tmp = calloc(1, sizeof(*tmp));
110 if(tmp == NULL)
111 return krb5_enomem(context);
112 tmp->next = r->next;
113 r->next = tmp;
114 tmp->realm = malloc(p - from + 1);
115 if(tmp->realm == NULL){
116 r->next = tmp->next;
117 free(tmp);
118 return krb5_enomem(context);
120 memcpy(tmp->realm, from, p - from);
121 tmp->realm[p - from] = '\0';
122 p--;
124 } else {
125 krb5_clear_error_message (context);
126 return KRB5KDC_ERR_POLICY;
129 return 0;
132 static int
133 make_paths(krb5_context context,
134 struct tr_realm *realms, const char *client_realm,
135 const char *server_realm)
137 struct tr_realm *r;
138 int ret;
139 const char *prev_realm = client_realm;
140 const char *next_realm = NULL;
141 for(r = realms; r; r = r->next){
142 /* it *might* be that you can have more than one empty
143 component in a row, at least that's how I interpret the
144 "," exception in 1510 */
145 if(r->realm[0] == '\0'){
146 while(r->next && r->next->realm[0] == '\0')
147 r = r->next;
148 if(r->next)
149 next_realm = r->next->realm;
150 else
151 next_realm = server_realm;
152 ret = make_path(context, r, prev_realm, next_realm);
153 if(ret){
154 free_realms(realms);
155 return ret;
158 prev_realm = r->realm;
160 return 0;
163 static int
164 expand_realms(krb5_context context,
165 struct tr_realm *realms, const char *client_realm)
167 struct tr_realm *r;
168 const char *prev_realm = NULL;
169 for(r = realms; r; r = r->next){
170 if(r->trailing_dot){
171 char *tmp;
172 size_t len;
174 if(prev_realm == NULL)
175 prev_realm = client_realm;
177 len = strlen(r->realm) + strlen(prev_realm) + 1;
179 tmp = realloc(r->realm, len);
180 if(tmp == NULL){
181 free_realms(realms);
182 return krb5_enomem(context);
184 r->realm = tmp;
185 strlcat(r->realm, prev_realm, len);
186 }else if(r->leading_slash && !r->leading_space && prev_realm){
187 /* yet another exception: if you use x500-names, the
188 leading realm doesn't have to be "quoted" with a space */
189 char *tmp;
190 size_t len = strlen(r->realm) + strlen(prev_realm) + 1;
192 tmp = malloc(len);
193 if(tmp == NULL){
194 free_realms(realms);
195 return krb5_enomem(context);
197 strlcpy(tmp, prev_realm, len);
198 strlcat(tmp, r->realm, len);
199 free(r->realm);
200 r->realm = tmp;
202 prev_realm = r->realm;
204 return 0;
207 static struct tr_realm *
208 make_realm(char *realm)
210 struct tr_realm *r;
211 char *p, *q;
212 int quote = 0;
213 r = calloc(1, sizeof(*r));
214 if(r == NULL){
215 free(realm);
216 return NULL;
218 r->realm = realm;
219 for(p = q = r->realm; *p; p++){
220 if(p == r->realm && *p == ' '){
221 r->leading_space = 1;
222 continue;
224 if(q == r->realm && *p == '/')
225 r->leading_slash = 1;
226 if(quote){
227 *q++ = *p;
228 quote = 0;
229 continue;
231 if(*p == '\\'){
232 quote = 1;
233 continue;
235 if(p[0] == '.' && p[1] == '\0')
236 r->trailing_dot = 1;
237 *q++ = *p;
239 *q = '\0';
240 return r;
243 static struct tr_realm*
244 append_realm(struct tr_realm *head, struct tr_realm *r)
246 struct tr_realm *p;
247 if(head == NULL){
248 r->next = NULL;
249 return r;
251 p = head;
252 while(p->next) p = p->next;
253 p->next = r;
254 return head;
257 static int
258 decode_realms(krb5_context context,
259 const char *tr, int length, struct tr_realm **realms)
261 struct tr_realm *r = NULL;
263 char *tmp;
264 int quote = 0;
265 const char *start = tr;
266 int i;
268 for(i = 0; i < length; i++){
269 if(quote){
270 quote = 0;
271 continue;
273 if(tr[i] == '\\'){
274 quote = 1;
275 continue;
277 if(tr[i] == ','){
278 tmp = malloc(tr + i - start + 1);
279 if(tmp == NULL)
280 return krb5_enomem(context);
281 memcpy(tmp, start, tr + i - start);
282 tmp[tr + i - start] = '\0';
283 r = make_realm(tmp);
284 if(r == NULL){
285 free_realms(*realms);
286 return krb5_enomem(context);
288 *realms = append_realm(*realms, r);
289 start = tr + i + 1;
292 tmp = malloc(tr + i - start + 1);
293 if(tmp == NULL){
294 free(*realms);
295 return krb5_enomem(context);
297 memcpy(tmp, start, tr + i - start);
298 tmp[tr + i - start] = '\0';
299 r = make_realm(tmp);
300 if(r == NULL){
301 free_realms(*realms);
302 return krb5_enomem(context);
304 *realms = append_realm(*realms, r);
306 return 0;
310 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
311 krb5_domain_x500_decode(krb5_context context,
312 krb5_data tr, char ***realms, unsigned int *num_realms,
313 const char *client_realm, const char *server_realm)
315 struct tr_realm *r = NULL;
316 struct tr_realm *p, **q;
317 int ret;
319 if(tr.length == 0) {
320 *realms = NULL;
321 *num_realms = 0;
322 return 0;
325 /* split string in components */
326 ret = decode_realms(context, tr.data, tr.length, &r);
327 if(ret)
328 return ret;
330 /* apply prefix rule */
331 ret = expand_realms(context, r, client_realm);
332 if(ret)
333 return ret;
335 ret = make_paths(context, r, client_realm, server_realm);
336 if(ret)
337 return ret;
339 /* remove empty components and count realms */
340 *num_realms = 0;
341 for(q = &r; *q; ){
342 if((*q)->realm[0] == '\0'){
343 p = *q;
344 *q = (*q)->next;
345 free(p->realm);
346 free(p);
347 }else{
348 q = &(*q)->next;
349 (*num_realms)++;
352 if (*num_realms + 1 > UINT_MAX/sizeof(**realms))
353 return ERANGE;
356 char **R;
357 R = malloc((*num_realms + 1) * sizeof(*R));
358 if (R == NULL)
359 return krb5_enomem(context);
360 *realms = R;
361 while(r){
362 *R++ = r->realm;
363 p = r->next;
364 free(r);
365 r = p;
368 return 0;
371 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
372 krb5_domain_x500_encode(char **realms, unsigned int num_realms,
373 krb5_data *encoding)
375 char *s = NULL;
376 int len = 0;
377 unsigned int i;
378 krb5_data_zero(encoding);
379 if (num_realms == 0)
380 return 0;
381 for(i = 0; i < num_realms; i++){
382 len += strlen(realms[i]);
383 if(realms[i][0] == '/')
384 len++;
386 len += num_realms - 1;
387 s = malloc(len + 1);
388 if (s == NULL)
389 return ENOMEM;
390 *s = '\0';
391 for(i = 0; i < num_realms; i++){
392 if(i)
393 strlcat(s, ",", len + 1);
394 if(realms[i][0] == '/')
395 strlcat(s, " ", len + 1);
396 strlcat(s, realms[i], len + 1);
398 encoding->data = s;
399 encoding->length = strlen(s);
400 return 0;
403 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
404 krb5_check_transited(krb5_context context,
405 krb5_const_realm client_realm,
406 krb5_const_realm server_realm,
407 krb5_realm *realms,
408 unsigned int num_realms,
409 int *bad_realm)
411 char **tr_realms;
412 char **p;
413 size_t i;
415 if(num_realms == 0)
416 return 0;
418 tr_realms = krb5_config_get_strings(context, NULL,
419 "capaths",
420 client_realm,
421 server_realm,
422 NULL);
423 for(i = 0; i < num_realms; i++) {
424 for(p = tr_realms; p && *p; p++) {
425 if(strcmp(*p, realms[i]) == 0)
426 break;
428 if(p == NULL || *p == NULL) {
429 krb5_config_free_strings(tr_realms);
430 krb5_set_error_message (context, KRB5KRB_AP_ERR_ILL_CR_TKT,
431 N_("no transit allowed "
432 "through realm %s", ""),
433 realms[i]);
434 if(bad_realm)
435 *bad_realm = i;
436 return KRB5KRB_AP_ERR_ILL_CR_TKT;
439 krb5_config_free_strings(tr_realms);
440 return 0;
443 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
444 krb5_check_transited_realms(krb5_context context,
445 const char *const *realms,
446 unsigned int num_realms,
447 int *bad_realm)
449 size_t i;
450 int ret = 0;
451 char **bad_realms = krb5_config_get_strings(context, NULL,
452 "libdefaults",
453 "transited_realms_reject",
454 NULL);
455 if(bad_realms == NULL)
456 return 0;
458 for(i = 0; i < num_realms; i++) {
459 char **p;
460 for(p = bad_realms; *p; p++)
461 if(strcmp(*p, realms[i]) == 0) {
462 ret = KRB5KRB_AP_ERR_ILL_CR_TKT;
463 krb5_set_error_message (context, ret,
464 N_("no transit allowed "
465 "through realm %s", ""),
466 *p);
467 if(bad_realm)
468 *bad_realm = i;
469 break;
472 krb5_config_free_strings(bad_realms);
473 return ret;
476 #if 0
478 main(int argc, char **argv)
480 krb5_data x;
481 char **r;
482 int num, i;
483 x.data = argv[1];
484 x.length = strlen(x.data);
485 if(domain_expand(x, &r, &num, argv[2], argv[3]))
486 exit(1);
487 for(i = 0; i < num; i++)
488 printf("%s\n", r[i]);
489 return 0;
491 #endif