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.

3104 lines
80 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. admin.c
  5. Abstract:
  6. This module implements the top level admin request routines. All
  7. routines within this module execute in the context of the server
  8. service (or equivalent calling user mode process).
  9. A routine that can complete an entire admin request
  10. in the caller's context will return an appropriate AFP error to
  11. the admin dispatch layer above.
  12. A routine that must queue a worker to the FSP Admin queue will return
  13. STATUS_PENDING to the admin dispatch layer above. This will indicate
  14. to the dispatch layer that it should queue up the appropriate request.
  15. In these cases, the routine's job is to merely validate any appropriate
  16. input and return the STATUS_PENDING error code.
  17. Author:
  18. Sue Adams (microsoft!suea)
  19. Revision History:
  20. 25 Jun 1992 Initial Version
  21. --*/
  22. #define FILENUM FILE_ADMIN
  23. #include <afp.h>
  24. #include <afpadmin.h>
  25. #include <secutil.h>
  26. #include <fdparm.h>
  27. #include <pathmap.h>
  28. #include <afpinfo.h>
  29. #include <access.h>
  30. #include <secutil.h>
  31. #include <gendisp.h>
  32. // This is the duration that we sleep before rescanning for the enumerate apis
  33. #define AFP_SLEEP_TIMER_TICK -(1*NUM_100ns_PER_SECOND/100) // 10ms
  34. LOCAL
  35. NTSTATUS
  36. afpConvertAdminPathToMacPath(
  37. IN PVOLDESC pVolDesc,
  38. IN PUNICODE_STRING AdminPath,
  39. OUT PANSI_STRING MacPath
  40. );
  41. LOCAL
  42. PETCMAPINFO
  43. afpGetNextFreeEtcMapEntry(
  44. IN OUT PLONG StartIndex
  45. );
  46. LOCAL
  47. VOID
  48. afpEtcMapDelete(
  49. PETCMAPINFO pEtcEntry
  50. );
  51. LOCAL
  52. NTSTATUS
  53. afpCopyMapInfo2ToMapInfo(
  54. OUT PETCMAPINFO pEtcDest,
  55. IN PETCMAPINFO2 pEtcSource
  56. );
  57. #ifdef ALLOC_PRAGMA
  58. #pragma alloc_text( PAGE, AfpAdminDeInit)
  59. #pragma alloc_text( PAGE, AfpSleepAWhile)
  60. #pragma alloc_text( PAGE, AfpAdmServiceStart)
  61. #pragma alloc_text( PAGE, AfpAdmServiceStop)
  62. #pragma alloc_text( PAGE, AfpAdmServicePause)
  63. #pragma alloc_text( PAGE, AfpAdmServiceContinue)
  64. #pragma alloc_text( PAGE, AfpAdmServerGetInfo)
  65. #pragma alloc_text( PAGE, AfpAdmClearProfCounters)
  66. #pragma alloc_text( PAGE, AfpAdmServerSetParms)
  67. #pragma alloc_text( PAGE, AfpAdmServerAddEtc)
  68. #pragma alloc_text( PAGE, AfpAdmServerSetEtc)
  69. #pragma alloc_text( PAGE, AfpAdmServerDeleteEtc)
  70. #pragma alloc_text( PAGE, AfpAdmServerAddIcon)
  71. #pragma alloc_text( PAGE, AfpAdmVolumeAdd)
  72. #pragma alloc_text( PAGE, AfpAdmWDirectoryGetInfo)
  73. #pragma alloc_text( PAGE, AfpAdmWDirectorySetInfo)
  74. #pragma alloc_text( PAGE, AfpAdmWFinderSetInfo)
  75. #pragma alloc_text( PAGE, AfpLookupEtcMapEntry)
  76. #pragma alloc_text( PAGE, afpEtcMapDelete)
  77. #pragma alloc_text( PAGE, afpGetNextFreeEtcMapEntry)
  78. #pragma alloc_text( PAGE, afpConvertAdminPathToMacPath)
  79. #pragma alloc_text( PAGE_AFP, AfpAdmGetStatistics)
  80. #pragma alloc_text( PAGE_AFP, AfpAdmClearStatistics)
  81. #pragma alloc_text( PAGE_AFP, AfpAdmGetProfCounters)
  82. #pragma alloc_text( PAGE_AFP, AfpAdmVolumeGetInfo)
  83. #pragma alloc_text( PAGE_AFP, AfpAdmVolumeSetInfo)
  84. #pragma alloc_text( PAGE_AFP, AfpAdmVolumeEnum)
  85. #pragma alloc_text( PAGE_AFP, AfpAdmSessionEnum)
  86. #pragma alloc_text( PAGE_AFP, AfpAdmConnectionEnum)
  87. #pragma alloc_text( PAGE_AFP, AfpAdmForkEnum)
  88. #pragma alloc_text( PAGE_AFP, AfpAdmMessageSend)
  89. #endif
  90. //
  91. // macro to ensure that the extension in a type/creator mapping is padded
  92. // with nulls by the server service so we don't end up in la-la land on a
  93. // lookup by extension
  94. //
  95. #define afpIsValidExtension(ext) (((ext)[AFP_EXTENSION_LEN] == '\0') && \
  96. ((ext)[0] != '\0') )
  97. //
  98. // invalid entries in AfpEtcMaps table are denoted by a null extension field
  99. //
  100. #define afpIsValidEtcMapEntry(ext) ((ext)[0] != '\0')
  101. #define afpCopyEtcMap(pdst,psrc) (RtlCopyMemory(pdst,psrc,sizeof(ETCMAPINFO)))
  102. #define afpIsServerIcon(picon) ((picon)->icon_icontype == 0)
  103. /*** AfpAdminDeInit
  104. *
  105. * De-initialize the data structures for admin APIs.
  106. */
  107. VOID
  108. AfpAdminDeInit(
  109. VOID
  110. )
  111. {
  112. PAGED_CODE( );
  113. // Free memory for server icon
  114. if (AfpServerIcon != NULL)
  115. AfpFreeMemory(AfpServerIcon);
  116. // Free memory used for global icons
  117. AfpFreeGlobalIconList();
  118. // Free memory used for ETC mappings
  119. if (AfpEtcMaps != NULL)
  120. {
  121. AfpFreeMemory(AfpEtcMaps);
  122. }
  123. // Free memory used for server name
  124. if (AfpServerName.Buffer != NULL)
  125. {
  126. AfpFreeMemory(AfpServerName.Buffer);
  127. }
  128. // Free any Server/Login Messages
  129. if (AfpServerMsg != NULL)
  130. {
  131. AfpFreeMemory(AfpServerMsg);
  132. }
  133. if (AfpLoginMsg.Buffer != NULL)
  134. {
  135. AfpFreeMemory(AfpLoginMsg.Buffer);
  136. }
  137. if (AfpLoginMsgU.Buffer != NULL)
  138. {
  139. AfpFreeMemory(AfpLoginMsgU.Buffer);
  140. }
  141. // Free the memory allocated for the admin sid
  142. if (AfpSidAdmins != NULL)
  143. AfpFreeMemory(AfpSidAdmins);
  144. // Free the memory allocated for the None sid (standalone only)
  145. if (AfpSidNone != NULL)
  146. AfpFreeMemory(AfpSidNone);
  147. }
  148. /*** AfpSleepAWhile
  149. *
  150. * Sleep for a multiple of AFP_SLEEP_TIMER_TICK ticks.
  151. */
  152. VOID
  153. AfpSleepAWhile(
  154. IN DWORD SleepDuration
  155. )
  156. {
  157. KTIMER SleepTimer;
  158. LARGE_INTEGER TimerValue;
  159. PAGED_CODE( );
  160. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  161. KeInitializeTimer(&SleepTimer);
  162. TimerValue.QuadPart = (SleepDuration * AFP_SLEEP_TIMER_TICK);
  163. KeSetTimer(&SleepTimer,
  164. TimerValue,
  165. NULL);
  166. AfpIoWait(&SleepTimer, NULL);
  167. }
  168. /*** AfpAdmServiceStart
  169. *
  170. * This is the service start code. The following is done as part of the service
  171. * startup.
  172. *
  173. * Registration of NBP Name.
  174. * Posting listens
  175. * And finally the server status block is set.
  176. */
  177. AFPSTATUS
  178. AfpAdmServiceStart(
  179. IN OUT PVOID InBuf OPTIONAL,
  180. IN LONG OutBufLen OPTIONAL,
  181. OUT PVOID OutBuf OPTIONAL
  182. )
  183. {
  184. AFPSTATUS Status = AFP_ERR_NONE;
  185. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  186. ("AfpAdmServiceStart entered\n"));
  187. do
  188. {
  189. // make sure serversetinfo has been called
  190. if ((AfpServerState != AFP_STATE_IDLE) ||
  191. (AfpServerName.Length == 0))
  192. {
  193. Status = AFPERR_InvalidServerState;
  194. break;
  195. }
  196. AfpServerState = AFP_STATE_START_PENDING;
  197. if (AfpServerBoundToAsp || AfpServerBoundToTcp)
  198. {
  199. // Det the server status block
  200. Status = AfpSetServerStatus();
  201. if (!NT_SUCCESS(Status))
  202. {
  203. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  204. ("AfpAdmServiceStart: AfpSetServerStatus returned %lx\n",Status));
  205. AFPLOG_ERROR(AFPSRVMSG_SET_STATUS, Status, NULL, 0, NULL);
  206. break;
  207. }
  208. if (AfpServerBoundToAsp)
  209. {
  210. // Register our name on this address
  211. Status = AfpSpRegisterName(&AfpServerName, True);
  212. if (!NT_SUCCESS(Status))
  213. {
  214. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  215. ("AfpAdmServiceStart: AfpSpRegisterName returned %lx\n",Status));
  216. break;
  217. }
  218. }
  219. // Enable listens now that we are ready for it.
  220. AfpSpEnableListens();
  221. // Set the server start time
  222. AfpGetCurrentTimeInMacFormat((PAFPTIME)&AfpServerStatistics.stat_ServerStartTime);
  223. }
  224. // server is ready to go
  225. AfpServerState = AFP_STATE_RUNNING;
  226. } while (False);
  227. if (!NT_SUCCESS(Status))
  228. {
  229. AfpServerState = AFP_STATE_IDLE; // Set state back to idle so we can be stopped
  230. }
  231. else
  232. {
  233. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR, ("SFM Service started\n"));
  234. }
  235. return Status;
  236. }
  237. /*** AfpAdmServiceStop
  238. *
  239. * This is the service stop code.
  240. */
  241. AFPSTATUS
  242. AfpAdmServiceStop(
  243. IN OUT PVOID InBuf OPTIONAL,
  244. IN LONG OutBufLen OPTIONAL,
  245. OUT PVOID OutBuf OPTIONAL
  246. )
  247. {
  248. NTSTATUS Status;
  249. AFP_SESSION_INFO SessInfo;
  250. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  251. ("AfpAdmServiceStop entered\n"));
  252. do
  253. {
  254. if ((AfpServerState != AFP_STATE_RUNNING) &&
  255. (AfpServerState != AFP_STATE_PAUSED) &&
  256. (AfpServerState != AFP_STATE_IDLE))
  257. {
  258. Status = AFPERR_InvalidServerState;
  259. break;
  260. }
  261. AfpServerState = AFP_STATE_STOP_PENDING;
  262. if (AfpServerBoundToAsp)
  263. {
  264. // First de-register our name from the network
  265. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  266. ("AfpAdmServiceStop: De-registering Name\n"));
  267. AfpSpRegisterName(&AfpServerName, False);
  268. if (AfpTdiNotificationHandle)
  269. {
  270. Status = TdiDeregisterPnPHandlers(AfpTdiNotificationHandle);
  271. if (!NT_SUCCESS(Status))
  272. {
  273. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  274. ("AfpAdmServiceStop: TdiDeregisterNotificationHandler failed with %lx\n",Status));
  275. }
  276. AfpTdiNotificationHandle = NULL;
  277. }
  278. else
  279. {
  280. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  281. ("AfpAdmServiceStop: BoundToAsp but no Tdi handle!!\n"));
  282. ASSERT(0);
  283. }
  284. }
  285. // Disable listens now that we are about to stop
  286. AfpSpDisableListens();
  287. // De-register our shutdown notification
  288. IoUnregisterShutdownNotification(AfpDeviceObject);
  289. // Now walk the list of active sessions and kill them
  290. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  291. ("AfpAdmServiceStop: Shutting down sessions\n"));
  292. KeClearEvent(&AfpStopConfirmEvent);
  293. SessInfo.afpsess_id = 0; // Shutdown all sessions
  294. AfpAdmWSessionClose(&SessInfo, 0, NULL);
  295. Status = STATUS_TIMEOUT;
  296. // Wait for the sessions to complete, if there were active sessions
  297. if (AfpNumSessions > 0) do
  298. {
  299. if (AfpNumSessions == 0)
  300. {
  301. break;
  302. }
  303. Status = AfpIoWait(&AfpStopConfirmEvent, &FiveSecTimeOut);
  304. if (Status == STATUS_TIMEOUT)
  305. {
  306. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  307. ("AfpAdmServiceStop: Timeout Waiting for %ld sessions to die, re-waiting\n",
  308. AfpNumSessions));
  309. }
  310. } while (Status == STATUS_TIMEOUT);
  311. // bring down the DSI-TCP interface
  312. DsiDestroyAdapter();
  313. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  314. ("AfpAdmServiceStop: blocked, waiting for DsiDestroyAdapter to finish...\n"));
  315. // wait until DSI cleans up its interface with TCP
  316. AfpIoWait(&DsiShutdownEvent, NULL);
  317. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  318. ("AfpAdmServiceStop: ..... DsiDestroyAdapter finished.\n"));
  319. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  320. ("AfpAdmServiceStop: Stopping Volumes\n"));
  321. // Set flag to indicate "net stop macfile" occured
  322. // The volume will be re-indexed on startup
  323. fAfpAdminStop = TRUE;
  324. // Now tell each of the volume scavengers to shut-down
  325. AfpVolumeStopAllVolumes();
  326. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  327. ("AfpAdmServiceStop: Stopping Security threads\n"));
  328. // Release all security utility threads.
  329. AfpTerminateSecurityUtility();
  330. #ifdef OPTIMIZE_GUEST_LOGONS
  331. // Close the 'cached' Guest token and security descriptor
  332. if (AfpGuestToken != NULL)
  333. {
  334. NtClose(AfpGuestToken);
  335. AfpGuestToken = NULL;
  336. #ifndef INHERIT_DIRECTORY_PERMS
  337. if (AfpGuestSecDesc->Dacl != NULL)
  338. AfpFreeMemory(AfpGuestSecDesc->Dacl);
  339. AfpFreeMemory(AfpGuestSecDesc);
  340. AfpGuestSecDesc = NULL;
  341. #endif
  342. }
  343. #endif
  344. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  345. ("AfpAdmServiceStop: All Done\n"));
  346. // Now shutdown the appletalk socket
  347. DBGPRINT(DBG_COMP_ADMINAPI, DBG_LEVEL_INFO,
  348. ("AfpAdmServerStop: Closing appletalk socket\n"));
  349. if (AfpServerBoundToAsp)
  350. {
  351. AfpSpCloseAddress();
  352. }
  353. else
  354. {
  355. DBGPRINT(DBG_COMP_ADMINAPI, DBG_LEVEL_ERR,
  356. ("AfpAdmServerStop: No binding, so didn't close appletalk socket\n"));
  357. }
  358. // Make sure we do not have resource leaks
  359. ASSERT(AfpServerStatistics.stat_CurrentFileLocks == 0);
  360. ASSERT(AfpServerStatistics.stat_CurrentFilesOpen == 0);
  361. ASSERT(AfpServerStatistics.stat_CurrentSessions == 0);
  362. ASSERT(AfpServerStatistics.stat_CurrentInternalOpens == 0);
  363. #ifdef PROFILING
  364. // Make sure we do not have resource leaks
  365. ASSERT(AfpServerProfile->perf_cAllocatedIrps == 0);
  366. ASSERT(AfpServerProfile->perf_cAllocatedMdls == 0);
  367. #endif
  368. ASSERT(IsListEmpty(&AfpDebugDelAllocHead));
  369. ASSERT(AfpDbgMdlsAlloced == 0);
  370. ASSERT(AfpDbgIrpsAlloced == 0);
  371. #if DBG
  372. if ((AfpReadCMAlloced != 0) || (AfpWriteCMAlloced != 0))
  373. {
  374. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  375. ("WARNING: AfpReadCMAlloced = %ld, AfpWriteCMAlloced %ld\n",
  376. AfpReadCMAlloced, AfpWriteCMAlloced));
  377. }
  378. #endif
  379. AfpServerState = AFP_STATE_STOPPED;
  380. } while (False);
  381. return STATUS_SUCCESS;
  382. }
  383. /*** AfpAdmServicePause
  384. *
  385. * Pause the server. Disconnect all outstanding sessions.
  386. */
  387. AFPSTATUS
  388. AfpAdmServicePause(
  389. IN OUT PVOID InBuf OPTIONAL,
  390. IN LONG OutBufLen OPTIONAL,
  391. OUT PVOID OutBuf OPTIONAL
  392. )
  393. {
  394. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  395. ("AfpAdmServicePause entered\n"));
  396. // make sure we are in the running state
  397. if (AfpServerState != AFP_STATE_RUNNING)
  398. {
  399. return AFPERR_InvalidServerState;
  400. }
  401. AfpServerState = AFP_STATE_PAUSE_PENDING;
  402. if (AfpServerBoundToAsp)
  403. {
  404. // Deregister our name on this address. Should we do this at all ? What
  405. // if we cannot re-register ourselves on CONTINUE ?
  406. AfpSpRegisterName(&AfpServerName, False);
  407. }
  408. // Disable listens now that we are paused
  409. AfpSpDisableListens();
  410. AfpServerState = AFP_STATE_PAUSED;
  411. return STATUS_SUCCESS;
  412. }
  413. /*** AfpAdmServiceContinue
  414. *
  415. * Continue (release pause) the server. Just re-post all the listens that were
  416. * disconnected when the server was paused.
  417. */
  418. AFPSTATUS
  419. AfpAdmServiceContinue(
  420. IN OUT PVOID InBuf OPTIONAL,
  421. IN LONG OutBufLen OPTIONAL,
  422. OUT PVOID OutBuf OPTIONAL
  423. )
  424. {
  425. AFPSTATUS Status;
  426. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  427. ("AfpAdmServiceContinue entered\n"));
  428. // make sure we are in the paused state
  429. if (AfpServerState != AFP_STATE_PAUSED)
  430. {
  431. return AFPERR_InvalidServerState;
  432. }
  433. AfpServerState = AFP_STATE_RUNNING;
  434. // Enable listens now that we are ready for it.
  435. AfpSpEnableListens();
  436. if (AfpServerBoundToAsp)
  437. {
  438. // Reregister our name on this address
  439. Status = AfpSpRegisterName(&AfpServerName, True);
  440. if (!NT_SUCCESS(Status))
  441. {
  442. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  443. ("AfpAdmServiceContinue: AfpSpRegisterName fails %lx\n",Status));
  444. return AFPERR_InvalidServerName;
  445. }
  446. }
  447. return STATUS_SUCCESS;
  448. }
  449. /*** AfpAdmServerGetInfo
  450. *
  451. * Return the current setting of the server parameters.
  452. *
  453. * NOTE: The following fields are not returned:
  454. * PagedLimit
  455. * NonPagedLimit
  456. * CodePage
  457. */
  458. AFPSTATUS
  459. AfpAdmServerGetInfo(
  460. IN OUT PVOID InBuf OPTIONAL,
  461. IN LONG OutBufLen OPTIONAL,
  462. OUT PVOID OutBuf OPTIONAL
  463. )
  464. {
  465. PAFP_SERVER_INFO pSrvrInfo = (PAFP_SERVER_INFO)OutBuf;
  466. UNICODE_STRING us;
  467. if ((DWORD)OutBufLen < (sizeof(AFP_SERVER_INFO) +
  468. (AfpServerName.Length + 1)*sizeof(WCHAR) +
  469. AfpLoginMsgU.MaximumLength))
  470. return AFPERR_BufferSize;
  471. pSrvrInfo->afpsrv_max_sessions = AfpServerMaxSessions;
  472. pSrvrInfo->afpsrv_options = AfpServerOptions;
  473. pSrvrInfo->afpsrv_name = NULL;
  474. pSrvrInfo->afpsrv_login_msg = NULL;
  475. if (AfpServerName.Length > 0)
  476. {
  477. pSrvrInfo->afpsrv_name = us.Buffer =
  478. (LPWSTR)((PBYTE)pSrvrInfo + sizeof(AFP_SERVER_INFO));
  479. us.MaximumLength = (AfpServerName.Length + 1) * sizeof(WCHAR);
  480. AfpConvertStringToUnicode(&AfpServerName, &us);
  481. POINTER_TO_OFFSET(pSrvrInfo->afpsrv_name, pSrvrInfo);
  482. }
  483. if ((AfpLoginMsgU.Length) > 0)
  484. {
  485. pSrvrInfo->afpsrv_login_msg = (PWCHAR)((PBYTE)pSrvrInfo + sizeof(AFP_SERVER_INFO) +
  486. ((AfpServerName.Length + 1) * sizeof(WCHAR)));
  487. RtlCopyMemory(pSrvrInfo->afpsrv_login_msg,
  488. AfpLoginMsgU.Buffer,
  489. AfpLoginMsgU.Length);
  490. pSrvrInfo->afpsrv_login_msg[AfpLoginMsgU.Length/sizeof(WCHAR)] = UNICODE_NULL;
  491. POINTER_TO_OFFSET(pSrvrInfo->afpsrv_login_msg, pSrvrInfo);
  492. }
  493. return AFP_ERR_NONE;
  494. }
  495. /*** AfpAdmGetStatistics
  496. *
  497. * Return a copy of the server global statistics (NT 3.1 only) in the output buffer
  498. *
  499. * LOCKS: AfpStatisticsLock (SPIN)
  500. */
  501. AFPSTATUS
  502. AfpAdmGetStatistics(
  503. IN OUT PVOID InBuf OPTIONAL,
  504. IN LONG OutBufLen OPTIONAL,
  505. OUT PVOID OutBuf OPTIONAL
  506. )
  507. {
  508. KIRQL OldIrql;
  509. NTSTATUS Status = STATUS_SUCCESS;
  510. AFPTIME TimeNow;
  511. InBuf;
  512. DBGPRINT(DBG_COMP_ADMINAPI_STAT, DBG_LEVEL_INFO,
  513. ("AfpAdmGetStatistics entered\n"));
  514. if (OutBufLen >= sizeof(AFP_STATISTICS_INFO))
  515. {
  516. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  517. RtlCopyMemory(OutBuf, &AfpServerStatistics, sizeof(AFP_STATISTICS_INFO));
  518. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  519. AfpGetCurrentTimeInMacFormat(&TimeNow);
  520. ((PAFP_STATISTICS_INFO)OutBuf)->stat_ServerStartTime =
  521. TimeNow - ((PAFP_STATISTICS_INFO)OutBuf)->stat_ServerStartTime;
  522. ((PAFP_STATISTICS_INFO)OutBuf)->stat_TimeStamp =
  523. TimeNow - ((PAFP_STATISTICS_INFO)OutBuf)->stat_TimeStamp;
  524. }
  525. else
  526. {
  527. Status = STATUS_BUFFER_TOO_SMALL;
  528. }
  529. return Status;
  530. }
  531. /*** AfpAdmGetStatisticsEx
  532. *
  533. * Return a copy of the server global statistics in the output buffer
  534. *
  535. * LOCKS: AfpStatisticsLock (SPIN)
  536. */
  537. AFPSTATUS
  538. AfpAdmGetStatisticsEx(
  539. IN OUT PVOID InBuf OPTIONAL,
  540. IN LONG OutBufLen OPTIONAL,
  541. OUT PVOID OutBuf OPTIONAL
  542. )
  543. {
  544. KIRQL OldIrql;
  545. NTSTATUS Status = STATUS_SUCCESS;
  546. AFPTIME TimeNow;
  547. InBuf;
  548. DBGPRINT(DBG_COMP_ADMINAPI_STAT, DBG_LEVEL_INFO,
  549. ("AfpAdmGetStatistics entered\n"));
  550. if (OutBufLen >= sizeof(AFP_STATISTICS_INFO_EX))
  551. {
  552. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  553. RtlCopyMemory(OutBuf, &AfpServerStatistics, sizeof(AFP_STATISTICS_INFO_EX));
  554. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  555. AfpGetCurrentTimeInMacFormat(&TimeNow);
  556. ((PAFP_STATISTICS_INFO_EX)OutBuf)->stat_ServerStartTime =
  557. TimeNow - ((PAFP_STATISTICS_INFO_EX)OutBuf)->stat_ServerStartTime;
  558. ((PAFP_STATISTICS_INFO_EX)OutBuf)->stat_TimeStamp =
  559. TimeNow - ((PAFP_STATISTICS_INFO_EX)OutBuf)->stat_TimeStamp;
  560. }
  561. else
  562. {
  563. Status = STATUS_BUFFER_TOO_SMALL;
  564. }
  565. return Status;
  566. }
  567. /*** AfpAdmClearStatistics
  568. *
  569. * Reset the server global statistics to their respective initial values
  570. */
  571. AFPSTATUS
  572. AfpAdmClearStatistics(
  573. IN OUT PVOID InBuf OPTIONAL,
  574. IN LONG OutBufLen OPTIONAL,
  575. OUT PVOID OutBuf OPTIONAL
  576. )
  577. {
  578. KIRQL OldIrql;
  579. DBGPRINT(DBG_COMP_ADMINAPI_STAT, DBG_LEVEL_INFO,
  580. ("AfpAdmClearStatistics entered\n"));
  581. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  582. AfpServerStatistics.stat_Errors = 0;
  583. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  584. return STATUS_SUCCESS;
  585. }
  586. /*** AfpAdmGetProfCounters
  587. *
  588. * Return a copy of the server profile counters.
  589. *
  590. * LOCKS: AfpStatisticsLock (SPIN)
  591. */
  592. AFPSTATUS
  593. AfpAdmGetProfCounters(
  594. IN OUT PVOID InBuf OPTIONAL,
  595. IN LONG OutBufLen OPTIONAL,
  596. OUT PVOID OutBuf OPTIONAL
  597. )
  598. {
  599. NTSTATUS Status = STATUS_SUCCESS;
  600. #ifdef PROFILING
  601. KIRQL OldIrql;
  602. DBGPRINT(DBG_COMP_ADMINAPI_STAT, DBG_LEVEL_INFO,
  603. ("AfpAdmGetProfCounters entered\n"));
  604. if (OutBufLen >= sizeof(AFP_PROFILE_INFO))
  605. {
  606. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  607. RtlCopyMemory(OutBuf, AfpServerProfile, sizeof(AFP_PROFILE_INFO));
  608. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  609. }
  610. else
  611. {
  612. Status = STATUS_BUFFER_TOO_SMALL;
  613. }
  614. #else
  615. RtlZeroMemory(OutBuf, sizeof(AFP_PROFILE_INFO));
  616. #endif
  617. return Status;
  618. }
  619. /*** AfpAdmClearProfCounters
  620. *
  621. * Reset the server profile counters
  622. */
  623. AFPSTATUS
  624. AfpAdmClearProfCounters(
  625. IN OUT PVOID InBuf OPTIONAL,
  626. IN LONG OutBufLen OPTIONAL,
  627. OUT PVOID OutBuf OPTIONAL
  628. )
  629. {
  630. InBuf;
  631. OutBufLen;
  632. OutBuf;
  633. // Currently a NOP
  634. PAGED_CODE( );
  635. DBGPRINT(DBG_COMP_ADMINAPI_STAT, DBG_LEVEL_INFO,
  636. ("AfpAdmClearProfCounters entered\n"));
  637. return STATUS_SUCCESS;
  638. }
  639. /*** AfpAdmServerSetParms
  640. *
  641. * This routine sets various server globals with data supplied by the admin.
  642. * The following server globals are set by this routine:
  643. *
  644. * - List of trusted domains and their Posix offsets.
  645. */
  646. AFPSTATUS
  647. AfpAdmServerSetParms(
  648. IN OUT PVOID InBuf OPTIONAL,
  649. IN LONG OutBufLen OPTIONAL,
  650. OUT PVOID OutBuf OPTIONAL
  651. )
  652. {
  653. PAFP_SID_OFFSET_DESC pSrvrParms = (PAFP_SID_OFFSET_DESC)InBuf;
  654. PAGED_CODE( );
  655. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  656. ("AfpAdmServerSetParms entered\n"));
  657. return (AfpInitSidOffsets(pSrvrParms->CountOfSidOffsets,
  658. pSrvrParms->SidOffsetPairs));
  659. }
  660. /*** AfpAdmServerAddEtc
  661. *
  662. * This routine adds a set of Extension/Type-Creator mappings to the global
  663. * list. This list can be changed while the server is in any state. It is
  664. * an error to add the default type creator mapping. The default mapping
  665. * can only be modified with AfpAdmServerSetEtc, never added nor deleted.
  666. * It is an error to try to add zero entries.
  667. *
  668. * This routine will complete in the context of the caller, and not be queued
  669. * to a worker thread.
  670. *
  671. * LOCKS: AfpEtcMapLock (SWMR, Exclusive)
  672. **/
  673. AFPSTATUS
  674. AfpAdmServerAddEtc(
  675. IN OUT PVOID InBuf OPTIONAL,
  676. IN LONG OutBufLen OPTIONAL,
  677. OUT PVOID OutBuf OPTIONAL
  678. )
  679. {
  680. LONG NumToAdd = ((PSRVETCPKT)InBuf)->retc_NumEtcMaps;
  681. PETCMAPINFO2 pEtcList = ((PSRVETCPKT)InBuf)->retc_EtcMaps;
  682. PETCMAPINFO ptemptable,pnextfree;
  683. LONG numfree, newtablesize, nextfreehint, i;
  684. UNICODE_STRING udefaultext,ulookupext;
  685. AFPSTATUS Status = AFPERR_InvalidParms;
  686. BOOLEAN UnlockSwmr = False;
  687. PAGED_CODE( );
  688. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  689. ("AfpAdmServerAddEtc entered\n"));
  690. if (NumToAdd != 0) do
  691. {
  692. //
  693. // make sure all the entries passed have valid extensions. We want to
  694. // add all or nothing, so we have to validate all of the data first thing.
  695. //
  696. RtlInitUnicodeString(&udefaultext, AFP_DEF_EXTENSION_W);
  697. for (i = 0; i < NumToAdd; i++)
  698. {
  699. if (!afpIsValidExtension(pEtcList[i].etc_extension))
  700. {
  701. break;
  702. }
  703. RtlInitUnicodeString(&ulookupext,pEtcList[i].etc_extension);
  704. if (RtlEqualUnicodeString(&udefaultext, &ulookupext,True))
  705. {
  706. break;
  707. }
  708. }
  709. if (i != NumToAdd)
  710. break;
  711. AfpSwmrAcquireExclusive(&AfpEtcMapLock);
  712. UnlockSwmr = True;
  713. if ((NumToAdd + AfpEtcMapCount) > AFP_MAX_ETCMAP_ENTRIES)
  714. {
  715. Status = AFPERR_TooManyEtcMaps;
  716. break;
  717. }
  718. if ((numfree = AfpEtcMapsSize - AfpEtcMapCount) < NumToAdd)
  719. {
  720. ASSERT(numfree >= 0);
  721. //
  722. // we need to add some room to the table
  723. //
  724. newtablesize = AfpEtcMapsSize +
  725. ((NumToAdd / AFP_MAX_FREE_ETCMAP_ENTRIES) + 1) * AFP_MAX_FREE_ETCMAP_ENTRIES;
  726. if ((ptemptable = (PETCMAPINFO)AfpAllocZeroedPagedMemory(newtablesize * sizeof(ETCMAPINFO))) == NULL)
  727. {
  728. Status = STATUS_INSUFFICIENT_RESOURCES;
  729. break;
  730. }
  731. if (AfpEtcMaps != NULL)
  732. {
  733. RtlCopyMemory(ptemptable, AfpEtcMaps, AfpEtcMapsSize * sizeof(ETCMAPINFO));
  734. AfpFreeMemory(AfpEtcMaps);
  735. }
  736. AfpEtcMaps = ptemptable;
  737. AfpEtcMapsSize = newtablesize;
  738. }
  739. nextfreehint = 0;
  740. for (i = 0; i < NumToAdd; i++)
  741. {
  742. pnextfree = afpGetNextFreeEtcMapEntry(&nextfreehint);
  743. ASSERT(pnextfree != NULL);
  744. afpCopyMapInfo2ToMapInfo(pnextfree, &pEtcList[i]);
  745. AfpEtcMapCount ++;
  746. }
  747. Status = STATUS_SUCCESS;
  748. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  749. ("AfpAdmServerAddEtc successful\n"));
  750. } while (False);
  751. if (UnlockSwmr)
  752. AfpSwmrRelease(&AfpEtcMapLock);
  753. return Status;
  754. }
  755. /*** AfpAdmServerSetEtc
  756. *
  757. * This routine changes an existing entry in the server global
  758. * Extension/Type-Creator mapping list for a given file extension, or the
  759. * default type/creator mapping.
  760. * An entry can be changed while the server is in any state.
  761. *
  762. * This routine will complete in the context of the caller, and not be queued
  763. * to a worker thread.
  764. *
  765. * LOCKS: AfpEtcMapLock (SWMR, Exclusive)
  766. */
  767. AFPSTATUS
  768. AfpAdmServerSetEtc(
  769. IN OUT PVOID InBuf OPTIONAL,
  770. IN LONG OutBufLen OPTIONAL,
  771. OUT PVOID OutBuf OPTIONAL
  772. )
  773. {
  774. // ignore the parmnum field
  775. PETCMAPINFO2 pEtc = (PETCMAPINFO2)((PBYTE)InBuf+sizeof(SETINFOREQPKT));
  776. PETCMAPINFO petcentry;
  777. ETCMAPINFO TmpEtcEntry;
  778. AFPSTATUS rc = STATUS_SUCCESS;
  779. BOOLEAN setdefaultetc;
  780. UNICODE_STRING ulookupext,udefaultext;
  781. PAGED_CODE( );
  782. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  783. ("AfpAdmServerSetEtc entered\n"));
  784. if (!afpIsValidExtension(pEtc->etc_extension))
  785. {
  786. return AFPERR_InvalidExtension;
  787. }
  788. RtlInitUnicodeString(&udefaultext,AFP_DEF_EXTENSION_W);
  789. RtlInitUnicodeString(&ulookupext,pEtc->etc_extension);
  790. setdefaultetc = RtlEqualUnicodeString(&udefaultext, &ulookupext,True);
  791. if (setdefaultetc)
  792. {
  793. petcentry = &AfpDefaultEtcMap;
  794. }
  795. AfpSwmrAcquireExclusive(&AfpEtcMapLock);
  796. afpCopyMapInfo2ToMapInfo(&TmpEtcEntry,pEtc);
  797. if (!setdefaultetc)
  798. {
  799. petcentry = AfpLookupEtcMapEntry(TmpEtcEntry.etc_extension);
  800. if (petcentry == NULL)
  801. {
  802. AfpSwmrRelease(&AfpEtcMapLock);
  803. return AFPERR_InvalidParms;
  804. }
  805. }
  806. RtlCopyMemory(petcentry, &TmpEtcEntry, sizeof(ETCMAPINFO));
  807. AfpSwmrRelease(&AfpEtcMapLock);
  808. return rc;
  809. }
  810. /*** AfpAdmServerDeleteEtc
  811. *
  812. * This routine deletes the server global Extension/Type-Creator mapping entry
  813. * for a given extension. The default type creator mapping can never be
  814. * deleted (since it is not kept in the table).
  815. *
  816. * This routine will complete in the context of the caller, and not be queued
  817. * to a worker thread.
  818. *
  819. * LOCKS: AfpEtcMapLock (SWMR, Exclusive)
  820. *
  821. */
  822. AFPSTATUS
  823. AfpAdmServerDeleteEtc(
  824. IN OUT PVOID InBuf OPTIONAL,
  825. IN LONG OutBufLen OPTIONAL,
  826. OUT PVOID OutBuf OPTIONAL
  827. )
  828. {
  829. PETCMAPINFO2 petc = (PETCMAPINFO2)InBuf;
  830. PETCMAPINFO petcentry;
  831. ETCMAPINFO TmpEtcEntry;
  832. AFPSTATUS rc = STATUS_SUCCESS;
  833. PAGED_CODE( );
  834. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  835. ("AfpAdmServerDeleteEtc entered\n"));
  836. if (!afpIsValidExtension(petc->etc_extension))
  837. {
  838. return AFPERR_InvalidParms;
  839. }
  840. AfpSwmrAcquireExclusive(&AfpEtcMapLock);
  841. afpCopyMapInfo2ToMapInfo(&TmpEtcEntry,petc);
  842. petcentry = AfpLookupEtcMapEntry(TmpEtcEntry.etc_extension);
  843. if (petcentry != NULL)
  844. {
  845. afpEtcMapDelete(petcentry);
  846. }
  847. else
  848. {
  849. rc = AFPERR_InvalidParms;
  850. }
  851. AfpSwmrRelease(&AfpEtcMapLock);
  852. return rc;
  853. }
  854. // Mapping icon types to their sizes
  855. LOCAL DWORD afpIconSizeTable[MAX_ICONTYPE] =
  856. {
  857. ICONSIZE_ICN ,
  858. ICONSIZE_ICN ,
  859. ICONSIZE_ICN4,
  860. ICONSIZE_ICN8,
  861. ICONSIZE_ICS ,
  862. ICONSIZE_ICS4,
  863. ICONSIZE_ICS8
  864. };
  865. /*** AfpAdmServerAddIcon
  866. *
  867. * This routine adds an icon of a given type, creator and icon type to the server
  868. * desktop. This supplements the volume desktop of every volume. An icon type
  869. * of 0 special cases to the server icon.
  870. *
  871. * This routine will complete in the context of the caller, and not be queued
  872. * to a worker thread.
  873. *
  874. */
  875. AFPSTATUS
  876. AfpAdmServerAddIcon(
  877. IN OUT PVOID InBuf OPTIONAL,
  878. IN LONG OutBufLen OPTIONAL,
  879. OUT PVOID OutBuf OPTIONAL
  880. )
  881. {
  882. DWORD icontypeafp;
  883. PSRVICONINFO pIcon = (PSRVICONINFO)InBuf;
  884. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  885. ("AfpAdmServerAddIcon entered\n"));
  886. if (pIcon->icon_icontype > MAX_ICONTYPE ||
  887. afpIconSizeTable[pIcon->icon_icontype] != pIcon->icon_length)
  888. {
  889. return AFPERR_InvalidParms;
  890. }
  891. //
  892. // check for the server icon (type is zero)
  893. //
  894. if (afpIsServerIcon(pIcon))
  895. {
  896. // Allocate memory for server icon
  897. if ((AfpServerIcon == NULL) &&
  898. (AfpServerIcon = AfpAllocNonPagedMemory(ICONSIZE_ICN)) == NULL)
  899. return STATUS_INSUFFICIENT_RESOURCES;
  900. RtlCopyMemory(AfpServerIcon,
  901. (PBYTE)pIcon+sizeof(SRVICONINFO),
  902. ICONSIZE_ICN);
  903. return((AfpServerState != AFP_STATE_IDLE) ?
  904. AfpSetServerStatus() : STATUS_SUCCESS);
  905. }
  906. else
  907. {
  908. icontypeafp = 1 << (pIcon->icon_icontype-1);
  909. return(AfpAddIconToGlobalList(*(PDWORD)(&pIcon->icon_type),
  910. *(PDWORD)(&pIcon->icon_creator),
  911. icontypeafp,
  912. pIcon->icon_length,
  913. (PBYTE)pIcon+sizeof(SRVICONINFO)));
  914. }
  915. }
  916. /*** AfpAdmVolumeAdd
  917. *
  918. * This routine adds a volume to the server global list of volumes headed by
  919. * AfpVolumeList. The volume descriptor is created and initialized. The ID
  920. * index is read in (or created). The same is true with the desktop.
  921. *
  922. * It is assumed that all volume info fields are set in the input buffer
  923. *
  924. * ADMIN QUEUE WORKER: AfpAdmWVolumeAdd
  925. *
  926. */
  927. AFPSTATUS
  928. AfpAdmVolumeAdd(
  929. IN OUT PVOID InBuf OPTIONAL,
  930. IN LONG OutBufLen OPTIONAL,
  931. OUT PVOID OutBuf OPTIONAL
  932. )
  933. {
  934. UNICODE_STRING uname,upwd;
  935. ULONG ansinamelen, ansipwdlen;
  936. PAFP_VOLUME_INFO pVolInfo = (PAFP_VOLUME_INFO)InBuf;
  937. PAGED_CODE( );
  938. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  939. ("AfpAdmVolumeAdd entered\n"));
  940. //
  941. // validate the input data
  942. //
  943. RtlInitUnicodeString(&uname, pVolInfo->afpvol_name);
  944. ansinamelen = RtlUnicodeStringToAnsiSize(&uname) - 1;
  945. //
  946. // check length of volume name and that no ":" exist in the name
  947. //
  948. if ((ansinamelen > AFP_VOLNAME_LEN) || (ansinamelen == 0) ||
  949. (wcschr(uname.Buffer, L':') != NULL))
  950. {
  951. return AFPERR_InvalidVolumeName;
  952. }
  953. if (pVolInfo->afpvol_props_mask & ~AFP_VOLUME_ALL)
  954. return AFPERR_InvalidParms;
  955. if ((pVolInfo->afpvol_max_uses == 0) ||
  956. (pVolInfo->afpvol_max_uses > AFP_VOLUME_UNLIMITED_USES))
  957. {
  958. return AFPERR_InvalidParms_MaxVolUses;
  959. }
  960. RtlInitUnicodeString(&upwd, pVolInfo->afpvol_password);
  961. ansipwdlen = RtlUnicodeStringToAnsiSize(&upwd) - 1;
  962. if (ansipwdlen > AFP_VOLPASS_LEN)
  963. {
  964. return AFPERR_InvalidPassword;
  965. }
  966. else if (ansipwdlen > 0)
  967. {
  968. pVolInfo->afpvol_props_mask |= AFP_VOLUME_HASPASSWORD;
  969. }
  970. //
  971. // Force this to be queued up to a worker thread.
  972. //
  973. return STATUS_PENDING;
  974. }
  975. /*** AfpAdmVolumeSetInfo
  976. *
  977. * The volume parameters that can be changed by this call are the volume
  978. * password, max_uses and volume properties mask.
  979. *
  980. * LOCKS: AfpVolumeListLock (SPIN), vds_VolLock (SPIN)
  981. * LOCK ORDER: vds_VolLock after AfpVolumeListLock
  982. *
  983. */
  984. AFPSTATUS
  985. AfpAdmVolumeSetInfo(
  986. IN OUT PVOID InBuf OPTIONAL,
  987. IN LONG OutBufLen OPTIONAL,
  988. OUT PVOID OutBuf OPTIONAL
  989. )
  990. {
  991. WCHAR upcasebuf[AFP_VOLNAME_LEN+1];
  992. UNICODE_STRING upwd,uname, upcasename;
  993. BYTE apwdbuf[AFP_VOLPASS_LEN+1];
  994. ANSI_STRING apwd;
  995. PVOLDESC pVolDesc;
  996. AFPSTATUS status;
  997. KIRQL OldIrql;
  998. DWORD parmflags = ((PSETINFOREQPKT)InBuf)->sirqp_parmnum;
  999. PAFP_VOLUME_INFO pVolInfo = (PAFP_VOLUME_INFO)((PCHAR)InBuf+sizeof(SETINFOREQPKT));
  1000. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  1001. ("AfpAdmVolumeSetInfo entered\n"));
  1002. AfpSetEmptyAnsiString(&apwd, AFP_VOLPASS_LEN+1, apwdbuf);
  1003. AfpSetEmptyUnicodeString(&upcasename, sizeof(upcasebuf), upcasebuf);
  1004. if ((parmflags & ~AFP_VOL_PARMNUM_ALL) ||
  1005. ((parmflags & AFP_VOL_PARMNUM_PROPSMASK) &&
  1006. (pVolInfo->afpvol_props_mask & ~AFP_VOLUME_ALL)) ||
  1007. ((parmflags & AFP_VOL_PARMNUM_MAXUSES) &&
  1008. ((pVolInfo->afpvol_max_uses == 0) ||
  1009. (pVolInfo->afpvol_max_uses > AFP_VOLUME_UNLIMITED_USES))))
  1010. {
  1011. return AFPERR_InvalidParms;
  1012. }
  1013. if (parmflags & AFP_VOL_PARMNUM_PASSWORD)
  1014. {
  1015. RtlInitUnicodeString(&upwd,pVolInfo->afpvol_password);
  1016. if ((!NT_SUCCESS(AfpConvertStringToAnsi(&upwd, &apwd))) ||
  1017. (apwd.Length > AFP_VOLPASS_LEN))
  1018. {
  1019. return AFPERR_InvalidPassword;
  1020. }
  1021. }
  1022. RtlInitUnicodeString(&uname, pVolInfo->afpvol_name);
  1023. if (!NT_SUCCESS(RtlUpcaseUnicodeString(&upcasename, &uname, False)))
  1024. {
  1025. return AFPERR_InvalidVolumeName;
  1026. }
  1027. // Will reference the volume if successful
  1028. if ((pVolDesc = AfpVolumeReferenceByUpCaseName(&upcasename)) == NULL)
  1029. {
  1030. return AFPERR_VolumeNonExist;
  1031. }
  1032. // Acquire the lock for the volume itself (we already have a reference)
  1033. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  1034. do
  1035. {
  1036. status = STATUS_SUCCESS;
  1037. if (parmflags & AFP_VOL_PARMNUM_PROPSMASK)
  1038. {
  1039. //
  1040. // set or clear the desired volume property bits
  1041. //
  1042. pVolDesc->vds_Flags = (USHORT)((pVolDesc->vds_Flags & ~AFP_VOLUME_ALL) |
  1043. (pVolInfo->afpvol_props_mask));
  1044. }
  1045. if (parmflags & AFP_VOL_PARMNUM_PASSWORD)
  1046. {
  1047. if (apwd.Length == 0)
  1048. {
  1049. pVolDesc->vds_MacPassword.Length = 0;
  1050. pVolDesc->vds_Flags &= ~AFP_VOLUME_HASPASSWORD;
  1051. pVolDesc->vds_MacPassword.Length = 0;
  1052. }
  1053. else
  1054. {
  1055. RtlZeroMemory(pVolDesc->vds_MacPassword.Buffer, AFP_VOLPASS_LEN);
  1056. AfpCopyAnsiString(&pVolDesc->vds_MacPassword, &apwd);
  1057. pVolDesc->vds_MacPassword.Length = AFP_VOLPASS_LEN;
  1058. pVolDesc->vds_Flags |= AFP_VOLUME_HASPASSWORD;
  1059. }
  1060. }
  1061. if (parmflags & AFP_VOL_PARMNUM_MAXUSES)
  1062. pVolDesc->vds_MaxUses = pVolInfo->afpvol_max_uses;
  1063. } while (False);
  1064. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock,OldIrql);
  1065. AfpVolumeDereference(pVolDesc);
  1066. return status;
  1067. }
  1068. /*** AfpAdmVolumeGetInfo
  1069. *
  1070. *
  1071. * LOCKS: AfpVolumeListLock (SPIN), vds_VolLock (SPIN)
  1072. * LOCK ORDER: vds_VolLock after AfpVolumeListLock
  1073. */
  1074. AFPSTATUS
  1075. AfpAdmVolumeGetInfo(
  1076. IN OUT PVOID InBuf OPTIONAL,
  1077. IN LONG OutBufLen OPTIONAL,
  1078. OUT PVOID OutBuf OPTIONAL
  1079. )
  1080. {
  1081. PVOLDESC pVolDesc;
  1082. AFPSTATUS Status;
  1083. KIRQL OldIrql;
  1084. PCHAR pCurStr;
  1085. WCHAR upcasebuf[AFP_VOLNAME_LEN+1];
  1086. UNICODE_STRING uvolpass, uname, upcasename;
  1087. PAFP_VOLUME_INFO pVolInfo = (PAFP_VOLUME_INFO)OutBuf;
  1088. BOOLEAN copypassword = False;
  1089. ANSI_STRING avolpass;
  1090. CHAR avolpassbuf[AFP_VOLPASS_LEN + 1];
  1091. USHORT extrabytes;
  1092. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  1093. ("AfpAdmVolumeGetInfo entered\n"));
  1094. AfpSetEmptyUnicodeString(&upcasename, sizeof(upcasebuf), upcasebuf);
  1095. RtlInitUnicodeString(&uname, ((PAFP_VOLUME_INFO)InBuf)->afpvol_name);
  1096. if (!NT_SUCCESS(RtlUpcaseUnicodeString(&upcasename, &uname, False)))
  1097. {
  1098. return AFPERR_InvalidVolumeName;
  1099. }
  1100. // Will reference the volume if successful
  1101. if ((pVolDesc = AfpVolumeReferenceByUpCaseName(&upcasename)) == NULL)
  1102. {
  1103. return AFPERR_VolumeNonExist;
  1104. }
  1105. // Acquire the lock for the volume itself
  1106. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  1107. do
  1108. {
  1109. if ((OutBufLen - sizeof(AFP_VOLUME_INFO)) <
  1110. (pVolDesc->vds_Name.Length + sizeof(UNICODE_NULL) +
  1111. (pVolDesc->vds_MacPassword.Length + 1) * sizeof(WCHAR) +
  1112. pVolDesc->vds_Path.Length +
  1113. (extrabytes =
  1114. (pVolDesc->vds_Path.Buffer[(pVolDesc->vds_Path.Length / sizeof(WCHAR)) - 2] == L':' ?
  1115. sizeof(WCHAR) : 0)) + sizeof(UNICODE_NULL)))
  1116. {
  1117. Status = AFPERR_BufferSize;
  1118. break;
  1119. }
  1120. Status = STATUS_SUCCESS;
  1121. pVolInfo->afpvol_max_uses = pVolDesc->vds_MaxUses;
  1122. pVolInfo->afpvol_props_mask = (pVolDesc->vds_Flags & AFP_VOLUME_ALL_DOWNLEVEL);
  1123. pVolInfo->afpvol_id = pVolDesc->vds_VolId;
  1124. pVolInfo->afpvol_curr_uses = pVolDesc->vds_UseCount;
  1125. pCurStr = (PBYTE)OutBuf + sizeof(AFP_VOLUME_INFO);
  1126. RtlCopyMemory(pCurStr, pVolDesc->vds_Name.Buffer,
  1127. pVolDesc->vds_Name.Length);
  1128. *(LPWSTR)(pCurStr + pVolDesc->vds_Name.Length) = UNICODE_NULL;
  1129. pVolInfo->afpvol_name = (LPWSTR)pCurStr;
  1130. POINTER_TO_OFFSET(pVolInfo->afpvol_name,pVolInfo);
  1131. pCurStr += pVolDesc->vds_Name.Length + sizeof(WCHAR);
  1132. RtlCopyMemory(pCurStr, pVolDesc->vds_Path.Buffer,
  1133. pVolDesc->vds_Path.Length);
  1134. // replace trailing backslash of path with a unicode null unless the
  1135. // next to last char is ':', then keep it and add a trailing null
  1136. *(LPWSTR)(pCurStr + pVolDesc->vds_Path.Length + extrabytes - sizeof(WCHAR)) = UNICODE_NULL;
  1137. pVolInfo->afpvol_path = (LPWSTR)pCurStr;
  1138. POINTER_TO_OFFSET(pVolInfo->afpvol_path,pVolInfo);
  1139. pCurStr += pVolDesc->vds_Path.Length + extrabytes;
  1140. copypassword = True;
  1141. uvolpass.Buffer = (LPWSTR)pCurStr;
  1142. uvolpass.MaximumLength = (pVolDesc->vds_MacPassword.Length + 1) * sizeof(WCHAR);
  1143. AfpSetEmptyAnsiString(&avolpass, sizeof(avolpassbuf), avolpassbuf);
  1144. AfpCopyAnsiString(&avolpass, &pVolDesc->vds_MacPassword);
  1145. } while(False);
  1146. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock,OldIrql);
  1147. AfpVolumeDereference(pVolDesc);
  1148. if (copypassword == True)
  1149. {
  1150. AfpConvertStringToUnicode(&avolpass, &uvolpass);
  1151. *(LPWSTR)(pCurStr + uvolpass.Length) = UNICODE_NULL;
  1152. pVolInfo->afpvol_password = (LPWSTR)pCurStr;
  1153. POINTER_TO_OFFSET(pVolInfo->afpvol_password,pVolInfo);
  1154. }
  1155. return Status;
  1156. }
  1157. /*** AfpAdmVolumeEnum
  1158. *
  1159. * Enumerate the list of configured volumes.
  1160. *
  1161. * LOCKS: AfpVolumeListLock (SPIN)
  1162. *
  1163. */
  1164. AFPSTATUS
  1165. AfpAdmVolumeEnum(
  1166. IN OUT PVOID InBuf OPTIONAL,
  1167. IN LONG OutBufLen OPTIONAL,
  1168. OUT PVOID OutBuf OPTIONAL
  1169. )
  1170. {
  1171. LONG startindex = (LONG)(((PENUMREQPKT)InBuf)->erqp_Index);
  1172. PENUMRESPPKT pErsp = (PENUMRESPPKT)OutBuf;
  1173. PAFP_VOLUME_INFO pnextvol = (PAFP_VOLUME_INFO)((PBYTE)OutBuf+sizeof(ENUMRESPPKT));
  1174. PBYTE pCurStr = (PBYTE)OutBuf+OutBufLen; // 1 past eob
  1175. KIRQL OldIrql;
  1176. AFPSTATUS status = STATUS_SUCCESS;
  1177. PVOLDESC pVolDesc;
  1178. LONG bytesleft, curvolindex, nextvollen, deadvolumes = 0, extrabytes;
  1179. if (startindex == 0)
  1180. {
  1181. startindex ++;
  1182. }
  1183. else if (startindex < 0)
  1184. {
  1185. return AFPERR_InvalidParms;
  1186. }
  1187. pErsp->ersp_cInBuf = 0;
  1188. pErsp->ersp_hResume = 1;
  1189. ACQUIRE_SPIN_LOCK(&AfpVolumeListLock, &OldIrql);
  1190. if (startindex > afpLargestVolIdInUse)
  1191. {
  1192. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  1193. if (pErsp->ersp_cTotEnts != 0)
  1194. {
  1195. status = AFPERR_InvalidParms;
  1196. }
  1197. return status;
  1198. }
  1199. curvolindex = 1;
  1200. for (pVolDesc = AfpVolumeList;
  1201. pVolDesc != NULL;
  1202. curvolindex++, pVolDesc = pVolDesc->vds_Next)
  1203. {
  1204. ASSERT(pVolDesc != NULL);
  1205. ACQUIRE_SPIN_LOCK_AT_DPC(&pVolDesc->vds_VolLock);
  1206. if (pVolDesc->vds_Flags & (VOLUME_DELETED | VOLUME_STOPPED | VOLUME_INTRANSITION))
  1207. {
  1208. deadvolumes ++;
  1209. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  1210. continue;
  1211. }
  1212. if (curvolindex < startindex)
  1213. {
  1214. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  1215. continue;
  1216. }
  1217. bytesleft = (LONG)((PBYTE)pCurStr - (PBYTE)pnextvol);
  1218. nextvollen = sizeof(AFP_VOLUME_INFO) +
  1219. pVolDesc->vds_Name.MaximumLength +
  1220. // replace trailing backslash with a null when copying
  1221. // unless the next to last char is ':', then keep it and
  1222. // add a trailing null
  1223. pVolDesc->vds_Path.Length + (extrabytes =
  1224. (pVolDesc->vds_Path.Buffer[(pVolDesc->vds_Path.Length / sizeof(WCHAR)) - 2] == L':' ?
  1225. sizeof(WCHAR) : 0));
  1226. if (nextvollen > bytesleft)
  1227. {
  1228. if (pErsp->ersp_cInBuf == 0)
  1229. status = AFPERR_BufferSize;
  1230. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  1231. break;
  1232. }
  1233. pnextvol->afpvol_max_uses = pVolDesc->vds_MaxUses;
  1234. pnextvol->afpvol_props_mask = (pVolDesc->vds_Flags & AFP_VOLUME_ALL_DOWNLEVEL);
  1235. pnextvol->afpvol_id = pVolDesc->vds_VolId;
  1236. pnextvol->afpvol_curr_uses = pVolDesc->vds_UseCount;
  1237. pCurStr -= pVolDesc->vds_Path.Length + extrabytes;
  1238. RtlCopyMemory(pCurStr,pVolDesc->vds_Path.Buffer,
  1239. pVolDesc->vds_Path.Length);
  1240. *(LPWSTR)(pCurStr + pVolDesc->vds_Path.Length + extrabytes - sizeof(WCHAR)) = L'\0';
  1241. pnextvol->afpvol_path = (LPWSTR)pCurStr;
  1242. POINTER_TO_OFFSET(pnextvol->afpvol_path,pnextvol);
  1243. pnextvol->afpvol_password = NULL;
  1244. pCurStr -= pVolDesc->vds_Name.MaximumLength;
  1245. RtlCopyMemory(pCurStr,pVolDesc->vds_Name.Buffer,
  1246. pVolDesc->vds_Name.MaximumLength);
  1247. pnextvol->afpvol_name = (LPWSTR)pCurStr;
  1248. POINTER_TO_OFFSET(pnextvol->afpvol_name,pnextvol);
  1249. pnextvol++;
  1250. pErsp->ersp_cInBuf++;
  1251. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  1252. }
  1253. pErsp->ersp_cTotEnts = AfpVolCount - deadvolumes;
  1254. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  1255. if (curvolindex <= (LONG)pErsp->ersp_cTotEnts)
  1256. {
  1257. status = STATUS_MORE_ENTRIES;
  1258. pErsp->ersp_hResume = curvolindex;
  1259. }
  1260. else
  1261. pErsp->ersp_hResume = 1;
  1262. return status;
  1263. }
  1264. /*** AfpAdmSessionEnum
  1265. *
  1266. * Enumerate the list of active sessions. This is a linear list rooted
  1267. * at AfpSessionList and protected by AfpSdaLock. This list is potentially
  1268. * pretty long (Unlimited # of sessions with the super ASP stuff).
  1269. *
  1270. * The resume handle returned is the session id of the last session returned.
  1271. * Session Id of 0 implies restart scan.
  1272. *
  1273. * The output buffer is constructed as follows.
  1274. *
  1275. * +---------------------------+
  1276. * | Session_Info_1 |
  1277. * +---------------------------+
  1278. * | Session_Info_2 |
  1279. * +---------------------------+
  1280. * . .
  1281. * . .
  1282. * +---------------------------+
  1283. * | Session_Info_n |
  1284. * +---------------------------+
  1285. * . .
  1286. * . .
  1287. * +---------------------------+
  1288. * | |
  1289. * |...........................|
  1290. * | Strings |
  1291. * |...........................|
  1292. * | |
  1293. * | |
  1294. * +---------------------------+
  1295. *
  1296. * LOCKS: AfpSdaLock (SPIN)
  1297. */
  1298. AFPSTATUS
  1299. AfpAdmSessionEnum(
  1300. IN OUT PVOID InBuf OPTIONAL,
  1301. IN LONG OutBufLen OPTIONAL,
  1302. OUT PVOID OutBuf OPTIONAL
  1303. )
  1304. {
  1305. PENUMRESPPKT pErsp = (PENUMRESPPKT)OutBuf;
  1306. PAFP_SESSION_INFO pSessInfo = (PAFP_SESSION_INFO)((PBYTE)OutBuf+sizeof(ENUMRESPPKT));
  1307. PSDA pSda;
  1308. PBYTE pString = (PBYTE)OutBuf+OutBufLen; // 1 past eob
  1309. DWORD StartId = (LONG)(((PENUMREQPKT)InBuf)->erqp_Index);
  1310. DWORD DeadSessions = 0;
  1311. KIRQL OldIrql;
  1312. AFPSTATUS Status = AFP_ERR_NONE;
  1313. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  1314. ("AfpAdmSessionEnum entered\n"));
  1315. if (OutBufLen < (sizeof(ENUMRESPPKT) + sizeof(PAFP_SESSION_INFO)))
  1316. return AFPERR_BufferSize;
  1317. if (StartId == 0)
  1318. StartId = MAXULONG;
  1319. // Initialize the response packet header
  1320. pErsp->ersp_cInBuf = 0;
  1321. pErsp->ersp_hResume = 0;
  1322. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  1323. for (pSda = AfpSessionList; pSda != NULL; pSda = pSda->sda_Next)
  1324. {
  1325. LONG BytesLeft;
  1326. LONG BytesNeeded;
  1327. // Skip entries that are marked to die
  1328. if ((pSda->sda_Flags & SDA_CLOSING) ||
  1329. !(pSda->sda_Flags & SDA_USER_LOGGEDIN))
  1330. {
  1331. DeadSessions++;
  1332. continue;
  1333. }
  1334. // Skip all entries we have looked at before
  1335. if (pSda->sda_SessionId > StartId)
  1336. continue;
  1337. // If there is not enough space in the buffer, abort now and
  1338. // initialize pErsp->ersp_hResume with the current session id
  1339. BytesLeft = (LONG)((PBYTE)pString - (PBYTE)pSessInfo);
  1340. BytesNeeded = sizeof(AFP_SESSION_INFO) +
  1341. pSda->sda_UserName.Length + sizeof(WCHAR) +
  1342. pSda->sda_WSName.Length + sizeof(WCHAR);
  1343. if ((BytesLeft <= 0) || (BytesNeeded > BytesLeft))
  1344. {
  1345. pErsp->ersp_hResume = pSda->sda_SessionId;
  1346. Status = STATUS_MORE_ENTRIES;
  1347. break;
  1348. }
  1349. StartId = pSda->sda_SessionId;
  1350. pSessInfo->afpsess_id = pSda->sda_SessionId;
  1351. pSessInfo->afpsess_num_cons = pSda->sda_cOpenVolumes;
  1352. pSessInfo->afpsess_num_opens = pSda->sda_cOpenForks;
  1353. pSessInfo->afpsess_logon_type = pSda->sda_ClientType;
  1354. AfpGetCurrentTimeInMacFormat(&pSessInfo->afpsess_time);
  1355. pSessInfo->afpsess_time -= pSda->sda_TimeLoggedOn;
  1356. // Copy the strings here
  1357. pSessInfo->afpsess_username = NULL;
  1358. pSessInfo->afpsess_ws_name = NULL;
  1359. if (pSda->sda_UserName.Length > 0)
  1360. {
  1361. pString -= (pSda->sda_UserName.Length + sizeof(WCHAR));
  1362. if (pSda->sda_UserName.Length > 0)
  1363. RtlCopyMemory(pString, pSda->sda_UserName.Buffer, pSda->sda_UserName.Length);
  1364. *(LPWSTR)(pString + pSda->sda_UserName.Length) = L'\0';
  1365. pSessInfo->afpsess_username = (LPWSTR)pString;
  1366. POINTER_TO_OFFSET(pSessInfo->afpsess_username, pSessInfo);
  1367. }
  1368. if ((pSda->sda_ClientType == SDA_CLIENT_MSUAM_V1) ||
  1369. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V2))
  1370. {
  1371. pString -= (pSda->sda_WSName.Length + sizeof(WCHAR));
  1372. if (pSda->sda_WSName.Length > 0)
  1373. RtlCopyMemory(pString, pSda->sda_WSName.Buffer, pSda->sda_WSName.Length);
  1374. *(LPWSTR)(pString + pSda->sda_WSName.Length) = L'\0';
  1375. pSessInfo->afpsess_ws_name = (LPWSTR)pString;
  1376. POINTER_TO_OFFSET(pSessInfo->afpsess_ws_name, pSessInfo);
  1377. }
  1378. pSessInfo ++;
  1379. pErsp->ersp_cInBuf ++;
  1380. }
  1381. // Fill up the response packet header
  1382. pErsp->ersp_cTotEnts = (DWORD)AfpNumSessions - DeadSessions;
  1383. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  1384. return Status;
  1385. }
  1386. /*** AfpAdmConnectionEnum
  1387. *
  1388. * Enumerate the list of active connections. This is a linear list rooted
  1389. * at AfpConnList and protected by AfpConnLock. This list is potentially
  1390. * pretty long (Unlimited # of sessions with the super ASP stuff).
  1391. *
  1392. * For that reason once every pass we check to see if we must forego the lock
  1393. * and restart scan again. The assumption here is that the admin operation can
  1394. * take a hit.
  1395. *
  1396. * The resume handle returned is the connection id of the last connection
  1397. * returned. connection Id of 0 implies restart scan.
  1398. *
  1399. * The output buffer is constructed as follows.
  1400. *
  1401. * +---------------------------+
  1402. * | Connection_Info_1 |
  1403. * +---------------------------+
  1404. * | Connection_Info_2 |
  1405. * +---------------------------+
  1406. * . .
  1407. * . .
  1408. * +---------------------------+
  1409. * | Connection_Info_n |
  1410. * +---------------------------+
  1411. * . .
  1412. * . .
  1413. * +---------------------------+
  1414. * | |
  1415. * |...........................|
  1416. * | Strings |
  1417. * |...........................|
  1418. * | |
  1419. * | |
  1420. * +---------------------------+
  1421. *
  1422. * The connections can be filtered based on either sessions or volumes.
  1423. *
  1424. * LOCKS: AfpConnLock (SPIN)
  1425. */
  1426. AFPSTATUS
  1427. AfpAdmConnectionEnum(
  1428. IN OUT PVOID InBuf OPTIONAL,
  1429. IN LONG OutBufLen OPTIONAL,
  1430. OUT PVOID OutBuf OPTIONAL
  1431. )
  1432. {
  1433. PENUMRESPPKT pErsp = (PENUMRESPPKT)OutBuf;
  1434. PENUMREQPKT pErqp = (PENUMREQPKT)InBuf;
  1435. PAFP_CONNECTION_INFO pConnInfo = (PAFP_CONNECTION_INFO)((PBYTE)OutBuf+sizeof(ENUMRESPPKT));
  1436. PCONNDESC pConnDesc;
  1437. PBYTE pString = (PBYTE)OutBuf+OutBufLen; // 1 past eob
  1438. LONG cTotal = 0;
  1439. DWORD DeadConns = 0;
  1440. KIRQL OldIrql;
  1441. AFPSTATUS Status = AFP_ERR_NONE;
  1442. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  1443. ("AfpAdmConnectionEnum entered\n"));
  1444. if ((((pErqp->erqp_Filter == AFP_FILTER_ON_SESSION_ID) ||
  1445. (pErqp->erqp_Filter == AFP_FILTER_ON_VOLUME_ID)) &&
  1446. (pErqp->erqp_ID == 0)) ||
  1447. ((pErqp->erqp_Filter != 0) &&
  1448. (pErqp->erqp_Filter != AFP_FILTER_ON_SESSION_ID) &&
  1449. (pErqp->erqp_Filter != AFP_FILTER_ON_VOLUME_ID)))
  1450. return AFPERR_InvalidParms;
  1451. if (OutBufLen < (sizeof(ENUMRESPPKT) + sizeof(PAFP_CONNECTION_INFO)))
  1452. return AFPERR_BufferSize;
  1453. if (pErqp->erqp_Index == 0)
  1454. pErqp->erqp_Index = MAXULONG;
  1455. // Initialize the response packet header
  1456. pErsp->ersp_cInBuf = 0;
  1457. pErsp->ersp_hResume = 0;
  1458. ACQUIRE_SPIN_LOCK(&AfpConnLock, &OldIrql);
  1459. for (pConnDesc = AfpConnList;
  1460. pConnDesc != NULL;
  1461. pConnDesc = pConnDesc->cds_NextGlobal)
  1462. {
  1463. PSDA pSda;
  1464. PVOLDESC pVolDesc;
  1465. LONG BytesLeft;
  1466. LONG BytesNeeded;
  1467. // We do not need to either lock or reference pSda and pVolDesc
  1468. // since we have implicit references to them via the pConnDesc.
  1469. pSda = pConnDesc->cds_pSda;
  1470. ASSERT(pSda != NULL);
  1471. pVolDesc = pConnDesc->cds_pVolDesc;
  1472. ASSERT(pVolDesc != NULL);
  1473. // If we are filtering, make sure we get the total count
  1474. // Skip this entry, if any filtering is requested and this does not
  1475. // match
  1476. if (pErqp->erqp_Filter != 0)
  1477. {
  1478. if (pErqp->erqp_Filter == AFP_FILTER_ON_SESSION_ID)
  1479. {
  1480. if (pSda->sda_SessionId != pErqp->erqp_ID)
  1481. continue;
  1482. cTotal = pSda->sda_cOpenVolumes;
  1483. }
  1484. else // if (pErqp->erqp_Filter == AFP_FILTER_ON_VOLUME_ID)
  1485. {
  1486. if (pVolDesc->vds_VolId != (LONG)pErqp->erqp_ID)
  1487. continue;
  1488. cTotal = pVolDesc->vds_UseCount;
  1489. }
  1490. }
  1491. else cTotal = AfpNumSessions;
  1492. // Skip all entries that are marked for death
  1493. if (pConnDesc->cds_Flags & CONN_CLOSING)
  1494. {
  1495. DeadConns++;
  1496. continue;
  1497. }
  1498. // Skip all entries we have looked at before
  1499. if (pConnDesc->cds_ConnId > pErqp->erqp_Index)
  1500. continue;
  1501. // If there is not enough space in the buffer, abort now and
  1502. // initialize pErsp->ersp_hResume with the current connection id
  1503. BytesLeft = (LONG)((PBYTE)pString - (PBYTE)pConnInfo);
  1504. BytesNeeded = sizeof(AFP_CONNECTION_INFO) +
  1505. pSda->sda_UserName.Length + sizeof(WCHAR) +
  1506. pVolDesc->vds_Name.Length + sizeof(WCHAR);
  1507. if ((BytesLeft <= 0) || (BytesNeeded > BytesLeft))
  1508. {
  1509. pErsp->ersp_hResume = pConnDesc->cds_ConnId;
  1510. Status = STATUS_MORE_ENTRIES;
  1511. break;
  1512. }
  1513. pErqp->erqp_Index = pConnDesc->cds_ConnId;
  1514. pConnInfo->afpconn_id = pConnDesc->cds_ConnId;
  1515. pConnInfo->afpconn_num_opens = pConnDesc->cds_cOpenForks;
  1516. AfpGetCurrentTimeInMacFormat((PAFPTIME)&pConnInfo->afpconn_time);
  1517. pConnInfo->afpconn_time -= pConnDesc->cds_TimeOpened;
  1518. // Copy the username name string
  1519. pConnInfo->afpconn_username = (LPWSTR)NULL;
  1520. if (pSda->sda_UserName.Length > 0)
  1521. {
  1522. pString -= (pSda->sda_UserName.Length + sizeof(WCHAR));
  1523. RtlCopyMemory(pString, pSda->sda_UserName.Buffer, pSda->sda_UserName.Length);
  1524. *(LPWSTR)(pString + pSda->sda_UserName.Length) = L'\0';
  1525. pConnInfo->afpconn_username = (LPWSTR)pString;
  1526. POINTER_TO_OFFSET(pConnInfo->afpconn_username, pConnInfo);
  1527. }
  1528. // Copy the volume name string
  1529. pString -= (pVolDesc->vds_Name.Length + sizeof(WCHAR));
  1530. RtlCopyMemory(pString, pVolDesc->vds_Name.Buffer, pVolDesc->vds_Name.Length);
  1531. *(LPWSTR)(pString + pVolDesc->vds_Name.Length) = L'\0';
  1532. pConnInfo->afpconn_volumename = (LPWSTR)pString;
  1533. POINTER_TO_OFFSET(pConnInfo->afpconn_volumename, pConnInfo);
  1534. pConnInfo ++;
  1535. pErsp->ersp_cInBuf ++;
  1536. }
  1537. // Fill up the response packet header
  1538. pErsp->ersp_cTotEnts = (DWORD)cTotal - DeadConns;
  1539. RELEASE_SPIN_LOCK(&AfpConnLock, OldIrql);
  1540. return Status;
  1541. }
  1542. /*** AfpAdmForkEnum
  1543. *
  1544. * Enumerate the list of open forks. This is a linear list rooted
  1545. * at AfpOpenForksList and protected by AfpForksLock. This list is potentially
  1546. * pretty long (Unlimited # of sessions with the super ASP stuff).
  1547. *
  1548. * The resume handle returned is the connection id of the last connection
  1549. * returned. connection Id of 0 implies restart scan.
  1550. *
  1551. * The output buffer is constructed as follows.
  1552. *
  1553. * +---------------------------+
  1554. * | File_Info_1 |
  1555. * +---------------------------+
  1556. * | File_Info_2 |
  1557. * +---------------------------+
  1558. * . .
  1559. * . .
  1560. * +---------------------------+
  1561. * | File_Info_n |
  1562. * +---------------------------+
  1563. * . .
  1564. * . .
  1565. * +---------------------------+
  1566. * | |
  1567. * |...........................|
  1568. * | Strings |
  1569. * |...........................|
  1570. * | |
  1571. * | |
  1572. * +---------------------------+
  1573. *
  1574. * LOCKS: AfpForksLock (SPIN)
  1575. */
  1576. AFPSTATUS
  1577. AfpAdmForkEnum(
  1578. IN OUT PVOID InBuf OPTIONAL,
  1579. IN LONG OutBufLen OPTIONAL,
  1580. OUT PVOID OutBuf OPTIONAL
  1581. )
  1582. {
  1583. PENUMRESPPKT pErsp = (PENUMRESPPKT)OutBuf;
  1584. PAFP_FILE_INFO pFileInfo = (PAFP_FILE_INFO)((PBYTE)OutBuf+sizeof(ENUMRESPPKT));
  1585. POPENFORKENTRY pOpenForkEntry;
  1586. POPENFORKDESC pOpenForkDesc;
  1587. PBYTE pString = (PBYTE)OutBuf+OutBufLen; // 1 past eob
  1588. DWORD StartId = (LONG)(((PENUMREQPKT)InBuf)->erqp_Index);
  1589. DWORD DeadForks = 0;
  1590. KIRQL OldIrql;
  1591. AFPSTATUS Status = AFP_ERR_NONE;
  1592. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  1593. ("AfpAdmForkEnum entered\n"));
  1594. if (OutBufLen < (sizeof(ENUMRESPPKT) + sizeof(PAFP_FILE_INFO)))
  1595. return AFPERR_BufferSize;
  1596. if (StartId == 0)
  1597. StartId = MAXULONG;
  1598. // Initialize the response packet header
  1599. pErsp->ersp_cInBuf = 0;
  1600. pErsp->ersp_hResume = 0;
  1601. ACQUIRE_SPIN_LOCK(&AfpForksLock, &OldIrql);
  1602. for (pOpenForkEntry = AfpOpenForksList; pOpenForkEntry != NULL;
  1603. pOpenForkEntry = pOpenForkEntry->ofe_Next)
  1604. {
  1605. LONG BytesLeft;
  1606. LONG BytesNeeded;
  1607. PSDA pSda;
  1608. PVOLDESC pVolDesc = pOpenForkEntry->ofe_pOpenForkDesc->ofd_pVolDesc;
  1609. // Skip all entries that are marked for death
  1610. if (pOpenForkEntry->ofe_Flags & OPEN_FORK_CLOSING)
  1611. {
  1612. DeadForks ++;
  1613. continue;
  1614. }
  1615. // Skip all entries we have looked at before
  1616. if (pOpenForkEntry->ofe_ForkId > StartId)
  1617. continue;
  1618. pSda = pOpenForkEntry->ofe_pSda;
  1619. pOpenForkDesc = pOpenForkEntry->ofe_pOpenForkDesc;
  1620. // If there is not enough space in the buffer, abort now and
  1621. // initialize pErsp->ersp_hResume with the current session id
  1622. BytesLeft = (LONG)((PBYTE)pString - (PBYTE)pFileInfo);
  1623. BytesNeeded = sizeof(AFP_FILE_INFO) + pSda->sda_UserName.Length +
  1624. sizeof(WCHAR) + /* NULL terminate username */
  1625. pVolDesc->vds_Path.Length +
  1626. pOpenForkDesc->ofd_FilePath.Length +
  1627. sizeof(WCHAR); /* NULL terminate path */
  1628. if ((BytesLeft <= 0) || (BytesNeeded > BytesLeft))
  1629. {
  1630. pErsp->ersp_hResume = pOpenForkEntry->ofe_ForkId;
  1631. Status = STATUS_MORE_ENTRIES;
  1632. break;
  1633. }
  1634. StartId = pOpenForkEntry->ofe_ForkId;
  1635. pFileInfo->afpfile_id = pOpenForkEntry->ofe_ForkId;
  1636. pFileInfo->afpfile_num_locks = pOpenForkEntry->ofe_cLocks;
  1637. pFileInfo->afpfile_fork_type = RESCFORK(pOpenForkEntry);
  1638. #if AFP_OPEN_MODE_NONE != FORK_OPEN_NONE
  1639. #error (AFP_OPEN_MODE_NONE != FORK_OPEN_NONE)
  1640. #endif
  1641. #if AFP_OPEN_MODE_READ != FORK_OPEN_READ
  1642. #error (AFP_OPEN_MODE_READ != FORK_OPEN_READ)
  1643. #endif
  1644. #if AFP_OPEN_MODE_WRITE != FORK_OPEN_WRITE
  1645. #error (AFP_OPEN_MODE_WRITE != FORK_OPEN_WRITE)
  1646. #endif
  1647. pFileInfo->afpfile_open_mode = (DWORD)pOpenForkEntry->ofe_OpenMode;
  1648. // Copy the strings here.
  1649. pFileInfo->afpfile_username = NULL;
  1650. pFileInfo->afpfile_path = NULL;
  1651. if (pSda->sda_UserName.Length > 0)
  1652. {
  1653. pString -= (pSda->sda_UserName.Length + sizeof(WCHAR));
  1654. RtlCopyMemory(pString, pSda->sda_UserName.Buffer, pSda->sda_UserName.Length);
  1655. *(LPWSTR)(pString + pSda->sda_UserName.Length) = L'\0';
  1656. pFileInfo->afpfile_username = (LPWSTR)pString;
  1657. POINTER_TO_OFFSET(pFileInfo->afpfile_username, pFileInfo);
  1658. }
  1659. if (pOpenForkDesc->ofd_FilePath.Length > 0)
  1660. {
  1661. pString -= pVolDesc->vds_Path.Length +
  1662. pOpenForkDesc->ofd_FilePath.Length +
  1663. sizeof(WCHAR);
  1664. pFileInfo->afpfile_path = (LPWSTR)pString;
  1665. POINTER_TO_OFFSET(pFileInfo->afpfile_path, pFileInfo);
  1666. RtlCopyMemory(pString, pVolDesc->vds_Path.Buffer,
  1667. pVolDesc->vds_Path.Length);
  1668. RtlCopyMemory(pString + pVolDesc->vds_Path.Length,
  1669. pOpenForkDesc->ofd_FilePath.Buffer,
  1670. pOpenForkDesc->ofd_FilePath.Length);
  1671. *(LPWSTR)(pString + pVolDesc->vds_Path.Length +
  1672. pOpenForkDesc->ofd_FilePath.Length) = L'\0';
  1673. }
  1674. pFileInfo ++;
  1675. pErsp->ersp_cInBuf ++;
  1676. }
  1677. // Fill up the response packet header
  1678. pErsp->ersp_cTotEnts = (DWORD)AfpNumOpenForks - DeadForks;
  1679. RELEASE_SPIN_LOCK(&AfpForksLock, OldIrql);
  1680. return Status;
  1681. }
  1682. /*** AfpAdmMessageSend
  1683. *
  1684. * Send a message to a specific session, or broadcast to all sessions.
  1685. * If session id is 0, this indicates a broadcast, and the message is copied
  1686. * to AfpServerMsg. Otherwise, the message is copied to the particular
  1687. * session's SDA. A message can be a max of 199 chars. It is an error to
  1688. * attempt to send a message of length 0. A message can only be sent to an
  1689. * AFP 2.1 client as a AFP 2.0 client has no capability to accept a message.
  1690. *
  1691. * LOCKS: AfpServerGlobalLock (SPIN)
  1692. */
  1693. AFPSTATUS
  1694. AfpAdmMessageSend(
  1695. IN OUT PVOID InBuf OPTIONAL,
  1696. IN LONG OutBufLen OPTIONAL,
  1697. OUT PVOID OutBuf OPTIONAL
  1698. )
  1699. {
  1700. PAFP_MESSAGE_INFO pMsgInfo = (PAFP_MESSAGE_INFO)InBuf;
  1701. PSDA pSda;
  1702. UNICODE_STRING umsg;
  1703. PANSI_STRING amsg;
  1704. USHORT msglen;
  1705. DWORD SessId;
  1706. KIRQL OldIrql;
  1707. AFPSTATUS Status = AFP_ERR_NONE;
  1708. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  1709. ("AfpAdmMessageSend entered\n"));
  1710. SessId = pMsgInfo->afpmsg_session_id;
  1711. RtlInitUnicodeString(&umsg, pMsgInfo->afpmsg_text);
  1712. msglen = (USHORT)RtlUnicodeStringToAnsiSize(&umsg)-1;
  1713. if ((msglen > AFP_MESSAGE_LEN) || (msglen == 0))
  1714. {
  1715. return AFPERR_InvalidParms;
  1716. }
  1717. if ((amsg =
  1718. (PANSI_STRING)AfpAllocNonPagedMemory(msglen + 1 + sizeof(ANSI_STRING))) == NULL)
  1719. {
  1720. return STATUS_INSUFFICIENT_RESOURCES;
  1721. }
  1722. amsg->Length = msglen;
  1723. amsg->MaximumLength = msglen + 1;
  1724. amsg->Buffer = (PBYTE)amsg + sizeof(ANSI_STRING);
  1725. Status = RtlUnicodeStringToAnsiString(amsg, &umsg, False);
  1726. if (!NT_SUCCESS(Status))
  1727. {
  1728. return AFPERR_InvalidParms;
  1729. }
  1730. else AfpConvertHostAnsiToMacAnsi(amsg);
  1731. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_INFO,
  1732. ("AfpAdmMessageSend: session id is 0x%x, message <%s>\n",
  1733. pMsgInfo->afpmsg_session_id, amsg->Buffer));
  1734. // If this is a broadcast message, initialize the global message
  1735. if (SessId == 0)
  1736. {
  1737. ACQUIRE_SPIN_LOCK(&AfpServerGlobalLock, &OldIrql);
  1738. // If there is a message there already, blow it
  1739. if (AfpServerMsg != NULL)
  1740. AfpFreeMemory(AfpServerMsg);
  1741. AfpServerMsg = amsg;
  1742. RELEASE_SPIN_LOCK(&AfpServerGlobalLock, OldIrql);
  1743. // Walk the session list and send attention to all AFP 2.1 clients
  1744. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  1745. for (pSda = AfpSessionList; pSda != NULL; pSda = pSda->sda_Next)
  1746. {
  1747. ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock);
  1748. if ((pSda->sda_ClientVersion >= AFP_VER_21) &&
  1749. ((pSda->sda_Flags & (SDA_CLOSING | SDA_SESSION_CLOSED)) == 0))
  1750. {
  1751. // We are using the async version of AfpSpSendAttention since
  1752. // we are calling with spin-lock held.
  1753. AfpSpSendAttention(pSda, ATTN_SERVER_MESSAGE, False);
  1754. }
  1755. else if (pSda->sda_ClientVersion < AFP_VER_21)
  1756. {
  1757. Status = AFPERR_InvalidSessionType;
  1758. }
  1759. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  1760. }
  1761. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  1762. }
  1763. else
  1764. {
  1765. // Find the session matching the session id and, if found and the client is AFP v2.1,
  1766. // copy the message to the SDA and send an attention to the client.
  1767. // Error if the session either does not exist or it is not an AFP 2.1
  1768. Status = AFPERR_InvalidId;
  1769. if ((pSda = AfpSdaReferenceSessionById(SessId)) != NULL)
  1770. {
  1771. Status = AFPERR_InvalidSessionType;
  1772. if (pSda->sda_ClientVersion >= AFP_VER_21)
  1773. {
  1774. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  1775. if (pSda->sda_Message != NULL)
  1776. AfpFreeMemory(pSda->sda_Message);
  1777. pSda->sda_Message = amsg;
  1778. AfpSpSendAttention(pSda, ATTN_SERVER_MESSAGE, False);
  1779. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  1780. Status = AFP_ERR_NONE;
  1781. }
  1782. AfpSdaDereferenceSession(pSda);
  1783. }
  1784. if (Status != AFP_ERR_NONE)
  1785. {
  1786. AfpFreeMemory(amsg);
  1787. }
  1788. }
  1789. return Status;
  1790. }
  1791. /*** AfpAdmWDirectoryGetInfo
  1792. *
  1793. * Query a directory's permissions.
  1794. */
  1795. AFPSTATUS
  1796. AfpAdmWDirectoryGetInfo(
  1797. IN OUT PVOID InBuf OPTIONAL,
  1798. IN LONG OutBufLen OPTIONAL,
  1799. OUT PVOID OutBuf OPTIONAL
  1800. )
  1801. {
  1802. PAFP_DIRECTORY_INFO pDirInfo = (PAFP_DIRECTORY_INFO)OutBuf;
  1803. PSID pSid = (PSID)((PBYTE)OutBuf + sizeof(AFP_DIRECTORY_INFO));
  1804. UNICODE_STRING VolumePath;
  1805. ANSI_STRING MacAnsiDirPath;
  1806. SDA Sda;
  1807. CONNDESC ConnDesc;
  1808. PVOLDESC pVolDesc;
  1809. FILEDIRPARM FDParm;
  1810. PATHMAPENTITY PME;
  1811. AFPSTATUS Status;
  1812. PAGED_CODE( );
  1813. DBGPRINT(DBG_COMP_ADMINAPI_DIR, DBG_LEVEL_INFO,
  1814. ("AfpAdmWDirectoryGetInfo entered for %ws\n",
  1815. ((PAFP_DIRECTORY_INFO)InBuf)->afpdir_path));
  1816. // validate the output buffer length
  1817. if (OutBufLen < sizeof(AFP_DIRECTORY_INFO))
  1818. return AFPERR_BufferSize;
  1819. MacAnsiDirPath.Length = 0;
  1820. MacAnsiDirPath.MaximumLength = 0;
  1821. MacAnsiDirPath.Buffer = NULL;
  1822. OutBufLen -= sizeof(AFP_DIRECTORY_INFO);
  1823. // First find the volume that this directory is path of
  1824. RtlInitUnicodeString(&VolumePath, ((PAFP_DIRECTORY_INFO)InBuf)->afpdir_path);
  1825. if (!NT_SUCCESS(Status = AfpVolumeReferenceByPath(&VolumePath, &pVolDesc)))
  1826. {
  1827. DBGPRINT(DBG_COMP_ADMINAPI_DIR, DBG_LEVEL_ERR,
  1828. ("AfpAdmWDirectoryGetInfo: AfpVolumeReferenceByPath returned error %ld\n",
  1829. Status));
  1830. return Status;
  1831. }
  1832. // Now get the volume relative path of the directory.
  1833. VolumePath.Buffer = (LPWSTR)((PBYTE)VolumePath.Buffer +
  1834. pVolDesc->vds_Path.Length);
  1835. VolumePath.Length -= pVolDesc->vds_Path.Length;
  1836. VolumePath.MaximumLength -= pVolDesc->vds_Path.Length;
  1837. if ((SHORT)(VolumePath.Length) < 0)
  1838. {
  1839. VolumePath.Length = 0;
  1840. VolumePath.MaximumLength = sizeof(WCHAR);
  1841. }
  1842. do
  1843. {
  1844. AfpInitializePME(&PME, 0, NULL);
  1845. if (!NT_SUCCESS(Status = afpConvertAdminPathToMacPath(pVolDesc,
  1846. &VolumePath,
  1847. &MacAnsiDirPath)))
  1848. {
  1849. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  1850. break;
  1851. }
  1852. // AfpMapAfpPathForLookup requires an Sda to figure out User's
  1853. // permission. For this API, we do not really need the User's
  1854. // permission, so kludge it up. Note that it is important to
  1855. // set the client type to SDA_CLIENT_ADMIN to avoid references
  1856. // to other sda fields. See access.c/fdparm.c/afpinfo.c for details.
  1857. RtlZeroMemory(&Sda, sizeof(Sda));
  1858. #if DBG
  1859. Sda.Signature = SDA_SIGNATURE;
  1860. #endif
  1861. Sda.sda_ClientType = SDA_CLIENT_ADMIN;
  1862. Sda.sda_UserSid = &AfpSidWorld;
  1863. Sda.sda_GroupSid = &AfpSidWorld;
  1864. // pathmap requires a ConnDesc to determine the VolDesc and Sda, so
  1865. // kludge up a fake one here
  1866. RtlZeroMemory(&ConnDesc, sizeof(ConnDesc));
  1867. #if DBG
  1868. ConnDesc.Signature = CONNDESC_SIGNATURE;
  1869. #endif
  1870. ConnDesc.cds_pSda = &Sda;
  1871. ConnDesc.cds_pVolDesc = pVolDesc;
  1872. AfpInitializeFDParms(&FDParm);
  1873. Status = AfpMapAfpPathForLookup(&ConnDesc,
  1874. AFP_ID_ROOT,
  1875. &MacAnsiDirPath,
  1876. AFP_LONGNAME,
  1877. DFE_DIR,
  1878. FD_INTERNAL_BITMAP_OPENACCESS_ADMINGET |
  1879. DIR_BITMAP_ACCESSRIGHTS |
  1880. FD_BITMAP_ATTR,
  1881. &PME,
  1882. &FDParm);
  1883. if (!NT_SUCCESS(Status))
  1884. {
  1885. if (Status == AFP_ERR_ACCESS_DENIED)
  1886. {
  1887. Status = STATUS_ACCESS_DENIED;
  1888. }
  1889. else
  1890. {
  1891. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  1892. }
  1893. break;
  1894. }
  1895. } while (False);
  1896. if (PME.pme_Handle.fsh_FileHandle != NULL)
  1897. AfpIoClose(&PME.pme_Handle);
  1898. if (MacAnsiDirPath.Buffer != NULL)
  1899. {
  1900. AfpFreeMemory(MacAnsiDirPath.Buffer);
  1901. }
  1902. AfpVolumeDereference(pVolDesc);
  1903. // All is hunky-dory so far. Now convert the information we have so far
  1904. // into the form accepted by the API
  1905. if (NT_SUCCESS(Status))
  1906. {
  1907. PSID pSidUG; // Sid of user or group
  1908. pDirInfo->afpdir_perms =
  1909. ((FDParm._fdp_OwnerRights & ~DIR_ACCESS_OWNER) << OWNER_RIGHTS_SHIFT) +
  1910. ((FDParm._fdp_GroupRights & ~DIR_ACCESS_OWNER) << GROUP_RIGHTS_SHIFT) +
  1911. ((FDParm._fdp_WorldRights & ~DIR_ACCESS_OWNER) << WORLD_RIGHTS_SHIFT);
  1912. if ((FDParm._fdp_Attr &
  1913. (FD_BITMAP_ATTR_RENAMEINH | FD_BITMAP_ATTR_DELETEINH)) ==
  1914. (FD_BITMAP_ATTR_RENAMEINH | FD_BITMAP_ATTR_DELETEINH))
  1915. pDirInfo->afpdir_perms |= AFP_PERM_INHIBIT_MOVE_DELETE;
  1916. DBGPRINT(DBG_COMP_ADMINAPI_DIR, DBG_LEVEL_INFO,
  1917. ("AfpAdmWDirectoryGetInfo: Perms %lx\n", pDirInfo->afpdir_perms));
  1918. pDirInfo->afpdir_path = NULL;
  1919. // Translate the owner and group ids to Sids. The name fields actually
  1920. // get the sids and the user mode code is responsible to convert it
  1921. // to names.
  1922. pDirInfo->afpdir_owner = NULL;
  1923. pDirInfo->afpdir_group = NULL;
  1924. do
  1925. {
  1926. LONG LengthSid;
  1927. //
  1928. // Convert the owner ID to SID
  1929. //
  1930. if (FDParm._fdp_OwnerId != 0)
  1931. {
  1932. Status = AfpMacIdToSid(FDParm._fdp_OwnerId, &pSidUG);
  1933. if (!NT_SUCCESS(Status))
  1934. {
  1935. Status = STATUS_NONE_MAPPED;
  1936. break;
  1937. }
  1938. AfpDumpSid("AfpAdmWDirectoryGetInfo: User Sid:", pSidUG);
  1939. LengthSid = RtlLengthSid(pSidUG);
  1940. if (OutBufLen < LengthSid)
  1941. Status = AFPERR_BufferSize;
  1942. else
  1943. {
  1944. RtlCopyMemory(pSid, pSidUG, LengthSid);
  1945. pDirInfo->afpdir_owner = pSid;
  1946. POINTER_TO_OFFSET(pDirInfo->afpdir_owner, pDirInfo);
  1947. pSid = (PSID)((PBYTE)pSid + LengthSid);
  1948. OutBufLen -= LengthSid;
  1949. }
  1950. if (!NT_SUCCESS(Status))
  1951. break;
  1952. }
  1953. //
  1954. // Convert the group ID to SID
  1955. //
  1956. if (FDParm._fdp_GroupId != 0)
  1957. {
  1958. Status = AfpMacIdToSid(FDParm._fdp_GroupId, &pSidUG);
  1959. if (!NT_SUCCESS(Status))
  1960. {
  1961. Status = STATUS_NONE_MAPPED;
  1962. break;
  1963. }
  1964. AfpDumpSid("AfpAdmWDirectoryGetInfo: Group Sid:", pSidUG);
  1965. LengthSid = RtlLengthSid(pSidUG);
  1966. if (OutBufLen < LengthSid)
  1967. Status = AFPERR_BufferSize;
  1968. else
  1969. {
  1970. RtlCopyMemory(pSid, pSidUG, LengthSid);
  1971. pDirInfo->afpdir_group = pSid;
  1972. POINTER_TO_OFFSET(pDirInfo->afpdir_group, pDirInfo);
  1973. // pSid = (PSID)((PBYTE)pSid + LengthSid);
  1974. // OutBufLen -= LengthSid;
  1975. }
  1976. }
  1977. } while (False);
  1978. }
  1979. return Status;
  1980. }
  1981. /*** AfpAdmWDirectorySetInfo
  1982. *
  1983. * Set a directory's permissions.
  1984. */
  1985. AFPSTATUS
  1986. AfpAdmWDirectorySetInfo(
  1987. IN OUT PVOID InBuf OPTIONAL,
  1988. IN LONG OutBufLen OPTIONAL,
  1989. OUT PVOID OutBuf OPTIONAL
  1990. )
  1991. {
  1992. PAFP_DIRECTORY_INFO pDirInfo;
  1993. DWORD ParmNum, Bitmap = 0;
  1994. UNICODE_STRING VolumePath;
  1995. SDA Sda;
  1996. CONNDESC ConnDesc;
  1997. PVOLDESC pVolDesc;
  1998. AFPSTATUS Status;
  1999. BYTE ParmBlock[4 * sizeof(DWORD)];
  2000. FILEDIRPARM FDParm;
  2001. PAGED_CODE( );
  2002. ParmNum = ((PSETINFOREQPKT)InBuf)->sirqp_parmnum;
  2003. pDirInfo = (PAFP_DIRECTORY_INFO)((PBYTE)InBuf + sizeof(SETINFOREQPKT));
  2004. DBGPRINT(DBG_COMP_ADMINAPI_DIR, DBG_LEVEL_INFO,
  2005. ("AfpAdmWDirectorySetInfo entered for %ws (%lx)\n",
  2006. pDirInfo->afpdir_path, ParmNum));
  2007. // Convert the parmnum to a bitmap for use by AfpSetFileDirParms
  2008. if (ParmNum & AFP_DIR_PARMNUM_PERMS)
  2009. Bitmap |= (DIR_BITMAP_ACCESSRIGHTS | FD_BITMAP_ATTR);
  2010. if (ParmNum & AFP_DIR_PARMNUM_OWNER)
  2011. {
  2012. if (pDirInfo->afpdir_owner == NULL)
  2013. return STATUS_INVALID_PARAMETER;
  2014. else
  2015. Bitmap |= DIR_BITMAP_OWNERID;
  2016. }
  2017. if (ParmNum & AFP_DIR_PARMNUM_GROUP)
  2018. {
  2019. if (pDirInfo->afpdir_group == NULL)
  2020. return STATUS_INVALID_PARAMETER;
  2021. else
  2022. Bitmap |= DIR_BITMAP_GROUPID;
  2023. }
  2024. // Find the volume that this directory is path of
  2025. RtlInitUnicodeString(&VolumePath, pDirInfo->afpdir_path);
  2026. if (!NT_SUCCESS(Status = AfpVolumeReferenceByPath(&VolumePath, &pVolDesc)))
  2027. return Status;
  2028. // Now get the volume relative path of the directory. Consume the leading
  2029. // '\' character
  2030. VolumePath.Buffer = (LPWSTR)((PBYTE)VolumePath.Buffer +
  2031. pVolDesc->vds_Path.Length);
  2032. VolumePath.Length -= pVolDesc->vds_Path.Length;
  2033. VolumePath.MaximumLength -= pVolDesc->vds_Path.Length;
  2034. if ((SHORT)(VolumePath.Length) < 0)
  2035. {
  2036. VolumePath.Length = 0;
  2037. VolumePath.MaximumLength = sizeof(WCHAR);
  2038. }
  2039. RtlZeroMemory(&Sda, sizeof(Sda));
  2040. if (Bitmap) do
  2041. {
  2042. if (!NT_SUCCESS(Status = afpConvertAdminPathToMacPath(pVolDesc,
  2043. &VolumePath,
  2044. &Sda.sda_Name1)))
  2045. {
  2046. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  2047. break;
  2048. }
  2049. // Kludge up a FILEDIRPARMS structure to call AfpPackFDParms with
  2050. AfpInitializeFDParms(&FDParm);
  2051. if (Bitmap & FD_BITMAP_ATTR)
  2052. {
  2053. FDParm._fdp_Attr = FD_BITMAP_ATTR_RENAMEINH |
  2054. FD_BITMAP_ATTR_DELETEINH;
  2055. if (pDirInfo->afpdir_perms & AFP_PERM_INHIBIT_MOVE_DELETE)
  2056. {
  2057. FDParm._fdp_Attr |= FD_BITMAP_ATTR_SET;
  2058. }
  2059. DBGPRINT(DBG_COMP_ADMINAPI_DIR, DBG_LEVEL_INFO,
  2060. ("AfpAdmWDirectorySetInfo: Changing Attributes to %lx\n",
  2061. FDParm._fdp_Attr));
  2062. }
  2063. if (Bitmap & DIR_BITMAP_ACCESSRIGHTS)
  2064. {
  2065. FDParm._fdp_OwnerRights = (BYTE)(pDirInfo->afpdir_perms >> OWNER_RIGHTS_SHIFT);
  2066. FDParm._fdp_GroupRights = (BYTE)(pDirInfo->afpdir_perms >> GROUP_RIGHTS_SHIFT);
  2067. FDParm._fdp_WorldRights = (BYTE)(pDirInfo->afpdir_perms >> WORLD_RIGHTS_SHIFT);
  2068. DBGPRINT(DBG_COMP_ADMINAPI_DIR, DBG_LEVEL_INFO,
  2069. ("AfpAdmWDirectorySetInfo: Setting Permissions %x,%x,%x\n",
  2070. FDParm._fdp_OwnerRights,
  2071. FDParm._fdp_GroupRights,
  2072. FDParm._fdp_WorldRights));
  2073. }
  2074. // See if we need to change owner and group ids
  2075. if (Bitmap & DIR_BITMAP_OWNERID)
  2076. {
  2077. Status = AfpSidToMacId((PSID)(pDirInfo->afpdir_owner),
  2078. &FDParm._fdp_OwnerId);
  2079. if (!NT_SUCCESS(Status))
  2080. {
  2081. Status = STATUS_NONE_MAPPED;
  2082. break;
  2083. }
  2084. AfpDumpSid("AfpAdmWDirectorySetInfo: Changing Owner to:",
  2085. (PSID)(pDirInfo->afpdir_owner));
  2086. }
  2087. if (Bitmap & DIR_BITMAP_GROUPID)
  2088. {
  2089. Status = AfpSidToMacId((PSID)(pDirInfo->afpdir_group),
  2090. &FDParm._fdp_GroupId);
  2091. if (!NT_SUCCESS(Status))
  2092. {
  2093. Status = STATUS_NONE_MAPPED;
  2094. break;
  2095. }
  2096. AfpDumpSid("AfpAdmWDirectorySetInfo: Changing Group to:",
  2097. (PSID)(pDirInfo->afpdir_group));
  2098. }
  2099. FDParm._fdp_Flags = DFE_FLAGS_DIR;
  2100. AfpPackFileDirParms(&FDParm, Bitmap, ParmBlock);
  2101. // AfpQueryFileDirParms requires an Sda to figure out User's
  2102. // permission. For this API, we do not really need the User's
  2103. // permission, so kludge it up. Note that it is important to
  2104. // set the client type to SDA_CLIENT_ADMIN to avoid references
  2105. // to other sda fields. See access.c/fdparm.c/afpinfo.c for details.
  2106. Sda.sda_ClientType = SDA_CLIENT_ADMIN;
  2107. Sda.sda_UserSid = &AfpSidWorld;
  2108. Sda.sda_GroupSid = &AfpSidWorld;
  2109. *((PULONG_PTR)Sda.sda_ReqBlock) = (ULONG_PTR)&ConnDesc;
  2110. //if (sizeof (DWORD) != sizeof (ULONG_PTR))
  2111. #ifdef _WIN64
  2112. // Create 64-bit space at start of buffer to hold ConnDesc pointer
  2113. // 64-bit specifics
  2114. Sda.sda_ReqBlock[2] = AFP_ID_ROOT;
  2115. Sda.sda_ReqBlock[3] = Bitmap;
  2116. #else
  2117. Sda.sda_ReqBlock[1] = AFP_ID_ROOT;
  2118. Sda.sda_ReqBlock[2] = Bitmap;
  2119. #endif
  2120. Sda.sda_PathType = AFP_LONGNAME;
  2121. Sda.sda_Name2.Buffer = ParmBlock;
  2122. Sda.sda_Name2.Length = Sda.sda_Name2.MaximumLength = sizeof(ParmBlock);
  2123. // pathmap requires a ConnDesc to determine the VolDesc and Sda, so
  2124. // kludge up a fake one here
  2125. RtlZeroMemory(&ConnDesc, sizeof(ConnDesc));
  2126. #if DBG
  2127. ConnDesc.Signature = CONNDESC_SIGNATURE;
  2128. Sda.Signature = SDA_SIGNATURE;
  2129. #endif
  2130. ConnDesc.cds_pSda = &Sda;
  2131. ConnDesc.cds_pVolDesc = pVolDesc;
  2132. if (!NT_SUCCESS(Status = AfpFspDispSetDirParms(&Sda)))
  2133. {
  2134. DBGPRINT(DBG_COMP_ADMINAPI_DIR, DBG_LEVEL_INFO,
  2135. ("AfpAdmWDirectorySetInfo: AfpFspDispSetDirParms failed 0x%lx\n",
  2136. Status));
  2137. if (Status == AFP_ERR_ACCESS_DENIED)
  2138. {
  2139. Status = STATUS_ACCESS_DENIED;
  2140. }
  2141. else
  2142. {
  2143. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  2144. }
  2145. }
  2146. } while (False);
  2147. if (Sda.sda_Name1.Buffer != NULL)
  2148. {
  2149. AfpFreeMemory(Sda.sda_Name1.Buffer);
  2150. }
  2151. AfpVolumeDereference(pVolDesc);
  2152. return Status;
  2153. }
  2154. /*** AfpAdmWFinderSetInfo
  2155. *
  2156. * Set the type and/or creator of a file.
  2157. * (Note this routine can be expanded later to set other Finder info if
  2158. * needed)
  2159. *
  2160. * LOCKS: vds_IdDbAccessLock (SWMR, Exclusive);
  2161. */
  2162. AFPSTATUS
  2163. AfpAdmWFinderSetInfo(
  2164. IN OUT PVOID InBuf OPTIONAL,
  2165. IN LONG OutBufLen OPTIONAL,
  2166. OUT PVOID OutBuf OPTIONAL
  2167. )
  2168. {
  2169. PAFP_FINDER_INFO pAdmFDInfo;
  2170. DWORD ParmNum, Bitmap = 0;
  2171. UNICODE_STRING VolumePath, UTypeCreatorString;
  2172. ANSI_STRING MacAnsiFileDirPath, ATypeCreatorString;
  2173. SDA Sda;
  2174. CONNDESC ConnDesc;
  2175. PVOLDESC pVolDesc;
  2176. AFPSTATUS Status;
  2177. FILEDIRPARM FDParm;
  2178. PATHMAPENTITY PME;
  2179. BYTE Type[AFP_TYPE_LEN] = " "; // Pad with spaces
  2180. BYTE Creator[AFP_CREATOR_LEN] = " "; // Pad with spaces
  2181. PAGED_CODE( );
  2182. pAdmFDInfo = (PAFP_FINDER_INFO)((PBYTE)InBuf + sizeof(SETINFOREQPKT));
  2183. ParmNum = ((PSETINFOREQPKT)InBuf)->sirqp_parmnum;
  2184. DBGPRINT(DBG_COMP_ADMINAPI_DIR, DBG_LEVEL_INFO,
  2185. ("AfpAdmWFinderSetInfo entered for %ws (%lx)\n",
  2186. pAdmFDInfo->afpfd_path, ParmNum));
  2187. if ((ParmNum & ~AFP_FD_PARMNUM_ALL) || !ParmNum)
  2188. {
  2189. return AFPERR_InvalidParms;
  2190. }
  2191. // Convert the parmnum to a bitmap for use by pathmap to retrieve current
  2192. // settings of FinderInfo, and convert type and creator to space padded
  2193. // mac ansi
  2194. if (ParmNum & AFP_FD_PARMNUM_TYPE)
  2195. {
  2196. Bitmap |= FD_BITMAP_FINDERINFO;
  2197. RtlInitUnicodeString(&UTypeCreatorString, pAdmFDInfo->afpfd_type);
  2198. if ((UTypeCreatorString.Length == 0) ||
  2199. (UTypeCreatorString.Length/sizeof(WCHAR) > AFP_TYPE_LEN))
  2200. {
  2201. return AFPERR_InvalidParms;
  2202. }
  2203. ATypeCreatorString.Length = 0;
  2204. ATypeCreatorString.MaximumLength = sizeof(Type);
  2205. ATypeCreatorString.Buffer = Type;
  2206. Status = AfpConvertStringToAnsi(&UTypeCreatorString,
  2207. &ATypeCreatorString);
  2208. if (!NT_SUCCESS(Status))
  2209. {
  2210. return STATUS_UNSUCCESSFUL;
  2211. }
  2212. }
  2213. if (ParmNum & AFP_FD_PARMNUM_CREATOR)
  2214. {
  2215. Bitmap |= FD_BITMAP_FINDERINFO;
  2216. RtlInitUnicodeString(&UTypeCreatorString, pAdmFDInfo->afpfd_creator);
  2217. if ((UTypeCreatorString.Length == 0) ||
  2218. (UTypeCreatorString.Length/sizeof(WCHAR) > AFP_CREATOR_LEN))
  2219. {
  2220. return AFPERR_InvalidParms;
  2221. }
  2222. ATypeCreatorString.Length = 0;
  2223. ATypeCreatorString.MaximumLength = sizeof(Creator);
  2224. ATypeCreatorString.Buffer = Creator;
  2225. Status = AfpConvertStringToAnsi(&UTypeCreatorString,
  2226. &ATypeCreatorString);
  2227. if (!NT_SUCCESS(Status))
  2228. {
  2229. return STATUS_UNSUCCESSFUL;
  2230. }
  2231. }
  2232. MacAnsiFileDirPath.Length = 0;
  2233. MacAnsiFileDirPath.MaximumLength = 0;
  2234. MacAnsiFileDirPath.Buffer = NULL;
  2235. // First find the volume that this directory is path of
  2236. RtlInitUnicodeString(&VolumePath, pAdmFDInfo->afpfd_path);
  2237. if (!NT_SUCCESS(Status = AfpVolumeReferenceByPath(&VolumePath, &pVolDesc)))
  2238. return Status;
  2239. // Now get the volume relative path of the file/directory.
  2240. VolumePath.Buffer = (LPWSTR)((PBYTE)VolumePath.Buffer +
  2241. pVolDesc->vds_Path.Length);
  2242. VolumePath.Length -= pVolDesc->vds_Path.Length;
  2243. VolumePath.MaximumLength -= pVolDesc->vds_Path.Length;
  2244. if ((SHORT)(VolumePath.Length) < 0)
  2245. {
  2246. VolumePath.Length = 0;
  2247. VolumePath.MaximumLength = sizeof(WCHAR);
  2248. }
  2249. if (Bitmap) do
  2250. {
  2251. AfpInitializeFDParms(&FDParm);
  2252. AfpInitializePME(&PME, 0, NULL);
  2253. if (!NT_SUCCESS(Status = afpConvertAdminPathToMacPath(pVolDesc,
  2254. &VolumePath,
  2255. &MacAnsiFileDirPath)))
  2256. {
  2257. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  2258. break;
  2259. }
  2260. // pathmap requires a ConnDesc to determine the VolDesc and Sda, so
  2261. // kludge up a fake one here
  2262. RtlZeroMemory(&ConnDesc, sizeof(ConnDesc));
  2263. #if DBG
  2264. ConnDesc.Signature = CONNDESC_SIGNATURE;
  2265. #endif
  2266. Sda.sda_ClientType = SDA_CLIENT_ADMIN;
  2267. ConnDesc.cds_pSda = &Sda;
  2268. ConnDesc.cds_pVolDesc = pVolDesc;
  2269. Status = AfpMapAfpPathForLookup(&ConnDesc, AFP_ID_ROOT,
  2270. &MacAnsiFileDirPath,
  2271. AFP_LONGNAME,
  2272. DFE_ANY,
  2273. FD_INTERNAL_BITMAP_OPENACCESS_ADMINGET |
  2274. FD_BITMAP_LONGNAME | Bitmap,
  2275. &PME,
  2276. &FDParm);
  2277. if (!NT_SUCCESS(Status))
  2278. {
  2279. if (Status == AFP_ERR_ACCESS_DENIED)
  2280. {
  2281. Status = STATUS_ACCESS_DENIED;
  2282. }
  2283. else
  2284. {
  2285. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  2286. }
  2287. break;
  2288. }
  2289. // Copy the input Finder info into the FDParms structure
  2290. if (ParmNum & AFP_FD_PARMNUM_TYPE)
  2291. RtlCopyMemory(&FDParm._fdp_FinderInfo.fd_Type,
  2292. Type, AFP_TYPE_LEN);
  2293. if (ParmNum & AFP_FD_PARMNUM_CREATOR)
  2294. RtlCopyMemory(&FDParm._fdp_FinderInfo.fd_Creator,
  2295. Creator, AFP_CREATOR_LEN);
  2296. // Set the AfpInfo
  2297. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  2298. Status = AfpSetAfpInfo(&PME.pme_Handle, Bitmap, &FDParm, pVolDesc, NULL);
  2299. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  2300. } while (False);
  2301. if (PME.pme_Handle.fsh_FileHandle != NULL)
  2302. AfpIoClose(&PME.pme_Handle);
  2303. if (MacAnsiFileDirPath.Buffer != NULL)
  2304. {
  2305. AfpFreeMemory(MacAnsiFileDirPath.Buffer);
  2306. }
  2307. AfpVolumeDereference(pVolDesc);
  2308. return Status;
  2309. }
  2310. /*** AfpLookupEtcMapEntry
  2311. *
  2312. * Lookup a type/creator mapping in the global table by comparing the
  2313. * extension to the desired extension. Note the default type creator
  2314. * mapping is not kept in the table.
  2315. *
  2316. * LOCKS_ASSUMED: AfpEtcMapLock (SWMR, Shared)
  2317. */
  2318. PETCMAPINFO
  2319. AfpLookupEtcMapEntry(
  2320. PUCHAR pExt
  2321. )
  2322. {
  2323. PETCMAPINFO petc = NULL;
  2324. ANSI_STRING alookupext, atableext;
  2325. int i;
  2326. PAGED_CODE( );
  2327. if (AfpEtcMapCount == 0)
  2328. {
  2329. return NULL;
  2330. }
  2331. ASSERT ((AfpEtcMapsSize > 0) && (AfpEtcMaps != NULL));
  2332. RtlInitString(&alookupext,pExt);
  2333. for (i=0;i<AfpEtcMapsSize;i++)
  2334. {
  2335. RtlInitString(&atableext,AfpEtcMaps[i].etc_extension);
  2336. if (RtlEqualString(&atableext, &alookupext,True))
  2337. {
  2338. petc = &(AfpEtcMaps[i]);
  2339. break;
  2340. }
  2341. }
  2342. return petc;
  2343. }
  2344. /*** afpEtcMapDelete
  2345. *
  2346. * Mark the extension/type/creator table entry as deleted by setting the
  2347. * extension field to null. Decrement the count of valid entries. If
  2348. * the number of free entries goes above a certain level, shrink the
  2349. * table down to a reasonable size.
  2350. *
  2351. * LOCKS_ASSUMED: AfpEtcMapLock (SWMR, Exclusive)
  2352. *
  2353. */
  2354. VOID
  2355. afpEtcMapDelete(
  2356. PETCMAPINFO pEtcEntry
  2357. )
  2358. {
  2359. PETCMAPINFO ptemptable;
  2360. LONG newtablesize, nextnewentry, i;
  2361. PAGED_CODE( );
  2362. //
  2363. // a null extension denotes an invalid ext/type/creator mapping table entry
  2364. //
  2365. pEtcEntry->etc_extension[0] = '\0';
  2366. AfpEtcMapCount --;
  2367. ASSERT (AfpEtcMapCount >= 0);
  2368. if ((AfpEtcMapsSize - AfpEtcMapCount) > AFP_MAX_FREE_ETCMAP_ENTRIES)
  2369. {
  2370. //
  2371. // shrink the type/creator table by AFP_MAX_FREE_ETCMAP_ENTRIES
  2372. //
  2373. newtablesize = (AfpEtcMapsSize - AFP_MAX_FREE_ETCMAP_ENTRIES);
  2374. if ((ptemptable = (PETCMAPINFO)AfpAllocZeroedPagedMemory(newtablesize * sizeof(ETCMAPINFO))) == NULL)
  2375. {
  2376. return;
  2377. }
  2378. nextnewentry = 0;
  2379. for (i=0;i<AfpEtcMapsSize;i++)
  2380. {
  2381. if (afpIsValidEtcMapEntry(AfpEtcMaps[i].etc_extension))
  2382. {
  2383. ASSERT(nextnewentry < AfpEtcMapCount);
  2384. RtlCopyMemory(&ptemptable[nextnewentry++], &AfpEtcMaps[i], sizeof(ETCMAPINFO));
  2385. }
  2386. }
  2387. AfpFreeMemory(AfpEtcMaps);
  2388. AfpEtcMaps = ptemptable;
  2389. AfpEtcMapsSize = newtablesize;
  2390. }
  2391. }
  2392. /*** afpGetNextFreeEtcMapEntry
  2393. *
  2394. * Look for an empty entry in the extension/type/creator table starting
  2395. * at the entry StartIndex.
  2396. *
  2397. * LOCKS_ASSUMED: AfpEtcMapLock (SWMR, Exclusive)
  2398. */
  2399. PETCMAPINFO
  2400. afpGetNextFreeEtcMapEntry(
  2401. IN OUT PLONG StartIndex
  2402. )
  2403. {
  2404. PETCMAPINFO tempptr = NULL;
  2405. LONG i;
  2406. PAGED_CODE( );
  2407. for (i = *StartIndex; i < AfpEtcMapsSize; i++)
  2408. {
  2409. if (!afpIsValidEtcMapEntry(AfpEtcMaps[i].etc_extension))
  2410. {
  2411. tempptr = &AfpEtcMaps[i];
  2412. *StartIndex = i++;
  2413. break;
  2414. }
  2415. }
  2416. return tempptr;
  2417. }
  2418. /*** afpCopyMapInfo2ToMapInfo
  2419. *
  2420. * Copy the etc info structure given to us by the Service into our structure, after
  2421. * converting the etc_extension field from Unicode to Ansi.
  2422. *
  2423. */
  2424. NTSTATUS
  2425. afpCopyMapInfo2ToMapInfo(
  2426. OUT PETCMAPINFO pEtcDest,
  2427. IN PETCMAPINFO2 pEtcSource
  2428. )
  2429. {
  2430. UCHAR ext[AFP_EXTENSION_LEN+1];
  2431. WCHAR wext[AFP_EXTENSION_LEN+1];
  2432. ANSI_STRING aext;
  2433. NTSTATUS Status;
  2434. UNICODE_STRING uext;
  2435. AfpSetEmptyAnsiString(&aext, sizeof(ext), ext);
  2436. uext.Length = uext.MaximumLength = sizeof(pEtcSource->etc_extension);
  2437. uext.Buffer = pEtcSource->etc_extension;
  2438. Status = AfpConvertMungedUnicodeToAnsi(&uext, &aext);
  2439. ASSERT(NT_SUCCESS(Status));
  2440. RtlCopyMemory(pEtcDest->etc_extension, aext.Buffer, AFP_EXTENSION_LEN);
  2441. pEtcDest->etc_extension[AFP_EXTENSION_LEN] = 0;
  2442. // Copy the other two fields as-is
  2443. RtlCopyMemory(pEtcDest->etc_type, pEtcSource->etc_type, AFP_TYPE_LEN);
  2444. RtlCopyMemory(pEtcDest->etc_creator, pEtcSource->etc_creator, AFP_CREATOR_LEN);
  2445. return STATUS_SUCCESS;
  2446. }
  2447. /*** afpConvertAdminPathToMacPath
  2448. *
  2449. * Convert an admin volume relative NTFS path which may contain
  2450. * components > 31 chars, or may contain shortnames, to the
  2451. * equivalent mac path (in mac ANSI) so that the path may be sent thru the
  2452. * pathmap code. Caller must free path buffer if success is returned.
  2453. */
  2454. NTSTATUS
  2455. afpConvertAdminPathToMacPath(
  2456. IN PVOLDESC pVolDesc,
  2457. IN PUNICODE_STRING AdminPath,
  2458. OUT PANSI_STRING MacPath
  2459. )
  2460. {
  2461. USHORT tempAdminPathlen = 0, numchars, numcomponents, i;
  2462. WCHAR wbuf[AFP_LONGNAME_LEN + 1];
  2463. UNICODE_STRING component, component2;
  2464. UNICODE_STRING pathSoFar, pathToParent;
  2465. NTSTATUS Status = STATUS_SUCCESS;
  2466. CHAR abuf[AFP_LONGNAME_LEN + 1];
  2467. ANSI_STRING macansiComponent;
  2468. PWSTR tempptr;
  2469. FILESYSHANDLE hComponent;
  2470. BOOLEAN NTFSShortname;
  2471. PAGED_CODE( );
  2472. // ASSERT(IS_VOLUME_NTFS(pVolDesc));
  2473. // assert that the path does not begin with a backslash
  2474. ASSERT((AdminPath->Length == 0) || (AdminPath->Buffer[0] != L'\\'));
  2475. component2.Length = 0;
  2476. component2.MaximumLength = sizeof(wbuf);
  2477. component2.Buffer = wbuf;
  2478. macansiComponent.Length = 0;
  2479. macansiComponent.MaximumLength = sizeof(abuf);
  2480. macansiComponent.Buffer = abuf;
  2481. MacPath->Length = MacPath->MaximumLength = 0;
  2482. MacPath->Buffer = NULL;
  2483. // return success if no path components
  2484. if (AdminPath->Length == 0)
  2485. {
  2486. return STATUS_SUCCESS;
  2487. }
  2488. numchars = AdminPath->Length / sizeof(WCHAR);
  2489. // strip a trailing path separator if it exists
  2490. if (AdminPath->Buffer[numchars - 1] == L'\\')
  2491. {
  2492. AdminPath->Length -= sizeof(WCHAR);
  2493. }
  2494. for (numcomponents = 1, i = 0; i < numchars; i++)
  2495. {
  2496. if (AdminPath->Buffer[i] == L'\\')
  2497. {
  2498. numcomponents++;
  2499. }
  2500. }
  2501. // allocate a buffer to hold the mac (in mac ANSI) version of the path and
  2502. // path separators
  2503. MacPath->MaximumLength = numcomponents * AFP_LONGNAME_LEN + numcomponents;
  2504. if ((MacPath->Buffer = (PCHAR)AfpAllocPagedMemory(MacPath->MaximumLength))
  2505. == NULL)
  2506. {
  2507. return STATUS_INSUFFICIENT_RESOURCES;
  2508. }
  2509. pathSoFar = *AdminPath;
  2510. pathSoFar.Length = 0;
  2511. tempptr = AdminPath->Buffer;
  2512. while (numcomponents)
  2513. {
  2514. hComponent.fsh_FileHandle = NULL;
  2515. component.Buffer = tempptr;
  2516. component2.Length = macansiComponent.Length = 0;
  2517. NTFSShortname = False;
  2518. numchars = 0;
  2519. while (True)
  2520. {
  2521. if (tempptr[numchars] == L'~')
  2522. {
  2523. NTFSShortname = True;
  2524. }
  2525. if ((tempptr[numchars] == L'\\') ||
  2526. ((numcomponents == 1) &&
  2527. (pathSoFar.Length + numchars * sizeof(WCHAR)
  2528. == AdminPath->Length)))
  2529. {
  2530. break;
  2531. }
  2532. numchars ++;
  2533. }
  2534. component.Length = component.MaximumLength = numchars * sizeof(WCHAR);
  2535. pathToParent = pathSoFar;
  2536. pathSoFar.Length += component.Length;
  2537. tempptr += numchars + 1;
  2538. if ((numchars > AFP_LONGNAME_LEN) || (NTFSShortname))
  2539. {
  2540. // open a handle to the directory so we can query the name;
  2541. // to query the shortname we need a handle to the actual
  2542. // directory; to query the longname, we need a handle to the
  2543. // parent directory because of the way we have to
  2544. // get the longname by enumerating the parent for one entry
  2545. // with the name we are looking for
  2546. if (NT_SUCCESS(Status = AfpIoOpen(&pVolDesc->vds_hRootDir,
  2547. AFP_STREAM_DATA,
  2548. FILEIO_OPEN_DIR,
  2549. ((numchars <= AFP_LONGNAME_LEN) && NTFSShortname) ?
  2550. &pathToParent : &pathSoFar,
  2551. FILEIO_ACCESS_NONE,
  2552. FILEIO_DENY_NONE,
  2553. False,
  2554. &hComponent)))
  2555. {
  2556. if (numchars > AFP_LONGNAME_LEN)
  2557. {
  2558. // query the shortname
  2559. Status = AfpIoQueryShortName(&hComponent, &macansiComponent);
  2560. }
  2561. else
  2562. {
  2563. // we saw a tilde and are assuming it is the shortname,
  2564. // and the path is 31 chars or less; query the longname
  2565. if (NT_SUCCESS(Status = AfpIoQueryLongName(&hComponent,
  2566. &component,
  2567. &component2)))
  2568. {
  2569. Status = AfpConvertMungedUnicodeToAnsi(&component2,
  2570. &macansiComponent);
  2571. }
  2572. }
  2573. AfpIoClose(&hComponent);
  2574. if (!NT_SUCCESS(Status))
  2575. {
  2576. break;
  2577. }
  2578. }
  2579. else
  2580. {
  2581. // open failed
  2582. break;
  2583. }
  2584. }
  2585. else
  2586. {
  2587. // use the component name as it was given by admin
  2588. if (!NT_SUCCESS(Status = AfpConvertMungedUnicodeToAnsi(&component,
  2589. &macansiComponent)))
  2590. {
  2591. break;
  2592. }
  2593. }
  2594. Status = RtlAppendStringToString(MacPath, &macansiComponent);
  2595. ASSERT(NT_SUCCESS(Status));
  2596. if (!NT_SUCCESS(Status))
  2597. {
  2598. break;
  2599. }
  2600. // include the path separator in the admin path seen so far
  2601. pathSoFar.Length += sizeof(WCHAR);
  2602. // add a path separator to the mac ansi path
  2603. MacPath->Buffer[MacPath->Length++] = AFP_PATHSEP;
  2604. ASSERT(MacPath->Length <= MacPath->MaximumLength);
  2605. numcomponents --;
  2606. } // while numcomponents
  2607. if (!NT_SUCCESS(Status) && (MacPath->Buffer != NULL))
  2608. {
  2609. AfpFreeMemory(MacPath->Buffer);
  2610. MacPath->Buffer = NULL;
  2611. }
  2612. return Status;
  2613. }