1308 lines
34 KiB
C
1308 lines
34 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
UASREAD.C
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Routines to _read UAS database entries.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Shanku Niyogi (W-SHANKN) 24-Oct-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
24-Oct-1991 w-shankn
|
|||
|
Created.
|
|||
|
07-Feb-1992 JohnRo
|
|||
|
Fixed compile errors!
|
|||
|
Fixed memory free bug (hAlloc was both local and global variable).
|
|||
|
Made changes suggested by PC-LINT.
|
|||
|
28-Feb-1992 JohnRo
|
|||
|
User info must include units_per_week field.
|
|||
|
28-Feb-1992 JohnRo
|
|||
|
Fixed bugs getting some numbers (e.g. codepage).
|
|||
|
03-Mar-1992 JohnRo
|
|||
|
Added some checking for non-null group name.
|
|||
|
11-Mar-1992 JohnRo
|
|||
|
Added command-line parsing stuff.
|
|||
|
Use WARNING_MSG(), ERROR_MSG(), PROGRESS_MSG() macros.
|
|||
|
18-Mar-1992 JohnRo
|
|||
|
Use iterator to allow hash-table collision handling.
|
|||
|
Added flag for verbose output at run time.
|
|||
|
19-Mar-1992 JohnRo
|
|||
|
Use our own version of decrypt code.
|
|||
|
Fixed bug in user iterator bump code.
|
|||
|
Added display of number of users in database and returned.
|
|||
|
05-May-1992 JohnRo
|
|||
|
Avoid dummy passwords altogether.
|
|||
|
Minor changes to verbose level vs. messages printed.
|
|||
|
Made changes suggested by PC-LINT.
|
|||
|
23-Mar-1993 JohnRo
|
|||
|
RAID 1187: logon hours are inappropriately set.
|
|||
|
Got rid of new warnings from the new compiler.
|
|||
|
Use <prefix.h> equates.
|
|||
|
10-May-1993 JohnRo
|
|||
|
RAID 6113: PortUAS: "dangerous handling of Unicode". Actually, PortUAS
|
|||
|
was handling Unicode better than other parts of the system, so PortUAS
|
|||
|
has to go down to the lowest common denominator. Hopefully after
|
|||
|
NT product 1, we can correct this. See BRAIN_DAMAGE_UNICODE below.
|
|||
|
30-Jul-1993 JohnRo
|
|||
|
Use NetpKdPrint() where possible.
|
|||
|
Made changes suggested by PC-LINT 5.0
|
|||
|
02-Sep-1993 JohnRo
|
|||
|
Use NetpNameCompare() to compare user names.
|
|||
|
Use NetApiBufferAllocate() instead of private version.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
// These must be included first:
|
|||
|
|
|||
|
#include <nt.h> // Needed by <crypt.h>
|
|||
|
#include <ntrtl.h> // Needed by <windows.h>
|
|||
|
#include <nturtl.h> // Needed by <windows.h>
|
|||
|
#include <windows.h> // _lread(), etc.
|
|||
|
#include <lmcons.h> // NET_API_STATUS, etc.
|
|||
|
|
|||
|
// These may be included in any order:
|
|||
|
|
|||
|
#include <crypt.h>
|
|||
|
#include <icanon.h> // I_NetNameCompare
|
|||
|
#include <lmaccess.h>
|
|||
|
#include <lmapibuf.h> // NetApiBufferAllocate(), NetApiBufferFree().
|
|||
|
#include <lmerr.h>
|
|||
|
#include <loghours.h> // NetpRotateLogonHours().
|
|||
|
#include <memory.h>
|
|||
|
#include <netdebug.h> // DBGSTATIC, NetpAssert().
|
|||
|
#include <netlibnt.h> // NetpNtStatusToApiStatus().
|
|||
|
#include <portuasp.h> // WARNING_MSG(), etc.
|
|||
|
#include <prefix.h> // PREFIX_ equates.
|
|||
|
#include <smbgtpt.h>
|
|||
|
#include <string.h> // strcmp(), strlen() etc.
|
|||
|
#include <tstring.h> // NetpCopy{type}To{type}, NetpSubsetStr(), etc.
|
|||
|
#include <wchar.h>
|
|||
|
#include <tchar.h>
|
|||
|
|
|||
|
#include "nlstxt.h" // NLS messages
|
|||
|
|
|||
|
//
|
|||
|
// Global variables (set by PortUasParseCommandLine()).
|
|||
|
//
|
|||
|
LPTSTR PortUasGlobalUserToSkipTo = NULL;
|
|||
|
BOOL Verbose = FALSE;
|
|||
|
extern int CurrentCP;
|
|||
|
|
|||
|
//
|
|||
|
// Static pointers to memory where data will be read in from UAS database.
|
|||
|
//
|
|||
|
|
|||
|
DBGSTATIC HANDLE hAlloc;
|
|||
|
DBGSTATIC HANDLE database = INVALID_HANDLE_VALUE;
|
|||
|
DBGSTATIC LPUAS_AHDR UasHeader;
|
|||
|
DBGSTATIC LPUAS_GROUPREC groups;
|
|||
|
DBGSTATIC LPUAS_DISKUSERHASH userHashes;
|
|||
|
DBGSTATIC LPUAS_USER_OBJECT user;
|
|||
|
DBGSTATIC BOOL uasInMemory = FALSE;
|
|||
|
DBGSTATIC USER_ITERATOR currentUser;
|
|||
|
|
|||
|
//
|
|||
|
// Static counters for user-interface.
|
|||
|
//
|
|||
|
DBGSTATIC DWORD usersDoneSoFar = 0; // Users processed or skipped.
|
|||
|
DBGSTATIC DWORD usersTotal;
|
|||
|
|
|||
|
//
|
|||
|
// Private functions.
|
|||
|
//
|
|||
|
|
|||
|
DBGSTATIC
|
|||
|
NET_API_STATUS
|
|||
|
PortUaspGetUserData(
|
|||
|
IN LPUSER_ITERATOR Iterator
|
|||
|
);
|
|||
|
|
|||
|
//FARBUGBUG This is a pretty big macro, now; probably should be a function.
|
|||
|
#define PortUaspPutString( Record, Field, String, Var ) \
|
|||
|
{ \
|
|||
|
int cch; \
|
|||
|
cch = strlen(String) + 1; \
|
|||
|
( Record ).Field = Var; \
|
|||
|
cch = MultiByteToWideChar(CurrentCP, MB_PRECOMPOSED, String, cch, Var, cch); \
|
|||
|
NetpAssert(cch != 0); \
|
|||
|
Var += cch; \
|
|||
|
}
|
|||
|
|
|||
|
#define MAKE_PTR( User, Field ) \
|
|||
|
((LPSTR)( &(User)->uo_record ) \
|
|||
|
+ ( SmbGetUshort( &(User)->uo_record.Field )))
|
|||
|
|
|||
|
#define UAS_GROUP_ENTRY_IS_VALID( EntryPtr ) \
|
|||
|
( ( ((BYTE) (EntryPtr)->name[0]) != UAS_REC_EMPTY ) \
|
|||
|
&& ( ((BYTE) (EntryPtr)->name[0]) != UAS_REC_DELETE ) )
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PortUasOpen(
|
|||
|
IN LPTSTR File
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Open LM2.0 UAS database and read contents into memory.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
File - pathname of UAS database file. Usually C:\LANMAN\ACCOUNTS\NET.ACC.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success if successful, or one of the following:
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - self-explanatory
|
|||
|
NERR_InvalidDatabase - file is corrupt or invalid
|
|||
|
NERR_ACFNotFound - can't find the file
|
|||
|
NERR_ACFFileIOFail - problem reading file
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
#ifdef BRAIN_DAMAGE_UNICODE
|
|||
|
DWORD i;
|
|||
|
#endif
|
|||
|
DWORD size;
|
|||
|
INT cb;
|
|||
|
LPBYTE alloc;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate memory. Memory required is for: UasHeader
|
|||
|
// group data
|
|||
|
// user hash table
|
|||
|
// single user entry
|
|||
|
|
|||
|
size = UAS_HASH_TBL_OFFSET + UAS_HASH_TBL_SIZE + UAS_MAX_USER_SIZE;
|
|||
|
if (( hAlloc =
|
|||
|
LocalAlloc( LMEM_MOVEABLE | LMEM_ZEROINIT, size )) == NULL ) {
|
|||
|
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if (( alloc = LocalLock( hAlloc )) == NULL ) {
|
|||
|
|
|||
|
(void) LocalFree( hAlloc );
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Assign portions of allocated memory to data sections.
|
|||
|
//
|
|||
|
|
|||
|
UasHeader = (LPUAS_AHDR)alloc;
|
|||
|
groups = (LPUAS_GROUPREC)( alloc + UAS_GROUP_HASH_START );
|
|||
|
userHashes = (LPUAS_DISKUSERHASH)( alloc + UAS_HASH_TBL_OFFSET );
|
|||
|
user = (LPUAS_USER_OBJECT)( alloc + UAS_HASH_TBL_OFFSET
|
|||
|
+ UAS_HASH_TBL_SIZE );
|
|||
|
|
|||
|
//
|
|||
|
// Open UAS database.
|
|||
|
//
|
|||
|
|
|||
|
database = CreateFile(File, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|||
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|||
|
if (database == INVALID_HANDLE_VALUE) {
|
|||
|
|
|||
|
return NERR_ACFNotFound;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read UasHeader.
|
|||
|
//
|
|||
|
|
|||
|
if (!ReadFile(database, UasHeader, UAS_GROUP_HASH_START, &cb, NULL) ||
|
|||
|
cb != UAS_GROUP_HASH_START ) {
|
|||
|
|
|||
|
PortUasClose();
|
|||
|
return NERR_ACFFileIOFail;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if the file is an actual UAS database.
|
|||
|
//
|
|||
|
|
|||
|
if ( strcmp( UasHeader->signature, UAS_LMSIG ) ||
|
|||
|
strcmp( UasHeader->DBIdInfo, UAS_DBIDINFO_TEXT ) ||
|
|||
|
SmbGetUshort( &UasHeader->integrity_flag ) == FALSE ) {
|
|||
|
|
|||
|
PortUasClose();
|
|||
|
return NERR_InvalidDatabase;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check size of database.
|
|||
|
//
|
|||
|
|
|||
|
if (( size = GetFileSize( database, NULL )) == (DWORD)-1L ) {
|
|||
|
|
|||
|
PortUasClose();
|
|||
|
return NERR_ACFFileIOFail;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (( size < ( SmbGetUlong( &UasHeader->free_list )
|
|||
|
+ UAS_DISK_BLOCK_SIZE ))
|
|||
|
|| ( size < ( SmbGetUlong( &UasHeader->access_list )
|
|||
|
+ UAS_DISK_BLOCK_SIZE ))
|
|||
|
|| (( size - UAS_HASH_TBL_OFFSET - 2 * UAS_HASH_TBL_SIZE )
|
|||
|
% UAS_DISK_BLOCK_SIZE )) {
|
|||
|
|
|||
|
PortUasClose();
|
|||
|
return NERR_InvalidDatabase;
|
|||
|
}
|
|||
|
|
|||
|
usersTotal = (DWORD) SmbGetUshort( &(UasHeader->num_users) );
|
|||
|
if (Verbose) {
|
|||
|
//PROGRESS_MSG( ("UAS database has " FORMAT_DWORD " users.\n",
|
|||
|
// usersTotal ) );
|
|||
|
(void)NlsPutMsg(STDOUT, PUAS_UAS_DATABASE_HAS_USERS, usersTotal );
|
|||
|
}
|
|||
|
usersDoneSoFar = 0;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get group information.
|
|||
|
//
|
|||
|
|
|||
|
if (!ReadFile(database, groups, UAS_GRECSIZE * UAS_MAXGROUP, &cb, NULL) ||
|
|||
|
cb != UAS_GRECSIZE * UAS_MAXGROUP ) {
|
|||
|
|
|||
|
PortUasClose();
|
|||
|
return NERR_ACFFileIOFail;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get user hash table.
|
|||
|
//
|
|||
|
|
|||
|
if (SetFilePointer(database, UAS_HASH_TBL_OFFSET, NULL, FILE_BEGIN) == -1) {
|
|||
|
|
|||
|
PortUasClose();
|
|||
|
return NERR_ACFFileIOFail;
|
|||
|
}
|
|||
|
|
|||
|
if (!ReadFile(database, userHashes, UAS_HASH_TBL_SIZE, &cb, NULL) ||
|
|||
|
cb != UAS_HASH_TBL_SIZE ) {
|
|||
|
|
|||
|
PortUasClose();
|
|||
|
return NERR_ACFFileIOFail;
|
|||
|
}
|
|||
|
|
|||
|
uasInMemory = TRUE;
|
|||
|
PortUasInitUserIterator( currentUser );
|
|||
|
return NERR_Success;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PortUasClose(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Close the currently open UAS database.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
if ( database != INVALID_HANDLE_VALUE ) {
|
|||
|
|
|||
|
uasInMemory = FALSE;
|
|||
|
PortUasInitUserIterator( currentUser );
|
|||
|
CloseHandle( database );
|
|||
|
(VOID) LocalUnlock( hAlloc );
|
|||
|
(VOID) LocalFree( hAlloc );
|
|||
|
database = INVALID_HANDLE_VALUE;
|
|||
|
|
|||
|
if (Verbose) {
|
|||
|
//PROGRESS_MSG( ("Processed or skipped " FORMAT_DWORD
|
|||
|
// " users of an expected " FORMAT_DWORD ".\n",
|
|||
|
// usersDoneSoFar, usersTotal) );
|
|||
|
(void)NlsPutMsg(STDOUT, PUAS_PROCESSED_OR_SKIPPED_USERS_OF_TOTAL,
|
|||
|
usersDoneSoFar, usersTotal );
|
|||
|
}
|
|||
|
NetpAssert( usersDoneSoFar == usersTotal );
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PortUasGetModals(
|
|||
|
OUT LPUSER_MODALS_INFO_0 * Modals0
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get user modals settings from current database.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Modals0 - A pointer to an LPUSER_MODALS_INFO_0 which will get a pointer
|
|||
|
to the returned level 0 user modals structure. This buffer
|
|||
|
must be freed with NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success if successful, or one of the following:
|
|||
|
|
|||
|
NERR_ACFNotLoaded - database not open
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - self-explanatory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Check if the database is in memory.
|
|||
|
//
|
|||
|
|
|||
|
if ( !uasInMemory ) {
|
|||
|
|
|||
|
return NERR_ACFNotLoaded;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Try to allocate two buffers for all the user modals data.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetApiBufferAllocate( sizeof(USER_MODALS_INFO_0), (PVOID *)Modals0 )){
|
|||
|
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill buffer with data.
|
|||
|
//
|
|||
|
|
|||
|
(*Modals0)->usrmod0_min_passwd_len
|
|||
|
= (DWORD)SmbGetUshort( &UasHeader->min_passwd_len );
|
|||
|
(*Modals0)->usrmod0_max_passwd_age
|
|||
|
= SmbGetUlong( &UasHeader->max_passwd_age );
|
|||
|
(*Modals0)->usrmod0_min_passwd_age
|
|||
|
= SmbGetUlong( &UasHeader->min_passwd_age );
|
|||
|
(*Modals0)->usrmod0_force_logoff
|
|||
|
= SmbGetUlong( &UasHeader->force_logoff );
|
|||
|
(*Modals0)->usrmod0_password_hist_len
|
|||
|
= (DWORD)SmbGetUshort( &UasHeader->passwd_hist_len );
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PortUasGetGroups(
|
|||
|
OUT LPBYTE * Buffer,
|
|||
|
OUT LPBYTE * Gids,
|
|||
|
OUT LPDWORD Entries
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get groups from the current database.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Buffer - A pointer to an LPBYTE which will get a pointer to the returned
|
|||
|
buffer. The buffer will contain a number of GROUP_INFO_1
|
|||
|
structures, similar to that returned from NetGroupEnum. This
|
|||
|
buffer must be freed with NetApiBufferFree.
|
|||
|
|
|||
|
Gids - A pointer to an LPBYTE which will get a pointer to an array
|
|||
|
of group IDs, corresponding to the entries in the returned
|
|||
|
buffer. This array must be freed with NetApiBufferFree.
|
|||
|
|
|||
|
Entries - A pointer to a DWORD which will receive the number of
|
|||
|
entries in the buffer. There are no more entries in the
|
|||
|
database.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success if successful, or one of the following:
|
|||
|
|
|||
|
NERR_ACFNotLoaded - database not open
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - self-explanatory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
DWORD i;
|
|||
|
DWORD count;
|
|||
|
DWORD size; // byte count.
|
|||
|
LPDWORD groupIds;
|
|||
|
LPGROUP_INFO_1 groupInfo;
|
|||
|
LPWSTR varData;
|
|||
|
|
|||
|
*Entries = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Check if the database is in memory.
|
|||
|
//
|
|||
|
|
|||
|
if ( !uasInMemory ) {
|
|||
|
|
|||
|
return NERR_ACFNotLoaded;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Go through the group entries, calculating required buffer size.
|
|||
|
//
|
|||
|
|
|||
|
size = 16;
|
|||
|
count = 0;
|
|||
|
for ( i = 0; i < UAS_MAXGROUP; i++ ) {
|
|||
|
|
|||
|
//
|
|||
|
// Only enumerate valid entries.
|
|||
|
//
|
|||
|
|
|||
|
if ( UAS_GROUP_ENTRY_IS_VALID( &groups[i] ) ) {
|
|||
|
|
|||
|
count++;
|
|||
|
size += sizeof(GROUP_INFO_1);
|
|||
|
size += sizeof(WCHAR) * ( strlen( (char *) groups[i].name ) + 1);
|
|||
|
size += sizeof(WCHAR) * ( strlen( (char *) groups[i].comment ) + 1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Try to get buffers big enough.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetApiBufferAllocate( 16 + count * sizeof(DWORD), (PVOID *)Gids )) {
|
|||
|
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if ( NetApiBufferAllocate( size, (PVOID *)Buffer )) {
|
|||
|
|
|||
|
(void) NetApiBufferFree( *Gids );
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill buffer with data.
|
|||
|
//
|
|||
|
|
|||
|
groupInfo = (LPGROUP_INFO_1)*Buffer;
|
|||
|
groupIds = (LPDWORD)*Gids;
|
|||
|
varData = (LPVOID)( &groupInfo[count] );
|
|||
|
count = 0;
|
|||
|
for ( i = 0; i < UAS_MAXGROUP; i++ ) {
|
|||
|
|
|||
|
//
|
|||
|
// Only enumerate valid entries.
|
|||
|
//
|
|||
|
|
|||
|
if ( UAS_GROUP_ENTRY_IS_VALID( &groups[i] ) ) {
|
|||
|
|
|||
|
NetpAssert( groups[i].name[0] != NULLC );
|
|||
|
|
|||
|
groupIds[count] = (DWORD)i;
|
|||
|
PortUaspPutString( groupInfo[count], grpi1_name,
|
|||
|
groups[i].name, varData );
|
|||
|
PortUaspPutString( groupInfo[count], grpi1_comment,
|
|||
|
groups[i].comment, varData );
|
|||
|
count++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*Entries = count;
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DBGSTATIC BOOL
|
|||
|
PortUasIsUserIteratorValid(
|
|||
|
IN LPUSER_ITERATOR Iterator
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
#define M(text) \
|
|||
|
{ \
|
|||
|
NetpKdPrint(( PREFIX_PORTUAS "PortUasIsUserIteratorValid: " \
|
|||
|
text ".\n" )); \
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (Iterator == NULL) {
|
|||
|
M("null ptr");
|
|||
|
return (FALSE);
|
|||
|
} else if ( (Iterator->Index == NULL_INDEX)
|
|||
|
&& (Iterator->DiskOffset==NULL_DISK_OFFSET) ) {
|
|||
|
|
|||
|
return (TRUE); // initial value
|
|||
|
} else if (Iterator->Index == UAS_USER_HASH_ENTRIES) {
|
|||
|
return (TRUE); // done
|
|||
|
} else if (Iterator->Index > UAS_USER_HASH_ENTRIES) {
|
|||
|
M("index too large");
|
|||
|
return (FALSE);
|
|||
|
} else if (Iterator->Index == NULL_INDEX) {
|
|||
|
M("null index w/o null disk offset");
|
|||
|
return (FALSE);
|
|||
|
} else if (Iterator->DiskOffset == NULL_DISK_OFFSET) {
|
|||
|
M("null disk offset w/o null index");
|
|||
|
return (FALSE);
|
|||
|
} else {
|
|||
|
return (TRUE); // normal (in between initial and done) value.
|
|||
|
}
|
|||
|
|
|||
|
/*NOTREACHED*/
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DBGSTATIC VOID
|
|||
|
PortUasFindNextNonemptyUserChain(
|
|||
|
IN OUT LPUSER_ITERATOR Iterator
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD CurrentChain;
|
|||
|
NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
|
|||
|
|
|||
|
CurrentChain = Iterator->Index;
|
|||
|
if (CurrentChain == NULL_INDEX) {
|
|||
|
CurrentChain = 0;
|
|||
|
} else if (CurrentChain == UAS_USER_HASH_ENTRIES) {
|
|||
|
return; // Already done.
|
|||
|
} else {
|
|||
|
++CurrentChain;
|
|||
|
}
|
|||
|
while (CurrentChain < UAS_USER_HASH_ENTRIES) {
|
|||
|
if ( (userHashes[CurrentChain].dh_disk) != NULL_DISK_OFFSET ) {
|
|||
|
Iterator->DiskOffset = userHashes[CurrentChain].dh_disk;
|
|||
|
break; // found a nonempty chain
|
|||
|
}
|
|||
|
++CurrentChain;
|
|||
|
}
|
|||
|
|
|||
|
Iterator->Index = CurrentChain; // may be UAS_USER_HASH_ENTRIES (done)
|
|||
|
NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DBGSTATIC VOID
|
|||
|
PortUasBumpUserIterator(
|
|||
|
IN OUT LPUSER_ITERATOR Iterator
|
|||
|
)
|
|||
|
{
|
|||
|
NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
|
|||
|
|
|||
|
if (Iterator->Index == NULL_INDEX) {
|
|||
|
|
|||
|
// Just starting out.
|
|||
|
|
|||
|
PortUasFindNextNonemptyUserChain( Iterator );
|
|||
|
|
|||
|
} else if (Iterator->Index == UAS_USER_HASH_ENTRIES) {
|
|||
|
|
|||
|
// Already done. Nothing else to do.
|
|||
|
|
|||
|
} else {
|
|||
|
DWORD NextDiskOffset;
|
|||
|
|
|||
|
// We're in a chain...
|
|||
|
|
|||
|
// We should only be here if we've got the one pointing to the
|
|||
|
// next one.
|
|||
|
NetpAssert( PortUasUserIteratorEqual( Iterator, ¤tUser ) );
|
|||
|
|
|||
|
//
|
|||
|
// Set disk offset to point to the next entry (if any) in chain.
|
|||
|
//
|
|||
|
NextDiskOffset = user->uo_header.do_next;
|
|||
|
|
|||
|
if (NextDiskOffset != NULL_DISK_OFFSET) {
|
|||
|
|
|||
|
//
|
|||
|
// We've got at least one more entry in this chain.
|
|||
|
//
|
|||
|
Iterator->DiskOffset = NextDiskOffset;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Handle end of chain by finding next nonempty chain.
|
|||
|
//
|
|||
|
PortUasFindNextNonemptyUserChain( Iterator );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
|
|||
|
|
|||
|
} // PortUasBumpUserIterator
|
|||
|
|
|||
|
|
|||
|
DBGSTATIC BOOL
|
|||
|
PortUasIsUserIteratorDone(
|
|||
|
IN LPUSER_ITERATOR Iterator
|
|||
|
)
|
|||
|
{
|
|||
|
NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
|
|||
|
|
|||
|
if (Iterator->Index == UAS_USER_HASH_ENTRIES) {
|
|||
|
return (TRUE);
|
|||
|
} else {
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PortUasGetUser(
|
|||
|
IN OUT LPUSER_ITERATOR Iterator,
|
|||
|
OUT LPBYTE * Buffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get a user from the current database.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BUGBUG: Index (DWORD) is now Iterator (structure). Update doc!
|
|||
|
Index - A pointer to a DWORD indicating which user entry to get. When
|
|||
|
the index is NULL_INDEX, the first entry is read. Otherwise,
|
|||
|
the index is incremented, and the next entry is read. On return,
|
|||
|
this index contains the index of the entry just read.
|
|||
|
|
|||
|
Buffer - A pointer to an LPBYTE which will get a pointer to the returned
|
|||
|
buffer. The buffer will contain a single USER_INFO_22
|
|||
|
structure, similar to that returned from NetUserGetInfo,
|
|||
|
except that the password will be a null array( filled with
|
|||
|
zeros). This buffer must be freed with NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success if successful, or one of the following:
|
|||
|
|
|||
|
NERR_UserNotFound - no more users left
|
|||
|
NERR_ACFNotLoaded - database not open
|
|||
|
ERROR_INVALID_PARAMETER - iterator is bad
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - self-explanatory
|
|||
|
NERR_ACFFileIOFail - error reading file
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NET_API_STATUS rc;
|
|||
|
DWORD size;
|
|||
|
LPUSER_INFO_22 userInfo;
|
|||
|
LPWSTR varData;
|
|||
|
|
|||
|
//
|
|||
|
// Check if the database is in memory.
|
|||
|
//
|
|||
|
|
|||
|
if ( !uasInMemory ) {
|
|||
|
|
|||
|
return NERR_ACFNotLoaded;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// (loop if we're skipping to a particular user)
|
|||
|
//
|
|||
|
/*lint -save -e716 */ // disable warnings for while(TRUE)
|
|||
|
while (TRUE) { // (loop if we're skipping to a particular user)
|
|||
|
|
|||
|
NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
|
|||
|
|
|||
|
PortUasBumpUserIterator( Iterator );
|
|||
|
|
|||
|
if (PortUasIsUserIteratorDone( Iterator ) ) {
|
|||
|
|
|||
|
return NERR_UserNotFound;
|
|||
|
}
|
|||
|
|
|||
|
++usersDoneSoFar;
|
|||
|
if (Verbose) {
|
|||
|
//PROGRESS_MSG( ("Reading user " FORMAT_DWORD " of " FORMAT_DWORD
|
|||
|
// ".\n", usersDoneSoFar, usersTotal) );
|
|||
|
(VOID) NlsPutMsg(
|
|||
|
STDOUT,
|
|||
|
PUAS_READING_USER_OF_TOTAL,
|
|||
|
usersDoneSoFar,
|
|||
|
usersTotal );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the user data in a global variable.
|
|||
|
//
|
|||
|
|
|||
|
rc = PortUaspGetUserData( Iterator );
|
|||
|
if (rc != NO_ERROR) {
|
|||
|
NetpAssert( rc != NERR_UserNotFound ); // Already handled!
|
|||
|
return rc;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Decide whether or not this is the one we're looking for or
|
|||
|
// if we're processing all users. If neither, then loop back
|
|||
|
// and get the next user.
|
|||
|
//
|
|||
|
|
|||
|
if (PortUasGlobalUserToSkipTo == NULL) {
|
|||
|
break; // Not skipping users, so use this one by definition.
|
|||
|
} else {
|
|||
|
LONG Result;
|
|||
|
TCHAR TempUserName[UNLEN+1];
|
|||
|
|
|||
|
if ( strlen( user->uo_record.name ) > UNLEN ) {
|
|||
|
// Don't use this one, we would trash the stack below.
|
|||
|
return (NERR_ACFFileIOFail); // corrupt database!
|
|||
|
}
|
|||
|
NetpCopyStrToTStr(
|
|||
|
TempUserName, // dest (TCHARs)
|
|||
|
(LPSTR) (user->uo_record.name) ); // src
|
|||
|
|
|||
|
Result = I_NetNameCompare(
|
|||
|
NULL, // local (no server name)
|
|||
|
PortUasGlobalUserToSkipTo,
|
|||
|
TempUserName,
|
|||
|
NAMETYPE_USER, // type is user name
|
|||
|
0 ); // flags: nothing special
|
|||
|
if (Result != 0) {
|
|||
|
//PROGRESS_MSG( ("Skipping user " FORMAT_LPSTR "...\n",
|
|||
|
// user->uo_record.name) );
|
|||
|
(void)NlsPutMsg(STDOUT, PUAS_SKIPPING_USER,
|
|||
|
user->uo_record.name);
|
|||
|
|
|||
|
} else {
|
|||
|
// Found the one we're looking for.
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/*lint -restore */ // re-enable warnings for while(TRUE)
|
|||
|
|
|||
|
//
|
|||
|
// Find required return buffer size
|
|||
|
//
|
|||
|
|
|||
|
size = strlen( user->uo_record.name )
|
|||
|
// no password at all, so don't add chars for it here.
|
|||
|
+ strlen( MAKE_PTR( user, directory_o ))
|
|||
|
+ strlen( MAKE_PTR( user, comment_o ))
|
|||
|
+ strlen( MAKE_PTR( user, script_o ))
|
|||
|
+ strlen( MAKE_PTR( user, full_name_o ))
|
|||
|
+ strlen( MAKE_PTR( user, usr_comment_o ))
|
|||
|
+ strlen( MAKE_PTR( user, parms_o ))
|
|||
|
+ strlen( MAKE_PTR( user, workstation_o ))
|
|||
|
+ strlen( MAKE_PTR( user, logon_server_o ))
|
|||
|
+ 10;
|
|||
|
size = size * sizeof(WCHAR)
|
|||
|
+ sizeof(USER_INFO_22)
|
|||
|
+ UNITS_PER_WEEK / 8 + 1;
|
|||
|
|
|||
|
//
|
|||
|
// Try to get a buffer big enough.
|
|||
|
//
|
|||
|
|
|||
|
rc = NetApiBufferAllocate( size, (PVOID *)Buffer );
|
|||
|
if (rc != NO_ERROR) {
|
|||
|
|
|||
|
NetpAssert( rc == ERROR_NOT_ENOUGH_MEMORY );
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
NetpAssert( Buffer != NULL );
|
|||
|
|
|||
|
//
|
|||
|
// Fill buffer with data.
|
|||
|
//
|
|||
|
|
|||
|
userInfo = (LPUSER_INFO_22)*Buffer;
|
|||
|
varData = (LPVOID)( &userInfo[1] );
|
|||
|
|
|||
|
PortUaspPutString( *userInfo, usri22_name,
|
|||
|
user->uo_record.name, varData );
|
|||
|
|
|||
|
RtlFillMemory( userInfo->usri22_password,
|
|||
|
sizeof(userInfo->usri22_password), 0);
|
|||
|
|
|||
|
userInfo->usri22_priv
|
|||
|
= (DWORD)SmbGetUshort( &user->uo_record.user.uc0_priv );
|
|||
|
PortUaspPutString( *userInfo, usri22_home_dir,
|
|||
|
MAKE_PTR( user, directory_o ), varData );
|
|||
|
PortUaspPutString( *userInfo, usri22_comment,
|
|||
|
MAKE_PTR( user, comment_o ), varData );
|
|||
|
userInfo->usri22_flags = (DWORD)SmbGetUshort( &user->uo_record.flags );
|
|||
|
PortUaspPutString( *userInfo, usri22_script_path,
|
|||
|
MAKE_PTR( user, script_o ), varData );
|
|||
|
userInfo->usri22_auth_flags
|
|||
|
= SmbGetUlong( &user->uo_record.user.uc0_auth_flags );
|
|||
|
PortUaspPutString( *userInfo, usri22_full_name,
|
|||
|
MAKE_PTR( user, full_name_o ), varData );
|
|||
|
PortUaspPutString( *userInfo, usri22_usr_comment,
|
|||
|
MAKE_PTR( user, usr_comment_o ), varData );
|
|||
|
PortUaspPutString( *userInfo, usri22_parms,
|
|||
|
MAKE_PTR( user, parms_o ), varData );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Convert the list of workstations from a blank separated list to
|
|||
|
// comma separated list.
|
|||
|
//
|
|||
|
PortUaspPutString( *userInfo, usri22_workstations,
|
|||
|
MAKE_PTR( user, workstation_o ), varData );
|
|||
|
|
|||
|
if ( wcslen( userInfo->usri22_workstations ) > 0 ) {
|
|||
|
NTSTATUS NtStatus;
|
|||
|
UNICODE_STRING BlankSep;
|
|||
|
UNICODE_STRING CommaSep;
|
|||
|
|
|||
|
RtlInitUnicodeString( &BlankSep, userInfo->usri22_workstations );
|
|||
|
|
|||
|
NtStatus = RtlConvertUiListToApiList( &BlankSep,
|
|||
|
&CommaSep,
|
|||
|
TRUE ); // Blank Is Delimiter
|
|||
|
|
|||
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|||
|
|
|||
|
// ERROR_MSG( ("Error processing workstation list for user " FORMAT_LPSTR,
|
|||
|
// user->uo_record.name) );
|
|||
|
(VOID) NlsPutMsg( STDOUT, PUAS_ERROR_PROCESSING_WORKSTATIONS,
|
|||
|
user->uo_record.name );
|
|||
|
return NetpNtStatusToApiStatus( NtStatus );
|
|||
|
}
|
|||
|
|
|||
|
NetpAssert( wcslen(CommaSep.Buffer) ==
|
|||
|
wcslen(userInfo->usri22_workstations) );
|
|||
|
(VOID) wcscpy( userInfo->usri22_workstations, CommaSep.Buffer );
|
|||
|
|
|||
|
(VOID) RtlFreeHeap(RtlProcessHeap(), 0, CommaSep.Buffer );
|
|||
|
}
|
|||
|
|
|||
|
userInfo->usri22_acct_expires
|
|||
|
= SmbGetUlong( &user->uo_record.acct_expires );
|
|||
|
#if 0 // BUGBUG - SAM doesn't support max storage
|
|||
|
userInfo->usri22_max_storage
|
|||
|
= SmbGetUlong( &user->uo_record.max_storage );
|
|||
|
#else
|
|||
|
userInfo->usri22_max_storage = USER_MAXSTORAGE_UNLIMITED;
|
|||
|
#endif
|
|||
|
userInfo->usri22_units_per_week = UNITS_PER_WEEK;
|
|||
|
|
|||
|
userInfo->usri22_logon_hours = (LPBYTE)varData;
|
|||
|
memcpy( (LPBYTE)varData, user->uo_record.logonhrs, UNITS_PER_WEEK / 8 );
|
|||
|
if ( !NetpRotateLogonHours(
|
|||
|
(LPVOID) varData, // rotate these hours (update in place)
|
|||
|
UNITS_PER_WEEK,
|
|||
|
TRUE /* yes, convert to GMT */ ) ) {
|
|||
|
|
|||
|
//ERROR_MSG( ("Error processing logon hours for user " FORMAT_LPSTR,
|
|||
|
// user->uo_record.name) );
|
|||
|
(VOID) NlsPutMsg(STDOUT, PUAS_ERROR_PROCESSING_LOGON_HOURS,
|
|||
|
user->uo_record.name);
|
|||
|
|
|||
|
// Tell caller about error. This may or may not have been our
|
|||
|
// fault, but NetpRotateLogonHours doesn't give any other clues.
|
|||
|
return (NERR_InternalError);
|
|||
|
}
|
|||
|
|
|||
|
varData = (LPWSTR)( (LPBYTE)varData + UNITS_PER_WEEK / 8 + 1 );
|
|||
|
|
|||
|
PortUaspPutString( *userInfo, usri22_logon_server,
|
|||
|
MAKE_PTR( user, logon_server_o ), varData );
|
|||
|
userInfo->usri22_country_code
|
|||
|
= (DWORD) SmbGetUshort( &user->uo_record.country_code );
|
|||
|
userInfo->usri22_code_page
|
|||
|
= (DWORD) SmbGetUshort( &user->uo_record.code_page );
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PortUasGetUserOWFPassword(
|
|||
|
IN LPUSER_ITERATOR Iterator,
|
|||
|
OUT LPBYTE * Password
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get a user's password, in one-way-encryption form.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BUGBUG: Index (DWORD) is now Iterator (structure). Update doc!
|
|||
|
Index - A DWORD indicating which entry to get. This can, but doesn't
|
|||
|
have to, be the value of the index returned from PortUasGetUser.
|
|||
|
|
|||
|
Password - A pointer to an LPBYTE which will get a pointer to the
|
|||
|
returned password. This buffer must be freed with
|
|||
|
NetApiBufferFree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success if successful, or one of the following:
|
|||
|
|
|||
|
NERR_UserNotFound - not a valid user index
|
|||
|
NERR_ACFNotLoaded - database not open
|
|||
|
ERROR_INVALID_PASSWORD - can't be decrypted
|
|||
|
ERROR_INVALID_PARAMETER - index is bad
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - self-explanatory
|
|||
|
NERR_ACFFileIOFail - error reading file
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
NET_API_STATUS rc;
|
|||
|
|
|||
|
//
|
|||
|
// Check if the database is in memory.
|
|||
|
//
|
|||
|
|
|||
|
if ( !uasInMemory ) {
|
|||
|
|
|||
|
return NERR_ACFNotLoaded;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check the iterator.
|
|||
|
//
|
|||
|
|
|||
|
NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
|
|||
|
|
|||
|
//
|
|||
|
// Get the user data, if necessary.
|
|||
|
//
|
|||
|
|
|||
|
if ( rc = PortUaspGetUserData( Iterator )) {
|
|||
|
|
|||
|
return rc;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Try to get a buffer.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetApiBufferAllocate( sizeof(LM_OWF_PASSWORD), (PVOID *)Password )) {
|
|||
|
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Decrypt password into buffer.
|
|||
|
//
|
|||
|
|
|||
|
#if 0
|
|||
|
if (Verbose) {
|
|||
|
DumpPassword( "from UAS", user->uo_record.passwd );
|
|||
|
}
|
|||
|
#endif
|
|||
|
if ( PortUasDecryptLmOwfPwdWithIndex(
|
|||
|
(PENCRYPTED_LM_OWF_PASSWORD)( user->uo_record.passwd ),
|
|||
|
(LPDWORD) &(Iterator->Index),
|
|||
|
(PLM_OWF_PASSWORD)*Password )) {
|
|||
|
|
|||
|
(void) NetApiBufferFree( *Password );
|
|||
|
return ERROR_INVALID_PASSWORD;
|
|||
|
}
|
|||
|
#if 0
|
|||
|
if (Verbose) {
|
|||
|
DumpPassword( "decrypted once", *Password );
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PortUasGetUserGroups(
|
|||
|
IN LPUSER_ITERATOR UserIterator,
|
|||
|
OUT LPBYTE * Buffer,
|
|||
|
OUT LPBYTE * Gids,
|
|||
|
OUT LPDWORD Entries
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get groups for a user in the current database.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BUGBUG: Index (DWORD) is now UserIterator (structure). Update doc!
|
|||
|
Index - A DWORD indicating which entry to get. This can, but doesn't
|
|||
|
have to, be the value of the index returned from PortUasGetUser.
|
|||
|
|
|||
|
Buffer - A pointer to an LPBYTE which will get a pointer to the returned
|
|||
|
buffer. The buffer will contain a number of GROUP_INFO_0
|
|||
|
structures, similar to that returned from NetUserGetGroups.
|
|||
|
|
|||
|
Gids - A pointer to an LPBYTE which will get a pointer to an array
|
|||
|
of group IDs, corresponding to the entries in the returned
|
|||
|
buffer. This array must be freed with NetApiBufferFree.
|
|||
|
|
|||
|
Entries - A pointer to a DWORD which will receive a count of the number
|
|||
|
of group entries returned.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success if successful, or one of the following:
|
|||
|
|
|||
|
NERR_UserNotFound - not a valid user iterator
|
|||
|
NERR_ACFNotLoaded - database not open
|
|||
|
ERROR_INVALID_PARAMETER - iterator is bad
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - self-explanatory
|
|||
|
NERR_ACFFileIOFail - error reading file
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NET_API_STATUS rc;
|
|||
|
DWORD count;
|
|||
|
DWORD size;
|
|||
|
LPBYTE groupMask;
|
|||
|
LPDWORD groupIds;
|
|||
|
LPGROUP_INFO_0 groupInfo;
|
|||
|
LPWSTR varData;
|
|||
|
DWORD i;
|
|||
|
|
|||
|
//
|
|||
|
// Check if the database is in memory.
|
|||
|
//
|
|||
|
|
|||
|
if ( !uasInMemory ) {
|
|||
|
|
|||
|
return NERR_ACFNotLoaded;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check the user iterator.
|
|||
|
//
|
|||
|
|
|||
|
NetpAssert( PortUasIsUserIteratorValid( UserIterator ) );
|
|||
|
|
|||
|
//
|
|||
|
// Get the user data, if necessary.
|
|||
|
//
|
|||
|
|
|||
|
if ( rc = PortUaspGetUserData( UserIterator )) {
|
|||
|
|
|||
|
return rc;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find the number of groups.
|
|||
|
//
|
|||
|
|
|||
|
count = 0;
|
|||
|
groupMask = user->uo_record.user.uc0_groups;
|
|||
|
|
|||
|
for ( i = 0; i < UAS_MAXGROUP; i++ ) {
|
|||
|
|
|||
|
if ( UAS_ISBITON( groupMask, i )) {
|
|||
|
|
|||
|
count++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Try to get a buffer of adequate size. The maximum size required is
|
|||
|
// calculated using the count above and the maximum size of a group name.
|
|||
|
// LANMAN 2.0 group names are smaller, we'll use that maximum.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetApiBufferAllocate( 16 + count * sizeof(DWORD), (PVOID *)Gids )) {
|
|||
|
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
size = count * (( LM20_GNLEN + 1 ) * sizeof(WCHAR) + sizeof(GROUP_INFO_0))
|
|||
|
+ 16;
|
|||
|
|
|||
|
if ( NetApiBufferAllocate( size, (PVOID *)Buffer )) {
|
|||
|
|
|||
|
(void) NetApiBufferFree( *Gids );
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// One by one, get the group names.
|
|||
|
//
|
|||
|
|
|||
|
groupInfo = (LPGROUP_INFO_0)*Buffer;
|
|||
|
groupIds = (LPDWORD)*Gids;
|
|||
|
varData = (LPVOID)( &groupInfo[count] );
|
|||
|
count = 0;
|
|||
|
for ( i = 0; i < UAS_MAXGROUP; i++ ) {
|
|||
|
|
|||
|
//
|
|||
|
// Only enumerate valid entries.
|
|||
|
//
|
|||
|
|
|||
|
if ( UAS_GROUP_ENTRY_IS_VALID( &groups[i] ) ) {
|
|||
|
|
|||
|
if ( UAS_ISBITON( groupMask, i )) {
|
|||
|
|
|||
|
groupIds[count] = i;
|
|||
|
PortUaspPutString( groupInfo[count], grpi0_name,
|
|||
|
groups[i].name, varData );
|
|||
|
count++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*Entries = count;
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DBGSTATIC
|
|||
|
NET_API_STATUS
|
|||
|
PortUaspGetUserData(
|
|||
|
IN LPUSER_ITERATOR Iterator
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get actual data for a user indexed in the hashing table. If the
|
|||
|
particular user is already loaded, it does nothing.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Iterator - indicates user to get.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success if successful, or one of the following:
|
|||
|
|
|||
|
NERR_UserNotFound - not a valid user
|
|||
|
NERR_ACFFileIOFail - error reading file
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
INT cb;
|
|||
|
UAS_DISK_OBJ_HDR usrHeader;
|
|||
|
|
|||
|
NetpAssert( PortUasIsUserIteratorValid( Iterator ) );
|
|||
|
|
|||
|
//
|
|||
|
// Is the user already loaded?
|
|||
|
//
|
|||
|
|
|||
|
if ( PortUasUserIteratorEqual( Iterator, ¤tUser ) ) {
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Is this a valid user?
|
|||
|
//
|
|||
|
|
|||
|
NetpAssert( Iterator->Index != NULL_INDEX );
|
|||
|
NetpAssert( Iterator->Index != UAS_USER_HASH_ENTRIES );
|
|||
|
NetpAssert( Iterator->DiskOffset != NULL_DISK_OFFSET );
|
|||
|
NetpAssert( userHashes[Iterator->Index].dh_disk != NULL_DISK_OFFSET );
|
|||
|
|
|||
|
//
|
|||
|
// Flag global data as being invalid, in case we get error during read.
|
|||
|
//
|
|||
|
PortUasInitUserIterator( currentUser );
|
|||
|
|
|||
|
//
|
|||
|
// Load the header for the user data.
|
|||
|
//
|
|||
|
|
|||
|
if (SetFilePointer(database, (LONG)Iterator->DiskOffset, NULL, FILE_BEGIN)
|
|||
|
== -1) {
|
|||
|
|
|||
|
return NERR_ACFFileIOFail;
|
|||
|
}
|
|||
|
|
|||
|
if (!ReadFile(database, &usrHeader, sizeof(UAS_DISK_OBJ_HDR), &cb, NULL) ||
|
|||
|
cb != sizeof(UAS_DISK_OBJ_HDR)) {
|
|||
|
|
|||
|
return NERR_ACFFileIOFail;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Use information in the header to rewind and read the correct amount.
|
|||
|
//
|
|||
|
|
|||
|
if (SetFilePointer(database, (LONG)Iterator->DiskOffset, NULL, FILE_BEGIN)
|
|||
|
== -1) {
|
|||
|
|
|||
|
return NERR_ACFFileIOFail;
|
|||
|
}
|
|||
|
|
|||
|
if (!ReadFile(database, user,
|
|||
|
(DWORD)usrHeader.do_numblocks * UAS_DISK_BLOCK_SIZE,
|
|||
|
&cb, NULL) ||
|
|||
|
cb != usrHeader.do_numblocks * UAS_DISK_BLOCK_SIZE ) {
|
|||
|
|
|||
|
return NERR_ACFFileIOFail;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Flag global data as valid again.
|
|||
|
//
|
|||
|
PortUasCopyUserIterator(
|
|||
|
& currentUser, // dest
|
|||
|
Iterator ); // src
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
|
|||
|
}
|