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

619 lines
19 KiB

  1. /****************************************************************************/
  2. // namespc.c
  3. //
  4. // Redirector namespace code
  5. //
  6. // Copyright (C) 1998-2000 Microsoft Corp.
  7. /****************************************************************************/
  8. #include "precomp.hxx"
  9. #define TRC_FILE "namespc"
  10. #include "trc.h"
  11. NTSTATUS
  12. DrCreateSrvCall(
  13. IN OUT PMRX_SRV_CALL pSrvCall,
  14. IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
  15. /*++
  16. Routine Description:
  17. This routine patches the RDBSS created srv call instance with the information required
  18. by the mini redirector.
  19. Arguments:
  20. CallBackContext - the call back context in RDBSS for continuation.
  21. Return Value:
  22. RXSTATUS - The return status for the operation
  23. --*/
  24. {
  25. NTSTATUS Status;
  26. PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext;
  27. PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(SCCBC->SrvCalldownStructure);
  28. SmartPtr<DrSession> Session;
  29. PWCHAR ClientName;
  30. BEGIN_FN("DrCreateSrvCall");
  31. TRC_NRM((TB, "SrvCallName %wZ", pSrvCall->pSrvCallName));
  32. ASSERT(pSrvCall);
  33. ASSERT(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL);
  34. ASSERT(pSrvCall->pSrvCallName);
  35. ASSERT(pSrvCall->pSrvCallName->Buffer);
  36. //
  37. // Actually do the work of setting up our stuff for this "server" (client)
  38. // Smb would attempt to contact the server now, but since our stuff
  39. // is client initiated, we already know if we have a connection
  40. //
  41. // Status = DrInitializeServerEntry(pSrvCall,pCallbackContext);
  42. //
  43. // Our SrvCalls look like \clientName
  44. //
  45. ClientName = pSrvCall->pSrvCallName->Buffer;
  46. if (ClientName[0] == OBJ_NAME_PATH_SEPARATOR) {
  47. ClientName++;
  48. }
  49. #if 0
  50. if (Sessions->FindSessionByClientName(ClientName, Session)) {
  51. TRC_NRM((TB, "Recognize SrvCall %wZ", pSrvCall->pSrvCallName));
  52. Status = STATUS_SUCCESS;
  53. }
  54. else {
  55. TRC_NRM((TB, "Unrecognize SrvCall %wZ", pSrvCall->pSrvCallName));
  56. Status = STATUS_BAD_NETWORK_NAME;
  57. }
  58. #endif
  59. if (_wcsicmp(ClientName, DRUNCSERVERNAME_U) == 0) {
  60. TRC_NRM((TB, "Recognize SrvCall %wZ", pSrvCall->pSrvCallName));
  61. Status = STATUS_SUCCESS;
  62. }
  63. else {
  64. TRC_NRM((TB, "Unrecognize SrvCall %wZ", pSrvCall->pSrvCallName));
  65. Status = STATUS_BAD_NETWORK_NAME;
  66. }
  67. SCCBC->RecommunicateContext = NULL;
  68. SCCBC->Status = Status;
  69. SrvCalldownStructure->CallBack(SCCBC);
  70. //
  71. // The CreateSrvCall callback is supposed to return STATUS_PENDING, the
  72. // real result goes in the ServCallbackContext thing
  73. //
  74. return STATUS_PENDING;
  75. }
  76. NTSTATUS
  77. DrSrvCallWinnerNotify(
  78. IN OUT PMRX_SRV_CALL SrvCall,
  79. IN BOOLEAN ThisMinirdrIsTheWinner,
  80. IN OUT PVOID RecommunicateContext
  81. )
  82. /*++
  83. Routine Description:
  84. This routine is called by RDBSS to notify the mini redirector whether the
  85. previous SrvCall is actually going to be processed by this redir.
  86. Arguments:
  87. SrvCall - the SrvCall in question
  88. ThisMinirdrIsTheWinner - True if we will be processing files on this SrvCall
  89. RecommunicateContext - the context we specificed in DrCreateSrvCall
  90. Return Value:
  91. NTSTATUS - The return status for the operation
  92. --*/
  93. {
  94. BEGIN_FN("DrSrvCallWinnerNotify");
  95. PAGED_CODE();
  96. if (!ThisMinirdrIsTheWinner) {
  97. TRC_NRM((TB, "This minirdr is not the winner"));
  98. //
  99. // Some other mini rdr has been choosen to connect. Destroy
  100. // the data structures created for this mini redirector.
  101. //
  102. return STATUS_SUCCESS;
  103. } else {
  104. TRC_NRM((TB, "This minirdr is the winner"));
  105. }
  106. SrvCall->Context = NULL;
  107. SrvCall->Flags |= SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS |
  108. SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES;
  109. return STATUS_SUCCESS;
  110. }
  111. NTSTATUS
  112. DrFinalizeSrvCall(
  113. PMRX_SRV_CALL pSrvCall,
  114. BOOLEAN Force
  115. )
  116. /*++
  117. Routine Description:
  118. This routine is called by RDBSS to notify the mini redirector when the
  119. SrvCall structure is being released.
  120. Arguments:
  121. SrvCall - the SrvCall in question
  122. Force - I don't know, there's no documentation on any of this stuff
  123. Return Value:
  124. NTSTATUS - The return status for the operation
  125. --*/
  126. {
  127. BEGIN_FN("DrFinalizeSrvCall");
  128. PAGED_CODE();
  129. //
  130. // We seem to get called with this even if we weren't the "winner"
  131. // Check to make sure this was filled in before we mess with it
  132. //
  133. return STATUS_SUCCESS;
  134. }
  135. NTSTATUS
  136. DrUpdateNetRootState(
  137. IN PMRX_NET_ROOT pNetRoot
  138. )
  139. {
  140. BEGIN_FN("DrUpdateNetRootState");
  141. return STATUS_SUCCESS;
  142. }
  143. VOID
  144. DrExtractNetRootName(
  145. IN PUNICODE_STRING FilePathName,
  146. IN PMRX_SRV_CALL SrvCall,
  147. OUT PUNICODE_STRING NetRootName,
  148. OUT PUNICODE_STRING RestOfName OPTIONAL
  149. )
  150. /*++
  151. Routine Description:
  152. This routine is called by RDBSS to get a NetRoot (share) name parsed out
  153. of the path. The SrvCall already has part parsed out.
  154. Arguments:
  155. FilePathName - The full path, including the SrvCall
  156. SrvCall - relevant SrvCall structure
  157. NetRootName - The place to put the NetRoot name
  158. RestOfName - What's self of the path afterwards
  159. Return Value:
  160. NTSTATUS - The return status for the operation
  161. --*/
  162. {
  163. UNICODE_STRING xRestOfName;
  164. ULONG length = FilePathName->Length;
  165. PWCH w = FilePathName->Buffer;
  166. PWCH wlimit = (PWCH)(((PCHAR)w)+length);
  167. PWCH wlow;
  168. BEGIN_FN("DrExtractNetRootName");
  169. PAGED_CODE();
  170. w += (SrvCall->pSrvCallName->Length/sizeof(WCHAR));
  171. NetRootName->Buffer = wlow = w;
  172. for (;;) {
  173. if (w >= wlimit)
  174. break;
  175. if ((*w == OBJ_NAME_PATH_SEPARATOR) && (w != wlow)) {
  176. break;
  177. }
  178. w++;
  179. }
  180. // Polish of the NetRootName UNICODE_STRING
  181. NetRootName->Length = NetRootName->MaximumLength
  182. = (USHORT) ((PCHAR)w - (PCHAR)wlow);
  183. if (!RestOfName) RestOfName = &xRestOfName;
  184. RestOfName->Buffer = w;
  185. RestOfName->Length = RestOfName->MaximumLength
  186. = (USHORT) ((PCHAR)wlimit - (PCHAR)w);
  187. TRC_NRM((TB, "DrExtractNetRootName FilePath=%wZ",FilePathName));
  188. TRC_NRM((TB, " Srv=%wZ,Root=%wZ,Rest=%wZ",
  189. SrvCall->pSrvCallName, NetRootName,
  190. RestOfName));
  191. return;
  192. }
  193. NTSTATUS
  194. DrFinalizeNetRoot(
  195. IN OUT PMRX_NET_ROOT pNetRoot,
  196. IN PBOOLEAN ForceDisconnect
  197. )
  198. {
  199. BEGIN_FN("DrFinalizeNetRoot");
  200. return STATUS_SUCCESS;
  201. }
  202. NTSTATUS
  203. DrCreateSCardDevice(SmartPtr<DrSession> &Session, PV_NET_ROOT pVNetRoot,
  204. SmartPtr<DrDevice> &Device)
  205. {
  206. NTSTATUS Status;
  207. PMRX_NET_ROOT pNetRoot = NULL;
  208. BEGIN_FN("DrCreateDevice");
  209. Status = STATUS_BAD_NETWORK_NAME;
  210. if (pVNetRoot != NULL) {
  211. pNetRoot = pVNetRoot->pNetRoot;
  212. }
  213. // We also need to create the smart card subsystem at this point
  214. // even a session may not exist and/or the client smartcard subsystem
  215. // is not connected
  216. Device = new(NonPagedPool) DrSmartCard(Session, RDPDR_DTYP_SMARTCARD,
  217. RDPDR_INVALIDDEVICEID, (PUCHAR)DR_SMARTCARD_SUBSYSTEM);
  218. if (Device != NULL) {
  219. //
  220. // Give the specific device a chance to initialize based on the data
  221. //
  222. TRC_DBG((TB, "Created new device"));
  223. Status = Device->Initialize(NULL, 0);
  224. if (NT_SUCCESS(Status)) {
  225. TRC_DBG((TB, "Device initialized, adding"));
  226. Device->SetDeviceStatus(dsAvailable);
  227. if (Session->GetDevMgr().AddDevice(Device)) {
  228. TRC_DBG((TB, "Added device"));
  229. }
  230. else {
  231. Device = NULL;
  232. if (!Session->FindDeviceByDosName((UCHAR *)DR_SMARTCARD_SUBSYSTEM,
  233. Device, TRUE)) {
  234. TRC_ERR((TB, "Failed to add device to devicelist"));
  235. goto EXIT_POINT;
  236. }
  237. }
  238. }
  239. else {
  240. TRC_ERR((TB, "Failed to initialize device"));
  241. Device = NULL;
  242. goto EXIT_POINT;
  243. }
  244. } else {
  245. TRC_ERR((TB, "Error creating new device: 0x%08lx", Status));
  246. goto EXIT_POINT;
  247. }
  248. if (pVNetRoot != NULL) {
  249. Device->AddRef();
  250. pVNetRoot->Context = (DrDevice *)Device;
  251. pNetRoot->DeviceType = RxDeviceType(DISK);
  252. pNetRoot->Type = NET_ROOT_DISK;
  253. #if DBG
  254. Device->_VNetRoot = (PVOID)pVNetRoot;
  255. #endif
  256. }
  257. Status = STATUS_SUCCESS;
  258. EXIT_POINT:
  259. return Status;
  260. }
  261. NTSTATUS
  262. DrCreateSession(ULONG SessionId, PV_NET_ROOT pVNetRoot, SmartPtr<DrSession> &Session)
  263. {
  264. NTSTATUS Status;
  265. BEGIN_FN("DrCreateSession");
  266. Status = STATUS_BAD_NETWORK_NAME;
  267. // For smart card subsystem, we'll need to create session and
  268. // smart card subsystem objects early before client connect
  269. Session = new(NonPagedPool) DrSession;
  270. if (Session != NULL) {
  271. TRC_DBG((TB, "Created new session"));
  272. if (Session->Initialize()) {
  273. TRC_DBG((TB, "Session connected, adding"));
  274. if (Sessions->AddSession(Session)) {
  275. TRC_DBG((TB, "Added session"));
  276. }
  277. else {
  278. Session = NULL;
  279. if (!Sessions->FindSessionById(SessionId, Session)) {
  280. TRC_DBG((TB, "Session couldn't be added to session list"));
  281. goto EXIT_POINT;
  282. }
  283. }
  284. }
  285. else {
  286. TRC_DBG((TB, "Session couldn't initialize"));
  287. Session = NULL;
  288. goto EXIT_POINT;
  289. }
  290. }
  291. else {
  292. TRC_ERR((TB, "Failed to allocate new session"));
  293. goto EXIT_POINT;
  294. }
  295. Session->SetSessionId(SessionId);
  296. Session->GetExchangeManager().Start();
  297. Status = STATUS_SUCCESS;
  298. EXIT_POINT:
  299. return Status;
  300. }
  301. NTSTATUS
  302. DrCreateVNetRoot(
  303. IN OUT PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
  304. )
  305. {
  306. NTSTATUS Status;
  307. PRX_CONTEXT pRxContext = CreateNetRootContext->RxContext;
  308. ULONG DeviceId;
  309. PMRX_SRV_CALL pSrvCall;
  310. PMRX_NET_ROOT pNetRoot;
  311. SmartPtr<DrSession> Session;
  312. SmartPtr<DrDevice> Device;
  313. PUNICODE_STRING pNetRootName, pSrvCallName;
  314. WCHAR NetRootBuffer[64];
  315. UNICODE_STRING NetRoot = {0, sizeof(NetRootBuffer), NetRootBuffer};
  316. PV_NET_ROOT pVNetRoot;
  317. UCHAR DeviceDosName[MAX_PATH];
  318. PWCHAR token;
  319. ULONG SessionId = -1;
  320. UNICODE_STRING SessionIdString;
  321. USHORT OemCodePage, AnsiCodePage;
  322. INT len;
  323. BEGIN_FN("DrCreateVNetRoot");
  324. pVNetRoot = CreateNetRootContext->pVNetRoot;
  325. pNetRoot = pVNetRoot->pNetRoot;
  326. pSrvCall = pNetRoot->pSrvCall;
  327. ASSERT(NodeType(pNetRoot) == RDBSS_NTC_NETROOT);
  328. ASSERT(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL);
  329. token = &pRxContext->CurrentIrpSp->FileObject->FileName.Buffer[0];
  330. //
  331. // Get the sessionId from the IRP fileName
  332. // File name in the format of:
  333. // \;<DosDeviceName>:<SessionId>\ClientName\DosDeviveName
  334. //
  335. for (unsigned i = 0; i < pRxContext->CurrentIrpSp->FileObject->FileName.Length / sizeof(WCHAR); i++) {
  336. if (*token == L':') {
  337. token++;
  338. SessionIdString.Length = pRxContext->CurrentIrpSp->FileObject->FileName.Length -
  339. (i+1) * sizeof(WCHAR);
  340. SessionIdString.MaximumLength = pRxContext->CurrentIrpSp->FileObject->FileName.MaximumLength -
  341. (i+1) * sizeof(WCHAR);
  342. SessionIdString.Buffer = token;
  343. RtlUnicodeStringToInteger(&SessionIdString, 0, &SessionId);
  344. break;
  345. }
  346. token++;
  347. }
  348. TRC_NRM((TB, "pVNetRoot->SessionId: %d", pVNetRoot->SessionId));
  349. TRC_NRM((TB, "SessionId from FileObject: %d", SessionId));
  350. //
  351. // We first try to get the session id from the FileObject name. If not,
  352. // then it's because we get called directly from a UNC name, in this case
  353. // we have to base on if the UNC is called from the session context and use that
  354. // as the session id.
  355. //
  356. if (SessionId == -1) {
  357. SessionId = pVNetRoot->SessionId;
  358. }
  359. //
  360. // Get the NetRoot name as the DeviceDosName
  361. //
  362. DrExtractNetRootName(pNetRoot->pNetRootName, pSrvCall, &NetRoot, NULL);
  363. if (NetRoot.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) {
  364. NetRoot.Buffer++;
  365. NetRoot.Length -= sizeof(WCHAR);
  366. NetRoot.MaximumLength -= sizeof(WCHAR);
  367. }
  368. TRC_NRM((TB, "Name of NetRoot: %wZ", &NetRoot));
  369. RtlGetDefaultCodePage(&AnsiCodePage,&OemCodePage);
  370. len = ConvertToAndFromWideChar(AnsiCodePage, NetRoot.Buffer,
  371. NetRoot.MaximumLength, (char *)DeviceDosName,
  372. MAX_PATH - 1, FALSE);
  373. if (len != -1) {
  374. DeviceDosName[len] = '\0';
  375. TRC_NRM((TB, "DeviceDosName=%s", DeviceDosName));
  376. }
  377. if (Sessions->FindSessionById(SessionId, Session)) {
  378. // The V_NET_ROOT is associated with a NET_ROOT. The two cases of interest are as
  379. // follows
  380. // 1) the V_NET_ROOT and the associated NET_ROOT are being newly created.
  381. // 2) a new V_NET_ROOT associated with an existing NET_ROOT is being created.
  382. //
  383. // These two cases can be distinguished by checking if the context associated with
  384. // NET_ROOT is NULL. Since the construction of NET_ROOT's/V_NET_ROOT's are serialized
  385. // by the wrapper this is a safe check.
  386. // ( The wrapper cannot have more then one thread tryingto initialize the same
  387. // NET_ROOT).
  388. if (pVNetRoot->Context == NULL) {
  389. if (len != -1) {
  390. if (Session->FindDeviceByDosName(DeviceDosName, Device, TRUE)) {
  391. Device->AddRef();
  392. pVNetRoot->Context = (DrDevice *)Device;
  393. Status = STATUS_SUCCESS;
  394. TRC_NRM((TB, "Successfully recognized VNetRoot"));
  395. // Set the Device type to DISK if this is file system or
  396. // smartcard subsystem,
  397. // set it to COMM if it is serial port.
  398. // otherwise, treated it as printer device.
  399. if (Device->GetDeviceType() == RDPDR_DTYP_FILESYSTEM) {
  400. if (Device->ShouldCreateDevice()) {
  401. pNetRoot->DeviceType = RxDeviceType(DISK);
  402. pNetRoot->Type = NET_ROOT_DISK;
  403. }
  404. else {
  405. Device->Release();
  406. pVNetRoot->Context = NULL;
  407. Status = STATUS_BAD_NETWORK_NAME;
  408. TRC_NRM((TB, "We have disabled drive mapping"));
  409. }
  410. }
  411. else if (Device->GetDeviceType() == RDPDR_DTYP_SERIAL) {
  412. pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT);
  413. pNetRoot->Type = NET_ROOT_COMM;
  414. }
  415. else if (Device->GetDeviceType() == RDPDR_DTYP_SMARTCARD) {
  416. pNetRoot->DeviceType = RxDeviceType(DISK);
  417. pNetRoot->Type = NET_ROOT_DISK;
  418. #if DBG
  419. Device->_VNetRoot = (PVOID)pVNetRoot;
  420. #endif
  421. }
  422. else {
  423. pNetRoot->Type = NET_ROOT_PRINT;
  424. pNetRoot->DeviceType = RxDeviceType(PRINTER);
  425. }
  426. } else {
  427. //
  428. // check to see if this is a smartcard subsystem request
  429. //
  430. if (_stricmp((CHAR *)DeviceDosName, (CHAR *)DR_SMARTCARD_SUBSYSTEM) == 0) {
  431. Status = DrCreateSCardDevice(Session, pVNetRoot, Device);
  432. goto EXIT_POINT;
  433. }
  434. else {
  435. TRC_NRM((TB, "Unrecognized VNetRoot"));
  436. Status = STATUS_BAD_NETWORK_NAME;
  437. }
  438. }
  439. } else {
  440. Status = STATUS_BAD_NETWORK_NAME;
  441. TRC_NRM((TB, "Couldn't find VNetRoot"));
  442. }
  443. } else {
  444. // It already has a happy context
  445. // BUGBUG: What if this is a crusty old out of date
  446. // DeviceEntry from before a disconnect? isn't this our big chance
  447. // to look for and swap in a better one?
  448. Status = STATUS_SUCCESS;
  449. }
  450. }
  451. else {
  452. // Check if this is a smartcard subsystem request
  453. if (_stricmp((CHAR *)DeviceDosName, (CHAR *)DR_SMARTCARD_SUBSYSTEM) != 0) {
  454. TRC_NRM((TB, "Unrecognized VNetRoot"));
  455. Status = STATUS_BAD_NETWORK_NAME;
  456. }
  457. else {
  458. Status = DrCreateSession(SessionId, pVNetRoot, Session);
  459. if (Status == STATUS_SUCCESS) {
  460. Status = DrCreateSCardDevice(Session, pVNetRoot, Device);
  461. }
  462. }
  463. }
  464. EXIT_POINT:
  465. CreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
  466. CreateNetRootContext->VirtualNetRootStatus = Status;
  467. CreateNetRootContext->Callback(CreateNetRootContext);
  468. ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
  469. (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
  470. return STATUS_PENDING;
  471. }
  472. NTSTATUS
  473. DrFinalizeVNetRoot(
  474. IN OUT PMRX_V_NET_ROOT pVirtualNetRoot,
  475. IN PBOOLEAN ForceDisconnect
  476. )
  477. {
  478. DrDevice *Device = (DrDevice *)pVirtualNetRoot->Context;
  479. BEGIN_FN("DrFinalizeVNetRoot");
  480. if (Device != NULL) {
  481. TRC_NRM((TB, "Releasing device entry in FinalizeNetRoot "
  482. "Context"));
  483. #if DBG
  484. Device->_VNetRootFinalized = TRUE;
  485. #endif
  486. Device->Release();
  487. pVirtualNetRoot->Context = NULL;
  488. }
  489. return STATUS_SUCCESS;
  490. }