Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
[kai/samba-autobuild/.git] / source3 / libads / kerberos.c
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 3 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, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25
26 #ifdef HAVE_KRB5
27
28 #define DEFAULT_KRB5_PORT 88
29
30 #define LIBADS_CCACHE_NAME "MEMORY:libads"
31
32 /*
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 ...
36 */
37 static krb5_error_code 
38 kerb_prompter(krb5_context ctx, void *data,
39                const char *name,
40                const char *banner,
41                int num_prompts,
42                krb5_prompt prompts[])
43 {
44         if (num_prompts == 0) return 0;
45
46         memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
47         if (prompts[0].reply->length > 0) {
48                 if (data) {
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);
52                 } else {
53                         prompts[0].reply->length = 0;
54                 }
55         }
56         return 0;
57 }
58
59 static bool smb_krb5_err_io_nstatus(TALLOC_CTX *mem_ctx, 
60                                     DATA_BLOB *edata_blob, 
61                                     KRB5_EDATA_NTSTATUS *edata)
62 {
63         bool ret = False;
64         prs_struct ps;
65
66         if (!mem_ctx || !edata_blob || !edata) 
67                 return False;
68
69         if (!prs_init(&ps, edata_blob->length, mem_ctx, UNMARSHALL))
70                 return False;
71
72         if (!prs_copy_data_in(&ps, (char *)edata_blob->data, edata_blob->length))
73                 goto out;
74
75         prs_set_offset(&ps, 0);
76
77         if (!prs_ntstatus("ntstatus", &ps, 1, &edata->ntstatus))
78                 goto out;
79
80         if (!prs_uint32("unknown1", &ps, 1, &edata->unknown1))
81                 goto out;
82
83         if (!prs_uint32("unknown2", &ps, 1, &edata->unknown2)) /* only seen 00000001 here */
84                 goto out;
85
86         ret = True;
87  out:
88         prs_mem_free(&ps);
89
90         return ret;
91 }
92
93  static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
94                                                    NTSTATUS *nt_status)
95 {
96         DATA_BLOB edata;
97         DATA_BLOB unwrapped_edata;
98         TALLOC_CTX *mem_ctx;
99         KRB5_EDATA_NTSTATUS parsed_edata;
100
101 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
102         edata = data_blob(error->e_data->data, error->e_data->length);
103 #else
104         edata = data_blob(error->e_data.data, error->e_data.length);
105 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
106
107 #ifdef DEVELOPER
108         dump_data(10, edata.data, edata.length);
109 #endif /* DEVELOPER */
110
111         mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
112         if (mem_ctx == NULL) {
113                 data_blob_free(&edata);
114                 return False;
115         }
116
117         if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
118                 data_blob_free(&edata);
119                 TALLOC_FREE(mem_ctx);
120                 return False;
121         }
122
123         data_blob_free(&edata);
124
125         if (!smb_krb5_err_io_nstatus(mem_ctx, &unwrapped_edata, &parsed_edata)) {
126                 data_blob_free(&unwrapped_edata);
127                 TALLOC_FREE(mem_ctx);
128                 return False;
129         }
130
131         data_blob_free(&unwrapped_edata);
132
133         if (nt_status) {
134                 *nt_status = parsed_edata.ntstatus;
135         }
136
137         TALLOC_FREE(mem_ctx);
138
139         return True;
140 }
141
142  static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx, 
143                                                                   krb5_get_init_creds_opt *opt, 
144                                                                   NTSTATUS *nt_status)
145 {
146         bool ret = False;
147         krb5_error *error = NULL;
148
149 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
150         ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
151         if (ret) {
152                 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n", 
153                         error_message(ret)));
154                 return False;
155         }
156 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
157
158         if (!error) {
159                 DEBUG(1,("no krb5_error\n"));
160                 return False;
161         }
162
163 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
164         if (!error->e_data) {
165 #else
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);
170                 return False;
171         }
172
173         ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
174
175         krb5_free_error(ctx, error);
176
177         return ret;
178 }
179
180 /*
181   simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
182   place in default cache location.
183   remus@snapserver.com
184 */
185 int kerberos_kinit_password_ext(const char *principal,
186                                 const char *password,
187                                 int time_offset,
188                                 time_t *expire_time,
189                                 time_t *renew_till_time,
190                                 const char *cache_name,
191                                 bool request_pac,
192                                 bool add_netbios_addr,
193                                 time_t renewable_time,
194                                 NTSTATUS *ntstatus)
195 {
196         krb5_context ctx = NULL;
197         krb5_error_code code = 0;
198         krb5_ccache cc = NULL;
199         krb5_principal me = NULL;
200         krb5_creds my_creds;
201         krb5_get_init_creds_opt *opt = NULL;
202         smb_krb5_addresses *addr = NULL;
203
204         ZERO_STRUCT(my_creds);
205
206         initialize_krb5_error_table();
207         if ((code = krb5_init_context(&ctx)))
208                 goto out;
209
210         if (time_offset != 0) {
211                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
212         }
213
214         DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
215                         principal,
216                         cache_name ? cache_name: krb5_cc_default_name(ctx),
217                         getenv("KRB5_CONFIG")));
218
219         if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
220                 goto out;
221         }
222         
223         if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
224                 goto out;
225         }
226
227         if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
228                 goto out;
229         }
230
231         krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
232         krb5_get_init_creds_opt_set_forwardable(opt, True);
233 #if 0
234         /* insane testing */
235         krb5_get_init_creds_opt_set_tkt_life(opt, 60);
236 #endif
237
238 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
239         if (request_pac) {
240                 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
241                         goto out;
242                 }
243         }
244 #endif
245         if (add_netbios_addr) {
246                 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
247                         goto out;
248                 }
249                 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
250         }
251
252         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), 
253                                                  kerb_prompter, CONST_DISCARD(char *,password),
254                                                  0, NULL, opt))) {
255                 goto out;
256         }
257
258         if ((code = krb5_cc_initialize(ctx, cc, me))) {
259                 goto out;
260         }
261         
262         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
263                 goto out;
264         }
265
266         if (expire_time) {
267                 *expire_time = (time_t) my_creds.times.endtime;
268         }
269
270         if (renew_till_time) {
271                 *renew_till_time = (time_t) my_creds.times.renew_till;
272         }
273  out:
274         if (ntstatus) {
275
276                 NTSTATUS status;
277
278                 /* fast path */
279                 if (code == 0) {
280                         *ntstatus = NT_STATUS_OK;
281                         goto cleanup;
282                 }
283
284                 /* try to get ntstatus code out of krb5_error when we have it
285                  * inside the krb5_get_init_creds_opt - gd */
286
287                 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
288                         *ntstatus = status;
289                         goto cleanup;
290                 }
291
292                 /* fall back to self-made-mapping */
293                 *ntstatus = krb5_to_nt_status(code);
294         }
295
296  cleanup:
297         krb5_free_cred_contents(ctx, &my_creds);
298         if (me) {
299                 krb5_free_principal(ctx, me);
300         }
301         if (addr) {
302                 smb_krb5_free_addresses(ctx, addr);
303         }
304         if (opt) {
305                 smb_krb5_get_init_creds_opt_free(ctx, opt);
306         }
307         if (cc) {
308                 krb5_cc_close(ctx, cc);
309         }
310         if (ctx) {
311                 krb5_free_context(ctx);
312         }
313         return code;
314 }
315
316
317
318 /* run kinit to setup our ccache */
319 int ads_kinit_password(ADS_STRUCT *ads)
320 {
321         char *s;
322         int ret;
323         const char *account_name;
324         fstring acct_name;
325
326         if ( IS_DC ) {
327                 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
328                 account_name = lp_workgroup();
329         } else {
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;
335                 }
336                 else 
337                         /* This looks like host/global_myname()@REA.LM */
338                         account_name = ads->auth.user_name;
339         }
340
341         if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
342                 return KRB5_CC_NOMEM;
343         }
344
345         if (!ads->auth.password) {
346                 SAFE_FREE(s);
347                 return KRB5_LIBOS_CANTREADPWD;
348         }
349         
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, 
352                         NULL);
353
354         if (ret) {
355                 DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
356                          s, error_message(ret)));
357         }
358         SAFE_FREE(s);
359         return ret;
360 }
361
362 int ads_kdestroy(const char *cc_name)
363 {
364         krb5_error_code code;
365         krb5_context ctx = NULL;
366         krb5_ccache cc = NULL;
367
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)));
372                 return code;
373         }
374   
375         if (!cc_name) {
376                 if ((code = krb5_cc_default(ctx, &cc))) {
377                         krb5_free_context(ctx);
378                         return code;
379                 }
380         } else {
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);
385                         return code;
386                 }
387         }
388
389         if ((code = krb5_cc_destroy (ctx, cc))) {
390                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
391                         error_message(code)));
392         }
393
394         krb5_free_context (ctx);
395         return code;
396 }
397
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  ************************************************************************/
404
405 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
406 {
407         char *key = NULL;
408         char *ret = NULL;
409
410         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
411         if (!key) {
412                 return NULL;
413         }
414         ret = (char *)secrets_fetch(key, NULL);
415         SAFE_FREE(key);
416         return ret;
417 }
418
419 /************************************************************************
420  Return the standard DES salt key
421 ************************************************************************/
422
423 char* kerberos_standard_des_salt( void )
424 {
425         fstring salt;
426
427         fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
428         strlower_m( salt );
429         fstrcat( salt, lp_realm() );
430
431         return SMB_STRDUP( salt );
432 }
433
434 /************************************************************************
435 ************************************************************************/
436
437 static char* des_salt_key( void )
438 {
439         char *key;
440
441         asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
442
443         return key;
444 }
445
446 /************************************************************************
447 ************************************************************************/
448
449 bool kerberos_secrets_store_des_salt( const char* salt )
450 {
451         char* key;
452         bool ret;
453
454         if ( (key = des_salt_key()) == NULL ) {
455                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
456                 return False;
457         }
458
459         if ( !salt ) {
460                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
461                 secrets_delete( key );
462                 return True;
463         }
464
465         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
466
467         ret = secrets_store( key, salt, strlen(salt)+1 );
468
469         SAFE_FREE( key );
470
471         return ret;
472 }
473
474 /************************************************************************
475 ************************************************************************/
476
477 char* kerberos_secrets_fetch_des_salt( void )
478 {
479         char *salt, *key;
480
481         if ( (key = des_salt_key()) == NULL ) {
482                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
483                 return False;
484         }
485
486         salt = (char*)secrets_fetch( key, NULL );
487
488         SAFE_FREE( key );
489
490         return salt;
491 }
492
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 ************************************************************************/
497
498 char *kerberos_get_default_realm_from_ccache( void )
499 {
500         char *realm = NULL;
501         krb5_context ctx = NULL;
502         krb5_ccache cc = NULL;
503         krb5_principal princ = NULL;
504
505         initialize_krb5_error_table();
506         if (krb5_init_context(&ctx)) {
507                 return NULL;
508         }
509
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"));
516                 goto out;
517         }
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"));
521                 goto out;
522         }
523
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)
527         {
528                 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
529                 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
530         }
531 #endif
532
533   out:
534
535         if (princ) {
536                 krb5_free_principal(ctx, princ);
537         }
538         if (cc) {
539                 krb5_cc_close(ctx, cc);
540         }
541         if (ctx) {
542                 krb5_free_context(ctx);
543         }
544
545         return realm;
546 }
547
548
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  ************************************************************************/
555
556 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
557                                                         krb5_principal host_princ,
558                                                         int enctype)
559 {
560         char *unparsed_name = NULL, *salt_princ_s = NULL;
561         krb5_principal ret_princ = NULL;
562         
563         /* lookup new key first */
564
565         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
566         
567                 /* look under the old key.  If this fails, just use the standard key */
568
569                 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
570                         return (krb5_principal)NULL;
571                 }
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();
575                 }
576         }
577
578         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
579                 ret_princ = NULL;
580         }
581         
582         SAFE_FREE(unparsed_name);
583         SAFE_FREE(salt_princ_s);
584         
585         return ret_princ;
586 }
587
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  ************************************************************************/
595
596 bool kerberos_secrets_store_salting_principal(const char *service,
597                                               int enctype,
598                                               const char *principal)
599 {
600         char *key = NULL;
601         bool ret = False;
602         krb5_context context = NULL;
603         krb5_principal princ = NULL;
604         char *princ_s = NULL;
605         char *unparsed_name = NULL;
606
607         krb5_init_context(&context);
608         if (!context) {
609                 return False;
610         }
611         if (strchr_m(service, '@')) {
612                 asprintf(&princ_s, "%s", service);
613         } else {
614                 asprintf(&princ_s, "%s@%s", service, lp_realm());
615         }
616
617         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
618                 goto out;
619                 
620         }
621         if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
622                 goto out;
623         }
624
625         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
626         if (!key)  {
627                 goto out;
628         }
629
630         if ((principal != NULL) && (strlen(principal) > 0)) {
631                 ret = secrets_store(key, principal, strlen(principal) + 1);
632         } else {
633                 ret = secrets_delete(key);
634         }
635
636  out:
637
638         SAFE_FREE(key);
639         SAFE_FREE(princ_s);
640         SAFE_FREE(unparsed_name);
641
642         if (context) {
643                 krb5_free_context(context);
644         }
645
646         return ret;
647 }
648
649
650 /************************************************************************
651 ************************************************************************/
652
653 int kerberos_kinit_password(const char *principal,
654                             const char *password,
655                             int time_offset,
656                             const char *cache_name)
657 {
658         return kerberos_kinit_password_ext(principal, 
659                                            password, 
660                                            time_offset, 
661                                            0, 
662                                            0,
663                                            cache_name,
664                                            False,
665                                            False,
666                                            0,
667                                            NULL);
668 }
669
670 /************************************************************************
671 ************************************************************************/
672
673 static char *print_kdc_line(char *mem_ctx,
674                         const char *prev_line,
675                         const struct sockaddr_storage *pss)
676 {
677         char *kdc_str = NULL;
678
679         if (pss->ss_family == AF_INET) {
680                 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
681                                         prev_line,
682                                         print_canonical_sockaddr(mem_ctx, pss));
683         } else {
684                 char addr[INET6_ADDRSTRLEN];
685                 uint16_t port = get_sockaddr_port(pss);
686
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,
693                                         sizeof(*pss),
694                                         hostname, sizeof(hostname),
695                                         NULL, 0,
696                                         NI_NAMEREQD);
697                         if (ret) {
698                                 DEBUG(0,("print_kdc_line: can't resolve name "
699                                         "for kdc with non-default port %s. "
700                                         "Error %s\n.",
701                                         print_canonical_sockaddr(mem_ctx, pss),
702                                         gai_strerror(ret)));
703                         }
704                         /* Success, use host:port */
705                         kdc_str = talloc_asprintf(mem_ctx,
706                                         "%s\tkdc = %s:%u\n",
707                                         prev_line,
708                                         hostname,
709                                         (unsigned int)port);
710                 } else {
711                         kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
712                                         prev_line,
713                                         print_sockaddr(addr,
714                                                 sizeof(addr),
715                                                 pss));
716                 }
717         }
718         return kdc_str;
719 }
720
721 /************************************************************************
722  Create a string list of available kdc's, possibly searching by sitename.
723  Does DNS queries.
724 ************************************************************************/
725
726 static char *get_kdc_ip_string(char *mem_ctx,
727                 const char *realm,
728                 const char *sitename,
729                 struct sockaddr_storage *pss)
730 {
731         int i;
732         struct ip_service *ip_srv_site = NULL;
733         struct ip_service *ip_srv_nonsite = NULL;
734         int count_site = 0;
735         int count_nonsite;
736         char *kdc_str = print_kdc_line(mem_ctx, "", pss);
737
738         if (kdc_str == NULL) {
739                 return NULL;
740         }
741
742         /* Get the KDC's only in this site. */
743
744         if (sitename) {
745
746                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
747
748                 for (i = 0; i < count_site; i++) {
749                         if (addr_equal(&ip_srv_site[i].ss, pss)) {
750                                 continue;
751                         }
752                         /* Append to the string - inefficient
753                          * but not done often. */
754                         kdc_str = print_kdc_line(mem_ctx,
755                                                 kdc_str,
756                                                 &ip_srv_site[i].ss);
757                         if (!kdc_str) {
758                                 SAFE_FREE(ip_srv_site);
759                                 return NULL;
760                         }
761                 }
762         }
763
764         /* Get all KDC's. */
765
766         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
767
768         for (i = 0; i < count_nonsite; i++) {
769                 int j;
770
771                 if (addr_equal(&ip_srv_nonsite[i].ss, pss)) {
772                         continue;
773                 }
774
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)) {
779                                 break;
780                         }
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) {
783                                 break;
784                         }
785                 }
786                 if (j != i) {
787                         continue;
788                 }
789
790                 /* Append to the string - inefficient but not done often. */
791                 kdc_str = print_kdc_line(mem_ctx,
792                                 kdc_str,
793                                 &ip_srv_nonsite[i].ss);
794                 if (!kdc_str) {
795                         SAFE_FREE(ip_srv_site);
796                         SAFE_FREE(ip_srv_nonsite);
797                         return NULL;
798                 }
799         }
800
801
802         SAFE_FREE(ip_srv_site);
803         SAFE_FREE(ip_srv_nonsite);
804
805         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
806                 kdc_str ));
807
808         return kdc_str;
809 }
810
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 ************************************************************************/
817
818 bool create_local_private_krb5_conf_for_domain(const char *realm,
819                                                 const char *domain,
820                                                 const char *sitename,
821                                                 struct sockaddr_storage *pss)
822 {
823         char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
824         char *tmpname = NULL;
825         char *fname = NULL;
826         char *file_contents = NULL;
827         char *kdc_ip_string = NULL;
828         size_t flen = 0;
829         ssize_t ret;
830         int fd;
831         char *realm_upper = NULL;
832
833         if (!dname) {
834                 return False;
835         }
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) ));
840                 TALLOC_FREE(dname);
841                 return False;
842         }
843
844         tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
845         if (!tmpname) {
846                 TALLOC_FREE(dname);
847                 return False;
848         }
849
850         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
851         if (!fname) {
852                 TALLOC_FREE(dname);
853                 return False;
854         }
855
856         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
857                 fname, realm, domain ));
858
859         realm_upper = talloc_strdup(fname, realm);
860         strupper_m(realm_upper);
861
862         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
863         if (!kdc_ip_string) {
864                 TALLOC_FREE(dname);
865                 return False;
866         }
867
868         file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
869                                 "[realms]\n\t%s = {\n"
870                                 "\t%s\t}\n",
871                                 realm_upper, realm_upper, kdc_ip_string);
872
873         if (!file_contents) {
874                 TALLOC_FREE(dname);
875                 return False;
876         }
877
878         flen = strlen(file_contents);
879
880         fd = smb_mkstemp(tmpname);
881         if (fd == -1) {
882                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
883                         " for file %s. Errno %s\n",
884                         tmpname, strerror(errno) ));
885         }
886
887         if (fchmod(fd, 0644)==-1) {
888                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
889                         " Errno %s\n",
890                         tmpname, strerror(errno) ));
891                 unlink(tmpname);
892                 close(fd);
893                 TALLOC_FREE(dname);
894                 return False;
895         }
896
897         ret = write(fd, file_contents, flen);
898         if (flen != ret) {
899                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
900                         " returned %d (should be %u). Errno %s\n",
901                         (int)ret, (unsigned int)flen, strerror(errno) ));
902                 unlink(tmpname);
903                 close(fd);
904                 TALLOC_FREE(dname);
905                 return False;
906         }
907         if (close(fd)==-1) {
908                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
909                         " Errno %s\n", strerror(errno) ));
910                 unlink(tmpname);
911                 TALLOC_FREE(dname);
912                 return False;
913         }
914
915         if (rename(tmpname, fname) == -1) {
916                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
917                         "of %s to %s failed. Errno %s\n",
918                         tmpname, fname, strerror(errno) ));
919                 unlink(tmpname);
920                 TALLOC_FREE(dname);
921                 return False;
922         }
923
924         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
925                 "file %s with realm %s KDC list = %s\n",
926                 fname, realm_upper, kdc_ip_string));
927
928         /* Set the environment variable to this file. */
929         setenv("KRB5_CONFIG", fname, 1);
930
931 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
932
933 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
934         /* Insanity, sheer insanity..... */
935
936         if (strequal(realm, lp_realm())) {
937                 char linkpath[PATH_MAX+1];
938                 int lret;
939
940                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
941                 if (lret != -1) {
942                         linkpath[lret] = '\0';
943                 }
944
945                 if (lret != -1 || strcmp(linkpath, fname) == 0) {
946                         /* Symlink already exists. */
947                         TALLOC_FREE(dname);
948                         return True;
949                 }
950
951                 /* Try and replace with a symlink. */
952                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
953                         const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
954                         if (errno != EEXIST) {
955                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
956                                         "of %s to %s failed. Errno %s\n",
957                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
958                                 TALLOC_FREE(dname);
959                                 return True; /* Not a fatal error. */
960                         }
961
962                         /* Yes, this is a race conditon... too bad. */
963                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
964                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
965                                         "of %s to %s failed. Errno %s\n",
966                                         SYSTEM_KRB5_CONF_PATH, newpath,
967                                         strerror(errno) ));
968                                 TALLOC_FREE(dname);
969                                 return True; /* Not a fatal error. */
970                         }
971
972                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
973                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
974                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
975                                         fname, strerror(errno) ));
976                                 TALLOC_FREE(dname);
977                                 return True; /* Not a fatal error. */
978                         }
979                 }
980         }
981 #endif
982
983         TALLOC_FREE(dname);
984
985         return True;
986 }
987 #endif