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