948 lines
30 KiB
C
948 lines
30 KiB
C
/*++
|
|
|
|
Copyright (c) 1991-92 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rxgroup.c
|
|
|
|
Abstract:
|
|
|
|
Contains RxNetGroup routines:
|
|
RxNetGroupAdd
|
|
RxNetGroupAddUser
|
|
RxNetGroupDel
|
|
RxNetGroupDelUser
|
|
RxNetGroupEnum
|
|
RxNetGroupGetInfo
|
|
RxNetGroupGetUsers
|
|
RxNetGroupSetInfo
|
|
RxNetGroupSetUsers
|
|
|
|
Author:
|
|
|
|
Richard L Firth (rfirth) 20-May-1991
|
|
|
|
Environment:
|
|
|
|
Win-32/flat address space
|
|
|
|
Notes:
|
|
|
|
Routines in this module assume that caller-supplied parameters have
|
|
already been verified. No effort is made to further check the veracity
|
|
of parms. Any actions causing exceptions must be trapped at a higher
|
|
level. This applies to ALL parameters - strings, pointers, buffers, etc.
|
|
|
|
Revision History:
|
|
|
|
20-May-1991 rfirth
|
|
Created
|
|
13-Sep-1991 JohnRo
|
|
Made changes suggested by PC-LINT.
|
|
25-Sep-1991 JohnRo
|
|
Correct UNICODE use. (Use POSSIBLE_WCSSIZE() and wcslen() for
|
|
LPWSTR types.) Fixed MIPS build problems.
|
|
21-Nov-1991 JohnRo
|
|
Removed NT dependencies to reduce recompiles.
|
|
05-Dec-1991 RFirth
|
|
Enum returns in TotalEntries (or EntriesLeft) the number of items to
|
|
be enumerated BEFORE this call. Used to be number left after this call
|
|
01-Apr-1992 JohnRo
|
|
Use NetApiBufferAllocate() instead of private version.
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#include "downlevl.h"
|
|
#include <rxgroup.h>
|
|
#include <lmaccess.h>
|
|
|
|
|
|
|
|
DBGSTATIC
|
|
VOID
|
|
get_group_descriptors(
|
|
DWORD Level,
|
|
LPDESC* pDesc16,
|
|
LPDESC* pDesc32,
|
|
LPDESC* pDescSmb
|
|
);
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
RxNetGroupAdd(
|
|
IN LPTSTR ServerName,
|
|
IN DWORD Level,
|
|
IN LPBYTE Buffer,
|
|
OUT LPDWORD ParmError OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a group in the User Account Database at a down-level server
|
|
|
|
Arguments:
|
|
|
|
ServerName - at which server to perform this request
|
|
Level - of information to add. Can be 0 or 1
|
|
Buffer - containing caller's GROUP_INFO_{0|1} structure
|
|
ParmError - pointer to returned parameter error identifier. NOT USED
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS:
|
|
Success = NERR_Success
|
|
Failure = ERROR_INVALID_LEVEL
|
|
Level must be 0 or 1
|
|
ERROR_INVALID_PARAMETER
|
|
Buffer is NULL pointer
|
|
--*/
|
|
|
|
{
|
|
DWORD buflen; // size of caller's buffer (we calculate it)
|
|
LPDESC pDesc16; // pointer to 16-bit info descriptor for RxRemoteApi
|
|
LPDESC pDesc32; // pointer to 32-bit info descriptor for RxRemoteApi
|
|
LPDESC pDescSmb; // pointer to SMB info descriptor for RxRemoteApi
|
|
|
|
|
|
UNREFERENCED_PARAMETER(ParmError);
|
|
|
|
|
|
//
|
|
// try to trap any basic problems
|
|
//
|
|
|
|
if (Level > 1) {
|
|
return ERROR_INVALID_LEVEL;
|
|
}
|
|
|
|
if (!Buffer) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Calculate the size of the buffer we are passing into the remoted API.
|
|
// The down-level logic expects a buffer size; Nt does not. If the sizes
|
|
// of the variable fields exceed the down-level maximums then we will get
|
|
// some kind of invalid parameter error. Let the caller handle it
|
|
//
|
|
|
|
buflen = ((Level == 1) ? sizeof(GROUP_INFO_1) : sizeof(GROUP_INFO_0))
|
|
+ POSSIBLE_STRLEN(((PGROUP_INFO_0)Buffer)->grpi0_name);
|
|
buflen += (Level == 1) ? POSSIBLE_STRLEN(((PGROUP_INFO_1)Buffer)->grpi1_comment) : 0;
|
|
|
|
//
|
|
// Get the data descriptor strings based on the info level then make the
|
|
// down-level call. We expect no return data, so just return the result
|
|
// to the caller
|
|
//
|
|
|
|
get_group_descriptors(Level, &pDesc16, &pDesc32, &pDescSmb);
|
|
return RxRemoteApi(API_WGroupAdd, // API #
|
|
ServerName, // on which server
|
|
REMSmb_NetGroupAdd_P, // parameter descriptor
|
|
pDesc16, // Data descriptor/16-bit
|
|
pDesc32, // Data descriptor/32-bit
|
|
pDescSmb, // Data descriptor/SMB
|
|
NULL, // Aux descriptor/16-bit
|
|
NULL, // Aux descriptor/32-bit
|
|
NULL, // Aux descriptor/SMB
|
|
FALSE, // this call needs user to be logged on
|
|
Level, // caller supplied parameters...
|
|
Buffer, // caller's GROUP_INFO_{0|1} struct
|
|
buflen // as supplied by us
|
|
);
|
|
}
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
RxNetGroupAddUser(
|
|
IN LPTSTR ServerName,
|
|
IN LPTSTR GroupName,
|
|
IN LPTSTR UserName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a user to a UAS group on a down-level server
|
|
|
|
Arguments:
|
|
|
|
ServerName - at which server to perform this request
|
|
GroupName - name of group to add user to
|
|
UserName - name of user to add
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS:
|
|
Success = NERR_Success
|
|
Failure = ERROR_INVALID_PARAMETER
|
|
GroupName or UserName not valid strings
|
|
--*/
|
|
|
|
{
|
|
if (!VALID_STRING(GroupName) && !VALID_STRING(UserName)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return RxRemoteApi(API_WGroupAddUser, // API #
|
|
ServerName, // where to remote it
|
|
REMSmb_NetGroupAddUser_P, // parameter descriptor
|
|
NULL, // Data descriptor/16-bit
|
|
NULL, // Data descriptor/32-bit
|
|
NULL, // Data descriptor/SMB
|
|
NULL, // Aux descriptor/16-bit
|
|
NULL, // Aux descriptor/32-bit
|
|
NULL, // Aux descriptor/SMB
|
|
FALSE, // this call needs user to be logged on
|
|
GroupName, // parm 1
|
|
UserName // parm 2
|
|
);
|
|
}
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
RxNetGroupDel(
|
|
IN LPTSTR ServerName,
|
|
IN LPTSTR GroupName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a group from a down-level server UAS database
|
|
|
|
Arguments:
|
|
|
|
ServerName - at which server to perform this request
|
|
GroupName - name of group to delete
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS:
|
|
Success = NERR_Success
|
|
Failure = ERROR_INVALID_PARAMETER
|
|
GroupName not valid string
|
|
--*/
|
|
|
|
{
|
|
if (!VALID_STRING(GroupName)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return RxRemoteApi(API_WGroupDel, // API #
|
|
ServerName, // where to remote it
|
|
REMSmb_NetGroupDel_P, // parameter descriptor
|
|
NULL, // Data descriptor/16-bit
|
|
NULL, // Data descriptor/32-bit
|
|
NULL, // Data descriptor/SMB
|
|
NULL, // Aux descriptor/16-bit
|
|
NULL, // Aux descriptor/32-bit
|
|
NULL, // Aux descriptor/SMB
|
|
FALSE, // this call needs user to be logged on
|
|
GroupName // parm 1
|
|
);
|
|
}
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
RxNetGroupDelUser(
|
|
IN LPTSTR ServerName,
|
|
IN LPTSTR GroupName,
|
|
IN LPTSTR UserName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a user from a group in a down-level UAS database
|
|
|
|
Arguments:
|
|
|
|
ServerName - at which server to perform this request
|
|
GroupName - name of group to delete user from
|
|
UserName - name of user to delete
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS:
|
|
Success = NERR_Success
|
|
Failure = ERROR_INVALID_PARAMETER
|
|
GroupName or UserName not valid strings
|
|
--*/
|
|
|
|
{
|
|
if (!VALID_STRING(GroupName) && !VALID_STRING(UserName)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return RxRemoteApi(API_WGroupDelUser, // API #
|
|
ServerName, // where to remote it
|
|
REMSmb_NetGroupDelUser_P, // parameter descriptor
|
|
NULL, // Data descriptor/16-bit
|
|
NULL, // Data descriptor/32-bit
|
|
NULL, // Data descriptor/SMB
|
|
NULL, // Aux descriptor/16-bit
|
|
NULL, // Aux descriptor/32-bit
|
|
NULL, // Aux descriptor/SMB
|
|
FALSE, // this call needs user to be logged on
|
|
GroupName, // parm 1
|
|
UserName // parm 2
|
|
);
|
|
}
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
RxNetGroupEnum(
|
|
IN LPTSTR ServerName,
|
|
IN DWORD Level,
|
|
OUT LPBYTE* Buffer,
|
|
IN DWORD PrefMaxLen,
|
|
OUT LPDWORD EntriesRead,
|
|
OUT LPDWORD EntriesLeft,
|
|
IN OUT PDWORD_PTR ResumeHandle OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets a list of GROUP_INFO_{0|1} structures from a down-level server
|
|
|
|
Arguments:
|
|
|
|
ServerName - at which server to perform this request
|
|
Level - of information to retrieve (0 or 1)
|
|
Buffer - pointer to pointer to returned buffer
|
|
PrefMaxLen - caller's maximum
|
|
EntriedRead - pointer to returned number of structures read
|
|
EntriesLeft - pointer to returned nunber of structures left to enumerate
|
|
ResumeHandle- handle used to restart enums. Not used by this routine
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS:
|
|
Success = NERR_Success
|
|
Failure = ERROR_INVALID_LEVEL
|
|
Level parameter must be 0 or 1
|
|
ERROR_INVALID_PARAMETER
|
|
Buffer parameter NULL pointer or non-NULL ResumeHandle
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS rc;
|
|
LPDESC pDesc16; // pointer to 16-bit info descriptor for RxRemoteApi
|
|
LPDESC pDesc32; // pointer to 32-bit info descriptor for RxRemoteApi
|
|
LPDESC pDescSmb; // pointer to SMB info descriptor for RxRemoteApi
|
|
LPBYTE localbuf; // pointer to buffer allocated in this routine
|
|
DWORD total_avail; // returned total available entries
|
|
DWORD entries_read; // returned entries in buffer
|
|
|
|
|
|
UNREFERENCED_PARAMETER(PrefMaxLen);
|
|
|
|
*EntriesRead = *EntriesLeft = 0;
|
|
*Buffer = NULL;
|
|
|
|
if (Level > 1) {
|
|
return ERROR_INVALID_LEVEL;
|
|
}
|
|
|
|
//
|
|
// Buffer must be a valid pointer. If ResumeHandle is not a NULL pointer
|
|
// and points to a non-zero handle value then return an INVALID_PARAMETER
|
|
// error - down-level does not supoort resume
|
|
//
|
|
|
|
if (!NULL_REFERENCE(ResumeHandle)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
get_group_descriptors(Level, &pDesc16, &pDesc32, &pDescSmb);
|
|
localbuf = NULL;
|
|
rc = RxRemoteApi(API_WGroupEnum, // API #
|
|
ServerName, // where to remote it
|
|
REMSmb_NetGroupEnum_P, // parameter descriptor
|
|
pDesc16, // Data descriptor/16-bit
|
|
pDesc32, // Data descriptor/32-bit
|
|
pDescSmb, // Data descriptor/SMB
|
|
NULL, // Aux descriptor/16-bit
|
|
NULL, // Aux descriptor/32-bit
|
|
NULL, // Aux descriptor/SMB
|
|
ALLOCATE_RESPONSE,
|
|
Level, // caller supplied parameters...
|
|
&localbuf,
|
|
65535,
|
|
&entries_read, // parm 4
|
|
&total_avail // parm 5
|
|
);
|
|
|
|
if (rc != NERR_Success) {
|
|
if (localbuf != NULL) {
|
|
(void) NetApiBufferFree(localbuf);
|
|
}
|
|
} else {
|
|
*Buffer = localbuf;
|
|
*EntriesRead = entries_read;
|
|
*EntriesLeft = total_avail;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
RxNetGroupGetInfo(
|
|
IN LPTSTR ServerName,
|
|
IN LPTSTR GroupName,
|
|
IN DWORD Level,
|
|
OUT LPBYTE* Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get information about a specific group in a down-level UAS database
|
|
|
|
Arguments:
|
|
|
|
ServerName - at which server to perform this request
|
|
GroupName - name of group to get information for
|
|
Level - level of information to return (0 or 1)
|
|
Buffer - pointer to returned pointer to info buffer
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS:
|
|
Success = NERR_Success
|
|
Failure = ERROR_INVALID_LEVEL
|
|
Level parameter must be 0 or 1
|
|
ERROR_INVALID_PARAMETER
|
|
Buffer parameter NULL pointer
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS rc;
|
|
LPDESC pDesc16; // pointer to 16-bit info descriptor for RxRemoteApi
|
|
LPDESC pDesc32; // pointer to 32-bit info descriptor for RxRemoteApi
|
|
LPDESC pDescSmb; // pointer to SMB info descriptor for RxRemoteApi
|
|
LPBYTE localbuf; // pointer to buffer allocated in this routine
|
|
DWORD totalbytes; // total available bytes returned from down-level
|
|
DWORD buflen; // size of info buffer, supplied by us
|
|
|
|
|
|
if (Level > 1) {
|
|
return ERROR_INVALID_LEVEL;
|
|
}
|
|
|
|
if (!Buffer) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// calculate the size requirement for the info buffer and allocate it
|
|
//
|
|
|
|
buflen = ((Level == 1) ? sizeof(GROUP_INFO_1) : sizeof(GROUP_INFO_0))
|
|
+ 2 * (LM20_GNLEN + 1);
|
|
buflen += (Level == 1) ? 2 * (LM20_MAXCOMMENTSZ + 1) : 0;
|
|
buflen = DWORD_ROUNDUP(buflen);
|
|
|
|
if (rc = NetApiBufferAllocate(buflen, (LPVOID *) &localbuf)) {
|
|
return rc;
|
|
}
|
|
get_group_descriptors(Level, &pDesc16, &pDesc32, &pDescSmb);
|
|
rc = RxRemoteApi(API_WGroupGetInfo, // API #
|
|
ServerName, // where to remote it
|
|
REMSmb_NetGroupGetInfo_P, // parameter descriptor
|
|
pDesc16, // Data descriptor/16-bit
|
|
pDesc32, // Data descriptor/32-bit
|
|
pDescSmb, // Data descriptor/SMB
|
|
NULL, // Aux descriptor/16-bit
|
|
NULL, // Aux descriptor/32-bit
|
|
NULL, // Aux descriptor/SMB
|
|
FALSE, // this call needs user to be logged on
|
|
GroupName, // parms to down-level start here
|
|
Level, // caller supplied parameters...
|
|
localbuf, // buffer for receiving structures
|
|
buflen, // size of buffer supplied by us
|
|
&totalbytes // returned from down-level. not used
|
|
);
|
|
if (rc == NERR_Success) {
|
|
*Buffer = localbuf;
|
|
} else {
|
|
(void) NetApiBufferFree(localbuf);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
RxNetGroupGetUsers(
|
|
IN LPTSTR ServerName,
|
|
IN LPTSTR GroupName,
|
|
IN DWORD Level,
|
|
OUT LPBYTE* Buffer,
|
|
IN DWORD PrefMaxLen,
|
|
OUT LPDWORD EntriesRead,
|
|
OUT LPDWORD EntriesLeft,
|
|
IN OUT PDWORD_PTR ResumeHandle OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get a list of all the members of a particular group
|
|
|
|
Arguments:
|
|
|
|
ServerName - at which server to perform this request
|
|
GroupName - name of group for which to retrieve member list
|
|
Level - level of group user information requested. Must be 0
|
|
Buffer - pointer to returned pointer to buffer containing info
|
|
PrefMaxLen - preferred maximum length of returned buffer
|
|
EntriesRead - pointer to returned number of entries in buffer
|
|
EntriesLeft - pointer to returned number of entries left
|
|
ResumeHandle- pointer to handle for resume. Not used by this function
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS:
|
|
Success = NERR_Success
|
|
Failure = ERROR_INVALID_LEVEL
|
|
Level parameter must be 0
|
|
ERROR_INVALID_PARAMETER
|
|
Buffer parameter NULL pointer
|
|
or ResumeHandle not NULL pointer or pointer to non-0 value
|
|
or GroupName not valid string
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS rc;
|
|
LPBYTE localbuf; // pointer to buffer allocated in this routine
|
|
DWORD entries_read, total_entries;
|
|
|
|
UNREFERENCED_PARAMETER(PrefMaxLen);
|
|
|
|
//
|
|
// set EntriesLeft and EntriesRead to default values. Test writability of
|
|
// parameters
|
|
//
|
|
|
|
*EntriesRead = *EntriesLeft = 0;
|
|
*Buffer = NULL;
|
|
|
|
if (Level) {
|
|
return ERROR_INVALID_LEVEL;
|
|
}
|
|
|
|
if (!NULL_REFERENCE(ResumeHandle) || !VALID_STRING(GroupName)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
localbuf = NULL;
|
|
rc = RxRemoteApi(API_WGroupGetUsers, // API #
|
|
ServerName, // where to remote it
|
|
REMSmb_NetGroupGetUsers_P, // parameter descriptor
|
|
REM16_group_users_info_0, // Data descriptor/16-bit
|
|
REM32_group_users_info_0, // Data descriptor/32-bit
|
|
REMSmb_group_users_info_0, // Data descriptor/SMB
|
|
NULL, // Aux descriptor/16-bit
|
|
NULL, // Aux descriptor/32-bit
|
|
NULL, // Aux descriptor/SMB
|
|
ALLOCATE_RESPONSE,
|
|
GroupName, // which group
|
|
0, // Level can only be 0 - push immediate
|
|
&localbuf, // buffer for receiving structures
|
|
65535,
|
|
&entries_read, // number of structures returned
|
|
&total_entries // total number of structures
|
|
);
|
|
|
|
if (rc == NERR_Success) {
|
|
*Buffer = localbuf;
|
|
*EntriesRead = entries_read;
|
|
*EntriesLeft = total_entries;
|
|
} else {
|
|
if (localbuf != NULL) {
|
|
(void) NetApiBufferFree(localbuf);
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
RxNetGroupSetInfo(
|
|
IN LPTSTR ServerName,
|
|
IN LPTSTR GroupName,
|
|
IN DWORD Level,
|
|
IN LPBYTE Buffer,
|
|
OUT LPDWORD ParmError OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set information about a group in a down-level UAS database
|
|
|
|
Assumes:
|
|
1. GroupName, Buffer and Level have been validated
|
|
2. There are only 2 possible levels - 1 & GROUP_COMMENT_INFOLEVEL (1002)
|
|
|
|
Arguments:
|
|
|
|
ServerName - at which server to perform this request
|
|
GroupName - name of group about which to set info
|
|
Level - level of info provided - 1 or 1002 (group comment)
|
|
Buffer - pointer to caller's buffer containing info to set
|
|
ParmError - pointer to returned parameter error
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS:
|
|
Success = NERR_Success
|
|
Failure = ERROR_INVALID_LEVEL
|
|
Level parameter must be 1 or 1002 (comment)
|
|
ERROR_INVALID_PARAMETER
|
|
Buffer parameter NULL pointer
|
|
or GroupName not valid string
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD parmnum;
|
|
DWORD buflen;
|
|
DWORD badparm;
|
|
DWORD len;
|
|
LPTSTR pointer;
|
|
DWORD field_index;
|
|
|
|
|
|
if (ParmError == NULL) {
|
|
ParmError = &badparm;
|
|
}
|
|
*ParmError = PARM_ERROR_NONE;
|
|
|
|
if (!VALID_STRING(GroupName) || !Buffer) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (STRLEN(GroupName) > LM20_GNLEN) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// check the requested level and convert to down-level parmnum. Info level
|
|
// is always 1 for down-level
|
|
//
|
|
|
|
if (Level == 1) { // entire GROUP_INFO_1 structure
|
|
buflen = sizeof(GROUP_INFO_1);
|
|
if (len = POSSIBLE_STRLEN(((PGROUP_INFO_1)Buffer)->grpi1_name)) {
|
|
if (len > LM20_GNLEN) {
|
|
*ParmError = GROUP_NAME_INFOLEVEL;
|
|
return ERROR_INVALID_PARAMETER;
|
|
} else {
|
|
buflen += len + 1;
|
|
}
|
|
}
|
|
pointer = (LPTSTR)((PGROUP_INFO_1)Buffer)->grpi1_comment;
|
|
parmnum = PARMNUM_ALL;
|
|
field_index = 0;
|
|
} else {
|
|
pointer = (LPTSTR)Buffer;
|
|
parmnum = GROUP_COMMENT_PARMNUM;
|
|
buflen = 0;
|
|
|
|
//
|
|
// The parmnum is SUPPOSED to be the ordinal number of the field, but
|
|
// some dope forgot that pad bytes are actually fields too, and messed
|
|
// up the nice convention. Hence this kludge. ParmNum 2 (comment field)
|
|
// for down-level, is actually group_info_1 structure field 3. Where
|
|
// *does* Microsoft find its employees?
|
|
// Note for the unenlightened: (aka disclaimer by me (basically: its not my fault))
|
|
// If we have a structure thus:
|
|
// struct group_info_1 {
|
|
// char grpi1_name[GNLEN + 1];
|
|
// char grpi1_pad;
|
|
// char far* grpi1_comment;
|
|
// };
|
|
// there will be a corresponding descriptor (ie a picture of what the
|
|
// structure looks like) thus:
|
|
// "B21Bz"
|
|
// Parmnums start at 1 (0 means entire structure). Thus, it is possible,
|
|
// knowing the format of descriptor strings, given a ParmNum, to come up
|
|
// with the corresponding field type (and its length). This info is used
|
|
// inside of RxRemoteApi (which if you look ahead, you'll see we're just
|
|
// about to call).
|
|
// In this particular case, there are 3 fields - B21 = embedded 21-byte
|
|
// group name, B = single byte pad character (put back on WORD boundary),
|
|
// z = pointer to ASCIZ string. There are indeed only 2 meaningful fields
|
|
// (name & comment), but that extra B pad field is significant.
|
|
// Therefore we have to provide a ParmNum of 2 which is put on the wire,
|
|
// so that the down-level code knows of what we speak, and a field index
|
|
// of 3 so that the Rap code underneath RxRemoteApi can divine that what
|
|
// we're sending is an ASCIZ string, not a single byte
|
|
// Messy, innit
|
|
//
|
|
|
|
field_index = 3;
|
|
}
|
|
|
|
if (len = POSSIBLE_STRLEN(pointer)) {
|
|
if (len > LM20_MAXCOMMENTSZ) {
|
|
*ParmError = GROUP_COMMENT_INFOLEVEL;
|
|
return ERROR_INVALID_PARAMETER;
|
|
} else {
|
|
buflen += len + 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if, by some unforeseen accident, the down-level routine returns an
|
|
// ERROR_INVALID_PARAMETER, the caller will just have to content him/her/it
|
|
// self (no lifeform prejudices here at MS) with an unknown parameter
|
|
// causing the calamity
|
|
//
|
|
|
|
*ParmError = PARM_ERROR_UNKNOWN;
|
|
return RxRemoteApi(API_WGroupSetInfo, // API #
|
|
ServerName, // where to remote it
|
|
REMSmb_NetGroupSetInfo_P, // parameter descriptor
|
|
REM16_group_info_1, // 16-bit data descriptor
|
|
REM32_group_info_1, // 32-bit data descriptor
|
|
REMSmb_group_info_1, // SMB data descriptor
|
|
NULL, // 16-bit aux data descriptor
|
|
NULL, // 32-bit aux data descriptor
|
|
NULL, // SMB aux data descriptor
|
|
FALSE, // this API requires user security
|
|
GroupName, // setinfo parm 1
|
|
1, // info level must be 1
|
|
Buffer, // caller's info to set
|
|
buflen, // length of caller's info
|
|
|
|
//
|
|
// glue ParmNum and field_index together
|
|
//
|
|
|
|
MAKE_PARMNUM_PAIR(parmnum, field_index)
|
|
);
|
|
}
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
RxNetGroupSetUsers(
|
|
IN LPTSTR ServerName,
|
|
IN LPTSTR GroupName,
|
|
IN DWORD Level,
|
|
IN LPBYTE Buffer,
|
|
IN DWORD Entries
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The purpose of this function is to force a group to have as its member list
|
|
only those users that are named in <Buffer>. If the user is not currently a
|
|
member of group <GroupName>, it is made so; if there are other users who are
|
|
currently members of group <GroupName>, but are not named in Buffer, then
|
|
they are removed from group <GroupName>.
|
|
|
|
This is a somewhat "funny" function - it expects a buffer containing
|
|
GROUP_USERS_INFO_0 structures, but has to force a in structure with an
|
|
aux count at the head of the buffer. Why couldn't it request that the
|
|
caller place one of these at the start of the buffer to save us the work?
|
|
|
|
Arguments:
|
|
|
|
ServerName - at which server to perform this request
|
|
GroupName - Name of group to set users for
|
|
Level - Must Be Zero
|
|
Buffer - pointer to buffer containing GROUP_USERS_INFO_0 structures
|
|
Entries - number of GROUP_USERS_INFO_0 structures in Buffer
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS:
|
|
Success = NERR_Success
|
|
Failure = ERROR_INVALID_LEVEL
|
|
Level parameter must be 0
|
|
ERROR_INVALID_PARAMETER
|
|
GroupName length exceeds LM20 maximum for type
|
|
user name in Buffer not valid string
|
|
user name in Buffer exceeds LM20 maximum for type
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS rc;
|
|
LPGROUP_USERS_INFO_0 users_info;
|
|
DWORD i;
|
|
DWORD buflen;
|
|
LPBYTE newbuf;
|
|
static LPDESC users_0_enumerator_desc16 = "B21BN";
|
|
static LPDESC users_0_enumerator_desc32 = "zQA";
|
|
|
|
//
|
|
// a little local structure never hurt anybody...
|
|
// This structure is required because the remoting code (particularly down
|
|
// level) can only handle there being >1 auxiliary structure, vs >1
|
|
// primary. Hence we have to convert the caller's supplied buffer of
|
|
// erstwhile primary structures to auxiliaries by forcing the structure
|
|
// below in at the head of the buffer, hence becoming the primary and
|
|
// providing an aux structure count (groan)
|
|
//
|
|
|
|
struct users_0_enumerator {
|
|
LPTSTR group_name;
|
|
DWORD user_count; // number of GROUP_USERS_INFO_0 structures in buffer
|
|
};
|
|
|
|
if (Level) {
|
|
return ERROR_INVALID_LEVEL; // MBZ, remember?
|
|
}
|
|
|
|
//
|
|
// only check we can make on the group name is to ensure it is within the
|
|
// down-level limits for length. GroupName should be already verified as
|
|
// a pointer to a valid string
|
|
//
|
|
|
|
if (STRLEN(GroupName) > LM20_GNLEN) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// iterate through the buffer, checking that each GROUP_USERS_INFO_0
|
|
// structure contains a pointer to a valid string which is in the
|
|
// correct range
|
|
//
|
|
|
|
users_info = (LPGROUP_USERS_INFO_0)Buffer;
|
|
for (i=0; i<Entries; ++i) {
|
|
if (!VALID_STRING(users_info->grui0_name)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
if (wcslen(users_info->grui0_name) > LM20_UNLEN) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
++users_info;
|
|
}
|
|
|
|
//
|
|
// allocate a buffer large enough to fit in <Entries> number of
|
|
// GROUP_USERS_INFO_0 structures, and 1 users_0_enumerator structure.
|
|
// Don't worry about string space - unfortunately the Rxp and Rap routines
|
|
// called by RxRemoteApi will allocate yet another buffer, do yet another
|
|
// copy and this time copy in the strings from user space. Hopefully, this
|
|
// routine won't get called too often
|
|
//
|
|
|
|
buflen = Entries * sizeof(GROUP_USERS_INFO_0) + sizeof(struct users_0_enumerator);
|
|
buflen = DWORD_ROUNDUP(buflen);
|
|
|
|
if (rc = NetApiBufferAllocate(buflen, (LPVOID *) &newbuf)) {
|
|
return rc; // aieegh! Failed to allocate memory?
|
|
}
|
|
|
|
((struct users_0_enumerator*)newbuf)->group_name = GroupName;
|
|
((struct users_0_enumerator*)newbuf)->user_count = Entries;
|
|
if (Entries) {
|
|
NetpMoveMemory(newbuf + sizeof(struct users_0_enumerator),
|
|
Buffer,
|
|
buflen - sizeof(struct users_0_enumerator)
|
|
);
|
|
}
|
|
|
|
rc = RxRemoteApi(API_WGroupSetUsers, // API #
|
|
ServerName, // where to remote it
|
|
REMSmb_NetGroupSetUsers_P, // parameter descriptor
|
|
users_0_enumerator_desc16, // the "fudged" 16-bit data descriptor
|
|
users_0_enumerator_desc32, // the "fudged" 32-bit data descriptor
|
|
users_0_enumerator_desc16, // SMB desc same as 16-bit
|
|
REM16_group_users_info_0, // "new" 16-bit aux descriptor
|
|
REM32_group_users_info_0, // "new" 32-bit aux descriptor
|
|
REMSmb_group_users_info_0, // SMB aux descriptor
|
|
FALSE, // this API requires user security
|
|
GroupName, // setinfo parm 1
|
|
0, // info level must be 0
|
|
newbuf, // "fudged" buffer
|
|
buflen, // length of "fudged" buffer
|
|
Entries // number of GROUP_USERS_INFO_0
|
|
);
|
|
NetpMemoryFree(newbuf);
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
DBGSTATIC
|
|
VOID
|
|
get_group_descriptors(
|
|
IN DWORD Level,
|
|
OUT LPDESC* pDesc16,
|
|
OUT LPDESC* pDesc32,
|
|
OUT LPDESC* pDescSmb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the descriptor strings for the various Group Info levels (0 or 1)
|
|
|
|
Arguments:
|
|
|
|
Level - of info required
|
|
pDesc16 - pointer to returned 16-bit data descriptor
|
|
pDesc32 - pointer to returned 32-bit data descriptor
|
|
pDescSmb - pointer to returned SMB data descriptor
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (Level) {
|
|
case 0:
|
|
*pDesc16 = REM16_group_info_0;
|
|
*pDesc32 = REM32_group_info_0;
|
|
*pDescSmb = REMSmb_group_info_0;
|
|
break;
|
|
|
|
case 1:
|
|
*pDesc16 = REM16_group_info_1;
|
|
*pDesc32 = REM32_group_info_1;
|
|
*pDescSmb = REMSmb_group_info_1;
|
|
break;
|
|
|
|
#if DBG
|
|
default:
|
|
NetpKdPrint(("%s.%u Unknown Level parameter: %u\n", __FILE__, __LINE__, Level));
|
|
NetpBreakPoint();
|
|
#endif
|
|
}
|
|
}
|