mirror of https://github.com/tongzx/nt5src
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.
2692 lines
59 KiB
2692 lines
59 KiB
/*++
|
|
|
|
Copyright (c) 1993-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
nwnetapi.c
|
|
|
|
Abstract:
|
|
|
|
|
|
Author:
|
|
|
|
Arthur Hanson (arth) 16-Jun-1994
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "globals.h"
|
|
|
|
#include <nwapi32.h>
|
|
#include "nwconv.h"
|
|
#include "convapi.h"
|
|
#include "nwnetapi.h"
|
|
#include "statbox.h"
|
|
|
|
#define SUPERVISOR "SUPERVISOR"
|
|
#define ACCOUNT_LOCKOUT "ACCT_LOCKOUT"
|
|
#define GROUP_MEMBERS "GROUP_MEMBERS"
|
|
#define GROUPS_IM_IN "GROUPS_I'M_IN"
|
|
#define IDENTIFICATION "IDENTIFICATION"
|
|
#define LOGIN_CONTROL "LOGIN_CONTROL"
|
|
#define PS_OPERATORS "PS_OPERATORS"
|
|
#define SECURITY_EQUALS "SECURITY_EQUALS"
|
|
#define USER_DEFAULTS "USER_DEFAULTS"
|
|
#define MS_EXTENDED_NCPS "MS_EXTENDED_NCPS"
|
|
#define FPNW_PDC "FPNWPDC"
|
|
|
|
#ifdef DEBUG
|
|
int ErrorBoxRetry(LPTSTR szFormat, ...);
|
|
#endif
|
|
|
|
// Couple of NetWare specific data structures - see NetWare programming books for
|
|
// info on these structures
|
|
#pragma pack(1)
|
|
typedef struct tagLoginControl {
|
|
BYTE byAccountExpires[3];
|
|
BYTE byAccountDisabled;
|
|
BYTE byPasswordExpires[3];
|
|
BYTE byGraceLogins;
|
|
WORD wPasswordInterval;
|
|
BYTE byGraceLoginReset;
|
|
BYTE byMinPasswordLength;
|
|
WORD wMaxConnections;
|
|
BYTE byLoginTimes[42];
|
|
BYTE byLastLogin[6];
|
|
BYTE byRestrictions;
|
|
BYTE byUnused;
|
|
long lMaxDiskBlocks;
|
|
WORD wBadLogins;
|
|
LONG lNextResetTime;
|
|
BYTE byBadLoginAddr[12];
|
|
}; // tagLoginControl
|
|
#pragma pack()
|
|
|
|
|
|
typedef struct tagAccountBalance {
|
|
long lBalance;
|
|
long lCreditLimit;
|
|
}; // tagAccountBalance
|
|
|
|
|
|
typedef struct tagUserDefaults {
|
|
BYTE byAccountExpiresYear;
|
|
BYTE byAccountExpiresMonth;
|
|
BYTE byAccountExpiresDay;
|
|
BYTE byRestrictions;
|
|
WORD wPasswordInterval;
|
|
BYTE byGraceLoginReset;
|
|
BYTE byMinPasswordLength;
|
|
WORD wMaxConnections;
|
|
BYTE byLoginTimes[42];
|
|
long lBalance;
|
|
long lCreditLimit;
|
|
long lMaxDiskBlocks;
|
|
}; // tagUserDefaults
|
|
|
|
|
|
// define the mapping for FILE objects. Note: we only use GENERIC and
|
|
// STANDARD bits!
|
|
RIGHTS_MAPPING FileRightsMapping = {
|
|
0,
|
|
{ FILE_GENERIC_READ,
|
|
FILE_GENERIC_WRITE,
|
|
FILE_GENERIC_EXECUTE,
|
|
FILE_ALL_ACCESS
|
|
},
|
|
{ { NW_FILE_READ, GENERIC_READ},
|
|
{ NW_FILE_WRITE, GENERIC_WRITE},
|
|
{ NW_FILE_CREATE, 0},
|
|
{ NW_FILE_DELETE, GENERIC_WRITE|DELETE},
|
|
{ NW_FILE_PERM, WRITE_DAC},
|
|
{ NW_FILE_SCAN, 0},
|
|
{ NW_FILE_MODIFY, GENERIC_WRITE},
|
|
{ NW_FILE_SUPERVISOR, GENERIC_ALL},
|
|
{ 0, 0 }
|
|
}
|
|
} ;
|
|
|
|
RIGHTS_MAPPING DirRightsMapping = {
|
|
CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
|
|
{ FILE_GENERIC_READ,
|
|
FILE_GENERIC_WRITE,
|
|
FILE_GENERIC_EXECUTE,
|
|
FILE_ALL_ACCESS
|
|
},
|
|
{ { NW_FILE_READ, GENERIC_READ|GENERIC_EXECUTE},
|
|
{ NW_FILE_WRITE, GENERIC_WRITE},
|
|
{ NW_FILE_CREATE, GENERIC_WRITE},
|
|
{ NW_FILE_DELETE, DELETE},
|
|
{ NW_FILE_PERM, WRITE_DAC},
|
|
{ NW_FILE_SCAN, GENERIC_READ},
|
|
{ NW_FILE_MODIFY, GENERIC_WRITE},
|
|
{ NW_FILE_SUPERVISOR, GENERIC_ALL},
|
|
{ 0, 0 }
|
|
}
|
|
} ;
|
|
|
|
VOID UserInfoLog(LPTSTR UserName, struct tagLoginControl tag);
|
|
VOID Moveit(NWCONN_HANDLE Conn, LPTSTR UserName);
|
|
VOID UserRecInit(NT_USER_INFO *UserInfo);
|
|
BOOL IsNCPServerFPNW(NWCONN_HANDLE Conn);
|
|
|
|
static NWCONN_HANDLE CachedConn = 0;
|
|
|
|
static TCHAR CachedServer[MAX_SERVER_NAME_LEN + 1];
|
|
static DWORD CachedServerTime = 0xffffffff; // minutes since 1985...
|
|
|
|
typedef struct _PRINT_SERVER_BUFFER {
|
|
TCHAR Name[20];
|
|
} PRINT_SERVER_BUFFER;
|
|
|
|
typedef struct _PRINT_SERVER_LIST {
|
|
ULONG Count;
|
|
PRINT_SERVER_BUFFER PSList[];
|
|
} PRINT_SERVER_LIST;
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
int
|
|
NWGetMaxServerNameLen()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
return MAX_SERVER_NAME_LEN;
|
|
|
|
} // NWGetMaxServerNameLen
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
int
|
|
NWGetMaxUserNameLen()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
return MAX_USER_NAME_LEN;
|
|
|
|
} // NWGetMaxUserNameLen
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWServerFree()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if (CachedConn)
|
|
NWDetachFromFileServer(CachedConn);
|
|
|
|
CachedConn = 0;
|
|
|
|
return (0);
|
|
|
|
} // NWServerFree
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWServerSet(
|
|
LPTSTR FileServer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
NWLOCAL_SCOPE ScopeFlag = 0;
|
|
NWCONN_HANDLE Conn = 0;
|
|
NWCCODE ret = 0;
|
|
char szAnsiFileServer[MAX_SERVER_NAME_LEN + 1];
|
|
|
|
NWServerFree();
|
|
|
|
lstrcpy(CachedServer, FileServer);
|
|
CharToOem(FileServer, szAnsiFileServer);
|
|
|
|
ret = NWAttachToFileServer(szAnsiFileServer, ScopeFlag, &Conn);
|
|
|
|
if (!ret) {
|
|
CachedConn = Conn;
|
|
NWServerTimeGet();
|
|
}
|
|
|
|
return ((DWORD) ret);
|
|
|
|
} // NWServerSet
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWUseDel(
|
|
LPTSTR ServerName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
static TCHAR LocServer[MAX_SERVER_NAME_LEN+3];
|
|
|
|
NWServerFree();
|
|
wsprintf(LocServer, Lids(IDS_S_27), ServerName);
|
|
WNetCancelConnection2(LocServer, 0, FALSE);
|
|
|
|
} // NWUseDel
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
NWUserNameValidate(
|
|
LPTSTR szUserName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR UserName[MAX_USER_NAME_LEN + 1];
|
|
DWORD Size;
|
|
|
|
// if same as logged on user then don't convert or overwrite
|
|
Size = sizeof(UserName);
|
|
WNetGetUser(NULL, UserName, &Size);
|
|
if (!lstrcmpi(szUserName, UserName))
|
|
return FALSE;
|
|
|
|
// Now check for other special names
|
|
if (!lstrcmpi(szUserName, Lids(IDS_S_28)))
|
|
return FALSE;
|
|
|
|
if (!lstrcmpi(szUserName, Lids(IDS_S_29)))
|
|
return FALSE;
|
|
|
|
if (!lstrcmpi(szUserName, Lids(IDS_S_30)))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
|
|
} // NWUserNameValidate
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
NWGroupNameValidate(
|
|
LPTSTR szGroupName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if (!lstrcmpi(szGroupName, Lids(IDS_S_31)))
|
|
return FALSE;
|
|
|
|
if (!lstrcmpi(szGroupName, Lids(IDS_S_28)))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
|
|
} // NWGroupNameValidate
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
LPTSTR
|
|
NWSpecialNamesMap(
|
|
LPTSTR Name
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
static BOOL InitStrings = FALSE;
|
|
static LPTSTR SpecialNames[5];
|
|
static LPTSTR SpecialMap[5];
|
|
|
|
if (!InitStrings) {
|
|
InitStrings = TRUE;
|
|
SpecialNames[0] = Lids(IDS_S_28);
|
|
SpecialNames[1] = Lids(IDS_S_30);
|
|
SpecialNames[2] = Lids(IDS_S_31);
|
|
SpecialNames[3] = Lids(IDS_S_29);
|
|
SpecialNames[4] = NULL;
|
|
|
|
SpecialMap[0] = Lids(IDS_S_32);
|
|
SpecialMap[1] = Lids(IDS_S_32);
|
|
SpecialMap[2] = Lids(IDS_S_33);
|
|
SpecialMap[3] = Lids(IDS_S_29);
|
|
SpecialMap[4] = NULL;
|
|
}
|
|
|
|
i = 0;
|
|
while(SpecialNames[i] != NULL) {
|
|
if (!lstrcmpi(SpecialNames[i], Name)) {
|
|
return SpecialMap[i];
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return Name;
|
|
|
|
} // NWSpecialNamesMap
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
NWIsAdmin(
|
|
LPTSTR UserName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
char szAnsiUserName[MAX_USER_NAME_LEN];
|
|
NWCCODE ret;
|
|
|
|
CharToOem(UserName, szAnsiUserName);
|
|
ret = NWIsObjectInSet(CachedConn, szAnsiUserName, OT_USER, SECURITY_EQUALS,
|
|
SUPERVISOR, OT_USER);
|
|
|
|
if (ret == SUCCESSFUL)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
|
|
} // NWIsAdmin
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
NWObjectNameGet(
|
|
DWORD ObjectID,
|
|
LPTSTR ObjectName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
char szAnsiObjectName[MAX_USER_NAME_LEN + 1];
|
|
WORD wFoundUserType = 0;
|
|
NWCCODE ret;
|
|
|
|
lstrcpy(ObjectName, TEXT(""));
|
|
|
|
if (!(ret = NWGetObjectName(CachedConn, ObjectID, szAnsiObjectName, &wFoundUserType))) {
|
|
|
|
//
|
|
// Got user - now convert and save off the information
|
|
//
|
|
OemToChar(szAnsiObjectName, ObjectName);
|
|
}
|
|
|
|
if (ret == SUCCESSFUL)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
|
|
} // NWObjectNameGet
|
|
|
|
|
|
#define DEF_NUM_RECS 200
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWUsersEnum(
|
|
USER_LIST **lpUsers,
|
|
BOOL Display
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
USER_LIST *Users = NULL;
|
|
USER_BUFFER *UserBuffer = NULL;
|
|
DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
|
|
DWORD Count = 0;
|
|
DWORD status = 0;
|
|
char szAnsiUserName[MAX_USER_NAME_LEN + 1];
|
|
TCHAR szUserName[MAX_USER_NAME_LEN + 1];
|
|
WORD wFoundUserType = 0;
|
|
DWORD dwObjectID = 0xFFFFFFFFL;
|
|
BYTE byPropertiesFlag = 0;
|
|
BYTE byObjectFlag = 0;
|
|
BYTE byObjectSecurity = 0;
|
|
NWCCODE ret;
|
|
|
|
if (Display)
|
|
Status_ItemLabel(Lids(IDS_S_44));
|
|
|
|
Users = (USER_LIST *) AllocMemory(sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
UserBuffer = Users->UserBuffer;
|
|
|
|
// init to NULL so doesn't have garbage if call fails
|
|
lstrcpyA(szAnsiUserName, "");
|
|
|
|
// Loop through bindery getting all the users.
|
|
while ((ret = NWScanObject(CachedConn, "*", OT_USER, &dwObjectID, szAnsiUserName,
|
|
&wFoundUserType, &byPropertiesFlag,
|
|
&byObjectFlag, &byObjectSecurity)) == SUCCESSFUL) {
|
|
|
|
// Got user - now convert and save off the information
|
|
OemToChar(szAnsiUserName, szUserName);
|
|
|
|
if (NWUserNameValidate(szUserName)) {
|
|
if (Display)
|
|
Status_Item(szUserName);
|
|
|
|
lstrcpy(UserBuffer[Count].Name, szUserName);
|
|
lstrcpy(UserBuffer[Count].NewName, szUserName);
|
|
Count++;
|
|
}
|
|
|
|
// Check if we have to re-allocate buffer
|
|
if (Count >= NumRecs) {
|
|
NumRecs += DEF_NUM_RECS;
|
|
Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
UserBuffer = Users->UserBuffer;
|
|
}
|
|
|
|
}
|
|
|
|
// Gotta clear this out from the last loop
|
|
if (Count)
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
// check if error occured...
|
|
if (ret)
|
|
status = ret;
|
|
|
|
// Now slim down the list to just what we need.
|
|
if (!status) {
|
|
Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER)* Count));
|
|
|
|
if (!Users)
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
else {
|
|
// Sort the server list before putting it in the dialog
|
|
UserBuffer = Users->UserBuffer;
|
|
qsort((void *) UserBuffer, (size_t) Count, sizeof(USER_BUFFER), UserListCompare);
|
|
}
|
|
}
|
|
|
|
if (Users != NULL)
|
|
Users->Count = Count;
|
|
|
|
*lpUsers = Users;
|
|
|
|
return status;
|
|
|
|
} // NWUsersEnum
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWGroupsEnum(
|
|
GROUP_LIST **lpGroups,
|
|
BOOL Display
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
GROUP_LIST *Groups = NULL;
|
|
GROUP_BUFFER *GroupBuffer;
|
|
DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
|
|
DWORD Count = 0;
|
|
DWORD status = 0;
|
|
char szAnsiGroupName[MAX_GROUP_NAME_LEN + 1];
|
|
TCHAR szGroupName[MAX_GROUP_NAME_LEN + 1];
|
|
WORD wFoundGroupType = 0;
|
|
DWORD dwObjectID = 0xFFFFFFFFL;
|
|
BYTE byPropertiesFlag = 0;
|
|
BYTE byObjectFlag = 0;
|
|
BYTE byObjectSecurity = 0;
|
|
NWCCODE ret;
|
|
|
|
if (Display)
|
|
Status_ItemLabel(Lids(IDS_S_45));
|
|
|
|
Groups = (GROUP_LIST *) AllocMemory(sizeof(GROUP_LIST) + (sizeof(GROUP_BUFFER) * NumRecs));
|
|
|
|
if (!Groups) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
GroupBuffer = Groups->GroupBuffer;
|
|
|
|
// init to NULL so doesn't have garbage if call fails
|
|
lstrcpyA(szAnsiGroupName, "");
|
|
|
|
// Loop through bindery getting all the users.
|
|
while ((ret = NWScanObject(CachedConn, "*", OT_USER_GROUP, &dwObjectID, szAnsiGroupName,
|
|
&wFoundGroupType, &byPropertiesFlag,
|
|
&byObjectFlag, &byObjectSecurity)) == SUCCESSFUL) {
|
|
|
|
// Got user - now convert and save off the information
|
|
OemToChar(szAnsiGroupName, szGroupName);
|
|
|
|
if (NWGroupNameValidate(szGroupName)) {
|
|
if (Display)
|
|
Status_Item(szGroupName);
|
|
|
|
lstrcpy(GroupBuffer[Count].Name, szGroupName);
|
|
lstrcpy(GroupBuffer[Count].NewName, szGroupName);
|
|
Count++;
|
|
}
|
|
|
|
// Check if we have to re-allocate buffer
|
|
if (Count >= NumRecs) {
|
|
NumRecs += DEF_NUM_RECS;
|
|
Groups = (GROUP_LIST *) ReallocMemory((HGLOBAL) Groups, sizeof(GROUP_LIST) + (sizeof(GROUP_BUFFER) * NumRecs));
|
|
|
|
if (!Groups) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
GroupBuffer = Groups->GroupBuffer;
|
|
}
|
|
|
|
}
|
|
|
|
// Gotta clear this out from the last loop
|
|
if (Count)
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
// check if error occured...
|
|
if (ret)
|
|
status = ret;
|
|
|
|
// Now slim down the list to just what we need.
|
|
if (!status) {
|
|
Groups = (GROUP_LIST *) ReallocMemory((HGLOBAL) Groups, sizeof(GROUP_LIST) + (sizeof(GROUP_BUFFER) * Count));
|
|
|
|
if (!Groups)
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
else {
|
|
// Sort the server list before putting it in the dialog
|
|
GroupBuffer = Groups->GroupBuffer;
|
|
qsort((void *) GroupBuffer, (size_t) Count, sizeof(GROUP_BUFFER), UserListCompare);
|
|
}
|
|
}
|
|
|
|
if (Groups != NULL)
|
|
Groups->Count = Count;
|
|
|
|
*lpGroups = Groups;
|
|
|
|
return status;
|
|
|
|
} // NWGroupsEnum
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWGroupUsersEnum(
|
|
LPTSTR GroupName,
|
|
USER_LIST **lpUsers
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
USER_LIST *Users = NULL;
|
|
USER_BUFFER *UserBuffer;
|
|
DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
|
|
DWORD Count = 0;
|
|
DWORD i = 0;
|
|
DWORD status = 0;
|
|
char szAnsiUserName[MAX_USER_NAME_LEN + 1];
|
|
char szAnsiGroupName[MAX_GROUP_NAME_LEN + 1];
|
|
TCHAR szUserName[MAX_USER_NAME_LEN + 1];
|
|
WORD wFoundUserType = 0;
|
|
BYTE byPropertyFlags = 0;
|
|
BYTE byObjectFlag = 0;
|
|
BYTE byObjectSecurity = 0;
|
|
UCHAR Segment = 1;
|
|
DWORD bySegment[32];
|
|
BYTE byMoreSegments;
|
|
NWCCODE ret;
|
|
|
|
Users = (USER_LIST *) AllocMemory(sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
UserBuffer = Users->UserBuffer;
|
|
|
|
// init to NULL so doesn't have garbage if call fails
|
|
lstrcpyA(szAnsiUserName, "");
|
|
CharToOem(GroupName, szAnsiGroupName);
|
|
|
|
// Loop through bindery getting all the users.
|
|
do {
|
|
if (!(ret = NWReadPropertyValue(CachedConn, szAnsiGroupName, OT_USER_GROUP, GROUP_MEMBERS,
|
|
Segment, (BYTE *) bySegment, &byMoreSegments, &byPropertyFlags))) {
|
|
|
|
Segment++;
|
|
// loop through properties converting them to user names
|
|
i = 0;
|
|
while ((bySegment[i]) && (i < 32)) {
|
|
if (!(ret = NWGetObjectName(CachedConn, bySegment[i], szAnsiUserName, &wFoundUserType))) {
|
|
// Got user - now convert and save off the information
|
|
OemToChar(szAnsiUserName, szUserName);
|
|
|
|
lstrcpy(UserBuffer[Count].Name, szUserName);
|
|
lstrcpy(UserBuffer[Count].NewName, szUserName);
|
|
Count++;
|
|
|
|
// Check if we have to re-allocate buffer
|
|
if (Count >= NumRecs) {
|
|
NumRecs += DEF_NUM_RECS;
|
|
Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
UserBuffer = Users->UserBuffer;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
} else // if NWReadPropertyValue
|
|
byMoreSegments = 0;
|
|
|
|
} while (byMoreSegments);
|
|
|
|
// Gotta clear this out from the last loop
|
|
if (Count)
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
// check if error occured...
|
|
if (ret)
|
|
status = ret;
|
|
|
|
// Now slim down the list to just what we need.
|
|
if (!status) {
|
|
Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * Count));
|
|
|
|
if (!Users)
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
else {
|
|
// Sort the server list before putting it in the dialog
|
|
UserBuffer = Users->UserBuffer;
|
|
qsort((void *) UserBuffer, (size_t) Count, sizeof(USER_BUFFER), UserListCompare);
|
|
}
|
|
}
|
|
|
|
if (Users != NULL)
|
|
Users->Count = Count;
|
|
|
|
*lpUsers = Users;
|
|
|
|
return status;
|
|
|
|
} // NWGroupUsersEnum
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWUserEquivalenceEnum(
|
|
LPTSTR UserName,
|
|
USER_LIST **lpUsers
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
USER_LIST *Users;
|
|
USER_BUFFER *UserBuffer;
|
|
DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
|
|
DWORD Count = 0;
|
|
DWORD i = 0;
|
|
DWORD status = 0;
|
|
char szAnsiUserName[MAX_USER_NAME_LEN + 1];
|
|
char szAnsiName[MAX_GROUP_NAME_LEN + 1];
|
|
TCHAR szUserName[MAX_USER_NAME_LEN + 1];
|
|
WORD wFoundUserType = 0;
|
|
DWORD dwObjectID = 0xFFFFFFFFL;
|
|
BYTE byPropertyFlags = 0;
|
|
BYTE byObjectFlag = 0;
|
|
BYTE byObjectSecurity = 0;
|
|
UCHAR Segment = 1;
|
|
DWORD bySegment[32];
|
|
BYTE byMoreSegments;
|
|
NWCCODE ret;
|
|
|
|
Users = (USER_LIST *) AllocMemory(sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
UserBuffer = Users->UserBuffer;
|
|
|
|
// init to NULL so doesn't have garbage if call fails
|
|
lstrcpyA(szAnsiUserName, "");
|
|
CharToOem(UserName, szAnsiName);
|
|
|
|
// Loop through bindery getting all the users.
|
|
do {
|
|
if (!(ret = NWReadPropertyValue(CachedConn, szAnsiName, OT_USER, SECURITY_EQUALS,
|
|
Segment, (BYTE *) bySegment, &byMoreSegments, &byPropertyFlags))) {
|
|
|
|
Segment++;
|
|
// loop through properties converting them to user names
|
|
i = 0;
|
|
while ((bySegment[i]) && (i < 32)) {
|
|
if (!(ret = NWGetObjectName(CachedConn, bySegment[i], szAnsiUserName, &wFoundUserType))) {
|
|
// Got user - now convert and save off the information
|
|
OemToChar(szAnsiUserName, szUserName);
|
|
|
|
// Map out Everyone equivalence
|
|
if (lstrcmpi(szUserName, Lids(IDS_S_31))) {
|
|
lstrcpy(UserBuffer[Count].Name, szUserName);
|
|
lstrcpy(UserBuffer[Count].NewName, szUserName);
|
|
Count++;
|
|
}
|
|
|
|
// Check if we have to re-allocate buffer
|
|
if (Count >= NumRecs) {
|
|
NumRecs += DEF_NUM_RECS;
|
|
Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
UserBuffer = Users->UserBuffer;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
} else // if NWReadPropertyValue
|
|
byMoreSegments = 0;
|
|
|
|
} while (byMoreSegments);
|
|
|
|
// Gotta clear this out from the last loop
|
|
if (Count)
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
// check if error occured...
|
|
if (ret)
|
|
status = ret;
|
|
|
|
// Now slim down the list to just what we need.
|
|
if (!status) {
|
|
Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * Count));
|
|
|
|
if (!Users)
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
else {
|
|
// Sort the server list before putting it in the dialog
|
|
UserBuffer = Users->UserBuffer;
|
|
qsort((void *) UserBuffer, (size_t) Count, sizeof(USER_BUFFER), UserListCompare);
|
|
}
|
|
}
|
|
|
|
if (Users != NULL)
|
|
Users->Count = Count;
|
|
|
|
*lpUsers = Users;
|
|
|
|
return status;
|
|
|
|
} // NWUserEquivalenceEnum
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWFileRightsEnum(
|
|
LPTSTR FileName,
|
|
USER_RIGHTS_LIST **lpUsers,
|
|
DWORD *UserCount,
|
|
BOOL DownLevel
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL Continue = TRUE;
|
|
USER_RIGHTS_LIST *Users = NULL;
|
|
DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
|
|
DWORD Count = 0;
|
|
DWORD i = 0;
|
|
DWORD status = 0;
|
|
char szAnsiUserName[MAX_USER_NAME_LEN + 1];
|
|
char szAnsiSearchDir[MAX_PATH + 1];
|
|
TCHAR szUserName[MAX_USER_NAME_LEN + 1];
|
|
WORD wFoundUserType = 0;
|
|
NWCCODE ret;
|
|
char FoundDir[16];
|
|
ULONG Entries;
|
|
|
|
TRUSTEE_INFO ti[20];
|
|
BYTE DirHandle, nDirHandle;
|
|
BYTE Sequence;
|
|
BYTE NumEntries = 0;
|
|
NWDATE_TIME dtime = 0;
|
|
NWOBJ_ID ownerID = 0;
|
|
|
|
if (DownLevel) {
|
|
Entries = 5;
|
|
Sequence = 1;
|
|
} else {
|
|
Entries = 20;
|
|
Sequence = 0;
|
|
}
|
|
|
|
DirHandle = nDirHandle = 0;
|
|
memset(ti, 0, sizeof(ti));
|
|
|
|
Users = (USER_RIGHTS_LIST *) AllocMemory(NumRecs * sizeof(USER_RIGHTS_LIST));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
|
|
// init to NULL so doesn't have garbage if call fails
|
|
lstrcpyA(szAnsiUserName, "");
|
|
CharToOem(FileName, szAnsiSearchDir);
|
|
|
|
// Loop through bindery getting all the users.
|
|
do {
|
|
if (DownLevel)
|
|
ret = NWCScanDirectoryForTrustees2(CachedConn, nDirHandle, szAnsiSearchDir,
|
|
&Sequence, FoundDir, &dtime, &ownerID, ti);
|
|
else
|
|
ret = NWCScanForTrustees(CachedConn, nDirHandle, szAnsiSearchDir,
|
|
&Sequence, &NumEntries, ti);
|
|
|
|
if (!ret) {
|
|
// loop through properties converting them to user names
|
|
for (i = 0; i < Entries; i++) {
|
|
if (ti[i].objectID != 0) {
|
|
if (!(ret = NWGetObjectName(CachedConn, ti[i].objectID, szAnsiUserName, &wFoundUserType))) {
|
|
// Got user - now convert and save off the information
|
|
OemToChar(szAnsiUserName, szUserName);
|
|
|
|
lstrcpy(Users[Count].Name, szUserName);
|
|
Users[Count].Rights = ti[i].objectRights;
|
|
Count++;
|
|
|
|
// Check if we have to re-allocate buffer
|
|
if (Count >= NumRecs) {
|
|
NumRecs += DEF_NUM_RECS;
|
|
Users = (USER_RIGHTS_LIST *) ReallocMemory((HGLOBAL) Users, NumRecs * sizeof(USER_RIGHTS_LIST));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
} // if realloc buffer
|
|
}
|
|
} // if objectID != 0
|
|
}
|
|
|
|
} else // NWScan failed
|
|
Continue = FALSE;
|
|
|
|
} while (Continue);
|
|
|
|
// Gotta clear this out from the last loop
|
|
if (Count)
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
// check if error occured...
|
|
if (ret) {
|
|
status = ret;
|
|
|
|
if (Users != NULL) {
|
|
FreeMemory(Users);
|
|
Count = 0;
|
|
}
|
|
}
|
|
|
|
// Now slim down the list to just what we need.
|
|
if (!status) {
|
|
Users = (USER_RIGHTS_LIST *) ReallocMemory((HGLOBAL) Users, Count * sizeof(USER_RIGHTS_LIST));
|
|
|
|
if (!Users)
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
else
|
|
// Sort the server list before putting it in the dialog
|
|
qsort((void *) Users, (size_t) Count, sizeof(USER_RIGHTS_LIST), UserListCompare);
|
|
}
|
|
|
|
*UserCount = Count;
|
|
*lpUsers = Users;
|
|
|
|
return status;
|
|
|
|
} // NWFileRightsEnum
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWLoginTimesMap(
|
|
BYTE *Times,
|
|
BYTE *NewTimes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD i, j;
|
|
int Bit = 0;
|
|
int Val;
|
|
BYTE BitSet;
|
|
|
|
for (i = 0; i < 21; i++) {
|
|
BitSet = 0;
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
if (BitTest(Bit, Times) || BitTest(Bit+1, Times)) {
|
|
Val = 0x1 << j;
|
|
BitSet = BitSet + (BYTE) Val;
|
|
}
|
|
|
|
Bit++; Bit++;
|
|
}
|
|
|
|
NewTimes[i] = BitSet;
|
|
}
|
|
|
|
|
|
} // NWLoginTimesMap
|
|
|
|
|
|
/*+-------------------------------------------------------------------------+
|
|
| Time Conversion |
|
|
+-------------------------------------------------------------------------+*/
|
|
|
|
#define IS_LEAP(y) ((y % 4 == 0) && (y % 100 != 0 || y % 400 == 0))
|
|
#define DAYS_IN_YEAR(y) (IS_LEAP(y) ? 366 : 365)
|
|
#define DAYS_IN_MONTH(m,y) (IS_LEAP(y) ? _days_month_leap[m] : _days_month[m])
|
|
#define SECS_IN_DAY (60L * 60L * 24L)
|
|
#define SECS_IN_HOUR (60L * 60L)
|
|
#define SECS_IN_MINUTE (60L)
|
|
|
|
static short _days_month_leap[] = { 31,29,31,30,31,30,31,31,30,31,30,31 };
|
|
static short _days_month[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
NWTimeMap(
|
|
DWORD Days,
|
|
DWORD dwMonth,
|
|
DWORD dwYear,
|
|
DWORD dwBasis,
|
|
ULONG *Time
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dw = 0;
|
|
DWORD dwDays = 0;
|
|
|
|
// Zero
|
|
*Time = 0L;
|
|
|
|
// Adjust year
|
|
if(dwYear < 70)
|
|
dwYear += 2000L;
|
|
else
|
|
if(dwYear < 100)
|
|
dwYear += 1900L;
|
|
|
|
if (dwYear < dwBasis)
|
|
return FALSE;
|
|
|
|
// Calculate days in previous years, take -1 so we skip current year
|
|
dw = dwYear - 1;
|
|
while(dw >= dwBasis) {
|
|
dwDays += DAYS_IN_YEAR(dw);
|
|
--dw;
|
|
}
|
|
|
|
// Days from month
|
|
if((dwMonth < 1)||(dwMonth > 12))
|
|
return FALSE;
|
|
|
|
// Loop through adding number of days in each month. Take -2 (-1 to skip
|
|
// current month, and -1 to make 0 based).
|
|
dw = dwMonth;
|
|
while(dw > 1) {
|
|
dwDays += DAYS_IN_MONTH(dw-2, dwYear);
|
|
--dw;
|
|
}
|
|
|
|
// Convert days
|
|
dw = Days;
|
|
if((dw >= 1) && (dw <= (DWORD) DAYS_IN_MONTH(dwMonth - 1, dwYear)))
|
|
dwDays += dw;
|
|
else
|
|
return FALSE; // out of range
|
|
|
|
*Time += dwDays * SECS_IN_DAY;
|
|
return TRUE;
|
|
} // NWTimeMap
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
LPTSTR
|
|
NWUserNameGet(
|
|
LPTSTR szUserName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
static TCHAR UserName[128];
|
|
char szAnsiUserName[MAX_USER_NAME_LEN];
|
|
NWCCODE ret;
|
|
BYTE bySegment[128];
|
|
BYTE byMoreSegments, byPropertyFlags;
|
|
LPSTR szAnsiFullName;
|
|
|
|
CharToOem(szUserName, szAnsiUserName);
|
|
ret = NWReadPropertyValue(CachedConn, szAnsiUserName, OT_USER, IDENTIFICATION,
|
|
1, bySegment, &byMoreSegments, &byPropertyFlags);
|
|
|
|
if (ret == SUCCESSFUL) {
|
|
szAnsiFullName = (LPSTR) bySegment;
|
|
OemToChar(szAnsiFullName, UserName);
|
|
return UserName;
|
|
}
|
|
|
|
return NULL;
|
|
|
|
} // NWUserNameGet
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWNetUserMapInfo (
|
|
LPTSTR szUserName,
|
|
VOID *UInfo,
|
|
NT_USER_INFO *NT_UInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG expires;
|
|
struct tagLoginControl *tag;
|
|
LPTSTR FullName;
|
|
|
|
tag = (struct tagLoginControl *) UInfo;
|
|
|
|
FullName = NWUserNameGet(szUserName);
|
|
if (FullName != NULL)
|
|
lstrcpyn(NT_UInfo->full_name, FullName, MAXCOMMENTSZ);
|
|
|
|
// Account disabled
|
|
if (tag->byAccountDisabled)
|
|
NT_UInfo->flags = NT_UInfo->flags | 0x02;
|
|
|
|
// account locked out
|
|
if ((tag->wBadLogins == 0xffff) &&
|
|
(tag->lNextResetTime > (LONG)CachedServerTime))
|
|
NT_UInfo->flags = NT_UInfo->flags | 0x02; // disable account...
|
|
|
|
// user can change password
|
|
if ((tag->byRestrictions & 0x01))
|
|
NT_UInfo->flags = NT_UInfo->flags | 0x40;
|
|
|
|
NWLoginTimesMap(tag->byLoginTimes, NT_UInfo->logon_hours);
|
|
|
|
// account expires
|
|
if (tag->byAccountExpires[0] == 0)
|
|
NT_UInfo->acct_expires = TIMEQ_FOREVER;
|
|
else
|
|
if (tag->byAccountExpires[0] < 70)
|
|
NT_UInfo->acct_expires = 0;
|
|
else {
|
|
// fits within time range so convert to #seconds since 1970
|
|
expires = 0;
|
|
NWTimeMap((DWORD) tag->byAccountExpires[2],
|
|
(DWORD) tag->byAccountExpires[1],
|
|
(DWORD) tag->byAccountExpires[0], 1970, &expires);
|
|
NT_UInfo->acct_expires = expires;
|
|
}
|
|
|
|
} // NWNetUserMapInfo
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWFPNWMapInfo(
|
|
VOID *NWUInfo,
|
|
PFPNW_INFO fpnw
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
struct tagLoginControl *tag;
|
|
|
|
tag = (struct tagLoginControl *) NWUInfo;
|
|
|
|
fpnw->MaxConnections = tag->wMaxConnections;
|
|
fpnw->PasswordInterval = tag->wPasswordInterval;
|
|
fpnw->GraceLoginAllowed = tag->byGraceLogins;
|
|
fpnw->GraceLoginRemaining = tag->byGraceLoginReset;
|
|
fpnw->LoginFrom = NULL;
|
|
fpnw->HomeDir = NULL;
|
|
|
|
} // NWFPNWMapInfo
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWUserDefaultsGet(
|
|
VOID **UDefaults
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
struct tagUserDefaults *UserDefaults = NULL;
|
|
NWCCODE ret;
|
|
BYTE bySegment[128];
|
|
BYTE byMoreSegments, byPropertyFlags;
|
|
|
|
ret = NWReadPropertyValue(CachedConn, SUPERVISOR, OT_USER, USER_DEFAULTS, 1, bySegment, &byMoreSegments, &byPropertyFlags);
|
|
|
|
if (ret == SUCCESSFUL) {
|
|
UserDefaults = AllocMemory(sizeof(struct tagUserDefaults));
|
|
memcpy(UserDefaults, bySegment, sizeof (struct tagUserDefaults));
|
|
|
|
// Now put the data in 'normal' Intel format
|
|
SWAPBYTES(UserDefaults->wPasswordInterval);
|
|
SWAPBYTES(UserDefaults->wMaxConnections);
|
|
SWAPWORDS(UserDefaults->lBalance);
|
|
SWAPWORDS(UserDefaults->lCreditLimit);
|
|
SWAPWORDS(UserDefaults->lMaxDiskBlocks);
|
|
}
|
|
|
|
*UDefaults = (void *) UserDefaults;
|
|
|
|
} // NWUserDefaultsGet
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWUserDefaultsMap(
|
|
VOID *NWUDefaults,
|
|
NT_DEFAULTS *NTDefaults
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
struct tagUserDefaults *UserDefaults = NULL;
|
|
|
|
if ((NWUDefaults == NULL) || (NTDefaults == NULL))
|
|
return;
|
|
|
|
UserDefaults = (struct tagUserDefaults *) NWUDefaults;
|
|
|
|
NTDefaults->min_passwd_len = (DWORD) UserDefaults->byMinPasswordLength;
|
|
NTDefaults->max_passwd_age = (DWORD) UserDefaults->wPasswordInterval * 86400;
|
|
NTDefaults->force_logoff = (DWORD) UserDefaults->byGraceLoginReset;
|
|
|
|
// These fields aren't used/converted
|
|
// NTDefaults->min-passwd_age - no such thing for NetWare
|
|
// NTDefaults->password_hist_len - no such thing for NetWare
|
|
|
|
} // NWUserDefaultsMap
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWLoginTimesLog(
|
|
BYTE *Times
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR *szDays[7];
|
|
DWORD Day;
|
|
DWORD Hours;
|
|
int Bit = 0, i;
|
|
static TCHAR szHours[80];
|
|
|
|
szDays[0] = Lids(IDS_SUN);
|
|
szDays[1] = Lids(IDS_MON);
|
|
szDays[2] = Lids(IDS_TUE);
|
|
szDays[3] = Lids(IDS_WED);
|
|
szDays[4] = Lids(IDS_THU);
|
|
szDays[5] = Lids(IDS_FRI);
|
|
szDays[6] = Lids(IDS_SAT);
|
|
|
|
LogWriteLog(1, Lids(IDS_CRLF));
|
|
LogWriteLog(1, Lids(IDS_L_104));
|
|
|
|
// while these should be level 2, there isn't room on 80 cols - so level 1
|
|
LogWriteLog(1, Lids(IDS_L_1));
|
|
LogWriteLog(1, Lids(IDS_L_2));
|
|
LogWriteLog(1, Lids(IDS_L_3));
|
|
|
|
for (Day = 0; Day < 7; Day++) {
|
|
LogWriteLog(1, szDays[Day]);
|
|
lstrcpy(szHours, TEXT(" "));
|
|
|
|
for (Hours = 0; Hours < 24; Hours++) {
|
|
for (i = 0; i < 2; i++) {
|
|
if (BitTest(Bit, Times))
|
|
lstrcat(szHours, TEXT("*"));
|
|
else
|
|
lstrcat(szHours, TEXT(" "));
|
|
|
|
Bit++;
|
|
}
|
|
|
|
lstrcat(szHours, TEXT(" "));
|
|
}
|
|
|
|
LogWriteLog(0, szHours);
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
}
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
} // NWLoginTimesLog
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWUserDefaultsLog(
|
|
VOID *UDefaults
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
struct tagUserDefaults *tag;
|
|
|
|
tag = (struct tagUserDefaults *) UDefaults;
|
|
|
|
// Account expires
|
|
LogWriteLog(1, Lids(IDS_L_109));
|
|
if (tag->byAccountExpiresYear == 0)
|
|
LogWriteLog(0, Lids(IDS_L_107));
|
|
else
|
|
LogWriteLog(0, TEXT("%02u/%02u/%04u"), (UINT) tag->byAccountExpiresDay,
|
|
(UINT) tag->byAccountExpiresMonth, (UINT) 1900 + tag->byAccountExpiresYear);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// Restrictions
|
|
LogWriteLog(1, Lids(IDS_L_110));
|
|
// user can change password
|
|
if ((tag->byRestrictions & 0x01))
|
|
LogWriteLog(2, Lids(IDS_L_111));
|
|
else
|
|
LogWriteLog(2, Lids(IDS_L_112));
|
|
|
|
// unique password required
|
|
if ((tag->byRestrictions & 0x02))
|
|
LogWriteLog(2, Lids(IDS_L_113), Lids(IDS_YES));
|
|
else
|
|
LogWriteLog(2, Lids(IDS_L_113), Lids(IDS_NO));
|
|
|
|
// Password interval
|
|
LogWriteLog(1, Lids(IDS_L_114));
|
|
if (tag->wPasswordInterval == 0)
|
|
LogWriteLog(0, Lids(IDS_L_107));
|
|
else
|
|
LogWriteLog(0, TEXT("%u"), (UINT) tag->wPasswordInterval);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// Grace Logins
|
|
LogWriteLog(1, Lids(IDS_L_115));
|
|
if (tag->byGraceLoginReset == 0xff)
|
|
LogWriteLog(0, Lids(IDS_L_108));
|
|
else
|
|
LogWriteLog(0, TEXT("%u"), (UINT) tag->byGraceLoginReset);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
LogWriteLog(1, Lids(IDS_L_116), (UINT) tag->byMinPasswordLength);
|
|
|
|
// Max Connections
|
|
LogWriteLog(1, Lids(IDS_L_117));
|
|
if (tag->wMaxConnections == 0)
|
|
LogWriteLog(0, Lids(IDS_L_108));
|
|
else
|
|
LogWriteLog(0, TEXT("%u"), (UINT) tag->wMaxConnections);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
LogWriteLog(1, Lids(IDS_L_118), (ULONG) tag->lBalance);
|
|
LogWriteLog(1, Lids(IDS_L_119), (ULONG) tag->lCreditLimit);
|
|
|
|
// Max Disk blocks
|
|
LogWriteLog(1, Lids(IDS_L_120));
|
|
if (tag->lMaxDiskBlocks == 0x7FFFFFFF)
|
|
LogWriteLog(0, Lids(IDS_L_108));
|
|
else
|
|
LogWriteLog(0, TEXT("%lu"), (ULONG) tag->lMaxDiskBlocks);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
} // NWUserDefaultsLog
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWUserInfoLog(
|
|
LPTSTR szUserName,
|
|
VOID *UInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
struct tagLoginControl *tag;
|
|
LPTSTR FullName;
|
|
|
|
tag = (struct tagLoginControl *) UInfo;
|
|
|
|
LogWriteLog(1, Lids(IDS_L_105));
|
|
|
|
// Full Name
|
|
LogWriteLog(2, Lids(IDS_L_106));
|
|
|
|
FullName = NWUserNameGet(szUserName);
|
|
if (FullName != NULL)
|
|
LogWriteLog(2, FullName);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// Account disabled
|
|
if (tag->byAccountDisabled == 0xff)
|
|
LogWriteLog(2, Lids(IDS_L_121), Lids(IDS_YES));
|
|
else if ((tag->wBadLogins == 0xffff) &&
|
|
(tag->lNextResetTime > (LONG)CachedServerTime))
|
|
LogWriteLog(2, Lids(IDS_L_121), Lids(IDS_LOCKED_OUT));
|
|
else
|
|
LogWriteLog(2, Lids(IDS_L_121), Lids(IDS_NO));
|
|
|
|
// Account expires
|
|
LogWriteLog(2, Lids(IDS_L_109));
|
|
if (tag->byAccountExpires[0] == 0)
|
|
LogWriteLog(0, Lids(IDS_L_107));
|
|
else
|
|
LogWriteLog(0, TEXT("%02u/%02u/%04u"), (UINT) tag->byAccountExpires[1],
|
|
(UINT) tag->byAccountExpires[2], (UINT) 1900 + tag->byAccountExpires[0]);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// Password Expires
|
|
LogWriteLog(2, Lids(IDS_L_122));
|
|
if (tag->byPasswordExpires[0] == 0)
|
|
LogWriteLog(0, Lids(IDS_L_107));
|
|
else
|
|
LogWriteLog(0, TEXT("%02u/%02u/19%02u"), (int) tag->byPasswordExpires[1],
|
|
(int) tag->byPasswordExpires[2], (int) tag->byPasswordExpires[0]);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// Grace logins
|
|
LogWriteLog(2, Lids(IDS_L_123));
|
|
if (tag->byGraceLogins == 0xff)
|
|
LogWriteLog(0, Lids(IDS_L_108));
|
|
else
|
|
LogWriteLog(0, TEXT("%u"), (UINT) tag->byGraceLogins);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// initial grace logins
|
|
LogWriteLog(2, Lids(IDS_L_115));
|
|
if (tag->byGraceLoginReset == 0xff)
|
|
LogWriteLog(0, Lids(IDS_L_108));
|
|
else
|
|
LogWriteLog(0, TEXT("%u"), (UINT) tag->byGraceLoginReset);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// Min password length
|
|
LogWriteLog(2, Lids(IDS_L_116), (UINT) tag->byMinPasswordLength);
|
|
|
|
// Password expiration
|
|
LogWriteLog(2, Lids(IDS_L_114));
|
|
if (tag->wPasswordInterval == 0)
|
|
LogWriteLog(0, Lids(IDS_L_107));
|
|
else
|
|
LogWriteLog(0, TEXT("%u"), (UINT) tag->wPasswordInterval);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// Max connections
|
|
LogWriteLog(2, Lids(IDS_L_117));
|
|
if (tag->wMaxConnections == 0)
|
|
LogWriteLog(0, Lids(IDS_L_108));
|
|
else
|
|
LogWriteLog(0, TEXT("%u"), (UINT) tag->wMaxConnections);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// Restrictions
|
|
// user can change password
|
|
LogWriteLog(2, Lids(IDS_L_110));
|
|
if ((tag->byRestrictions & 0x01))
|
|
LogWriteLog(3, Lids(IDS_L_111));
|
|
else
|
|
LogWriteLog(3, Lids(IDS_L_112));
|
|
|
|
// unique password required
|
|
if ((tag->byRestrictions & 0x02))
|
|
LogWriteLog(3, Lids(IDS_L_113), Lids(IDS_YES));
|
|
else
|
|
LogWriteLog(3, Lids(IDS_L_113), Lids(IDS_NO));
|
|
|
|
LogWriteLog(2, Lids(IDS_L_124), (UINT) tag->wBadLogins);
|
|
|
|
// Max Disk Blocks
|
|
LogWriteLog(2, Lids(IDS_L_120));
|
|
if (tag->lMaxDiskBlocks == 0x7FFFFFFF)
|
|
LogWriteLog(0, Lids(IDS_L_108));
|
|
else
|
|
LogWriteLog(0, TEXT("%lX"), tag->lMaxDiskBlocks);
|
|
|
|
LogWriteLog(0, Lids(IDS_CRLF));
|
|
|
|
// Login Times
|
|
NWLoginTimesLog(tag->byLoginTimes);
|
|
|
|
} // NWUserInfoLog
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWUserInfoGet(
|
|
LPTSTR szUserName,
|
|
VOID **UInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
static struct tagLoginControl xUI;
|
|
struct tagLoginControl *UserInfo = NULL;
|
|
char szAnsiUserName[MAX_USER_NAME_LEN];
|
|
NWCCODE ret;
|
|
BYTE bySegment[128];
|
|
BYTE byMoreSegments, byPropertyFlags;
|
|
|
|
CharToOem(szUserName, szAnsiUserName);
|
|
ret = NWReadPropertyValue(CachedConn, szAnsiUserName, OT_USER, LOGIN_CONTROL, 1, bySegment, &byMoreSegments, &byPropertyFlags);
|
|
|
|
if (ret == SUCCESSFUL) {
|
|
UserInfo = &xUI;
|
|
memset(UserInfo, 0, sizeof(struct tagLoginControl));
|
|
memcpy(UserInfo, bySegment, sizeof (struct tagLoginControl));
|
|
|
|
// Now put the data in 'normal' Intel format
|
|
SWAPBYTES(UserInfo->wPasswordInterval);
|
|
SWAPBYTES(UserInfo->wMaxConnections);
|
|
SWAPWORDS(UserInfo->lMaxDiskBlocks);
|
|
SWAPBYTES(UserInfo->wBadLogins);
|
|
SWAPWORDS(UserInfo->lNextResetTime);
|
|
}
|
|
|
|
*UInfo = (void *) UserInfo;
|
|
|
|
} // NWUserInfoGet
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWServerEnum(
|
|
LPTSTR Container,
|
|
SERVER_BROWSE_LIST **lpServList
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
int NumBufs = 0;
|
|
DWORD TotalEntries = 0;
|
|
ENUM_REC *BufHead, *CurrBuf, *OldBuf;
|
|
SERVER_BROWSE_LIST *ServList = NULL;
|
|
SERVER_BROWSE_BUFFER *SList = NULL;
|
|
DWORD status = 0;
|
|
DWORD i, j;
|
|
NETRESOURCE ResourceBuf;
|
|
|
|
// Container is ignored - NW is a flat network topology...
|
|
SetProvider(NW_PROVIDER, &ResourceBuf);
|
|
|
|
BufHead = CurrBuf = OldBuf = NULL;
|
|
status = EnumBufferBuild(&BufHead, &NumBufs, ResourceBuf);
|
|
|
|
if (!status) {
|
|
// We have 0 to xxx Enum recs each with a buffer sitting off of it. Now
|
|
// need to consolidate these into one global enum list...
|
|
if (NumBufs) {
|
|
CurrBuf = BufHead;
|
|
|
|
// Figure out how many total entries there are
|
|
while (CurrBuf) {
|
|
TotalEntries += CurrBuf->cEntries;
|
|
CurrBuf = CurrBuf->next;
|
|
}
|
|
|
|
CurrBuf = BufHead;
|
|
|
|
// Now create a Server List to hold all of these.
|
|
ServList = AllocMemory(sizeof(SERVER_BROWSE_LIST) + TotalEntries * sizeof(SERVER_BROWSE_BUFFER));
|
|
|
|
if (ServList == NULL) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
ServList->Count = TotalEntries;
|
|
SList = (SERVER_BROWSE_BUFFER *) &ServList->SList;
|
|
|
|
j = 0;
|
|
|
|
// Now loop through copying the data...
|
|
while (CurrBuf) {
|
|
for(i = 0; i < CurrBuf->cEntries; i++) {
|
|
if (CurrBuf->lpnr[i].lpRemoteName != NULL)
|
|
if (CurrBuf->lpnr[i].lpRemoteName[0] == TEXT('\\') && CurrBuf->lpnr[i].lpRemoteName[1] == TEXT('\\'))
|
|
lstrcpy(SList[j].Name, &CurrBuf->lpnr[i].lpRemoteName[2]);
|
|
else
|
|
lstrcpy(SList[j].Name, CurrBuf->lpnr[i].lpRemoteName);
|
|
else
|
|
lstrcpy(SList[j].Name, TEXT(""));
|
|
|
|
if (CurrBuf->lpnr[i].lpComment != NULL)
|
|
lstrcpy(SList[j].Description, CurrBuf->lpnr[i].lpComment);
|
|
else
|
|
lstrcpy(SList[j].Description, TEXT(""));
|
|
|
|
SList[j].Container = FALSE;
|
|
j++;
|
|
}
|
|
|
|
OldBuf = CurrBuf;
|
|
CurrBuf = CurrBuf->next;
|
|
|
|
// Free the old buffer
|
|
FreeMemory((HGLOBAL) OldBuf);
|
|
|
|
} // while
|
|
|
|
} // else (ServList)
|
|
|
|
} // if (numbufs)
|
|
|
|
}
|
|
|
|
*lpServList = ServList;
|
|
return status;
|
|
|
|
} // NWServerEnum
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
ULONG
|
|
NWShareSizeGet(
|
|
LPTSTR Share
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
static TCHAR RootPath[MAX_PATH + 1];
|
|
DWORD sectorsPC, bytesPS, FreeClusters, Clusters;
|
|
DWORD TotalSpace, FreeSpace;
|
|
|
|
TotalSpace = FreeSpace = 0;
|
|
|
|
wsprintf(RootPath, TEXT("\\\\%s\\%s\\"), CachedServer, Share);
|
|
if (GetDiskFreeSpace(RootPath, §orsPC, &bytesPS, &FreeClusters, &Clusters)) {
|
|
TotalSpace = Clusters * sectorsPC * bytesPS;
|
|
FreeSpace = FreeClusters * sectorsPC * bytesPS;
|
|
}
|
|
|
|
// total - free = approx allocated space (if multiple shares on drive then
|
|
// this doesn't take that into account, we just want an approximation...
|
|
return TotalSpace - FreeSpace;
|
|
|
|
} // NWShareSizeGet
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWSharesEnum(
|
|
SHARE_LIST **lpShares
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
int NumBufs = 0;
|
|
DWORD TotalEntries = 0;
|
|
ENUM_REC *BufHead, *CurrBuf, *OldBuf;
|
|
SHARE_LIST *ShareList = NULL;
|
|
SHARE_BUFFER *SList = NULL;
|
|
DWORD status;
|
|
DWORD i, j;
|
|
NETRESOURCE ResourceBuf;
|
|
|
|
// Setup NETRESOURCE data structure
|
|
SetProvider(NW_PROVIDER, &ResourceBuf);
|
|
|
|
ResourceBuf.lpRemoteName = CachedServer;
|
|
ResourceBuf.dwUsage = RESOURCEUSAGE_CONTAINER;
|
|
|
|
status = EnumBufferBuild(&BufHead, &NumBufs, ResourceBuf);
|
|
|
|
if (!status) {
|
|
// We have 0 to xxx Enum recs each with a buffer sitting off of it. Now
|
|
// need to consolidate these into one global enum list...
|
|
if (NumBufs) {
|
|
CurrBuf = BufHead;
|
|
|
|
// Figure out how many total entries there are
|
|
while (CurrBuf) {
|
|
TotalEntries += CurrBuf->cEntries;
|
|
CurrBuf = CurrBuf->next;
|
|
}
|
|
|
|
CurrBuf = BufHead;
|
|
|
|
// Now create a Server List to hold all of these.
|
|
ShareList = (SHARE_LIST *) AllocMemory(sizeof(SHARE_LIST) + (TotalEntries * sizeof(SHARE_BUFFER)));
|
|
|
|
if (ShareList == NULL) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
j = 0;
|
|
|
|
// Zero out everything and get pointer to list
|
|
memset(ShareList, 0, sizeof(SHARE_LIST) + (TotalEntries * sizeof(SHARE_BUFFER)));
|
|
ShareList->Count = TotalEntries;
|
|
SList = (SHARE_BUFFER *) &ShareList->SList;
|
|
|
|
// Now loop through copying the data...
|
|
while (CurrBuf) {
|
|
for(i = 0; i < CurrBuf->cEntries; i++) {
|
|
if (CurrBuf->lpnr[i].lpRemoteName != NULL)
|
|
lstrcpy(SList[j].Name, ShareNameParse(CurrBuf->lpnr[i].lpRemoteName));
|
|
else
|
|
lstrcpy(SList[j].Name, TEXT(""));
|
|
|
|
SList[j].Size = NWShareSizeGet(SList[j].Name);
|
|
SList[j].Index = (USHORT) j;
|
|
j++;
|
|
}
|
|
|
|
OldBuf = CurrBuf;
|
|
CurrBuf = CurrBuf->next;
|
|
|
|
// Free the old buffer
|
|
FreeMemory((HGLOBAL) OldBuf);
|
|
|
|
} // while
|
|
|
|
} // else (ShareList)
|
|
|
|
} // if (numbufs)
|
|
|
|
}
|
|
|
|
*lpShares = ShareList;
|
|
return status;
|
|
|
|
} // NWSharesEnum
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWServerInfoReset(
|
|
SOURCE_SERVER_BUFFER *SServ
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
static VERSION_INFO NWInfo;
|
|
NWCCODE ret = 0;
|
|
|
|
ret = NWGetFileServerVersionInfo(CachedConn, &NWInfo);
|
|
|
|
// BUGBUG: This API returns fail (8801) - but is actually succeding,
|
|
// just ignore error for right now as it really doesn't matter for the
|
|
// version info.
|
|
// if (ret == SUCCESSFUL) {
|
|
SServ->VerMaj = NWInfo.Version;
|
|
SServ->VerMin = NWInfo.SubVersion;
|
|
// }
|
|
|
|
} // NWServerInfoReset
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
NWServerInfoSet(
|
|
LPTSTR ServerName,
|
|
SOURCE_SERVER_BUFFER *SServ
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
static VERSION_INFO NWInfo;
|
|
NWCCODE ret = 0;
|
|
|
|
CursorHourGlass();
|
|
lstrcpy(SServ->Name, ServerName);
|
|
NWServerInfoReset(SServ);
|
|
|
|
// Fill in share list
|
|
NWSharesEnum(&SServ->ShareList);
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
DWORD i;
|
|
|
|
dprintf(TEXT("Adding NW Server: %s\n"), SServ->Name);
|
|
dprintf(TEXT(" Version: %u.%u\n"), (UINT) SServ->VerMaj, (UINT) SServ->VerMin);
|
|
dprintf(TEXT(" Shares\n"));
|
|
dprintf(TEXT(" +---------------------------------------+\n"));
|
|
if (SServ->ShareList) {
|
|
for (i = 0; i < SServ->ShareList->Count; i++) {
|
|
dprintf(TEXT(" %-15s AllocSpace %lu\n"), SServ->ShareList->SList[i].Name, SServ->ShareList->SList[i].Size);
|
|
}
|
|
}
|
|
else
|
|
dprintf(TEXT(" <Serv List enum failed!!>\n"));
|
|
|
|
dprintf(TEXT("\n"));
|
|
|
|
}
|
|
#endif
|
|
|
|
CursorNormal();
|
|
|
|
} // NWServerInfoSet
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
NWServerValidate(
|
|
HWND hWnd,
|
|
LPTSTR ServerName,
|
|
BOOL DupFlag
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validates a given server - makes sure it can be connected to and
|
|
that the user has admin privs on it.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
BOOL ret = FALSE;
|
|
SOURCE_SERVER_BUFFER *SServ = NULL;
|
|
DWORD dwObjectID = 0;
|
|
DWORD Size;
|
|
BYTE AccessLevel;
|
|
TCHAR UserName[MAX_USER_NAME_LEN + 1];
|
|
static TCHAR LocServer[MAX_SERVER_NAME_LEN+3];
|
|
LPVOID lpMessageBuffer;
|
|
|
|
CursorHourGlass();
|
|
|
|
if (DupFlag)
|
|
SServ = SServListFind(ServerName);
|
|
|
|
if (SServ == NULL) {
|
|
// Get Current Logged On User
|
|
lstrcpy(UserName, TEXT(""));
|
|
Size = sizeof(UserName);
|
|
WNetGetUser(NULL, UserName, &Size);
|
|
|
|
lstrcpy(LocServer, TEXT("\\\\"));
|
|
lstrcat(LocServer, ServerName);
|
|
|
|
if (UseAddPswd(hWnd, UserName, LocServer, Lids(IDS_S_6), NW_PROVIDER)) {
|
|
|
|
Status = NWServerSet(ServerName);
|
|
|
|
if (Status) {
|
|
|
|
if (GetLastError() != 0)
|
|
WarningError(Lids(IDS_NWCANT_CON), ServerName);
|
|
|
|
} else {
|
|
if (IsNCPServerFPNW(CachedConn))
|
|
WarningError(Lids(IDS_E_18), ServerName);
|
|
else {
|
|
Status = NWCGetBinderyAccessLevel(CachedConn, &AccessLevel, &dwObjectID);
|
|
|
|
if (!Status) {
|
|
AccessLevel &= BS_SUPER_READ;
|
|
if (AccessLevel == BS_SUPER_READ)
|
|
ret = TRUE;
|
|
else
|
|
WarningError(Lids(IDS_NWNO_ADMIN), ServerName);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL, GetLastError(), 0,
|
|
(LPTSTR) &lpMessageBuffer, 0, NULL );
|
|
|
|
if (GetLastError() != 0)
|
|
WarningError(Lids(IDS_E_9), ServerName, lpMessageBuffer);
|
|
|
|
LocalFree(lpMessageBuffer);
|
|
}
|
|
} else {
|
|
// Already in source server list - can't appear more then once
|
|
WarningError(Lids(IDS_E_14), ServerName);
|
|
}
|
|
|
|
CursorNormal();
|
|
return ret;
|
|
|
|
} // NWServerValidate
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
LPTSTR
|
|
NWRightsLog(
|
|
DWORD Rights
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
static TCHAR NWRights[15];
|
|
|
|
lstrcpy(NWRights, Lids(IDS_S_34));
|
|
|
|
// Read
|
|
if (!(Rights & 0x01))
|
|
NWRights[2] = TEXT(' ');
|
|
|
|
// Write
|
|
if (!(Rights & 0x02))
|
|
NWRights[3] = TEXT(' ');
|
|
|
|
// Create
|
|
if (!(Rights & 0x08))
|
|
NWRights[4] = TEXT(' ');
|
|
|
|
// Delete (Erase)
|
|
if (!(Rights & 0x10))
|
|
NWRights[5] = TEXT(' ');
|
|
|
|
// Parental
|
|
if (!(Rights & 0x20))
|
|
NWRights[8] = TEXT(' ');
|
|
|
|
// Search
|
|
if (!(Rights & 0x40))
|
|
NWRights[7] = TEXT(' ');
|
|
|
|
// Modify
|
|
if (!(Rights & 0x80))
|
|
NWRights[6] = TEXT(' ');
|
|
|
|
// Supervisor (all rights set)
|
|
if ((Rights & 0xFB) != 0xFB)
|
|
NWRights[1] = TEXT(' ');
|
|
|
|
return NWRights;
|
|
|
|
} // NWRightsLog
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
NTSTATUS
|
|
MapNwRightsToNTAccess(
|
|
ULONG NWRights,
|
|
PRIGHTS_MAPPING pMap,
|
|
ACCESS_MASK *pAccessMask
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map a NW Right to the appropriate NT AccessMask
|
|
|
|
Arguments:
|
|
|
|
NWRights - Netware rights we wish to map
|
|
pMap - pointer to structure that defines the mapping
|
|
|
|
Return Value:
|
|
|
|
The NT AccessMask corresponding to the NW Rights
|
|
|
|
--*/
|
|
|
|
{
|
|
PNW_TO_NT_MAPPING pNWToNtMap = pMap->Nw2NtMapping ;
|
|
ACCESS_MASK AccessMask = 0 ;
|
|
|
|
if (!pAccessMask)
|
|
return STATUS_INVALID_PARAMETER ;
|
|
|
|
*pAccessMask = 0x0 ;
|
|
|
|
// go thru the mapping structuring, OR-ing in bits along the way
|
|
while (pNWToNtMap->NWRight) {
|
|
|
|
if (pNWToNtMap->NWRight & NWRights)
|
|
AccessMask |= pNWToNtMap->NTAccess ;
|
|
|
|
pNWToNtMap++ ;
|
|
}
|
|
|
|
*pAccessMask = AccessMask ;
|
|
|
|
return STATUS_SUCCESS ;
|
|
} // MapNwRightsToNTAccess
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWPrintServersEnum(
|
|
PRINT_SERVER_LIST **PS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PRINT_SERVER_LIST *psl;
|
|
PRINT_SERVER_BUFFER *pbuff;
|
|
DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
|
|
DWORD Count = 0;
|
|
DWORD status = 0;
|
|
char szAnsiPrinterName[MAX_USER_NAME_LEN + 1];
|
|
TCHAR szPrinterName[MAX_USER_NAME_LEN + 1];
|
|
WORD wFoundUserType = 0;
|
|
DWORD dwObjectID = 0xFFFFFFFFL;
|
|
BYTE byPropertiesFlag = 0;
|
|
BYTE byObjectFlag = 0;
|
|
BYTE byObjectSecurity = 0;
|
|
NWCCODE ret;
|
|
|
|
psl = (PRINT_SERVER_LIST *) AllocMemory(sizeof(PRINT_SERVER_LIST) + (NumRecs * sizeof(PRINT_SERVER_BUFFER)));
|
|
|
|
if (!psl) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
pbuff = psl->PSList;
|
|
|
|
// init to NULL so doesn't have garbage if call fails
|
|
lstrcpyA(szAnsiPrinterName, "");
|
|
|
|
// Loop through bindery getting all the users.
|
|
while ((ret = NWScanObject(CachedConn, "*", OT_PRINT_SERVER, &dwObjectID, szAnsiPrinterName,
|
|
&wFoundUserType, &byPropertiesFlag,
|
|
&byObjectFlag, &byObjectSecurity)) == SUCCESSFUL) {
|
|
|
|
// Got user - now convert and save off the information
|
|
OemToChar(szAnsiPrinterName, szPrinterName);
|
|
|
|
lstrcpy(pbuff[Count].Name, szPrinterName);
|
|
Count++;
|
|
|
|
// Check if we have to re-allocate buffer
|
|
if (Count >= NumRecs) {
|
|
NumRecs += DEF_NUM_RECS;
|
|
psl = (PRINT_SERVER_LIST *) ReallocMemory((HGLOBAL) psl, sizeof(PRINT_SERVER_LIST) + (NumRecs * sizeof(PRINT_SERVER_BUFFER)));
|
|
pbuff = psl->PSList;
|
|
|
|
if (!psl) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Gotta clear this out from the last loop
|
|
if (Count)
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
// check if error occured...
|
|
if (ret)
|
|
status = ret;
|
|
|
|
// Now slim down the list to just what we need.
|
|
if (!status) {
|
|
psl = (PRINT_SERVER_LIST *) ReallocMemory((HGLOBAL) psl, sizeof(PRINT_SERVER_LIST) + (Count * sizeof(PRINT_SERVER_BUFFER)));
|
|
|
|
if (!psl)
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
psl->Count = Count;
|
|
*PS = psl;
|
|
|
|
return status;
|
|
|
|
} // NWPrintServersEnum
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
NWPrintOpsEnum(
|
|
USER_LIST **lpUsers
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
First need to enumerate all the print servers on the NetWare system
|
|
we are pointing to. Next loop through each of these print servers
|
|
and enumerate the print operators on each of them.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PRINT_SERVER_LIST *psl = NULL;
|
|
PRINT_SERVER_BUFFER *PSList;
|
|
ULONG pCount;
|
|
USER_LIST *Users = NULL;
|
|
USER_BUFFER *UserBuffer;
|
|
DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
|
|
DWORD Count = 0;
|
|
DWORD ipsl = 0, iseg = 0;
|
|
DWORD status = 0;
|
|
char szAnsiUserName[MAX_USER_NAME_LEN + 1];
|
|
char szAnsiName[MAX_GROUP_NAME_LEN + 1];
|
|
TCHAR szUserName[MAX_USER_NAME_LEN + 1];
|
|
WORD wFoundUserType = 0;
|
|
DWORD dwObjectID = 0xFFFFFFFFL;
|
|
BYTE byPropertyFlags = 0;
|
|
BYTE byObjectFlag = 0;
|
|
BYTE byObjectSecurity = 0;
|
|
UCHAR Segment = 1;
|
|
DWORD bySegment[32];
|
|
BYTE byMoreSegments;
|
|
NWCCODE ret;
|
|
|
|
*lpUsers = NULL;
|
|
|
|
// Enumerate the print servers - if there are none, then there are no printer ops
|
|
NWPrintServersEnum(&psl);
|
|
if ((psl == NULL) || (psl->Count == 0)) {
|
|
if (psl != NULL)
|
|
FreeMemory(psl);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Got some servers - loop through them enumerating users
|
|
Users = (USER_LIST *) AllocMemory(sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
UserBuffer = Users->UserBuffer;
|
|
PSList = psl->PSList;
|
|
|
|
for (pCount = 0; pCount < psl->Count; pCount++) {
|
|
// init to NULL so doesn't have garbage if call fails
|
|
lstrcpyA(szAnsiUserName, "");
|
|
CharToOem(PSList[ipsl++].Name, szAnsiName);
|
|
|
|
// Loop through bindery getting all the users.
|
|
do {
|
|
if (!(ret = NWReadPropertyValue(CachedConn, szAnsiName, OT_PRINT_SERVER, PS_OPERATORS,
|
|
Segment, (BYTE *) bySegment, &byMoreSegments, &byPropertyFlags))) {
|
|
|
|
Segment++;
|
|
// loop through properties converting them to user names
|
|
iseg = 0;
|
|
while ((bySegment[iseg]) && (iseg < 32)) {
|
|
if (!(ret = NWGetObjectName(CachedConn, bySegment[iseg], szAnsiUserName, &wFoundUserType))) {
|
|
// Got user - now convert and save off the information
|
|
OemToChar(szAnsiUserName, szUserName);
|
|
|
|
// Map out Supervisor (already print-op privs)
|
|
if (lstrcmpi(szUserName, Lids(IDS_S_28))) {
|
|
lstrcpy(UserBuffer[Count].Name, szUserName);
|
|
lstrcpy(UserBuffer[Count].NewName, szUserName);
|
|
Count++;
|
|
}
|
|
|
|
// Check if we have to re-allocate buffer
|
|
if (Count >= NumRecs) {
|
|
NumRecs += DEF_NUM_RECS;
|
|
Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
|
|
|
|
if (!Users) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
UserBuffer = Users->UserBuffer;
|
|
}
|
|
}
|
|
iseg++;
|
|
}
|
|
|
|
} else // if NWReadPropertyValue
|
|
byMoreSegments = 0;
|
|
|
|
} while (byMoreSegments);
|
|
|
|
// Gotta clear this out from the last loop
|
|
if (Count)
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
// check if error occured...
|
|
if (ret)
|
|
status = ret;
|
|
|
|
// Now slim down the list to just what we need.
|
|
if (!status) {
|
|
Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * Count));
|
|
|
|
if (!Users)
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
else {
|
|
// Sort the server list before putting it in the dialog
|
|
UserBuffer = Users->UserBuffer;
|
|
qsort((void *) UserBuffer, (size_t) Count, sizeof(USER_BUFFER), UserListCompare);
|
|
}
|
|
}
|
|
|
|
Users->Count = Count;
|
|
*lpUsers = Users;
|
|
|
|
return status;
|
|
|
|
} // NWPrintOpsEnum
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
NWServerTimeGet(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Queries server for it's current local time which is then converted to
|
|
elasped minutes since 1985 in order to compare with the lNextResetTime
|
|
field of the LOGIN_CONTROL structure (which must be byte-aligned).
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwYear = 0;
|
|
DWORD dwMonth = 0;
|
|
DWORD dwDay = 0;
|
|
DWORD dwHour = 0;
|
|
DWORD dwMinute = 0;
|
|
DWORD dwSecond = 0;
|
|
DWORD dwDayOfWeek = 0;
|
|
DWORD dwServerTime = 0;
|
|
|
|
CachedServerTime = 0xffffffff; // re-initialize...
|
|
|
|
if (!NWGetFileServerDateAndTime(
|
|
CachedConn,
|
|
(LPBYTE)&dwYear,
|
|
(LPBYTE)&dwMonth,
|
|
(LPBYTE)&dwDay,
|
|
(LPBYTE)&dwHour,
|
|
(LPBYTE)&dwMinute,
|
|
(LPBYTE)&dwSecond,
|
|
(LPBYTE)&dwDayOfWeek))
|
|
{
|
|
if (NWTimeMap(dwDay, dwMonth, dwYear, 1985, &dwServerTime))
|
|
{
|
|
dwServerTime += dwHour * 3600;
|
|
dwServerTime += dwMinute * 60;
|
|
dwServerTime += dwSecond;
|
|
|
|
CachedServerTime = dwServerTime / 60; // convert to minutes...
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
IsNCPServerFPNW(
|
|
NWCONN_HANDLE Conn
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if this an FPNW server by checking for a specific object
|
|
type and property.
|
|
|
|
Arguments:
|
|
|
|
Conn - connection id of ncp server.
|
|
|
|
Return Value:
|
|
|
|
Returns true if ncp server is fpnw.
|
|
|
|
--*/
|
|
|
|
{
|
|
NWCCODE ret;
|
|
BYTE bySegment[128];
|
|
BYTE byMoreSegments, byPropertyFlags;
|
|
|
|
memset(bySegment, 0, sizeof(bySegment));
|
|
|
|
ret = NWReadPropertyValue(
|
|
CachedConn,
|
|
MS_EXTENDED_NCPS,
|
|
0x3B06,
|
|
FPNW_PDC,
|
|
1,
|
|
bySegment,
|
|
&byMoreSegments,
|
|
&byPropertyFlags
|
|
);
|
|
|
|
return (ret == SUCCESSFUL) && (BOOL)(BYTE)bySegment[0];
|
|
}
|