af4ba8683137f723ea27793bec68c1f20de7c76b
[vlendec/samba-autobuild/.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                 return True;
315         }
316
317         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
318
319         ret = secrets_store( key, salt, strlen(salt)+1 );
320
321         SAFE_FREE( key );
322
323         return ret;
324 }
325
326 /************************************************************************
327 ************************************************************************/
328
329 char* kerberos_secrets_fetch_des_salt( void )
330 {
331         char *salt, *key;
332
333         if ( (key = des_salt_key()) == NULL ) {
334                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
335                 return False;
336         }
337
338         salt = (char*)secrets_fetch( key, NULL );
339
340         SAFE_FREE( key );
341
342         return salt;
343 }
344
345
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  ************************************************************************/
352
353 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
354                                                         krb5_principal host_princ,
355                                                         int enctype)
356 {
357         char *unparsed_name = NULL, *salt_princ_s = NULL;
358         krb5_principal ret_princ = NULL;
359         
360         /* lookup new key first */
361
362         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
363         
364                 /* look under the old key.  If this fails, just use the standard key */
365
366                 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
367                         return (krb5_principal)NULL;
368                 }
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();
372                 }
373         }
374
375         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
376                 ret_princ = NULL;
377         }
378         
379         SAFE_FREE(unparsed_name);
380         SAFE_FREE(salt_princ_s);
381         
382         return ret_princ;
383 }
384
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  ************************************************************************/
392
393 BOOL kerberos_secrets_store_salting_principal(const char *service,
394                                               int enctype,
395                                               const char *principal)
396 {
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;
403
404         krb5_init_context(&context);
405         if (!context) {
406                 return False;
407         }
408         if (strchr_m(service, '@')) {
409                 asprintf(&princ_s, "%s", service);
410         } else {
411                 asprintf(&princ_s, "%s@%s", service, lp_realm());
412         }
413
414         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
415                 goto out;
416                 
417         }
418         if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
419                 goto out;
420         }
421
422         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
423         if (!key)  {
424                 goto out;
425         }
426
427         if ((principal != NULL) && (strlen(principal) > 0)) {
428                 ret = secrets_store(key, principal, strlen(principal) + 1);
429         } else {
430                 ret = secrets_delete(key);
431         }
432
433  out:
434
435         SAFE_FREE(key);
436         SAFE_FREE(princ_s);
437         SAFE_FREE(unparsed_name);
438
439         if (context) {
440                 krb5_free_context(context);
441         }
442
443         return ret;
444 }
445
446
447 /************************************************************************
448 ************************************************************************/
449
450 int kerberos_kinit_password(const char *principal,
451                             const char *password,
452                             int time_offset,
453                             const char *cache_name)
454 {
455         return kerberos_kinit_password_ext(principal, 
456                                            password, 
457                                            time_offset, 
458                                            0, 
459                                            0,
460                                            cache_name,
461                                            False,
462                                            False,
463                                            0);
464 }
465
466 #endif