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.
882 lines
21 KiB
882 lines
21 KiB
/*++
|
|
|
|
KEYTAB.C
|
|
|
|
Implementation of the actual keytab routines.
|
|
|
|
Copyright (C) 1997 Microsoft Corporation
|
|
Created 01-10-1997 DavidCHR
|
|
|
|
--*/
|
|
|
|
#include "master.h"
|
|
#include "keytab.h"
|
|
#include "keytypes.h"
|
|
#include "defs.h"
|
|
|
|
/* declaring KEYTAB_ALLOC and KEYTAB_FREE lets me hook into these
|
|
routines whenever I want. when it's done, I'll just #def them. */
|
|
|
|
PVOID
|
|
KEYTAB_ALLOC ( KTLONG32 numBytes ) {
|
|
|
|
return malloc(numBytes);
|
|
|
|
}
|
|
|
|
VOID
|
|
KEYTAB_FREE ( PVOID toFree ) {
|
|
|
|
free(toFree);
|
|
|
|
}
|
|
|
|
PKTENT
|
|
CloneKeyEntry( PKTENT pEntry ) {
|
|
|
|
KTLONG32 i;
|
|
PKTENT p=NULL;
|
|
BOOL ret=FALSE;
|
|
|
|
p = (PKTENT) KEYTAB_ALLOC( sizeof( KTENT ) );
|
|
BREAK_IF( p == NULL,
|
|
"Failed to alloc base key struct",
|
|
cleanup );
|
|
memcpy( p, pEntry, sizeof(KTENT) );
|
|
|
|
p->Components = NULL; // initialize these in case of failure.
|
|
p->KeyData = NULL;
|
|
|
|
p->Realm = (PCHAR) KEYTAB_ALLOC( p->szRealm );
|
|
BREAK_IF( p->Realm == NULL, "Failed to alloc realm data", cleanup );
|
|
memcpy( p->Realm, pEntry->Realm, p->szRealm );
|
|
|
|
p->Components = (PKTCOMPONENT) KEYTAB_ALLOC( p->cEntries *
|
|
sizeof(KTCOMPONENT) );
|
|
|
|
BREAK_IF( p->Components == NULL, "Failed to alloc components", cleanup );
|
|
|
|
for ( i = 0 ; i < p->cEntries ; i++ ) {
|
|
|
|
p->Components[i].szComponentData =
|
|
pEntry->Components[i].szComponentData;
|
|
|
|
memcpy( p ->Components[i].Component,
|
|
pEntry->Components[i].Component,
|
|
p ->Components[i].szComponentData );
|
|
}
|
|
|
|
p->KeyData = (PK5_OCTET) KEYTAB_ALLOC ( p->KeyLength );
|
|
BREAK_IF( p->KeyData == NULL, "Failed to alloc keydata", cleanup );
|
|
memcpy( p->KeyData, pEntry->KeyData, p->KeyLength );
|
|
|
|
return p;
|
|
|
|
cleanup:
|
|
|
|
FreeKeyEntry(p);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* base linklist operations */
|
|
|
|
BOOL
|
|
AddEntryToKeytab( PKTFILE Keytab,
|
|
PKTENT Entry,
|
|
BOOL copy ) {
|
|
|
|
PKTENT p;
|
|
|
|
if (copy) {
|
|
p = CloneKeyEntry( Entry );
|
|
} else {
|
|
p = Entry;
|
|
}
|
|
|
|
if (p == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ( NULL == Keytab->FirstKeyEntry ) {
|
|
|
|
Keytab->FirstKeyEntry = Keytab->LastKeyEntry = p;
|
|
|
|
} else {
|
|
Keytab->LastKeyEntry->nextEntry = p;
|
|
Keytab->LastKeyEntry = p;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
RemoveEntryFromKeytab( PKTFILE Keytab,
|
|
PKTENT Entry,
|
|
BOOL dealloc ) {
|
|
|
|
if ( (NULL == Keytab) || ( NULL == Entry ) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ( Keytab->FirstKeyEntry == Entry ) {
|
|
|
|
// removing the first key
|
|
|
|
Keytab->FirstKeyEntry = Entry->nextEntry;
|
|
|
|
if ( Entry->nextEntry == NULL ) {
|
|
// we're the ONLY entry.
|
|
|
|
Keytab->LastKeyEntry = NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
BOOL found=FALSE;
|
|
PKTENT p;
|
|
|
|
// scroll through the keys, looking for this one.
|
|
// not very efficient, but keytabs shouldn't get very big.
|
|
|
|
for (p = Keytab->FirstKeyEntry;
|
|
p != NULL;
|
|
p = p->nextEntry ) {
|
|
|
|
if (p->nextEntry == Entry) {
|
|
found = TRUE;
|
|
p->nextEntry = Entry->nextEntry;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
// wasn't in the linklist.
|
|
return FALSE;
|
|
}
|
|
|
|
if (Entry->nextEntry == NULL ) {
|
|
|
|
// removing the last key entry.
|
|
Keytab->LastKeyEntry = p;
|
|
}
|
|
|
|
}
|
|
|
|
if (dealloc) {
|
|
|
|
FreeKeyEntry(Entry);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeKeyEntry( PKTENT pEntry) {
|
|
|
|
KTLONG32 i;
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
if (pEntry->Realm != NULL ) {
|
|
KEYTAB_FREE(pEntry->Realm);
|
|
}
|
|
|
|
if (pEntry->KeyData != NULL) {
|
|
KEYTAB_FREE(pEntry->KeyData);
|
|
}
|
|
|
|
if (pEntry->Components != NULL) {
|
|
for (i = 0; i < pEntry->cEntries ; i++ ) {
|
|
if ( pEntry->Components[i].Component != NULL ) {
|
|
KEYTAB_FREE(pEntry->Components[i].Component);
|
|
}
|
|
}
|
|
KEYTAB_FREE(pEntry->Components);
|
|
}
|
|
|
|
KEYTAB_FREE(pEntry );
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
FreeKeyTab( PKTFILE pktf ) {
|
|
|
|
PKTENT pEntry=NULL;
|
|
PKTENT next=NULL;
|
|
|
|
if (pktf != NULL) {
|
|
for (pEntry = pktf->FirstKeyEntry ;
|
|
pEntry != NULL;
|
|
pEntry = next ) {
|
|
KTLONG32 i;
|
|
|
|
next = pEntry->nextEntry; /* must do this, because we're freeing
|
|
as we go */
|
|
FreeKeyEntry( pEntry );
|
|
|
|
KEYTAB_FREE(pEntry );
|
|
|
|
}
|
|
KEYTAB_FREE(pktf);
|
|
}
|
|
|
|
}
|
|
|
|
/* These macros make this somewhat LESS painful */
|
|
|
|
#define READ(readwhat, errormsg, statusmsg) { \
|
|
debug(statusmsg); \
|
|
BREAK_IF( !Read(hFile, &(readwhat), sizeof(readwhat), 1), \
|
|
errormsg, cleanup); \
|
|
debug("ok\n"); \
|
|
}
|
|
|
|
#define READSTRING(readwhat, howlong, errormsg, statusmsg) { \
|
|
debug(statusmsg); \
|
|
BREAK_IF( !Read(hFile, readwhat, sizeof(CHAR), howlong), \
|
|
errormsg, cleanup); \
|
|
debug("ok\n"); \
|
|
}
|
|
|
|
#define WRITE(writewhat, description) { \
|
|
debug("writing %hs...", description); \
|
|
BREAK_IF( !Write(hFile, &(writewhat), sizeof(writewhat), 1), \
|
|
"error writing " description, cleanup); \
|
|
debug("ok\n"); \
|
|
}
|
|
|
|
#define WRITE_STRING(writewhat, howlong, description) { \
|
|
debug("writing %hs...", description); \
|
|
BREAK_IF( !Write(hFile, writewhat, sizeof(CHAR), howlong), \
|
|
"error writing " description, cleanup); \
|
|
debug("ok\n"); \
|
|
}
|
|
|
|
#define WRITE_X( size, marshaller, writewhat, description ) { \
|
|
K5_INT##size k5_marshaller_variable; \
|
|
k5_marshaller_variable = marshaller( writewhat );\
|
|
WRITE( k5_marshaller_variable, description );\
|
|
}
|
|
|
|
// NBO-- Network Byte Order
|
|
|
|
#define WRITE_NBO( writewhat, description) {\
|
|
switch( sizeof( writewhat ) ) {\
|
|
case 1: /* marshall a char? */\
|
|
debug("marshalling a char(?)...");\
|
|
WRITE( writewhat, description );\
|
|
break;\
|
|
case 2:\
|
|
debug( #writewhat ": marshalling a short...");\
|
|
WRITE_X( 16, htons, ((unsigned short)writewhat), description);\
|
|
break;\
|
|
case 4:\
|
|
debug( #writewhat ": marshalling a long...");\
|
|
WRITE_X( 32, htonl, writewhat, description);\
|
|
break;\
|
|
default:\
|
|
fprintf(stderr, "Not written: argument is of unhandled size (%d)\n",\
|
|
sizeof(writewhat));\
|
|
}}
|
|
|
|
|
|
|
|
/* Write:
|
|
|
|
helper function to write raw bytes to disk. Takes:
|
|
|
|
hFile: handle to a file open for writing.
|
|
source: pointer to data to be written to the file
|
|
szSource: size of one data element in Source
|
|
numSources: number of data elements in Source
|
|
|
|
(basically, it tries to write szSource * numSources of raw bytes
|
|
from source to the file at hFile).
|
|
|
|
returns TRUE if it succeeds, and FALSE otherwise.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
Write( IN HANDLE hFile,
|
|
IN PVOID source,
|
|
IN KTLONG32 szSource,
|
|
IN KTLONG32 numSources /* =1 */ ) {
|
|
|
|
#ifdef WINNT /* Windows NT implementation of the file write call */
|
|
|
|
KTLONG32 temp;
|
|
KTLONG32 i;
|
|
|
|
temp = szSource * numSources;
|
|
|
|
debug("(writing %d bytes: ", temp );
|
|
for (i = 0; i < temp ; i++ ) {
|
|
|
|
unsigned char byte;
|
|
|
|
byte = ((PCHAR) source)[i];
|
|
|
|
debug("%02x", byte );
|
|
}
|
|
debug(")");
|
|
|
|
return WriteFile( hFile, source, temp, &temp, NULL );
|
|
|
|
#else
|
|
|
|
ssize_t bytesToWrite, bytesWritten;
|
|
|
|
bytesToWrite = szSource * numSources;
|
|
bytesWritten = write( hFile, (const void *)source,
|
|
bytesToWrite );
|
|
|
|
if( bytesWritten == -1 ) {
|
|
debug("WARNING: nothing written to the file! Errno = 0x%x / %d\n",
|
|
errno , errno );
|
|
return FALSE;
|
|
}
|
|
|
|
if ( bytesWritten != bytesToWrite ) {
|
|
debug("WARNING: not all bytes made it to the file (?)\n"
|
|
" errno = 0x%x / %d\n", errno, errno );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/* Read:
|
|
|
|
Semantics and return are the same as for "Write", except that
|
|
target is filled with szTarget*numTargets bytes from hFile, and that
|
|
hFile must be open for read access.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
Read( IN HANDLE hFile,
|
|
OUT PVOID target,
|
|
IN KTLONG32 szTarget,
|
|
IN KTLONG32 numTargets/* =1 */) {
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
#ifdef WINNT /* the SetFilePointer shinanigens are me trying to check on
|
|
how many bytes have ACTUALLY been read/written from the
|
|
file */
|
|
|
|
KTLONG32 temp;
|
|
KTLONG32 filepos;
|
|
LONG zero=0L;
|
|
|
|
filepos = SetFilePointer( hFile, 0, &zero, FILE_CURRENT);
|
|
|
|
debug("reading %d bytes from pos 0x%x...", szTarget * numTargets,
|
|
filepos);
|
|
|
|
ret = ReadFile( hFile,
|
|
target,
|
|
(szTarget*numTargets),
|
|
&temp,
|
|
NULL );
|
|
|
|
if ( !ret ) {
|
|
|
|
debug( "ReadFile failed: 0x%x\n",
|
|
GetLastError() );
|
|
|
|
} else if ( !temp ) {
|
|
|
|
debug( "ReadFile read zero bytes. Assuming EOF\n" );
|
|
|
|
SetLastError( ERROR_HANDLE_EOF );
|
|
ret = FALSE;
|
|
|
|
} else {
|
|
|
|
temp = SetFilePointer( hFile, 0, &zero, FILE_CURRENT);
|
|
|
|
if ( filepos == temp ) {
|
|
debug("WARNING! file position has not changed!");
|
|
SetLastError( ERROR_NO_DATA );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
#else /* UNIX IMPLEMENTATION-- since read() returns the number of bytes
|
|
that we actually read from the file, the
|
|
SetFilePointer (fseek) nonsense is not
|
|
required. */
|
|
|
|
ssize_t bytesRead;
|
|
ssize_t bytesToRead;
|
|
|
|
bytesToRead = szTarget * numTargets;
|
|
|
|
bytesRead = read( hFile, target, bytesToRead );
|
|
|
|
if ( bytesRead == -1 ) {
|
|
debug("WARNING! An error occurred while writing to the file!\n"
|
|
"ERRNO: 0x%x / %d.\n", errno, errno );
|
|
|
|
}
|
|
|
|
ret = (bytesRead == bytesToRead );
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
BOOL
|
|
ReadKeytabFromFile( PKTFILE *ppktfile, // free with FreeKeyTab when done
|
|
PCHAR filename ) {
|
|
|
|
PKTFILE ktfile=NULL;
|
|
HANDLE hFile = NULL;
|
|
BOOL ret=FALSE;
|
|
KTLONG32 i;
|
|
|
|
BREAK_IF( ppktfile == NULL,
|
|
"passed a NULL save-pointer",
|
|
cleanup );
|
|
|
|
debug("Opening keytab file \"%hs\"...", filename);
|
|
|
|
#ifdef WINNT
|
|
hFile = CreateFileA( filename,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
BREAK_IF ( (NULL == hFile) || ( INVALID_HANDLE_VALUE == hFile ),
|
|
"Failed to open file!", cleanup );
|
|
|
|
#else
|
|
|
|
hFile = open( filename, O_RDONLY,
|
|
/* file mask is 0x550: read-write by user and group */
|
|
S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP );
|
|
|
|
BREAK_IF( hFile == -1,
|
|
"Failed to open file!", cleanup );
|
|
|
|
#endif
|
|
|
|
debug("ok!\n");
|
|
|
|
ktfile = (PKTFILE) KEYTAB_ALLOC (sizeof(KTFILE));
|
|
|
|
/* Prefix bug 439480 resulted from the below BREAK_IF
|
|
being interchanged with initialization code. Duhhh. */
|
|
|
|
BREAK_IF( ktfile == NULL,
|
|
"Failed to allocate ktfile",
|
|
cleanup );
|
|
|
|
ktfile->FirstKeyEntry = ktfile->LastKeyEntry = NULL;
|
|
|
|
READ( ktfile->Version, "Failed to read KTVNO",
|
|
"reading KTVNO");
|
|
|
|
/* Version number is stored in network byte order */
|
|
|
|
ktfile->Version = ntohs( ktfile->Version);
|
|
|
|
debug("Keytab version 0x%x\n", ktfile->Version );
|
|
|
|
do {
|
|
PKTENT entry=NULL;
|
|
|
|
entry = (PKTENT) KEYTAB_ALLOC(sizeof(KTENT));
|
|
|
|
// PREFIX bug 439481: not checking the result of KEYTAB_ALLOC.
|
|
|
|
BREAK_IF( !entry,
|
|
"Unable to alloc a new KTENT.",
|
|
cleanup );
|
|
|
|
entry->Realm = NULL;
|
|
entry->Components = NULL;
|
|
entry->KeyData = NULL;
|
|
entry->nextEntry = NULL;
|
|
|
|
#if 1
|
|
if ( !Read( hFile,
|
|
&(entry->keySize),
|
|
sizeof( entry->keySize ),
|
|
1 ) ) {
|
|
|
|
if ( GetLastError() != ERROR_HANDLE_EOF ) {
|
|
|
|
fprintf( stderr,
|
|
"\n ** Failed to read Keytab %hs's leading bytes: 0x%x\n",
|
|
filename,
|
|
GetLastError() );
|
|
|
|
} else {
|
|
|
|
ret = TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
#else
|
|
BREAK_IF( !Read( hFile, &(entry->keySize), sizeof(entry->keySize), 1),
|
|
"Failed to read leading bytes (probably done)",
|
|
no_more_entries );
|
|
#endif
|
|
|
|
entry->keySize = htonl(entry->keySize);
|
|
debug("trash bytes: 0x%x\n", entry->keySize );
|
|
|
|
/* Quickly perform linklist operation on the new node */
|
|
|
|
if (NULL == ktfile->FirstKeyEntry) {
|
|
ktfile->FirstKeyEntry = ktfile->LastKeyEntry = entry;
|
|
} else {
|
|
ktfile->LastKeyEntry->nextEntry = entry;
|
|
ktfile->LastKeyEntry = entry;
|
|
}
|
|
|
|
READ( entry->cEntries,
|
|
"Failed to read key's number of components",
|
|
"reading key components...");
|
|
|
|
entry->cEntries = ntohs( entry->cEntries );
|
|
debug("components number %d\n", entry->cEntries );
|
|
|
|
READ( entry->szRealm,
|
|
"Failed to read key's realm size",
|
|
"reading key realm size...");
|
|
|
|
entry->szRealm = ntohs( entry->szRealm );
|
|
debug("realm size %d\n", entry->szRealm);
|
|
|
|
entry->Realm = (PCHAR) KEYTAB_ALLOC( ( entry->szRealm +1 )
|
|
* sizeof(CHAR) );
|
|
|
|
BREAK_IF ( !entry->Realm,
|
|
"Could not allocate key's realm storage",
|
|
cleanup );
|
|
|
|
READSTRING( entry->Realm, entry->szRealm,
|
|
"Could not read key's realmname",
|
|
"reading realmname...");
|
|
|
|
entry->Realm[ entry->szRealm ] = '\0';
|
|
|
|
debug("realm: \"%hs\"\n", entry->Realm );
|
|
entry->Components = (PKTCOMPONENT) KEYTAB_ALLOC (entry->cEntries *
|
|
sizeof(KTCOMPONENT));
|
|
|
|
BREAK_IF( !entry->Components,
|
|
"Could not allocate key components!",
|
|
cleanup );
|
|
|
|
for (i = 0 ; i < entry->cEntries ; i++ ) {
|
|
|
|
READ( entry->Components[i].szComponentData,
|
|
"Failed to read component size for one entry",
|
|
"reading key component size...");
|
|
|
|
entry->Components[i].szComponentData =
|
|
ntohs( entry->Components[i].szComponentData );
|
|
|
|
debug("Component size: %d\n",
|
|
entry->Components[i].szComponentData );
|
|
|
|
entry->Components[i].Component = (PCHAR) KEYTAB_ALLOC (
|
|
( entry->Components[i].szComponentData +1 ) *
|
|
sizeof(CHAR) );
|
|
|
|
entry->Components[i].Component[
|
|
entry->Components[i].szComponentData ] = '\0';
|
|
|
|
BREAK_IF( !entry->Components[i].Component,
|
|
"Could not allocate entry component storage",
|
|
cleanup );
|
|
|
|
READSTRING( entry->Components[i].Component,
|
|
entry->Components[i].szComponentData,
|
|
"Failed to read component data",
|
|
"reading component data...");
|
|
|
|
debug("Component data: \"%hs\"\n",
|
|
entry->Components[i].Component );
|
|
|
|
}
|
|
|
|
READ( entry->PrincType,
|
|
"Failed to read principal type",
|
|
"reading principal type...");
|
|
|
|
entry->PrincType = ntohl( entry->PrincType ); // in network byte order
|
|
debug("princtype: %d\n", entry->PrincType);
|
|
|
|
READ( entry->TimeStamp,
|
|
"Failed to read entry timestamp",
|
|
"reading timestamp...");
|
|
|
|
entry->TimeStamp = ntohl( entry->TimeStamp ); // also network bytes.
|
|
debug("Timestamp 0x%x\n", entry->TimeStamp );
|
|
|
|
READ( entry->Version,
|
|
"Failed to read kvno",
|
|
"reading kvno...");
|
|
|
|
// kvno is in host order already.
|
|
|
|
READ( entry->KeyType,
|
|
"Failed to read entry encryption type",
|
|
"reading encryption type...");
|
|
|
|
entry->KeyType = ntohs( entry->KeyType );
|
|
|
|
READ( entry->KeyLength,
|
|
"Failed to read entry keylength",
|
|
"reading keylength... ");
|
|
|
|
#if 1
|
|
entry->KeyLength = ntohs ( entry->KeyLength );
|
|
|
|
#else // I used to think this was 32-bit.
|
|
|
|
entry->KeyLength = ntohl ( entry->KeyLength );
|
|
#endif
|
|
|
|
debug("KeyLength is %d\n", entry->KeyLength);
|
|
|
|
entry->KeyData = (PK5_OCTET) KEYTAB_ALLOC (entry->KeyLength *
|
|
sizeof(K5_OCTET));
|
|
|
|
BREAK_IF( !entry->KeyData,
|
|
"Could not allocate entry keydata storage",
|
|
cleanup );
|
|
|
|
READSTRING( entry->KeyData, entry->KeyLength,
|
|
"Failed to read entry key data",
|
|
"reading key data")
|
|
|
|
} while (1);
|
|
|
|
cleanup:
|
|
|
|
#ifdef WINNT
|
|
if ((hFile != NULL) && ( hFile != INVALID_HANDLE_VALUE)) {
|
|
CloseHandle(hFile);
|
|
}
|
|
#else
|
|
if (hFile != -1 ) {
|
|
close(hFile);
|
|
}
|
|
#endif
|
|
|
|
if (ret) {
|
|
*ppktfile = ktfile;
|
|
} else {
|
|
FreeKeyTab( ktfile );
|
|
}
|
|
return ret;
|
|
|
|
}
|
|
|
|
/* define this macro only for DisplayKeytab.
|
|
It's a convenience routine to print this field only if the option
|
|
is set. */
|
|
|
|
#define PRINTFIELD( option, format, value ) { if (options & option) { fprintf(stream, format, value); } }
|
|
|
|
/* DisplayKeytab:
|
|
|
|
prints out the keytab, using options to define which fields we want
|
|
to actually see. (see keytab.hxx for what to put in "options") */
|
|
|
|
VOID
|
|
DisplayKeytab( FILE *stream,
|
|
PKTFILE ktfile,
|
|
KTLONG32 options) {
|
|
|
|
KTLONG32 i;
|
|
PKTENT ent;
|
|
|
|
|
|
|
|
if (options == 0L) {
|
|
return;
|
|
}
|
|
|
|
PRINTFIELD(KT_KTVNO, "Keytab version: 0x%x\n", ktfile->Version);
|
|
|
|
for (ent = ktfile->FirstKeyEntry ;
|
|
ent != NULL;
|
|
ent = ent->nextEntry ) {
|
|
|
|
PRINTFIELD( KT_RESERVED, "keysize %d ", ent->keySize );
|
|
|
|
for (i = 0 ; i < ent->cEntries ; i++ ) {
|
|
PRINTFIELD( KT_COMPONENTS,
|
|
(i == 0 ? "%hs" : "/%hs"),
|
|
ent->Components[i].Component );
|
|
}
|
|
|
|
PRINTFIELD( KT_REALM, "@%hs", ent->Realm );
|
|
PRINTFIELD( KT_PRINCTYPE, " ptype %d", ent->PrincType );
|
|
PRINTFIELD( KT_PRINCTYPE, " (%hs)", LookupTable( ent->PrincType, &K5PType_Strings ).string);
|
|
PRINTFIELD( KT_VNO, " vno %d", ent->Version );
|
|
PRINTFIELD( KT_KEYTYPE, " etype 0x%x", ent->KeyType );
|
|
PRINTFIELD( KT_KEYTYPE, " (%hs)", LookupTable( ent->KeyType,
|
|
&K5EType_Strings ).string );
|
|
PRINTFIELD( KT_KEYLENGTH, " keylength %d", ent->KeyLength );
|
|
|
|
if (options & KT_KEYDATA ) {
|
|
|
|
fprintf(stream, " (0x" );
|
|
for ( i = 0 ; i < ent->KeyLength ; i++ ) {
|
|
fprintf(stream, "%02x", ent->KeyData[i] );
|
|
}
|
|
fprintf(stream, ")" );
|
|
}
|
|
|
|
fprintf(stream, "\n");
|
|
}
|
|
}
|
|
|
|
#undef PRINTFIELD // we only need it for that function
|
|
|
|
/* computes the length of a kerberos keytab for the keySize field */
|
|
|
|
K5_INT32
|
|
ComputeKeytabLength( PKTENT p ) {
|
|
|
|
K5_INT32 ret=0L;
|
|
KTLONG32 i;
|
|
|
|
// these are the variables within this level
|
|
|
|
ret = p->szRealm + p->KeyLength;
|
|
|
|
// these are static
|
|
|
|
ret += ( sizeof( p->cEntries ) + sizeof(p->szRealm) +
|
|
sizeof( p->PrincType ) + sizeof( p->TimeStamp ) +
|
|
sizeof( p->Version ) + sizeof (p->KeyLength ) +
|
|
sizeof( p->KeyType ) );
|
|
|
|
for (i = 0 ; i < p->cEntries; i++ ) {
|
|
ret += ( p->Components[i].szComponentData +
|
|
sizeof(p->Components[i].szComponentData) );
|
|
}
|
|
|
|
debug("ComputeKeytabLength: returning %d\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* This depends very much on the same keytab model that
|
|
the other functions do */
|
|
|
|
BOOL
|
|
WriteKeytabToFile( PKTFILE ktfile,
|
|
PCHAR filename ) {
|
|
|
|
HANDLE hFile = NULL;
|
|
BOOL ret=FALSE;
|
|
KTLONG32 i;
|
|
PKTENT entry;
|
|
|
|
BREAK_IF( ktfile == NULL,
|
|
"passed a NULL save-pointer",
|
|
cleanup );
|
|
|
|
debug("opening keytab file \"%hs\" for write...", filename);
|
|
|
|
#ifdef WINNT
|
|
|
|
hFile = CreateFileA( filename,
|
|
GENERIC_WRITE,
|
|
0L,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
BREAK_IF( ( hFile == INVALID_HANDLE_VALUE ),
|
|
"Failed to create file!", cleanup );
|
|
|
|
#else
|
|
hFile = open( filename, O_WRONLY | O_CREAT | O_TRUNC,
|
|
/* file mask is 0x550: read-write by user and group */
|
|
S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP );
|
|
|
|
BREAK_IF( hFile == -1,
|
|
"Failed to create file!", cleanup );
|
|
|
|
#endif
|
|
|
|
debug("ok\n");
|
|
|
|
WRITE_NBO( ktfile->Version, "KTFVNO" );
|
|
|
|
for( entry = ktfile->FirstKeyEntry ;
|
|
entry != NULL ;
|
|
entry = entry->nextEntry ) {
|
|
|
|
WRITE_NBO( entry->keySize, "key size (in bytes)");
|
|
|
|
WRITE_NBO( entry->cEntries, "number of components" );
|
|
WRITE_NBO( entry->szRealm, "Realm length" );
|
|
WRITE_STRING( entry->Realm, entry->szRealm, "Realm data" );
|
|
|
|
for (i = 0 ; i < entry->cEntries ; i++ ) {
|
|
WRITE_NBO( entry->Components[i].szComponentData,
|
|
"component datasize");
|
|
WRITE_STRING( entry->Components[i].Component,
|
|
entry->Components[i].szComponentData,
|
|
"component data");
|
|
}
|
|
|
|
WRITE_NBO( entry->PrincType, "Principal Type");
|
|
WRITE_NBO( entry->TimeStamp, "Timestamp" );
|
|
WRITE( entry->Version, "Key Version Number" );
|
|
WRITE_NBO( entry->KeyType, "Key Encryption Type" );
|
|
|
|
#if 0 // eh?
|
|
/* again, this is a kludge to get around the keylength
|
|
problem we can't explain */
|
|
#endif
|
|
|
|
ASSERT( sizeof( entry->KeyLength ) == 2 );
|
|
|
|
WRITE_NBO(entry->KeyLength, "key length" );
|
|
|
|
WRITE_STRING( entry->KeyData,
|
|
entry->KeyLength,
|
|
"key data itself" );
|
|
}
|
|
|
|
ret = TRUE;
|
|
|
|
cleanup:
|
|
CloseHandle(hFile);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|