1 /*
2 * Copyright (c) 1997-2002 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 #ifdef HAVE_RES_SEARCH
36 #define USE_RESOLVER
37 #endif
38 #ifdef HAVE_ARPA_NAMESER_H
39 #include <arpa/nameser.h>
40 #endif
41 #include <fnmatch.h>
42 #include "resolve.h"
43
44 RCSID("$Id: principal.c,v 1.99 2006/10/18 06:53:22 lha Exp $");
45
46 #define princ_num_comp(P) ((P)->name.name_string.len)
47 #define princ_type(P) ((P)->name.name_type)
48 #define princ_comp(P) ((P)->name.name_string.val)
49 #define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
50 #define princ_realm(P) ((P)->realm)
51
52 void KRB5_LIB_FUNCTION
krb5_free_principal(krb5_context context,krb5_principal p)53 krb5_free_principal(krb5_context context,
54 krb5_principal p)
55 {
56 if(p){
57 free_Principal(p);
58 free(p);
59 }
60 }
61
62 void KRB5_LIB_FUNCTION
krb5_principal_set_type(krb5_context context,krb5_principal principal,int type)63 krb5_principal_set_type(krb5_context context,
64 krb5_principal principal,
65 int type)
66 {
67 princ_type(principal) = type;
68 }
69
70 int KRB5_LIB_FUNCTION
krb5_principal_get_type(krb5_context context,krb5_const_principal principal)71 krb5_principal_get_type(krb5_context context,
72 krb5_const_principal principal)
73 {
74 return princ_type(principal);
75 }
76
77 const char* KRB5_LIB_FUNCTION
krb5_principal_get_realm(krb5_context context,krb5_const_principal principal)78 krb5_principal_get_realm(krb5_context context,
79 krb5_const_principal principal)
80 {
81 return princ_realm(principal);
82 }
83
84 const char* KRB5_LIB_FUNCTION
krb5_principal_get_comp_string(krb5_context context,krb5_const_principal principal,unsigned int component)85 krb5_principal_get_comp_string(krb5_context context,
86 krb5_const_principal principal,
87 unsigned int component)
88 {
89 if(component >= princ_num_comp(principal))
90 return NULL;
91 return princ_ncomp(principal, component);
92 }
93
94 krb5_error_code KRB5_LIB_FUNCTION
krb5_parse_name_flags(krb5_context context,const char * name,int flags,krb5_principal * principal)95 krb5_parse_name_flags(krb5_context context,
96 const char *name,
97 int flags,
98 krb5_principal *principal)
99 {
100 krb5_error_code ret;
101 heim_general_string *comp;
102 heim_general_string realm = NULL;
103 int ncomp;
104
105 const char *p;
106 char *q;
107 char *s;
108 char *start;
109
110 int n;
111 char c;
112 int got_realm = 0;
113
114 *principal = NULL;
115
116 #define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_MUST_REALM)
117
118 if ((flags & RFLAGS) == RFLAGS) {
119 krb5_set_error_string(context, "Can't require both realm and "
120 "no realm at the same time");
121 return KRB5_ERR_NO_SERVICE;
122 }
123 #undef RFLAGS
124
125 /* count number of component */
126 ncomp = 1;
127 for(p = name; *p; p++){
128 if(*p=='\\'){
129 if(!p[1]) {
130 krb5_set_error_string (context,
131 "trailing \\ in principal name");
132 return KRB5_PARSE_MALFORMED;
133 }
134 p++;
135 } else if(*p == '/')
136 ncomp++;
137 }
138 comp = calloc(ncomp, sizeof(*comp));
139 if (comp == NULL) {
140 krb5_set_error_string (context, "malloc: out of memory");
141 return ENOMEM;
142 }
143
144 n = 0;
145 p = start = q = s = strdup(name);
146 if (start == NULL) {
147 free (comp);
148 krb5_set_error_string (context, "malloc: out of memory");
149 return ENOMEM;
150 }
151 while(*p){
152 c = *p++;
153 if(c == '\\'){
154 c = *p++;
155 if(c == 'n')
156 c = '\n';
157 else if(c == 't')
158 c = '\t';
159 else if(c == 'b')
160 c = '\b';
161 else if(c == '0')
162 c = '\0';
163 else if(c == '\0') {
164 krb5_set_error_string (context,
165 "trailing \\ in principal name");
166 ret = KRB5_PARSE_MALFORMED;
167 goto exit;
168 }
169 }else if(c == '/' || c == '@'){
170 if(got_realm){
171 krb5_set_error_string (context,
172 "part after realm in principal name");
173 ret = KRB5_PARSE_MALFORMED;
174 goto exit;
175 }else{
176 comp[n] = malloc(q - start + 1);
177 if (comp[n] == NULL) {
178 krb5_set_error_string (context, "malloc: out of memory");
179 ret = ENOMEM;
180 goto exit;
181 }
182 memcpy(comp[n], start, q - start);
183 comp[n][q - start] = 0;
184 n++;
185 }
186 if(c == '@')
187 got_realm = 1;
188 start = q;
189 continue;
190 }
191 if(got_realm && (c == ':' || c == '/' || c == '\0')) {
192 krb5_set_error_string (context,
193 "part after realm in principal name");
194 ret = KRB5_PARSE_MALFORMED;
195 goto exit;
196 }
197 *q++ = c;
198 }
199 if(got_realm){
200 if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
201 krb5_set_error_string (context, "realm found in 'short' principal "
202 "expected to be without one");
203 ret = KRB5_PARSE_MALFORMED;
204 goto exit;
205 }
206 realm = malloc(q - start + 1);
207 if (realm == NULL) {
208 krb5_set_error_string (context, "malloc: out of memory");
209 ret = ENOMEM;
210 goto exit;
211 }
212 memcpy(realm, start, q - start);
213 realm[q - start] = 0;
214 }else{
215 if (flags & KRB5_PRINCIPAL_PARSE_MUST_REALM) {
216 krb5_set_error_string (context, "realm NOT found in principal "
217 "expected to be with one");
218 ret = KRB5_PARSE_MALFORMED;
219 goto exit;
220 } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
221 realm = NULL;
222 } else {
223 ret = krb5_get_default_realm (context, &realm);
224 if (ret)
225 goto exit;
226 }
227
228 comp[n] = malloc(q - start + 1);
229 if (comp[n] == NULL) {
230 krb5_set_error_string (context, "malloc: out of memory");
231 ret = ENOMEM;
232 goto exit;
233 }
234 memcpy(comp[n], start, q - start);
235 comp[n][q - start] = 0;
236 n++;
237 }
238 *principal = malloc(sizeof(**principal));
239 if (*principal == NULL) {
240 krb5_set_error_string (context, "malloc: out of memory");
241 ret = ENOMEM;
242 goto exit;
243 }
244 (*principal)->name.name_type = KRB5_NT_PRINCIPAL;
245 (*principal)->name.name_string.val = comp;
246 princ_num_comp(*principal) = n;
247 (*principal)->realm = realm;
248 free(s);
249 return 0;
250 exit:
251 while(n>0){
252 free(comp[--n]);
253 }
254 free(comp);
255 free(realm);
256 free(s);
257 return ret;
258 }
259
260 krb5_error_code KRB5_LIB_FUNCTION
krb5_parse_name(krb5_context context,const char * name,krb5_principal * principal)261 krb5_parse_name(krb5_context context,
262 const char *name,
263 krb5_principal *principal)
264 {
265 return krb5_parse_name_flags(context, name, 0, principal);
266 }
267
268 static const char quotable_chars[] = " \n\t\b\\/@";
269 static const char replace_chars[] = " ntb\\/@";
270
271 #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
272
273 static size_t
quote_string(const char * s,char * out,size_t idx,size_t len)274 quote_string(const char *s, char *out, size_t idx, size_t len)
275 {
276 const char *p, *q;
277 for(p = s; *p && idx < len; p++){
278 if((q = strchr(quotable_chars, *p))){
279 add_char(out, idx, len, '\\');
280 add_char(out, idx, len, replace_chars[q - quotable_chars]);
281 }else
282 add_char(out, idx, len, *p);
283 }
284 if(idx < len)
285 out[idx] = '\0';
286 return idx;
287 }
288
289
290 static krb5_error_code
unparse_name_fixed(krb5_context context,krb5_const_principal principal,char * name,size_t len,int flags)291 unparse_name_fixed(krb5_context context,
292 krb5_const_principal principal,
293 char *name,
294 size_t len,
295 int flags)
296 {
297 size_t idx = 0;
298 int i;
299 int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0;
300 int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0;
301
302 if (!no_realm && princ_realm(principal) == NULL) {
303 krb5_set_error_string(context, "Realm missing from principal, "
304 "can't unparse");
305 return ERANGE;
306 }
307
308 for(i = 0; i < princ_num_comp(principal); i++){
309 if(i)
310 add_char(name, idx, len, '/');
311 idx = quote_string(princ_ncomp(principal, i), name, idx, len);
312 if(idx == len) {
313 krb5_set_error_string(context, "Out of space printing principal");
314 return ERANGE;
315 }
316 }
317 /* add realm if different from default realm */
318 if(short_form && !no_realm) {
319 krb5_realm r;
320 krb5_error_code ret;
321 ret = krb5_get_default_realm(context, &r);
322 if(ret)
323 return ret;
324 if(strcmp(princ_realm(principal), r) != 0)
325 short_form = 0;
326 free(r);
327 }
328 if(!short_form && !no_realm) {
329 add_char(name, idx, len, '@');
330 idx = quote_string(princ_realm(principal), name, idx, len);
331 if(idx == len) {
332 krb5_set_error_string(context,
333 "Out of space printing realm of principal");
334 return ERANGE;
335 }
336 }
337 return 0;
338 }
339
340 krb5_error_code KRB5_LIB_FUNCTION
krb5_unparse_name_fixed(krb5_context context,krb5_const_principal principal,char * name,size_t len)341 krb5_unparse_name_fixed(krb5_context context,
342 krb5_const_principal principal,
343 char *name,
344 size_t len)
345 {
346 return unparse_name_fixed(context, principal, name, len, 0);
347 }
348
349 krb5_error_code KRB5_LIB_FUNCTION
krb5_unparse_name_fixed_short(krb5_context context,krb5_const_principal principal,char * name,size_t len)350 krb5_unparse_name_fixed_short(krb5_context context,
351 krb5_const_principal principal,
352 char *name,
353 size_t len)
354 {
355 return unparse_name_fixed(context, principal, name, len,
356 KRB5_PRINCIPAL_UNPARSE_SHORT);
357 }
358
359 krb5_error_code KRB5_LIB_FUNCTION
krb5_unparse_name_fixed_flags(krb5_context context,krb5_const_principal principal,int flags,char * name,size_t len)360 krb5_unparse_name_fixed_flags(krb5_context context,
361 krb5_const_principal principal,
362 int flags,
363 char *name,
364 size_t len)
365 {
366 return unparse_name_fixed(context, principal, name, len, flags);
367 }
368
369 static krb5_error_code
unparse_name(krb5_context context,krb5_const_principal principal,char ** name,int flags)370 unparse_name(krb5_context context,
371 krb5_const_principal principal,
372 char **name,
373 int flags)
374 {
375 size_t len = 0, plen;
376 int i;
377 krb5_error_code ret;
378 /* count length */
379 if (princ_realm(principal)) {
380 plen = strlen(princ_realm(principal));
381
382 if(strcspn(princ_realm(principal), quotable_chars) == plen)
383 len += plen;
384 else
385 len += 2*plen;
386 len++; /* '@' */
387 }
388 for(i = 0; i < princ_num_comp(principal); i++){
389 plen = strlen(princ_ncomp(principal, i));
390 if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen)
391 len += plen;
392 else
393 len += 2*plen;
394 len++;
395 }
396 len++; /* '\0' */
397 *name = malloc(len);
398 if(*name == NULL) {
399 krb5_set_error_string (context, "malloc: out of memory");
400 return ENOMEM;
401 }
402 ret = unparse_name_fixed(context, principal, *name, len, flags);
403 if(ret) {
404 free(*name);
405 *name = NULL;
406 }
407 return ret;
408 }
409
410 krb5_error_code KRB5_LIB_FUNCTION
krb5_unparse_name(krb5_context context,krb5_const_principal principal,char ** name)411 krb5_unparse_name(krb5_context context,
412 krb5_const_principal principal,
413 char **name)
414 {
415 return unparse_name(context, principal, name, 0);
416 }
417
418 krb5_error_code KRB5_LIB_FUNCTION
krb5_unparse_name_flags(krb5_context context,krb5_const_principal principal,int flags,char ** name)419 krb5_unparse_name_flags(krb5_context context,
420 krb5_const_principal principal,
421 int flags,
422 char **name)
423 {
424 return unparse_name(context, principal, name, flags);
425 }
426
427 krb5_error_code KRB5_LIB_FUNCTION
krb5_unparse_name_short(krb5_context context,krb5_const_principal principal,char ** name)428 krb5_unparse_name_short(krb5_context context,
429 krb5_const_principal principal,
430 char **name)
431 {
432 return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT);
433 }
434
435 #if 0 /* not implemented */
436
437 krb5_error_code KRB5_LIB_FUNCTION
438 krb5_unparse_name_ext(krb5_context context,
439 krb5_const_principal principal,
440 char **name,
441 size_t *size)
442 {
443 krb5_abortx(context, "unimplemented krb5_unparse_name_ext called");
444 }
445
446 #endif
447
448 krb5_realm * KRB5_LIB_FUNCTION
krb5_princ_realm(krb5_context context,krb5_principal principal)449 krb5_princ_realm(krb5_context context,
450 krb5_principal principal)
451 {
452 return &princ_realm(principal);
453 }
454
455
456 void KRB5_LIB_FUNCTION
krb5_princ_set_realm(krb5_context context,krb5_principal principal,krb5_realm * realm)457 krb5_princ_set_realm(krb5_context context,
458 krb5_principal principal,
459 krb5_realm *realm)
460 {
461 princ_realm(principal) = *realm;
462 }
463
464
465 krb5_error_code KRB5_LIB_FUNCTION
krb5_build_principal(krb5_context context,krb5_principal * principal,int rlen,krb5_const_realm realm,...)466 krb5_build_principal(krb5_context context,
467 krb5_principal *principal,
468 int rlen,
469 krb5_const_realm realm,
470 ...)
471 {
472 krb5_error_code ret;
473 va_list ap;
474 va_start(ap, realm);
475 ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
476 va_end(ap);
477 return ret;
478 }
479
480 static krb5_error_code
append_component(krb5_context context,krb5_principal p,const char * comp,size_t comp_len)481 append_component(krb5_context context, krb5_principal p,
482 const char *comp,
483 size_t comp_len)
484 {
485 heim_general_string *tmp;
486 size_t len = princ_num_comp(p);
487
488 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
489 if(tmp == NULL) {
490 krb5_set_error_string (context, "malloc: out of memory");
491 return ENOMEM;
492 }
493 princ_comp(p) = tmp;
494 princ_ncomp(p, len) = malloc(comp_len + 1);
495 if (princ_ncomp(p, len) == NULL) {
496 krb5_set_error_string (context, "malloc: out of memory");
497 return ENOMEM;
498 }
499 memcpy (princ_ncomp(p, len), comp, comp_len);
500 princ_ncomp(p, len)[comp_len] = '\0';
501 princ_num_comp(p)++;
502 return 0;
503 }
504
505 static void
va_ext_princ(krb5_context context,krb5_principal p,va_list ap)506 va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
507 {
508 while(1){
509 const char *s;
510 int len;
511 len = va_arg(ap, int);
512 if(len == 0)
513 break;
514 s = va_arg(ap, const char*);
515 append_component(context, p, s, len);
516 }
517 }
518
519 static void
va_princ(krb5_context context,krb5_principal p,va_list ap)520 va_princ(krb5_context context, krb5_principal p, va_list ap)
521 {
522 while(1){
523 const char *s;
524 s = va_arg(ap, const char*);
525 if(s == NULL)
526 break;
527 append_component(context, p, s, strlen(s));
528 }
529 }
530
531
532 static krb5_error_code
build_principal(krb5_context context,krb5_principal * principal,int rlen,krb5_const_realm realm,void (* func)(krb5_context,krb5_principal,va_list),va_list ap)533 build_principal(krb5_context context,
534 krb5_principal *principal,
535 int rlen,
536 krb5_const_realm realm,
537 void (*func)(krb5_context, krb5_principal, va_list),
538 va_list ap)
539 {
540 krb5_principal p;
541
542 p = calloc(1, sizeof(*p));
543 if (p == NULL) {
544 krb5_set_error_string (context, "malloc: out of memory");
545 return ENOMEM;
546 }
547 princ_type(p) = KRB5_NT_PRINCIPAL;
548
549 princ_realm(p) = strdup(realm);
550 if(p->realm == NULL){
551 free(p);
552 krb5_set_error_string (context, "malloc: out of memory");
553 return ENOMEM;
554 }
555
556 (*func)(context, p, ap);
557 *principal = p;
558 return 0;
559 }
560
561 krb5_error_code KRB5_LIB_FUNCTION
krb5_make_principal(krb5_context context,krb5_principal * principal,krb5_const_realm realm,...)562 krb5_make_principal(krb5_context context,
563 krb5_principal *principal,
564 krb5_const_realm realm,
565 ...)
566 {
567 krb5_error_code ret;
568 krb5_realm r = NULL;
569 va_list ap;
570 if(realm == NULL) {
571 ret = krb5_get_default_realm(context, &r);
572 if(ret)
573 return ret;
574 realm = r;
575 }
576 va_start(ap, realm);
577 ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
578 va_end(ap);
579 if(r)
580 free(r);
581 return ret;
582 }
583
584 krb5_error_code KRB5_LIB_FUNCTION
krb5_build_principal_va(krb5_context context,krb5_principal * principal,int rlen,krb5_const_realm realm,va_list ap)585 krb5_build_principal_va(krb5_context context,
586 krb5_principal *principal,
587 int rlen,
588 krb5_const_realm realm,
589 va_list ap)
590 {
591 return build_principal(context, principal, rlen, realm, va_princ, ap);
592 }
593
594 krb5_error_code KRB5_LIB_FUNCTION
krb5_build_principal_va_ext(krb5_context context,krb5_principal * principal,int rlen,krb5_const_realm realm,va_list ap)595 krb5_build_principal_va_ext(krb5_context context,
596 krb5_principal *principal,
597 int rlen,
598 krb5_const_realm realm,
599 va_list ap)
600 {
601 return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
602 }
603
604
605 krb5_error_code KRB5_LIB_FUNCTION
krb5_build_principal_ext(krb5_context context,krb5_principal * principal,int rlen,krb5_const_realm realm,...)606 krb5_build_principal_ext(krb5_context context,
607 krb5_principal *principal,
608 int rlen,
609 krb5_const_realm realm,
610 ...)
611 {
612 krb5_error_code ret;
613 va_list ap;
614 va_start(ap, realm);
615 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
616 va_end(ap);
617 return ret;
618 }
619
620
621 krb5_error_code KRB5_LIB_FUNCTION
krb5_copy_principal(krb5_context context,krb5_const_principal inprinc,krb5_principal * outprinc)622 krb5_copy_principal(krb5_context context,
623 krb5_const_principal inprinc,
624 krb5_principal *outprinc)
625 {
626 krb5_principal p = malloc(sizeof(*p));
627 if (p == NULL) {
628 krb5_set_error_string (context, "malloc: out of memory");
629 return ENOMEM;
630 }
631 if(copy_Principal(inprinc, p)) {
632 free(p);
633 krb5_set_error_string (context, "malloc: out of memory");
634 return ENOMEM;
635 }
636 *outprinc = p;
637 return 0;
638 }
639
640 /*
641 * return TRUE iff princ1 == princ2 (without considering the realm)
642 */
643
644 krb5_boolean KRB5_LIB_FUNCTION
krb5_principal_compare_any_realm(krb5_context context,krb5_const_principal princ1,krb5_const_principal princ2)645 krb5_principal_compare_any_realm(krb5_context context,
646 krb5_const_principal princ1,
647 krb5_const_principal princ2)
648 {
649 int i;
650 if(princ_num_comp(princ1) != princ_num_comp(princ2))
651 return FALSE;
652 for(i = 0; i < princ_num_comp(princ1); i++){
653 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
654 return FALSE;
655 }
656 return TRUE;
657 }
658
659 /*
660 * return TRUE iff princ1 == princ2
661 */
662
663 krb5_boolean KRB5_LIB_FUNCTION
krb5_principal_compare(krb5_context context,krb5_const_principal princ1,krb5_const_principal princ2)664 krb5_principal_compare(krb5_context context,
665 krb5_const_principal princ1,
666 krb5_const_principal princ2)
667 {
668 if(!krb5_realm_compare(context, princ1, princ2))
669 return FALSE;
670 return krb5_principal_compare_any_realm(context, princ1, princ2);
671 }
672
673 /*
674 * return TRUE iff realm(princ1) == realm(princ2)
675 */
676
677 krb5_boolean KRB5_LIB_FUNCTION
krb5_realm_compare(krb5_context context,krb5_const_principal princ1,krb5_const_principal princ2)678 krb5_realm_compare(krb5_context context,
679 krb5_const_principal princ1,
680 krb5_const_principal princ2)
681 {
682 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
683 }
684
685 /*
686 * return TRUE iff princ matches pattern
687 */
688
689 krb5_boolean KRB5_LIB_FUNCTION
krb5_principal_match(krb5_context context,krb5_const_principal princ,krb5_const_principal pattern)690 krb5_principal_match(krb5_context context,
691 krb5_const_principal princ,
692 krb5_const_principal pattern)
693 {
694 int i;
695 if(princ_num_comp(princ) != princ_num_comp(pattern))
696 return FALSE;
697 if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0)
698 return FALSE;
699 for(i = 0; i < princ_num_comp(princ); i++){
700 if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0)
701 return FALSE;
702 }
703 return TRUE;
704 }
705
706
707 static struct v4_name_convert {
708 const char *from;
709 const char *to;
710 } default_v4_name_convert[] = {
711 { "ftp", "ftp" },
712 { "hprop", "hprop" },
713 { "pop", "pop" },
714 { "imap", "imap" },
715 { "rcmd", "host" },
716 { "smtp", "smtp" },
717 { NULL, NULL }
718 };
719
720 /*
721 * return the converted instance name of `name' in `realm'.
722 * look in the configuration file and then in the default set above.
723 * return NULL if no conversion is appropriate.
724 */
725
726 static const char*
get_name_conversion(krb5_context context,const char * realm,const char * name)727 get_name_conversion(krb5_context context, const char *realm, const char *name)
728 {
729 struct v4_name_convert *q;
730 const char *p;
731
732 p = krb5_config_get_string(context, NULL, "realms", realm,
733 "v4_name_convert", "host", name, NULL);
734 if(p == NULL)
735 p = krb5_config_get_string(context, NULL, "libdefaults",
736 "v4_name_convert", "host", name, NULL);
737 if(p)
738 return p;
739
740 /* XXX should be possible to override default list */
741 p = krb5_config_get_string(context, NULL,
742 "realms",
743 realm,
744 "v4_name_convert",
745 "plain",
746 name,
747 NULL);
748 if(p)
749 return NULL;
750 p = krb5_config_get_string(context, NULL,
751 "libdefaults",
752 "v4_name_convert",
753 "plain",
754 name,
755 NULL);
756 if(p)
757 return NULL;
758 for(q = default_v4_name_convert; q->from; q++)
759 if(strcmp(q->from, name) == 0)
760 return q->to;
761 return NULL;
762 }
763
764 /*
765 * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'.
766 * if `resolve', use DNS.
767 * if `func', use that function for validating the conversion
768 */
769
770 krb5_error_code KRB5_LIB_FUNCTION
krb5_425_conv_principal_ext2(krb5_context context,const char * name,const char * instance,const char * realm,krb5_boolean (* func)(krb5_context,void *,krb5_principal),void * funcctx,krb5_boolean resolve,krb5_principal * princ)771 krb5_425_conv_principal_ext2(krb5_context context,
772 const char *name,
773 const char *instance,
774 const char *realm,
775 krb5_boolean (*func)(krb5_context,
776 void *, krb5_principal),
777 void *funcctx,
778 krb5_boolean resolve,
779 krb5_principal *princ)
780 {
781 const char *p;
782 krb5_error_code ret;
783 krb5_principal pr;
784 char host[MAXHOSTNAMELEN];
785 char local_hostname[MAXHOSTNAMELEN];
786
787 /* do the following: if the name is found in the
788 `v4_name_convert:host' part, is is assumed to be a `host' type
789 principal, and the instance is looked up in the
790 `v4_instance_convert' part. if not found there the name is
791 (optionally) looked up as a hostname, and if that doesn't yield
792 anything, the `default_domain' is appended to the instance
793 */
794
795 if(instance == NULL)
796 goto no_host;
797 if(instance[0] == 0){
798 instance = NULL;
799 goto no_host;
800 }
801 p = get_name_conversion(context, realm, name);
802 if(p == NULL)
803 goto no_host;
804 name = p;
805 p = krb5_config_get_string(context, NULL, "realms", realm,
806 "v4_instance_convert", instance, NULL);
807 if(p){
808 instance = p;
809 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
810 if(func == NULL || (*func)(context, funcctx, pr)){
811 *princ = pr;
812 return 0;
813 }
814 krb5_free_principal(context, pr);
815 *princ = NULL;
816 krb5_clear_error_string (context);
817 return HEIM_ERR_V4_PRINC_NO_CONV;
818 }
819 if(resolve){
820 krb5_boolean passed = FALSE;
821 char *inst = NULL;
822 #ifdef USE_RESOLVER
823 struct dns_reply *r;
824
825 r = dns_lookup(instance, "aaaa");
826 if (r) {
827 if (r->head && r->head->type == T_AAAA) {
828 inst = strdup(r->head->domain);
829 passed = TRUE;
830 }
831 dns_free_data(r);
832 } else {
833 r = dns_lookup(instance, "a");
834 if (r) {
835 if(r->head && r->head->type == T_A) {
836 inst = strdup(r->head->domain);
837 passed = TRUE;
838 }
839 dns_free_data(r);
840 }
841 }
842 #else
843 struct addrinfo hints, *ai;
844
845 memset (&hints, 0, sizeof(hints));
846 hints.ai_flags = AI_CANONNAME;
847 ret = getaddrinfo(instance, NULL, &hints, &ai);
848 if (ret == 0) {
849 const struct addrinfo *a;
850 for (a = ai; a != NULL; a = a->ai_next) {
851 if (a->ai_canonname != NULL) {
852 inst = strdup (a->ai_canonname);
853 passed = TRUE;
854 break;
855 }
856 }
857 freeaddrinfo (ai);
858 }
859 #endif
860 if (passed) {
861 if (inst == NULL) {
862 krb5_set_error_string (context, "malloc: out of memory");
863 return ENOMEM;
864 }
865 strlwr(inst);
866 ret = krb5_make_principal(context, &pr, realm, name, inst,
867 NULL);
868 free (inst);
869 if(ret == 0) {
870 if(func == NULL || (*func)(context, funcctx, pr)){
871 *princ = pr;
872 return 0;
873 }
874 krb5_free_principal(context, pr);
875 }
876 }
877 }
878 if(func != NULL) {
879 snprintf(host, sizeof(host), "%s.%s", instance, realm);
880 strlwr(host);
881 ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
882 if((*func)(context, funcctx, pr)){
883 *princ = pr;
884 return 0;
885 }
886 krb5_free_principal(context, pr);
887 }
888
889 /*
890 * if the instance is the first component of the local hostname,
891 * the converted host should be the long hostname.
892 */
893
894 if (func == NULL &&
895 gethostname (local_hostname, sizeof(local_hostname)) == 0 &&
896 strncmp(instance, local_hostname, strlen(instance)) == 0 &&
897 local_hostname[strlen(instance)] == '.') {
898 strlcpy(host, local_hostname, sizeof(host));
899 goto local_host;
900 }
901
902 {
903 char **domains, **d;
904 domains = krb5_config_get_strings(context, NULL, "realms", realm,
905 "v4_domains", NULL);
906 for(d = domains; d && *d; d++){
907 snprintf(host, sizeof(host), "%s.%s", instance, *d);
908 ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
909 if(func == NULL || (*func)(context, funcctx, pr)){
910 *princ = pr;
911 krb5_config_free_strings(domains);
912 return 0;
913 }
914 krb5_free_principal(context, pr);
915 }
916 krb5_config_free_strings(domains);
917 }
918
919
920 p = krb5_config_get_string(context, NULL, "realms", realm,
921 "default_domain", NULL);
922 if(p == NULL){
923 /* this should be an error, just faking a name is not good */
924 krb5_clear_error_string (context);
925 return HEIM_ERR_V4_PRINC_NO_CONV;
926 }
927
928 if (*p == '.')
929 ++p;
930 snprintf(host, sizeof(host), "%s.%s", instance, p);
931 local_host:
932 ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
933 if(func == NULL || (*func)(context, funcctx, pr)){
934 *princ = pr;
935 return 0;
936 }
937 krb5_free_principal(context, pr);
938 krb5_clear_error_string (context);
939 return HEIM_ERR_V4_PRINC_NO_CONV;
940 no_host:
941 p = krb5_config_get_string(context, NULL,
942 "realms",
943 realm,
944 "v4_name_convert",
945 "plain",
946 name,
947 NULL);
948 if(p == NULL)
949 p = krb5_config_get_string(context, NULL,
950 "libdefaults",
951 "v4_name_convert",
952 "plain",
953 name,
954 NULL);
955 if(p)
956 name = p;
957
958 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
959 if(func == NULL || (*func)(context, funcctx, pr)){
960 *princ = pr;
961 return 0;
962 }
963 krb5_free_principal(context, pr);
964 krb5_clear_error_string (context);
965 return HEIM_ERR_V4_PRINC_NO_CONV;
966 }
967
968 static krb5_boolean
convert_func(krb5_context conxtext,void * funcctx,krb5_principal principal)969 convert_func(krb5_context conxtext, void *funcctx, krb5_principal principal)
970 {
971 krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx;
972 return (*func)(conxtext, principal);
973 }
974
975 krb5_error_code KRB5_LIB_FUNCTION
krb5_425_conv_principal_ext(krb5_context context,const char * name,const char * instance,const char * realm,krb5_boolean (* func)(krb5_context,krb5_principal),krb5_boolean resolve,krb5_principal * principal)976 krb5_425_conv_principal_ext(krb5_context context,
977 const char *name,
978 const char *instance,
979 const char *realm,
980 krb5_boolean (*func)(krb5_context, krb5_principal),
981 krb5_boolean resolve,
982 krb5_principal *principal)
983 {
984 return krb5_425_conv_principal_ext2(context,
985 name,
986 instance,
987 realm,
988 func ? convert_func : NULL,
989 func,
990 resolve,
991 principal);
992 }
993
994
995
996 krb5_error_code KRB5_LIB_FUNCTION
krb5_425_conv_principal(krb5_context context,const char * name,const char * instance,const char * realm,krb5_principal * princ)997 krb5_425_conv_principal(krb5_context context,
998 const char *name,
999 const char *instance,
1000 const char *realm,
1001 krb5_principal *princ)
1002 {
1003 krb5_boolean resolve = krb5_config_get_bool(context,
1004 NULL,
1005 "libdefaults",
1006 "v4_instance_resolve",
1007 NULL);
1008
1009 return krb5_425_conv_principal_ext(context, name, instance, realm,
1010 NULL, resolve, princ);
1011 }
1012
1013
1014 static int
check_list(const krb5_config_binding * l,const char * name,const char ** out)1015 check_list(const krb5_config_binding *l, const char *name, const char **out)
1016 {
1017 while(l){
1018 if (l->type != krb5_config_string)
1019 continue;
1020 if(strcmp(name, l->u.string) == 0) {
1021 *out = l->name;
1022 return 1;
1023 }
1024 l = l->next;
1025 }
1026 return 0;
1027 }
1028
1029 static int
name_convert(krb5_context context,const char * name,const char * realm,const char ** out)1030 name_convert(krb5_context context, const char *name, const char *realm,
1031 const char **out)
1032 {
1033 const krb5_config_binding *l;
1034 l = krb5_config_get_list (context,
1035 NULL,
1036 "realms",
1037 realm,
1038 "v4_name_convert",
1039 "host",
1040 NULL);
1041 if(l && check_list(l, name, out))
1042 return KRB5_NT_SRV_HST;
1043 l = krb5_config_get_list (context,
1044 NULL,
1045 "libdefaults",
1046 "v4_name_convert",
1047 "host",
1048 NULL);
1049 if(l && check_list(l, name, out))
1050 return KRB5_NT_SRV_HST;
1051 l = krb5_config_get_list (context,
1052 NULL,
1053 "realms",
1054 realm,
1055 "v4_name_convert",
1056 "plain",
1057 NULL);
1058 if(l && check_list(l, name, out))
1059 return KRB5_NT_UNKNOWN;
1060 l = krb5_config_get_list (context,
1061 NULL,
1062 "libdefaults",
1063 "v4_name_convert",
1064 "host",
1065 NULL);
1066 if(l && check_list(l, name, out))
1067 return KRB5_NT_UNKNOWN;
1068
1069 /* didn't find it in config file, try built-in list */
1070 {
1071 struct v4_name_convert *q;
1072 for(q = default_v4_name_convert; q->from; q++) {
1073 if(strcmp(name, q->to) == 0) {
1074 *out = q->from;
1075 return KRB5_NT_SRV_HST;
1076 }
1077 }
1078 }
1079 return -1;
1080 }
1081
1082 /*
1083 * convert the v5 principal in `principal' into a v4 corresponding one
1084 * in `name, instance, realm'
1085 * this is limited interface since there's no length given for these
1086 * three parameters. They have to be 40 bytes each (ANAME_SZ).
1087 */
1088
1089 krb5_error_code KRB5_LIB_FUNCTION
krb5_524_conv_principal(krb5_context context,const krb5_principal principal,char * name,char * instance,char * realm)1090 krb5_524_conv_principal(krb5_context context,
1091 const krb5_principal principal,
1092 char *name,
1093 char *instance,
1094 char *realm)
1095 {
1096 const char *n, *i, *r;
1097 char tmpinst[40];
1098 int type = princ_type(principal);
1099 const int aname_sz = 40;
1100
1101 r = principal->realm;
1102
1103 switch(principal->name.name_string.len){
1104 case 1:
1105 n = principal->name.name_string.val[0];
1106 i = "";
1107 break;
1108 case 2:
1109 n = principal->name.name_string.val[0];
1110 i = principal->name.name_string.val[1];
1111 break;
1112 default:
1113 krb5_set_error_string (context,
1114 "cannot convert a %d component principal",
1115 principal->name.name_string.len);
1116 return KRB5_PARSE_MALFORMED;
1117 }
1118
1119 {
1120 const char *tmp;
1121 int t = name_convert(context, n, r, &tmp);
1122 if(t >= 0) {
1123 type = t;
1124 n = tmp;
1125 }
1126 }
1127
1128 if(type == KRB5_NT_SRV_HST){
1129 char *p;
1130
1131 strlcpy (tmpinst, i, sizeof(tmpinst));
1132 p = strchr(tmpinst, '.');
1133 if(p)
1134 *p = 0;
1135 i = tmpinst;
1136 }
1137
1138 if (strlcpy (name, n, aname_sz) >= aname_sz) {
1139 krb5_set_error_string (context,
1140 "too long name component to convert");
1141 return KRB5_PARSE_MALFORMED;
1142 }
1143 if (strlcpy (instance, i, aname_sz) >= aname_sz) {
1144 krb5_set_error_string (context,
1145 "too long instance component to convert");
1146 return KRB5_PARSE_MALFORMED;
1147 }
1148 if (strlcpy (realm, r, aname_sz) >= aname_sz) {
1149 krb5_set_error_string (context,
1150 "too long realm component to convert");
1151 return KRB5_PARSE_MALFORMED;
1152 }
1153 return 0;
1154 }
1155
1156 /*
1157 * Create a principal in `ret_princ' for the service `sname' running
1158 * on host `hostname'. */
1159
1160 krb5_error_code KRB5_LIB_FUNCTION
krb5_sname_to_principal(krb5_context context,const char * hostname,const char * sname,int32_t type,krb5_principal * ret_princ)1161 krb5_sname_to_principal (krb5_context context,
1162 const char *hostname,
1163 const char *sname,
1164 int32_t type,
1165 krb5_principal *ret_princ)
1166 {
1167 krb5_error_code ret;
1168 char localhost[MAXHOSTNAMELEN];
1169 char **realms, *host = NULL;
1170
1171 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) {
1172 krb5_set_error_string (context, "unsupported name type %d",
1173 type);
1174 return KRB5_SNAME_UNSUPP_NAMETYPE;
1175 }
1176 if(hostname == NULL) {
1177 gethostname(localhost, sizeof(localhost));
1178 hostname = localhost;
1179 }
1180 if(sname == NULL)
1181 sname = "host";
1182 if(type == KRB5_NT_SRV_HST) {
1183 ret = krb5_expand_hostname_realms (context, hostname,
1184 &host, &realms);
1185 if (ret)
1186 return ret;
1187 strlwr(host);
1188 hostname = host;
1189 } else {
1190 ret = krb5_get_host_realm(context, hostname, &realms);
1191 if(ret)
1192 return ret;
1193 }
1194
1195 ret = krb5_make_principal(context, ret_princ, realms[0], sname,
1196 hostname, NULL);
1197 if(host)
1198 free(host);
1199 krb5_free_host_realm(context, realms);
1200 return ret;
1201 }
1202