3645 lines
80 KiB
C
3645 lines
80 KiB
C
/*++
|
|
|
|
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 (¤tTime);
|
|
|
|
uniPasswordAge.Buffer = (PWCHAR) ¤tTime;
|
|
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 = (USHORT) nStringLength;
|
|
uniNWWorkstations.MaximumLength = (USHORT) 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 = (USHORT) nStringLength;
|
|
uniNWHomeDir.MaximumLength = (USHORT) 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 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 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_PTR 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 = (ULONG) (*pFpnwVolumeEnum) ( NULL, 1, (LPBYTE *)&VolumeInfo, &entriesread, &resumehandle );
|
|
else
|
|
Status = (ULONG) (*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, §orsPC, &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 = (USHORT)(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 = (USHORT)(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
|