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, struct in_addr primary_ip)
475 struct ip_service *ip_srv;
477 char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
478 inet_ntoa(primary_ip));
480 if (kdc_str == NULL) {
484 if (!NT_STATUS_IS_OK(get_kdc_list(realm, &ip_srv, &count))) {
485 DEBUG(10,("get_kdc_ip_string: get_kdc_list failed. Returning %s\n",
490 for (i = 0; i < count; i++) {
491 if (ip_equal(ip_srv[i].ip, primary_ip)) {
494 /* Append to the string - inefficient but not done often. */
495 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
496 kdc_str, inet_ntoa(ip_srv[i].ip));
505 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
511 /************************************************************************
512 Create a specific krb5.conf file in the private directory pointing
513 at a specific kdc for a realm. Keyed off domain name. Sets
514 KRB5_CONFIG environment variable to point to this file. Must be
515 run as root or will fail (which is a good thing :-).
516 ************************************************************************/
518 BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain, struct in_addr ip)
520 char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
521 char *tmpname = NULL;
523 char *file_contents = NULL;
524 char *kdc_ip_string = NULL;
528 char *realm_upper = NULL;
533 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
534 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
535 "failed to create directory %s. Error was %s\n",
536 dname, strerror(errno) ));
541 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
547 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
553 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
554 fname, realm, domain ));
556 realm_upper = talloc_strdup(fname, realm);
557 strupper_m(realm_upper);
559 kdc_ip_string = get_kdc_ip_string(dname, realm, ip);
560 if (!kdc_ip_string) {
565 file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
566 "[realms]\n\t%s = {\n"
568 realm_upper, realm_upper, kdc_ip_string);
570 if (!file_contents) {
575 flen = strlen(file_contents);
577 fd = smb_mkstemp(tmpname);
579 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
580 " for file %s. Errno %s\n",
581 tmpname, strerror(errno) ));
584 if (fchmod(fd, 0644)==-1) {
585 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
587 tmpname, strerror(errno) ));
594 ret = write(fd, file_contents, flen);
596 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
597 " returned %d (should be %u). Errno %s\n",
598 (int)ret, (unsigned int)flen, strerror(errno) ));
605 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
606 " Errno %s\n", strerror(errno) ));
612 if (rename(tmpname, fname) == -1) {
613 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
614 "of %s to %s failed. Errno %s\n",
615 tmpname, fname, strerror(errno) ));
621 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
622 "file %s with realm %s KDC = %s\n",
623 fname, realm_upper, inet_ntoa(ip) ));
625 /* Set the environment variable to this file. */
626 setenv("KRB5_CONFIG", fname, 1);
628 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
630 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
631 /* Insanity, sheer insanity..... */
633 if (strequal(realm, lp_realm())) {
637 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
638 linkpath[sizeof(pstring)-1] = '\0';
640 if (lret == 0 || strcmp(linkpath, fname) == 0) {
641 /* Symlink already exists. */
646 /* Try and replace with a symlink. */
647 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
648 if (errno != EEXIST) {
649 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
650 "of %s to %s failed. Errno %s\n",
651 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
653 return True; /* Not a fatal error. */
656 pstrcpy(linkpath, SYSTEM_KRB5_CONF_PATH);
657 pstrcat(linkpath, ".saved");
659 /* Yes, this is a race conditon... too bad. */
660 if (rename(SYSTEM_KRB5_CONF_PATH, linkpath) == -1) {
661 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
662 "of %s to %s failed. Errno %s\n",
663 SYSTEM_KRB5_CONF_PATH, linkpath,
666 return True; /* Not a fatal error. */
669 if (symlink(fname, "/etc/krb5.conf") == -1) {
670 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
671 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
672 fname, strerror(errno) ));
674 return True; /* Not a fatal error. */