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.

525 lines
15 KiB

  1. #include "pch.h"
  2. #include "sysmigp.h"
  3. // Win95-specific (in the SDK)
  4. #include <svrapi.h>
  5. //
  6. // Types for LAN Man structs
  7. //
  8. typedef struct access_info_2 ACCESS_INFO_2;
  9. typedef struct access_list_2 ACCESS_LIST_2;
  10. typedef struct share_info_50 SHARE_INFO_50;
  11. //
  12. // Flags that help determine when custom access is enabled
  13. //
  14. #define READ_ACCESS_FLAGS 0x0081
  15. #define READ_ACCESS_MASK 0x7fff
  16. #define FULL_ACCESS_FLAGS 0x00b7
  17. #define FULL_ACCESS_MASK 0x7fff
  18. //
  19. // Types for dynamically loading SVRAPI.DLL
  20. //
  21. typedef DWORD(NETSHAREENUM_PROTOTYPE)(
  22. const char FAR * pszServer,
  23. short sLevel,
  24. char FAR * pbBuffer,
  25. unsigned short cbBuffer,
  26. unsigned short FAR * pcEntriesRead,
  27. unsigned short FAR * pcTotalAvail
  28. );
  29. typedef NETSHAREENUM_PROTOTYPE * NETSHAREENUM_PROC;
  30. typedef DWORD(NETACCESSENUM_PROTOTYPE)(
  31. const char FAR * pszServer,
  32. char FAR * pszBasePath,
  33. short fsRecursive,
  34. short sLevel,
  35. char FAR * pbBuffer,
  36. unsigned short cbBuffer,
  37. unsigned short FAR * pcEntriesRead,
  38. unsigned short FAR * pcTotalAvail
  39. );
  40. typedef NETACCESSENUM_PROTOTYPE * NETACCESSENUM_PROC;
  41. HANDLE g_SvrApiDll;
  42. NETSHAREENUM_PROC pNetShareEnum;
  43. NETACCESSENUM_PROC pNetAccessEnum;
  44. BOOL
  45. pLoadSvrApiDll (
  46. VOID
  47. )
  48. /*++
  49. Routine Description:
  50. Loads up svrapi.dll if it exsits and obtains the entry points for
  51. NetShareEnum and NetAccessEnum.
  52. Arguments:
  53. none
  54. Return value:
  55. TRUE if the DLL was loaded, or FALSE if the DLL could not be loaded
  56. for any reason.
  57. --*/
  58. {
  59. BOOL b;
  60. g_SvrApiDll = LoadLibrary (S_SVRAPI_DLL);
  61. if (!g_SvrApiDll) {
  62. return FALSE;
  63. }
  64. pNetShareEnum = (NETSHAREENUM_PROC) GetProcAddress (g_SvrApiDll, S_ANSI_NETSHAREENUM);
  65. pNetAccessEnum = (NETACCESSENUM_PROC) GetProcAddress (g_SvrApiDll, S_ANSI_NETACCESSENUM);
  66. b = (pNetShareEnum != NULL) && (pNetAccessEnum != NULL);
  67. if (!b) {
  68. FreeLibrary (g_SvrApiDll);
  69. g_SvrApiDll = NULL;
  70. }
  71. return b;
  72. }
  73. VOID
  74. pFreeSvrApiDll (
  75. VOID
  76. )
  77. {
  78. if (g_SvrApiDll) {
  79. FreeLibrary (g_SvrApiDll);
  80. g_SvrApiDll = NULL;
  81. }
  82. }
  83. VOID
  84. pAddIncompatibilityAlert (
  85. DWORD MessageId,
  86. PCTSTR Share,
  87. PCTSTR Path
  88. )
  89. {
  90. PCTSTR Group;
  91. PCTSTR Warning;
  92. PCTSTR Args[2];
  93. PCTSTR Object;
  94. Args[0] = Share;
  95. Args[1] = Path;
  96. Warning = ParseMessageID (MessageId, Args);
  97. Group = BuildMessageGroup (MSG_INSTALL_NOTES_ROOT, MSG_NET_SHARES_SUBGROUP, Share);
  98. Object = JoinPaths (TEXT("*SHARES"), Share);
  99. MYASSERT (Warning);
  100. MYASSERT (Group);
  101. MYASSERT (Object);
  102. MsgMgr_ObjectMsg_Add (Object, Group, Warning);
  103. FreeStringResource (Warning);
  104. FreeText (Group);
  105. FreePathString (Object);
  106. }
  107. DWORD
  108. pSaveShares (
  109. VOID
  110. )
  111. /*++
  112. Routine Description:
  113. Enumerates all shares on the machine and saves them to MemDb.
  114. In password-access mode, the shares are preserved but the passwords
  115. are not. An incompatibility message is generated if a password is
  116. lost.
  117. In user-level-access mode, the shares are preserved and the name of
  118. each user who has permission to the share is written to memdb. If
  119. the user has custom access permission flags, an incompatibility
  120. message is generated, and the user gets the least restrictive
  121. security that matches the custom access flags.
  122. Arguments:
  123. none
  124. Return value:
  125. TRUE if the shares were enumerated successfully, or FALSE if a failure
  126. occurs from a Net API.
  127. --*/
  128. {
  129. CHAR Buf[16384]; // static because NetShareEnum is unreliable
  130. SHARE_INFO_50 *psi;
  131. DWORD rc = ERROR_SUCCESS;
  132. WORD wEntriesRead;
  133. WORD wEntriesAvailable;
  134. WORD Flags;
  135. TCHAR MemDbKey[MEMDB_MAX];
  136. BOOL LostCustomAccess = FALSE;
  137. MBCHAR ch;
  138. PCSTR ntPath;
  139. BOOL skip;
  140. if (!pLoadSvrApiDll()) {
  141. DEBUGMSG ((DBG_WARNING, "SvrApi.Dll was not loaded. Net shares are not preserved."));
  142. return ERROR_SUCCESS;
  143. }
  144. __try {
  145. rc = pNetShareEnum (NULL,
  146. 50,
  147. Buf,
  148. sizeof (Buf),
  149. &wEntriesRead,
  150. &wEntriesAvailable
  151. );
  152. if (rc != ERROR_SUCCESS) {
  153. if (rc == NERR_ServerNotStarted) {
  154. rc = ERROR_SUCCESS;
  155. __leave;
  156. }
  157. LOG ((LOG_ERROR, "Failure while enumerating network shares."));
  158. __leave;
  159. }
  160. if (wEntriesAvailable != 0 && wEntriesRead != wEntriesAvailable) {
  161. LOG ((
  162. LOG_ERROR,
  163. "Could not read all available shares! Available: %d, Read: %d",
  164. wEntriesAvailable,
  165. wEntriesRead
  166. ));
  167. }
  168. while (wEntriesRead) {
  169. wEntriesRead--;
  170. psi = (SHARE_INFO_50 *) Buf;
  171. psi = &psi[wEntriesRead];
  172. DEBUGMSG ((DBG_NAUSEA, "Processing share %s (%s)", psi->shi50_netname, psi->shi50_path));
  173. // Require share to be a user-defined, persistent disk share
  174. if ((psi->shi50_flags & SHI50F_SYSTEM) ||
  175. !(psi->shi50_flags & SHI50F_PERSIST) ||
  176. (psi->shi50_type != STYPE_DISKTREE &&
  177. psi->shi50_type != STYPE_PRINTQ)
  178. ) {
  179. continue;
  180. }
  181. //
  182. // Verify folder will not be in %windir% on NT
  183. //
  184. ntPath = GetPathStringOnNt (psi->shi50_path);
  185. if (!ntPath) {
  186. MYASSERT (FALSE);
  187. continue;
  188. }
  189. skip = FALSE;
  190. if (StringIPrefix (ntPath, g_WinDir)) {
  191. ch = _mbsnextc (ntPath + g_WinDirWackChars - 1);
  192. if (ch == 0 || ch == '\\') {
  193. DEBUGMSG ((DBG_VERBOSE, "Skipping share %s because it is in %%windir%%", psi->shi50_netname));
  194. skip = TRUE;
  195. }
  196. }
  197. FreePathString (ntPath);
  198. if (skip) {
  199. continue;
  200. }
  201. //
  202. // Process passwords
  203. //
  204. if (!(psi->shi50_flags & SHI50F_ACLS)) {
  205. //
  206. // Skip if passwords are specified
  207. //
  208. if (psi->shi50_rw_password[0] && psi->shi50_ro_password[0]) {
  209. LOG ((LOG_WARNING, "Skipping share %s because it is guarded by share-level passwords", psi->shi50_netname));
  210. continue;
  211. }
  212. if (psi->shi50_rw_password[0] &&
  213. (psi->shi50_flags & SHI50F_ACCESSMASK) == SHI50F_FULL
  214. ) {
  215. LOG ((LOG_WARNING, "Skipping full access share %s because it is guarded by a password", psi->shi50_netname));
  216. continue;
  217. }
  218. if (psi->shi50_ro_password[0] &&
  219. (psi->shi50_flags & SHI50F_ACCESSMASK) == SHI50F_RDONLY
  220. ) {
  221. LOG ((LOG_WARNING, "Skipping read-only share %s because it is guarded by a password", psi->shi50_netname));
  222. continue;
  223. }
  224. }
  225. //
  226. // Mark directory to be preserved, so we don't delete it if we remove other
  227. // things and make it empty.
  228. //
  229. MarkDirectoryAsPreserved (psi->shi50_path);
  230. //
  231. // Save the remark, path, type and access
  232. //
  233. MemDbSetValueEx (MEMDB_CATEGORY_NETSHARES, psi->shi50_netname,
  234. MEMDB_FIELD_REMARK, psi->shi50_remark,0,NULL);
  235. MemDbSetValueEx (MEMDB_CATEGORY_NETSHARES, psi->shi50_netname,
  236. MEMDB_FIELD_PATH, psi->shi50_path,0,NULL);
  237. MemDbSetValueEx (MEMDB_CATEGORY_NETSHARES, psi->shi50_netname,
  238. MEMDB_FIELD_TYPE, NULL, psi->shi50_type, NULL);
  239. if ((psi->shi50_flags & SHI50F_ACCESSMASK) == SHI50F_ACCESSMASK) {
  240. CHAR AccessInfoBuf[16384];
  241. WORD wItemsAvail, wItemsRead;
  242. ACCESS_INFO_2 *pai;
  243. ACCESS_LIST_2 *pal;
  244. //
  245. // Obtain entire access list and write it to memdb
  246. //
  247. rc = pNetAccessEnum (NULL,
  248. psi->shi50_path,
  249. 0,
  250. 2,
  251. AccessInfoBuf,
  252. sizeof (AccessInfoBuf),
  253. &wItemsRead,
  254. &wItemsAvail
  255. );
  256. //
  257. // If this call fails with not loaded, we have password-level
  258. // security (so we don't need to enumerate the ACLs).
  259. //
  260. if (rc != NERR_ACFNotLoaded) {
  261. if (rc != ERROR_SUCCESS) {
  262. //
  263. //
  264. //
  265. LOG ((LOG_ERROR, "Failure while enumerating network access for %s, rc=%u", psi->shi50_path, rc));
  266. pAddIncompatibilityAlert (
  267. MSG_INVALID_ACL_LIST,
  268. psi->shi50_netname,
  269. psi->shi50_path
  270. );
  271. } else {
  272. int i;
  273. if (wItemsAvail != wItemsRead) {
  274. LOG ((LOG_ERROR, "More access items are available than what can be listed."));
  275. }
  276. // An interesting characteristic!
  277. DEBUGMSG_IF ((wItemsRead != 1, DBG_WHOOPS, "Warning: wItemsRead == %u", wItemsRead));
  278. // Structure has one ACCESS_INFO_2 struct followed by one or more
  279. // ACCESS_LIST_2 structs
  280. pai = (ACCESS_INFO_2 *) AccessInfoBuf;
  281. pal = (ACCESS_LIST_2 *) (&pai[1]);
  282. for (i = 0 ; i < pai->acc2_count ; i++) {
  283. //
  284. // Add incompatibility messages for Custom access rights
  285. //
  286. DEBUGMSG ((DBG_NAUSEA, "Share %s, Access flags: %x",
  287. psi->shi50_netname, pal->acl2_access));
  288. Flags = pal->acl2_access & READ_ACCESS_FLAGS;
  289. if (Flags && Flags != READ_ACCESS_FLAGS) {
  290. LostCustomAccess = TRUE;
  291. }
  292. Flags = pal->acl2_access & FULL_ACCESS_FLAGS;
  293. if (Flags && Flags != FULL_ACCESS_FLAGS) {
  294. LostCustomAccess = TRUE;
  295. }
  296. //
  297. // Write NetShares\<share>\ACL\<user/group> to memdb,
  298. // using the 32-bit key value to hold the access flags.
  299. //
  300. wsprintf (MemDbKey, TEXT("%s\\%s\\%s\\%s"), MEMDB_CATEGORY_NETSHARES,
  301. psi->shi50_netname, MEMDB_FIELD_ACCESS_LIST, pal->acl2_ugname);
  302. MemDbSetValue (MemDbKey, pal->acl2_access);
  303. //
  304. // Write to KnownDomain\<user/group> unless the user or group
  305. // is an asterisk.
  306. //
  307. if (StringCompare (pal->acl2_ugname, TEXT("*"))) {
  308. MemDbSetValueEx (
  309. MEMDB_CATEGORY_KNOWNDOMAIN,
  310. pal->acl2_ugname,
  311. NULL,
  312. NULL,
  313. 0,
  314. NULL
  315. );
  316. }
  317. pal++;
  318. }
  319. psi->shi50_flags |= SHI50F_ACLS;
  320. }
  321. }
  322. }
  323. //
  324. // Write share flags (SHI50F_*)
  325. //
  326. wsprintf (MemDbKey, TEXT("%s\\%s"), MEMDB_CATEGORY_NETSHARES, psi->shi50_netname);
  327. if (!MemDbSetValue (MemDbKey, psi->shi50_flags)) {
  328. LOG ((LOG_ERROR, "Failure while saving share information to database."));
  329. }
  330. if (!(psi->shi50_flags & SHI50F_ACLS)) {
  331. //
  332. // Write password-level permissions
  333. //
  334. if (psi->shi50_rw_password[0]) {
  335. MemDbSetValueEx (MEMDB_CATEGORY_NETSHARES, psi->shi50_netname,
  336. MEMDB_FIELD_RW_PASSWORD, psi->shi50_rw_password,
  337. 0,NULL);
  338. }
  339. if (psi->shi50_ro_password[0]) {
  340. MemDbSetValueEx (MEMDB_CATEGORY_NETSHARES, psi->shi50_netname,
  341. MEMDB_FIELD_RO_PASSWORD, psi->shi50_ro_password,
  342. 0,NULL);
  343. }
  344. if (psi->shi50_ro_password[0] || psi->shi50_rw_password[0]) {
  345. pAddIncompatibilityAlert (
  346. MSG_LOST_SHARE_PASSWORDS,
  347. psi->shi50_netname,
  348. psi->shi50_path
  349. );
  350. }
  351. }
  352. if (LostCustomAccess) {
  353. LostCustomAccess = FALSE;
  354. pAddIncompatibilityAlert (
  355. MSG_LOST_ACCESS_FLAGS,
  356. psi->shi50_netname,
  357. psi->shi50_path
  358. );
  359. }
  360. rc = ERROR_SUCCESS;
  361. }
  362. }
  363. __finally {
  364. pFreeSvrApiDll();
  365. }
  366. return rc;
  367. }
  368. DWORD
  369. SaveShares (
  370. IN DWORD Request
  371. )
  372. {
  373. switch (Request) {
  374. case REQUEST_QUERYTICKS:
  375. return TICKS_SAVE_SHARES;
  376. case REQUEST_RUN:
  377. return pSaveShares ();
  378. default:
  379. DEBUGMSG ((DBG_ERROR, "Bad parameter in SaveShares"));
  380. }
  381. return 0;
  382. }
  383. VOID
  384. WkstaMig (
  385. VOID
  386. )
  387. /*++
  388. Routine Description:
  389. This routine provides a single location to add additional routines
  390. needed to perform workstation migration.
  391. Arguments:
  392. none
  393. Return value:
  394. none - Error path is not yet implemented.
  395. --*/
  396. {
  397. if (pSaveShares() != ERROR_SUCCESS) {
  398. DEBUGMSG ((DBG_WHOOPS, "SaveShares failed, error ignored."));
  399. }
  400. }