summaryrefslogtreecommitdiffstats
path: root/private/nw/convert/nwconv/nwnetapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/convert/nwconv/nwnetapi.c')
-rw-r--r--private/nw/convert/nwconv/nwnetapi.c2692
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, &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];
+}