89357b01fbd801f47bda155fc0db5f01d98caa04
[samba.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((char *)prompts[0].reply->data, (const char *)data,
50                                 prompts[0].reply->length-1);
51                         prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
52                 } else {
53                         prompts[0].reply->length = 0;
54                 }
55         }
56         return 0;
57 }
58
59  static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
60                                                    NTSTATUS *nt_status)
61 {
62         DATA_BLOB edata;
63         DATA_BLOB unwrapped_edata;
64         TALLOC_CTX *mem_ctx;
65         struct KRB5_EDATA_NTSTATUS parsed_edata;
66         enum ndr_err_code ndr_err;
67
68 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
69         edata = data_blob(error->e_data->data, error->e_data->length);
70 #else
71         edata = data_blob(error->e_data.data, error->e_data.length);
72 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
73
74 #ifdef DEVELOPER
75         dump_data(10, edata.data, edata.length);
76 #endif /* DEVELOPER */
77
78         mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
79         if (mem_ctx == NULL) {
80                 data_blob_free(&edata);
81                 return False;
82         }
83
84         if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
85                 data_blob_free(&edata);
86                 TALLOC_FREE(mem_ctx);
87                 return False;
88         }
89
90         data_blob_free(&edata);
91
92         ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx, NULL,
93                         &parsed_edata,
94                         (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
95         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
96                 data_blob_free(&unwrapped_edata);
97                 TALLOC_FREE(mem_ctx);
98                 return False;
99         }
100
101         data_blob_free(&unwrapped_edata);
102
103         if (nt_status) {
104                 *nt_status = parsed_edata.ntstatus;
105         }
106
107         TALLOC_FREE(mem_ctx);
108
109         return True;
110 }
111
112  static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx, 
113                                                                   krb5_get_init_creds_opt *opt, 
114                                                                   NTSTATUS *nt_status)
115 {
116         bool ret = False;
117         krb5_error *error = NULL;
118
119 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
120         ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
121         if (ret) {
122                 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n", 
123                         error_message(ret)));
124                 return False;
125         }
126 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
127
128         if (!error) {
129                 DEBUG(1,("no krb5_error\n"));
130                 return False;
131         }
132
133 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
134         if (!error->e_data) {
135 #else
136         if (error->e_data.data == NULL) {
137 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
138                 DEBUG(1,("no edata in krb5_error\n")); 
139                 krb5_free_error(ctx, error);
140                 return False;
141         }
142
143         ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
144
145         krb5_free_error(ctx, error);
146
147         return ret;
148 }
149
150 /*
151   simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
152   place in default cache location.
153   remus@snapserver.com
154 */
155 int kerberos_kinit_password_ext(const char *principal,
156                                 const char *password,
157                                 int time_offset,
158                                 time_t *expire_time,
159                                 time_t *renew_till_time,
160                                 const char *cache_name,
161                                 bool request_pac,
162                                 bool add_netbios_addr,
163                                 time_t renewable_time,
164                                 NTSTATUS *ntstatus)
165 {
166         krb5_context ctx = NULL;
167         krb5_error_code code = 0;
168         krb5_ccache cc = NULL;
169         krb5_principal me = NULL;
170         krb5_creds my_creds;
171         krb5_get_init_creds_opt *opt = NULL;
172         smb_krb5_addresses *addr = NULL;
173
174         ZERO_STRUCT(my_creds);
175
176         initialize_krb5_error_table();
177         if ((code = krb5_init_context(&ctx)))
178                 goto out;
179
180         if (time_offset != 0) {
181                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
182         }
183
184         DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
185                         principal,
186                         cache_name ? cache_name: krb5_cc_default_name(ctx),
187                         getenv("KRB5_CONFIG")));
188
189         if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
190                 goto out;
191         }
192         
193         if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
194                 goto out;
195         }
196
197         if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
198                 goto out;
199         }
200
201         krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
202         krb5_get_init_creds_opt_set_forwardable(opt, True);
203 #if 0
204         /* insane testing */
205         krb5_get_init_creds_opt_set_tkt_life(opt, 60);
206 #endif
207
208 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
209         if (request_pac) {
210                 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
211                         goto out;
212                 }
213         }
214 #endif
215         if (add_netbios_addr) {
216                 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
217                         goto out;
218                 }
219                 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
220         }
221
222         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), 
223                                                  kerb_prompter, CONST_DISCARD(char *,password),
224                                                  0, NULL, opt))) {
225                 goto out;
226         }
227
228         if ((code = krb5_cc_initialize(ctx, cc, me))) {
229                 goto out;
230         }
231         
232         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
233                 goto out;
234         }
235
236         if (expire_time) {
237                 *expire_time = (time_t) my_creds.times.endtime;
238         }
239
240         if (renew_till_time) {
241                 *renew_till_time = (time_t) my_creds.times.renew_till;
242         }
243  out:
244         if (ntstatus) {
245
246                 NTSTATUS status;
247
248                 /* fast path */
249                 if (code == 0) {
250                         *ntstatus = NT_STATUS_OK;
251                         goto cleanup;
252                 }
253
254                 /* try to get ntstatus code out of krb5_error when we have it
255                  * inside the krb5_get_init_creds_opt - gd */
256
257                 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
258                         *ntstatus = status;
259                         goto cleanup;
260                 }
261
262                 /* fall back to self-made-mapping */
263                 *ntstatus = krb5_to_nt_status(code);
264         }
265
266  cleanup:
267         krb5_free_cred_contents(ctx, &my_creds);
268         if (me) {
269                 krb5_free_principal(ctx, me);
270         }
271         if (addr) {
272                 smb_krb5_free_addresses(ctx, addr);
273         }
274         if (opt) {
275                 smb_krb5_get_init_creds_opt_free(ctx, opt);
276         }
277         if (cc) {
278                 krb5_cc_close(ctx, cc);
279         }
280         if (ctx) {
281                 krb5_free_context(ctx);
282         }
283         return code;
284 }
285
286
287
288 /* run kinit to setup our ccache */
289 int ads_kinit_password(ADS_STRUCT *ads)
290 {
291         char *s;
292         int ret;
293         const char *account_name;
294         fstring acct_name;
295
296         if (ads->auth.flags & ADS_AUTH_USER_CREDS) {
297                 account_name = ads->auth.user_name;
298                 goto got_accountname;
299         }
300
301         if ( IS_DC ) {
302                 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
303                 account_name = lp_workgroup();
304         } else {
305                 /* always use the sAMAccountName for security = domain */
306                 /* global_myname()$@REA.LM */
307                 if ( lp_security() == SEC_DOMAIN ) {
308                         fstr_sprintf( acct_name, "%s$", global_myname() );
309                         account_name = acct_name;
310                 }
311                 else 
312                         /* This looks like host/global_myname()@REA.LM */
313                         account_name = ads->auth.user_name;
314         }
315
316  got_accountname:
317         if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
318                 return KRB5_CC_NOMEM;
319         }
320
321         if (!ads->auth.password) {
322                 SAFE_FREE(s);
323                 return KRB5_LIBOS_CANTREADPWD;
324         }
325         
326         ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
327                         &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable, 
328                         NULL);
329
330         if (ret) {
331                 DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
332                          s, error_message(ret)));
333         }
334         SAFE_FREE(s);
335         return ret;
336 }
337
338 int ads_kdestroy(const char *cc_name)
339 {
340         krb5_error_code code;
341         krb5_context ctx = NULL;
342         krb5_ccache cc = NULL;
343
344         initialize_krb5_error_table();
345         if ((code = krb5_init_context (&ctx))) {
346                 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
347                         error_message(code)));
348                 return code;
349         }
350   
351         if (!cc_name) {
352                 if ((code = krb5_cc_default(ctx, &cc))) {
353                         krb5_free_context(ctx);
354                         return code;
355                 }
356         } else {
357                 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
358                         DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
359                                   error_message(code)));
360                         krb5_free_context(ctx);
361                         return code;
362                 }
363         }
364
365         if ((code = krb5_cc_destroy (ctx, cc))) {
366                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
367                         error_message(code)));
368         }
369
370         krb5_free_context (ctx);
371         return code;
372 }
373
374 /************************************************************************
375  Routine to fetch the salting principal for a service.  Active
376  Directory may use a non-obvious principal name to generate the salt
377  when it determines the key to use for encrypting tickets for a service,
378  and hopefully we detected that when we joined the domain.
379  ************************************************************************/
380
381 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
382 {
383         char *key = NULL;
384         char *ret = NULL;
385
386         if (asprintf(&key, "%s/%s/enctype=%d",
387                      SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
388                 return NULL;
389         }
390         ret = (char *)secrets_fetch(key, NULL);
391         SAFE_FREE(key);
392         return ret;
393 }
394
395 /************************************************************************
396  Return the standard DES salt key
397 ************************************************************************/
398
399 char* kerberos_standard_des_salt( void )
400 {
401         fstring salt;
402
403         fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
404         strlower_m( salt );
405         fstrcat( salt, lp_realm() );
406
407         return SMB_STRDUP( salt );
408 }
409
410 /************************************************************************
411 ************************************************************************/
412
413 static char* des_salt_key( void )
414 {
415         char *key;
416
417         if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
418                      lp_realm()) == -1) {
419                 return NULL;
420         }
421
422         return key;
423 }
424
425 /************************************************************************
426 ************************************************************************/
427
428 bool kerberos_secrets_store_des_salt( const char* salt )
429 {
430         char* key;
431         bool ret;
432
433         if ( (key = des_salt_key()) == NULL ) {
434                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
435                 return False;
436         }
437
438         if ( !salt ) {
439                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
440                 secrets_delete( key );
441                 return True;
442         }
443
444         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
445
446         ret = secrets_store( key, salt, strlen(salt)+1 );
447
448         SAFE_FREE( key );
449
450         return ret;
451 }
452
453 /************************************************************************
454 ************************************************************************/
455
456 char* kerberos_secrets_fetch_des_salt( void )
457 {
458         char *salt, *key;
459
460         if ( (key = des_salt_key()) == NULL ) {
461                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
462                 return False;
463         }
464
465         salt = (char*)secrets_fetch( key, NULL );
466
467         SAFE_FREE( key );
468
469         return salt;
470 }
471
472 /************************************************************************
473  Routine to get the default realm from the kerberos credentials cache.
474  Caller must free if the return value is not NULL.
475 ************************************************************************/
476
477 char *kerberos_get_default_realm_from_ccache( void )
478 {
479         char *realm = NULL;
480         krb5_context ctx = NULL;
481         krb5_ccache cc = NULL;
482         krb5_principal princ = NULL;
483
484         initialize_krb5_error_table();
485         if (krb5_init_context(&ctx)) {
486                 return NULL;
487         }
488
489         DEBUG(5,("kerberos_get_default_realm_from_ccache: "
490                 "Trying to read krb5 cache: %s\n",
491                 krb5_cc_default_name(ctx)));
492         if (krb5_cc_default(ctx, &cc)) {
493                 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
494                         "failed to read default cache\n"));
495                 goto out;
496         }
497         if (krb5_cc_get_principal(ctx, cc, &princ)) {
498                 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
499                         "failed to get default principal\n"));
500                 goto out;
501         }
502
503 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
504         realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
505 #elif defined(HAVE_KRB5_PRINC_REALM)
506         {
507                 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
508                 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
509         }
510 #endif
511
512   out:
513
514         if (ctx) {
515                 if (princ) {
516                         krb5_free_principal(ctx, princ);
517                 }
518                 if (cc) {
519                         krb5_cc_close(ctx, cc);
520                 }
521                 krb5_free_context(ctx);
522         }
523
524         return realm;
525 }
526
527
528 /************************************************************************
529  Routine to get the salting principal for this service.  This is 
530  maintained for backwards compatibilty with releases prior to 3.0.24.
531  Since we store the salting principal string only at join, we may have 
532  to look for the older tdb keys.  Caller must free if return is not null.
533  ************************************************************************/
534
535 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
536                                                         krb5_principal host_princ,
537                                                         int enctype)
538 {
539         char *unparsed_name = NULL, *salt_princ_s = NULL;
540         krb5_principal ret_princ = NULL;
541         
542         /* lookup new key first */
543
544         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
545         
546                 /* look under the old key.  If this fails, just use the standard key */
547
548                 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
549                         return (krb5_principal)NULL;
550                 }
551                 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
552                         /* fall back to host/machine.realm@REALM */
553                         salt_princ_s = kerberos_standard_des_salt();
554                 }
555         }
556
557         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
558                 ret_princ = NULL;
559         }
560         
561         TALLOC_FREE(unparsed_name);
562         SAFE_FREE(salt_princ_s);
563         
564         return ret_princ;
565 }
566
567 /************************************************************************
568  Routine to set the salting principal for this service.  Active
569  Directory may use a non-obvious principal name to generate the salt
570  when it determines the key to use for encrypting tickets for a service,
571  and hopefully we detected that when we joined the domain.
572  Setting principal to NULL deletes this entry.
573  ************************************************************************/
574
575 bool kerberos_secrets_store_salting_principal(const char *service,
576                                               int enctype,
577                                               const char *principal)
578 {
579         char *key = NULL;
580         bool ret = False;
581         krb5_context context = NULL;
582         krb5_principal princ = NULL;
583         char *princ_s = NULL;
584         char *unparsed_name = NULL;
585         krb5_error_code code;
586
587         if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
588                 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
589                           error_message(code)));
590                 return False;
591         }
592         if (strchr_m(service, '@')) {
593                 if (asprintf(&princ_s, "%s", service) == -1) {
594                         goto out;
595                 }
596         } else {
597                 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
598                         goto out;
599                 }
600         }
601
602         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
603                 goto out;
604                 
605         }
606         if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
607                 goto out;
608         }
609
610         if (asprintf(&key, "%s/%s/enctype=%d",
611                      SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
612             == -1) {
613                 goto out;
614         }
615
616         if ((principal != NULL) && (strlen(principal) > 0)) {
617                 ret = secrets_store(key, principal, strlen(principal) + 1);
618         } else {
619                 ret = secrets_delete(key);
620         }
621
622  out:
623
624         SAFE_FREE(key);
625         SAFE_FREE(princ_s);
626         TALLOC_FREE(unparsed_name);
627
628         if (princ) {
629                 krb5_free_principal(context, princ);
630         }
631
632         if (context) {
633                 krb5_free_context(context);
634         }
635
636         return ret;
637 }
638
639
640 /************************************************************************
641 ************************************************************************/
642
643 int kerberos_kinit_password(const char *principal,
644                             const char *password,
645                             int time_offset,
646                             const char *cache_name)
647 {
648         return kerberos_kinit_password_ext(principal, 
649                                            password, 
650                                            time_offset, 
651                                            0, 
652                                            0,
653                                            cache_name,
654                                            False,
655                                            False,
656                                            0,
657                                            NULL);
658 }
659
660 /************************************************************************
661 ************************************************************************/
662
663 static char *print_kdc_line(char *mem_ctx,
664                         const char *prev_line,
665                         const struct sockaddr_storage *pss)
666 {
667         char *kdc_str = NULL;
668
669         if (pss->ss_family == AF_INET) {
670                 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
671                                         prev_line,
672                                         print_canonical_sockaddr(mem_ctx, pss));
673         } else {
674                 char addr[INET6_ADDRSTRLEN];
675                 uint16_t port = get_sockaddr_port(pss);
676
677                 if (port != 0 && port != DEFAULT_KRB5_PORT) {
678                         /* Currently for IPv6 we can't specify a non-default
679                            krb5 port with an address, as this requires a ':'.
680                            Resolve to a name. */
681                         char hostname[MAX_DNS_NAME_LENGTH];
682                         int ret = sys_getnameinfo((const struct sockaddr *)pss,
683                                         sizeof(*pss),
684                                         hostname, sizeof(hostname),
685                                         NULL, 0,
686                                         NI_NAMEREQD);
687                         if (ret) {
688                                 DEBUG(0,("print_kdc_line: can't resolve name "
689                                         "for kdc with non-default port %s. "
690                                         "Error %s\n.",
691                                         print_canonical_sockaddr(mem_ctx, pss),
692                                         gai_strerror(ret)));
693                         }
694                         /* Success, use host:port */
695                         kdc_str = talloc_asprintf(mem_ctx,
696                                         "%s\tkdc = %s:%u\n",
697                                         prev_line,
698                                         hostname,
699                                         (unsigned int)port);
700                 } else {
701                         kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
702                                         prev_line,
703                                         print_sockaddr(addr,
704                                                 sizeof(addr),
705                                                 pss));
706                 }
707         }
708         return kdc_str;
709 }
710
711 /************************************************************************
712  Create a string list of available kdc's, possibly searching by sitename.
713  Does DNS queries.
714
715  If "sitename" is given, the DC's in that site are listed first.
716
717 ************************************************************************/
718
719 static char *get_kdc_ip_string(char *mem_ctx,
720                 const char *realm,
721                 const char *sitename,
722                 struct sockaddr_storage *pss)
723 {
724         int i;
725         struct ip_service *ip_srv_site = NULL;
726         struct ip_service *ip_srv_nonsite = NULL;
727         int count_site = 0;
728         int count_nonsite;
729         char *kdc_str = print_kdc_line(mem_ctx, "", pss);
730
731         if (kdc_str == NULL) {
732                 return NULL;
733         }
734
735         /*
736          * First get the KDC's only in this site, the rest will be
737          * appended later
738          */
739
740         if (sitename) {
741
742                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
743
744                 for (i = 0; i < count_site; i++) {
745                         if (sockaddr_equal((struct sockaddr *)&ip_srv_site[i].ss,
746                                                    (struct sockaddr *)pss)) {
747                                 continue;
748                         }
749                         /* Append to the string - inefficient
750                          * but not done often. */
751                         kdc_str = print_kdc_line(mem_ctx,
752                                                 kdc_str,
753                                                 &ip_srv_site[i].ss);
754                         if (!kdc_str) {
755                                 SAFE_FREE(ip_srv_site);
756                                 return NULL;
757                         }
758                 }
759         }
760
761         /* Get all KDC's. */
762
763         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
764
765         for (i = 0; i < count_nonsite; i++) {
766                 int j;
767
768                 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss, (struct sockaddr *)pss)) {
769                         continue;
770                 }
771
772                 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
773                 for (j = 0; j < count_site; j++) {
774                         if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss,
775                                                 (struct sockaddr *)&ip_srv_site[j].ss)) {
776                                 break;
777                         }
778                         /* As the lists are sorted we can break early if nonsite > site. */
779                         if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
780                                 break;
781                         }
782                 }
783                 if (j != i) {
784                         continue;
785                 }
786
787                 /* Append to the string - inefficient but not done often. */
788                 kdc_str = print_kdc_line(mem_ctx,
789                                 kdc_str,
790                                 &ip_srv_nonsite[i].ss);
791                 if (!kdc_str) {
792                         SAFE_FREE(ip_srv_site);
793                         SAFE_FREE(ip_srv_nonsite);
794                         return NULL;
795                 }
796         }
797
798
799         SAFE_FREE(ip_srv_site);
800         SAFE_FREE(ip_srv_nonsite);
801
802         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
803                 kdc_str ));
804
805         return kdc_str;
806 }
807
808 /************************************************************************
809  Create  a specific krb5.conf file in the private directory pointing
810  at a specific kdc for a realm. Keyed off domain name. Sets
811  KRB5_CONFIG environment variable to point to this file. Must be
812  run as root or will fail (which is a good thing :-).
813 ************************************************************************/
814
815 bool create_local_private_krb5_conf_for_domain(const char *realm,
816                                                 const char *domain,
817                                                 const char *sitename,
818                                                 struct sockaddr_storage *pss)
819 {
820         char *dname;
821         char *tmpname = NULL;
822         char *fname = NULL;
823         char *file_contents = NULL;
824         char *kdc_ip_string = NULL;
825         size_t flen = 0;
826         ssize_t ret;
827         int fd;
828         char *realm_upper = NULL;
829         bool result = false;
830
831         if (!lp_create_krb5_conf()) {
832                 return false;
833         }
834
835         dname = lock_path("smb_krb5");
836         if (!dname) {
837                 return false;
838         }
839         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
840                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
841                         "failed to create directory %s. Error was %s\n",
842                         dname, strerror(errno) ));
843                 goto done;
844         }
845
846         tmpname = lock_path("smb_tmp_krb5.XXXXXX");
847         if (!tmpname) {
848                 goto done;
849         }
850
851         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
852         if (!fname) {
853                 goto done;
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                 goto done;
865         }
866
867         file_contents = talloc_asprintf(fname,
868                                         "[libdefaults]\n\tdefault_realm = %s\n"
869                                         "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
870                                         "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
871                                         "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
872                                         "[realms]\n\t%s = {\n"
873                                         "\t%s\t}\n",
874                                         realm_upper, realm_upper, kdc_ip_string);
875
876         if (!file_contents) {
877                 goto done;
878         }
879
880         flen = strlen(file_contents);
881
882         fd = mkstemp(tmpname);
883         if (fd == -1) {
884                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
885                         " for file %s. Errno %s\n",
886                         tmpname, strerror(errno) ));
887                 goto done;
888         }
889
890         if (fchmod(fd, 0644)==-1) {
891                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
892                         " Errno %s\n",
893                         tmpname, strerror(errno) ));
894                 unlink(tmpname);
895                 close(fd);
896                 goto done;
897         }
898
899         ret = write(fd, file_contents, flen);
900         if (flen != ret) {
901                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
902                         " returned %d (should be %u). Errno %s\n",
903                         (int)ret, (unsigned int)flen, strerror(errno) ));
904                 unlink(tmpname);
905                 close(fd);
906                 goto done;
907         }
908         if (close(fd)==-1) {
909                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
910                         " Errno %s\n", strerror(errno) ));
911                 unlink(tmpname);
912                 goto done;
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                 goto done;
921         }
922
923         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
924                 "file %s with realm %s KDC list = %s\n",
925                 fname, realm_upper, kdc_ip_string));
926
927         /* Set the environment variable to this file. */
928         setenv("KRB5_CONFIG", fname, 1);
929
930         result = true;
931
932 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
933
934 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
935         /* Insanity, sheer insanity..... */
936
937         if (strequal(realm, lp_realm())) {
938                 char linkpath[PATH_MAX+1];
939                 int lret;
940
941                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
942                 if (lret != -1) {
943                         linkpath[lret] = '\0';
944                 }
945
946                 if (lret != -1 || strcmp(linkpath, fname) == 0) {
947                         /* Symlink already exists. */
948                         goto done;
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                                 goto done; /* Not a fatal error. */
959                         }
960
961                         /* Yes, this is a race conditon... too bad. */
962                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
963                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
964                                         "of %s to %s failed. Errno %s\n",
965                                         SYSTEM_KRB5_CONF_PATH, newpath,
966                                         strerror(errno) ));
967                                 goto done; /* Not a fatal error. */
968                         }
969
970                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
971                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
972                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
973                                         fname, strerror(errno) ));
974                                 goto done; /* Not a fatal error. */
975                         }
976                 }
977         }
978 #endif
979
980 done:
981         TALLOC_FREE(tmpname);
982         TALLOC_FREE(dname);
983
984         return result;
985 }
986 #endif