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