source: branches/samba-3.0/source/libads/kerberos.c@ 347

Last change on this file since 347 was 140, checked in by Paul Smedley, 17 years ago

Update branch to 3.0.31 release

File size: 21.5 KB
Line 
1/*
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.
9
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 2 of the License, or
13 (at your option) any later version.
14
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.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23*/
24
25#include "includes.h"
26
27#ifdef HAVE_KRB5
28
29#define LIBADS_CCACHE_NAME "MEMORY:libads"
30
31/*
32 we use a prompter to avoid a crash bug in the kerberos libs when
33 dealing with empty passwords
34 this prompter is just a string copy ...
35*/
36static krb5_error_code
37kerb_prompter(krb5_context ctx, void *data,
38 const char *name,
39 const char *banner,
40 int num_prompts,
41 krb5_prompt prompts[])
42{
43 if (num_prompts == 0) return 0;
44
45 memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
46 if (prompts[0].reply->length > 0) {
47 if (data) {
48 strncpy(prompts[0].reply->data, (const char *)data,
49 prompts[0].reply->length-1);
50 prompts[0].reply->length = strlen(prompts[0].reply->data);
51 } else {
52 prompts[0].reply->length = 0;
53 }
54 }
55 return 0;
56}
57
58/*
59 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
60 place in default cache location.
61 remus@snapserver.com
62*/
63int kerberos_kinit_password_ext(const char *principal,
64 const char *password,
65 int time_offset,
66 time_t *expire_time,
67 time_t *renew_till_time,
68 const char *cache_name,
69 BOOL request_pac,
70 BOOL add_netbios_addr,
71 time_t renewable_time)
72{
73 krb5_context ctx = NULL;
74 krb5_error_code code = 0;
75 krb5_ccache cc = NULL;
76 krb5_principal me;
77 krb5_creds my_creds;
78 krb5_get_init_creds_opt *opt = NULL;
79 smb_krb5_addresses *addr = NULL;
80
81 initialize_krb5_error_table();
82 if ((code = krb5_init_context(&ctx)))
83 return code;
84
85 if (time_offset != 0) {
86 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
87 }
88
89 DEBUG(10,("kerberos_kinit_password: using [%s] as ccache and config [%s]\n",
90 cache_name ? cache_name: krb5_cc_default_name(ctx),
91 getenv("KRB5_CONFIG")));
92
93 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
94 krb5_free_context(ctx);
95 return code;
96 }
97
98 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
99 krb5_cc_close(ctx, cc);
100 krb5_free_context(ctx);
101 return code;
102 }
103
104 code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt);
105 if (code) {
106 krb5_cc_close(ctx, cc);
107 krb5_free_context(ctx);
108 return code;
109 }
110
111 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
112 krb5_get_init_creds_opt_set_forwardable(opt, True);
113#if 0
114 /* insane testing */
115 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
116#endif
117
118#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
119 if (request_pac) {
120 code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac);
121 if (code) {
122 krb5_cc_close(ctx, cc);
123 krb5_free_principal(ctx, me);
124 krb5_free_context(ctx);
125 return code;
126 }
127 }
128#endif
129 if (add_netbios_addr) {
130 code = smb_krb5_gen_netbios_krb5_address(&addr);
131 if (code) {
132 krb5_cc_close(ctx, cc);
133 krb5_free_principal(ctx, me);
134 krb5_free_context(ctx);
135 return code;
136 }
137 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
138 }
139
140 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
141 kerb_prompter, CONST_DISCARD(char *,password),
142 0, NULL, opt)))
143 {
144 smb_krb5_get_init_creds_opt_free(ctx, opt);
145 smb_krb5_free_addresses(ctx, addr);
146 krb5_cc_close(ctx, cc);
147 krb5_free_principal(ctx, me);
148 krb5_free_context(ctx);
149 return code;
150 }
151
152 smb_krb5_get_init_creds_opt_free(ctx, opt);
153
154 if ((code = krb5_cc_initialize(ctx, cc, me))) {
155 smb_krb5_free_addresses(ctx, addr);
156 krb5_free_cred_contents(ctx, &my_creds);
157 krb5_cc_close(ctx, cc);
158 krb5_free_principal(ctx, me);
159 krb5_free_context(ctx);
160 return code;
161 }
162
163 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
164 krb5_cc_close(ctx, cc);
165 smb_krb5_free_addresses(ctx, addr);
166 krb5_free_cred_contents(ctx, &my_creds);
167 krb5_free_principal(ctx, me);
168 krb5_free_context(ctx);
169 return code;
170 }
171
172 if (expire_time) {
173 *expire_time = (time_t) my_creds.times.endtime;
174 }
175
176 if (renew_till_time) {
177 *renew_till_time = (time_t) my_creds.times.renew_till;
178 }
179
180 krb5_cc_close(ctx, cc);
181 smb_krb5_free_addresses(ctx, addr);
182 krb5_free_cred_contents(ctx, &my_creds);
183 krb5_free_principal(ctx, me);
184 krb5_free_context(ctx);
185
186 return 0;
187}
188
189
190
191/* run kinit to setup our ccache */
192int ads_kinit_password(ADS_STRUCT *ads)
193{
194 char *s;
195 int ret;
196 const char *account_name;
197 fstring acct_name;
198
199 if ( IS_DC ) {
200 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
201 account_name = lp_workgroup();
202 } else {
203 /* always use the sAMAccountName for security = domain */
204 /* global_myname()$@REA.LM */
205 if ( lp_security() == SEC_DOMAIN ) {
206 fstr_sprintf( acct_name, "%s$", global_myname() );
207 account_name = acct_name;
208 }
209 else
210 /* This looks like host/global_myname()@REA.LM */
211 account_name = ads->auth.user_name;
212 }
213
214 if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
215 return KRB5_CC_NOMEM;
216 }
217
218 if (!ads->auth.password) {
219 SAFE_FREE(s);
220 return KRB5_LIBOS_CANTREADPWD;
221 }
222
223 ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
224 &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable);
225
226 if (ret) {
227 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
228 s, error_message(ret)));
229 }
230 SAFE_FREE(s);
231 return ret;
232}
233
234int ads_kdestroy(const char *cc_name)
235{
236 krb5_error_code code;
237 krb5_context ctx = NULL;
238 krb5_ccache cc = NULL;
239
240 initialize_krb5_error_table();
241 if ((code = krb5_init_context (&ctx))) {
242 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
243 error_message(code)));
244 return code;
245 }
246
247 if (!cc_name) {
248 if ((code = krb5_cc_default(ctx, &cc))) {
249 krb5_free_context(ctx);
250 return code;
251 }
252 } else {
253 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
254 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
255 error_message(code)));
256 krb5_free_context(ctx);
257 return code;
258 }
259 }
260
261 if ((code = krb5_cc_destroy (ctx, cc))) {
262 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
263 error_message(code)));
264 }
265
266 krb5_free_context (ctx);
267 return code;
268}
269
270/************************************************************************
271 Routine to fetch the salting principal for a service. Active
272 Directory may use a non-obvious principal name to generate the salt
273 when it determines the key to use for encrypting tickets for a service,
274 and hopefully we detected that when we joined the domain.
275 ************************************************************************/
276
277static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
278{
279 char *key = NULL;
280 char *ret = NULL;
281
282 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
283 if (!key) {
284 return NULL;
285 }
286 ret = (char *)secrets_fetch(key, NULL);
287 SAFE_FREE(key);
288 return ret;
289}
290
291/************************************************************************
292 Return the standard DES salt key
293************************************************************************/
294
295char* kerberos_standard_des_salt( void )
296{
297 fstring salt;
298
299 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
300 strlower_m( salt );
301 fstrcat( salt, lp_realm() );
302
303 return SMB_STRDUP( salt );
304}
305
306/************************************************************************
307************************************************************************/
308
309static char* des_salt_key( void )
310{
311 char *key;
312
313 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
314
315 return key;
316}
317
318/************************************************************************
319************************************************************************/
320
321BOOL kerberos_secrets_store_des_salt( const char* salt )
322{
323 char* key;
324 BOOL ret;
325
326 if ( (key = des_salt_key()) == NULL ) {
327 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
328 return False;
329 }
330
331 if ( !salt ) {
332 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
333 secrets_delete( key );
334 return True;
335 }
336
337 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
338
339 ret = secrets_store( key, salt, strlen(salt)+1 );
340
341 SAFE_FREE( key );
342
343 return ret;
344}
345
346/************************************************************************
347************************************************************************/
348
349char* kerberos_secrets_fetch_des_salt( void )
350{
351 char *salt, *key;
352
353 if ( (key = des_salt_key()) == NULL ) {
354 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
355 return False;
356 }
357
358 salt = (char*)secrets_fetch( key, NULL );
359
360 SAFE_FREE( key );
361
362 return salt;
363}
364
365/************************************************************************
366 Routine to get the default realm from the kerberos credentials cache.
367 Caller must free if the return value is not NULL.
368************************************************************************/
369
370char *kerberos_get_default_realm_from_ccache( void )
371{
372 char *realm = NULL;
373 krb5_context ctx = NULL;
374 krb5_ccache cc = NULL;
375 krb5_principal princ = NULL;
376
377 initialize_krb5_error_table();
378 if (krb5_init_context(&ctx)) {
379 return NULL;
380 }
381
382 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
383 "Trying to read krb5 cache: %s\n",
384 krb5_cc_default_name(ctx)));
385 if (krb5_cc_default(ctx, &cc)) {
386 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
387 "failed to read default cache\n"));
388 goto out;
389 }
390 if (krb5_cc_get_principal(ctx, cc, &princ)) {
391 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
392 "failed to get default principal\n"));
393 goto out;
394 }
395
396#if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
397 realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
398#elif defined(HAVE_KRB5_PRINC_REALM)
399 {
400 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
401 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
402 }
403#endif
404
405 out:
406
407 if (princ) {
408 krb5_free_principal(ctx, princ);
409 }
410 if (cc) {
411 krb5_cc_close(ctx, cc);
412 }
413 if (ctx) {
414 krb5_free_context(ctx);
415 }
416
417 return realm;
418}
419
420
421/************************************************************************
422 Routine to get the salting principal for this service. This is
423 maintained for backwards compatibilty with releases prior to 3.0.24.
424 Since we store the salting principal string only at join, we may have
425 to look for the older tdb keys. Caller must free if return is not null.
426 ************************************************************************/
427
428krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
429 krb5_principal host_princ,
430 int enctype)
431{
432 char *unparsed_name = NULL, *salt_princ_s = NULL;
433 krb5_principal ret_princ = NULL;
434
435 /* lookup new key first */
436
437 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
438
439 /* look under the old key. If this fails, just use the standard key */
440
441 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
442 return (krb5_principal)NULL;
443 }
444 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
445 /* fall back to host/machine.realm@REALM */
446 salt_princ_s = kerberos_standard_des_salt();
447 }
448 }
449
450 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
451 ret_princ = NULL;
452 }
453
454 SAFE_FREE(unparsed_name);
455 SAFE_FREE(salt_princ_s);
456
457 return ret_princ;
458}
459
460/************************************************************************
461 Routine to set the salting principal for this service. Active
462 Directory may use a non-obvious principal name to generate the salt
463 when it determines the key to use for encrypting tickets for a service,
464 and hopefully we detected that when we joined the domain.
465 Setting principal to NULL deletes this entry.
466 ************************************************************************/
467
468BOOL kerberos_secrets_store_salting_principal(const char *service,
469 int enctype,
470 const char *principal)
471{
472 char *key = NULL;
473 BOOL ret = False;
474 krb5_context context = NULL;
475 krb5_principal princ = NULL;
476 char *princ_s = NULL;
477 char *unparsed_name = NULL;
478
479 krb5_init_context(&context);
480 if (!context) {
481 return False;
482 }
483 if (strchr_m(service, '@')) {
484 asprintf(&princ_s, "%s", service);
485 } else {
486 asprintf(&princ_s, "%s@%s", service, lp_realm());
487 }
488
489 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
490 goto out;
491
492 }
493 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
494 goto out;
495 }
496
497 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
498 if (!key) {
499 goto out;
500 }
501
502 if ((principal != NULL) && (strlen(principal) > 0)) {
503 ret = secrets_store(key, principal, strlen(principal) + 1);
504 } else {
505 ret = secrets_delete(key);
506 }
507
508 out:
509
510 SAFE_FREE(key);
511 SAFE_FREE(princ_s);
512 SAFE_FREE(unparsed_name);
513
514 if (princ) {
515 krb5_free_principal(context, princ);
516 }
517
518 if (context) {
519 krb5_free_context(context);
520 }
521
522 return ret;
523}
524
525
526/************************************************************************
527************************************************************************/
528
529int kerberos_kinit_password(const char *principal,
530 const char *password,
531 int time_offset,
532 const char *cache_name)
533{
534 return kerberos_kinit_password_ext(principal,
535 password,
536 time_offset,
537 0,
538 0,
539 cache_name,
540 False,
541 False,
542 0);
543}
544
545/************************************************************************
546 Create a string list of available kdc's, possibly searching by sitename.
547 Does DNS queries.
548************************************************************************/
549
550static char *get_kdc_ip_string(char *mem_ctx, const char *realm, const char *sitename, struct in_addr primary_ip)
551{
552 int i;
553 struct ip_service *ip_srv_site = NULL;
554 struct ip_service *ip_srv_nonsite;
555 int count_site = 0;
556 int count_nonsite;
557 char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
558 inet_ntoa(primary_ip));
559
560 if (kdc_str == NULL) {
561 return NULL;
562 }
563
564 /* Get the KDC's only in this site. */
565
566 if (sitename) {
567
568 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
569
570 for (i = 0; i < count_site; i++) {
571 if (ip_equal(ip_srv_site[i].ip, primary_ip)) {
572 continue;
573 }
574 /* Append to the string - inefficient but not done often. */
575 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
576 kdc_str, inet_ntoa(ip_srv_site[i].ip));
577 if (!kdc_str) {
578 SAFE_FREE(ip_srv_site);
579 return NULL;
580 }
581 }
582 }
583
584 /* Get all KDC's. */
585
586 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
587
588 for (i = 0; i < count_nonsite; i++) {
589 int j;
590
591 if (ip_equal(ip_srv_nonsite[i].ip, primary_ip)) {
592 continue;
593 }
594
595 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
596 for (j = 0; j < count_site; j++) {
597 if (ip_equal(ip_srv_nonsite[i].ip, ip_srv_site[j].ip)) {
598 break;
599 }
600 /* As the lists are sorted we can break early if nonsite > site. */
601 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
602 break;
603 }
604 }
605 if (j != i) {
606 continue;
607 }
608
609 /* Append to the string - inefficient but not done often. */
610 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
611 kdc_str, inet_ntoa(ip_srv_nonsite[i].ip));
612 if (!kdc_str) {
613 SAFE_FREE(ip_srv_site);
614 SAFE_FREE(ip_srv_nonsite);
615 return NULL;
616 }
617 }
618
619
620 SAFE_FREE(ip_srv_site);
621 SAFE_FREE(ip_srv_nonsite);
622
623 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
624 kdc_str ));
625
626 return kdc_str;
627}
628
629/************************************************************************
630 Create a specific krb5.conf file in the private directory pointing
631 at a specific kdc for a realm. Keyed off domain name. Sets
632 KRB5_CONFIG environment variable to point to this file. Must be
633 run as root or will fail (which is a good thing :-).
634************************************************************************/
635
636BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain,
637 const char *sitename, struct in_addr ip)
638{
639 char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
640 char *tmpname = NULL;
641 char *fname = NULL;
642 char *file_contents = NULL;
643 char *kdc_ip_string = NULL;
644 size_t flen = 0;
645 ssize_t ret;
646 int fd;
647 char *realm_upper = NULL;
648
649 if (!dname) {
650 return False;
651 }
652 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
653 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
654 "failed to create directory %s. Error was %s\n",
655 dname, strerror(errno) ));
656 TALLOC_FREE(dname);
657 return False;
658 }
659
660 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
661 if (!tmpname) {
662 TALLOC_FREE(dname);
663 return False;
664 }
665
666 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
667 if (!fname) {
668 TALLOC_FREE(dname);
669 return False;
670 }
671
672 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
673 fname, realm, domain ));
674
675 realm_upper = talloc_strdup(fname, realm);
676 strupper_m(realm_upper);
677
678 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, ip);
679 if (!kdc_ip_string) {
680 TALLOC_FREE(dname);
681 return False;
682 }
683
684 file_contents = talloc_asprintf(fname,
685 "[libdefaults]\n\tdefault_realm = %s\n"
686 "default_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
687 "default_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
688 "preferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
689 "[realms]\n\t%s = {\n"
690 "\t%s\t}\n",
691 realm_upper, realm_upper, kdc_ip_string);
692
693 if (!file_contents) {
694 TALLOC_FREE(dname);
695 return False;
696 }
697
698 flen = strlen(file_contents);
699
700 fd = smb_mkstemp(tmpname);
701 if (fd == -1) {
702 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
703 " for file %s. Errno %s\n",
704 tmpname, strerror(errno) ));
705 }
706
707 if (fchmod(fd, 0644)==-1) {
708 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
709 " Errno %s\n",
710 tmpname, strerror(errno) ));
711 unlink(tmpname);
712 close(fd);
713 TALLOC_FREE(dname);
714 return False;
715 }
716
717 ret = write(fd, file_contents, flen);
718 if (flen != ret) {
719 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
720 " returned %d (should be %u). Errno %s\n",
721 (int)ret, (unsigned int)flen, strerror(errno) ));
722 unlink(tmpname);
723 close(fd);
724 TALLOC_FREE(dname);
725 return False;
726 }
727 if (close(fd)==-1) {
728 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
729 " Errno %s\n", strerror(errno) ));
730 unlink(tmpname);
731 TALLOC_FREE(dname);
732 return False;
733 }
734
735 if (rename(tmpname, fname) == -1) {
736 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
737 "of %s to %s failed. Errno %s\n",
738 tmpname, fname, strerror(errno) ));
739 unlink(tmpname);
740 TALLOC_FREE(dname);
741 return False;
742 }
743
744 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
745 "file %s with realm %s KDC = %s\n",
746 fname, realm_upper, inet_ntoa(ip) ));
747
748 /* Set the environment variable to this file. */
749 setenv("KRB5_CONFIG", fname, 1);
750
751#if defined(OVERWRITE_SYSTEM_KRB5_CONF)
752
753#define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
754 /* Insanity, sheer insanity..... */
755
756 if (strequal(realm, lp_realm())) {
757 pstring linkpath;
758 int lret;
759
760 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
761 linkpath[sizeof(pstring)-1] = '\0';
762
763 if (lret == 0 || strcmp(linkpath, fname) == 0) {
764 /* Symlink already exists. */
765 TALLOC_FREE(dname);
766 return True;
767 }
768
769 /* Try and replace with a symlink. */
770 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
771 if (errno != EEXIST) {
772 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
773 "of %s to %s failed. Errno %s\n",
774 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
775 TALLOC_FREE(dname);
776 return True; /* Not a fatal error. */
777 }
778
779 pstrcpy(linkpath, SYSTEM_KRB5_CONF_PATH);
780 pstrcat(linkpath, ".saved");
781
782 /* Yes, this is a race conditon... too bad. */
783 if (rename(SYSTEM_KRB5_CONF_PATH, linkpath) == -1) {
784 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
785 "of %s to %s failed. Errno %s\n",
786 SYSTEM_KRB5_CONF_PATH, linkpath,
787 strerror(errno) ));
788 TALLOC_FREE(dname);
789 return True; /* Not a fatal error. */
790 }
791
792 if (symlink(fname, "/etc/krb5.conf") == -1) {
793 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
794 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
795 fname, strerror(errno) ));
796 TALLOC_FREE(dname);
797 return True; /* Not a fatal error. */
798 }
799 }
800 }
801#endif
802
803 TALLOC_FREE(dname);
804
805 return True;
806}
807#endif
Note: See TracBrowser for help on using the repository browser.