|
|
/*
|
|
|
Copyright (C) 2003 Olaf Flebbe, Science and Computing AG
|
|
|
o.flebbe@science-computing.de
|
|
|
Copyright (C) 2013 Timothy Pearson, Northern Illinois University
|
|
|
kb9vqf@pearsoncomputing.net
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
(at your option) any later version.
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
along with this program; if not, write to the Free Software
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
*/
|
|
|
#define WINDOWS_MEAN_AND_LEAN
|
|
|
#define UNICODE
|
|
|
|
|
|
#include <windows.h>
|
|
|
#include <lm.h>
|
|
|
#include <time.h>
|
|
|
#include "netusergroup.h"
|
|
|
|
|
|
int
|
|
|
addUserToGroup( const mystring& userName, const mystring& groupName) {
|
|
|
if (addGroup( groupName)) {
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
LOCALGROUP_MEMBERS_INFO_3 gmember;
|
|
|
gmember.lgrmi3_domainandname = (LPWSTR) userName.c_str();
|
|
|
int ret = NetLocalGroupAddMembers( NULL, groupName.c_str(), 3, (LPBYTE )&gmember, 1);
|
|
|
if (!(ret == NERR_Success || ret == ERROR_MEMBER_IN_ALIAS))
|
|
|
return 1;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int
|
|
|
delUserFromGroup( const mystring& userName, const mystring& groupName) {
|
|
|
LOCALGROUP_MEMBERS_INFO_3 gmember;
|
|
|
gmember.lgrmi3_domainandname = (LPWSTR) userName.c_str();
|
|
|
int ret = NetLocalGroupDelMembers( NULL, groupName.c_str(), 3, (LPBYTE )&gmember, 1);
|
|
|
if (!(ret == NERR_Success || ret == ERROR_MEMBER_IN_ALIAS))
|
|
|
return 1;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
int addGroup( const mystring& groupName) {
|
|
|
LOCALGROUP_INFO_0 gent;
|
|
|
gent.lgrpi0_name = _wcsdup( groupName.c_str());
|
|
|
int ret = NetLocalGroupAdd( NULL, 0, (LPBYTE )&gent, NULL);
|
|
|
free( gent.lgrpi0_name);
|
|
|
if (!(ret == NERR_Success || ret == NERR_GroupExists || ret == ERROR_ALIAS_EXISTS)) {
|
|
|
return 1;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int
|
|
|
addUser( const mystring& userName) {
|
|
|
USER_INFO_1 ui;
|
|
|
|
|
|
ui.usri1_name = (LPWSTR) userName.c_str();
|
|
|
ui.usri1_password = L"xyzzy";
|
|
|
ui.usri1_flags = UF_SCRIPT | UF_PASSWD_CANT_CHANGE | UF_ACCOUNTDISABLE;
|
|
|
|
|
|
ui.usri1_script_path = NULL;
|
|
|
ui.usri1_priv = USER_PRIV_USER;
|
|
|
ui.usri1_comment = NULL;
|
|
|
ui.usri1_home_dir = NULL;
|
|
|
ui.usri1_password_age = 0;
|
|
|
|
|
|
int ret = NetUserAdd( NULL,1, (LPBYTE )&ui, NULL);
|
|
|
return (!(ret == NERR_Success || ret == NERR_UserExists));
|
|
|
}
|
|
|
|
|
|
int addUser( const mystring& userName, const mystring& password, const mystring& homepath, const mystring& homedrive,
|
|
|
const mystring& profile, const mystring& script) {
|
|
|
USER_INFO_4 ui; /* INFO_3 f<>r 2000? */
|
|
|
|
|
|
memset( &ui, 0, sizeof( ui));
|
|
|
ui.usri4_name = (LPWSTR) userName.c_str();
|
|
|
ui.usri4_password = (LPWSTR) password.c_str();
|
|
|
ui.usri4_priv = USER_PRIV_USER;
|
|
|
ui.usri4_home_dir = (LPWSTR) homepath.c_str();
|
|
|
|
|
|
ui.usri4_flags = UF_SCRIPT | UF_PASSWD_CANT_CHANGE | UF_ACCOUNTDISABLE;
|
|
|
|
|
|
ui.usri4_script_path = (LPWSTR) script.c_str();
|
|
|
ui.usri4_max_storage = USER_MAXSTORAGE_UNLIMITED;
|
|
|
ui.usri4_country_code = 0; /* Arghhh! not documented*/
|
|
|
ui.usri4_code_page = 1252;
|
|
|
|
|
|
ui.usri4_primary_group_id = DOMAIN_GROUP_RID_USERS;
|
|
|
|
|
|
ui.usri4_profile = (LPWSTR) profile.c_str();
|
|
|
ui.usri4_home_dir_drive = (LPWSTR) homedrive.c_str();
|
|
|
int ret = NetUserAdd( NULL, 4, (LPBYTE )&ui, NULL);
|
|
|
return (!(ret == NERR_Success || ret == NERR_UserExists));
|
|
|
}
|
|
|
|
|
|
int modifyUser( const mystring& userName, const mystring& password, const mystring& homepath, const mystring& homedrive,
|
|
|
const mystring& profile, const mystring& script) {
|
|
|
LPUSER_INFO_4 ui = NULL;
|
|
|
if (NERR_Success == NetUserGetInfo( NULL, userName.c_str(), 4, (LPBYTE *)&ui)) {
|
|
|
ui->usri4_name = (LPWSTR) userName.c_str();
|
|
|
ui->usri4_home_dir = (LPWSTR) homepath.c_str();
|
|
|
|
|
|
ui->usri4_script_path = (LPWSTR) script.c_str();
|
|
|
|
|
|
ui->usri4_profile = (LPWSTR) profile.c_str();
|
|
|
ui->usri4_home_dir_drive = (LPWSTR) homedrive.c_str();
|
|
|
int ret = NetUserSetInfo( NULL, userName.c_str(), 4, (LPBYTE )ui, NULL);
|
|
|
return (!(ret == NERR_Success || ret == NERR_UserExists));
|
|
|
}
|
|
|
else {
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int
|
|
|
resetAccountExpiry( const mystring& userName, const mystring& password, FILE *fp) {
|
|
|
if (fp) {
|
|
|
fprintf( fp, "resetting account expiration for user '%S'\n", userName.c_str());
|
|
|
fflush(fp);
|
|
|
}
|
|
|
LPUSER_INFO_4 ui = NULL;
|
|
|
if (NERR_Success == NetUserGetInfo( NULL, userName.c_str(), 4, (LPBYTE *)&ui)) {
|
|
|
ui->usri4_acct_expires = (DWORD)time(0) + 10; /* only allow login for up to 10 seconds after Kerberized authentication */
|
|
|
//ui->usri4_acct_expires = TIMEQ_FOREVER;
|
|
|
ui->usri4_password = (LPWSTR) password.c_str();
|
|
|
ui->usri4_flags = (ui->usri4_flags & (~UF_ACCOUNTDISABLE)); /* ensure account is enabled */
|
|
|
int ret = NetUserSetInfo( NULL, userName.c_str(), 4, (LPBYTE )ui, NULL);
|
|
|
if (fp) {
|
|
|
fprintf( fp, "new time %d: commit returned %d\n", ui->usri4_acct_expires, ret);
|
|
|
fflush(fp);
|
|
|
}
|
|
|
return (!(ret == NERR_Success || ret == NERR_UserExists));
|
|
|
}
|
|
|
else {
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// return 1: User exists and disabled
|
|
|
// return 0: User exists and enabled
|
|
|
// return -1: User does not exist
|
|
|
int
|
|
|
isDisabledUser( const mystring& userName) {
|
|
|
|
|
|
// This API is sick
|
|
|
LPUSER_INFO_1 ui = NULL;
|
|
|
int flag = -1;
|
|
|
if (NERR_Success == NetUserGetInfo( NULL, userName.c_str(), 1, (LPBYTE *)&ui)) {
|
|
|
flag = (ui->usri1_flags & UF_ACCOUNTDISABLE) == UF_ACCOUNTDISABLE;
|
|
|
}
|
|
|
if (ui != NULL)
|
|
|
NetApiBufferFree( ui);
|
|
|
return flag;
|
|
|
}
|
|
|
|
|
|
int
|
|
|
delUser( const mystring& userName) {
|
|
|
return NetUserDel( NULL, userName.c_str());
|
|
|
}
|
|
|
|
|
|
stringSet
|
|
|
listGroups( const mystring& user) {
|
|
|
LPLOCALGROUP_USERS_INFO_0 pBuf = NULL;
|
|
|
LPLOCALGROUP_USERS_INFO_0 pTmpBuf;
|
|
|
|
|
|
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
|
|
|
DWORD dwEntriesRead = 0;
|
|
|
DWORD dwTotalEntries = 0;
|
|
|
|
|
|
DWORD i;
|
|
|
DWORD dwTotalCount = 0;
|
|
|
NET_API_STATUS nStatus;
|
|
|
stringSet groupList;
|
|
|
|
|
|
do
|
|
|
{
|
|
|
if (pBuf != NULL) {
|
|
|
NetApiBufferFree(pBuf);
|
|
|
pBuf = NULL;
|
|
|
}
|
|
|
nStatus = NetUserGetLocalGroups( NULL,
|
|
|
user.c_str(),
|
|
|
0,
|
|
|
0,
|
|
|
(LPBYTE*)&pBuf,
|
|
|
dwPrefMaxLen,
|
|
|
&dwEntriesRead,
|
|
|
&dwTotalEntries);
|
|
|
dwPrefMaxLen = dwTotalEntries;
|
|
|
// TODO: Endless loop possible?
|
|
|
} while (nStatus == ERROR_MORE_DATA);
|
|
|
//
|
|
|
// If the call succeeds,
|
|
|
//
|
|
|
if (nStatus == NERR_Success) {
|
|
|
if ((pTmpBuf = pBuf) != NULL) {
|
|
|
//
|
|
|
// Loop through the entries.
|
|
|
//
|
|
|
for (i = 0; (i < dwEntriesRead); i++) {
|
|
|
groupList.insert( mystring( pTmpBuf->lgrui0_name));
|
|
|
pTmpBuf++;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
return groupList;
|
|
|
}
|
|
|
//
|
|
|
// Free the allocated buffer.
|
|
|
//
|
|
|
if (pBuf != NULL)
|
|
|
{
|
|
|
NetApiBufferFree(pBuf);
|
|
|
pBuf = NULL;
|
|
|
}
|
|
|
|
|
|
return groupList;
|
|
|
}
|
|
|
|
|
|
|
|
|
stringSet
|
|
|
listUsers() {
|
|
|
LPUSER_INFO_0 pBuf = NULL;
|
|
|
LPUSER_INFO_0 pTmpBuf;
|
|
|
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
|
|
|
DWORD dwEntriesRead = 0;
|
|
|
DWORD dwTotalEntries = 0;
|
|
|
DWORD dwResumeHandle = 0;
|
|
|
DWORD i;
|
|
|
DWORD dwTotalCount = 0;
|
|
|
NET_API_STATUS nStatus;
|
|
|
stringSet userList;
|
|
|
//
|
|
|
// Call the NetUserEnum function, specifying level 0;
|
|
|
// enumerate global user account types only.
|
|
|
//
|
|
|
do // begin do
|
|
|
{
|
|
|
if (pBuf != NULL) {
|
|
|
NetApiBufferFree(pBuf);
|
|
|
pBuf = NULL;
|
|
|
}
|
|
|
nStatus = NetUserEnum( NULL,
|
|
|
0,
|
|
|
FILTER_NORMAL_ACCOUNT, // global users
|
|
|
(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++)
|
|
|
{
|
|
|
userList.insert( mystring( pTmpBuf->usri0_name));
|
|
|
pTmpBuf++;
|
|
|
dwTotalCount++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
else
|
|
|
return userList;
|
|
|
//
|
|
|
// Free 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);
|
|
|
|
|
|
return userList;
|
|
|
} |