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