mirror of https://github.com/lianthony/NT4.0
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.
466 lines
18 KiB
466 lines
18 KiB
/*
|
|
NETUSER.C -- a sample program demonstrating NetUser API functions.
|
|
|
|
This program requires that you have admin or accounts operator
|
|
privilege on the specified server.
|
|
|
|
usage: netuser [-s \\server] [-u username] [-p password]
|
|
[-c comment] [-l privilege level]
|
|
where \\server = Name of the server. A servername must be preceded
|
|
by two backslashes (\\).
|
|
username = Name of the user.
|
|
password = Password for the user.
|
|
comment = Comment string for the user.
|
|
privilege level = Privilege level for the user
|
|
(0=Guest, 1=User, 2=Admin).
|
|
|
|
API Used to...
|
|
================== ============================================
|
|
NetUserAdd Add a new user with a level 1 call
|
|
NetUserEnum List of users and user comments
|
|
NetUserGetInfo Display user details
|
|
NetUserSetInfo Disable, then re-enable the account
|
|
NetUserPasswordSet Change the new user's password
|
|
NetUserSetGroups Set the groups to which a user belongs
|
|
NetUserGetGroups Get the groups to which a user belongs
|
|
NetUserDel Delete the new user
|
|
NetUserModalsGet Get current modals for users in database
|
|
NetUserModalsSet Increment the password history length by one
|
|
|
|
This code sample is provided for demonstration purposes only.
|
|
Microsoft makes no warranty, either express or implied,
|
|
as to its usability in any given situation.
|
|
*/
|
|
|
|
#ifndef UNICODE
|
|
#define UNICODE // Net APIs all require this.
|
|
#endif
|
|
|
|
#include <windows.h> // DWORD, LPWSTR, etc (needed by lm.h).
|
|
#include <lm.h> // LAN Manager header files
|
|
|
|
#include <assert.h> // assert().
|
|
#include <stdio.h> // C run-time header files
|
|
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1, qsort().
|
|
#include <wchar.h> // _wcsicmp().
|
|
|
|
#include "samples.h" // Internal routine header file
|
|
|
|
#define DEFAULT_NEWUSER L"BRUCE"
|
|
#define DEFAULT_PASSWORD L"PASSWORD"
|
|
#define DEFAULT_NEW_PASSWORD L"NEWPASS"
|
|
#define DEFAULT_PRIVILEGE 1 // 0=Guest, 1=User, 2=Admin
|
|
#define DEFAULT_COMMENT L"New user"
|
|
#define DEFAULT_NEWGROUP L"TESTERS"
|
|
|
|
|
|
#ifndef NULL_USERSETINFO_PASSWD_U
|
|
#define NULL_USERSETINFO_PASSWD_U L" "
|
|
#endif
|
|
|
|
|
|
int Compare(LPUSER_INFO_2 arg1, LPUSER_INFO_2 arg2);
|
|
void Usage (char * pszProgram);
|
|
|
|
int _CRTAPI1
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
LPWSTR pszServer = NULL; // Servername
|
|
LPWSTR pszNewUser = DEFAULT_NEWUSER; // Name of new user
|
|
LPWSTR pszPassword = DEFAULT_PASSWORD; // Password for new user
|
|
LPWSTR pszComment = DEFAULT_COMMENT; // Comment for new user
|
|
LPWSTR pszNewGroup = DEFAULT_NEWGROUP; // Name of new group
|
|
DWORD cbBuffer;
|
|
LPBYTE pbBuffer; // Pointer to data buffer
|
|
int iCount; // Index counter
|
|
DWORD cEntriesRead; // Count of entries read
|
|
DWORD cTotalAvail; // Entries available
|
|
DWORD dwPrivLevel = DEFAULT_PRIVILEGE;// New user privilege
|
|
DWORD dwFlags; // User flags
|
|
DWORD dwHistLen; // Password history
|
|
API_RET_TYPE uReturnCode; // API return code
|
|
LPUSER_INFO_1 pUserInfo1; // User info; level 1
|
|
LPUSER_INFO_2 pUserInfo2; // User info; level 2
|
|
LPGROUP_INFO_0 pGroupInfo0; // Group info; level 0
|
|
LPUSER_MODALS_INFO_0 pUserModals0; // Modals info; level 0
|
|
|
|
for (iCount = 1; iCount < argc; iCount++)
|
|
{
|
|
if ((*argv[iCount] == '-') || (*argv[iCount] == '/'))
|
|
{
|
|
switch (tolower(*(argv[iCount]+1))) // Process switches
|
|
{
|
|
case 's': // -s servername
|
|
pszServer = SafeMallocWStrFromStr( argv[++iCount] );
|
|
break;
|
|
case 'u': // -u username
|
|
pszNewUser = SafeMallocWStrFromStr( argv[++iCount] );
|
|
break;
|
|
case 'p': // -p password
|
|
pszPassword = SafeMallocWStrFromStr( argv[++iCount] );
|
|
break;
|
|
case 'c': // -c comment
|
|
pszComment = SafeMallocWStrFromStr( argv[++iCount] );
|
|
break;
|
|
case 'l': // -l privilege level
|
|
dwPrivLevel = (DWORD) atoi(argv[++iCount]);
|
|
break;
|
|
case 'h':
|
|
default:
|
|
Usage(argv[0]);
|
|
}
|
|
}
|
|
else
|
|
Usage(argv[0]);
|
|
}
|
|
|
|
//========================================================================
|
|
// NetUserAdd
|
|
//
|
|
// This API adds a new user at info level 1. Note comments carefully.
|
|
//========================================================================
|
|
|
|
cbBuffer = sizeof(USER_INFO_1);
|
|
pUserInfo1 = (LPUSER_INFO_1) SafeMalloc(cbBuffer);
|
|
|
|
/*
|
|
* Copy the fixed-length strings into the data buffer.
|
|
* The password and username must be uppercase or the user will
|
|
* not be able to log on through the net command or through the
|
|
* full-screen user interface. The password is encrypted before
|
|
* being sent to the server.
|
|
*/
|
|
pUserInfo1->usri1_name = pszNewUser;
|
|
pUserInfo1->usri1_password = pszPassword;
|
|
|
|
pUserInfo1->usri1_priv = dwPrivLevel;
|
|
pUserInfo1->usri1_home_dir = L"";
|
|
pUserInfo1->usri1_comment = pszComment;
|
|
pUserInfo1->usri1_script_path = L"";
|
|
pUserInfo1->usri1_flags = UF_SCRIPT;
|
|
/*
|
|
* At least UF_SCRIPT must be included here. If usriX_flags is
|
|
* left as 0, NetUserAdd returns ERROR_INVALID_PARAMETER.
|
|
*/
|
|
|
|
uReturnCode = NetUserAdd(pszServer, // Servername
|
|
1, // Info level (1 or 2)
|
|
(LPVOID) pUserInfo1, // Input buffer
|
|
NULL); // Don't care about parm err
|
|
|
|
printf("NetUserAdd of %ws returned %lu\n", pszNewUser, uReturnCode);
|
|
free(pUserInfo1);
|
|
|
|
//========================================================================
|
|
// NetUserEnum
|
|
//
|
|
// This API lists usernames and comments and sorts the names
|
|
// alphabetically before displaying them.
|
|
//========================================================================
|
|
|
|
pbBuffer = NULL;
|
|
uReturnCode = NetUserEnum(pszServer, // Servername
|
|
1, // Info level (0,1,2,10)
|
|
FILTER_NORMAL_ACCOUNT, // filter
|
|
&pbBuffer, // Data returned here (alloc by API)
|
|
MAX_PREFERRED_LENGTH, // pref max len (all at once)
|
|
&cEntriesRead, // Count of entries read
|
|
&cTotalAvail, // Count of entries available
|
|
NULL); // No resume handle
|
|
|
|
printf("NetUserEnum returned %lu\n", uReturnCode);
|
|
|
|
switch (uReturnCode) {
|
|
case NERR_Success:
|
|
if (cEntriesRead > 0) {
|
|
assert( pbBuffer != NULL );
|
|
pUserInfo1 = (LPUSER_INFO_1) pbBuffer;
|
|
#if 0
|
|
printf("Sorting %lu entries...\n", cEntriesRead);
|
|
qsort(
|
|
pbBuffer,
|
|
(size_t) cEntriesRead,
|
|
(size_t) sizeof(USER_INFO_1),
|
|
(LPVOID) Compare);
|
|
#endif
|
|
for (iCount = 0; iCount < (int) cEntriesRead; iCount++)
|
|
{
|
|
printf(" %-24ws (%ws)\n", pUserInfo1->usri1_name,
|
|
pUserInfo1->usri1_comment);
|
|
pUserInfo1++;
|
|
}
|
|
} else {
|
|
printf("(No entries matched.)\n");
|
|
printf(" Entries read = %lu, Entries available = %lu \n",
|
|
cEntriesRead, cTotalAvail);
|
|
}
|
|
break;
|
|
case ERROR_MORE_DATA:
|
|
printf(" Entries read = %lu, Entries available = %lu \n",
|
|
cEntriesRead, cTotalAvail);
|
|
break;
|
|
}
|
|
if (pbBuffer != NULL) {
|
|
free(pbBuffer);
|
|
}
|
|
|
|
//========================================================================
|
|
// NetUserGetInfo
|
|
//
|
|
// This API prints details about the new user.
|
|
//========================================================================
|
|
|
|
uReturnCode = NetUserGetInfo(pszServer, // Servername
|
|
pszNewUser, // Username
|
|
2, // Level (0,1,2,10,11)
|
|
&pbBuffer); // alloc buffer and set ptr
|
|
|
|
printf("NetUserGetInfo returned %lu\n", uReturnCode);
|
|
pUserInfo2 = (LPUSER_INFO_2) pbBuffer;
|
|
|
|
if (uReturnCode == NERR_Success)
|
|
{
|
|
printf(" User Name = %ws \n", pUserInfo2->usri2_name);
|
|
printf(" Privilege = %lu \n", pUserInfo2->usri2_priv);
|
|
printf(" Comment = %ws \n", pUserInfo2->usri2_comment);
|
|
printf(" Full name = %ws \n", pUserInfo2->usri2_full_name);
|
|
printf(" Workstations = %ws \n", pUserInfo2->usri2_workstations);
|
|
printf(" Logon server = %ws \n", pUserInfo2->usri2_logon_server);
|
|
}
|
|
|
|
//========================================================================
|
|
// NetUserSetInfo
|
|
//
|
|
// There are two ways to call NetUserSetInfo. If ParmNum is PARMNUM_ALL,
|
|
// you must pass a whole user_info_X structure. Otherwise, you can set
|
|
// ParmNum to the element of the structure you want to change. Both ways
|
|
// are shown here.
|
|
//========================================================================
|
|
|
|
// Disable the account by setting the UF_ACCOUNTDISABLE bit to 1.
|
|
pUserInfo2->usri2_flags |= UF_ACCOUNTDISABLE;
|
|
|
|
pUserInfo2->usri2_password = NULL_USERSETINFO_PASSWD_U;
|
|
/*
|
|
* This previous step is important. When you get a structure from
|
|
* NetUserGetInfo, it does not contain the password. If you want
|
|
* to send that same structure back to NetUserSetInfo (using
|
|
* ParmNum=PARMNUM_ALL), you must set usriX_password to
|
|
* NULL_USERSETINFO_PASSWD to indicate that you want the old password
|
|
* left unchanged.
|
|
*/
|
|
uReturnCode = NetUserSetInfo(pszServer, // Servername
|
|
pszNewUser, // Username
|
|
2, // Info level (1 or 2)
|
|
(LPVOID) pUserInfo2, // Data buffer
|
|
PARMNUM_ALL); // Parameter number code
|
|
|
|
printf("NetUserSetInfo with ParmNum = %lu returned %lu\n",
|
|
PARMNUM_ALL, uReturnCode);
|
|
|
|
/*
|
|
* The following is a more typical use of NetUserSetInfo when you only
|
|
* want to change one field in the structure. The example enables
|
|
* an account by setting the UF_ACCOUNTDISABLE bit to 0.
|
|
*/
|
|
|
|
dwFlags = pUserInfo2->usri2_flags & ~UF_ACCOUNTDISABLE;
|
|
|
|
uReturnCode = NetUserSetInfo(pszServer, // Servername
|
|
pszNewUser, // Username
|
|
USER_FLAGS_INFOLEVEL, // level & parmnum
|
|
(LPVOID) &dwFlags, // Data buffer
|
|
NULL); // Don't care about parm err
|
|
|
|
printf("NetUserSetInfo with ParmNum = %lu returned %lu\n",
|
|
USER_FLAGS_INFOLEVEL, uReturnCode);
|
|
free(pbBuffer);
|
|
|
|
//========================================================================
|
|
// NetUserPasswordSet
|
|
//
|
|
// This API changes a user's password. It allows users to change their
|
|
// own password if they know their old one. An administrator would
|
|
// typically use NetUserSetInfo, which does not require knowledge of
|
|
// the old password.
|
|
//========================================================================
|
|
|
|
#if 0
|
|
uReturnCode = NetUserPasswordSet(pszServer, // Servername
|
|
pszNewUser, // Username
|
|
pszPassword, // Old password
|
|
DEFAULT_NEW_PASSWORD); // New password
|
|
|
|
printf("NetUserPasswordSet returned %lu\n", uReturnCode);
|
|
#endif
|
|
|
|
//========================================================================
|
|
// NetGroupAdd
|
|
//
|
|
// This API creates a new group.
|
|
//========================================================================
|
|
|
|
cbBuffer = sizeof(GROUP_INFO_0);
|
|
pGroupInfo0 = (LPGROUP_INFO_0) SafeMalloc(cbBuffer);
|
|
pGroupInfo0->grpi0_name = pszNewGroup;
|
|
|
|
uReturnCode = NetGroupAdd(pszServer, // Servername
|
|
0, // Info level (0 or 1)
|
|
(LPVOID) pGroupInfo0, // Input buffer
|
|
NULL); // Don't care about parm err
|
|
|
|
printf("NetGroupAdd of group \"%ws\" returned %lu\n",
|
|
pszNewGroup, uReturnCode);
|
|
|
|
//========================================================================
|
|
// NetUserSetGroups
|
|
// OR NetGroupAddUser
|
|
//
|
|
// This API sets this as the group to which the new user belongs.
|
|
//========================================================================
|
|
|
|
#if 0
|
|
// Under NT, there are now "special groups" which prevent this from
|
|
// working.
|
|
uReturnCode = NetUserSetGroups(pszServer, // Servername
|
|
pszNewUser, // Username
|
|
0, // Info level; must be 0
|
|
(LPVOID) pGroupInfo0, // Input buffer
|
|
1); // Number of groups to set
|
|
printf("NetUserSetGroups for user \"%ws\" returned %lu\n",
|
|
pszNewUser, uReturnCode);
|
|
#else
|
|
uReturnCode = NetGroupAddUser(pszServer, // Servername
|
|
pszNewGroup, // Group name
|
|
pszNewUser ); // Username
|
|
printf("NetGroupAddUser for user \"%ws\" returned %lu\n",
|
|
pszNewUser, uReturnCode);
|
|
|
|
#endif
|
|
|
|
if (pGroupInfo0 != NULL) {
|
|
free(pGroupInfo0);
|
|
}
|
|
|
|
|
|
//======================================================================
|
|
// NetUserGetGroups
|
|
//
|
|
// This API lists the groups to which the new user belongs.
|
|
//======================================================================
|
|
|
|
uReturnCode = NetUserGetGroups(pszServer, // Servername
|
|
pszNewUser, // Username
|
|
0, // Level; must be 0
|
|
&pbBuffer, // Return buffer (alloc by API)
|
|
MAX_PREFERRED_LENGTH, // pref max len (all at once)
|
|
&cEntriesRead, // Count of groups read
|
|
&cTotalAvail); // Count of groups available
|
|
|
|
printf("NetUserGetGroups returned %lu\n", uReturnCode);
|
|
|
|
if (uReturnCode == NERR_Success)
|
|
{
|
|
pGroupInfo0 = (LPGROUP_INFO_0) pbBuffer;
|
|
for (iCount = 0; iCount < (int) cEntriesRead; iCount++)
|
|
{
|
|
printf(" %ws\n", pGroupInfo0->grpi0_name);
|
|
pGroupInfo0++;
|
|
}
|
|
}
|
|
free(pbBuffer);
|
|
|
|
//========================================================================
|
|
// NetUserDel
|
|
//
|
|
// This API deletes the new user added at the start of this program and
|
|
// deletes the new group that was added to demonstrate NetUserSetGroups.
|
|
//========================================================================
|
|
|
|
uReturnCode = NetUserDel(pszServer, // Servername
|
|
pszNewUser); // Username
|
|
|
|
printf("NetUserDel of user \"%ws\" returned %lu\n",
|
|
pszNewUser, uReturnCode);
|
|
|
|
uReturnCode = NetGroupDel(pszServer, // Servername
|
|
pszNewGroup); // Groupname
|
|
|
|
printf("NetGroupDel of group \"%ws\" returned %lu\n",
|
|
pszNewGroup, uReturnCode);
|
|
|
|
//========================================================================
|
|
// NetUserModalsGet
|
|
//
|
|
// This API gets modal information for all users in the
|
|
// user account subsystem.
|
|
//========================================================================
|
|
|
|
uReturnCode = NetUserModalsGet(pszServer, // Servername
|
|
0, // Info level (0 or 1)
|
|
(LPBYTE *) (LPVOID) &pUserModals0); // buf (alloc by API)
|
|
|
|
printf("NetUserModalsGet returned %lu\n", uReturnCode);
|
|
if (uReturnCode == NERR_Success)
|
|
{
|
|
printf(" Min. password length = %lu\n",
|
|
pUserModals0->usrmod0_min_passwd_len);
|
|
if (pUserModals0->usrmod0_max_passwd_age == TIMEQ_FOREVER)
|
|
printf(" Max. password age (days) = UNLIMITED\n");
|
|
else
|
|
printf(" Max. password age (days) = %lu\n",
|
|
pUserModals0->usrmod0_max_passwd_age / (ONE_DAY));
|
|
printf(" Min. password age (days) = %lu\n",
|
|
pUserModals0->usrmod0_min_passwd_age / (ONE_DAY));
|
|
if (pUserModals0->usrmod0_force_logoff == USER_NO_LOGOFF)
|
|
printf(" Forced logoff time = NEVER\n");
|
|
else
|
|
printf(" Forced logoff time (minutes) = %lu\n",
|
|
pUserModals0->usrmod0_force_logoff / 60);
|
|
printf(" Password history = %lu\n",
|
|
pUserModals0->usrmod0_password_hist_len);
|
|
}
|
|
|
|
//========================================================================
|
|
// NetUserModalsSet
|
|
//
|
|
// There are two ways to call NetUserModalsSet. If ParmNum is
|
|
// PARMNUM_ALL, you must pass in a whole user_modals_info_X structure.
|
|
// Otherwise, you can set ParmNum to the element of the structure
|
|
// to change. In this example, the password history length is incremented
|
|
// using MODAL0_PARMNUM_HISTLEN as the value of ParmNum.
|
|
//========================================================================
|
|
|
|
if (pUserModals0->usrmod0_password_hist_len == DEF_MAX_PWHIST)
|
|
dwHistLen = 0;
|
|
else
|
|
dwHistLen = pUserModals0->usrmod0_password_hist_len + 1;
|
|
|
|
uReturnCode = NetUserModalsSet(pszServer, // Servername
|
|
MODALS_PASSWD_HIST_LEN_INFOLEVEL, // info level & parmnum
|
|
(LPVOID) &dwHistLen, // Input buffer
|
|
NULL); // Don't care about parm err
|
|
|
|
printf("NetUserModalsSet returned %lu\n", uReturnCode);
|
|
free(pUserModals0);
|
|
|
|
return (EXIT_SUCCESS);
|
|
}
|
|
|
|
// Compare function used by quicksort.
|
|
int Compare(LPUSER_INFO_2 arg1, LPUSER_INFO_2 arg2)
|
|
{
|
|
return(_wcsicmp(arg1->usri2_name, arg2->usri2_name));
|
|
}
|
|
|
|
void Usage (char * pszProgram)
|
|
{
|
|
fprintf(stderr, "NetUser API sample program: 32-bit, Unicode version.\n");
|
|
fprintf(stderr, "Usage: %s [-s \\\\server] [-u username] "
|
|
"[-p password] [-c comment]\n\t\t"
|
|
"[-l privilege level] \n", pszProgram);
|
|
exit(EXIT_FAILURE);
|
|
}
|