home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / security / winnt / machacct / machacct.c next >
C/C++ Source or Header  |  1997-10-05  |  10KB  |  396 lines

  1. /*++
  2.  
  3. Copyright 1996 - 1997 Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     machacct.c
  8.  
  9. Abstract:
  10.  
  11.     The following sample illustrates how to create a machine account on the
  12.     specified domain.
  13.  
  14.     Machine account types are defined by the following flags:
  15.  
  16.     UF_SERVER_TRUST_ACCOUNT (Backup domain controller)
  17.     UF_WORKSTATION_TRUST_ACCOUNT (Workstation and server)
  18.     UF_INTERDOMAIN_TRUST_ACCOUNT (Interdomain trust account)
  19.  
  20.     This sample attempts to create a workstation machine account, of type
  21.     UF_WORKSTATION_TRUST_ACCOUNT.  This account type used for workstations
  22.     and non-DC servers which are domain members.
  23.  
  24.     If the computer account creation fails with GetLastError ==
  25.     ERROR_ACCESS_DENIED, the sample attempts to enable the
  26.     SeMachineAccountPrivilege for the caller. If the privilege is enabled
  27.     successfully, the computer account add operation is re-tried.
  28.  
  29.     Deleting machine accounts can be accomplished using the NetUserDel()
  30.     Windows NT Lan Manager API call.
  31.  
  32.     Account update operations against a domain must be performed against
  33.     the primary domain controller for the specified domain.  This sample
  34.     uses the NetGetDCName Windows NT Lan Manager API call to determine
  35.     the computer name of the primary domain controller.
  36.  
  37.     Commandline parameter argv[1] indicates the name of the account to
  38.     create, which is typically the name of the machine.
  39.  
  40.     Commandline parameter argv[2] is optional and indicates the target domain.
  41.     If this commandline argument is omitted, the machine account is created
  42.     on the local domain.  It is recommended that you always supply a domain
  43.     name in this sample, as this insures that the update occurs at the primary
  44.     domain controller.
  45.  
  46.     The following commandline creates a machine account named WINBASE in
  47.     the domain named NTWKSTA
  48.  
  49.     machacct.exe WINBASE NTWKSTA
  50.  
  51. Author:
  52.  
  53.     Scott Field (sfield)    16-Apr-96
  54.         Minor cleanup
  55.  
  56.     Scott Field (sfield)    19-Sep-95
  57.  
  58. --*/
  59.  
  60. #include <windows.h>
  61. #include <stdio.h>
  62. #include <lm.h>
  63.  
  64. BOOL
  65. AddMachineAccount(
  66.     LPWSTR wTargetComputer, // specifies where to add account
  67.     LPWSTR MachineAccount,  // name of account
  68.     DWORD AccountType       // account type
  69.     );
  70.  
  71. BOOL
  72. SetCurrentPrivilege(
  73.     LPCTSTR Privilege,      // Privilege to enable/disable
  74.     BOOL bEnablePrivilege   // to enable or disable privilege
  75.     );
  76.  
  77. void
  78. DisplayError(
  79.     LPSTR szAPI,    // pointer to failed API name
  80.     DWORD dwLastError
  81.     );
  82.  
  83. #define RTN_OK 0
  84. #define RTN_USAGE 1
  85. #define RTN_ERROR 13
  86.  
  87. //
  88. // Unicode entry point and argv
  89. //
  90.  
  91. int
  92. __cdecl
  93. wmain(
  94.     int argc,
  95.     wchar_t *argv[]
  96.     )
  97. {
  98.     LPWSTR wMachineAccount;
  99.     LPWSTR wPrimaryDC;
  100.     LPTSTR MachineAccountPrivilege = SE_MACHINE_ACCOUNT_NAME;
  101.     DWORD dwTrustAccountType = UF_WORKSTATION_TRUST_ACCOUNT;
  102.     NET_API_STATUS nas;
  103.     BOOL bSuccess;
  104.  
  105.     if(argc < 2) {
  106.         fprintf(stderr, "Usage: %ls <machineaccountname> [domain]\n",
  107.             argv[0]);
  108.         return RTN_USAGE;
  109.     }
  110.  
  111.     wMachineAccount = argv[1];
  112.  
  113.     //
  114.     // if a domain name was specified, fetch the computer name of the
  115.     // primary domain controller
  116.     //
  117.     if(argc == 3) {
  118.  
  119.         nas = NetGetDCName(NULL, argv[2], (LPBYTE *)&wPrimaryDC);
  120.  
  121.         if(nas != NERR_Success) {
  122.             DisplayError("NetGetDCName", nas);
  123.             return RTN_ERROR;
  124.         }
  125.     } else {
  126.         //
  127.         // default will operate on local machine.  Non-NULL wPrimaryDC will
  128.         // cause buffer to be freed
  129.         //
  130.         wPrimaryDC = NULL;
  131.     }
  132.  
  133.     bSuccess = AddMachineAccount(
  134.         wPrimaryDC,         // primary DC computer name
  135.         wMachineAccount,    // computer account name
  136.         dwTrustAccountType  // computer account type
  137.         );
  138.  
  139.     if(!bSuccess && GetLastError() == ERROR_ACCESS_DENIED ) {
  140.  
  141.         //
  142.         // try to enable the SeMachineAccountPrivilege
  143.         //
  144.         if(SetCurrentPrivilege( MachineAccountPrivilege, TRUE )) {
  145.  
  146.             //
  147.             // enabled the privilege.  retry the add operation
  148.             //
  149.             bSuccess = AddMachineAccount(
  150.                 wPrimaryDC,
  151.                 wMachineAccount,
  152.                 dwTrustAccountType
  153.                 );
  154.  
  155.             //
  156.             // disable the privilege
  157.             //
  158.             SetCurrentPrivilege( MachineAccountPrivilege, FALSE );
  159.         }
  160.     }
  161.  
  162.     //
  163.     // free the buffer allocated for the PDC computer name
  164.     //
  165.     if(wPrimaryDC) NetApiBufferFree(wPrimaryDC);
  166.  
  167.     if(!bSuccess) {
  168.         DisplayError("AddMachineAccount", GetLastError());
  169.         return RTN_ERROR;
  170.     }
  171.  
  172.     return RTN_OK;
  173. }
  174.  
  175. BOOL
  176. AddMachineAccount(
  177.     LPWSTR wTargetComputer,
  178.     LPWSTR MachineAccount,
  179.     DWORD AccountType
  180.     )
  181. {
  182.     WCHAR wAccount[MAX_COMPUTERNAME_LENGTH + 2];
  183.     LPWSTR wPassword;
  184.     USER_INFO_1 ui;
  185.     DWORD cchAccount;
  186.     DWORD cchLength;
  187.     NET_API_STATUS nas;
  188.  
  189.     //
  190.     // ensure a valid computer account type was passed
  191.     // TODO SetLastError
  192.     //
  193.     if (AccountType != UF_WORKSTATION_TRUST_ACCOUNT &&
  194.         AccountType != UF_SERVER_TRUST_ACCOUNT &&
  195.         AccountType != UF_INTERDOMAIN_TRUST_ACCOUNT
  196.         ) {
  197.         SetLastError(ERROR_INVALID_PARAMETER);
  198.         return FALSE;
  199.     }
  200.  
  201.     //
  202.     // obtain number of chars in computer account name
  203.     //
  204.     cchLength = cchAccount = lstrlenW(MachineAccount);
  205.  
  206.     //
  207.     // ensure computer name doesn't exceed maximum length
  208.     //
  209.     if(cchLength > MAX_COMPUTERNAME_LENGTH) {
  210.         SetLastError(ERROR_INVALID_ACCOUNT_NAME);
  211.         return FALSE;
  212.     }
  213.  
  214.     //
  215.     // password is the computer account name converted to lowercase
  216.     // convert the passed MachineAccount in place
  217.     //
  218.     wPassword = MachineAccount;
  219.  
  220.     //
  221.     // copy MachineAccount to the wAccount buffer allocated while
  222.     // converting computer account name to uppercase.
  223.     // convert password (inplace) to lowercase
  224.     //
  225.     while(cchAccount--) {
  226.         wAccount[cchAccount] = towupper( MachineAccount[cchAccount] );
  227.         wPassword[cchAccount] = towlower( wPassword[cchAccount] );
  228.     }
  229.  
  230.     //
  231.     // computer account names have a trailing Unicode '$'
  232.     //
  233.     wAccount[cchLength] = L'$';
  234.     wAccount[cchLength + 1] = L'\0'; // terminate the string
  235.  
  236.     //
  237.     // if the password is greater than the max allowed, truncate
  238.     //
  239.     if(cchLength > LM20_PWLEN) wPassword[LM20_PWLEN] = L'\0';
  240.  
  241.     //
  242.     // initialize USER_INFO_x structure
  243.     //
  244.     ZeroMemory(&ui, sizeof(ui));
  245.  
  246.     ui.usri1_name = wAccount;
  247.     ui.usri1_password = wPassword;
  248.  
  249.     ui.usri1_flags = AccountType | UF_SCRIPT;
  250.     ui.usri1_priv = USER_PRIV_USER;
  251.  
  252.     nas = NetUserAdd(
  253.                 wTargetComputer,    // target computer name
  254.                 1,                  // info level
  255.                 (LPBYTE) &ui,       // buffer
  256.                 NULL
  257.                 );
  258.  
  259.     //
  260.     // indicate whether it was successful
  261.     //
  262.     if(nas == NERR_Success) {
  263.         return TRUE;
  264.     }
  265.     else {
  266.         SetLastError(nas);
  267.         return FALSE;
  268.     }
  269. }
  270.  
  271. BOOL
  272. SetCurrentPrivilege(
  273.     LPCTSTR Privilege,      // Privilege to enable/disable
  274.     BOOL bEnablePrivilege   // to enable or disable privilege
  275.     )
  276. {
  277.     HANDLE hToken;
  278.     TOKEN_PRIVILEGES tp;
  279.     LUID luid;
  280.     TOKEN_PRIVILEGES tpPrevious;
  281.     DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
  282.     BOOL bSuccess=FALSE;
  283.  
  284.     if(!LookupPrivilegeValue(NULL, Privilege, &luid)) return FALSE;
  285.  
  286.     if(!OpenProcessToken(
  287.             GetCurrentProcess(),
  288.             TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  289.             &hToken
  290.             )) return FALSE;
  291.  
  292.     //
  293.     // first pass.  get current privilege setting
  294.     //
  295.     tp.PrivilegeCount           = 1;
  296.     tp.Privileges[0].Luid       = luid;
  297.     tp.Privileges[0].Attributes = 0;
  298.  
  299.     AdjustTokenPrivileges(
  300.             hToken,
  301.             FALSE,
  302.             &tp,
  303.             sizeof(TOKEN_PRIVILEGES),
  304.             &tpPrevious,
  305.             &cbPrevious
  306.             );
  307.  
  308.     if(GetLastError() == ERROR_SUCCESS) {
  309.         //
  310.         // second pass.  set privilege based on previous setting
  311.         //
  312.         tpPrevious.PrivilegeCount     = 1;
  313.         tpPrevious.Privileges[0].Luid = luid;
  314.  
  315.         if(bEnablePrivilege) {
  316.             tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
  317.         }
  318.         else {
  319.             tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
  320.                 tpPrevious.Privileges[0].Attributes);
  321.         }
  322.  
  323.         AdjustTokenPrivileges(
  324.                 hToken,
  325.                 FALSE,
  326.                 &tpPrevious,
  327.                 cbPrevious,
  328.                 NULL,
  329.                 NULL
  330.                 );
  331.  
  332.         if(GetLastError() == ERROR_SUCCESS) bSuccess=TRUE;
  333.     }
  334.  
  335.     CloseHandle(hToken);
  336.  
  337.     return bSuccess;
  338. }
  339.  
  340. void
  341. DisplayError(
  342.     LPSTR szAPI,    // pointer to failed API name
  343.     DWORD dwLastError
  344.     )
  345. {
  346.     HMODULE hModule = NULL;
  347.     LPSTR MessageBuffer;
  348.     DWORD dwBufferLength;
  349.  
  350.     fprintf(stderr,"%s error! (rc=%lu)\n", szAPI, dwLastError);
  351.  
  352.     if(dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
  353.         hModule = LoadLibraryEx(
  354.             TEXT("netmsg.dll"),
  355.             NULL,
  356.             LOAD_LIBRARY_AS_DATAFILE
  357.             );
  358.     }
  359.  
  360.     if(dwBufferLength=FormatMessageA(
  361.         FORMAT_MESSAGE_ALLOCATE_BUFFER |
  362.         FORMAT_MESSAGE_IGNORE_INSERTS |
  363.         FORMAT_MESSAGE_FROM_SYSTEM |
  364.         ((hModule != NULL) ? FORMAT_MESSAGE_FROM_HMODULE : 0),
  365.         hModule, // module to get message from
  366.         dwLastError,
  367.         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
  368.         (LPSTR) &MessageBuffer,
  369.         0,
  370.         NULL
  371.         ))
  372.     {
  373.         DWORD dwBytesWritten;
  374.  
  375.         //
  376.         // Output message string on stderr
  377.         //
  378.         WriteFile(
  379.             GetStdHandle(STD_ERROR_HANDLE),
  380.             MessageBuffer,
  381.             dwBufferLength,
  382.             &dwBytesWritten,
  383.             NULL
  384.             );
  385.  
  386.         //
  387.         // free the buffer allocated by the system
  388.         //
  389.         LocalFree(MessageBuffer);
  390.     }
  391.  
  392.     if(hModule != NULL)
  393.         FreeLibrary(hModule);
  394. }
  395.  
  396.