My Training Period: xx hours. Before you begin, read someinstruction here.
The expected abilities:
The following is the previous program example that has been run on Windows 2000 Server Domain Controller (DC) ofkpts.org domain. The DC logged on as Domain Administrator and the compiler used was Visual C++ 6.0. Don’t forget to add netapi32.lib to the Visual C++ project (The steps can be found somewhere in this Tutorial :o)).
//********* mydomadduser.cpp ********** // For Win 2000 #define _WIN32_WINNT 0x0500 // Wide character/Unicode based program #ifndef UNICODE #define UNICODE #endif
#include <windows.h> #include <stdio.h> #include <lm.h>
// This program accept 3 arguments: servername, user account and password. // It is run locally on Win 2000 DC of kpts.org domain. The DC server name is tutorkpts. // May be NULL if it is run on local... int wmain(int argc, wchar_t *argv[ ]) { USER_INFO_1 ui; DWORD dwLevel = 1; DWORD dwError = 0; NET_API_STATUS nStatus;
if(argc != 4) { // For NT40 need to append \\Servername fwprintf(stderr, L"Usage: %s ServerName UserName Password.\n", argv[0]); // or use fwprintf(stderr, L"Usage: %s UserName Password.\n", argv[0]); // for local machine and adjust other array element appropriately. exit(1); }
// Set up the USER_INFO_1 structure. // USER_PRIV_USER: name identifies an normal user // UF_SCRIPT: required for LAN Manager 2.0 and Windows NT and later. ui.usri1_name = argv[2]; // Username entered through command line ui.usri1_password = argv[4]; // Password, through command line ui.usri1_priv = USER_PRIV_USER;// As a normal/restricted user ui.usri1_home_dir = L""; // No home directory, just dummy or point it to NULL ui.usri1_comment = L"This is a test normal user account using NetUserAdd()"; // Comment ui.usri1_flags = UF_SCRIPT; // Must be UF_SCRIPT ui.usri1_script_path = L""; // No script path, just dummy or point it to NULL
// Call the NetUserAdd() function, specifying level 1. nStatus = NetUserAdd(argv[1], dwLevel, (LPBYTE)&ui, &dwError);
// If the call succeeds, inform the user. if(nStatus == NERR_Success) { fwprintf(stderr, L"%s user has been successfully added on %s machine.\n", argv[2], argv[1]); fwprintf(stderr, L"Username: %s password: %s.\n", argv[2], argv[3]); } // Otherwise, print the system error. else fprintf(stderr, "A system error has occurred: %d\n", nStatus);
return 0; }
A sample output:
|
Then, verify the user account creation through Active Directory Users and Computers Microsoft Management Console (MMC).
Start→ Programs→ Administrative Tools→ Active Directory Users and Computers MMC.
Figure 6:anonymdomuser, a domain user account.
Figure 7:anonymdomuser property page.
Figure 8: Anotheranonymdomuser property page.
-----------------------------------------------------Unicode----------------------------------------------------------
Note: In the Unicode programming, you can define a wide-character version of the main() function. You can usewmain() instead ofmain() if you want to write portable code that adheres to the Unicode specification. You declare formal parameters towmain() using a similar format to main(). The declaration syntax for wmain is as follows:
int wmain();
Or, optionally:
int wmain(int argc[ , wchar_t *argv[ ] [, wchar_t *envp[ ] ] ]);
You can then pass wide-character arguments and, optionally, a wide-character environment pointer to the program. The argv and envp parameters to wmain() are of type wchar_t*. If your program uses a main() function, the multibyte-character environment is created by the operating system at program startup. A wide-character copy of the environment is created only when needed for example, by a call to the_wgetenv or_wputenv functions. On the first call to _wputenv, or on the first call to _wgetenv if an MBCS environment already exists, a corresponding wide-character string environment is created and is then pointed to by the_wenviron global variable, which is a wide-character version of the _environ global variable. At this point, two copies of the environment (MBCS and Unicode) exist simultaneously and are maintained by the operating system throughout the life of the program. Similarly, if your program uses awmain() function, an MBCS (ASCII) environment is created on the first call to_putenv orgetenv, and is pointed to by the _environ global variable.
The types forargc andargv are defined by the language. The namesargc,argv, andenvp are traditional, but are not required by the compiler.
Alternatively, themain() andwmain() functions can be declared as returning void (no return value). If you declaremain() orwmain() as returningvoid, you cannot return an exit code to the parent process or operating system using areturn statement; to return an exit code whenmain() orwmain() is declared asvoid, you must use the exit() function. Complete stories can be foundUnicode & Multibyte.
-----------------------------------------------------Unicode----------------------------------------------------------
NetUserEnum() Program Example
The following code sample demonstrates how to retrieve information about the user accounts on a server with a call to theNetUserEnum() function. The sample calls NetUserEnum(), specifying information level 0 (USER_INFO_0) to enumerate only global user accounts. If the call succeeds, the code loops through the entries and prints the name of each user account. Finally, the code sample frees the memory allocated for the information buffer and prints a total of the users enumerated.
//***** myenumerateuser.cpp ********
// For WinXp
#define _WIN32_WINNT 0x0501
// Wide character/Unicode based program
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <lm.h>
// This program accept 1 argument, a servername
// else, local computer is assumed
int wmain(int argc, wchar_t *argv[ ])
{
// Use LPUSER_INFO_1 type for more Level 1 detail info.
LPUSER_INFO_1 pBuf = NULL;
LPUSER_INFO_1 pTmpBuf;
DWORD dwLevel = 1;
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
DWORD dwEntriesRead = 0;
DWORD dwTotalEntries = 0;
DWORD dwResumeHandle = 0;
DWORD i;
DWORD dwTotalCount = 0;
NET_API_STATUS nStatus;
LPTSTR pszServerName = NULL;
// Some prompt
// If argc == 1, local computer is assumed
if(argc > 2)
{
fwprintf(stderr, L"Usage: %s [ServerName]\n", argv[0]);
exit(1);
}
// The server name is supplied so it is not the default local computer.
if(argc == 2)
pszServerName = argv[1];
wprintf(L"\nUser accounts, flags and their privileges on %s machine: \n", pszServerName);
// Call the NetUserEnum() function, specifying level 0,
// enumerate global user account types only.
do// begin do
{
// If pszServerName is NULL, local pc is assumed, here we use servername but it
// is just a local WinXP machine. Try other entries also such as password etc.
nStatus = NetUserEnum(pszServerName,
dwLevel,
FILTER_NORMAL_ACCOUNT, // global users, change it appropriately to dig other info
(LPBYTE*)&pBuf,
dwPrefMaxLen,
&dwEntriesRead,
&dwTotalEntries,
&dwResumeHandle);
// If the call succeeds,
if((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
{
if((pTmpBuf = pBuf) != NULL)
{
// Loop through the entries.
for(i = 0; (i < dwEntriesRead); i++)
{
// Check buffer
assert(pTmpBuf != NULL);
if(pTmpBuf == NULL)
{
fprintf(stderr, "An access violation has occurred\n");
break;
}
// Print the name of the user account, flag and their privilege.
wprintf(L"... %s::%0x::%0x\n", pTmpBuf->usri1_name, pTmpBuf->usri1_flags, pTmpBuf->usri1_priv);
pTmpBuf++;
dwTotalCount++;
}
}
}
// Otherwise, print the system error.
else
fprintf(stderr, "A system error has occurred: %d\n", nStatus);
// Release the allocated buffer.
if(pBuf != NULL)
{
NetApiBufferFree(pBuf);
pBuf = NULL;
}
}
// Continue to call NetUserEnum while there are more entries.
while (nStatus == ERROR_MORE_DATA); // end do
// Check again for allocated memory.
if(pBuf != NULL)
NetApiBufferFree(pBuf);
// Print the final count of users enumerated.
fprintf(stderr, "\nTotal of %d entries enumerated\n", dwTotalCount);
return 0;
}
A sample output:
|
Well, when trying to enumerate the password, the output is NULL lol! Need decryption?
The following code sample demonstrates how to disable a user account with a call to theNetUserSetInfo() function. The code sample fills in theusri1008_flags member of the USER_INFO_1008 structure, specifying the valueUF_ACCOUNTDISABLE. Then the sample calls NetUserSetInfo(), specifying information level 0.
//********** mysetuserinfo.cpp ************
// For WinXp
#define _WIN32_WINNT 0x0501
// Wide character/Unicode based program
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#include <lm.h>
// This program accept 2 arguments, a servername and a user account to be disabled
int wmain(int argc, wchar_t *argv[ ])
{
// Disable the user account
DWORD dwLevel = 1008;
USER_INFO_1008 ui;
NET_API_STATUS nStatus;
// If not enough arguments supplied.
if(argc != 3)
{
fwprintf(stderr, L"Usage: %s ServerName UserName\n", argv[0]);
// Just exit, no further processing.
exit(1);
}
// Fill in the USER_INFO_1008 structure member.
// UF_SCRIPT: required for LAN Manager 2.0 and Windows NT and later.
// UF_ACCOUNTDISABLE: disable the user account.
ui.usri1008_flags = (UF_SCRIPT | UF_ACCOUNTDISABLE);
// Call the NetUserSetInfo() function
// to disable the account, specifying level 1008.
nStatus = NetUserSetInfo(argv[1],
argv[2],
dwLevel,
(LPBYTE)&ui,
NULL);
// Display the result of the call.
if(nStatus == NERR_Success)
fwprintf(stderr, L"User account %s has been disabled.\n", argv[2]);
else
fprintf(stderr, "A system error has occurred: %d\n", nStatus);
return 0;
}
A sample output:
E:\myproject\win32prog\Debug>mysetuserinfo
Usage: mysetuserinfo ServerName UserName
E:\myproject\win32prog\Debug>mysetuserinfo mypersonal myuser#1
User account myuser#1 has been disabled.
E:\myproject\win32prog\Debug>
Verify our work.
Figure 9:myuser#1 user account has been disabled.
The following program example set the"Password never expires" and "User cannot change password".
//******** mysetuserinfo2.cpp *******
// For WinXp
#define _WIN32_WINNT 0x0501
// Wide character/Unicode based program
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#include <lm.h>
// This program accept 2 arguments, a servername and a user account
int wmain(int argc, wchar_t *argv[ ])
{
DWORD dwLevel = 1008;
USER_INFO_1008 ui;
NET_API_STATUS nStatus;
// If not enough arguments supplied.
if(argc != 3)
{
fwprintf(stderr, L"Usage: %s ServerName UserName\n", argv[0]);
// Just exit, no further processing.
exit(1);
}
// Fill in the USER_INFO_1008 structure member. UF_SCRIPT: required for LAN Manager 2.0 and Windows NT and later.
ui.usri1008_flags = (UF_SCRIPT | UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD);
// Call the NetUserSetInfo() function to set Password never expires and User cannot change password.
nStatus = NetUserSetInfo(argv[1],
argv[2],
dwLevel,
(LPBYTE)&ui,
NULL);
// Display the result of the call.
if(nStatus == NERR_Success)
{
fwprintf(stderr, L"%s user account has been set for:\n", argv[2]);
fwprintf(stderr, L"-- Password never expires.\n");
fwprintf(stderr, L"-- User cannot change password.\n");
}
else
fprintf(stderr, "A system error has occurred: %d\n", nStatus);
return 0;
}
A sample output:
E:\myproject\win32prog\Debug>mysetuserinfo2
Usage: mysetuserinfo2 ServerName UserName
E:\myproject\win32prog\Debug>mysetuserinfo2 mypersonal myuser#2
myuser#2 user account has been set for:
-- Password never expires.
-- User cannot change password.
E:\myproject\win32prog\Debug>
Then, let verify our task.
Figure 10: myuser#2 user account with some settings has been created.
#######################################################
The following is the previous example that has been run on Windows 2000 Server Domain Controller (DC) ofkpts.org domain. The DC logged on as Domain Administrator and the compiler used was Visual C++ 6.0.
//******** mydomsetuserinfo2.cpp *******
// For Win2000
#define _WIN32_WINNT 0x0500
// Wide character/Unicode based program
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#include <lm.h>
// This program accept 2 arguments, a servername and a username
int wmain(int argc, wchar_t *argv[ ])
{
DWORD dwLevel = 1008;
USER_INFO_1008 ui;
NET_API_STATUS nStatus;
// If not enough arguments supplied.
if(argc != 3)
{
fwprintf(stderr, L"Usage: %s ServerName UserName\n", argv[0]);
// Just exit, no further processing.
exit(1);
}
// Fill in the USER_INFO_1008 structure member. UF_SCRIPT: required for LAN Manager 2.0 and Windows NT and later.
ui.usri1008_flags = (UF_SCRIPT | UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD);
// Call the NetUserSetInfo() function to set Password never expires and User cannot change password.
nStatus = NetUserSetInfo(argv[1],
argv[2],
dwLevel,
(LPBYTE)&ui,
NULL);
// Display the result of the call.
if(nStatus == NERR_Success)
{
fwprintf(stderr, L"%s user account has been set for:\n", argv[2]);
fwprintf(stderr, L"-- Password never expires.\n");
fwprintf(stderr, L"-- User cannot change password.\n");
}
else
fprintf(stderr, "A system error has occurred: %d\n", nStatus);
return 0;
}
A sample output:
C:\myproject\win32prog\Debug>mydomsetuserinfo2
Usage: mydomsetuserinfo2 ServerName UserName
C:\myproject\win32prog\Debug>mydomsetuserinfo2 tutorkpts anonymdomuser
anonymdomuser user account has been set for:
-- Password never expires.
-- User cannot change password.
Figure 11: Settinganonymdomuser account properties.
---------------------------User Accounts and Groups: Story and Program Examples, Part I-----------------------
Further reading and digging:
Check the best selling C, C++ and Windows books at Amazon.com.
Microsoft C references, online MSDN.
Microsoft Visual C++, online MSDN.
ReactOS - Windows binary compatible OS - C/C++ source code repository, Doxygen.
Linux Access Control Lists (ACL) info can be found atAccess Control Lists.
For Multi-bytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).
Structure, enum, union and typedef story can be foundC/C++ struct, enum, union & typedef.
Notation used in MSDN is Hungarian Notation instead of CamelCase and is discussedWindows programming notations.
Windows data type information is inWindows data types used in Win32 programming.