root/source4/auth/kerberos/kerberos_pac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_pac_checksum
  2. kerberos_decode_pac
  3. kerberos_pac_logon_info
  4. make_pac_checksum
  5. kerberos_encode_pac
  6. kerberos_create_pac
  7. kerberos_pac_to_server_info
  8. kerberos_pac_blob_to_server_info

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    Create and parse the krb5 PAC
   5    
   6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005,2008
   7    Copyright (C) Andrew Tridgell 2001
   8    Copyright (C) Luke Howard 2002-2003
   9    Copyright (C) Stefan Metzmacher 2004-2005
  10 
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 3 of the License, or
  14    (at your option) any later version.
  15    
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20 
  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 "system/kerberos.h"
  28 #include "auth/auth.h"
  29 #include "auth/kerberos/kerberos.h"
  30 #include "librpc/gen_ndr/ndr_krb5pac.h"
  31 #include "lib/ldb/include/ldb.h"
  32 #include "auth/auth_sam_reply.h"
  33 
  34 krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
  35                                    DATA_BLOB pac_data,
  36                                    struct PAC_SIGNATURE_DATA *sig,
  37                                    krb5_context context,
  38                                    const krb5_keyblock *keyblock)
  39 {
  40         krb5_error_code ret;
  41         krb5_crypto crypto;
  42         Checksum cksum;
  43 
  44         cksum.cksumtype         = (CKSUMTYPE)sig->type;
  45         cksum.checksum.length   = sig->signature.length;
  46         cksum.checksum.data     = sig->signature.data;
  47 
  48         ret = krb5_crypto_init(context,
  49                                keyblock,
  50                                0,
  51                                &crypto);
  52         if (ret) {
  53                 DEBUG(0,("krb5_crypto_init() failed: %s\n", 
  54                           smb_get_krb5_error_message(context, ret, mem_ctx)));
  55                 return ret;
  56         }
  57         ret = krb5_verify_checksum(context,
  58                                    crypto,
  59                                    KRB5_KU_OTHER_CKSUM,
  60                                    pac_data.data,
  61                                    pac_data.length,
  62                                    &cksum);
  63         krb5_crypto_destroy(context, crypto);
  64 
  65         return ret;
  66 }
  67 
  68  NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  69                               struct smb_iconv_convenience *iconv_convenience,
  70                               struct PAC_DATA **pac_data_out,
  71                               DATA_BLOB blob,
  72                               krb5_context context,
  73                               const krb5_keyblock *krbtgt_keyblock,
  74                               const krb5_keyblock *service_keyblock,
  75                               krb5_const_principal client_principal,
  76                               time_t tgs_authtime,
  77                               krb5_error_code *k5ret)
  78 {
  79         krb5_error_code ret;
  80         NTSTATUS status;
  81         enum ndr_err_code ndr_err;
  82         struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL;
  83         struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL;
  84         struct PAC_SIGNATURE_DATA *srv_sig_wipe = NULL;
  85         struct PAC_SIGNATURE_DATA *kdc_sig_wipe = NULL;
  86         struct PAC_LOGON_INFO *logon_info = NULL;
  87         struct PAC_LOGON_NAME *logon_name = NULL;
  88         struct PAC_DATA *pac_data;
  89         struct PAC_DATA_RAW *pac_data_raw;
  90 
  91         DATA_BLOB *srv_sig_blob = NULL;
  92         DATA_BLOB *kdc_sig_blob = NULL;
  93 
  94         DATA_BLOB modified_pac_blob;
  95         NTTIME tgs_authtime_nttime;
  96         krb5_principal client_principal_pac;
  97         int i;
  98 
  99         krb5_clear_error_string(context);
 100 
 101         if (k5ret) {
 102                 *k5ret = KRB5_PARSE_MALFORMED;
 103         }
 104 
 105         pac_data = talloc(mem_ctx, struct PAC_DATA);
 106         pac_data_raw = talloc(mem_ctx, struct PAC_DATA_RAW);
 107         kdc_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
 108         srv_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
 109         if (!pac_data_raw || !pac_data || !kdc_sig_wipe || !srv_sig_wipe) {
 110                 if (k5ret) {
 111                         *k5ret = ENOMEM;
 112                 }
 113                 return NT_STATUS_NO_MEMORY;
 114         }
 115 
 116         ndr_err = ndr_pull_struct_blob(&blob, pac_data, 
 117                         iconv_convenience, pac_data,
 118                        (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
 119         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 120                 status = ndr_map_error2ntstatus(ndr_err);
 121                 DEBUG(0,("can't parse the PAC: %s\n",
 122                         nt_errstr(status)));
 123                 return status;
 124         }
 125 
 126         if (pac_data->num_buffers < 4) {
 127                 /* we need logon_ingo, service_key and kdc_key */
 128                 DEBUG(0,("less than 4 PAC buffers\n"));
 129                 return NT_STATUS_INVALID_PARAMETER;
 130         }
 131 
 132         ndr_err = ndr_pull_struct_blob(&blob, pac_data_raw, 
 133                                        iconv_convenience, pac_data_raw,
 134                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA_RAW);
 135         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 136                 status = ndr_map_error2ntstatus(ndr_err);
 137                 DEBUG(0,("can't parse the PAC: %s\n",
 138                         nt_errstr(status)));
 139                 return status;
 140         }
 141 
 142         if (pac_data_raw->num_buffers < 4) {
 143                 /* we need logon_ingo, service_key and kdc_key */
 144                 DEBUG(0,("less than 4 PAC buffers\n"));
 145                 return NT_STATUS_INVALID_PARAMETER;
 146         }
 147 
 148         if (pac_data->num_buffers != pac_data_raw->num_buffers) {
 149                 /* we need logon_ingo, service_key and kdc_key */
 150                 DEBUG(0,("misparse!  PAC_DATA has %d buffers while PAC_DATA_RAW has %d\n",
 151                          pac_data->num_buffers, pac_data_raw->num_buffers));
 152                 return NT_STATUS_INVALID_PARAMETER;
 153         }
 154 
 155         for (i=0; i < pac_data->num_buffers; i++) {
 156                 if (pac_data->buffers[i].type != pac_data_raw->buffers[i].type) {
 157                         DEBUG(0,("misparse!  PAC_DATA buffer %d has type %d while PAC_DATA_RAW has %d\n",
 158                                  i, pac_data->buffers[i].type, pac_data->buffers[i].type));
 159                         return NT_STATUS_INVALID_PARAMETER;
 160                 }
 161                 switch (pac_data->buffers[i].type) {
 162                         case PAC_TYPE_LOGON_INFO:
 163                                 if (!pac_data->buffers[i].info) {
 164                                         break;
 165                                 }
 166                                 logon_info = pac_data->buffers[i].info->logon_info.info;
 167                                 break;
 168                         case PAC_TYPE_SRV_CHECKSUM:
 169                                 if (!pac_data->buffers[i].info) {
 170                                         break;
 171                                 }
 172                                 srv_sig_ptr = &pac_data->buffers[i].info->srv_cksum;
 173                                 srv_sig_blob = &pac_data_raw->buffers[i].info->remaining;
 174                                 break;
 175                         case PAC_TYPE_KDC_CHECKSUM:
 176                                 if (!pac_data->buffers[i].info) {
 177                                         break;
 178                                 }
 179                                 kdc_sig_ptr = &pac_data->buffers[i].info->kdc_cksum;
 180                                 kdc_sig_blob = &pac_data_raw->buffers[i].info->remaining;
 181                                 break;
 182                         case PAC_TYPE_LOGON_NAME:
 183                                 logon_name = &pac_data->buffers[i].info->logon_name;
 184                                 break;
 185                         default:
 186                                 break;
 187                 }
 188         }
 189 
 190         if (!logon_info) {
 191                 DEBUG(0,("PAC no logon_info\n"));
 192                 return NT_STATUS_INVALID_PARAMETER;
 193         }
 194 
 195         if (!logon_name) {
 196                 DEBUG(0,("PAC no logon_name\n"));
 197                 return NT_STATUS_INVALID_PARAMETER;
 198         }
 199 
 200         if (!srv_sig_ptr || !srv_sig_blob) {
 201                 DEBUG(0,("PAC no srv_key\n"));
 202                 return NT_STATUS_INVALID_PARAMETER;
 203         }
 204 
 205         if (!kdc_sig_ptr || !kdc_sig_blob) {
 206                 DEBUG(0,("PAC no kdc_key\n"));
 207                 return NT_STATUS_INVALID_PARAMETER;
 208         }
 209 
 210         /* Find and zero out the signatures, as required by the signing algorithm */
 211 
 212         /* We find the data blobs above, now we parse them to get at the exact portion we should zero */
 213         ndr_err = ndr_pull_struct_blob(kdc_sig_blob, kdc_sig_wipe, 
 214                                        iconv_convenience, kdc_sig_wipe,
 215                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
 216         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 217                 status = ndr_map_error2ntstatus(ndr_err);
 218                 DEBUG(0,("can't parse the KDC signature: %s\n",
 219                         nt_errstr(status)));
 220                 return status;
 221         }
 222         
 223         ndr_err = ndr_pull_struct_blob(srv_sig_blob, srv_sig_wipe, 
 224                                        iconv_convenience, srv_sig_wipe,
 225                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
 226         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 227                 status = ndr_map_error2ntstatus(ndr_err);
 228                 DEBUG(0,("can't parse the SRV signature: %s\n",
 229                         nt_errstr(status)));
 230                 return status;
 231         }
 232 
 233         /* Now zero the decoded structure */
 234         memset(kdc_sig_wipe->signature.data, '\0', kdc_sig_wipe->signature.length);
 235         memset(srv_sig_wipe->signature.data, '\0', srv_sig_wipe->signature.length);
 236         
 237         /* and reencode, back into the same place it came from */
 238         ndr_err = ndr_push_struct_blob(kdc_sig_blob, pac_data_raw, 
 239                                        iconv_convenience,
 240                                        kdc_sig_wipe,
 241                                        (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA);
 242         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 243                 status = ndr_map_error2ntstatus(ndr_err);
 244                 DEBUG(0,("can't repack the KDC signature: %s\n",
 245                         nt_errstr(status)));
 246                 return status;
 247         }
 248         ndr_err = ndr_push_struct_blob(srv_sig_blob, pac_data_raw, 
 249                                        iconv_convenience,
 250                                        srv_sig_wipe,
 251                                        (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA);
 252         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 253                 status = ndr_map_error2ntstatus(ndr_err);
 254                 DEBUG(0,("can't repack the SRV signature: %s\n",
 255                         nt_errstr(status)));
 256                 return status;
 257         }
 258 
 259         /* push out the whole structure, but now with zero'ed signatures */
 260         ndr_err = ndr_push_struct_blob(&modified_pac_blob, pac_data_raw, 
 261                                        iconv_convenience,
 262                                        pac_data_raw,
 263                                        (ndr_push_flags_fn_t)ndr_push_PAC_DATA_RAW);
 264         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 265                 status = ndr_map_error2ntstatus(ndr_err);
 266                 DEBUG(0,("can't repack the RAW PAC: %s\n",
 267                         nt_errstr(status)));
 268                 return status;
 269         }
 270 
 271         /* verify by service_key */
 272         ret = check_pac_checksum(mem_ctx, 
 273                                  modified_pac_blob, srv_sig_ptr, 
 274                                  context, 
 275                                  service_keyblock);
 276         if (ret) {
 277                 DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n",
 278                           smb_get_krb5_error_message(context, ret, mem_ctx)));
 279                 if (k5ret) {
 280                         *k5ret = ret;
 281                 }
 282                 return NT_STATUS_ACCESS_DENIED;
 283         }
 284 
 285         if (krbtgt_keyblock) {
 286                 ret = check_pac_checksum(mem_ctx, 
 287                                             srv_sig_ptr->signature, kdc_sig_ptr, 
 288                                             context, krbtgt_keyblock);
 289                 if (ret) {
 290                         DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n",
 291                                   smb_get_krb5_error_message(context, ret, mem_ctx)));
 292                         if (k5ret) {
 293                                 *k5ret = ret;
 294                         }
 295                         return NT_STATUS_ACCESS_DENIED;
 296                 }
 297         }
 298 
 299         /* Convert to NT time, so as not to loose accuracy in comparison */
 300         unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);
 301 
 302         if (tgs_authtime_nttime != logon_name->logon_time) {
 303                 DEBUG(2, ("PAC Decode: Logon time mismatch between ticket and PAC!\n"));
 304                 DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time)));
 305                 DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime)));
 306                 return NT_STATUS_ACCESS_DENIED;
 307         }
 308 
 309         ret = krb5_parse_name_flags(context, logon_name->account_name, KRB5_PRINCIPAL_PARSE_NO_REALM, 
 310                                     &client_principal_pac);
 311         if (ret) {
 312                 DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n", 
 313                           logon_name->account_name, 
 314                           smb_get_krb5_error_message(context, ret, mem_ctx)));
 315                 if (k5ret) {
 316                         *k5ret = ret;
 317                 }
 318                 return NT_STATUS_INVALID_PARAMETER;
 319         }
 320 
 321         if (!krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) {
 322                 DEBUG(2, ("Name in PAC [%s] does not match principal name in ticket\n", 
 323                           logon_name->account_name));
 324                 return NT_STATUS_ACCESS_DENIED;
 325         }
 326         
 327 #if 0
 328         if (strcasecmp(logon_info->info3.base.account_name.string, 
 329                        "Administrator")== 0) {
 330                 file_save("tmp_pac_data-admin.dat",blob.data,blob.length);
 331         }
 332 #endif
 333 
 334         DEBUG(3,("Found account name from PAC: %s [%s]\n",
 335                  logon_info->info3.base.account_name.string, 
 336                  logon_info->info3.base.full_name.string));
 337         *pac_data_out = pac_data;
 338 
 339         return NT_STATUS_OK;
 340 }
 341 
 342 _PUBLIC_  NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 343                                   struct smb_iconv_convenience *iconv_convenience,
 344                                   struct PAC_LOGON_INFO **logon_info,
 345                                   DATA_BLOB blob,
 346                                   krb5_context context,
 347                                   const krb5_keyblock *krbtgt_keyblock,
 348                                   const krb5_keyblock *service_keyblock,
 349                                   krb5_const_principal client_principal,
 350                                   time_t tgs_authtime, 
 351                                   krb5_error_code *k5ret)
 352 {
 353         NTSTATUS nt_status;
 354         struct PAC_DATA *pac_data;
 355         int i;
 356         nt_status = kerberos_decode_pac(mem_ctx, 
 357                                         iconv_convenience,
 358                                         &pac_data,
 359                                         blob,
 360                                         context,
 361                                         krbtgt_keyblock,
 362                                         service_keyblock,
 363                                         client_principal, 
 364                                         tgs_authtime,
 365                                         k5ret);
 366         if (!NT_STATUS_IS_OK(nt_status)) {
 367                 return nt_status;
 368         }
 369 
 370         *logon_info = NULL;
 371         for (i=0; i < pac_data->num_buffers; i++) {
 372                 if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) {
 373                         continue;
 374                 }
 375                 *logon_info = pac_data->buffers[i].info->logon_info.info; 
 376         }
 377         if (!*logon_info) {
 378                 return NT_STATUS_INVALID_PARAMETER;
 379         }
 380         return NT_STATUS_OK;
 381 }
 382 
 383 static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 384                                          DATA_BLOB *pac_data,
 385                                          struct PAC_SIGNATURE_DATA *sig,
 386                                          krb5_context context,
 387                                          const krb5_keyblock *keyblock)
 388 {
 389         krb5_error_code ret;
 390         krb5_crypto crypto;
 391         Checksum cksum;
 392 
 393 
 394         ret = krb5_crypto_init(context,
 395                                keyblock,
 396                                0,
 397                                &crypto);
 398         if (ret) {
 399                 DEBUG(0,("krb5_crypto_init() failed: %s\n",
 400                           smb_get_krb5_error_message(context, ret, mem_ctx)));
 401                 return ret;
 402         }
 403         ret = krb5_create_checksum(context,
 404                                    crypto,
 405                                    KRB5_KU_OTHER_CKSUM,
 406                                    0,
 407                                    pac_data->data,
 408                                    pac_data->length,
 409                                    &cksum);
 410         if (ret) {
 411                 DEBUG(2, ("PAC Verification failed: %s\n", 
 412                           smb_get_krb5_error_message(context, ret, mem_ctx)));
 413         }
 414 
 415         krb5_crypto_destroy(context, crypto);
 416 
 417         if (ret) {
 418                 return ret;
 419         }
 420 
 421         sig->type = cksum.cksumtype;
 422         sig->signature = data_blob_talloc(mem_ctx, cksum.checksum.data, cksum.checksum.length);
 423         free_Checksum(&cksum);
 424 
 425         return 0;
 426 }
 427 
 428  krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 429                                      struct smb_iconv_convenience *iconv_convenience,
 430                                     struct PAC_DATA *pac_data,
 431                                     krb5_context context,
 432                                     const krb5_keyblock *krbtgt_keyblock,
 433                                     const krb5_keyblock *service_keyblock,
 434                                     DATA_BLOB *pac) 
 435 {
 436         NTSTATUS nt_status;
 437         krb5_error_code ret;
 438         enum ndr_err_code ndr_err;
 439         DATA_BLOB zero_blob = data_blob(NULL, 0);
 440         DATA_BLOB tmp_blob = data_blob(NULL, 0);
 441         struct PAC_SIGNATURE_DATA *kdc_checksum = NULL;
 442         struct PAC_SIGNATURE_DATA *srv_checksum = NULL;
 443         int i;
 444 
 445         /* First, just get the keytypes filled in (and lengths right, eventually) */
 446         for (i=0; i < pac_data->num_buffers; i++) {
 447                 if (pac_data->buffers[i].type != PAC_TYPE_KDC_CHECKSUM) {
 448                         continue;
 449                 }
 450                 kdc_checksum = &pac_data->buffers[i].info->kdc_cksum, 
 451                 ret = make_pac_checksum(mem_ctx, &zero_blob,
 452                                         kdc_checksum, 
 453                                         context, krbtgt_keyblock);
 454                 if (ret) {
 455                         DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", 
 456                                   smb_get_krb5_error_message(context, ret, mem_ctx)));
 457                         talloc_free(pac_data);
 458                         return ret;
 459                 }
 460         }
 461         
 462         for (i=0; i < pac_data->num_buffers; i++) {
 463                 if (pac_data->buffers[i].type != PAC_TYPE_SRV_CHECKSUM) {
 464                         continue;
 465                 }
 466                 srv_checksum = &pac_data->buffers[i].info->srv_cksum; 
 467                 ret = make_pac_checksum(mem_ctx, &zero_blob, 
 468                                         srv_checksum, 
 469                                         context, service_keyblock);
 470                 if (ret) {
 471                         DEBUG(2, ("making service PAC checksum failed: %s\n", 
 472                                   smb_get_krb5_error_message(context, ret, mem_ctx)));
 473                         talloc_free(pac_data);
 474                         return ret;
 475                 }
 476         }
 477 
 478         if (!kdc_checksum) {
 479                 DEBUG(2, ("Invalid PAC constructed for signing, no KDC checksum present!"));
 480                 return EINVAL;
 481         }
 482         if (!srv_checksum) {
 483                 DEBUG(2, ("Invalid PAC constructed for signing, no SRV checksum present!"));
 484                 return EINVAL;
 485         }
 486 
 487         /* But wipe out the actual signatures */
 488         memset(kdc_checksum->signature.data, '\0', kdc_checksum->signature.length);
 489         memset(srv_checksum->signature.data, '\0', srv_checksum->signature.length);
 490 
 491         ndr_err = ndr_push_struct_blob(&tmp_blob, mem_ctx, 
 492                                        iconv_convenience,
 493                                        pac_data,
 494                                        (ndr_push_flags_fn_t)ndr_push_PAC_DATA);
 495         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 496                 nt_status = ndr_map_error2ntstatus(ndr_err);
 497                 DEBUG(1, ("PAC (presig) push failed: %s\n", nt_errstr(nt_status)));
 498                 talloc_free(pac_data);
 499                 return EINVAL;
 500         }
 501 
 502         /* Then sign the result of the previous push, where the sig was zero'ed out */
 503         ret = make_pac_checksum(mem_ctx, &tmp_blob, srv_checksum,
 504                                 context, service_keyblock);
 505 
 506         /* Then sign Server checksum */
 507         ret = make_pac_checksum(mem_ctx, &srv_checksum->signature, kdc_checksum, context, krbtgt_keyblock);
 508         if (ret) {
 509                 DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", 
 510                           smb_get_krb5_error_message(context, ret, mem_ctx)));
 511                 talloc_free(pac_data);
 512                 return ret;
 513         }
 514 
 515         /* And push it out again, this time to the world.  This relies on determanistic pointer values */
 516         ndr_err = ndr_push_struct_blob(&tmp_blob, mem_ctx, 
 517                                        iconv_convenience,
 518                                        pac_data,
 519                                        (ndr_push_flags_fn_t)ndr_push_PAC_DATA);
 520         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 521                 nt_status = ndr_map_error2ntstatus(ndr_err);
 522                 DEBUG(1, ("PAC (final) push failed: %s\n", nt_errstr(nt_status)));
 523                 talloc_free(pac_data);
 524                 return EINVAL;
 525         }
 526 
 527         *pac = tmp_blob;
 528 
 529         return ret;
 530 }
 531 
 532 
 533  krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 534                                      struct smb_iconv_convenience *iconv_convenience,
 535                                      struct auth_serversupplied_info *server_info,
 536                                      krb5_context context,
 537                                      const krb5_keyblock *krbtgt_keyblock,
 538                                      const krb5_keyblock *service_keyblock,
 539                                      krb5_principal client_principal,
 540                                      time_t tgs_authtime,
 541                                      DATA_BLOB *pac)
 542 {
 543         NTSTATUS nt_status;
 544         krb5_error_code ret;
 545         struct PAC_DATA *pac_data = talloc(mem_ctx, struct PAC_DATA);
 546         struct netr_SamInfo3 *sam3;
 547         union PAC_INFO *u_LOGON_INFO;
 548         struct PAC_LOGON_INFO *LOGON_INFO;
 549         union PAC_INFO *u_LOGON_NAME;
 550         struct PAC_LOGON_NAME *LOGON_NAME;
 551         union PAC_INFO *u_KDC_CHECKSUM;
 552         union PAC_INFO *u_SRV_CHECKSUM;
 553 
 554         char *name;
 555                 
 556         enum {
 557                 PAC_BUF_LOGON_INFO = 0,
 558                 PAC_BUF_LOGON_NAME = 1,
 559                 PAC_BUF_SRV_CHECKSUM = 2,
 560                 PAC_BUF_KDC_CHECKSUM = 3,
 561                 PAC_BUF_NUM_BUFFERS = 4
 562         };
 563 
 564         if (!pac_data) {
 565                 return ENOMEM;
 566         }
 567 
 568         pac_data->num_buffers = PAC_BUF_NUM_BUFFERS;
 569         pac_data->version = 0;
 570 
 571         pac_data->buffers = talloc_array(pac_data, 
 572                                          struct PAC_BUFFER,
 573                                          pac_data->num_buffers);
 574         if (!pac_data->buffers) {
 575                 talloc_free(pac_data);
 576                 return ENOMEM;
 577         }
 578 
 579         /* LOGON_INFO */
 580         u_LOGON_INFO = talloc_zero(pac_data->buffers, union PAC_INFO);
 581         if (!u_LOGON_INFO) {
 582                 talloc_free(pac_data);
 583                 return ENOMEM;
 584         }
 585         pac_data->buffers[PAC_BUF_LOGON_INFO].type = PAC_TYPE_LOGON_INFO;
 586         pac_data->buffers[PAC_BUF_LOGON_INFO].info = u_LOGON_INFO;
 587 
 588         /* LOGON_NAME */
 589         u_LOGON_NAME = talloc_zero(pac_data->buffers, union PAC_INFO);
 590         if (!u_LOGON_NAME) {
 591                 talloc_free(pac_data);
 592                 return ENOMEM;
 593         }
 594         pac_data->buffers[PAC_BUF_LOGON_NAME].type = PAC_TYPE_LOGON_NAME;
 595         pac_data->buffers[PAC_BUF_LOGON_NAME].info = u_LOGON_NAME;
 596         LOGON_NAME = &u_LOGON_NAME->logon_name;
 597 
 598         /* SRV_CHECKSUM */
 599         u_SRV_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO);
 600         if (!u_SRV_CHECKSUM) {
 601                 talloc_free(pac_data);
 602                 return ENOMEM;
 603         }
 604         pac_data->buffers[PAC_BUF_SRV_CHECKSUM].type = PAC_TYPE_SRV_CHECKSUM;
 605         pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info = u_SRV_CHECKSUM;
 606 
 607         /* KDC_CHECKSUM */
 608         u_KDC_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO);
 609         if (!u_KDC_CHECKSUM) {
 610                 talloc_free(pac_data);
 611                 return ENOMEM;
 612         }
 613         pac_data->buffers[PAC_BUF_KDC_CHECKSUM].type = PAC_TYPE_KDC_CHECKSUM;
 614         pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info = u_KDC_CHECKSUM;
 615 
 616         /* now the real work begins... */
 617 
 618         LOGON_INFO = talloc_zero(u_LOGON_INFO, struct PAC_LOGON_INFO);
 619         if (!LOGON_INFO) {
 620                 talloc_free(pac_data);
 621                 return ENOMEM;
 622         }
 623         nt_status = auth_convert_server_info_saminfo3(LOGON_INFO, server_info, &sam3);
 624         if (!NT_STATUS_IS_OK(nt_status)) {
 625                 DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status)));
 626                 talloc_free(pac_data);
 627                 return EINVAL;
 628         }
 629 
 630         u_LOGON_INFO->logon_info.info           = LOGON_INFO;
 631         LOGON_INFO->info3 = *sam3;
 632 
 633         ret = krb5_unparse_name_flags(context, client_principal, 
 634                                       KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name);
 635         if (ret) {
 636                 return ret;
 637         }
 638         LOGON_NAME->account_name        = talloc_strdup(LOGON_NAME, name);
 639         free(name);
 640         /*
 641           this logon_time field is absolutely critical. This is what
 642           caused all our PAC troubles :-)
 643         */
 644         unix_to_nt_time(&LOGON_NAME->logon_time, tgs_authtime);
 645 
 646         ret = kerberos_encode_pac(mem_ctx, 
 647                                   iconv_convenience,
 648                                   pac_data, 
 649                                   context,
 650                                   krbtgt_keyblock,
 651                                   service_keyblock,
 652                                   pac);
 653         talloc_free(pac_data);
 654         return ret;
 655 }
 656 
 657 krb5_error_code kerberos_pac_to_server_info(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 658                                                 struct smb_iconv_convenience *iconv_convenience,
 659                                                 krb5_pac pac,
 660                                                 krb5_context context,
 661                                                 struct auth_serversupplied_info **server_info) 
 662 {
 663         NTSTATUS nt_status;
 664         enum ndr_err_code ndr_err;
 665         krb5_error_code ret;
 666 
 667         DATA_BLOB pac_logon_info_in, pac_srv_checksum_in, pac_kdc_checksum_in;
 668         krb5_data k5pac_logon_info_in, k5pac_srv_checksum_in, k5pac_kdc_checksum_in;
 669 
 670         union PAC_INFO info;
 671         union netr_Validation validation;
 672         struct auth_serversupplied_info *server_info_out;
 673 
 674         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
 675 
 676         if (!tmp_ctx) {
 677                 return ENOMEM;
 678         }
 679 
 680         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_LOGON_INFO, &k5pac_logon_info_in);
 681         if (ret != 0) {
 682                 talloc_free(tmp_ctx);
 683                 return EINVAL;
 684         }
 685 
 686         pac_logon_info_in = data_blob_const(k5pac_logon_info_in.data, k5pac_logon_info_in.length);
 687 
 688         ndr_err = ndr_pull_union_blob(&pac_logon_info_in, tmp_ctx, iconv_convenience, &info,
 689                                       PAC_TYPE_LOGON_INFO,
 690                                       (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
 691         krb5_data_free(&k5pac_logon_info_in);
 692         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err) || !info.logon_info.info) {
 693                 nt_status = ndr_map_error2ntstatus(ndr_err);
 694                 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
 695                 talloc_free(tmp_ctx);
 696                 return EINVAL;
 697         }
 698 
 699         /* Pull this right into the normal auth sysstem structures */
 700         validation.sam3 = &info.logon_info.info->info3;
 701         nt_status = make_server_info_netlogon_validation(mem_ctx,
 702                                                          "",
 703                                                          3, &validation,
 704                                                          &server_info_out); 
 705         if (!NT_STATUS_IS_OK(nt_status)) {
 706                 talloc_free(tmp_ctx);
 707                 return EINVAL;
 708         }
 709         
 710         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_SRV_CHECKSUM, &k5pac_srv_checksum_in);
 711         if (ret != 0) {
 712                 talloc_free(tmp_ctx);
 713                 return ret;
 714         }
 715 
 716         pac_srv_checksum_in = data_blob_const(k5pac_srv_checksum_in.data, k5pac_srv_checksum_in.length);
 717                 
 718         ndr_err = ndr_pull_struct_blob(&pac_srv_checksum_in, server_info_out, 
 719                                        iconv_convenience, &server_info_out->pac_srv_sig,
 720                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
 721         krb5_data_free(&k5pac_srv_checksum_in);
 722         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 723                 nt_status = ndr_map_error2ntstatus(ndr_err);
 724                 DEBUG(0,("can't parse the KDC signature: %s\n",
 725                         nt_errstr(nt_status)));
 726                 return EINVAL;
 727         }
 728 
 729         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_KDC_CHECKSUM, &k5pac_kdc_checksum_in);
 730         if (ret != 0) {
 731                 talloc_free(tmp_ctx);
 732                 return ret;
 733         }
 734 
 735         pac_kdc_checksum_in = data_blob_const(k5pac_kdc_checksum_in.data, k5pac_kdc_checksum_in.length);
 736                 
 737         ndr_err = ndr_pull_struct_blob(&pac_kdc_checksum_in, server_info_out, 
 738                                        iconv_convenience, &server_info_out->pac_kdc_sig,
 739                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
 740         krb5_data_free(&k5pac_kdc_checksum_in);
 741         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 742                 nt_status = ndr_map_error2ntstatus(ndr_err);
 743                 DEBUG(0,("can't parse the KDC signature: %s\n",
 744                         nt_errstr(nt_status)));
 745                 return EINVAL;
 746         }
 747 
 748         *server_info = server_info_out;
 749         
 750         return 0;
 751 }
 752 
 753 
 754 NTSTATUS kerberos_pac_blob_to_server_info(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 755                                                      struct smb_iconv_convenience *iconv_convenience,
 756                                                      DATA_BLOB pac_blob, 
 757                                                      krb5_context context,
 758                                                      struct auth_serversupplied_info **server_info) 
 759 {
 760         krb5_error_code ret;
 761         krb5_pac pac;
 762         ret = krb5_pac_parse(context, 
 763                              pac_blob.data, pac_blob.length, 
 764                              &pac);
 765         if (ret) {
 766                 return map_nt_error_from_unix(ret);
 767         }
 768 
 769 
 770         ret = kerberos_pac_to_server_info(mem_ctx, iconv_convenience, pac, context, server_info);
 771         krb5_pac_free(context, pac);
 772         if (ret) {
 773                 return map_nt_error_from_unix(ret);
 774         }
 775         return NT_STATUS_OK;
 776 }

/* [<][>][^][v][top][bottom][index][help] */