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
, data
, prompts
[0].reply
->length
-1);
49 prompts
[0].reply
->length
= strlen(prompts
[0].reply
->data
);
51 prompts
[0].reply
->length
= 0;
58 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
59 place in default cache location.
62 int kerberos_kinit_password_ext(const char *principal
,
66 time_t *renew_till_time
,
67 const char *cache_name
,
69 BOOL add_netbios_addr
,
70 time_t renewable_time
)
72 krb5_context ctx
= NULL
;
73 krb5_error_code code
= 0;
74 krb5_ccache cc
= NULL
;
77 krb5_get_init_creds_opt opt
;
78 smb_krb5_addresses
*addr
= NULL
;
80 initialize_krb5_error_table();
81 if ((code
= krb5_init_context(&ctx
)))
84 if (time_offset
!= 0) {
85 krb5_set_real_time(ctx
, time(NULL
) + time_offset
, 0);
88 DEBUG(10,("kerberos_kinit_password: using %s as ccache\n",
89 cache_name
? cache_name
: krb5_cc_default_name(ctx
)));
91 if ((code
= krb5_cc_resolve(ctx
, cache_name
? cache_name
: krb5_cc_default_name(ctx
), &cc
))) {
92 krb5_free_context(ctx
);
96 if ((code
= smb_krb5_parse_name(ctx
, principal
, &me
))) {
97 krb5_free_context(ctx
);
101 krb5_get_init_creds_opt_init(&opt
);
102 krb5_get_init_creds_opt_set_renew_life(&opt
, renewable_time
);
103 krb5_get_init_creds_opt_set_forwardable(&opt
, 1);
106 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
107 code
= krb5_get_init_creds_opt_set_pac_request(ctx
, &opt
, True
);
109 krb5_free_principal(ctx
, me
);
110 krb5_free_context(ctx
);
116 if (add_netbios_addr
) {
117 code
= smb_krb5_gen_netbios_krb5_address(&addr
);
119 krb5_free_principal(ctx
, me
);
120 krb5_free_context(ctx
);
123 krb5_get_init_creds_opt_set_address_list(&opt
, addr
->addrs
);
126 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, CONST_DISCARD(char *,password
),
127 kerb_prompter
, NULL
, 0, NULL
, &opt
)))
129 smb_krb5_free_addresses(ctx
, addr
);
130 krb5_free_principal(ctx
, me
);
131 krb5_free_context(ctx
);
135 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
136 smb_krb5_free_addresses(ctx
, addr
);
137 krb5_free_cred_contents(ctx
, &my_creds
);
138 krb5_free_principal(ctx
, me
);
139 krb5_free_context(ctx
);
143 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
144 krb5_cc_close(ctx
, cc
);
145 smb_krb5_free_addresses(ctx
, addr
);
146 krb5_free_cred_contents(ctx
, &my_creds
);
147 krb5_free_principal(ctx
, me
);
148 krb5_free_context(ctx
);
153 *expire_time
= (time_t) my_creds
.times
.endtime
;
156 if (renew_till_time
) {
157 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
160 krb5_cc_close(ctx
, cc
);
161 smb_krb5_free_addresses(ctx
, addr
);
162 krb5_free_cred_contents(ctx
, &my_creds
);
163 krb5_free_principal(ctx
, me
);
164 krb5_free_context(ctx
);
171 /* run kinit to setup our ccache */
172 int ads_kinit_password(ADS_STRUCT
*ads
)
176 const char *account_name
;
180 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
181 account_name
= lp_workgroup();
183 /* always use the sAMAccountName for security = domain */
184 /* global_myname()$@REA.LM */
185 if ( lp_security() == SEC_DOMAIN
) {
186 fstr_sprintf( acct_name
, "%s$", global_myname() );
187 account_name
= acct_name
;
190 /* This looks like host/global_myname()@REA.LM */
191 account_name
= ads
->auth
.user_name
;
194 if (asprintf(&s
, "%s@%s", account_name
, ads
->auth
.realm
) == -1) {
195 return KRB5_CC_NOMEM
;
198 if (!ads
->auth
.password
) {
200 return KRB5_LIBOS_CANTREADPWD
;
203 ret
= kerberos_kinit_password_ext(s
, ads
->auth
.password
, ads
->auth
.time_offset
,
204 &ads
->auth
.expire
, NULL
, NULL
, False
, False
, ads
->auth
.renewable
);
207 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
208 s
, error_message(ret
)));
214 int ads_kdestroy(const char *cc_name
)
216 krb5_error_code code
;
217 krb5_context ctx
= NULL
;
218 krb5_ccache cc
= NULL
;
220 initialize_krb5_error_table();
221 if ((code
= krb5_init_context (&ctx
))) {
222 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
223 error_message(code
)));
228 if ((code
= krb5_cc_default(ctx
, &cc
))) {
229 krb5_free_context(ctx
);
233 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
234 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
235 error_message(code
)));
236 krb5_free_context(ctx
);
241 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
242 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
243 error_message(code
)));
246 krb5_free_context (ctx
);
250 /************************************************************************
251 Routine to fetch the salting principal for a service. Active
252 Directory may use a non-obvious principal name to generate the salt
253 when it determines the key to use for encrypting tickets for a service,
254 and hopefully we detected that when we joined the domain.
255 ************************************************************************/
257 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
262 asprintf(&key
, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL
, service
, enctype
);
266 ret
= (char *)secrets_fetch(key
, NULL
);
271 /************************************************************************
272 Return the standard DES salt key
273 ************************************************************************/
275 char* kerberos_standard_des_salt( void )
279 fstr_sprintf( salt
, "host/%s.%s@", global_myname(), lp_realm() );
281 fstrcat( salt
, lp_realm() );
283 return SMB_STRDUP( salt
);
286 /************************************************************************
287 ************************************************************************/
289 static char* des_salt_key( void )
293 asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
, lp_realm());
298 /************************************************************************
299 ************************************************************************/
301 BOOL
kerberos_secrets_store_des_salt( const char* salt
)
306 if ( (key
= des_salt_key()) == NULL
) {
307 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
312 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
313 secrets_delete( key
);
317 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
319 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
326 /************************************************************************
327 ************************************************************************/
329 char* kerberos_secrets_fetch_des_salt( void )
333 if ( (key
= des_salt_key()) == NULL
) {
334 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
338 salt
= (char*)secrets_fetch( key
, NULL
);
346 /************************************************************************
347 Routine to get the salting principal for this service. This is
348 maintained for backwards compatibilty with releases prior to 3.0.24.
349 Since we store the salting principal string only at join, we may have
350 to look for the older tdb keys. Caller must free if return is not null.
351 ************************************************************************/
353 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
354 krb5_principal host_princ
,
357 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
358 krb5_principal ret_princ
= NULL
;
360 /* lookup new key first */
362 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
364 /* look under the old key. If this fails, just use the standard key */
366 if (smb_krb5_unparse_name(context
, host_princ
, &unparsed_name
) != 0) {
367 return (krb5_principal
)NULL
;
369 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
370 /* fall back to host/machine.realm@REALM */
371 salt_princ_s
= kerberos_standard_des_salt();
375 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
379 SAFE_FREE(unparsed_name
);
380 SAFE_FREE(salt_princ_s
);
385 /************************************************************************
386 Routine to set the salting principal for this service. Active
387 Directory may use a non-obvious principal name to generate the salt
388 when it determines the key to use for encrypting tickets for a service,
389 and hopefully we detected that when we joined the domain.
390 Setting principal to NULL deletes this entry.
391 ************************************************************************/
393 BOOL
kerberos_secrets_store_salting_principal(const char *service
,
395 const char *principal
)
399 krb5_context context
= NULL
;
400 krb5_principal princ
= NULL
;
401 char *princ_s
= NULL
;
402 char *unparsed_name
= NULL
;
404 krb5_init_context(&context
);
408 if (strchr_m(service
, '@')) {
409 asprintf(&princ_s
, "%s", service
);
411 asprintf(&princ_s
, "%s@%s", service
, lp_realm());
414 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
418 if (smb_krb5_unparse_name(context
, princ
, &unparsed_name
) != 0) {
422 asprintf(&key
, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
);
427 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
428 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
430 ret
= secrets_delete(key
);
437 SAFE_FREE(unparsed_name
);
440 krb5_free_context(context
);
447 /************************************************************************
448 ************************************************************************/
450 int kerberos_kinit_password(const char *principal
,
451 const char *password
,
453 const char *cache_name
)
455 return kerberos_kinit_password_ext(principal
,