/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
*
* Copyright 2008 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
*/
/*
*/
#include "k5-int.h"
#include "k5-utf8.h"
#include "authdata.h"
/* draft-brezak-win2k-krb-authz-00 */
/*
* A PAC consists of a sequence of PAC_INFO_BUFFERs, preceeded by
* a PACTYPE header. Decoding the contents of the buffers is left
* to the application (notwithstanding signature verification).
*/
typedef struct _PAC_INFO_BUFFER {
/* ulType */
typedef struct _PACTYPE {
} PACTYPE;
struct krb5_pac_data {
};
static krb5_error_code
/*
* Add a buffer to the provided PAC and update header.
*/
static krb5_error_code
{
char *pac_data;
/* Check there isn't already a buffer of this type */
/* Solaris Kerberos */
"Duplicate PAC buffer of type %d",
type);
return EEXIST;
}
sizeof(PACTYPE) +
return ENOMEM;
}
return ENOMEM;
}
/* Update offsets of existing buffers */
/* Make room for new PAC_INFO_BUFFER */
/* Initialise new PAC_INFO_BUFFER */
/* Copy in new PAC data and zero padding bytes */
if (zerofill)
else
}
return 0;
}
{
}
/*
* Free a PAC
*/
void KRB5_CALLCONV
{
}
}
}
static krb5_error_code
{
size_t i;
/* Solaris Kerberos */
"Invalid argument 'pac' is NULL");
return EINVAL;
}
else {
/* Solaris Kerberos */
"Invalid buffer found looping thru "
"PAC buffers (type=%d, i=%zd)",
type, i);
return EINVAL;
}
}
}
/* Solaris Kerberos */
"No PAC buffer found (type=%d)",
type);
return ENOENT;
}
}
return 0;
}
/*
* Find a buffer and copy data into output
*/
{
krb5_data d;
if (ret != 0)
return ret;
return ENOMEM;
return 0;
}
/*
* Return an array of the types of data in the PAC
*/
{
size_t i;
return ENOMEM;
return 0;
}
/*
* Initialize PAC
*/
{
return ENOMEM;
return ENOMEM;
}
return ENOMEM;
}
return 0;
}
static krb5_error_code
{
if (cbuffers != 0)
cbuffers--;
return ENOMEM;
return ENOMEM;
}
if (code != 0) {
return ENOMEM;
}
return 0;
}
/*
* Parse the supplied data into the PAC allocated by this function
*/
const void *ptr,
{
size_t i;
const unsigned char *p = (const unsigned char *)ptr;
if (len < PACTYPE_LENGTH) {
/* Solaris Kerberos */
"PAC type length is out of range (len=%zd)",
len);
return ERANGE;
}
cbuffers = load_32_le(p);
p += 4;
version = load_32_le(p);
p += 4;
if (version != 0) {
/* Solaris Kerberos */
"Invalid PAC version is %d, should be 0",
version);
return EINVAL;
}
if (len < header_len) {
/* Solaris Kerberos */
"PAC header len (%zd) out of range",
len);
return ERANGE;
}
if (ret != 0)
return ret;
return ENOMEM;
}
p += 4;
p += 4;
p += 8;
/* Solaris Kerberos */
"PAC buffer offset mis-aligned");
return EINVAL;
}
/* Solaris Kerberos */
"PAC offset is out of range");
return ERANGE;
}
}
return ENOMEM;
}
return 0;
}
static krb5_error_code
{
ntTime /= 10000000;
if (abstime > KRB5_INT32_MAX)
return ERANGE;
return 0;
}
static krb5_error_code
{
*ntTime = elapsedSeconds;
if (elapsedSeconds > 0)
*ntTime += NT_TIME_EPOCH;
*ntTime *= 10000000;
return 0;
}
static krb5_error_code
{
char *pac_princname;
unsigned char *p;
if (ret != 0)
return ret;
/* Solaris Kerberos */
"PAC client info length out of range "
return ERANGE;
}
p = (unsigned char *)client_info.data;
pac_nt_authtime = load_64_le(p);
p += 8;
p += 2;
if (ret != 0)
return ret;
pac_princname_length % 2) {
/* Solaris Kerberos */
"PAC client info length is out of range");
return ERANGE;
}
&pac_princname, NULL);
if (ret != 0)
return ret;
if (ret != 0) {
return ret;
}
if (pac_authtime != authtime) {
/* Solaris Kerberos */
/* Need better ret code here but don't see one */
sizeof (timestring), &fill);
sizeof (pac_timestring), &fill);
"PAC verify fail: PAC authtime '%s' does "
"not match authtime '%s'. PAC principal is"
}
} else if (!krb5_principal_compare_flags(context,
/* Solaris Kerberos */
if (pac_princname && !perr) {
"Wrong principal in request: PAC verify: "
"Principal in PAC is '%s' and does not "
}
if (p_name)
}
return ret;
}
static krb5_error_code
{
size_t i;
break;
}
}
/* Solaris Kerberos */
"No PAC buffer found (type=%d)",
type);
return ENOENT;
}
return ERANGE;
return KRB5_BAD_MSIZE;
/* Zero out the data portion of the checksum only */
0,
return 0;
}
static krb5_error_code
const krb5_keyblock *server)
{
krb5_octet *p;
if (ret != 0)
return ret;
return KRB5_BAD_MSIZE;
return KRB5KRB_AP_ERR_INAPP_CKSUM;
return ENOMEM;
/* Zero out both checksum buffers */
if (ret != 0) {
return ret;
}
if (ret != 0) {
return ret;
}
if (ret != 0) {
return ret;
}
/* Solaris Kerberos */
"Decrypt integrity check failed for PAC");
}
return ret;
}
static krb5_error_code
const krb5_keyblock *privsvr)
{
krb5_octet *p;
if (ret != 0)
return ret;
return KRB5_BAD_MSIZE;
if (ret != 0)
return ret;
return KRB5_BAD_MSIZE;
if (ret != 0)
return ret;
/* Solaris Kerberos */
"Decrypt integrity check failed for PAC");
}
return ret;
}
const krb5_keyblock *server,
const krb5_keyblock *privsvr)
{
return EINVAL;
if (ret != 0)
return ret;
if (ret != 0)
return ret;
}
if (ret != 0)
return ret;
}
return 0;
}
static krb5_error_code
{
/* If we already have a CLIENT_INFO buffer, then just validate it */
PAC_CLIENT_INFO, &client_info) == 0) {
}
if (ret != 0)
goto cleanup;
if (ret != 0)
goto cleanup;
if (ret != 0)
goto cleanup;
p = (unsigned char *)client_info.data;
/* copy in authtime converted to a 64-bit NT time */
store_64_le(nt_authtime, p);
p += 8;
/* copy in number of UCS-2 characters in principal name */
p += 2;
/* copy in principal name */
if (princ_name_ucs2 != NULL)
return ret;
}
static krb5_error_code
const krb5_keyblock *key,
{
if (ret != 0)
return ret;
if (ret != 0)
return ret;
if (ret == 0) {
/*
* If we're resigning PAC, make sure we can fit checksum
* into existing buffer
*/
return ERANGE;
} else {
/* Add a zero filled buffer */
if (ret != 0)
return ret;
}
/* Encode checksum type into buffer */
return 0;
}
/* in-place encoding of PAC header */
static krb5_error_code
{
size_t i;
unsigned char *p;
p += 4;
p += 4;
p += 4;
p += 4;
p += 8;
return ERANGE;
}
return 0;
}
#if 0
/*
* Solaris Kerberos
* We don't have the new MIT iov interfaces yet and don't need them yet.
* We'll need this for full 1.7 resync.
*/
const krb5_keyblock *server_key,
const krb5_keyblock *privsvr_key,
{
if (ret != 0)
return ret;
}
/* Create zeroed buffers for both checksums */
if (ret != 0)
return ret;
if (ret != 0)
return ret;
/* Now, encode the PAC header so that the checksums will include it */
if (ret != 0)
return ret;
/* Generate the server checksum over the entire PAC */
if (ret != 0)
return ret;
if (ret != 0)
return ret;
/* Generate the privsvr checksum over the server checksum buffer */
if (ret != 0)
return ret;
if (ret != 0)
return ret;
return ENOMEM;
return 0;
}
#endif
/*
* PAC auth data attribute backend
*/
struct mspac_context {
};
static krb5_error_code
{
*plugin_context = NULL;
return 0;
}
static void
void *plugin_context,
{
}
static void
{
return;
}
static krb5_error_code
void *plugin_context,
void **request_context)
{
return ENOMEM;
return 0;
}
static krb5_error_code
void *plugin_context,
void *request_context,
{
if (kdc_issued)
return EINVAL;
}
return code;
}
static krb5_error_code
void *plugin_context,
void *request_context,
{
return 0;
return ENOMEM;
return ENOMEM;
}
if (code != 0) {
return code;
}
*out_authdata = authdata;
return 0;
}
static krb5_error_code
void *plugin_context,
void *request_context,
const krb5_auth_context *auth_context,
const krb5_keyblock *key,
const krb5_ap_req *req)
{
return EINVAL;
key,
NULL);
#if 0
/*
* Now, we could return 0 and just set pac->verified to FALSE.
* Thoughts?
*/
if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
code = 0;
}
#endif
return code;
}
static void
void *plugin_context,
void *request_context)
{
}
}
static struct {
} mspac_attribute_types[] = {
{ PAC_CREDENTIALS_INFO, { KV5M_DATA, STRLENOF("urn:mspac:credentials-info"), "urn:mspac:credentials-info" } },
{ PAC_SERVER_CHECKSUM, { KV5M_DATA, STRLENOF("urn:mspac:server-checksum"), "urn:mspac:server-checksum" } },
{ PAC_PRIVSVR_CHECKSUM, { KV5M_DATA, STRLENOF("urn:mspac:privsvr-checksum"), "urn:mspac:privsvr-checksum" } },
{ PAC_DELEGATION_INFO, { KV5M_DATA, STRLENOF("urn:mspac:delegation-info"), "urn:mspac:delegation-info" } },
};
static krb5_error_code
{
unsigned int i;
for (i = 0; i < MSPAC_ATTRIBUTE_COUNT; i++) {
return 0;
}
}
return ENOENT;
}
static krb5_error_code
{
unsigned int i;
for (i = 0; i < MSPAC_ATTRIBUTE_COUNT; i++) {
return 0;
}
}
{
char *endptr;
return 0;
}
return ENOENT;
}
static krb5_error_code
void *plugin_context,
void *request_context,
{
unsigned int i, j;
return ENOENT;
return ENOMEM;
j = 0;
/* The entire PAC */
&attrs[j++]);
if (code != 0) {
return code;
}
/* PAC buffers */
if (code == 0) {
if (code != 0) {
return code;
}
} else {
int length;
if (length < 0) {
return ENOMEM;
}
}
}
return 0;
}
static krb5_error_code
void *plugin_context,
void *request_context,
int *more)
{
if (display_value != NULL) {
display_value->length = 0;
}
return ENOENT;
if (code != 0)
return code;
/* -1 is a magic type that refers to the entire PAC */
value);
else
code = 0;
} else {
else
}
if (code == 0) {
}
*more = 0;
return code;
}
static krb5_error_code
void *plugin_context,
void *request_context,
{
return ENOENT;
if (code != 0)
return code;
/* -1 is a magic type that refers to the entire PAC */
if (code != 0)
return code;
} else {
}
return code;
}
static krb5_error_code
void *plugin_context,
void *request_context,
void **ptr)
{
return 0;
return 0;
if (code == 0) {
}
return code;
}
static void
void *plugin_context,
void *request_context,
void *ptr)
{
return;
}
static krb5_error_code
void *plugin_context,
void *request_context,
{
*sizep += sizeof(krb5_int32);
*sizep += sizeof(krb5_int32);
return 0;
}
static krb5_error_code
void *plugin_context,
void *request_context,
krb5_octet **buffer,
{
} else {
}
} else {
}
return code;
}
static krb5_error_code
void *plugin_context,
void *request_context,
krb5_octet **buffer,
{
/* length */
if (code != 0)
return code;
if (ibuf != 0) {
if (code != 0)
return code;
}
/* verified */
if (code != 0) {
return code;
}
}
}
return 0;
}
static krb5_error_code
void *plugin_context,
void *request_context,
void *dst_plugin_context,
void *dst_request_context)
{
return code;
}
"mspac",
NULL, /* delete_attribute_proc */
};