1 /* $NetBSD: principal.c,v 1.1.1.2 2014/04/24 12:45:51 pettai Exp $ */
2
3 /*
4 * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
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.
18 *
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.
22 *
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.
34 */
35
36 /**
37 * @page krb5_principal_intro The principal handing functions.
38 *
39 * A Kerberos principal is a email address looking string that
40 * contains to parts separeted by a @. The later part is the kerbero
41 * realm the principal belongs to and the former is a list of 0 or
42 * more components. For example
43 * @verbatim
44 lha@SU.SE
45 host/hummel.it.su.se@SU.SE
46 host/admin@H5L.ORG
47 @endverbatim
48 *
49 * See the library functions here: @ref krb5_principal
50 */
51
52 #include "krb5_locl.h"
53 #ifdef HAVE_RES_SEARCH
54 #define USE_RESOLVER
55 #endif
56 #ifdef HAVE_ARPA_NAMESER_H
57 #include <arpa/nameser.h>
58 #endif
59 #include <fnmatch.h>
60 #include <krb5/resolve.h>
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 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_free_principal(krb5_context context,krb5_principal p)82 krb5_free_principal(krb5_context context,
83 krb5_principal p)
84 {
85 if(p){
86 free_Principal(p);
87 free(p);
88 }
89 }
90
91 /**
92 * Set the type of the principal
93 *
94 * @param context A Kerberos context.
95 * @param principal principal to set the type for
96 * @param type the new type
97 *
98 * @return An krb5 error code, see krb5_get_error_message().
99 *
100 * @ingroup krb5_principal
101 */
102
103 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_principal_set_type(krb5_context context,krb5_principal principal,int type)104 krb5_principal_set_type(krb5_context context,
105 krb5_principal principal,
106 int type)
107 {
108 princ_type(principal) = type;
109 }
110
111 /**
112 * Get the type of the principal
113 *
114 * @param context A Kerberos context.
115 * @param principal principal to get the type for
116 *
117 * @return the type of principal
118 *
119 * @ingroup krb5_principal
120 */
121
122 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_principal_get_type(krb5_context context,krb5_const_principal principal)123 krb5_principal_get_type(krb5_context context,
124 krb5_const_principal principal)
125 {
126 return princ_type(principal);
127 }
128
129 /**
130 * Get the realm of the principal
131 *
132 * @param context A Kerberos context.
133 * @param principal principal to get the realm for
134 *
135 * @return realm of the principal, don't free or use after krb5_principal is freed
136 *
137 * @ingroup krb5_principal
138 */
139
140 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
krb5_principal_get_realm(krb5_context context,krb5_const_principal principal)141 krb5_principal_get_realm(krb5_context context,
142 krb5_const_principal principal)
143 {
144 return princ_realm(principal);
145 }
146
147 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
krb5_principal_get_comp_string(krb5_context context,krb5_const_principal principal,unsigned int component)148 krb5_principal_get_comp_string(krb5_context context,
149 krb5_const_principal principal,
150 unsigned int component)
151 {
152 if(component >= princ_num_comp(principal))
153 return NULL;
154 return princ_ncomp(principal, component);
155 }
156
157 /**
158 * Get number of component is principal.
159 *
160 * @param context Kerberos 5 context
161 * @param principal principal to query
162 *
163 * @return number of components in string
164 *
165 * @ingroup krb5_principal
166 */
167
168 KRB5_LIB_FUNCTION unsigned int KRB5_LIB_CALL
krb5_principal_get_num_comp(krb5_context context,krb5_const_principal principal)169 krb5_principal_get_num_comp(krb5_context context,
170 krb5_const_principal principal)
171 {
172 return princ_num_comp(principal);
173 }
174
175 /**
176 * Parse a name into a krb5_principal structure, flags controls the behavior.
177 *
178 * @param context Kerberos 5 context
179 * @param name name to parse into a Kerberos principal
180 * @param flags flags to control the behavior
181 * @param principal returned principal, free with krb5_free_principal().
182 *
183 * @return An krb5 error code, see krb5_get_error_message().
184 *
185 * @ingroup krb5_principal
186 */
187
188 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_parse_name_flags(krb5_context context,const char * name,int flags,krb5_principal * principal)189 krb5_parse_name_flags(krb5_context context,
190 const char *name,
191 int flags,
192 krb5_principal *principal)
193 {
194 krb5_error_code ret;
195 heim_general_string *comp;
196 heim_general_string realm = NULL;
197 int ncomp;
198
199 const char *p;
200 char *q;
201 char *s;
202 char *start;
203
204 int n;
205 char c;
206 int got_realm = 0;
207 int first_at = 1;
208 int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE);
209
210 *principal = NULL;
211
212 #define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_REQUIRE_REALM)
213
214 if ((flags & RFLAGS) == RFLAGS) {
215 krb5_set_error_message(context, KRB5_ERR_NO_SERVICE,
216 N_("Can't require both realm and "
217 "no realm at the same time", ""));
218 return KRB5_ERR_NO_SERVICE;
219 }
220 #undef RFLAGS
221
222 /* count number of component,
223 * enterprise names only have one component
224 */
225 ncomp = 1;
226 if (!enterprise) {
227 for(p = name; *p; p++){
228 if(*p=='\\'){
229 if(!p[1]) {
230 krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
231 N_("trailing \\ in principal name", ""));
232 return KRB5_PARSE_MALFORMED;
233 }
234 p++;
235 } else if(*p == '/')
236 ncomp++;
237 else if(*p == '@')
238 break;
239 }
240 }
241 comp = calloc(ncomp, sizeof(*comp));
242 if (comp == NULL) {
243 krb5_set_error_message(context, ENOMEM,
244 N_("malloc: out of memory", ""));
245 return ENOMEM;
246 }
247
248 n = 0;
249 p = start = q = s = strdup(name);
250 if (start == NULL) {
251 free (comp);
252 krb5_set_error_message(context, ENOMEM,
253 N_("malloc: out of memory", ""));
254 return ENOMEM;
255 }
256 while(*p){
257 c = *p++;
258 if(c == '\\'){
259 c = *p++;
260 if(c == 'n')
261 c = '\n';
262 else if(c == 't')
263 c = '\t';
264 else if(c == 'b')
265 c = '\b';
266 else if(c == '0')
267 c = '\0';
268 else if(c == '\0') {
269 ret = KRB5_PARSE_MALFORMED;
270 krb5_set_error_message(context, ret,
271 N_("trailing \\ in principal name", ""));
272 goto exit;
273 }
274 }else if(enterprise && first_at) {
275 if (c == '@')
276 first_at = 0;
277 }else if((c == '/' && !enterprise) || c == '@'){
278 if(got_realm){
279 ret = KRB5_PARSE_MALFORMED;
280 krb5_set_error_message(context, ret,
281 N_("part after realm in principal name", ""));
282 goto exit;
283 }else{
284 comp[n] = malloc(q - start + 1);
285 if (comp[n] == NULL) {
286 ret = ENOMEM;
287 krb5_set_error_message(context, ret,
288 N_("malloc: out of memory", ""));
289 goto exit;
290 }
291 memcpy(comp[n], start, q - start);
292 comp[n][q - start] = 0;
293 n++;
294 }
295 if(c == '@')
296 got_realm = 1;
297 start = q;
298 continue;
299 }
300 if(got_realm && (c == '/' || c == '\0')) {
301 ret = KRB5_PARSE_MALFORMED;
302 krb5_set_error_message(context, ret,
303 N_("part after realm in principal name", ""));
304 goto exit;
305 }
306 *q++ = c;
307 }
308 if(got_realm){
309 if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
310 ret = KRB5_PARSE_MALFORMED;
311 krb5_set_error_message(context, ret,
312 N_("realm found in 'short' principal "
313 "expected to be without one", ""));
314 goto exit;
315 }
316 realm = malloc(q - start + 1);
317 if (realm == NULL) {
318 ret = ENOMEM;
319 krb5_set_error_message(context, ret,
320 N_("malloc: out of memory", ""));
321 goto exit;
322 }
323 memcpy(realm, start, q - start);
324 realm[q - start] = 0;
325 }else{
326 if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) {
327 ret = KRB5_PARSE_MALFORMED;
328 krb5_set_error_message(context, ret,
329 N_("realm NOT found in principal "
330 "expected to be with one", ""));
331 goto exit;
332 } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
333 realm = NULL;
334 } else {
335 ret = krb5_get_default_realm (context, &realm);
336 if (ret)
337 goto exit;
338 }
339
340 comp[n] = malloc(q - start + 1);
341 if (comp[n] == NULL) {
342 ret = ENOMEM;
343 krb5_set_error_message(context, ret,
344 N_("malloc: out of memory", ""));
345 goto exit;
346 }
347 memcpy(comp[n], start, q - start);
348 comp[n][q - start] = 0;
349 n++;
350 }
351 *principal = malloc(sizeof(**principal));
352 if (*principal == NULL) {
353 ret = ENOMEM;
354 krb5_set_error_message(context, ret,
355 N_("malloc: out of memory", ""));
356 goto exit;
357 }
358 if (enterprise)
359 (*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL;
360 else
361 (*principal)->name.name_type = KRB5_NT_PRINCIPAL;
362 (*principal)->name.name_string.val = comp;
363 princ_num_comp(*principal) = n;
364 (*principal)->realm = realm;
365 free(s);
366 return 0;
367 exit:
368 while(n>0){
369 free(comp[--n]);
370 }
371 free(comp);
372 free(realm);
373 free(s);
374 return ret;
375 }
376
377 /**
378 * Parse a name into a krb5_principal structure
379 *
380 * @param context Kerberos 5 context
381 * @param name name to parse into a Kerberos principal
382 * @param principal returned principal, free with krb5_free_principal().
383 *
384 * @return An krb5 error code, see krb5_get_error_message().
385 *
386 * @ingroup krb5_principal
387 */
388
389 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_parse_name(krb5_context context,const char * name,krb5_principal * principal)390 krb5_parse_name(krb5_context context,
391 const char *name,
392 krb5_principal *principal)
393 {
394 return krb5_parse_name_flags(context, name, 0, principal);
395 }
396
397 static const char quotable_chars[] = " \n\t\b\\/@";
398 static const char replace_chars[] = " ntb\\/@";
399 static const char nq_chars[] = " \\/@";
400
401 #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
402
403 static size_t
quote_string(const char * s,char * out,size_t idx,size_t len,int display)404 quote_string(const char *s, char *out, size_t idx, size_t len, int display)
405 {
406 const char *p, *q;
407 for(p = s; *p && idx < len; p++){
408 q = strchr(quotable_chars, *p);
409 if (q && display) {
410 add_char(out, idx, len, replace_chars[q - quotable_chars]);
411 } else if (q) {
412 add_char(out, idx, len, '\\');
413 add_char(out, idx, len, replace_chars[q - quotable_chars]);
414 }else
415 add_char(out, idx, len, *p);
416 }
417 if(idx < len)
418 out[idx] = '\0';
419 return idx;
420 }
421
422
423 static krb5_error_code
unparse_name_fixed(krb5_context context,krb5_const_principal principal,char * name,size_t len,int flags)424 unparse_name_fixed(krb5_context context,
425 krb5_const_principal principal,
426 char *name,
427 size_t len,
428 int flags)
429 {
430 size_t idx = 0;
431 size_t i;
432 int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0;
433 int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0;
434 int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0;
435
436 if (!no_realm && princ_realm(principal) == NULL) {
437 krb5_set_error_message(context, ERANGE,
438 N_("Realm missing from principal, "
439 "can't unparse", ""));
440 return ERANGE;
441 }
442
443 for(i = 0; i < princ_num_comp(principal); i++){
444 if(i)
445 add_char(name, idx, len, '/');
446 idx = quote_string(princ_ncomp(principal, i), name, idx, len, display);
447 if(idx == len) {
448 krb5_set_error_message(context, ERANGE,
449 N_("Out of space printing principal", ""));
450 return ERANGE;
451 }
452 }
453 /* add realm if different from default realm */
454 if(short_form && !no_realm) {
455 krb5_realm r;
456 krb5_error_code ret;
457 ret = krb5_get_default_realm(context, &r);
458 if(ret)
459 return ret;
460 if(strcmp(princ_realm(principal), r) != 0)
461 short_form = 0;
462 free(r);
463 }
464 if(!short_form && !no_realm) {
465 add_char(name, idx, len, '@');
466 idx = quote_string(princ_realm(principal), name, idx, len, display);
467 if(idx == len) {
468 krb5_set_error_message(context, ERANGE,
469 N_("Out of space printing "
470 "realm of principal", ""));
471 return ERANGE;
472 }
473 }
474 return 0;
475 }
476
477 /**
478 * Unparse the principal name to a fixed buffer
479 *
480 * @param context A Kerberos context.
481 * @param principal principal to unparse
482 * @param name buffer to write name to
483 * @param len length of buffer
484 *
485 * @return An krb5 error code, see krb5_get_error_message().
486 *
487 * @ingroup krb5_principal
488 */
489
490 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_unparse_name_fixed(krb5_context context,krb5_const_principal principal,char * name,size_t len)491 krb5_unparse_name_fixed(krb5_context context,
492 krb5_const_principal principal,
493 char *name,
494 size_t len)
495 {
496 return unparse_name_fixed(context, principal, name, len, 0);
497 }
498
499 /**
500 * Unparse the principal name to a fixed buffer. The realm is skipped
501 * if its a default realm.
502 *
503 * @param context A Kerberos context.
504 * @param principal principal to unparse
505 * @param name buffer to write name to
506 * @param len length of buffer
507 *
508 * @return An krb5 error code, see krb5_get_error_message().
509 *
510 * @ingroup krb5_principal
511 */
512
513 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_unparse_name_fixed_short(krb5_context context,krb5_const_principal principal,char * name,size_t len)514 krb5_unparse_name_fixed_short(krb5_context context,
515 krb5_const_principal principal,
516 char *name,
517 size_t len)
518 {
519 return unparse_name_fixed(context, principal, name, len,
520 KRB5_PRINCIPAL_UNPARSE_SHORT);
521 }
522
523 /**
524 * Unparse the principal name with unparse flags to a fixed buffer.
525 *
526 * @param context A Kerberos context.
527 * @param principal principal to unparse
528 * @param flags unparse flags
529 * @param name buffer to write name to
530 * @param len length of buffer
531 *
532 * @return An krb5 error code, see krb5_get_error_message().
533 *
534 * @ingroup krb5_principal
535 */
536
537 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_unparse_name_fixed_flags(krb5_context context,krb5_const_principal principal,int flags,char * name,size_t len)538 krb5_unparse_name_fixed_flags(krb5_context context,
539 krb5_const_principal principal,
540 int flags,
541 char *name,
542 size_t len)
543 {
544 return unparse_name_fixed(context, principal, name, len, flags);
545 }
546
547 static krb5_error_code
unparse_name(krb5_context context,krb5_const_principal principal,char ** name,int flags)548 unparse_name(krb5_context context,
549 krb5_const_principal principal,
550 char **name,
551 int flags)
552 {
553 size_t len = 0, plen;
554 size_t i;
555 krb5_error_code ret;
556 /* count length */
557 if (princ_realm(principal)) {
558 plen = strlen(princ_realm(principal));
559
560 if(strcspn(princ_realm(principal), quotable_chars) == plen)
561 len += plen;
562 else
563 len += 2*plen;
564 len++; /* '@' */
565 }
566 for(i = 0; i < princ_num_comp(principal); i++){
567 plen = strlen(princ_ncomp(principal, i));
568 if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen)
569 len += plen;
570 else
571 len += 2*plen;
572 len++;
573 }
574 len++; /* '\0' */
575 *name = malloc(len);
576 if(*name == NULL) {
577 krb5_set_error_message(context, ENOMEM,
578 N_("malloc: out of memory", ""));
579 return ENOMEM;
580 }
581 ret = unparse_name_fixed(context, principal, *name, len, flags);
582 if(ret) {
583 free(*name);
584 *name = NULL;
585 }
586 return ret;
587 }
588
589 /**
590 * Unparse the Kerberos name into a string
591 *
592 * @param context Kerberos 5 context
593 * @param principal principal to query
594 * @param name resulting string, free with krb5_xfree()
595 *
596 * @return An krb5 error code, see krb5_get_error_message().
597 *
598 * @ingroup krb5_principal
599 */
600
601 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_unparse_name(krb5_context context,krb5_const_principal principal,char ** name)602 krb5_unparse_name(krb5_context context,
603 krb5_const_principal principal,
604 char **name)
605 {
606 return unparse_name(context, principal, name, 0);
607 }
608
609 /**
610 * Unparse the Kerberos name into a string
611 *
612 * @param context Kerberos 5 context
613 * @param principal principal to query
614 * @param flags flag to determine the behavior
615 * @param name resulting string, free with krb5_xfree()
616 *
617 * @return An krb5 error code, see krb5_get_error_message().
618 *
619 * @ingroup krb5_principal
620 */
621
622 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_unparse_name_flags(krb5_context context,krb5_const_principal principal,int flags,char ** name)623 krb5_unparse_name_flags(krb5_context context,
624 krb5_const_principal principal,
625 int flags,
626 char **name)
627 {
628 return unparse_name(context, principal, name, flags);
629 }
630
631 /**
632 * Unparse the principal name to a allocated buffer. The realm is
633 * skipped if its a default realm.
634 *
635 * @param context A Kerberos context.
636 * @param principal principal to unparse
637 * @param name returned buffer, free with krb5_xfree()
638 *
639 * @return An krb5 error code, see krb5_get_error_message().
640 *
641 * @ingroup krb5_principal
642 */
643
644 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_unparse_name_short(krb5_context context,krb5_const_principal principal,char ** name)645 krb5_unparse_name_short(krb5_context context,
646 krb5_const_principal principal,
647 char **name)
648 {
649 return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT);
650 }
651
652 /**
653 * Set a new realm for a principal, and as a side-effect free the
654 * previous realm.
655 *
656 * @param context A Kerberos context.
657 * @param principal principal set the realm for
658 * @param realm the new realm to set
659 *
660 * @return An krb5 error code, see krb5_get_error_message().
661 *
662 * @ingroup krb5_principal
663 */
664
665 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_principal_set_realm(krb5_context context,krb5_principal principal,krb5_const_realm realm)666 krb5_principal_set_realm(krb5_context context,
667 krb5_principal principal,
668 krb5_const_realm realm)
669 {
670 if (princ_realm(principal))
671 free(princ_realm(principal));
672
673 princ_realm(principal) = strdup(realm);
674 if (princ_realm(principal) == NULL) {
675 krb5_set_error_message(context, ENOMEM,
676 N_("malloc: out of memory", ""));
677 return ENOMEM;
678 }
679 return 0;
680 }
681
682 #ifndef HEIMDAL_SMALLER
683 /**
684 * Build a principal using vararg style building
685 *
686 * @param context A Kerberos context.
687 * @param principal returned principal
688 * @param rlen length of realm
689 * @param realm realm name
690 * @param ... a list of components ended with NULL.
691 *
692 * @return An krb5 error code, see krb5_get_error_message().
693 *
694 * @ingroup krb5_principal
695 */
696
697 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_build_principal(krb5_context context,krb5_principal * principal,int rlen,krb5_const_realm realm,...)698 krb5_build_principal(krb5_context context,
699 krb5_principal *principal,
700 int rlen,
701 krb5_const_realm realm,
702 ...)
703 {
704 krb5_error_code ret;
705 va_list ap;
706 va_start(ap, realm);
707 ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
708 va_end(ap);
709 return ret;
710 }
711 #endif
712
713 /**
714 * Build a principal using vararg style building
715 *
716 * @param context A Kerberos context.
717 * @param principal returned principal
718 * @param realm realm name
719 * @param ... a list of components ended with NULL.
720 *
721 * @return An krb5 error code, see krb5_get_error_message().
722 *
723 * @ingroup krb5_principal
724 */
725
726 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_make_principal(krb5_context context,krb5_principal * principal,krb5_const_realm realm,...)727 krb5_make_principal(krb5_context context,
728 krb5_principal *principal,
729 krb5_const_realm realm,
730 ...)
731 {
732 krb5_error_code ret;
733 krb5_realm r = NULL;
734 va_list ap;
735 if(realm == NULL) {
736 ret = krb5_get_default_realm(context, &r);
737 if(ret)
738 return ret;
739 realm = r;
740 }
741 va_start(ap, realm);
742 ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
743 va_end(ap);
744 if(r)
745 free(r);
746 return ret;
747 }
748
749 static krb5_error_code
append_component(krb5_context context,krb5_principal p,const char * comp,size_t comp_len)750 append_component(krb5_context context, krb5_principal p,
751 const char *comp,
752 size_t comp_len)
753 {
754 heim_general_string *tmp;
755 size_t len = princ_num_comp(p);
756
757 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
758 if(tmp == NULL) {
759 krb5_set_error_message(context, ENOMEM,
760 N_("malloc: out of memory", ""));
761 return ENOMEM;
762 }
763 princ_comp(p) = tmp;
764 princ_ncomp(p, len) = malloc(comp_len + 1);
765 if (princ_ncomp(p, len) == NULL) {
766 krb5_set_error_message(context, ENOMEM,
767 N_("malloc: out of memory", ""));
768 return ENOMEM;
769 }
770 memcpy (princ_ncomp(p, len), comp, comp_len);
771 princ_ncomp(p, len)[comp_len] = '\0';
772 princ_num_comp(p)++;
773 return 0;
774 }
775
776 static void
va_ext_princ(krb5_context context,krb5_principal p,va_list ap)777 va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
778 {
779 while(1){
780 const char *s;
781 int len;
782 len = va_arg(ap, int);
783 if(len == 0)
784 break;
785 s = va_arg(ap, const char*);
786 append_component(context, p, s, len);
787 }
788 }
789
790 static void
va_princ(krb5_context context,krb5_principal p,va_list ap)791 va_princ(krb5_context context, krb5_principal p, va_list ap)
792 {
793 while(1){
794 const char *s;
795 s = va_arg(ap, const char*);
796 if(s == NULL)
797 break;
798 append_component(context, p, s, strlen(s));
799 }
800 }
801
802 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)803 build_principal(krb5_context context,
804 krb5_principal *principal,
805 int rlen,
806 krb5_const_realm realm,
807 void (*func)(krb5_context, krb5_principal, va_list),
808 va_list ap)
809 {
810 krb5_principal p;
811
812 p = calloc(1, sizeof(*p));
813 if (p == NULL) {
814 krb5_set_error_message(context, ENOMEM,
815 N_("malloc: out of memory", ""));
816 return ENOMEM;
817 }
818 princ_type(p) = KRB5_NT_PRINCIPAL;
819
820 princ_realm(p) = strdup(realm);
821 if(p->realm == NULL){
822 free(p);
823 krb5_set_error_message(context, ENOMEM,
824 N_("malloc: out of memory", ""));
825 return ENOMEM;
826 }
827
828 (*func)(context, p, ap);
829 *principal = p;
830 return 0;
831 }
832
833 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_build_principal_va(krb5_context context,krb5_principal * principal,int rlen,krb5_const_realm realm,va_list ap)834 krb5_build_principal_va(krb5_context context,
835 krb5_principal *principal,
836 int rlen,
837 krb5_const_realm realm,
838 va_list ap)
839 {
840 return build_principal(context, principal, rlen, realm, va_princ, ap);
841 }
842
843 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_build_principal_va_ext(krb5_context context,krb5_principal * principal,int rlen,krb5_const_realm realm,va_list ap)844 krb5_build_principal_va_ext(krb5_context context,
845 krb5_principal *principal,
846 int rlen,
847 krb5_const_realm realm,
848 va_list ap)
849 {
850 return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
851 }
852
853
854 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_build_principal_ext(krb5_context context,krb5_principal * principal,int rlen,krb5_const_realm realm,...)855 krb5_build_principal_ext(krb5_context context,
856 krb5_principal *principal,
857 int rlen,
858 krb5_const_realm realm,
859 ...)
860 {
861 krb5_error_code ret;
862 va_list ap;
863 va_start(ap, realm);
864 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
865 va_end(ap);
866 return ret;
867 }
868
869 /**
870 * Copy a principal
871 *
872 * @param context A Kerberos context.
873 * @param inprinc principal to copy
874 * @param outprinc copied principal, free with krb5_free_principal()
875 *
876 * @return An krb5 error code, see krb5_get_error_message().
877 *
878 * @ingroup krb5_principal
879 */
880
881
882 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_copy_principal(krb5_context context,krb5_const_principal inprinc,krb5_principal * outprinc)883 krb5_copy_principal(krb5_context context,
884 krb5_const_principal inprinc,
885 krb5_principal *outprinc)
886 {
887 krb5_principal p = malloc(sizeof(*p));
888 if (p == NULL) {
889 krb5_set_error_message(context, ENOMEM,
890 N_("malloc: out of memory", ""));
891 return ENOMEM;
892 }
893 if(copy_Principal(inprinc, p)) {
894 free(p);
895 krb5_set_error_message(context, ENOMEM,
896 N_("malloc: out of memory", ""));
897 return ENOMEM;
898 }
899 *outprinc = p;
900 return 0;
901 }
902
903 /**
904 * Return TRUE iff princ1 == princ2 (without considering the realm)
905 *
906 * @param context Kerberos 5 context
907 * @param princ1 first principal to compare
908 * @param princ2 second principal to compare
909 *
910 * @return non zero if equal, 0 if not
911 *
912 * @ingroup krb5_principal
913 * @see krb5_principal_compare()
914 * @see krb5_realm_compare()
915 */
916
917 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_principal_compare_any_realm(krb5_context context,krb5_const_principal princ1,krb5_const_principal princ2)918 krb5_principal_compare_any_realm(krb5_context context,
919 krb5_const_principal princ1,
920 krb5_const_principal princ2)
921 {
922 size_t i;
923 if(princ_num_comp(princ1) != princ_num_comp(princ2))
924 return FALSE;
925 for(i = 0; i < princ_num_comp(princ1); i++){
926 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
927 return FALSE;
928 }
929 return TRUE;
930 }
931
932 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
_krb5_principal_compare_PrincipalName(krb5_context context,krb5_const_principal princ1,PrincipalName * princ2)933 _krb5_principal_compare_PrincipalName(krb5_context context,
934 krb5_const_principal princ1,
935 PrincipalName *princ2)
936 {
937 size_t i;
938 if (princ_num_comp(princ1) != princ2->name_string.len)
939 return FALSE;
940 for(i = 0; i < princ_num_comp(princ1); i++){
941 if(strcmp(princ_ncomp(princ1, i), princ2->name_string.val[i]) != 0)
942 return FALSE;
943 }
944 return TRUE;
945 }
946
947
948 /**
949 * Compares the two principals, including realm of the principals and returns
950 * TRUE if they are the same and FALSE if not.
951 *
952 * @param context Kerberos 5 context
953 * @param princ1 first principal to compare
954 * @param princ2 second principal to compare
955 *
956 * @ingroup krb5_principal
957 * @see krb5_principal_compare_any_realm()
958 * @see krb5_realm_compare()
959 */
960
961 /*
962 * return TRUE iff princ1 == princ2
963 */
964
965 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_principal_compare(krb5_context context,krb5_const_principal princ1,krb5_const_principal princ2)966 krb5_principal_compare(krb5_context context,
967 krb5_const_principal princ1,
968 krb5_const_principal princ2)
969 {
970 if(!krb5_realm_compare(context, princ1, princ2))
971 return FALSE;
972 return krb5_principal_compare_any_realm(context, princ1, princ2);
973 }
974
975 /**
976 * return TRUE iff realm(princ1) == realm(princ2)
977 *
978 * @param context Kerberos 5 context
979 * @param princ1 first principal to compare
980 * @param princ2 second principal to compare
981 *
982 * @ingroup krb5_principal
983 * @see krb5_principal_compare_any_realm()
984 * @see krb5_principal_compare()
985 */
986
987 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_realm_compare(krb5_context context,krb5_const_principal princ1,krb5_const_principal princ2)988 krb5_realm_compare(krb5_context context,
989 krb5_const_principal princ1,
990 krb5_const_principal princ2)
991 {
992 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
993 }
994
995 /**
996 * return TRUE iff princ matches pattern
997 *
998 * @ingroup krb5_principal
999 */
1000
1001 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_principal_match(krb5_context context,krb5_const_principal princ,krb5_const_principal pattern)1002 krb5_principal_match(krb5_context context,
1003 krb5_const_principal princ,
1004 krb5_const_principal pattern)
1005 {
1006 size_t i;
1007 if(princ_num_comp(princ) != princ_num_comp(pattern))
1008 return FALSE;
1009 if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0)
1010 return FALSE;
1011 for(i = 0; i < princ_num_comp(princ); i++){
1012 if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0)
1013 return FALSE;
1014 }
1015 return TRUE;
1016 }
1017
1018 /**
1019 * Create a principal for the service running on hostname. If
1020 * KRB5_NT_SRV_HST is used, the hostname is canonization using DNS (or
1021 * some other service), this is potentially insecure.
1022 *
1023 * @param context A Kerberos context.
1024 * @param hostname hostname to use
1025 * @param sname Service name to use
1026 * @param type name type of pricipal, use KRB5_NT_SRV_HST or KRB5_NT_UNKNOWN.
1027 * @param ret_princ return principal, free with krb5_free_principal().
1028 *
1029 * @return An krb5 error code, see krb5_get_error_message().
1030 *
1031 * @ingroup krb5_principal
1032 */
1033
1034 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_sname_to_principal(krb5_context context,const char * hostname,const char * sname,int32_t type,krb5_principal * ret_princ)1035 krb5_sname_to_principal (krb5_context context,
1036 const char *hostname,
1037 const char *sname,
1038 int32_t type,
1039 krb5_principal *ret_princ)
1040 {
1041 krb5_error_code ret;
1042 char localhost[MAXHOSTNAMELEN];
1043 char **realms, *host = NULL;
1044
1045 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) {
1046 krb5_set_error_message(context, KRB5_SNAME_UNSUPP_NAMETYPE,
1047 N_("unsupported name type %d", ""),
1048 (int)type);
1049 return KRB5_SNAME_UNSUPP_NAMETYPE;
1050 }
1051 if(hostname == NULL) {
1052 ret = gethostname(localhost, sizeof(localhost) - 1);
1053 if (ret != 0) {
1054 ret = errno;
1055 krb5_set_error_message(context, ret,
1056 N_("Failed to get local hostname", ""));
1057 return ret;
1058 }
1059 localhost[sizeof(localhost) - 1] = '\0';
1060 hostname = localhost;
1061 }
1062 if(sname == NULL)
1063 sname = "host";
1064 if(type == KRB5_NT_SRV_HST) {
1065 ret = krb5_expand_hostname_realms (context, hostname,
1066 &host, &realms);
1067 if (ret)
1068 return ret;
1069 strlwr(host);
1070 hostname = host;
1071 } else {
1072 ret = krb5_get_host_realm(context, hostname, &realms);
1073 if(ret)
1074 return ret;
1075 }
1076
1077 ret = krb5_make_principal(context, ret_princ, realms[0], sname,
1078 hostname, NULL);
1079 if(host)
1080 free(host);
1081 krb5_free_host_realm(context, realms);
1082 return ret;
1083 }
1084
1085 static const struct {
1086 const char *type;
1087 int32_t value;
1088 } nametypes[] = {
1089 { "UNKNOWN", KRB5_NT_UNKNOWN },
1090 { "PRINCIPAL", KRB5_NT_PRINCIPAL },
1091 { "SRV_INST", KRB5_NT_SRV_INST },
1092 { "SRV_HST", KRB5_NT_SRV_HST },
1093 { "SRV_XHST", KRB5_NT_SRV_XHST },
1094 { "UID", KRB5_NT_UID },
1095 { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL },
1096 { "SMTP_NAME", KRB5_NT_SMTP_NAME },
1097 { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL },
1098 { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID },
1099 { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL },
1100 { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID },
1101 { NULL, 0 }
1102 };
1103
1104 /**
1105 * Parse nametype string and return a nametype integer
1106 *
1107 * @ingroup krb5_principal
1108 */
1109
1110 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_parse_nametype(krb5_context context,const char * str,int32_t * nametype)1111 krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype)
1112 {
1113 size_t i;
1114
1115 for(i = 0; nametypes[i].type; i++) {
1116 if (strcasecmp(nametypes[i].type, str) == 0) {
1117 *nametype = nametypes[i].value;
1118 return 0;
1119 }
1120 }
1121 krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
1122 N_("Failed to find name type %s", ""), str);
1123 return KRB5_PARSE_MALFORMED;
1124 }
1125
1126 /**
1127 * Check if the cname part of the principal is a krbtgt principal
1128 *
1129 * @ingroup krb5_principal
1130 */
1131
1132 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_principal_is_krbtgt(krb5_context context,krb5_const_principal p)1133 krb5_principal_is_krbtgt(krb5_context context, krb5_const_principal p)
1134 {
1135 return p->name.name_string.len == 2 &&
1136 strcmp(p->name.name_string.val[0], KRB5_TGS_NAME) == 0;
1137
1138 }
1139