Add two new parameters to control how we verify kerberos tickets. Removes lp_use_kerb...
[ira/wip.git] / source3 / libads / kerberos_verify.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) Luke Howard 2003   
7    Copyright (C) Guenther Deschner 2003, 2005
8    Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003
9    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
10    Copyright (C) Jeremy Allison 2007
11    
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16    
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21    
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27
28 #ifdef HAVE_KRB5
29
30 #if !defined(HAVE_KRB5_PRINC_COMPONENT)
31 const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int );
32 #endif
33
34 static bool ads_dedicated_keytab_verify_ticket(krb5_context context,
35                                           krb5_auth_context auth_context,
36                                           const DATA_BLOB *ticket,
37                                           krb5_ticket **pp_tkt,
38                                           krb5_keyblock **keyblock,
39                                           krb5_error_code *perr)
40 {
41         krb5_error_code ret = 0;
42         bool auth_ok = false;
43         krb5_keytab keytab = NULL;
44         krb5_keytab_entry kt_entry;
45         krb5_ticket *dec_ticket = NULL;
46
47         krb5_data packet;
48
49         *pp_tkt = NULL;
50         *keyblock = NULL;
51         *perr = 0;
52
53         ZERO_STRUCT(kt_entry);
54
55         ret = smb_krb5_open_keytab(context, lp_dedicated_keytab_file(), true,
56             &keytab);
57         if (ret) {
58                 DEBUG(1, ("smb_krb5_open_keytab failed (%s)\n",
59                         error_message(ret)));
60                 goto out;
61         }
62
63         packet.length = ticket->length;
64         packet.data = (char *)ticket->data;
65         *pp_tkt = NULL;
66
67         ret = krb5_rd_req(context, &auth_context, &packet, NULL, keytab,
68             NULL, &dec_ticket);
69         if (ret) {
70                 DEBUG(0, ("krb5_rd_req failed (%s)\n", error_message(ret)));
71                 goto out;
72         }
73
74         /* Get the key for checking the pac signature */
75         ret = krb5_kt_get_entry(context, keytab, dec_ticket->server,
76             dec_ticket->enc_part.kvno, dec_ticket->enc_part.enctype,
77             &kt_entry);
78         if (ret) {
79                 DEBUG(0, ("krb5_kt_get_entry failed (%s)\n",
80                           error_message(ret)));
81                 goto out;
82         }
83
84 #ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
85         ret = krb5_copy_keyblock(context, &kt_entry.keyblock, keyblock);
86 #elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) /* MIT */
87         ret = krb5_copy_keyblock(context, &kt_entry.key, keyblock);
88 #else
89 #error UNKNOWN_KRB5_KEYTAB_ENTRY_FORMAT
90 #endif
91         smb_krb5_kt_free_entry(context, &kt_entry);
92
93         if (ret) {
94                 DEBUG(0, ("failed to copy key: %s\n",
95                           error_message(ret)));
96                 goto out;
97         }
98
99         auth_ok = true;
100         *pp_tkt = dec_ticket;
101         dec_ticket = NULL;
102
103   out:
104         if (dec_ticket)
105                 krb5_free_ticket(context, dec_ticket);
106
107         if (keytab)
108                 krb5_kt_close(context, keytab);
109
110         *perr = ret;
111         return auth_ok;
112 }
113
114 /**********************************************************************************
115  Try to verify a ticket using the system keytab... the system keytab has kvno -1 entries, so
116  it's more like what microsoft does... see comment in utils/net_ads.c in the
117  ads_keytab_add_entry function for details.
118 ***********************************************************************************/
119
120 static bool ads_keytab_verify_ticket(krb5_context context,
121                                         krb5_auth_context auth_context,
122                                         const DATA_BLOB *ticket,
123                                         krb5_ticket **pp_tkt,
124                                         krb5_keyblock **keyblock,
125                                         krb5_error_code *perr)
126 {
127         krb5_error_code ret = 0;
128         bool auth_ok = False;
129         krb5_keytab keytab = NULL;
130         krb5_kt_cursor kt_cursor;
131         krb5_keytab_entry kt_entry;
132         char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
133         char *entry_princ_s = NULL;
134         fstring my_name, my_fqdn;
135         int i;
136         int number_matched_principals = 0;
137         krb5_data packet;
138
139         *pp_tkt = NULL;
140         *keyblock = NULL;
141         *perr = 0;
142
143         /* Generate the list of principal names which we expect
144          * clients might want to use for authenticating to the file
145          * service.  We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */
146
147         fstrcpy(my_name, global_myname());
148
149         my_fqdn[0] = '\0';
150         name_to_fqdn(my_fqdn, global_myname());
151
152         if (asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm()) == -1) {
153                 goto out;
154         }
155         if (asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm()) == -1) {
156                 goto out;
157         }
158         if (asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm()) == -1) {
159                 goto out;
160         }
161         if (asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) {
162                 goto out;
163         }
164         if (asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm()) == -1) {
165                 goto out;
166         }
167         if (asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm()) == -1) {
168                 goto out;
169         }
170         if (asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) {
171                 goto out;
172         }
173
174         ZERO_STRUCT(kt_entry);
175         ZERO_STRUCT(kt_cursor);
176
177         ret = smb_krb5_open_keytab(context, NULL, False, &keytab);
178         if (ret) {
179                 DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
180                 goto out;
181         }
182
183         /* Iterate through the keytab.  For each key, if the principal
184          * name case-insensitively matches one of the allowed formats,
185          * try verifying the ticket using that principal. */
186
187         ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor);
188         if (ret) {
189                 DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret)));
190                 goto out;
191         }
192   
193         while (!auth_ok && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) {
194                 ret = smb_krb5_unparse_name(context, kt_entry.principal, &entry_princ_s);
195                 if (ret) {
196                         DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_unparse_name failed (%s)\n",
197                                 error_message(ret)));
198                         goto out;
199                 }
200
201                 for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
202
203                         if (!strequal(entry_princ_s, valid_princ_formats[i])) {
204                                 continue;
205                         }
206
207                         number_matched_principals++;
208                         packet.length = ticket->length;
209                         packet.data = (char *)ticket->data;
210                         *pp_tkt = NULL;
211
212                         ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet,
213                                                                       kt_entry.principal, keytab,
214                                                                       NULL, pp_tkt, keyblock);
215
216                         if (ret) {
217                                 DEBUG(10,("ads_keytab_verify_ticket: "
218                                         "krb5_rd_req_return_keyblock_from_keytab(%s) failed: %s\n",
219                                         entry_princ_s, error_message(ret)));
220
221                                 /* workaround for MIT: 
222                                 * as krb5_ktfile_get_entry will explicitly
223                                 * close the krb5_keytab as soon as krb5_rd_req
224                                 * has successfully decrypted the ticket but the
225                                 * ticket is not valid yet (due to clockskew)
226                                 * there is no point in querying more keytab
227                                 * entries - Guenther */
228                                         
229                                 if (ret == KRB5KRB_AP_ERR_TKT_NYV || 
230                                     ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
231                                     ret == KRB5KRB_AP_ERR_SKEW) {
232                                         break;
233                                 }
234                         } else {
235                                 DEBUG(3,("ads_keytab_verify_ticket: "
236                                         "krb5_rd_req_return_keyblock_from_keytab succeeded for principal %s\n",
237                                         entry_princ_s));
238                                 auth_ok = True;
239                                 break;
240                         }
241                 }
242
243                 /* Free the name we parsed. */
244                 SAFE_FREE(entry_princ_s);
245
246                 /* Free the entry we just read. */
247                 smb_krb5_kt_free_entry(context, &kt_entry);
248                 ZERO_STRUCT(kt_entry);
249         }
250         krb5_kt_end_seq_get(context, keytab, &kt_cursor);
251
252         ZERO_STRUCT(kt_cursor);
253
254   out:
255         
256         for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
257                 SAFE_FREE(valid_princ_formats[i]);
258         }
259         
260         if (!auth_ok) {
261                 if (!number_matched_principals) {
262                         DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n"));
263                 } else {
264                         DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n",
265                                 number_matched_principals));
266                 }
267         }
268
269         SAFE_FREE(entry_princ_s);
270
271         {
272                 krb5_keytab_entry zero_kt_entry;
273                 ZERO_STRUCT(zero_kt_entry);
274                 if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
275                         smb_krb5_kt_free_entry(context, &kt_entry);
276                 }
277         }
278
279         {
280                 krb5_kt_cursor zero_csr;
281                 ZERO_STRUCT(zero_csr);
282                 if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
283                         krb5_kt_end_seq_get(context, keytab, &kt_cursor);
284                 }
285         }
286
287         if (keytab) {
288                 krb5_kt_close(context, keytab);
289         }
290         *perr = ret;
291         return auth_ok;
292 }
293
294 /**********************************************************************************
295  Try to verify a ticket using the secrets.tdb.
296 ***********************************************************************************/
297
298 static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
299                                                 krb5_auth_context auth_context,
300                                                 krb5_principal host_princ,
301                                                 const DATA_BLOB *ticket,
302                                                 krb5_ticket **pp_tkt,
303                                                 krb5_keyblock **keyblock,
304                                                 krb5_error_code *perr)
305 {
306         krb5_error_code ret = 0;
307         bool auth_ok = False;
308         char *password_s = NULL;
309         krb5_data password;
310         krb5_enctype enctypes[] = { 
311 #if defined(ENCTYPE_ARCFOUR_HMAC)
312                 ENCTYPE_ARCFOUR_HMAC,
313 #endif
314                 ENCTYPE_DES_CBC_CRC, 
315                 ENCTYPE_DES_CBC_MD5, 
316                 ENCTYPE_NULL
317         };
318         krb5_data packet;
319         int i;
320
321         *pp_tkt = NULL;
322         *keyblock = NULL;
323         *perr = 0;
324
325
326         if (!secrets_init()) {
327                 DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n"));
328                 *perr = KRB5_CONFIG_CANTOPEN;
329                 return False;
330         }
331
332         password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
333         if (!password_s) {
334                 DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n"));
335                 *perr = KRB5_LIBOS_CANTREADPWD;
336                 return False;
337         }
338
339         password.data = password_s;
340         password.length = strlen(password_s);
341
342         /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */
343
344         packet.length = ticket->length;
345         packet.data = (char *)ticket->data;
346
347         /* We need to setup a auth context with each possible encoding type in turn. */
348         for (i=0;enctypes[i];i++) {
349                 krb5_keyblock *key = NULL;
350
351                 if (!(key = SMB_MALLOC_P(krb5_keyblock))) {
352                         ret = ENOMEM;
353                         goto out;
354                 }
355         
356                 if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i], false)) {
357                         SAFE_FREE(key);
358                         continue;
359                 }
360
361                 krb5_auth_con_setuseruserkey(context, auth_context, key);
362
363                 if (!(ret = krb5_rd_req(context, &auth_context, &packet, 
364                                         NULL,
365                                         NULL, NULL, pp_tkt))) {
366                         DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n",
367                                 (unsigned int)enctypes[i] ));
368                         auth_ok = True;
369                         krb5_copy_keyblock(context, key, keyblock);
370                         krb5_free_keyblock(context, key);
371                         break;
372                 }
373
374                 DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10,
375                                 ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n",
376                                 (unsigned int)enctypes[i], error_message(ret)));
377
378                 /* successfully decrypted but ticket is just not valid at the moment */
379                 if (ret == KRB5KRB_AP_ERR_TKT_NYV || 
380                     ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
381                     ret == KRB5KRB_AP_ERR_SKEW) {
382                         krb5_free_keyblock(context, key);
383                         break;
384                 }
385
386                 krb5_free_keyblock(context, key);
387
388         }
389
390  out:
391         SAFE_FREE(password_s);
392         *perr = ret;
393         return auth_ok;
394 }
395
396 /**********************************************************************************
397  Verify an incoming ticket and parse out the principal name and 
398  authorization_data if available.
399 ***********************************************************************************/
400
401 NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
402                            const char *realm,
403                            time_t time_offset,
404                            const DATA_BLOB *ticket,
405                            char **principal,
406                            struct PAC_DATA **pac_data,
407                            DATA_BLOB *ap_rep,
408                            DATA_BLOB *session_key,
409                            bool use_replay_cache)
410 {
411         NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
412         NTSTATUS pac_ret;
413         DATA_BLOB auth_data;
414         krb5_context context = NULL;
415         krb5_auth_context auth_context = NULL;
416         krb5_data packet;
417         krb5_ticket *tkt = NULL;
418         krb5_rcache rcache = NULL;
419         krb5_keyblock *keyblock = NULL;
420         time_t authtime;
421         krb5_error_code ret = 0;
422         int flags = 0;  
423         krb5_principal host_princ = NULL;
424         krb5_const_principal client_principal = NULL;
425         char *host_princ_s = NULL;
426         bool auth_ok = False;
427         bool got_auth_data = False;
428         struct named_mutex *mutex = NULL;
429
430         ZERO_STRUCT(packet);
431         ZERO_STRUCT(auth_data);
432
433         *principal = NULL;
434         *pac_data = NULL;
435         *ap_rep = data_blob_null;
436         *session_key = data_blob_null;
437
438         initialize_krb5_error_table();
439         ret = krb5_init_context(&context);
440         if (ret) {
441                 DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret)));
442                 return NT_STATUS_LOGON_FAILURE;
443         }
444
445         if (time_offset != 0) {
446                 krb5_set_real_time(context, time(NULL) + time_offset, 0);
447         }
448
449         ret = krb5_set_default_realm(context, realm);
450         if (ret) {
451                 DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret)));
452                 goto out;
453         }
454
455         /* This whole process is far more complex than I would
456            like. We have to go through all this to allow us to store
457            the secret internally, instead of using /etc/krb5.keytab */
458
459         ret = krb5_auth_con_init(context, &auth_context);
460         if (ret) {
461                 DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret)));
462                 goto out;
463         }
464
465         krb5_auth_con_getflags( context, auth_context, &flags );
466         if ( !use_replay_cache ) {
467                 /* Disable default use of a replay cache */
468                 flags &= ~KRB5_AUTH_CONTEXT_DO_TIME;
469                 krb5_auth_con_setflags( context, auth_context, flags );
470         }
471
472         if (asprintf(&host_princ_s, "%s$", global_myname()) == -1) {
473                 goto out;
474         }
475
476         strlower_m(host_princ_s);
477         ret = smb_krb5_parse_name(context, host_princ_s, &host_princ);
478         if (ret) {
479                 DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n",
480                                         host_princ_s, error_message(ret)));
481                 goto out;
482         }
483
484
485         if ( use_replay_cache ) {
486                 
487                 /* Lock a mutex surrounding the replay as there is no 
488                    locking in the MIT krb5 code surrounding the replay 
489                    cache... */
490
491                 mutex = grab_named_mutex(talloc_tos(), "replay cache mutex",
492                                          10);
493                 if (mutex == NULL) {
494                         DEBUG(1,("ads_verify_ticket: unable to protect "
495                                  "replay cache with mutex.\n"));
496                         ret = KRB5_CC_IO;
497                         goto out;
498                 }
499
500                 /* JRA. We must set the rcache here. This will prevent 
501                    replay attacks. */
502                 
503                 ret = krb5_get_server_rcache(context, 
504                                              krb5_princ_component(context, host_princ, 0), 
505                                              &rcache);
506                 if (ret) {
507                         DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache "
508                                  "failed (%s)\n", error_message(ret)));
509                         goto out;
510                 }
511
512                 ret = krb5_auth_con_setrcache(context, auth_context, rcache);
513                 if (ret) {
514                         DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache "
515                                  "failed (%s)\n", error_message(ret)));
516                         goto out;
517                 }
518         }
519
520         switch (lp_kerberos_method()) {
521         default:
522         case KERBEROS_VERIFY_SECRETS:
523                 auth_ok = ads_secrets_verify_ticket(context, auth_context,
524                     host_princ, ticket, &tkt, &keyblock, &ret);
525                 break;
526         case KERBEROS_VERIFY_SYSTEM_KEYTAB:
527                 auth_ok = ads_keytab_verify_ticket(context, auth_context,
528                     ticket, &tkt, &keyblock, &ret);
529                 break;
530         case KERBEROS_VERIFY_DEDICATED_KEYTAB:
531                 auth_ok = ads_dedicated_keytab_verify_ticket(context,
532                     auth_context, ticket, &tkt, &keyblock, &ret);
533                 break;
534         case KERBEROS_VERIFY_SECRETS_AND_KEYTAB:
535                 /* First try secrets.tdb and fallback to the krb5.keytab if
536                    necessary.  This is the pre 3.4 behavior when
537                    "use kerberos keytab" was true.*/
538                 auth_ok = ads_secrets_verify_ticket(context, auth_context,
539                     host_princ, ticket, &tkt, &keyblock, &ret);
540
541                 if (!auth_ok) {
542                         /* Only fallback if we failed to decrypt the ticket */
543                         if (ret != KRB5KRB_AP_ERR_TKT_NYV &&
544                             ret != KRB5KRB_AP_ERR_TKT_EXPIRED &&
545                             ret != KRB5KRB_AP_ERR_SKEW) {
546                                 auth_ok = ads_keytab_verify_ticket(context,
547                                     auth_context, ticket, &tkt, &keyblock,
548                                     &ret);
549                         }
550                 }
551                 break;
552         }
553
554         if ( use_replay_cache ) {               
555                 TALLOC_FREE(mutex);
556 #if 0
557                 /* Heimdal leaks here, if we fix the leak, MIT crashes */
558                 if (rcache) {
559                         krb5_rc_close(context, rcache);
560                 }
561 #endif
562         }       
563
564         if (!auth_ok) {
565                 DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", 
566                          error_message(ret)));
567                 /* Try map the error return in case it's something like
568                  * a clock skew error.
569                  */
570                 sret = krb5_to_nt_status(ret);
571                 if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) {
572                         sret = NT_STATUS_LOGON_FAILURE;
573                 }
574                 DEBUG(10,("ads_verify_ticket: returning error %s\n",
575                         nt_errstr(sret) ));
576                 goto out;
577         } 
578         
579         authtime = get_authtime_from_tkt(tkt);
580         client_principal = get_principal_from_tkt(tkt);
581
582         ret = krb5_mk_rep(context, auth_context, &packet);
583         if (ret) {
584                 DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
585                         error_message(ret)));
586                 goto out;
587         }
588
589         *ap_rep = data_blob(packet.data, packet.length);
590         if (packet.data) {
591                 kerberos_free_data_contents(context, &packet);
592                 ZERO_STRUCT(packet);
593         }
594
595         get_krb5_smb_session_key(context, auth_context, session_key, True);
596         dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length);
597
598 #if 0
599         file_save("/tmp/ticket.dat", ticket->data, ticket->length);
600 #endif
601
602         /* continue when no PAC is retrieved or we couldn't decode the PAC 
603            (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or
604            Kerberos tickets encrypted using a DES key) - Guenther */
605
606         got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt);
607         if (!got_auth_data) {
608                 DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n"));
609         }
610
611         if (got_auth_data) {
612                 pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data);
613                 if (!NT_STATUS_IS_OK(pac_ret)) {
614                         DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret)));
615                         *pac_data = NULL;
616                 }
617                 data_blob_free(&auth_data);
618         }
619
620 #if 0
621 #if defined(HAVE_KRB5_TKT_ENC_PART2)
622         /* MIT */
623         if (tkt->enc_part2) {
624                 file_save("/tmp/authdata.dat",
625                           tkt->enc_part2->authorization_data[0]->contents,
626                           tkt->enc_part2->authorization_data[0]->length);
627         }
628 #else
629         /* Heimdal */
630         if (tkt->ticket.authorization_data) {
631                 file_save("/tmp/authdata.dat",
632                           tkt->ticket.authorization_data->val->ad_data.data,
633                           tkt->ticket.authorization_data->val->ad_data.length);
634         }
635 #endif
636 #endif
637
638         if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) {
639                 DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", 
640                          error_message(ret)));
641                 sret = NT_STATUS_LOGON_FAILURE;
642                 goto out;
643         }
644
645         sret = NT_STATUS_OK;
646
647  out:
648
649         TALLOC_FREE(mutex);
650
651         if (!NT_STATUS_IS_OK(sret)) {
652                 data_blob_free(&auth_data);
653         }
654
655         if (!NT_STATUS_IS_OK(sret)) {
656                 data_blob_free(ap_rep);
657         }
658
659         if (host_princ) {
660                 krb5_free_principal(context, host_princ);
661         }
662
663         if (keyblock) {
664                 krb5_free_keyblock(context, keyblock);
665         }
666
667         if (tkt != NULL) {
668                 krb5_free_ticket(context, tkt);
669         }
670
671         SAFE_FREE(host_princ_s);
672
673         if (auth_context) {
674                 krb5_auth_con_free(context, auth_context);
675         }
676
677         if (context) {
678                 krb5_free_context(context);
679         }
680
681         return sret;
682 }
683
684 #endif /* HAVE_KRB5 */