diff options
Diffstat (limited to '')
-rw-r--r-- | private/nw/convert/nwconv/nwnetapi.c | 2692 |
1 files changed, 2692 insertions, 0 deletions
diff --git a/private/nw/convert/nwconv/nwnetapi.c b/private/nw/convert/nwconv/nwnetapi.c new file mode 100644 index 000000000..2815484ee --- /dev/null +++ b/private/nw/convert/nwconv/nwnetapi.c @@ -0,0 +1,2692 @@ +/*++ + +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]; +} |