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