r16952: New derive DES salt code and Krb5 keytab generation
[samba.git] / source3 / libads / kerberos.c
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.
9
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.
14    
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.
19    
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.
23 */
24
25 #include "includes.h"
26
27 #ifdef HAVE_KRB5
28
29 #define LIBADS_CCACHE_NAME "MEMORY:libads"
30
31 /*
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 ...
35 */
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[])
42 {
43         if (num_prompts == 0) return 0;
44
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;
52                 }
53         }
54         return 0;
55 }
56
57 /*
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
61 */
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)
71 {
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;
79
80         initialize_krb5_error_table();
81         if ((code = krb5_init_context(&ctx)))
82                 return code;
83
84         if (time_offset != 0) {
85                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
86         }
87
88         DEBUG(10,("kerberos_kinit_password: using %s as ccache\n",
89                         cache_name ? cache_name: krb5_cc_default_name(ctx)));
90
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;
94         }
95         
96         if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
97                 krb5_free_context(ctx); 
98                 return code;
99         }
100
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);
104         
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;
112                 }
113 #endif
114         }
115
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;    
122                 }
123                 krb5_get_init_creds_opt_set_address_list(&opt, addr->addrs);
124         }
125
126         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), 
127                                                  kerb_prompter, NULL, 0, NULL, &opt)))
128         {
129                 smb_krb5_free_addresses(ctx, addr);
130                 krb5_free_principal(ctx, me);
131                 krb5_free_context(ctx);         
132                 return code;
133         }
134         
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;
141         }
142         
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;
150         }
151
152         if (expire_time) {
153                 *expire_time = (time_t) my_creds.times.endtime;
154         }
155
156         if (renew_till_time) {
157                 *renew_till_time = (time_t) my_creds.times.renew_till;
158         }
159
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);         
165         
166         return 0;
167 }
168
169
170
171 /* run kinit to setup our ccache */
172 int ads_kinit_password(ADS_STRUCT *ads)
173 {
174         char *s;
175         int ret;
176         const char *account_name;
177         fstring acct_name;
178
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;
188                 }
189                 else 
190                         /* This looks like host/global_myname()@REA.LM */
191                         account_name = ads->auth.user_name;
192         }
193
194         if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
195                 return KRB5_CC_NOMEM;
196         }
197
198         if (!ads->auth.password) {
199                 SAFE_FREE(s);
200                 return KRB5_LIBOS_CANTREADPWD;
201         }
202         
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);
205
206         if (ret) {
207                 DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
208                          s, error_message(ret)));
209         }
210         SAFE_FREE(s);
211         return ret;
212 }
213
214 int ads_kdestroy(const char *cc_name)
215 {
216         krb5_error_code code;
217         krb5_context ctx = NULL;
218         krb5_ccache cc = NULL;
219
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;
225         }
226   
227         if (!cc_name) {
228                 if ((code = krb5_cc_default(ctx, &cc))) {
229                         krb5_free_context(ctx);
230                         return code;
231                 }
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;
238                 }
239         }
240
241         if ((code = krb5_cc_destroy (ctx, cc))) {
242                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
243                         error_message(code)));
244         }
245
246         krb5_free_context (ctx);
247         return code;
248 }
249
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  ************************************************************************/
256
257 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
258 {
259         char *key = NULL;
260         char *ret = NULL;
261
262         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
263         if (!key) {
264                 return NULL;
265         }
266         ret = (char *)secrets_fetch(key, NULL);
267         SAFE_FREE(key);
268         return ret;
269 }
270
271 /************************************************************************
272  Return the standard DES salt key
273 ************************************************************************/
274
275 char* kerberos_standard_des_salt( void )
276 {
277         fstring salt;
278
279         fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
280         strlower_m( salt );
281         fstrcat( salt, lp_realm() );
282
283         return SMB_STRDUP( salt );
284 }
285
286 /************************************************************************
287 ************************************************************************/
288
289 static char* des_salt_key( void )
290 {
291         char *key;
292
293         asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
294
295         return key;
296 }
297
298 /************************************************************************
299 ************************************************************************/
300
301 BOOL kerberos_secrets_store_des_salt( const char* salt )
302 {
303         char* key;
304         BOOL ret;
305
306         if ( (key = des_salt_key()) == NULL ) {
307                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
308                 return False;
309         }
310
311         if ( !salt ) {
312                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
313                 secrets_delete( key );
314         }
315
316         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
317
318         ret = secrets_store( key, salt, strlen(salt)+1 );
319
320         SAFE_FREE( key );
321
322         return ret;
323 }
324
325 /************************************************************************
326 ************************************************************************/
327
328 char* kerberos_secrets_fetch_des_salt( void )
329 {
330         char *salt, *key;
331
332         if ( (key = des_salt_key()) == NULL ) {
333                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
334                 return False;
335         }
336
337         if ( !salt ) {
338                 DEBUG(8,("kerberos_secrets_fetch_des_salt: NULL salt!\n"));
339                 secrets_delete( key );
340         }
341
342         salt = (char*)secrets_fetch( key, NULL );
343
344         SAFE_FREE( key );
345
346         return salt;
347 }
348
349
350 /************************************************************************
351  Routine to get the salting principal for this service.  This is 
352  maintained for backwards compatibilty with releases prior to 3.0.24.
353  Since we store the salting principal string only at join, we may have 
354  to look for the older tdb keys.  Caller must free if return is not null.
355  ************************************************************************/
356
357 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
358                                                         krb5_principal host_princ,
359                                                         int enctype)
360 {
361         char *unparsed_name = NULL, *salt_princ_s = NULL;
362         krb5_principal ret_princ = NULL;
363         
364         /* lookup new key first */
365
366         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
367         
368                 /* look under the old key.  If this fails, just use the standard key */
369
370                 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
371                         return (krb5_principal)NULL;
372                 }
373                 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
374                         /* fall back to host/machine.realm@REALM */
375                         salt_princ_s = kerberos_standard_des_salt();
376                 }
377         }
378
379         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
380                 ret_princ = NULL;
381         }
382         
383         SAFE_FREE(unparsed_name);
384         SAFE_FREE(salt_princ_s);
385         
386         return ret_princ;
387 }
388
389 /************************************************************************
390  Routine to set the salting principal for this service.  Active
391  Directory may use a non-obvious principal name to generate the salt
392  when it determines the key to use for encrypting tickets for a service,
393  and hopefully we detected that when we joined the domain.
394  Setting principal to NULL deletes this entry.
395  ************************************************************************/
396
397 BOOL kerberos_secrets_store_salting_principal(const char *service,
398                                               int enctype,
399                                               const char *principal)
400 {
401         char *key = NULL;
402         BOOL ret = False;
403         krb5_context context = NULL;
404         krb5_principal princ = NULL;
405         char *princ_s = NULL;
406         char *unparsed_name = NULL;
407
408         krb5_init_context(&context);
409         if (!context) {
410                 return False;
411         }
412         if (strchr_m(service, '@')) {
413                 asprintf(&princ_s, "%s", service);
414         } else {
415                 asprintf(&princ_s, "%s@%s", service, lp_realm());
416         }
417
418         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
419                 goto out;
420                 
421         }
422         if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
423                 goto out;
424         }
425
426         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
427         if (!key)  {
428                 goto out;
429         }
430
431         if ((principal != NULL) && (strlen(principal) > 0)) {
432                 ret = secrets_store(key, principal, strlen(principal) + 1);
433         } else {
434                 ret = secrets_delete(key);
435         }
436
437  out:
438
439         SAFE_FREE(key);
440         SAFE_FREE(princ_s);
441         SAFE_FREE(unparsed_name);
442
443         if (context) {
444                 krb5_free_context(context);
445         }
446
447         return ret;
448 }
449
450
451 /************************************************************************
452 ************************************************************************/
453
454 int kerberos_kinit_password(const char *principal,
455                             const char *password,
456                             int time_offset,
457                             const char *cache_name)
458 {
459         return kerberos_kinit_password_ext(principal, 
460                                            password, 
461                                            time_offset, 
462                                            0, 
463                                            0,
464                                            cache_name,
465                                            False,
466                                            False,
467                                            0);
468 }
469
470 #endif