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.
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,
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) {
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);
52 prompts[0].reply->length = 0;
59 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
60 place in default cache location.
63 int kerberos_kinit_password_ext(const char *principal,
67 time_t *renew_till_time,
68 const char *cache_name,
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;
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)))
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 and config [%s]\n",
90 cache_name ? cache_name: krb5_cc_default_name(ctx),
91 getenv("KRB5_CONFIG")));
93 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
94 krb5_free_context(ctx);
98 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
99 krb5_free_context(ctx);
103 krb5_get_init_creds_opt_init(&opt);
104 krb5_get_init_creds_opt_set_renew_life(&opt, renewable_time);
105 krb5_get_init_creds_opt_set_forwardable(&opt, 1);
108 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
109 code = krb5_get_init_creds_opt_set_pac_request(ctx, &opt, True);
111 krb5_free_principal(ctx, me);
112 krb5_free_context(ctx);
118 if (add_netbios_addr) {
119 code = smb_krb5_gen_netbios_krb5_address(&addr);
121 krb5_free_principal(ctx, me);
122 krb5_free_context(ctx);
125 krb5_get_init_creds_opt_set_address_list(&opt, addr->addrs);
128 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
129 kerb_prompter, NULL, 0, NULL, &opt)))
131 smb_krb5_free_addresses(ctx, addr);
132 krb5_free_principal(ctx, me);
133 krb5_free_context(ctx);
137 if ((code = krb5_cc_initialize(ctx, cc, me))) {
138 smb_krb5_free_addresses(ctx, addr);
139 krb5_free_cred_contents(ctx, &my_creds);
140 krb5_free_principal(ctx, me);
141 krb5_free_context(ctx);
145 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
146 krb5_cc_close(ctx, cc);
147 smb_krb5_free_addresses(ctx, addr);
148 krb5_free_cred_contents(ctx, &my_creds);
149 krb5_free_principal(ctx, me);
150 krb5_free_context(ctx);
155 *expire_time = (time_t) my_creds.times.endtime;
158 if (renew_till_time) {
159 *renew_till_time = (time_t) my_creds.times.renew_till;
162 krb5_cc_close(ctx, cc);
163 smb_krb5_free_addresses(ctx, addr);
164 krb5_free_cred_contents(ctx, &my_creds);
165 krb5_free_principal(ctx, me);
166 krb5_free_context(ctx);
173 /* run kinit to setup our ccache */
174 int ads_kinit_password(ADS_STRUCT *ads)
178 const char *account_name;
182 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
183 account_name = lp_workgroup();
185 /* always use the sAMAccountName for security = domain */
186 /* global_myname()$@REA.LM */
187 if ( lp_security() == SEC_DOMAIN ) {
188 fstr_sprintf( acct_name, "%s$", global_myname() );
189 account_name = acct_name;
192 /* This looks like host/global_myname()@REA.LM */
193 account_name = ads->auth.user_name;
196 if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
197 return KRB5_CC_NOMEM;
200 if (!ads->auth.password) {
202 return KRB5_LIBOS_CANTREADPWD;
205 ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
206 &ads->auth.expire, NULL, NULL, False, False, ads->auth.renewable);
209 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
210 s, error_message(ret)));
216 int ads_kdestroy(const char *cc_name)
218 krb5_error_code code;
219 krb5_context ctx = NULL;
220 krb5_ccache cc = NULL;
222 initialize_krb5_error_table();
223 if ((code = krb5_init_context (&ctx))) {
224 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
225 error_message(code)));
230 if ((code = krb5_cc_default(ctx, &cc))) {
231 krb5_free_context(ctx);
235 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
236 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
237 error_message(code)));
238 krb5_free_context(ctx);
243 if ((code = krb5_cc_destroy (ctx, cc))) {
244 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
245 error_message(code)));
248 krb5_free_context (ctx);
252 /************************************************************************
253 Routine to fetch the salting principal for a service. Active
254 Directory may use a non-obvious principal name to generate the salt
255 when it determines the key to use for encrypting tickets for a service,
256 and hopefully we detected that when we joined the domain.
257 ************************************************************************/
259 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
264 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
268 ret = (char *)secrets_fetch(key, NULL);
273 /************************************************************************
274 Return the standard DES salt key
275 ************************************************************************/
277 char* kerberos_standard_des_salt( void )
281 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
283 fstrcat( salt, lp_realm() );
285 return SMB_STRDUP( salt );
288 /************************************************************************
289 ************************************************************************/
291 static char* des_salt_key( void )
295 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
300 /************************************************************************
301 ************************************************************************/
303 BOOL kerberos_secrets_store_des_salt( const char* salt )
308 if ( (key = des_salt_key()) == NULL ) {
309 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
314 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
315 secrets_delete( key );
319 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
321 ret = secrets_store( key, salt, strlen(salt)+1 );
328 /************************************************************************
329 ************************************************************************/
331 char* kerberos_secrets_fetch_des_salt( void )
335 if ( (key = des_salt_key()) == NULL ) {
336 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
340 salt = (char*)secrets_fetch( key, NULL );
348 /************************************************************************
349 Routine to get the salting principal for this service. This is
350 maintained for backwards compatibilty with releases prior to 3.0.24.
351 Since we store the salting principal string only at join, we may have
352 to look for the older tdb keys. Caller must free if return is not null.
353 ************************************************************************/
355 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
356 krb5_principal host_princ,
359 char *unparsed_name = NULL, *salt_princ_s = NULL;
360 krb5_principal ret_princ = NULL;
362 /* lookup new key first */
364 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
366 /* look under the old key. If this fails, just use the standard key */
368 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
369 return (krb5_principal)NULL;
371 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
372 /* fall back to host/machine.realm@REALM */
373 salt_princ_s = kerberos_standard_des_salt();
377 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
381 SAFE_FREE(unparsed_name);
382 SAFE_FREE(salt_princ_s);
387 /************************************************************************
388 Routine to set the salting principal for this service. Active
389 Directory may use a non-obvious principal name to generate the salt
390 when it determines the key to use for encrypting tickets for a service,
391 and hopefully we detected that when we joined the domain.
392 Setting principal to NULL deletes this entry.
393 ************************************************************************/
395 BOOL kerberos_secrets_store_salting_principal(const char *service,
397 const char *principal)
401 krb5_context context = NULL;
402 krb5_principal princ = NULL;
403 char *princ_s = NULL;
404 char *unparsed_name = NULL;
406 krb5_init_context(&context);
410 if (strchr_m(service, '@')) {
411 asprintf(&princ_s, "%s", service);
413 asprintf(&princ_s, "%s@%s", service, lp_realm());
416 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
420 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
424 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
429 if ((principal != NULL) && (strlen(principal) > 0)) {
430 ret = secrets_store(key, principal, strlen(principal) + 1);
432 ret = secrets_delete(key);
439 SAFE_FREE(unparsed_name);
442 krb5_free_context(context);
449 /************************************************************************
450 ************************************************************************/
452 int kerberos_kinit_password(const char *principal,
453 const char *password,
455 const char *cache_name)
457 return kerberos_kinit_password_ext(principal,
468 /************************************************************************
469 Create a string list of available kdc's, possibly searching by sitename.
471 ************************************************************************/
473 static char *get_kdc_ip_string(char *mem_ctx, const char *realm, const char *sitename, struct in_addr primary_ip)
475 struct ip_service *ip_srv_site;
476 struct ip_service *ip_srv_nonsite;
477 int count_site, count_nonsite, i;
478 char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
479 inet_ntoa(primary_ip));
481 if (kdc_str == NULL) {
485 /* Get the KDC's only in this site. */
489 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
491 for (i = 0; i < count_site; i++) {
492 if (ip_equal(ip_srv_site[i].ip, primary_ip)) {
495 /* Append to the string - inefficient but not done often. */
496 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
497 kdc_str, inet_ntoa(ip_srv_site[i].ip));
499 SAFE_FREE(ip_srv_site);
507 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
509 for (i = 0; i < count_nonsite; i++) {
512 if (ip_equal(ip_srv_nonsite[i].ip, primary_ip)) {
516 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
517 for (j = 0; j < count_site; j++) {
518 if (ip_equal(ip_srv_nonsite[i].ip, ip_srv_site[j].ip)) {
521 /* As the lists are sorted we can break early if nonsite > site. */
522 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
530 /* Append to the string - inefficient but not done often. */
531 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
532 kdc_str, inet_ntoa(ip_srv_nonsite[i].ip));
534 SAFE_FREE(ip_srv_site);
535 SAFE_FREE(ip_srv_nonsite);
541 SAFE_FREE(ip_srv_site);
542 SAFE_FREE(ip_srv_nonsite);
544 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
550 /************************************************************************
551 Create a specific krb5.conf file in the private directory pointing
552 at a specific kdc for a realm. Keyed off domain name. Sets
553 KRB5_CONFIG environment variable to point to this file. Must be
554 run as root or will fail (which is a good thing :-).
555 ************************************************************************/
557 BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain,
558 const char *sitename, struct in_addr ip)
560 char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
561 char *tmpname = NULL;
563 char *file_contents = NULL;
564 char *kdc_ip_string = NULL;
568 char *realm_upper = NULL;
573 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
574 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
575 "failed to create directory %s. Error was %s\n",
576 dname, strerror(errno) ));
581 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
587 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
593 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
594 fname, realm, domain ));
596 realm_upper = talloc_strdup(fname, realm);
597 strupper_m(realm_upper);
599 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, ip);
600 if (!kdc_ip_string) {
605 file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
606 "[realms]\n\t%s = {\n"
608 realm_upper, realm_upper, kdc_ip_string);
610 if (!file_contents) {
615 flen = strlen(file_contents);
617 fd = smb_mkstemp(tmpname);
619 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
620 " for file %s. Errno %s\n",
621 tmpname, strerror(errno) ));
624 if (fchmod(fd, 0644)==-1) {
625 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
627 tmpname, strerror(errno) ));
634 ret = write(fd, file_contents, flen);
636 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
637 " returned %d (should be %u). Errno %s\n",
638 (int)ret, (unsigned int)flen, strerror(errno) ));
645 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
646 " Errno %s\n", strerror(errno) ));
652 if (rename(tmpname, fname) == -1) {
653 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
654 "of %s to %s failed. Errno %s\n",
655 tmpname, fname, strerror(errno) ));
661 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
662 "file %s with realm %s KDC = %s\n",
663 fname, realm_upper, inet_ntoa(ip) ));
665 /* Set the environment variable to this file. */
666 setenv("KRB5_CONFIG", fname, 1);
668 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
670 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
671 /* Insanity, sheer insanity..... */
673 if (strequal(realm, lp_realm())) {
677 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
678 linkpath[sizeof(pstring)-1] = '\0';
680 if (lret == 0 || strcmp(linkpath, fname) == 0) {
681 /* Symlink already exists. */
686 /* Try and replace with a symlink. */
687 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
688 if (errno != EEXIST) {
689 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
690 "of %s to %s failed. Errno %s\n",
691 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
693 return True; /* Not a fatal error. */
696 pstrcpy(linkpath, SYSTEM_KRB5_CONF_PATH);
697 pstrcat(linkpath, ".saved");
699 /* Yes, this is a race conditon... too bad. */
700 if (rename(SYSTEM_KRB5_CONF_PATH, linkpath) == -1) {
701 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
702 "of %s to %s failed. Errno %s\n",
703 SYSTEM_KRB5_CONF_PATH, linkpath,
706 return True; /* Not a fatal error. */
709 if (symlink(fname, "/etc/krb5.conf") == -1) {
710 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
711 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
712 fname, strerror(errno) ));
714 return True; /* Not a fatal error. */