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.

1212 lines
31 KiB

  1. /*--
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. creduit.cxx
  5. Abstract:
  6. Test program for the credential manager UI API.
  7. Author:
  8. 16-Jan-2001 (cliffv)
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. --*/
  15. #define UNICODE
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <shellapi.h>
  21. #include <wincred.h>
  22. #include <credp.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <lmerr.h>
  26. #include <align.h>
  27. #define _CREDUI_
  28. #include <wincrui.h>
  29. #include <lmcons.h>
  30. extern "C" {
  31. #include <names.h>
  32. #include <rpcutil.h>
  33. }
  34. #include <winerror.dbg>
  35. //
  36. // Structure defining a array of parsed strings
  37. //
  38. typedef struct _STRING_ARRAY {
  39. BOOLEAN Specified;
  40. DWORD Count;
  41. #define STRING_ARRAY_COUNT 100
  42. LPWSTR Strings[STRING_ARRAY_COUNT];
  43. } STRING_ARRAY, *PSTRING_ARRAY;
  44. //
  45. // Parsed Parameters
  46. //
  47. LPWSTR CommandLine;
  48. DWORD GlCommand = 0xFFFFFFFF;
  49. BOOLEAN GlAnsi;
  50. BOOLEAN GlDoGui;
  51. LPWSTR GlUserName;
  52. LPWSTR GlTargetName;
  53. LPWSTR GlMessage;
  54. LPWSTR GlTitle;
  55. LPWSTR GlAuthError;
  56. DWORD GlCreduiFlags;
  57. BOOLEAN GlNoConfirm;
  58. BOOL GlSave;
  59. //
  60. // Table of valid parameters to the command.
  61. //
  62. struct _PARAMAMTER_DEF {
  63. LPWSTR Name; // Name of the parameter
  64. LPSTR ValueName; // Test describing parameter value
  65. DWORD Type; // Parameter type
  66. #define PARM_COMMAND 1 // Parameter defines a command
  67. #define PARM_COMMAND_STR 2 // Parameter defines a command (and has text string)
  68. #define PARM_COMMAND_OPTSTR 3 // Parameter defines a command (and optionaly has text string)
  69. #define PARM_STRING 4 // Parameter defines a text string
  70. #define PARM_STRING_ENUM 5 // Parameter is an enumeration of text strings
  71. #define PARM_STRING_ARRAY 6 // Parameter is an array of text strings
  72. #define PARM_BOOLEAN 7 // Parameter set a boolean
  73. #define PARM_BIT 8 // Parameter sets a bit in a DWORD
  74. PVOID Global; // Address of global to write
  75. LPWSTR *EnumStrings;
  76. //
  77. // Describe relationships to other parameters.
  78. //
  79. DWORD Relationships;
  80. #define ALLOW_CRED 0x01 // If specified, this parameter allows other IS_CRED parameters
  81. #define IS_CRED 0x02 // This parameter is only allow if an ALLOW_CRED parameter has been seen previously
  82. #define ALLOW_TI 0x10 // If specified, this parameter allows other IS_TI or IS_TIX parameters
  83. #define IS_TI 0x20 // This parameter is only allow if an ALLOW_TI parameter has been seen previously
  84. #define IS_TIX 0x40 // This parameter is only allow if an ALLOW_TI parameter has been seen previously
  85. LPSTR Comment;
  86. } ParameterDefinitions[] =
  87. {
  88. {L"UserName", "UserName", PARM_STRING, &GlUserName, NULL, 0, "User Name" },
  89. {L"TargetName", "TargetName", PARM_STRING, &GlTargetName, NULL, 0, "Target Name" },
  90. {L"Message", "Message", PARM_STRING, &GlMessage, NULL, 0, "Message for dialog box" },
  91. {L"Title", "Title", PARM_STRING, &GlTitle, NULL, 0, "Title for dialog box" },
  92. {L"Gui", NULL, PARM_BOOLEAN, &GlDoGui, NULL, 0, "Call GUI version of API" },
  93. {L"Ansi", NULL, PARM_BOOLEAN, &GlAnsi, NULL, 0, "Use ANSI version of APIs" },
  94. { NULL },
  95. {L"ReqSmartcard", (LPSTR)ULongToPtr(CREDUI_FLAGS_REQUIRE_SMARTCARD), PARM_BIT, &GlCreduiFlags, NULL, 0, "Require smartcard" },
  96. {L"ReqCertificate", (LPSTR)ULongToPtr(CREDUI_FLAGS_REQUIRE_CERTIFICATE), PARM_BIT, &GlCreduiFlags, NULL, 0, "Require certificate" },
  97. {L"ExcCertificates",(LPSTR)ULongToPtr(CREDUI_FLAGS_EXCLUDE_CERTIFICATES), PARM_BIT, &GlCreduiFlags, NULL, 0, "Exclude certificates" },
  98. { NULL },
  99. {L"GenericCreds", (LPSTR)ULongToPtr(CREDUI_FLAGS_GENERIC_CREDENTIALS), PARM_BIT, &GlCreduiFlags, NULL, 0, "Generic Credentials" },
  100. {L"RunasCreds", (LPSTR)ULongToPtr(CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS),PARM_BIT,&GlCreduiFlags, NULL, 0, "Runas Credentials" },
  101. { NULL },
  102. {L"Persist", (LPSTR)ULongToPtr(CREDUI_FLAGS_PERSIST), PARM_BIT, &GlCreduiFlags, NULL, 0, "Always save Credentials" },
  103. {L"NoPersist", (LPSTR)ULongToPtr(CREDUI_FLAGS_DO_NOT_PERSIST), PARM_BIT, &GlCreduiFlags, NULL, 0, "Never save Credentials" },
  104. {L"ShowSaveCheckbox:(T/F)",(LPSTR)ULongToPtr(CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX), PARM_BIT, &GlCreduiFlags, ((LPWSTR *)&GlSave), 0, "Show Save checkbox (initial value)" },
  105. { NULL },
  106. {L"ValidateUsername",(LPSTR)ULongToPtr(CREDUI_FLAGS_VALIDATE_USERNAME), PARM_BIT, &GlCreduiFlags, NULL, 0, "Validate Username" },
  107. {L"CompleteUsername",(LPSTR)ULongToPtr(CREDUI_FLAGS_COMPLETE_USERNAME), PARM_BIT, &GlCreduiFlags, NULL, 0, "Complete Username" },
  108. { NULL },
  109. {L"Confirm", (LPSTR)ULongToPtr(CREDUI_FLAGS_EXPECT_CONFIRMATION), PARM_BIT, &GlCreduiFlags, NULL, 0, "Confirm that the credential worked" },
  110. {L"NoConfirm", NULL, PARM_BOOLEAN,&GlNoConfirm,NULL, 0, "Confirm that the credential failed" },
  111. { NULL },
  112. {L"AlwaysShowUi",(LPSTR)ULongToPtr(CREDUI_FLAGS_ALWAYS_SHOW_UI), PARM_BIT, &GlCreduiFlags, NULL, 0, "Always Show UI" },
  113. {L"IncorrectPassword",(LPSTR)ULongToPtr(CREDUI_FLAGS_INCORRECT_PASSWORD), PARM_BIT, &GlCreduiFlags, NULL, 0, "Show 'incorrect password' tip" },
  114. {L"AuthError", "ErrorNum", PARM_STRING, &GlAuthError, NULL, 0, "Previous auth error number" },
  115. };
  116. #define PARAMETER_COUNT (sizeof(ParameterDefinitions)/sizeof(ParameterDefinitions[0]))
  117. VOID
  118. PrintOneUsage(
  119. LPWSTR Argument OPTIONAL,
  120. ULONG ArgumentIndex
  121. )
  122. /*++
  123. Routine Description:
  124. Print the command line parameter usage for one parameter
  125. Arguments:
  126. Argument - Argument as typed by caller
  127. NULL if printing complete list of arguments
  128. ArugmentIndex - Index of the parameter to print
  129. Return Value:
  130. None
  131. --*/
  132. {
  133. ULONG j;
  134. if ( ParameterDefinitions[ArgumentIndex].Name == NULL ) {
  135. fprintf( stderr, "\n" );
  136. return;
  137. }
  138. if ( Argument != NULL ) {
  139. fprintf( stderr, "\nSyntax of '%ls' parameter is:\n", Argument );
  140. }
  141. fprintf( stderr, " /%ls", ParameterDefinitions[ArgumentIndex].Name );
  142. switch ( ParameterDefinitions[ArgumentIndex].Type ) {
  143. case PARM_COMMAND:
  144. case PARM_BOOLEAN:
  145. break;
  146. case PARM_BIT:
  147. if ( ParameterDefinitions[ArgumentIndex].EnumStrings == NULL ) {
  148. break;
  149. } else {
  150. fprintf( stderr, ":{T/F}" );
  151. break;
  152. }
  153. case PARM_COMMAND_OPTSTR:
  154. fprintf( stderr, "[:<%s>]", ParameterDefinitions[ArgumentIndex].ValueName );
  155. break;
  156. case PARM_STRING:
  157. case PARM_COMMAND_STR:
  158. fprintf( stderr, ":<%s>", ParameterDefinitions[ArgumentIndex].ValueName );
  159. break;
  160. case PARM_STRING_ENUM:
  161. fprintf( stderr, ":<" );
  162. for ( j=0; ParameterDefinitions[ArgumentIndex].EnumStrings[j] != NULL; j++) {
  163. if ( j!= 0 ) {
  164. fprintf( stderr, "|");
  165. }
  166. fprintf( stderr, "%ls", ParameterDefinitions[ArgumentIndex].EnumStrings[j] );
  167. }
  168. fprintf( stderr, ">" );
  169. break;
  170. case PARM_STRING_ARRAY:
  171. fprintf( stderr, ":<%s>", ParameterDefinitions[ArgumentIndex].ValueName );
  172. break;
  173. }
  174. if ( Argument == NULL ) {
  175. fprintf( stderr, " - %s", ParameterDefinitions[ArgumentIndex].Comment );
  176. }
  177. fprintf( stderr, "\n" );
  178. }
  179. VOID
  180. PrintUsage(
  181. )
  182. /*++
  183. Routine Description:
  184. Print the command line parameter usage.
  185. Arguments:
  186. None
  187. Return Value:
  188. None
  189. --*/
  190. {
  191. ULONG i;
  192. fprintf( stderr, "\nUsage: creduit [Options]\n\nWhere options are:\n\n");
  193. for ( i=0; i<PARAMETER_COUNT; i++ ) {
  194. PrintOneUsage( NULL, i );
  195. }
  196. }
  197. LPSTR
  198. FindSymbolicNameForStatus(
  199. DWORD Id
  200. )
  201. {
  202. ULONG i;
  203. i = 0;
  204. if (Id == 0) {
  205. return "NO_ERROR";
  206. }
  207. #ifdef notdef
  208. if (Id & 0xC0000000) {
  209. while (ntstatusSymbolicNames[ i ].SymbolicName) {
  210. if (ntstatusSymbolicNames[ i ].MessageId == (NTSTATUS)Id) {
  211. return ntstatusSymbolicNames[ i ].SymbolicName;
  212. } else {
  213. i += 1;
  214. }
  215. }
  216. }
  217. #endif // notdef
  218. while (winerrorSymbolicNames[ i ].SymbolicName) {
  219. if (winerrorSymbolicNames[ i ].MessageId == Id) {
  220. return winerrorSymbolicNames[ i ].SymbolicName;
  221. } else {
  222. i += 1;
  223. }
  224. }
  225. #ifdef notdef
  226. while (neteventSymbolicNames[ i ].SymbolicName) {
  227. if (neteventSymbolicNames[ i ].MessageId == Id) {
  228. return neteventSymbolicNames[ i ].SymbolicName
  229. } else {
  230. i += 1;
  231. }
  232. }
  233. #endif // notdef
  234. return NULL;
  235. }
  236. VOID
  237. PrintStatus(
  238. DWORD NetStatus
  239. )
  240. /*++
  241. Routine Description:
  242. Print a net status code.
  243. Arguments:
  244. NetStatus - The net status code to print.
  245. Return Value:
  246. None
  247. --*/
  248. {
  249. printf( "Status = %lu 0x%lx", NetStatus, NetStatus );
  250. switch (NetStatus) {
  251. case NERR_Success:
  252. printf( " NERR_Success" );
  253. break;
  254. case NERR_DCNotFound:
  255. printf( " NERR_DCNotFound" );
  256. break;
  257. case NERR_UserNotFound:
  258. printf( " NERR_UserNotFound" );
  259. break;
  260. case NERR_NetNotStarted:
  261. printf( " NERR_NetNotStarted" );
  262. break;
  263. case NERR_WkstaNotStarted:
  264. printf( " NERR_WkstaNotStarted" );
  265. break;
  266. case NERR_ServerNotStarted:
  267. printf( " NERR_ServerNotStarted" );
  268. break;
  269. case NERR_BrowserNotStarted:
  270. printf( " NERR_BrowserNotStarted" );
  271. break;
  272. case NERR_ServiceNotInstalled:
  273. printf( " NERR_ServiceNotInstalled" );
  274. break;
  275. case NERR_BadTransactConfig:
  276. printf( " NERR_BadTransactConfig" );
  277. break;
  278. default:
  279. printf( " %s", FindSymbolicNameForStatus( NetStatus ) );
  280. break;
  281. }
  282. printf( "\n" );
  283. }
  284. VOID
  285. PrintBytes(
  286. PVOID Buffer,
  287. DWORD BufferSize
  288. )
  289. /*++
  290. Routine Description:
  291. Dumps the buffer content as hex and characters.
  292. Arguments:
  293. Buffer: buffer pointer.
  294. BufferSize: size of the buffer.
  295. Return Value:
  296. none
  297. --*/
  298. {
  299. #define NUM_CHARS 16
  300. DWORD i, limit;
  301. CHAR TextBuffer[NUM_CHARS + 1];
  302. LPBYTE BufferPtr = (LPBYTE)Buffer;
  303. BOOLEAN DumpDwords = FALSE;
  304. //
  305. // Preprocess
  306. //
  307. if ( BufferSize > NUM_CHARS ) {
  308. printf("\n"); // Ensure this starts on a new line
  309. printf("------------------------------------\n");
  310. } else {
  311. if ( BufferSize % sizeof(DWORD) == 0 ) {
  312. DumpDwords = TRUE;
  313. }
  314. }
  315. //
  316. // Hex dump of the bytes
  317. //
  318. limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
  319. for (i = 0; i < limit; i++) {
  320. if (i < BufferSize) {
  321. if ( DumpDwords ) {
  322. if ( i % sizeof(DWORD) == 0 ) {
  323. DWORD ADword;
  324. RtlCopyMemory( &ADword, &BufferPtr[i], sizeof(DWORD) );
  325. printf("%08x ", ADword);
  326. }
  327. } else {
  328. printf("%02x ", BufferPtr[i]);
  329. }
  330. if ( isprint(BufferPtr[i]) ) {
  331. TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i];
  332. } else {
  333. TextBuffer[i % NUM_CHARS] = '.';
  334. }
  335. } else {
  336. if ( DumpDwords ) {
  337. TextBuffer[i % NUM_CHARS] = '\0';
  338. } else {
  339. if ( BufferSize > NUM_CHARS ) {
  340. printf(" ");
  341. TextBuffer[i % NUM_CHARS] = ' ';
  342. } else {
  343. TextBuffer[i % NUM_CHARS] = '\0';
  344. }
  345. }
  346. }
  347. if ((i + 1) % NUM_CHARS == 0) {
  348. TextBuffer[NUM_CHARS] = 0;
  349. printf(" %s\n", TextBuffer);
  350. }
  351. }
  352. if ( BufferSize > NUM_CHARS ) {
  353. printf("------------------------------------\n");
  354. } else if ( BufferSize < NUM_CHARS ) {
  355. printf("\n");
  356. }
  357. }
  358. VOID
  359. PrintTime(
  360. LPSTR Comment,
  361. LPFILETIME ConvertTime
  362. )
  363. /*++
  364. Routine Description:
  365. Print the specified time
  366. Arguments:
  367. Comment - Comment to print in front of the time
  368. Time - GMT time to print (Nothing is printed if this is zero)
  369. Return Value:
  370. None
  371. --*/
  372. {
  373. //
  374. // If we've been asked to convert an NT GMT time to ascii,
  375. // Do so
  376. //
  377. if ( ConvertTime->dwLowDateTime != 0 || ConvertTime->dwHighDateTime != 0 ) {
  378. SYSTEMTIME SystemTime;
  379. FILETIME LocalFileTime;
  380. printf( "%s", Comment );
  381. if ( !FileTimeToLocalFileTime( ConvertTime, &LocalFileTime ) ) {
  382. printf( "Can't convert time from GMT to Local time: " );
  383. PrintStatus( GetLastError() );
  384. return;
  385. }
  386. if ( !FileTimeToSystemTime( &LocalFileTime, &SystemTime ) ) {
  387. printf( "Can't convert time from file time to system time: " );
  388. PrintStatus( GetLastError() );
  389. return;
  390. }
  391. printf( "%ld/%ld/%ld %ld:%2.2ld:%2.2ld\n",
  392. SystemTime.wMonth,
  393. SystemTime.wDay,
  394. SystemTime.wYear,
  395. SystemTime.wHour,
  396. SystemTime.wMinute,
  397. SystemTime.wSecond );
  398. }
  399. }
  400. BOOLEAN
  401. ParseParameters(
  402. VOID
  403. )
  404. /*++
  405. Routine Description:
  406. Parse the command line parameters
  407. Arguments:
  408. None
  409. Return Value:
  410. TRUE if parse was successful.
  411. --*/
  412. {
  413. LPWSTR *argvw;
  414. int argcw;
  415. int i;
  416. ULONG j;
  417. LPWSTR OrigArgument;
  418. LPWSTR Argument;
  419. //
  420. // Get the command line in Unicode
  421. //
  422. CommandLine = GetCommandLine();
  423. argvw = CommandLineToArgvW( CommandLine, &argcw );
  424. if ( argvw == NULL ) {
  425. fprintf( stderr, "Can't convert command line to Unicode: %ld\n", GetLastError() );
  426. return FALSE;
  427. }
  428. //
  429. // Loop through the command line arguments
  430. //
  431. for ( i=1; i<argcw; i++ ) {
  432. OrigArgument = Argument = argvw[i];
  433. //
  434. // Check if the Argument is a switch
  435. //
  436. if ( Argument[0] == '-' || Argument[0] == '/' ) {
  437. DWORD ArgumentIndex;
  438. ULONG ArgumentLength;
  439. PWCHAR ColonPointer;
  440. Argument ++;
  441. //
  442. // Find the colon at the end of the argument
  443. //
  444. ColonPointer = wcschr( Argument, L':' );
  445. if ( ColonPointer != NULL ) {
  446. *ColonPointer = '\0';
  447. }
  448. ArgumentLength = wcslen(Argument);
  449. //
  450. // Loop through the list of valid arguments finding all that match
  451. //
  452. ArgumentIndex = 0xFFFFFFFF;
  453. for ( j=0; j<PARAMETER_COUNT; j++ ) {
  454. //
  455. // Ignore placeholders
  456. //
  457. if ( ParameterDefinitions[j].Name == NULL ) {
  458. continue;
  459. }
  460. //
  461. // Compare the names
  462. //
  463. if ( _wcsnicmp( Argument, ParameterDefinitions[j].Name, ArgumentLength ) == 0 ) {
  464. //
  465. // If more than one matches,
  466. // it's an error
  467. //
  468. if ( ArgumentIndex != 0xFFFFFFFF ) {
  469. fprintf( stderr,
  470. "\nArgument '%ls' is ambiguous: %ls or %ls.\n",
  471. OrigArgument,
  472. ParameterDefinitions[j].Name,
  473. ParameterDefinitions[ArgumentIndex].Name );
  474. return FALSE;
  475. }
  476. ArgumentIndex = j;
  477. //
  478. // If this is an exact match,
  479. // we're done.
  480. //
  481. if ( ArgumentLength == wcslen(ParameterDefinitions[j].Name)) {
  482. break;
  483. }
  484. }
  485. }
  486. //
  487. // If there were not matches,
  488. // complain.
  489. //
  490. if ( ArgumentIndex == 0xFFFFFFFF ) {
  491. fprintf( stderr,
  492. "\nArgument '%ls' is invalid.\n",
  493. OrigArgument );
  494. PrintUsage();
  495. return FALSE;
  496. }
  497. //
  498. // Ensure the : is present as required
  499. //
  500. //
  501. // Return TRUE if the specified argument should have a : character after the
  502. // argument name.
  503. //
  504. if ( ParameterDefinitions[ArgumentIndex].Type == PARM_COMMAND ||
  505. ParameterDefinitions[ArgumentIndex].Type == PARM_BOOLEAN ||
  506. (ParameterDefinitions[ArgumentIndex].Type == PARM_BIT &&
  507. ParameterDefinitions[ArgumentIndex].EnumStrings == NULL ) ) {
  508. if ( ColonPointer != NULL ) {
  509. PrintOneUsage( OrigArgument, ArgumentIndex );
  510. return FALSE;
  511. }
  512. } else {
  513. if ( ColonPointer == NULL ) {
  514. if ( ParameterDefinitions[ArgumentIndex].Type != PARM_COMMAND_OPTSTR ) {
  515. PrintOneUsage( OrigArgument, ArgumentIndex );
  516. return FALSE;
  517. }
  518. } else {
  519. Argument = ColonPointer + 1;
  520. }
  521. }
  522. //
  523. // Parse the rest of the argument
  524. //
  525. // Handle commands
  526. //
  527. switch ( ParameterDefinitions[ArgumentIndex].Type ) {
  528. case PARM_COMMAND:
  529. case PARM_COMMAND_STR:
  530. case PARM_COMMAND_OPTSTR:
  531. if ( GlCommand != 0xFFFFFFFF ) {
  532. fprintf( stderr,
  533. "\nArgument '%ls' and '/%ls' are mutually exclusive.\n",
  534. OrigArgument,
  535. ParameterDefinitions[GlCommand].Name );
  536. return FALSE;
  537. }
  538. GlCommand = ArgumentIndex;
  539. /* Drop through */
  540. //
  541. // Handle parameters of the form /xxx:string
  542. //
  543. case PARM_STRING: {
  544. LPWSTR *StringPointer;
  545. StringPointer = (LPWSTR *)(ParameterDefinitions[ArgumentIndex].Global);
  546. //
  547. // If a string is not present,
  548. // we're done.
  549. //
  550. if ( ColonPointer == NULL ) {
  551. break;
  552. }
  553. //
  554. // Ensure argument only specified once.
  555. //
  556. if ( *StringPointer != NULL ) {
  557. fprintf( stderr,
  558. "\nArgument '%ls' may only be specified once.\n",
  559. OrigArgument );
  560. return FALSE;
  561. }
  562. //
  563. // Ensure an actual string was specified.
  564. //
  565. if ( *Argument == '\0' ) {
  566. fprintf( stderr,
  567. "\nArgument '%ls' requires a value.\n",
  568. OrigArgument );
  569. return FALSE;
  570. }
  571. *StringPointer = Argument;
  572. break;
  573. }
  574. //
  575. // Handle parameters of the form /xxx:a|b|c
  576. //
  577. case PARM_STRING_ENUM: {
  578. ULONG EnumIndex;
  579. LPDWORD DwordPointer;
  580. LPWSTR *EnumStrings;
  581. //
  582. // Ensure argument only specified once.
  583. //
  584. DwordPointer = (LPDWORD)(ParameterDefinitions[ArgumentIndex].Global);
  585. if ( *DwordPointer != 0 ) {
  586. fprintf( stderr,
  587. "\nArgument '%ls' may only be specified once.\n",
  588. OrigArgument );
  589. return FALSE;
  590. }
  591. EnumStrings = ParameterDefinitions[ArgumentIndex].EnumStrings;
  592. ArgumentLength = wcslen(Argument);
  593. //
  594. // Loop through the list of valid values finding all that match
  595. //
  596. EnumIndex = 0xFFFFFFFF;
  597. for ( j=0; EnumStrings[j] != NULL; j++ ) {
  598. //
  599. // Compare the names
  600. //
  601. if ( _wcsnicmp( Argument, EnumStrings[j], ArgumentLength ) == 0 ) {
  602. //
  603. // If more than one matches,
  604. // it's an error
  605. //
  606. if ( EnumIndex != 0xFFFFFFFF ) {
  607. PrintOneUsage( OrigArgument, ArgumentIndex );
  608. fprintf( stderr,
  609. "\nValue '%ls' is ambiguous: %ls or %ls.\n",
  610. Argument,
  611. EnumStrings[j],
  612. EnumStrings[EnumIndex] );
  613. return FALSE;
  614. }
  615. EnumIndex = j;
  616. //
  617. // If this is an exact match,
  618. // we're done.
  619. //
  620. if ( ArgumentLength == wcslen(EnumStrings[j]) ) {
  621. break;
  622. }
  623. }
  624. }
  625. //
  626. // If there were not matches,
  627. // complain.
  628. //
  629. if ( EnumIndex == 0xFFFFFFFF ) {
  630. PrintOneUsage( OrigArgument, ArgumentIndex );
  631. fprintf( stderr,
  632. "\nValue '%ls' is invalid.\n",
  633. Argument );
  634. return FALSE;
  635. }
  636. *DwordPointer = EnumIndex + 1;
  637. break;
  638. }
  639. //
  640. // Handle parameters of the form /xxx:a,b,c
  641. //
  642. case PARM_STRING_ARRAY: {
  643. PWCHAR CommaPointer;
  644. PSTRING_ARRAY StringArray;
  645. StringArray = ((PSTRING_ARRAY)(ParameterDefinitions[ArgumentIndex].Global));
  646. //
  647. // Ensure argument only specified once.
  648. //
  649. if ( StringArray->Specified ) {
  650. fprintf( stderr,
  651. "\nArgument '%ls' may only be specified once.\n",
  652. OrigArgument );
  653. return FALSE;
  654. }
  655. StringArray->Specified = TRUE;
  656. //
  657. // Loop through the values specified by the user
  658. //
  659. for (;;) {
  660. //
  661. // Ensure an actual string was specified.
  662. //
  663. if ( *Argument == '\0' ) {
  664. fprintf( stderr,
  665. "\nArgument '%ls' requires a value.\n",
  666. OrigArgument );
  667. return FALSE;
  668. }
  669. //
  670. // Save it
  671. //
  672. StringArray->Count ++;
  673. if ( StringArray->Count >= STRING_ARRAY_COUNT ) {
  674. fprintf( stderr,
  675. "\nArgument '%ls' has too many values.\n",
  676. OrigArgument );
  677. return FALSE;
  678. }
  679. StringArray->Strings[StringArray->Count-1] = Argument;
  680. //
  681. // Determine if there is another value
  682. //
  683. CommaPointer = wcschr( Argument, L',' );
  684. if ( CommaPointer == NULL ) {
  685. break;
  686. }
  687. *CommaPointer = '\0';
  688. Argument = CommaPointer + 1;
  689. };
  690. break;
  691. }
  692. //
  693. // Handle parameters of the form /xxx
  694. //
  695. case PARM_BOOLEAN: {
  696. BOOLEAN *BooleanPointer;
  697. BooleanPointer = (BOOLEAN *)(ParameterDefinitions[ArgumentIndex].Global);
  698. *BooleanPointer = TRUE;
  699. break;
  700. }
  701. //
  702. // Handle parameters of the form /xxx that imply setting a bit
  703. //
  704. case PARM_BIT: {
  705. DWORD *DwordPointer;
  706. DwordPointer = (DWORD *)(ParameterDefinitions[ArgumentIndex].Global);
  707. *DwordPointer |= PtrToUlong( ParameterDefinitions[ArgumentIndex].ValueName );
  708. //
  709. // Some of these have TRUE or FALSE as an optional argument
  710. //
  711. if ( ParameterDefinitions[ArgumentIndex].EnumStrings != NULL ) {
  712. if ( toupper(*Argument) == 'T' ) {
  713. *((BOOL *)(ParameterDefinitions[ArgumentIndex].EnumStrings)) = TRUE;
  714. } else if ( toupper(*Argument) == 'F' ) {
  715. *((BOOL *)(ParameterDefinitions[ArgumentIndex].EnumStrings)) = FALSE;
  716. } else {
  717. fprintf( stderr,
  718. "\nArgument '%ls' requires a T or F as value.\n",
  719. OrigArgument );
  720. return FALSE;
  721. }
  722. }
  723. break;
  724. }
  725. default:
  726. fprintf( stderr,
  727. "\nArgument '%ls' had an internal error.\n",
  728. OrigArgument );
  729. return FALSE;
  730. }
  731. //
  732. // Handle arguments that aren't switches.
  733. //
  734. } else {
  735. //
  736. // All current arguments are switches
  737. //
  738. PrintUsage();
  739. return FALSE;
  740. }
  741. }
  742. return TRUE;
  743. }
  744. //
  745. // Include routines to support the /ANSI parameter
  746. //
  747. LPSTR
  748. NetpAllocAStrFromWStr (
  749. IN LPCWSTR Unicode
  750. )
  751. /*++
  752. Routine Description:
  753. Convert an UNICODE (zero terminated) string to the corresponding ANSI
  754. string.
  755. Arguments:
  756. Unicode - Specifies the UNICODE zero terminated string to convert.
  757. Return Value:
  758. NULL - There was some error in the conversion.
  759. Otherwise, it returns a pointer to the zero terminated ANSI string in
  760. an allocated buffer. The buffer must be freed using NetApiBufferFree.
  761. --*/
  762. {
  763. ANSI_STRING AnsiString;
  764. UNICODE_STRING UnicodeString;
  765. RtlInitUnicodeString( &UnicodeString, Unicode );
  766. AnsiString.MaximumLength =
  767. (USHORT) RtlUnicodeStringToAnsiSize( &UnicodeString );
  768. AnsiString.Buffer = (PCHAR) LocalAlloc( 0, AnsiString.MaximumLength );
  769. if ( AnsiString.Buffer == NULL) {
  770. return (NULL);
  771. }
  772. if(!NT_SUCCESS( RtlUnicodeStringToAnsiString( &AnsiString,
  773. &UnicodeString,
  774. FALSE))){
  775. (void) LocalFree( AnsiString.Buffer );
  776. return NULL;
  777. }
  778. return AnsiString.Buffer;
  779. } // NetpAllocStrFromWStr
  780. extern "C"
  781. BOOL
  782. DllMain(
  783. HINSTANCE instance,
  784. DWORD reason,
  785. VOID *
  786. );
  787. int __cdecl
  788. main(
  789. IN int argc,
  790. IN char ** argv
  791. )
  792. /*++
  793. Routine Description:
  794. Drive the credential manager API.
  795. Arguments:
  796. argc - the number of command-line arguments.
  797. argv - an array of pointers to the arguments.
  798. Return Value:
  799. Exit status
  800. --*/
  801. {
  802. DWORD WinStatus;
  803. WCHAR Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
  804. WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1];
  805. DWORD AuthError = NO_ERROR;
  806. CREDUI_INFOW UiInfoW;
  807. PCREDUI_INFOW UiInfoWptr = NULL;
  808. //
  809. // Parse the command line parameters
  810. //
  811. UserName[0] = '\0';
  812. Password[0] = '\0';
  813. if ( !ParseParameters() ) {
  814. return 1;
  815. }
  816. //
  817. // Fill in the parameters
  818. //
  819. if ( GlUserName != NULL) {
  820. wcscpy( UserName, GlUserName );
  821. }
  822. //
  823. // Get the error number
  824. //
  825. if ( GlAuthError != NULL ) {
  826. LPWSTR End;
  827. AuthError = wcstoul( GlAuthError, &End, 10 );
  828. }
  829. //
  830. // Handle special parameters
  831. //
  832. if ( GlNoConfirm ) {
  833. GlCreduiFlags |= CREDUI_FLAGS_EXPECT_CONFIRMATION;
  834. }
  835. //
  836. // Build the UI info
  837. //
  838. if ( GlMessage || GlTitle ) {
  839. UiInfoWptr = &UiInfoW;
  840. ZeroMemory( &UiInfoW, sizeof(UiInfoW) );
  841. UiInfoW.cbSize = sizeof(UiInfoW);
  842. UiInfoW.pszMessageText = GlMessage;
  843. UiInfoW.pszCaptionText = GlTitle;
  844. }
  845. //
  846. // Execute the requested command
  847. //
  848. switch ( GlCommand ) {
  849. case 0xFFFFFFFF:
  850. if ( GlAnsi ) {
  851. printf( "We don't yet do ansi.\n");
  852. } else {
  853. if ( GlDoGui ) {
  854. WinStatus = CredUIPromptForCredentialsW(
  855. UiInfoWptr,
  856. GlTargetName,
  857. NULL, // No security context
  858. AuthError,
  859. UserName,
  860. sizeof(UserName)/sizeof(WCHAR),
  861. Password,
  862. sizeof(Password)/sizeof(WCHAR),
  863. &GlSave,
  864. GlCreduiFlags );
  865. } else {
  866. WinStatus = CredUICmdLinePromptForCredentialsW(
  867. GlTargetName,
  868. NULL, // No security context
  869. AuthError,
  870. UserName,
  871. sizeof(UserName)/sizeof(WCHAR),
  872. Password,
  873. sizeof(Password)/sizeof(WCHAR),
  874. &GlSave,
  875. GlCreduiFlags );
  876. }
  877. if ( WinStatus != NO_ERROR ) {
  878. fprintf( stderr, "CredUIPromptForCredentialsW failed: \n" );
  879. PrintStatus( WinStatus );
  880. return 1;
  881. }
  882. printf( "UserName: '%ws'\n", UserName );
  883. printf( "Password: '%ws'\n", Password );
  884. printf( "Save: %ld\n", GlSave );
  885. //
  886. // Do confirmation
  887. //
  888. if ( GlCreduiFlags & CREDUI_FLAGS_EXPECT_CONFIRMATION ) {
  889. WinStatus = CredUIConfirmCredentialsW( GlTargetName, !GlNoConfirm );
  890. if ( WinStatus != NO_ERROR ) {
  891. fprintf( stderr, "CredUIConfirmCredentialsW failed: \n" );
  892. PrintStatus( WinStatus );
  893. }
  894. }
  895. }
  896. break;
  897. default:
  898. fprintf( stderr, "Internal error: %ld\n", GlCommand );
  899. return 1;
  900. }
  901. fprintf( stderr, "Command completed successfully.\n" );
  902. return 0;
  903. }