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.

1325 lines
40 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. ccred.cxx
  5. Abstract:
  6. This module abstracts user credentials for the multiple credential support.
  7. Author:
  8. Blake Jones (t-blakej) 08-08-1997
  9. Revision History:
  10. --*/
  11. #include "winnt.hxx"
  12. extern "C" {
  13. #include "winnetwk.h"
  14. }
  15. #pragma hdrstop
  16. //
  17. // The resource to bind to on remote machines.
  18. //
  19. static const PWSTR g_pszResourceName = TEXT("IPC$");
  20. //
  21. // The error to return from CCred::ref when a bind to a different server
  22. // is attempted. The caller (should be CWinNTCredentials::RefServer)
  23. // should catch this and dispense with it appropriately.
  24. //
  25. // This should be an error other than E_OUTOFMEMORY or anything that
  26. // WNetAddConnection2 can return. This is pretty much a bogus error,
  27. // but I'm appropriating it just for RefServer.
  28. //
  29. static const HRESULT dwRebindErr = HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS);
  30. //////////////////////////////////////////////////////////////////////////////
  31. //
  32. // Internal class declarations:
  33. //
  34. //+---------------------------------------------------------------------------
  35. // ____ _ _ ____ _
  36. // / ___|_ __(_) |_/ ___| ___ ___| |_
  37. // | | | '__| | __\___ \ / _ \/ __| __|
  38. // | |___| | | | |_ ___) | __/ (__| |_
  39. // \____|_| |_|\__|____/ \___|\___|\__|
  40. //
  41. // Class CritSect -- C++ wrapper around an NT critical section object.
  42. //
  43. // Constructors:
  44. // CritSect() - initialize the NT object
  45. //
  46. // Public methods:
  47. // Lock - enter the critical section
  48. // Locked - whether we're in the crit. sect.
  49. // Unlock - leave the critical section
  50. //
  51. //----------------------------------------------------------------------------
  52. class CritSect
  53. {
  54. public:
  55. CritSect() { InitializeCriticalSection(&m_cs); m_bLocked = FALSE; }
  56. void Lock() { EnterCriticalSection(&m_cs); m_bLocked = TRUE; }
  57. BOOL Locked() { return m_bLocked; }
  58. void Unlock() { LeaveCriticalSection(&m_cs); m_bLocked = FALSE; }
  59. ~CritSect() { DeleteCriticalSection(&m_cs); }
  60. private:
  61. CRITICAL_SECTION m_cs;
  62. BOOL m_bLocked;
  63. };
  64. //+---------------------------------------------------------------------------
  65. // ____ ____ _ _____ _ _
  66. // / ___/ ___|_ __ ___ __| |_ _|_ _| |__ | | ___
  67. // | | | | | '__/ _ \/ _` | | |/ _` | '_ \| |/ _ \
  68. // | |__| |___| | | __/ (_| | | | (_| | |_) | | __/
  69. // \____\____|_| \___|\__,_| |_|\__,_|_.__/|_|\___|
  70. //
  71. // Class CCredTable -- performs the authentication requests for the CCred
  72. // objects, and keeps a mapping for deregistration of objects.
  73. //
  74. // Constructors:
  75. // CCredTable() - make an empty credential table
  76. //
  77. // Public methods:
  78. // AddCred - try to obtain a credential;
  79. // if successful, add it to the table
  80. // DelCred - remove a credential from the table
  81. //
  82. //----------------------------------------------------------------------------
  83. class CCredTable
  84. {
  85. public:
  86. CCredTable();
  87. ~CCredTable();
  88. HRESULT
  89. AddCred(PWSTR pszUserName, PWSTR pszPassword, PWSTR pszServer,
  90. DWORD *dwIndex);
  91. HRESULT
  92. DelCred(DWORD dwIndex);
  93. private:
  94. HRESULT
  95. GrowTable(void);
  96. //
  97. // The type used for storing credential->resource name mappings
  98. // for deregistration.
  99. //
  100. struct cred { PWSTR m_pResource; BOOL m_bUsed; DWORD m_dwCount;
  101. BOOL m_fAlreadyConnected; // was net use already established
  102. };
  103. cred *m_pCredentials; // the cred->resource name table
  104. DWORD m_dwAlloc; // # table entries allocated
  105. DWORD m_dwUsed; // # table entries used
  106. CritSect m_cs; // to guard table access
  107. };
  108. //+---------------------------------------------------------------------------
  109. // ____ ____ _
  110. // / ___/ ___|_ __ ___ __| |
  111. // | | | | | '__/ _ \/ _` |
  112. // | |__| |___| | | __/ (_| |
  113. // \____\____|_| \___|\__,_|
  114. //
  115. // Class CCred - encapsulates the reference-countable parts of the
  116. // WinNT authentication object.
  117. //
  118. // Constructors:
  119. // CCred() - create an empty CCred
  120. // CCred(PWSTR pszUserName, - create a CCred with a username
  121. // PWSTR pszPassword) and password. This does not bind
  122. // to a server yet.
  123. //
  124. // Public methods:
  125. // GetUserName - get the username of the credentials
  126. // SetUserName - set the username of the credentials
  127. // GetPassword - get the password of the credentials
  128. // SetPassword - set the password of the credentials
  129. // ref - add a reference to this object
  130. // deref - remove a reference from this object
  131. //
  132. //----------------------------------------------------------------------------
  133. class CCred
  134. {
  135. // so it can call the copy ctor
  136. friend class CWinNTCredentials;
  137. public:
  138. CCred();
  139. CCred(PWSTR pszUserName, PWSTR pszPassword);
  140. ~CCred();
  141. HRESULT ref(PWSTR pszServer);
  142. HRESULT deref();
  143. HRESULT GetUserName(PWSTR *ppszUserName);
  144. HRESULT GetPassword(PWSTR *ppszPassword);
  145. DWORD m_dwUsageCount; // this object's usage count
  146. private:
  147. CCred(const CCred& other); // only called by CWinNTCredentials
  148. CCred& operator=(const CCred&); // deliberately not implemented
  149. //
  150. // Used for storing the password encrypted.
  151. //
  152. enum { NW_ENCODE_SEED3 = 0x83 };
  153. PWSTR m_pszUserName; // username
  154. PWSTR m_pszPassword; // password
  155. DWORD m_dwPasswdLen; // #bytes allocated for password
  156. PWSTR m_pszServer; // server on which we have credentials
  157. DWORD m_dwIndex; // index in the CredTable
  158. DWORD m_dwRefCount; // this object's reference count
  159. static CCredTable g_CredTable; // the table
  160. };
  161. //
  162. // The table.
  163. //
  164. CCredTable CCred::g_CredTable;
  165. //////////////////////////////////////////////////////////////////////////////
  166. //
  167. // Class definitions:
  168. //
  169. ///---------------------------------------------------------------------------
  170. // ____ ____ _
  171. // / ___/ ___|_ __ ___ __| |
  172. // | | | | | '__/ _ \/ _` |
  173. // | |__| |___| | | __/ (_| | definitions
  174. // \____\____|_| \___|\__,_|
  175. //
  176. ///---------------------------------------------------------------------------
  177. //+---------------------------------------------------------------------------
  178. //
  179. // CCred constructor
  180. //
  181. // Create an empty credential object.
  182. //
  183. //----------------------------------------------------------------------------
  184. CCred::CCred() :
  185. m_pszUserName(NULL), m_pszPassword(NULL), m_pszServer(NULL),
  186. m_dwIndex((DWORD) -1), m_dwRefCount(0), m_dwUsageCount(1), m_dwPasswdLen(0)
  187. {
  188. }
  189. //+---------------------------------------------------------------------------
  190. //
  191. // CCred constructor
  192. //
  193. // Create a credential object with a username and a password.
  194. // This doesn't increase the reference count, since it doesn't make any
  195. // connections to the server.
  196. //
  197. // Arguments:
  198. // [pszUserName] - username
  199. // [pszPassword] - password
  200. //
  201. //----------------------------------------------------------------------------
  202. CCred::CCred(PWSTR pszUserName, PWSTR pszPassword) :
  203. m_pszUserName(NULL), m_pszPassword(NULL), m_pszServer(NULL),
  204. m_dwIndex((DWORD) -1), m_dwRefCount(0), m_dwUsageCount(1), m_dwPasswdLen(0)
  205. {
  206. //
  207. // NTRAID#NTBUG9-67020-2000-7-26-AjayR. We need a way to fail
  208. // on the constructor.
  209. //
  210. m_pszUserName = pszUserName ? AllocADsStr(pszUserName) : NULL;
  211. if (pszPassword)
  212. {
  213. UNICODE_STRING Password;
  214. UCHAR Seed = NW_ENCODE_SEED3;
  215. m_dwPasswdLen = (wcslen(pszPassword) + 1)*sizeof(WCHAR) +
  216. (DES_BLOCKLEN -1);
  217. m_pszPassword = (PWSTR) AllocADsMem(m_dwPasswdLen);
  218. ADsAssert(m_pszPassword != NULL);
  219. if (m_pszPassword) {
  220. wcscpy(m_pszPassword, pszPassword);
  221. RtlInitUnicodeString(&Password, m_pszPassword);
  222. if(NULL == g_pRtlEncryptMemory)
  223. RtlRunEncodeUnicodeString(&Seed, &Password);
  224. else {
  225. DWORD extra = 0;
  226. NTSTATUS ntStatus = 0;
  227. if(extra = (Password.MaximumLength % DES_BLOCKLEN))
  228. Password.MaximumLength += (DES_BLOCKLEN - extra);
  229. ntStatus = g_pRtlEncryptMemory(
  230. Password.Buffer,
  231. Password.MaximumLength,
  232. 0
  233. );
  234. ADsAssert(ntStatus == STATUS_SUCCESS);
  235. m_dwPasswdLen = Password.MaximumLength;
  236. }
  237. }
  238. }
  239. else {
  240. m_dwPasswdLen = 0;
  241. m_pszPassword = NULL;
  242. }
  243. }
  244. //+---------------------------------------------------------------------------
  245. //
  246. // CCred constructor
  247. //
  248. // Create a credential object with a username and a password.
  249. // This doesn't copy the reference count of the "other" object, nor the
  250. // server nor the server connection index. This is used to create
  251. // credentials with the same user/pass on a different server.
  252. // This should only be used by CWinNTCredentials::RefServer.
  253. //
  254. // Arguments:
  255. // [other] - credentials to copy
  256. //
  257. //----------------------------------------------------------------------------
  258. CCred::CCred(const CCred& other) : m_pszServer(NULL),
  259. m_dwIndex((DWORD) -1), m_dwRefCount(0), m_dwUsageCount(1)
  260. {
  261. m_pszUserName =
  262. other.m_pszUserName ? AllocADsStr(other.m_pszUserName) : NULL;
  263. if(other.m_pszPassword != NULL) {
  264. m_pszPassword = (PWSTR) AllocADsMem(other.m_dwPasswdLen);
  265. ADsAssert(m_pszPassword != NULL);
  266. if(m_pszPassword != NULL) {
  267. memcpy(m_pszPassword, other.m_pszPassword, other.m_dwPasswdLen);
  268. m_dwPasswdLen = other.m_dwPasswdLen;
  269. }
  270. else
  271. m_dwPasswdLen = 0;
  272. }
  273. else {
  274. m_dwPasswdLen = 0;
  275. m_pszPassword = NULL;
  276. }
  277. }
  278. //+---------------------------------------------------------------------------
  279. //
  280. // CCred destructor
  281. //
  282. // Doesn't lower the reference count.
  283. // The object is really deleted in deref().
  284. // It will release the underlying info only if the
  285. // there are no outstanding references
  286. // -- AjayR modified on 6-24-98.
  287. //
  288. //----------------------------------------------------------------------------
  289. CCred::~CCred()
  290. {
  291. //
  292. // Clean up only if the usageCount and refCount are 0
  293. // Any other case means someone has a pointer to this
  294. //
  295. if (m_dwUsageCount == 0 && m_dwRefCount == 0) {
  296. if (m_pszUserName)
  297. FreeADsStr(m_pszUserName);
  298. if (m_pszPassword)
  299. FreeADsMem(m_pszPassword);
  300. if (m_pszServer)
  301. FreeADsStr(m_pszServer);
  302. }
  303. }
  304. //+---------------------------------------------------------------------------
  305. //
  306. // CCred::ref
  307. //
  308. // Adds a reference to this credential object, and if necessary, binds
  309. // to the specified server. If this is already bound to the given server,
  310. // the reference count is simply increased.
  311. //
  312. // Arguments:
  313. // [pszServer] - server to bind to
  314. //
  315. // Returns:
  316. // S_OK - if we bound to the server, or are already bound to
  317. // the given server.
  318. // E_FAIL - if this object is bound, and "pszServer" is not the
  319. // same server as we are bound to.
  320. // E_OUTOFMEMORY - if we run out of memory.
  321. // Other error codes resulting from WNetAddConnection2.
  322. //
  323. //----------------------------------------------------------------------------
  324. HRESULT
  325. CCred::ref(PWSTR pszServer)
  326. {
  327. HRESULT hr = S_OK;
  328. PWSTR pszPassword = NULL;
  329. if (!m_pszServer)
  330. {
  331. hr = GetPassword(&pszPassword);
  332. BAIL_ON_FAILURE(hr);
  333. hr = g_CredTable.AddCred(m_pszUserName, pszPassword, pszServer,
  334. &m_dwIndex);
  335. //
  336. // Zero out the memory holding the password, now we have finished
  337. // with it.
  338. //
  339. SecureZeroMemory(pszPassword, wcslen(pszPassword) * sizeof(WCHAR));
  340. if (SUCCEEDED(hr))
  341. {
  342. m_dwRefCount++;
  343. m_pszServer = AllocADsStr(pszServer);
  344. }
  345. else
  346. // Don't set m_pszServer, since we didn't bind.
  347. m_dwIndex = (DWORD) -1;
  348. }
  349. else
  350. {
  351. if (_wcsicmp(m_pszServer, pszServer) == 0)
  352. m_dwRefCount++;
  353. else
  354. //
  355. // Don't rebind to another server. Let the caller do it
  356. // explicitly, if desired.
  357. //
  358. hr = dwRebindErr;
  359. }
  360. error:
  361. if (pszPassword)
  362. FreeADsStr(pszPassword);
  363. RRETURN(hr);
  364. }
  365. //+---------------------------------------------------------------------------
  366. //
  367. // CCred::deref
  368. //
  369. // Removes a reference from this credential object. When the reference count
  370. // drops to zero, it unbinds from the associated server and deletes itself.
  371. // After the caller calls deref(), it shouldn't touch this object ever again.
  372. //
  373. // Returns:
  374. // S_OK - deref occurred okay.
  375. // Other error codes resulting from WNetCancelConnection2.
  376. //
  377. //----------------------------------------------------------------------------
  378. HRESULT
  379. CCred::deref(void)
  380. {
  381. HRESULT hr = S_OK;
  382. ADsAssert(m_dwRefCount > 0);
  383. m_dwRefCount--;
  384. if (m_dwRefCount == 0)
  385. {
  386. hr = g_CredTable.DelCred(m_dwIndex);
  387. // Reset the index and free server to play extra safe
  388. m_dwIndex = (DWORD) -1;
  389. if (m_pszServer) {
  390. FreeADsStr(m_pszServer);
  391. m_pszServer = NULL;
  392. }
  393. #if DBG
  394. if (hr == E_INVALIDARG)
  395. ADsAssert(FALSE && "Invalid table index in CCred::deref()!");
  396. #endif
  397. }
  398. RRETURN(hr);
  399. }
  400. //+---------------------------------------------------------------------------
  401. //
  402. // CCred::GetUserName
  403. //
  404. // Retrieves the username represented by this credentials object.
  405. //
  406. // Arguments:
  407. // [ppszUserName] - address of a PWSTR to receive a
  408. // pointer to the username.
  409. // Returns:
  410. // S_OK - on success
  411. // E_OUTOFMEMORY - if we run out of memory.
  412. //
  413. //----------------------------------------------------------------------------
  414. HRESULT
  415. CCred::GetUserName(PWSTR *ppszUserName)
  416. {
  417. if (!m_pszUserName)
  418. *ppszUserName = NULL;
  419. else
  420. {
  421. *ppszUserName = AllocADsStr(m_pszUserName);
  422. if (!*ppszUserName)
  423. RRETURN(E_OUTOFMEMORY);
  424. }
  425. RRETURN(S_OK);
  426. }
  427. //+---------------------------------------------------------------------------
  428. //
  429. // CCred::GetPassword
  430. //
  431. // Retrieves the password represented by this credentials object.
  432. //
  433. // Arguments:
  434. // [ppszPassword] - address of a PWSTR to receive a
  435. // pointer to the password.
  436. // Returns:
  437. // S_OK - on success
  438. // E_OUTOFMEMORY - if we run out of memory.
  439. //
  440. //----------------------------------------------------------------------------
  441. HRESULT
  442. CCred::GetPassword(PWSTR * ppszPassword)
  443. {
  444. UNICODE_STRING Password;
  445. PWSTR pTempPassword = NULL;
  446. UCHAR Seed = NW_ENCODE_SEED3;
  447. Password.Length = 0;
  448. if (!m_pszPassword)
  449. *ppszPassword = NULL;
  450. else
  451. {
  452. pTempPassword = (PWSTR) AllocADsMem(m_dwPasswdLen);
  453. if (!pTempPassword)
  454. RRETURN(E_OUTOFMEMORY);
  455. memcpy(pTempPassword, m_pszPassword, m_dwPasswdLen);
  456. if(NULL == g_pRtlDecryptMemory) {
  457. RtlInitUnicodeString(&Password, pTempPassword);
  458. RtlRunDecodeUnicodeString(Seed, &Password);
  459. }
  460. else {
  461. NTSTATUS ntStatus = 0;
  462. ntStatus = g_pRtlDecryptMemory(pTempPassword, m_dwPasswdLen, 0);
  463. if(ntStatus != STATUS_SUCCESS)
  464. RRETURN(E_FAIL);
  465. }
  466. *ppszPassword = pTempPassword;
  467. }
  468. RRETURN(S_OK);
  469. }
  470. ///---------------------------------------------------------------------------
  471. // ____ ____ _ _____ _ _
  472. // / ___/ ___|_ __ ___ __| |_ _|_ _| |__ | | ___
  473. // | | | | | '__/ _ \/ _` | | |/ _` | '_ \| |/ _ \
  474. // | |__| |___| | | __/ (_| | | | (_| | |_) | | __/ definitions
  475. // \____\____|_| \___|\__,_| |_|\__,_|_.__/|_|\___|
  476. //
  477. ///---------------------------------------------------------------------------
  478. //+---------------------------------------------------------------------------
  479. //
  480. // CCredTable constructor
  481. //
  482. // Creates an empty CCredTable.
  483. //
  484. //----------------------------------------------------------------------------
  485. CCredTable::CCredTable() :
  486. m_pCredentials(NULL), m_dwAlloc(0), m_dwUsed(0)
  487. {
  488. }
  489. //+---------------------------------------------------------------------------
  490. //
  491. // CCredTable destructor
  492. //
  493. // Destroys the CCredTable. If there are entries still in use at dtor
  494. // time, it will print a debug message. (Maybe it should assert?)
  495. //
  496. //----------------------------------------------------------------------------
  497. CCredTable::~CCredTable()
  498. {
  499. for (DWORD dw = 0; dw < m_dwUsed; ++dw)
  500. {
  501. if (m_pCredentials[dw].m_bUsed)
  502. {
  503. // the share name could be up to MAX_PATH.
  504. #if 0
  505. WCHAR pszMessage[64 + MAX_PATH];
  506. wsprintf(pszMessage, TEXT("Credential %d (\"%s\") not free!"),
  507. dw, m_pCredentials[dw].m_pResource);
  508. OutputDebugString(pszMessage);
  509. #endif
  510. }
  511. //
  512. // Try to cancel the connection, so we don't have lots left
  513. // lying around, but don't complain if we can't disconnect.
  514. //
  515. DelCred(dw);
  516. }
  517. if (m_pCredentials)
  518. FreeADsMem(m_pCredentials);
  519. }
  520. //+---------------------------------------------------------------------------
  521. //
  522. // CCredTable::AddCred
  523. //
  524. // Tries to get credentials for a server's "IPC$" resource. If the
  525. // credentials are gained, an entry is added to the resource table.
  526. // The "index" returned allows the caller to delete the resource
  527. // when it's done with it.
  528. //
  529. // Arguments:
  530. // [pszUserName] - username to use
  531. // [pszPassword] - password to use
  532. // [pszServer] - server to connect to
  533. // [pdwIndex] - address of a DWORD to receive
  534. // the table index of this resource.
  535. // Returns:
  536. // S_OK - if we bound to the server.
  537. // E_OUTOFMEMORY - if we run out of memory.
  538. // Other error codes resulting from WNetAddConnection2.
  539. //
  540. //----------------------------------------------------------------------------
  541. HRESULT
  542. CCredTable::AddCred(PWSTR pszUserName, PWSTR pszPassword, PWSTR pszServer,
  543. DWORD *pdwIndex)
  544. {
  545. HRESULT hr = S_OK;
  546. BOOL fAlreadyInTable = FALSE;
  547. DWORD dwCtr = 0;
  548. NET_API_STATUS nasStatus = 0;
  549. USE_INFO_1 *pUseInfo = NULL;
  550. BOOL fConnectionAdded = FALSE;
  551. BOOL fInCritSect = FALSE;
  552. *pdwIndex = (DWORD) -1;
  553. //
  554. // Open a connection to IPC$ on the server.
  555. //
  556. NETRESOURCE NetResource;
  557. memset(&NetResource, 0, sizeof(NETRESOURCE));
  558. NetResource.dwType = RESOURCETYPE_ANY;
  559. NetResource.lpLocalName = NULL;
  560. NetResource.lpProvider = NULL;
  561. WCHAR RemoteName[MAX_PATH];
  562. if( (wcslen(pszServer) + wcslen(g_pszResourceName) + 4) > MAX_PATH) {
  563. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  564. }
  565. wsprintf(RemoteName, TEXT("\\\\%ls\\%ls"), pszServer, g_pszResourceName);
  566. NetResource.lpRemoteName = RemoteName;
  567. //
  568. // WNetAddConnection2 ignores the other members of NETRESOURCE.
  569. //
  570. DWORD dwResult;
  571. dwResult = WNetAddConnection2(&NetResource, pszPassword, pszUserName, 0);
  572. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwResult));
  573. fConnectionAdded = TRUE;
  574. m_cs.Lock();
  575. fInCritSect = TRUE;
  576. //
  577. // At this point, we know that the NetUse call succeeded.
  578. // We are not going to see if we need to add this to the
  579. // table or not. If we already have a net use to the same
  580. // resource then we need not add this to the table and
  581. // instead we should bump up the refCount and return the
  582. // index of the already stored resource.
  583. //
  584. for (dwCtr = 0; (dwCtr < m_dwUsed) && !fAlreadyInTable; dwCtr++) {
  585. if (m_pCredentials[dwCtr].m_bUsed
  586. && m_pCredentials[dwCtr].m_pResource) {
  587. #ifdef WIN95
  588. if (_wcsicmp(
  589. m_pCredentials[dwCtr].m_pResource,
  590. RemoteName
  591. )
  592. == 0 ) {
  593. #else
  594. if (CompareStringW(
  595. LOCALE_SYSTEM_DEFAULT,
  596. NORM_IGNORECASE,
  597. m_pCredentials[dwCtr].m_pResource,
  598. -1,
  599. RemoteName,
  600. -1
  601. ) == CSTR_EQUAL ) {
  602. #endif
  603. *pdwIndex = dwCtr;
  604. fAlreadyInTable = TRUE;
  605. m_pCredentials[dwCtr].m_dwCount++;
  606. }
  607. }
  608. }
  609. //
  610. // Index will not be -1 if we found a match in the table.
  611. //
  612. if (!fAlreadyInTable) {
  613. if (m_dwUsed == m_dwAlloc)
  614. hr = GrowTable();
  615. BAIL_ON_FAILURE(hr);
  616. ADsAssert(m_dwUsed < m_dwAlloc);
  617. m_pCredentials[m_dwUsed].m_pResource = AllocADsStr(RemoteName);
  618. if (!m_pCredentials[m_dwUsed].m_pResource)
  619. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  620. m_pCredentials[m_dwUsed].m_bUsed = TRUE;
  621. m_pCredentials[m_dwUsed].m_dwCount = 1;
  622. //
  623. // check to see if there was already a net use connection existing at
  624. // the time WNetAddConnection2 was called.
  625. //
  626. nasStatus = NetUseGetInfo(
  627. NULL,
  628. RemoteName,
  629. 1, // level
  630. (LPBYTE *) &pUseInfo
  631. );
  632. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(nasStatus));
  633. ADsAssert(pUseInfo != NULL);
  634. if(pUseInfo->ui1_usecount == 1) {
  635. // only this process has an open connection
  636. m_pCredentials[m_dwUsed].m_fAlreadyConnected = FALSE;
  637. }
  638. else {
  639. m_pCredentials[m_dwUsed].m_fAlreadyConnected = TRUE;
  640. }
  641. // do this last thing.
  642. *pdwIndex = m_dwUsed++;
  643. }
  644. m_cs.Unlock();
  645. fInCritSect = FALSE;
  646. if(pUseInfo != NULL)
  647. NetApiBufferFree(pUseInfo);
  648. RRETURN(hr);
  649. error:
  650. if (m_dwUsed != m_dwAlloc && m_pCredentials[m_dwUsed].m_pResource != NULL)
  651. {
  652. FreeADsStr(m_pCredentials[m_dwUsed].m_pResource);
  653. m_pCredentials[m_dwUsed].m_pResource = NULL;
  654. }
  655. if (fInCritSect)
  656. m_cs.Unlock();
  657. if (fConnectionAdded)
  658. (void) WNetCancelConnection2(RemoteName, 0, FALSE);
  659. if(pUseInfo != NULL)
  660. NetApiBufferFree(pUseInfo);
  661. RRETURN(hr);
  662. }
  663. //+---------------------------------------------------------------------------
  664. //
  665. // CCredTable::DelCred
  666. //
  667. // Disconnects from the "ADMIN$" resource specified by the table entry
  668. // with index "dwIndex".
  669. //
  670. // Arguments:
  671. // [DWORD dwIndex] - index of table entry to delete
  672. //
  673. // Returns:
  674. // S_OK - deref occurred okay.
  675. // E_INVALIDARG - the table index is invalid.
  676. // Other error codes resulting from WNetCancelConnection2.
  677. //
  678. //----------------------------------------------------------------------------
  679. HRESULT
  680. CCredTable::DelCred(DWORD dwIndex)
  681. {
  682. HRESULT hr = S_OK;
  683. DWORD dwResult;
  684. m_cs.Lock();
  685. if (((LONG)dwIndex) < 0 || dwIndex >= m_dwUsed)
  686. hr = E_INVALIDARG;
  687. else if (m_pCredentials[dwIndex].m_bUsed == FALSE)
  688. hr = S_OK;
  689. else
  690. {
  691. ADsAssert(m_pCredentials[dwIndex].m_dwCount);
  692. //
  693. // Delete only if the refCount is zero.
  694. //
  695. if (--m_pCredentials[dwIndex].m_dwCount == 0) {
  696. //
  697. // cancel connection only if if it was not already present at the
  698. // time we did WNetAddConnection2
  699. //
  700. if(m_pCredentials[dwIndex].m_fAlreadyConnected == FALSE) {
  701. dwResult = WNetCancelConnection2(
  702. m_pCredentials[dwIndex].m_pResource, 0, FALSE);
  703. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwResult));
  704. }
  705. FreeADsStr(m_pCredentials[dwIndex].m_pResource);
  706. m_pCredentials[dwIndex].m_pResource = NULL;
  707. m_pCredentials[dwIndex].m_bUsed = FALSE;
  708. m_pCredentials[dwIndex].m_dwCount = 0;
  709. m_pCredentials[dwIndex].m_fAlreadyConnected = FALSE;
  710. }
  711. else {
  712. hr = S_OK;
  713. }
  714. }
  715. error:
  716. m_cs.Unlock();
  717. RRETURN(hr);
  718. }
  719. //+---------------------------------------------------------------------------
  720. //
  721. // CCredTable::GrowTable
  722. //
  723. // Increase the size of the CredTable by a fixed amount. Private method.
  724. //
  725. // Returns:
  726. // S_OK - deref occurred okay.
  727. // E_OUTOFMEMORY - we ran out of memory.
  728. //
  729. //----------------------------------------------------------------------------
  730. HRESULT
  731. CCredTable::GrowTable(void)
  732. {
  733. ADsAssert(m_cs.Locked());
  734. cred *pCredentials = (cred *)ReallocADsMem(m_pCredentials,
  735. m_dwAlloc * sizeof(cred), (m_dwAlloc + 10) * sizeof(cred));
  736. if (!pCredentials)
  737. RRETURN(E_OUTOFMEMORY);
  738. m_pCredentials = pCredentials;
  739. for (DWORD dw = m_dwAlloc; dw < m_dwAlloc + 10; dw++)
  740. {
  741. m_pCredentials[dw].m_bUsed = FALSE;
  742. m_pCredentials[dw].m_pResource = NULL;
  743. m_pCredentials[dw].m_dwCount = 0;
  744. m_pCredentials[dw].m_fAlreadyConnected = FALSE;
  745. }
  746. m_dwAlloc += 10;
  747. RRETURN(S_OK);
  748. }
  749. //////////////////////////////////////////////////////////////////////////////
  750. // _____ ___ _ _ _____ ___ _ _ _ _
  751. // / __\ \ / (_)_ _ | \| |_ _/ __|_ _ ___ __| |___ _ _| |_(_)__ _| |___
  752. // | (__ \ \/\/ /| | ' \| .` | | || (__| '_/ -_) _` / -_) ' \ _| / _` | (_-<
  753. // \___| \_/\_/ |_|_||_|_|\_| |_| \___|_| \___\__,_\___|_||_\__|_\__,_|_/__/
  754. // definitions
  755. //
  756. //////////////////////////////////////////////////////////////////////////////
  757. //+---------------------------------------------------------------------------
  758. //
  759. // CWinNTCredentials constructor
  760. //
  761. // Creates an empty CWinNTCredentials object.
  762. //
  763. //----------------------------------------------------------------------------
  764. CWinNTCredentials::CWinNTCredentials():
  765. m_cRefAdded(0), m_pCred(NULL), m_dwFlags(0)
  766. {
  767. }
  768. //+---------------------------------------------------------------------------
  769. //
  770. // CWinNTCredentials constructor
  771. //
  772. // Creates a CWinNTCredentials object for a given username/password.
  773. //
  774. // Arguments:
  775. // [pszUserName] - username
  776. // [pszPassword] - password
  777. //
  778. //----------------------------------------------------------------------------
  779. CWinNTCredentials::CWinNTCredentials(PWSTR pszUserName, PWSTR pszPassword, DWORD dwFlags) :
  780. m_cRefAdded(0), m_pCred(NULL), m_dwFlags(dwFlags)
  781. {
  782. //
  783. // If both username and password are NULL or "", don't create a cred.
  784. //
  785. if ((pszUserName && *pszUserName) || (pszPassword && *pszPassword))
  786. m_pCred = new CCred(pszUserName, pszPassword);
  787. }
  788. //+---------------------------------------------------------------------------
  789. //
  790. // CWinNTCredentials copy constructor
  791. //
  792. // Copies a CWinNTCredentials object from another.
  793. // This sets the "referenced" flag to FALSE, and doesn't increase the
  794. // reference count. That should be done explicitly with ref().
  795. //
  796. // Arguments:
  797. // [other] - credentials to copy
  798. //
  799. //----------------------------------------------------------------------------
  800. CWinNTCredentials::CWinNTCredentials(const CWinNTCredentials& other) :
  801. m_cRefAdded(0), m_pCred(other.m_pCred), m_dwFlags(other.m_dwFlags)
  802. {
  803. }
  804. //+---------------------------------------------------------------------------
  805. //
  806. // CWinNTCredentials destructor
  807. //
  808. // Dereferences the credentials. If the reference count drops to zero,
  809. // the internal refcounted credentials object goes away.
  810. //
  811. //----------------------------------------------------------------------------
  812. CWinNTCredentials::~CWinNTCredentials()
  813. {
  814. Clear_pCredObject();
  815. }
  816. //+---------------------------------------------------------------------------
  817. //
  818. // CWinNTCredentials::Clear_pCredObject
  819. //
  820. // Dereferences the credentials. If the reference count drops to zero,
  821. // the internal refcounted credentials object goes away.
  822. // This is a private member function as this needs to be called
  823. // in different places and therefore the destructor is not the
  824. // right place - AjayR 6-25-98.
  825. //
  826. //----------------------------------------------------------------------------
  827. void
  828. CWinNTCredentials::Clear_pCredObject()
  829. {
  830. if (m_cRefAdded) {
  831. m_pCred->deref();
  832. m_cRefAdded--;
  833. }
  834. if (m_pCred) {
  835. m_pCred->m_dwUsageCount--;
  836. if (m_pCred->m_dwUsageCount == 0) {
  837. delete m_pCred;
  838. m_pCred = NULL;
  839. }
  840. }
  841. }
  842. //+---------------------------------------------------------------------------
  843. //
  844. // CWinNTCredentials copy operator
  845. //
  846. // Copies a CWinNTCredentials object from another. This dereferences
  847. // the old object, and doesn't increase the reference count of the
  848. // new object. That should be done explicitly with ref().
  849. //
  850. // Arguments:
  851. // [other] - credentials to copy
  852. //
  853. //----------------------------------------------------------------------------
  854. const CWinNTCredentials&
  855. CWinNTCredentials::operator=(const CWinNTCredentials& other)
  856. {
  857. if (&other != this)
  858. {
  859. // Clean up the current m_pCred
  860. Clear_pCredObject();
  861. m_dwFlags = other.m_dwFlags;
  862. m_pCred = other.m_pCred;
  863. if (m_pCred) {
  864. m_pCred->m_dwUsageCount++;
  865. }
  866. m_cRefAdded = 0;
  867. // Don't addref here.
  868. }
  869. return *this;
  870. }
  871. //+---------------------------------------------------------------------------
  872. //
  873. // CWinNTCredentials::RefServer
  874. //
  875. // Increments the credentials object's reference count, and if necessary,
  876. // attempts to connect to the server's "ADMIN$" resource.
  877. //
  878. // Arguments:
  879. // [pszServer] - server to establish credentials with
  880. //
  881. //----------------------------------------------------------------------------
  882. HRESULT
  883. CWinNTCredentials::RefServer(PWSTR pszServer, BOOL fAllowRebinding)
  884. {
  885. HRESULT hr = S_OK;
  886. if (m_pCred)
  887. {
  888. ADsAssert(pszServer && *pszServer);
  889. hr = m_pCred->ref(pszServer);
  890. //
  891. // We usually don't want to allow rebinding, to catch coding mistakes.
  892. // The only time we want to is when we open a Computer object from a
  893. // Domain, which has been opened via OpenDSObject.
  894. //
  895. if (hr == dwRebindErr && fAllowRebinding)
  896. {
  897. // Copy the username and password, and try again.
  898. CCred * pCCred = new CCred(*m_pCred);
  899. // clear the m_pCred object
  900. Clear_pCredObject();
  901. //
  902. // assign the m_pCred object to the copy and try
  903. // and rebind if the new CCred object is not null
  904. //
  905. m_pCred = pCCred;
  906. //
  907. // m_cRefAdded is this CWinNTCredentials object's contribution
  908. // to the refcount of m_pCred. Since we have a new CCred object,
  909. // set m_cRefAdded to 0.
  910. //
  911. m_cRefAdded = 0;
  912. if (m_pCred)
  913. hr = m_pCred->ref(pszServer);
  914. else
  915. hr = E_OUTOFMEMORY;
  916. }
  917. if (SUCCEEDED(hr))
  918. m_cRefAdded++;
  919. }
  920. RRETURN(hr);
  921. }
  922. //+---------------------------------------------------------------------------
  923. //
  924. // CWinNTCredentials::DeRefServer
  925. //
  926. // Call this only in special cases, when you know that the credentials
  927. // object is being passed around will have to RefServer/RefDomain
  928. // more than once as we are in the process of validating/finding
  929. // the object as opposed to actually creating the adsi object.
  930. // AjayR added on 6-24-98.
  931. //
  932. // Arguments:
  933. // [pszServer] - server to deref
  934. //
  935. //----------------------------------------------------------------------------
  936. HRESULT
  937. CWinNTCredentials::DeRefServer()
  938. {
  939. HRESULT hr = S_OK;
  940. if (m_pCred && m_cRefAdded)
  941. {
  942. hr = m_pCred->deref();
  943. m_cRefAdded--;
  944. }
  945. RRETURN(hr);
  946. }
  947. //+---------------------------------------------------------------------------
  948. //
  949. // CWinNTCredentials::RefDomain
  950. //
  951. // Increments the credentials object's reference count, and if necessary,
  952. // attempts to connect to the server's "ADMIN$" resource.
  953. //
  954. // Arguments:
  955. // [pszDomain] - domain to establish credentials with
  956. //
  957. //----------------------------------------------------------------------------
  958. HRESULT
  959. CWinNTCredentials::RefDomain(PWSTR pszDomain)
  960. {
  961. HRESULT hr = S_OK;
  962. // Don't take the hit of WinNTGetCachedDCName if we have null creds.
  963. if (m_pCred)
  964. {
  965. WCHAR szDCName[MAX_PATH];
  966. ADsAssert(pszDomain && *pszDomain);
  967. hr = WinNTGetCachedDCName(pszDomain, szDCName, m_dwFlags);
  968. if (SUCCEEDED(hr))
  969. // +2 for the initial "\\"
  970. hr = RefServer(szDCName + 2);
  971. }
  972. RRETURN(hr);
  973. }
  974. //+---------------------------------------------------------------------------
  975. //
  976. // CWinNTCredentials::DeRefDomain
  977. //
  978. // Call this only in special cases, when you know that the credentials
  979. // object is being passed around will have to RefServer/RefDomain
  980. // more than once as we are in the process of validating/finding
  981. // the object as opposed to actually creating the adsi object.
  982. // AjayR added on 6-24-98.
  983. //
  984. // Arguments:
  985. // [pszServer] - server to deref
  986. //
  987. //----------------------------------------------------------------------------
  988. HRESULT
  989. CWinNTCredentials::DeRefDomain()
  990. {
  991. HRESULT hr = S_OK;
  992. //
  993. // Call DeRefServer - since we just want to whack the ref
  994. //
  995. hr = DeRefServer();
  996. RRETURN(hr);
  997. }
  998. //+---------------------------------------------------------------------------
  999. //
  1000. // CWinNTCredentials::Ref
  1001. //
  1002. // Increments the credentials object's reference count, and if necessary,
  1003. // attempts to connect to the server's "ADMIN$" resource.
  1004. //
  1005. // This takes both a server and a domain; since several objects are created
  1006. // with both server and domain as arguments (which one is used depends on
  1007. // what the object's ADs parent is), this is a commonly used bit of code.
  1008. //
  1009. // Arguments:
  1010. // [pszServer] - server to bind to
  1011. // [pszDomain] - domain of the PDC to bind to
  1012. // [dwType] - WINNT_DOMAIN_ID or WINNT_COMPUTER_ID
  1013. //
  1014. // Returns:
  1015. // S_OK - if we bound to the server, or are already bound to
  1016. // the given server.
  1017. // E_FAIL - if this object is bound, and the specified server
  1018. // is not the same server as we are bound to.
  1019. // E_OUTOFMEMORY - if we run out of memory.
  1020. // Other error codes resulting from WNetAddConnection2 and from
  1021. // WinNTGetCachedDCName.
  1022. //
  1023. //----------------------------------------------------------------------------
  1024. HRESULT
  1025. CWinNTCredentials::Ref(PWSTR pszServer, PWSTR pszDomain, DWORD dwType)
  1026. {
  1027. HRESULT hr = S_OK;
  1028. ADsAssert(dwType == WINNT_DOMAIN_ID || dwType == WINNT_COMPUTER_ID);
  1029. // Don't take the hit of WinNTGetCachedDCName if we have null creds.
  1030. if (m_pCred)
  1031. {
  1032. if (dwType == WINNT_DOMAIN_ID)
  1033. hr = RefDomain(pszDomain);
  1034. else
  1035. hr = RefServer(pszServer);
  1036. }
  1037. RRETURN(hr);
  1038. }
  1039. //+---------------------------------------------------------------------------
  1040. //
  1041. // CWinNTCredentials::GetUserName
  1042. //
  1043. // Retrieves the username represented by this credentials object.
  1044. //
  1045. // Arguments:
  1046. // [ppszUserName] - address of a PWSTR to receive a
  1047. // pointer to the username.
  1048. // Returns:
  1049. // S_OK - on success
  1050. // E_OUTOFMEMORY - if we run out of memory.
  1051. //
  1052. //----------------------------------------------------------------------------
  1053. HRESULT
  1054. CWinNTCredentials::GetUserName(PWSTR *ppszUserName)
  1055. {
  1056. HRESULT hr;
  1057. if (!ppszUserName)
  1058. RRETURN(E_ADS_BAD_PARAMETER);
  1059. //
  1060. // Based on the rest of the codes, if UserName & Password are both "",
  1061. // no CCred is created & m_pCred = NULL. (See Constructor). Before we
  1062. // can hit CCred::GetUserName and get back *ppszUserName=NULL with hr =
  1063. // S_OK, we will have AV already. So need to check if m_pCred 1st.
  1064. //
  1065. if (m_pCred)
  1066. {
  1067. hr = m_pCred->GetUserName(ppszUserName);
  1068. }
  1069. else
  1070. {
  1071. *ppszUserName = NULL;
  1072. hr = S_OK;
  1073. }
  1074. RRETURN(hr);
  1075. }
  1076. //+---------------------------------------------------------------------------
  1077. //
  1078. // CWinNTCredentials::GetPassword
  1079. //
  1080. // Retrieves the password represented by this credentials object.
  1081. //
  1082. // Arguments:
  1083. // [ppszPassword] - address of a PWSTR to receive a
  1084. // pointer to the password.
  1085. // Returns:
  1086. // S_OK - on success
  1087. // E_OUTOFMEMORY - if we run out of memory.
  1088. //
  1089. //----------------------------------------------------------------------------
  1090. HRESULT
  1091. CWinNTCredentials::GetPassword(PWSTR * ppszPassword)
  1092. {
  1093. HRESULT hr;
  1094. if (!ppszPassword)
  1095. RRETURN(E_ADS_BAD_PARAMETER);
  1096. //
  1097. // Based on the rest of the codes, if UserName & Password are both "",
  1098. // no CCred is created & m_pCred = NULL. (See Constructor). Before we
  1099. // can hit CCred::GetUserName and get back *ppszPassword=NULL with hr =
  1100. // S_OK, we will have AV already. So need to check if m_pCred 1st.
  1101. //
  1102. if (m_pCred)
  1103. {
  1104. hr = m_pCred->GetPassword(ppszPassword);
  1105. }
  1106. else
  1107. {
  1108. *ppszPassword = NULL;
  1109. hr = S_OK;
  1110. }
  1111. RRETURN(hr);
  1112. }
  1113. //+---------------------------------------------------------------------------
  1114. //
  1115. // CWinNTCredentials::Bound
  1116. //
  1117. // Returns TRUE iff this object has a reference to a server.
  1118. //
  1119. //----------------------------------------------------------------------------
  1120. BOOL
  1121. CWinNTCredentials::Bound()
  1122. {
  1123. RRETURN(m_cRefAdded != 0);
  1124. }
  1125. void
  1126. CWinNTCredentials::SetFlags(DWORD dwFlags)
  1127. {
  1128. m_dwFlags = dwFlags;
  1129. }
  1130. DWORD
  1131. CWinNTCredentials::GetFlags() const
  1132. {
  1133. RRETURN(m_dwFlags);
  1134. }
  1135. void
  1136. CWinNTCredentials::SetUmiFlag(void)
  1137. {
  1138. m_dwFlags |= ADS_AUTH_RESERVED;
  1139. }
  1140. void
  1141. CWinNTCredentials::ResetUmiFlag(void)
  1142. {
  1143. m_dwFlags &= (~ADS_AUTH_RESERVED);
  1144. }