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