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