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