You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1160 lines
31 KiB
1160 lines
31 KiB
#define UNICODE
|
|
#define INC_OLE2
|
|
#include <windows.h>
|
|
#include <activeds.h>
|
|
#include <ntsecapi.h>
|
|
#include <stdio.h> // printf
|
|
#include <stdlib.h> // strtoul
|
|
#include <assert.h>
|
|
#define SECURITY_WIN32
|
|
#include <security.h> // General definition of a Security Support Provider
|
|
#include <shlwapi.h>
|
|
|
|
typedef int krb5_int32;
|
|
typedef short krb5_int16;
|
|
|
|
typedef unsigned int krb5_kvno;
|
|
typedef unsigned char krb5_octet;
|
|
typedef unsigned int krb5_enctype;
|
|
|
|
typedef krb5_int32 krb5_deltat;
|
|
typedef krb5_int32 krb5_flags;
|
|
typedef krb5_int32 krb5_timestamp;
|
|
typedef krb5_int32 krb5_error_code;
|
|
|
|
typedef char FAR * krb5_principal;
|
|
typedef void FAR * krb5_pointer;
|
|
|
|
/*
|
|
* Note --- these structures cannot be modified without changing the
|
|
* database version number in libkdb.a, but should be expandable by
|
|
* adding new tl_data types.
|
|
*/
|
|
typedef struct _krb5_tl_data {
|
|
struct _krb5_tl_data* tl_data_next; /* NOT saved */
|
|
krb5_int16 tl_data_type;
|
|
krb5_int16 tl_data_length;
|
|
krb5_octet * tl_data_contents;
|
|
} krb5_tl_data;
|
|
|
|
/*
|
|
* If this ever changes up the version number and make the arrays be as
|
|
* big as necessary.
|
|
*
|
|
* Currently the first type is the enctype and the second is the salt type.
|
|
*/
|
|
typedef struct _krb5_key_data {
|
|
krb5_int16 key_data_ver; /* Version */
|
|
krb5_int16 key_data_kvno; /* Key Version */
|
|
krb5_int16 key_data_type[2]; /* Array of types */
|
|
krb5_int16 key_data_length[2]; /* Array of lengths */
|
|
krb5_octet * key_data_contents[2]; /* Array of pointers */
|
|
} krb5_key_data;
|
|
|
|
#define KRB5_KDB_V1_KEY_DATA_ARRAY 2 /* # of array elements */
|
|
|
|
typedef struct _krb5_db_entry_new {
|
|
krb5_int16 len;
|
|
krb5_flags attributes;
|
|
krb5_deltat max_life;
|
|
krb5_deltat max_renewable_life;
|
|
krb5_timestamp expiration; /* When the client expires */
|
|
krb5_timestamp pw_expiration; /* When its passwd expires */
|
|
krb5_timestamp last_success; /* Last successful passwd */
|
|
krb5_timestamp last_failed; /* Last failed passwd attempt */
|
|
krb5_kvno fail_auth_count; /* # of failed passwd attempt */
|
|
krb5_int16 n_tl_data;
|
|
krb5_int16 n_key_data;
|
|
krb5_int16 e_length; /* Length of extra data */
|
|
krb5_octet * e_data; /* Extra data to be saved */
|
|
|
|
krb5_principal princ; /* Length, data */
|
|
krb5_tl_data * tl_data; /* Linked list */
|
|
krb5_key_data * key_data; /* Array */
|
|
} krb5_db_entry;
|
|
|
|
typedef struct _krb5_keyblock {
|
|
krb5_enctype enctype;
|
|
int length;
|
|
krb5_octet FAR *contents;
|
|
} krb5_keyblock;
|
|
|
|
krb5_keyblock mkey;
|
|
|
|
|
|
/* Strings */
|
|
|
|
static const char k5_dump_header[] = "kdb5_util load_dump version 4\n";
|
|
|
|
/* Message strings */
|
|
static const char regex_err[] = "%s: regular expression error - %s\n";
|
|
static const char regex_merr[] = "%s: regular expression match error - %s\n";
|
|
static const char pname_unp_err[] = "%s: cannot unparse principal name (%s)\n";
|
|
static const char mname_unp_err[] = "%s: cannot unparse modifier name (%s)\n";
|
|
static const char nokeys_err[] = "%s: cannot find any standard key for %s\n";
|
|
static const char sdump_tl_inc_err[] = "%s: tagged data list inconsistency for %s (counted %d, stored %d)\n";
|
|
static const char stand_fmt_name[] = "Kerberos version 5";
|
|
static const char old_fmt_name[] = "Kerberos version 5 old format";
|
|
static const char b6_fmt_name[] = "Kerberos version 5 beta 6 format";
|
|
static const char ofopen_error[] = "%s: cannot open %s for writing (%s)\n";
|
|
static const char oflock_error[] = "%s: cannot lock %s (%s)\n";
|
|
static const char dumprec_err[] = "%s: error performing %s dump (%s)\n";
|
|
static const char dumphdr_err[] = "%s: error dumping %s header (%s)\n";
|
|
static const char trash_end_fmt[] = "%s(%d): ignoring trash at end of line: ";
|
|
static const char read_name_string[] = "name string";
|
|
static const char read_key_type[] = "key type";
|
|
static const char read_key_data[] = "key data";
|
|
static const char read_pr_data1[] = "first set of principal attributes";
|
|
static const char read_mod_name[] = "modifier name";
|
|
static const char read_pr_data2[] = "second set of principal attributes";
|
|
static const char read_salt_data[] = "salt data";
|
|
static const char read_akey_type[] = "alternate key type";
|
|
static const char read_akey_data[] = "alternate key data";
|
|
static const char read_asalt_type[] = "alternate salt type";
|
|
static const char read_asalt_data[] = "alternate salt data";
|
|
static const char read_exp_data[] = "expansion data";
|
|
static const char store_err_fmt[] = "%s(%d): cannot store %s(%s)\n";
|
|
static const char add_princ_fmt[] = "%s\n";
|
|
static const char parse_err_fmt[] = "%s(%d): cannot parse %s (%s)\n";
|
|
static const char read_err_fmt[] = "%s(%d): cannot read %s\n";
|
|
static const char no_mem_fmt[] = "%s(%d): no memory for buffers\n";
|
|
static const char rhead_err_fmt[] = "%s(%d): cannot match size tokens\n";
|
|
static const char err_line_fmt[] = "%s: error processing line %d of %s\n";
|
|
static const char head_bad_fmt[] = "%s: dump header bad in %s\n";
|
|
static const char read_bytecnt[] = "record byte count";
|
|
static const char read_encdata[] = "encoded data";
|
|
static const char n_name_unp_fmt[] = "%s(%s): cannot unparse name\n";
|
|
static const char n_dec_cont_fmt[] = "%s(%s): cannot decode contents\n";
|
|
static const char read_nint_data[] = "principal static attributes";
|
|
static const char read_tcontents[] = "tagged data contents";
|
|
static const char read_ttypelen[] = "tagged data type and length";
|
|
static const char read_kcontents[] = "key data contents";
|
|
static const char read_ktypelen[] = "key data type and length";
|
|
static const char read_econtents[] = "extra data contents";
|
|
static const char k5beta_fmt_name[] = "Kerberos version 5 old format";
|
|
static const char standard_fmt_name[] = "Kerberos version 5 format";
|
|
static const char no_name_mem_fmt[] = "%s: cannot get memory for temporary name\n";
|
|
static const char ctx_err_fmt[] = "%s: cannot initialize Kerberos context\n";
|
|
static const char stdin_name[] = "standard input";
|
|
static const char restfail_fmt[] = "%s: %s restore failed\n";
|
|
static const char close_err_fmt[] = "%s: cannot close database (%s)\n";
|
|
static const char dbinit_err_fmt[] = "%s: cannot initialize database (%s)\n";
|
|
static const char dblock_err_fmt[] = "%s: cannot initialize database lock (%s)\n";
|
|
static const char dbname_err_fmt[] = "%s: cannot set database name to %s (%s)\n";
|
|
static const char dbdelerr_fmt[] = "%s: cannot delete bad database %s (%s)\n";
|
|
static const char dbunlockerr_fmt[] = "%s: cannot unlock database %s (%s)\n";
|
|
static const char dbrenerr_fmt[] = "%s: cannot rename database %s to %s (%s)\n";
|
|
static const char dbcreaterr_fmt[] = "%s: cannot create database %s (%s)\n";
|
|
static const char dfile_err_fmt[] = "%s: cannot open %s (%s)\n";
|
|
|
|
static const char oldoption[] = "-old";
|
|
static const char b6option[] = "-b6";
|
|
static const char verboseoption[] = "-verbose";
|
|
static const char updateoption[] = "-update";
|
|
static const char ovoption[] = "-ov";
|
|
static const char dump_tmptrail[] = "~";
|
|
|
|
#define ENCTYPE_NULL 0x0000
|
|
#define ENCTYPE_DES_CBC_CRC 0x0001 /* DES cbc mode with CRC-32 */
|
|
#define ENCTYPE_DES_CBC_MD4 0x0002 /* DES cbc mode with RSA-MD4 */
|
|
#define ENCTYPE_DES_CBC_MD5 0x0003 /* DES cbc mode with RSA-MD5 */
|
|
#define ENCTYPE_DES_CBC_RAW 0x0004 /* DES cbc mode raw */
|
|
#define ENCTYPE_DES3_CBC_SHA 0x0005 /* DES-3 cbc mode with NIST-SHA */
|
|
#define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */
|
|
#define ENCTYPE_RC4_MD4 -128
|
|
#define ENCTYPE_RC4_PLAIN2 -129
|
|
#define ENCTYPE_RC4_LM -130
|
|
#define ENCTYPE_RC4_SHA -131
|
|
#define ENCTYPE_DES_PLAIN -132
|
|
#define ENCTYPE_RC4_HMAC_OLD -133
|
|
#define ENCTYPE_RC4_PLAIN_OLD -134
|
|
#define ENCTYPE_RC4_HMAC_OLD_EXP -135
|
|
#define ENCTYPE_RC4_PLAIN_OLD_EXP -136
|
|
#define ENCTYPE_DES_CBC_MD5_EXP -137
|
|
#define ENCTYPE_DES_PLAIN_EXP -138
|
|
#define ENCTYPE_RC4_PLAIN -140
|
|
#define ENCTYPE_RC4_PLAIN_EXP -141
|
|
#define ENCTYPE_UNKNOWN 0x01ff
|
|
|
|
/* Salt types */
|
|
#define KRB5_KDB_SALTTYPE_NORMAL 0
|
|
#define KRB5_KDB_SALTTYPE_V4 1
|
|
#define KRB5_KDB_SALTTYPE_NOREALM 2
|
|
#define KRB5_KDB_SALTTYPE_ONLYREALM 3
|
|
#define KRB5_KDB_SALTTYPE_SPECIAL 4
|
|
#define KRB5_KDB_SALTTYPE_AFS3 5
|
|
|
|
/* Attributes */
|
|
#define KRB5_KDB_DISALLOW_POSTDATED 0x00000001
|
|
#define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002
|
|
#define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004
|
|
#define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008
|
|
#define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010
|
|
#define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020
|
|
#define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040
|
|
#define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080
|
|
#define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100
|
|
#define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200
|
|
#define KRB5_KDB_DISALLOW_SVR 0x00001000
|
|
#define KRB5_KDB_PWCHANGE_SERVICE 0x00002000
|
|
#define KRB5_KDB_SUPPORT_DESMD5 0x00004000
|
|
#define KRB5_KDB_NEW_PRINC 0x00008000
|
|
|
|
//
|
|
// SALT flags for encryption, from rfc1510 update 3des enctype
|
|
//
|
|
|
|
#define KERB_ENC_TIMESTAMP_SALT 1
|
|
#define KERB_TICKET_SALT 2
|
|
#define KERB_AS_REP_SALT 3
|
|
#define KERB_TGS_REQ_SESSKEY_SALT 4
|
|
#define KERB_TGS_REQ_SUBKEY_SALT 5
|
|
#define KERB_TGS_REQ_AP_REQ_AUTH_CKSUM_SALT 6
|
|
#define KERB_TGS_REQ_AP_REQ_AUTH_SALT 7
|
|
#define KERB_TGS_REP_SALT 8
|
|
#define KERB_TGS_REP_SUBKEY_SALT 9
|
|
#define KERB_AP_REQ_AUTH_CKSUM_SALT 10
|
|
#define KERB_AP_REQ_AUTH_SALT 11
|
|
#define KERB_AP_REP_SALT 12
|
|
#define KERB_PRIV_SALT 13
|
|
#define KERB_CRED_SALT 14
|
|
#define KERB_SAFE_SALT 15
|
|
#define KERB_NON_KERB_SALT 16
|
|
#define KERB_NON_KERB_CKSUM_SALT 17
|
|
#define KERB_KERB_ERROR_SALT 18
|
|
#define KERB_KDC_ISSUED_CKSUM_SALT 19
|
|
#define KERB_MANDATORY_TKT_EXT_CKSUM_SALT 20
|
|
#define KERB_AUTH_DATA_TKT_EXT_CKSUM_SALT 21
|
|
|
|
LPSTR
|
|
get_error_text(DWORD dwError)
|
|
{
|
|
PCHAR pBuf = NULL;
|
|
DWORD cMsgLen = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | 40,
|
|
NULL,
|
|
dwError,
|
|
MAKELANGID(0, SUBLANG_ENGLISH_US),
|
|
(LPSTR) &pBuf,
|
|
128,
|
|
NULL);
|
|
if (!cMsgLen) {
|
|
pBuf = (LPSTR)malloc(30);
|
|
sprintf(pBuf, "(%d)", dwError);
|
|
}
|
|
return(pBuf);
|
|
}
|
|
|
|
void
|
|
print_salt_string(
|
|
int stype,
|
|
int len,
|
|
char *str
|
|
)
|
|
{
|
|
int i;
|
|
|
|
switch (stype) {
|
|
case KRB5_KDB_SALTTYPE_NORMAL:
|
|
printf("Normal\n");
|
|
break;
|
|
|
|
case KRB5_KDB_SALTTYPE_V4:
|
|
printf("V4\n");
|
|
break;
|
|
|
|
case KRB5_KDB_SALTTYPE_NOREALM:
|
|
printf("No Realm : \"%*s\"\n", len, str);
|
|
break;
|
|
|
|
case KRB5_KDB_SALTTYPE_ONLYREALM:
|
|
printf("Only Realm : \"%*s\"\n", len, str);
|
|
break;
|
|
|
|
case KRB5_KDB_SALTTYPE_AFS3:
|
|
printf("AFS3 : \"%*s\"\n", len, str);
|
|
break;
|
|
|
|
case KRB5_KDB_SALTTYPE_SPECIAL:
|
|
printf("Special [%d]:", len);
|
|
goto dump;
|
|
|
|
default:
|
|
printf("salttype %d [%d]:", stype, len);
|
|
dump:;
|
|
for (i=0; i < len; i++)
|
|
printf(" %02x", str[i]);
|
|
printf("\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
char *
|
|
etype_string(
|
|
int enctype
|
|
)
|
|
{
|
|
static char buf[32];
|
|
|
|
switch (enctype) {
|
|
case ENCTYPE_DES_CBC_CRC:
|
|
return "DES-CBC-CRC";
|
|
break;
|
|
case ENCTYPE_DES_CBC_MD4:
|
|
return "DES-CBC-MD4";
|
|
break;
|
|
case ENCTYPE_DES_CBC_MD5:
|
|
return "DES-CBC-MD5";
|
|
break;
|
|
case ENCTYPE_DES3_CBC_SHA:
|
|
return "DES3-CBC-SHA";
|
|
break;
|
|
case ENCTYPE_RC4_MD4:
|
|
return "RC4-MD4";
|
|
break;
|
|
case ENCTYPE_RC4_PLAIN2:
|
|
return "RC4-PLAIN2";
|
|
break;
|
|
case ENCTYPE_RC4_LM:
|
|
return "RC4-LM";
|
|
break;
|
|
case ENCTYPE_RC4_SHA:
|
|
return "RC4-SHA";
|
|
break;
|
|
case ENCTYPE_DES_PLAIN:
|
|
return "DES-PLAIN";
|
|
break;
|
|
case ENCTYPE_RC4_HMAC_OLD:
|
|
return "RC4-HMAC-OLD";
|
|
break;
|
|
case ENCTYPE_RC4_PLAIN_OLD:
|
|
return "RC4-PLAIN-OLD";
|
|
break;
|
|
case ENCTYPE_RC4_HMAC_OLD_EXP:
|
|
return "RC4-HMAC-OLD-EXP";
|
|
break;
|
|
case ENCTYPE_RC4_PLAIN_OLD_EXP:
|
|
return "RC4-PLAIN-OLD-EXP";
|
|
break;
|
|
case ENCTYPE_DES_CBC_MD5_EXP:
|
|
return "DES-CBC-MD5-40bit";
|
|
break;
|
|
case ENCTYPE_DES_PLAIN_EXP:
|
|
return "DES-PLAIN-40bit";
|
|
break;
|
|
case ENCTYPE_RC4_PLAIN:
|
|
return "RC4-PLAIN";
|
|
break;
|
|
case ENCTYPE_RC4_PLAIN_EXP:
|
|
return "RC4-PLAIN-EXP";
|
|
break;
|
|
|
|
default:
|
|
sprintf(buf, "etype %d", enctype);
|
|
return buf;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
print_tl_data(
|
|
int n_data,
|
|
krb5_tl_data *tl_data
|
|
)
|
|
{
|
|
krb5_tl_data *tlp;
|
|
int i;
|
|
|
|
if (n_data) {
|
|
printf("\ttl_data:\n");
|
|
|
|
for (tlp = tl_data; tlp; tlp = tlp->tl_data_next) {
|
|
printf("\t\ttype=%d len=%d ",
|
|
tlp->tl_data_type, tlp->tl_data_length);
|
|
for (i = 0; i < tlp->tl_data_length; i++)
|
|
printf(" %02x", tlp->tl_data_contents[i]);
|
|
printf("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
decrypt_key(
|
|
krb5_keyblock *key,
|
|
void *indata,
|
|
int inlen,
|
|
void *outdata,
|
|
int *outlen
|
|
)
|
|
{
|
|
#define SEC_SUCCESS(Status) ((Status) >= 0)
|
|
static const UCHAR iVec[8] = {0};
|
|
static HANDLE lsaHandle = NULL;
|
|
static ULONG packageId = 0;
|
|
NTSTATUS Status, SubStatus;
|
|
LSA_STRING Name;
|
|
PKERB_DECRYPT_REQUEST DecryptRequest;
|
|
ULONG OutLen, DecryptReqLength;
|
|
PUCHAR OutBuf;
|
|
int retval = 0;
|
|
|
|
if (!lsaHandle) {
|
|
Status = LsaConnectUntrusted(&lsaHandle);
|
|
if (!SEC_SUCCESS(Status)) {
|
|
fprintf(stderr, "Failed to create LsaHandle - 0x%x\n", Status);
|
|
exit(3);
|
|
}
|
|
|
|
Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
|
|
Name.Length = (USHORT)strlen(Name.Buffer);
|
|
Name.MaximumLength = Name.Length + 1;
|
|
|
|
Status = LsaLookupAuthenticationPackage(lsaHandle,
|
|
&Name,
|
|
&packageId);
|
|
if (!SEC_SUCCESS(Status)) {
|
|
LsaDeregisterLogonProcess(lsaHandle);
|
|
fprintf(stderr, "Failed to register LsaHandle - 0x%x\n", Status);
|
|
exit(3);
|
|
}
|
|
}
|
|
|
|
DecryptReqLength =
|
|
sizeof(KERB_DECRYPT_REQUEST) + key->length + 8 + inlen;
|
|
DecryptRequest = (PKERB_DECRYPT_REQUEST)LocalAlloc(LMEM_ZEROINIT, DecryptReqLength);
|
|
|
|
DecryptRequest->MessageType = KerbDecryptDataMessage;
|
|
DecryptRequest->LogonId.LowPart = 0;
|
|
DecryptRequest->LogonId.HighPart = 0;
|
|
DecryptRequest->Flags = 0;
|
|
DecryptRequest->KeyUsage = KERB_TICKET_SALT;
|
|
DecryptRequest->CryptoType = key->enctype;
|
|
DecryptRequest->Key.KeyType = key->enctype;
|
|
DecryptRequest->Key.Length = key->length;
|
|
DecryptRequest->Key.Value = (PUCHAR) (DecryptRequest + 1);
|
|
memcpy(DecryptRequest->Key.Value, key->contents, key->length);
|
|
DecryptRequest->InitialVectorSize = 8;
|
|
DecryptRequest->InitialVector = (PUCHAR)
|
|
((PUCHAR)DecryptRequest->Key.Value + DecryptRequest->Key.Length);
|
|
memcpy(DecryptRequest->InitialVector, iVec, 8);
|
|
DecryptRequest->EncryptedDataSize = inlen;
|
|
DecryptRequest->EncryptedData = (PUCHAR)
|
|
((PUCHAR)DecryptRequest->InitialVector + DecryptRequest->InitialVectorSize);
|
|
memcpy(DecryptRequest->EncryptedData, indata, inlen);
|
|
|
|
Status = LsaCallAuthenticationPackage(lsaHandle,
|
|
packageId,
|
|
DecryptRequest,
|
|
DecryptReqLength,
|
|
(PVOID *)&OutBuf,
|
|
&OutLen,
|
|
&SubStatus);
|
|
|
|
if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) {
|
|
fprintf(stderr, "Decrypt: LsaCallAuthPackage failed: %s\n",
|
|
get_error_text(SubStatus));
|
|
exit(4);
|
|
}
|
|
|
|
if ((long)OutLen > *outlen) {
|
|
fprintf(stderr, "Decrypt: outbuf too small (%d < %d)\n",
|
|
OutLen, *outlen);
|
|
*outlen = OutLen;
|
|
retval = -1;
|
|
}
|
|
else if (outdata) {
|
|
*outlen = OutLen;
|
|
memcpy(outdata, OutBuf, OutLen);
|
|
}
|
|
|
|
LsaFreeReturnBuffer(OutBuf);
|
|
|
|
return(retval);
|
|
}
|
|
|
|
|
|
void
|
|
print_key_data(
|
|
int n_key_data,
|
|
krb5_key_data *kd
|
|
)
|
|
{
|
|
int n, i;
|
|
krb5_keyblock key;
|
|
krb5_octet *ptr;
|
|
int tmplen;
|
|
|
|
for (n = 0; n < n_key_data; n++) {
|
|
ptr = kd[n].key_data_contents[0];
|
|
key.enctype = kd[n].key_data_type[0];
|
|
key.length = *(short *)ptr;
|
|
ptr += 2;
|
|
|
|
printf("\tkey[%d]: ver=%d kvno=%d\n",
|
|
n, kd[n].key_data_ver,
|
|
kd[n].key_data_kvno);
|
|
printf("\t\tetype=%s [%d]: ",
|
|
etype_string(key.enctype),
|
|
key.enctype);
|
|
printf(" keylength=%d ", key.length);
|
|
|
|
printf("\n\t\tEncrypted key: ");
|
|
for (i = 0; i < kd[n].key_data_length[0]; i++)
|
|
printf(" %02x", kd[n].key_data_contents[0][i]);
|
|
|
|
if (mkey.length) {
|
|
// First get the length needed
|
|
decrypt_key(&mkey, ptr, (kd[n].key_data_length[0] - 2),
|
|
NULL, &tmplen);
|
|
key.contents = (krb5_octet *)malloc(tmplen);
|
|
assert(key.contents != 0);
|
|
|
|
// Now decrypt it
|
|
decrypt_key(&mkey, ptr, (kd[n].key_data_length[0] - 2),
|
|
key.contents, &tmplen);
|
|
|
|
printf("\n\t\tDecrypted key: ");
|
|
for (i = 0; i < key.length; i++)
|
|
printf(" %02x", key.contents[i]);
|
|
}
|
|
|
|
printf("\n\t\tsalt=");
|
|
print_salt_string(kd[n].key_data_type[1], kd[n].key_data_length[1],
|
|
(char *)kd[n].key_data_contents[1]);
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
ds_put_principal(
|
|
IADs *ds,
|
|
krb5_db_entry &dbentry
|
|
)
|
|
{
|
|
// Check for accounts that we can't import
|
|
if ((strncmp(dbentry.princ, "K/M", 3) == 0) ||
|
|
(strncmp(dbentry.princ, "krbtgt/", 7) == 0) ||
|
|
(strncmp(dbentry.princ, "kadmin/", 7) == 0)) {
|
|
|
|
return -1;
|
|
}
|
|
|
|
char *cp;
|
|
char *SAMName = StrDupA(dbentry.princ);
|
|
|
|
// Zap the realm
|
|
if (cp = strrchr(SAMName, '@'))
|
|
*cp = '\0';
|
|
|
|
// Check if this princ has an instance - likely SPN
|
|
if (cp = strchr(SAMName, '/')) {
|
|
// We don't do anything with SPN's right now
|
|
return (-1);
|
|
}
|
|
|
|
printf(add_princ_fmt, SAMName);
|
|
|
|
// Search for the entry in the domain
|
|
|
|
// If this is to be an SPN; create the base account
|
|
// (or use an existing one)
|
|
|
|
// Now create the user
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Read a string of bytes while counting the number of lines passed.
|
|
*/
|
|
static int
|
|
read_string(
|
|
FILE *f,
|
|
char *buf,
|
|
int len,
|
|
int *lp
|
|
)
|
|
{
|
|
int c;
|
|
int i, retval;
|
|
|
|
retval = 0;
|
|
for (i=0; i<len; i++) {
|
|
c = fgetc(f);
|
|
if (c < 0) {
|
|
retval = 1;
|
|
break;
|
|
}
|
|
if (c == '\n')
|
|
(*lp)++;
|
|
buf[i] = (char) c;
|
|
}
|
|
buf[len] = '\0';
|
|
return(retval);
|
|
}
|
|
|
|
/*
|
|
* Read a string of two character representations of bytes.
|
|
*/
|
|
static int
|
|
read_octet_string(
|
|
FILE *f,
|
|
krb5_octet *buf,
|
|
int len
|
|
)
|
|
{
|
|
int c;
|
|
int i, retval;
|
|
|
|
retval = 0;
|
|
for (i=0; i<len; i++) {
|
|
if (fscanf(f, "%02x", &c) != 1) {
|
|
retval = 1;
|
|
break;
|
|
}
|
|
buf[i] = (krb5_octet) c;
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
/*
|
|
* Find the end of an old format record.
|
|
*/
|
|
static void
|
|
find_record_end(
|
|
FILE *f,
|
|
const char *fn,
|
|
int lineno
|
|
)
|
|
{
|
|
int ch;
|
|
|
|
if (((ch = fgetc(f)) != ';') || ((ch = fgetc(f)) != '\n')) {
|
|
fprintf(stderr, trash_end_fmt, fn, lineno);
|
|
while (ch != '\n') {
|
|
putc(ch, stderr);
|
|
ch = fgetc(f);
|
|
}
|
|
putc(ch, stderr);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* process_k5beta6_record() - Handle a dump record in krb5b6 format.
|
|
*
|
|
* Returns -1 for end of file, 0 for success and 1 for failure.
|
|
*/
|
|
static int
|
|
process_k5beta6_record(
|
|
const char *fname,
|
|
IADs *ds,
|
|
FILE *filep,
|
|
int verbose,
|
|
int *linenop
|
|
)
|
|
{
|
|
int retval;
|
|
krb5_db_entry dbentry;
|
|
krb5_int32 t1, t2, t3, t4, t5, t6, t7, t8, t9;
|
|
int nread;
|
|
int error;
|
|
int i, j;
|
|
char *name;
|
|
krb5_key_data *kp, *kdatap;
|
|
krb5_tl_data **tlp, *tl;
|
|
krb5_octet *op;
|
|
krb5_error_code kret;
|
|
const char *try2read;
|
|
|
|
try2read = (char *) NULL;
|
|
memset((char *) &dbentry, 0, sizeof(dbentry));
|
|
(*linenop)++;
|
|
retval = 1;
|
|
name = (char *) NULL;
|
|
kp = (krb5_key_data *) NULL;
|
|
op = (krb5_octet *) NULL;
|
|
error = 0;
|
|
kret = 0;
|
|
nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t", &t1, &t2, &t3, &t4, &t5);
|
|
if (nread == 5) {
|
|
/* Get memory for flattened principal name */
|
|
if (!(name = (char *) malloc((size_t) t2 + 1)))
|
|
error++;
|
|
|
|
/* Get memory for and form tagged data linked list */
|
|
tlp = &dbentry.tl_data;
|
|
for (i=0; i<t3; i++) {
|
|
if ((*tlp = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
|
|
memset(*tlp, 0, sizeof(krb5_tl_data));
|
|
tlp = &((*tlp)->tl_data_next);
|
|
dbentry.n_tl_data++;
|
|
}
|
|
else {
|
|
error++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Get memory for key list */
|
|
if (t4 && !(kp = (krb5_key_data *) malloc((size_t)
|
|
(t4*sizeof(krb5_key_data)))))
|
|
error++;
|
|
|
|
/* Get memory for extra data */
|
|
if (t5 && !(op = (krb5_octet *) malloc((size_t) t5)))
|
|
error++;
|
|
|
|
if (!error) {
|
|
dbentry.len = (krb5_int16)t1;
|
|
dbentry.n_key_data = (krb5_int16)t4;
|
|
dbentry.e_length = (krb5_int16)t5;
|
|
if (kp) {
|
|
memset(kp, 0, (size_t) (t4*sizeof(krb5_key_data)));
|
|
dbentry.key_data = kp;
|
|
kp = (krb5_key_data *) NULL;
|
|
}
|
|
if (op) {
|
|
memset(op, 0, (size_t) t5);
|
|
dbentry.e_data = op;
|
|
op = (krb5_octet *) NULL;
|
|
}
|
|
|
|
/* Read in and parse the principal name */
|
|
if (!read_string(filep, name, t2, linenop)) {
|
|
|
|
dbentry.princ = StrDupA(name);
|
|
|
|
/* Get the fixed principal attributes */
|
|
nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
|
|
&t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9);
|
|
if (nread == 8) {
|
|
dbentry.attributes = (krb5_flags) t2;
|
|
dbentry.max_life = (krb5_deltat) t3;
|
|
dbentry.max_renewable_life = (krb5_deltat) t4;
|
|
dbentry.expiration = (krb5_timestamp) t5;
|
|
dbentry.pw_expiration = (krb5_timestamp) t6;
|
|
dbentry.last_success = (krb5_timestamp) t7;
|
|
dbentry.last_failed = (krb5_timestamp) t8;
|
|
dbentry.fail_auth_count = (krb5_kvno) t9;
|
|
} else {
|
|
try2read = read_nint_data;
|
|
error++;
|
|
}
|
|
|
|
/*
|
|
* Get the tagged data.
|
|
*
|
|
* Really, this code ought to discard tl data types
|
|
* that it knows are special to the current version
|
|
* and were not supported in the previous version.
|
|
* But it's a pain to implement that here, and doing
|
|
* it at dump time has almost as good an effect, so
|
|
* that's what I did. [krb5-admin/89/
|
|
*/
|
|
if (!error && dbentry.n_tl_data) {
|
|
for (tl = dbentry.tl_data; tl; tl = tl->tl_data_next) {
|
|
nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
|
|
if (nread == 2) {
|
|
tl->tl_data_type = (krb5_int16) t1;
|
|
tl->tl_data_length = (krb5_int16) t2;
|
|
if (tl->tl_data_length) {
|
|
if (!(tl->tl_data_contents =
|
|
(krb5_octet *) malloc((size_t) t2+1)) ||
|
|
read_octet_string(filep,
|
|
tl->tl_data_contents,
|
|
t2)) {
|
|
try2read = read_tcontents;
|
|
error++;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
/* Should be a null field */
|
|
nread = fscanf(filep, "%d", &t9);
|
|
if ((nread != 1) || (t9 != -1)) {
|
|
error++;
|
|
try2read = read_tcontents;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
try2read = read_ttypelen;
|
|
error++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Get the key data */
|
|
if (!error && dbentry.n_key_data) {
|
|
for (i=0; !error && (i<dbentry.n_key_data); i++) {
|
|
kdatap = &dbentry.key_data[i];
|
|
nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
|
|
if (nread == 2) {
|
|
kdatap->key_data_ver = (krb5_int16) t1;
|
|
kdatap->key_data_kvno = (krb5_int16) t2;
|
|
|
|
for (j=0; j<t1; j++) {
|
|
nread = fscanf(filep, "%d\t%d\t", &t3, &t4);
|
|
if (nread == 2) {
|
|
kdatap->key_data_type[j] = (krb5_int16)t3;
|
|
kdatap->key_data_length[j] = (krb5_int16)t4;
|
|
if (t4) {
|
|
if (!(kdatap->key_data_contents[j] =
|
|
(krb5_octet *)
|
|
malloc((size_t) t4+1)) ||
|
|
read_octet_string(filep,
|
|
kdatap->key_data_contents[j],
|
|
t4)) {
|
|
try2read = read_kcontents;
|
|
error++;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
/* Should be a null field */
|
|
nread = fscanf(filep, "%d", &t9);
|
|
if ((nread != 1) || (t9 != -1)) {
|
|
error++;
|
|
try2read = read_kcontents;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
try2read = read_ktypelen;
|
|
error++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Get the extra data */
|
|
if (!error && dbentry.e_length) {
|
|
if (read_octet_string(filep,
|
|
dbentry.e_data,
|
|
(int) dbentry.e_length)) {
|
|
try2read = read_econtents;
|
|
error++;
|
|
}
|
|
}
|
|
else {
|
|
nread = fscanf(filep, "%d", &t9);
|
|
if ((nread != 1) || (t9 != -1)) {
|
|
error++;
|
|
try2read = read_econtents;
|
|
}
|
|
}
|
|
|
|
/* Finally, find the end of the record. */
|
|
if (!error)
|
|
find_record_end(filep, fname, *linenop);
|
|
|
|
/*
|
|
* We have either read in all the data or choked.
|
|
*/
|
|
if (!error) {
|
|
retval = 0;
|
|
if (verbose == 2) {
|
|
printf("%s\n", dbentry.princ);
|
|
printf("\tattr=0x%x\n", dbentry.attributes);
|
|
printf("\tmax_life=%d, max_renewable_life=%d\n",
|
|
dbentry.max_life, dbentry.max_renewable_life);
|
|
printf("\texpiration=%d, pw_exp=%d\n",
|
|
dbentry.expiration, dbentry.pw_expiration);
|
|
printf("\te_length=%d n_tl_data=%d, n_key_data=%d\n",
|
|
dbentry.e_length, dbentry.n_tl_data,
|
|
dbentry.n_key_data);
|
|
print_tl_data(dbentry.n_tl_data, dbentry.tl_data);
|
|
print_key_data(dbentry.n_key_data, dbentry.key_data);
|
|
}
|
|
|
|
if ((kret = ds_put_principal(ds,
|
|
dbentry))) {
|
|
fprintf(stderr, store_err_fmt,
|
|
fname, *linenop,
|
|
name, ""/*error_message(kret)*/);
|
|
}
|
|
else
|
|
{
|
|
retval = 0;
|
|
}
|
|
}
|
|
else {
|
|
fprintf(stderr, read_err_fmt, fname, *linenop, try2read);
|
|
}
|
|
}
|
|
else {
|
|
if (kret)
|
|
fprintf(stderr, parse_err_fmt,
|
|
fname, *linenop, name, ""/*error_message(kret)*/);
|
|
else
|
|
fprintf(stderr, no_mem_fmt, fname, *linenop);
|
|
}
|
|
}
|
|
else {
|
|
fprintf(stderr, rhead_err_fmt, fname, *linenop);
|
|
}
|
|
|
|
if (op)
|
|
free(op);
|
|
if (kp)
|
|
free(kp);
|
|
if (name)
|
|
free(name);
|
|
if (dbentry.princ)
|
|
free(dbentry.princ);
|
|
}
|
|
else {
|
|
if (nread == EOF)
|
|
retval = -1;
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
int process_k5beta7_policy(
|
|
const char *fname,
|
|
IADs *ds,
|
|
FILE *filep,
|
|
int verbose,
|
|
int *linenop,
|
|
void *pol_db
|
|
)
|
|
{
|
|
char namebuf[1024];
|
|
int nread;
|
|
struct krb5_policy {
|
|
char *name;
|
|
int pw_min_life;
|
|
int pw_max_life;
|
|
int pw_min_length;
|
|
int pw_min_classes;
|
|
int pw_history_num;
|
|
int policy_refcnt;
|
|
} rec;
|
|
|
|
(*linenop)++;
|
|
rec.name = namebuf;
|
|
|
|
nread = fscanf(filep, "%1024s\t%d\t%d\t%d\t%d\t%d\t%d", rec.name,
|
|
&rec.pw_min_life, &rec.pw_max_life,
|
|
&rec.pw_min_length, &rec.pw_min_classes,
|
|
&rec.pw_history_num, &rec.policy_refcnt);
|
|
if (nread == EOF)
|
|
return -1;
|
|
else if (nread != 7) {
|
|
fprintf(stderr, "cannot parse policy on line %d (%d read)\n",
|
|
*linenop, nread);
|
|
return 1;
|
|
}
|
|
|
|
#if 0
|
|
if (ret = osa_adb_create_policy(pol_db, &rec)) {
|
|
if (ret == OSA_ADB_DUP &&
|
|
(ret = osa_adb_put_policy(pol_db, &rec))) {
|
|
fprintf(stderr, "cannot create policy on line %d: %s\n",
|
|
*linenop, error_message(ret));
|
|
return 1;
|
|
}
|
|
}
|
|
#else
|
|
fprintf(stderr, "Policy %s : min_life=%d max_life=%d min_len=%d min_classes=%d histnum=%d refcnt=%d\n",
|
|
rec.name,
|
|
rec.pw_min_life, rec.pw_max_life,
|
|
rec.pw_min_length, rec.pw_min_classes,
|
|
rec.pw_history_num, rec.policy_refcnt);
|
|
#endif
|
|
if (verbose)
|
|
fprintf(stderr, "created policy %s - \n", rec.name);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* process_k5beta7_record() - Handle a dump record in krb5b6 format.
|
|
*
|
|
* Returns -1 for end of file, 0 for success and 1 for failure.
|
|
*/
|
|
static int
|
|
process_k5beta7_record(
|
|
const char *fname,
|
|
IADs *ds,
|
|
FILE *filep,
|
|
int verbose,
|
|
int *linenop,
|
|
void *pol_db
|
|
)
|
|
{
|
|
int nread;
|
|
char rectype[100];
|
|
|
|
nread = fscanf(filep, "%100s\t", rectype);
|
|
if (nread == EOF)
|
|
return -1;
|
|
else if (nread != 1)
|
|
return 1;
|
|
if (strcmp(rectype, "princ") == 0)
|
|
process_k5beta6_record(fname, ds, filep, verbose,
|
|
linenop);
|
|
else if (strcmp(rectype, "policy") == 0)
|
|
process_k5beta7_policy(fname, ds, filep, verbose,
|
|
linenop, pol_db);
|
|
else {
|
|
fprintf(stderr, "unknown record type \"%s\" on line %d\n",
|
|
rectype, *linenop);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* restore_dump() - Restore the database from a standard dump file.
|
|
*/
|
|
static int
|
|
restore_dump(
|
|
const char *programname,
|
|
const char *dumpfile,
|
|
IADs *ds,
|
|
FILE *f,
|
|
FILE *k,
|
|
int verbose
|
|
)
|
|
{
|
|
int error;
|
|
int lineno;
|
|
char buf[2*sizeof(k5_dump_header)];
|
|
short enctype;
|
|
int i;
|
|
int pol_db;
|
|
|
|
if (k) {
|
|
/*
|
|
* Read the master key file
|
|
*/
|
|
if (fread(&enctype, 2, 1, k) != 1) {
|
|
perror("Unable to read master key file");
|
|
exit(2);
|
|
}
|
|
mkey.enctype = enctype;
|
|
if (fread((krb5_pointer) &mkey.length,
|
|
sizeof(mkey.length), 1, k) != 1) {
|
|
perror("Cannot read master key length");
|
|
exit(2);
|
|
}
|
|
if (!mkey.length || mkey.length < 0) {
|
|
fprintf(stderr, "Bad stored master key.\n");
|
|
exit(2);
|
|
}
|
|
if (!(mkey.contents = (krb5_octet *)malloc(mkey.length))) {
|
|
fprintf(stderr, "Read mkey memory allocation failure.\n");
|
|
exit(2);
|
|
}
|
|
if (fread(mkey.contents,
|
|
sizeof(mkey.contents[0]), mkey.length, k) != mkey.length) {
|
|
memset(mkey.contents, 0, mkey.length);
|
|
perror("Cannot read master key");
|
|
exit(2);
|
|
}
|
|
fclose(k);
|
|
|
|
printf("Master key: etype=%s [%d]: ",
|
|
etype_string(mkey.enctype), mkey.enctype);
|
|
for (i = 0; i < mkey.length; i++)
|
|
printf(" %02x", mkey.contents[i]);
|
|
printf("\n");
|
|
}
|
|
|
|
/*
|
|
* Get/check the header.
|
|
*/
|
|
error = 0;
|
|
if (fgets(buf, sizeof(buf), f) == NULL) {
|
|
return(1);
|
|
}
|
|
|
|
if (!strcmp(buf, k5_dump_header)) {
|
|
lineno = 1;
|
|
/*
|
|
* Process the records.
|
|
*/
|
|
while (!(error = process_k5beta7_record(dumpfile,
|
|
ds,
|
|
f,
|
|
verbose,
|
|
&lineno, (void *)&pol_db)))
|
|
;
|
|
if (error != -1)
|
|
fprintf(stderr, err_line_fmt, programname, lineno, dumpfile);
|
|
else
|
|
error = 0;
|
|
|
|
/*
|
|
* Close the input file.
|
|
*/
|
|
if (f != stdin)
|
|
fclose(f);
|
|
}
|
|
else {
|
|
printf("buf=\"%s\"\n", buf);
|
|
fprintf(stderr, head_bad_fmt, programname, dumpfile);
|
|
error++;
|
|
}
|
|
return(error);
|
|
}
|
|
|
|
void __cdecl
|
|
main(int argc, char *argv[])
|
|
{
|
|
FILE *kdbFile, *mkeyFile = NULL;
|
|
int retval;
|
|
IADs *pDS;
|
|
int n = 1;
|
|
int verbose = 1;
|
|
HRESULT hr;
|
|
|
|
if (argc < 2 || argc > 5) {
|
|
printf("Usage: %s [-m <mkey>] <dumpfile>\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
if (argc == 4) {
|
|
if (strcmp(argv[1], "-m") == 0) {
|
|
mkeyFile = fopen(argv[2], "rb");
|
|
if (!mkeyFile) {
|
|
perror("Unable to open master key file");
|
|
exit(1);
|
|
}
|
|
n = 3;
|
|
}
|
|
}
|
|
|
|
kdbFile = fopen(argv[n], "rb");
|
|
if (!kdbFile) {
|
|
perror("Unable to open dump file");
|
|
exit(1);
|
|
}
|
|
|
|
// need to open DS and pass that in
|
|
hr = CoInitialize(NULL);
|
|
if (FAILED(hr)) {
|
|
fprintf(stderr, "Unable to init com - %s\n", get_error_text(hr));
|
|
exit(2);
|
|
}
|
|
|
|
hr = ADsGetObject(TEXT("LDAP://rootDSE"), IID_IADs,
|
|
(void **)&pDS);
|
|
if (FAILED(hr)) {
|
|
fprintf(stderr, "Unable to bind to DS - %s\n", get_error_text(hr));
|
|
exit(2);
|
|
}
|
|
|
|
retval = restore_dump(argv[0], argv[1], pDS, kdbFile, mkeyFile, verbose);
|
|
|
|
fclose(kdbFile);
|
|
exit(retval);
|
|
}
|