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.

1332 lines
39 KiB

  1. // *********************************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // Module Name:
  6. //
  7. // RmtConnectivity.c
  8. //
  9. // Abstract:
  10. //
  11. // This modules implements remote connectivity functionality for all the
  12. // command line tools.
  13. //
  14. // Author:
  15. //
  16. // Sunil G.V.N. Murali ([email protected]) 13-Nov-2000
  17. //
  18. // Revision History:
  19. //
  20. // Sunil G.V.N. Murali ([email protected]) 13-Sep-2000 : Created It.
  21. //
  22. // *********************************************************************************
  23. #include "pch.h"
  24. #include "cmdline.h"
  25. #include "cmdlineres.h"
  26. //
  27. // constants / defines / enumerations
  28. //
  29. #define STR_INPUT_PASSWORD GetResString( IDS_STR_INPUT_PASSWORD )
  30. #define ERROR_LOCAL_CREDENTIALS GetResString( IDS_ERROR_LOCAL_CREDENTIALS )
  31. // share names
  32. #define SHARE_IPC L"IPC$"
  33. #define SHARE_ADMIN L"ADMIN$"
  34. // permanent indexes to the temporary buffers
  35. #define INDEX_TEMP_TARGETVERSION 0
  36. #define INDEX_TEMP_COMPUTERNAME 1
  37. #define INDEX_TEMP_HOSTNAME 2
  38. #define INDEX_TEMP_IPVALIDATION 3
  39. #define INDEX_TEMP_HOSTBYADDR 4
  40. #define INDEX_TEMP_CONNECTSERVER 5
  41. // externs
  42. extern BOOL g_bWinsockLoaded;
  43. //
  44. // implementation
  45. //
  46. __inline
  47. LPWSTR
  48. GetRmtTempBuffer( IN DWORD dwIndexNumber,
  49. IN LPCWSTR pwszText,
  50. IN DWORD dwLength,
  51. IN BOOL bNullify )
  52. /*++
  53. Routine Description:
  54. since every file will need the temporary buffers -- in order to see
  55. that their buffers wont be override with other functions, we are
  56. creating seperate buffer space a for each file
  57. this function will provide an access to those internal buffers and also
  58. safe guards the file buffer boundaries
  59. Arguments:
  60. [ in ] dwIndexNumber - file specific index number
  61. [ in ] pwszText - default text that needs to be copied into
  62. temporary buffer
  63. [ in ] dwLength - Length of the temporary buffer that is required
  64. Ignored when pwszText is specified
  65. [ in ] bNullify - Informs whether to clear the buffer or not
  66. before giving the temporary buffer
  67. Return Value:
  68. NULL - when any failure occurs
  69. NOTE: do not rely on GetLastError to know the reason
  70. for the failure.
  71. success - return memory address of the requested size
  72. NOTE:
  73. ----
  74. if pwszText and dwLength both are NULL, then we treat that the caller
  75. is asking for the reference of the buffer and we return the buffer address.
  76. In this call, there wont be any memory allocations -- if the requested index
  77. doesn't exist, we return as failure
  78. Also, the buffer returned by this function need not released by the caller.
  79. While exiting from the tool, all the memory will be freed automatically by
  80. the ReleaseGlobals functions.
  81. --*/
  82. {
  83. if ( dwIndexNumber >= TEMP_RMTCONNECTIVITY_C_COUNT )
  84. {
  85. return NULL;
  86. }
  87. // check if caller is requesting existing buffer contents
  88. if ( pwszText == NULL && dwLength == 0 && bNullify == FALSE )
  89. {
  90. // yes -- we need to pass the existing buffer contents
  91. return GetInternalTemporaryBufferRef(
  92. dwIndexNumber + INDEX_TEMP_RMTCONNECTIVITY_C );
  93. }
  94. // ...
  95. return GetInternalTemporaryBuffer(
  96. dwIndexNumber + INDEX_TEMP_RMTCONNECTIVITY_C, pwszText, dwLength, bNullify );
  97. }
  98. BOOL
  99. IsUserAdmin( VOID )
  100. /*++
  101. Routine Description:
  102. Checks the user associated with the current process is Administrator or not
  103. Arguments:
  104. Return Value:
  105. Returns TRUE if user is Administrator or FALSE otherwise
  106. --*/
  107. {
  108. // local variables
  109. PSID pSid = NULL;
  110. BOOL bMember = FALSE;
  111. BOOL bResult = FALSE;
  112. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  113. // prepare universal administrators group SID
  114. bResult = AllocateAndInitializeSid(
  115. &NtAuthority,
  116. 2,
  117. SECURITY_BUILTIN_DOMAIN_RID,
  118. DOMAIN_ALIAS_RID_ADMINS,
  119. 0, 0, 0, 0, 0, 0,
  120. &pSid );
  121. if ( bResult == TRUE )
  122. {
  123. bResult = CheckTokenMembership( NULL, pSid, &bMember );
  124. if ( bResult == TRUE && bMember == TRUE )
  125. {
  126. // current user is a member of administrators group
  127. bResult = TRUE;
  128. }
  129. else if ( bResult == FALSE )
  130. {
  131. // some error has occured -- need use GetLastError to know the reason
  132. bResult = FALSE;
  133. }
  134. else
  135. {
  136. // the user is not an administrator
  137. bResult = FALSE;
  138. }
  139. // free the allocated SID
  140. FreeSid( pSid );
  141. }
  142. else
  143. {
  144. // error has occured -- user GetLastError to know the reason
  145. }
  146. // return the result
  147. return bResult;
  148. }
  149. BOOL
  150. IsUNCFormat( IN LPCWSTR pwszServer )
  151. /*++
  152. Routine Description:
  153. Determines whether server name is specified in UNC format or not
  154. Arguments:
  155. [ in ] pwszServer : server name
  156. Return Value:
  157. TRUE : if specified in UNC format
  158. FALSE : if not specified in UNC format
  159. --*/
  160. {
  161. // check the input
  162. if ( pwszServer == NULL )
  163. {
  164. INVALID_PARAMETER();
  165. return FALSE;
  166. }
  167. // check the length -- it should be more that 2 characters
  168. if ( StringLength( pwszServer, 0 ) <= 2 )
  169. {
  170. // server name cannot be in UNC format
  171. return FALSE;
  172. }
  173. // now compare and return the result
  174. return ( StringCompare( pwszServer, _T( "\\\\" ), TRUE, 2 ) == 0 );
  175. }
  176. BOOL
  177. IsLocalSystem( IN LPCWSTR pwszServer )
  178. /*++
  179. Routine Description:
  180. Determines whether server is referring to the local or remote system
  181. Arguments:
  182. [ in ] pwszServer : server name
  183. Return Value:
  184. TRUE : for local system
  185. FALSE : for remote system
  186. --*/
  187. {
  188. // local variables
  189. DWORD dwSize = 0;
  190. BOOL bResult = FALSE;
  191. LPWSTR pwszHostName = NULL;
  192. LPWSTR pwszComputerName = NULL;
  193. // clear the last error
  194. CLEAR_LAST_ERROR();
  195. // if the server name is empty, it is a local system
  196. if ( pwszServer == NULL || lstrlen( pwszServer ) == 0 )
  197. {
  198. return TRUE;
  199. }
  200. // get the buffer that is required to the get the machine name
  201. GetComputerNameEx( ComputerNamePhysicalNetBIOS, NULL, &dwSize );
  202. if ( GetLastError() != ERROR_MORE_DATA )
  203. {
  204. return FALSE;
  205. }
  206. // now get the temporary buffer for getting the computer name
  207. pwszComputerName = GetRmtTempBuffer( INDEX_TEMP_COMPUTERNAME, NULL, dwSize, TRUE );
  208. if ( pwszComputerName == NULL )
  209. {
  210. OUT_OF_MEMORY();
  211. return FALSE;
  212. }
  213. // get the computer name -- and check the result
  214. bResult = GetComputerNameEx( ComputerNamePhysicalNetBIOS, pwszComputerName, &dwSize );
  215. if ( bResult == FALSE )
  216. {
  217. return FALSE;
  218. }
  219. // now do the comparision
  220. if ( StringCompare( pwszComputerName, pwszServer, TRUE, 0 ) == 0 )
  221. {
  222. // server name passed by the caller is local system name
  223. return TRUE;
  224. }
  225. // check pwszSever having IP address
  226. if( IsValidIPAddress( pwszServer ) == TRUE )
  227. {
  228. //
  229. // resolve the ipaddress to host name
  230. dwSize = 0;
  231. // first get the length of the buffer required to store
  232. // the resolved ip address
  233. bResult = GetHostByIPAddr( pwszServer, NULL, &dwSize, FALSE );
  234. if ( bResult == FALSE )
  235. {
  236. return FALSE;
  237. }
  238. // allocate buffer of the required length
  239. pwszHostName = GetRmtTempBuffer( INDEX_TEMP_HOSTNAME, NULL, dwSize, TRUE );
  240. if ( pwszHostName == NULL )
  241. {
  242. return FALSE;
  243. }
  244. // now get the resolved ip address
  245. bResult = GetHostByIPAddr( pwszServer, pwszHostName, &dwSize, FALSE );
  246. if ( bResult == FALSE )
  247. {
  248. return FALSE;
  249. }
  250. // check if resolved ipaddress matches with the current host name
  251. if ( StringCompare( pwszComputerName, pwszHostName, TRUE, 0 ) == 0 )
  252. {
  253. return TRUE; // local system
  254. }
  255. else
  256. {
  257. //if it is 127.0.0.1, then it is local host, check for that
  258. if ( StringCompare( pwszHostName, L"localhost", TRUE, 0 ) == 0 )
  259. {
  260. return TRUE;
  261. }
  262. else
  263. {
  264. return FALSE; // not a local system
  265. }
  266. }
  267. }
  268. // get the local system fully qualified name and check
  269. dwSize = 0;
  270. GetComputerNameEx( ComputerNamePhysicalDnsFullyQualified, NULL, &dwSize );
  271. if ( GetLastError() != ERROR_MORE_DATA )
  272. {
  273. return FALSE;
  274. }
  275. // now get the temporary buffer for getting the computer name
  276. pwszComputerName = GetRmtTempBuffer( INDEX_TEMP_COMPUTERNAME, NULL, dwSize, TRUE );
  277. if ( pwszComputerName == NULL )
  278. {
  279. return FALSE;
  280. }
  281. // get the FQDN name
  282. bResult = GetComputerNameEx(
  283. ComputerNamePhysicalDnsFullyQualified, pwszComputerName, &dwSize );
  284. if ( bResult == FALSE )
  285. {
  286. return FALSE;
  287. }
  288. // check the FQDN with server name passed by the caller
  289. if ( StringCompare( pwszComputerName, pwszServer, TRUE, 0 ) == 0 )
  290. {
  291. return TRUE;
  292. }
  293. // finally ... it might not be local system name
  294. // NOTE: there are chances for us to not be able to identify whether
  295. // the system name specified is a local system or remote system
  296. return FALSE;
  297. }
  298. BOOL
  299. IsValidServer( IN LPCWSTR pwszServer )
  300. /*++
  301. Routine Description:
  302. Validates the server name
  303. Arguments:
  304. [ in ] pszServer : server name
  305. Return Value:
  306. TRUE if valid, FALSE if not valid
  307. --*/
  308. {
  309. // local variables
  310. const WCHAR pwszInvalidChars[] = L" \\/[]:|<>+=;,?$#()!@^\"`{}*%";
  311. LPWSTR pwszHostName = NULL;
  312. DWORD dwSize = 0;
  313. BOOL bResult = FALSE;
  314. // check for NULL or length... if so return
  315. if ( pwszServer == NULL || lstrlen( pwszServer ) == 0 )
  316. {
  317. return TRUE;
  318. }
  319. // check whether this is a valid ip address or not
  320. if ( IsValidIPAddress( pwszServer ) == TRUE )
  321. {
  322. //
  323. // resolve the ipaddress to host name
  324. dwSize = 0;
  325. // first get the length of the buffer required to store
  326. // the resolved ip address
  327. bResult = GetHostByIPAddr( pwszServer, NULL, &dwSize, FALSE );
  328. if ( bResult == FALSE )
  329. {
  330. return FALSE;
  331. }
  332. // allocate buffer of the required length
  333. pwszHostName = GetRmtTempBuffer( INDEX_TEMP_HOSTNAME, NULL, dwSize, TRUE );
  334. if ( pwszHostName == NULL )
  335. {
  336. return FALSE;
  337. }
  338. // now get the resolved ip address
  339. bResult = GetHostByIPAddr( pwszServer, pwszHostName, &dwSize, FALSE );
  340. if ( bResult == FALSE )
  341. {
  342. return FALSE;
  343. }
  344. return TRUE; // it's valid ip address ... so is valid server name
  345. }
  346. // now check the server name for invalid characters
  347. // \/[]:|<>+=;,?$#()!@^"`{}*%
  348. // copy the contents into the internal buffer and check for the invalid characters
  349. if ( FindOneOf2( pwszServer, pwszInvalidChars, TRUE, 0 ) != -1 )
  350. {
  351. SetLastError( ERROR_BAD_NETPATH );
  352. return FALSE;
  353. }
  354. // passed all the conditions -- valid system name
  355. return TRUE;
  356. }
  357. BOOL
  358. IsValidIPAddress( IN LPCWSTR pwszAddress )
  359. /*++
  360. Routine Description:
  361. Validates the server name
  362. Arguments:
  363. [ in ] pszAddress : server name in the form of IP Address
  364. Return Value:
  365. TRUE if valid,
  366. FALSE if not valid
  367. --*/
  368. {
  369. // local variables
  370. DWORD dw = 0;
  371. LONG lValue = 0;
  372. LPWSTR pwszTemp = NULL;
  373. LPWSTR pwszBuffer = NULL;
  374. DWORD dwOctets[ 4 ] = { 0, 0, 0, 0 };
  375. // check the buffer
  376. if ( pwszAddress == NULL || lstrlen( pwszAddress ) == 0 )
  377. {
  378. SetLastError( DNS_ERROR_INVALID_TYPE );
  379. return FALSE;
  380. }
  381. // get the temporary buffer for IP validation
  382. pwszBuffer = GetRmtTempBuffer( INDEX_TEMP_IPVALIDATION, pwszAddress, 0, FALSE );
  383. if ( pwszBuffer == NULL )
  384. {
  385. OUT_OF_MEMORY();
  386. return FALSE;
  387. }
  388. // parse and get the octet values
  389. pwszTemp = wcstok( pwszBuffer, L"." );
  390. while ( pwszTemp != NULL )
  391. {
  392. // check whether the current octet is numeric or not
  393. if ( IsNumeric( pwszTemp, 10, FALSE ) == FALSE )
  394. {
  395. return FALSE;
  396. }
  397. // get the value of the octet and check the range
  398. lValue = AsLong( pwszTemp, 10 );
  399. if ( lValue < 0 || lValue > 255 )
  400. {
  401. return FALSE;
  402. }
  403. // fetch next octet and store first four octates only
  404. if( dw < 4 )
  405. {
  406. dwOctets[ dw++ ] = lValue;
  407. }
  408. else
  409. {
  410. dw++;
  411. }
  412. // ...
  413. pwszTemp = wcstok( NULL, L"." );
  414. }
  415. // check and return
  416. if ( dw != 4 )
  417. {
  418. SetLastError( DNS_ERROR_INVALID_TYPE );
  419. return FALSE;
  420. }
  421. // now check the special condition
  422. // ?? time being this is not implemented ??
  423. // return the validity of the ip address
  424. return TRUE;
  425. }
  426. BOOL
  427. GetHostByIPAddr( IN LPCWSTR pwszServer,
  428. OUT LPWSTR pwszHostName,
  429. IN OUT DWORD* pdwHostNameLength,
  430. IN BOOL bNeedFQDN )
  431. /*++
  432. Routine Description:
  433. Get HostName from ipaddress.
  434. Arguments:
  435. pszServer : Server name in IP address format
  436. pszHostName : Host name for given IP address which returns back
  437. bNeedFQDN : Boolean variable tells about
  438. Return Value:
  439. --*/
  440. {
  441. // local variables
  442. WSADATA wsaData;
  443. DWORD dwErr = 0;
  444. DWORD dwLength = 0;
  445. ULONG ulInetAddr = 0;
  446. BOOL bReturnValue = FALSE;
  447. LPSTR pszTemp = NULL;
  448. WORD wVersionRequested = 0;
  449. BOOL bNeedToResolve = FALSE;
  450. //
  451. // this function might be called too many times with the same server name
  452. // again and again at different stages of the tool -- so, in order to
  453. // optimize the network traffic, we store the information returned by
  454. // gethostbyaddr for the life time of the tool quits
  455. // we also store the current server name in global data structure so that
  456. // we can determine whether the server name being asked to resolve this
  457. // time is same as the one that is passed earlier.
  458. LPCWSTR pwszSavedName = NULL;
  459. static HOSTENT* pHostEnt = NULL;
  460. // check the input
  461. if ( pwszServer == NULL || pdwHostNameLength == NULL )
  462. {
  463. INVALID_PARAMETER();
  464. return FALSE;
  465. }
  466. // check the length argument
  467. if ( *pdwHostNameLength != 0 &&
  468. ( *pdwHostNameLength < 2 || pwszHostName == NULL ) )
  469. {
  470. INVALID_PARAMETER();
  471. return FALSE;
  472. }
  473. // check whether winsock module is loaded into process memory or not
  474. // if not load it now
  475. if ( g_bWinsockLoaded == FALSE )
  476. {
  477. // initiate the use of Ws2_32.dll by a process ( VERSION: 2.2 )
  478. wVersionRequested = MAKEWORD( 2, 2 );
  479. dwErr = WSAStartup( wVersionRequested, &wsaData );
  480. if ( dwErr != 0 )
  481. {
  482. SetLastError( WSAGetLastError() );
  483. return FALSE;
  484. }
  485. // remember that winsock library is loaded
  486. g_bWinsockLoaded = TRUE;
  487. }
  488. // check whether we need to resolve or not
  489. bNeedToResolve = TRUE;
  490. /////////////////////////////////////////////////////////////////////////////
  491. // because of weird behavior of this optimization, we are commenting out this
  492. /////////////////////////////////////////////////////////////////////////////
  493. // pwszSavedName = GetRmtTempBuffer( INDEX_TEMP_HOSTBYADDR, NULL, 0, FALSE );
  494. // if ( pwszSavedName != NULL )
  495. // {
  496. // if ( StringCompare( pwszServer, pwszSavedName, TRUE, 0 ) == 0 )
  497. // {
  498. // bNeedToResolve = FALSE;
  499. // }
  500. // }
  501. /////////////////////////////////////////////////////////////////////////////
  502. // proceed with the resolving only if needed
  503. if ( bNeedToResolve == TRUE || pHostEnt == NULL )
  504. {
  505. // allocate a buffer to store the server name in multibyte format
  506. dwLength = lstrlen( pwszServer ) + 5;
  507. pszTemp = ( LPSTR ) AllocateMemory( dwLength * sizeof( CHAR ) );
  508. if ( pszTemp == NULL )
  509. {
  510. OUT_OF_MEMORY();
  511. return FALSE;
  512. }
  513. // convert the server name into multibyte string. this is because
  514. // current winsock implementation works only with multibyte
  515. // string and there is no support for unicode
  516. bReturnValue = GetAsMultiByteString2( pwszServer, pszTemp, &dwLength );
  517. if ( bReturnValue == FALSE )
  518. {
  519. return FALSE;
  520. }
  521. // inet_addr function converts a string containing an Internet Protocol (Ipv4)
  522. // dotted address into a proper address for the IN_ADDR structure.
  523. ulInetAddr = inet_addr( pszTemp );
  524. if ( ulInetAddr == INADDR_NONE )
  525. {
  526. FreeMemory( &pszTemp );
  527. UNEXPECTED_ERROR();
  528. return FALSE;
  529. }
  530. // gethostbyaddr function retrieves the host information
  531. // corresponding to a network address.
  532. pHostEnt = gethostbyaddr( (LPSTR) &ulInetAddr, sizeof( ulInetAddr ), PF_INET );
  533. if ( pHostEnt == NULL )
  534. {
  535. // ?? DONT KNOW WHAT TO DO IF THIS FUNCTION FAILS ??
  536. // ?? CURRENTLY SIMPLY RETURNS FALSE ??
  537. UNEXPECTED_ERROR();
  538. return FALSE;
  539. }
  540. // release the memory allocated so far
  541. FreeMemory( &pszTemp );
  542. // save the server name for which we just resolved the IP address
  543. pwszSavedName = GetRmtTempBuffer( INDEX_TEMP_HOSTBYADDR, pwszServer, 0, FALSE );
  544. if ( pwszSavedName == NULL )
  545. {
  546. OUT_OF_MEMORY();
  547. return FALSE;
  548. }
  549. }
  550. // check whether user wants the FQDN name or NetBIOS name
  551. // if NetBIOS name is required, then remove the domain name
  552. if ( pHostEnt != NULL )
  553. {
  554. pszTemp = pHostEnt->h_name;
  555. if ( bNeedFQDN == FALSE && pszTemp != NULL )
  556. {
  557. pszTemp = strtok( pHostEnt->h_name, "." );
  558. }
  559. // we got info in char type ... convert it into UNICODE string
  560. if ( pszTemp != NULL )
  561. {
  562. bReturnValue = GetAsUnicodeString2( pszTemp, pwszHostName, pdwHostNameLength );
  563. if ( bReturnValue == FALSE )
  564. {
  565. return FALSE;
  566. }
  567. }
  568. // return
  569. return TRUE;
  570. }
  571. else
  572. {
  573. // failed case
  574. return FALSE;
  575. }
  576. }
  577. DWORD
  578. GetTargetVersion(
  579. LPCWSTR pwszServer
  580. )
  581. /*++
  582. Routine Description:
  583. It returns the version of OS of the specified system
  584. Arguments:
  585. [ in ] pszServer Server name for which the Version of OS
  586. to be known
  587. Return Value:
  588. DWORD A DWORD value represents the version of OS.
  589. --*/
  590. {
  591. // local variables
  592. DWORD dwVersion = 0;
  593. LPWSTR pwszUNCPath = NULL;
  594. NET_API_STATUS netstatus;
  595. SERVER_INFO_101* pSrvInfo = NULL;
  596. // check the inputs
  597. if ( pwszServer == NULL || StringLength( pwszServer, 0 ) == 0 )
  598. {
  599. return 0;
  600. }
  601. // prepare the server name in UNC format
  602. if ( IsUNCFormat( pwszServer ) == FALSE )
  603. {
  604. if ( SetReason2( 1, L"\\\\%s", pwszServer ) == FALSE )
  605. {
  606. OUT_OF_MEMORY();
  607. SaveLastError();
  608. return 0;
  609. }
  610. }
  611. else
  612. {
  613. if ( SetReason( pwszServer ) == FALSE )
  614. {
  615. OUT_OF_MEMORY();
  616. SaveLastError();
  617. return 0;
  618. }
  619. }
  620. // now get the server name which is saved via 'failure' buffer
  621. pwszUNCPath = GetRmtTempBuffer(
  622. INDEX_TEMP_TARGETVERSION, GetReason(), 0, FALSE );
  623. if ( pwszUNCPath == NULL )
  624. {
  625. OUT_OF_MEMORY();
  626. SaveLastError();
  627. return 0;
  628. }
  629. // get the version info
  630. netstatus = NetServerGetInfo( pwszUNCPath, 101, (LPBYTE*) &pSrvInfo );
  631. // check the result .. if not success return
  632. if ( netstatus != NERR_Success )
  633. {
  634. return 0;
  635. }
  636. // prepare the version
  637. dwVersion = 0;
  638. if ( ( pSrvInfo->sv101_type & SV_TYPE_NT ) )
  639. {
  640. // --> "sv101_version_major" least significant 4 bits of the byte,
  641. // the major release version number of the operating system.
  642. // --> "sv101_version_minor" the minor release version number of
  643. // the operating system
  644. dwVersion = (pSrvInfo->sv101_version_major & MAJOR_VERSION_MASK) * 1000;
  645. dwVersion += pSrvInfo->sv101_version_minor;
  646. }
  647. // release the buffer allocated by network api
  648. NetApiBufferFree( pSrvInfo );
  649. // return
  650. return dwVersion;
  651. }
  652. DWORD
  653. ConnectServer( IN LPCWSTR pwszServer,
  654. IN LPCWSTR pwszUser,
  655. IN LPCWSTR pwszPassword )
  656. /*++
  657. Routine Description:
  658. Connects to the remote Server. This is stub function.
  659. Arguments:
  660. [ in ] pwszServer : server name
  661. [ in ] pwszUser : user
  662. [ in ] pwszPassword : password
  663. Return Value:
  664. NO_ERROR if succeeds other appropriate error code if failed
  665. --*/
  666. {
  667. // invoke the original function and return the result
  668. return ConnectServer2( pwszServer, pwszUser, pwszPassword, L"IPC$" );
  669. }
  670. DWORD
  671. ConnectServer2( IN LPCWSTR pwszServer,
  672. IN LPCWSTR pwszUser,
  673. IN LPCWSTR pwszPassword,
  674. IN LPCWSTR pwszShare )
  675. /*++
  676. Routine Description:
  677. Connects to the remote Server
  678. Arguments:
  679. [ in ] pwszServer : server name
  680. [ in ] pwszUser : user
  681. [ in ] pwszPassword : password
  682. [ in ] pwszShare : share name to connect to
  683. Return Value:
  684. NO_ERROR if succeeds other appropriate error code if failed
  685. --*/
  686. {
  687. // local variables
  688. DWORD dwConnect = 0;
  689. NETRESOURCE resource;
  690. LPWSTR pwszUNCPath = NULL;
  691. LPCWSTR pwszMachine = NULL;
  692. // if the server name refers to the local system,
  693. // and also, if user credentials were not supplied, then treat
  694. // connection is successfull
  695. // if user credentials information is passed for local system,
  696. // return ERROR_LOCAL_CREDENTIALS
  697. if ( pwszServer == NULL || IsLocalSystem( pwszServer ) == TRUE )
  698. {
  699. if ( pwszUser == NULL || lstrlen( pwszUser ) == 0 )
  700. {
  701. return NO_ERROR; // local sustem
  702. }
  703. else
  704. {
  705. SetReason( ERROR_LOCAL_CREDENTIALS );
  706. SetLastError( E_LOCAL_CREDENTIALS );
  707. return E_LOCAL_CREDENTIALS;
  708. }
  709. }
  710. // check whether the server name is in UNC format or not
  711. // if yes, extract the server name
  712. pwszMachine = pwszServer; // assume server is not in UNC format
  713. if ( IsUNCFormat( pwszServer ) == TRUE )
  714. {
  715. pwszMachine = pwszServer + 2;
  716. }
  717. // validate the server name
  718. if ( IsValidServer( pwszMachine ) == FALSE )
  719. {
  720. SaveLastError();
  721. return GetLastError();
  722. }
  723. //
  724. // prepare the machine name into UNC format
  725. if ( pwszShare == NULL || lstrlen( pwszShare ) == 0 )
  726. {
  727. // we will make use of the 'failure' buffer to format the string
  728. if ( SetReason2( 1, L"\\\\%s", pwszMachine ) == FALSE )
  729. {
  730. OUT_OF_MEMORY();
  731. SaveLastError();
  732. return ERROR_NOT_ENOUGH_MEMORY;
  733. }
  734. }
  735. else
  736. {
  737. // we will make use of the 'failure' buffer to format the string
  738. if ( SetReason2( 2, L"\\\\%s\\%s", pwszMachine, pwszShare ) == FALSE )
  739. {
  740. OUT_OF_MEMORY();
  741. SaveLastError();
  742. return ERROR_NOT_ENOUGH_MEMORY;
  743. }
  744. }
  745. // get the formatted buffer from the 'failure'
  746. pwszUNCPath = GetRmtTempBuffer( INDEX_TEMP_CONNECTSERVER, GetReason(), 0, FALSE );
  747. if ( pwszUNCPath == NULL )
  748. {
  749. OUT_OF_MEMORY();
  750. SaveLastError();
  751. return ERROR_NOT_ENOUGH_MEMORY;
  752. }
  753. // initialize the resource structure with null
  754. ZeroMemory( &resource, sizeof( resource ) );
  755. resource.dwType = RESOURCETYPE_ANY;
  756. resource.lpProvider = NULL;
  757. resource.lpLocalName = NULL;
  758. resource.lpRemoteName = pwszUNCPath;
  759. // try establishing connection to the remote server
  760. dwConnect = WNetAddConnection2( &resource, pwszPassword, pwszUser, 0 );
  761. // check the result
  762. // and if error has occured, get the appropriate message
  763. switch( dwConnect )
  764. {
  765. case NO_ERROR:
  766. {
  767. dwConnect = 0;
  768. CLEAR_LAST_ERROR();
  769. // check for the OS compatibilty
  770. if ( IsCompatibleOperatingSystem( GetTargetVersion( pwszMachine ) ) == FALSE )
  771. {
  772. // since the connection already established close the connection
  773. CloseConnection( pwszMachine );
  774. // set the error text
  775. SetReason( ERROR_REMOTE_INCOMPATIBLE );
  776. dwConnect = ERROR_EXTENDED_ERROR;
  777. }
  778. // ...
  779. break;
  780. }
  781. case ERROR_EXTENDED_ERROR:
  782. WNetSaveLastError(); // save the extended error
  783. break;
  784. default:
  785. // set the last error
  786. SetLastError( dwConnect );
  787. SaveLastError();
  788. break;
  789. }
  790. // return the result of the connection establishment
  791. return dwConnect;
  792. }
  793. DWORD
  794. CloseConnection( IN LPCWSTR pwszServer )
  795. /*++
  796. Routine Description:
  797. Closes the remote connection.
  798. Arguments:
  799. [in] szServer -- remote machine to close the connection
  800. Return Value:
  801. DWORD -- NO_ERROR if succeeds.
  802. -- Possible error codes.
  803. --*/
  804. {
  805. // forcibly close the connection
  806. return CloseConnection2( pwszServer, NULL, CI_CLOSE_BY_FORCE | CI_SHARE_IPC );
  807. }
  808. DWORD
  809. CloseConnection2( IN LPCWSTR pwszServer,
  810. IN LPCWSTR pwszShare,
  811. IN DWORD dwFlags )
  812. /*++
  813. Routine Description:
  814. Closes the established connection on the remote system.
  815. Arguments:
  816. [ in ] szServer - Null terminated string that specifies the remote
  817. system name. NULL specifie the local system.
  818. [ in ] pszShare - Share name of remote system to be closed, it is null in this case.
  819. [ in ] dwFlags - Flags specifies how and what connection should be closed.
  820. Return Value:
  821. --*/
  822. {
  823. // local variables
  824. DWORD dwCancel = 0;
  825. BOOL bForce = FALSE;
  826. LPCWSTR pwszMachine = NULL;
  827. LPCWSTR pwszUNCPath = NULL;
  828. // check the server contents ... it might be referring to the local system
  829. if ( pwszServer == NULL || lstrlen( pwszServer ) == 0 )
  830. {
  831. return NO_ERROR;
  832. }
  833. // check whether the server name is in UNC format or not
  834. // if yes, extract the server name
  835. pwszMachine = pwszServer; // assume server is not in UNC format
  836. if ( IsUNCFormat( pwszServer ) == TRUE )
  837. {
  838. pwszMachine = pwszServer + 2;
  839. }
  840. // determine if share name has to appended or not for this server name
  841. if ( dwFlags & CI_SHARE_IPC )
  842. {
  843. // --> \\server\ipc$
  844. if ( SetReason2( 2, L"\\\\%s\\%s", pwszMachine, SHARE_IPC ) == FALSE )
  845. {
  846. OUT_OF_MEMORY();
  847. return ERROR_NOT_ENOUGH_MEMORY;
  848. }
  849. }
  850. else if ( dwFlags & CI_SHARE_ADMIN )
  851. {
  852. // --> \\server\admin$
  853. if ( SetReason2( 2, L"\\\\%s\\%s", pwszMachine, SHARE_ADMIN ) == FALSE )
  854. {
  855. OUT_OF_MEMORY();
  856. return ERROR_NOT_ENOUGH_MEMORY;
  857. }
  858. }
  859. else if ( dwFlags & CI_SHARE_CUSTOM && pwszShare != NULL )
  860. {
  861. // --> \\server\share
  862. if ( SetReason2( 2, L"\\\\%s\\%s", pwszMachine, pwszShare ) == FALSE )
  863. {
  864. OUT_OF_MEMORY();
  865. return ERROR_NOT_ENOUGH_MEMORY;
  866. }
  867. }
  868. else
  869. {
  870. // --> \\server
  871. if ( SetReason2( 1, L"\\\\%s", pwszMachine ) == FALSE )
  872. {
  873. OUT_OF_MEMORY();
  874. return ERROR_NOT_ENOUGH_MEMORY;
  875. }
  876. }
  877. // get the formatted unc path via failure string
  878. pwszUNCPath = GetRmtTempBuffer(
  879. INDEX_TEMP_CONNECTSERVER, GetReason(), 0, FALSE );
  880. if ( pwszUNCPath == NULL )
  881. {
  882. OUT_OF_MEMORY();
  883. return ERROR_NOT_ENOUGH_MEMORY;
  884. }
  885. // determine whether to close this connection forcibly or not
  886. if ( dwFlags & CI_CLOSE_BY_FORCE )
  887. {
  888. bForce = TRUE;
  889. }
  890. //
  891. // cancel the connection
  892. dwCancel = WNetCancelConnection2( pwszUNCPath, 0, bForce );
  893. // check the result
  894. // and if error has occured, get the appropriate message
  895. switch( dwCancel )
  896. {
  897. case NO_ERROR:
  898. dwCancel = 0;
  899. CLEAR_LAST_ERROR();
  900. break;
  901. case ERROR_EXTENDED_ERROR:
  902. WNetSaveLastError(); // save the extended error
  903. break;
  904. default:
  905. // set the last error
  906. SaveLastError();
  907. break;
  908. }
  909. // return the result of the cancelling the connection
  910. return dwCancel;
  911. }
  912. BOOL
  913. EstablishConnection( IN LPCWSTR pwszServer,
  914. IN LPWSTR pwszUserName,
  915. IN DWORD dwUserLength,
  916. IN LPWSTR pwszPassword,
  917. IN DWORD dwPasswordLength,
  918. IN BOOL bNeedPassword )
  919. /*++
  920. Routine Description:
  921. Establishes a connection to the remote system.
  922. Arguments:
  923. [in] szServer --Nullterminated string to establish the conection.
  924. --NULL connects to the local system.
  925. [in] szUserName --Null terminated string that specifies the user name.
  926. --NULL takes the default user name.
  927. [in] dwUserLength --Length of the username.
  928. [in] szPassword --Null terminated string that specifies the password
  929. --NULL takes the default user name's password.
  930. [in] dwPasswordLength --Length of the password.
  931. [in] bNeedPassword --True if password is required to establish the connection.
  932. --False if it is not required.
  933. Return Value:
  934. BOOL -- True if it establishes
  935. -- False if it fails.
  936. --*/
  937. {
  938. // local variables
  939. BOOL bDefault = FALSE;
  940. DWORD dwConnectResult = 0;
  941. LPCWSTR pwszMachine = NULL;
  942. // clear the error .. if any
  943. CLEAR_LAST_ERROR();
  944. // check the input
  945. if ( pwszServer == NULL || StringLength( pwszServer, 0 ) == 0 )
  946. {
  947. // we assume user wants to connect to the local machine
  948. // simply return success
  949. return TRUE;
  950. }
  951. // ...
  952. if ( bNeedPassword == TRUE &&
  953. ( pwszUserName == NULL || dwUserLength < 2 ||
  954. pwszPassword == NULL || dwPasswordLength < 2) )
  955. {
  956. INVALID_PARAMETER();
  957. SaveLastError();
  958. return FALSE;
  959. }
  960. // check whether the server name is in UNC format or not
  961. // if yes, extract the server name
  962. pwszMachine = pwszServer; // assume server is not in UNC format
  963. if ( IsUNCFormat( pwszServer ) == TRUE )
  964. {
  965. pwszMachine = pwszServer + 2;
  966. }
  967. // sometime users want the utility to prompt for the password
  968. // check what user wants the utility to do
  969. if ( bNeedPassword == TRUE &&
  970. pwszPassword != NULL &&
  971. StringCompare( pwszPassword, L"*", TRUE, 0 ) == 0 )
  972. {
  973. // user wants the utility to prompt for the password..
  974. // But, before that we have to make sure whether the specified server is valid or not.
  975. // If the server is valid let the flow directly jump to the password acceptance part
  976. // else return failure..
  977. // validate the server name
  978. if ( IsValidServer( pwszMachine ) == FALSE )
  979. {
  980. SaveLastError();
  981. return FALSE;
  982. }
  983. }
  984. else
  985. {
  986. // try to establish connection to the remote system with the credentials supplied
  987. bDefault = FALSE;
  988. // validate the server name
  989. if ( IsValidServer( pwszMachine ) == FALSE )
  990. {
  991. SaveLastError();
  992. return FALSE;
  993. }
  994. if ( pwszUserName == NULL || lstrlen( pwszUserName ) == 0 )
  995. {
  996. // user name is empty
  997. // so, it is obvious that password will also be empty
  998. // even if password is specified, we have to ignore that
  999. bDefault = TRUE;
  1000. dwConnectResult = ConnectServer( pwszServer, NULL, NULL );
  1001. }
  1002. else
  1003. {
  1004. // credentials were supplied
  1005. // but password might not be specified ... so check and act accordingly
  1006. dwConnectResult = ConnectServer( pwszServer,
  1007. pwszUserName, ( bNeedPassword == FALSE ? pwszPassword : NULL ) );
  1008. // determine whether to close the connection or retain the connection
  1009. if ( bNeedPassword == TRUE )
  1010. {
  1011. // connection might have already established .. so to be on safer side
  1012. // we inform the caller not to close the connection
  1013. bDefault = TRUE;
  1014. }
  1015. }
  1016. // check the result ... if successful in establishing connection ... return
  1017. if ( ERROR_ALREADY_ASSIGNED == dwConnectResult )
  1018. {
  1019. SetLastError( I_NO_CLOSE_CONNECTION );
  1020. return TRUE;
  1021. }
  1022. // check the result ... if successful in establishing connection ... return
  1023. else if ( dwConnectResult == NO_ERROR )
  1024. {
  1025. if ( bDefault == TRUE )
  1026. {
  1027. SetLastError( I_NO_CLOSE_CONNECTION );
  1028. }
  1029. else
  1030. {
  1031. SetLastError( NO_ERROR );
  1032. }
  1033. // ...
  1034. return TRUE;
  1035. }
  1036. // now check the kind of error occurred
  1037. switch( dwConnectResult )
  1038. {
  1039. case ERROR_LOGON_FAILURE:
  1040. case ERROR_INVALID_PASSWORD:
  1041. break;
  1042. case ERROR_SESSION_CREDENTIAL_CONFLICT:
  1043. // user credentials conflict ... client has to handle this situation
  1044. // wrt to this module, connection to the remote system is success
  1045. SetLastError( dwConnectResult );
  1046. return TRUE;
  1047. case E_LOCAL_CREDENTIALS:
  1048. // user credentials not accepted for local system
  1049. SetReason( ERROR_LOCAL_CREDENTIALS );
  1050. SetLastError( E_LOCAL_CREDENTIALS );
  1051. return TRUE;
  1052. case ERROR_DUP_NAME:
  1053. case ERROR_NETWORK_UNREACHABLE:
  1054. case ERROR_HOST_UNREACHABLE:
  1055. case ERROR_PROTOCOL_UNREACHABLE:
  1056. case ERROR_INVALID_NETNAME:
  1057. // change the error code so that user gets correct message
  1058. SetLastError( ERROR_NO_NETWORK );
  1059. SaveLastError();
  1060. SetLastError( dwConnectResult ); // reset the error code
  1061. return FALSE;
  1062. default:
  1063. SaveLastError();
  1064. return FALSE; // no use of accepting the password .. return failure
  1065. break;
  1066. }
  1067. // if failed in establishing connection to the remote terminal
  1068. // even if the password is specifed, then there is nothing to do ... simply return failure
  1069. if ( bNeedPassword == FALSE )
  1070. {
  1071. return FALSE;
  1072. }
  1073. }
  1074. // check whether user name is specified or not
  1075. // if not, get the local system's current user name under whose credentials, the process
  1076. // is running
  1077. if ( lstrlen( pwszUserName ) == 0 )
  1078. {
  1079. // get the user name
  1080. if ( GetUserNameEx( NameSamCompatible, pwszUserName, &dwUserLength ) == FALSE )
  1081. {
  1082. // error occured while trying to get the current user info
  1083. SaveLastError();
  1084. return FALSE;
  1085. }
  1086. }
  1087. // display message on the screen which says "Type Password for ..."
  1088. ShowMessageEx( stdout, 1, TRUE, STR_INPUT_PASSWORD, pwszUserName );
  1089. // accept the password from the user
  1090. GetPassword( pwszPassword, dwPasswordLength );
  1091. // now again try to establish the connection using the currently
  1092. // supplied credentials
  1093. dwConnectResult = ConnectServer( pwszServer, pwszUserName, pwszPassword );
  1094. if ( dwConnectResult == NO_ERROR )
  1095. {
  1096. return TRUE; // connection established successfully
  1097. }
  1098. // now check the kind of error occurred
  1099. switch( dwConnectResult )
  1100. {
  1101. case ERROR_SESSION_CREDENTIAL_CONFLICT:
  1102. // user credentials conflict ... client has to handle this situation
  1103. // wrt to this module, connection to the remote system is success
  1104. SetLastError( dwConnectResult );
  1105. return TRUE;
  1106. case E_LOCAL_CREDENTIALS:
  1107. // user credentials not accepted for local system
  1108. SetReason( ERROR_LOCAL_CREDENTIALS );
  1109. SetLastError( E_LOCAL_CREDENTIALS );
  1110. return TRUE;
  1111. case ERROR_DUP_NAME:
  1112. case ERROR_NETWORK_UNREACHABLE:
  1113. case ERROR_HOST_UNREACHABLE:
  1114. case ERROR_PROTOCOL_UNREACHABLE:
  1115. case ERROR_INVALID_NETNAME:
  1116. // change the error code so that user gets correct message
  1117. SetLastError( ERROR_NO_NETWORK );
  1118. SaveLastError();
  1119. SetLastError( dwConnectResult ); // reset the error code
  1120. return FALSE;
  1121. default:
  1122. SaveLastError();
  1123. return FALSE; // no use of accepting the password .. return failure
  1124. break;
  1125. }
  1126. }
  1127. BOOL
  1128. EstablishConnection2( IN PTCONNECTIONINFO pci )
  1129. /*++
  1130. Routine Description:
  1131. Establishes a connection to the remote system.
  1132. Arguments:
  1133. [in] pci : A pointer to TCONNECTIONINFO structure which contains
  1134. connection information needed for establishing connection
  1135. Return Value:
  1136. --*/
  1137. {
  1138. UNREFERENCED_PARAMETER( pci );
  1139. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  1140. SaveLastError();
  1141. return FALSE;
  1142. }