Memory leak fixes from Chere Zhou <czhou@isilon.com>.
[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(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         if (asprintf(&key, "%s/%s/enctype=%d",
411                      SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
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         if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
442                      lp_realm()) == -1) {
443                 return NULL;
444         }
445
446         return key;
447 }
448
449 /************************************************************************
450 ************************************************************************/
451
452 bool kerberos_secrets_store_des_salt( const char* salt )
453 {
454         char* key;
455         bool ret;
456
457         if ( (key = des_salt_key()) == NULL ) {
458                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
459                 return False;
460         }
461
462         if ( !salt ) {
463                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
464                 secrets_delete( key );
465                 return True;
466         }
467
468         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
469
470         ret = secrets_store( key, salt, strlen(salt)+1 );
471
472         SAFE_FREE( key );
473
474         return ret;
475 }
476
477 /************************************************************************
478 ************************************************************************/
479
480 char* kerberos_secrets_fetch_des_salt( void )
481 {
482         char *salt, *key;
483
484         if ( (key = des_salt_key()) == NULL ) {
485                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
486                 return False;
487         }
488
489         salt = (char*)secrets_fetch( key, NULL );
490
491         SAFE_FREE( key );
492
493         return salt;
494 }
495
496 /************************************************************************
497  Routine to get the default realm from the kerberos credentials cache.
498  Caller must free if the return value is not NULL.
499 ************************************************************************/
500
501 char *kerberos_get_default_realm_from_ccache( void )
502 {
503         char *realm = NULL;
504         krb5_context ctx = NULL;
505         krb5_ccache cc = NULL;
506         krb5_principal princ = NULL;
507
508         initialize_krb5_error_table();
509         if (krb5_init_context(&ctx)) {
510                 return NULL;
511         }
512
513         DEBUG(5,("kerberos_get_default_realm_from_ccache: "
514                 "Trying to read krb5 cache: %s\n",
515                 krb5_cc_default_name(ctx)));
516         if (krb5_cc_default(ctx, &cc)) {
517                 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
518                         "failed to read default cache\n"));
519                 goto out;
520         }
521         if (krb5_cc_get_principal(ctx, cc, &princ)) {
522                 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
523                         "failed to get default principal\n"));
524                 goto out;
525         }
526
527 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
528         realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
529 #elif defined(HAVE_KRB5_PRINC_REALM)
530         {
531                 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
532                 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
533         }
534 #endif
535
536   out:
537
538         if (princ) {
539                 krb5_free_principal(ctx, princ);
540         }
541         if (cc) {
542                 krb5_cc_close(ctx, cc);
543         }
544         if (ctx) {
545                 krb5_free_context(ctx);
546         }
547
548         return realm;
549 }
550
551
552 /************************************************************************
553  Routine to get the salting principal for this service.  This is 
554  maintained for backwards compatibilty with releases prior to 3.0.24.
555  Since we store the salting principal string only at join, we may have 
556  to look for the older tdb keys.  Caller must free if return is not null.
557  ************************************************************************/
558
559 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
560                                                         krb5_principal host_princ,
561                                                         int enctype)
562 {
563         char *unparsed_name = NULL, *salt_princ_s = NULL;
564         krb5_principal ret_princ = NULL;
565         
566         /* lookup new key first */
567
568         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
569         
570                 /* look under the old key.  If this fails, just use the standard key */
571
572                 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
573                         return (krb5_principal)NULL;
574                 }
575                 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
576                         /* fall back to host/machine.realm@REALM */
577                         salt_princ_s = kerberos_standard_des_salt();
578                 }
579         }
580
581         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
582                 ret_princ = NULL;
583         }
584         
585         SAFE_FREE(unparsed_name);
586         SAFE_FREE(salt_princ_s);
587         
588         return ret_princ;
589 }
590
591 /************************************************************************
592  Routine to set the salting principal for this service.  Active
593  Directory may use a non-obvious principal name to generate the salt
594  when it determines the key to use for encrypting tickets for a service,
595  and hopefully we detected that when we joined the domain.
596  Setting principal to NULL deletes this entry.
597  ************************************************************************/
598
599 bool kerberos_secrets_store_salting_principal(const char *service,
600                                               int enctype,
601                                               const char *principal)
602 {
603         char *key = NULL;
604         bool ret = False;
605         krb5_context context = NULL;
606         krb5_principal princ = NULL;
607         char *princ_s = NULL;
608         char *unparsed_name = NULL;
609         krb5_error_code code;
610
611         if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
612                 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
613                           error_message(code)));
614                 return False;
615         }
616         if (strchr_m(service, '@')) {
617                 if (asprintf(&princ_s, "%s", service) == -1) {
618                         goto out;
619                 }
620         } else {
621                 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
622                         goto out;
623                 }
624         }
625
626         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
627                 goto out;
628                 
629         }
630         if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
631                 goto out;
632         }
633
634         if (asprintf(&key, "%s/%s/enctype=%d",
635                      SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
636             == -1) {
637                 goto out;
638         }
639
640         if ((principal != NULL) && (strlen(principal) > 0)) {
641                 ret = secrets_store(key, principal, strlen(principal) + 1);
642         } else {
643                 ret = secrets_delete(key);
644         }
645
646  out:
647
648         SAFE_FREE(key);
649         SAFE_FREE(princ_s);
650         SAFE_FREE(unparsed_name);
651
652         if (princ) {
653                 krb5_free_principal(context, princ);
654         }
655
656         if (context) {
657                 krb5_free_context(context);
658         }
659
660         return ret;
661 }
662
663
664 /************************************************************************
665 ************************************************************************/
666
667 int kerberos_kinit_password(const char *principal,
668                             const char *password,
669                             int time_offset,
670                             const char *cache_name)
671 {
672         return kerberos_kinit_password_ext(principal, 
673                                            password, 
674                                            time_offset, 
675                                            0, 
676                                            0,
677                                            cache_name,
678                                            False,
679                                            False,
680                                            0,
681                                            NULL);
682 }
683
684 /************************************************************************
685 ************************************************************************/
686
687 static char *print_kdc_line(char *mem_ctx,
688                         const char *prev_line,
689                         const struct sockaddr_storage *pss)
690 {
691         char *kdc_str = NULL;
692
693         if (pss->ss_family == AF_INET) {
694                 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
695                                         prev_line,
696                                         print_canonical_sockaddr(mem_ctx, pss));
697         } else {
698                 char addr[INET6_ADDRSTRLEN];
699                 uint16_t port = get_sockaddr_port(pss);
700
701                 if (port != 0 && port != DEFAULT_KRB5_PORT) {
702                         /* Currently for IPv6 we can't specify a non-default
703                            krb5 port with an address, as this requires a ':'.
704                            Resolve to a name. */
705                         char hostname[MAX_DNS_NAME_LENGTH];
706                         int ret = sys_getnameinfo((const struct sockaddr *)pss,
707                                         sizeof(*pss),
708                                         hostname, sizeof(hostname),
709                                         NULL, 0,
710                                         NI_NAMEREQD);
711                         if (ret) {
712                                 DEBUG(0,("print_kdc_line: can't resolve name "
713                                         "for kdc with non-default port %s. "
714                                         "Error %s\n.",
715                                         print_canonical_sockaddr(mem_ctx, pss),
716                                         gai_strerror(ret)));
717                         }
718                         /* Success, use host:port */
719                         kdc_str = talloc_asprintf(mem_ctx,
720                                         "%s\tkdc = %s:%u\n",
721                                         prev_line,
722                                         hostname,
723                                         (unsigned int)port);
724                 } else {
725                         kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
726                                         prev_line,
727                                         print_sockaddr(addr,
728                                                 sizeof(addr),
729                                                 pss));
730                 }
731         }
732         return kdc_str;
733 }
734
735 /************************************************************************
736  Create a string list of available kdc's, possibly searching by sitename.
737  Does DNS queries.
738
739  If "sitename" is given, the DC's in that site are listed first.
740
741 ************************************************************************/
742
743 static char *get_kdc_ip_string(char *mem_ctx,
744                 const char *realm,
745                 const char *sitename,
746                 struct sockaddr_storage *pss)
747 {
748         int i;
749         struct ip_service *ip_srv_site = NULL;
750         struct ip_service *ip_srv_nonsite = NULL;
751         int count_site = 0;
752         int count_nonsite;
753         char *kdc_str = print_kdc_line(mem_ctx, "", pss);
754
755         if (kdc_str == NULL) {
756                 return NULL;
757         }
758
759         /*
760          * First get the KDC's only in this site, the rest will be
761          * appended later
762          */
763
764         if (sitename) {
765
766                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
767
768                 for (i = 0; i < count_site; i++) {
769                         if (addr_equal(&ip_srv_site[i].ss, pss)) {
770                                 continue;
771                         }
772                         /* Append to the string - inefficient
773                          * but not done often. */
774                         kdc_str = print_kdc_line(mem_ctx,
775                                                 kdc_str,
776                                                 &ip_srv_site[i].ss);
777                         if (!kdc_str) {
778                                 SAFE_FREE(ip_srv_site);
779                                 return NULL;
780                         }
781                 }
782         }
783
784         /* Get all KDC's. */
785
786         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
787
788         for (i = 0; i < count_nonsite; i++) {
789                 int j;
790
791                 if (addr_equal(&ip_srv_nonsite[i].ss, pss)) {
792                         continue;
793                 }
794
795                 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
796                 for (j = 0; j < count_site; j++) {
797                         if (addr_equal(&ip_srv_nonsite[i].ss,
798                                                 &ip_srv_site[j].ss)) {
799                                 break;
800                         }
801                         /* As the lists are sorted we can break early if nonsite > site. */
802                         if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
803                                 break;
804                         }
805                 }
806                 if (j != i) {
807                         continue;
808                 }
809
810                 /* Append to the string - inefficient but not done often. */
811                 kdc_str = print_kdc_line(mem_ctx,
812                                 kdc_str,
813                                 &ip_srv_nonsite[i].ss);
814                 if (!kdc_str) {
815                         SAFE_FREE(ip_srv_site);
816                         SAFE_FREE(ip_srv_nonsite);
817                         return NULL;
818                 }
819         }
820
821
822         SAFE_FREE(ip_srv_site);
823         SAFE_FREE(ip_srv_nonsite);
824
825         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
826                 kdc_str ));
827
828         return kdc_str;
829 }
830
831 /************************************************************************
832  Create  a specific krb5.conf file in the private directory pointing
833  at a specific kdc for a realm. Keyed off domain name. Sets
834  KRB5_CONFIG environment variable to point to this file. Must be
835  run as root or will fail (which is a good thing :-).
836 ************************************************************************/
837
838 bool create_local_private_krb5_conf_for_domain(const char *realm,
839                                                 const char *domain,
840                                                 const char *sitename,
841                                                 struct sockaddr_storage *pss)
842 {
843         char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
844         char *tmpname = NULL;
845         char *fname = NULL;
846         char *file_contents = NULL;
847         char *kdc_ip_string = NULL;
848         size_t flen = 0;
849         ssize_t ret;
850         int fd;
851         char *realm_upper = NULL;
852
853         if (!dname) {
854                 return False;
855         }
856         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
857                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
858                         "failed to create directory %s. Error was %s\n",
859                         dname, strerror(errno) ));
860                 TALLOC_FREE(dname);
861                 return False;
862         }
863
864         tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
865         if (!tmpname) {
866                 TALLOC_FREE(dname);
867                 return False;
868         }
869
870         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
871         if (!fname) {
872                 TALLOC_FREE(dname);
873                 return False;
874         }
875
876         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
877                 fname, realm, domain ));
878
879         realm_upper = talloc_strdup(fname, realm);
880         strupper_m(realm_upper);
881
882         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
883         if (!kdc_ip_string) {
884                 TALLOC_FREE(dname);
885                 return False;
886         }
887
888         file_contents = talloc_asprintf(fname,
889                                         "[libdefaults]\n\tdefault_realm = %s\n"
890                                         "default_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
891                                         "default_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
892                                         "preferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
893                                         "[realms]\n\t%s = {\n"
894                                         "\t%s\t}\n",
895                                         realm_upper, realm_upper, kdc_ip_string);
896
897         if (!file_contents) {
898                 TALLOC_FREE(dname);
899                 return False;
900         }
901
902         flen = strlen(file_contents);
903
904         fd = smb_mkstemp(tmpname);
905         if (fd == -1) {
906                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
907                         " for file %s. Errno %s\n",
908                         tmpname, strerror(errno) ));
909                 TALLOC_FREE(dname);
910                 return false;
911         }
912
913         if (fchmod(fd, 0644)==-1) {
914                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
915                         " Errno %s\n",
916                         tmpname, strerror(errno) ));
917                 unlink(tmpname);
918                 close(fd);
919                 TALLOC_FREE(dname);
920                 return False;
921         }
922
923         ret = write(fd, file_contents, flen);
924         if (flen != ret) {
925                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
926                         " returned %d (should be %u). Errno %s\n",
927                         (int)ret, (unsigned int)flen, strerror(errno) ));
928                 unlink(tmpname);
929                 close(fd);
930                 TALLOC_FREE(dname);
931                 return False;
932         }
933         if (close(fd)==-1) {
934                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
935                         " Errno %s\n", strerror(errno) ));
936                 unlink(tmpname);
937                 TALLOC_FREE(dname);
938                 return False;
939         }
940
941         if (rename(tmpname, fname) == -1) {
942                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
943                         "of %s to %s failed. Errno %s\n",
944                         tmpname, fname, strerror(errno) ));
945                 unlink(tmpname);
946                 TALLOC_FREE(dname);
947                 return False;
948         }
949
950         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
951                 "file %s with realm %s KDC list = %s\n",
952                 fname, realm_upper, kdc_ip_string));
953
954         /* Set the environment variable to this file. */
955         setenv("KRB5_CONFIG", fname, 1);
956
957 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
958
959 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
960         /* Insanity, sheer insanity..... */
961
962         if (strequal(realm, lp_realm())) {
963                 char linkpath[PATH_MAX+1];
964                 int lret;
965
966                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
967                 if (lret != -1) {
968                         linkpath[lret] = '\0';
969                 }
970
971                 if (lret != -1 || strcmp(linkpath, fname) == 0) {
972                         /* Symlink already exists. */
973                         TALLOC_FREE(dname);
974                         return True;
975                 }
976
977                 /* Try and replace with a symlink. */
978                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
979                         const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
980                         if (errno != EEXIST) {
981                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
982                                         "of %s to %s failed. Errno %s\n",
983                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
984                                 TALLOC_FREE(dname);
985                                 return True; /* Not a fatal error. */
986                         }
987
988                         /* Yes, this is a race conditon... too bad. */
989                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
990                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
991                                         "of %s to %s failed. Errno %s\n",
992                                         SYSTEM_KRB5_CONF_PATH, newpath,
993                                         strerror(errno) ));
994                                 TALLOC_FREE(dname);
995                                 return True; /* Not a fatal error. */
996                         }
997
998                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
999                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1000                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1001                                         fname, strerror(errno) ));
1002                                 TALLOC_FREE(dname);
1003                                 return True; /* Not a fatal error. */
1004                         }
1005                 }
1006         }
1007 #endif
1008
1009         TALLOC_FREE(dname);
1010
1011         return True;
1012 }
1013 #endif