Leaked source code of windows server 2003
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.

483 lines
13 KiB

  1. /*++
  2. mkkey.c
  3. routines to create the key in the keytab.
  4. 3/27/1997 - Created from routines in munge.c, DavidCHR
  5. CONTENTS: CreateUnicodeStringFromAnsiString
  6. --*/
  7. #include "master.h"
  8. #include "defs.h"
  9. #include "keytab.h"
  10. #include "keytypes.h"
  11. /******************************************************************
  12. * hack to preserve our debugging macro because asn1code.h *
  13. * will redefine it... egads, I thought everyone used DEBUG *
  14. * only for debugging... (it still ends up redefined...) *
  15. ******************************************************************/
  16. #ifdef DEBUG
  17. #define OLDDEBUG DEBUG
  18. #endif
  19. #include <kerbcon.h>
  20. #undef _KERBCOMM_H_ /* WASBUG 73905 */
  21. #include "kerbcomm.h"
  22. #undef DEBUG
  23. #ifdef OLDDEBUG
  24. #define DEBUG OLDDEBUG
  25. #endif
  26. /******************************************************************/
  27. BOOL KtDumpSalt = (
  28. #if DBG
  29. TRUE
  30. #else
  31. FALSE
  32. #endif
  33. );
  34. /* This is the character we separate principal components with */
  35. #define COMPONENT_SEPARATOR '/'
  36. /*++**************************************************************
  37. NAME: CreateUnicodeStringFromAnsiString
  38. allocates a unicode string from an ANSI string.
  39. MODIFIES: ppUnicodeString -- returned unicode string
  40. TAKES: AnsiString -- ansi string to convert
  41. RETURNS: TRUE when the function succeeds.
  42. FALSE otherwise.
  43. LASTERROR: not set
  44. LOGGING: fprintf on failure
  45. CREATED: Feb 8, 1999
  46. LOCKING: none
  47. CALLED BY: anyone
  48. FREE WITH: free()
  49. **************************************************************--*/
  50. BOOL
  51. CreateUnicodeStringFromAnsiString( IN PCHAR AnsiString,
  52. OUT PUNICODE_STRING *ppUnicodeString ) {
  53. USHORT StringLength;
  54. LPBYTE pbString;
  55. PUNICODE_STRING pu;
  56. StringLength = (USHORT)lstrlen( AnsiString ); // does not include null byte
  57. pbString = (PBYTE) malloc( ( ( ( StringLength ) +1 ) * sizeof( WCHAR ) ) +
  58. sizeof( UNICODE_STRING ) );
  59. if ( pbString ) {
  60. pu = (PUNICODE_STRING) pbString;
  61. pbString += sizeof( *pu );
  62. pu->Buffer = (LPWSTR) pbString;
  63. pu->Length = StringLength * sizeof( WCHAR );
  64. pu->MaximumLength = pu->Length + sizeof( WCHAR );
  65. wsprintfW( pu->Buffer,
  66. L"%hs",
  67. AnsiString );
  68. *ppUnicodeString = pu;
  69. return TRUE;
  70. } else {
  71. fprintf( stderr,
  72. "Failed to make unicode string from \"%hs\".\n",
  73. AnsiString );
  74. }
  75. return FALSE;
  76. }
  77. /* KtCreateKey:
  78. create a keytab entry from the given data.
  79. returns TRUE on success, FALSE on failure.
  80. *ppKeyEntry must be freed with FreeKeyEntry when you're done with it.
  81. */
  82. LPWSTR RawHash = NULL;
  83. BOOL
  84. KtCreateKey( PKTENT *ppKeyEntry,
  85. PCHAR principal,
  86. PCHAR password,
  87. PCHAR realmname,
  88. K5_OCTET keyVersionNumber,
  89. ULONG principalType,
  90. ULONG keyType,
  91. ULONG cryptosystem
  92. ) {
  93. PKTENT pEntry = NULL;
  94. PCHAR ioBuffer = NULL;
  95. ULONG i;
  96. ULONG compCounter = 0;
  97. USHORT buffCounter = 0;
  98. BOOL ret = FALSE;
  99. BOOL FreeUnicodeSalt = FALSE;
  100. UNICODE_STRING UnicodePassword = { 0 };
  101. UNICODE_STRING UnicodePrincipal = { 0 };
  102. UNICODE_STRING UnicodeSalt = { 0 };
  103. PWCHAR tmpUnicodeBuffer = NULL;
  104. KERB_ENCRYPTION_KEY KerbKey = { 0 };
  105. WCHAR wSaltBuffer [BUFFER_SIZE];
  106. #ifdef BUILD_SALT
  107. LONG32 saltCounter = 0;
  108. CHAR saltBuffer [BUFFER_SIZE];
  109. #endif
  110. /* you must actually provide these parameters */
  111. ASSERT( ppKeyEntry != NULL );
  112. ASSERT( principal != NULL );
  113. ASSERT( realmname != NULL );
  114. ASSERT( password != NULL );
  115. ASSERT( strlen( password ) < BUFFER_SIZE );
  116. ASSERT( strlen( principal ) < BUFFER_SIZE );
  117. ASSERT( strlen( realmname ) < BUFFER_SIZE );
  118. #ifdef BUILD_SALT
  119. /* if we're building the salt ourselves, initialize the keysalt */
  120. sprintf( saltBuffer, "%s", realmname );
  121. saltCounter = strlen( realmname );
  122. #endif
  123. BREAK_IF( !ONEALLOC( pEntry, KTENT, KEYTAB_ALLOC),
  124. "Failed to allocate base keytab element",
  125. cleanup );
  126. /* zero out the structure, so we know what we have and
  127. haven't allocated if the function fails */
  128. memset( pEntry, 0, sizeof( KTENT ) );
  129. /* first, count the principal components */
  130. for( i = 0 ; principal[i] != '\0' ; i++ ) {
  131. if (principal[i] == COMPONENT_SEPARATOR) {
  132. pEntry->cEntries++;
  133. }
  134. }
  135. pEntry->cEntries++; /* don't forget the final component, which is not
  136. bounded by the separator, but by the NULL */
  137. BREAK_IF( !MYALLOC( pEntry->Components, KTCOMPONENT,
  138. pEntry->cEntries, KEYTAB_ALLOC ),
  139. "Failed to allocate keytab component vector",
  140. cleanup );
  141. /* allocate the buffer for the principal components.
  142. We allocate it the same size as the principal, because
  143. that's the maximum size any single component could be--
  144. the principal could be a one component princ. */
  145. BREAK_IF( !MYALLOC( ioBuffer, CHAR,
  146. strlen(principal)+1, KEYTAB_ALLOC ),
  147. "Failed to allocate local buffer for storage",
  148. cleanup );
  149. /* now, we copy the components themselves, using the iobuffer to
  150. marshall the individual data elements--
  151. basically, add a char to the iobuffer for every char in the principal
  152. until you hit a / (component separator) or the trailing null.
  153. in those cases, we now know the size of the component and we have
  154. the text in a local buffer. allocate a buffer for it, save the size
  155. and strcpy the data itself. */
  156. i = 0;
  157. do {
  158. debug( "%c", principal[i] );
  159. if( (principal[i] == COMPONENT_SEPARATOR) ||
  160. (principal[i] == '\0' /* delimit final component */ ) ) {
  161. /* this component is done. Save and reset the buffer. */
  162. pEntry->Components[compCounter].szComponentData = buffCounter;
  163. #if 0
  164. debug( " --> component boundary for component %d.\n"
  165. " size = %d, value = %*s\n",
  166. compCounter,
  167. buffCounter,
  168. buffCounter,
  169. ioBuffer );
  170. #endif
  171. BREAK_IF( !MYALLOC( pEntry->Components[compCounter].Component,
  172. CHAR, buffCounter+1, KEYTAB_ALLOC ),
  173. "Failed to allocate marshalled component data",
  174. cleanup );
  175. memcpy( pEntry->Components[compCounter].Component,
  176. ioBuffer, buffCounter );
  177. pEntry->Components[compCounter].Component[buffCounter] = '\0';
  178. buffCounter = 0;
  179. compCounter ++;
  180. } else {
  181. ioBuffer[buffCounter] = principal[i];
  182. buffCounter++;
  183. #ifdef BUILD_SALT
  184. /* also send the principal characters WITHOUT SLASHES
  185. to the salt initializer.
  186. WASBUG 73909: the %wc doesn't look right here.
  187. Sure enough, it wasn't. So we removed it. */
  188. sprintf( saltBuffer+saltCounter, "%c", principal[i] );
  189. ASSERT( saltCounter < BUFFER_SIZE ); /* not a very strong assert,
  190. but useful */
  191. saltCounter ++;
  192. ASSERT( saltBuffer[saltCounter] == '\0' ); /* assert that it stays
  193. null terminated at the
  194. saltCounter */
  195. #endif
  196. }
  197. i++;
  198. } while ( principal[i-1] != '\0' );
  199. /* there's still a component in the buffer. Save that component
  200. by assigning the pointer, rather than allocating more memory.
  201. WASBUG 73911: may waste large amounts of memory if the principal is
  202. really big. However, it probably won't be-- we're talking about
  203. strings that humans would generally have to type, so the waste is
  204. going to be in bytes. Also, most of the time, the last component
  205. is the biggest; of the form:
  206. sample/<hostname> or host/<hostname>
  207. ...hostname is generally going to be much larger than sample or host.
  208. */
  209. pEntry->Components[compCounter].szComponentData = buffCounter;
  210. pEntry->Components[compCounter].Component = ioBuffer;
  211. ioBuffer[buffCounter] = '\0';
  212. ioBuffer = NULL; /* keep from
  213. deallocating */
  214. pEntry->Version = keyVersionNumber;
  215. pEntry->szRealm = (K5_INT16) strlen(realmname);
  216. pEntry->KeyType = (unsigned short)keyType;
  217. pEntry->PrincType = principalType;
  218. /* copy the realm name */
  219. BREAK_IF( !MYALLOC( pEntry->Realm, CHAR, pEntry->szRealm+1, KEYTAB_ALLOC),
  220. "Failed to allocate destination realm data", cleanup );
  221. memcpy( pEntry->Realm, realmname, pEntry->szRealm+1 ); /* copy the null */
  222. /***********************************************************************/
  223. /*** ***/
  224. /*** Windows NT Key Creation Side ***/
  225. /*** ***/
  226. /***********************************************************************/
  227. /* create unicode variants of the input parameters */
  228. BREAK_IF( !MYALLOC( tmpUnicodeBuffer, WCHAR,
  229. strlen( password )+1, KEYTAB_ALLOC ),
  230. "Failed to alloc buffer for password", cleanup );
  231. wsprintfW( tmpUnicodeBuffer, L"%hs", password );
  232. RtlInitUnicodeString( &UnicodePassword, tmpUnicodeBuffer );
  233. BREAK_IF( !MYALLOC( tmpUnicodeBuffer, WCHAR,
  234. strlen( principal )+1, KEYTAB_ALLOC ),
  235. "Failed to alloc buffer for principal", cleanup );
  236. wsprintfW( tmpUnicodeBuffer, L"%hs", principal );
  237. RtlInitUnicodeString( &UnicodePrincipal, tmpUnicodeBuffer );
  238. wsprintfW( wSaltBuffer, L"%hs", realmname );
  239. RtlInitUnicodeString( &UnicodeSalt, wSaltBuffer );
  240. {
  241. KERB_ACCOUNT_TYPE acctType;
  242. acctType = UnknownAccount;
  243. if ( RawHash ) {
  244. if ( KtDumpSalt ) {
  245. fprintf( stderr,
  246. "Using supplied salt.\n" );
  247. }
  248. RtlInitUnicodeString( &UnicodeSalt,
  249. RawHash );
  250. } else {
  251. PUNICODE_STRING pRealmString;
  252. if ( CreateUnicodeStringFromAnsiString( realmname,
  253. &pRealmString ) ) {
  254. KERBERR kerberr;
  255. if ( KtDumpSalt ) {
  256. fprintf( stderr,
  257. "Building salt with principalname %wZ"
  258. " and domain %wZ...\n",
  259. &UnicodePrincipal,
  260. pRealmString );
  261. }
  262. debug( "KerbBuildKeySalt( Realm = %wZ\n"
  263. " Princ = %wZ\n"
  264. " acctType = %d.\n",
  265. pRealmString,
  266. &UnicodePrincipal,
  267. acctType );
  268. kerberr = KerbBuildKeySalt( pRealmString,
  269. &UnicodePrincipal,
  270. acctType,
  271. &UnicodeSalt );
  272. free( pRealmString );
  273. BREAK_IF( kerberr,
  274. "Failed to KerbBuildKeySalt",
  275. cleanup );
  276. FreeUnicodeSalt = TRUE;
  277. }
  278. }
  279. } // scope block.
  280. if ( KtDumpSalt ) {
  281. fprintf( stderr,
  282. "Hashing password with salt \"%wZ\".\n",
  283. &UnicodeSalt );
  284. }
  285. debug( "KerbHashPasswordEx( UnicodePassword = %wZ \n"
  286. " UnicodeSalt = %wZ \n"
  287. " cryptosystem = 0x%x\n"
  288. " &KerbKey = 0x%p )...\n",
  289. &UnicodePassword,
  290. &UnicodeSalt,
  291. cryptosystem,
  292. &KerbKey );
  293. BREAK_IF( KerbHashPasswordEx( &UnicodePassword,
  294. &UnicodeSalt,
  295. cryptosystem,
  296. &KerbKey ),
  297. "KerbHashPasswordEx failed.",
  298. cleanup );
  299. pEntry->KeyLength = (USHORT)KerbKey.keyvalue.length;
  300. BREAK_IF( !MYALLOC( pEntry->KeyData, K5_OCTET,
  301. pEntry->KeyLength, KEYTAB_ALLOC ),
  302. "Failed to allocate keydata", cleanup );
  303. memcpy( pEntry->KeyData, KerbKey.keyvalue.value,
  304. pEntry->KeyLength );
  305. /* NOTE: no keyentry changes beyond this line.
  306. we must compute the key size LAST! */
  307. pEntry->keySize = ComputeKeytabLength( pEntry );
  308. *ppKeyEntry = pEntry; /* save this */
  309. pEntry = NULL; /* save us from freeing it */
  310. ret = TRUE;
  311. cleanup:
  312. #define FREE_IF_NOT_NULL( element ) { if ( element != NULL ) { KEYTAB_FREE( element ); } }
  313. if ( pEntry ) {
  314. FreeKeyEntry (pEntry );
  315. }
  316. WINNT_ONLY( FREE_IF_NOT_NULL( UnicodePassword.Buffer ) );
  317. WINNT_ONLY( FREE_IF_NOT_NULL( UnicodePrincipal.Buffer ) );
  318. #ifndef BUILD_KEYSALT
  319. /* WASBUG 73915: how to free UnicodeSalt?
  320. ...with KerbFreeString. */
  321. ASSERT( FreeUnicodeSalt );
  322. KerbFreeString( &UnicodeSalt );
  323. #else
  324. /* Check my logic. */
  325. ASSERT( !FreeUnicodeSalt );
  326. #endif
  327. /* WASBUG 73918: how do I get rid of the data in KerbKey?
  328. ...with KerbFreeKey. */
  329. KerbFreeKey( &KerbKey );
  330. return ret;
  331. }