windows-nt/Source/XPSP1/NT/ds/nw/convert/nwconv/nwnetapi.c
2020-09-26 16:20:57 +08:00

2693 lines
59 KiB
C

/*++
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, &sectorsPC, &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];
}