r18201: Make explicit what's going on here.
[Samba/nascimento.git] / source3 / libads / kerberos.c
blob40c3019a3195fb5a5096fb4922bb31280a161764
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.
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.
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.
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.
25 #include "includes.h"
27 #ifdef HAVE_KRB5
29 #define LIBADS_CCACHE_NAME "MEMORY:libads"
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 ...
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[])
43 if (num_prompts == 0) return 0;
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;
55 return 0;
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
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)
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;
81 initialize_krb5_error_table();
82 if ((code = krb5_init_context(&ctx)))
83 return code;
85 if (time_offset != 0) {
86 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
89 DEBUG(10,("kerberos_kinit_password: using %s as ccache\n",
90 cache_name ? cache_name: krb5_cc_default_name(ctx)));
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;
97 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
98 krb5_free_context(ctx);
99 return code;
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);
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;
114 #endif
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;
124 krb5_get_init_creds_opt_set_address_list(&opt, addr->addrs);
127 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
128 kerb_prompter, NULL, 0, NULL, &opt)))
130 smb_krb5_free_addresses(ctx, addr);
131 krb5_free_principal(ctx, me);
132 krb5_free_context(ctx);
133 return code;
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;
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;
153 if (expire_time) {
154 *expire_time = (time_t) my_creds.times.endtime;
157 if (renew_till_time) {
158 *renew_till_time = (time_t) my_creds.times.renew_till;
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);
167 return 0;
172 /* run kinit to setup our ccache */
173 int ads_kinit_password(ADS_STRUCT *ads)
175 char *s;
176 int ret;
177 const char *account_name;
178 fstring acct_name;
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;
190 else
191 /* This looks like host/global_myname()@REA.LM */
192 account_name = ads->auth.user_name;
195 if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
196 return KRB5_CC_NOMEM;
199 if (!ads->auth.password) {
200 SAFE_FREE(s);
201 return KRB5_LIBOS_CANTREADPWD;
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);
207 if (ret) {
208 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
209 s, error_message(ret)));
211 SAFE_FREE(s);
212 return ret;
215 int ads_kdestroy(const char *cc_name)
217 krb5_error_code code;
218 krb5_context ctx = NULL;
219 krb5_ccache cc = NULL;
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;
228 if (!cc_name) {
229 if ((code = krb5_cc_default(ctx, &cc))) {
230 krb5_free_context(ctx);
231 return code;
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;
242 if ((code = krb5_cc_destroy (ctx, cc))) {
243 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
244 error_message(code)));
247 krb5_free_context (ctx);
248 return code;
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 ************************************************************************/
258 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
260 char *key = NULL;
261 char *ret = NULL;
263 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
264 if (!key) {
265 return NULL;
267 ret = (char *)secrets_fetch(key, NULL);
268 SAFE_FREE(key);
269 return ret;
272 /************************************************************************
273 Return the standard DES salt key
274 ************************************************************************/
276 char* kerberos_standard_des_salt( void )
278 fstring salt;
280 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
281 strlower_m( salt );
282 fstrcat( salt, lp_realm() );
284 return SMB_STRDUP( salt );
287 /************************************************************************
288 ************************************************************************/
290 static char* des_salt_key( void )
292 char *key;
294 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
296 return key;
299 /************************************************************************
300 ************************************************************************/
302 BOOL kerberos_secrets_store_des_salt( const char* salt )
304 char* key;
305 BOOL ret;
307 if ( (key = des_salt_key()) == NULL ) {
308 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
309 return False;
312 if ( !salt ) {
313 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
314 secrets_delete( key );
315 return True;
318 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
320 ret = secrets_store( key, salt, strlen(salt)+1 );
322 SAFE_FREE( key );
324 return ret;
327 /************************************************************************
328 ************************************************************************/
330 char* kerberos_secrets_fetch_des_salt( void )
332 char *salt, *key;
334 if ( (key = des_salt_key()) == NULL ) {
335 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
336 return False;
339 salt = (char*)secrets_fetch( key, NULL );
341 SAFE_FREE( key );
343 return salt;
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 ************************************************************************/
354 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
355 krb5_principal host_princ,
356 int enctype)
358 char *unparsed_name = NULL, *salt_princ_s = NULL;
359 krb5_principal ret_princ = NULL;
361 /* lookup new key first */
363 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
365 /* look under the old key. If this fails, just use the standard key */
367 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
368 return (krb5_principal)NULL;
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();
376 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
377 ret_princ = NULL;
380 SAFE_FREE(unparsed_name);
381 SAFE_FREE(salt_princ_s);
383 return ret_princ;
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 ************************************************************************/
394 BOOL kerberos_secrets_store_salting_principal(const char *service,
395 int enctype,
396 const char *principal)
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;
405 krb5_init_context(&context);
406 if (!context) {
407 return False;
409 if (strchr_m(service, '@')) {
410 asprintf(&princ_s, "%s", service);
411 } else {
412 asprintf(&princ_s, "%s@%s", service, lp_realm());
415 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
416 goto out;
419 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
420 goto out;
423 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
424 if (!key) {
425 goto out;
428 if ((principal != NULL) && (strlen(principal) > 0)) {
429 ret = secrets_store(key, principal, strlen(principal) + 1);
430 } else {
431 ret = secrets_delete(key);
434 out:
436 SAFE_FREE(key);
437 SAFE_FREE(princ_s);
438 SAFE_FREE(unparsed_name);
440 if (context) {
441 krb5_free_context(context);
444 return ret;
448 /************************************************************************
449 ************************************************************************/
451 int kerberos_kinit_password(const char *principal,
452 const char *password,
453 int time_offset,
454 const char *cache_name)
456 return kerberos_kinit_password_ext(principal,
457 password,
458 time_offset,
461 cache_name,
462 False,
463 False,
467 /************************************************************************
468 Create a string list of available kdc's, possibly searching by sitename.
469 Does DNS queries.
470 ************************************************************************/
472 static char *get_kdc_ip_string(char *mem_ctx, const char *realm, struct in_addr primary_ip)
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));
479 if (kdc_str == NULL) {
480 return NULL;
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;
489 for (i = 0; i < count; i++) {
490 if (ip_equal(ip_srv[i].ip, primary_ip)) {
491 continue;
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;
502 SAFE_FREE(ip_srv);
504 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
505 kdc_str ));
507 return kdc_str;
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 ************************************************************************/
517 BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain, struct in_addr ip)
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;
529 if (!dname) {
530 return False;
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;
540 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
541 if (!tmpname) {
542 TALLOC_FREE(dname);
543 return False;
546 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
547 if (!fname) {
548 TALLOC_FREE(dname);
549 return False;
552 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
553 fname, realm, domain ));
555 realm_upper = talloc_strdup(fname, realm);
556 strupper_m(realm_upper);
558 kdc_ip_string = get_kdc_ip_string(dname, realm, ip);
559 if (!kdc_ip_string) {
560 TALLOC_FREE(dname);
561 return False;
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);
569 if (!file_contents) {
570 TALLOC_FREE(dname);
571 return False;
574 flen = strlen(file_contents);
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) ));
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;
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;
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;
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) ));
614 /* Set the environment variable to this file. */
615 setenv("KRB5_CONFIG", fname, 1);
617 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
619 /* Insanity, sheer insanity..... */
621 if (symlink(fname, "/etc/krb5.conf") == -1) {
622 if (errno != EEXIST) {
623 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
624 "of %s to /etc/krb5.conf failed. Errno %s\n",
625 fname, strerror(errno) ));
626 TALLOC_FREE(dname);
627 return True; /* Not a fatal error. */
630 /* Yes, this is a race conditon... too bad. */
631 if (unlink("/etc/krb5.conf") == -1) {
632 DEBUG(0,("create_local_private_krb5_conf_for_domain: unlink "
633 "of /etc/krb5.conf failed. Errno %s\n",
634 strerror(errno) ));
635 TALLOC_FREE(dname);
636 return True; /* Not a fatal error. */
638 if (symlink(fname, "/etc/krb5.conf") == -1) {
639 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
640 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
641 fname, strerror(errno) ));
642 TALLOC_FREE(dname);
643 return True; /* Not a fatal error. */
646 #endif
648 TALLOC_FREE(dname);
650 return True;
652 #endif