r16272: Fix memleak.
[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
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 #ifdef HAVE_KRB5
27
28 #define LIBADS_CCACHE_NAME "MEMORY:libads"
29
30 /*
31   we use a prompter to avoid a crash bug in the kerberos libs when 
32   dealing with empty passwords
33   this prompter is just a string copy ...
34 */
35 static krb5_error_code 
36 kerb_prompter(krb5_context ctx, void *data,
37                const char *name,
38                const char *banner,
39                int num_prompts,
40                krb5_prompt prompts[])
41 {
42         if (num_prompts == 0) return 0;
43
44         memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
45         if (prompts[0].reply->length > 0) {
46                 if (data) {
47                         strncpy(prompts[0].reply->data, data, prompts[0].reply->length-1);
48                         prompts[0].reply->length = strlen(prompts[0].reply->data);
49                 } else {
50                         prompts[0].reply->length = 0;
51                 }
52         }
53         return 0;
54 }
55
56 /*
57   simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
58   place in default cache location.
59   remus@snapserver.com
60 */
61 int kerberos_kinit_password_ext(const char *principal,
62                                 const char *password,
63                                 int time_offset,
64                                 time_t *expire_time,
65                                 time_t *renew_till_time,
66                                 const char *cache_name,
67                                 BOOL request_pac,
68                                 BOOL add_netbios_addr,
69                                 time_t renewable_time)
70 {
71         krb5_context ctx = NULL;
72         krb5_error_code code = 0;
73         krb5_ccache cc = NULL;
74         krb5_principal me;
75         krb5_creds my_creds;
76         krb5_get_init_creds_opt opt;
77         smb_krb5_addresses *addr = NULL;
78
79         initialize_krb5_error_table();
80         if ((code = krb5_init_context(&ctx)))
81                 return code;
82
83         if (time_offset != 0) {
84                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
85         }
86
87         DEBUG(10,("kerberos_kinit_password: using %s as ccache\n",
88                         cache_name ? cache_name: krb5_cc_default_name(ctx)));
89
90         if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
91                 krb5_free_context(ctx);
92                 return code;
93         }
94         
95         if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
96                 krb5_free_context(ctx); 
97                 return code;
98         }
99
100         krb5_get_init_creds_opt_init(&opt);
101         krb5_get_init_creds_opt_set_renew_life(&opt, renewable_time);
102         krb5_get_init_creds_opt_set_forwardable(&opt, 1);
103         
104         if (request_pac) {
105 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
106                 code = krb5_get_init_creds_opt_set_pac_request(ctx, &opt, True);
107                 if (code) {
108                         krb5_free_principal(ctx, me);
109                         krb5_free_context(ctx);
110                         return code;
111                 }
112 #endif
113         }
114
115         if (add_netbios_addr) {
116                 code = smb_krb5_gen_netbios_krb5_address(&addr);
117                 if (code) {
118                         krb5_free_principal(ctx, me);
119                         krb5_free_context(ctx);         
120                         return code;    
121                 }
122                 krb5_get_init_creds_opt_set_address_list(&opt, addr->addrs);
123         }
124
125         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), 
126                                                  kerb_prompter, NULL, 0, NULL, &opt)))
127         {
128                 smb_krb5_free_addresses(ctx, addr);
129                 krb5_free_principal(ctx, me);
130                 krb5_free_context(ctx);         
131                 return code;
132         }
133         
134         if ((code = krb5_cc_initialize(ctx, cc, me))) {
135                 smb_krb5_free_addresses(ctx, addr);
136                 krb5_free_cred_contents(ctx, &my_creds);
137                 krb5_free_principal(ctx, me);
138                 krb5_free_context(ctx);         
139                 return code;
140         }
141         
142         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
143                 krb5_cc_close(ctx, cc);
144                 smb_krb5_free_addresses(ctx, addr);
145                 krb5_free_cred_contents(ctx, &my_creds);
146                 krb5_free_principal(ctx, me);
147                 krb5_free_context(ctx);         
148                 return code;
149         }
150
151         if (expire_time) {
152                 *expire_time = (time_t) my_creds.times.endtime;
153         }
154
155         if (renew_till_time) {
156                 *renew_till_time = (time_t) my_creds.times.renew_till;
157         }
158
159         krb5_cc_close(ctx, cc);
160         smb_krb5_free_addresses(ctx, addr);
161         krb5_free_cred_contents(ctx, &my_creds);
162         krb5_free_principal(ctx, me);
163         krb5_free_context(ctx);         
164         
165         return 0;
166 }
167
168
169
170 /* run kinit to setup our ccache */
171 int ads_kinit_password(ADS_STRUCT *ads)
172 {
173         char *s;
174         int ret;
175         const char *account_name;
176         fstring acct_name;
177
178         if ( IS_DC ) {
179                 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
180                 account_name = lp_workgroup();
181         } else {
182                 /* always use the sAMAccountName for security = domain */
183                 /* global_myname()$@REA.LM */
184                 if ( lp_security() == SEC_DOMAIN ) {
185                         fstr_sprintf( acct_name, "%s$", global_myname() );
186                         account_name = acct_name;
187                 }
188                 else 
189                         /* This looks like host/global_myname()@REA.LM */
190                         account_name = ads->auth.user_name;
191         }
192
193         if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
194                 return KRB5_CC_NOMEM;
195         }
196
197         if (!ads->auth.password) {
198                 SAFE_FREE(s);
199                 return KRB5_LIBOS_CANTREADPWD;
200         }
201         
202         ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
203                         &ads->auth.expire, NULL, NULL, False, False, ads->auth.renewable);
204
205         if (ret) {
206                 DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
207                          s, error_message(ret)));
208         }
209         SAFE_FREE(s);
210         return ret;
211 }
212
213 int ads_kdestroy(const char *cc_name)
214 {
215         krb5_error_code code;
216         krb5_context ctx = NULL;
217         krb5_ccache cc = NULL;
218
219         initialize_krb5_error_table();
220         if ((code = krb5_init_context (&ctx))) {
221                 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
222                         error_message(code)));
223                 return code;
224         }
225   
226         if (!cc_name) {
227                 if ((code = krb5_cc_default(ctx, &cc))) {
228                         krb5_free_context(ctx);
229                         return code;
230                 }
231         } else {
232                 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
233                         DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
234                                   error_message(code)));
235                         krb5_free_context(ctx);
236                         return code;
237                 }
238         }
239
240         if ((code = krb5_cc_destroy (ctx, cc))) {
241                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
242                         error_message(code)));
243         }
244
245         krb5_free_context (ctx);
246         return code;
247 }
248
249 /************************************************************************
250  Routine to fetch the salting principal for a service.  Active
251  Directory may use a non-obvious principal name to generate the salt
252  when it determines the key to use for encrypting tickets for a service,
253  and hopefully we detected that when we joined the domain.
254  ************************************************************************/
255
256 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
257 {
258         char *key = NULL;
259         char *ret = NULL;
260
261         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
262         if (!key) {
263                 return NULL;
264         }
265         ret = (char *)secrets_fetch(key, NULL);
266         SAFE_FREE(key);
267         return ret;
268 }
269
270 /************************************************************************
271  Routine to get the salting principal for this service.  Active
272  Directory may use a non-obvious principal name to generate the salt
273  when it determines the key to use for encrypting tickets for a service,
274  and hopefully we detected that when we joined the domain.
275  Caller must free if return is not null.
276  ************************************************************************/
277
278 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
279                                                         krb5_principal host_princ,
280                                                         int enctype)
281 {
282         char *unparsed_name = NULL, *salt_princ_s = NULL;
283         krb5_principal ret_princ = NULL;
284
285         if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
286                 return (krb5_principal)NULL;
287         }
288
289         if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
290                 SAFE_FREE(unparsed_name);
291                 return (krb5_principal)NULL;
292         }
293
294         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
295                 SAFE_FREE(unparsed_name);
296                 SAFE_FREE(salt_princ_s);
297                 return (krb5_principal)NULL;
298         }
299         SAFE_FREE(unparsed_name);
300         SAFE_FREE(salt_princ_s);
301         return ret_princ;
302 }
303
304 /************************************************************************
305  Routine to set the salting principal for this service.  Active
306  Directory may use a non-obvious principal name to generate the salt
307  when it determines the key to use for encrypting tickets for a service,
308  and hopefully we detected that when we joined the domain.
309  Setting principal to NULL deletes this entry.
310  ************************************************************************/
311
312 BOOL kerberos_secrets_store_salting_principal(const char *service,
313                                               int enctype,
314                                               const char *principal)
315 {
316         char *key = NULL;
317         BOOL ret = False;
318         krb5_context context = NULL;
319         krb5_principal princ = NULL;
320         char *princ_s = NULL;
321         char *unparsed_name = NULL;
322
323         krb5_init_context(&context);
324         if (!context) {
325                 return False;
326         }
327         if (strchr_m(service, '@')) {
328                 asprintf(&princ_s, "%s", service);
329         } else {
330                 asprintf(&princ_s, "%s@%s", service, lp_realm());
331         }
332
333         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
334                 goto out;
335                 
336         }
337         if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
338                 goto out;
339         }
340
341         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
342         if (!key)  {
343                 goto out;
344         }
345
346         if ((principal != NULL) && (strlen(principal) > 0)) {
347                 ret = secrets_store(key, principal, strlen(principal) + 1);
348         } else {
349                 ret = secrets_delete(key);
350         }
351
352  out:
353
354         SAFE_FREE(key);
355         SAFE_FREE(princ_s);
356         SAFE_FREE(unparsed_name);
357
358         if (context) {
359                 krb5_free_context(context);
360         }
361
362         return ret;
363 }
364
365 /************************************************************************
366  Routine to get initial credentials as a service ticket for the local machine.
367  Returns a buffer initialized with krb5_mk_req_extended.
368  ************************************************************************/
369
370 static krb5_error_code get_service_ticket(krb5_context ctx,
371                                         krb5_ccache ccache,
372                                         const char *service_principal,
373                                         int enctype,
374                                         krb5_data *p_outbuf)
375 {
376         krb5_creds creds, *new_creds = NULL;
377         char *service_s = NULL;
378         char *machine_account = NULL, *password = NULL;
379         krb5_data in_data;
380         krb5_auth_context auth_context = NULL;
381         krb5_error_code err = 0;
382
383         ZERO_STRUCT(creds);
384
385         asprintf(&machine_account, "%s$@%s", global_myname(), lp_realm());
386         if (machine_account == NULL) {
387                 goto out;
388         }
389         password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
390         if (password == NULL) {
391                 goto out;
392         }
393         if ((err = kerberos_kinit_password(machine_account, password, 
394                                            0, LIBADS_CCACHE_NAME)) != 0) {
395                 DEBUG(0,("get_service_ticket: kerberos_kinit_password %s failed: %s\n", 
396                         machine_account,
397                         error_message(err)));
398                 goto out;
399         }
400
401         /* Ok - the above call has gotten a TGT. Now we need to get a service
402            ticket to ourselves. */
403
404         /* Set up the enctype and client and server principal fields for krb5_get_credentials. */
405         kerberos_set_creds_enctype(&creds, enctype);
406
407         if ((err = krb5_cc_get_principal(ctx, ccache, &creds.client))) {
408                 DEBUG(3, ("get_service_ticket: krb5_cc_get_principal failed: %s\n", 
409                         error_message(err)));
410                 goto out;
411         }
412
413         if (strchr_m(service_principal, '@')) {
414                 asprintf(&service_s, "%s", service_principal);
415         } else {
416                 asprintf(&service_s, "%s@%s", service_principal, lp_realm());
417         }
418
419         if ((err = smb_krb5_parse_name(ctx, service_s, &creds.server))) {
420                 DEBUG(0,("get_service_ticket: smb_krb5_parse_name %s failed: %s\n", 
421                         service_s, error_message(err)));
422                 goto out;
423         }
424
425         if ((err = krb5_get_credentials(ctx, 0, ccache, &creds, &new_creds))) {
426                 DEBUG(5,("get_service_ticket: krb5_get_credentials for %s enctype %d failed: %s\n", 
427                         service_s, enctype, error_message(err)));
428                 goto out;
429         }
430
431         memset(&in_data, '\0', sizeof(in_data));
432         if ((err = krb5_mk_req_extended(ctx, &auth_context, 0, &in_data,
433                         new_creds, p_outbuf)) != 0) {
434                 DEBUG(0,("get_service_ticket: krb5_mk_req_extended failed: %s\n", 
435                         error_message(err)));
436                 goto out;
437         }
438
439  out:
440
441         if (auth_context) {
442                 krb5_auth_con_free(ctx, auth_context);
443         }
444         if (new_creds) {
445                 krb5_free_creds(ctx, new_creds);
446         }
447         if (creds.server) {
448                 krb5_free_principal(ctx, creds.server);
449         }
450         if (creds.client) {
451                 krb5_free_principal(ctx, creds.client);
452         }
453
454         SAFE_FREE(service_s);
455         SAFE_FREE(password);
456         SAFE_FREE(machine_account);
457         return err;
458 }
459
460 /************************************************************************
461  Check if the machine password can be used in conjunction with the salting_principal
462  to generate a key which will successfully decrypt the AP_REQ already
463  gotten as a message to the local machine.
464  ************************************************************************/
465
466 static BOOL verify_service_password(krb5_context ctx,
467                                     int enctype,
468                                     const char *salting_principal,
469                                     krb5_data *in_data)
470 {
471         BOOL ret = False;
472         krb5_principal salting_kprinc = NULL;
473         krb5_ticket *ticket = NULL;
474         krb5_keyblock key;
475         krb5_data passdata;
476         char *salting_s = NULL;
477         char *machine_account = NULL, *password = NULL;
478         krb5_auth_context auth_context = NULL;
479         krb5_error_code err;
480
481         memset(&passdata, '\0', sizeof(passdata));
482         memset(&key, '\0', sizeof(key));
483
484         asprintf(&machine_account, "%s$@%s", global_myname(), lp_realm());
485         if (machine_account == NULL) {
486                 goto out;
487         }
488         password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
489         if (password == NULL) {
490                 goto out;
491         }
492
493         if (strchr_m(salting_principal, '@')) {
494                 asprintf(&salting_s, "%s", salting_principal);
495         } else {
496                 asprintf(&salting_s, "%s@%s", salting_principal, lp_realm());
497         }
498
499         if ((err = smb_krb5_parse_name(ctx, salting_s, &salting_kprinc))) {
500                 DEBUG(0,("verify_service_password: smb_krb5_parse_name %s failed: %s\n", 
501                         salting_s, error_message(err)));
502                 goto out;
503         }
504
505         passdata.length = strlen(password);
506         passdata.data = (char*)password;
507         if ((err = create_kerberos_key_from_string_direct(ctx, salting_kprinc, &passdata, &key, enctype))) {
508                 DEBUG(0,("verify_service_password: create_kerberos_key_from_string %d failed: %s\n",
509                         enctype, error_message(err)));
510                 goto out;
511         }
512
513         if ((err = krb5_auth_con_init(ctx, &auth_context)) != 0) {
514                 DEBUG(0,("verify_service_password: krb5_auth_con_init failed %s\n", error_message(err)));
515                 goto out;
516         }
517
518         if ((err = krb5_auth_con_setuseruserkey(ctx, auth_context, &key)) != 0) {
519                 DEBUG(0,("verify_service_password: krb5_auth_con_setuseruserkey failed %s\n", error_message(err)));
520                 goto out;
521         }
522
523         if (!(err = krb5_rd_req(ctx, &auth_context, in_data, NULL, NULL, NULL, &ticket))) {
524                 DEBUG(10,("verify_service_password: decrypted message with enctype %u salt %s!\n",
525                                 (unsigned int)enctype, salting_s));
526                 ret = True;
527         }
528
529  out:
530
531         memset(&passdata, 0, sizeof(passdata));
532         krb5_free_keyblock_contents(ctx, &key);
533         if (ticket != NULL) {
534                 krb5_free_ticket(ctx, ticket);
535         }
536         if (salting_kprinc) {
537                 krb5_free_principal(ctx, salting_kprinc);
538         }
539         SAFE_FREE(salting_s);
540         SAFE_FREE(password);
541         SAFE_FREE(machine_account);
542         return ret;
543 }
544
545 /************************************************************************
546  *
547  * From the current draft of kerberos-clarifications:
548  *
549  *     It is not possible to reliably generate a user's key given a pass
550  *     phrase without contacting the KDC, since it will not be known
551  *     whether alternate salt or parameter values are required.
552  *
553  * And because our server has a password, we have this exact problem.  We
554  * make multiple guesses as to which principal name provides the salt which
555  * the KDC is using.
556  *
557  ************************************************************************/
558
559 static void kerberos_derive_salting_principal_for_enctype(const char *service_principal,
560                                                           krb5_context ctx,
561                                                           krb5_ccache ccache,
562                                                           krb5_enctype enctype,
563                                                           krb5_enctype *enctypes)
564 {
565         char *salting_principals[3] = {NULL, NULL, NULL}, *second_principal = NULL;
566         krb5_error_code err = 0;
567         krb5_data outbuf;
568         int i, j;
569
570         memset(&outbuf, '\0', sizeof(outbuf));
571
572         /* Check that the service_principal is useful. */
573         if ((service_principal == NULL) || (strlen(service_principal) == 0)) {
574                 return;
575         }
576
577         /* Generate our first guess -- the principal as-given. */
578         asprintf(&salting_principals[0], "%s", service_principal);
579         if ((salting_principals[0] == NULL) || (strlen(salting_principals[0]) == 0)) {
580                 return;
581         }
582
583         /* Generate our second guess -- the computer's principal, as Win2k3. */
584         asprintf(&second_principal, "host/%s.%s", global_myname(), lp_realm());
585         if (second_principal != NULL) {
586                 strlower_m(second_principal);
587                 asprintf(&salting_principals[1], "%s@%s", second_principal, lp_realm());
588                 SAFE_FREE(second_principal);
589         }
590         if ((salting_principals[1] == NULL) || (strlen(salting_principals[1]) == 0)) {
591                 goto out;
592         }
593
594         /* Generate our third guess -- the computer's principal, as Win2k. */
595         asprintf(&second_principal, "HOST/%s", global_myname());
596         if (second_principal != NULL) {
597                 strlower_m(second_principal + 5);
598                 asprintf(&salting_principals[2], "%s@%s",
599                         second_principal, lp_realm());
600                 SAFE_FREE(second_principal);
601         }
602         if ((salting_principals[2] == NULL) || (strlen(salting_principals[2]) == 0)) {
603                 goto out;
604         }
605
606         /* Get a service ticket for ourselves into our memory ccache. */
607         /* This will commonly fail if there is no principal by that name (and we're trying
608            many names). So don't print a debug 0 error. */
609
610         if ((err = get_service_ticket(ctx, ccache, service_principal, enctype, &outbuf)) != 0) {
611                 DEBUG(3, ("verify_service_password: get_service_ticket failed: %s\n", 
612                         error_message(err)));
613                 goto out;
614         }
615
616         /* At this point we have a message to ourselves, salted only the KDC knows how. We
617            have to work out what that salting is. */
618
619         /* Try and find the correct salting principal. */
620         for (i = 0; i < sizeof(salting_principals) / sizeof(salting_principals[i]); i++) {
621                 if (verify_service_password(ctx, enctype, salting_principals[i], &outbuf)) {
622                         break;
623                 }
624         }
625
626         /* If we failed to get a match, return. */
627         if (i >= sizeof(salting_principals) / sizeof(salting_principals[i])) {
628                 goto out;
629         }
630
631         /* If we succeeded, store the principal for use for all enctypes which
632          * share the same cipher and string-to-key function.  Doing this here
633          * allows servers which just pass a keytab to krb5_rd_req() to work
634          * correctly. */
635         for (j = 0; enctypes[j] != 0; j++) {
636                 if (enctype != enctypes[j]) {
637                         /* If this enctype isn't compatible with the one which
638                          * we used, skip it. */
639
640                         if (!kerberos_compatible_enctypes(ctx, enctypes[j], enctype))
641                                 continue;
642                 }
643                 /* If the principal which gives us the proper salt is the one
644                  * which we would normally guess, don't bother noting anything
645                  * in the secrets tdb. */
646                 if (strcmp(service_principal, salting_principals[i]) != 0) {
647                         kerberos_secrets_store_salting_principal(service_principal,
648                                                                 enctypes[j],
649                                                                 salting_principals[i]);
650                 }
651         }
652
653  out :
654
655         kerberos_free_data_contents(ctx, &outbuf);
656         SAFE_FREE(salting_principals[0]);
657         SAFE_FREE(salting_principals[1]);
658         SAFE_FREE(salting_principals[2]);
659         SAFE_FREE(second_principal);
660 }
661
662 /************************************************************************
663  Go through all the possible enctypes for this principal.
664  ************************************************************************/
665
666 static void kerberos_derive_salting_principal_direct(krb5_context context,
667                                         krb5_ccache ccache,
668                                         krb5_enctype *enctypes,
669                                         char *service_principal)
670 {
671         int i;
672
673         /* Try for each enctype separately, because the rules are
674          * different for different enctypes. */
675         for (i = 0; enctypes[i] != 0; i++) {
676                 /* Delete secrets entry first. */
677                 kerberos_secrets_store_salting_principal(service_principal, 0, NULL);
678 #ifdef ENCTYPE_ARCFOUR_HMAC
679                 if (enctypes[i] == ENCTYPE_ARCFOUR_HMAC) {
680                         /* Of course this'll always work, so just save
681                          * ourselves the effort. */
682                         continue;
683                 }
684 #endif
685                 /* Try to figure out what's going on with this
686                  * principal. */
687                 kerberos_derive_salting_principal_for_enctype(service_principal,
688                                                                 context,
689                                                                 ccache,
690                                                                 enctypes[i],
691                                                                 enctypes);
692         }
693 }
694
695 /************************************************************************
696  Wrapper function for the above.
697  ************************************************************************/
698
699 BOOL kerberos_derive_salting_principal(char *service_principal)
700 {
701         krb5_context context = NULL;
702         krb5_enctype *enctypes = NULL;
703         krb5_ccache ccache = NULL;
704         krb5_error_code ret = 0;
705
706         initialize_krb5_error_table();
707         if ((ret = krb5_init_context(&context)) != 0) {
708                 DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n",
709                         error_message(ret)));
710                 return False;
711         }
712         if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) {
713                 DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n",
714                         error_message(ret)));
715                 goto out;
716         }
717
718         if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) {
719                 DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n", 
720                         LIBADS_CCACHE_NAME, error_message(ret)));
721                 goto out;
722         }
723
724         kerberos_derive_salting_principal_direct(context, ccache, enctypes, service_principal);
725
726   out: 
727         if (enctypes) {
728                 free_kerberos_etypes(context, enctypes);
729         }
730         if (ccache) {
731                 krb5_cc_destroy(context, ccache);
732         }
733         if (context) {
734                 krb5_free_context(context);
735         }
736
737         return ret ? False : True;
738 }
739
740 /************************************************************************
741  Core function to try and determine what salt is being used for any keytab
742  keys.
743  ************************************************************************/
744
745 BOOL kerberos_derive_cifs_salting_principals(void)
746 {
747         fstring my_fqdn;
748         char *service = NULL;
749         krb5_context context = NULL;
750         krb5_enctype *enctypes = NULL;
751         krb5_ccache ccache = NULL;
752         krb5_error_code ret = 0;
753         BOOL retval = False;
754
755         initialize_krb5_error_table();
756         if ((ret = krb5_init_context(&context)) != 0) {
757                 DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n",
758                         error_message(ret)));
759                 return False;
760         }
761         if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) {
762                 DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n",
763                         error_message(ret)));
764                 goto out;
765         }
766
767         if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) {
768                 DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n", 
769                         LIBADS_CCACHE_NAME, error_message(ret)));
770                 goto out;
771         }
772
773         if (asprintf(&service, "%s$", global_myname()) != -1) {
774                 strlower_m(service);
775                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
776                 SAFE_FREE(service);
777         }
778         if (asprintf(&service, "cifs/%s", global_myname()) != -1) {
779                 strlower_m(service);
780                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
781                 SAFE_FREE(service);
782         }
783         if (asprintf(&service, "host/%s", global_myname()) != -1) {
784                 strlower_m(service);
785                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
786                 SAFE_FREE(service);
787         }
788         if (asprintf(&service, "cifs/%s.%s", global_myname(), lp_realm()) != -1) {
789                 strlower_m(service);
790                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
791                 SAFE_FREE(service);
792         }
793         if (asprintf(&service, "host/%s.%s", global_myname(), lp_realm()) != -1) {
794                 strlower_m(service);
795                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
796                 SAFE_FREE(service);
797         }
798         name_to_fqdn(my_fqdn, global_myname());
799         if (asprintf(&service, "cifs/%s", my_fqdn) != -1) {
800                 strlower_m(service);
801                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
802                 SAFE_FREE(service);
803         }
804         if (asprintf(&service, "host/%s", my_fqdn) != -1) {
805                 strlower_m(service);
806                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
807                 SAFE_FREE(service);
808         }
809
810         retval = True;
811
812   out: 
813         if (enctypes) {
814                 free_kerberos_etypes(context, enctypes);
815         }
816         if (ccache) {
817                 krb5_cc_destroy(context, ccache);
818         }
819         if (context) {
820                 krb5_free_context(context);
821         }
822         return retval;
823 }
824
825 int kerberos_kinit_password(const char *principal,
826                             const char *password,
827                             int time_offset,
828                             const char *cache_name)
829 {
830         return kerberos_kinit_password_ext(principal, 
831                                            password, 
832                                            time_offset, 
833                                            0, 
834                                            0,
835                                            cache_name,
836                                            False,
837                                            False,
838                                            0);
839 }
840
841 #endif