Source code of Windows XP (NT5)
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.

2692 lines
59 KiB

  1. /*++
  2. Copyright (c) 1993-1995 Microsoft Corporation
  3. Module Name:
  4. nwnetapi.c
  5. Abstract:
  6. Author:
  7. Arthur Hanson (arth) 16-Jun-1994
  8. Revision History:
  9. --*/
  10. #include "globals.h"
  11. #include <nwapi32.h>
  12. #include "nwconv.h"
  13. #include "convapi.h"
  14. #include "nwnetapi.h"
  15. #include "statbox.h"
  16. #define SUPERVISOR "SUPERVISOR"
  17. #define ACCOUNT_LOCKOUT "ACCT_LOCKOUT"
  18. #define GROUP_MEMBERS "GROUP_MEMBERS"
  19. #define GROUPS_IM_IN "GROUPS_I'M_IN"
  20. #define IDENTIFICATION "IDENTIFICATION"
  21. #define LOGIN_CONTROL "LOGIN_CONTROL"
  22. #define PS_OPERATORS "PS_OPERATORS"
  23. #define SECURITY_EQUALS "SECURITY_EQUALS"
  24. #define USER_DEFAULTS "USER_DEFAULTS"
  25. #define MS_EXTENDED_NCPS "MS_EXTENDED_NCPS"
  26. #define FPNW_PDC "FPNWPDC"
  27. #ifdef DEBUG
  28. int ErrorBoxRetry(LPTSTR szFormat, ...);
  29. #endif
  30. // Couple of NetWare specific data structures - see NetWare programming books for
  31. // info on these structures
  32. #pragma pack(1)
  33. typedef struct tagLoginControl {
  34. BYTE byAccountExpires[3];
  35. BYTE byAccountDisabled;
  36. BYTE byPasswordExpires[3];
  37. BYTE byGraceLogins;
  38. WORD wPasswordInterval;
  39. BYTE byGraceLoginReset;
  40. BYTE byMinPasswordLength;
  41. WORD wMaxConnections;
  42. BYTE byLoginTimes[42];
  43. BYTE byLastLogin[6];
  44. BYTE byRestrictions;
  45. BYTE byUnused;
  46. long lMaxDiskBlocks;
  47. WORD wBadLogins;
  48. LONG lNextResetTime;
  49. BYTE byBadLoginAddr[12];
  50. }; // tagLoginControl
  51. #pragma pack()
  52. typedef struct tagAccountBalance {
  53. long lBalance;
  54. long lCreditLimit;
  55. }; // tagAccountBalance
  56. typedef struct tagUserDefaults {
  57. BYTE byAccountExpiresYear;
  58. BYTE byAccountExpiresMonth;
  59. BYTE byAccountExpiresDay;
  60. BYTE byRestrictions;
  61. WORD wPasswordInterval;
  62. BYTE byGraceLoginReset;
  63. BYTE byMinPasswordLength;
  64. WORD wMaxConnections;
  65. BYTE byLoginTimes[42];
  66. long lBalance;
  67. long lCreditLimit;
  68. long lMaxDiskBlocks;
  69. }; // tagUserDefaults
  70. // define the mapping for FILE objects. Note: we only use GENERIC and
  71. // STANDARD bits!
  72. RIGHTS_MAPPING FileRightsMapping = {
  73. 0,
  74. { FILE_GENERIC_READ,
  75. FILE_GENERIC_WRITE,
  76. FILE_GENERIC_EXECUTE,
  77. FILE_ALL_ACCESS
  78. },
  79. { { NW_FILE_READ, GENERIC_READ},
  80. { NW_FILE_WRITE, GENERIC_WRITE},
  81. { NW_FILE_CREATE, 0},
  82. { NW_FILE_DELETE, GENERIC_WRITE|DELETE},
  83. { NW_FILE_PERM, WRITE_DAC},
  84. { NW_FILE_SCAN, 0},
  85. { NW_FILE_MODIFY, GENERIC_WRITE},
  86. { NW_FILE_SUPERVISOR, GENERIC_ALL},
  87. { 0, 0 }
  88. }
  89. } ;
  90. RIGHTS_MAPPING DirRightsMapping = {
  91. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  92. { FILE_GENERIC_READ,
  93. FILE_GENERIC_WRITE,
  94. FILE_GENERIC_EXECUTE,
  95. FILE_ALL_ACCESS
  96. },
  97. { { NW_FILE_READ, GENERIC_READ|GENERIC_EXECUTE},
  98. { NW_FILE_WRITE, GENERIC_WRITE},
  99. { NW_FILE_CREATE, GENERIC_WRITE},
  100. { NW_FILE_DELETE, DELETE},
  101. { NW_FILE_PERM, WRITE_DAC},
  102. { NW_FILE_SCAN, GENERIC_READ},
  103. { NW_FILE_MODIFY, GENERIC_WRITE},
  104. { NW_FILE_SUPERVISOR, GENERIC_ALL},
  105. { 0, 0 }
  106. }
  107. } ;
  108. VOID UserInfoLog(LPTSTR UserName, struct tagLoginControl tag);
  109. VOID Moveit(NWCONN_HANDLE Conn, LPTSTR UserName);
  110. VOID UserRecInit(NT_USER_INFO *UserInfo);
  111. BOOL IsNCPServerFPNW(NWCONN_HANDLE Conn);
  112. static NWCONN_HANDLE CachedConn = 0;
  113. static TCHAR CachedServer[MAX_SERVER_NAME_LEN + 1];
  114. static DWORD CachedServerTime = 0xffffffff; // minutes since 1985...
  115. typedef struct _PRINT_SERVER_BUFFER {
  116. TCHAR Name[20];
  117. } PRINT_SERVER_BUFFER;
  118. typedef struct _PRINT_SERVER_LIST {
  119. ULONG Count;
  120. PRINT_SERVER_BUFFER PSList[];
  121. } PRINT_SERVER_LIST;
  122. /////////////////////////////////////////////////////////////////////////
  123. int
  124. NWGetMaxServerNameLen()
  125. /*++
  126. Routine Description:
  127. Arguments:
  128. Return Value:
  129. --*/
  130. {
  131. return MAX_SERVER_NAME_LEN;
  132. } // NWGetMaxServerNameLen
  133. /////////////////////////////////////////////////////////////////////////
  134. int
  135. NWGetMaxUserNameLen()
  136. /*++
  137. Routine Description:
  138. Arguments:
  139. Return Value:
  140. --*/
  141. {
  142. return MAX_USER_NAME_LEN;
  143. } // NWGetMaxUserNameLen
  144. /////////////////////////////////////////////////////////////////////////
  145. DWORD
  146. NWServerFree()
  147. /*++
  148. Routine Description:
  149. Arguments:
  150. Return Value:
  151. --*/
  152. {
  153. if (CachedConn)
  154. NWDetachFromFileServer(CachedConn);
  155. CachedConn = 0;
  156. return (0);
  157. } // NWServerFree
  158. /////////////////////////////////////////////////////////////////////////
  159. DWORD
  160. NWServerSet(
  161. LPTSTR FileServer
  162. )
  163. /*++
  164. Routine Description:
  165. Arguments:
  166. Return Value:
  167. --*/
  168. {
  169. NWLOCAL_SCOPE ScopeFlag = 0;
  170. NWCONN_HANDLE Conn = 0;
  171. NWCCODE ret = 0;
  172. char szAnsiFileServer[MAX_SERVER_NAME_LEN + 1];
  173. NWServerFree();
  174. lstrcpy(CachedServer, FileServer);
  175. CharToOem(FileServer, szAnsiFileServer);
  176. ret = NWAttachToFileServer(szAnsiFileServer, ScopeFlag, &Conn);
  177. if (!ret) {
  178. CachedConn = Conn;
  179. NWServerTimeGet();
  180. }
  181. return ((DWORD) ret);
  182. } // NWServerSet
  183. /////////////////////////////////////////////////////////////////////////
  184. VOID
  185. NWUseDel(
  186. LPTSTR ServerName
  187. )
  188. /*++
  189. Routine Description:
  190. Arguments:
  191. Return Value:
  192. --*/
  193. {
  194. static TCHAR LocServer[MAX_SERVER_NAME_LEN+3];
  195. NWServerFree();
  196. wsprintf(LocServer, Lids(IDS_S_27), ServerName);
  197. WNetCancelConnection2(LocServer, 0, FALSE);
  198. } // NWUseDel
  199. /////////////////////////////////////////////////////////////////////////
  200. BOOL
  201. NWUserNameValidate(
  202. LPTSTR szUserName
  203. )
  204. /*++
  205. Routine Description:
  206. Arguments:
  207. Return Value:
  208. --*/
  209. {
  210. TCHAR UserName[MAX_USER_NAME_LEN + 1];
  211. DWORD Size;
  212. // if same as logged on user then don't convert or overwrite
  213. Size = sizeof(UserName);
  214. WNetGetUser(NULL, UserName, &Size);
  215. if (!lstrcmpi(szUserName, UserName))
  216. return FALSE;
  217. // Now check for other special names
  218. if (!lstrcmpi(szUserName, Lids(IDS_S_28)))
  219. return FALSE;
  220. if (!lstrcmpi(szUserName, Lids(IDS_S_29)))
  221. return FALSE;
  222. if (!lstrcmpi(szUserName, Lids(IDS_S_30)))
  223. return FALSE;
  224. return TRUE;
  225. } // NWUserNameValidate
  226. /////////////////////////////////////////////////////////////////////////
  227. BOOL
  228. NWGroupNameValidate(
  229. LPTSTR szGroupName
  230. )
  231. /*++
  232. Routine Description:
  233. Arguments:
  234. Return Value:
  235. --*/
  236. {
  237. if (!lstrcmpi(szGroupName, Lids(IDS_S_31)))
  238. return FALSE;
  239. if (!lstrcmpi(szGroupName, Lids(IDS_S_28)))
  240. return FALSE;
  241. return TRUE;
  242. } // NWGroupNameValidate
  243. /////////////////////////////////////////////////////////////////////////
  244. LPTSTR
  245. NWSpecialNamesMap(
  246. LPTSTR Name
  247. )
  248. /*++
  249. Routine Description:
  250. Arguments:
  251. Return Value:
  252. --*/
  253. {
  254. ULONG i;
  255. static BOOL InitStrings = FALSE;
  256. static LPTSTR SpecialNames[5];
  257. static LPTSTR SpecialMap[5];
  258. if (!InitStrings) {
  259. InitStrings = TRUE;
  260. SpecialNames[0] = Lids(IDS_S_28);
  261. SpecialNames[1] = Lids(IDS_S_30);
  262. SpecialNames[2] = Lids(IDS_S_31);
  263. SpecialNames[3] = Lids(IDS_S_29);
  264. SpecialNames[4] = NULL;
  265. SpecialMap[0] = Lids(IDS_S_32);
  266. SpecialMap[1] = Lids(IDS_S_32);
  267. SpecialMap[2] = Lids(IDS_S_33);
  268. SpecialMap[3] = Lids(IDS_S_29);
  269. SpecialMap[4] = NULL;
  270. }
  271. i = 0;
  272. while(SpecialNames[i] != NULL) {
  273. if (!lstrcmpi(SpecialNames[i], Name)) {
  274. return SpecialMap[i];
  275. }
  276. i++;
  277. }
  278. return Name;
  279. } // NWSpecialNamesMap
  280. /////////////////////////////////////////////////////////////////////////
  281. BOOL
  282. NWIsAdmin(
  283. LPTSTR UserName
  284. )
  285. /*++
  286. Routine Description:
  287. Arguments:
  288. Return Value:
  289. --*/
  290. {
  291. char szAnsiUserName[MAX_USER_NAME_LEN];
  292. NWCCODE ret;
  293. CharToOem(UserName, szAnsiUserName);
  294. ret = NWIsObjectInSet(CachedConn, szAnsiUserName, OT_USER, SECURITY_EQUALS,
  295. SUPERVISOR, OT_USER);
  296. if (ret == SUCCESSFUL)
  297. return TRUE;
  298. else
  299. return FALSE;
  300. } // NWIsAdmin
  301. /////////////////////////////////////////////////////////////////////////
  302. BOOL
  303. NWObjectNameGet(
  304. DWORD ObjectID,
  305. LPTSTR ObjectName
  306. )
  307. /*++
  308. Routine Description:
  309. Arguments:
  310. Return Value:
  311. --*/
  312. {
  313. char szAnsiObjectName[MAX_USER_NAME_LEN + 1];
  314. WORD wFoundUserType = 0;
  315. NWCCODE ret;
  316. lstrcpy(ObjectName, TEXT(""));
  317. if (!(ret = NWGetObjectName(CachedConn, ObjectID, szAnsiObjectName, &wFoundUserType))) {
  318. //
  319. // Got user - now convert and save off the information
  320. //
  321. OemToChar(szAnsiObjectName, ObjectName);
  322. }
  323. if (ret == SUCCESSFUL)
  324. return TRUE;
  325. else
  326. return FALSE;
  327. } // NWObjectNameGet
  328. #define DEF_NUM_RECS 200
  329. /////////////////////////////////////////////////////////////////////////
  330. DWORD
  331. NWUsersEnum(
  332. USER_LIST **lpUsers,
  333. BOOL Display
  334. )
  335. /*++
  336. Routine Description:
  337. Arguments:
  338. Return Value:
  339. --*/
  340. {
  341. USER_LIST *Users = NULL;
  342. USER_BUFFER *UserBuffer = NULL;
  343. DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
  344. DWORD Count = 0;
  345. DWORD status = 0;
  346. char szAnsiUserName[MAX_USER_NAME_LEN + 1];
  347. TCHAR szUserName[MAX_USER_NAME_LEN + 1];
  348. WORD wFoundUserType = 0;
  349. DWORD dwObjectID = 0xFFFFFFFFL;
  350. BYTE byPropertiesFlag = 0;
  351. BYTE byObjectFlag = 0;
  352. BYTE byObjectSecurity = 0;
  353. NWCCODE ret;
  354. if (Display)
  355. Status_ItemLabel(Lids(IDS_S_44));
  356. Users = (USER_LIST *) AllocMemory(sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
  357. if (!Users) {
  358. status = ERROR_NOT_ENOUGH_MEMORY;
  359. } else {
  360. UserBuffer = Users->UserBuffer;
  361. // init to NULL so doesn't have garbage if call fails
  362. lstrcpyA(szAnsiUserName, "");
  363. // Loop through bindery getting all the users.
  364. while ((ret = NWScanObject(CachedConn, "*", OT_USER, &dwObjectID, szAnsiUserName,
  365. &wFoundUserType, &byPropertiesFlag,
  366. &byObjectFlag, &byObjectSecurity)) == SUCCESSFUL) {
  367. // Got user - now convert and save off the information
  368. OemToChar(szAnsiUserName, szUserName);
  369. if (NWUserNameValidate(szUserName)) {
  370. if (Display)
  371. Status_Item(szUserName);
  372. lstrcpy(UserBuffer[Count].Name, szUserName);
  373. lstrcpy(UserBuffer[Count].NewName, szUserName);
  374. Count++;
  375. }
  376. // Check if we have to re-allocate buffer
  377. if (Count >= NumRecs) {
  378. NumRecs += DEF_NUM_RECS;
  379. Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
  380. if (!Users) {
  381. status = ERROR_NOT_ENOUGH_MEMORY;
  382. break;
  383. }
  384. UserBuffer = Users->UserBuffer;
  385. }
  386. }
  387. // Gotta clear this out from the last loop
  388. if (Count)
  389. ret = 0;
  390. }
  391. // check if error occured...
  392. if (ret)
  393. status = ret;
  394. // Now slim down the list to just what we need.
  395. if (!status) {
  396. Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER)* Count));
  397. if (!Users)
  398. status = ERROR_NOT_ENOUGH_MEMORY;
  399. else {
  400. // Sort the server list before putting it in the dialog
  401. UserBuffer = Users->UserBuffer;
  402. qsort((void *) UserBuffer, (size_t) Count, sizeof(USER_BUFFER), UserListCompare);
  403. }
  404. }
  405. if (Users != NULL)
  406. Users->Count = Count;
  407. *lpUsers = Users;
  408. return status;
  409. } // NWUsersEnum
  410. /////////////////////////////////////////////////////////////////////////
  411. DWORD
  412. NWGroupsEnum(
  413. GROUP_LIST **lpGroups,
  414. BOOL Display
  415. )
  416. /*++
  417. Routine Description:
  418. Arguments:
  419. Return Value:
  420. --*/
  421. {
  422. GROUP_LIST *Groups = NULL;
  423. GROUP_BUFFER *GroupBuffer;
  424. DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
  425. DWORD Count = 0;
  426. DWORD status = 0;
  427. char szAnsiGroupName[MAX_GROUP_NAME_LEN + 1];
  428. TCHAR szGroupName[MAX_GROUP_NAME_LEN + 1];
  429. WORD wFoundGroupType = 0;
  430. DWORD dwObjectID = 0xFFFFFFFFL;
  431. BYTE byPropertiesFlag = 0;
  432. BYTE byObjectFlag = 0;
  433. BYTE byObjectSecurity = 0;
  434. NWCCODE ret;
  435. if (Display)
  436. Status_ItemLabel(Lids(IDS_S_45));
  437. Groups = (GROUP_LIST *) AllocMemory(sizeof(GROUP_LIST) + (sizeof(GROUP_BUFFER) * NumRecs));
  438. if (!Groups) {
  439. status = ERROR_NOT_ENOUGH_MEMORY;
  440. } else {
  441. GroupBuffer = Groups->GroupBuffer;
  442. // init to NULL so doesn't have garbage if call fails
  443. lstrcpyA(szAnsiGroupName, "");
  444. // Loop through bindery getting all the users.
  445. while ((ret = NWScanObject(CachedConn, "*", OT_USER_GROUP, &dwObjectID, szAnsiGroupName,
  446. &wFoundGroupType, &byPropertiesFlag,
  447. &byObjectFlag, &byObjectSecurity)) == SUCCESSFUL) {
  448. // Got user - now convert and save off the information
  449. OemToChar(szAnsiGroupName, szGroupName);
  450. if (NWGroupNameValidate(szGroupName)) {
  451. if (Display)
  452. Status_Item(szGroupName);
  453. lstrcpy(GroupBuffer[Count].Name, szGroupName);
  454. lstrcpy(GroupBuffer[Count].NewName, szGroupName);
  455. Count++;
  456. }
  457. // Check if we have to re-allocate buffer
  458. if (Count >= NumRecs) {
  459. NumRecs += DEF_NUM_RECS;
  460. Groups = (GROUP_LIST *) ReallocMemory((HGLOBAL) Groups, sizeof(GROUP_LIST) + (sizeof(GROUP_BUFFER) * NumRecs));
  461. if (!Groups) {
  462. status = ERROR_NOT_ENOUGH_MEMORY;
  463. break;
  464. }
  465. GroupBuffer = Groups->GroupBuffer;
  466. }
  467. }
  468. // Gotta clear this out from the last loop
  469. if (Count)
  470. ret = 0;
  471. }
  472. // check if error occured...
  473. if (ret)
  474. status = ret;
  475. // Now slim down the list to just what we need.
  476. if (!status) {
  477. Groups = (GROUP_LIST *) ReallocMemory((HGLOBAL) Groups, sizeof(GROUP_LIST) + (sizeof(GROUP_BUFFER) * Count));
  478. if (!Groups)
  479. status = ERROR_NOT_ENOUGH_MEMORY;
  480. else {
  481. // Sort the server list before putting it in the dialog
  482. GroupBuffer = Groups->GroupBuffer;
  483. qsort((void *) GroupBuffer, (size_t) Count, sizeof(GROUP_BUFFER), UserListCompare);
  484. }
  485. }
  486. if (Groups != NULL)
  487. Groups->Count = Count;
  488. *lpGroups = Groups;
  489. return status;
  490. } // NWGroupsEnum
  491. /////////////////////////////////////////////////////////////////////////
  492. DWORD
  493. NWGroupUsersEnum(
  494. LPTSTR GroupName,
  495. USER_LIST **lpUsers
  496. )
  497. /*++
  498. Routine Description:
  499. Arguments:
  500. Return Value:
  501. --*/
  502. {
  503. USER_LIST *Users = NULL;
  504. USER_BUFFER *UserBuffer;
  505. DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
  506. DWORD Count = 0;
  507. DWORD i = 0;
  508. DWORD status = 0;
  509. char szAnsiUserName[MAX_USER_NAME_LEN + 1];
  510. char szAnsiGroupName[MAX_GROUP_NAME_LEN + 1];
  511. TCHAR szUserName[MAX_USER_NAME_LEN + 1];
  512. WORD wFoundUserType = 0;
  513. BYTE byPropertyFlags = 0;
  514. BYTE byObjectFlag = 0;
  515. BYTE byObjectSecurity = 0;
  516. UCHAR Segment = 1;
  517. DWORD bySegment[32];
  518. BYTE byMoreSegments;
  519. NWCCODE ret;
  520. Users = (USER_LIST *) AllocMemory(sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
  521. if (!Users) {
  522. status = ERROR_NOT_ENOUGH_MEMORY;
  523. } else {
  524. UserBuffer = Users->UserBuffer;
  525. // init to NULL so doesn't have garbage if call fails
  526. lstrcpyA(szAnsiUserName, "");
  527. CharToOem(GroupName, szAnsiGroupName);
  528. // Loop through bindery getting all the users.
  529. do {
  530. if (!(ret = NWReadPropertyValue(CachedConn, szAnsiGroupName, OT_USER_GROUP, GROUP_MEMBERS,
  531. Segment, (BYTE *) bySegment, &byMoreSegments, &byPropertyFlags))) {
  532. Segment++;
  533. // loop through properties converting them to user names
  534. i = 0;
  535. while ((bySegment[i]) && (i < 32)) {
  536. if (!(ret = NWGetObjectName(CachedConn, bySegment[i], szAnsiUserName, &wFoundUserType))) {
  537. // Got user - now convert and save off the information
  538. OemToChar(szAnsiUserName, szUserName);
  539. lstrcpy(UserBuffer[Count].Name, szUserName);
  540. lstrcpy(UserBuffer[Count].NewName, szUserName);
  541. Count++;
  542. // Check if we have to re-allocate buffer
  543. if (Count >= NumRecs) {
  544. NumRecs += DEF_NUM_RECS;
  545. Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
  546. if (!Users) {
  547. status = ERROR_NOT_ENOUGH_MEMORY;
  548. break;
  549. }
  550. UserBuffer = Users->UserBuffer;
  551. }
  552. }
  553. i++;
  554. }
  555. } else // if NWReadPropertyValue
  556. byMoreSegments = 0;
  557. } while (byMoreSegments);
  558. // Gotta clear this out from the last loop
  559. if (Count)
  560. ret = 0;
  561. }
  562. // check if error occured...
  563. if (ret)
  564. status = ret;
  565. // Now slim down the list to just what we need.
  566. if (!status) {
  567. Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * Count));
  568. if (!Users)
  569. status = ERROR_NOT_ENOUGH_MEMORY;
  570. else {
  571. // Sort the server list before putting it in the dialog
  572. UserBuffer = Users->UserBuffer;
  573. qsort((void *) UserBuffer, (size_t) Count, sizeof(USER_BUFFER), UserListCompare);
  574. }
  575. }
  576. if (Users != NULL)
  577. Users->Count = Count;
  578. *lpUsers = Users;
  579. return status;
  580. } // NWGroupUsersEnum
  581. /////////////////////////////////////////////////////////////////////////
  582. DWORD
  583. NWUserEquivalenceEnum(
  584. LPTSTR UserName,
  585. USER_LIST **lpUsers
  586. )
  587. /*++
  588. Routine Description:
  589. Arguments:
  590. Return Value:
  591. --*/
  592. {
  593. USER_LIST *Users;
  594. USER_BUFFER *UserBuffer;
  595. DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
  596. DWORD Count = 0;
  597. DWORD i = 0;
  598. DWORD status = 0;
  599. char szAnsiUserName[MAX_USER_NAME_LEN + 1];
  600. char szAnsiName[MAX_GROUP_NAME_LEN + 1];
  601. TCHAR szUserName[MAX_USER_NAME_LEN + 1];
  602. WORD wFoundUserType = 0;
  603. DWORD dwObjectID = 0xFFFFFFFFL;
  604. BYTE byPropertyFlags = 0;
  605. BYTE byObjectFlag = 0;
  606. BYTE byObjectSecurity = 0;
  607. UCHAR Segment = 1;
  608. DWORD bySegment[32];
  609. BYTE byMoreSegments;
  610. NWCCODE ret;
  611. Users = (USER_LIST *) AllocMemory(sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
  612. if (!Users) {
  613. status = ERROR_NOT_ENOUGH_MEMORY;
  614. } else {
  615. UserBuffer = Users->UserBuffer;
  616. // init to NULL so doesn't have garbage if call fails
  617. lstrcpyA(szAnsiUserName, "");
  618. CharToOem(UserName, szAnsiName);
  619. // Loop through bindery getting all the users.
  620. do {
  621. if (!(ret = NWReadPropertyValue(CachedConn, szAnsiName, OT_USER, SECURITY_EQUALS,
  622. Segment, (BYTE *) bySegment, &byMoreSegments, &byPropertyFlags))) {
  623. Segment++;
  624. // loop through properties converting them to user names
  625. i = 0;
  626. while ((bySegment[i]) && (i < 32)) {
  627. if (!(ret = NWGetObjectName(CachedConn, bySegment[i], szAnsiUserName, &wFoundUserType))) {
  628. // Got user - now convert and save off the information
  629. OemToChar(szAnsiUserName, szUserName);
  630. // Map out Everyone equivalence
  631. if (lstrcmpi(szUserName, Lids(IDS_S_31))) {
  632. lstrcpy(UserBuffer[Count].Name, szUserName);
  633. lstrcpy(UserBuffer[Count].NewName, szUserName);
  634. Count++;
  635. }
  636. // Check if we have to re-allocate buffer
  637. if (Count >= NumRecs) {
  638. NumRecs += DEF_NUM_RECS;
  639. Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
  640. if (!Users) {
  641. status = ERROR_NOT_ENOUGH_MEMORY;
  642. break;
  643. }
  644. UserBuffer = Users->UserBuffer;
  645. }
  646. }
  647. i++;
  648. }
  649. } else // if NWReadPropertyValue
  650. byMoreSegments = 0;
  651. } while (byMoreSegments);
  652. // Gotta clear this out from the last loop
  653. if (Count)
  654. ret = 0;
  655. }
  656. // check if error occured...
  657. if (ret)
  658. status = ret;
  659. // Now slim down the list to just what we need.
  660. if (!status) {
  661. Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * Count));
  662. if (!Users)
  663. status = ERROR_NOT_ENOUGH_MEMORY;
  664. else {
  665. // Sort the server list before putting it in the dialog
  666. UserBuffer = Users->UserBuffer;
  667. qsort((void *) UserBuffer, (size_t) Count, sizeof(USER_BUFFER), UserListCompare);
  668. }
  669. }
  670. if (Users != NULL)
  671. Users->Count = Count;
  672. *lpUsers = Users;
  673. return status;
  674. } // NWUserEquivalenceEnum
  675. /////////////////////////////////////////////////////////////////////////
  676. DWORD
  677. NWFileRightsEnum(
  678. LPTSTR FileName,
  679. USER_RIGHTS_LIST **lpUsers,
  680. DWORD *UserCount,
  681. BOOL DownLevel
  682. )
  683. /*++
  684. Routine Description:
  685. Arguments:
  686. Return Value:
  687. --*/
  688. {
  689. BOOL Continue = TRUE;
  690. USER_RIGHTS_LIST *Users = NULL;
  691. DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
  692. DWORD Count = 0;
  693. DWORD i = 0;
  694. DWORD status = 0;
  695. char szAnsiUserName[MAX_USER_NAME_LEN + 1];
  696. char szAnsiSearchDir[MAX_PATH + 1];
  697. TCHAR szUserName[MAX_USER_NAME_LEN + 1];
  698. WORD wFoundUserType = 0;
  699. NWCCODE ret;
  700. char FoundDir[16];
  701. ULONG Entries;
  702. TRUSTEE_INFO ti[20];
  703. BYTE DirHandle, nDirHandle;
  704. BYTE Sequence;
  705. BYTE NumEntries = 0;
  706. NWDATE_TIME dtime = 0;
  707. NWOBJ_ID ownerID = 0;
  708. if (DownLevel) {
  709. Entries = 5;
  710. Sequence = 1;
  711. } else {
  712. Entries = 20;
  713. Sequence = 0;
  714. }
  715. DirHandle = nDirHandle = 0;
  716. memset(ti, 0, sizeof(ti));
  717. Users = (USER_RIGHTS_LIST *) AllocMemory(NumRecs * sizeof(USER_RIGHTS_LIST));
  718. if (!Users) {
  719. status = ERROR_NOT_ENOUGH_MEMORY;
  720. } else {
  721. // init to NULL so doesn't have garbage if call fails
  722. lstrcpyA(szAnsiUserName, "");
  723. CharToOem(FileName, szAnsiSearchDir);
  724. // Loop through bindery getting all the users.
  725. do {
  726. if (DownLevel)
  727. ret = NWCScanDirectoryForTrustees2(CachedConn, nDirHandle, szAnsiSearchDir,
  728. &Sequence, FoundDir, &dtime, &ownerID, ti);
  729. else
  730. ret = NWCScanForTrustees(CachedConn, nDirHandle, szAnsiSearchDir,
  731. &Sequence, &NumEntries, ti);
  732. if (!ret) {
  733. // loop through properties converting them to user names
  734. for (i = 0; i < Entries; i++) {
  735. if (ti[i].objectID != 0) {
  736. if (!(ret = NWGetObjectName(CachedConn, ti[i].objectID, szAnsiUserName, &wFoundUserType))) {
  737. // Got user - now convert and save off the information
  738. OemToChar(szAnsiUserName, szUserName);
  739. lstrcpy(Users[Count].Name, szUserName);
  740. Users[Count].Rights = ti[i].objectRights;
  741. Count++;
  742. // Check if we have to re-allocate buffer
  743. if (Count >= NumRecs) {
  744. NumRecs += DEF_NUM_RECS;
  745. Users = (USER_RIGHTS_LIST *) ReallocMemory((HGLOBAL) Users, NumRecs * sizeof(USER_RIGHTS_LIST));
  746. if (!Users) {
  747. status = ERROR_NOT_ENOUGH_MEMORY;
  748. break;
  749. }
  750. } // if realloc buffer
  751. }
  752. } // if objectID != 0
  753. }
  754. } else // NWScan failed
  755. Continue = FALSE;
  756. } while (Continue);
  757. // Gotta clear this out from the last loop
  758. if (Count)
  759. ret = 0;
  760. }
  761. // check if error occured...
  762. if (ret) {
  763. status = ret;
  764. if (Users != NULL) {
  765. FreeMemory(Users);
  766. Count = 0;
  767. }
  768. }
  769. // Now slim down the list to just what we need.
  770. if (!status) {
  771. Users = (USER_RIGHTS_LIST *) ReallocMemory((HGLOBAL) Users, Count * sizeof(USER_RIGHTS_LIST));
  772. if (!Users)
  773. status = ERROR_NOT_ENOUGH_MEMORY;
  774. else
  775. // Sort the server list before putting it in the dialog
  776. qsort((void *) Users, (size_t) Count, sizeof(USER_RIGHTS_LIST), UserListCompare);
  777. }
  778. *UserCount = Count;
  779. *lpUsers = Users;
  780. return status;
  781. } // NWFileRightsEnum
  782. /////////////////////////////////////////////////////////////////////////
  783. VOID
  784. NWLoginTimesMap(
  785. BYTE *Times,
  786. BYTE *NewTimes
  787. )
  788. /*++
  789. Routine Description:
  790. Arguments:
  791. Return Value:
  792. --*/
  793. {
  794. DWORD i, j;
  795. int Bit = 0;
  796. int Val;
  797. BYTE BitSet;
  798. for (i = 0; i < 21; i++) {
  799. BitSet = 0;
  800. for (j = 0; j < 8; j++) {
  801. if (BitTest(Bit, Times) || BitTest(Bit+1, Times)) {
  802. Val = 0x1 << j;
  803. BitSet = BitSet + (BYTE) Val;
  804. }
  805. Bit++; Bit++;
  806. }
  807. NewTimes[i] = BitSet;
  808. }
  809. } // NWLoginTimesMap
  810. /*+-------------------------------------------------------------------------+
  811. | Time Conversion |
  812. +-------------------------------------------------------------------------+*/
  813. #define IS_LEAP(y) ((y % 4 == 0) && (y % 100 != 0 || y % 400 == 0))
  814. #define DAYS_IN_YEAR(y) (IS_LEAP(y) ? 366 : 365)
  815. #define DAYS_IN_MONTH(m,y) (IS_LEAP(y) ? _days_month_leap[m] : _days_month[m])
  816. #define SECS_IN_DAY (60L * 60L * 24L)
  817. #define SECS_IN_HOUR (60L * 60L)
  818. #define SECS_IN_MINUTE (60L)
  819. static short _days_month_leap[] = { 31,29,31,30,31,30,31,31,30,31,30,31 };
  820. static short _days_month[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
  821. /////////////////////////////////////////////////////////////////////////
  822. BOOL
  823. NWTimeMap(
  824. DWORD Days,
  825. DWORD dwMonth,
  826. DWORD dwYear,
  827. DWORD dwBasis,
  828. ULONG *Time
  829. )
  830. /*++
  831. Routine Description:
  832. Arguments:
  833. Return Value:
  834. --*/
  835. {
  836. DWORD dw = 0;
  837. DWORD dwDays = 0;
  838. // Zero
  839. *Time = 0L;
  840. // Adjust year
  841. if(dwYear < 70)
  842. dwYear += 2000L;
  843. else
  844. if(dwYear < 100)
  845. dwYear += 1900L;
  846. if (dwYear < dwBasis)
  847. return FALSE;
  848. // Calculate days in previous years, take -1 so we skip current year
  849. dw = dwYear - 1;
  850. while(dw >= dwBasis) {
  851. dwDays += DAYS_IN_YEAR(dw);
  852. --dw;
  853. }
  854. // Days from month
  855. if((dwMonth < 1)||(dwMonth > 12))
  856. return FALSE;
  857. // Loop through adding number of days in each month. Take -2 (-1 to skip
  858. // current month, and -1 to make 0 based).
  859. dw = dwMonth;
  860. while(dw > 1) {
  861. dwDays += DAYS_IN_MONTH(dw-2, dwYear);
  862. --dw;
  863. }
  864. // Convert days
  865. dw = Days;
  866. if((dw >= 1) && (dw <= (DWORD) DAYS_IN_MONTH(dwMonth - 1, dwYear)))
  867. dwDays += dw;
  868. else
  869. return FALSE; // out of range
  870. *Time += dwDays * SECS_IN_DAY;
  871. return TRUE;
  872. } // NWTimeMap
  873. /////////////////////////////////////////////////////////////////////////
  874. LPTSTR
  875. NWUserNameGet(
  876. LPTSTR szUserName
  877. )
  878. /*++
  879. Routine Description:
  880. Arguments:
  881. Return Value:
  882. --*/
  883. {
  884. static TCHAR UserName[128];
  885. char szAnsiUserName[MAX_USER_NAME_LEN];
  886. NWCCODE ret;
  887. BYTE bySegment[128];
  888. BYTE byMoreSegments, byPropertyFlags;
  889. LPSTR szAnsiFullName;
  890. CharToOem(szUserName, szAnsiUserName);
  891. ret = NWReadPropertyValue(CachedConn, szAnsiUserName, OT_USER, IDENTIFICATION,
  892. 1, bySegment, &byMoreSegments, &byPropertyFlags);
  893. if (ret == SUCCESSFUL) {
  894. szAnsiFullName = (LPSTR) bySegment;
  895. OemToChar(szAnsiFullName, UserName);
  896. return UserName;
  897. }
  898. return NULL;
  899. } // NWUserNameGet
  900. /////////////////////////////////////////////////////////////////////////
  901. VOID
  902. NWNetUserMapInfo (
  903. LPTSTR szUserName,
  904. VOID *UInfo,
  905. NT_USER_INFO *NT_UInfo
  906. )
  907. /*++
  908. Routine Description:
  909. Arguments:
  910. Return Value:
  911. --*/
  912. {
  913. ULONG expires;
  914. struct tagLoginControl *tag;
  915. LPTSTR FullName;
  916. tag = (struct tagLoginControl *) UInfo;
  917. FullName = NWUserNameGet(szUserName);
  918. if (FullName != NULL)
  919. lstrcpyn(NT_UInfo->full_name, FullName, MAXCOMMENTSZ);
  920. // Account disabled
  921. if (tag->byAccountDisabled)
  922. NT_UInfo->flags = NT_UInfo->flags | 0x02;
  923. // account locked out
  924. if ((tag->wBadLogins == 0xffff) &&
  925. (tag->lNextResetTime > (LONG)CachedServerTime))
  926. NT_UInfo->flags = NT_UInfo->flags | 0x02; // disable account...
  927. // user can change password
  928. if ((tag->byRestrictions & 0x01))
  929. NT_UInfo->flags = NT_UInfo->flags | 0x40;
  930. NWLoginTimesMap(tag->byLoginTimes, NT_UInfo->logon_hours);
  931. // account expires
  932. if (tag->byAccountExpires[0] == 0)
  933. NT_UInfo->acct_expires = TIMEQ_FOREVER;
  934. else
  935. if (tag->byAccountExpires[0] < 70)
  936. NT_UInfo->acct_expires = 0;
  937. else {
  938. // fits within time range so convert to #seconds since 1970
  939. expires = 0;
  940. NWTimeMap((DWORD) tag->byAccountExpires[2],
  941. (DWORD) tag->byAccountExpires[1],
  942. (DWORD) tag->byAccountExpires[0], 1970, &expires);
  943. NT_UInfo->acct_expires = expires;
  944. }
  945. } // NWNetUserMapInfo
  946. /////////////////////////////////////////////////////////////////////////
  947. VOID
  948. NWFPNWMapInfo(
  949. VOID *NWUInfo,
  950. PFPNW_INFO fpnw
  951. )
  952. /*++
  953. Routine Description:
  954. Arguments:
  955. Return Value:
  956. --*/
  957. {
  958. struct tagLoginControl *tag;
  959. tag = (struct tagLoginControl *) NWUInfo;
  960. fpnw->MaxConnections = tag->wMaxConnections;
  961. fpnw->PasswordInterval = tag->wPasswordInterval;
  962. fpnw->GraceLoginAllowed = tag->byGraceLogins;
  963. fpnw->GraceLoginRemaining = tag->byGraceLoginReset;
  964. fpnw->LoginFrom = NULL;
  965. fpnw->HomeDir = NULL;
  966. } // NWFPNWMapInfo
  967. /////////////////////////////////////////////////////////////////////////
  968. VOID
  969. NWUserDefaultsGet(
  970. VOID **UDefaults
  971. )
  972. /*++
  973. Routine Description:
  974. Arguments:
  975. Return Value:
  976. --*/
  977. {
  978. struct tagUserDefaults *UserDefaults = NULL;
  979. NWCCODE ret;
  980. BYTE bySegment[128];
  981. BYTE byMoreSegments, byPropertyFlags;
  982. ret = NWReadPropertyValue(CachedConn, SUPERVISOR, OT_USER, USER_DEFAULTS, 1, bySegment, &byMoreSegments, &byPropertyFlags);
  983. if (ret == SUCCESSFUL) {
  984. UserDefaults = AllocMemory(sizeof(struct tagUserDefaults));
  985. memcpy(UserDefaults, bySegment, sizeof (struct tagUserDefaults));
  986. // Now put the data in 'normal' Intel format
  987. SWAPBYTES(UserDefaults->wPasswordInterval);
  988. SWAPBYTES(UserDefaults->wMaxConnections);
  989. SWAPWORDS(UserDefaults->lBalance);
  990. SWAPWORDS(UserDefaults->lCreditLimit);
  991. SWAPWORDS(UserDefaults->lMaxDiskBlocks);
  992. }
  993. *UDefaults = (void *) UserDefaults;
  994. } // NWUserDefaultsGet
  995. /////////////////////////////////////////////////////////////////////////
  996. VOID
  997. NWUserDefaultsMap(
  998. VOID *NWUDefaults,
  999. NT_DEFAULTS *NTDefaults
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. Arguments:
  1004. Return Value:
  1005. --*/
  1006. {
  1007. struct tagUserDefaults *UserDefaults = NULL;
  1008. if ((NWUDefaults == NULL) || (NTDefaults == NULL))
  1009. return;
  1010. UserDefaults = (struct tagUserDefaults *) NWUDefaults;
  1011. NTDefaults->min_passwd_len = (DWORD) UserDefaults->byMinPasswordLength;
  1012. NTDefaults->max_passwd_age = (DWORD) UserDefaults->wPasswordInterval * 86400;
  1013. NTDefaults->force_logoff = (DWORD) UserDefaults->byGraceLoginReset;
  1014. // These fields aren't used/converted
  1015. // NTDefaults->min-passwd_age - no such thing for NetWare
  1016. // NTDefaults->password_hist_len - no such thing for NetWare
  1017. } // NWUserDefaultsMap
  1018. /////////////////////////////////////////////////////////////////////////
  1019. VOID
  1020. NWLoginTimesLog(
  1021. BYTE *Times
  1022. )
  1023. /*++
  1024. Routine Description:
  1025. Arguments:
  1026. Return Value:
  1027. --*/
  1028. {
  1029. TCHAR *szDays[7];
  1030. DWORD Day;
  1031. DWORD Hours;
  1032. int Bit = 0, i;
  1033. static TCHAR szHours[80];
  1034. szDays[0] = Lids(IDS_SUN);
  1035. szDays[1] = Lids(IDS_MON);
  1036. szDays[2] = Lids(IDS_TUE);
  1037. szDays[3] = Lids(IDS_WED);
  1038. szDays[4] = Lids(IDS_THU);
  1039. szDays[5] = Lids(IDS_FRI);
  1040. szDays[6] = Lids(IDS_SAT);
  1041. LogWriteLog(1, Lids(IDS_CRLF));
  1042. LogWriteLog(1, Lids(IDS_L_104));
  1043. // while these should be level 2, there isn't room on 80 cols - so level 1
  1044. LogWriteLog(1, Lids(IDS_L_1));
  1045. LogWriteLog(1, Lids(IDS_L_2));
  1046. LogWriteLog(1, Lids(IDS_L_3));
  1047. for (Day = 0; Day < 7; Day++) {
  1048. LogWriteLog(1, szDays[Day]);
  1049. lstrcpy(szHours, TEXT(" "));
  1050. for (Hours = 0; Hours < 24; Hours++) {
  1051. for (i = 0; i < 2; i++) {
  1052. if (BitTest(Bit, Times))
  1053. lstrcat(szHours, TEXT("*"));
  1054. else
  1055. lstrcat(szHours, TEXT(" "));
  1056. Bit++;
  1057. }
  1058. lstrcat(szHours, TEXT(" "));
  1059. }
  1060. LogWriteLog(0, szHours);
  1061. LogWriteLog(0, Lids(IDS_CRLF));
  1062. }
  1063. LogWriteLog(0, Lids(IDS_CRLF));
  1064. } // NWLoginTimesLog
  1065. /////////////////////////////////////////////////////////////////////////
  1066. VOID
  1067. NWUserDefaultsLog(
  1068. VOID *UDefaults
  1069. )
  1070. /*++
  1071. Routine Description:
  1072. Arguments:
  1073. Return Value:
  1074. --*/
  1075. {
  1076. struct tagUserDefaults *tag;
  1077. tag = (struct tagUserDefaults *) UDefaults;
  1078. // Account expires
  1079. LogWriteLog(1, Lids(IDS_L_109));
  1080. if (tag->byAccountExpiresYear == 0)
  1081. LogWriteLog(0, Lids(IDS_L_107));
  1082. else
  1083. LogWriteLog(0, TEXT("%02u/%02u/%04u"), (UINT) tag->byAccountExpiresDay,
  1084. (UINT) tag->byAccountExpiresMonth, (UINT) 1900 + tag->byAccountExpiresYear);
  1085. LogWriteLog(0, Lids(IDS_CRLF));
  1086. // Restrictions
  1087. LogWriteLog(1, Lids(IDS_L_110));
  1088. // user can change password
  1089. if ((tag->byRestrictions & 0x01))
  1090. LogWriteLog(2, Lids(IDS_L_111));
  1091. else
  1092. LogWriteLog(2, Lids(IDS_L_112));
  1093. // unique password required
  1094. if ((tag->byRestrictions & 0x02))
  1095. LogWriteLog(2, Lids(IDS_L_113), Lids(IDS_YES));
  1096. else
  1097. LogWriteLog(2, Lids(IDS_L_113), Lids(IDS_NO));
  1098. // Password interval
  1099. LogWriteLog(1, Lids(IDS_L_114));
  1100. if (tag->wPasswordInterval == 0)
  1101. LogWriteLog(0, Lids(IDS_L_107));
  1102. else
  1103. LogWriteLog(0, TEXT("%u"), (UINT) tag->wPasswordInterval);
  1104. LogWriteLog(0, Lids(IDS_CRLF));
  1105. // Grace Logins
  1106. LogWriteLog(1, Lids(IDS_L_115));
  1107. if (tag->byGraceLoginReset == 0xff)
  1108. LogWriteLog(0, Lids(IDS_L_108));
  1109. else
  1110. LogWriteLog(0, TEXT("%u"), (UINT) tag->byGraceLoginReset);
  1111. LogWriteLog(0, Lids(IDS_CRLF));
  1112. LogWriteLog(1, Lids(IDS_L_116), (UINT) tag->byMinPasswordLength);
  1113. // Max Connections
  1114. LogWriteLog(1, Lids(IDS_L_117));
  1115. if (tag->wMaxConnections == 0)
  1116. LogWriteLog(0, Lids(IDS_L_108));
  1117. else
  1118. LogWriteLog(0, TEXT("%u"), (UINT) tag->wMaxConnections);
  1119. LogWriteLog(0, Lids(IDS_CRLF));
  1120. LogWriteLog(1, Lids(IDS_L_118), (ULONG) tag->lBalance);
  1121. LogWriteLog(1, Lids(IDS_L_119), (ULONG) tag->lCreditLimit);
  1122. // Max Disk blocks
  1123. LogWriteLog(1, Lids(IDS_L_120));
  1124. if (tag->lMaxDiskBlocks == 0x7FFFFFFF)
  1125. LogWriteLog(0, Lids(IDS_L_108));
  1126. else
  1127. LogWriteLog(0, TEXT("%lu"), (ULONG) tag->lMaxDiskBlocks);
  1128. LogWriteLog(0, Lids(IDS_CRLF));
  1129. LogWriteLog(0, Lids(IDS_CRLF));
  1130. } // NWUserDefaultsLog
  1131. /////////////////////////////////////////////////////////////////////////
  1132. VOID
  1133. NWUserInfoLog(
  1134. LPTSTR szUserName,
  1135. VOID *UInfo
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Arguments:
  1140. Return Value:
  1141. --*/
  1142. {
  1143. struct tagLoginControl *tag;
  1144. LPTSTR FullName;
  1145. tag = (struct tagLoginControl *) UInfo;
  1146. LogWriteLog(1, Lids(IDS_L_105));
  1147. // Full Name
  1148. LogWriteLog(2, Lids(IDS_L_106));
  1149. FullName = NWUserNameGet(szUserName);
  1150. if (FullName != NULL)
  1151. LogWriteLog(2, FullName);
  1152. LogWriteLog(0, Lids(IDS_CRLF));
  1153. // Account disabled
  1154. if (tag->byAccountDisabled == 0xff)
  1155. LogWriteLog(2, Lids(IDS_L_121), Lids(IDS_YES));
  1156. else if ((tag->wBadLogins == 0xffff) &&
  1157. (tag->lNextResetTime > (LONG)CachedServerTime))
  1158. LogWriteLog(2, Lids(IDS_L_121), Lids(IDS_LOCKED_OUT));
  1159. else
  1160. LogWriteLog(2, Lids(IDS_L_121), Lids(IDS_NO));
  1161. // Account expires
  1162. LogWriteLog(2, Lids(IDS_L_109));
  1163. if (tag->byAccountExpires[0] == 0)
  1164. LogWriteLog(0, Lids(IDS_L_107));
  1165. else
  1166. LogWriteLog(0, TEXT("%02u/%02u/%04u"), (UINT) tag->byAccountExpires[1],
  1167. (UINT) tag->byAccountExpires[2], (UINT) 1900 + tag->byAccountExpires[0]);
  1168. LogWriteLog(0, Lids(IDS_CRLF));
  1169. // Password Expires
  1170. LogWriteLog(2, Lids(IDS_L_122));
  1171. if (tag->byPasswordExpires[0] == 0)
  1172. LogWriteLog(0, Lids(IDS_L_107));
  1173. else
  1174. LogWriteLog(0, TEXT("%02u/%02u/19%02u"), (int) tag->byPasswordExpires[1],
  1175. (int) tag->byPasswordExpires[2], (int) tag->byPasswordExpires[0]);
  1176. LogWriteLog(0, Lids(IDS_CRLF));
  1177. // Grace logins
  1178. LogWriteLog(2, Lids(IDS_L_123));
  1179. if (tag->byGraceLogins == 0xff)
  1180. LogWriteLog(0, Lids(IDS_L_108));
  1181. else
  1182. LogWriteLog(0, TEXT("%u"), (UINT) tag->byGraceLogins);
  1183. LogWriteLog(0, Lids(IDS_CRLF));
  1184. // initial grace logins
  1185. LogWriteLog(2, Lids(IDS_L_115));
  1186. if (tag->byGraceLoginReset == 0xff)
  1187. LogWriteLog(0, Lids(IDS_L_108));
  1188. else
  1189. LogWriteLog(0, TEXT("%u"), (UINT) tag->byGraceLoginReset);
  1190. LogWriteLog(0, Lids(IDS_CRLF));
  1191. // Min password length
  1192. LogWriteLog(2, Lids(IDS_L_116), (UINT) tag->byMinPasswordLength);
  1193. // Password expiration
  1194. LogWriteLog(2, Lids(IDS_L_114));
  1195. if (tag->wPasswordInterval == 0)
  1196. LogWriteLog(0, Lids(IDS_L_107));
  1197. else
  1198. LogWriteLog(0, TEXT("%u"), (UINT) tag->wPasswordInterval);
  1199. LogWriteLog(0, Lids(IDS_CRLF));
  1200. // Max connections
  1201. LogWriteLog(2, Lids(IDS_L_117));
  1202. if (tag->wMaxConnections == 0)
  1203. LogWriteLog(0, Lids(IDS_L_108));
  1204. else
  1205. LogWriteLog(0, TEXT("%u"), (UINT) tag->wMaxConnections);
  1206. LogWriteLog(0, Lids(IDS_CRLF));
  1207. // Restrictions
  1208. // user can change password
  1209. LogWriteLog(2, Lids(IDS_L_110));
  1210. if ((tag->byRestrictions & 0x01))
  1211. LogWriteLog(3, Lids(IDS_L_111));
  1212. else
  1213. LogWriteLog(3, Lids(IDS_L_112));
  1214. // unique password required
  1215. if ((tag->byRestrictions & 0x02))
  1216. LogWriteLog(3, Lids(IDS_L_113), Lids(IDS_YES));
  1217. else
  1218. LogWriteLog(3, Lids(IDS_L_113), Lids(IDS_NO));
  1219. LogWriteLog(2, Lids(IDS_L_124), (UINT) tag->wBadLogins);
  1220. // Max Disk Blocks
  1221. LogWriteLog(2, Lids(IDS_L_120));
  1222. if (tag->lMaxDiskBlocks == 0x7FFFFFFF)
  1223. LogWriteLog(0, Lids(IDS_L_108));
  1224. else
  1225. LogWriteLog(0, TEXT("%lX"), tag->lMaxDiskBlocks);
  1226. LogWriteLog(0, Lids(IDS_CRLF));
  1227. // Login Times
  1228. NWLoginTimesLog(tag->byLoginTimes);
  1229. } // NWUserInfoLog
  1230. /////////////////////////////////////////////////////////////////////////
  1231. VOID
  1232. NWUserInfoGet(
  1233. LPTSTR szUserName,
  1234. VOID **UInfo
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. Arguments:
  1239. Return Value:
  1240. --*/
  1241. {
  1242. static struct tagLoginControl xUI;
  1243. struct tagLoginControl *UserInfo = NULL;
  1244. char szAnsiUserName[MAX_USER_NAME_LEN];
  1245. NWCCODE ret;
  1246. BYTE bySegment[128];
  1247. BYTE byMoreSegments, byPropertyFlags;
  1248. CharToOem(szUserName, szAnsiUserName);
  1249. ret = NWReadPropertyValue(CachedConn, szAnsiUserName, OT_USER, LOGIN_CONTROL, 1, bySegment, &byMoreSegments, &byPropertyFlags);
  1250. if (ret == SUCCESSFUL) {
  1251. UserInfo = &xUI;
  1252. memset(UserInfo, 0, sizeof(struct tagLoginControl));
  1253. memcpy(UserInfo, bySegment, sizeof (struct tagLoginControl));
  1254. // Now put the data in 'normal' Intel format
  1255. SWAPBYTES(UserInfo->wPasswordInterval);
  1256. SWAPBYTES(UserInfo->wMaxConnections);
  1257. SWAPWORDS(UserInfo->lMaxDiskBlocks);
  1258. SWAPBYTES(UserInfo->wBadLogins);
  1259. SWAPWORDS(UserInfo->lNextResetTime);
  1260. }
  1261. *UInfo = (void *) UserInfo;
  1262. } // NWUserInfoGet
  1263. /////////////////////////////////////////////////////////////////////////
  1264. DWORD
  1265. NWServerEnum(
  1266. LPTSTR Container,
  1267. SERVER_BROWSE_LIST **lpServList
  1268. )
  1269. /*++
  1270. Routine Description:
  1271. Arguments:
  1272. Return Value:
  1273. --*/
  1274. {
  1275. int NumBufs = 0;
  1276. DWORD TotalEntries = 0;
  1277. ENUM_REC *BufHead, *CurrBuf, *OldBuf;
  1278. SERVER_BROWSE_LIST *ServList = NULL;
  1279. SERVER_BROWSE_BUFFER *SList = NULL;
  1280. DWORD status = 0;
  1281. DWORD i, j;
  1282. NETRESOURCE ResourceBuf;
  1283. // Container is ignored - NW is a flat network topology...
  1284. SetProvider(NW_PROVIDER, &ResourceBuf);
  1285. BufHead = CurrBuf = OldBuf = NULL;
  1286. status = EnumBufferBuild(&BufHead, &NumBufs, ResourceBuf);
  1287. if (!status) {
  1288. // We have 0 to xxx Enum recs each with a buffer sitting off of it. Now
  1289. // need to consolidate these into one global enum list...
  1290. if (NumBufs) {
  1291. CurrBuf = BufHead;
  1292. // Figure out how many total entries there are
  1293. while (CurrBuf) {
  1294. TotalEntries += CurrBuf->cEntries;
  1295. CurrBuf = CurrBuf->next;
  1296. }
  1297. CurrBuf = BufHead;
  1298. // Now create a Server List to hold all of these.
  1299. ServList = AllocMemory(sizeof(SERVER_BROWSE_LIST) + TotalEntries * sizeof(SERVER_BROWSE_BUFFER));
  1300. if (ServList == NULL) {
  1301. status = ERROR_NOT_ENOUGH_MEMORY;
  1302. } else {
  1303. ServList->Count = TotalEntries;
  1304. SList = (SERVER_BROWSE_BUFFER *) &ServList->SList;
  1305. j = 0;
  1306. // Now loop through copying the data...
  1307. while (CurrBuf) {
  1308. for(i = 0; i < CurrBuf->cEntries; i++) {
  1309. if (CurrBuf->lpnr[i].lpRemoteName != NULL)
  1310. if (CurrBuf->lpnr[i].lpRemoteName[0] == TEXT('\\') && CurrBuf->lpnr[i].lpRemoteName[1] == TEXT('\\'))
  1311. lstrcpy(SList[j].Name, &CurrBuf->lpnr[i].lpRemoteName[2]);
  1312. else
  1313. lstrcpy(SList[j].Name, CurrBuf->lpnr[i].lpRemoteName);
  1314. else
  1315. lstrcpy(SList[j].Name, TEXT(""));
  1316. if (CurrBuf->lpnr[i].lpComment != NULL)
  1317. lstrcpy(SList[j].Description, CurrBuf->lpnr[i].lpComment);
  1318. else
  1319. lstrcpy(SList[j].Description, TEXT(""));
  1320. SList[j].Container = FALSE;
  1321. j++;
  1322. }
  1323. OldBuf = CurrBuf;
  1324. CurrBuf = CurrBuf->next;
  1325. // Free the old buffer
  1326. FreeMemory((HGLOBAL) OldBuf);
  1327. } // while
  1328. } // else (ServList)
  1329. } // if (numbufs)
  1330. }
  1331. *lpServList = ServList;
  1332. return status;
  1333. } // NWServerEnum
  1334. /////////////////////////////////////////////////////////////////////////
  1335. ULONG
  1336. NWShareSizeGet(
  1337. LPTSTR Share
  1338. )
  1339. /*++
  1340. Routine Description:
  1341. Arguments:
  1342. Return Value:
  1343. --*/
  1344. {
  1345. static TCHAR RootPath[MAX_PATH + 1];
  1346. DWORD sectorsPC, bytesPS, FreeClusters, Clusters;
  1347. DWORD TotalSpace, FreeSpace;
  1348. TotalSpace = FreeSpace = 0;
  1349. wsprintf(RootPath, TEXT("\\\\%s\\%s\\"), CachedServer, Share);
  1350. if (GetDiskFreeSpace(RootPath, &sectorsPC, &bytesPS, &FreeClusters, &Clusters)) {
  1351. TotalSpace = Clusters * sectorsPC * bytesPS;
  1352. FreeSpace = FreeClusters * sectorsPC * bytesPS;
  1353. }
  1354. // total - free = approx allocated space (if multiple shares on drive then
  1355. // this doesn't take that into account, we just want an approximation...
  1356. return TotalSpace - FreeSpace;
  1357. } // NWShareSizeGet
  1358. /////////////////////////////////////////////////////////////////////////
  1359. DWORD
  1360. NWSharesEnum(
  1361. SHARE_LIST **lpShares
  1362. )
  1363. /*++
  1364. Routine Description:
  1365. Arguments:
  1366. Return Value:
  1367. --*/
  1368. {
  1369. int NumBufs = 0;
  1370. DWORD TotalEntries = 0;
  1371. ENUM_REC *BufHead, *CurrBuf, *OldBuf;
  1372. SHARE_LIST *ShareList = NULL;
  1373. SHARE_BUFFER *SList = NULL;
  1374. DWORD status;
  1375. DWORD i, j;
  1376. NETRESOURCE ResourceBuf;
  1377. // Setup NETRESOURCE data structure
  1378. SetProvider(NW_PROVIDER, &ResourceBuf);
  1379. ResourceBuf.lpRemoteName = CachedServer;
  1380. ResourceBuf.dwUsage = RESOURCEUSAGE_CONTAINER;
  1381. status = EnumBufferBuild(&BufHead, &NumBufs, ResourceBuf);
  1382. if (!status) {
  1383. // We have 0 to xxx Enum recs each with a buffer sitting off of it. Now
  1384. // need to consolidate these into one global enum list...
  1385. if (NumBufs) {
  1386. CurrBuf = BufHead;
  1387. // Figure out how many total entries there are
  1388. while (CurrBuf) {
  1389. TotalEntries += CurrBuf->cEntries;
  1390. CurrBuf = CurrBuf->next;
  1391. }
  1392. CurrBuf = BufHead;
  1393. // Now create a Server List to hold all of these.
  1394. ShareList = (SHARE_LIST *) AllocMemory(sizeof(SHARE_LIST) + (TotalEntries * sizeof(SHARE_BUFFER)));
  1395. if (ShareList == NULL) {
  1396. status = ERROR_NOT_ENOUGH_MEMORY;
  1397. } else {
  1398. j = 0;
  1399. // Zero out everything and get pointer to list
  1400. memset(ShareList, 0, sizeof(SHARE_LIST) + (TotalEntries * sizeof(SHARE_BUFFER)));
  1401. ShareList->Count = TotalEntries;
  1402. SList = (SHARE_BUFFER *) &ShareList->SList;
  1403. // Now loop through copying the data...
  1404. while (CurrBuf) {
  1405. for(i = 0; i < CurrBuf->cEntries; i++) {
  1406. if (CurrBuf->lpnr[i].lpRemoteName != NULL)
  1407. lstrcpy(SList[j].Name, ShareNameParse(CurrBuf->lpnr[i].lpRemoteName));
  1408. else
  1409. lstrcpy(SList[j].Name, TEXT(""));
  1410. SList[j].Size = NWShareSizeGet(SList[j].Name);
  1411. SList[j].Index = (USHORT) j;
  1412. j++;
  1413. }
  1414. OldBuf = CurrBuf;
  1415. CurrBuf = CurrBuf->next;
  1416. // Free the old buffer
  1417. FreeMemory((HGLOBAL) OldBuf);
  1418. } // while
  1419. } // else (ShareList)
  1420. } // if (numbufs)
  1421. }
  1422. *lpShares = ShareList;
  1423. return status;
  1424. } // NWSharesEnum
  1425. /////////////////////////////////////////////////////////////////////////
  1426. VOID
  1427. NWServerInfoReset(
  1428. SOURCE_SERVER_BUFFER *SServ
  1429. )
  1430. /*++
  1431. Routine Description:
  1432. Arguments:
  1433. Return Value:
  1434. --*/
  1435. {
  1436. static VERSION_INFO NWInfo;
  1437. NWCCODE ret = 0;
  1438. ret = NWGetFileServerVersionInfo(CachedConn, &NWInfo);
  1439. // BUGBUG: This API returns fail (8801) - but is actually succeding,
  1440. // just ignore error for right now as it really doesn't matter for the
  1441. // version info.
  1442. // if (ret == SUCCESSFUL) {
  1443. SServ->VerMaj = NWInfo.Version;
  1444. SServ->VerMin = NWInfo.SubVersion;
  1445. // }
  1446. } // NWServerInfoReset
  1447. /////////////////////////////////////////////////////////////////////////
  1448. VOID
  1449. NWServerInfoSet(
  1450. LPTSTR ServerName,
  1451. SOURCE_SERVER_BUFFER *SServ
  1452. )
  1453. /*++
  1454. Routine Description:
  1455. Arguments:
  1456. Return Value:
  1457. --*/
  1458. {
  1459. static VERSION_INFO NWInfo;
  1460. NWCCODE ret = 0;
  1461. CursorHourGlass();
  1462. lstrcpy(SServ->Name, ServerName);
  1463. NWServerInfoReset(SServ);
  1464. // Fill in share list
  1465. NWSharesEnum(&SServ->ShareList);
  1466. #ifdef DEBUG
  1467. {
  1468. DWORD i;
  1469. dprintf(TEXT("Adding NW Server: %s\n"), SServ->Name);
  1470. dprintf(TEXT(" Version: %u.%u\n"), (UINT) SServ->VerMaj, (UINT) SServ->VerMin);
  1471. dprintf(TEXT(" Shares\n"));
  1472. dprintf(TEXT(" +---------------------------------------+\n"));
  1473. if (SServ->ShareList) {
  1474. for (i = 0; i < SServ->ShareList->Count; i++) {
  1475. dprintf(TEXT(" %-15s AllocSpace %lu\n"), SServ->ShareList->SList[i].Name, SServ->ShareList->SList[i].Size);
  1476. }
  1477. }
  1478. else
  1479. dprintf(TEXT(" <Serv List enum failed!!>\n"));
  1480. dprintf(TEXT("\n"));
  1481. }
  1482. #endif
  1483. CursorNormal();
  1484. } // NWServerInfoSet
  1485. /////////////////////////////////////////////////////////////////////////
  1486. BOOL
  1487. NWServerValidate(
  1488. HWND hWnd,
  1489. LPTSTR ServerName,
  1490. BOOL DupFlag
  1491. )
  1492. /*++
  1493. Routine Description:
  1494. Validates a given server - makes sure it can be connected to and
  1495. that the user has admin privs on it.
  1496. Arguments:
  1497. Return Value:
  1498. --*/
  1499. {
  1500. DWORD Status;
  1501. BOOL ret = FALSE;
  1502. SOURCE_SERVER_BUFFER *SServ = NULL;
  1503. DWORD dwObjectID = 0;
  1504. DWORD Size;
  1505. BYTE AccessLevel;
  1506. TCHAR UserName[MAX_USER_NAME_LEN + 1];
  1507. static TCHAR LocServer[MAX_SERVER_NAME_LEN+3];
  1508. LPVOID lpMessageBuffer;
  1509. CursorHourGlass();
  1510. if (DupFlag)
  1511. SServ = SServListFind(ServerName);
  1512. if (SServ == NULL) {
  1513. // Get Current Logged On User
  1514. lstrcpy(UserName, TEXT(""));
  1515. Size = sizeof(UserName);
  1516. WNetGetUser(NULL, UserName, &Size);
  1517. lstrcpy(LocServer, TEXT("\\\\"));
  1518. lstrcat(LocServer, ServerName);
  1519. if (UseAddPswd(hWnd, UserName, LocServer, Lids(IDS_S_6), NW_PROVIDER)) {
  1520. Status = NWServerSet(ServerName);
  1521. if (Status) {
  1522. if (GetLastError() != 0)
  1523. WarningError(Lids(IDS_NWCANT_CON), ServerName);
  1524. } else {
  1525. if (IsNCPServerFPNW(CachedConn))
  1526. WarningError(Lids(IDS_E_18), ServerName);
  1527. else {
  1528. Status = NWCGetBinderyAccessLevel(CachedConn, &AccessLevel, &dwObjectID);
  1529. if (!Status) {
  1530. AccessLevel &= BS_SUPER_READ;
  1531. if (AccessLevel == BS_SUPER_READ)
  1532. ret = TRUE;
  1533. else
  1534. WarningError(Lids(IDS_NWNO_ADMIN), ServerName);
  1535. }
  1536. }
  1537. }
  1538. } else {
  1539. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  1540. NULL, GetLastError(), 0,
  1541. (LPTSTR) &lpMessageBuffer, 0, NULL );
  1542. if (GetLastError() != 0)
  1543. WarningError(Lids(IDS_E_9), ServerName, lpMessageBuffer);
  1544. LocalFree(lpMessageBuffer);
  1545. }
  1546. } else {
  1547. // Already in source server list - can't appear more then once
  1548. WarningError(Lids(IDS_E_14), ServerName);
  1549. }
  1550. CursorNormal();
  1551. return ret;
  1552. } // NWServerValidate
  1553. /////////////////////////////////////////////////////////////////////////
  1554. LPTSTR
  1555. NWRightsLog(
  1556. DWORD Rights
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. Arguments:
  1561. Return Value:
  1562. --*/
  1563. {
  1564. static TCHAR NWRights[15];
  1565. lstrcpy(NWRights, Lids(IDS_S_34));
  1566. // Read
  1567. if (!(Rights & 0x01))
  1568. NWRights[2] = TEXT(' ');
  1569. // Write
  1570. if (!(Rights & 0x02))
  1571. NWRights[3] = TEXT(' ');
  1572. // Create
  1573. if (!(Rights & 0x08))
  1574. NWRights[4] = TEXT(' ');
  1575. // Delete (Erase)
  1576. if (!(Rights & 0x10))
  1577. NWRights[5] = TEXT(' ');
  1578. // Parental
  1579. if (!(Rights & 0x20))
  1580. NWRights[8] = TEXT(' ');
  1581. // Search
  1582. if (!(Rights & 0x40))
  1583. NWRights[7] = TEXT(' ');
  1584. // Modify
  1585. if (!(Rights & 0x80))
  1586. NWRights[6] = TEXT(' ');
  1587. // Supervisor (all rights set)
  1588. if ((Rights & 0xFB) != 0xFB)
  1589. NWRights[1] = TEXT(' ');
  1590. return NWRights;
  1591. } // NWRightsLog
  1592. /////////////////////////////////////////////////////////////////////////
  1593. NTSTATUS
  1594. MapNwRightsToNTAccess(
  1595. ULONG NWRights,
  1596. PRIGHTS_MAPPING pMap,
  1597. ACCESS_MASK *pAccessMask
  1598. )
  1599. /*++
  1600. Routine Description:
  1601. Map a NW Right to the appropriate NT AccessMask
  1602. Arguments:
  1603. NWRights - Netware rights we wish to map
  1604. pMap - pointer to structure that defines the mapping
  1605. Return Value:
  1606. The NT AccessMask corresponding to the NW Rights
  1607. --*/
  1608. {
  1609. PNW_TO_NT_MAPPING pNWToNtMap = pMap->Nw2NtMapping ;
  1610. ACCESS_MASK AccessMask = 0 ;
  1611. if (!pAccessMask)
  1612. return STATUS_INVALID_PARAMETER ;
  1613. *pAccessMask = 0x0 ;
  1614. // go thru the mapping structuring, OR-ing in bits along the way
  1615. while (pNWToNtMap->NWRight) {
  1616. if (pNWToNtMap->NWRight & NWRights)
  1617. AccessMask |= pNWToNtMap->NTAccess ;
  1618. pNWToNtMap++ ;
  1619. }
  1620. *pAccessMask = AccessMask ;
  1621. return STATUS_SUCCESS ;
  1622. } // MapNwRightsToNTAccess
  1623. /////////////////////////////////////////////////////////////////////////
  1624. DWORD
  1625. NWPrintServersEnum(
  1626. PRINT_SERVER_LIST **PS
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. Arguments:
  1631. Return Value:
  1632. --*/
  1633. {
  1634. PRINT_SERVER_LIST *psl;
  1635. PRINT_SERVER_BUFFER *pbuff;
  1636. DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
  1637. DWORD Count = 0;
  1638. DWORD status = 0;
  1639. char szAnsiPrinterName[MAX_USER_NAME_LEN + 1];
  1640. TCHAR szPrinterName[MAX_USER_NAME_LEN + 1];
  1641. WORD wFoundUserType = 0;
  1642. DWORD dwObjectID = 0xFFFFFFFFL;
  1643. BYTE byPropertiesFlag = 0;
  1644. BYTE byObjectFlag = 0;
  1645. BYTE byObjectSecurity = 0;
  1646. NWCCODE ret;
  1647. psl = (PRINT_SERVER_LIST *) AllocMemory(sizeof(PRINT_SERVER_LIST) + (NumRecs * sizeof(PRINT_SERVER_BUFFER)));
  1648. if (!psl) {
  1649. status = ERROR_NOT_ENOUGH_MEMORY;
  1650. } else {
  1651. pbuff = psl->PSList;
  1652. // init to NULL so doesn't have garbage if call fails
  1653. lstrcpyA(szAnsiPrinterName, "");
  1654. // Loop through bindery getting all the users.
  1655. while ((ret = NWScanObject(CachedConn, "*", OT_PRINT_SERVER, &dwObjectID, szAnsiPrinterName,
  1656. &wFoundUserType, &byPropertiesFlag,
  1657. &byObjectFlag, &byObjectSecurity)) == SUCCESSFUL) {
  1658. // Got user - now convert and save off the information
  1659. OemToChar(szAnsiPrinterName, szPrinterName);
  1660. lstrcpy(pbuff[Count].Name, szPrinterName);
  1661. Count++;
  1662. // Check if we have to re-allocate buffer
  1663. if (Count >= NumRecs) {
  1664. NumRecs += DEF_NUM_RECS;
  1665. psl = (PRINT_SERVER_LIST *) ReallocMemory((HGLOBAL) psl, sizeof(PRINT_SERVER_LIST) + (NumRecs * sizeof(PRINT_SERVER_BUFFER)));
  1666. pbuff = psl->PSList;
  1667. if (!psl) {
  1668. status = ERROR_NOT_ENOUGH_MEMORY;
  1669. break;
  1670. }
  1671. }
  1672. }
  1673. // Gotta clear this out from the last loop
  1674. if (Count)
  1675. ret = 0;
  1676. }
  1677. // check if error occured...
  1678. if (ret)
  1679. status = ret;
  1680. // Now slim down the list to just what we need.
  1681. if (!status) {
  1682. psl = (PRINT_SERVER_LIST *) ReallocMemory((HGLOBAL) psl, sizeof(PRINT_SERVER_LIST) + (Count * sizeof(PRINT_SERVER_BUFFER)));
  1683. if (!psl)
  1684. status = ERROR_NOT_ENOUGH_MEMORY;
  1685. }
  1686. psl->Count = Count;
  1687. *PS = psl;
  1688. return status;
  1689. } // NWPrintServersEnum
  1690. /////////////////////////////////////////////////////////////////////////
  1691. DWORD
  1692. NWPrintOpsEnum(
  1693. USER_LIST **lpUsers
  1694. )
  1695. /*++
  1696. Routine Description:
  1697. First need to enumerate all the print servers on the NetWare system
  1698. we are pointing to. Next loop through each of these print servers
  1699. and enumerate the print operators on each of them.
  1700. Arguments:
  1701. Return Value:
  1702. --*/
  1703. {
  1704. PRINT_SERVER_LIST *psl = NULL;
  1705. PRINT_SERVER_BUFFER *PSList;
  1706. ULONG pCount;
  1707. USER_LIST *Users = NULL;
  1708. USER_BUFFER *UserBuffer;
  1709. DWORD NumRecs = DEF_NUM_RECS; // Default 200 names
  1710. DWORD Count = 0;
  1711. DWORD ipsl = 0, iseg = 0;
  1712. DWORD status = 0;
  1713. char szAnsiUserName[MAX_USER_NAME_LEN + 1];
  1714. char szAnsiName[MAX_GROUP_NAME_LEN + 1];
  1715. TCHAR szUserName[MAX_USER_NAME_LEN + 1];
  1716. WORD wFoundUserType = 0;
  1717. DWORD dwObjectID = 0xFFFFFFFFL;
  1718. BYTE byPropertyFlags = 0;
  1719. BYTE byObjectFlag = 0;
  1720. BYTE byObjectSecurity = 0;
  1721. UCHAR Segment = 1;
  1722. DWORD bySegment[32];
  1723. BYTE byMoreSegments;
  1724. NWCCODE ret;
  1725. *lpUsers = NULL;
  1726. // Enumerate the print servers - if there are none, then there are no printer ops
  1727. NWPrintServersEnum(&psl);
  1728. if ((psl == NULL) || (psl->Count == 0)) {
  1729. if (psl != NULL)
  1730. FreeMemory(psl);
  1731. return 0;
  1732. }
  1733. // Got some servers - loop through them enumerating users
  1734. Users = (USER_LIST *) AllocMemory(sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
  1735. if (!Users) {
  1736. status = ERROR_NOT_ENOUGH_MEMORY;
  1737. } else {
  1738. UserBuffer = Users->UserBuffer;
  1739. PSList = psl->PSList;
  1740. for (pCount = 0; pCount < psl->Count; pCount++) {
  1741. // init to NULL so doesn't have garbage if call fails
  1742. lstrcpyA(szAnsiUserName, "");
  1743. CharToOem(PSList[ipsl++].Name, szAnsiName);
  1744. // Loop through bindery getting all the users.
  1745. do {
  1746. if (!(ret = NWReadPropertyValue(CachedConn, szAnsiName, OT_PRINT_SERVER, PS_OPERATORS,
  1747. Segment, (BYTE *) bySegment, &byMoreSegments, &byPropertyFlags))) {
  1748. Segment++;
  1749. // loop through properties converting them to user names
  1750. iseg = 0;
  1751. while ((bySegment[iseg]) && (iseg < 32)) {
  1752. if (!(ret = NWGetObjectName(CachedConn, bySegment[iseg], szAnsiUserName, &wFoundUserType))) {
  1753. // Got user - now convert and save off the information
  1754. OemToChar(szAnsiUserName, szUserName);
  1755. // Map out Supervisor (already print-op privs)
  1756. if (lstrcmpi(szUserName, Lids(IDS_S_28))) {
  1757. lstrcpy(UserBuffer[Count].Name, szUserName);
  1758. lstrcpy(UserBuffer[Count].NewName, szUserName);
  1759. Count++;
  1760. }
  1761. // Check if we have to re-allocate buffer
  1762. if (Count >= NumRecs) {
  1763. NumRecs += DEF_NUM_RECS;
  1764. Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * NumRecs));
  1765. if (!Users) {
  1766. status = ERROR_NOT_ENOUGH_MEMORY;
  1767. break;
  1768. }
  1769. UserBuffer = Users->UserBuffer;
  1770. }
  1771. }
  1772. iseg++;
  1773. }
  1774. } else // if NWReadPropertyValue
  1775. byMoreSegments = 0;
  1776. } while (byMoreSegments);
  1777. // Gotta clear this out from the last loop
  1778. if (Count)
  1779. ret = 0;
  1780. }
  1781. }
  1782. // check if error occured...
  1783. if (ret)
  1784. status = ret;
  1785. // Now slim down the list to just what we need.
  1786. if (!status) {
  1787. Users = (USER_LIST *) ReallocMemory((HGLOBAL) Users, sizeof(USER_LIST) + (sizeof(USER_BUFFER) * Count));
  1788. if (!Users)
  1789. status = ERROR_NOT_ENOUGH_MEMORY;
  1790. else {
  1791. // Sort the server list before putting it in the dialog
  1792. UserBuffer = Users->UserBuffer;
  1793. qsort((void *) UserBuffer, (size_t) Count, sizeof(USER_BUFFER), UserListCompare);
  1794. }
  1795. }
  1796. Users->Count = Count;
  1797. *lpUsers = Users;
  1798. return status;
  1799. } // NWPrintOpsEnum
  1800. /////////////////////////////////////////////////////////////////////////
  1801. VOID
  1802. NWServerTimeGet(
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. Queries server for it's current local time which is then converted to
  1807. elasped minutes since 1985 in order to compare with the lNextResetTime
  1808. field of the LOGIN_CONTROL structure (which must be byte-aligned).
  1809. Arguments:
  1810. None.
  1811. Return Value:
  1812. None.
  1813. --*/
  1814. {
  1815. DWORD dwYear = 0;
  1816. DWORD dwMonth = 0;
  1817. DWORD dwDay = 0;
  1818. DWORD dwHour = 0;
  1819. DWORD dwMinute = 0;
  1820. DWORD dwSecond = 0;
  1821. DWORD dwDayOfWeek = 0;
  1822. DWORD dwServerTime = 0;
  1823. CachedServerTime = 0xffffffff; // re-initialize...
  1824. if (!NWGetFileServerDateAndTime(
  1825. CachedConn,
  1826. (LPBYTE)&dwYear,
  1827. (LPBYTE)&dwMonth,
  1828. (LPBYTE)&dwDay,
  1829. (LPBYTE)&dwHour,
  1830. (LPBYTE)&dwMinute,
  1831. (LPBYTE)&dwSecond,
  1832. (LPBYTE)&dwDayOfWeek))
  1833. {
  1834. if (NWTimeMap(dwDay, dwMonth, dwYear, 1985, &dwServerTime))
  1835. {
  1836. dwServerTime += dwHour * 3600;
  1837. dwServerTime += dwMinute * 60;
  1838. dwServerTime += dwSecond;
  1839. CachedServerTime = dwServerTime / 60; // convert to minutes...
  1840. }
  1841. }
  1842. }
  1843. /////////////////////////////////////////////////////////////////////////
  1844. BOOL
  1845. IsNCPServerFPNW(
  1846. NWCONN_HANDLE Conn
  1847. )
  1848. /*++
  1849. Routine Description:
  1850. Check if this an FPNW server by checking for a specific object
  1851. type and property.
  1852. Arguments:
  1853. Conn - connection id of ncp server.
  1854. Return Value:
  1855. Returns true if ncp server is fpnw.
  1856. --*/
  1857. {
  1858. NWCCODE ret;
  1859. BYTE bySegment[128];
  1860. BYTE byMoreSegments, byPropertyFlags;
  1861. memset(bySegment, 0, sizeof(bySegment));
  1862. ret = NWReadPropertyValue(
  1863. CachedConn,
  1864. MS_EXTENDED_NCPS,
  1865. 0x3B06,
  1866. FPNW_PDC,
  1867. 1,
  1868. bySegment,
  1869. &byMoreSegments,
  1870. &byPropertyFlags
  1871. );
  1872. return (ret == SUCCESSFUL) && (BOOL)(BYTE)bySegment[0];
  1873. }