Source code of Windows XP (NT5)
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.

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