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 * @return An krb5 error code, see krb5_get_error_message(). 77 * 78 * @ingroup krb5_principal 79 */ 80 81KRB5_LIB_FUNCTION void KRB5_LIB_CALL 82krb5_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 103KRB5_LIB_FUNCTION void KRB5_LIB_CALL 104krb5_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 122KRB5_LIB_FUNCTION int KRB5_LIB_CALL 123krb5_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 140KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 141krb5_principal_get_realm(krb5_context context, 142 krb5_const_principal principal) 143{ 144 return princ_realm(principal); 145} 146 147KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 148krb5_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 168KRB5_LIB_FUNCTION unsigned int KRB5_LIB_CALL 169krb5_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 188KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 189krb5_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; 367exit: 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 389KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 390krb5_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 397static const char quotable_chars[] = " \n\t\b\\/@"; 398static const char replace_chars[] = " ntb\\/@"; 399static const char nq_chars[] = " \\/@"; 400 401#define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0); 402 403static size_t 404quote_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 423static krb5_error_code 424unparse_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 490KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 491krb5_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 513KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 514krb5_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 537KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 538krb5_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 547static krb5_error_code 548unparse_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 601KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 602krb5_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 622KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 623krb5_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 644KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 645krb5_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 665KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 666krb5_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/** 683 * Build a principal using vararg style building 684 * 685 * @param context A Kerberos context. 686 * @param principal returned principal 687 * @param rlen length of realm 688 * @param realm realm name 689 * @param ... a list of components ended with NULL. 690 * 691 * @return An krb5 error code, see krb5_get_error_message(). 692 * 693 * @ingroup krb5_principal 694 */ 695 696KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 697krb5_build_principal(krb5_context context, 698 krb5_principal *principal, 699 int rlen, 700 krb5_const_realm realm, 701 ...) 702{ 703 krb5_error_code ret; 704 va_list ap; 705 va_start(ap, realm); 706 ret = krb5_build_principal_va(context, principal, rlen, realm, ap); 707 va_end(ap); 708 return ret; 709} 710 711/** 712 * Build a principal using vararg style building 713 * 714 * @param context A Kerberos context. 715 * @param principal returned principal 716 * @param realm realm name 717 * @param ... a list of components ended with NULL. 718 * 719 * @return An krb5 error code, see krb5_get_error_message(). 720 * 721 * @ingroup krb5_principal 722 */ 723 724KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 725krb5_make_principal(krb5_context context, 726 krb5_principal *principal, 727 krb5_const_realm realm, 728 ...) 729{ 730 krb5_error_code ret; 731 krb5_realm r = NULL; 732 va_list ap; 733 if(realm == NULL) { 734 ret = krb5_get_default_realm(context, &r); 735 if(ret) 736 return ret; 737 realm = r; 738 } 739 va_start(ap, realm); 740 ret = krb5_build_principal_va(context, principal, (int)strlen(realm), realm, ap); 741 va_end(ap); 742 if(r) 743 free(r); 744 return ret; 745} 746 747static krb5_error_code 748append_component(krb5_context context, krb5_principal p, 749 const char *comp, 750 size_t comp_len) 751{ 752 heim_general_string *tmp; 753 size_t len = princ_num_comp(p); 754 755 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp)); 756 if(tmp == NULL) { 757 krb5_set_error_message(context, ENOMEM, 758 N_("malloc: out of memory", "")); 759 return ENOMEM; 760 } 761 princ_comp(p) = tmp; 762 princ_ncomp(p, len) = malloc(comp_len + 1); 763 if (princ_ncomp(p, len) == NULL) { 764 krb5_set_error_message(context, ENOMEM, 765 N_("malloc: out of memory", "")); 766 return ENOMEM; 767 } 768 memcpy (princ_ncomp(p, len), comp, comp_len); 769 princ_ncomp(p, len)[comp_len] = '\0'; 770 princ_num_comp(p)++; 771 return 0; 772} 773 774static void 775va_ext_princ(krb5_context context, krb5_principal p, va_list ap) 776{ 777 while(1){ 778 const char *s; 779 int len; 780 len = va_arg(ap, int); 781 if(len == 0) 782 break; 783 s = va_arg(ap, const char*); 784 append_component(context, p, s, len); 785 } 786} 787 788static void 789va_princ(krb5_context context, krb5_principal p, va_list ap) 790{ 791 while(1){ 792 const char *s; 793 s = va_arg(ap, const char*); 794 if(s == NULL) 795 break; 796 append_component(context, p, s, strlen(s)); 797 } 798} 799 800static krb5_error_code 801build_principal(krb5_context context, 802 krb5_principal *principal, 803 int rlen, 804 krb5_const_realm realm, 805 void (*func)(krb5_context, krb5_principal, va_list), 806 va_list ap) 807{ 808 krb5_principal p; 809 810 p = calloc(1, sizeof(*p)); 811 if (p == NULL) { 812 krb5_set_error_message(context, ENOMEM, 813 N_("malloc: out of memory", "")); 814 return ENOMEM; 815 } 816 princ_type(p) = KRB5_NT_PRINCIPAL; 817 818 princ_realm(p) = strdup(realm); 819 if(p->realm == NULL){ 820 free(p); 821 krb5_set_error_message(context, ENOMEM, 822 N_("malloc: out of memory", "")); 823 return ENOMEM; 824 } 825 826 (*func)(context, p, ap); 827 *principal = p; 828 return 0; 829} 830 831KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 832krb5_build_principal_va(krb5_context context, 833 krb5_principal *principal, 834 int rlen, 835 krb5_const_realm realm, 836 va_list ap) 837{ 838 return build_principal(context, principal, rlen, realm, va_princ, ap); 839} 840 841KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 842krb5_build_principal_va_ext(krb5_context context, 843 krb5_principal *principal, 844 int rlen, 845 krb5_const_realm realm, 846 va_list ap) 847{ 848 return build_principal(context, principal, rlen, realm, va_ext_princ, ap); 849} 850 851 852KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 853krb5_build_principal_ext(krb5_context context, 854 krb5_principal *principal, 855 int rlen, 856 krb5_const_realm realm, 857 ...) 858{ 859 krb5_error_code ret; 860 va_list ap; 861 va_start(ap, realm); 862 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap); 863 va_end(ap); 864 return ret; 865} 866 867/** 868 * Copy a principal 869 * 870 * @param context A Kerberos context. 871 * @param inprinc principal to copy 872 * @param outprinc copied principal, free with krb5_free_principal() 873 * 874 * @return An krb5 error code, see krb5_get_error_message(). 875 * 876 * @ingroup krb5_principal 877 */ 878 879 880KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 881krb5_copy_principal(krb5_context context, 882 krb5_const_principal inprinc, 883 krb5_principal *outprinc) 884{ 885 krb5_principal p = malloc(sizeof(*p)); 886 if (p == NULL) { 887 krb5_set_error_message(context, ENOMEM, 888 N_("malloc: out of memory", "")); 889 return ENOMEM; 890 } 891 if(copy_Principal(inprinc, p)) { 892 free(p); 893 krb5_set_error_message(context, ENOMEM, 894 N_("malloc: out of memory", "")); 895 return ENOMEM; 896 } 897 *outprinc = p; 898 return 0; 899} 900 901/** 902 * Return TRUE iff princ1 == princ2 (without considering the realm) 903 * 904 * @param context Kerberos 5 context 905 * @param princ1 first principal to compare 906 * @param princ2 second principal to compare 907 * 908 * @return non zero if equal, 0 if not 909 * 910 * @ingroup krb5_principal 911 * @see krb5_principal_compare() 912 * @see krb5_realm_compare() 913 */ 914 915KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 916krb5_principal_compare_any_realm(krb5_context context, 917 krb5_const_principal princ1, 918 krb5_const_principal princ2) 919{ 920 size_t i; 921 if(princ_num_comp(princ1) != princ_num_comp(princ2)) 922 return FALSE; 923 for(i = 0; i < princ_num_comp(princ1); i++){ 924 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0) 925 return FALSE; 926 } 927 return TRUE; 928} 929 930KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 931_krb5_principal_compare_PrincipalName(krb5_context context, 932 krb5_const_principal princ1, 933 PrincipalName *princ2) 934{ 935 size_t i; 936 if (princ_num_comp(princ1) != princ2->name_string.len) 937 return FALSE; 938 for(i = 0; i < princ_num_comp(princ1); i++){ 939 if(strcmp(princ_ncomp(princ1, i), princ2->name_string.val[i]) != 0) 940 return FALSE; 941 } 942 return TRUE; 943} 944 945 946/** 947 * Compares the two principals, including realm of the principals and returns 948 * TRUE if they are the same and FALSE if not. 949 * 950 * @param context Kerberos 5 context 951 * @param princ1 first principal to compare 952 * @param princ2 second principal to compare 953 * 954 * @ingroup krb5_principal 955 * @see krb5_principal_compare_any_realm() 956 * @see krb5_realm_compare() 957 */ 958 959/* 960 * return TRUE iff princ1 == princ2 961 */ 962 963KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 964krb5_principal_compare(krb5_context context, 965 krb5_const_principal princ1, 966 krb5_const_principal princ2) 967{ 968 if(!krb5_realm_compare(context, princ1, princ2)) 969 return FALSE; 970 return krb5_principal_compare_any_realm(context, princ1, princ2); 971} 972 973/** 974 * return TRUE iff realm(princ1) == realm(princ2) 975 * 976 * @param context Kerberos 5 context 977 * @param princ1 first principal to compare 978 * @param princ2 second principal to compare 979 * 980 * @ingroup krb5_principal 981 * @see krb5_principal_compare_any_realm() 982 * @see krb5_principal_compare() 983 */ 984 985KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 986krb5_realm_compare(krb5_context context, 987 krb5_const_principal princ1, 988 krb5_const_principal princ2) 989{ 990 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0; 991} 992 993/** 994 * return TRUE iff princ matches pattern 995 * 996 * @ingroup krb5_principal 997 */ 998 999KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1000krb5_principal_match(krb5_context context, 1001 krb5_const_principal princ, 1002 krb5_const_principal pattern) 1003{ 1004 size_t i; 1005 if(princ_num_comp(princ) != princ_num_comp(pattern)) 1006 return FALSE; 1007 if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0) 1008 return FALSE; 1009 for(i = 0; i < princ_num_comp(princ); i++){ 1010 if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0) 1011 return FALSE; 1012 } 1013 return TRUE; 1014} 1015 1016/** 1017 * Create a principal for the service running on hostname. If 1018 * KRB5_NT_SRV_HST is used, the hostname is canonization using DNS (or 1019 * some other service), this is potentially insecure. 1020 * 1021 * @param context A Kerberos context. 1022 * @param hostname hostname to use 1023 * @param sname Service name to use 1024 * @param type name type of pricipal, use KRB5_NT_SRV_HST or KRB5_NT_UNKNOWN. 1025 * @param ret_princ return principal, free with krb5_free_principal(). 1026 * 1027 * @return An krb5 error code, see krb5_get_error_message(). 1028 * 1029 * @ingroup krb5_principal 1030 */ 1031 1032KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1033krb5_sname_to_principal (krb5_context context, 1034 const char *hostname, 1035 const char *sname, 1036 int32_t type, 1037 krb5_principal *ret_princ) 1038{ 1039 krb5_error_code ret; 1040 char localhost[MAXHOSTNAMELEN]; 1041 char **realms; 1042 size_t len; 1043 1044 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) { 1045 krb5_set_error_message(context, KRB5_SNAME_UNSUPP_NAMETYPE, 1046 N_("unsupported name type %d", ""), 1047 (int)type); 1048 return KRB5_SNAME_UNSUPP_NAMETYPE; 1049 } 1050 if(hostname == NULL) { 1051 ret = gethostname(localhost, sizeof(localhost) - 1); 1052 if (ret != 0) { 1053 ret = errno; 1054 krb5_set_error_message(context, ret, 1055 N_("Failed to get local hostname", "")); 1056 return ret; 1057 } 1058 localhost[sizeof(localhost) - 1] = '\0'; 1059 } else { 1060 strlcpy(localhost, hostname, sizeof(localhost)); 1061 } 1062 if(sname == NULL) 1063 sname = "host"; 1064 if(type == KRB5_NT_SRV_HST) { 1065 char *host; 1066 1067 ret = krb5_expand_hostname_realms (context, localhost, 1068 &host, &realms); 1069 if (ret) 1070 return ret; 1071 strlwr(host); 1072 strlcpy(localhost, host, sizeof(localhost)); 1073 free(host); 1074 } else { 1075 ret = krb5_get_host_realm(context, hostname, &realms); 1076 if(ret) 1077 return ret; 1078 } 1079 1080 /* 1081 * Squash any trailing . on the hostname since that is jolly good 1082 * to have when looking up a DNS name (qualified), but its no good 1083 * to have in the kerberos principal since those are supposed to 1084 * be in qualified format already. 1085 */ 1086 1087 len = strlen(localhost); 1088 if (len > 0 && localhost[len - 1] == '.') 1089 localhost[len - 1] = '\0'; 1090 1091 ret = krb5_make_principal(context, ret_princ, realms[0], sname, 1092 localhost, NULL); 1093 krb5_free_host_realm(context, realms); 1094 return ret; 1095} 1096 1097static const struct { 1098 const char *type; 1099 int32_t value; 1100} nametypes[] = { 1101 { "UNKNOWN", KRB5_NT_UNKNOWN }, 1102 { "PRINCIPAL", KRB5_NT_PRINCIPAL }, 1103 { "SRV_INST", KRB5_NT_SRV_INST }, 1104 { "SRV_HST", KRB5_NT_SRV_HST }, 1105 { "SRV_XHST", KRB5_NT_SRV_XHST }, 1106 { "UID", KRB5_NT_UID }, 1107 { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL }, 1108 { "SMTP_NAME", KRB5_NT_SMTP_NAME }, 1109 { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL }, 1110 { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID }, 1111 { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL }, 1112 { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID }, 1113 { NULL, 0 } 1114}; 1115 1116/** 1117 * Parse nametype string and return a nametype integer 1118 * 1119 * @ingroup krb5_principal 1120 */ 1121 1122KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1123krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype) 1124{ 1125 size_t i; 1126 1127 for(i = 0; nametypes[i].type; i++) { 1128 if (strcasecmp(nametypes[i].type, str) == 0) { 1129 *nametype = nametypes[i].value; 1130 return 0; 1131 } 1132 } 1133 krb5_set_error_message(context, KRB5_PARSE_MALFORMED, 1134 N_("Failed to find name type %s", ""), str); 1135 return KRB5_PARSE_MALFORMED; 1136} 1137 1138/** 1139 * Returns true if name is Kerberos NULL name 1140 * 1141 * @ingroup krb5_principal 1142 */ 1143 1144krb5_boolean KRB5_LIB_FUNCTION 1145krb5_principal_is_null(krb5_context context, krb5_const_principal principal) 1146{ 1147 if (principal->name.name_type == KRB5_NT_WELLKNOWN && 1148 principal->name.name_string.len == 2 && 1149 strcmp(principal->name.name_string.val[0], "WELLKNOWN") == 0 && 1150 strcmp(principal->name.name_string.val[1], "NULL") == 0) 1151 return TRUE; 1152 return FALSE; 1153} 1154 1155const char _krb5_wellknown_lkdc[] = "WELLKNOWN:COM.APPLE.LKDC"; 1156static const char lkdc_prefix[] = "LKDC:"; 1157 1158/** 1159 * Returns true if name is Kerberos an LKDC realm 1160 * 1161 * @ingroup krb5_principal 1162 */ 1163 1164krb5_boolean KRB5_LIB_FUNCTION 1165krb5_realm_is_lkdc(const char *realm) 1166{ 1167 1168 return strncmp(realm, lkdc_prefix, sizeof(lkdc_prefix)-1) == 0 || 1169 strncmp(realm, _krb5_wellknown_lkdc, sizeof(_krb5_wellknown_lkdc) - 1) == 0; 1170} 1171 1172/** 1173 * Returns true if name is Kerberos an LKDC realm 1174 * 1175 * @ingroup krb5_principal 1176 */ 1177 1178krb5_boolean KRB5_LIB_FUNCTION 1179krb5_principal_is_lkdc(krb5_context context, krb5_const_principal principal) 1180{ 1181 return krb5_realm_is_lkdc(principal->realm); 1182} 1183 1184/** 1185 * Returns true if name is Kerberos an LKDC realm 1186 * 1187 * @ingroup krb5_principal 1188 */ 1189 1190krb5_boolean KRB5_LIB_FUNCTION 1191krb5_principal_is_pku2u(krb5_context context, krb5_const_principal principal) 1192{ 1193 return strcmp(principal->realm, KRB5_PKU2U_REALM_NAME) == 0; 1194} 1195 1196/** 1197 * Check if the cname part of the principal is a krbtgt principal 1198 * 1199 * @ingroup krb5_principal 1200 */ 1201 1202KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1203krb5_principal_is_krbtgt(krb5_context context, krb5_const_principal p) 1204{ 1205 return p->name.name_string.len == 2 && 1206 strcmp(p->name.name_string.val[0], KRB5_TGS_NAME) == 0; 1207} 1208 1209/** 1210 * Returns true iff name is an WELLKNOWN:ORG.H5L.HOSTBASED-SERVICE 1211 * 1212 * @ingroup krb5_principal 1213 */ 1214 1215krb5_boolean KRB5_LIB_FUNCTION 1216krb5_principal_is_gss_hostbased_service(krb5_context context, 1217 krb5_const_principal principal) 1218{ 1219 if (principal == NULL) 1220 return FALSE; 1221 if (principal->name.name_string.len != 2) 1222 return FALSE; 1223 if (strcmp(principal->name.name_string.val[1], KRB5_GSS_HOSTBASED_SERVICE_NAME) != 0) 1224 return FALSE; 1225 return TRUE; 1226} 1227 1228/** 1229 * Check if the cname part of the principal is a initial or renewed krbtgt principal 1230 * 1231 * @ingroup krb5_principal 1232 */ 1233 1234 1235krb5_boolean KRB5_LIB_FUNCTION 1236krb5_principal_is_root_krbtgt(krb5_context context, krb5_const_principal p) 1237{ 1238 return p->name.name_string.len == 2 && 1239 strcmp(p->name.name_string.val[0], KRB5_TGS_NAME) == 0 && 1240 strcmp(p->name.name_string.val[1], p->realm) == 0; 1241} 1242