windows-nt/Source/XPSP1/NT/ds/netapi/rpcxlate/rxapi/rxgroup.c
2020-09-26 16:20:57 +08:00

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
}
}