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