1 /* 2 * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /** 35 * @page krb5_principal_intro The principal handing functions. 36 * 37 * A Kerberos principal is a email address looking string that 38 * contains to parts separeted by a @. The later part is the kerbero 39 * realm the principal belongs to and the former is a list of 0 or 40 * more components. For example 41 * @verbatim 42 lha@SU.SE 43 host/hummel.it.su.se@SU.SE 44 host/admin@H5L.ORG 45 @endverbatim 46 * 47 * See the library functions here: @ref krb5_principal 48 */ 49 50 #include "krb5_locl.h" 51 #ifdef HAVE_RES_SEARCH 52 #define USE_RESOLVER 53 #endif 54 #ifdef HAVE_ARPA_NAMESER_H 55 #include <arpa/nameser.h> 56 #endif 57 #include <fnmatch.h> 58 #include "resolve.h" 59 60 #define princ_num_comp(P) ((P)->name.name_string.len) 61 #define princ_type(P) ((P)->name.name_type) 62 #define princ_comp(P) ((P)->name.name_string.val) 63 #define princ_ncomp(P, N) ((P)->name.name_string.val[(N)]) 64 #define princ_realm(P) ((P)->realm) 65 66 /** 67 * Frees a Kerberos principal allocated by the library with 68 * krb5_parse_name(), krb5_make_principal() or any other related 69 * principal functions. 70 * 71 * @param context A Kerberos context. 72 * @param p a principal to free. 73 * 74 * @return An krb5 error code, see krb5_get_error_message(). 75 * 76 * @ingroup krb5_principal 77 */ 78 79 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 80 krb5_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 * @return An krb5 error code, see krb5_get_error_message(). 97 * 98 * @ingroup krb5_principal 99 */ 100 101 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 102 krb5_principal_set_type(krb5_context context, 103 krb5_principal principal, 104 int type) 105 { 106 princ_type(principal) = type; 107 } 108 109 /** 110 * Get the type of the principal 111 * 112 * @param context A Kerberos context. 113 * @param principal principal to get the type for 114 * 115 * @return the type of principal 116 * 117 * @ingroup krb5_principal 118 */ 119 120 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 121 krb5_principal_get_type(krb5_context context, 122 krb5_const_principal principal) 123 { 124 return princ_type(principal); 125 } 126 127 /** 128 * Get the realm of the principal 129 * 130 * @param context A Kerberos context. 131 * @param principal principal to get the realm for 132 * 133 * @return realm of the principal, don't free or use after krb5_principal is freed 134 * 135 * @ingroup krb5_principal 136 */ 137 138 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 139 krb5_principal_get_realm(krb5_context context, 140 krb5_const_principal principal) 141 { 142 return princ_realm(principal); 143 } 144 145 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 146 krb5_principal_get_comp_string(krb5_context context, 147 krb5_const_principal principal, 148 unsigned int component) 149 { 150 if(component >= princ_num_comp(principal)) 151 return NULL; 152 return princ_ncomp(principal, component); 153 } 154 155 /** 156 * Get number of component is principal. 157 * 158 * @param context Kerberos 5 context 159 * @param principal principal to query 160 * 161 * @return number of components in string 162 * 163 * @ingroup krb5_principal 164 */ 165 166 KRB5_LIB_FUNCTION unsigned int KRB5_LIB_CALL 167 krb5_principal_get_num_comp(krb5_context context, 168 krb5_const_principal principal) 169 { 170 return princ_num_comp(principal); 171 } 172 173 /** 174 * Parse a name into a krb5_principal structure, flags controls the behavior. 175 * 176 * @param context Kerberos 5 context 177 * @param name name to parse into a Kerberos principal 178 * @param flags flags to control the behavior 179 * @param principal returned principal, free with krb5_free_principal(). 180 * 181 * @return An krb5 error code, see krb5_get_error_message(). 182 * 183 * @ingroup krb5_principal 184 */ 185 186 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 187 krb5_parse_name_flags(krb5_context context, 188 const char *name, 189 int flags, 190 krb5_principal *principal) 191 { 192 krb5_error_code ret; 193 heim_general_string *comp; 194 heim_general_string realm = NULL; 195 int ncomp; 196 197 const char *p; 198 char *q; 199 char *s; 200 char *start; 201 202 int n; 203 char c; 204 int got_realm = 0; 205 int first_at = 1; 206 int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE); 207 208 *principal = NULL; 209 210 #define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) 211 212 if ((flags & RFLAGS) == RFLAGS) { 213 krb5_set_error_message(context, KRB5_ERR_NO_SERVICE, 214 N_("Can't require both realm and " 215 "no realm at the same time", "")); 216 return KRB5_ERR_NO_SERVICE; 217 } 218 #undef RFLAGS 219 220 /* count number of component, 221 * enterprise names only have one component 222 */ 223 ncomp = 1; 224 if (!enterprise) { 225 for(p = name; *p; p++){ 226 if(*p=='\\'){ 227 if(!p[1]) { 228 krb5_set_error_message(context, KRB5_PARSE_MALFORMED, 229 N_("trailing \\ in principal name", "")); 230 return KRB5_PARSE_MALFORMED; 231 } 232 p++; 233 } else if(*p == '/') 234 ncomp++; 235 else if(*p == '@') 236 break; 237 } 238 } 239 comp = calloc(ncomp, sizeof(*comp)); 240 if (comp == NULL) { 241 krb5_set_error_message(context, ENOMEM, 242 N_("malloc: out of memory", "")); 243 return ENOMEM; 244 } 245 246 n = 0; 247 p = start = q = s = strdup(name); 248 if (start == NULL) { 249 free (comp); 250 krb5_set_error_message(context, ENOMEM, 251 N_("malloc: out of memory", "")); 252 return ENOMEM; 253 } 254 while(*p){ 255 c = *p++; 256 if(c == '\\'){ 257 c = *p++; 258 if(c == 'n') 259 c = '\n'; 260 else if(c == 't') 261 c = '\t'; 262 else if(c == 'b') 263 c = '\b'; 264 else if(c == '0') 265 c = '\0'; 266 else if(c == '\0') { 267 ret = KRB5_PARSE_MALFORMED; 268 krb5_set_error_message(context, ret, 269 N_("trailing \\ in principal name", "")); 270 goto exit; 271 } 272 }else if(enterprise && first_at) { 273 if (c == '@') 274 first_at = 0; 275 }else if((c == '/' && !enterprise) || c == '@'){ 276 if(got_realm){ 277 ret = KRB5_PARSE_MALFORMED; 278 krb5_set_error_message(context, ret, 279 N_("part after realm in principal name", "")); 280 goto exit; 281 }else{ 282 comp[n] = malloc(q - start + 1); 283 if (comp[n] == NULL) { 284 ret = ENOMEM; 285 krb5_set_error_message(context, ret, 286 N_("malloc: out of memory", "")); 287 goto exit; 288 } 289 memcpy(comp[n], start, q - start); 290 comp[n][q - start] = 0; 291 n++; 292 } 293 if(c == '@') 294 got_realm = 1; 295 start = q; 296 continue; 297 } 298 if(got_realm && (c == '/' || c == '\0')) { 299 ret = KRB5_PARSE_MALFORMED; 300 krb5_set_error_message(context, ret, 301 N_("part after realm in principal name", "")); 302 goto exit; 303 } 304 *q++ = c; 305 } 306 if(got_realm){ 307 if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) { 308 ret = KRB5_PARSE_MALFORMED; 309 krb5_set_error_message(context, ret, 310 N_("realm found in 'short' principal " 311 "expected to be without one", "")); 312 goto exit; 313 } 314 realm = malloc(q - start + 1); 315 if (realm == NULL) { 316 ret = ENOMEM; 317 krb5_set_error_message(context, ret, 318 N_("malloc: out of memory", "")); 319 goto exit; 320 } 321 memcpy(realm, start, q - start); 322 realm[q - start] = 0; 323 }else{ 324 if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) { 325 ret = KRB5_PARSE_MALFORMED; 326 krb5_set_error_message(context, ret, 327 N_("realm NOT found in principal " 328 "expected to be with one", "")); 329 goto exit; 330 } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) { 331 realm = NULL; 332 } else { 333 ret = krb5_get_default_realm (context, &realm); 334 if (ret) 335 goto exit; 336 } 337 338 comp[n] = malloc(q - start + 1); 339 if (comp[n] == NULL) { 340 ret = ENOMEM; 341 krb5_set_error_message(context, ret, 342 N_("malloc: out of memory", "")); 343 goto exit; 344 } 345 memcpy(comp[n], start, q - start); 346 comp[n][q - start] = 0; 347 n++; 348 } 349 *principal = malloc(sizeof(**principal)); 350 if (*principal == NULL) { 351 ret = ENOMEM; 352 krb5_set_error_message(context, ret, 353 N_("malloc: out of memory", "")); 354 goto exit; 355 } 356 if (enterprise) 357 (*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL; 358 else 359 (*principal)->name.name_type = KRB5_NT_PRINCIPAL; 360 (*principal)->name.name_string.val = comp; 361 princ_num_comp(*principal) = n; 362 (*principal)->realm = realm; 363 free(s); 364 return 0; 365 exit: 366 while(n>0){ 367 free(comp[--n]); 368 } 369 free(comp); 370 free(realm); 371 free(s); 372 return ret; 373 } 374 375 /** 376 * Parse a name into a krb5_principal structure 377 * 378 * @param context Kerberos 5 context 379 * @param name name to parse into a Kerberos principal 380 * @param principal returned principal, free with krb5_free_principal(). 381 * 382 * @return An krb5 error code, see krb5_get_error_message(). 383 * 384 * @ingroup krb5_principal 385 */ 386 387 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 388 krb5_parse_name(krb5_context context, 389 const char *name, 390 krb5_principal *principal) 391 { 392 return krb5_parse_name_flags(context, name, 0, principal); 393 } 394 395 static const char quotable_chars[] = " \n\t\b\\/@"; 396 static const char replace_chars[] = " ntb\\/@"; 397 static const char nq_chars[] = " \\/@"; 398 399 #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0); 400 401 static size_t 402 quote_string(const char *s, char *out, size_t idx, size_t len, int display) 403 { 404 const char *p, *q; 405 for(p = s; *p && idx < len; p++){ 406 q = strchr(quotable_chars, *p); 407 if (q && display) { 408 add_char(out, idx, len, replace_chars[q - quotable_chars]); 409 } else if (q) { 410 add_char(out, idx, len, '\\'); 411 add_char(out, idx, len, replace_chars[q - quotable_chars]); 412 }else 413 add_char(out, idx, len, *p); 414 } 415 if(idx < len) 416 out[idx] = '\0'; 417 return idx; 418 } 419 420 421 static krb5_error_code 422 unparse_name_fixed(krb5_context context, 423 krb5_const_principal principal, 424 char *name, 425 size_t len, 426 int flags) 427 { 428 size_t idx = 0; 429 size_t i; 430 int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0; 431 int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0; 432 int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0; 433 434 if (!no_realm && princ_realm(principal) == NULL) { 435 krb5_set_error_message(context, ERANGE, 436 N_("Realm missing from principal, " 437 "can't unparse", "")); 438 return ERANGE; 439 } 440 441 for(i = 0; i < princ_num_comp(principal); i++){ 442 if(i) 443 add_char(name, idx, len, '/'); 444 idx = quote_string(princ_ncomp(principal, i), name, idx, len, display); 445 if(idx == len) { 446 krb5_set_error_message(context, ERANGE, 447 N_("Out of space printing principal", "")); 448 return ERANGE; 449 } 450 } 451 /* add realm if different from default realm */ 452 if(short_form && !no_realm) { 453 krb5_realm r; 454 krb5_error_code ret; 455 ret = krb5_get_default_realm(context, &r); 456 if(ret) 457 return ret; 458 if(strcmp(princ_realm(principal), r) != 0) 459 short_form = 0; 460 free(r); 461 } 462 if(!short_form && !no_realm) { 463 add_char(name, idx, len, '@'); 464 idx = quote_string(princ_realm(principal), name, idx, len, display); 465 if(idx == len) { 466 krb5_set_error_message(context, ERANGE, 467 N_("Out of space printing " 468 "realm of principal", "")); 469 return ERANGE; 470 } 471 } 472 return 0; 473 } 474 475 /** 476 * Unparse the principal name to a fixed buffer 477 * 478 * @param context A Kerberos context. 479 * @param principal principal to unparse 480 * @param name buffer to write name to 481 * @param len length of buffer 482 * 483 * @return An krb5 error code, see krb5_get_error_message(). 484 * 485 * @ingroup krb5_principal 486 */ 487 488 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 489 krb5_unparse_name_fixed(krb5_context context, 490 krb5_const_principal principal, 491 char *name, 492 size_t len) 493 { 494 return unparse_name_fixed(context, principal, name, len, 0); 495 } 496 497 /** 498 * Unparse the principal name to a fixed buffer. The realm is skipped 499 * if its a default realm. 500 * 501 * @param context A Kerberos context. 502 * @param principal principal to unparse 503 * @param name buffer to write name to 504 * @param len length of buffer 505 * 506 * @return An krb5 error code, see krb5_get_error_message(). 507 * 508 * @ingroup krb5_principal 509 */ 510 511 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 512 krb5_unparse_name_fixed_short(krb5_context context, 513 krb5_const_principal principal, 514 char *name, 515 size_t len) 516 { 517 return unparse_name_fixed(context, principal, name, len, 518 KRB5_PRINCIPAL_UNPARSE_SHORT); 519 } 520 521 /** 522 * Unparse the principal name with unparse flags to a fixed buffer. 523 * 524 * @param context A Kerberos context. 525 * @param principal principal to unparse 526 * @param flags unparse flags 527 * @param name buffer to write name to 528 * @param len length of buffer 529 * 530 * @return An krb5 error code, see krb5_get_error_message(). 531 * 532 * @ingroup krb5_principal 533 */ 534 535 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 536 krb5_unparse_name_fixed_flags(krb5_context context, 537 krb5_const_principal principal, 538 int flags, 539 char *name, 540 size_t len) 541 { 542 return unparse_name_fixed(context, principal, name, len, flags); 543 } 544 545 static krb5_error_code 546 unparse_name(krb5_context context, 547 krb5_const_principal principal, 548 char **name, 549 int flags) 550 { 551 size_t len = 0, plen; 552 size_t i; 553 krb5_error_code ret; 554 /* count length */ 555 if (princ_realm(principal)) { 556 plen = strlen(princ_realm(principal)); 557 558 if(strcspn(princ_realm(principal), quotable_chars) == plen) 559 len += plen; 560 else 561 len += 2*plen; 562 len++; /* '@' */ 563 } 564 for(i = 0; i < princ_num_comp(principal); i++){ 565 plen = strlen(princ_ncomp(principal, i)); 566 if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen) 567 len += plen; 568 else 569 len += 2*plen; 570 len++; 571 } 572 len++; /* '\0' */ 573 *name = malloc(len); 574 if(*name == NULL) { 575 krb5_set_error_message(context, ENOMEM, 576 N_("malloc: out of memory", "")); 577 return ENOMEM; 578 } 579 ret = unparse_name_fixed(context, principal, *name, len, flags); 580 if(ret) { 581 free(*name); 582 *name = NULL; 583 } 584 return ret; 585 } 586 587 /** 588 * Unparse the Kerberos name into a string 589 * 590 * @param context Kerberos 5 context 591 * @param principal principal to query 592 * @param name resulting string, free with krb5_xfree() 593 * 594 * @return An krb5 error code, see krb5_get_error_message(). 595 * 596 * @ingroup krb5_principal 597 */ 598 599 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 600 krb5_unparse_name(krb5_context context, 601 krb5_const_principal principal, 602 char **name) 603 { 604 return unparse_name(context, principal, name, 0); 605 } 606 607 /** 608 * Unparse the Kerberos name into a string 609 * 610 * @param context Kerberos 5 context 611 * @param principal principal to query 612 * @param flags flag to determine the behavior 613 * @param name resulting string, free with krb5_xfree() 614 * 615 * @return An krb5 error code, see krb5_get_error_message(). 616 * 617 * @ingroup krb5_principal 618 */ 619 620 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 621 krb5_unparse_name_flags(krb5_context context, 622 krb5_const_principal principal, 623 int flags, 624 char **name) 625 { 626 return unparse_name(context, principal, name, flags); 627 } 628 629 /** 630 * Unparse the principal name to a allocated buffer. The realm is 631 * skipped if its a default realm. 632 * 633 * @param context A Kerberos context. 634 * @param principal principal to unparse 635 * @param name returned buffer, free with krb5_xfree() 636 * 637 * @return An krb5 error code, see krb5_get_error_message(). 638 * 639 * @ingroup krb5_principal 640 */ 641 642 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 643 krb5_unparse_name_short(krb5_context context, 644 krb5_const_principal principal, 645 char **name) 646 { 647 return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT); 648 } 649 650 /** 651 * Set a new realm for a principal, and as a side-effect free the 652 * previous realm. 653 * 654 * @param context A Kerberos context. 655 * @param principal principal set the realm for 656 * @param realm the new realm to set 657 * 658 * @return An krb5 error code, see krb5_get_error_message(). 659 * 660 * @ingroup krb5_principal 661 */ 662 663 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 664 krb5_principal_set_realm(krb5_context context, 665 krb5_principal principal, 666 krb5_const_realm realm) 667 { 668 if (princ_realm(principal)) 669 free(princ_realm(principal)); 670 671 princ_realm(principal) = strdup(realm); 672 if (princ_realm(principal) == NULL) { 673 krb5_set_error_message(context, ENOMEM, 674 N_("malloc: out of memory", "")); 675 return ENOMEM; 676 } 677 return 0; 678 } 679 680 #ifndef HEIMDAL_SMALLER 681 /** 682 * Build a principal using vararg style building 683 * 684 * @param context A Kerberos context. 685 * @param principal returned principal 686 * @param rlen length of realm 687 * @param realm realm name 688 * @param ... a list of components ended with NULL. 689 * 690 * @return An krb5 error code, see krb5_get_error_message(). 691 * 692 * @ingroup krb5_principal 693 */ 694 695 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 696 krb5_build_principal(krb5_context context, 697 krb5_principal *principal, 698 int rlen, 699 krb5_const_realm realm, 700 ...) 701 { 702 krb5_error_code ret; 703 va_list ap; 704 va_start(ap, realm); 705 ret = krb5_build_principal_va(context, principal, rlen, realm, ap); 706 va_end(ap); 707 return ret; 708 } 709 #endif 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 724 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 725 krb5_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, strlen(realm), realm, ap); 741 va_end(ap); 742 if(r) 743 free(r); 744 return ret; 745 } 746 747 static krb5_error_code 748 append_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 774 static void 775 va_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 788 static void 789 va_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 800 static krb5_error_code 801 build_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 831 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 832 krb5_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 841 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 842 krb5_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 852 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 853 krb5_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 880 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 881 krb5_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 915 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 916 krb5_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 930 KRB5_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 963 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 964 krb5_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 985 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 986 krb5_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 999 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1000 krb5_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 1032 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1033 krb5_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, *host = NULL; 1042 1043 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) { 1044 krb5_set_error_message(context, KRB5_SNAME_UNSUPP_NAMETYPE, 1045 N_("unsupported name type %d", ""), 1046 (int)type); 1047 return KRB5_SNAME_UNSUPP_NAMETYPE; 1048 } 1049 if(hostname == NULL) { 1050 ret = gethostname(localhost, sizeof(localhost) - 1); 1051 if (ret != 0) { 1052 ret = errno; 1053 krb5_set_error_message(context, ret, 1054 N_("Failed to get local hostname", "")); 1055 return ret; 1056 } 1057 localhost[sizeof(localhost) - 1] = '\0'; 1058 hostname = localhost; 1059 } 1060 if(sname == NULL) 1061 sname = "host"; 1062 if(type == KRB5_NT_SRV_HST) { 1063 ret = krb5_expand_hostname_realms (context, hostname, 1064 &host, &realms); 1065 if (ret) 1066 return ret; 1067 strlwr(host); 1068 hostname = host; 1069 } else { 1070 ret = krb5_get_host_realm(context, hostname, &realms); 1071 if(ret) 1072 return ret; 1073 } 1074 1075 ret = krb5_make_principal(context, ret_princ, realms[0], sname, 1076 hostname, NULL); 1077 if(host) 1078 free(host); 1079 krb5_free_host_realm(context, realms); 1080 return ret; 1081 } 1082 1083 static const struct { 1084 const char *type; 1085 int32_t value; 1086 } nametypes[] = { 1087 { "UNKNOWN", KRB5_NT_UNKNOWN }, 1088 { "PRINCIPAL", KRB5_NT_PRINCIPAL }, 1089 { "SRV_INST", KRB5_NT_SRV_INST }, 1090 { "SRV_HST", KRB5_NT_SRV_HST }, 1091 { "SRV_XHST", KRB5_NT_SRV_XHST }, 1092 { "UID", KRB5_NT_UID }, 1093 { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL }, 1094 { "SMTP_NAME", KRB5_NT_SMTP_NAME }, 1095 { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL }, 1096 { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID }, 1097 { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL }, 1098 { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID }, 1099 { NULL, 0 } 1100 }; 1101 1102 /** 1103 * Parse nametype string and return a nametype integer 1104 * 1105 * @ingroup krb5_principal 1106 */ 1107 1108 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1109 krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype) 1110 { 1111 size_t i; 1112 1113 for(i = 0; nametypes[i].type; i++) { 1114 if (strcasecmp(nametypes[i].type, str) == 0) { 1115 *nametype = nametypes[i].value; 1116 return 0; 1117 } 1118 } 1119 krb5_set_error_message(context, KRB5_PARSE_MALFORMED, 1120 N_("Failed to find name type %s", ""), str); 1121 return KRB5_PARSE_MALFORMED; 1122 } 1123 1124 /** 1125 * Check if the cname part of the principal is a krbtgt principal 1126 * 1127 * @ingroup krb5_principal 1128 */ 1129 1130 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1131 krb5_principal_is_krbtgt(krb5_context context, krb5_const_principal p) 1132 { 1133 return p->name.name_string.len == 2 && 1134 strcmp(p->name.name_string.val[0], KRB5_TGS_NAME) == 0; 1135 1136 } 1137