r17942: Jerry is right - when no site support is enabled
[tprouty/samba.git] / source / 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, (const char *)data,
49                                 prompts[0].reply->length-1);
50                         prompts[0].reply->length = strlen(prompts[0].reply->data);
51                 } else {
52                         prompts[0].reply->length = 0;
53                 }
54         }
55         return 0;
56 }
57
58 /*
59   simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
60   place in default cache location.
61   remus@snapserver.com
62 */
63 int kerberos_kinit_password_ext(const char *principal,
64                                 const char *password,
65                                 int time_offset,
66                                 time_t *expire_time,
67                                 time_t *renew_till_time,
68                                 const char *cache_name,
69                                 BOOL request_pac,
70                                 BOOL add_netbios_addr,
71                                 time_t renewable_time)
72 {
73         krb5_context ctx = NULL;
74         krb5_error_code code = 0;
75         krb5_ccache cc = NULL;
76         krb5_principal me;
77         krb5_creds my_creds;
78         krb5_get_init_creds_opt opt;
79         smb_krb5_addresses *addr = NULL;
80
81         initialize_krb5_error_table();
82         if ((code = krb5_init_context(&ctx)))
83                 return code;
84
85         if (time_offset != 0) {
86                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
87         }
88
89         DEBUG(10,("kerberos_kinit_password: using %s as ccache\n",
90                         cache_name ? cache_name: krb5_cc_default_name(ctx)));
91
92         if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
93                 krb5_free_context(ctx);
94                 return code;
95         }
96         
97         if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
98                 krb5_free_context(ctx); 
99                 return code;
100         }
101
102         krb5_get_init_creds_opt_init(&opt);
103         krb5_get_init_creds_opt_set_renew_life(&opt, renewable_time);
104         krb5_get_init_creds_opt_set_forwardable(&opt, 1);
105         
106         if (request_pac) {
107 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
108                 code = krb5_get_init_creds_opt_set_pac_request(ctx, &opt, True);
109                 if (code) {
110                         krb5_free_principal(ctx, me);
111                         krb5_free_context(ctx);
112                         return code;
113                 }
114 #endif
115         }
116
117         if (add_netbios_addr) {
118                 code = smb_krb5_gen_netbios_krb5_address(&addr);
119                 if (code) {
120                         krb5_free_principal(ctx, me);
121                         krb5_free_context(ctx);         
122                         return code;    
123                 }
124                 krb5_get_init_creds_opt_set_address_list(&opt, addr->addrs);
125         }
126
127         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), 
128                                                  kerb_prompter, NULL, 0, NULL, &opt)))
129         {
130                 smb_krb5_free_addresses(ctx, addr);
131                 krb5_free_principal(ctx, me);
132                 krb5_free_context(ctx);         
133                 return code;
134         }
135         
136         if ((code = krb5_cc_initialize(ctx, cc, me))) {
137                 smb_krb5_free_addresses(ctx, addr);
138                 krb5_free_cred_contents(ctx, &my_creds);
139                 krb5_free_principal(ctx, me);
140                 krb5_free_context(ctx);         
141                 return code;
142         }
143         
144         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
145                 krb5_cc_close(ctx, cc);
146                 smb_krb5_free_addresses(ctx, addr);
147                 krb5_free_cred_contents(ctx, &my_creds);
148                 krb5_free_principal(ctx, me);
149                 krb5_free_context(ctx);         
150                 return code;
151         }
152
153         if (expire_time) {
154                 *expire_time = (time_t) my_creds.times.endtime;
155         }
156
157         if (renew_till_time) {
158                 *renew_till_time = (time_t) my_creds.times.renew_till;
159         }
160
161         krb5_cc_close(ctx, cc);
162         smb_krb5_free_addresses(ctx, addr);
163         krb5_free_cred_contents(ctx, &my_creds);
164         krb5_free_principal(ctx, me);
165         krb5_free_context(ctx);         
166         
167         return 0;
168 }
169
170
171
172 /* run kinit to setup our ccache */
173 int ads_kinit_password(ADS_STRUCT *ads)
174 {
175         char *s;
176         int ret;
177         const char *account_name;
178         fstring acct_name;
179
180         if ( IS_DC ) {
181                 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
182                 account_name = lp_workgroup();
183         } else {
184                 /* always use the sAMAccountName for security = domain */
185                 /* global_myname()$@REA.LM */
186                 if ( lp_security() == SEC_DOMAIN ) {
187                         fstr_sprintf( acct_name, "%s$", global_myname() );
188                         account_name = acct_name;
189                 }
190                 else 
191                         /* This looks like host/global_myname()@REA.LM */
192                         account_name = ads->auth.user_name;
193         }
194
195         if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
196                 return KRB5_CC_NOMEM;
197         }
198
199         if (!ads->auth.password) {
200                 SAFE_FREE(s);
201                 return KRB5_LIBOS_CANTREADPWD;
202         }
203         
204         ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
205                         &ads->auth.expire, NULL, NULL, False, False, ads->auth.renewable);
206
207         if (ret) {
208                 DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
209                          s, error_message(ret)));
210         }
211         SAFE_FREE(s);
212         return ret;
213 }
214
215 int ads_kdestroy(const char *cc_name)
216 {
217         krb5_error_code code;
218         krb5_context ctx = NULL;
219         krb5_ccache cc = NULL;
220
221         initialize_krb5_error_table();
222         if ((code = krb5_init_context (&ctx))) {
223                 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
224                         error_message(code)));
225                 return code;
226         }
227   
228         if (!cc_name) {
229                 if ((code = krb5_cc_default(ctx, &cc))) {
230                         krb5_free_context(ctx);
231                         return code;
232                 }
233         } else {
234                 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
235                         DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
236                                   error_message(code)));
237                         krb5_free_context(ctx);
238                         return code;
239                 }
240         }
241
242         if ((code = krb5_cc_destroy (ctx, cc))) {
243                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
244                         error_message(code)));
245         }
246
247         krb5_free_context (ctx);
248         return code;
249 }
250
251 /************************************************************************
252  Routine to fetch the salting principal for a service.  Active
253  Directory may use a non-obvious principal name to generate the salt
254  when it determines the key to use for encrypting tickets for a service,
255  and hopefully we detected that when we joined the domain.
256  ************************************************************************/
257
258 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
259 {
260         char *key = NULL;
261         char *ret = NULL;
262
263         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
264         if (!key) {
265                 return NULL;
266         }
267         ret = (char *)secrets_fetch(key, NULL);
268         SAFE_FREE(key);
269         return ret;
270 }
271
272 /************************************************************************
273  Return the standard DES salt key
274 ************************************************************************/
275
276 char* kerberos_standard_des_salt( void )
277 {
278         fstring salt;
279
280         fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
281         strlower_m( salt );
282         fstrcat( salt, lp_realm() );
283
284         return SMB_STRDUP( salt );
285 }
286
287 /************************************************************************
288 ************************************************************************/
289
290 static char* des_salt_key( void )
291 {
292         char *key;
293
294         asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
295
296         return key;
297 }
298
299 /************************************************************************
300 ************************************************************************/
301
302 BOOL kerberos_secrets_store_des_salt( const char* salt )
303 {
304         char* key;
305         BOOL ret;
306
307         if ( (key = des_salt_key()) == NULL ) {
308                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
309                 return False;
310         }
311
312         if ( !salt ) {
313                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
314                 secrets_delete( key );
315                 return True;
316         }
317
318         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
319
320         ret = secrets_store( key, salt, strlen(salt)+1 );
321
322         SAFE_FREE( key );
323
324         return ret;
325 }
326
327 /************************************************************************
328 ************************************************************************/
329
330 char* kerberos_secrets_fetch_des_salt( void )
331 {
332         char *salt, *key;
333
334         if ( (key = des_salt_key()) == NULL ) {
335                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
336                 return False;
337         }
338
339         salt = (char*)secrets_fetch( key, NULL );
340
341         SAFE_FREE( key );
342
343         return salt;
344 }
345
346
347 /************************************************************************
348  Routine to get the salting principal for this service.  This is 
349  maintained for backwards compatibilty with releases prior to 3.0.24.
350  Since we store the salting principal string only at join, we may have 
351  to look for the older tdb keys.  Caller must free if return is not null.
352  ************************************************************************/
353
354 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
355                                                         krb5_principal host_princ,
356                                                         int enctype)
357 {
358         char *unparsed_name = NULL, *salt_princ_s = NULL;
359         krb5_principal ret_princ = NULL;
360         
361         /* lookup new key first */
362
363         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
364         
365                 /* look under the old key.  If this fails, just use the standard key */
366
367                 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
368                         return (krb5_principal)NULL;
369                 }
370                 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
371                         /* fall back to host/machine.realm@REALM */
372                         salt_princ_s = kerberos_standard_des_salt();
373                 }
374         }
375
376         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
377                 ret_princ = NULL;
378         }
379         
380         SAFE_FREE(unparsed_name);
381         SAFE_FREE(salt_princ_s);
382         
383         return ret_princ;
384 }
385
386 /************************************************************************
387  Routine to set the salting principal for this service.  Active
388  Directory may use a non-obvious principal name to generate the salt
389  when it determines the key to use for encrypting tickets for a service,
390  and hopefully we detected that when we joined the domain.
391  Setting principal to NULL deletes this entry.
392  ************************************************************************/
393
394 BOOL kerberos_secrets_store_salting_principal(const char *service,
395                                               int enctype,
396                                               const char *principal)
397 {
398         char *key = NULL;
399         BOOL ret = False;
400         krb5_context context = NULL;
401         krb5_principal princ = NULL;
402         char *princ_s = NULL;
403         char *unparsed_name = NULL;
404
405         krb5_init_context(&context);
406         if (!context) {
407                 return False;
408         }
409         if (strchr_m(service, '@')) {
410                 asprintf(&princ_s, "%s", service);
411         } else {
412                 asprintf(&princ_s, "%s@%s", service, lp_realm());
413         }
414
415         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
416                 goto out;
417                 
418         }
419         if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
420                 goto out;
421         }
422
423         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
424         if (!key)  {
425                 goto out;
426         }
427
428         if ((principal != NULL) && (strlen(principal) > 0)) {
429                 ret = secrets_store(key, principal, strlen(principal) + 1);
430         } else {
431                 ret = secrets_delete(key);
432         }
433
434  out:
435
436         SAFE_FREE(key);
437         SAFE_FREE(princ_s);
438         SAFE_FREE(unparsed_name);
439
440         if (context) {
441                 krb5_free_context(context);
442         }
443
444         return ret;
445 }
446
447
448 /************************************************************************
449 ************************************************************************/
450
451 int kerberos_kinit_password(const char *principal,
452                             const char *password,
453                             int time_offset,
454                             const char *cache_name)
455 {
456         return kerberos_kinit_password_ext(principal, 
457                                            password, 
458                                            time_offset, 
459                                            0, 
460                                            0,
461                                            cache_name,
462                                            False,
463                                            False,
464                                            0);
465 }
466
467 #endif