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