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
= NULL
;
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_cc_close(ctx
, cc
);
100 krb5_free_context(ctx
);
104 code
= smb_krb5_get_init_creds_opt_alloc(ctx
, &opt
);
106 krb5_cc_close(ctx
, cc
);
107 krb5_free_context(ctx
);
111 krb5_get_init_creds_opt_set_renew_life(opt
, renewable_time
);
112 krb5_get_init_creds_opt_set_forwardable(opt
, True
);
115 krb5_get_init_creds_opt_set_tkt_life(opt
, 60);
118 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
120 code
= krb5_get_init_creds_opt_set_pac_request(ctx
, opt
, (krb5_boolean
)request_pac
);
122 krb5_cc_close(ctx
, cc
);
123 krb5_free_principal(ctx
, me
);
124 krb5_free_context(ctx
);
129 if (add_netbios_addr
) {
130 code
= smb_krb5_gen_netbios_krb5_address(&addr
);
132 krb5_cc_close(ctx
, cc
);
133 krb5_free_principal(ctx
, me
);
134 krb5_free_context(ctx
);
137 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
140 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, CONST_DISCARD(char *,password
),
141 kerb_prompter
, CONST_DISCARD(char *,password
),
144 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
145 smb_krb5_free_addresses(ctx
, addr
);
146 krb5_cc_close(ctx
, cc
);
147 krb5_free_principal(ctx
, me
);
148 krb5_free_context(ctx
);
152 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
154 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
155 smb_krb5_free_addresses(ctx
, addr
);
156 krb5_free_cred_contents(ctx
, &my_creds
);
157 krb5_cc_close(ctx
, cc
);
158 krb5_free_principal(ctx
, me
);
159 krb5_free_context(ctx
);
163 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
164 krb5_cc_close(ctx
, cc
);
165 smb_krb5_free_addresses(ctx
, addr
);
166 krb5_free_cred_contents(ctx
, &my_creds
);
167 krb5_free_principal(ctx
, me
);
168 krb5_free_context(ctx
);
173 *expire_time
= (time_t) my_creds
.times
.endtime
;
176 if (renew_till_time
) {
177 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
180 krb5_cc_close(ctx
, cc
);
181 smb_krb5_free_addresses(ctx
, addr
);
182 krb5_free_cred_contents(ctx
, &my_creds
);
183 krb5_free_principal(ctx
, me
);
184 krb5_free_context(ctx
);
191 /* run kinit to setup our ccache */
192 int ads_kinit_password(ADS_STRUCT
*ads
)
196 const char *account_name
;
200 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
201 account_name
= lp_workgroup();
203 /* always use the sAMAccountName for security = domain */
204 /* global_myname()$@REA.LM */
205 if ( lp_security() == SEC_DOMAIN
) {
206 fstr_sprintf( acct_name
, "%s$", global_myname() );
207 account_name
= acct_name
;
210 /* This looks like host/global_myname()@REA.LM */
211 account_name
= ads
->auth
.user_name
;
214 if (asprintf(&s
, "%s@%s", account_name
, ads
->auth
.realm
) == -1) {
215 return KRB5_CC_NOMEM
;
218 if (!ads
->auth
.password
) {
220 return KRB5_LIBOS_CANTREADPWD
;
223 ret
= kerberos_kinit_password_ext(s
, ads
->auth
.password
, ads
->auth
.time_offset
,
224 &ads
->auth
.tgt_expire
, NULL
, NULL
, False
, False
, ads
->auth
.renewable
);
227 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
228 s
, error_message(ret
)));
234 int ads_kdestroy(const char *cc_name
)
236 krb5_error_code code
;
237 krb5_context ctx
= NULL
;
238 krb5_ccache cc
= NULL
;
240 initialize_krb5_error_table();
241 if ((code
= krb5_init_context (&ctx
))) {
242 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
243 error_message(code
)));
248 if ((code
= krb5_cc_default(ctx
, &cc
))) {
249 krb5_free_context(ctx
);
253 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
254 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
255 error_message(code
)));
256 krb5_free_context(ctx
);
261 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
262 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
263 error_message(code
)));
266 krb5_free_context (ctx
);
270 /************************************************************************
271 Routine to fetch the salting principal for a service. Active
272 Directory may use a non-obvious principal name to generate the salt
273 when it determines the key to use for encrypting tickets for a service,
274 and hopefully we detected that when we joined the domain.
275 ************************************************************************/
277 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
282 asprintf(&key
, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL
, service
, enctype
);
286 ret
= (char *)secrets_fetch(key
, NULL
);
291 /************************************************************************
292 Return the standard DES salt key
293 ************************************************************************/
295 char* kerberos_standard_des_salt( void )
299 fstr_sprintf( salt
, "host/%s.%s@", global_myname(), lp_realm() );
301 fstrcat( salt
, lp_realm() );
303 return SMB_STRDUP( salt
);
306 /************************************************************************
307 ************************************************************************/
309 static char* des_salt_key( void )
313 asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
, lp_realm());
318 /************************************************************************
319 ************************************************************************/
321 BOOL
kerberos_secrets_store_des_salt( const char* salt
)
326 if ( (key
= des_salt_key()) == NULL
) {
327 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
332 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
333 secrets_delete( key
);
337 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
339 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
346 /************************************************************************
347 ************************************************************************/
349 char* kerberos_secrets_fetch_des_salt( void )
353 if ( (key
= des_salt_key()) == NULL
) {
354 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
358 salt
= (char*)secrets_fetch( key
, NULL
);
365 /************************************************************************
366 Routine to get the default realm from the kerberos credentials cache.
367 Caller must free if the return value is not NULL.
368 ************************************************************************/
370 char *kerberos_get_default_realm_from_ccache( void )
373 krb5_context ctx
= NULL
;
374 krb5_ccache cc
= NULL
;
375 krb5_principal princ
= NULL
;
377 initialize_krb5_error_table();
378 if (krb5_init_context(&ctx
)) {
382 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
383 "Trying to read krb5 cache: %s\n",
384 krb5_cc_default_name(ctx
)));
385 if (krb5_cc_default(ctx
, &cc
)) {
386 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
387 "failed to read default cache\n"));
390 if (krb5_cc_get_principal(ctx
, cc
, &princ
)) {
391 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
392 "failed to get default principal\n"));
396 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
397 realm
= SMB_STRDUP(krb5_principal_get_realm(ctx
, princ
));
398 #elif defined(HAVE_KRB5_PRINC_REALM)
400 krb5_data
*realm_data
= krb5_princ_realm(ctx
, princ
);
401 realm
= SMB_STRNDUP(realm_data
->data
, realm_data
->length
);
408 krb5_free_principal(ctx
, princ
);
411 krb5_cc_close(ctx
, cc
);
414 krb5_free_context(ctx
);
421 /************************************************************************
422 Routine to get the salting principal for this service. This is
423 maintained for backwards compatibilty with releases prior to 3.0.24.
424 Since we store the salting principal string only at join, we may have
425 to look for the older tdb keys. Caller must free if return is not null.
426 ************************************************************************/
428 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
429 krb5_principal host_princ
,
432 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
433 krb5_principal ret_princ
= NULL
;
435 /* lookup new key first */
437 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
439 /* look under the old key. If this fails, just use the standard key */
441 if (smb_krb5_unparse_name(context
, host_princ
, &unparsed_name
) != 0) {
442 return (krb5_principal
)NULL
;
444 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
445 /* fall back to host/machine.realm@REALM */
446 salt_princ_s
= kerberos_standard_des_salt();
450 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
454 SAFE_FREE(unparsed_name
);
455 SAFE_FREE(salt_princ_s
);
460 /************************************************************************
461 Routine to set the salting principal for this service. Active
462 Directory may use a non-obvious principal name to generate the salt
463 when it determines the key to use for encrypting tickets for a service,
464 and hopefully we detected that when we joined the domain.
465 Setting principal to NULL deletes this entry.
466 ************************************************************************/
468 BOOL
kerberos_secrets_store_salting_principal(const char *service
,
470 const char *principal
)
474 krb5_context context
= NULL
;
475 krb5_principal princ
= NULL
;
476 char *princ_s
= NULL
;
477 char *unparsed_name
= NULL
;
479 krb5_init_context(&context
);
483 if (strchr_m(service
, '@')) {
484 asprintf(&princ_s
, "%s", service
);
486 asprintf(&princ_s
, "%s@%s", service
, lp_realm());
489 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
493 if (smb_krb5_unparse_name(context
, princ
, &unparsed_name
) != 0) {
497 asprintf(&key
, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
);
502 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
503 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
505 ret
= secrets_delete(key
);
512 SAFE_FREE(unparsed_name
);
515 krb5_free_principal(context
, princ
);
519 krb5_free_context(context
);
526 /************************************************************************
527 ************************************************************************/
529 int kerberos_kinit_password(const char *principal
,
530 const char *password
,
532 const char *cache_name
)
534 return kerberos_kinit_password_ext(principal
,
545 /************************************************************************
546 Create a string list of available kdc's, possibly searching by sitename.
548 ************************************************************************/
550 static char *get_kdc_ip_string(char *mem_ctx
, const char *realm
, const char *sitename
, struct in_addr primary_ip
)
553 struct ip_service
*ip_srv_site
= NULL
;
554 struct ip_service
*ip_srv_nonsite
;
557 char *kdc_str
= talloc_asprintf(mem_ctx
, "\tkdc = %s\n",
558 inet_ntoa(primary_ip
));
560 if (kdc_str
== NULL
) {
564 /* Get the KDC's only in this site. */
568 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
570 for (i
= 0; i
< count_site
; i
++) {
571 if (ip_equal(ip_srv_site
[i
].ip
, primary_ip
)) {
574 /* Append to the string - inefficient but not done often. */
575 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
576 kdc_str
, inet_ntoa(ip_srv_site
[i
].ip
));
578 SAFE_FREE(ip_srv_site
);
586 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
588 for (i
= 0; i
< count_nonsite
; i
++) {
591 if (ip_equal(ip_srv_nonsite
[i
].ip
, primary_ip
)) {
595 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
596 for (j
= 0; j
< count_site
; j
++) {
597 if (ip_equal(ip_srv_nonsite
[i
].ip
, ip_srv_site
[j
].ip
)) {
600 /* As the lists are sorted we can break early if nonsite > site. */
601 if (ip_service_compare(&ip_srv_nonsite
[i
], &ip_srv_site
[j
]) > 0) {
609 /* Append to the string - inefficient but not done often. */
610 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
611 kdc_str
, inet_ntoa(ip_srv_nonsite
[i
].ip
));
613 SAFE_FREE(ip_srv_site
);
614 SAFE_FREE(ip_srv_nonsite
);
620 SAFE_FREE(ip_srv_site
);
621 SAFE_FREE(ip_srv_nonsite
);
623 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
629 /************************************************************************
630 Create a specific krb5.conf file in the private directory pointing
631 at a specific kdc for a realm. Keyed off domain name. Sets
632 KRB5_CONFIG environment variable to point to this file. Must be
633 run as root or will fail (which is a good thing :-).
634 ************************************************************************/
636 BOOL
create_local_private_krb5_conf_for_domain(const char *realm
, const char *domain
,
637 const char *sitename
, struct in_addr ip
)
639 char *dname
= talloc_asprintf(NULL
, "%s/smb_krb5", lp_lockdir());
640 char *tmpname
= NULL
;
642 char *file_contents
= NULL
;
643 char *kdc_ip_string
= NULL
;
647 char *realm_upper
= NULL
;
652 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
653 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
654 "failed to create directory %s. Error was %s\n",
655 dname
, strerror(errno
) ));
660 tmpname
= talloc_asprintf(dname
, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
666 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
672 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
673 fname
, realm
, domain
));
675 realm_upper
= talloc_strdup(fname
, realm
);
676 strupper_m(realm_upper
);
678 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, ip
);
679 if (!kdc_ip_string
) {
684 file_contents
= talloc_asprintf(fname
,
685 "[libdefaults]\n\tdefault_realm = %s\n"
686 "default_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
687 "default_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
688 "preferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
689 "[realms]\n\t%s = {\n"
691 realm_upper
, realm_upper
, kdc_ip_string
);
693 if (!file_contents
) {
698 flen
= strlen(file_contents
);
700 fd
= smb_mkstemp(tmpname
);
702 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
703 " for file %s. Errno %s\n",
704 tmpname
, strerror(errno
) ));
707 if (fchmod(fd
, 0644)==-1) {
708 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
710 tmpname
, strerror(errno
) ));
717 ret
= write(fd
, file_contents
, flen
);
719 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
720 " returned %d (should be %u). Errno %s\n",
721 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
728 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
729 " Errno %s\n", strerror(errno
) ));
735 if (rename(tmpname
, fname
) == -1) {
736 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
737 "of %s to %s failed. Errno %s\n",
738 tmpname
, fname
, strerror(errno
) ));
744 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
745 "file %s with realm %s KDC = %s\n",
746 fname
, realm_upper
, inet_ntoa(ip
) ));
748 /* Set the environment variable to this file. */
749 setenv("KRB5_CONFIG", fname
, 1);
751 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
753 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
754 /* Insanity, sheer insanity..... */
756 if (strequal(realm
, lp_realm())) {
760 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
, sizeof(linkpath
)-1);
761 linkpath
[sizeof(pstring
)-1] = '\0';
763 if (lret
== 0 || strcmp(linkpath
, fname
) == 0) {
764 /* Symlink already exists. */
769 /* Try and replace with a symlink. */
770 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
771 if (errno
!= EEXIST
) {
772 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
773 "of %s to %s failed. Errno %s\n",
774 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
776 return True
; /* Not a fatal error. */
779 pstrcpy(linkpath
, SYSTEM_KRB5_CONF_PATH
);
780 pstrcat(linkpath
, ".saved");
782 /* Yes, this is a race conditon... too bad. */
783 if (rename(SYSTEM_KRB5_CONF_PATH
, linkpath
) == -1) {
784 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
785 "of %s to %s failed. Errno %s\n",
786 SYSTEM_KRB5_CONF_PATH
, linkpath
,
789 return True
; /* Not a fatal error. */
792 if (symlink(fname
, "/etc/krb5.conf") == -1) {
793 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
794 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
795 fname
, strerror(errno
) ));
797 return True
; /* Not a fatal error. */