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