summaryrefslogtreecommitdiffstats
path: root/private/nw/convert/nwconv/ntnetapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/convert/nwconv/ntnetapi.c')
-rw-r--r--private/nw/convert/nwconv/ntnetapi.c3644
1 files changed, 3644 insertions, 0 deletions
diff --git a/private/nw/convert/nwconv/ntnetapi.c b/private/nw/convert/nwconv/ntnetapi.c
new file mode 100644
index 000000000..a363bf99d
--- /dev/null
+++ b/private/nw/convert/nwconv/ntnetapi.c
@@ -0,0 +1,3644 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ NTNetaAPI.c
+
+Abstract:
+
+
+Author:
+
+ Arthur Hanson (arth) 16-Jun-1994
+
+Revision History:
+
+--*/
+
+
+#include "globals.h"
+
+#include <ntlsa.h>
+#include <ntsam.h>
+#include <ntddnwfs.h>
+#include <align.h>
+
+#include <math.h>
+#include "convapi.h"
+#include "ntnetapi.h"
+#include "nwnetapi.h"
+#include "loghours.h"
+#include "usrprop.h"
+#include "crypt.h"
+// #include <nwstruct.h>
+#include <nwconv.h>
+#include "fpnwapi.h"
+
+#ifdef DEBUG
+int ErrorBoxRetry(LPTSTR szFormat, ...);
+#endif
+
+void ErrorIt(LPTSTR szFormat, ...);
+NTSTATUS ACEAdd( PSECURITY_DESCRIPTOR pSD, PSID pSid, ACCESS_MASK AccessMask, ULONG AceFlags, PSECURITY_DESCRIPTOR *ppNewSD );
+
+static LPTSTR LocalName = NULL;
+
+// +3 for leading slashes and ending NULL
+static TCHAR CachedServer[MAX_SERVER_NAME_LEN+3];
+static BOOL LocalMachine = FALSE;
+
+// keep this around so we don't have to keep re-do query
+static LPSERVER_INFO_101 ServInfo = NULL;
+// #define TYPE_DOMAIN SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL | SV_TYPE_DOMAIN_MEMBER
+#define TYPE_DOMAIN SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL
+
+static SAM_HANDLE SAMHandle = (SAM_HANDLE) 0;
+static SAM_HANDLE DomainHandle = (SAM_HANDLE) 0;
+static PSID DomainID;
+static WCHAR UserParms[1024];
+
+#define NCP_LSA_SECRET_KEY L"G$MNSEncryptionKey"
+#define NCP_LSA_SECRET_LENGTH USER_SESSION_KEY_LENGTH
+
+static char Secret[USER_SESSION_KEY_LENGTH];
+static HANDLE FPNWLib = NULL;
+static DWORD (FAR * NWVolumeAdd) (LPWSTR, DWORD, PNWVOLUMEINFO) = NULL;
+
+//
+// This bit is set when the server is running on a NTAS machine or
+// the object is from a trusted domain. NWConv is always on NTAS
+//
+
+#define BINDLIB_REMOTE_DOMAIN_BIAS 0x10000000
+
+//
+// misc macros that are useful
+//
+#define SWAPWORD(w) ((WORD)((w & 0xFF) << 8)|(WORD)(w >> 8))
+#define SWAPLONG(l) MAKELONG(SWAPWORD(HIWORD(l)),SWAPWORD(LOWORD(l)))
+
+
+typedef struct _NT_CONN_BUFFER {
+ struct _NT_CONN_BUFFER *next;
+ struct _NT_CONN_BUFFER *prev;
+
+ LPTSTR Name;
+} NT_CONN_BUFFER;
+
+static NT_CONN_BUFFER *NTConnListStart = NULL;
+static NT_CONN_BUFFER *NTConnListEnd = NULL;
+
+HANDLE FpnwHandle = NULL;
+static FARPROC pFpnwVolumeEnum = NULL;
+static FARPROC pFpnwApiBufferFree = NULL;
+
+
+/////////////////////////////////////////////////////////////////////////
+LPSTR
+FPNWSecretGet(
+ LPTSTR ServerName
+ )
+
+/*++
+
+Routine Description:
+
+ Checks the given machine for the FPNW secret.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ SECURITY_QUALITY_OF_SERVICE QualityOfService;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ LSA_HANDLE PolicyHandle;
+ LSA_HANDLE SecretHandle;
+ NTSTATUS Status;
+ UNICODE_STRING UnicodeSecretName;
+ PUNICODE_STRING punicodeCurrentValue;
+ PUSER_INFO_2 pUserInfo = NULL;
+
+ static TCHAR LocServer[MAX_SERVER_NAME_LEN+3];
+ UNICODE_STRING UnicodeServerName;
+ BOOL ret = TRUE;
+
+ memset(Secret, 0, USER_SESSION_KEY_LENGTH);
+ wsprintf(LocServer, TEXT("\\\\%s"), ServerName);
+
+ // Verify & init secret name.
+ RtlInitUnicodeString( &UnicodeSecretName, NCP_LSA_SECRET_KEY );
+ RtlInitUnicodeString( &UnicodeServerName, LocServer);
+
+ // Prepare to open the policy object.
+ QualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ QualityOfService.ImpersonationLevel = SecurityImpersonation;
+ QualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ QualityOfService.EffectiveOnly = FALSE;
+
+ InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
+ ObjectAttributes.SecurityQualityOfService = &QualityOfService;
+
+ // Open a handle to the target machine's LSA policy.
+ Status = LsaOpenPolicy( &UnicodeServerName, &ObjectAttributes, 0, &PolicyHandle );
+
+ if( !NT_SUCCESS( Status ) ) {
+ ret = FALSE;
+ goto FatalExit0;
+ }
+
+ // Open the secret object.
+ Status = LsaOpenSecret( PolicyHandle, &UnicodeSecretName, SECRET_QUERY_VALUE, &SecretHandle );
+
+ if( !NT_SUCCESS( Status ) ) {
+ ret = FALSE;
+ goto FatalExit1;
+ }
+
+ // Query the secret.
+ Status = LsaQuerySecret( SecretHandle, &punicodeCurrentValue, NULL, NULL, NULL );
+
+ if( !NT_SUCCESS( Status ) ) {
+ ret = FALSE;
+ goto FatalExit2;
+ }
+
+ if (punicodeCurrentValue != NULL) {
+ memcpy(Secret, punicodeCurrentValue->Buffer, USER_SESSION_KEY_LENGTH);
+ LsaFreeMemory( (PVOID)punicodeCurrentValue );
+ }
+
+FatalExit2:
+ LsaClose( SecretHandle );
+
+FatalExit1:
+ LsaClose( PolicyHandle );
+
+FatalExit0:
+
+ if (ret)
+ return Secret;
+ else
+ return NULL;
+
+} // FPNWSecretGet
+
+
+/////////////////////////////////////////////////////////////////////////
+NTSTATUS
+SetGraceLoginAllowed(
+ USHORT ushGraceLoginAllowed
+ )
+
+/*++
+
+Routine Description:
+
+ Store Grace Login Allowed in UserParms.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS err = NERR_Success;
+ USHORT ushTemp = ushGraceLoginAllowed;
+ UNICODE_STRING uniGraceLoginAllowed;
+ LPWSTR lpNewUserParms = NULL;
+ BOOL fUpdate;
+
+ uniGraceLoginAllowed.Buffer = &ushTemp;
+ uniGraceLoginAllowed.Length = 2;
+ uniGraceLoginAllowed.MaximumLength = 2;
+
+ err = SetUserProperty (UserParms, GRACELOGINALLOWED, uniGraceLoginAllowed, USER_PROPERTY_TYPE_ITEM, &lpNewUserParms, &fUpdate);
+ if ((err == NERR_Success) && (lpNewUserParms != NULL)) {
+ if (fUpdate)
+ lstrcpyW(UserParms, lpNewUserParms);
+
+ LocalFree(lpNewUserParms);
+ }
+
+ return err;
+} // SetGraceLoginAllowed
+
+
+/////////////////////////////////////////////////////////////////////////
+NTSTATUS
+SetGraceLoginRemainingTimes(
+ USHORT ushGraceLoginRemainingTimes
+ )
+
+/*++
+
+Routine Description:
+
+ Store Grace Login Remaining Times in UserParms. if ushGraceLogin is 0,
+ "GraceLogin" field will be deleted from UserParms.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS err = NERR_Success;
+ USHORT ushTemp = ushGraceLoginRemainingTimes;
+ UNICODE_STRING uniGraceLoginRemainingTimes;
+ LPWSTR lpNewUserParms = NULL;
+ BOOL fUpdate;
+
+ uniGraceLoginRemainingTimes.Buffer = &ushTemp;
+ uniGraceLoginRemainingTimes.Length = 2;
+ uniGraceLoginRemainingTimes.MaximumLength = 2;
+
+ err = SetUserProperty (UserParms, GRACELOGINREMAINING, uniGraceLoginRemainingTimes, USER_PROPERTY_TYPE_ITEM, &lpNewUserParms, &fUpdate);
+ if ((err == NERR_Success) && (lpNewUserParms != NULL)) {
+ if (fUpdate)
+ lstrcpyW(UserParms, lpNewUserParms);
+
+ LocalFree(lpNewUserParms);
+ }
+
+ return err;
+} // SetGraceLoginRemainingTimes
+
+
+/////////////////////////////////////////////////////////////////////////
+NTSTATUS
+SetMaxConnections(
+ USHORT ushMaxConnections
+ )
+
+/*++
+
+Routine Description:
+
+ Store Maximum Concurret Connections in UserParms. If ushMaxConnections
+ is 0xffff or 0, "MaxConnections" field will be deleted from UserParms,
+ otherwise the value is stored.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS err = NERR_Success;
+ USHORT ushTemp = ushMaxConnections;
+ UNICODE_STRING uniMaxConnections;
+ LPWSTR lpNewUserParms = NULL;
+ BOOL fUpdate;
+
+ uniMaxConnections.Buffer = &ushMaxConnections;
+ uniMaxConnections.Length = 2;
+ uniMaxConnections.MaximumLength = 2;
+
+ err = SetUserProperty (UserParms, MAXCONNECTIONS, uniMaxConnections, USER_PROPERTY_TYPE_ITEM, &lpNewUserParms, &fUpdate);
+ if ((err == NERR_Success) && (lpNewUserParms != NULL)) {
+ if (fUpdate)
+ lstrcpyW(UserParms, lpNewUserParms);
+
+ LocalFree(lpNewUserParms);
+ }
+
+ return err;
+} // SetMaxConnections
+
+
+/////////////////////////////////////////////////////////////////////////
+NTSTATUS
+SetNWPasswordAge(
+ BOOL fExpired
+ )
+
+/*++
+
+Routine Description:
+
+ If fExpired is TRUE, set the NWPasswordSet field to be all fs.
+ otherwise set it to be the current time.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS err = NERR_Success;
+ LARGE_INTEGER currentTime;
+ LPWSTR lpNewUserParms = NULL;
+ UNICODE_STRING uniPasswordAge;
+ BOOL fUpdate;
+
+ if (fExpired) {
+ currentTime.HighPart = 0xffffffff;
+ currentTime.LowPart = 0xffffffff;
+ } else
+ NtQuerySystemTime (&currentTime);
+
+ uniPasswordAge.Buffer = (PWCHAR) &currentTime;
+ uniPasswordAge.Length = sizeof (LARGE_INTEGER);
+ uniPasswordAge.MaximumLength = sizeof (LARGE_INTEGER);
+
+ err = SetUserProperty (UserParms, NWTIMEPASSWORDSET, uniPasswordAge, USER_PROPERTY_TYPE_ITEM, &lpNewUserParms, &fUpdate);
+ if ((err == NERR_Success) &&(lpNewUserParms != NULL)) {
+ if (fUpdate)
+ lstrcpyW(UserParms, lpNewUserParms);
+
+ LocalFree(lpNewUserParms);
+ }
+
+ return err;
+} // SetNWPasswordAge
+
+
+/////////////////////////////////////////////////////////////////////////
+NTSTATUS
+SetNWPassword(
+ DWORD dwUserId,
+ const TCHAR *pchNWPassword,
+ BOOL ForcePasswordChange
+ )
+
+/*++
+
+Routine Description:
+
+ Set "NWPassword" field is fIsNetWareUser is TRUE, Otherwise, delete
+ the field from UserParms.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS err;
+ TCHAR pchEncryptedNWPassword[NWENCRYPTEDPASSWORDLENGTH + 1];
+ LPWSTR lpNewUserParms = NULL;
+ BOOL fUpdate;
+ UNICODE_STRING uniPassword;
+
+#ifdef DEBUG
+ dprintf(TEXT("Set NetWare password: [%s]\r\n"), pchNWPassword);
+#endif
+
+ do {
+ // Now munge the UserID to the format required by ReturnNetwareForm...
+ dwUserId |= BINDLIB_REMOTE_DOMAIN_BIAS;
+ err = ReturnNetwareForm( Secret, dwUserId, pchNWPassword, (UCHAR *) pchEncryptedNWPassword );
+
+ if ( err != NERR_Success )
+ break;
+
+ uniPassword.Buffer = pchEncryptedNWPassword;
+ uniPassword.Length = NWENCRYPTEDPASSWORDLENGTH * sizeof (WCHAR);
+ uniPassword.MaximumLength = NWENCRYPTEDPASSWORDLENGTH * sizeof (WCHAR);
+
+ err = SetUserProperty (UserParms, NWPASSWORD, uniPassword, USER_PROPERTY_TYPE_ITEM, &lpNewUserParms, &fUpdate);
+ if ((err == NERR_Success) && (lpNewUserParms != NULL)) {
+ if (fUpdate)
+ lstrcpyW(UserParms, lpNewUserParms);
+
+ LocalFree(lpNewUserParms);
+
+ if ((err = SetNWPasswordAge (ForcePasswordChange)) != NERR_Success )
+ break;
+ }
+ } while (FALSE);
+
+ return err;
+} // SetNWPassword
+
+
+/////////////////////////////////////////////////////////////////////////
+NTSTATUS
+SetNWWorkstations(
+ const TCHAR * pchNWWorkstations
+ )
+
+/*++
+
+Routine Description:
+
+ Store NetWare allowed workstation addresses to UserParms. If
+ pchNWWorkstations is NULL, this function will delete "NWLgonFrom"
+ field from UserParms.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS err = NERR_Success;
+ UNICODE_STRING uniNWWorkstations;
+ CHAR * pchTemp = NULL;
+ LPWSTR lpNewUserParms = NULL;
+ BOOL fUpdate;
+
+ if (pchNWWorkstations == NULL) {
+ uniNWWorkstations.Buffer = NULL;
+ uniNWWorkstations.Length = 0;
+ uniNWWorkstations.MaximumLength = 0;
+ } else {
+ BOOL fDummy;
+ INT nStringLength = lstrlen(pchNWWorkstations) + 1;
+ pchTemp = (CHAR *) LocalAlloc (LPTR, nStringLength);
+
+ if ( pchTemp == NULL )
+ err = ERROR_NOT_ENOUGH_MEMORY;
+
+ if ( err == NERR_Success && !WideCharToMultiByte (CP_ACP, 0, pchNWWorkstations, nStringLength, pchTemp, nStringLength, NULL, &fDummy))
+ err = GetLastError();
+
+ if ( err == NERR_Success ) {
+ uniNWWorkstations.Buffer = (WCHAR *) pchTemp;
+ uniNWWorkstations.Length = nStringLength;
+ uniNWWorkstations.MaximumLength = nStringLength;
+ }
+ }
+
+ err = err? err: SetUserProperty (UserParms, NWLOGONFROM, uniNWWorkstations, USER_PROPERTY_TYPE_ITEM, &lpNewUserParms, &fUpdate);
+
+ if ((err == NERR_Success) && (lpNewUserParms != NULL)) {
+ if (fUpdate)
+ lstrcpyW(UserParms, lpNewUserParms);
+
+ LocalFree(lpNewUserParms);
+ }
+
+ if (pchTemp != NULL)
+ LocalFree (pchTemp);
+
+ return err;
+} // SetNWWorkstations
+
+
+/////////////////////////////////////////////////////////////////////////
+NTSTATUS SetNWHomeDir(
+ const TCHAR * pchNWHomeDir
+ )
+
+/*++
+
+Routine Description:
+
+ Store NetWare Home Directory to UserParms If pchNWWorkstations is NULL,
+ this function will delete "NWLgonFrom" field from UserParms.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS err = NERR_Success;
+ UNICODE_STRING uniNWHomeDir;
+ CHAR * pchTemp = NULL;
+ LPWSTR lpNewUserParms = NULL;
+ BOOL fUpdate;
+
+ if (pchNWHomeDir == NULL) {
+ uniNWHomeDir.Buffer = NULL;
+ uniNWHomeDir.Length = 0;
+ uniNWHomeDir.MaximumLength = 0;
+ } else {
+ BOOL fDummy;
+ INT nStringLength = lstrlen(pchNWHomeDir) + 1;
+ pchTemp = (CHAR *) LocalAlloc (LPTR, nStringLength);
+
+ if ( pchTemp == NULL )
+ err = ERROR_NOT_ENOUGH_MEMORY;
+
+ if ( err == NERR_Success && !WideCharToMultiByte (CP_ACP, 0, pchNWHomeDir, nStringLength, pchTemp, nStringLength, NULL, &fDummy))
+ err = GetLastError();
+
+ if ( err == NERR_Success ) {
+ uniNWHomeDir.Buffer = (WCHAR *) pchTemp;
+ uniNWHomeDir.Length = nStringLength;
+ uniNWHomeDir.MaximumLength = nStringLength;
+ }
+ }
+
+ err = err? err : SetUserProperty (UserParms, NWHOMEDIR, uniNWHomeDir, USER_PROPERTY_TYPE_ITEM, &lpNewUserParms, &fUpdate);
+
+ if ((err == NERR_Success) && (lpNewUserParms != NULL)) {
+ if (fUpdate)
+ lstrcpyW(UserParms, lpNewUserParms);
+
+ LocalFree(lpNewUserParms);
+ }
+
+ if (pchTemp != NULL)
+ LocalFree (pchTemp);
+
+ return err;
+} // SetNWHomeDir
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTObjectIDGet(
+ LPTSTR ObjectName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING UniNewObjectName;
+ PULONG pRids = NULL;
+ PSID_NAME_USE pSidNameUse = NULL;
+ ULONG ObjectID = 0;
+
+ RtlInitUnicodeString(&UniNewObjectName, ObjectName);
+
+ status = SamLookupNamesInDomain(DomainHandle,
+ 1,
+ &UniNewObjectName,
+ &pRids,
+ &pSidNameUse);
+
+ if ((status == STATUS_SUCCESS) && (pRids != NULL) && (pSidNameUse != NULL)) {
+ // Found the stupid name - so copy and free SAM garbage
+ ObjectID = pRids[0];
+ ObjectID |= BINDLIB_REMOTE_DOMAIN_BIAS;
+
+ SamFreeMemory(pRids);
+ SamFreeMemory(pSidNameUse);
+ }
+
+ return ObjectID;
+} // NTObjectIDGet
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTSAMParmsSet(
+ LPTSTR ObjectName,
+ FPNW_INFO fpnw,
+ LPTSTR Password,
+ BOOL ForcePasswordChange
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING UniNewObjectName;
+ PULONG pRids = NULL;
+ PSID_NAME_USE pSidNameUse = NULL;
+ ULONG ObjectID;
+ SID_NAME_USE SidNameUse;
+ SAM_HANDLE Handle = (SAM_HANDLE) 0;
+ PUSER_PARAMETERS_INFORMATION UserParmInfo = NULL;
+ USER_PARAMETERS_INFORMATION NewUserParmInfo;
+ LPWSTR lpNewUserParms = NULL;
+
+ RtlInitUnicodeString(&UniNewObjectName, ObjectName);
+
+ status = SamLookupNamesInDomain(DomainHandle,
+ 1,
+ &UniNewObjectName,
+ &pRids,
+ &pSidNameUse);
+
+ if ((status == STATUS_SUCCESS) && (pRids != NULL) && (pSidNameUse != NULL)) {
+ // Found the stupid name - so copy and free SAM garbage
+ ObjectID = pRids[0];
+ SidNameUse = pSidNameUse[0];
+
+ SamFreeMemory(pRids);
+ SamFreeMemory(pSidNameUse);
+
+ status = SamOpenUser(DomainHandle,
+ STANDARD_RIGHTS_READ |
+ STANDARD_RIGHTS_WRITE |
+ USER_ALL_ACCESS,
+ ObjectID,
+ &Handle);
+
+
+ // Now get the user parms
+ if (status == STATUS_SUCCESS)
+ status = SamQueryInformationUser(Handle, UserParametersInformation, (PVOID *) &UserParmInfo);
+
+ memset(UserParms, 0, sizeof(UserParms));
+ if ((status == STATUS_SUCCESS) && (UserParmInfo != NULL)) {
+ memcpy(UserParms, UserParmInfo->Parameters.Buffer, UserParmInfo->Parameters.Length * sizeof(WCHAR));
+ SamFreeMemory(UserParmInfo);
+
+ if (
+ ((status = SetNWPassword (ObjectID, Password, ForcePasswordChange)) == NERR_Success) &&
+ ((status = SetMaxConnections (fpnw.MaxConnections)) == NERR_Success) &&
+ ((status = SetGraceLoginAllowed (fpnw.GraceLoginAllowed)) == NERR_Success) &&
+ ((status = SetGraceLoginRemainingTimes (fpnw.GraceLoginRemaining)) == NERR_Success) &&
+ ((status = SetNWWorkstations (fpnw.LoginFrom)) == NERR_Success) &&
+ ((status = SetNWHomeDir (fpnw.HomeDir)) == NERR_Success) )
+ {
+ RtlInitUnicodeString(&NewUserParmInfo.Parameters, UserParms);
+ status = SamSetInformationUser(Handle, UserParametersInformation, (PVOID) &NewUserParmInfo);
+ }
+
+ }
+ }
+
+ if (Handle != (SAM_HANDLE) 0)
+ SamCloseHandle(Handle);
+
+ return 0;
+} // NTSAMParmsSet
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTSAMConnect(
+ LPTSTR ServerName,
+ LPTSTR DomainName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ OBJECT_ATTRIBUTES object_attrib;
+ UNICODE_STRING UniDomainName;
+ UNICODE_STRING UniServerName;
+
+ //
+ // Do all the garbage for connecting to SAM
+ //
+ RtlInitUnicodeString(&UniServerName, ServerName);
+ RtlInitUnicodeString(&UniDomainName, DomainName);
+ InitializeObjectAttributes(&object_attrib, NULL, 0, NULL, NULL);
+ status = SamConnect(&UniServerName, &SAMHandle, SAM_SERVER_ALL_ACCESS, &object_attrib);
+
+ if (status == STATUS_SUCCESS)
+ status = SamLookupDomainInSamServer(SAMHandle, &UniDomainName, &DomainID);
+
+ if (status == STATUS_SUCCESS)
+ status = SamOpenDomain(SAMHandle, DOMAIN_ALL_ACCESS, DomainID, &DomainHandle);
+
+ FPNWSecretGet(ServerName);
+ return (DWORD) status;
+} // NTSAMConnect
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTSAMClose()
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ if (DomainHandle != (SAM_HANDLE) 0)
+ SamCloseHandle(DomainHandle);
+
+ if (DomainID != (PSID) 0)
+ SamFreeMemory(DomainID);
+
+ if (SAMHandle != (SAM_HANDLE) 0)
+ SamCloseHandle(SAMHandle);
+
+ SAMHandle = (SAM_HANDLE) 0;
+ DomainHandle = (SAM_HANDLE) 0;
+ DomainID = (PSID) 0;
+
+} // NTSAMClose
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTServerSet(
+ LPTSTR ServerName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+
+ // Fixup the destination server name
+ lstrcpy(CachedServer, TEXT("\\\\"));
+ lstrcat(CachedServer, ServerName);
+
+ if (!LocalName)
+ GetLocalName(&LocalName);
+
+ if (lstrcmpi(ServerName, LocalName) == 0)
+ LocalMachine = TRUE;
+ else
+ LocalMachine = FALSE;
+
+ if (FpnwHandle == NULL)
+ FpnwHandle = LoadLibrary(TEXT("FPNWCLNT.DLL"));
+
+ if ((FpnwHandle != NULL) && (pFpnwVolumeEnum == NULL)) {
+ pFpnwVolumeEnum = GetProcAddress(FpnwHandle, ("FpnwVolumeEnum"));
+ pFpnwApiBufferFree = GetProcAddress(FpnwHandle, ("FpnwApiBufferFree"));
+ }
+
+ return (0);
+
+} // NTServerSet
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTServerFree()
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LocalMachine = FALSE;
+ lstrcpy(CachedServer, TEXT(""));
+ return (0);
+
+} // NTServerFree
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+FPNWShareAdd(
+ LPTSTR ShareName,
+ LPTSTR Path
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NET_API_STATUS Status = 0;
+ NWVOLUMEINFO NWVol;
+
+ if (FPNWLib == NULL)
+ FPNWLib = LoadLibrary(TEXT("FPNWCLNT.DLL"));
+
+ if (FPNWLib == NULL)
+ return 1;
+
+ if (NWVolumeAdd == NULL)
+ NWVolumeAdd = (DWORD (FAR * ) (LPWSTR, DWORD, PNWVOLUMEINFO)) GetProcAddress(FPNWLib, "NwVolumeAdd");
+
+ NWVol.lpVolumeName = AllocMemory((lstrlen(ShareName) + 1) * sizeof(TCHAR));
+ NWVol.lpPath = AllocMemory((lstrlen(Path) + 1) * sizeof(TCHAR));
+ if ((NWVol.lpVolumeName == NULL) || (NWVol.lpPath == NULL))
+ return 1;
+
+ lstrcpy(NWVol.lpVolumeName, ShareName);
+ NWVol.dwType = NWVOL_TYPE_DISKTREE;
+ NWVol.dwMaxUses = NWVOL_MAX_USES_UNLIMITED;
+ NWVol.dwCurrentUses = 0;
+ lstrcpy(NWVol.lpPath, Path);
+
+ if (LocalMachine)
+ Status = NWVolumeAdd(NULL, 1, &NWVol);
+ else
+ Status = NWVolumeAdd(CachedServer, 1, &NWVol);
+
+ return Status;
+
+} // FPNWShareAdd
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTShareAdd(
+ LPTSTR ShareName,
+ LPTSTR Path
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NET_API_STATUS Status = 0;
+ SHARE_INFO_2 shi2;
+ DWORD parmerr;
+
+ memset(&shi2, 0, sizeof(SHARE_INFO_2));
+
+ shi2.shi2_netname = ShareName;
+ shi2.shi2_type = STYPE_DISKTREE;
+ shi2.shi2_max_uses = (DWORD) 0xffffffff;
+ shi2.shi2_path = Path;
+
+ if (LocalMachine)
+ Status = NetShareAdd(NULL, 2, (LPBYTE) &shi2, &parmerr);
+ else
+ Status = NetShareAdd(CachedServer, 2, (LPBYTE) &shi2, &parmerr);
+
+ return Status;
+
+} // NTShareAdd
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTUsersEnum(
+ USER_LIST **lpUserList
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPUSER_INFO_0 buffer = NULL;
+ NET_API_STATUS Status = 0;
+ DWORD prefmaxlength = 0xffffffff;
+ DWORD totalentries = 0;
+ DWORD entriesread = 0;
+ DWORD resumehandle = 0;
+ DWORD i;
+ USER_LIST *UserList = NULL;
+ USER_BUFFER *UserBuffer = NULL;
+
+ if (LocalMachine)
+ Status = NetUserEnum(NULL, 0, 0, (LPBYTE *) &buffer, prefmaxlength, &entriesread, &totalentries, &resumehandle);
+ else
+ Status = NetUserEnum(CachedServer, 0, 0, (LPBYTE *) &buffer, prefmaxlength, &entriesread, &totalentries, &resumehandle);
+
+ if (Status == NO_ERROR) {
+
+ UserList = AllocMemory(sizeof(USER_LIST) + (sizeof(USER_BUFFER) * entriesread));
+
+ if (!UserList) {
+ Status = ERROR_NOT_ENOUGH_MEMORY;
+ } else {
+ UserBuffer = UserList->UserBuffer;
+
+ for (i = 0; i < entriesread; i++) {
+ lstrcpy(UserBuffer[i].Name, buffer[i].usri0_name);
+ lstrcpy(UserBuffer[i].NewName, buffer[i].usri0_name);
+ }
+
+ qsort((void *) UserBuffer, (size_t) entriesread, sizeof(USER_BUFFER), UserListCompare);
+ }
+ }
+
+ if (buffer != NULL)
+ NetApiBufferFree((LPVOID) buffer);
+
+ if (UserList != NULL)
+ UserList->Count = entriesread;
+
+ *lpUserList = UserList;
+ return Status;
+
+} // NTUsersEnum
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTGroupsEnum(
+ GROUP_LIST **lpGroupList
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPGROUP_INFO_0 buffer = NULL;
+ NET_API_STATUS Status = 0;
+ DWORD prefmaxlength = 0xffffffff;
+ DWORD totalentries = 0;
+ DWORD entriesread = 0;
+ DWORD resumehandle = 0;
+ DWORD i;
+ GROUP_LIST *GroupList = NULL;
+ GROUP_BUFFER *GroupBuffer = NULL;
+
+ if (LocalMachine)
+ Status = NetGroupEnum(NULL, 0, (LPBYTE *) &buffer, prefmaxlength, &entriesread, &totalentries, &resumehandle);
+ else
+ Status = NetGroupEnum(CachedServer, 0, (LPBYTE *) &buffer, prefmaxlength, &entriesread, &totalentries, &resumehandle);
+
+ if (Status == NO_ERROR) {
+
+ GroupList = AllocMemory(sizeof(GROUP_LIST) + (sizeof(GROUP_BUFFER) * entriesread));
+
+ if (!GroupList) {
+ Status = ERROR_NOT_ENOUGH_MEMORY;
+ } else {
+ GroupBuffer = GroupList->GroupBuffer;
+
+ for (i = 0; i < entriesread; i++) {
+ lstrcpy(GroupBuffer[i].Name, buffer[i].grpi0_name);
+ lstrcpy(GroupBuffer[i].NewName, buffer[i].grpi0_name);
+ }
+ }
+ }
+
+ if (buffer != NULL)
+ NetApiBufferFree((LPVOID) buffer);
+
+ if (GroupList != NULL)
+ GroupList->Count = entriesread;
+
+ *lpGroupList = GroupList;
+ return Status;
+
+} // NTGroupsEnum
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTDomainEnum(
+ SERVER_BROWSE_LIST **lpServList
+ )
+
+/*++
+
+Routine Description:
+
+ Enumerates all NT servers in a given domain.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPSERVER_INFO_101 buffer = NULL;
+ NET_API_STATUS Status = 0;
+ DWORD prefmaxlength = 0xffffffff;
+ DWORD totalentries = 0;
+ DWORD entriesread = 0;
+ DWORD resumehandle = 0;
+ DWORD i;
+ BOOL Container = FALSE;
+ SERVER_BROWSE_LIST *ServList = NULL;
+ SERVER_BROWSE_BUFFER *SList;
+
+ Status = NetServerEnum(NULL, 101, (LPBYTE *) &buffer, prefmaxlength, &entriesread, &totalentries, SV_TYPE_DOMAIN_ENUM, NULL, &resumehandle);
+
+ if (Status == NO_ERROR) {
+
+ ServList = AllocMemory(sizeof(SERVER_BROWSE_LIST) + (sizeof(SERVER_BROWSE_BUFFER) * entriesread));
+
+ if (!ServList) {
+ Status = ERROR_NOT_ENOUGH_MEMORY;
+ } else {
+ ServList->Count = entriesread;
+ SList = (SERVER_BROWSE_BUFFER *) &ServList->SList;
+
+ for (i = 0; i < entriesread; i++) {
+ lstrcpy(SList[i].Name, buffer[i].sv101_name);
+ lstrcpy(SList[i].Description, buffer[i].sv101_comment);
+ SList[i].Container = FALSE;
+ SList[i].child = NULL;
+ }
+ }
+ }
+
+ if (buffer != NULL)
+ NetApiBufferFree((LPVOID) buffer);
+
+ *lpServList = ServList;
+ return Status;
+
+} // NTDomainEnum
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTServerEnum(
+ LPTSTR szContainer,
+ SERVER_BROWSE_LIST **lpServList
+ )
+
+/*++
+
+Routine Description:
+
+ Enumerates all NT servers in a given domain.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPSERVER_INFO_101 buffer = NULL;
+ NET_API_STATUS Status = 0;
+ DWORD prefmaxlength = 0xffffffff;
+ DWORD totalentries = 0;
+ DWORD entriesread = 0;
+ DWORD resumehandle = 0;
+ DWORD i;
+ BOOL Container = FALSE;
+ SERVER_BROWSE_LIST *ServList = NULL;
+ SERVER_BROWSE_BUFFER *SList;
+
+ if (((szContainer != NULL) && (lstrlen(szContainer))))
+ Container = TRUE;
+
+ if (Container)
+ Status = NetServerEnum(NULL, 101, (LPBYTE *) &buffer, prefmaxlength, &entriesread, &totalentries, SV_TYPE_NT, szContainer, &resumehandle);
+ else
+ Status = NetServerEnum(NULL, 101, (LPBYTE *) &buffer, prefmaxlength, &entriesread, &totalentries, SV_TYPE_DOMAIN_ENUM, NULL, &resumehandle);
+
+ if (Status == NO_ERROR) {
+
+ ServList = AllocMemory(sizeof(SERVER_BROWSE_LIST) + (sizeof(SERVER_BROWSE_BUFFER) * entriesread));
+
+ if (!ServList) {
+ Status = ERROR_NOT_ENOUGH_MEMORY;
+ } else {
+ ServList->Count = entriesread;
+ SList = (SERVER_BROWSE_BUFFER *) &ServList->SList;
+
+ for (i = 0; i < entriesread; i++) {
+ lstrcpy(SList[i].Name, buffer[i].sv101_name);
+ lstrcpy(SList[i].Description, buffer[i].sv101_comment);
+ SList[i].Container = !Container;
+ SList[i].child = NULL;
+ }
+ }
+ }
+
+ if (buffer != NULL)
+ NetApiBufferFree((LPVOID) buffer);
+
+ *lpServList = ServList;
+ return Status;
+
+} // NTServerEnum
+
+
+/////////////////////////////////////////////////////////////////////////
+BOOL
+NTShareNameValidate(
+ LPTSTR szShareName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ TCHAR *ptr = szShareName;
+ BOOL ret;
+
+ ret = TRUE;
+
+ if (*ptr) {
+ // go to end
+ while (*ptr)
+ ptr++;
+
+ // now back up to last character
+ ptr--;
+ if (*ptr == TEXT('$')) // for ADMIN$, IPC$, etc...
+ ret = FALSE;
+
+ } else
+ // Don't allow zero length - not sure why we would ever get these...
+ ret = FALSE;
+
+ return ret;
+
+} // NTShareNameValidate
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTSharesEnum(
+ SHARE_LIST **lpShares,
+ DRIVE_LIST *Drives
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPSHARE_INFO_2 buffer = NULL;
+ NET_API_STATUS Status = 0;
+ DWORD prefmaxlength = 0xffffffff;
+ DWORD totalentries = 0;
+ DWORD entriesread = 0;
+ DWORD ActualEntries = 0;
+ DWORD resumehandle = 0;
+ DWORD i, di;
+ SHARE_LIST *ShareList = NULL;
+ SHARE_BUFFER *SList;
+ DRIVE_BUFFER *DList;
+ ULONG TotalDrives;
+ TCHAR Drive[2];
+ PFPNWVOLUMEINFO VolumeInfo, VolumeEntry;
+ BOOL Found;
+
+ if (LocalMachine)
+ Status = NetShareEnum(NULL, 2, (LPBYTE *) &buffer, prefmaxlength, &entriesread, &totalentries, &resumehandle);
+ else
+ Status = NetShareEnum(CachedServer, 2, (LPBYTE *) &buffer, prefmaxlength, &entriesread, &totalentries, &resumehandle);
+
+ if (Status == NO_ERROR) {
+
+ // We have the list - but need to prune out IPC$, Admin$, etc...
+ for (i = 0; i < entriesread; i++)
+ if ((buffer[i].shi2_type == STYPE_DISKTREE) && NTShareNameValidate(buffer[i].shi2_netname))
+ ActualEntries++;
+
+ ShareList = AllocMemory(sizeof(SHARE_LIST) + (sizeof(SHARE_BUFFER) * ActualEntries));
+
+ if (!ShareList) {
+ Status = ERROR_NOT_ENOUGH_MEMORY;
+ } else {
+ SList = (SHARE_BUFFER *) &ShareList->SList;
+
+ ShareList->Count = ActualEntries;
+ ActualEntries = 0;
+
+ TotalDrives = 0;
+ Drive[1] = TEXT('\0');
+ if (Drives != NULL) {
+ DList = Drives->DList;
+ TotalDrives = Drives->Count;
+ }
+
+ // loop through copying the data
+ for (i = 0; i < entriesread; i++)
+ if ((buffer[i].shi2_type == STYPE_DISKTREE) && NTShareNameValidate(buffer[i].shi2_netname)) {
+ lstrcpy(SList[ActualEntries].Name, buffer[i].shi2_netname);
+ lstrcpy(SList[ActualEntries].Path, buffer[i].shi2_path);
+ SList[ActualEntries].Index = (USHORT) ActualEntries;
+
+ // Scan drive list looking for match to share path
+ for (di = 0; di < TotalDrives; di++) {
+ // Get first char from path - should be drive letter
+ Drive[0] = *buffer[i].shi2_path;
+ if (!lstrcmpi(Drive, DList[di].Drive))
+ SList[ActualEntries].Drive = &DList[di];
+ }
+
+ ActualEntries++;
+ }
+
+ }
+ }
+
+ //
+ // Now loop through any FPNW shares and tack those on as well
+ //
+ VolumeInfo = NULL;
+ resumehandle = entriesread = 0;
+
+ if (pFpnwVolumeEnum != NULL)
+ if (LocalMachine)
+ Status = (*pFpnwVolumeEnum) ( NULL, 1, (LPBYTE *)&VolumeInfo, &entriesread, &resumehandle );
+ else
+ Status = (*pFpnwVolumeEnum) ( CachedServer, 1, (LPBYTE *)&VolumeInfo, &entriesread, &resumehandle );
+
+#if DBG
+dprintf(TEXT("Status: 0x%lX Entries: %lu\n"), Status, entriesread);
+#endif
+ if ( !Status && entriesread ) {
+
+ if (ShareList)
+ ShareList = ReallocMemory(ShareList, sizeof(SHARE_LIST) + (sizeof(SHARE_BUFFER) * (ActualEntries + entriesread)));
+ else
+ ShareList = AllocMemory(sizeof(SHARE_LIST) + (sizeof(SHARE_BUFFER) * entriesread));
+
+ if (!ShareList) {
+ Status = ERROR_NOT_ENOUGH_MEMORY;
+ } else {
+ SList = (SHARE_BUFFER *) &ShareList->SList; // reset pointer...
+
+ // loop through copying the data
+ for (i = 0; i < entriesread; i++) {
+ //
+ // Make sure not in NT Share list already
+ //
+ Found = FALSE;
+
+ for (di = 0; di < ShareList->Count; di++)
+ if (!lstrcmpi(SList[di].Name, VolumeInfo[i].lpVolumeName))
+ Found = TRUE;
+
+ if ((!Found) && (VolumeInfo[i].dwType == FPNWVOL_TYPE_DISKTREE) ) {
+ lstrcpy(SList[ActualEntries].Name, VolumeInfo[i].lpVolumeName);
+ lstrcpy(SList[ActualEntries].Path, VolumeInfo[i].lpPath);
+ SList[ActualEntries].Index = (USHORT) ActualEntries;
+
+ // Scan drive list looking for match to share path
+ for (di = 0; di < TotalDrives; di++) {
+ // Get first char from path - should be drive letter
+ Drive[0] = *VolumeInfo[i].lpPath;
+ if (!lstrcmpi(Drive, DList[di].Drive))
+ SList[ActualEntries].Drive = &DList[di];
+ }
+
+ ActualEntries++;
+ }
+ }
+ }
+ }
+
+ if (ShareList)
+ ShareList->Count = ActualEntries;
+
+ if (VolumeInfo && (pFpnwApiBufferFree != NULL))
+ (*pFpnwApiBufferFree) ( VolumeInfo );
+
+ if (buffer != NULL)
+ NetApiBufferFree((LPVOID) buffer);
+
+ *lpShares = ShareList;
+ return Status;
+} // NTSharesEnum
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTGroupSave(
+ LPTSTR Name
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static NET_API_STATUS Status = 0;
+ GROUP_INFO_0 grpi0;
+ DWORD err;
+
+ grpi0.grpi0_name = Name;
+
+ if (LocalMachine)
+ Status = NetGroupAdd(NULL, 0, (LPBYTE) &grpi0, &err);
+ else {
+ Status = NetGroupAdd(CachedServer, 0, (LPBYTE) &grpi0, &err);
+ }
+ return Status;
+
+} // NTGroupSave
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTGroupUserAdd(
+ LPTSTR GroupName,
+ LPTSTR UserName,
+ BOOL Local
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NET_API_STATUS Status = 0;
+ SID *pUserSID = NULL;
+
+ if (LocalMachine)
+ if (Local) {
+ pUserSID = NTSIDGet(NULL, UserName);
+
+ if (pUserSID != NULL)
+ Status = NetLocalGroupAddMember(NULL, GroupName, pUserSID);
+
+ } else
+ Status = NetGroupAddUser(NULL, GroupName, UserName);
+ else {
+ if (Local) {
+ pUserSID = NTSIDGet(CachedServer, UserName);
+
+ if (pUserSID != NULL)
+ Status = NetLocalGroupAddMember(CachedServer, GroupName, pUserSID);
+ } else
+ Status = NetGroupAddUser(CachedServer, GroupName, UserName);
+ }
+
+ // If complaining because user is already there, ignore
+ if (Status == NERR_UserInGroup)
+ Status = 0;
+
+ return Status;
+
+} // NTGroupUserAdd
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTUserInfoSave(
+ NT_USER_INFO *NT_UInfo,
+ PFPNW_INFO fpnw
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static NET_API_STATUS Status = 0;
+ struct _USER_INFO_3 *usri3;
+ DWORD err;
+
+ usri3 = (struct _USER_INFO_3 *) NT_UInfo;
+
+ // Map logon hours to GMT time - as NetAPI re-fixes it
+ NetpRotateLogonHours(NT_UInfo->logon_hours, UNITS_PER_WEEK, TRUE);
+
+ if (LocalMachine)
+ Status = NetUserAdd(NULL, 3, (LPBYTE) usri3, &err);
+ else
+ Status = NetUserAdd(CachedServer, 3, (LPBYTE) usri3, &err);
+
+ if ((!Status) && (fpnw != NULL)) {
+ // Need to get user info via LSA call before calling setuserparms
+ }
+
+ return Status;
+
+} // NTUserInfoSave
+
+
+#define NEW_NULL_PASSWD TEXT(" ")
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTUserInfoSet(
+ NT_USER_INFO *NT_UInfo,
+ PFPNW_INFO fpnw
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPWSTR Password;
+ LPWSTR Name;
+ static NET_API_STATUS Status = 0;
+ struct _USER_INFO_3 *usri3;
+ DWORD err;
+
+ // Tell it not to replace the password
+ Password = NT_UInfo->password;
+ NT_UInfo->password = NULL;
+
+ Name = NT_UInfo->name;
+ usri3 = (struct _USER_INFO_3 *) NT_UInfo;
+
+ // Map logon hours to GMT time - as NetAPI re-fixes it
+ NetpRotateLogonHours(NT_UInfo->logon_hours, UNITS_PER_WEEK, TRUE);
+
+ if (LocalMachine)
+ Status = NetUserSetInfo(NULL, Name, 3, (LPBYTE) usri3, &err);
+ else
+ Status = NetUserSetInfo(CachedServer, Name, 3, (LPBYTE) usri3, &err);
+
+ if ((!Status) && (fpnw != NULL)) {
+ }
+
+ // Reset the password in our data structure.
+ NT_UInfo->password = Password;
+ return Status;
+
+} // NTUserInfoSet
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTUserRecInit(
+ LPTSTR UserName,
+ NT_USER_INFO *NT_UInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a user record, uses static variables for string holders
+ so is not re-entrant, and will overwrite previous records data if
+ called again.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static TCHAR uname[UNLEN + 1];
+ static TCHAR upassword[ENCRYPTED_PWLEN];
+ static TCHAR uhomedir[PATHLEN + 1];
+ static TCHAR ucomment[MAXCOMMENTSZ + 1];
+ static TCHAR uscriptpath[PATHLEN + 1];
+ static TCHAR ufullname[MAXCOMMENTSZ + 1];
+ static TCHAR uucomment[MAXCOMMENTSZ + 1];
+ static TCHAR uparms[MAXCOMMENTSZ + 1];
+ static TCHAR uworkstations[1];
+ static BYTE ulogonhours[21];
+ static TCHAR ulogonserver[1];
+ static TCHAR uprofile[1];
+ static TCHAR uhome_dir_drive[1];
+
+ // init all the static data holders.
+ memset(uname, 0, sizeof( uname ));
+ lstrcpy(uname, UserName);
+
+ memset(upassword, 0, sizeof( upassword ));
+ memset(uhomedir, 0, sizeof( uhomedir ));
+ memset(ucomment, 0, sizeof( ucomment ));
+ memset(uscriptpath, 0, sizeof( uscriptpath ));
+ memset(ufullname, 0, sizeof( ufullname ));
+ memset(uucomment, 0, sizeof( uucomment ));
+ memset(uparms, 0, sizeof( uparms ));
+ memset(uworkstations, 0, sizeof( uworkstations ));
+ memset(ulogonhours, 0, sizeof( ulogonhours ));
+ memset(ulogonserver, 0, sizeof( ulogonserver ));
+ memset(uprofile, 0, sizeof( uprofile ));
+ memset(uhome_dir_drive, 0, sizeof( uhome_dir_drive ));
+
+ memset(NT_UInfo, 0, sizeof(NT_USER_INFO));
+
+ // point the passed in record to these data holders
+ NT_UInfo->name = uname;
+ NT_UInfo->password = upassword;
+ NT_UInfo->home_dir = uhomedir;
+ NT_UInfo->comment = ucomment;
+ NT_UInfo->script_path = uscriptpath;
+ NT_UInfo->full_name = ufullname;
+ NT_UInfo->usr_comment = uucomment;
+ NT_UInfo->parms = uparms;
+ NT_UInfo->workstations = uworkstations;
+ NT_UInfo->logon_hours = ulogonhours;
+ NT_UInfo->logon_server = ulogonserver;
+ NT_UInfo->profile = uprofile;
+ NT_UInfo->home_dir_drive = uhome_dir_drive;
+ NT_UInfo->units_per_week = UNITS_PER_WEEK;
+
+ // Set the default values for special fields
+ NT_UInfo->primary_group_id = DOMAIN_GROUP_RID_USERS;
+ NT_UInfo->priv = USER_PRIV_USER;
+ NT_UInfo->acct_expires = TIMEQ_FOREVER;
+ NT_UInfo->max_storage = USER_MAXSTORAGE_UNLIMITED;
+ NT_UInfo->flags = UF_SCRIPT;
+
+} // NTUserRecInit
+
+
+/////////////////////////////////////////////////////////////////////////
+LPTSTR
+NTDriveShare(
+ LPTSTR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static TCHAR RootPath[MAX_SERVER_NAME_LEN + 3];
+
+ if (LocalMachine)
+ wsprintf(RootPath, TEXT("%s:\\"), DriveLetter);
+ else
+ wsprintf(RootPath, TEXT("%s\\%s$\\"), CachedServer, DriveLetter);
+
+ return RootPath;
+
+} // NTDriveShare
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTDriveInfoGet(
+ DRIVE_BUFFER *DBuff
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ DWORD volMaxCompLength, volFileSystemFlags;
+ DWORD sectorsPC, bytesPS, FreeClusters, Clusters;
+ TCHAR NameBuffer[20];
+ TCHAR volName[20];
+ LPTSTR RootPath;
+ UINT previousErrorMode;
+
+ //
+ // Disable DriveAccess Error, because no media is inserted onto specified drive.
+ //
+ previousErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS|
+ SEM_NOOPENFILEERRORBOX);
+
+ volMaxCompLength = volFileSystemFlags = 0;
+ sectorsPC = bytesPS = FreeClusters = Clusters = 0;
+
+ // First get file system type
+ RootPath = NTDriveShare(DBuff->Drive);
+ if (GetVolumeInformation(RootPath, volName, sizeof(volName), NULL, &volMaxCompLength, &volFileSystemFlags, NameBuffer, sizeof(NameBuffer))) {
+ if (GetDriveType(RootPath) == DRIVE_CDROM)
+ lstrcpy(DBuff->DriveType, Lids(IDS_S_49));
+ else
+ lstrcpyn(DBuff->DriveType, NameBuffer, sizeof(DBuff->DriveType)-1);
+
+ lstrcpyn(DBuff->Name, volName, sizeof(DBuff->Name)-1);
+
+ if (!lstrcmpi(NameBuffer, Lids(IDS_S_9)))
+ DBuff->Type = DRIVE_TYPE_NTFS;
+ }
+ else {
+ if (GetDriveType(RootPath) == DRIVE_CDROM)
+ lstrcpy(DBuff->DriveType, Lids(IDS_S_49));
+ else
+ lstrcpy(DBuff->DriveType, TEXT("\0"));
+
+ lstrcpy(DBuff->Name, TEXT("\0"));
+
+ if (!lstrcmpi(NameBuffer, Lids(IDS_S_9)))
+ DBuff->Type = DRIVE_TYPE_NTFS;
+ }
+
+ if (GetDiskFreeSpace(RootPath, &sectorsPC, &bytesPS, &FreeClusters, &Clusters)) {
+ DBuff->TotalSpace = Clusters * sectorsPC * bytesPS;
+ DBuff->FreeSpace = FreeClusters * sectorsPC * bytesPS;
+ }
+ else {
+ DBuff->TotalSpace = 0;
+ DBuff->FreeSpace = 0;
+ }
+
+ //
+ // Back to original error mode.
+ //
+ SetErrorMode(previousErrorMode);
+
+} // NTDriveInfoGet
+
+
+/////////////////////////////////////////////////////////////////////////
+BOOL
+NTDriveValidate(
+ TCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ BOOL ret = FALSE;
+
+ // Just make sure it isn't one of the two floppys
+ if (!((DriveLetter == TEXT('A')) || (DriveLetter == TEXT('B'))))
+ ret = TRUE;
+
+ return ret;
+
+} // NTDriveValidate
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTDrivesEnum(
+ DRIVE_LIST **lpDrives
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ TCHAR *buffer = NULL;
+ NET_API_STATUS Status = 0;
+ DWORD entriesread, totalentries, resumehandle, actualentries, i;
+ DRIVE_LIST *DriveList;
+ DRIVE_BUFFER *DList;
+
+ entriesread = totalentries = resumehandle = actualentries = 0;
+
+ if (LocalMachine)
+ Status = NetServerDiskEnum(NULL, 0, (LPBYTE *) &buffer, 0xFFFFFFFF, &entriesread, &totalentries, &resumehandle);
+ else
+ Status = NetServerDiskEnum(CachedServer, 0, (LPBYTE *) &buffer, 0xFFFFFFFF, &entriesread, &totalentries, &resumehandle);
+
+ if (Status == NO_ERROR) {
+ // We have the list - but need to prune out A:, B:
+ for (i = 0; i < entriesread; i++)
+ if (NTDriveValidate(buffer[i * 3]))
+ actualentries++;
+
+ // temporarily use i to hold total size of data structure
+ i = sizeof(DRIVE_LIST) + (sizeof(DRIVE_BUFFER) * actualentries);
+ DriveList = AllocMemory(i);
+
+ if (!DriveList) {
+ Status = ERROR_NOT_ENOUGH_MEMORY;
+ } else {
+ memset(DriveList, 0, i);
+ DList = (DRIVE_BUFFER *) &DriveList->DList;
+ DriveList->Count = actualentries;
+
+ // Now fill in the individual data items
+ actualentries = 0;
+ for (i = 0; i < entriesread; i++)
+ if (NTDriveValidate(buffer[i * 3])) {
+ DList[actualentries].Drive[0] = buffer[i * 3];
+ NTDriveInfoGet(&DList[actualentries]);
+ actualentries++;
+ }
+ }
+ }
+
+ if (buffer != NULL)
+ NetApiBufferFree((LPVOID) buffer);
+
+ *lpDrives = DriveList;
+ return;
+
+} // NTDrivesEnum
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTServerGetInfo(
+ LPTSTR ServerName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ TCHAR LocServer[MAX_SERVER_NAME_LEN + 3];
+ NET_API_STATUS Status = 0;
+
+ if (ServInfo != NULL)
+ NetApiBufferFree((LPVOID) ServInfo);
+
+ ServInfo = NULL;
+
+ wsprintf(LocServer, TEXT("\\\\%s"), ServerName);
+
+ if (!LocalName)
+ GetLocalName(&LocalName);
+
+ if (lstrcmpi(ServerName, LocalName) == 0)
+ Status = NetServerGetInfo(NULL, 101, (LPBYTE *) &ServInfo);
+ else
+ Status = NetServerGetInfo(LocServer, 101, (LPBYTE *) &ServInfo);
+
+ if (Status) {
+ ServInfo = NULL;
+ return;
+ }
+
+} // NTServerGetInfo
+
+
+/////////////////////////////////////////////////////////////////////////
+NT_CONN_BUFFER *
+NTConnListFind(
+ LPTSTR ServerName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ BOOL Found = FALSE;
+ static NT_CONN_BUFFER *ServList;
+
+ ServList = NTConnListStart;
+
+ while ((ServList && !Found)) {
+ if (!lstrcmpi(ServList->Name, ServerName))
+ Found = TRUE;
+ else
+ ServList = ServList->next;
+ }
+
+ if (!Found)
+ ServList = NULL;
+
+ return (ServList);
+
+} // NTConnListFind
+
+
+/////////////////////////////////////////////////////////////////////////
+NT_CONN_BUFFER *
+NTConnListAdd(
+ LPTSTR ServerName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static NT_CONN_BUFFER *tmpPtr;
+ ULONG Size, strlen1;
+
+ tmpPtr = NULL;
+ strlen1 = (lstrlen(ServerName) + 1) * sizeof(TCHAR);
+ Size = sizeof(NT_CONN_BUFFER) + strlen1;
+ tmpPtr = AllocMemory(Size);
+
+ if (tmpPtr != NULL) {
+ // init it to NULL's
+ memset(tmpPtr, 0, Size);
+ tmpPtr->Name = (LPTSTR) ((BYTE *) tmpPtr + sizeof(NT_CONN_BUFFER));
+ lstrcpy(tmpPtr->Name, ServerName);
+
+ // link it into the list
+ if (!NTConnListStart)
+ NTConnListStart = NTConnListEnd = tmpPtr;
+ else {
+ NTConnListEnd->next = tmpPtr;
+ tmpPtr->prev = NTConnListEnd;
+ NTConnListEnd = tmpPtr;
+ }
+ }
+
+ return (tmpPtr);
+
+} // NTConnListAdd
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTConnListDelete(
+ NT_CONN_BUFFER *tmpPtr
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NT_CONN_BUFFER *PrevPtr;
+ NT_CONN_BUFFER *NextPtr;
+
+ if (tmpPtr == NULL)
+ return;
+
+ // Now unlink the actual server record
+ PrevPtr = tmpPtr->prev;
+ NextPtr = tmpPtr->next;
+
+ if (PrevPtr)
+ PrevPtr->next = NextPtr;
+
+ if (NextPtr)
+ NextPtr->prev = PrevPtr;
+
+ // Check if at end of list
+ if (NTConnListEnd == tmpPtr)
+ NTConnListEnd = PrevPtr;
+
+ // Check if at start of list
+ if (NTConnListStart == tmpPtr)
+ NTConnListStart = NextPtr;
+
+ FreeMemory(tmpPtr);
+
+} // NTConnListDelete
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTConnListDeleteAll()
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static TCHAR LocServer[MAX_SERVER_NAME_LEN + 3];
+ NT_CONN_BUFFER *ServList;
+ NT_CONN_BUFFER *ServListNext;
+
+ // Now remove the entries from the internal list
+ ServList = NTConnListStart;
+
+ while (ServList) {
+ ServListNext = ServList->next;
+
+ wsprintf(LocServer, Lids(IDS_S_10), ServList->Name);
+ WNetCancelConnection2(LocServer, 0, FALSE);
+
+ NTConnListDelete(ServList);
+ ServList = ServListNext;
+ }
+
+} // NTConnListDeleteAll
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTUseDel(
+ LPTSTR ServerName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static TCHAR LocServer[MAX_SERVER_NAME_LEN + 3];
+ NT_CONN_BUFFER *NTConn;
+
+ // Find it in our connection list - if it exists get rid of it.
+ NTConn = NTConnListFind(ServerName);
+ if (NTConn != NULL)
+ NTConnListDelete(NTConn);
+
+ NTServerFree();
+ wsprintf(LocServer, Lids(IDS_S_10), ServerName);
+ WNetCancelConnection2(LocServer, 0, FALSE);
+
+} // NTUseDel
+
+
+/////////////////////////////////////////////////////////////////////////
+BOOL
+NTServerValidate(
+ HWND hWnd,
+ LPTSTR ServerName
+ )
+
+/*++
+
+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:
+
+
+--*/
+
+{
+ BOOL ret = FALSE;
+ DWORD idsErr = 0;
+ DWORD lastErr = 0;
+ DWORD Size;
+ NET_API_STATUS Status;
+ LPUSER_INFO_1 UserInfo1 = NULL;
+ TCHAR UserName[MAX_NT_USER_NAME_LEN + 1];
+ TCHAR ServName[MAX_SERVER_NAME_LEN + 3]; // +3 for leading slashes and ending NULL
+ LPVOID lpMessageBuffer = NULL;
+
+ NTServerSet(ServerName);
+
+ // server already connected then return success
+ if (NTConnListFind(ServerName)) {
+ return TRUE;
+ }
+
+ CursorHourGlass();
+
+ // Get Current Logged On User
+ lstrcpy(UserName, TEXT(""));
+ Size = sizeof(UserName);
+ WNetGetUser(NULL, UserName, &Size);
+
+ // Fixup the destination server name
+ lstrcpy(ServName, TEXT( "\\\\" ));
+ lstrcat(ServName, ServerName);
+
+ // Make an ADMIN$ connection to the server
+ if (UseAddPswd(hWnd, UserName, ServName, Lids(IDS_S_11), NT_PROVIDER)) {
+
+ // Double check we have admin privs
+ // Get connection to the system and check for admin privs...
+ Status = NetUserGetInfo(ServName, UserName, 1, (LPBYTE *) &UserInfo1);
+
+ if (Status == ERROR_SUCCESS) {
+
+ // Got User info, now make sure admin flag is set
+ if (!(UserInfo1->usri1_priv & USER_PRIV_ADMIN)) {
+ idsErr = IDS_E_6;
+ goto cleanup;
+ }
+
+ // We may have a connection to admin$ and we may have proven
+ // that the user we made the connection with really is an admin
+ // but sitting at the local machine we still may have a problem
+ // acquiring all of the administrative information necessary to
+ // accomplish a successful conversion. each and every one of the
+ // functions that make network calls should return errors and if
+ // that were the case then the errors would propagate up and we
+ // could deal with the access denial reasonably. unfortunately,
+ // alot of assumptions are made after the success of this call
+ // so we must perform yet another test here...
+ if (LocalMachine) {
+
+ DWORD EntriesRead = 0;
+ DWORD TotalEntries = 0;
+ LPSHARE_INFO_2 ShareInfo2 = NULL;
+
+ Status = NetShareEnum(
+ ServName,
+ 2,
+ (LPBYTE *) &ShareInfo2,
+ MAX_PREFERRED_LENGTH,
+ &EntriesRead,
+ &TotalEntries,
+ NULL
+ );
+
+ if (ShareInfo2 != NULL)
+ NetApiBufferFree((LPVOID) ShareInfo2); // discarded...
+
+ if (Status != ERROR_SUCCESS) {
+ idsErr = (Status == ERROR_ACCESS_DENIED) ? IDS_E_6 : IDS_E_5;
+ goto cleanup;
+ }
+ }
+
+ // Now get server info and make certain this is an NT server
+ // instead of an LM type server. Note: Info from the call is
+ // cached and used later, so don't remove it!!
+ NTServerGetInfo(ServerName);
+
+ if (ServInfo) {
+
+ if (ServInfo->sv101_platform_id == SV_PLATFORM_ID_NT) {
+
+ if (ServInfo->sv101_type & (TYPE_DOMAIN)) {
+
+ // If NTAS and have admin privs then we are set
+ // then add it to our connection list...
+ NTConnListAdd(ServerName);
+ ret = TRUE;
+
+ } else {
+ idsErr = IDS_E_8;
+ }
+
+ } else {
+ idsErr = IDS_E_8;
+ }
+
+ } else {
+ idsErr = IDS_E_7;
+ }
+
+ } else {
+
+ // determine error string id and bail out...
+ idsErr = (Status == ERROR_ACCESS_DENIED) ? IDS_E_6 : IDS_E_5;
+ }
+
+ } else if (lastErr = GetLastError()) {
+
+ // error string id
+ idsErr = IDS_E_9;
+
+ // use system default language resource
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ lastErr,
+ 0,
+ (LPTSTR)&lpMessageBuffer,
+ 0,
+ NULL
+ );
+
+ }
+
+cleanup:
+
+ if (lpMessageBuffer) {
+ WarningError(Lids((WORD)(DWORD)idsErr), ServerName, lpMessageBuffer);
+ LocalFree(lpMessageBuffer);
+ } else if (idsErr) {
+ WarningError(Lids((WORD)(DWORD)idsErr), ServerName);
+ }
+
+ if (UserInfo1 != NULL)
+ NetApiBufferFree((LPVOID) UserInfo1);
+
+ CursorNormal();
+ return ret;
+
+} // NTServerValidate
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTServerInfoReset(
+ HWND hWnd,
+ DEST_SERVER_BUFFER *DServ,
+ BOOL ResetDomain
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPTSTR apiPDCName = NULL;
+ TCHAR PDCName[MAX_SERVER_NAME_LEN + 1];
+ TCHAR LocServer[MAX_SERVER_NAME_LEN + 3];
+ DOMAIN_BUFFER *DBuff;
+ TCHAR Domain[DNLEN + 1];
+ NET_API_STATUS Status = 0;
+
+ lstrcpy(PDCName, TEXT(""));
+
+ if (ServInfo) {
+ DServ->Type = ServInfo->sv101_type;
+ DServ->VerMaj = ServInfo->sv101_version_major;
+ DServ->VerMin = ServInfo->sv101_version_minor;
+ DServ->IsNTAS = IsNTAS(DServ->Name);
+ DServ->IsFPNW = IsFPNW(DServ->Name);
+
+ // If there was no old domain, don't worry about reseting it
+ if (ResetDomain && (DServ->Domain == NULL))
+ ResetDomain = FALSE;
+
+ // Check if we are a member of a domain.
+ if (ServInfo->sv101_type & (TYPE_DOMAIN)) {
+ wsprintf(LocServer, TEXT("\\\\%s"), DServ->Name);
+ Status = NetGetDCName(LocServer, NULL, (LPBYTE *) &apiPDCName);
+
+ if (!Status) {
+ // get rid of leading 2 backslashes
+ if (lstrlen(apiPDCName) > 2)
+ lstrcpy(PDCName, &apiPDCName[2]);
+
+ if (NTServerValidate(hWnd, PDCName)) {
+ DServ->IsFPNW = IsFPNW(PDCName);
+ DServ->InDomain = TRUE;
+
+ // Get Domain
+ memset(Domain, 0, sizeof(Domain));
+ NTDomainGet(DServ->Name, Domain);
+
+ if (ResetDomain) {
+ DomainListDelete(DServ->Domain);
+ DServ->Domain = NULL;
+ }
+
+ // Check if we need to add server to server list
+ DBuff = DomainListFind(Domain);
+
+ if (DBuff == NULL) {
+ DBuff = DomainListAdd(Domain, PDCName);
+ DBuff->Type = ServInfo->sv101_type;
+ DBuff->VerMaj = ServInfo->sv101_version_major;
+ DBuff->VerMin = ServInfo->sv101_version_minor;
+ }
+
+ DBuff->UseCount++;
+ DServ->Domain = DBuff;
+ } // if Domain valid
+
+ if (apiPDCName != NULL)
+ NetApiBufferFree((LPVOID) apiPDCName);
+ }
+
+ }
+
+ }
+
+ // make sure we are pointing to the right one
+ NTServerSet(DServ->Name);
+
+ // Fill in Drive Lists
+ NTDrivesEnum(&DServ->DriveList);
+
+} // NTServerInfoReset
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTServerInfoSet(
+ HWND hWnd,
+ LPTSTR ServerName,
+ DEST_SERVER_BUFFER *DServ
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPTSTR apiPDCName = NULL;
+ NET_API_STATUS Status = 0;
+
+ CursorHourGlass();
+ DServ->UseCount++;
+
+ NTServerInfoReset(hWnd, DServ, FALSE);
+
+ // Fill in share and Drive Lists
+ NTSharesEnum(&DServ->ShareList, DServ->DriveList);
+
+
+#ifdef DEBUG
+{
+ DWORD i;
+
+ dprintf(TEXT("Adding NT Server: %s\n"), DServ->Name);
+ dprintf(TEXT(" Version: %lu.%lu\n"), DServ->VerMaj, DServ->VerMin);
+
+ if (DServ->InDomain && DServ->Domain)
+ dprintf(TEXT(" In Domain: %s [\\\\%s]\n"), DServ->Domain->Name, DServ->Domain->PDCName);
+
+ dprintf(TEXT("\n"));
+ dprintf(TEXT(" Drives:\n"));
+ dprintf(TEXT(" +-------------------+\n"));
+ for (i = 0; i < DServ->DriveList->Count; i++)
+ dprintf(TEXT(" %s\n"), DServ->DriveList->DList[i].Drive);
+ dprintf(TEXT("\n"));
+
+ dprintf(TEXT(" Shares:\n"));
+ dprintf(TEXT(" +-------------------+\n"));
+ for (i = 0; i < DServ->ShareList->Count; i++)
+ dprintf(TEXT(" %s\n"), DServ->ShareList->SList[i].Name);
+ dprintf(TEXT("\n"));
+
+}
+#endif
+
+ CursorNormal();
+
+} // NTServerInfoSet
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTLoginTimesLog(
+ BYTE *Times
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ TCHAR *szDays[7];
+ DWORD Day;
+ DWORD Hours;
+ int Bit = 0;
+ 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_56));
+
+ // while these should be indent 2, there isn't room on 80 cols - so indent 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++) {
+ 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));
+
+} // NTLoginTimesLog
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTUserRecLog(
+ NT_USER_INFO NT_UInfo
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPTSTR tmpStr;
+
+ LogWriteLog(1, Lids(IDS_L_57));
+
+ LogWriteLog(2, Lids(IDS_L_58), NT_UInfo.full_name);
+ LogWriteLog(2, Lids(IDS_L_59), NT_UInfo.password);
+
+ switch(NT_UInfo.priv) {
+ case 0:
+ tmpStr = Lids(IDS_L_60);
+ break;
+
+ case 1:
+ tmpStr = Lids(IDS_L_61);
+ break;
+
+ case 2:
+ tmpStr = Lids(IDS_L_62);
+ break;
+ }
+
+ LogWriteLog(2, Lids(IDS_L_63), tmpStr);
+
+ LogWriteLog(2, Lids(IDS_L_64), NT_UInfo.home_dir);
+ LogWriteLog(2, Lids(IDS_L_65), NT_UInfo.comment);
+
+ // Flags
+ LogWriteLog(2, Lids(IDS_L_66));
+ if (NT_UInfo.flags & 0x01)
+ LogWriteLog(3, Lids(IDS_L_67), Lids(IDS_YES));
+ else
+ LogWriteLog(3, Lids(IDS_L_67), Lids(IDS_NO));
+
+ if (NT_UInfo.flags & 0x02)
+ LogWriteLog(3, Lids(IDS_L_68), Lids(IDS_YES));
+ else
+ LogWriteLog(3, Lids(IDS_L_68), Lids(IDS_NO));
+
+ if (NT_UInfo.flags & 0x04)
+ LogWriteLog(3, Lids(IDS_L_69), Lids(IDS_YES));
+ else
+ LogWriteLog(3, Lids(IDS_L_69), Lids(IDS_NO));
+
+ if (NT_UInfo.flags & 0x08)
+ LogWriteLog(3, Lids(IDS_L_70), Lids(IDS_YES));
+ else
+ LogWriteLog(3, Lids(IDS_L_70), Lids(IDS_NO));
+
+ if (NT_UInfo.flags & 0x20)
+ LogWriteLog(3, Lids(IDS_L_71), Lids(IDS_NO));
+ else
+ LogWriteLog(3, Lids(IDS_L_71), Lids(IDS_YES));
+
+ if (NT_UInfo.flags & 0x40)
+ LogWriteLog(3, Lids(IDS_L_72), Lids(IDS_NO));
+ else
+ LogWriteLog(3, Lids(IDS_L_72), Lids(IDS_YES));
+
+ // Script path
+ LogWriteLog(2, Lids(IDS_L_73), NT_UInfo.script_path);
+
+ LogWriteLog(2, Lids(IDS_L_74), NT_UInfo.full_name);
+
+ LogWriteLog(2, Lids(IDS_L_75), NT_UInfo.logon_server);
+
+ NTLoginTimesLog((BYTE *) NT_UInfo.logon_hours);
+
+ LogWriteLog(0, Lids(IDS_CRLF));
+
+} // NTUserRecLog
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTDomainSynch(
+ DEST_SERVER_BUFFER *DServ
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPBYTE buffer = NULL;
+ BOOL UsePDC = FALSE;
+ NET_API_STATUS Status;
+ TCHAR LocServer[MAX_SERVER_NAME_LEN + 3];
+
+ wsprintf(LocServer, TEXT("\\\\%s"), DServ->Name);
+
+ if ((DServ->InDomain) && (DServ->Domain != NULL)) {
+ wsprintf(LocServer, TEXT("\\\\%s"), DServ->Domain->PDCName);
+ UsePDC = TRUE;
+ }
+
+ if (UsePDC)
+ Status = I_NetLogonControl(LocServer, NETLOGON_CONTROL_PDC_REPLICATE, 1, &buffer);
+ else
+ Status = I_NetLogonControl(LocServer, NETLOGON_CONTROL_SYNCHRONIZE, 1, &buffer);
+
+ if (buffer != NULL)
+ NetApiBufferFree(buffer);
+
+} // NTDomainSynch
+
+
+/////////////////////////////////////////////////////////////////////////
+BOOL
+NTDomainInSynch(
+ LPTSTR Server
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PNETLOGON_INFO_1 buffer = NULL;
+ NET_API_STATUS Status;
+
+ Status = I_NetLogonControl(Server, NETLOGON_CONTROL_QUERY, 1, (PBYTE *) &buffer);
+
+ if (Status) {
+ return TRUE;
+ }
+
+ if (buffer && buffer->netlog1_flags)
+ return FALSE;
+
+ if (buffer != NULL)
+ NetApiBufferFree(buffer);
+
+ return TRUE;
+
+} // NTDomainInSynch
+
+
+/////////////////////////////////////////////////////////////////////////
+BOOL
+NTDomainGet(
+ LPTSTR ServerName,
+ LPTSTR Domain
+ )
+
+/*++
+
+Routine Description:
+
+ Gee - what a simple way to get the domain a server is part of!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static TCHAR Serv[MAX_SERVER_NAME_LEN + 3];
+ UNICODE_STRING us;
+ NTSTATUS ret;
+ OBJECT_ATTRIBUTES oa;
+ ACCESS_MASK am;
+ SECURITY_QUALITY_OF_SERVICE qos;
+ LSA_HANDLE hLSA;
+ PPOLICY_PRIMARY_DOMAIN_INFO pvBuffer;
+
+ if (ServerName[0] == TEXT('\\'))
+ lstrcpy(Serv, ServerName);
+ else
+ wsprintf(Serv, TEXT("\\\\%s"), ServerName);
+
+ // Set up unicode string structure
+ us.Length = lstrlen(Serv) * sizeof(TCHAR);
+ us.MaximumLength = us.Length + sizeof(TCHAR);
+ us.Buffer = Serv;
+
+ // only need read access
+ am = POLICY_READ | POLICY_VIEW_LOCAL_INFORMATION;
+
+ // set up quality of service
+ qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ qos.ImpersonationLevel = SecurityImpersonation;
+ qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ qos.EffectiveOnly = FALSE;
+
+ // Macro sets everything except security field
+ InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL );
+ oa.SecurityQualityOfService = &qos;
+
+ ret = LsaOpenPolicy(&us, &oa, am, &hLSA);
+
+ if (!ret) {
+ ret = LsaQueryInformationPolicy(hLSA, PolicyPrimaryDomainInformation, (PVOID *) &pvBuffer);
+ LsaClose(hLSA);
+ if ((!ret) && (pvBuffer != NULL)) {
+ lstrcpy(Domain, pvBuffer->Name.Buffer);
+ LsaFreeMemory((PVOID) pvBuffer);
+ }
+ }
+
+ if (ret)
+ return FALSE;
+ else
+ return TRUE;
+
+} // NTDomainGet
+
+
+/////////////////////////////////////////////////////////////////////////
+BOOL
+IsFPNW(
+ LPTSTR ServerName
+ )
+
+/*++
+
+Routine Description:
+
+ Checks the given machine for the FPNW secret.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return (FPNWSecretGet(ServerName) != NULL);
+
+} // IsFPNW
+
+
+/////////////////////////////////////////////////////////////////////////
+BOOL
+IsNTAS(
+ LPTSTR ServerName
+ )
+
+/*++
+
+Routine Description:
+
+ Checks the given machines registry to determine if it is an NTAS
+ system. The new 'Server' type is also counted as NTAS as all we
+ use this for is to determine if local or global groups should be
+ used.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ HKEY hKey, hKey2;
+ DWORD dwType, dwSize;
+ static TCHAR LocServer[MAX_SERVER_NAME_LEN + 3];
+ static TCHAR Type[50];
+ LONG Status;
+ BOOL ret = FALSE;
+
+ wsprintf(LocServer, TEXT("\\\\%s"), ServerName);
+
+ dwSize = sizeof(Type);
+ if (RegConnectRegistry(LocServer, HKEY_LOCAL_MACHINE, &hKey) == ERROR_SUCCESS)
+ if ((Status = RegOpenKeyEx(hKey, Lids(IDS_S_12), 0, KEY_READ, &hKey2)) == ERROR_SUCCESS)
+ if ((Status = RegQueryValueEx(hKey2, Lids(IDS_S_13), NULL, &dwType, (LPBYTE) Type, &dwSize)) == ERROR_SUCCESS)
+ if (!lstrcmpi(Type, Lids(IDS_S_14)))
+ ret = TRUE;
+
+ RegCloseKey(hKey);
+ return ret;
+
+} // IsNTAS
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTTrustedDomainsEnum(
+ LPTSTR ServerName,
+ TRUSTED_DOMAIN_LIST **pTList
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static TCHAR Serv[MAX_SERVER_NAME_LEN + 3];
+ TRUSTED_DOMAIN_LIST *TList = NULL;
+ UNICODE_STRING us;
+ NTSTATUS ret;
+ OBJECT_ATTRIBUTES oa;
+ ACCESS_MASK am;
+ SECURITY_QUALITY_OF_SERVICE qos;
+ LSA_HANDLE hLSA;
+ PPOLICY_PRIMARY_DOMAIN_INFO pvBuffer = NULL;
+ LSA_ENUMERATION_HANDLE lsaenumh = 0;
+ LSA_TRUST_INFORMATION *lsat;
+ ULONG maxrequested = 0xffff;
+ ULONG cItems;
+ ULONG i;
+
+ if (ServerName[0] == TEXT('\\'))
+ lstrcpy(Serv, ServerName);
+ else
+ wsprintf(Serv, TEXT("\\\\%s"), ServerName);
+
+ // Set up unicode string structure
+ us.Length = lstrlen(Serv) * sizeof(TCHAR);
+ us.MaximumLength = us.Length + sizeof(TCHAR);
+ us.Buffer = Serv;
+
+ // only need read access
+ am = POLICY_READ | POLICY_VIEW_LOCAL_INFORMATION;
+
+ // set up quality of service
+ qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ qos.ImpersonationLevel = SecurityImpersonation;
+ qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ qos.EffectiveOnly = FALSE;
+
+ // Macro sets everything except security field
+ InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL );
+ oa.SecurityQualityOfService = &qos;
+
+ ret = LsaOpenPolicy(&us, &oa, am, &hLSA);
+
+ if (!ret) {
+ ret = LsaEnumerateTrustedDomains(hLSA, &lsaenumh, (PVOID *) &pvBuffer, maxrequested, &cItems);
+ LsaClose(hLSA);
+ if ((!ret) && (pvBuffer != NULL)) {
+ lsat = (LSA_TRUST_INFORMATION *) pvBuffer;
+ TList = (TRUSTED_DOMAIN_LIST *) AllocMemory(sizeof(TRUSTED_DOMAIN_LIST) + (cItems * ((MAX_DOMAIN_NAME_LEN + 1) * sizeof(TCHAR))));
+ memset(TList, 0, sizeof(TRUSTED_DOMAIN_LIST) + (cItems * ((MAX_DOMAIN_NAME_LEN + 1) * sizeof(TCHAR))));
+
+ if (TList != NULL) {
+ TList->Count = cItems;
+
+ for (i = 0; i < cItems; i++)
+ memcpy(TList->Name[i], lsat[i].Name.Buffer, lsat[i].Name.Length);
+ }
+ LsaFreeMemory((PVOID) pvBuffer);
+ }
+ }
+
+ *pTList = TList;
+
+} // NTTrustedDomainsEnum
+
+
+/////////////////////////////////////////////////////////////////////////
+DOMAIN_BUFFER *
+NTTrustedDomainSet(
+ HWND hWnd,
+ LPTSTR Server,
+ LPTSTR TrustedDomain
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LPTSTR apiPDCName = NULL;
+ TCHAR PDCName[MAX_SERVER_NAME_LEN];
+ TCHAR LocServer[MAX_SERVER_NAME_LEN + 3];
+ static DOMAIN_BUFFER *DBuff;
+ NET_API_STATUS Status = 0;
+
+ DBuff = NULL;
+ lstrcpy(PDCName, TEXT(""));
+
+ wsprintf(LocServer, TEXT("\\\\%s"), Server);
+ Status = NetGetDCName(LocServer, TrustedDomain, (LPBYTE *) &apiPDCName);
+
+ if (!Status) {
+ // get rid of leading 2 backslashes
+ if (lstrlen(apiPDCName) > 2)
+ lstrcpy(PDCName, &apiPDCName[2]);
+
+ if (NTServerValidate(hWnd, PDCName)) {
+ // Check if we need to add domain to domain list
+ DBuff = DomainListFind(TrustedDomain);
+
+ if (DBuff == NULL) {
+ DBuff = DomainListAdd(TrustedDomain, PDCName);
+ DBuff->Type = ServInfo->sv101_type;
+ DBuff->VerMaj = ServInfo->sv101_version_major;
+ DBuff->VerMin = ServInfo->sv101_version_minor;
+ }
+
+ DBuff->UseCount++;
+ } // if Domain valid
+
+ if (apiPDCName != NULL)
+ NetApiBufferFree((LPVOID) apiPDCName);
+ }
+
+ // make sure we are pointing to the right one
+ NTServerSet(Server);
+ return DBuff;
+
+} // NTTrustedDomainSet
+
+
+/////////////////////////////////////////////////////////////////////////
+SID *
+NTSIDGet(
+ LPTSTR ServerName,
+ LPTSTR pUserName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static TCHAR lpszDomain[80];
+ DWORD dwDomainLength = 80;
+
+ static UCHAR psnuType[1024];
+ static SID UserSID[1024];
+ DWORD dwSIDBufSize = 1024;
+ BOOL Retry = TRUE;
+
+ // Get SID for user
+ while (Retry) {
+ if (!LookupAccountName(ServerName, pUserName, UserSID, &dwSIDBufSize,
+ lpszDomain, &dwDomainLength, (PSID_NAME_USE) psnuType)) {
+#ifdef DEBUG
+ dprintf(TEXT("Error %d: LookupAccountName\n"), GetLastError());
+#endif
+ if (GetLastError() == ERROR_NONE_MAPPED)
+ if (NTDomainInSynch(ServerName))
+ Retry = FALSE;
+ else
+ Sleep(5000L);
+
+ } else
+ return UserSID;
+ }
+
+ return NULL;
+
+} // NTSIDGet
+
+
+#define SD_SIZE (65536 + SECURITY_DESCRIPTOR_MIN_LENGTH)
+
+/////////////////////////////////////////////////////////////////////////
+BOOL
+NTFile_AccessRightsAdd(
+ LPTSTR ServerName,
+ LPTSTR pUserName,
+ LPTSTR pFileName,
+ ACCESS_MASK AccessMask,
+ BOOL Dir
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS ret;
+ SID *pUserSID;
+
+ // File SD variables
+ static UCHAR ucSDbuf[SD_SIZE];
+ PSECURITY_DESCRIPTOR pFileSD = (PSECURITY_DESCRIPTOR) ucSDbuf;
+ DWORD dwSDLengthNeeded = 0;
+
+ // New SD variables
+ UCHAR NewSD[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ PSECURITY_DESCRIPTOR psdNewSD=(PSECURITY_DESCRIPTOR)NewSD;
+
+
+ // +-----------------------------------------------------------------+
+ // | Main Code |
+ // +-----------------------------------------------------------------+
+ pUserSID = NTSIDGet(ServerName, pUserName);
+ if (pUserSID == NULL) {
+ LogWriteLog(5, Lids(IDS_L_76), GetLastError());
+ ErrorIt(Lids(IDS_L_77), GetLastError(), pUserName);
+ return FALSE;
+ }
+
+ // Get security descriptor (SD) for file
+ if(!GetFileSecurity(pFileName, (SECURITY_INFORMATION) (DACL_SECURITY_INFORMATION),
+ pFileSD, SD_SIZE, (LPDWORD) &dwSDLengthNeeded)) {
+#ifdef DEBUG
+ dprintf(TEXT("Error %d: GetFileSecurity\n"), GetLastError());
+#endif
+ LogWriteLog(5, Lids(IDS_L_76), GetLastError());
+ ErrorIt(Lids(IDS_L_77), GetLastError(), pUserName);
+ return (FALSE);
+ }
+
+ if (Dir)
+ ret = ACEAdd(pFileSD, pUserSID, AccessMask, DirRightsMapping.NtAceFlags, &psdNewSD );
+ else
+ ret = ACEAdd(pFileSD, pUserSID, AccessMask, FileRightsMapping.NtAceFlags, &psdNewSD );
+
+ if (ret) {
+#ifdef DEBUG
+ dprintf(TEXT("Error %d: NWAddRight\n"), GetLastError());
+#endif
+ LogWriteLog(5, Lids(IDS_L_76), GetLastError());
+ ErrorIt(Lids(IDS_L_77), GetLastError(), pUserName);
+ return FALSE;
+ }
+
+ // Set the SD to the File
+ if (!SetFileSecurity(pFileName, DACL_SECURITY_INFORMATION, psdNewSD)) {
+#ifdef DEBUG
+ dprintf(TEXT("Error %d: SetFileSecurity\n"), GetLastError());
+#endif
+ LogWriteLog(5, Lids(IDS_L_76), GetLastError());
+ ErrorIt(Lids(IDS_L_77), GetLastError(), pUserName);
+
+ if (psdNewSD != pFileSD)
+ NW_FREE(psdNewSD);
+ return FALSE;
+ }
+
+ // Free the memory allocated for the new ACL, but only if
+ // it was allocated.
+ if (psdNewSD != pFileSD)
+ NW_FREE(psdNewSD);
+ return TRUE;
+
+} // NTFile_AccessRightsAdd
+
+
+/////////////////////////////////////////////////////////////////////////
+NTSTATUS
+ACEAdd(
+ PSECURITY_DESCRIPTOR pSD,
+ PSID pSid,
+ ACCESS_MASK AccessMask,
+ ULONG AceFlags,
+ PSECURITY_DESCRIPTOR *ppNewSD
+ )
+
+/*++
+
+Routine Description:
+
+ ACEAdd() - Taken from ChuckC's NWRights.C
+
+Arguments:
+
+ psd - The security desciptor to modify. This must be a valid
+ security descriptor.
+
+ psid - The SID of the user/group for which we are adding this right.
+
+ AccessMask - The access mask that we wish to add.
+
+ ppNewSD - used to return the new Security descriptor.
+
+Return Value:
+
+ NTSTATUS code
+
+--*/
+
+{
+ ACL Acl ;
+ PACL pAcl, pNewAcl = NULL ;
+ PACCESS_ALLOWED_ACE pAccessAce, pNewAce = NULL ;
+ NTSTATUS ntstatus ;
+ BOOLEAN fDaclPresent, fDaclDefaulted;
+ BOOLEAN Found = FALSE;
+ LONG i ;
+
+ // validate and initialize
+ if (!pSD || !pSid || !ppNewSD || !RtlValidSecurityDescriptor(pSD)) {
+#ifdef DEBUG
+ dprintf(TEXT("ACEAdd: got invalid parm\n"));
+#endif
+ return (STATUS_INVALID_PARAMETER) ;
+ }
+
+ // if AccessMask == 0, no need to add the ACE
+
+ if( !AccessMask ) {
+
+ *ppNewSD = pSD;
+ return( STATUS_SUCCESS );
+ }
+
+ *ppNewSD = NULL ;
+
+ // extract the DACL from the securiry descriptor
+ ntstatus = RtlGetDaclSecurityDescriptor(pSD, &fDaclPresent, &pAcl, &fDaclDefaulted) ;
+ if (!NT_SUCCESS(ntstatus)) {
+#ifdef DEBUG
+ dprintf(TEXT("ACEAdd: RtlGetDaclSecurityDescriptor failed\n"));
+#endif
+ goto CleanupAndExit ;
+ }
+
+ // if no DACL present, we create one
+ if ((!fDaclPresent) || (pAcl == NULL)) {
+ // create Dacl
+ ntstatus = RtlCreateAcl(&Acl, sizeof(Acl), ACL_REVISION) ;
+
+ if (!NT_SUCCESS(ntstatus)) {
+#ifdef DEBUG
+ dprintf(TEXT("ACEAdd: RtlCreateAcl failed\n"));
+#endif
+ goto CleanupAndExit ;
+ }
+
+ pAcl = &Acl ;
+ }
+
+ // loop thru ACEs, looking for entry with the user/group SID
+ pAccessAce = NULL ;
+ for (i = 0; i < pAcl->AceCount; i++) {
+ ACE_HEADER *pAce ;
+
+ ntstatus = RtlGetAce(pAcl,i,&pAce) ;
+
+ if (!NT_SUCCESS(ntstatus)) {
+#ifdef DEBUG
+ dprintf(TEXT("ACEAdd: RtlGetAce failed\n"));
+#endif
+ goto CleanupAndExit ;
+ }
+
+ if (pAce->AceType == ACCESS_ALLOWED_ACE_TYPE) {
+ // found a granting ace, which is what we want
+ PSID pAceSid ;
+
+ pAccessAce = (ACCESS_ALLOWED_ACE *) pAce ;
+ pAceSid = (PSID) &pAccessAce->SidStart ;
+
+ //
+ // is this the same SID?
+ // if yes, modify access mask and carry on.
+ //
+ if (RtlEqualSid(pAceSid, pSid)) {
+
+ ACCESS_MASK access_mask ;
+
+ ASSERT(pAccessAce != NULL) ;
+
+ access_mask = pAccessAce->Mask ;
+
+ if ( (access_mask & AccessMask) == access_mask ) {
+ ntstatus = STATUS_MEMBER_IN_GROUP ;
+ goto CleanupAndExit ;
+ }
+
+ pAccessAce->Mask = AccessMask ;
+ Found = TRUE ;
+ }
+ } else {
+ // ignore it. we only deal with granting aces.
+ }
+ }
+
+ if ( !Found ) { // now set the DACL to have the desired rights
+ // reached end of ACE list without finding match. so we need to
+ // create a new ACE.
+ USHORT NewAclSize, NewAceSize ;
+
+ // calculate the sizes
+ NewAceSize = (USHORT)(sizeof(ACE_HEADER) +
+ sizeof(ACCESS_MASK) +
+ RtlLengthSid(pSid));
+
+ NewAclSize = pAcl->AclSize + NewAceSize ;
+
+ // allocate new ACE and new ACL (since we are growing it)
+ pNewAce = (PACCESS_ALLOWED_ACE) NW_ALLOC(NewAceSize) ;
+ if (!pNewAce) {
+ #ifdef DEBUG
+ dprintf(TEXT("ACEAdd: memory allocation failed for new ACE\n"));
+ #endif
+ ntstatus = STATUS_INSUFFICIENT_RESOURCES ;
+ goto CleanupAndExit ;
+ }
+
+ pNewAce->Header.AceFlags = (UCHAR)AceFlags;
+ pNewAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
+ pNewAce->Header.AceSize = NewAceSize;
+ pNewAce->Mask = AccessMask;
+ RtlCopySid( RtlLengthSid(pSid), (PSID)(&pNewAce->SidStart), pSid );
+
+ pNewAcl = (PACL) NW_ALLOC(NewAclSize) ;
+ if (!pNewAcl) {
+ #ifdef DEBUG
+ dprintf(TEXT("ACEAdd: memory allocation failed for new ACL\n"));
+ #endif
+ ntstatus = STATUS_INSUFFICIENT_RESOURCES ;
+ goto CleanupAndExit ;
+ }
+
+ RtlCopyMemory(pNewAcl, pAcl, pAcl->AclSize) ;
+ pNewAcl->AclSize = NewAclSize ;
+
+ // Add the ACE to the end of the ACL
+ ntstatus = RtlAddAce(pNewAcl, ACL_REVISION, pNewAcl->AceCount, pNewAce, NewAceSize) ;
+
+ if (!NT_SUCCESS(ntstatus)) {
+ #ifdef DEBUG
+ dprintf(TEXT("ACEAdd: RtlAddAce failed\n"));
+ #endif
+ goto CleanupAndExit ;
+ }
+
+ pAcl = pNewAcl ;
+ }
+
+
+
+ // set the dacl back into the security descriptor. we need create
+ // a new security descriptor, since the old one may not have space
+ // for any additional ACE.
+ ntstatus = CreateNewSecurityDescriptor(ppNewSD, pSD, pAcl) ;
+
+ if (!NT_SUCCESS(ntstatus)) {
+#ifdef DEBUG
+ dprintf(TEXT("ACEAdd: CreateNewSecurityDescriptor failed\n"));
+#endif
+ }
+
+CleanupAndExit:
+
+ if (pNewAcl)
+ NW_FREE(pNewAcl) ;
+
+ if (pNewAce)
+ NW_FREE(pNewAce) ;
+
+ return ntstatus ;
+} // ACEAdd
+
+
+/////////////////////////////////////////////////////////////////////////
+NTSTATUS
+CreateNewSecurityDescriptor(
+ PSECURITY_DESCRIPTOR *ppNewSD,
+ PSECURITY_DESCRIPTOR pSD,
+ PACL pAcl
+ )
+
+/*++
+
+Routine Description:
+
+ From a SD and a Dacl, create a new SD. The new SD will be fully self
+ contained (it is self relative) and does not have pointers to other
+ structures.
+
+Arguments:
+
+ ppNewSD - used to return the new SD. Caller should free with NW_FREE
+
+ pSD - the self relative SD we use to build the new SD
+
+ pAcl - the new DACL that will be used for the new SD
+
+Return Value:
+
+ NTSTATUS code
+
+--*/
+
+{
+ PACL pSacl ;
+ PSID psidGroup, psidOwner ;
+ BOOLEAN fSaclPresent ;
+ BOOLEAN fSaclDefaulted, fGroupDefaulted, fOwnerDefaulted ;
+ ULONG NewSDSize ;
+ SECURITY_DESCRIPTOR NewSD ;
+ PSECURITY_DESCRIPTOR pNewSD ;
+ NTSTATUS ntstatus ;
+
+
+ // extract the originals from the securiry descriptor
+ ntstatus = RtlGetSaclSecurityDescriptor(pSD, &fSaclPresent, &pSacl, &fSaclDefaulted) ;
+ if (!NT_SUCCESS(ntstatus))
+ return ntstatus ;
+
+ ntstatus = RtlGetOwnerSecurityDescriptor(pSD, &psidOwner, &fOwnerDefaulted) ;
+ if (!NT_SUCCESS(ntstatus))
+ return ntstatus ;
+
+ ntstatus = RtlGetGroupSecurityDescriptor(pSD, &psidGroup, &fGroupDefaulted) ;
+ if (!NT_SUCCESS(ntstatus))
+ return ntstatus ;
+
+ // now create a new SD and set the info in it. we cannot return this one
+ // since it has pointers to old SD.
+ ntstatus = RtlCreateSecurityDescriptor(&NewSD, SECURITY_DESCRIPTOR_REVISION) ;
+ if (!NT_SUCCESS(ntstatus))
+ return ntstatus ;
+
+ ntstatus = RtlSetDaclSecurityDescriptor(&NewSD, TRUE, pAcl, FALSE) ;
+
+ if (!NT_SUCCESS(ntstatus))
+ return ntstatus ;
+
+ ntstatus = RtlSetSaclSecurityDescriptor(&NewSD, fSaclPresent, pSacl, fSaclDefaulted) ;
+ if (!NT_SUCCESS(ntstatus))
+ return ntstatus ;
+
+ ntstatus = RtlSetOwnerSecurityDescriptor(&NewSD, psidOwner, fOwnerDefaulted) ;
+ if (!NT_SUCCESS(ntstatus))
+ return ntstatus ;
+
+ ntstatus = RtlSetGroupSecurityDescriptor(&NewSD, psidGroup, fGroupDefaulted) ;
+ if (!NT_SUCCESS(ntstatus))
+ return ntstatus ;
+
+ // calculate size needed for the returned SD and allocated it
+ NewSDSize = RtlLengthSecurityDescriptor(&NewSD) ;
+
+ pNewSD = (PSECURITY_DESCRIPTOR) NW_ALLOC(NewSDSize) ;
+
+ if (!pNewSD)
+ return (STATUS_INSUFFICIENT_RESOURCES) ;
+
+ // convert the absolute to self relative
+ ntstatus = RtlAbsoluteToSelfRelativeSD(&NewSD, pNewSD, &NewSDSize) ;
+
+ if (NT_SUCCESS(ntstatus))
+ *ppNewSD = pNewSD ;
+ else
+ NW_FREE(pNewSD) ;
+
+ return ntstatus ;
+} // CreateNewSecurityDescriptor
+
+
+/////////////////////////////////////////////////////////////////////////
+LPTSTR
+NTAccessLog(
+ ACCESS_MASK AccessMask
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ static TCHAR AccessDesc[80];
+ TCHAR AccessStr[80];
+
+ if (AccessMask == 0) {
+ lstrcpy(AccessDesc, Lids(IDS_L_78));
+ return AccessDesc;
+ } else
+ if ((AccessMask & GENERIC_ALL) == GENERIC_ALL) {
+ lstrcpy(AccessDesc, Lids(IDS_L_79));
+ return AccessDesc;
+ } else {
+ lstrcpy(AccessStr, TEXT("("));
+
+ if ((AccessMask & GENERIC_READ) == GENERIC_READ)
+ lstrcat(AccessStr, Lids(IDS_L_80));
+
+ if ((AccessMask & GENERIC_WRITE) == GENERIC_WRITE)
+ lstrcat(AccessStr, Lids(IDS_L_81));
+
+ if ((AccessMask & GENERIC_EXECUTE) == GENERIC_EXECUTE)
+ lstrcat(AccessStr, Lids(IDS_L_82));
+
+ if ((AccessMask & DELETE) == DELETE)
+ lstrcat(AccessStr, Lids(IDS_L_83));
+
+ if ((AccessMask & WRITE_DAC) == WRITE_DAC)
+ lstrcat(AccessStr, Lids(IDS_L_84));
+
+ lstrcat(AccessStr, TEXT(")"));
+
+ // Figured out the individual rights, now need to see if this corresponds
+ // to a generic mapping
+ if (!lstrcmpi(AccessStr, Lids(IDS_L_85))) {
+ lstrcpy(AccessDesc, Lids(IDS_L_86));
+ return AccessDesc;
+ }
+
+ if (!lstrcmpi(AccessStr, Lids(IDS_L_87))) {
+ lstrcpy(AccessDesc, Lids(IDS_L_88));
+ return AccessDesc;
+ }
+
+ if (!lstrcmpi(AccessStr, Lids(IDS_L_89))) {
+ lstrcpy(AccessDesc, Lids(IDS_L_90));
+ return AccessDesc;
+ }
+
+ if (!lstrcmpi(AccessStr, Lids(IDS_L_91))) {
+ lstrcpy(AccessDesc, Lids(IDS_L_92));
+ return AccessDesc;
+ }
+
+ wsprintf(AccessDesc, Lids(IDS_L_93), AccessStr);
+ }
+
+ return AccessDesc;
+
+} // NTAccessLog
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTUserDefaultsGet(
+ NT_DEFAULTS **UDefaults
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ USER_MODALS_INFO_0 *NTDefaults = NULL;
+ NET_API_STATUS Status = 0;
+
+ if (LocalMachine)
+ Status = NetUserModalsGet(NULL, 0, (LPBYTE *) &NTDefaults);
+ else
+ Status = NetUserModalsGet(CachedServer, 0, (LPBYTE *) &NTDefaults);
+
+ if (Status) {
+ NTDefaults = NULL;
+ return;
+ }
+
+ *UDefaults = (NT_DEFAULTS *) NTDefaults;
+} // NTUserDefaultsGet
+
+
+/////////////////////////////////////////////////////////////////////////
+DWORD
+NTUserDefaultsSet(
+ NT_DEFAULTS NTDefaults
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NET_API_STATUS Status = 0;
+ DWORD err;
+
+ if (LocalMachine)
+ Status = NetUserModalsSet(NULL, 0, (LPBYTE) &NTDefaults, &err);
+ else
+ Status = NetUserModalsSet(CachedServer, 0, (LPBYTE) &NTDefaults, &err);
+
+ return Status;
+
+} // NTUserDefaultsSet
+
+
+/////////////////////////////////////////////////////////////////////////
+VOID
+NTUserDefaultsLog(
+ NT_DEFAULTS UDefaults
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LogWriteLog(1, Lids(IDS_L_94), UDefaults.min_passwd_len);
+
+ // Age is in seconds, convert to days
+ LogWriteLog(1, Lids(IDS_L_95), UDefaults.max_passwd_age / 86400);
+ LogWriteLog(1, Lids(IDS_L_96), UDefaults.force_logoff);
+ LogWriteLog(0, Lids(IDS_CRLF));
+} // NTUserDefaultsLog