Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1315 lines
38 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. if (SUCCEEDED(hr))
  336. {
  337. m_dwRefCount++;
  338. m_pszServer = AllocADsStr(pszServer);
  339. }
  340. else
  341. // Don't set m_pszServer, since we didn't bind.
  342. m_dwIndex = (DWORD) -1;
  343. }
  344. else
  345. {
  346. if (_wcsicmp(m_pszServer, pszServer) == 0)
  347. m_dwRefCount++;
  348. else
  349. //
  350. // Don't rebind to another server. Let the caller do it
  351. // explicitly, if desired.
  352. //
  353. hr = dwRebindErr;
  354. }
  355. error:
  356. if (pszPassword)
  357. FreeADsStr(pszPassword);
  358. RRETURN(hr);
  359. }
  360. //+---------------------------------------------------------------------------
  361. //
  362. // CCred::deref
  363. //
  364. // Removes a reference from this credential object. When the reference count
  365. // drops to zero, it unbinds from the associated server and deletes itself.
  366. // After the caller calls deref(), it shouldn't touch this object ever again.
  367. //
  368. // Returns:
  369. // S_OK - deref occurred okay.
  370. // Other error codes resulting from WNetCancelConnection2.
  371. //
  372. //----------------------------------------------------------------------------
  373. HRESULT
  374. CCred::deref(void)
  375. {
  376. HRESULT hr = S_OK;
  377. ADsAssert(m_dwRefCount > 0);
  378. m_dwRefCount--;
  379. if (m_dwRefCount == 0)
  380. {
  381. hr = g_CredTable.DelCred(m_dwIndex);
  382. // Reset the index and free server to play extra safe
  383. m_dwIndex = (DWORD) -1;
  384. if (m_pszServer) {
  385. FreeADsStr(m_pszServer);
  386. m_pszServer = NULL;
  387. }
  388. #if DBG
  389. if (hr == E_INVALIDARG)
  390. ADsAssert(FALSE && "Invalid table index in CCred::deref()!");
  391. #endif
  392. }
  393. RRETURN(hr);
  394. }
  395. //+---------------------------------------------------------------------------
  396. //
  397. // CCred::GetUserName
  398. //
  399. // Retrieves the username represented by this credentials object.
  400. //
  401. // Arguments:
  402. // [ppszUserName] - address of a PWSTR to receive a
  403. // pointer to the username.
  404. // Returns:
  405. // S_OK - on success
  406. // E_OUTOFMEMORY - if we run out of memory.
  407. //
  408. //----------------------------------------------------------------------------
  409. HRESULT
  410. CCred::GetUserName(PWSTR *ppszUserName)
  411. {
  412. if (!m_pszUserName)
  413. *ppszUserName = NULL;
  414. else
  415. {
  416. *ppszUserName = AllocADsStr(m_pszUserName);
  417. if (!*ppszUserName)
  418. RRETURN(E_OUTOFMEMORY);
  419. }
  420. RRETURN(S_OK);
  421. }
  422. //+---------------------------------------------------------------------------
  423. //
  424. // CCred::GetPassword
  425. //
  426. // Retrieves the password represented by this credentials object.
  427. //
  428. // Arguments:
  429. // [ppszPassword] - address of a PWSTR to receive a
  430. // pointer to the password.
  431. // Returns:
  432. // S_OK - on success
  433. // E_OUTOFMEMORY - if we run out of memory.
  434. //
  435. //----------------------------------------------------------------------------
  436. HRESULT
  437. CCred::GetPassword(PWSTR * ppszPassword)
  438. {
  439. UNICODE_STRING Password;
  440. PWSTR pTempPassword = NULL;
  441. UCHAR Seed = NW_ENCODE_SEED3;
  442. Password.Length = 0;
  443. if (!m_pszPassword)
  444. *ppszPassword = NULL;
  445. else
  446. {
  447. pTempPassword = (PWSTR) AllocADsMem(m_dwPasswdLen);
  448. if (!pTempPassword)
  449. RRETURN(E_OUTOFMEMORY);
  450. memcpy(pTempPassword, m_pszPassword, m_dwPasswdLen);
  451. if(NULL == g_pRtlDecryptMemory) {
  452. RtlInitUnicodeString(&Password, pTempPassword);
  453. RtlRunDecodeUnicodeString(Seed, &Password);
  454. }
  455. else {
  456. NTSTATUS ntStatus = 0;
  457. ntStatus = g_pRtlDecryptMemory(pTempPassword, m_dwPasswdLen, 0);
  458. if(ntStatus != STATUS_SUCCESS)
  459. RRETURN(E_FAIL);
  460. }
  461. *ppszPassword = pTempPassword;
  462. }
  463. RRETURN(S_OK);
  464. }
  465. ///---------------------------------------------------------------------------
  466. // ____ ____ _ _____ _ _
  467. // / ___/ ___|_ __ ___ __| |_ _|_ _| |__ | | ___
  468. // | | | | | '__/ _ \/ _` | | |/ _` | '_ \| |/ _ \
  469. // | |__| |___| | | __/ (_| | | | (_| | |_) | | __/ definitions
  470. // \____\____|_| \___|\__,_| |_|\__,_|_.__/|_|\___|
  471. //
  472. ///---------------------------------------------------------------------------
  473. //+---------------------------------------------------------------------------
  474. //
  475. // CCredTable constructor
  476. //
  477. // Creates an empty CCredTable.
  478. //
  479. //----------------------------------------------------------------------------
  480. CCredTable::CCredTable() :
  481. m_pCredentials(NULL), m_dwAlloc(0), m_dwUsed(0)
  482. {
  483. }
  484. //+---------------------------------------------------------------------------
  485. //
  486. // CCredTable destructor
  487. //
  488. // Destroys the CCredTable. If there are entries still in use at dtor
  489. // time, it will print a debug message. (Maybe it should assert?)
  490. //
  491. //----------------------------------------------------------------------------
  492. CCredTable::~CCredTable()
  493. {
  494. for (DWORD dw = 0; dw < m_dwUsed; ++dw)
  495. {
  496. if (m_pCredentials[dw].m_bUsed)
  497. {
  498. // the share name could be up to MAX_PATH.
  499. #if 0
  500. WCHAR pszMessage[64 + MAX_PATH];
  501. wsprintf(pszMessage, TEXT("Credential %d (\"%s\") not free!"),
  502. dw, m_pCredentials[dw].m_pResource);
  503. OutputDebugString(pszMessage);
  504. #endif
  505. }
  506. //
  507. // Try to cancel the connection, so we don't have lots left
  508. // lying around, but don't complain if we can't disconnect.
  509. //
  510. DelCred(dw);
  511. }
  512. if (m_pCredentials)
  513. FreeADsMem(m_pCredentials);
  514. }
  515. //+---------------------------------------------------------------------------
  516. //
  517. // CCredTable::AddCred
  518. //
  519. // Tries to get credentials for a server's "IPC$" resource. If the
  520. // credentials are gained, an entry is added to the resource table.
  521. // The "index" returned allows the caller to delete the resource
  522. // when it's done with it.
  523. //
  524. // Arguments:
  525. // [pszUserName] - username to use
  526. // [pszPassword] - password to use
  527. // [pszServer] - server to connect to
  528. // [pdwIndex] - address of a DWORD to receive
  529. // the table index of this resource.
  530. // Returns:
  531. // S_OK - if we bound to the server.
  532. // E_OUTOFMEMORY - if we run out of memory.
  533. // Other error codes resulting from WNetAddConnection2.
  534. //
  535. //----------------------------------------------------------------------------
  536. HRESULT
  537. CCredTable::AddCred(PWSTR pszUserName, PWSTR pszPassword, PWSTR pszServer,
  538. DWORD *pdwIndex)
  539. {
  540. HRESULT hr = S_OK;
  541. BOOL fAlreadyInTable = FALSE;
  542. DWORD dwCtr = 0;
  543. NET_API_STATUS nasStatus = 0;
  544. USE_INFO_1 *pUseInfo = NULL;
  545. BOOL fConnectionAdded = FALSE;
  546. *pdwIndex = (DWORD) -1;
  547. //
  548. // Open a connection to IPC$ on the server.
  549. //
  550. NETRESOURCE NetResource;
  551. memset(&NetResource, 0, sizeof(NETRESOURCE));
  552. NetResource.dwType = RESOURCETYPE_ANY;
  553. NetResource.lpLocalName = NULL;
  554. NetResource.lpProvider = NULL;
  555. WCHAR RemoteName[MAX_PATH];
  556. if( (wcslen(pszServer) + wcslen(g_pszResourceName) + 4) > MAX_PATH) {
  557. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  558. }
  559. wsprintf(RemoteName, TEXT("\\\\%ls\\%ls"), pszServer, g_pszResourceName);
  560. NetResource.lpRemoteName = RemoteName;
  561. //
  562. // WNetAddConnection2 ignores the other members of NETRESOURCE.
  563. //
  564. DWORD dwResult;
  565. dwResult = WNetAddConnection2(&NetResource, pszPassword, pszUserName, 0);
  566. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwResult));
  567. fConnectionAdded = TRUE;
  568. m_cs.Lock();
  569. //
  570. // At this point, we know that the NetUse call succeeded.
  571. // We are not going to see if we need to add this to the
  572. // table or not. If we already have a net use to the same
  573. // resource then we need not add this to the table and
  574. // instead we should bump up the refCount and return the
  575. // index of the already stored resource.
  576. //
  577. for (dwCtr = 0; (dwCtr < m_dwUsed) && !fAlreadyInTable; dwCtr++) {
  578. if (m_pCredentials[dwCtr].m_bUsed
  579. && m_pCredentials[dwCtr].m_pResource) {
  580. #ifdef WIN95
  581. if (_wcsicmp(
  582. m_pCredentials[dwCtr].m_pResource,
  583. RemoteName
  584. )
  585. == 0 ) {
  586. #else
  587. if (CompareStringW(
  588. LOCALE_SYSTEM_DEFAULT,
  589. NORM_IGNORECASE,
  590. m_pCredentials[dwCtr].m_pResource,
  591. -1,
  592. RemoteName,
  593. -1
  594. ) == CSTR_EQUAL ) {
  595. #endif
  596. *pdwIndex = dwCtr;
  597. fAlreadyInTable = TRUE;
  598. m_pCredentials[dwCtr].m_dwCount++;
  599. }
  600. }
  601. }
  602. //
  603. // Index will not be -1 if we found a match in the table.
  604. //
  605. if (!fAlreadyInTable) {
  606. if (m_dwUsed == m_dwAlloc)
  607. hr = GrowTable();
  608. BAIL_ON_FAILURE(hr);
  609. ADsAssert(m_dwUsed < m_dwAlloc);
  610. m_pCredentials[m_dwUsed].m_pResource = AllocADsStr(RemoteName);
  611. if (!m_pCredentials[m_dwUsed].m_pResource)
  612. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  613. m_pCredentials[m_dwUsed].m_bUsed = TRUE;
  614. m_pCredentials[m_dwUsed].m_dwCount = 1;
  615. //
  616. // check to see if there was already a net use connection existing at
  617. // the time WNetAddConnection2 was called.
  618. //
  619. nasStatus = NetUseGetInfo(
  620. NULL,
  621. RemoteName,
  622. 1, // level
  623. (LPBYTE *) &pUseInfo
  624. );
  625. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(nasStatus));
  626. ADsAssert(pUseInfo != NULL);
  627. if(pUseInfo->ui1_usecount == 1) {
  628. // only this process has an open connection
  629. m_pCredentials[m_dwUsed].m_fAlreadyConnected = FALSE;
  630. }
  631. else {
  632. m_pCredentials[m_dwUsed].m_fAlreadyConnected = TRUE;
  633. }
  634. // do this last thing.
  635. *pdwIndex = m_dwUsed++;
  636. }
  637. m_cs.Unlock();
  638. if(pUseInfo != NULL)
  639. NetApiBufferFree(pUseInfo);
  640. RRETURN(hr);
  641. error:
  642. if (m_dwUsed != m_dwAlloc && m_pCredentials[m_dwUsed].m_pResource != NULL)
  643. {
  644. FreeADsStr(m_pCredentials[m_dwUsed].m_pResource);
  645. m_pCredentials[m_dwUsed].m_pResource = NULL;
  646. }
  647. if (m_cs.Locked())
  648. m_cs.Unlock();
  649. if (fConnectionAdded)
  650. (void) WNetCancelConnection2(RemoteName, 0, FALSE);
  651. if(pUseInfo != NULL)
  652. NetApiBufferFree(pUseInfo);
  653. RRETURN(hr);
  654. }
  655. //+---------------------------------------------------------------------------
  656. //
  657. // CCredTable::DelCred
  658. //
  659. // Disconnects from the "ADMIN$" resource specified by the table entry
  660. // with index "dwIndex".
  661. //
  662. // Arguments:
  663. // [DWORD dwIndex] - index of table entry to delete
  664. //
  665. // Returns:
  666. // S_OK - deref occurred okay.
  667. // E_INVALIDARG - the table index is invalid.
  668. // Other error codes resulting from WNetCancelConnection2.
  669. //
  670. //----------------------------------------------------------------------------
  671. HRESULT
  672. CCredTable::DelCred(DWORD dwIndex)
  673. {
  674. HRESULT hr = S_OK;
  675. DWORD dwResult;
  676. m_cs.Lock();
  677. if (((LONG)dwIndex) < 0 || dwIndex >= m_dwUsed)
  678. hr = E_INVALIDARG;
  679. else if (m_pCredentials[dwIndex].m_bUsed == FALSE)
  680. hr = S_OK;
  681. else
  682. {
  683. ADsAssert(m_pCredentials[dwIndex].m_dwCount);
  684. //
  685. // Delete only if the refCount is zero.
  686. //
  687. if (--m_pCredentials[dwIndex].m_dwCount == 0) {
  688. //
  689. // cancel connection only if if it was not already present at the
  690. // time we did WNetAddConnection2
  691. //
  692. if(m_pCredentials[dwIndex].m_fAlreadyConnected == FALSE) {
  693. dwResult = WNetCancelConnection2(
  694. m_pCredentials[dwIndex].m_pResource, 0, FALSE);
  695. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwResult));
  696. }
  697. FreeADsStr(m_pCredentials[dwIndex].m_pResource);
  698. m_pCredentials[dwIndex].m_pResource = NULL;
  699. m_pCredentials[dwIndex].m_bUsed = FALSE;
  700. m_pCredentials[dwIndex].m_dwCount = 0;
  701. m_pCredentials[dwIndex].m_fAlreadyConnected = FALSE;
  702. }
  703. else {
  704. hr = S_OK;
  705. }
  706. }
  707. error:
  708. m_cs.Unlock();
  709. RRETURN(hr);
  710. }
  711. //+---------------------------------------------------------------------------
  712. //
  713. // CCredTable::GrowTable
  714. //
  715. // Increase the size of the CredTable by a fixed amount. Private method.
  716. //
  717. // Returns:
  718. // S_OK - deref occurred okay.
  719. // E_OUTOFMEMORY - we ran out of memory.
  720. //
  721. //----------------------------------------------------------------------------
  722. HRESULT
  723. CCredTable::GrowTable(void)
  724. {
  725. ADsAssert(m_cs.Locked());
  726. cred *pCredentials = (cred *)ReallocADsMem(m_pCredentials,
  727. m_dwAlloc * sizeof(cred), (m_dwAlloc + 10) * sizeof(cred));
  728. if (!pCredentials)
  729. RRETURN(E_OUTOFMEMORY);
  730. m_pCredentials = pCredentials;
  731. for (DWORD dw = m_dwAlloc; dw < m_dwAlloc + 10; dw++)
  732. {
  733. m_pCredentials[dw].m_bUsed = FALSE;
  734. m_pCredentials[dw].m_pResource = NULL;
  735. m_pCredentials[dw].m_dwCount = 0;
  736. m_pCredentials[dw].m_fAlreadyConnected = FALSE;
  737. }
  738. m_dwAlloc += 10;
  739. RRETURN(S_OK);
  740. }
  741. //////////////////////////////////////////////////////////////////////////////
  742. // _____ ___ _ _ _____ ___ _ _ _ _
  743. // / __\ \ / (_)_ _ | \| |_ _/ __|_ _ ___ __| |___ _ _| |_(_)__ _| |___
  744. // | (__ \ \/\/ /| | ' \| .` | | || (__| '_/ -_) _` / -_) ' \ _| / _` | (_-<
  745. // \___| \_/\_/ |_|_||_|_|\_| |_| \___|_| \___\__,_\___|_||_\__|_\__,_|_/__/
  746. // definitions
  747. //
  748. //////////////////////////////////////////////////////////////////////////////
  749. //+---------------------------------------------------------------------------
  750. //
  751. // CWinNTCredentials constructor
  752. //
  753. // Creates an empty CWinNTCredentials object.
  754. //
  755. //----------------------------------------------------------------------------
  756. CWinNTCredentials::CWinNTCredentials():
  757. m_cRefAdded(0), m_pCred(NULL), m_dwFlags(0)
  758. {
  759. }
  760. //+---------------------------------------------------------------------------
  761. //
  762. // CWinNTCredentials constructor
  763. //
  764. // Creates a CWinNTCredentials object for a given username/password.
  765. //
  766. // Arguments:
  767. // [pszUserName] - username
  768. // [pszPassword] - password
  769. //
  770. //----------------------------------------------------------------------------
  771. CWinNTCredentials::CWinNTCredentials(PWSTR pszUserName, PWSTR pszPassword, DWORD dwFlags) :
  772. m_cRefAdded(0), m_pCred(NULL), m_dwFlags(dwFlags)
  773. {
  774. //
  775. // If both username and password are NULL or "", don't create a cred.
  776. //
  777. if ((pszUserName && *pszUserName) || (pszPassword && *pszPassword))
  778. m_pCred = new CCred(pszUserName, pszPassword);
  779. }
  780. //+---------------------------------------------------------------------------
  781. //
  782. // CWinNTCredentials copy constructor
  783. //
  784. // Copies a CWinNTCredentials object from another.
  785. // This sets the "referenced" flag to FALSE, and doesn't increase the
  786. // reference count. That should be done explicitly with ref().
  787. //
  788. // Arguments:
  789. // [other] - credentials to copy
  790. //
  791. //----------------------------------------------------------------------------
  792. CWinNTCredentials::CWinNTCredentials(const CWinNTCredentials& other) :
  793. m_cRefAdded(0), m_pCred(other.m_pCred), m_dwFlags(other.m_dwFlags)
  794. {
  795. }
  796. //+---------------------------------------------------------------------------
  797. //
  798. // CWinNTCredentials destructor
  799. //
  800. // Dereferences the credentials. If the reference count drops to zero,
  801. // the internal refcounted credentials object goes away.
  802. //
  803. //----------------------------------------------------------------------------
  804. CWinNTCredentials::~CWinNTCredentials()
  805. {
  806. Clear_pCredObject();
  807. }
  808. //+---------------------------------------------------------------------------
  809. //
  810. // CWinNTCredentials::Clear_pCredObject
  811. //
  812. // Dereferences the credentials. If the reference count drops to zero,
  813. // the internal refcounted credentials object goes away.
  814. // This is a private member function as this needs to be called
  815. // in different places and therefore the destructor is not the
  816. // right place - AjayR 6-25-98.
  817. //
  818. //----------------------------------------------------------------------------
  819. void
  820. CWinNTCredentials::Clear_pCredObject()
  821. {
  822. if (m_cRefAdded) {
  823. m_pCred->deref();
  824. m_cRefAdded--;
  825. }
  826. if (m_pCred) {
  827. m_pCred->m_dwUsageCount--;
  828. if (m_pCred->m_dwUsageCount == 0) {
  829. delete m_pCred;
  830. m_pCred = NULL;
  831. }
  832. }
  833. }
  834. //+---------------------------------------------------------------------------
  835. //
  836. // CWinNTCredentials copy operator
  837. //
  838. // Copies a CWinNTCredentials object from another. This dereferences
  839. // the old object, and doesn't increase the reference count of the
  840. // new object. That should be done explicitly with ref().
  841. //
  842. // Arguments:
  843. // [other] - credentials to copy
  844. //
  845. //----------------------------------------------------------------------------
  846. const CWinNTCredentials&
  847. CWinNTCredentials::operator=(const CWinNTCredentials& other)
  848. {
  849. if (&other != this)
  850. {
  851. // Clean up the current m_pCred
  852. Clear_pCredObject();
  853. m_dwFlags = other.m_dwFlags;
  854. m_pCred = other.m_pCred;
  855. if (m_pCred) {
  856. m_pCred->m_dwUsageCount++;
  857. }
  858. m_cRefAdded = 0;
  859. // Don't addref here.
  860. }
  861. return *this;
  862. }
  863. //+---------------------------------------------------------------------------
  864. //
  865. // CWinNTCredentials::RefServer
  866. //
  867. // Increments the credentials object's reference count, and if necessary,
  868. // attempts to connect to the server's "ADMIN$" resource.
  869. //
  870. // Arguments:
  871. // [pszServer] - server to establish credentials with
  872. //
  873. //----------------------------------------------------------------------------
  874. HRESULT
  875. CWinNTCredentials::RefServer(PWSTR pszServer, BOOL fAllowRebinding)
  876. {
  877. HRESULT hr = S_OK;
  878. if (m_pCred)
  879. {
  880. ADsAssert(pszServer && *pszServer);
  881. hr = m_pCred->ref(pszServer);
  882. //
  883. // We usually don't want to allow rebinding, to catch coding mistakes.
  884. // The only time we want to is when we open a Computer object from a
  885. // Domain, which has been opened via OpenDSObject.
  886. //
  887. if (hr == dwRebindErr && fAllowRebinding)
  888. {
  889. // Copy the username and password, and try again.
  890. CCred * pCCred = new CCred(*m_pCred);
  891. // clear the m_pCred object
  892. Clear_pCredObject();
  893. //
  894. // assign the m_pCred object to the copy and try
  895. // and rebind if the new CCred object is not null
  896. //
  897. m_pCred = pCCred;
  898. //
  899. // m_cRefAdded is this CWinNTCredentials object's contribution
  900. // to the refcount of m_pCred. Since we have a new CCred object,
  901. // set m_cRefAdded to 0.
  902. //
  903. m_cRefAdded = 0;
  904. if (m_pCred)
  905. hr = m_pCred->ref(pszServer);
  906. else
  907. hr = E_OUTOFMEMORY;
  908. }
  909. if (SUCCEEDED(hr))
  910. m_cRefAdded++;
  911. }
  912. RRETURN(hr);
  913. }
  914. //+---------------------------------------------------------------------------
  915. //
  916. // CWinNTCredentials::DeRefServer
  917. //
  918. // Call this only in special cases, when you know that the credentials
  919. // object is being passed around will have to RefServer/RefDomain
  920. // more than once as we are in the process of validating/finding
  921. // the object as opposed to actually creating the adsi object.
  922. // AjayR added on 6-24-98.
  923. //
  924. // Arguments:
  925. // [pszServer] - server to deref
  926. //
  927. //----------------------------------------------------------------------------
  928. HRESULT
  929. CWinNTCredentials::DeRefServer()
  930. {
  931. HRESULT hr = S_OK;
  932. if (m_pCred && m_cRefAdded)
  933. {
  934. hr = m_pCred->deref();
  935. m_cRefAdded--;
  936. }
  937. RRETURN(hr);
  938. }
  939. //+---------------------------------------------------------------------------
  940. //
  941. // CWinNTCredentials::RefDomain
  942. //
  943. // Increments the credentials object's reference count, and if necessary,
  944. // attempts to connect to the server's "ADMIN$" resource.
  945. //
  946. // Arguments:
  947. // [pszDomain] - domain to establish credentials with
  948. //
  949. //----------------------------------------------------------------------------
  950. HRESULT
  951. CWinNTCredentials::RefDomain(PWSTR pszDomain)
  952. {
  953. HRESULT hr = S_OK;
  954. // Don't take the hit of WinNTGetCachedDCName if we have null creds.
  955. if (m_pCred)
  956. {
  957. WCHAR szDCName[MAX_PATH];
  958. ADsAssert(pszDomain && *pszDomain);
  959. hr = WinNTGetCachedDCName(pszDomain, szDCName, m_dwFlags);
  960. if (SUCCEEDED(hr))
  961. // +2 for the initial "\\"
  962. hr = RefServer(szDCName + 2);
  963. }
  964. RRETURN(hr);
  965. }
  966. //+---------------------------------------------------------------------------
  967. //
  968. // CWinNTCredentials::DeRefDomain
  969. //
  970. // Call this only in special cases, when you know that the credentials
  971. // object is being passed around will have to RefServer/RefDomain
  972. // more than once as we are in the process of validating/finding
  973. // the object as opposed to actually creating the adsi object.
  974. // AjayR added on 6-24-98.
  975. //
  976. // Arguments:
  977. // [pszServer] - server to deref
  978. //
  979. //----------------------------------------------------------------------------
  980. HRESULT
  981. CWinNTCredentials::DeRefDomain()
  982. {
  983. HRESULT hr = S_OK;
  984. //
  985. // Call DeRefServer - since we just want to whack the ref
  986. //
  987. hr = DeRefServer();
  988. RRETURN(hr);
  989. }
  990. //+---------------------------------------------------------------------------
  991. //
  992. // CWinNTCredentials::Ref
  993. //
  994. // Increments the credentials object's reference count, and if necessary,
  995. // attempts to connect to the server's "ADMIN$" resource.
  996. //
  997. // This takes both a server and a domain; since several objects are created
  998. // with both server and domain as arguments (which one is used depends on
  999. // what the object's ADs parent is), this is a commonly used bit of code.
  1000. //
  1001. // Arguments:
  1002. // [pszServer] - server to bind to
  1003. // [pszDomain] - domain of the PDC to bind to
  1004. // [dwType] - WINNT_DOMAIN_ID or WINNT_COMPUTER_ID
  1005. //
  1006. // Returns:
  1007. // S_OK - if we bound to the server, or are already bound to
  1008. // the given server.
  1009. // E_FAIL - if this object is bound, and the specified server
  1010. // is not the same server as we are bound to.
  1011. // E_OUTOFMEMORY - if we run out of memory.
  1012. // Other error codes resulting from WNetAddConnection2 and from
  1013. // WinNTGetCachedDCName.
  1014. //
  1015. //----------------------------------------------------------------------------
  1016. HRESULT
  1017. CWinNTCredentials::Ref(PWSTR pszServer, PWSTR pszDomain, DWORD dwType)
  1018. {
  1019. HRESULT hr = S_OK;
  1020. ADsAssert(dwType == WINNT_DOMAIN_ID || dwType == WINNT_COMPUTER_ID);
  1021. // Don't take the hit of WinNTGetCachedDCName if we have null creds.
  1022. if (m_pCred)
  1023. {
  1024. if (dwType == WINNT_DOMAIN_ID)
  1025. hr = RefDomain(pszDomain);
  1026. else
  1027. hr = RefServer(pszServer);
  1028. }
  1029. RRETURN(hr);
  1030. }
  1031. //+---------------------------------------------------------------------------
  1032. //
  1033. // CWinNTCredentials::GetUserName
  1034. //
  1035. // Retrieves the username represented by this credentials object.
  1036. //
  1037. // Arguments:
  1038. // [ppszUserName] - address of a PWSTR to receive a
  1039. // pointer to the username.
  1040. // Returns:
  1041. // S_OK - on success
  1042. // E_OUTOFMEMORY - if we run out of memory.
  1043. //
  1044. //----------------------------------------------------------------------------
  1045. HRESULT
  1046. CWinNTCredentials::GetUserName(PWSTR *ppszUserName)
  1047. {
  1048. HRESULT hr;
  1049. if (!ppszUserName)
  1050. RRETURN(E_ADS_BAD_PARAMETER);
  1051. //
  1052. // Based on the rest of the codes, if UserName & Password are both "",
  1053. // no CCred is created & m_pCred = NULL. (See Constructor). Before we
  1054. // can hit CCred::GetUserName and get back *ppszUserName=NULL with hr =
  1055. // S_OK, we will have AV already. So need to check if m_pCred 1st.
  1056. //
  1057. if (m_pCred)
  1058. {
  1059. hr = m_pCred->GetUserName(ppszUserName);
  1060. }
  1061. else
  1062. {
  1063. *ppszUserName = NULL;
  1064. hr = S_OK;
  1065. }
  1066. RRETURN(hr);
  1067. }
  1068. //+---------------------------------------------------------------------------
  1069. //
  1070. // CWinNTCredentials::GetPassword
  1071. //
  1072. // Retrieves the password represented by this credentials object.
  1073. //
  1074. // Arguments:
  1075. // [ppszPassword] - address of a PWSTR to receive a
  1076. // pointer to the password.
  1077. // Returns:
  1078. // S_OK - on success
  1079. // E_OUTOFMEMORY - if we run out of memory.
  1080. //
  1081. //----------------------------------------------------------------------------
  1082. HRESULT
  1083. CWinNTCredentials::GetPassword(PWSTR * ppszPassword)
  1084. {
  1085. HRESULT hr;
  1086. if (!ppszPassword)
  1087. RRETURN(E_ADS_BAD_PARAMETER);
  1088. //
  1089. // Based on the rest of the codes, if UserName & Password are both "",
  1090. // no CCred is created & m_pCred = NULL. (See Constructor). Before we
  1091. // can hit CCred::GetUserName and get back *ppszPassword=NULL with hr =
  1092. // S_OK, we will have AV already. So need to check if m_pCred 1st.
  1093. //
  1094. if (m_pCred)
  1095. {
  1096. hr = m_pCred->GetPassword(ppszPassword);
  1097. }
  1098. else
  1099. {
  1100. *ppszPassword = NULL;
  1101. hr = S_OK;
  1102. }
  1103. RRETURN(hr);
  1104. }
  1105. //+---------------------------------------------------------------------------
  1106. //
  1107. // CWinNTCredentials::Bound
  1108. //
  1109. // Returns TRUE iff this object has a reference to a server.
  1110. //
  1111. //----------------------------------------------------------------------------
  1112. BOOL
  1113. CWinNTCredentials::Bound()
  1114. {
  1115. RRETURN(m_cRefAdded != 0);
  1116. }
  1117. void
  1118. CWinNTCredentials::SetFlags(DWORD dwFlags)
  1119. {
  1120. m_dwFlags = dwFlags;
  1121. }
  1122. DWORD
  1123. CWinNTCredentials::GetFlags() const
  1124. {
  1125. RRETURN(m_dwFlags);
  1126. }
  1127. void
  1128. CWinNTCredentials::SetUmiFlag(void)
  1129. {
  1130. m_dwFlags |= ADS_AUTH_RESERVED;
  1131. }
  1132. void
  1133. CWinNTCredentials::ResetUmiFlag(void)
  1134. {
  1135. m_dwFlags &= (~ADS_AUTH_RESERVED);
  1136. }