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