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