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

785 lines
18 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. api.c
  5. Abstract:
  6. This module contains misc APIs that are used by the
  7. NWC wksta.
  8. Author:
  9. ChuckC 2-Mar-94 Created
  10. Revision History:
  11. --*/
  12. #include <stdlib.h>
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <windows.h>
  17. #include <nwcons.h>
  18. #include <nwmisc.h>
  19. #include <nwapi32.h>
  20. #include "nwstatus.h"
  21. #include "nwevent.h"
  22. DWORD
  23. NwMapStatus(
  24. IN NTSTATUS NtStatus
  25. );
  26. DWORD
  27. NwOpenPreferredServer(
  28. PHANDLE ServerHandle
  29. );
  30. NTSTATUS
  31. NwOpenHandle(
  32. IN PUNICODE_STRING ObjectName,
  33. IN BOOL ValidateFlag,
  34. OUT PHANDLE ObjectHandle
  35. );
  36. NTSTATUS
  37. NwCallNtOpenFile(
  38. OUT PHANDLE ObjectHandle,
  39. IN ACCESS_MASK DesiredAccess,
  40. IN PUNICODE_STRING ObjectName,
  41. IN ULONG OpenOptions
  42. );
  43. //
  44. // list of error mappings known for E3H calls. we do not have a single list
  45. // because Netware reuses the numbers depending on call.
  46. //
  47. typedef struct _ERROR_MAP_ENTRY
  48. {
  49. UCHAR NetError;
  50. NTSTATUS ResultingStatus;
  51. } ERROR_MAP_ENTRY ;
  52. ERROR_MAP_ENTRY Error_Map_Bindery[] =
  53. {
  54. //
  55. // NetWare specific error mappings. Specific to E3H.
  56. //
  57. { 1, STATUS_DISK_FULL },
  58. {128, STATUS_SHARING_VIOLATION },
  59. {129, STATUS_INSUFF_SERVER_RESOURCES },
  60. {130, STATUS_ACCESS_DENIED },
  61. {131, STATUS_DATA_ERROR },
  62. {132, STATUS_ACCESS_DENIED },
  63. {133, STATUS_ACCESS_DENIED },
  64. {134, STATUS_ACCESS_DENIED },
  65. {135, STATUS_OBJECT_NAME_INVALID },
  66. {136, STATUS_INVALID_HANDLE },
  67. {137, STATUS_ACCESS_DENIED },
  68. {138, STATUS_ACCESS_DENIED },
  69. {139, STATUS_ACCESS_DENIED },
  70. {140, STATUS_ACCESS_DENIED },
  71. {141, STATUS_SHARING_VIOLATION },
  72. {142, STATUS_SHARING_VIOLATION },
  73. {143, STATUS_ACCESS_DENIED },
  74. {144, STATUS_ACCESS_DENIED },
  75. {145, STATUS_OBJECT_NAME_COLLISION },
  76. {146, STATUS_OBJECT_NAME_COLLISION },
  77. {147, STATUS_ACCESS_DENIED },
  78. {148, STATUS_ACCESS_DENIED },
  79. {150, STATUS_INSUFF_SERVER_RESOURCES },
  80. {151, STATUS_NO_SPOOL_SPACE },
  81. {152, STATUS_NO_SUCH_DEVICE },
  82. {153, STATUS_DISK_FULL },
  83. {154, STATUS_NOT_SAME_DEVICE },
  84. {155, STATUS_INVALID_HANDLE },
  85. {156, STATUS_OBJECT_PATH_NOT_FOUND },
  86. {157, STATUS_INSUFF_SERVER_RESOURCES },
  87. {158, STATUS_OBJECT_PATH_INVALID },
  88. {159, STATUS_SHARING_VIOLATION },
  89. {160, STATUS_DIRECTORY_NOT_EMPTY },
  90. {161, STATUS_DATA_ERROR },
  91. {162, STATUS_SHARING_VIOLATION },
  92. {192, STATUS_ACCESS_DENIED },
  93. {198, STATUS_ACCESS_DENIED },
  94. {211, STATUS_ACCESS_DENIED },
  95. {212, STATUS_PRINT_QUEUE_FULL },
  96. {213, STATUS_PRINT_CANCELLED },
  97. {214, STATUS_ACCESS_DENIED },
  98. {215, STATUS_PASSWORD_RESTRICTION },
  99. {216, STATUS_PASSWORD_RESTRICTION },
  100. {220, STATUS_ACCOUNT_DISABLED },
  101. {222, STATUS_PASSWORD_EXPIRED },
  102. {223, STATUS_PASSWORD_EXPIRED },
  103. {239, STATUS_OBJECT_NAME_INVALID },
  104. {240, STATUS_OBJECT_NAME_INVALID },
  105. {251, STATUS_INVALID_PARAMETER },
  106. {252, STATUS_NO_MORE_ENTRIES },
  107. {253, STATUS_FILE_LOCK_CONFLICT },
  108. {254, STATUS_FILE_LOCK_CONFLICT },
  109. {255, STATUS_UNSUCCESSFUL}
  110. };
  111. ERROR_MAP_ENTRY Error_Map_General[] =
  112. {
  113. { 1, STATUS_DISK_FULL },
  114. {128, STATUS_SHARING_VIOLATION },
  115. {129, STATUS_INSUFF_SERVER_RESOURCES },
  116. {130, STATUS_ACCESS_DENIED },
  117. {131, STATUS_DATA_ERROR },
  118. {132, STATUS_ACCESS_DENIED },
  119. {133, STATUS_ACCESS_DENIED },
  120. {134, STATUS_ACCESS_DENIED },
  121. {135, STATUS_OBJECT_NAME_INVALID },
  122. {136, STATUS_INVALID_HANDLE },
  123. {137, STATUS_ACCESS_DENIED },
  124. {138, STATUS_ACCESS_DENIED },
  125. {139, STATUS_ACCESS_DENIED },
  126. {140, STATUS_ACCESS_DENIED },
  127. {141, STATUS_SHARING_VIOLATION },
  128. {142, STATUS_SHARING_VIOLATION },
  129. {143, STATUS_ACCESS_DENIED },
  130. {144, STATUS_ACCESS_DENIED },
  131. {145, STATUS_OBJECT_NAME_COLLISION },
  132. {146, STATUS_OBJECT_NAME_COLLISION },
  133. {147, STATUS_ACCESS_DENIED },
  134. {148, STATUS_ACCESS_DENIED },
  135. {150, STATUS_INSUFF_SERVER_RESOURCES },
  136. {151, STATUS_NO_SPOOL_SPACE },
  137. {152, STATUS_NO_SUCH_DEVICE },
  138. {153, STATUS_DISK_FULL },
  139. {154, STATUS_NOT_SAME_DEVICE },
  140. {155, STATUS_INVALID_HANDLE },
  141. {156, STATUS_OBJECT_PATH_NOT_FOUND },
  142. {157, STATUS_INSUFF_SERVER_RESOURCES },
  143. {158, STATUS_OBJECT_PATH_INVALID },
  144. {159, STATUS_SHARING_VIOLATION },
  145. {160, STATUS_DIRECTORY_NOT_EMPTY },
  146. {161, STATUS_DATA_ERROR },
  147. {162, STATUS_SHARING_VIOLATION },
  148. {192, STATUS_ACCESS_DENIED },
  149. {198, STATUS_ACCESS_DENIED },
  150. {211, STATUS_ACCESS_DENIED },
  151. {212, STATUS_PRINT_QUEUE_FULL },
  152. {213, STATUS_PRINT_CANCELLED },
  153. {214, STATUS_ACCESS_DENIED },
  154. {215, STATUS_DEVICE_BUSY },
  155. {216, STATUS_DEVICE_DOES_NOT_EXIST },
  156. {220, STATUS_ACCOUNT_DISABLED },
  157. {222, STATUS_PASSWORD_EXPIRED },
  158. {223, STATUS_PASSWORD_EXPIRED },
  159. {239, STATUS_OBJECT_NAME_INVALID },
  160. {240, STATUS_OBJECT_NAME_INVALID },
  161. {251, STATUS_INVALID_PARAMETER },
  162. {252, STATUS_NO_MORE_ENTRIES },
  163. {253, STATUS_FILE_LOCK_CONFLICT },
  164. {254, STATUS_FILE_LOCK_CONFLICT },
  165. {255, STATUS_UNSUCCESSFUL}
  166. };
  167. #define NUM_ERRORS(x) (sizeof(x)/sizeof(x[0]))
  168. DWORD
  169. NwMapBinderyCompletionCode(
  170. IN NTSTATUS NtStatus
  171. )
  172. /*++
  173. Routine Description:
  174. This function takes a bindery completion code embedded in an NT status
  175. code and maps it to the appropriate Win32 error code. Used specifically
  176. for E3H operations.
  177. Arguments:
  178. NtStatus - Supplies the NT status (that contains the code in low 16 bits)
  179. Return Value:
  180. Returns the appropriate Win32 error.
  181. --*/
  182. {
  183. DWORD i; UCHAR code ;
  184. //
  185. // A small optimization for the most common case.
  186. //
  187. if (NtStatus == STATUS_SUCCESS)
  188. return NO_ERROR;
  189. //
  190. // Map connection errors specially.
  191. //
  192. if ( ( (NtStatus & 0xFFFF0000) == 0xC0010000) &&
  193. ( (NtStatus & 0xFF00) != 0 ) )
  194. {
  195. return ERROR_UNEXP_NET_ERR;
  196. }
  197. //
  198. // if facility code not set, assume it is NT Status
  199. //
  200. if ( (NtStatus & 0xFFFF0000) != 0xC0010000)
  201. return RtlNtStatusToDosError(NtStatus);
  202. code = (UCHAR)(NtStatus & 0x000000FF);
  203. for (i = 0; i < NUM_ERRORS(Error_Map_Bindery); i++)
  204. {
  205. if (Error_Map_Bindery[i].NetError == code)
  206. return( NwMapStatus(Error_Map_Bindery[i].ResultingStatus));
  207. }
  208. //
  209. // if cannot find let NwMapStatus do its best
  210. //
  211. return NwMapStatus(NtStatus);
  212. }
  213. DWORD
  214. NwMapStatus(
  215. IN NTSTATUS NtStatus
  216. )
  217. /*++
  218. Routine Description:
  219. This function takes an NT status code and maps it to the appropriate
  220. Win32 error code. If facility code is set, assume it is NW specific
  221. Arguments:
  222. NtStatus - Supplies the NT status.
  223. Return Value:
  224. Returns the appropriate Win32 error.
  225. --*/
  226. {
  227. DWORD i; UCHAR code ;
  228. //
  229. // A small optimization for the most common case.
  230. //
  231. if (NtStatus == STATUS_SUCCESS)
  232. return NO_ERROR;
  233. //
  234. // Map connection errors specially.
  235. //
  236. if ( ( (NtStatus & 0xFFFF0000) == 0xC0010000) &&
  237. ( (NtStatus & 0xFF00) != 0 ) )
  238. {
  239. return ERROR_UNEXP_NET_ERR;
  240. }
  241. //
  242. // if facility code set, assume it is NW Completion code
  243. //
  244. if ( (NtStatus & 0xFFFF0000) == 0xC0010000)
  245. {
  246. code = (UCHAR)(NtStatus & 0x000000FF);
  247. for (i = 0; i < NUM_ERRORS(Error_Map_General); i++)
  248. {
  249. if (Error_Map_General[i].NetError == code)
  250. {
  251. //
  252. // map it to NTSTATUS and then drop thru to map to Win32
  253. //
  254. NtStatus = Error_Map_General[i].ResultingStatus ;
  255. break ;
  256. }
  257. }
  258. }
  259. switch (NtStatus) {
  260. case STATUS_OBJECT_NAME_COLLISION:
  261. return ERROR_ALREADY_ASSIGNED;
  262. case STATUS_OBJECT_NAME_NOT_FOUND:
  263. return ERROR_NOT_CONNECTED;
  264. case STATUS_IMAGE_ALREADY_LOADED:
  265. case STATUS_REDIRECTOR_STARTED:
  266. return ERROR_SERVICE_ALREADY_RUNNING;
  267. case STATUS_REDIRECTOR_HAS_OPEN_HANDLES:
  268. return ERROR_REDIRECTOR_HAS_OPEN_HANDLES;
  269. case STATUS_NO_MORE_FILES:
  270. case STATUS_NO_MORE_ENTRIES:
  271. return WN_NO_MORE_ENTRIES;
  272. case STATUS_MORE_ENTRIES:
  273. return WN_MORE_DATA;
  274. case STATUS_CONNECTION_IN_USE:
  275. return ERROR_DEVICE_IN_USE;
  276. case NWRDR_PASSWORD_HAS_EXPIRED:
  277. return NW_PASSWORD_HAS_EXPIRED;
  278. case STATUS_INVALID_DEVICE_REQUEST:
  279. return ERROR_CONNECTION_INVALID;
  280. default:
  281. return RtlNtStatusToDosError(NtStatus);
  282. }
  283. }
  284. DWORD
  285. NwGetGraceLoginCount(
  286. LPWSTR Server,
  287. LPWSTR UserName,
  288. LPDWORD lpResult
  289. )
  290. /*++
  291. Routine Description:
  292. Get the number grace logins for a user.
  293. Arguments:
  294. Server - the server to authenticate against
  295. UserName - the user account
  296. Return Value:
  297. Returns the appropriate Win32 error.
  298. --*/
  299. {
  300. DWORD status ;
  301. HANDLE hConn ;
  302. CHAR UserNameO[NW_MAX_USERNAME_LEN+1] ;
  303. BYTE LoginControl[128] ;
  304. BYTE MoreFlags, PropFlags ;
  305. //
  306. // skip the backslashes if present
  307. //
  308. if (*Server == L'\\')
  309. Server += 2 ;
  310. //
  311. // attach to the NW server
  312. //
  313. if (status = NWAttachToFileServerW(Server,
  314. 0,
  315. &hConn))
  316. {
  317. return status ;
  318. }
  319. //
  320. // convert unicode UserName to OEM, and then call the NCP
  321. //
  322. if ( !WideCharToMultiByte(CP_OEMCP,
  323. 0,
  324. UserName,
  325. -1,
  326. UserNameO,
  327. sizeof(UserNameO),
  328. NULL,
  329. NULL))
  330. {
  331. status = GetLastError() ;
  332. }
  333. else
  334. {
  335. status = NWReadPropertyValue( hConn,
  336. UserNameO,
  337. OT_USER,
  338. "LOGIN_CONTROL",
  339. 1,
  340. LoginControl,
  341. &MoreFlags,
  342. &PropFlags) ;
  343. }
  344. //
  345. // dont need these anymore. if any error, bag out
  346. //
  347. (void) NWDetachFromFileServer(hConn) ;
  348. if (status == NO_ERROR)
  349. *lpResult = (DWORD) LoginControl[7] ;
  350. return status ;
  351. }
  352. WORD
  353. NwParseNdsUncPath(
  354. IN OUT LPWSTR * Result,
  355. IN LPWSTR ContainerName,
  356. IN ULONG flag
  357. )
  358. /*++
  359. Routine Description:
  360. This function is used to extract either the tree name, fully distinguished
  361. name path to an object, or object name, out of a complete NDS UNC path.
  362. Arguments:
  363. Result - parsed result buffer.
  364. ContainerName - Complete NDS UNC path that is to be parsed.
  365. flag - Flag indicating operation to be performed:
  366. PARSE_NDS_GET_TREE_NAME
  367. PARSE_NDS_GET_PATH_NAME
  368. PARSE_NDS_GET_OBJECT_NAME
  369. Return Value:
  370. Length of string in result buffer. If error occured, 0 is returned.
  371. --*/ // NwParseNdsUncPath
  372. {
  373. unsigned short length = 2;
  374. unsigned short totalLength = (USHORT) wcslen( ContainerName );
  375. if ( totalLength < 2 )
  376. return 0;
  377. //
  378. // First get length to indicate the character in the string that indicates the
  379. // "\" in between the tree name and the rest of the UNC path.
  380. //
  381. // Example: \\<tree name>\<path to object>[\|.]<object>
  382. // ^
  383. // |
  384. //
  385. while ( length < totalLength && ContainerName[length] != L'\\' )
  386. {
  387. length++;
  388. }
  389. if ( flag == PARSE_NDS_GET_TREE_NAME )
  390. {
  391. *Result = (LPWSTR) ( ContainerName + 2 );
  392. return ( length - 2 ) * sizeof( WCHAR ); // Take off 2 for the two \\'s
  393. }
  394. if ( flag == PARSE_NDS_GET_PATH_NAME && length == totalLength )
  395. {
  396. *Result = ContainerName;
  397. return 0;
  398. }
  399. if ( flag == PARSE_NDS_GET_PATH_NAME )
  400. {
  401. *Result = ContainerName + length + 1;
  402. return ( totalLength - length - 1 ) * sizeof( WCHAR );
  403. }
  404. *Result = ContainerName + totalLength - 1;
  405. length = 1;
  406. while ( **Result != L'\\' )
  407. {
  408. *Result--;
  409. length++;
  410. }
  411. *Result++;
  412. length--;
  413. return length * sizeof( WCHAR );
  414. }
  415. DWORD
  416. NwOpenAServer(
  417. PWCHAR pwszServName,
  418. PHANDLE ServerHandle,
  419. BOOL fVerify
  420. )
  421. /*++
  422. Routine Description:
  423. This routine opens a handle to a server.
  424. Arguments:
  425. ServerHandle - Receives an opened handle to the preferred or
  426. nearest server.
  427. Return Value:
  428. NO_ERROR or reason for failure.
  429. --*/
  430. {
  431. UNICODE_STRING AServer;
  432. WCHAR wszName[sizeof(NW_RDR_NAME) + (48 * sizeof(WCHAR))];
  433. DWORD wLen;
  434. if(!pwszServName)
  435. {
  436. pwszServName = NW_RDR_PREFERRED_SERVER;
  437. RtlInitUnicodeString(&AServer, wszName);
  438. }
  439. else
  440. {
  441. wLen = wcslen(pwszServName);
  442. if(wLen > 47)
  443. {
  444. return(WSAEFAULT);
  445. }
  446. wcscpy(wszName, NW_RDR_NAME);
  447. wcscat(wszName, pwszServName);
  448. RtlInitUnicodeString(&AServer, wszName);
  449. }
  450. return RtlNtStatusToDosError(
  451. NwOpenHandle(&AServer, fVerify, ServerHandle)
  452. );
  453. }
  454. DWORD
  455. NwOpenPreferredServer(
  456. PHANDLE ServerHandle
  457. )
  458. /*++
  459. Routine Description:
  460. This routine opens a handle to the preferred server. If the
  461. preferred server has not been specified, a handle to the
  462. nearest server is opened instead.
  463. Arguments:
  464. ServerHandle - Receives an opened handle to the preferred or
  465. nearest server.
  466. Return Value:
  467. NO_ERROR or reason for failure.
  468. --*/
  469. {
  470. UNICODE_STRING PreferredServer;
  471. //
  472. // The NetWare redirector recognizes "*" to mean the preferred
  473. // or nearest server.
  474. //
  475. RtlInitUnicodeString(&PreferredServer, NW_RDR_PREFERRED_SERVER);
  476. return RtlNtStatusToDosError(
  477. NwOpenHandle(&PreferredServer, FALSE, ServerHandle)
  478. );
  479. }
  480. NTSTATUS
  481. NwOpenHandle(
  482. IN PUNICODE_STRING ObjectName,
  483. IN BOOL ValidateFlag,
  484. OUT PHANDLE ObjectHandle
  485. )
  486. /*++
  487. Routine Description:
  488. This function opens a handle to \Device\Nwrdr\<ObjectName>.
  489. Arguments:
  490. ObjectName - Supplies the name of the redirector object to open.
  491. ValidateFlag - Supplies a flag which if TRUE, opens the handle to
  492. the object by validating the default user account.
  493. ObjectHandle - Receives a pointer to the opened object handle.
  494. Return Value:
  495. STATUS_SUCCESS or reason for failure.
  496. --*/
  497. {
  498. ACCESS_MASK DesiredAccess = SYNCHRONIZE;
  499. if (ValidateFlag) {
  500. //
  501. // The redirector only authenticates the default user credential
  502. // if the remote resource is opened with write access.
  503. //
  504. DesiredAccess |= FILE_WRITE_DATA;
  505. }
  506. *ObjectHandle = NULL;
  507. return NwCallNtOpenFile(
  508. ObjectHandle,
  509. DesiredAccess,
  510. ObjectName,
  511. FILE_SYNCHRONOUS_IO_NONALERT
  512. );
  513. }
  514. NTSTATUS
  515. NwCallNtOpenFile(
  516. OUT PHANDLE ObjectHandle,
  517. IN ACCESS_MASK DesiredAccess,
  518. IN PUNICODE_STRING ObjectName,
  519. IN ULONG OpenOptions
  520. )
  521. {
  522. NTSTATUS ntstatus;
  523. IO_STATUS_BLOCK IoStatusBlock;
  524. OBJECT_ATTRIBUTES ObjectAttributes;
  525. InitializeObjectAttributes(
  526. &ObjectAttributes,
  527. ObjectName,
  528. OBJ_CASE_INSENSITIVE,
  529. NULL,
  530. NULL
  531. );
  532. ntstatus = NtOpenFile(
  533. ObjectHandle,
  534. DesiredAccess,
  535. &ObjectAttributes,
  536. &IoStatusBlock,
  537. FILE_SHARE_VALID_FLAGS,
  538. OpenOptions
  539. );
  540. if (!NT_ERROR(ntstatus) &&
  541. !NT_INFORMATION(ntstatus) &&
  542. !NT_WARNING(ntstatus)) {
  543. ntstatus = IoStatusBlock.Status;
  544. }
  545. return ntstatus;
  546. }
  547. BOOL
  548. NwConvertToUnicode(
  549. OUT LPWSTR *UnicodeOut,
  550. IN LPSTR OemIn
  551. )
  552. /*++
  553. Routine Description:
  554. This function converts the given OEM string to a Unicode string.
  555. The Unicode string is returned in a buffer allocated by this
  556. function and must be freed with LocalFree.
  557. Arguments:
  558. UnicodeOut - Receives a pointer to the Unicode string.
  559. OemIn - This is a pointer to an ansi string that is to be converted.
  560. Return Value:
  561. TRUE - The conversion was successful.
  562. FALSE - The conversion was unsuccessful. In this case a buffer for
  563. the unicode string was not allocated.
  564. --*/
  565. {
  566. NTSTATUS ntstatus;
  567. DWORD BufSize;
  568. UNICODE_STRING UnicodeString;
  569. OEM_STRING OemString;
  570. //
  571. // Allocate a buffer for the unicode string.
  572. //
  573. BufSize = (strlen(OemIn) + 1) * sizeof(WCHAR);
  574. *UnicodeOut = LocalAlloc(LMEM_ZEROINIT, BufSize);
  575. if (*UnicodeOut == NULL) {
  576. KdPrint(("NWWORKSTATION: NwConvertToUnicode:LocalAlloc failed %lu\n",
  577. GetLastError()));
  578. return FALSE;
  579. }
  580. //
  581. // Initialize the string structures
  582. //
  583. RtlInitAnsiString((PANSI_STRING) &OemString, OemIn);
  584. UnicodeString.Buffer = *UnicodeOut;
  585. UnicodeString.MaximumLength = (USHORT) BufSize;
  586. UnicodeString.Length = 0;
  587. //
  588. // Call the conversion function.
  589. //
  590. ntstatus = RtlOemStringToUnicodeString(
  591. &UnicodeString, // Destination
  592. &OemString, // Source
  593. FALSE // Allocate the destination
  594. );
  595. if (ntstatus != STATUS_SUCCESS) {
  596. KdPrint(("NWWORKSTATION: NwConvertToUnicode: RtlOemStringToUnicodeString failure x%08lx\n",
  597. ntstatus));
  598. (void) LocalFree((HLOCAL) *UnicodeOut);
  599. *UnicodeOut = NULL;
  600. return FALSE;
  601. }
  602. *UnicodeOut = UnicodeString.Buffer;
  603. return TRUE;
  604. }