//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1994. // // File: shrinfo.cxx // // Contents: Lanman SHARE_INFO_502 encapsulation // // History: 21-Feb-95 BruceFo Created // //---------------------------------------------------------------------------- #include "headers.hxx" #pragma hdrstop #include "shrinfo.hxx" #include "util.hxx" CShareInfo::CShareInfo( VOID ) : m_bOwn(TRUE), m_flags(0), m_pInfo(NULL), m_dwCacheFlags (0), m_bCachingSupported (true) { INIT_SIG(CShareInfo); Close(); // doubly-linked list } CShareInfo::CShareInfo( IN SHARE_INFO_502* pInfo ) : m_bOwn(FALSE), m_flags(0), m_pInfo(pInfo), m_dwCacheFlags (0), m_bCachingSupported (true) { INIT_SIG(CShareInfo); Close(); // doubly-linked list } HRESULT CShareInfo::InitInstance( VOID ) { CHECK_SIG(CShareInfo); if (m_bOwn) { appAssert(m_pInfo == NULL); m_pInfo = new SHARE_INFO_502; if (NULL == m_pInfo) { return E_OUTOFMEMORY; } m_pInfo->shi502_netname = NULL; m_pInfo->shi502_type = STYPE_DISKTREE; m_pInfo->shi502_remark = NULL; // JonN-543153-2002/04/02 m_pInfo->shi502_permissions = ACCESS_READ | ACCESS_EXEC; // m_pInfo->shi502_permissions = ACCESS_ALL; m_pInfo->shi502_max_uses = SHI_USES_UNLIMITED; m_pInfo->shi502_path = NULL; m_pInfo->shi502_passwd = NULL; m_pInfo->shi502_reserved = 0; if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( c_szReadonlyShareSD, SDDL_REVISION_1, &m_pInfo->shi502_security_descriptor, NULL)) { // If we continued here and the user clicked Apply, the share // would be wide open (no security). return E_ACCESSDENIED; } } return S_OK; } CShareInfo::~CShareInfo() { CHECK_SIG(CShareInfo); if (m_bOwn) { if (NULL != m_pInfo) // must check; InitInstance might have failed { delete[] m_pInfo->shi502_netname; delete[] m_pInfo->shi502_remark; delete[] m_pInfo->shi502_path; delete[] m_pInfo->shi502_passwd; if (NULL != m_pInfo->shi502_security_descriptor) { ::LocalFree(m_pInfo->shi502_security_descriptor); m_pInfo->shi502_security_descriptor = NULL; } delete m_pInfo; } } } NET_API_STATUS CShareInfo::Commit( IN PWSTR pszMachine ) { CHECK_SIG(CShareInfo); appAssert(NULL != m_pInfo); if (NULL == m_pInfo) return E_POINTER; // 2002/03/21-JonN handle this case if (m_flags == 0) { // nothing changed appDebugOut((DEB_ITRACE, "CShareInfo::Commit: nothing (%ws)\n", m_pInfo->shi502_netname)); return NERR_Success; } // #if DBG == 1 // Dump(L"Commit"); // #endif // DBG == 1 NET_API_STATUS ret = NERR_Success; // JonN 05/30/00 PREFIX 114205 // Note: we store a path, even for admin$. However, the NetShare* APIs // don't like seeing a path for admin$, so we temporarily strip it here // if necessary, before calling any APIs. LPWSTR pszPathTmp = m_pInfo->shi502_path; if (0 == _wcsicmp(g_szAdminShare, m_pInfo->shi502_netname)) { m_pInfo->shi502_path = NULL; } if (SHARE_FLAG_ADDED == m_flags) { appDebugOut((DEB_TRACE, "CShareInfo::Commit: add (%ws)\n", m_pInfo->shi502_netname)); ret = NetShareAdd(pszMachine, 502, (LPBYTE)m_pInfo, NULL); if ( NERR_Success == ret ) ret = WriteCacheFlags (); } else if (SHARE_FLAG_REMOVE == m_flags) { appDebugOut((DEB_TRACE, "CShareInfo::Commit: remove (%ws)\n", m_pInfo->shi502_netname)); ret = NetShareDel(pszMachine, m_pInfo->shi502_netname, 0); if (NERR_NetNameNotFound == ret) { // Share didn't exist, but we are removing. No problem. ret = NERR_Success; } } else if (SHARE_FLAG_MODIFY == m_flags) { appDebugOut((DEB_TRACE, "CShareInfo::Commit: modify (%ws)\n", m_pInfo->shi502_netname)); DWORD parm_err; ret = NetShareSetInfo(pszMachine, m_pInfo->shi502_netname, 502, (LPBYTE)m_pInfo, &parm_err); if ( NERR_Success == ret ) ret = WriteCacheFlags (); } // Restore the original, in case of admin$ m_pInfo->shi502_path = pszPathTmp; // Must refresh the cache of shares after all commits if (ret != NERR_Success) { appDebugOut((DEB_TRACE, "CShareInfo::Commit: err = %d\n", ret)); } return ret; } SHARE_INFO_502* CShareInfo::GetShareInfo( VOID ) { CHECK_SIG(CShareInfo); appAssert(NULL != m_pInfo); return m_pInfo; } PWSTR CShareInfo::GetNetname( VOID ) { CHECK_SIG(CShareInfo); appAssert(NULL != m_pInfo); if ( m_pInfo ) return m_pInfo->shi502_netname; else return 0; } DWORD CShareInfo::GetType( VOID ) { CHECK_SIG(CShareInfo); appAssert(NULL != m_pInfo); if ( m_pInfo ) return m_pInfo->shi502_type; else return 0; } PWSTR CShareInfo::GetRemark( VOID ) { CHECK_SIG(CShareInfo); appAssert(NULL != m_pInfo); if ( m_pInfo ) return m_pInfo->shi502_remark; else return 0; } DWORD CShareInfo::GetMaxUses( VOID ) { CHECK_SIG(CShareInfo); appAssert(NULL != m_pInfo); if ( m_pInfo ) return m_pInfo->shi502_max_uses; else return 0; } PWSTR CShareInfo::GetPath( VOID ) { CHECK_SIG(CShareInfo); appAssert(NULL != m_pInfo); if ( m_pInfo ) return m_pInfo->shi502_path; else return 0; } PSECURITY_DESCRIPTOR CShareInfo::GetSecurityDescriptor( VOID ) { CHECK_SIG(CShareInfo); appAssert(NULL != m_pInfo); if ( m_pInfo ) return m_pInfo->shi502_security_descriptor; else return 0; } HRESULT CShareInfo::SetNetname( IN PWSTR pszNetname ) { CHECK_SIG(CShareInfo); appAssert(m_flags != SHARE_FLAG_REMOVE); appAssert(pszNetname && wcslen(pszNetname) <= NNLEN); if (!TakeOwn()) { return E_OUTOFMEMORY; } appDebugOut((DEB_ITRACE, "CShareInfo::SetNetname() = '%ws'\n", pszNetname)); delete[] m_pInfo->shi502_netname; m_pInfo->shi502_netname = NewDup(pszNetname); if (m_flags != SHARE_FLAG_ADDED) { m_flags = SHARE_FLAG_MODIFY; } return S_OK; } HRESULT CShareInfo::SetType( IN DWORD dwType ) { CHECK_SIG(CShareInfo); appAssert(m_flags != SHARE_FLAG_REMOVE); if (dwType != m_pInfo->shi502_type) { // only take ownership and set the data if it's changed! if (!TakeOwn()) { return E_OUTOFMEMORY; } appDebugOut((DEB_ITRACE, "CShareInfo::SetType(%ws) = %d\n", m_pInfo->shi502_netname, dwType)); m_pInfo->shi502_type = dwType; if (m_flags != SHARE_FLAG_ADDED) { m_flags = SHARE_FLAG_MODIFY; } } return S_OK; } HRESULT CShareInfo::SetRemark( IN PWSTR pszRemark ) { CHECK_SIG(CShareInfo); appAssert(m_flags != SHARE_FLAG_REMOVE); if (!TakeOwn()) { return E_OUTOFMEMORY; } appDebugOut((DEB_ITRACE, "CShareInfo::SetRemark(%ws) = '%ws'\n", m_pInfo->shi502_netname, pszRemark)); delete[] m_pInfo->shi502_remark; m_pInfo->shi502_remark = NewDup(pszRemark); if (m_flags != SHARE_FLAG_ADDED) { m_flags = SHARE_FLAG_MODIFY; } return S_OK; } HRESULT CShareInfo::SetMaxUses( IN DWORD dwMaxUses ) { CHECK_SIG(CShareInfo); appAssert(m_flags != SHARE_FLAG_REMOVE); if (dwMaxUses != m_pInfo->shi502_max_uses) { // only take ownership and set the data if it's changed! if (!TakeOwn()) { return E_OUTOFMEMORY; } appDebugOut((DEB_ITRACE, "CShareInfo::SetMaxUses(%ws) = %d\n", m_pInfo->shi502_netname, dwMaxUses)); m_pInfo->shi502_max_uses = dwMaxUses; if (m_flags != SHARE_FLAG_ADDED) { m_flags = SHARE_FLAG_MODIFY; } } return S_OK; } HRESULT CShareInfo::SetPath( IN PWSTR pszPath ) { CHECK_SIG(CShareInfo); appAssert(m_flags != SHARE_FLAG_REMOVE); if (!TakeOwn()) { return E_OUTOFMEMORY; } appDebugOut((DEB_ITRACE, "CShareInfo::SetPath(%ws) = '%ws'\n", m_pInfo->shi502_netname, pszPath)); delete[] m_pInfo->shi502_path; if (pszPath[0] == TEXT('\0')) { m_pInfo->shi502_path = NULL; // so IPC$ and ADMIN$ work } else { m_pInfo->shi502_path = NewDup(pszPath); } if (m_flags != SHARE_FLAG_ADDED) { m_flags = SHARE_FLAG_MODIFY; } return S_OK; } HRESULT CShareInfo::SetSecurityDescriptor( IN PSECURITY_DESCRIPTOR pSecDesc ) { CHECK_SIG(CShareInfo); appAssert(m_flags != SHARE_FLAG_REMOVE); if (!TakeOwn()) { return E_OUTOFMEMORY; } appDebugOut((DEB_ITRACE, "CShareInfo::SetSecurityDescriptor(%ws) = ...\n", m_pInfo->shi502_netname)); PSECURITY_DESCRIPTOR pSDNew; HRESULT hr = CopySecurityDescriptor(pSecDesc, &pSDNew); if (SUCCEEDED(hr)) { if (NULL != m_pInfo->shi502_security_descriptor) ::LocalFree(m_pInfo->shi502_security_descriptor); m_pInfo->shi502_security_descriptor = pSDNew; if (m_flags != SHARE_FLAG_ADDED) { m_flags = SHARE_FLAG_MODIFY; } } return hr; } // security descriptors alloced via ::LocalAlloc HRESULT CShareInfo::TransferSecurityDescriptor( IN PSECURITY_DESCRIPTOR pSecDesc ) { CHECK_SIG(CShareInfo); appAssert(m_flags != SHARE_FLAG_REMOVE); if (!TakeOwn()) { return E_OUTOFMEMORY; } appDebugOut((DEB_ITRACE, "CShareInfo::TransferSecurityDescriptor(%ws) = ...\n", m_pInfo->shi502_netname)); if (NULL != m_pInfo->shi502_security_descriptor) ::LocalFree(m_pInfo->shi502_security_descriptor); m_pInfo->shi502_security_descriptor = pSecDesc; if (m_flags != SHARE_FLAG_ADDED) { m_flags = SHARE_FLAG_MODIFY; } return S_OK; } ULONG CShareInfo::GetFlag( VOID ) { CHECK_SIG(CShareInfo); return m_flags; } VOID CShareInfo::SetDirtyFlag( ULONG flag ) { CHECK_SIG(CShareInfo); m_flags = flag; } HRESULT CShareInfo::Copy( IN SHARE_INFO_502* pInfo ) { CHECK_SIG(CShareInfo); // get a valid SHARE_INFO_502 structure... if (m_bOwn) { // delete what's already there appAssert(NULL != m_pInfo); delete[] m_pInfo->shi502_netname; delete[] m_pInfo->shi502_remark; delete[] m_pInfo->shi502_path; delete[] m_pInfo->shi502_passwd; if (NULL != m_pInfo->shi502_security_descriptor) { ::LocalFree(m_pInfo->shi502_security_descriptor); m_pInfo->shi502_security_descriptor = NULL; } } else { m_pInfo = new SHARE_INFO_502; if (NULL == m_pInfo) { return E_OUTOFMEMORY; } } appAssert(NULL != m_pInfo); m_bOwn = TRUE; m_pInfo->shi502_netname = NULL; m_pInfo->shi502_type = pInfo->shi502_type; m_pInfo->shi502_remark = NULL; m_pInfo->shi502_permissions = pInfo->shi502_permissions; m_pInfo->shi502_max_uses = pInfo->shi502_max_uses; m_pInfo->shi502_path = NULL; m_pInfo->shi502_passwd = NULL; m_pInfo->shi502_reserved = pInfo->shi502_reserved; m_pInfo->shi502_security_descriptor = NULL; if (NULL != pInfo->shi502_netname) { m_pInfo->shi502_netname = NewDup(pInfo->shi502_netname); } if (NULL != pInfo->shi502_remark) { m_pInfo->shi502_remark = NewDup(pInfo->shi502_remark); } if (NULL != pInfo->shi502_path) { m_pInfo->shi502_path = NewDup(pInfo->shi502_path); } if (NULL != pInfo->shi502_passwd) { m_pInfo->shi502_passwd = NewDup(pInfo->shi502_passwd); } if (NULL != pInfo->shi502_security_descriptor) { CopySecurityDescriptor(pInfo->shi502_security_descriptor, &m_pInfo->shi502_security_descriptor); } return S_OK; } BOOL CShareInfo::TakeOwn( VOID ) { CHECK_SIG(CShareInfo); if (m_pInfo == NULL) return FALSE; if (m_bOwn) { return TRUE; // already own the memory } SHARE_INFO_502* pInfo = new SHARE_INFO_502; if (NULL == pInfo) { return FALSE; } pInfo->shi502_type = m_pInfo->shi502_type; pInfo->shi502_permissions = m_pInfo->shi502_permissions; pInfo->shi502_max_uses = m_pInfo->shi502_max_uses; pInfo->shi502_reserved = 0; pInfo->shi502_netname = NULL; if (NULL != m_pInfo->shi502_netname) { pInfo->shi502_netname = NewDup(m_pInfo->shi502_netname); } pInfo->shi502_remark = NULL; if (NULL != m_pInfo->shi502_remark) { pInfo->shi502_remark = NewDup(m_pInfo->shi502_remark); } pInfo->shi502_path = NULL; if (NULL != m_pInfo->shi502_path) { pInfo->shi502_path = NewDup(m_pInfo->shi502_path); } pInfo->shi502_passwd = NULL; if (NULL != m_pInfo->shi502_passwd) { pInfo->shi502_passwd = NewDup(m_pInfo->shi502_passwd); } pInfo->shi502_security_descriptor = NULL; if (NULL != m_pInfo->shi502_security_descriptor) { CopySecurityDescriptor(m_pInfo->shi502_security_descriptor, &pInfo->shi502_security_descriptor); } m_pInfo = pInfo; m_bOwn = TRUE; #if DBG == 1 Dump(L"After TakeOwn"); #endif // DBG == 1 return TRUE; } VOID DeleteShareInfoList( IN CShareInfo* pShareInfoList, IN BOOL fDeleteDummyHeadNode ) { if (NULL == pShareInfoList) { // allow "deletion" of NULL list return; } for (CShareInfo* p = (CShareInfo*) pShareInfoList->Next(); p != pShareInfoList; ) { CShareInfo* pNext = (CShareInfo*)p->Next(); delete p; p = pNext; } if (fDeleteDummyHeadNode) { delete pShareInfoList; } else { pShareInfoList->Close(); // reset pointers } } #if DBG == 1 VOID CShareInfo::Dump( IN PWSTR pszCaption ) { CHECK_SIG(CShareInfo); appDebugOut((DEB_TRACE, "CShareInfo::Dump, %ws\n", pszCaption)); appDebugOut((DEB_TRACE | DEB_NOCOMPNAME, "\t This: 0x%08lx\n" "\t Info: 0x%08lx\n" "\tOwn memory?: %ws\n" "\t Flags: %ws\n" "\t Share name: %ws\n" "\t Type: %d\n" "\t Comment: %ws\n" "\tPermissions: %d\n" "\t Max uses: %d\n" "\t Path: %ws\n" "\t Password: %ws\n" "\t Reserved: %d\n" "\t Security? %ws\n" , this, m_pInfo, m_bOwn ? L"yes" : L"no", (m_flags == 0) ? L"none" : (m_flags == SHARE_FLAG_ADDED) ? L"added" : (m_flags == SHARE_FLAG_REMOVE) ? L"remove" : (m_flags == SHARE_FLAG_MODIFY) ? L"modify" : L"UNKNOWN!", (NULL == m_pInfo->shi502_netname) ? L"none" : m_pInfo->shi502_netname, m_pInfo->shi502_type, (NULL == m_pInfo->shi502_remark) ? L"none" : m_pInfo->shi502_remark, m_pInfo->shi502_permissions, m_pInfo->shi502_max_uses, (NULL == m_pInfo->shi502_path) ? L"none" : m_pInfo->shi502_path, (NULL == m_pInfo->shi502_passwd) ? L"none" : m_pInfo->shi502_passwd, m_pInfo->shi502_reserved, (NULL == m_pInfo->shi502_security_descriptor) ? L"No" : L"Yes" )); } #endif // DBG == 1 DWORD CShareInfo::GetCacheFlags( VOID ) const { CHECK_SIG(CShareInfo); return m_dwCacheFlags; } void CShareInfo::SetCacheFlags( DWORD dwFlags ) { CHECK_SIG(CShareInfo); m_dwCacheFlags = dwFlags; if ( SHARE_FLAG_ADDED != m_flags ) m_flags = SHARE_FLAG_MODIFY; } // // These methods cover the separate API to determine whether IntelliMirror // caching is enabled. By default (FPNW and SFM) they are disabled. // // We read this data at level 501 in order to determine whether the target // server is NT4. NetShareGetInfo[1005] actually succeeds on an NT4 server, // whereas NetShareGetInfo[501] fails with ERROR_INVALID_LEVEL. We want this // to fail so that we can disable the checkbox where the underlying // functionality is not supported. // // CODEWORK: If this becomes remotable, we'll need to do a better job of // handling the error case when this method fails. // NET_API_STATUS CShareInfo::ReadCacheFlags( VOID ) { CHECK_SIG(CShareInfo); NET_API_STATUS retval = NERR_Success; m_dwCacheFlags = 0; if ( m_bCachingSupported ) // If we've already determined that caching is // not supported, don't call this again { SHARE_INFO_501* pshi501 = NULL; PWSTR pwszNetName = GetNetname (); if ( pwszNetName && *pwszNetName ) { retval = ::NetShareGetInfo( L"", // machine name pwszNetName, // share name 501, (LPBYTE*)&pshi501); if (NERR_Success == retval) { if ( pshi501 ) { m_dwCacheFlags = pshi501->shi501_flags; ::NetApiBufferFree (pshi501); } } else if ( ERROR_INVALID_LEVEL == retval ) { // This share is probably on an NT 4.0 machine and does not // support caching m_bCachingSupported = false; retval = NERR_Success; } else if ( NERR_Success != retval ) m_bCachingSupported = false; } } return retval; } NET_API_STATUS CShareInfo::WriteCacheFlags( VOID ) { CHECK_SIG(CShareInfo); NET_API_STATUS retval = NERR_Success; if ( m_bCachingSupported ) // If we've already determined that caching is // not supported, don't call this again { SHARE_INFO_1005 shi1005; ZeroMemory( &shi1005, sizeof(shi1005) ); shi1005.shi1005_flags = m_dwCacheFlags; DWORD dwDummy = 0; retval = ::NetShareSetInfo( L"", // machine name GetNetname (), // share name 1005, (LPBYTE)&shi1005, &dwDummy); if ( ERROR_INVALID_LEVEL == retval ) { // This share is probably on an NT 4.0 machine and does not support // caching m_bCachingSupported = false; retval = NERR_Success; } else if ( NERR_Success != retval ) m_bCachingSupported = false; } return retval; }