r18225: If we're going to overwrite krb5.conf, at least
[samba.git] / source / 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 2 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, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26
27 #ifdef HAVE_KRB5
28
29 #define LIBADS_CCACHE_NAME "MEMORY:libads"
30
31 /*
32   we use a prompter to avoid a crash bug in the kerberos libs when 
33   dealing with empty passwords
34   this prompter is just a string copy ...
35 */
36 static krb5_error_code 
37 kerb_prompter(krb5_context ctx, void *data,
38                const char *name,
39                const char *banner,
40                int num_prompts,
41                krb5_prompt prompts[])
42 {
43         if (num_prompts == 0) return 0;
44
45         memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
46         if (prompts[0].reply->length > 0) {
47                 if (data) {
48                         strncpy(prompts[0].reply->data, (const char *)data,
49                                 prompts[0].reply->length-1);
50                         prompts[0].reply->length = strlen(prompts[0].reply->data);
51                 } else {
52                         prompts[0].reply->length = 0;
53                 }
54         }
55         return 0;
56 }
57
58 /*
59   simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
60   place in default cache location.
61   remus@snapserver.com
62 */
63 int kerberos_kinit_password_ext(const char *principal,
64                                 const char *password,
65                                 int time_offset,
66                                 time_t *expire_time,
67                                 time_t *renew_till_time,
68                                 const char *cache_name,
69                                 BOOL request_pac,
70                                 BOOL add_netbios_addr,
71                                 time_t renewable_time)
72 {
73         krb5_context ctx = NULL;
74         krb5_error_code code = 0;
75         krb5_ccache cc = NULL;
76         krb5_principal me;
77         krb5_creds my_creds;
78         krb5_get_init_creds_opt opt;
79         smb_krb5_addresses *addr = NULL;
80
81         initialize_krb5_error_table();
82         if ((code = krb5_init_context(&ctx)))
83                 return code;
84
85         if (time_offset != 0) {
86                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
87         }
88
89         DEBUG(10,("kerberos_kinit_password: using %s as ccache\n",
90                         cache_name ? cache_name: krb5_cc_default_name(ctx)));
91
92         if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
93                 krb5_free_context(ctx);
94                 return code;
95         }
96         
97         if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
98                 krb5_free_context(ctx); 
99                 return code;
100         }
101
102         krb5_get_init_creds_opt_init(&opt);
103         krb5_get_init_creds_opt_set_renew_life(&opt, renewable_time);
104         krb5_get_init_creds_opt_set_forwardable(&opt, 1);
105         
106         if (request_pac) {
107 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
108                 code = krb5_get_init_creds_opt_set_pac_request(ctx, &opt, True);
109                 if (code) {
110                         krb5_free_principal(ctx, me);
111                         krb5_free_context(ctx);
112                         return code;
113                 }
114 #endif
115         }
116
117         if (add_netbios_addr) {
118                 code = smb_krb5_gen_netbios_krb5_address(&addr);
119                 if (code) {
120                         krb5_free_principal(ctx, me);
121                         krb5_free_context(ctx);         
122                         return code;    
123                 }
124                 krb5_get_init_creds_opt_set_address_list(&opt, addr->addrs);
125         }
126
127         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), 
128                                                  kerb_prompter, NULL, 0, NULL, &opt)))
129         {
130                 smb_krb5_free_addresses(ctx, addr);
131                 krb5_free_principal(ctx, me);
132                 krb5_free_context(ctx);         
133                 return code;
134         }
135         
136         if ((code = krb5_cc_initialize(ctx, cc, me))) {
137                 smb_krb5_free_addresses(ctx, addr);
138                 krb5_free_cred_contents(ctx, &my_creds);
139                 krb5_free_principal(ctx, me);
140                 krb5_free_context(ctx);         
141                 return code;
142         }
143         
144         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
145                 krb5_cc_close(ctx, cc);
146                 smb_krb5_free_addresses(ctx, addr);
147                 krb5_free_cred_contents(ctx, &my_creds);
148                 krb5_free_principal(ctx, me);
149                 krb5_free_context(ctx);         
150                 return code;
151         }
152
153         if (expire_time) {
154                 *expire_time = (time_t) my_creds.times.endtime;
155         }
156
157         if (renew_till_time) {
158                 *renew_till_time = (time_t) my_creds.times.renew_till;
159         }
160
161         krb5_cc_close(ctx, cc);
162         smb_krb5_free_addresses(ctx, addr);
163         krb5_free_cred_contents(ctx, &my_creds);
164         krb5_free_principal(ctx, me);
165         krb5_free_context(ctx);         
166         
167         return 0;
168 }
169
170
171
172 /* run kinit to setup our ccache */
173 int ads_kinit_password(ADS_STRUCT *ads)
174 {
175         char *s;
176         int ret;
177         const char *account_name;
178         fstring acct_name;
179
180         if ( IS_DC ) {
181                 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
182                 account_name = lp_workgroup();
183         } else {
184                 /* always use the sAMAccountName for security = domain */
185                 /* global_myname()$@REA.LM */
186                 if ( lp_security() == SEC_DOMAIN ) {
187                         fstr_sprintf( acct_name, "%s$", global_myname() );
188                         account_name = acct_name;
189                 }
190                 else 
191                         /* This looks like host/global_myname()@REA.LM */
192                         account_name = ads->auth.user_name;
193         }
194
195         if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
196                 return KRB5_CC_NOMEM;
197         }
198
199         if (!ads->auth.password) {
200                 SAFE_FREE(s);
201                 return KRB5_LIBOS_CANTREADPWD;
202         }
203         
204         ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
205                         &ads->auth.expire, NULL, NULL, False, False, ads->auth.renewable);
206
207         if (ret) {
208                 DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
209                          s, error_message(ret)));
210         }
211         SAFE_FREE(s);
212         return ret;
213 }
214
215 int ads_kdestroy(const char *cc_name)
216 {
217         krb5_error_code code;
218         krb5_context ctx = NULL;
219         krb5_ccache cc = NULL;
220
221         initialize_krb5_error_table();
222         if ((code = krb5_init_context (&ctx))) {
223                 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
224                         error_message(code)));
225                 return code;
226         }
227   
228         if (!cc_name) {
229                 if ((code = krb5_cc_default(ctx, &cc))) {
230                         krb5_free_context(ctx);
231                         return code;
232                 }
233         } else {
234                 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
235                         DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
236                                   error_message(code)));
237                         krb5_free_context(ctx);
238                         return code;
239                 }
240         }
241
242         if ((code = krb5_cc_destroy (ctx, cc))) {
243                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
244                         error_message(code)));
245         }
246
247         krb5_free_context (ctx);
248         return code;
249 }
250
251 /************************************************************************
252  Routine to fetch the salting principal for a service.  Active
253  Directory may use a non-obvious principal name to generate the salt
254  when it determines the key to use for encrypting tickets for a service,
255  and hopefully we detected that when we joined the domain.
256  ************************************************************************/
257
258 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
259 {
260         char *key = NULL;
261         char *ret = NULL;
262
263         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
264         if (!key) {
265                 return NULL;
266         }
267         ret = (char *)secrets_fetch(key, NULL);
268         SAFE_FREE(key);
269         return ret;
270 }
271
272 /************************************************************************
273  Return the standard DES salt key
274 ************************************************************************/
275
276 char* kerberos_standard_des_salt( void )
277 {
278         fstring salt;
279
280         fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
281         strlower_m( salt );
282         fstrcat( salt, lp_realm() );
283
284         return SMB_STRDUP( salt );
285 }
286
287 /************************************************************************
288 ************************************************************************/
289
290 static char* des_salt_key( void )
291 {
292         char *key;
293
294         asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
295
296         return key;
297 }
298
299 /************************************************************************
300 ************************************************************************/
301
302 BOOL kerberos_secrets_store_des_salt( const char* salt )
303 {
304         char* key;
305         BOOL ret;
306
307         if ( (key = des_salt_key()) == NULL ) {
308                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
309                 return False;
310         }
311
312         if ( !salt ) {
313                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
314                 secrets_delete( key );
315                 return True;
316         }
317
318         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
319
320         ret = secrets_store( key, salt, strlen(salt)+1 );
321
322         SAFE_FREE( key );
323
324         return ret;
325 }
326
327 /************************************************************************
328 ************************************************************************/
329
330 char* kerberos_secrets_fetch_des_salt( void )
331 {
332         char *salt, *key;
333
334         if ( (key = des_salt_key()) == NULL ) {
335                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
336                 return False;
337         }
338
339         salt = (char*)secrets_fetch( key, NULL );
340
341         SAFE_FREE( key );
342
343         return salt;
344 }
345
346
347 /************************************************************************
348  Routine to get the salting principal for this service.  This is 
349  maintained for backwards compatibilty with releases prior to 3.0.24.
350  Since we store the salting principal string only at join, we may have 
351  to look for the older tdb keys.  Caller must free if return is not null.
352  ************************************************************************/
353
354 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
355                                                         krb5_principal host_princ,
356                                                         int enctype)
357 {
358         char *unparsed_name = NULL, *salt_princ_s = NULL;
359         krb5_principal ret_princ = NULL;
360         
361         /* lookup new key first */
362
363         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
364         
365                 /* look under the old key.  If this fails, just use the standard key */
366
367                 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
368                         return (krb5_principal)NULL;
369                 }
370                 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
371                         /* fall back to host/machine.realm@REALM */
372                         salt_princ_s = kerberos_standard_des_salt();
373                 }
374         }
375
376         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
377                 ret_princ = NULL;
378         }
379         
380         SAFE_FREE(unparsed_name);
381         SAFE_FREE(salt_princ_s);
382         
383         return ret_princ;
384 }
385
386 /************************************************************************
387  Routine to set the salting principal for this service.  Active
388  Directory may use a non-obvious principal name to generate the salt
389  when it determines the key to use for encrypting tickets for a service,
390  and hopefully we detected that when we joined the domain.
391  Setting principal to NULL deletes this entry.
392  ************************************************************************/
393
394 BOOL kerberos_secrets_store_salting_principal(const char *service,
395                                               int enctype,
396                                               const char *principal)
397 {
398         char *key = NULL;
399         BOOL ret = False;
400         krb5_context context = NULL;
401         krb5_principal princ = NULL;
402         char *princ_s = NULL;
403         char *unparsed_name = NULL;
404
405         krb5_init_context(&context);
406         if (!context) {
407                 return False;
408         }
409         if (strchr_m(service, '@')) {
410                 asprintf(&princ_s, "%s", service);
411         } else {
412                 asprintf(&princ_s, "%s@%s", service, lp_realm());
413         }
414
415         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
416                 goto out;
417                 
418         }
419         if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
420                 goto out;
421         }
422
423         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
424         if (!key)  {
425                 goto out;
426         }
427
428         if ((principal != NULL) && (strlen(principal) > 0)) {
429                 ret = secrets_store(key, principal, strlen(principal) + 1);
430         } else {
431                 ret = secrets_delete(key);
432         }
433
434  out:
435
436         SAFE_FREE(key);
437         SAFE_FREE(princ_s);
438         SAFE_FREE(unparsed_name);
439
440         if (context) {
441                 krb5_free_context(context);
442         }
443
444         return ret;
445 }
446
447
448 /************************************************************************
449 ************************************************************************/
450
451 int kerberos_kinit_password(const char *principal,
452                             const char *password,
453                             int time_offset,
454                             const char *cache_name)
455 {
456         return kerberos_kinit_password_ext(principal, 
457                                            password, 
458                                            time_offset, 
459                                            0, 
460                                            0,
461                                            cache_name,
462                                            False,
463                                            False,
464                                            0);
465 }
466
467 /************************************************************************
468  Create a string list of available kdc's, possibly searching by sitename.
469  Does DNS queries.
470 ************************************************************************/
471
472 static char *get_kdc_ip_string(char *mem_ctx, const char *realm, struct in_addr primary_ip)
473 {
474         struct ip_service *ip_srv;
475         int count, i;
476         char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
477                                         inet_ntoa(primary_ip));
478
479         if (kdc_str == NULL) {
480                 return NULL;
481         }
482
483         if (!NT_STATUS_IS_OK(get_kdc_list(realm, &ip_srv, &count))) {
484                 DEBUG(10,("get_kdc_ip_string: get_kdc_list failed. Returning %s\n",
485                         kdc_str ));
486                 return kdc_str;
487         }
488
489         for (i = 0; i < count; i++) {
490                 if (ip_equal(ip_srv[i].ip, primary_ip)) {
491                         continue;
492                 }
493                 /* Append to the string - inefficient but not done often. */
494                 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
495                         kdc_str, inet_ntoa(ip_srv[i].ip));
496                 if (!kdc_str) {
497                         SAFE_FREE(ip_srv);
498                         return NULL;
499                 }
500         }
501
502         SAFE_FREE(ip_srv);
503
504         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
505                 kdc_str ));
506
507         return kdc_str;
508 }
509
510 /************************************************************************
511  Create  a specific krb5.conf file in the private directory pointing
512  at a specific kdc for a realm. Keyed off domain name. Sets
513  KRB5_CONFIG environment variable to point to this file. Must be
514  run as root or will fail (which is a good thing :-).
515 ************************************************************************/
516
517 BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain, struct in_addr ip)
518 {
519         char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
520         char *tmpname = NULL;
521         char *fname = NULL;
522         char *file_contents = NULL;
523         char *kdc_ip_string = NULL;
524         size_t flen = 0;
525         ssize_t ret;
526         int fd;
527         char *realm_upper = NULL;
528
529         if (!dname) {
530                 return False;
531         }
532         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
533                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
534                         "failed to create directory %s. Error was %s\n",
535                         dname, strerror(errno) ));
536                 TALLOC_FREE(dname);
537                 return False;
538         }
539
540         tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
541         if (!tmpname) {
542                 TALLOC_FREE(dname);
543                 return False;
544         }
545
546         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
547         if (!fname) {
548                 TALLOC_FREE(dname);
549                 return False;
550         }
551
552         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
553                 fname, realm, domain ));
554
555         realm_upper = talloc_strdup(fname, realm);
556         strupper_m(realm_upper);
557
558         kdc_ip_string = get_kdc_ip_string(dname, realm, ip);
559         if (!kdc_ip_string) {
560                 TALLOC_FREE(dname);
561                 return False;
562         }
563                 
564         file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
565                                 "[realms]\n\t%s = {\n"
566                                 "\t\t%s\t}\n",
567                                 realm_upper, realm_upper, kdc_ip_string);
568
569         if (!file_contents) {
570                 TALLOC_FREE(dname);
571                 return False;
572         }
573
574         flen = strlen(file_contents);
575
576         fd = smb_mkstemp(tmpname);
577         if (fd == -1) {
578                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
579                         " for file %s. Errno %s\n",
580                         tmpname, strerror(errno) ));
581         }
582
583         ret = write(fd, file_contents, flen);
584         if (flen != ret) {
585                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
586                         " returned %d (should be %u). Errno %s\n",
587                         (int)ret, (unsigned int)flen, strerror(errno) ));
588                 unlink(tmpname);
589                 close(fd);
590                 TALLOC_FREE(dname);
591                 return False;
592         }
593         if (close(fd)==-1) {
594                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
595                         " Errno %s\n", strerror(errno) ));
596                 unlink(tmpname);
597                 TALLOC_FREE(dname);
598                 return False;
599         }
600
601         if (rename(tmpname, fname) == -1) {
602                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
603                         "of %s to %s failed. Errno %s\n",
604                         tmpname, fname, strerror(errno) ));
605                 unlink(tmpname);
606                 TALLOC_FREE(dname);
607                 return False;
608         }
609
610         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
611                 "file %s with realm %s KDC = %s\n",
612                 fname, realm_upper, inet_ntoa(ip) ));
613
614         /* Set the environment variable to this file. */
615         setenv("KRB5_CONFIG", fname, 1);
616
617 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
618
619 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
620         /* Insanity, sheer insanity..... */
621
622
623         {
624                 pstring linkpath;
625                 int lret;
626
627                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
628                 linkpath[sizeof(pstring)-1] = '\0';
629
630                 if (lret == 0 || strcmp(linkpath, fname) == 0) {
631                         /* Symlink already exists. */
632                         TALLOC_FREE(dname);
633                         return True;
634                 }
635
636                 /* Try and replace with a symlink. */
637                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
638                         if (errno != EEXIST) {
639                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
640                                         "of %s to %s failed. Errno %s\n",
641                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
642                                 TALLOC_FREE(dname);
643                                 return True; /* Not a fatal error. */
644                         }
645
646                         pstrcpy(linkpath, SYSTEM_KRB5_CONF_PATH);
647                         pstrcat(linkpath, ".saved");
648
649                         /* Yes, this is a race conditon... too bad. */
650                         if (rename(SYSTEM_KRB5_CONF_PATH, linkpath) == -1) {
651                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
652                                         "of %s to %s failed. Errno %s\n",
653                                         SYSTEM_KRB5_CONF_PATH, linkpath,
654                                         strerror(errno) ));
655                                 TALLOC_FREE(dname);
656                                 return True; /* Not a fatal error. */
657                         }
658
659                         if (symlink(fname, "/etc/krb5.conf") == -1) {
660                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
661                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
662                                         fname, strerror(errno) ));
663                                 TALLOC_FREE(dname);
664                                 return True; /* Not a fatal error. */
665                         }
666                 }
667         }
668 #endif
669
670         TALLOC_FREE(dname);
671
672         return True;
673 }
674 #endif