|< Windows User Accounts & Groups Programming 1 | Main | Windows User Accounts & Groups Programming 3 >| Site Index | Download |


 

 

 

 

MODULE M1

WINDOWS OS

.::USER ACCOUNTS AND GROUPS:  STORY & PROGRAM EXAMPLES::.

PART 2

 

 

 

 

What do we have in this Module?

  1. NetUserEnum() Program Example

  2. NetUserSetInfo() Program Example

 

 

My Training Period: xx hours. Before you begin, read some instruction here.

 

The expected abilities:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The following is the previous program example that has been run on Windows 2000 Server Domain Controller (DC) of kpts.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:

C:\myproject\win32prog\Debug>mydomadduser

Usage: mydomadduser ServerName UserName Password.

 

C:\myproject\win32prog\Debug>mydomadduser tutorkpts anonymdomuser 876543219

anonymdomuser user has been successfully added on tutorkpts machine.

Username: anonymdomuser password: 876543219.

 

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.

 

Add domain user

 

Figure 6: anonymdomuser, a domain user account.

 

Add domain user verification

 

Figure 7: anonymdomuser property page.

 

More add domain user verification

 

Figure 8: Another anonymdomuser property page.

 

-----------------------------------------------------Unicode----------------------------------------------------------

 

Note: In the Unicode programming, you can define a wide-character version of the main() function.  You can use wmain() instead of main() if you want to write portable code that adheres to the Unicode specification.  You declare formal parameters to wmain() 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 a wmain() function, an MBCS (ASCII) environment is created on the first call to _putenv or getenv, and is pointed to by the _environ global variable.

The types for argc and argv are defined by the language.  The names argc, argv, and envp are traditional, but are not required by the compiler.

Alternatively, the main() and wmain() functions can be declared as returning void (no return value).  If you declare main() or wmain() as returning void, you cannot return an exit code to the parent process or operating system using a return statement; to return an exit code when main() or wmain() is declared as void, you must use the exit() function.  Complete stories can be found Unicode & 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 the NetUserEnum() 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:

E:\myproject\win32prog\Debug>myenumerateuser mypersonal

 

User accounts, flags and their privileges on mypersonal machine:

... ACTUser::10241::1

... Administrator::10201::2

... ASPNET::10261::1

... Guest::10263::0

... HelpAssistant::10243::0

... IUSR_MYPERSONAL::10261::0

... IWAM_MYPERSONAL::10261::0

... Mike::10201::2

... myuser#1::800201::0

... myuser#2::800201::0

... SQLDebugger::10241::1

... SUPPORT_388945a0::10243::0

... testuser::10241::1

 

Total of 13 entries enumerated

 

E:\myproject\win32prog\Debug>

 

Well, when trying to enumerate the password, the output is NULL lol!  Need decryption?

 

NetUserSetInfo() Program Example

 

The following code sample demonstrates how to disable a user account with a call to the NetUserSetInfo() function.  The code sample fills in the usri1008_flags member of the USER_INFO_1008 structure, specifying the value UF_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.

 

Set other user information

 

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.

 

Another example setting user information

 

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) of kpts.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.

 

Set domain user's information

 

Figure 11: Setting anonymdomuser account properties.

 

---------------------------User Accounts and Groups: Story and Program Examples, Part I-----------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

 

  1. Check the best selling C, C++ and Windows books at Amazon.com.

  2. Microsoft Visual C++, online MSDN.

  3. MSDN library.

  4. For Multibytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).

  5. Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.

  6. Notation used in MSDN is Hungarian Notation instead of CamelCase and is discussed Windows programming notations.

  7. Windows data type information is in Windows data types used in Win32 programming.

 

 

 

 

 

 

|< Windows User Accounts & Groups Programming 1 | Main | Windows User Accounts & Groups Programming 3 >| Site Index | Download |