s3: Allow previous password to be stored and use it to check tickets
[kamenim/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         bool cont = true;
311         char *password_s = NULL;
312         /* Let's make some room for 2 password (old and new)*/
313         krb5_data passwords[2];
314         krb5_enctype enctypes[] = { 
315 #if defined(ENCTYPE_ARCFOUR_HMAC)
316                 ENCTYPE_ARCFOUR_HMAC,
317 #endif
318                 ENCTYPE_DES_CBC_CRC, 
319                 ENCTYPE_DES_CBC_MD5, 
320                 ENCTYPE_NULL
321         };
322         krb5_data packet;
323         int i, j;
324
325         *pp_tkt = NULL;
326         *keyblock = NULL;
327         *perr = 0;
328
329         ZERO_STRUCT(passwords);
330
331         if (!secrets_init()) {
332                 DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n"));
333                 *perr = KRB5_CONFIG_CANTOPEN;
334                 return False;
335         }
336
337         password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
338         if (!password_s) {
339                 DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n"));
340                 *perr = KRB5_LIBOS_CANTREADPWD;
341                 return False;
342         }
343
344         passwords[0].data = password_s;
345         passwords[0].length = strlen(password_s);
346
347         password_s = secrets_fetch_prev_machine_password(lp_workgroup());
348         if (password_s) {
349                 DEBUG(10,("ads_secrets_verify_ticket: found previous password\n"));
350                 passwords[1].data = password_s;
351                 passwords[1].length = strlen(password_s);
352         }
353
354         /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */
355
356         packet.length = ticket->length;
357         packet.data = (char *)ticket->data;
358
359         /* We need to setup a auth context with each possible encoding type in turn. */
360         for (j=0; j<2 && passwords[j].length; j++) {
361
362                 for (i=0;enctypes[i];i++) {
363                         krb5_keyblock *key = NULL;
364
365                         if (!(key = SMB_MALLOC_P(krb5_keyblock))) {
366                                 ret = ENOMEM;
367                                 goto out;
368                         }
369
370                         if (create_kerberos_key_from_string(context, host_princ, &passwords[j], key, enctypes[i], false)) {
371                                 SAFE_FREE(key);
372                                 continue;
373                         }
374
375                         krb5_auth_con_setuseruserkey(context, auth_context, key);
376
377                         if (!(ret = krb5_rd_req(context, &auth_context, &packet,
378                                                 NULL,
379                                                 NULL, NULL, pp_tkt))) {
380                                 DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n",
381                                         (unsigned int)enctypes[i] ));
382                                 auth_ok = True;
383                                 cont = false;
384                                 krb5_copy_keyblock(context, key, keyblock);
385                                 krb5_free_keyblock(context, key);
386                                 break;
387                         }
388
389                         DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10,
390                                         ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n",
391                                         (unsigned int)enctypes[i], error_message(ret)));
392
393                         /* successfully decrypted but ticket is just not valid at the moment */
394                         if (ret == KRB5KRB_AP_ERR_TKT_NYV ||
395                             ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
396                             ret == KRB5KRB_AP_ERR_SKEW) {
397                                 krb5_free_keyblock(context, key);
398                                 cont = false;
399                                 break;
400                         }
401
402                         krb5_free_keyblock(context, key);
403                 }
404                 if (!cont) {
405                         /* If we found a valid pass then no need to try
406                          * the next one or we have invalid ticket so no need
407                          * to try next password*/
408                         break;
409                 }
410         }
411
412  out:
413         SAFE_FREE(passwords[0].data);
414         SAFE_FREE(passwords[1].data);
415         *perr = ret;
416         return auth_ok;
417 }
418
419 /**********************************************************************************
420  Verify an incoming ticket and parse out the principal name and 
421  authorization_data if available.
422 ***********************************************************************************/
423
424 NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
425                            const char *realm,
426                            time_t time_offset,
427                            const DATA_BLOB *ticket,
428                            char **principal,
429                            struct PAC_LOGON_INFO **logon_info,
430                            DATA_BLOB *ap_rep,
431                            DATA_BLOB *session_key,
432                            bool use_replay_cache)
433 {
434         NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
435         NTSTATUS pac_ret;
436         DATA_BLOB auth_data;
437         krb5_context context = NULL;
438         krb5_auth_context auth_context = NULL;
439         krb5_data packet;
440         krb5_ticket *tkt = NULL;
441         krb5_rcache rcache = NULL;
442         krb5_keyblock *keyblock = NULL;
443         time_t authtime;
444         krb5_error_code ret = 0;
445         int flags = 0;  
446         krb5_principal host_princ = NULL;
447         krb5_const_principal client_principal = NULL;
448         char *host_princ_s = NULL;
449         bool auth_ok = False;
450         bool got_auth_data = False;
451         struct named_mutex *mutex = NULL;
452
453         ZERO_STRUCT(packet);
454         ZERO_STRUCT(auth_data);
455
456         *principal = NULL;
457         *logon_info = NULL;
458         *ap_rep = data_blob_null;
459         *session_key = data_blob_null;
460
461         initialize_krb5_error_table();
462         ret = krb5_init_context(&context);
463         if (ret) {
464                 DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret)));
465                 return NT_STATUS_LOGON_FAILURE;
466         }
467
468         if (time_offset != 0) {
469                 krb5_set_real_time(context, time(NULL) + time_offset, 0);
470         }
471
472         ret = krb5_set_default_realm(context, realm);
473         if (ret) {
474                 DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret)));
475                 goto out;
476         }
477
478         /* This whole process is far more complex than I would
479            like. We have to go through all this to allow us to store
480            the secret internally, instead of using /etc/krb5.keytab */
481
482         ret = krb5_auth_con_init(context, &auth_context);
483         if (ret) {
484                 DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret)));
485                 goto out;
486         }
487
488         krb5_auth_con_getflags( context, auth_context, &flags );
489         if ( !use_replay_cache ) {
490                 /* Disable default use of a replay cache */
491                 flags &= ~KRB5_AUTH_CONTEXT_DO_TIME;
492                 krb5_auth_con_setflags( context, auth_context, flags );
493         }
494
495         if (asprintf(&host_princ_s, "%s$", global_myname()) == -1) {
496                 goto out;
497         }
498
499         strlower_m(host_princ_s);
500         ret = smb_krb5_parse_name(context, host_princ_s, &host_princ);
501         if (ret) {
502                 DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n",
503                                         host_princ_s, error_message(ret)));
504                 goto out;
505         }
506
507
508         if ( use_replay_cache ) {
509                 
510                 /* Lock a mutex surrounding the replay as there is no 
511                    locking in the MIT krb5 code surrounding the replay 
512                    cache... */
513
514                 mutex = grab_named_mutex(talloc_tos(), "replay cache mutex",
515                                          10);
516                 if (mutex == NULL) {
517                         DEBUG(1,("ads_verify_ticket: unable to protect "
518                                  "replay cache with mutex.\n"));
519                         ret = KRB5_CC_IO;
520                         goto out;
521                 }
522
523                 /* JRA. We must set the rcache here. This will prevent 
524                    replay attacks. */
525                 
526                 ret = krb5_get_server_rcache(context, 
527                                              krb5_princ_component(context, host_princ, 0), 
528                                              &rcache);
529                 if (ret) {
530                         DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache "
531                                  "failed (%s)\n", error_message(ret)));
532                         goto out;
533                 }
534
535                 ret = krb5_auth_con_setrcache(context, auth_context, rcache);
536                 if (ret) {
537                         DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache "
538                                  "failed (%s)\n", error_message(ret)));
539                         goto out;
540                 }
541         }
542
543         switch (lp_kerberos_method()) {
544         default:
545         case KERBEROS_VERIFY_SECRETS:
546                 auth_ok = ads_secrets_verify_ticket(context, auth_context,
547                     host_princ, ticket, &tkt, &keyblock, &ret);
548                 break;
549         case KERBEROS_VERIFY_SYSTEM_KEYTAB:
550                 auth_ok = ads_keytab_verify_ticket(context, auth_context,
551                     ticket, &tkt, &keyblock, &ret);
552                 break;
553         case KERBEROS_VERIFY_DEDICATED_KEYTAB:
554                 auth_ok = ads_dedicated_keytab_verify_ticket(context,
555                     auth_context, ticket, &tkt, &keyblock, &ret);
556                 break;
557         case KERBEROS_VERIFY_SECRETS_AND_KEYTAB:
558                 /* First try secrets.tdb and fallback to the krb5.keytab if
559                    necessary.  This is the pre 3.4 behavior when
560                    "use kerberos keytab" was true.*/
561                 auth_ok = ads_secrets_verify_ticket(context, auth_context,
562                     host_princ, ticket, &tkt, &keyblock, &ret);
563
564                 if (!auth_ok) {
565                         /* Only fallback if we failed to decrypt the ticket */
566                         if (ret != KRB5KRB_AP_ERR_TKT_NYV &&
567                             ret != KRB5KRB_AP_ERR_TKT_EXPIRED &&
568                             ret != KRB5KRB_AP_ERR_SKEW) {
569                                 auth_ok = ads_keytab_verify_ticket(context,
570                                     auth_context, ticket, &tkt, &keyblock,
571                                     &ret);
572                         }
573                 }
574                 break;
575         }
576
577         if ( use_replay_cache ) {               
578                 TALLOC_FREE(mutex);
579 #if 0
580                 /* Heimdal leaks here, if we fix the leak, MIT crashes */
581                 if (rcache) {
582                         krb5_rc_close(context, rcache);
583                 }
584 #endif
585         }       
586
587         if (!auth_ok) {
588                 DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", 
589                          error_message(ret)));
590                 /* Try map the error return in case it's something like
591                  * a clock skew error.
592                  */
593                 sret = krb5_to_nt_status(ret);
594                 if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) {
595                         sret = NT_STATUS_LOGON_FAILURE;
596                 }
597                 DEBUG(10,("ads_verify_ticket: returning error %s\n",
598                         nt_errstr(sret) ));
599                 goto out;
600         } 
601         
602         authtime = get_authtime_from_tkt(tkt);
603         client_principal = get_principal_from_tkt(tkt);
604
605         ret = krb5_mk_rep(context, auth_context, &packet);
606         if (ret) {
607                 DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
608                         error_message(ret)));
609                 goto out;
610         }
611
612         *ap_rep = data_blob(packet.data, packet.length);
613         if (packet.data) {
614                 kerberos_free_data_contents(context, &packet);
615                 ZERO_STRUCT(packet);
616         }
617
618         get_krb5_smb_session_key(context, auth_context, session_key, True);
619         dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length);
620
621 #if 0
622         file_save("/tmp/ticket.dat", ticket->data, ticket->length);
623 #endif
624
625         /* continue when no PAC is retrieved or we couldn't decode the PAC 
626            (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or
627            Kerberos tickets encrypted using a DES key) - Guenther */
628
629         got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt);
630         if (!got_auth_data) {
631                 DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n"));
632         }
633
634         if (got_auth_data) {
635                 struct PAC_DATA *pac_data;
636                 pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, &pac_data);
637                 data_blob_free(&auth_data);
638                 if (!NT_STATUS_IS_OK(pac_ret)) {
639                         DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret)));
640                 } else {
641                         uint32_t i;
642                         for (i=0; i < pac_data->num_buffers; i++) {
643
644                                 if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) {
645                                         continue;
646                                 }
647
648                                 *logon_info = pac_data->buffers[i].info->logon_info.info;
649                         }
650
651                         if (!*logon_info) {
652                                 DEBUG(1,("correctly decoded PAC but found no logon_info!  This should not happen\n"));
653                                 return NT_STATUS_INVALID_USER_BUFFER;
654                         }
655                 }
656         }
657
658 #if 0
659 #if defined(HAVE_KRB5_TKT_ENC_PART2)
660         /* MIT */
661         if (tkt->enc_part2) {
662                 file_save("/tmp/authdata.dat",
663                           tkt->enc_part2->authorization_data[0]->contents,
664                           tkt->enc_part2->authorization_data[0]->length);
665         }
666 #else
667         /* Heimdal */
668         if (tkt->ticket.authorization_data) {
669                 file_save("/tmp/authdata.dat",
670                           tkt->ticket.authorization_data->val->ad_data.data,
671                           tkt->ticket.authorization_data->val->ad_data.length);
672         }
673 #endif
674 #endif
675
676         if ((ret = smb_krb5_unparse_name(mem_ctx, context, client_principal, principal))) {
677                 DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", 
678                          error_message(ret)));
679                 sret = NT_STATUS_LOGON_FAILURE;
680                 goto out;
681         }
682
683         sret = NT_STATUS_OK;
684
685  out:
686
687         TALLOC_FREE(mutex);
688
689         if (!NT_STATUS_IS_OK(sret)) {
690                 data_blob_free(&auth_data);
691         }
692
693         if (!NT_STATUS_IS_OK(sret)) {
694                 data_blob_free(ap_rep);
695         }
696
697         if (host_princ) {
698                 krb5_free_principal(context, host_princ);
699         }
700
701         if (keyblock) {
702                 krb5_free_keyblock(context, keyblock);
703         }
704
705         if (tkt != NULL) {
706                 krb5_free_ticket(context, tkt);
707         }
708
709         SAFE_FREE(host_princ_s);
710
711         if (auth_context) {
712                 krb5_auth_con_free(context, auth_context);
713         }
714
715         if (context) {
716                 krb5_free_context(context);
717         }
718
719         return sret;
720 }
721
722 #endif /* HAVE_KRB5 */