Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

947 lines
31 KiB

  1. /*++
  2. Copyright (c) 1991-92 Microsoft Corporation
  3. Module Name:
  4. rxgroup.c
  5. Abstract:
  6. Contains RxNetGroup routines:
  7. RxNetGroupAdd
  8. RxNetGroupAddUser
  9. RxNetGroupDel
  10. RxNetGroupDelUser
  11. RxNetGroupEnum
  12. RxNetGroupGetInfo
  13. RxNetGroupGetUsers
  14. RxNetGroupSetInfo
  15. RxNetGroupSetUsers
  16. Author:
  17. Richard L Firth (rfirth) 20-May-1991
  18. Environment:
  19. Win-32/flat address space
  20. Notes:
  21. Routines in this module assume that caller-supplied parameters have
  22. already been verified. No effort is made to further check the veracity
  23. of parms. Any actions causing exceptions must be trapped at a higher
  24. level. This applies to ALL parameters - strings, pointers, buffers, etc.
  25. Revision History:
  26. 20-May-1991 rfirth
  27. Created
  28. 13-Sep-1991 JohnRo
  29. Made changes suggested by PC-LINT.
  30. 25-Sep-1991 JohnRo
  31. Correct UNICODE use. (Use POSSIBLE_WCSSIZE() and wcslen() for
  32. LPWSTR types.) Fixed MIPS build problems.
  33. 21-Nov-1991 JohnRo
  34. Removed NT dependencies to reduce recompiles.
  35. 05-Dec-1991 RFirth
  36. Enum returns in TotalEntries (or EntriesLeft) the number of items to
  37. be enumerated BEFORE this call. Used to be number left after this call
  38. 01-Apr-1992 JohnRo
  39. Use NetApiBufferAllocate() instead of private version.
  40. --*/
  41. #include "downlevl.h"
  42. #include <rxgroup.h>
  43. #include <lmaccess.h>
  44. DBGSTATIC
  45. VOID
  46. get_group_descriptors(
  47. DWORD Level,
  48. LPDESC* pDesc16,
  49. LPDESC* pDesc32,
  50. LPDESC* pDescSmb
  51. );
  52. NET_API_STATUS
  53. RxNetGroupAdd(
  54. IN LPTSTR ServerName,
  55. IN DWORD Level,
  56. IN LPBYTE Buffer,
  57. OUT LPDWORD ParmError OPTIONAL
  58. )
  59. /*++
  60. Routine Description:
  61. Creates a group in the User Account Database at a down-level server
  62. Arguments:
  63. ServerName - at which server to perform this request
  64. Level - of information to add. Can be 0 or 1
  65. Buffer - containing caller's GROUP_INFO_{0|1} structure
  66. ParmError - pointer to returned parameter error identifier. NOT USED
  67. Return Value:
  68. NET_API_STATUS:
  69. Success = NERR_Success
  70. Failure = ERROR_INVALID_LEVEL
  71. Level must be 0 or 1
  72. ERROR_INVALID_PARAMETER
  73. Buffer is NULL pointer
  74. --*/
  75. {
  76. DWORD buflen; // size of caller's buffer (we calculate it)
  77. LPDESC pDesc16; // pointer to 16-bit info descriptor for RxRemoteApi
  78. LPDESC pDesc32; // pointer to 32-bit info descriptor for RxRemoteApi
  79. LPDESC pDescSmb; // pointer to SMB info descriptor for RxRemoteApi
  80. UNREFERENCED_PARAMETER(ParmError);
  81. //
  82. // try to trap any basic problems
  83. //
  84. if (Level > 1) {
  85. return ERROR_INVALID_LEVEL;
  86. }
  87. if (!Buffer) {
  88. return ERROR_INVALID_PARAMETER;
  89. }
  90. //
  91. // Calculate the size of the buffer we are passing into the remoted API.
  92. // The down-level logic expects a buffer size; Nt does not. If the sizes
  93. // of the variable fields exceed the down-level maximums then we will get
  94. // some kind of invalid parameter error. Let the caller handle it
  95. //
  96. buflen = ((Level == 1) ? sizeof(GROUP_INFO_1) : sizeof(GROUP_INFO_0))
  97. + POSSIBLE_STRLEN(((PGROUP_INFO_0)Buffer)->grpi0_name);
  98. buflen += (Level == 1) ? POSSIBLE_STRLEN(((PGROUP_INFO_1)Buffer)->grpi1_comment) : 0;
  99. //
  100. // Get the data descriptor strings based on the info level then make the
  101. // down-level call. We expect no return data, so just return the result
  102. // to the caller
  103. //
  104. get_group_descriptors(Level, &pDesc16, &pDesc32, &pDescSmb);
  105. return RxRemoteApi(API_WGroupAdd, // API #
  106. ServerName, // on which server
  107. REMSmb_NetGroupAdd_P, // parameter descriptor
  108. pDesc16, // Data descriptor/16-bit
  109. pDesc32, // Data descriptor/32-bit
  110. pDescSmb, // Data descriptor/SMB
  111. NULL, // Aux descriptor/16-bit
  112. NULL, // Aux descriptor/32-bit
  113. NULL, // Aux descriptor/SMB
  114. FALSE, // this call needs user to be logged on
  115. Level, // caller supplied parameters...
  116. Buffer, // caller's GROUP_INFO_{0|1} struct
  117. buflen // as supplied by us
  118. );
  119. }
  120. NET_API_STATUS
  121. RxNetGroupAddUser(
  122. IN LPTSTR ServerName,
  123. IN LPTSTR GroupName,
  124. IN LPTSTR UserName
  125. )
  126. /*++
  127. Routine Description:
  128. Adds a user to a UAS group on a down-level server
  129. Arguments:
  130. ServerName - at which server to perform this request
  131. GroupName - name of group to add user to
  132. UserName - name of user to add
  133. Return Value:
  134. NET_API_STATUS:
  135. Success = NERR_Success
  136. Failure = ERROR_INVALID_PARAMETER
  137. GroupName or UserName not valid strings
  138. --*/
  139. {
  140. if (!VALID_STRING(GroupName) && !VALID_STRING(UserName)) {
  141. return ERROR_INVALID_PARAMETER;
  142. }
  143. return RxRemoteApi(API_WGroupAddUser, // API #
  144. ServerName, // where to remote it
  145. REMSmb_NetGroupAddUser_P, // parameter descriptor
  146. NULL, // Data descriptor/16-bit
  147. NULL, // Data descriptor/32-bit
  148. NULL, // Data descriptor/SMB
  149. NULL, // Aux descriptor/16-bit
  150. NULL, // Aux descriptor/32-bit
  151. NULL, // Aux descriptor/SMB
  152. FALSE, // this call needs user to be logged on
  153. GroupName, // parm 1
  154. UserName // parm 2
  155. );
  156. }
  157. NET_API_STATUS
  158. RxNetGroupDel(
  159. IN LPTSTR ServerName,
  160. IN LPTSTR GroupName
  161. )
  162. /*++
  163. Routine Description:
  164. Deletes a group from a down-level server UAS database
  165. Arguments:
  166. ServerName - at which server to perform this request
  167. GroupName - name of group to delete
  168. Return Value:
  169. NET_API_STATUS:
  170. Success = NERR_Success
  171. Failure = ERROR_INVALID_PARAMETER
  172. GroupName not valid string
  173. --*/
  174. {
  175. if (!VALID_STRING(GroupName)) {
  176. return ERROR_INVALID_PARAMETER;
  177. }
  178. return RxRemoteApi(API_WGroupDel, // API #
  179. ServerName, // where to remote it
  180. REMSmb_NetGroupDel_P, // parameter descriptor
  181. NULL, // Data descriptor/16-bit
  182. NULL, // Data descriptor/32-bit
  183. NULL, // Data descriptor/SMB
  184. NULL, // Aux descriptor/16-bit
  185. NULL, // Aux descriptor/32-bit
  186. NULL, // Aux descriptor/SMB
  187. FALSE, // this call needs user to be logged on
  188. GroupName // parm 1
  189. );
  190. }
  191. NET_API_STATUS
  192. RxNetGroupDelUser(
  193. IN LPTSTR ServerName,
  194. IN LPTSTR GroupName,
  195. IN LPTSTR UserName
  196. )
  197. /*++
  198. Routine Description:
  199. Deletes a user from a group in a down-level UAS database
  200. Arguments:
  201. ServerName - at which server to perform this request
  202. GroupName - name of group to delete user from
  203. UserName - name of user to delete
  204. Return Value:
  205. NET_API_STATUS:
  206. Success = NERR_Success
  207. Failure = ERROR_INVALID_PARAMETER
  208. GroupName or UserName not valid strings
  209. --*/
  210. {
  211. if (!VALID_STRING(GroupName) && !VALID_STRING(UserName)) {
  212. return ERROR_INVALID_PARAMETER;
  213. }
  214. return RxRemoteApi(API_WGroupDelUser, // API #
  215. ServerName, // where to remote it
  216. REMSmb_NetGroupDelUser_P, // parameter descriptor
  217. NULL, // Data descriptor/16-bit
  218. NULL, // Data descriptor/32-bit
  219. NULL, // Data descriptor/SMB
  220. NULL, // Aux descriptor/16-bit
  221. NULL, // Aux descriptor/32-bit
  222. NULL, // Aux descriptor/SMB
  223. FALSE, // this call needs user to be logged on
  224. GroupName, // parm 1
  225. UserName // parm 2
  226. );
  227. }
  228. NET_API_STATUS
  229. RxNetGroupEnum(
  230. IN LPTSTR ServerName,
  231. IN DWORD Level,
  232. OUT LPBYTE* Buffer,
  233. IN DWORD PrefMaxLen,
  234. OUT LPDWORD EntriesRead,
  235. OUT LPDWORD EntriesLeft,
  236. IN OUT PDWORD_PTR ResumeHandle OPTIONAL
  237. )
  238. /*++
  239. Routine Description:
  240. Gets a list of GROUP_INFO_{0|1} structures from a down-level server
  241. Arguments:
  242. ServerName - at which server to perform this request
  243. Level - of information to retrieve (0 or 1)
  244. Buffer - pointer to pointer to returned buffer
  245. PrefMaxLen - caller's maximum
  246. EntriedRead - pointer to returned number of structures read
  247. EntriesLeft - pointer to returned nunber of structures left to enumerate
  248. ResumeHandle- handle used to restart enums. Not used by this routine
  249. Return Value:
  250. NET_API_STATUS:
  251. Success = NERR_Success
  252. Failure = ERROR_INVALID_LEVEL
  253. Level parameter must be 0 or 1
  254. ERROR_INVALID_PARAMETER
  255. Buffer parameter NULL pointer or non-NULL ResumeHandle
  256. --*/
  257. {
  258. NET_API_STATUS rc;
  259. LPDESC pDesc16; // pointer to 16-bit info descriptor for RxRemoteApi
  260. LPDESC pDesc32; // pointer to 32-bit info descriptor for RxRemoteApi
  261. LPDESC pDescSmb; // pointer to SMB info descriptor for RxRemoteApi
  262. LPBYTE localbuf; // pointer to buffer allocated in this routine
  263. DWORD total_avail; // returned total available entries
  264. DWORD entries_read; // returned entries in buffer
  265. UNREFERENCED_PARAMETER(PrefMaxLen);
  266. *EntriesRead = *EntriesLeft = 0;
  267. *Buffer = NULL;
  268. if (Level > 1) {
  269. return ERROR_INVALID_LEVEL;
  270. }
  271. //
  272. // Buffer must be a valid pointer. If ResumeHandle is not a NULL pointer
  273. // and points to a non-zero handle value then return an INVALID_PARAMETER
  274. // error - down-level does not supoort resume
  275. //
  276. if (!NULL_REFERENCE(ResumeHandle)) {
  277. return ERROR_INVALID_PARAMETER;
  278. }
  279. get_group_descriptors(Level, &pDesc16, &pDesc32, &pDescSmb);
  280. localbuf = NULL;
  281. rc = RxRemoteApi(API_WGroupEnum, // API #
  282. ServerName, // where to remote it
  283. REMSmb_NetGroupEnum_P, // parameter descriptor
  284. pDesc16, // Data descriptor/16-bit
  285. pDesc32, // Data descriptor/32-bit
  286. pDescSmb, // Data descriptor/SMB
  287. NULL, // Aux descriptor/16-bit
  288. NULL, // Aux descriptor/32-bit
  289. NULL, // Aux descriptor/SMB
  290. ALLOCATE_RESPONSE,
  291. Level, // caller supplied parameters...
  292. &localbuf,
  293. 65535,
  294. &entries_read, // parm 4
  295. &total_avail // parm 5
  296. );
  297. if (rc != NERR_Success) {
  298. if (localbuf != NULL) {
  299. (void) NetApiBufferFree(localbuf);
  300. }
  301. } else {
  302. *Buffer = localbuf;
  303. *EntriesRead = entries_read;
  304. *EntriesLeft = total_avail;
  305. }
  306. return rc;
  307. }
  308. NET_API_STATUS
  309. RxNetGroupGetInfo(
  310. IN LPTSTR ServerName,
  311. IN LPTSTR GroupName,
  312. IN DWORD Level,
  313. OUT LPBYTE* Buffer
  314. )
  315. /*++
  316. Routine Description:
  317. Get information about a specific group in a down-level UAS database
  318. Arguments:
  319. ServerName - at which server to perform this request
  320. GroupName - name of group to get information for
  321. Level - level of information to return (0 or 1)
  322. Buffer - pointer to returned pointer to info buffer
  323. Return Value:
  324. NET_API_STATUS:
  325. Success = NERR_Success
  326. Failure = ERROR_INVALID_LEVEL
  327. Level parameter must be 0 or 1
  328. ERROR_INVALID_PARAMETER
  329. Buffer parameter NULL pointer
  330. --*/
  331. {
  332. NET_API_STATUS rc;
  333. LPDESC pDesc16; // pointer to 16-bit info descriptor for RxRemoteApi
  334. LPDESC pDesc32; // pointer to 32-bit info descriptor for RxRemoteApi
  335. LPDESC pDescSmb; // pointer to SMB info descriptor for RxRemoteApi
  336. LPBYTE localbuf; // pointer to buffer allocated in this routine
  337. DWORD totalbytes; // total available bytes returned from down-level
  338. DWORD buflen; // size of info buffer, supplied by us
  339. if (Level > 1) {
  340. return ERROR_INVALID_LEVEL;
  341. }
  342. if (!Buffer) {
  343. return ERROR_INVALID_PARAMETER;
  344. }
  345. //
  346. // calculate the size requirement for the info buffer and allocate it
  347. //
  348. buflen = ((Level == 1) ? sizeof(GROUP_INFO_1) : sizeof(GROUP_INFO_0))
  349. + 2 * (LM20_GNLEN + 1);
  350. buflen += (Level == 1) ? 2 * (LM20_MAXCOMMENTSZ + 1) : 0;
  351. buflen = DWORD_ROUNDUP(buflen);
  352. if (rc = NetApiBufferAllocate(buflen, (LPVOID *) &localbuf)) {
  353. return rc;
  354. }
  355. get_group_descriptors(Level, &pDesc16, &pDesc32, &pDescSmb);
  356. rc = RxRemoteApi(API_WGroupGetInfo, // API #
  357. ServerName, // where to remote it
  358. REMSmb_NetGroupGetInfo_P, // parameter descriptor
  359. pDesc16, // Data descriptor/16-bit
  360. pDesc32, // Data descriptor/32-bit
  361. pDescSmb, // Data descriptor/SMB
  362. NULL, // Aux descriptor/16-bit
  363. NULL, // Aux descriptor/32-bit
  364. NULL, // Aux descriptor/SMB
  365. FALSE, // this call needs user to be logged on
  366. GroupName, // parms to down-level start here
  367. Level, // caller supplied parameters...
  368. localbuf, // buffer for receiving structures
  369. buflen, // size of buffer supplied by us
  370. &totalbytes // returned from down-level. not used
  371. );
  372. if (rc == NERR_Success) {
  373. *Buffer = localbuf;
  374. } else {
  375. (void) NetApiBufferFree(localbuf);
  376. }
  377. return rc;
  378. }
  379. NET_API_STATUS
  380. RxNetGroupGetUsers(
  381. IN LPTSTR ServerName,
  382. IN LPTSTR GroupName,
  383. IN DWORD Level,
  384. OUT LPBYTE* Buffer,
  385. IN DWORD PrefMaxLen,
  386. OUT LPDWORD EntriesRead,
  387. OUT LPDWORD EntriesLeft,
  388. IN OUT PDWORD_PTR ResumeHandle OPTIONAL
  389. )
  390. /*++
  391. Routine Description:
  392. Get a list of all the members of a particular group
  393. Arguments:
  394. ServerName - at which server to perform this request
  395. GroupName - name of group for which to retrieve member list
  396. Level - level of group user information requested. Must be 0
  397. Buffer - pointer to returned pointer to buffer containing info
  398. PrefMaxLen - preferred maximum length of returned buffer
  399. EntriesRead - pointer to returned number of entries in buffer
  400. EntriesLeft - pointer to returned number of entries left
  401. ResumeHandle- pointer to handle for resume. Not used by this function
  402. Return Value:
  403. NET_API_STATUS:
  404. Success = NERR_Success
  405. Failure = ERROR_INVALID_LEVEL
  406. Level parameter must be 0
  407. ERROR_INVALID_PARAMETER
  408. Buffer parameter NULL pointer
  409. or ResumeHandle not NULL pointer or pointer to non-0 value
  410. or GroupName not valid string
  411. --*/
  412. {
  413. NET_API_STATUS rc;
  414. LPBYTE localbuf; // pointer to buffer allocated in this routine
  415. DWORD entries_read, total_entries;
  416. UNREFERENCED_PARAMETER(PrefMaxLen);
  417. //
  418. // set EntriesLeft and EntriesRead to default values. Test writability of
  419. // parameters
  420. //
  421. *EntriesRead = *EntriesLeft = 0;
  422. *Buffer = NULL;
  423. if (Level) {
  424. return ERROR_INVALID_LEVEL;
  425. }
  426. if (!NULL_REFERENCE(ResumeHandle) || !VALID_STRING(GroupName)) {
  427. return ERROR_INVALID_PARAMETER;
  428. }
  429. localbuf = NULL;
  430. rc = RxRemoteApi(API_WGroupGetUsers, // API #
  431. ServerName, // where to remote it
  432. REMSmb_NetGroupGetUsers_P, // parameter descriptor
  433. REM16_group_users_info_0, // Data descriptor/16-bit
  434. REM32_group_users_info_0, // Data descriptor/32-bit
  435. REMSmb_group_users_info_0, // Data descriptor/SMB
  436. NULL, // Aux descriptor/16-bit
  437. NULL, // Aux descriptor/32-bit
  438. NULL, // Aux descriptor/SMB
  439. ALLOCATE_RESPONSE,
  440. GroupName, // which group
  441. 0, // Level can only be 0 - push immediate
  442. &localbuf, // buffer for receiving structures
  443. 65535,
  444. &entries_read, // number of structures returned
  445. &total_entries // total number of structures
  446. );
  447. if (rc == NERR_Success) {
  448. *Buffer = localbuf;
  449. *EntriesRead = entries_read;
  450. *EntriesLeft = total_entries;
  451. } else {
  452. if (localbuf != NULL) {
  453. (void) NetApiBufferFree(localbuf);
  454. }
  455. }
  456. return rc;
  457. }
  458. NET_API_STATUS
  459. RxNetGroupSetInfo(
  460. IN LPTSTR ServerName,
  461. IN LPTSTR GroupName,
  462. IN DWORD Level,
  463. IN LPBYTE Buffer,
  464. OUT LPDWORD ParmError OPTIONAL
  465. )
  466. /*++
  467. Routine Description:
  468. Set information about a group in a down-level UAS database
  469. Assumes:
  470. 1. GroupName, Buffer and Level have been validated
  471. 2. There are only 2 possible levels - 1 & GROUP_COMMENT_INFOLEVEL (1002)
  472. Arguments:
  473. ServerName - at which server to perform this request
  474. GroupName - name of group about which to set info
  475. Level - level of info provided - 1 or 1002 (group comment)
  476. Buffer - pointer to caller's buffer containing info to set
  477. ParmError - pointer to returned parameter error
  478. Return Value:
  479. NET_API_STATUS:
  480. Success = NERR_Success
  481. Failure = ERROR_INVALID_LEVEL
  482. Level parameter must be 1 or 1002 (comment)
  483. ERROR_INVALID_PARAMETER
  484. Buffer parameter NULL pointer
  485. or GroupName not valid string
  486. --*/
  487. {
  488. DWORD parmnum;
  489. DWORD buflen;
  490. DWORD badparm;
  491. DWORD len;
  492. LPTSTR pointer;
  493. DWORD field_index;
  494. if (ParmError == NULL) {
  495. ParmError = &badparm;
  496. }
  497. *ParmError = PARM_ERROR_NONE;
  498. if (!VALID_STRING(GroupName) || !Buffer) {
  499. return ERROR_INVALID_PARAMETER;
  500. }
  501. if (STRLEN(GroupName) > LM20_GNLEN) {
  502. return ERROR_INVALID_PARAMETER;
  503. }
  504. //
  505. // check the requested level and convert to down-level parmnum. Info level
  506. // is always 1 for down-level
  507. //
  508. if (Level == 1) { // entire GROUP_INFO_1 structure
  509. buflen = sizeof(GROUP_INFO_1);
  510. if (len = POSSIBLE_STRLEN(((PGROUP_INFO_1)Buffer)->grpi1_name)) {
  511. if (len > LM20_GNLEN) {
  512. *ParmError = GROUP_NAME_INFOLEVEL;
  513. return ERROR_INVALID_PARAMETER;
  514. } else {
  515. buflen += len + 1;
  516. }
  517. }
  518. pointer = (LPTSTR)((PGROUP_INFO_1)Buffer)->grpi1_comment;
  519. parmnum = PARMNUM_ALL;
  520. field_index = 0;
  521. } else {
  522. pointer = (LPTSTR)Buffer;
  523. parmnum = GROUP_COMMENT_PARMNUM;
  524. buflen = 0;
  525. //
  526. // The parmnum is SUPPOSED to be the ordinal number of the field, but
  527. // some dope forgot that pad bytes are actually fields too, and messed
  528. // up the nice convention. Hence this kludge. ParmNum 2 (comment field)
  529. // for down-level, is actually group_info_1 structure field 3. Where
  530. // *does* Microsoft find its employees?
  531. // Note for the unenlightened: (aka disclaimer by me (basically: its not my fault))
  532. // If we have a structure thus:
  533. // struct group_info_1 {
  534. // char grpi1_name[GNLEN + 1];
  535. // char grpi1_pad;
  536. // char far* grpi1_comment;
  537. // };
  538. // there will be a corresponding descriptor (ie a picture of what the
  539. // structure looks like) thus:
  540. // "B21Bz"
  541. // Parmnums start at 1 (0 means entire structure). Thus, it is possible,
  542. // knowing the format of descriptor strings, given a ParmNum, to come up
  543. // with the corresponding field type (and its length). This info is used
  544. // inside of RxRemoteApi (which if you look ahead, you'll see we're just
  545. // about to call).
  546. // In this particular case, there are 3 fields - B21 = embedded 21-byte
  547. // group name, B = single byte pad character (put back on WORD boundary),
  548. // z = pointer to ASCIZ string. There are indeed only 2 meaningful fields
  549. // (name & comment), but that extra B pad field is significant.
  550. // Therefore we have to provide a ParmNum of 2 which is put on the wire,
  551. // so that the down-level code knows of what we speak, and a field index
  552. // of 3 so that the Rap code underneath RxRemoteApi can divine that what
  553. // we're sending is an ASCIZ string, not a single byte
  554. // Messy, innit
  555. //
  556. field_index = 3;
  557. }
  558. if (len = POSSIBLE_STRLEN(pointer)) {
  559. if (len > LM20_MAXCOMMENTSZ) {
  560. *ParmError = GROUP_COMMENT_INFOLEVEL;
  561. return ERROR_INVALID_PARAMETER;
  562. } else {
  563. buflen += len + 1;
  564. }
  565. }
  566. //
  567. // if, by some unforeseen accident, the down-level routine returns an
  568. // ERROR_INVALID_PARAMETER, the caller will just have to content him/her/it
  569. // self (no lifeform prejudices here at MS) with an unknown parameter
  570. // causing the calamity
  571. //
  572. *ParmError = PARM_ERROR_UNKNOWN;
  573. return RxRemoteApi(API_WGroupSetInfo, // API #
  574. ServerName, // where to remote it
  575. REMSmb_NetGroupSetInfo_P, // parameter descriptor
  576. REM16_group_info_1, // 16-bit data descriptor
  577. REM32_group_info_1, // 32-bit data descriptor
  578. REMSmb_group_info_1, // SMB data descriptor
  579. NULL, // 16-bit aux data descriptor
  580. NULL, // 32-bit aux data descriptor
  581. NULL, // SMB aux data descriptor
  582. FALSE, // this API requires user security
  583. GroupName, // setinfo parm 1
  584. 1, // info level must be 1
  585. Buffer, // caller's info to set
  586. buflen, // length of caller's info
  587. //
  588. // glue ParmNum and field_index together
  589. //
  590. MAKE_PARMNUM_PAIR(parmnum, field_index)
  591. );
  592. }
  593. NET_API_STATUS
  594. RxNetGroupSetUsers(
  595. IN LPTSTR ServerName,
  596. IN LPTSTR GroupName,
  597. IN DWORD Level,
  598. IN LPBYTE Buffer,
  599. IN DWORD Entries
  600. )
  601. /*++
  602. Routine Description:
  603. The purpose of this function is to force a group to have as its member list
  604. only those users that are named in <Buffer>. If the user is not currently a
  605. member of group <GroupName>, it is made so; if there are other users who are
  606. currently members of group <GroupName>, but are not named in Buffer, then
  607. they are removed from group <GroupName>.
  608. This is a somewhat "funny" function - it expects a buffer containing
  609. GROUP_USERS_INFO_0 structures, but has to force a in structure with an
  610. aux count at the head of the buffer. Why couldn't it request that the
  611. caller place one of these at the start of the buffer to save us the work?
  612. Arguments:
  613. ServerName - at which server to perform this request
  614. GroupName - Name of group to set users for
  615. Level - Must Be Zero
  616. Buffer - pointer to buffer containing GROUP_USERS_INFO_0 structures
  617. Entries - number of GROUP_USERS_INFO_0 structures in Buffer
  618. Return Value:
  619. NET_API_STATUS:
  620. Success = NERR_Success
  621. Failure = ERROR_INVALID_LEVEL
  622. Level parameter must be 0
  623. ERROR_INVALID_PARAMETER
  624. GroupName length exceeds LM20 maximum for type
  625. user name in Buffer not valid string
  626. user name in Buffer exceeds LM20 maximum for type
  627. --*/
  628. {
  629. NET_API_STATUS rc;
  630. LPGROUP_USERS_INFO_0 users_info;
  631. DWORD i;
  632. DWORD buflen;
  633. LPBYTE newbuf;
  634. static LPDESC users_0_enumerator_desc16 = "B21BN";
  635. static LPDESC users_0_enumerator_desc32 = "zQA";
  636. //
  637. // a little local structure never hurt anybody...
  638. // This structure is required because the remoting code (particularly down
  639. // level) can only handle there being >1 auxiliary structure, vs >1
  640. // primary. Hence we have to convert the caller's supplied buffer of
  641. // erstwhile primary structures to auxiliaries by forcing the structure
  642. // below in at the head of the buffer, hence becoming the primary and
  643. // providing an aux structure count (groan)
  644. //
  645. struct users_0_enumerator {
  646. LPTSTR group_name;
  647. DWORD user_count; // number of GROUP_USERS_INFO_0 structures in buffer
  648. };
  649. if (Level) {
  650. return ERROR_INVALID_LEVEL; // MBZ, remember?
  651. }
  652. //
  653. // only check we can make on the group name is to ensure it is within the
  654. // down-level limits for length. GroupName should be already verified as
  655. // a pointer to a valid string
  656. //
  657. if (STRLEN(GroupName) > LM20_GNLEN) {
  658. return ERROR_INVALID_PARAMETER;
  659. }
  660. //
  661. // iterate through the buffer, checking that each GROUP_USERS_INFO_0
  662. // structure contains a pointer to a valid string which is in the
  663. // correct range
  664. //
  665. users_info = (LPGROUP_USERS_INFO_0)Buffer;
  666. for (i=0; i<Entries; ++i) {
  667. if (!VALID_STRING(users_info->grui0_name)) {
  668. return ERROR_INVALID_PARAMETER;
  669. }
  670. if (wcslen(users_info->grui0_name) > LM20_UNLEN) {
  671. return ERROR_INVALID_PARAMETER;
  672. }
  673. ++users_info;
  674. }
  675. //
  676. // allocate a buffer large enough to fit in <Entries> number of
  677. // GROUP_USERS_INFO_0 structures, and 1 users_0_enumerator structure.
  678. // Don't worry about string space - unfortunately the Rxp and Rap routines
  679. // called by RxRemoteApi will allocate yet another buffer, do yet another
  680. // copy and this time copy in the strings from user space. Hopefully, this
  681. // routine won't get called too often
  682. //
  683. buflen = Entries * sizeof(GROUP_USERS_INFO_0) + sizeof(struct users_0_enumerator);
  684. buflen = DWORD_ROUNDUP(buflen);
  685. if (rc = NetApiBufferAllocate(buflen, (LPVOID *) &newbuf)) {
  686. return rc; // aieegh! Failed to allocate memory?
  687. }
  688. ((struct users_0_enumerator*)newbuf)->group_name = GroupName;
  689. ((struct users_0_enumerator*)newbuf)->user_count = Entries;
  690. if (Entries) {
  691. NetpMoveMemory(newbuf + sizeof(struct users_0_enumerator),
  692. Buffer,
  693. buflen - sizeof(struct users_0_enumerator)
  694. );
  695. }
  696. rc = RxRemoteApi(API_WGroupSetUsers, // API #
  697. ServerName, // where to remote it
  698. REMSmb_NetGroupSetUsers_P, // parameter descriptor
  699. users_0_enumerator_desc16, // the "fudged" 16-bit data descriptor
  700. users_0_enumerator_desc32, // the "fudged" 32-bit data descriptor
  701. users_0_enumerator_desc16, // SMB desc same as 16-bit
  702. REM16_group_users_info_0, // "new" 16-bit aux descriptor
  703. REM32_group_users_info_0, // "new" 32-bit aux descriptor
  704. REMSmb_group_users_info_0, // SMB aux descriptor
  705. FALSE, // this API requires user security
  706. GroupName, // setinfo parm 1
  707. 0, // info level must be 0
  708. newbuf, // "fudged" buffer
  709. buflen, // length of "fudged" buffer
  710. Entries // number of GROUP_USERS_INFO_0
  711. );
  712. NetpMemoryFree(newbuf);
  713. return rc;
  714. }
  715. DBGSTATIC
  716. VOID
  717. get_group_descriptors(
  718. IN DWORD Level,
  719. OUT LPDESC* pDesc16,
  720. OUT LPDESC* pDesc32,
  721. OUT LPDESC* pDescSmb
  722. )
  723. /*++
  724. Routine Description:
  725. Returns the descriptor strings for the various Group Info levels (0 or 1)
  726. Arguments:
  727. Level - of info required
  728. pDesc16 - pointer to returned 16-bit data descriptor
  729. pDesc32 - pointer to returned 32-bit data descriptor
  730. pDescSmb - pointer to returned SMB data descriptor
  731. Return Value:
  732. None.
  733. --*/
  734. {
  735. switch (Level) {
  736. case 0:
  737. *pDesc16 = REM16_group_info_0;
  738. *pDesc32 = REM32_group_info_0;
  739. *pDescSmb = REMSmb_group_info_0;
  740. break;
  741. case 1:
  742. *pDesc16 = REM16_group_info_1;
  743. *pDesc32 = REM32_group_info_1;
  744. *pDescSmb = REMSmb_group_info_1;
  745. break;
  746. #if DBG
  747. default:
  748. NetpKdPrint(("%s.%u Unknown Level parameter: %u\n", __FILE__, __LINE__, Level));
  749. NetpBreakPoint();
  750. #endif
  751. }
  752. }