Changeset 988 for vendor/current/source3/libads/kerberos.c
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source3/libads/kerberos.c
r860 r988 27 27 #include "../librpc/gen_ndr/ndr_misc.h" 28 28 #include "libads/kerberos_proto.h" 29 #include "libads/cldap.h" 29 30 #include "secrets.h" 31 #include "../lib/tsocket/tsocket.h" 30 32 31 33 #ifdef HAVE_KRB5 32 33 #define DEFAULT_KRB5_PORT 8834 34 35 35 #define LIBADS_CCACHE_NAME "MEMORY:libads" … … 48 48 { 49 49 if (num_prompts == 0) return 0; 50 50 #if HAVE_KRB5_PROMPT_TYPE 51 52 /* 53 * only heimdal has a prompt type and we need to deal with it here to 54 * avoid loops. 55 * 56 * removing the prompter completely is not an option as at least these 57 * versions would crash: heimdal-1.0.2 and heimdal-1.1. Later heimdal 58 * version have looping detection and return with a proper error code. 59 */ 60 61 if ((num_prompts == 2) && 62 (prompts[0].type == KRB5_PROMPT_TYPE_NEW_PASSWORD) && 63 (prompts[1].type == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN)) { 64 /* 65 * We don't want to change passwords here. We're 66 * called from heimal when the KDC returns 67 * KRB5KDC_ERR_KEY_EXPIRED, but at this point we don't 68 * have the chance to ask the user for a new 69 * password. If we return 0 (i.e. success), we will be 70 * spinning in the endless for-loop in 71 * change_password() in 72 * source4/heimdal/lib/krb5/init_creds_pw.c:526ff 73 */ 74 return KRB5KDC_ERR_KEY_EXPIRED; 75 } 76 #endif /* HAVE_KRB5_PROMPT_TYPE */ 51 77 memset(prompts[0].reply->data, '\0', prompts[0].reply->length); 52 78 if (prompts[0].reply->length > 0) { … … 218 244 #endif 219 245 if (add_netbios_addr) { 220 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) { 246 if ((code = smb_krb5_gen_netbios_krb5_address(&addr, 247 lp_netbios_name()))) { 221 248 goto out; 222 249 } … … 224 251 } 225 252 226 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),227 kerb_prompter, CONST_DISCARD(char *,password),253 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password), 254 kerb_prompter, discard_const_p(char, password), 228 255 0, NULL, opt))) { 229 256 goto out; … … 353 380 fstring salt; 354 381 355 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );356 strlower_m( salt );382 fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() ); 383 (void)strlower_m( salt ); 357 384 fstrcat( salt, lp_realm() ); 358 385 … … 406 433 ************************************************************************/ 407 434 435 static 408 436 char* kerberos_secrets_fetch_des_salt( void ) 409 437 { … … 412 440 if ( (key = des_salt_key()) == NULL ) { 413 441 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n")); 414 return False;442 return NULL; 415 443 } 416 444 … … 420 448 421 449 return salt; 422 }423 424 /************************************************************************425 Routine to get the default realm from the kerberos credentials cache.426 Caller must free if the return value is not NULL.427 ************************************************************************/428 429 char *kerberos_get_default_realm_from_ccache( void )430 {431 char *realm = NULL;432 krb5_context ctx = NULL;433 krb5_ccache cc = NULL;434 krb5_principal princ = NULL;435 436 initialize_krb5_error_table();437 if (krb5_init_context(&ctx)) {438 return NULL;439 }440 441 DEBUG(5,("kerberos_get_default_realm_from_ccache: "442 "Trying to read krb5 cache: %s\n",443 krb5_cc_default_name(ctx)));444 if (krb5_cc_default(ctx, &cc)) {445 DEBUG(0,("kerberos_get_default_realm_from_ccache: "446 "failed to read default cache\n"));447 goto out;448 }449 if (krb5_cc_get_principal(ctx, cc, &princ)) {450 DEBUG(0,("kerberos_get_default_realm_from_ccache: "451 "failed to get default principal\n"));452 goto out;453 }454 455 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)456 realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));457 #elif defined(HAVE_KRB5_PRINC_REALM)458 {459 krb5_data *realm_data = krb5_princ_realm(ctx, princ);460 realm = SMB_STRNDUP(realm_data->data, realm_data->length);461 }462 #endif463 464 out:465 466 if (ctx) {467 if (princ) {468 krb5_free_principal(ctx, princ);469 }470 if (cc) {471 krb5_cc_close(ctx, cc);472 }473 krb5_free_context(ctx);474 }475 476 return realm;477 }478 479 /************************************************************************480 Routine to get the realm from a given DNS name. Returns malloc'ed memory.481 Caller must free() if the return value is not NULL.482 ************************************************************************/483 484 char *kerberos_get_realm_from_hostname(const char *hostname)485 {486 #if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM)487 #if defined(HAVE_KRB5_REALM_TYPE)488 /* Heimdal. */489 krb5_realm *realm_list = NULL;490 #else491 /* MIT */492 char **realm_list = NULL;493 #endif494 char *realm = NULL;495 krb5_error_code kerr;496 krb5_context ctx = NULL;497 498 initialize_krb5_error_table();499 if (krb5_init_context(&ctx)) {500 return NULL;501 }502 503 kerr = krb5_get_host_realm(ctx, hostname, &realm_list);504 if (kerr != 0) {505 DEBUG(3,("kerberos_get_realm_from_hostname %s: "506 "failed %s\n",507 hostname ? hostname : "(NULL)",508 error_message(kerr) ));509 goto out;510 }511 512 if (realm_list && realm_list[0]) {513 realm = SMB_STRDUP(realm_list[0]);514 }515 516 out:517 518 if (ctx) {519 if (realm_list) {520 krb5_free_host_realm(ctx, realm_list);521 realm_list = NULL;522 }523 krb5_free_context(ctx);524 ctx = NULL;525 }526 return realm;527 #else528 return NULL;529 #endif530 450 } 531 451 … … 537 457 ************************************************************************/ 538 458 459 static 539 460 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context, 540 461 krb5_principal host_princ, … … 567 488 568 489 return ret_princ; 490 } 491 492 int create_kerberos_key_from_string(krb5_context context, 493 krb5_principal host_princ, 494 krb5_data *password, 495 krb5_keyblock *key, 496 krb5_enctype enctype, 497 bool no_salt) 498 { 499 krb5_principal salt_princ = NULL; 500 int ret; 501 /* 502 * Check if we've determined that the KDC is salting keys for this 503 * principal/enctype in a non-obvious way. If it is, try to match 504 * its behavior. 505 */ 506 if (no_salt) { 507 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length); 508 if (!KRB5_KEY_DATA(key)) { 509 return ENOMEM; 510 } 511 memcpy(KRB5_KEY_DATA(key), password->data, password->length); 512 KRB5_KEY_LENGTH(key) = password->length; 513 KRB5_KEY_TYPE(key) = enctype; 514 return 0; 515 } 516 salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype); 517 ret = smb_krb5_create_key_from_string(context, 518 salt_princ ? salt_princ : host_princ, 519 NULL, 520 password, 521 enctype, 522 key); 523 if (salt_princ) { 524 krb5_free_principal(context, salt_princ); 525 } 526 return ret; 569 527 } 570 528 … … 664 622 ************************************************************************/ 665 623 666 static char *print_kdc_line(char *mem_ctx,667 const char *prev_line,668 const struct sockaddr_storage *pss,669 const char *kdc_name)670 {671 char *kdc_str = NULL;672 673 if (pss->ss_family == AF_INET) {674 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",675 prev_line,676 print_canonical_sockaddr(mem_ctx, pss));677 } else {678 char addr[INET6_ADDRSTRLEN];679 uint16_t port = get_sockaddr_port(pss);680 681 DEBUG(10,("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",682 kdc_name, port));683 684 if (port != 0 && port != DEFAULT_KRB5_PORT) {685 /* Currently for IPv6 we can't specify a non-default686 krb5 port with an address, as this requires a ':'.687 Resolve to a name. */688 char hostname[MAX_DNS_NAME_LENGTH];689 int ret = sys_getnameinfo((const struct sockaddr *)pss,690 sizeof(*pss),691 hostname, sizeof(hostname),692 NULL, 0,693 NI_NAMEREQD);694 if (ret) {695 DEBUG(0,("print_kdc_line: can't resolve name "696 "for kdc with non-default port %s. "697 "Error %s\n.",698 print_canonical_sockaddr(mem_ctx, pss),699 gai_strerror(ret)));700 return NULL;701 }702 /* Success, use host:port */703 kdc_str = talloc_asprintf(mem_ctx,704 "%s\tkdc = %s:%u\n",705 prev_line,706 hostname,707 (unsigned int)port);708 } else {709 710 /* no krb5 lib currently supports "kdc = ipv6 address"711 * at all, so just fill in just the kdc_name if we have712 * it and let the krb5 lib figure out the appropriate713 * ipv6 address - gd */714 715 if (kdc_name) {716 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",717 prev_line, kdc_name);718 } else {719 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",720 prev_line,721 print_sockaddr(addr,722 sizeof(addr),723 pss));724 }725 }726 }727 return kdc_str;728 }729 730 624 /************************************************************************ 731 625 Create a string list of available kdc's, possibly searching by sitename. … … 736 630 ************************************************************************/ 737 631 632 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs, 633 const struct sockaddr_storage *addr) 634 { 635 int i; 636 637 for (i=0; i<*num_addrs; i++) { 638 if (sockaddr_equal((const struct sockaddr *)&addrs[i], 639 (const struct sockaddr *)addr)) { 640 return; 641 } 642 } 643 addrs[i] = *addr; 644 *num_addrs += 1; 645 } 646 647 /* print_canonical_sockaddr prints an ipv6 addr in the form of 648 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not 649 * always properly dealt with by some older krb5 libraries. Adding the hard-coded 650 * portnumber workarounds the issue. - gd */ 651 652 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx, 653 const struct sockaddr_storage *pss) 654 { 655 char *str = NULL; 656 657 str = print_canonical_sockaddr(mem_ctx, pss); 658 if (str == NULL) { 659 return NULL; 660 } 661 662 if (pss->ss_family != AF_INET6) { 663 return str; 664 } 665 666 #if defined(HAVE_IPV6) 667 str = talloc_asprintf_append(str, ":88"); 668 #endif 669 return str; 670 } 671 738 672 static char *get_kdc_ip_string(char *mem_ctx, 739 673 const char *realm, 740 674 const char *sitename, 741 struct sockaddr_storage *pss,742 const char *kdc_name) 743 { 675 const struct sockaddr_storage *pss) 676 { 677 TALLOC_CTX *frame = talloc_stackframe(); 744 678 int i; 745 679 struct ip_service *ip_srv_site = NULL; … … 747 681 int count_site = 0; 748 682 int count_nonsite; 749 char *kdc_str = print_kdc_line(mem_ctx, "", pss, kdc_name); 683 int num_dcs; 684 struct sockaddr_storage *dc_addrs; 685 struct tsocket_address **dc_addrs2 = NULL; 686 const struct tsocket_address * const *dc_addrs3 = NULL; 687 char *result = NULL; 688 struct netlogon_samlogon_response **responses = NULL; 689 NTSTATUS status; 690 char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "", 691 print_canonical_sockaddr_with_port(mem_ctx, pss)); 750 692 751 693 if (kdc_str == NULL) { 694 TALLOC_FREE(frame); 752 695 return NULL; 753 696 } … … 759 702 760 703 if (sitename) { 761 762 704 get_kdc_list(realm, sitename, &ip_srv_site, &count_site); 763 764 for (i = 0; i < count_site; i++) { 765 if (sockaddr_equal((struct sockaddr *)&ip_srv_site[i].ss, 766 (struct sockaddr *)pss)) { 767 continue; 768 } 769 /* Append to the string - inefficient 770 * but not done often. */ 771 kdc_str = print_kdc_line(mem_ctx, 772 kdc_str, 773 &ip_srv_site[i].ss, 774 NULL); 775 if (!kdc_str) { 776 SAFE_FREE(ip_srv_site); 777 return NULL; 778 } 779 } 705 DEBUG(10, ("got %d addresses from site %s search\n", count_site, 706 sitename)); 780 707 } 781 708 … … 783 710 784 711 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite); 712 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite)); 713 714 dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage, 715 count_site + count_nonsite); 716 if (dc_addrs == NULL) { 717 goto out; 718 } 719 720 num_dcs = 0; 721 722 for (i = 0; i < count_site; i++) { 723 if (!sockaddr_equal( 724 (const struct sockaddr *)pss, 725 (const struct sockaddr *)&ip_srv_site[i].ss)) { 726 add_sockaddr_unique(dc_addrs, &num_dcs, 727 &ip_srv_site[i].ss); 728 } 729 } 785 730 786 731 for (i = 0; i < count_nonsite; i++) { 787 int j; 788 789 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss, (struct sockaddr *)pss)) { 732 if (!sockaddr_equal( 733 (const struct sockaddr *)pss, 734 (const struct sockaddr *)&ip_srv_nonsite[i].ss)) { 735 add_sockaddr_unique(dc_addrs, &num_dcs, 736 &ip_srv_nonsite[i].ss); 737 } 738 } 739 740 dc_addrs2 = talloc_zero_array(talloc_tos(), 741 struct tsocket_address *, 742 num_dcs); 743 744 DEBUG(10, ("%d additional KDCs to test\n", num_dcs)); 745 if (num_dcs == 0) { 746 goto out; 747 } 748 if (dc_addrs2 == NULL) { 749 goto out; 750 } 751 752 for (i=0; i<num_dcs; i++) { 753 char addr[INET6_ADDRSTRLEN]; 754 int ret; 755 756 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]); 757 758 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip", 759 addr, LDAP_PORT, 760 &dc_addrs2[i]); 761 if (ret != 0) { 762 status = map_nt_error_from_unix(errno); 763 DEBUG(2,("Failed to create tsocket_address for %s - %s\n", 764 addr, nt_errstr(status))); 765 goto out; 766 } 767 } 768 769 dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2; 770 771 status = cldap_multi_netlogon(talloc_tos(), 772 dc_addrs3, num_dcs, 773 realm, lp_netbios_name(), 774 NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX, 775 MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses); 776 TALLOC_FREE(dc_addrs2); 777 dc_addrs3 = NULL; 778 779 if (!NT_STATUS_IS_OK(status)) { 780 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: " 781 "%s\n", nt_errstr(status))); 782 goto out; 783 } 784 785 for (i=0; i<num_dcs; i++) { 786 char *new_kdc_str; 787 788 if (responses[i] == NULL) { 790 789 continue; 791 790 } 792 791 793 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */794 for (j = 0; j < count_site; j++) {795 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss,796 (struct sockaddr *)&ip_srv_site[j].ss)) {797 break;798 }799 /* As the lists are sorted we can break early if nonsite > site. */800 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {801 break;802 }803 }804 if (j != i) {805 continue;806 }807 808 792 /* Append to the string - inefficient but not done often. */ 809 kdc_str = print_kdc_line(mem_ctx, 810 kdc_str, 811 &ip_srv_nonsite[i].ss, 812 NULL); 813 if (!kdc_str) { 814 SAFE_FREE(ip_srv_site); 815 SAFE_FREE(ip_srv_nonsite); 816 return NULL; 817 } 818 } 819 820 793 new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", 794 kdc_str, 795 print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i])); 796 if (new_kdc_str == NULL) { 797 goto out; 798 } 799 TALLOC_FREE(kdc_str); 800 kdc_str = new_kdc_str; 801 } 802 803 out: 804 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str)); 805 806 result = kdc_str; 821 807 SAFE_FREE(ip_srv_site); 822 808 SAFE_FREE(ip_srv_nonsite); 823 824 DEBUG(10,("get_kdc_ip_string: Returning %s\n", 825 kdc_str )); 826 827 return kdc_str; 809 TALLOC_FREE(frame); 810 return result; 828 811 } 829 812 … … 838 821 const char *domain, 839 822 const char *sitename, 840 struct sockaddr_storage *pss, 841 const char *kdc_name) 823 const struct sockaddr_storage *pss) 842 824 { 843 825 char *dname; … … 852 834 bool result = false; 853 835 char *aes_enctypes = NULL; 836 mode_t mask; 854 837 855 838 if (!lp_create_krb5_conf()) { … … 863 846 } 864 847 865 if (domain == NULL || pss == NULL || kdc_name == NULL) {848 if (domain == NULL || pss == NULL) { 866 849 return false; 867 850 } … … 892 875 893 876 realm_upper = talloc_strdup(fname, realm); 894 strupper_m(realm_upper); 895 896 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss, kdc_name); 877 if (!strupper_m(realm_upper)) { 878 goto done; 879 } 880 881 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss); 897 882 if (!kdc_ip_string) { 898 883 goto done; … … 921 906 "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n" 922 907 "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n" 923 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n" 908 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n" 909 "\tdns_lookup_realm = false\n\n" 924 910 "[realms]\n\t%s = {\n" 925 " \t%s\t}\n",911 "%s\t}\n", 926 912 realm_upper, aes_enctypes, aes_enctypes, aes_enctypes, 927 913 realm_upper, kdc_ip_string); … … 933 919 flen = strlen(file_contents); 934 920 921 mask = umask(S_IRWXO | S_IRWXG); 935 922 fd = mkstemp(tmpname); 923 umask(mask); 936 924 if (fd == -1) { 937 925 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed," … … 989 977 990 978 if (strequal(realm, lp_realm())) { 991 char linkpath[PATH_MAX+1]; 992 int lret; 993 994 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1); 995 if (lret != -1) { 996 linkpath[lret] = '\0'; 997 } 998 999 if (lret != -1 || strcmp(linkpath, fname) == 0) { 1000 /* Symlink already exists. */ 1001 goto done; 979 SMB_STRUCT_STAT sbuf; 980 981 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) { 982 if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) { 983 int lret; 984 size_t alloc_size = sbuf.st_ex_size + 1; 985 char *linkpath = talloc_array(talloc_tos(), char, 986 alloc_size); 987 if (!linkpath) { 988 goto done; 989 } 990 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, 991 alloc_size - 1); 992 if (lret == -1) { 993 TALLOC_FREE(linkpath); 994 goto done; 995 } 996 linkpath[lret] = '\0'; 997 998 if (strcmp(linkpath, fname) == 0) { 999 /* Symlink already exists. */ 1000 TALLOC_FREE(linkpath); 1001 goto done; 1002 } 1003 TALLOC_FREE(linkpath); 1004 } 1002 1005 } 1003 1006 1004 1007 /* Try and replace with a symlink. */ 1005 1008 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) { 1006 const char *newpath = SYSTEM_KRB5_CONF_PATH ##".saved";1009 const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved"; 1007 1010 if (errno != EEXIST) { 1008 1011 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
Note:
See TracChangeset
for help on using the changeset viewer.