r17094: merge fixes for 3.0.23a
[Samba/gbeck.git] / source / libads / kerberos.c
blobaf4ba8683137f723ea27793bec68c1f20de7c76b
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, data, prompts[0].reply->length-1);
49 prompts[0].reply->length = strlen(prompts[0].reply->data);
50 } else {
51 prompts[0].reply->length = 0;
54 return 0;
58 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
59 place in default cache location.
60 remus@snapserver.com
62 int kerberos_kinit_password_ext(const char *principal,
63 const char *password,
64 int time_offset,
65 time_t *expire_time,
66 time_t *renew_till_time,
67 const char *cache_name,
68 BOOL request_pac,
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;
75 krb5_principal me;
76 krb5_creds my_creds;
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)))
82 return code;
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);
93 return code;
96 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
97 krb5_free_context(ctx);
98 return code;
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);
105 if (request_pac) {
106 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
107 code = krb5_get_init_creds_opt_set_pac_request(ctx, &opt, True);
108 if (code) {
109 krb5_free_principal(ctx, me);
110 krb5_free_context(ctx);
111 return code;
113 #endif
116 if (add_netbios_addr) {
117 code = smb_krb5_gen_netbios_krb5_address(&addr);
118 if (code) {
119 krb5_free_principal(ctx, me);
120 krb5_free_context(ctx);
121 return code;
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);
132 return code;
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);
140 return code;
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);
149 return code;
152 if (expire_time) {
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);
166 return 0;
171 /* run kinit to setup our ccache */
172 int ads_kinit_password(ADS_STRUCT *ads)
174 char *s;
175 int ret;
176 const char *account_name;
177 fstring acct_name;
179 if ( IS_DC ) {
180 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
181 account_name = lp_workgroup();
182 } else {
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;
189 else
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) {
199 SAFE_FREE(s);
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);
206 if (ret) {
207 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
208 s, error_message(ret)));
210 SAFE_FREE(s);
211 return 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)));
224 return code;
227 if (!cc_name) {
228 if ((code = krb5_cc_default(ctx, &cc))) {
229 krb5_free_context(ctx);
230 return code;
232 } else {
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);
237 return code;
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);
247 return code;
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)
259 char *key = NULL;
260 char *ret = NULL;
262 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
263 if (!key) {
264 return NULL;
266 ret = (char *)secrets_fetch(key, NULL);
267 SAFE_FREE(key);
268 return ret;
271 /************************************************************************
272 Return the standard DES salt key
273 ************************************************************************/
275 char* kerberos_standard_des_salt( void )
277 fstring salt;
279 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
280 strlower_m( salt );
281 fstrcat( salt, lp_realm() );
283 return SMB_STRDUP( salt );
286 /************************************************************************
287 ************************************************************************/
289 static char* des_salt_key( void )
291 char *key;
293 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
295 return key;
298 /************************************************************************
299 ************************************************************************/
301 BOOL kerberos_secrets_store_des_salt( const char* salt )
303 char* key;
304 BOOL ret;
306 if ( (key = des_salt_key()) == NULL ) {
307 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
308 return False;
311 if ( !salt ) {
312 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
313 secrets_delete( key );
314 return True;
317 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
319 ret = secrets_store( key, salt, strlen(salt)+1 );
321 SAFE_FREE( key );
323 return ret;
326 /************************************************************************
327 ************************************************************************/
329 char* kerberos_secrets_fetch_des_salt( void )
331 char *salt, *key;
333 if ( (key = des_salt_key()) == NULL ) {
334 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
335 return False;
338 salt = (char*)secrets_fetch( key, NULL );
340 SAFE_FREE( key );
342 return salt;
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,
355 int enctype)
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) {
376 ret_princ = NULL;
379 SAFE_FREE(unparsed_name);
380 SAFE_FREE(salt_princ_s);
382 return ret_princ;
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,
394 int enctype,
395 const char *principal)
397 char *key = NULL;
398 BOOL ret = False;
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);
405 if (!context) {
406 return False;
408 if (strchr_m(service, '@')) {
409 asprintf(&princ_s, "%s", service);
410 } else {
411 asprintf(&princ_s, "%s@%s", service, lp_realm());
414 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
415 goto out;
418 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
419 goto out;
422 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
423 if (!key) {
424 goto out;
427 if ((principal != NULL) && (strlen(principal) > 0)) {
428 ret = secrets_store(key, principal, strlen(principal) + 1);
429 } else {
430 ret = secrets_delete(key);
433 out:
435 SAFE_FREE(key);
436 SAFE_FREE(princ_s);
437 SAFE_FREE(unparsed_name);
439 if (context) {
440 krb5_free_context(context);
443 return ret;
447 /************************************************************************
448 ************************************************************************/
450 int kerberos_kinit_password(const char *principal,
451 const char *password,
452 int time_offset,
453 const char *cache_name)
455 return kerberos_kinit_password_ext(principal,
456 password,
457 time_offset,
460 cache_name,
461 False,
462 False,
466 #endif