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