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.

431 lines
20 KiB

  1. This is a minimal description of this code, ntshrui.dll.
  2. What it is
  3. ----------
  4. This is a port/rewrite of the Win95 msshrui.dll (Win95 SLM source found in
  5. \\flipper\chinet\src\wnet\msshrui, Win96+ on \\trango\slm\...). It provides a
  6. "Sharing" property page for directories to allow local LanMan (SMB) shares
  7. to be created for the selected directory. It provides a "Sharing..."
  8. context menu to provide quick access to the "Sharing" property page.
  9. It also provides a "Sharing" copy hook to handle directory renames and
  10. move/deletes properly by warning the user about the shares that may
  11. be need to be deleted in the process (shares aren't recreated based
  12. on the directory's new name). Finally, there are a few API entrypoints
  13. for programs to perform Share operations.
  14. All of this functionality is dependent on being able to execute a NetShareEnum
  15. at level 502, which requires Administrators local group or comm, print,
  16. or server operator group membership. The APIs will fail and there will be no
  17. Sharing UI in the explorer if this is not true.
  18. One goal of the Win95 shell, carried forward to the NT shell, is to
  19. be completely independent of network-specific code. The shell will
  20. call WNet apis, which are network-independent. However, there are
  21. no network-independent share creation APIs. Thus, the shell consults
  22. the HKEY_CLASSES_ROOT\Network\SharingHandler key to determine the
  23. network-specific sharing handler DLL. Note that under Windows 95,
  24. only one server at a time was allowed to run. Under NT, multiple
  25. servers may run (SFM -- Macintosh, FPNW -- NetWare, SMB -- Windows
  26. Networking). However, the shell hasn't been expanded to handle this.
  27. The exported APIs are:
  28. DllGetClassObject
  29. DllCanUnloadNow
  30. IsPathSharedA
  31. IsPathSharedW
  32. IsPathShared = IsPathSharedA
  33. SharingDialogA
  34. SharingDialogW
  35. SharingDialog = SharingDialogA
  36. GetNetResourceFromLocalPathA
  37. GetNetResourceFromLocalPathW
  38. GetNetResourceFromLocalPath = GetNetResourceFromLocalPathA
  39. GetLocalPathFromNetResourceA
  40. GetLocalPathFromNetResourceW
  41. GetLocalPathFromNetResource = GetLocalPathFromNetResourceA
  42. There are A and W versions for all of these, even though there aren't
  43. clients for all versions of the API. Namely, the shell uses the W
  44. versions. However, the SharingDialog API is used only in its A version
  45. by the FAX group (they are the only known client). However, to avoid
  46. problems later, both A and W versions are implemented.
  47. There are two Windows 95 APIs not implmented:
  48. PrintShareProperties
  49. ShareShutdownNotify
  50. The implemented, exported APIs do the following:
  51. DllGetClassObject, DllCanUnloadNow -- standard OLE entrypoints. Used
  52. for the shell extensions (context-menu, property sheet, copy hook).
  53. IsPathShared -- returns TRUE if a path is shared. Used by the shell to
  54. determine when to put a "sharing" hand on a folder. Must be fast, as
  55. the shell calls it for every folder it displays.
  56. SharingDialog -- Displays the same dialog as the property sheet page, but
  57. in a modal dialog form. used by the FAX group.
  58. GetNetResourceFromLocalPath -- Given a local path on a machine, returns
  59. a UNC form of that path, if the path is shared. This is used to store
  60. a network-aware form of the path in a shortcut for use if the shortcut
  61. is copied to another machine, such that the local path stored in the
  62. shortcut isn't available.
  63. GetLocalPathFromNetResource -- The opposite of the above, it determines
  64. the local path of an object given a UNC path.
  65. The Sharing page
  66. ----------------
  67. The Sharing property page and context-menu shortcut should appear when the
  68. user right-clicks on anything that corresponds to a file system directory.
  69. This is basically a folder or a disk icon. The drive can be either a hard
  70. drive, a floppy, or a CD-ROM. We only support the page when the folder or
  71. drive is local: the page is not available when looking at remote folders
  72. either via a UNC path in the network neighborhood or via a mapped drive
  73. letter path.
  74. The Sharing page behaves as follows. If there are no shares, the "Not Shared"
  75. radio button is checked and everything inside the "Shared As" radio button box
  76. is grayed. Clicking "Shared As" ungrays the controls within its box.
  77. There are two "modes" when the "Shared As" button is checked: initial mode and
  78. already-shared mode. Initial mode is when the folder has not yet been shared.
  79. In this case, the "Share name" control is a single-line edit control. All the
  80. controls can be used to enter information for one new share. In
  81. "already-shared" mode, the folder already is shared with one or more names.
  82. In this case, the "Share name" control is a drop-down list box with a list of
  83. shares for this directory. The other controls are filled with the data
  84. associated with the share currently selected in the drop-down control. Changing
  85. the comment, user limit, or permissions at this point causes the selected
  86. share to be modified accordingly, but does not add a new share.
  87. Note that standard property sheet semantics hold with all the changes made to
  88. the sharing characteristics of the selected folder, namely, that no changes
  89. are actually made to the machine state until "OK" or "Apply" is chosen.
  90. In initial mode, only a single share can be created (unless you hit "apply"
  91. and subsequently change to "already-shared" mode). In already-shared mode,
  92. there are one or two additional buttons to control creating/deleting shares.
  93. The "New Share..." button will always be visible in this mode. Pressing it
  94. pops up a "New Share" modal dialog that allows you to create another share
  95. name for the same directory. This other share might have a different comment,
  96. different user limit, and most importantly, different permissions. The
  97. operation of the controls in this dialog are identical to the operation of
  98. the controls on the property sheet in "initial" mode. If there are two or
  99. more shares for the directory, then the "Remove Share" button is visible.
  100. Pressing this removes the currently selected share (pending "OK" or
  101. "Apply" of course).
  102. To delete the final share, or to delete all the shares at once, you must
  103. choose the "Not shared" radio button. If there is currently more than one
  104. share for the directory, this confirmation message is displayed:
  105. This folder is shared more than once. Are you sure you wish
  106. to remove all these shares?
  107. yes/no
  108. Hitting "no" causes the "Shared As" button to be clicked again. Hitting "yes"
  109. causes all shares to be marked for removal. However, the shares are still
  110. left in the property sheet, but grayed. If the "Shared As" button is pressed
  111. again, then it will be as if the "Not Shared" button was never pressed: all
  112. share properties are retained, and hitting "Apply" or "OK" will make all
  113. previously requested changes.
  114. A default share name is put in the "Share Name" SLE in "initial" mode, as
  115. follows. If the directory is not the root of the volume, for example,
  116. C:\foo\bar, then the default share name is the last component of the path,
  117. in this case, bar. If the directory is a root, then the default is the drive
  118. letter, in the previous example, C. However, if the default name is already
  119. used as a share name on the system, then there is no default given.
  120. The user limit controls work as follows. The "Allow" text box allows
  121. the user to enter a specific number of users. Only numbers are allowed to
  122. be typed: no letters or other characters. If the number is out of range,
  123. the number reverts to the default user limit (10) when the edit control loses
  124. focus. Note that no error message is given: we do this silently. Up and down
  125. arrows increase and decrease the number. Since we are using the Win95
  126. up/down control, the range for the number is 1 to 32767. The number doesn't
  127. wrap. If the user chooses "Maximum allowed" after having typed a number in
  128. the "allow" edit box, the edit box is cleared but the number is remembered.
  129. If the user subsequently clicks the "allow" radio button, the remembered
  130. number is reinserted into the edit control as the default.
  131. The Permissions button brings up the standard security (ACL) editor with
  132. the permissions of the share. The default permissions for a share are World
  133. access, Full control. As with everything else, the permissions aren't
  134. committed until the property page "OK" or "Apply" button is pressed.
  135. Note that hitting the escape key should cancel the property page no matter
  136. what the current keyboard focus is. I mention this because I've had problems
  137. getting this to work with the focus on the (subclassed) "Allow" edit control.
  138. If the user types a share name that is the same as another share for this same
  139. directory (in the "New Share" dialog), then the following warning message
  140. is displayed:
  141. The share name %1 already exists for this resource. Please
  142. choose another share name.
  143. If the user types a share name in the "New Share" dialog or on the property
  144. sheet (initial mode, and then hits "Apply" or "OK"), and that name is the same
  145. as another share on the machine for another path, then this message is
  146. displayed:
  147. You are already sharing %1 using the name %2. Do you want
  148. to share %3 using the name %2 instead?
  149. If the user hits "yes", then we use the new name as a new share, and put the
  150. other share on a list of "shares of the same name but different directories"
  151. to delete when the user hits "OK" or "Apply".
  152. The share names are validated as follows. If no share name is typed in you
  153. get this error:
  154. You must type a share name for this resource.
  155. If you use illegal characters in the share name (particularly *, but there may
  156. be others), you get this error:
  157. The share name contains invalid characters.
  158. If the name is not accessible from DOS, because it isn't 8.3 or for some other
  159. reason, you get this warning:
  160. The share name %1 is not accessible from some MS-DOS
  161. workstations. Are you sure you want to use the share name?
  162. Note that there is special handling code to allow users to create and delete
  163. the default disk shares, namely <drive>$ for each hard drive, and admin$. Only
  164. configuration of IPC$ is not supported, as it has no associated storage.
  165. These are handled specially as follows. Selecting one of them, getting the
  166. sharing property page, and pressing "Permissions" will pop up the message:
  167. This has been shared for administrative purposes.
  168. The permissions cannot be set.
  169. When the share name is being validated in the property page or "New Share"
  170. dialog, a check is made against "IPC$". If it matches, this message is
  171. displayed:
  172. The share names ADMIN$ and IPC$ are reserved and may not be used.
  173. Note that we mention ADMIN$ as a restricted share name, even though we allow
  174. its creation in one particular case. If they use the name "ADMIN$", we
  175. disallow it for all cases except if the selected directory is the Windows
  176. directory, since that is the only place ADMIN$ can share.
  177. We do allow the creation of <drive>$ shares at places besides the proper
  178. drive. I.e., we allow you to share D:\ as C$. If, however, you share C:\ as
  179. C$, it gains special "default" status, any permissions you may have edited are
  180. discarded (silently) and the default permissions are instantiated.
  181. Applying changes
  182. ----------------
  183. When the user hits "OK" or "Apply" the following things occur. First, the
  184. list of shares with the same name as new shares but with different directories
  185. is deleted. Second, all share changes for the current directory are applied:
  186. either added, deleted, or modified. The following error messages may occur
  187. if we get a network error. For add:
  188. An error occurred while trying to share %1. %2
  189. The shared resource was not created at this time.
  190. For delete:
  191. An error occurred while trying to delete share %1. %2
  192. For modify:
  193. An error occurred while trying to modify share %1. %2
  194. After the changes are applied, the page is refreshed. This is unnecessary
  195. if the user hit "OK", but essential if they pressed "Apply". The Apply button
  196. is grayed out, indicating there are no pending changes. Note that the act of
  197. applying changes might convert the page from "already-shared" mode to initial
  198. mode or vice-versa.
  199. When a share to be deleted that is currently being accessed by a user, one of
  200. the following error messages will be displayed (the same error messages are
  201. used in the copy hook handler):
  202. There are %1!d! user(s) connected to %2. If you stop sharing %2,
  203. they will be disconnected. Do you want to continue?
  204. There are %1!d! file(s) open by %2!d! user(s) connected to %3.
  205. If you stop sharing %3, the files will close, which may cause
  206. these users to lose data. Do you want to continue?
  207. One bug to beware of: when adding a second or greater share, or when deleting
  208. shares but leaving at least one, the combo box of shares should be re-filled
  209. correctly with the new set of shares for the directory.
  210. Copy hook
  211. ---------
  212. A copy hook in the tool monitors shell rename/move/delete operations on
  213. directories. If the directory or a subdirectory is shared, then an appropriate
  214. error message is displayed and the user is forced to verify the operation.
  215. In particular, one of the following messages will be displayed:
  216. There are %1!d! user(s) connected to %2. If you stop sharing %2,
  217. they will be disconnected. Do you want to continue?
  218. There are %1!d! file(s) open by %2!d! user(s) connected to %3.
  219. If you stop sharing %3, the files will close, which may cause
  220. these users to lose data. Do you want to continue?
  221. You are sharing %1 as %2. Others may be using files in this
  222. folder. If you delete the folder, it will no longer be shared.
  223. Are you sure you want to delete it?
  224. Security editor
  225. ---------------
  226. If the security editor DLL (acledit.dll) can't be loaded, this message is
  227. reported:
  228. Error invoking the security editor.
  229. Initialization
  230. --------------
  231. All of the above discussion assumes that the LanMan server service is
  232. running. This section describes how we determine the server is running,
  233. how we initialize our cache of shares (subsequently used by the Explorer
  234. to use for annotating folders with "hand" icons), what we do if the server
  235. is started manually after boot time, and what we do if the server is stopped
  236. sometime after boot time.
  237. Windows 95 initializes during DLL initialization by doing a NetServerGetInfo
  238. to determine if the server is running. We can't do this because it is bad
  239. to do net operations in DLL initialization code, for reasons having to do
  240. with the process mutant. In addition, because the server is a service
  241. controlled by the service controller that can be started manually and stopped
  242. at will, we would like to update the display of visible shares in the
  243. Explorer whenever the server starts or stops. For instance, if the server
  244. stops, we would like to remove all the "hand" icons from visible shared
  245. folders.
  246. Ideally, we would receive a notification from either the service controller
  247. or the server service whenever the server starts or stops. Since there is no
  248. support for this in the system, and none is likely to appear soon, we do two
  249. things. One, during initialization we wait as appropriate for the server to
  250. start. Note that the server starts asynchronously from the shell at boot time,
  251. so it is more than conceivable that the shell will start before the server
  252. does. In this case, if we can detect that the server is configured to start
  253. and is in fact starting, then we wait for it. We have certain timeouts to
  254. ensure that we don't wait too long. Secondly, if the server starts or stops
  255. after the shell has started, the user only needs to hit "refresh" in one
  256. Explorer window. If at this point we notice that the server has changed state,
  257. then we cause *all* explorer windows to refresh.
  258. Test scenarios
  259. --------------
  260. The following are a list of ad-hoc test scenarios to pursue on this component.
  261. In all cases, assume there are two machines: A and B, and the user is sitting
  262. at machine A.
  263. For the next few scenarios, log on as a normal user (not power user or
  264. administrator, etc).
  265. -- Be sure there is no sharing UI, even for things known to be shared.
  266. Exercise copy hook functionality by renaming/moving/deleting a directory.
  267. -- Rename a directory known to be shared. Log off, Log on as administrator.
  268. NOTE: There is no UI (save for winfile / server manager) to get rid of the
  269. orphaned share! Rename the directory back to the name that was shared.
  270. See if the explorer paints the "sharing" hand on it.
  271. -- Invoke all the APIs programmatically, and be sure they return appropriate
  272. errors.
  273. For the rest of these, log on as a member of the Administrators group.
  274. -- Open My Computer. Be sure the "Sharing..." context-menu item appears on
  275. all local drive objects, on floppy drives, and on CD-ROMs. Be sure it doesn't
  276. appear on network-mapped drive letters. Share each of them.
  277. -- Notice that hard drive roots (c:\, d:\, etc) should be shared by default, as
  278. should the windows directory via ADMIN$. On the sharing property page for
  279. these, press "Permissions" and notice you get a warning message disallowing
  280. permissions changes.
  281. -- Remove and recreate the default shares, including ADMIN$. Create a share
  282. C$ on D:\, and note that it isn't a default share at that point (you can edit
  283. its permissions).
  284. -- Share a directory. Hit apply. Add a number of shares. Hit apply. Make sure
  285. the combo box is correct. Delete a bunch of shares, hit apply. Make sure the
  286. combo is once again correct.
  287. -- Make sure the "New Share" and "Remove Share" appear and disappear at the
  288. proper times.
  289. -- Make sure the tab order doesn't include the "allow x users" edit control
  290. or spin button unless the "Allow" radio button is selected.
  291. -- Make sure the comment is limited to 256 characters, and the share name to
  292. 80 characters, in both the "initial mode" property page and the "New Share"
  293. dialog.
  294. -- Make sure context-sensitive help appears on all relevant controls of both
  295. the property page and New Share dialog. Make sure the Help buttons are active
  296. on all five ACL editor dialogs. (When we have a help file).
  297. -- Make sure all keyboard mnemonics are unique, and that all controls have
  298. appropriate mnemonics.
  299. -- Make sure that choosing a share in the combo box, changing a parameter,
  300. choosing another share in the combo box, changing one of its parameters works.
  301. That is, switching between shares in the combo box should show the selected
  302. share's data. Hit apply after these changes. Make sure the data got applied
  303. correctly (use "net share" at the command line, or a separate API tool), and
  304. that further switching between shares in the combo box still displays the
  305. correct data.
  306. -- In "New Share", type a share name that already exists. Get a pop-up and
  307. choose "yes" to reuse the share name. Hit apply and be sure the old one went
  308. away and the new one got created. Be sure the explorer "sharing hands" also
  309. changed appropriately. Do the same test when creating a share directly on the
  310. sharing page in "initial mode".
  311. -- In the property page, delete a share that a user has a connection to.
  312. Delete a share that a user has a connection to *and* a file open on. These are
  313. two different scenarios that should pop up warnings when the user hits "apply".
  314. -- In the explorer, delete, rename, and move (by drag/drop), a shared
  315. directory. Make sure the sharing warning comes up. Do the same thing when
  316. a user has a connection to the share. Do the same thing when a user has a
  317. file open on the connection. These should bring up three different warning
  318. scenarios. Do the same thing for a parent of a shared directory. Do the same
  319. thing for a directory that has more than one shared child directory, each with
  320. connections and open files.
  321. -- Test the APIs
  322. -- Stop the server (via "net stop server") between any two operations.
  323. For instance, after bringing up the property sheet, and editing some items,
  324. stop the server before hitting Apply.
  325. -- Stop the server, then try to rename/delete/move a shared folder in the
  326. explorer.
  327. -- Bring up properties on a shared directory, stop the server, *hit F5 in the
  328. explorer to refresh it, then try to apply share changes.
  329. -- Stop the server, hit "F5" (refresh) in an explorer window to clear the
  330. "sharing" hands, then start the server and hit F5 again to see the sharing
  331. hands reappear.