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