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