ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * lib/krb5/krb/pac.c
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * Copyright 2008 by the Massachusetts Institute of Technology.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * All Rights Reserved.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * Export of this software from the United States of America may
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * require a specific license from the United States Government.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * It is the responsibility of any person or organization contemplating
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * export to obtain such a license before exporting.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * distribute this software and its documentation for any purpose and
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * without fee is hereby granted, provided that the above copyright
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * notice appear in all copies and that both that copyright notice and
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * this permission notice appear in supporting documentation, and that
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * the name of M.I.T. not be used in advertising or publicity pertaining
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * to distribution of the software without specific, written prior
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * permission. Furthermore if you modify this software you must label
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * your software as modified software and not distribute it in such a
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * fashion that it might be confused with the original M.I.T. software.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * M.I.T. makes no representations about the suitability of
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * this software for any purpose. It is provided "as is" without express
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * or implied warranty.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#include "k5-int.h"
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#include "k5-utf8.h"
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/* draft-brezak-win2k-krb-authz-00 */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * A PAC consists of a sequence of PAC_INFO_BUFFERs, preceeded by
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * a PACTYPE header. Decoding the contents of the buffers is left
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * to the application (notwithstanding signature verification).
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * SUNW17PACresync
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * These should eventually go to k5-platform.h or equiv.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic inline unsigned short
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryload_16_le (const void *cvp)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const unsigned char *p = cvp;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#if defined(__GNUC__) && defined(K5_LE)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return GET(16,p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return GETSWAPPED(16,p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#else
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return (p[0] | (p[1] << 8));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#endif
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic inline unsigned int
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryload_32_le (const void *cvp)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const unsigned char *p = cvp;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#if defined(__GNUC__) && defined(K5_LE)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return GET(32,p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return GETSWAPPED(32,p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#else
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#endif
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic inline UINT64_TYPE
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryload_64_le (const void *cvp)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const unsigned char *p = cvp;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#if defined(__GNUC__) && defined(K5_LE)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return GET(64,p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return GETSWAPPED(64,p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#else
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ((UINT64_TYPE)load_32_le(p+4) << 32) | load_32_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#endif
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic inline void
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystore_16_le (unsigned int val, void *vp)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry unsigned char *p = vp;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#if defined(__GNUC__) && defined(K5_LE)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PUT(16,p,val);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PUTSWAPPED(16,p,val);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#else
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[1] = (val >> 8) & 0xff;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[0] = (val ) & 0xff;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#endif
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic inline void
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystore_32_le (unsigned int val, void *vp)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry unsigned char *p = vp;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#if defined(__GNUC__) && defined(K5_LE)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PUT(32,p,val);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PUTSWAPPED(32,p,val);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#else
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[3] = (val >> 24) & 0xff;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[2] = (val >> 16) & 0xff;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[1] = (val >> 8) & 0xff;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[0] = (val ) & 0xff;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#endif
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic inline void
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystore_64_le (UINT64_TYPE val, void *vp)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry unsigned char *p = vp;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#if defined(__GNUC__) && defined(K5_LE)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PUT(64,p,val);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PUTSWAPPED(64,p,val);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#else
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[7] = (unsigned char)((val >> 56) & 0xff);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[6] = (unsigned char)((val >> 48) & 0xff);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[5] = (unsigned char)((val >> 40) & 0xff);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[4] = (unsigned char)((val >> 32) & 0xff);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[3] = (unsigned char)((val >> 24) & 0xff);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[2] = (unsigned char)((val >> 16) & 0xff);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[1] = (unsigned char)((val >> 8) & 0xff);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p[0] = (unsigned char)((val ) & 0xff);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#endif
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrytypedef struct _PAC_INFO_BUFFER {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 ulType;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 cbBufferSize;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_8 Offset;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry} PAC_INFO_BUFFER;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define PAC_INFO_BUFFER_LENGTH 16
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/* ulType */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define PAC_LOGON_INFO 1
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define PAC_SERVER_CHECKSUM 6
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define PAC_PRIVSVR_CHECKSUM 7
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define PAC_CLIENT_INFO 10
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrytypedef struct _PACTYPE {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 cBuffers;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 Version;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PAC_INFO_BUFFER Buffers[1];
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry} PACTYPE;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define PAC_ALIGNMENT 8
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define PACTYPE_LENGTH 8U
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define PAC_SIGNATURE_DATA_LENGTH 4U
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define PAC_CLIENT_INFO_LENGTH 10U
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#define NT_TIME_EPOCH 11644473600LL
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystruct krb5_pac_data {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PACTYPE *pac; /* PAC header + info buffer array */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data data; /* PAC data (including uninitialised header) */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry};
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_pac_locate_buffer(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 type,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data *data);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * Add a buffer to the provided PAC and update header.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_pac_add_buffer(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 type,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_data *data,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_boolean zerofill,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data *out_data)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PACTYPE *header;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t header_len, i, pad = 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry char *pac_data;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert((data->data == NULL) == zerofill);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Check there isn't already a buffer of this type */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (k5_pac_locate_buffer(context, pac, type, NULL) == 0) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, EINVAL,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "Duplicate PAC buffer of type %d",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry type);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return EINVAL;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry header = (PACTYPE *)realloc(pac->pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry sizeof(PACTYPE) +
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry (pac->pac->cBuffers * sizeof(PAC_INFO_BUFFER)));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (header == NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac = header;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry header_len = PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (data->length % PAC_ALIGNMENT)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pad = PAC_ALIGNMENT - (data->length % PAC_ALIGNMENT);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac_data = realloc(pac->data.data,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->data.length + PAC_INFO_BUFFER_LENGTH + data->length + pad);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac_data == NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->data.data = pac_data;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Update offsets of existing buffers */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry for (i = 0; i < pac->pac->cBuffers; i++)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac->Buffers[i].Offset += PAC_INFO_BUFFER_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Make room for new PAC_INFO_BUFFER */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memmove(pac->data.data + header_len + PAC_INFO_BUFFER_LENGTH,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->data.data + header_len,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->data.length - header_len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memset(pac->data.data + header_len, 0, PAC_INFO_BUFFER_LENGTH);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Initialise new PAC_INFO_BUFFER */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac->Buffers[i].ulType = type;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac->Buffers[i].cbBufferSize = data->length;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac->Buffers[i].Offset = pac->data.length + PAC_INFO_BUFFER_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert((pac->pac->Buffers[i].Offset % PAC_ALIGNMENT) == 0);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Copy in new PAC data and zero padding bytes */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (zerofill)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memset(pac->data.data + pac->pac->Buffers[i].Offset, 0, data->length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry else
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memcpy(pac->data.data + pac->pac->Buffers[i].Offset, data->data, data->length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memset(pac->data.data + pac->pac->Buffers[i].Offset + data->length, 0, pad);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac->cBuffers++;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->data.length += PAC_INFO_BUFFER_LENGTH + data->length + pad;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (out_data != NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry out_data->data = pac->data.data + pac->pac->Buffers[i].Offset;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry out_data->length = data->length;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_error_code KRB5_CALLCONV
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_pac_add_buffer(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 type,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_data *data)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return k5_pac_add_buffer(context, pac, type, data, FALSE, NULL);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * Free a PAC
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryvoid KRB5_CALLCONV
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_pac_free(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac != NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac->data.data != NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memset(pac->data.data, 0, pac->data.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(pac->data.data);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac->pac != NULL)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(pac->pac);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memset(pac, 0, sizeof(*pac));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(pac);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_pac_locate_buffer(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 type,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data *data)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PAC_INFO_BUFFER *buffer = NULL;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t i;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (pac == NULL) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, EINVAL,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "Invalid argument 'pac' is NULL");
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return EINVAL;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry for (i = 0; i < pac->pac->cBuffers; i++) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac->pac->Buffers[i].ulType == type) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (buffer == NULL)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry buffer = &pac->pac->Buffers[i];
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry else {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, EINVAL,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "Invalid buffer found looping thru PAC buffers (type=%d, i=%d)",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry type, i);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return EINVAL;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (buffer == NULL) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ENOENT,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "No PAC buffer found (type=%d)",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry type);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOENT;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert(buffer->Offset + buffer->cbBufferSize <= pac->data.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (data != NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry data->length = buffer->cbBufferSize;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry data->data = pac->data.data + buffer->Offset;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * Find a buffer and copy data into output
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_error_code KRB5_CALLCONV
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_pac_get_buffer(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 type,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data *data)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data d;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_error_code ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_locate_buffer(context, pac, type, &d);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry data->data = malloc(d.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (data->data == NULL)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry data->length = d.length;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memcpy(data->data, d.data, d.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * Return an array of the types of data in the PAC
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_error_code KRB5_CALLCONV
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_pac_get_types(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t *len,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 **types)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t i;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *types = (krb5_ui_4 *)malloc(pac->pac->cBuffers * sizeof(krb5_ui_4));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (*types == NULL)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *len = pac->pac->cBuffers;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry for (i = 0; i < pac->pac->cBuffers; i++)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry (*types)[i] = pac->pac->Buffers[i].ulType;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * Initialize PAC
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_error_code KRB5_CALLCONV
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_pac_init(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac *ppac)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac = (krb5_pac)malloc(sizeof(*pac));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac == NULL)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac = (PACTYPE *)malloc(sizeof(PACTYPE));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac->pac == NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free( pac);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac->cBuffers = 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac->Version = 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->data.length = PACTYPE_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->data.data = calloc(1, pac->data.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac->data.data == NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac_free(context, pac);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *ppac = pac;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * Parse the supplied data into the PAC allocated by this function
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_error_code KRB5_CALLCONV
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_pac_parse(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const void *ptr,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t len,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac *ppac)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_error_code ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t i;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const unsigned char *p = (const unsigned char *)ptr;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t header_len;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 cbuffers, version;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *ppac = NULL;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (len < PACTYPE_LENGTH) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ERANGE,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "PAC type length is out of range (len=%d)",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ERANGE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry cbuffers = load_32_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 4;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry version = load_32_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 4;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (version != 0) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, EINVAL,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "Invalid PAC version is %d, should be 0",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry version);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return EINVAL;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry header_len = PACTYPE_LENGTH + (cbuffers * PAC_INFO_BUFFER_LENGTH);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (len < header_len) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ERANGE,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "PAC header len (%d) out of range",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ERANGE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5_pac_init(context, &pac);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac = (PACTYPE *)realloc(pac->pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry sizeof(PACTYPE) + ((cbuffers - 1) * sizeof(PAC_INFO_BUFFER)));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac->pac == NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac_free(context, pac);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac->cBuffers = cbuffers;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->pac->Version = version;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry for (i = 0; i < pac->pac->cBuffers; i++) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PAC_INFO_BUFFER *buffer = &pac->pac->Buffers[i];
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry buffer->ulType = load_32_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 4;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry buffer->cbBufferSize = load_32_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 4;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry buffer->Offset = load_64_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 8;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (buffer->Offset % PAC_ALIGNMENT) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac_free(context, pac);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, EINVAL,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "PAC buffer offset mis-aligned");
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return EINVAL;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (buffer->Offset < header_len ||
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry buffer->Offset + buffer->cbBufferSize > len) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac_free(context, pac);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ERANGE,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "PAC offset is out of range");
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ERANGE;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->data.data = realloc(pac->data.data, len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac->data.data == NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac_free(context, pac);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memcpy(pac->data.data, ptr, len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac->data.length = len;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *ppac = pac;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barryk5_time_to_seconds_since_1970(krb5_context context, krb5_int64 ntTime, krb5_timestamp *elapsedSeconds)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_8 abstime;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ntTime /= 10000000;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (abstime > KRB5_INT32_MAX) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ERANGE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *elapsedSeconds = abstime;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_seconds_since_1970_to_time(krb5_timestamp elapsedSeconds, krb5_ui_8 *ntTime)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *ntTime = elapsedSeconds;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (elapsedSeconds > 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *ntTime += NT_TIME_EPOCH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry *ntTime *= 10000000;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_pac_validate_client(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_timestamp authtime,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_const_principal principal)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_error_code ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data client_info;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry char *pac_princname;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry unsigned char *p;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_timestamp pac_authtime;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_2 pac_princname_length;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_int64 pac_nt_authtime;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_principal pac_principal;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_locate_buffer(context, pac, PAC_CLIENT_INFO, &client_info);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (client_info.length < PAC_CLIENT_INFO_LENGTH) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ERANGE,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "PAC client info length out of range",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry client_info.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ERANGE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p = (unsigned char *)client_info.data;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac_nt_authtime = load_64_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 8;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac_princname_length = load_16_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 2;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry ret = k5_time_to_seconds_since_1970(context, pac_nt_authtime, &pac_authtime);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (client_info.length < PAC_CLIENT_INFO_LENGTH + pac_princname_length ||
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry pac_princname_length % 2) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ERANGE,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "PAC client info length is out of range");
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ERANGE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2, &pac_princname, NULL);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5_parse_name_flags(context, pac_princname, 0, &pac_principal);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(pac_princname);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (pac_authtime != authtime) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry char timestring[17];
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry char pac_timestring[17];
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry char fill = ' ';
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry int err, pac_err;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Need better ret code here but don't see one */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = KRB5KRB_AP_WRONG_PRINC;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry err = krb5_timestamp_to_sfstring(pac_authtime,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry timestring,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry sizeof (timestring), &fill);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry pac_err = krb5_timestamp_to_sfstring(pac_authtime,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry pac_timestring,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry sizeof (pac_timestring), &fill);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (pac_princname && !err && !pac_err) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ret,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "PAC verify fail: PAC authtime '%s' does not match authtime '%s'. PAC principal is '%s'",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry pac_timestring, timestring, pac_princname);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry } else if (krb5_principal_compare(context, pac_principal, principal) == FALSE) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry char *p_name = NULL;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_error_code perr;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry ret = KRB5KRB_AP_WRONG_PRINC;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry perr = krb5_unparse_name(context, principal, &p_name);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (pac_princname && !perr) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ret,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "Wrong principal in request: PAC verify: Principal in PAC is '%s' and does not match '%s'",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry pac_princname, p_name);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (p_name)
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_free_unparsed_name(context, p_name);
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry free(pac_princname);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_free_principal(context, pac_principal);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_pac_zero_signature(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 type,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data *data)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PAC_INFO_BUFFER *buffer = NULL;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t i;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert(type == PAC_SERVER_CHECKSUM || type == PAC_PRIVSVR_CHECKSUM);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert(data->length >= pac->data.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry for (i = 0; i < pac->pac->cBuffers; i++) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac->pac->Buffers[i].ulType == type) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry buffer = &pac->pac->Buffers[i];
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry break;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (buffer == NULL) {
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ENOENT,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "No PAC buffer found (type=%d)",
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry type);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOENT;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (buffer->Offset + buffer->cbBufferSize > pac->data.length) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ERANGE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (buffer->cbBufferSize < PAC_SIGNATURE_DATA_LENGTH) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return KRB5_BAD_MSIZE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Zero out the data portion of the checksum only */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memset(data->data + buffer->Offset + PAC_SIGNATURE_DATA_LENGTH,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry 0,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry buffer->cbBufferSize - PAC_SIGNATURE_DATA_LENGTH);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_pac_verify_server_checksum(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_keyblock *server)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_error_code ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data pac_data; /* PAC with zeroed checksums */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_checksum checksum;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data checksum_data;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_boolean valid;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_octet *p;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &checksum_data);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return KRB5_BAD_MSIZE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p = (krb5_octet *)checksum_data.data;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry checksum.checksum_type = load_32_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac_data.length = pac->data.length;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry pac_data.data = malloc(pac->data.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (pac_data.data == NULL)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memcpy(pac_data.data, pac->data.data, pac->data.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Zero out both checksum buffers */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_zero_signature(context, pac, PAC_SERVER_CHECKSUM, &pac_data);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(pac_data.data);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_zero_signature(context, pac, PAC_PRIVSVR_CHECKSUM, &pac_data);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(pac_data.data);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5_c_verify_checksum(context, server, KRB5_KEYUSAGE_APP_DATA_CKSUM,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry &pac_data, &checksum, &valid);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(pac_data.data);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (valid == FALSE) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ret,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "Decrypt integrity check failed for PAC");
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(pac_data.data); /* SUNW17PACresync - mem leak fix */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_pac_verify_kdc_checksum(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_keyblock *privsvr)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_error_code ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data server_checksum, privsvr_checksum;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_checksum checksum;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_boolean valid;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_octet *p;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_locate_buffer(context, pac, PAC_PRIVSVR_CHECKSUM, &privsvr_checksum);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return KRB5_BAD_MSIZE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &server_checksum);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return KRB5_BAD_MSIZE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p = (krb5_octet *)privsvr_checksum.data;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry checksum.checksum_type = load_32_le(p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry checksum.length = privsvr_checksum.length - PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5_c_verify_checksum(context, privsvr, KRB5_KEYUSAGE_APP_DATA_CKSUM,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry &server_checksum, &checksum, &valid);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (valid == FALSE) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry /* Solaris Kerberos */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry krb5_set_error_message(context, ret,
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry "Decrypt integrity check failed for PAC");
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_error_code KRB5_CALLCONV
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_pac_verify(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_timestamp authtime,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_const_principal principal,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_keyblock *server,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_keyblock *privsvr)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_error_code ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (server == NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return EINVAL;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_verify_server_checksum(context, pac, server);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (privsvr != NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_verify_kdc_checksum(context, pac, privsvr);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (principal != NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_validate_client(context, pac, authtime, principal);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_insert_client_info(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_timestamp authtime,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_const_principal principal)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_error_code ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data client_info;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry char *princ_name_utf8 = NULL;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry unsigned char *princ_name_ucs2 = NULL, *p;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t princ_name_ucs2_len = 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_8 nt_authtime;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* If we already have a CLIENT_INFO buffer, then just validate it */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (k5_pac_locate_buffer(context, pac, PAC_CLIENT_INFO, &client_info) == 0) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return k5_pac_validate_client(context, pac, authtime, principal);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5_unparse_name_flags(context, principal,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry KRB5_PRINCIPAL_UNPARSE_NO_REALM, &princ_name_utf8);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry goto cleanup;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5int_utf8s_to_ucs2les(princ_name_utf8,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry &princ_name_ucs2,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry &princ_name_ucs2_len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry goto cleanup;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_ucs2_len;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry client_info.data = NULL;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_add_buffer(context, pac, PAC_CLIENT_INFO, &client_info, TRUE, &client_info);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry goto cleanup;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p = (unsigned char *)client_info.data;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* copy in authtime converted to a 64-bit NT time */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry k5_seconds_since_1970_to_time(authtime, &nt_authtime);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry store_64_le(nt_authtime, p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 8;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* copy in number of UCS-2 characters in principal name */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry store_16_le(princ_name_ucs2_len, p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 2;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* copy in principal name */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memcpy(p, princ_name_ucs2, princ_name_ucs2_len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrycleanup:
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (princ_name_utf8 != NULL)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(princ_name_utf8);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (princ_name_ucs2 != NULL)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry free(princ_name_ucs2);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_insert_checksum(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_ui_4 type,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_keyblock *key,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_cksumtype *cksumtype)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_error_code ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t len;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data cksumdata;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5int_c_mandatory_cksumtype(context, key->enctype, cksumtype);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5_c_checksum_length(context, *cksumtype, &len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_locate_buffer(context, pac, type, &cksumdata);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret == 0) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* If we're resigning PAC, make sure we can fit checksum into existing buffer */
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry if (cksumdata.length != PAC_SIGNATURE_DATA_LENGTH + len) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ERANGE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memset(cksumdata.data, 0, cksumdata.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry } else {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Add a zero filled buffer */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry cksumdata.length = PAC_SIGNATURE_DATA_LENGTH + len;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry cksumdata.data = NULL;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_add_buffer(context, pac, type, &cksumdata, TRUE, &cksumdata);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Encode checksum type into buffer */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry store_32_le((krb5_ui_4)*cksumtype, cksumdata.data);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/* in-place encoding of PAC header */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrystatic krb5_error_code
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barryk5_pac_encode_header(krb5_context context, krb5_pac pac)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t i;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry unsigned char *p;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry size_t header_len;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry header_len = PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert(pac->data.length >= header_len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p = (unsigned char *)pac->data.data;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry store_32_le(pac->pac->cBuffers, p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 4;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry store_32_le(pac->pac->Version, p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 4;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry for (i = 0; i < pac->pac->cBuffers; i++) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry PAC_INFO_BUFFER *buffer = &pac->pac->Buffers[i];
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry store_32_le(buffer->ulType, p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 4;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry store_32_le(buffer->cbBufferSize, p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 4;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry store_64_le(buffer->Offset, p);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry p += 8;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert((buffer->Offset % PAC_ALIGNMENT) == 0);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert(buffer->Offset + buffer->cbBufferSize <= pac->data.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert(buffer->Offset >= header_len);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (buffer->Offset % PAC_ALIGNMENT ||
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry buffer->Offset + buffer->cbBufferSize > pac->data.length ||
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry buffer->Offset < header_len) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ERANGE;
5e01956f3000408c2a2c5a08c8d0acf2c2a9d8eeGlenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#if 0
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry/*
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * SUNW17PACresync
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * We don't have the new MIT iov interfaces yet and don't need them yet.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry * We'll need this for full 1.7 resync.
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5_error_code KRB5_CALLCONV
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barrykrb5int_pac_sign(krb5_context context,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_pac pac,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_timestamp authtime,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_const_principal principal,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_keyblock *server_key,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry const krb5_keyblock *privsvr_key,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data *data)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry{
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_error_code ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_data server_cksum, privsvr_cksum;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_cksumtype server_cksumtype, privsvr_cksumtype;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry krb5_crypto_iov iov[2];
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry data->length = 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry data->data = NULL;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (principal != NULL) {
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_insert_client_info(context, pac, authtime, principal);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry }
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Create zeroed buffers for both checksums */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_insert_checksum(context, pac, PAC_SERVER_CHECKSUM,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry server_key, &server_cksumtype);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_insert_checksum(context, pac, PAC_PRIVSVR_CHECKSUM,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry privsvr_key, &privsvr_cksumtype);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Now, encode the PAC header so that the checksums will include it */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_encode_header(context, pac);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Generate the server checksum over the entire PAC */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &server_cksum);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert(server_cksum.length > PAC_SIGNATURE_DATA_LENGTH);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[0].data = pac->data;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[1].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[1].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5_c_make_checksum_iov(context, server_cksumtype,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry server_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov, sizeof(iov)/sizeof(iov[0]));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry /* Generate the privsvr checksum over the server checksum buffer */
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = k5_pac_locate_buffer(context, pac, PAC_PRIVSVR_CHECKSUM, &privsvr_cksum);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry assert(privsvr_cksum.length > PAC_SIGNATURE_DATA_LENGTH);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[0].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[0].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[1].data.data = privsvr_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov[1].data.length = privsvr_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry ret = krb5_c_make_checksum_iov(context, privsvr_cksumtype,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry privsvr_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry iov, sizeof(iov)/sizeof(iov[0]));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (ret != 0)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ret;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry data->data = malloc(pac->data.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry if (data->data == NULL)
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return ENOMEM;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry data->length = pac->data.length;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memcpy(data->data, pac->data.data, pac->data.length);
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry memset(pac->data.data, 0, PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH));
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry return 0;
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry}
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry#endif
ba7b222e36bac28710a7f43739283302b617e7f5Glenn Barry