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.

672 lines
16 KiB

  1. /*++
  2. SUPPORT.CXX
  3. Copyright (C) 1999 Microsoft Corporation, all rights reserved.
  4. DESCRIPTION: support functions for ktpass
  5. Created, May 21, 1999 by DavidCHR.
  6. CONTENTS: ReadRegistryStrings
  7. --*/
  8. #include "everything.hxx"
  9. NTSTATUS
  10. OpenLsa( VOID )
  11. {
  12. OBJECT_ATTRIBUTES oa;
  13. NTSTATUS Status;
  14. UNICODE_STRING ServerString;
  15. RtlInitUnicodeString(
  16. &ServerString,
  17. ServerName
  18. );
  19. InitializeObjectAttributes(&oa,NULL,0,NULL,NULL);
  20. Status = LsaOpenPolicy(&ServerString,&oa,MAXIMUM_ALLOWED,&LsaHandle);
  21. return(Status);
  22. }
  23. NTSTATUS
  24. OpenLocalLsa( OUT PLSA_HANDLE phLsa ) {
  25. static LSA_HANDLE hLsa = NULL;
  26. NTSTATUS N = STATUS_SUCCESS;
  27. if ( !hLsa ) {
  28. N = LsaConnectUntrusted( &hLsa );
  29. if ( !NT_SUCCESS( N ) ) {
  30. printf( "Failed to connect to the local LSA: 0x%x\n",
  31. N );
  32. }
  33. }
  34. if ( NT_SUCCESS( N ) ) {
  35. *phLsa = hLsa;
  36. } else {
  37. hLsa = NULL;
  38. }
  39. return N;
  40. }
  41. /*++**************************************************************
  42. NAME: ReadActualPassword
  43. convenience routine for reading the password for a particular
  44. account. Disables command line echo for the duration.
  45. MODIFIES: Password -- receives the new password
  46. TAKES: Description -- descriptive string to insert
  47. into prompts and error messages.
  48. flags -- see everything.h:
  49. PROMPT_USING_POSSESSIVE_CASE
  50. PROMPT_FOR_PASSWORD_TWICE
  51. RETURNS: TRUE when the function succeeds.
  52. FALSE otherwise.
  53. LASTERROR: not set
  54. LOGGING: printf on failure
  55. CREATED: Apr 7, 1999
  56. LOCKING: none
  57. CALLED BY: anyone
  58. FREE WITH: n/a -- no resources are allocated
  59. CONTENTS: CallAuthPackage
  60. **************************************************************--*/
  61. BOOL
  62. ReadActualPassword( IN LPWSTR Description,
  63. IN ULONG flags,
  64. IN ULONG PasswordLength,
  65. OUT LPWSTR Password ) {
  66. HANDLE hConsole;
  67. DWORD dwMode;
  68. BOOL ret = FALSE;
  69. ULONG Length;
  70. WCHAR TempPassword[ MAX_PASSWD_LEN ];
  71. ULONG i;
  72. hConsole = GetStdHandle( STD_INPUT_HANDLE );
  73. if ( hConsole ) {
  74. // get the old console settings.
  75. if ( GetConsoleMode( hConsole,
  76. &dwMode ) ) {
  77. // now turn off typing echo
  78. if ( SetConsoleMode( hConsole,
  79. dwMode &~ ENABLE_ECHO_INPUT ) ) {
  80. fprintf( stderr,
  81. ( flags & PROMPT_USING_POSSESSIVE_CASE ) ?
  82. "Enter password for %ws: " :
  83. "Enter %ws password: ",
  84. Description );
  85. if ( !fgetws( Password, PasswordLength, stdin ) ) {
  86. fprintf( stderr,
  87. "EOF on input. Aborted.\n" );
  88. goto restoreConsoleMode;
  89. }
  90. for ( i = 0; i < PasswordLength; i++ )
  91. {
  92. if ( Password[i] == L'\n' )
  93. {
  94. Password[i] = L'\0';
  95. break;
  96. }
  97. }
  98. if ( flags & PROMPT_FOR_PASSWORD_TWICE ) {
  99. fprintf( stderr,
  100. "\nNow re-enter password to confirm: " );
  101. if ( !fgetws( TempPassword, MAX_PASSWD_LEN, stdin ) ) {
  102. fprintf( stderr,
  103. "EOF on input. Aborted.\n" );
  104. goto restoreConsoleMode;
  105. }
  106. for ( i = 0; i < MAX_PASSWD_LEN; i++ )
  107. {
  108. if ( TempPassword[i] == L'\n' )
  109. {
  110. TempPassword[i] = L'\0';
  111. break;
  112. }
  113. }
  114. }
  115. fprintf( stderr,
  116. "\n" );
  117. if ( flags & PROMPT_FOR_PASSWORD_TWICE ) {
  118. // verify that the two passwords are the same.
  119. if ( wcscmp( Password,
  120. TempPassword ) == 0 ) {
  121. ret = TRUE;
  122. } else {
  123. fprintf( stderr,
  124. "Passwords do not match.\n" );
  125. }
  126. } else {
  127. ret = TRUE;
  128. }
  129. restoreConsoleMode:
  130. // restore echo
  131. SetConsoleMode( hConsole,
  132. dwMode );
  133. } else {
  134. fprintf( stderr,
  135. "Failed to disable line echo for password entry of %ws: 0x%x.\n",
  136. Description,
  137. GetLastError() );
  138. }
  139. } else {
  140. fprintf( stderr,
  141. "Failed to retrieve current console settings: 0x%x\n",
  142. GetLastError() );
  143. }
  144. } else {
  145. fprintf( stderr,
  146. "Failed to obtain console handle so we could disable line input echo: 0x%x\n",
  147. GetLastError() );
  148. }
  149. SecureZeroMemory( TempPassword, sizeof( TempPassword ));
  150. return ret;
  151. }
  152. /*++**************************************************************
  153. NAME: ReadOptionallyStarredPassword
  154. if the given password is "*", read a new password from stdin.
  155. Otherwise, return the given password.
  156. MODIFIES: pPassword -- receives the real password
  157. TAKES: Password -- password to check for *
  158. Description, flags -- as ReadActualPassword
  159. RETURNS: TRUE when the function succeeds.
  160. FALSE otherwise.
  161. LASTERROR: not set
  162. LOGGING: printf on failure
  163. CREATED: Apr 7, 1999
  164. LOCKING: none
  165. CALLED BY: anyone
  166. FREE WITH: free()
  167. **************************************************************--*/
  168. BOOL
  169. ReadOptionallyStarredPassword( IN LPWSTR InPassword,
  170. IN ULONG flags,
  171. IN LPWSTR Description,
  172. OUT LPWSTR *pPassword ) {
  173. ULONG Length;
  174. LPWSTR OutPass;
  175. BOOL ReadPass;
  176. BOOL ret = FALSE;
  177. Length = lstrlenW( InPassword );
  178. if ( ( 1 == Length ) &&
  179. ( L'*' == InPassword[ 0 ] ) ) {
  180. ReadPass = TRUE;
  181. Length = MAX_PASSWD_LEN;
  182. } else {
  183. ReadPass = FALSE;
  184. }
  185. Length++; // null character
  186. Length *= sizeof( WCHAR );
  187. OutPass = (LPWSTR) malloc( Length );
  188. if ( OutPass != NULL ) {
  189. if ( ReadPass ) {
  190. ret = ReadActualPassword( Description,
  191. flags,
  192. Length / sizeof( WCHAR ),
  193. OutPass );
  194. } else {
  195. lstrcpyW( OutPass,
  196. InPassword );
  197. ret = TRUE;
  198. }
  199. if ( ret ) {
  200. *pPassword = OutPass;
  201. } else {
  202. SecureZeroMemory( OutPass, Length );
  203. free( OutPass );
  204. }
  205. } else {
  206. fprintf( stderr,
  207. "Failed to allocate memory for %ws password.\n",
  208. Description );
  209. }
  210. return ret;
  211. }
  212. /*++**************************************************************
  213. NAME: CallAuthPackage
  214. convenience routine to centralize calls to LsaCallAuthentication
  215. Package.
  216. MODIFIES: ppvOutput -- data returned by LsaCallAuthPackage
  217. pulOutputSize -- returned size of that buffer
  218. TAKES: pvData -- submission data for that same api
  219. ulInputSize -- sizeof the given buffer
  220. RETURNS: a status code indicating success or failure
  221. LOGGING: none
  222. CREATED: Apr 13, 1999
  223. LOCKING: none
  224. CALLED BY: anyone, most notably ChangeViaKpasswd
  225. FREE WITH: ppvOutput with LsaFreeReturnBuffer
  226. **************************************************************--*/
  227. NTSTATUS
  228. CallAuthPackage( IN PVOID pvData,
  229. IN ULONG ulInputSize,
  230. OUT PVOID *ppvOutput,
  231. OUT PULONG pulOutputSize ) {
  232. // These are globals that are specific to this function.
  233. static STRING Name = { 0 };
  234. static ULONG PackageId = 0;
  235. static BOOL NameSetup = FALSE;
  236. LSA_HANDLE hLsa;
  237. NTSTATUS N;
  238. if ( NT_SUCCESS( N = OpenLocalLsa( &hLsa ) ) ) {
  239. if ( !NameSetup ) {
  240. RtlInitString( &Name,
  241. MICROSOFT_KERBEROS_NAME_A );
  242. N = LsaLookupAuthenticationPackage( hLsa,
  243. &Name,
  244. &PackageId );
  245. NameSetup = NT_SUCCESS( N );
  246. }
  247. if ( NT_SUCCESS( N ) ) {
  248. NTSTATUS SubStatus;
  249. N = LsaCallAuthenticationPackage( hLsa,
  250. PackageId,
  251. pvData,
  252. ulInputSize,
  253. ppvOutput,
  254. pulOutputSize,
  255. &SubStatus );
  256. if ( !NT_SUCCESS( N ) ||
  257. !NT_SUCCESS( SubStatus ) ) {
  258. printf( "CallAuthPackage failed, status 0x%x, substatus 0x%x.\n",
  259. N, SubStatus );
  260. }
  261. if ( NT_SUCCESS( N ) ) {
  262. N = SubStatus;
  263. }
  264. }
  265. }
  266. return N;
  267. }
  268. VOID
  269. InitStringAndMoveOn( IN LPWSTR RealString,
  270. IN OUT LPWSTR *pCursor,
  271. IN OUT PUNICODE_STRING pString ) {
  272. ULONG Length;
  273. Length = lstrlenW( RealString ) +1;
  274. memcpy( *pCursor,
  275. RealString,
  276. Length * sizeof( WCHAR ) );
  277. RtlInitUnicodeString( pString,
  278. *pCursor );
  279. *pCursor += Length;
  280. // ASSERT( **pCursor == L'\0' );
  281. }
  282. NTSTATUS
  283. ChangeViaKpasswd( LPWSTR * Parameters ) {
  284. LPWSTR OldPassword = NULL, NewPassword = NULL;
  285. NTSTATUS ret = STATUS_UNSUCCESSFUL;
  286. PKERB_CHANGEPASSWORD_REQUEST pPasswd = NULL;
  287. LPWSTR Cursor;
  288. PVOID pvTrash;
  289. ULONG size, ulTrash;
  290. if ( !GlobalDomainSetting ) {
  291. printf( "Can't change password without /domain.\n" );
  292. ret = STATUS_INVALID_PARAMETER;
  293. } else if ( !( ReadOptionallyStarredPassword( Parameters[ 0 ],
  294. 0, // no flags
  295. L"your old",
  296. &OldPassword ) &&
  297. ReadOptionallyStarredPassword( Parameters[ 1 ],
  298. PROMPT_FOR_PASSWORD_TWICE,
  299. L"your new",
  300. &NewPassword ) ) ) {
  301. printf( "Failed to validate passwords for password change.\n" );
  302. ret = STATUS_INTERNAL_ERROR;
  303. } else {
  304. size = lstrlenW( GlobalDomainSetting ) + 1;
  305. size += lstrlenW( GlobalClientName ) + 1;
  306. size += lstrlenW( OldPassword ) + 1;
  307. size += lstrlenW( NewPassword ) + 1;
  308. // all strings above this line
  309. size *= sizeof( WCHAR );
  310. size += sizeof( *pPasswd ) ; // buffer
  311. pPasswd = (PKERB_CHANGEPASSWORD_REQUEST) malloc( size );
  312. if ( pPasswd ) {
  313. // start at the end of the password-request buffer
  314. Cursor = (LPWSTR) &( pPasswd[1] );
  315. pPasswd->MessageType = KerbChangePasswordMessage;
  316. InitStringAndMoveOn( GlobalDomainSetting,
  317. &Cursor,
  318. &pPasswd->DomainName );
  319. InitStringAndMoveOn( GlobalClientName,
  320. &Cursor,
  321. &pPasswd->AccountName );
  322. InitStringAndMoveOn( OldPassword,
  323. &Cursor,
  324. &pPasswd->OldPassword );
  325. InitStringAndMoveOn( NewPassword,
  326. &Cursor,
  327. &pPasswd->NewPassword );
  328. pPasswd->Impersonating = FALSE; // TRUE; // FALSE;
  329. ret = CallAuthPackage( pPasswd,
  330. size,
  331. (PVOID *) &pvTrash,
  332. &ulTrash );
  333. if ( NT_SUCCESS( ret ) ) {
  334. printf( "Password changed.\n" );
  335. } else {
  336. printf( "Failed to change password: 0x%x\n",
  337. ret );
  338. }
  339. // zero the buffer to minimize exposure of the password.
  340. SecureZeroMemory(
  341. pPasswd,
  342. size );
  343. free( pPasswd );
  344. } else {
  345. printf( "Failed to allocate %ld-byte password change request.\n",
  346. size );
  347. ret = STATUS_NO_MEMORY;
  348. }
  349. }
  350. // zero the buffers to minimize exposure of the passwords
  351. if ( NewPassword )
  352. {
  353. SecureZeroMemory( NewPassword, lstrlenW( NewPassword ));
  354. free( NewPassword );
  355. }
  356. if ( OldPassword )
  357. {
  358. SecureZeroMemory( OldPassword, lstrlenW( OldPassword ));
  359. free( OldPassword );
  360. }
  361. return ret;
  362. }
  363. DWORD
  364. OpenKerberosKey(
  365. OUT PHKEY KerbHandle
  366. )
  367. {
  368. DWORD RegErr;
  369. HKEY ServerHandle = NULL;
  370. DWORD Disposition;
  371. RegErr = RegConnectRegistry(
  372. ServerName,
  373. HKEY_LOCAL_MACHINE,
  374. &ServerHandle
  375. );
  376. if (RegErr)
  377. {
  378. printf("Failed to connect to registry: %d (0x%x) \n",RegErr, RegErr);
  379. goto Cleanup;
  380. }
  381. RegErr = RegCreateKeyEx(
  382. ServerHandle,
  383. KERB_KERBEROS_KEY,
  384. 0,
  385. NULL,
  386. 0, // no options
  387. KEY_CREATE_SUB_KEY,
  388. NULL,
  389. KerbHandle,
  390. &Disposition
  391. );
  392. if (RegErr)
  393. {
  394. printf("Failed to create Kerberos key: %d (0x%x)\n",RegErr, RegErr);
  395. goto Cleanup;
  396. }
  397. Cleanup:
  398. if (ServerHandle)
  399. {
  400. RegCloseKey(ServerHandle);
  401. }
  402. return(RegErr);
  403. }
  404. DWORD
  405. OpenSubKey( IN LPWSTR * Parameters,
  406. OUT PHKEY phKey ) {
  407. DWORD RegErr;
  408. HKEY KerbHandle = NULL;
  409. HKEY DomainHandle = NULL;
  410. HKEY DomainRoot = NULL;
  411. DWORD Disposition;
  412. LPWSTR OldServerNames = NULL;
  413. LPWSTR NewServerNames = NULL;
  414. ULONG OldKdcLength = 0;
  415. ULONG NewKdcLength = 0;
  416. ULONG Type;
  417. RegErr = OpenKerberosKey(&KerbHandle);
  418. if ( RegErr == ERROR_SUCCESS )
  419. {
  420. RegErr = RegCreateKeyEx( KerbHandle,
  421. KERB_DOMAINS_SUBKEY,
  422. 0,
  423. NULL,
  424. 0, // no options
  425. KEY_CREATE_SUB_KEY,
  426. NULL,
  427. &DomainRoot,
  428. &Disposition );
  429. if ( RegErr == ERROR_SUCCESS )
  430. {
  431. if ( Parameters && Parameters[ 0 ] )
  432. {
  433. RegErr = RegCreateKeyEx( DomainRoot,
  434. Parameters[0],
  435. 0,
  436. NULL,
  437. 0, // no options
  438. KEY_CREATE_SUB_KEY | KEY_SET_VALUE | KEY_QUERY_VALUE,
  439. NULL,
  440. &DomainHandle,
  441. &Disposition );
  442. if ( RegErr == ERROR_SUCCESS )
  443. {
  444. *phKey = DomainHandle;
  445. }
  446. else
  447. {
  448. printf("Failed to create %ws key: 0x%x\n", Parameters[ 0 ], RegErr);
  449. }
  450. RegCloseKey( DomainRoot );
  451. }
  452. else /* return the domain root if no domain is requested. */
  453. {
  454. *phKey = DomainRoot;
  455. }
  456. }
  457. else
  458. {
  459. printf( "Failed to create key %ws: 0x%x\n", Parameters[ 0 ], RegErr );
  460. }
  461. RegCloseKey( KerbHandle );
  462. }
  463. else
  464. {
  465. printf( "Failed to open Kerberos Key: 0x%x\n", RegErr );
  466. }
  467. return RegErr;
  468. }