r15240: Correctly disallow unauthorized access when logging on with the
[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                 return KRB5_LIBOS_CANTREADPWD;
199         }
200         
201         ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
202                         &ads->auth.expire, NULL, NULL, False, False, ads->auth.renewable);
203
204         if (ret) {
205                 DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
206                          s, error_message(ret)));
207         }
208         free(s);
209         return ret;
210 }
211
212 int ads_kdestroy(const char *cc_name)
213 {
214         krb5_error_code code;
215         krb5_context ctx = NULL;
216         krb5_ccache cc = NULL;
217
218         initialize_krb5_error_table();
219         if ((code = krb5_init_context (&ctx))) {
220                 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
221                         error_message(code)));
222                 return code;
223         }
224   
225         if (!cc_name) {
226                 if ((code = krb5_cc_default(ctx, &cc))) {
227                         krb5_free_context(ctx);
228                         return code;
229                 }
230         } else {
231                 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
232                         DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
233                                   error_message(code)));
234                         krb5_free_context(ctx);
235                         return code;
236                 }
237         }
238
239         if ((code = krb5_cc_destroy (ctx, cc))) {
240                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
241                         error_message(code)));
242         }
243
244         krb5_free_context (ctx);
245         return code;
246 }
247
248 /************************************************************************
249  Routine to fetch the salting principal for a service.  Active
250  Directory may use a non-obvious principal name to generate the salt
251  when it determines the key to use for encrypting tickets for a service,
252  and hopefully we detected that when we joined the domain.
253  ************************************************************************/
254
255 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
256 {
257         char *key = NULL;
258         char *ret = NULL;
259
260         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
261         if (!key) {
262                 return NULL;
263         }
264         ret = (char *)secrets_fetch(key, NULL);
265         SAFE_FREE(key);
266         return ret;
267 }
268
269 /************************************************************************
270  Routine to get the salting principal for this service.  Active
271  Directory may use a non-obvious principal name to generate the salt
272  when it determines the key to use for encrypting tickets for a service,
273  and hopefully we detected that when we joined the domain.
274  Caller must free if return is not null.
275  ************************************************************************/
276
277 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
278                                                         krb5_principal host_princ,
279                                                         int enctype)
280 {
281         char *unparsed_name = NULL, *salt_princ_s = NULL;
282         krb5_principal ret_princ = NULL;
283
284         if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
285                 return (krb5_principal)NULL;
286         }
287
288         if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
289                 SAFE_FREE(unparsed_name);
290                 return (krb5_principal)NULL;
291         }
292
293         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
294                 SAFE_FREE(unparsed_name);
295                 SAFE_FREE(salt_princ_s);
296                 return (krb5_principal)NULL;
297         }
298         SAFE_FREE(unparsed_name);
299         SAFE_FREE(salt_princ_s);
300         return ret_princ;
301 }
302
303 /************************************************************************
304  Routine to set the salting principal for this service.  Active
305  Directory may use a non-obvious principal name to generate the salt
306  when it determines the key to use for encrypting tickets for a service,
307  and hopefully we detected that when we joined the domain.
308  Setting principal to NULL deletes this entry.
309  ************************************************************************/
310
311 BOOL kerberos_secrets_store_salting_principal(const char *service,
312                                               int enctype,
313                                               const char *principal)
314 {
315         char *key = NULL;
316         BOOL ret = False;
317         krb5_context context = NULL;
318         krb5_principal princ = NULL;
319         char *princ_s = NULL;
320         char *unparsed_name = NULL;
321
322         krb5_init_context(&context);
323         if (!context) {
324                 return False;
325         }
326         if (strchr_m(service, '@')) {
327                 asprintf(&princ_s, "%s", service);
328         } else {
329                 asprintf(&princ_s, "%s@%s", service, lp_realm());
330         }
331
332         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
333                 goto out;
334                 
335         }
336         if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
337                 goto out;
338         }
339
340         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
341         if (!key)  {
342                 goto out;
343         }
344
345         if ((principal != NULL) && (strlen(principal) > 0)) {
346                 ret = secrets_store(key, principal, strlen(principal) + 1);
347         } else {
348                 ret = secrets_delete(key);
349         }
350
351  out:
352
353         SAFE_FREE(key);
354         SAFE_FREE(princ_s);
355         SAFE_FREE(unparsed_name);
356
357         if (context) {
358                 krb5_free_context(context);
359         }
360
361         return ret;
362 }
363
364 /************************************************************************
365  Routine to get initial credentials as a service ticket for the local machine.
366  Returns a buffer initialized with krb5_mk_req_extended.
367  ************************************************************************/
368
369 static krb5_error_code get_service_ticket(krb5_context ctx,
370                                         krb5_ccache ccache,
371                                         const char *service_principal,
372                                         int enctype,
373                                         krb5_data *p_outbuf)
374 {
375         krb5_creds creds, *new_creds = NULL;
376         char *service_s = NULL;
377         char *machine_account = NULL, *password = NULL;
378         krb5_data in_data;
379         krb5_auth_context auth_context = NULL;
380         krb5_error_code err = 0;
381
382         ZERO_STRUCT(creds);
383
384         asprintf(&machine_account, "%s$@%s", global_myname(), lp_realm());
385         if (machine_account == NULL) {
386                 goto out;
387         }
388         password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
389         if (password == NULL) {
390                 goto out;
391         }
392         if ((err = kerberos_kinit_password(machine_account, password, 
393                                            0, LIBADS_CCACHE_NAME)) != 0) {
394                 DEBUG(0,("get_service_ticket: kerberos_kinit_password %s failed: %s\n", 
395                         machine_account,
396                         error_message(err)));
397                 goto out;
398         }
399
400         /* Ok - the above call has gotten a TGT. Now we need to get a service
401            ticket to ourselves. */
402
403         /* Set up the enctype and client and server principal fields for krb5_get_credentials. */
404         kerberos_set_creds_enctype(&creds, enctype);
405
406         if ((err = krb5_cc_get_principal(ctx, ccache, &creds.client))) {
407                 DEBUG(3, ("get_service_ticket: krb5_cc_get_principal failed: %s\n", 
408                         error_message(err)));
409                 goto out;
410         }
411
412         if (strchr_m(service_principal, '@')) {
413                 asprintf(&service_s, "%s", service_principal);
414         } else {
415                 asprintf(&service_s, "%s@%s", service_principal, lp_realm());
416         }
417
418         if ((err = smb_krb5_parse_name(ctx, service_s, &creds.server))) {
419                 DEBUG(0,("get_service_ticket: smb_krb5_parse_name %s failed: %s\n", 
420                         service_s, error_message(err)));
421                 goto out;
422         }
423
424         if ((err = krb5_get_credentials(ctx, 0, ccache, &creds, &new_creds))) {
425                 DEBUG(5,("get_service_ticket: krb5_get_credentials for %s enctype %d failed: %s\n", 
426                         service_s, enctype, error_message(err)));
427                 goto out;
428         }
429
430         memset(&in_data, '\0', sizeof(in_data));
431         if ((err = krb5_mk_req_extended(ctx, &auth_context, 0, &in_data,
432                         new_creds, p_outbuf)) != 0) {
433                 DEBUG(0,("get_service_ticket: krb5_mk_req_extended failed: %s\n", 
434                         error_message(err)));
435                 goto out;
436         }
437
438  out:
439
440         if (auth_context) {
441                 krb5_auth_con_free(ctx, auth_context);
442         }
443         if (new_creds) {
444                 krb5_free_creds(ctx, new_creds);
445         }
446         if (creds.server) {
447                 krb5_free_principal(ctx, creds.server);
448         }
449         if (creds.client) {
450                 krb5_free_principal(ctx, creds.client);
451         }
452
453         SAFE_FREE(service_s);
454         SAFE_FREE(password);
455         SAFE_FREE(machine_account);
456         return err;
457 }
458
459 /************************************************************************
460  Check if the machine password can be used in conjunction with the salting_principal
461  to generate a key which will successfully decrypt the AP_REQ already
462  gotten as a message to the local machine.
463  ************************************************************************/
464
465 static BOOL verify_service_password(krb5_context ctx,
466                                     int enctype,
467                                     const char *salting_principal,
468                                     krb5_data *in_data)
469 {
470         BOOL ret = False;
471         krb5_principal salting_kprinc = NULL;
472         krb5_ticket *ticket = NULL;
473         krb5_keyblock key;
474         krb5_data passdata;
475         char *salting_s = NULL;
476         char *machine_account = NULL, *password = NULL;
477         krb5_auth_context auth_context = NULL;
478         krb5_error_code err;
479
480         memset(&passdata, '\0', sizeof(passdata));
481         memset(&key, '\0', sizeof(key));
482
483         asprintf(&machine_account, "%s$@%s", global_myname(), lp_realm());
484         if (machine_account == NULL) {
485                 goto out;
486         }
487         password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
488         if (password == NULL) {
489                 goto out;
490         }
491
492         if (strchr_m(salting_principal, '@')) {
493                 asprintf(&salting_s, "%s", salting_principal);
494         } else {
495                 asprintf(&salting_s, "%s@%s", salting_principal, lp_realm());
496         }
497
498         if ((err = smb_krb5_parse_name(ctx, salting_s, &salting_kprinc))) {
499                 DEBUG(0,("verify_service_password: smb_krb5_parse_name %s failed: %s\n", 
500                         salting_s, error_message(err)));
501                 goto out;
502         }
503
504         passdata.length = strlen(password);
505         passdata.data = (char*)password;
506         if ((err = create_kerberos_key_from_string_direct(ctx, salting_kprinc, &passdata, &key, enctype))) {
507                 DEBUG(0,("verify_service_password: create_kerberos_key_from_string %d failed: %s\n",
508                         enctype, error_message(err)));
509                 goto out;
510         }
511
512         if ((err = krb5_auth_con_init(ctx, &auth_context)) != 0) {
513                 DEBUG(0,("verify_service_password: krb5_auth_con_init failed %s\n", error_message(err)));
514                 goto out;
515         }
516
517         if ((err = krb5_auth_con_setuseruserkey(ctx, auth_context, &key)) != 0) {
518                 DEBUG(0,("verify_service_password: krb5_auth_con_setuseruserkey failed %s\n", error_message(err)));
519                 goto out;
520         }
521
522         if (!(err = krb5_rd_req(ctx, &auth_context, in_data, NULL, NULL, NULL, &ticket))) {
523                 DEBUG(10,("verify_service_password: decrypted message with enctype %u salt %s!\n",
524                                 (unsigned int)enctype, salting_s));
525                 ret = True;
526         }
527
528  out:
529
530         memset(&passdata, 0, sizeof(passdata));
531         krb5_free_keyblock_contents(ctx, &key);
532         if (ticket != NULL) {
533                 krb5_free_ticket(ctx, ticket);
534         }
535         if (salting_kprinc) {
536                 krb5_free_principal(ctx, salting_kprinc);
537         }
538         SAFE_FREE(salting_s);
539         SAFE_FREE(password);
540         SAFE_FREE(machine_account);
541         return ret;
542 }
543
544 /************************************************************************
545  *
546  * From the current draft of kerberos-clarifications:
547  *
548  *     It is not possible to reliably generate a user's key given a pass
549  *     phrase without contacting the KDC, since it will not be known
550  *     whether alternate salt or parameter values are required.
551  *
552  * And because our server has a password, we have this exact problem.  We
553  * make multiple guesses as to which principal name provides the salt which
554  * the KDC is using.
555  *
556  ************************************************************************/
557
558 static void kerberos_derive_salting_principal_for_enctype(const char *service_principal,
559                                                           krb5_context ctx,
560                                                           krb5_ccache ccache,
561                                                           krb5_enctype enctype,
562                                                           krb5_enctype *enctypes)
563 {
564         char *salting_principals[3] = {NULL, NULL, NULL}, *second_principal = NULL;
565         krb5_error_code err = 0;
566         krb5_data outbuf;
567         int i, j;
568
569         memset(&outbuf, '\0', sizeof(outbuf));
570
571         /* Check that the service_principal is useful. */
572         if ((service_principal == NULL) || (strlen(service_principal) == 0)) {
573                 return;
574         }
575
576         /* Generate our first guess -- the principal as-given. */
577         asprintf(&salting_principals[0], "%s", service_principal);
578         if ((salting_principals[0] == NULL) || (strlen(salting_principals[0]) == 0)) {
579                 return;
580         }
581
582         /* Generate our second guess -- the computer's principal, as Win2k3. */
583         asprintf(&second_principal, "host/%s.%s", global_myname(), lp_realm());
584         if (second_principal != NULL) {
585                 strlower_m(second_principal);
586                 asprintf(&salting_principals[1], "%s@%s", second_principal, lp_realm());
587                 SAFE_FREE(second_principal);
588         }
589         if ((salting_principals[1] == NULL) || (strlen(salting_principals[1]) == 0)) {
590                 goto out;
591         }
592
593         /* Generate our third guess -- the computer's principal, as Win2k. */
594         asprintf(&second_principal, "HOST/%s", global_myname());
595         if (second_principal != NULL) {
596                 strlower_m(second_principal + 5);
597                 asprintf(&salting_principals[2], "%s@%s",
598                         second_principal, lp_realm());
599                 SAFE_FREE(second_principal);
600         }
601         if ((salting_principals[2] == NULL) || (strlen(salting_principals[2]) == 0)) {
602                 goto out;
603         }
604
605         /* Get a service ticket for ourselves into our memory ccache. */
606         /* This will commonly fail if there is no principal by that name (and we're trying
607            many names). So don't print a debug 0 error. */
608
609         if ((err = get_service_ticket(ctx, ccache, service_principal, enctype, &outbuf)) != 0) {
610                 DEBUG(3, ("verify_service_password: get_service_ticket failed: %s\n", 
611                         error_message(err)));
612                 goto out;
613         }
614
615         /* At this point we have a message to ourselves, salted only the KDC knows how. We
616            have to work out what that salting is. */
617
618         /* Try and find the correct salting principal. */
619         for (i = 0; i < sizeof(salting_principals) / sizeof(salting_principals[i]); i++) {
620                 if (verify_service_password(ctx, enctype, salting_principals[i], &outbuf)) {
621                         break;
622                 }
623         }
624
625         /* If we failed to get a match, return. */
626         if (i >= sizeof(salting_principals) / sizeof(salting_principals[i])) {
627                 goto out;
628         }
629
630         /* If we succeeded, store the principal for use for all enctypes which
631          * share the same cipher and string-to-key function.  Doing this here
632          * allows servers which just pass a keytab to krb5_rd_req() to work
633          * correctly. */
634         for (j = 0; enctypes[j] != 0; j++) {
635                 if (enctype != enctypes[j]) {
636                         /* If this enctype isn't compatible with the one which
637                          * we used, skip it. */
638
639                         if (!kerberos_compatible_enctypes(ctx, enctypes[j], enctype))
640                                 continue;
641                 }
642                 /* If the principal which gives us the proper salt is the one
643                  * which we would normally guess, don't bother noting anything
644                  * in the secrets tdb. */
645                 if (strcmp(service_principal, salting_principals[i]) != 0) {
646                         kerberos_secrets_store_salting_principal(service_principal,
647                                                                 enctypes[j],
648                                                                 salting_principals[i]);
649                 }
650         }
651
652  out :
653
654         kerberos_free_data_contents(ctx, &outbuf);
655         SAFE_FREE(salting_principals[0]);
656         SAFE_FREE(salting_principals[1]);
657         SAFE_FREE(salting_principals[2]);
658         SAFE_FREE(second_principal);
659 }
660
661 /************************************************************************
662  Go through all the possible enctypes for this principal.
663  ************************************************************************/
664
665 static void kerberos_derive_salting_principal_direct(krb5_context context,
666                                         krb5_ccache ccache,
667                                         krb5_enctype *enctypes,
668                                         char *service_principal)
669 {
670         int i;
671
672         /* Try for each enctype separately, because the rules are
673          * different for different enctypes. */
674         for (i = 0; enctypes[i] != 0; i++) {
675                 /* Delete secrets entry first. */
676                 kerberos_secrets_store_salting_principal(service_principal, 0, NULL);
677 #ifdef ENCTYPE_ARCFOUR_HMAC
678                 if (enctypes[i] == ENCTYPE_ARCFOUR_HMAC) {
679                         /* Of course this'll always work, so just save
680                          * ourselves the effort. */
681                         continue;
682                 }
683 #endif
684                 /* Try to figure out what's going on with this
685                  * principal. */
686                 kerberos_derive_salting_principal_for_enctype(service_principal,
687                                                                 context,
688                                                                 ccache,
689                                                                 enctypes[i],
690                                                                 enctypes);
691         }
692 }
693
694 /************************************************************************
695  Wrapper function for the above.
696  ************************************************************************/
697
698 BOOL kerberos_derive_salting_principal(char *service_principal)
699 {
700         krb5_context context = NULL;
701         krb5_enctype *enctypes = NULL;
702         krb5_ccache ccache = NULL;
703         krb5_error_code ret = 0;
704
705         initialize_krb5_error_table();
706         if ((ret = krb5_init_context(&context)) != 0) {
707                 DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n",
708                         error_message(ret)));
709                 return False;
710         }
711         if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) {
712                 DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n",
713                         error_message(ret)));
714                 goto out;
715         }
716
717         if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) {
718                 DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n", 
719                         LIBADS_CCACHE_NAME, error_message(ret)));
720                 goto out;
721         }
722
723         kerberos_derive_salting_principal_direct(context, ccache, enctypes, service_principal);
724
725   out: 
726         if (enctypes) {
727                 free_kerberos_etypes(context, enctypes);
728         }
729         if (ccache) {
730                 krb5_cc_destroy(context, ccache);
731         }
732         if (context) {
733                 krb5_free_context(context);
734         }
735
736         return ret ? False : True;
737 }
738
739 /************************************************************************
740  Core function to try and determine what salt is being used for any keytab
741  keys.
742  ************************************************************************/
743
744 BOOL kerberos_derive_cifs_salting_principals(void)
745 {
746         fstring my_fqdn;
747         char *service = NULL;
748         krb5_context context = NULL;
749         krb5_enctype *enctypes = NULL;
750         krb5_ccache ccache = NULL;
751         krb5_error_code ret = 0;
752         BOOL retval = False;
753
754         initialize_krb5_error_table();
755         if ((ret = krb5_init_context(&context)) != 0) {
756                 DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n",
757                         error_message(ret)));
758                 return False;
759         }
760         if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) {
761                 DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n",
762                         error_message(ret)));
763                 goto out;
764         }
765
766         if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) {
767                 DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n", 
768                         LIBADS_CCACHE_NAME, error_message(ret)));
769                 goto out;
770         }
771
772         if (asprintf(&service, "%s$", global_myname()) != -1) {
773                 strlower_m(service);
774                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
775                 SAFE_FREE(service);
776         }
777         if (asprintf(&service, "cifs/%s", global_myname()) != -1) {
778                 strlower_m(service);
779                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
780                 SAFE_FREE(service);
781         }
782         if (asprintf(&service, "host/%s", global_myname()) != -1) {
783                 strlower_m(service);
784                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
785                 SAFE_FREE(service);
786         }
787         if (asprintf(&service, "cifs/%s.%s", global_myname(), lp_realm()) != -1) {
788                 strlower_m(service);
789                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
790                 SAFE_FREE(service);
791         }
792         if (asprintf(&service, "host/%s.%s", global_myname(), lp_realm()) != -1) {
793                 strlower_m(service);
794                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
795                 SAFE_FREE(service);
796         }
797         name_to_fqdn(my_fqdn, global_myname());
798         if (asprintf(&service, "cifs/%s", my_fqdn) != -1) {
799                 strlower_m(service);
800                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
801                 SAFE_FREE(service);
802         }
803         if (asprintf(&service, "host/%s", my_fqdn) != -1) {
804                 strlower_m(service);
805                 kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
806                 SAFE_FREE(service);
807         }
808
809         retval = True;
810
811   out: 
812         if (enctypes) {
813                 free_kerberos_etypes(context, enctypes);
814         }
815         if (ccache) {
816                 krb5_cc_destroy(context, ccache);
817         }
818         if (context) {
819                 krb5_free_context(context);
820         }
821         return retval;
822 }
823
824 int kerberos_kinit_password(const char *principal,
825                             const char *password,
826                             int time_offset,
827                             const char *cache_name)
828 {
829         return kerberos_kinit_password_ext(principal, 
830                                            password, 
831                                            time_offset, 
832                                            0, 
833                                            0,
834                                            cache_name,
835                                            False,
836                                            False,
837                                            0);
838 }
839
840 #endif