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/>.
26 #include "../librpc/gen_ndr/ndr_misc.h"
27 #include "libads/kerberos_proto.h"
31 #define DEFAULT_KRB5_PORT 88
33 #define LIBADS_CCACHE_NAME "MEMORY:libads"
36 we use a prompter to avoid a crash bug in the kerberos libs when
37 dealing with empty passwords
38 this prompter is just a string copy ...
40 static krb5_error_code
41 kerb_prompter(krb5_context ctx, void *data,
45 krb5_prompt prompts[])
47 if (num_prompts == 0) return 0;
49 memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
50 if (prompts[0].reply->length > 0) {
52 strncpy((char *)prompts[0].reply->data, (const char *)data,
53 prompts[0].reply->length-1);
54 prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
56 prompts[0].reply->length = 0;
62 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
66 DATA_BLOB unwrapped_edata;
68 struct KRB5_EDATA_NTSTATUS parsed_edata;
69 enum ndr_err_code ndr_err;
71 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
72 edata = data_blob(error->e_data->data, error->e_data->length);
74 edata = data_blob(error->e_data.data, error->e_data.length);
75 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
78 dump_data(10, edata.data, edata.length);
79 #endif /* DEVELOPER */
81 mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
82 if (mem_ctx == NULL) {
83 data_blob_free(&edata);
87 if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
88 data_blob_free(&edata);
93 data_blob_free(&edata);
95 ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx,
96 &parsed_edata, (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
97 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
98 data_blob_free(&unwrapped_edata);
103 data_blob_free(&unwrapped_edata);
106 *nt_status = parsed_edata.ntstatus;
109 TALLOC_FREE(mem_ctx);
114 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx,
115 krb5_get_init_creds_opt *opt,
119 krb5_error *error = NULL;
121 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
122 ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
124 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
125 error_message(ret)));
128 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
131 DEBUG(1,("no krb5_error\n"));
135 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
136 if (!error->e_data) {
138 if (error->e_data.data == NULL) {
139 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
140 DEBUG(1,("no edata in krb5_error\n"));
141 krb5_free_error(ctx, error);
145 ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
147 krb5_free_error(ctx, error);
153 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
154 place in default cache location.
157 int kerberos_kinit_password_ext(const char *principal,
158 const char *password,
161 time_t *renew_till_time,
162 const char *cache_name,
164 bool add_netbios_addr,
165 time_t renewable_time,
168 krb5_context ctx = NULL;
169 krb5_error_code code = 0;
170 krb5_ccache cc = NULL;
171 krb5_principal me = NULL;
173 krb5_get_init_creds_opt *opt = NULL;
174 smb_krb5_addresses *addr = NULL;
176 ZERO_STRUCT(my_creds);
178 initialize_krb5_error_table();
179 if ((code = krb5_init_context(&ctx)))
182 if (time_offset != 0) {
183 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
186 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
188 cache_name ? cache_name: krb5_cc_default_name(ctx),
189 getenv("KRB5_CONFIG")));
191 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
195 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
199 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
203 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
204 krb5_get_init_creds_opt_set_forwardable(opt, True);
207 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
210 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
212 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
217 if (add_netbios_addr) {
218 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
221 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
224 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
225 kerb_prompter, CONST_DISCARD(char *,password),
230 if ((code = krb5_cc_initialize(ctx, cc, me))) {
234 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
239 *expire_time = (time_t) my_creds.times.endtime;
242 if (renew_till_time) {
243 *renew_till_time = (time_t) my_creds.times.renew_till;
252 *ntstatus = NT_STATUS_OK;
256 /* try to get ntstatus code out of krb5_error when we have it
257 * inside the krb5_get_init_creds_opt - gd */
259 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
264 /* fall back to self-made-mapping */
265 *ntstatus = krb5_to_nt_status(code);
269 krb5_free_cred_contents(ctx, &my_creds);
271 krb5_free_principal(ctx, me);
274 smb_krb5_free_addresses(ctx, addr);
277 smb_krb5_get_init_creds_opt_free(ctx, opt);
280 krb5_cc_close(ctx, cc);
283 krb5_free_context(ctx);
288 int ads_kdestroy(const char *cc_name)
290 krb5_error_code code;
291 krb5_context ctx = NULL;
292 krb5_ccache cc = NULL;
294 initialize_krb5_error_table();
295 if ((code = krb5_init_context (&ctx))) {
296 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
297 error_message(code)));
302 if ((code = krb5_cc_default(ctx, &cc))) {
303 krb5_free_context(ctx);
307 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
308 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
309 error_message(code)));
310 krb5_free_context(ctx);
315 if ((code = krb5_cc_destroy (ctx, cc))) {
316 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
317 error_message(code)));
320 krb5_free_context (ctx);
324 /************************************************************************
325 Routine to fetch the salting principal for a service. Active
326 Directory may use a non-obvious principal name to generate the salt
327 when it determines the key to use for encrypting tickets for a service,
328 and hopefully we detected that when we joined the domain.
329 ************************************************************************/
331 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
336 if (asprintf(&key, "%s/%s/enctype=%d",
337 SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
340 ret = (char *)secrets_fetch(key, NULL);
345 /************************************************************************
346 Return the standard DES salt key
347 ************************************************************************/
349 char* kerberos_standard_des_salt( void )
353 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
355 fstrcat( salt, lp_realm() );
357 return SMB_STRDUP( salt );
360 /************************************************************************
361 ************************************************************************/
363 static char* des_salt_key( void )
367 if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
375 /************************************************************************
376 ************************************************************************/
378 bool kerberos_secrets_store_des_salt( const char* salt )
383 if ( (key = des_salt_key()) == NULL ) {
384 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
389 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
390 secrets_delete( key );
394 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
396 ret = secrets_store( key, salt, strlen(salt)+1 );
403 /************************************************************************
404 ************************************************************************/
406 char* kerberos_secrets_fetch_des_salt( void )
410 if ( (key = des_salt_key()) == NULL ) {
411 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
415 salt = (char*)secrets_fetch( key, NULL );
422 /************************************************************************
423 Routine to get the default realm from the kerberos credentials cache.
424 Caller must free if the return value is not NULL.
425 ************************************************************************/
427 char *kerberos_get_default_realm_from_ccache( void )
430 krb5_context ctx = NULL;
431 krb5_ccache cc = NULL;
432 krb5_principal princ = NULL;
434 initialize_krb5_error_table();
435 if (krb5_init_context(&ctx)) {
439 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
440 "Trying to read krb5 cache: %s\n",
441 krb5_cc_default_name(ctx)));
442 if (krb5_cc_default(ctx, &cc)) {
443 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
444 "failed to read default cache\n"));
447 if (krb5_cc_get_principal(ctx, cc, &princ)) {
448 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
449 "failed to get default principal\n"));
453 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
454 realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
455 #elif defined(HAVE_KRB5_PRINC_REALM)
457 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
458 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
466 krb5_free_principal(ctx, princ);
469 krb5_cc_close(ctx, cc);
471 krb5_free_context(ctx);
477 /************************************************************************
478 Routine to get the realm from a given DNS name. Returns malloc'ed memory.
479 Caller must free() if the return value is not NULL.
480 ************************************************************************/
482 char *kerberos_get_realm_from_hostname(const char *hostname)
484 #if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM)
485 #if defined(HAVE_KRB5_REALM_TYPE)
487 krb5_realm *realm_list = NULL;
490 char **realm_list = NULL;
493 krb5_error_code kerr;
494 krb5_context ctx = NULL;
496 initialize_krb5_error_table();
497 if (krb5_init_context(&ctx)) {
501 kerr = krb5_get_host_realm(ctx, hostname, &realm_list);
503 DEBUG(3,("kerberos_get_realm_from_hostname %s: "
505 hostname ? hostname : "(NULL)",
506 error_message(kerr) ));
510 if (realm_list && realm_list[0]) {
511 realm = SMB_STRDUP(realm_list[0]);
518 krb5_free_host_realm(ctx, realm_list);
521 krb5_free_context(ctx);
530 /************************************************************************
531 Routine to get the salting principal for this service. This is
532 maintained for backwards compatibilty with releases prior to 3.0.24.
533 Since we store the salting principal string only at join, we may have
534 to look for the older tdb keys. Caller must free if return is not null.
535 ************************************************************************/
537 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
538 krb5_principal host_princ,
541 char *unparsed_name = NULL, *salt_princ_s = NULL;
542 krb5_principal ret_princ = NULL;
544 /* lookup new key first */
546 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
548 /* look under the old key. If this fails, just use the standard key */
550 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
551 return (krb5_principal)NULL;
553 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
554 /* fall back to host/machine.realm@REALM */
555 salt_princ_s = kerberos_standard_des_salt();
559 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
563 TALLOC_FREE(unparsed_name);
564 SAFE_FREE(salt_princ_s);
569 /************************************************************************
570 Routine to set the salting principal for this service. Active
571 Directory may use a non-obvious principal name to generate the salt
572 when it determines the key to use for encrypting tickets for a service,
573 and hopefully we detected that when we joined the domain.
574 Setting principal to NULL deletes this entry.
575 ************************************************************************/
577 bool kerberos_secrets_store_salting_principal(const char *service,
579 const char *principal)
583 krb5_context context = NULL;
584 krb5_principal princ = NULL;
585 char *princ_s = NULL;
586 char *unparsed_name = NULL;
587 krb5_error_code code;
589 if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
590 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
591 error_message(code)));
594 if (strchr_m(service, '@')) {
595 if (asprintf(&princ_s, "%s", service) == -1) {
599 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
604 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
608 if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
612 if (asprintf(&key, "%s/%s/enctype=%d",
613 SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
618 if ((principal != NULL) && (strlen(principal) > 0)) {
619 ret = secrets_store(key, principal, strlen(principal) + 1);
621 ret = secrets_delete(key);
628 TALLOC_FREE(unparsed_name);
631 krb5_free_principal(context, princ);
635 krb5_free_context(context);
642 /************************************************************************
643 ************************************************************************/
645 int kerberos_kinit_password(const char *principal,
646 const char *password,
648 const char *cache_name)
650 return kerberos_kinit_password_ext(principal,
662 /************************************************************************
663 ************************************************************************/
665 static char *print_kdc_line(char *mem_ctx,
666 const char *prev_line,
667 const struct sockaddr_storage *pss,
668 const char *kdc_name)
670 char *kdc_str = NULL;
672 if (pss->ss_family == AF_INET) {
673 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
675 print_canonical_sockaddr(mem_ctx, pss));
677 char addr[INET6_ADDRSTRLEN];
678 uint16_t port = get_sockaddr_port(pss);
680 DEBUG(10,("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
683 if (port != 0 && port != DEFAULT_KRB5_PORT) {
684 /* Currently for IPv6 we can't specify a non-default
685 krb5 port with an address, as this requires a ':'.
686 Resolve to a name. */
687 char hostname[MAX_DNS_NAME_LENGTH];
688 int ret = sys_getnameinfo((const struct sockaddr *)pss,
690 hostname, sizeof(hostname),
694 DEBUG(0,("print_kdc_line: can't resolve name "
695 "for kdc with non-default port %s. "
697 print_canonical_sockaddr(mem_ctx, pss),
701 /* Success, use host:port */
702 kdc_str = talloc_asprintf(mem_ctx,
709 /* no krb5 lib currently supports "kdc = ipv6 address"
710 * at all, so just fill in just the kdc_name if we have
711 * it and let the krb5 lib figure out the appropriate
712 * ipv6 address - gd */
715 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
716 prev_line, kdc_name);
718 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
729 /************************************************************************
730 Create a string list of available kdc's, possibly searching by sitename.
733 If "sitename" is given, the DC's in that site are listed first.
735 ************************************************************************/
737 static char *get_kdc_ip_string(char *mem_ctx,
739 const char *sitename,
740 struct sockaddr_storage *pss,
741 const char *kdc_name)
744 struct ip_service *ip_srv_site = NULL;
745 struct ip_service *ip_srv_nonsite = NULL;
748 char *kdc_str = print_kdc_line(mem_ctx, "", pss, kdc_name);
750 if (kdc_str == NULL) {
755 * First get the KDC's only in this site, the rest will be
761 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
763 for (i = 0; i < count_site; i++) {
764 if (sockaddr_equal((struct sockaddr *)&ip_srv_site[i].ss,
765 (struct sockaddr *)pss)) {
768 /* Append to the string - inefficient
769 * but not done often. */
770 kdc_str = print_kdc_line(mem_ctx,
775 SAFE_FREE(ip_srv_site);
783 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
785 for (i = 0; i < count_nonsite; i++) {
788 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss, (struct sockaddr *)pss)) {
792 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
793 for (j = 0; j < count_site; j++) {
794 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss,
795 (struct sockaddr *)&ip_srv_site[j].ss)) {
798 /* As the lists are sorted we can break early if nonsite > site. */
799 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
807 /* Append to the string - inefficient but not done often. */
808 kdc_str = print_kdc_line(mem_ctx,
810 &ip_srv_nonsite[i].ss,
813 SAFE_FREE(ip_srv_site);
814 SAFE_FREE(ip_srv_nonsite);
820 SAFE_FREE(ip_srv_site);
821 SAFE_FREE(ip_srv_nonsite);
823 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
829 /************************************************************************
830 Create a specific krb5.conf file in the private directory pointing
831 at a specific kdc for a realm. Keyed off domain name. Sets
832 KRB5_CONFIG environment variable to point to this file. Must be
833 run as root or will fail (which is a good thing :-).
834 ************************************************************************/
836 bool create_local_private_krb5_conf_for_domain(const char *realm,
838 const char *sitename,
839 struct sockaddr_storage *pss,
840 const char *kdc_name)
843 char *tmpname = NULL;
845 char *file_contents = NULL;
846 char *kdc_ip_string = NULL;
850 char *realm_upper = NULL;
853 if (!lp_create_krb5_conf()) {
857 dname = lock_path("smb_krb5");
861 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
862 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
863 "failed to create directory %s. Error was %s\n",
864 dname, strerror(errno) ));
868 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
873 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
878 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
879 fname, realm, domain ));
881 realm_upper = talloc_strdup(fname, realm);
882 strupper_m(realm_upper);
884 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss, kdc_name);
885 if (!kdc_ip_string) {
889 file_contents = talloc_asprintf(fname,
890 "[libdefaults]\n\tdefault_realm = %s\n"
891 "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
892 "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
893 "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
894 "[realms]\n\t%s = {\n"
896 realm_upper, realm_upper, kdc_ip_string);
898 if (!file_contents) {
902 flen = strlen(file_contents);
904 fd = mkstemp(tmpname);
906 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
907 " for file %s. Errno %s\n",
908 tmpname, strerror(errno) ));
912 if (fchmod(fd, 0644)==-1) {
913 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
915 tmpname, strerror(errno) ));
921 ret = write(fd, file_contents, flen);
923 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
924 " returned %d (should be %u). Errno %s\n",
925 (int)ret, (unsigned int)flen, strerror(errno) ));
931 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
932 " Errno %s\n", strerror(errno) ));
937 if (rename(tmpname, fname) == -1) {
938 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
939 "of %s to %s failed. Errno %s\n",
940 tmpname, fname, strerror(errno) ));
945 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
946 "file %s with realm %s KDC list = %s\n",
947 fname, realm_upper, kdc_ip_string));
949 /* Set the environment variable to this file. */
950 setenv("KRB5_CONFIG", fname, 1);
954 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
956 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
957 /* Insanity, sheer insanity..... */
959 if (strequal(realm, lp_realm())) {
960 char linkpath[PATH_MAX+1];
963 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
965 linkpath[lret] = '\0';
968 if (lret != -1 || strcmp(linkpath, fname) == 0) {
969 /* Symlink already exists. */
973 /* Try and replace with a symlink. */
974 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
975 const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
976 if (errno != EEXIST) {
977 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
978 "of %s to %s failed. Errno %s\n",
979 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
980 goto done; /* Not a fatal error. */
983 /* Yes, this is a race conditon... too bad. */
984 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
985 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
986 "of %s to %s failed. Errno %s\n",
987 SYSTEM_KRB5_CONF_PATH, newpath,
989 goto done; /* Not a fatal error. */
992 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
993 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
994 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
995 fname, strerror(errno) ));
996 goto done; /* Not a fatal error. */
1003 TALLOC_FREE(tmpname);