2 Unix SMB/CIFS implementation.
3 kerberos utility library
4 Copyright (C) Andrew Tridgell 2001
5 Copyright (C) Remus Koos 2001
6 Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 2004.
7 Copyright (C) Jeremy Allison 2004.
8 Copyright (C) Gerald Carter 2006.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #define DEFAULT_KRB5_PORT 88
30 #define LIBADS_CCACHE_NAME "MEMORY:libads"
33 we use a prompter to avoid a crash bug in the kerberos libs when
34 dealing with empty passwords
35 this prompter is just a string copy ...
37 static krb5_error_code
38 kerb_prompter(krb5_context ctx, void *data,
42 krb5_prompt prompts[])
44 if (num_prompts == 0) return 0;
46 memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
47 if (prompts[0].reply->length > 0) {
49 strncpy(prompts[0].reply->data, (const char *)data,
50 prompts[0].reply->length-1);
51 prompts[0].reply->length = strlen(prompts[0].reply->data);
53 prompts[0].reply->length = 0;
59 static bool smb_krb5_err_io_nstatus(TALLOC_CTX *mem_ctx,
60 DATA_BLOB *edata_blob,
61 KRB5_EDATA_NTSTATUS *edata)
66 if (!mem_ctx || !edata_blob || !edata)
69 if (!prs_init(&ps, edata_blob->length, mem_ctx, UNMARSHALL))
72 if (!prs_copy_data_in(&ps, (char *)edata_blob->data, edata_blob->length))
75 prs_set_offset(&ps, 0);
77 if (!prs_ntstatus("ntstatus", &ps, 1, &edata->ntstatus))
80 if (!prs_uint32("unknown1", &ps, 1, &edata->unknown1))
83 if (!prs_uint32("unknown2", &ps, 1, &edata->unknown2)) /* only seen 00000001 here */
93 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
97 DATA_BLOB unwrapped_edata;
99 KRB5_EDATA_NTSTATUS parsed_edata;
101 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
102 edata = data_blob(error->e_data->data, error->e_data->length);
104 edata = data_blob(error->e_data.data, error->e_data.length);
105 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
108 dump_data(10, edata.data, edata.length);
109 #endif /* DEVELOPER */
111 mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
112 if (mem_ctx == NULL) {
113 data_blob_free(&edata);
117 if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
118 data_blob_free(&edata);
119 TALLOC_FREE(mem_ctx);
123 data_blob_free(&edata);
125 if (!smb_krb5_err_io_nstatus(mem_ctx, &unwrapped_edata, &parsed_edata)) {
126 data_blob_free(&unwrapped_edata);
127 TALLOC_FREE(mem_ctx);
131 data_blob_free(&unwrapped_edata);
134 *nt_status = parsed_edata.ntstatus;
137 TALLOC_FREE(mem_ctx);
142 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx,
143 krb5_get_init_creds_opt *opt,
147 krb5_error *error = NULL;
149 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
150 ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
152 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
153 error_message(ret)));
156 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
159 DEBUG(1,("no krb5_error\n"));
163 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
164 if (!error->e_data) {
166 if (error->e_data.data == NULL) {
167 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
168 DEBUG(1,("no edata in krb5_error\n"));
169 krb5_free_error(ctx, error);
173 ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
175 krb5_free_error(ctx, error);
181 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
182 place in default cache location.
185 int kerberos_kinit_password_ext(const char *principal,
186 const char *password,
189 time_t *renew_till_time,
190 const char *cache_name,
192 bool add_netbios_addr,
193 time_t renewable_time,
196 krb5_context ctx = NULL;
197 krb5_error_code code = 0;
198 krb5_ccache cc = NULL;
199 krb5_principal me = NULL;
201 krb5_get_init_creds_opt *opt = NULL;
202 smb_krb5_addresses *addr = NULL;
204 ZERO_STRUCT(my_creds);
206 initialize_krb5_error_table();
207 if ((code = krb5_init_context(&ctx)))
210 if (time_offset != 0) {
211 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
214 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
216 cache_name ? cache_name: krb5_cc_default_name(ctx),
217 getenv("KRB5_CONFIG")));
219 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
223 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
227 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
231 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
232 krb5_get_init_creds_opt_set_forwardable(opt, True);
235 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
238 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
240 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
245 if (add_netbios_addr) {
246 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
249 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
252 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
253 kerb_prompter, CONST_DISCARD(char *,password),
258 if ((code = krb5_cc_initialize(ctx, cc, me))) {
262 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
267 *expire_time = (time_t) my_creds.times.endtime;
270 if (renew_till_time) {
271 *renew_till_time = (time_t) my_creds.times.renew_till;
280 *ntstatus = NT_STATUS_OK;
284 /* try to get ntstatus code out of krb5_error when we have it
285 * inside the krb5_get_init_creds_opt - gd */
287 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
292 /* fall back to self-made-mapping */
293 *ntstatus = krb5_to_nt_status(code);
297 krb5_free_cred_contents(ctx, &my_creds);
299 krb5_free_principal(ctx, me);
302 smb_krb5_free_addresses(ctx, addr);
305 smb_krb5_get_init_creds_opt_free(ctx, opt);
308 krb5_cc_close(ctx, cc);
311 krb5_free_context(ctx);
318 /* run kinit to setup our ccache */
319 int ads_kinit_password(ADS_STRUCT *ads)
323 const char *account_name;
327 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
328 account_name = lp_workgroup();
330 /* always use the sAMAccountName for security = domain */
331 /* global_myname()$@REA.LM */
332 if ( lp_security() == SEC_DOMAIN ) {
333 fstr_sprintf( acct_name, "%s$", global_myname() );
334 account_name = acct_name;
337 /* This looks like host/global_myname()@REA.LM */
338 account_name = ads->auth.user_name;
341 if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
342 return KRB5_CC_NOMEM;
345 if (!ads->auth.password) {
347 return KRB5_LIBOS_CANTREADPWD;
350 ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
351 &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable,
355 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
356 s, error_message(ret)));
362 int ads_kdestroy(const char *cc_name)
364 krb5_error_code code;
365 krb5_context ctx = NULL;
366 krb5_ccache cc = NULL;
368 initialize_krb5_error_table();
369 if ((code = krb5_init_context (&ctx))) {
370 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
371 error_message(code)));
376 if ((code = krb5_cc_default(ctx, &cc))) {
377 krb5_free_context(ctx);
381 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
382 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
383 error_message(code)));
384 krb5_free_context(ctx);
389 if ((code = krb5_cc_destroy (ctx, cc))) {
390 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
391 error_message(code)));
394 krb5_free_context (ctx);
398 /************************************************************************
399 Routine to fetch the salting principal for a service. Active
400 Directory may use a non-obvious principal name to generate the salt
401 when it determines the key to use for encrypting tickets for a service,
402 and hopefully we detected that when we joined the domain.
403 ************************************************************************/
405 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
410 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
414 ret = (char *)secrets_fetch(key, NULL);
419 /************************************************************************
420 Return the standard DES salt key
421 ************************************************************************/
423 char* kerberos_standard_des_salt( void )
427 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
429 fstrcat( salt, lp_realm() );
431 return SMB_STRDUP( salt );
434 /************************************************************************
435 ************************************************************************/
437 static char* des_salt_key( void )
441 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
446 /************************************************************************
447 ************************************************************************/
449 bool kerberos_secrets_store_des_salt( const char* salt )
454 if ( (key = des_salt_key()) == NULL ) {
455 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
460 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
461 secrets_delete( key );
465 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
467 ret = secrets_store( key, salt, strlen(salt)+1 );
474 /************************************************************************
475 ************************************************************************/
477 char* kerberos_secrets_fetch_des_salt( void )
481 if ( (key = des_salt_key()) == NULL ) {
482 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
486 salt = (char*)secrets_fetch( key, NULL );
493 /************************************************************************
494 Routine to get the default realm from the kerberos credentials cache.
495 Caller must free if the return value is not NULL.
496 ************************************************************************/
498 char *kerberos_get_default_realm_from_ccache( void )
501 krb5_context ctx = NULL;
502 krb5_ccache cc = NULL;
503 krb5_principal princ = NULL;
505 initialize_krb5_error_table();
506 if (krb5_init_context(&ctx)) {
510 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
511 "Trying to read krb5 cache: %s\n",
512 krb5_cc_default_name(ctx)));
513 if (krb5_cc_default(ctx, &cc)) {
514 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
515 "failed to read default cache\n"));
518 if (krb5_cc_get_principal(ctx, cc, &princ)) {
519 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
520 "failed to get default principal\n"));
524 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
525 realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
526 #elif defined(HAVE_KRB5_PRINC_REALM)
528 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
529 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
536 krb5_free_principal(ctx, princ);
539 krb5_cc_close(ctx, cc);
542 krb5_free_context(ctx);
549 /************************************************************************
550 Routine to get the salting principal for this service. This is
551 maintained for backwards compatibilty with releases prior to 3.0.24.
552 Since we store the salting principal string only at join, we may have
553 to look for the older tdb keys. Caller must free if return is not null.
554 ************************************************************************/
556 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
557 krb5_principal host_princ,
560 char *unparsed_name = NULL, *salt_princ_s = NULL;
561 krb5_principal ret_princ = NULL;
563 /* lookup new key first */
565 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
567 /* look under the old key. If this fails, just use the standard key */
569 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
570 return (krb5_principal)NULL;
572 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
573 /* fall back to host/machine.realm@REALM */
574 salt_princ_s = kerberos_standard_des_salt();
578 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
582 SAFE_FREE(unparsed_name);
583 SAFE_FREE(salt_princ_s);
588 /************************************************************************
589 Routine to set the salting principal for this service. Active
590 Directory may use a non-obvious principal name to generate the salt
591 when it determines the key to use for encrypting tickets for a service,
592 and hopefully we detected that when we joined the domain.
593 Setting principal to NULL deletes this entry.
594 ************************************************************************/
596 bool kerberos_secrets_store_salting_principal(const char *service,
598 const char *principal)
602 krb5_context context = NULL;
603 krb5_principal princ = NULL;
604 char *princ_s = NULL;
605 char *unparsed_name = NULL;
607 krb5_init_context(&context);
611 if (strchr_m(service, '@')) {
612 asprintf(&princ_s, "%s", service);
614 asprintf(&princ_s, "%s@%s", service, lp_realm());
617 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
621 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
625 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
630 if ((principal != NULL) && (strlen(principal) > 0)) {
631 ret = secrets_store(key, principal, strlen(principal) + 1);
633 ret = secrets_delete(key);
640 SAFE_FREE(unparsed_name);
643 krb5_free_context(context);
650 /************************************************************************
651 ************************************************************************/
653 int kerberos_kinit_password(const char *principal,
654 const char *password,
656 const char *cache_name)
658 return kerberos_kinit_password_ext(principal,
670 /************************************************************************
671 ************************************************************************/
673 static char *print_kdc_line(char *mem_ctx,
674 const char *prev_line,
675 const struct sockaddr_storage *pss)
677 char *kdc_str = NULL;
679 if (pss->ss_family == AF_INET) {
680 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
682 print_canonical_sockaddr(mem_ctx, pss));
684 char addr[INET6_ADDRSTRLEN];
685 uint16_t port = get_sockaddr_port(pss);
687 if (port != 0 && port != DEFAULT_KRB5_PORT) {
688 /* Currently for IPv6 we can't specify a non-default
689 krb5 port with an address, as this requires a ':'.
690 Resolve to a name. */
691 char hostname[MAX_DNS_NAME_LENGTH];
692 int ret = sys_getnameinfo((const struct sockaddr *)pss,
694 hostname, sizeof(hostname),
698 DEBUG(0,("print_kdc_line: can't resolve name "
699 "for kdc with non-default port %s. "
701 print_canonical_sockaddr(mem_ctx, pss),
704 /* Success, use host:port */
705 kdc_str = talloc_asprintf(mem_ctx,
711 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
721 /************************************************************************
722 Create a string list of available kdc's, possibly searching by sitename.
724 ************************************************************************/
726 static char *get_kdc_ip_string(char *mem_ctx,
728 const char *sitename,
729 struct sockaddr_storage *pss)
732 struct ip_service *ip_srv_site = NULL;
733 struct ip_service *ip_srv_nonsite = NULL;
736 char *kdc_str = print_kdc_line(mem_ctx, "", pss);
738 if (kdc_str == NULL) {
742 /* Get the KDC's only in this site. */
746 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
748 for (i = 0; i < count_site; i++) {
749 if (addr_equal(&ip_srv_site[i].ss, pss)) {
752 /* Append to the string - inefficient
753 * but not done often. */
754 kdc_str = print_kdc_line(mem_ctx,
758 SAFE_FREE(ip_srv_site);
766 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
768 for (i = 0; i < count_nonsite; i++) {
771 if (addr_equal(&ip_srv_nonsite[i].ss, pss)) {
775 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
776 for (j = 0; j < count_site; j++) {
777 if (addr_equal(&ip_srv_nonsite[i].ss,
778 &ip_srv_site[j].ss)) {
781 /* As the lists are sorted we can break early if nonsite > site. */
782 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
790 /* Append to the string - inefficient but not done often. */
791 kdc_str = print_kdc_line(mem_ctx,
793 &ip_srv_nonsite[i].ss);
795 SAFE_FREE(ip_srv_site);
796 SAFE_FREE(ip_srv_nonsite);
802 SAFE_FREE(ip_srv_site);
803 SAFE_FREE(ip_srv_nonsite);
805 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
811 /************************************************************************
812 Create a specific krb5.conf file in the private directory pointing
813 at a specific kdc for a realm. Keyed off domain name. Sets
814 KRB5_CONFIG environment variable to point to this file. Must be
815 run as root or will fail (which is a good thing :-).
816 ************************************************************************/
818 bool create_local_private_krb5_conf_for_domain(const char *realm,
820 const char *sitename,
821 struct sockaddr_storage *pss)
823 char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
824 char *tmpname = NULL;
826 char *file_contents = NULL;
827 char *kdc_ip_string = NULL;
831 char *realm_upper = NULL;
836 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
837 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
838 "failed to create directory %s. Error was %s\n",
839 dname, strerror(errno) ));
844 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
850 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
856 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
857 fname, realm, domain ));
859 realm_upper = talloc_strdup(fname, realm);
860 strupper_m(realm_upper);
862 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
863 if (!kdc_ip_string) {
868 file_contents = talloc_asprintf(fname,
869 "[libdefaults]\n\tdefault_realm = %s\n"
870 "default_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
871 "default_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
872 "preferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
873 "[realms]\n\t%s = {\n"
875 realm_upper, realm_upper, kdc_ip_string);
877 if (!file_contents) {
882 flen = strlen(file_contents);
884 fd = smb_mkstemp(tmpname);
886 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
887 " for file %s. Errno %s\n",
888 tmpname, strerror(errno) ));
891 if (fchmod(fd, 0644)==-1) {
892 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
894 tmpname, strerror(errno) ));
901 ret = write(fd, file_contents, flen);
903 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
904 " returned %d (should be %u). Errno %s\n",
905 (int)ret, (unsigned int)flen, strerror(errno) ));
912 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
913 " Errno %s\n", strerror(errno) ));
919 if (rename(tmpname, fname) == -1) {
920 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
921 "of %s to %s failed. Errno %s\n",
922 tmpname, fname, strerror(errno) ));
928 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
929 "file %s with realm %s KDC list = %s\n",
930 fname, realm_upper, kdc_ip_string));
932 /* Set the environment variable to this file. */
933 setenv("KRB5_CONFIG", fname, 1);
935 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
937 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
938 /* Insanity, sheer insanity..... */
940 if (strequal(realm, lp_realm())) {
941 char linkpath[PATH_MAX+1];
944 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
946 linkpath[lret] = '\0';
949 if (lret != -1 || strcmp(linkpath, fname) == 0) {
950 /* Symlink already exists. */
955 /* Try and replace with a symlink. */
956 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
957 const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
958 if (errno != EEXIST) {
959 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
960 "of %s to %s failed. Errno %s\n",
961 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
963 return True; /* Not a fatal error. */
966 /* Yes, this is a race conditon... too bad. */
967 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
968 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
969 "of %s to %s failed. Errno %s\n",
970 SYSTEM_KRB5_CONF_PATH, newpath,
973 return True; /* Not a fatal error. */
976 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
977 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
978 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
979 fname, strerror(errno) ));
981 return True; /* Not a fatal error. */