/*++ mkkey.c routines to create the key in the keytab. 3/27/1997 - Created from routines in munge.c, DavidCHR CONTENTS: CreateUnicodeStringFromAnsiString --*/ #include "master.h" #include "defs.h" #include "keytab.h" #include "keytypes.h" /****************************************************************** * hack to preserve our debugging macro because asn1code.h * * will redefine it... egads, I thought everyone used DEBUG * * only for debugging... (it still ends up redefined...) * ******************************************************************/ #ifdef DEBUG #define OLDDEBUG DEBUG #endif #include #undef _KERBCOMM_H_ /* WASBUG 73905 */ #include "kerbcomm.h" #undef DEBUG #ifdef OLDDEBUG #define DEBUG OLDDEBUG #endif /******************************************************************/ BOOL KtDumpSalt = ( #if DBG TRUE #else FALSE #endif ); /* This is the character we separate principal components with */ #define COMPONENT_SEPARATOR '/' /*++************************************************************** NAME: CreateUnicodeStringFromAnsiString allocates a unicode string from an ANSI string. MODIFIES: ppUnicodeString -- returned unicode string TAKES: AnsiString -- ansi string to convert RETURNS: TRUE when the function succeeds. FALSE otherwise. LASTERROR: not set LOGGING: fprintf on failure CREATED: Feb 8, 1999 LOCKING: none CALLED BY: anyone FREE WITH: free() **************************************************************--*/ BOOL CreateUnicodeStringFromAnsiString( IN PCHAR AnsiString, OUT PUNICODE_STRING *ppUnicodeString ) { USHORT StringLength; LPBYTE pbString; PUNICODE_STRING pu; StringLength = (USHORT)lstrlen( AnsiString ); // does not include null byte pbString = (PBYTE) malloc( ( ( ( StringLength ) +1 ) * sizeof( WCHAR ) ) + sizeof( UNICODE_STRING ) ); if ( pbString ) { pu = (PUNICODE_STRING) pbString; pbString += sizeof( *pu ); pu->Buffer = (LPWSTR) pbString; pu->Length = StringLength * sizeof( WCHAR ); pu->MaximumLength = pu->Length + sizeof( WCHAR ); wsprintfW( pu->Buffer, L"%hs", AnsiString ); *ppUnicodeString = pu; return TRUE; } else { fprintf( stderr, "Failed to make unicode string from \"%hs\".\n", AnsiString ); } return FALSE; } /* KtCreateKey: create a keytab entry from the given data. returns TRUE on success, FALSE on failure. *ppKeyEntry must be freed with FreeKeyEntry when you're done with it. */ LPWSTR RawHash = NULL; BOOL KtCreateKey( PKTENT *ppKeyEntry, PCHAR principal, PCHAR password, PCHAR realmname, K5_OCTET keyVersionNumber, ULONG principalType, ULONG keyType, ULONG cryptosystem ) { PKTENT pEntry = NULL; PCHAR ioBuffer = NULL; ULONG i; ULONG compCounter = 0; USHORT buffCounter = 0; BOOL ret = FALSE; BOOL FreeUnicodeSalt = FALSE; UNICODE_STRING UnicodePassword = { 0 }; UNICODE_STRING UnicodePrincipal = { 0 }; UNICODE_STRING UnicodeSalt = { 0 }; PWCHAR tmpUnicodeBuffer = NULL; KERB_ENCRYPTION_KEY KerbKey = { 0 }; WCHAR wSaltBuffer [BUFFER_SIZE]; #ifdef BUILD_SALT LONG32 saltCounter = 0; CHAR saltBuffer [BUFFER_SIZE]; #endif /* you must actually provide these parameters */ ASSERT( ppKeyEntry != NULL ); ASSERT( principal != NULL ); ASSERT( realmname != NULL ); ASSERT( password != NULL ); ASSERT( strlen( password ) < BUFFER_SIZE ); ASSERT( strlen( principal ) < BUFFER_SIZE ); ASSERT( strlen( realmname ) < BUFFER_SIZE ); #ifdef BUILD_SALT /* if we're building the salt ourselves, initialize the keysalt */ sprintf( saltBuffer, "%s", realmname ); saltCounter = strlen( realmname ); #endif BREAK_IF( !ONEALLOC( pEntry, KTENT, KEYTAB_ALLOC), "Failed to allocate base keytab element", cleanup ); /* zero out the structure, so we know what we have and haven't allocated if the function fails */ memset( pEntry, 0, sizeof( KTENT ) ); /* first, count the principal components */ for( i = 0 ; principal[i] != '\0' ; i++ ) { if (principal[i] == COMPONENT_SEPARATOR) { pEntry->cEntries++; } } pEntry->cEntries++; /* don't forget the final component, which is not bounded by the separator, but by the NULL */ BREAK_IF( !MYALLOC( pEntry->Components, KTCOMPONENT, pEntry->cEntries, KEYTAB_ALLOC ), "Failed to allocate keytab component vector", cleanup ); /* allocate the buffer for the principal components. We allocate it the same size as the principal, because that's the maximum size any single component could be-- the principal could be a one component princ. */ BREAK_IF( !MYALLOC( ioBuffer, CHAR, strlen(principal)+1, KEYTAB_ALLOC ), "Failed to allocate local buffer for storage", cleanup ); /* now, we copy the components themselves, using the iobuffer to marshall the individual data elements-- basically, add a char to the iobuffer for every char in the principal until you hit a / (component separator) or the trailing null. in those cases, we now know the size of the component and we have the text in a local buffer. allocate a buffer for it, save the size and strcpy the data itself. */ i = 0; do { debug( "%c", principal[i] ); if( (principal[i] == COMPONENT_SEPARATOR) || (principal[i] == '\0' /* delimit final component */ ) ) { /* this component is done. Save and reset the buffer. */ pEntry->Components[compCounter].szComponentData = buffCounter; #if 0 debug( " --> component boundary for component %d.\n" " size = %d, value = %*s\n", compCounter, buffCounter, buffCounter, ioBuffer ); #endif BREAK_IF( !MYALLOC( pEntry->Components[compCounter].Component, CHAR, buffCounter+1, KEYTAB_ALLOC ), "Failed to allocate marshalled component data", cleanup ); memcpy( pEntry->Components[compCounter].Component, ioBuffer, buffCounter ); pEntry->Components[compCounter].Component[buffCounter] = '\0'; buffCounter = 0; compCounter ++; } else { ioBuffer[buffCounter] = principal[i]; buffCounter++; #ifdef BUILD_SALT /* also send the principal characters WITHOUT SLASHES to the salt initializer. WASBUG 73909: the %wc doesn't look right here. Sure enough, it wasn't. So we removed it. */ sprintf( saltBuffer+saltCounter, "%c", principal[i] ); ASSERT( saltCounter < BUFFER_SIZE ); /* not a very strong assert, but useful */ saltCounter ++; ASSERT( saltBuffer[saltCounter] == '\0' ); /* assert that it stays null terminated at the saltCounter */ #endif } i++; } while ( principal[i-1] != '\0' ); /* there's still a component in the buffer. Save that component by assigning the pointer, rather than allocating more memory. WASBUG 73911: may waste large amounts of memory if the principal is really big. However, it probably won't be-- we're talking about strings that humans would generally have to type, so the waste is going to be in bytes. Also, most of the time, the last component is the biggest; of the form: sample/ or host/ ...hostname is generally going to be much larger than sample or host. */ pEntry->Components[compCounter].szComponentData = buffCounter; pEntry->Components[compCounter].Component = ioBuffer; ioBuffer[buffCounter] = '\0'; ioBuffer = NULL; /* keep from deallocating */ pEntry->Version = keyVersionNumber; pEntry->szRealm = (K5_INT16) strlen(realmname); pEntry->KeyType = (unsigned short)keyType; pEntry->PrincType = principalType; /* copy the realm name */ BREAK_IF( !MYALLOC( pEntry->Realm, CHAR, pEntry->szRealm+1, KEYTAB_ALLOC), "Failed to allocate destination realm data", cleanup ); memcpy( pEntry->Realm, realmname, pEntry->szRealm+1 ); /* copy the null */ /***********************************************************************/ /*** ***/ /*** Windows NT Key Creation Side ***/ /*** ***/ /***********************************************************************/ /* create unicode variants of the input parameters */ BREAK_IF( !MYALLOC( tmpUnicodeBuffer, WCHAR, strlen( password )+1, KEYTAB_ALLOC ), "Failed to alloc buffer for password", cleanup ); wsprintfW( tmpUnicodeBuffer, L"%hs", password ); RtlInitUnicodeString( &UnicodePassword, tmpUnicodeBuffer ); BREAK_IF( !MYALLOC( tmpUnicodeBuffer, WCHAR, strlen( principal )+1, KEYTAB_ALLOC ), "Failed to alloc buffer for principal", cleanup ); wsprintfW( tmpUnicodeBuffer, L"%hs", principal ); RtlInitUnicodeString( &UnicodePrincipal, tmpUnicodeBuffer ); wsprintfW( wSaltBuffer, L"%hs", realmname ); RtlInitUnicodeString( &UnicodeSalt, wSaltBuffer ); { KERB_ACCOUNT_TYPE acctType; acctType = UnknownAccount; if ( RawHash ) { if ( KtDumpSalt ) { fprintf( stderr, "Using supplied salt.\n" ); } RtlInitUnicodeString( &UnicodeSalt, RawHash ); } else { PUNICODE_STRING pRealmString; if ( CreateUnicodeStringFromAnsiString( realmname, &pRealmString ) ) { KERBERR kerberr; if ( KtDumpSalt ) { fprintf( stderr, "Building salt with principalname %wZ" " and domain %wZ...\n", &UnicodePrincipal, pRealmString ); } debug( "KerbBuildKeySalt( Realm = %wZ\n" " Princ = %wZ\n" " acctType = %d.\n", pRealmString, &UnicodePrincipal, acctType ); kerberr = KerbBuildKeySalt( pRealmString, &UnicodePrincipal, acctType, &UnicodeSalt ); free( pRealmString ); BREAK_IF( kerberr, "Failed to KerbBuildKeySalt", cleanup ); FreeUnicodeSalt = TRUE; } } } // scope block. if ( KtDumpSalt ) { fprintf( stderr, "Hashing password with salt \"%wZ\".\n", &UnicodeSalt ); } debug( "KerbHashPasswordEx( UnicodePassword = %wZ \n" " UnicodeSalt = %wZ \n" " cryptosystem = 0x%x\n" " &KerbKey = 0x%p )...\n", &UnicodePassword, &UnicodeSalt, cryptosystem, &KerbKey ); BREAK_IF( KerbHashPasswordEx( &UnicodePassword, &UnicodeSalt, cryptosystem, &KerbKey ), "KerbHashPasswordEx failed.", cleanup ); pEntry->KeyLength = (USHORT)KerbKey.keyvalue.length; BREAK_IF( !MYALLOC( pEntry->KeyData, K5_OCTET, pEntry->KeyLength, KEYTAB_ALLOC ), "Failed to allocate keydata", cleanup ); memcpy( pEntry->KeyData, KerbKey.keyvalue.value, pEntry->KeyLength ); /* NOTE: no keyentry changes beyond this line. we must compute the key size LAST! */ pEntry->keySize = ComputeKeytabLength( pEntry ); *ppKeyEntry = pEntry; /* save this */ pEntry = NULL; /* save us from freeing it */ ret = TRUE; cleanup: #define FREE_IF_NOT_NULL( element ) { if ( element != NULL ) { KEYTAB_FREE( element ); } } if ( pEntry ) { FreeKeyEntry (pEntry ); } WINNT_ONLY( FREE_IF_NOT_NULL( UnicodePassword.Buffer ) ); WINNT_ONLY( FREE_IF_NOT_NULL( UnicodePrincipal.Buffer ) ); #ifndef BUILD_KEYSALT /* WASBUG 73915: how to free UnicodeSalt? ...with KerbFreeString. */ ASSERT( FreeUnicodeSalt ); KerbFreeString( &UnicodeSalt ); #else /* Check my logic. */ ASSERT( !FreeUnicodeSalt ); #endif /* WASBUG 73918: how do I get rid of the data in KerbKey? ...with KerbFreeKey. */ KerbFreeKey( &KerbKey ); return ret; }