bool CWin32SMBDirectory::GetNetworkResources(const CURL& basePath, CFileItemList& items) { assert(basePath.GetShareName().empty()); // this function returns only servers or shares std::string hostName(basePath.GetHostName()); if (hostName.empty()) return localGetNetworkResources(NULL, basePath.Get(), items, false); // get all servers from network // get all shares from server std::string basePathStr(basePath.Get()); if (basePathStr.empty()) return false; if (basePathStr.back() != '/') basePathStr.push_back('/'); std::wstring remoteName; if (!basePathStr.empty() && !g_charsetConverter.utf8ToW("\\\\" + basePath.GetHostName(), remoteName, false, false, true)) { CLog::Log(LOGERROR, "%s: can't convert host name \"%s\" to wide character form", __FUNCTION__, basePath.GetHostName().c_str()); return false; } _NETRESOURCEW netResBasePath = {}; netResBasePath.dwScope = RESOURCE_GLOBALNET; netResBasePath.dwType = RESOURCETYPE_ANY; netResBasePath.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; netResBasePath.dwUsage = RESOURCEUSAGE_CONTAINER; netResBasePath.lpRemoteName = (LPWSTR)remoteName.c_str(); return localGetNetworkResources(&netResBasePath, basePathStr, items, true); }
bool CResourceFile::TranslatePath(const CURL &url, std::string &translatedPath) { translatedPath = url.Get(); // only handle resource:// paths if (!url.IsProtocol("resource")) return false; // the share name represents an identifier that can be mapped to an addon ID std::string addonId = url.GetShareName(); std::string filePath; if (url.GetFileName().length() > addonId.length()) filePath = url.GetFileName().substr(addonId.size() + 1); if (addonId.empty()) return false; AddonPtr addon; if (!CServiceBroker::GetAddonMgr().GetAddon(addonId, addon, ADDON_UNKNOWN, true) || addon == NULL) return false; std::shared_ptr<CResource> resource = std::dynamic_pointer_cast<ADDON::CResource>(addon); if (resource == NULL) return false; if (!resource->IsAllowed(filePath)) return false; translatedPath = CUtil::ValidatePath(resource->GetFullPath(filePath)); return true; }
// check for empty string, remove trailing slash if any, convert to win32 form inline static std::wstring prepareWin32SMBDirectoryName(const CURL& url) { assert(url.GetProtocol() == "smb"); if (url.GetHostName().empty() || url.GetShareName().empty()) return std::wstring(); // can't use win32 standard file API, return empty string std::wstring nameW(CWIN32Util::ConvertPathToWin32Form("\\\\?\\UNC\\" + url.GetHostName() + '\\' + url.GetFileName())); if (!nameW.empty() && nameW.back() == L'\\') nameW.pop_back(); // remove slash at the end if any return nameW; }
int CFileSMB::OpenFile(const CURL &url, CStdString& strAuth) { int fd = -1; smb.Init(); strAuth = GetAuthenticatedPath(url); CStdString strPath = strAuth; { CSingleLock lock(smb); fd = smbc_open(strPath.c_str(), O_RDONLY, 0); } // file open failed, try to open the directory to force authentication #ifndef _LINUX if (fd < 0 && smb.ConvertUnixToNT(errno) == NT_STATUS_ACCESS_DENIED) #else if (fd < 0 && errno == EACCES) #endif { CURL urlshare(url); /* just replace the filename with the sharename */ urlshare.SetFileName(url.GetShareName()); CSMBDirectory smbDir; // TODO: Currently we always allow prompting on files. This may need to // change in the future as background scanners are more prolific. smbDir.SetAllowPrompting(true); fd = smbDir.Open(urlshare); // directory open worked, try opening the file again if (fd >= 0) { CSingleLock lock(smb); // close current directory filehandle // dont need to purge since its the same server and share smbc_closedir(fd); // set up new filehandle (as CFileSMB::Open does) strPath = GetAuthenticatedPath(url); fd = smbc_open(strPath.c_str(), O_RDONLY, 0); } } if (fd >= 0) strAuth = strPath; return fd; }
CVFSURLWrapper(const CURL& url2) { m_strings.push_back(url2.Get()); m_strings.push_back(url2.GetDomain()); m_strings.push_back(url2.GetHostName()); m_strings.push_back(url2.GetFileName()); m_strings.push_back(url2.GetOptions()); m_strings.push_back(url2.GetUserName()); m_strings.push_back(url2.GetPassWord()); m_strings.push_back(url2.GetRedacted()); m_strings.push_back(url2.GetShareName()); url.url = m_strings[0].c_str(); url.domain = m_strings[1].c_str(); url.hostname = m_strings[2].c_str(); url.filename = m_strings[3].c_str(); url.port = url2.GetPort(); url.options = m_strings[4].c_str(); url.username = m_strings[5].c_str(); url.password = m_strings[6].c_str(); url.redacted = m_strings[7].c_str(); url.sharename = m_strings[8].c_str(); }
bool CWin32SMBDirectory::RealCreate(const CURL& url, bool tryToConnect) { assert(url.GetProtocol() == "smb"); if (url.GetHostName().empty() || url.GetShareName().empty() || url.GetFileName() == url.GetShareName()) return false; // can't create new hosts or shares std::wstring nameW(prepareWin32SMBDirectoryName(url)); if (nameW.empty()) return false; if (!CreateDirectoryW(nameW.c_str(), NULL)) { if (GetLastError() == ERROR_ALREADY_EXISTS) return RealExists(url, false); // is it file or directory? else { if (tryToConnect) { CURL authUrl(url); if (ConnectAndAuthenticate(authUrl)) return RealCreate(authUrl, false); } return false; } } // if directory name starts from dot, make it hidden const size_t lastSlashPos = nameW.rfind(L'\\'); if (lastSlashPos < nameW.length() - 1 && nameW[lastSlashPos + 1] == L'.') { DWORD dirAttrs = GetFileAttributesW(nameW.c_str()); if (dirAttrs == INVALID_FILE_ATTRIBUTES || !SetFileAttributesW(nameW.c_str(), dirAttrs | FILE_ATTRIBUTE_HIDDEN)) CLog::Log(LOGWARNING, "%s: Can't set hidden attribute for newly created directory \"%s\"", url.Get().c_str()); } return true; }
bool CWINSMBDirectory::ConnectToShare(const CURL& url) { NETRESOURCE nr; CURL urlIn(url); DWORD dwRet=-1; CStdString strUNC("\\\\"+url.GetHostName()); if(!url.GetShareName().empty()) strUNC.append("\\"+url.GetShareName()); CStdString strPath; memset(&nr,0,sizeof(nr)); nr.dwType = RESOURCETYPE_ANY; nr.lpRemoteName = (char*)strUNC.c_str(); // in general we shouldn't need the password manager as we won't disconnect from shares yet CPasswordManager::GetInstance().AuthenticateURL(urlIn); CStdString strAuth = URLEncode(urlIn); while(dwRet != NO_ERROR) { strPath = URLEncode(urlIn); LPCTSTR pUser = urlIn.GetUserNameA().empty() ? NULL : (LPCTSTR)urlIn.GetUserNameA().c_str(); LPCTSTR pPass = urlIn.GetPassWord().empty() ? NULL : (LPCTSTR)urlIn.GetPassWord().c_str(); dwRet = WNetAddConnection2(&nr, pPass, pUser, CONNECT_TEMPORARY); #ifdef _DEBUG CLog::Log(LOGDEBUG,"Trying to connect to %s with username(%s) and password(%s)", strUNC.c_str(), urlIn.GetUserNameA().c_str(), urlIn.GetPassWord().c_str()); #else CLog::Log(LOGDEBUG,"Trying to connect to %s with username(%s) and password(%s)", strUNC.c_str(), urlIn.GetUserNameA().c_str(), "XXXX"); #endif if(dwRet == ERROR_ACCESS_DENIED || dwRet == ERROR_INVALID_PASSWORD || dwRet == ERROR_LOGON_FAILURE) { CLog::Log(LOGERROR,"Couldn't connect to %s, access denied", strUNC.c_str()); if (m_flags & DIR_FLAG_ALLOW_PROMPT) RequireAuthentication(urlIn.Get()); break; } else if(dwRet == ERROR_SESSION_CREDENTIAL_CONFLICT) { DWORD dwRet2=-1; CStdString strRN = nr.lpRemoteName; do { dwRet2 = WNetCancelConnection2((LPCSTR)strRN.c_str(), 0, false); strRN.erase(strRN.find_last_of("\\"),CStdString::npos); } while(dwRet2 == ERROR_NOT_CONNECTED && !strRN.Equals("\\\\")); } else if(dwRet != NO_ERROR) { break; } } if(dwRet != NO_ERROR) { CLog::Log(LOGERROR,"Couldn't connect to %s, error code %d", strUNC.c_str(), dwRet); return false; } return true; }
CStdString CPasswordManager::GetLookupPath(const CURL &url) const { return "smb://" + url.GetHostName() + "/" + url.GetShareName(); }
bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items) { // We accept nfs://server/path[/file]]]] int ret = 0; FILETIME fileTime, localTime; CSingleLock lock(gNfsConnection); std::string strDirName=""; std::string myStrPath(url.Get()); URIUtils::AddSlashAtEnd(myStrPath); //be sure the dir ends with a slash if(!gNfsConnection.Connect(url,strDirName)) { //connect has failed - so try to get the exported filesystems if no path is given to the url if(url.GetShareName().empty()) { if(url.GetHostName().empty()) { return GetServerList(items); } else { return GetDirectoryFromExportList(myStrPath, items); } } else { return false; } } struct nfsdir *nfsdir = NULL; struct nfsdirent *nfsdirent = NULL; ret = gNfsConnection.GetImpl()->nfs_opendir(gNfsConnection.GetNfsContext(), strDirName.c_str(), &nfsdir); if(ret != 0) { CLog::Log(LOGERROR, "Failed to open(%s) %s\n", strDirName.c_str(), gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext())); return false; } lock.Leave(); while((nfsdirent = gNfsConnection.GetImpl()->nfs_readdir(gNfsConnection.GetNfsContext(), nfsdir)) != NULL) { struct nfsdirent tmpDirent = *nfsdirent; std::string strName = tmpDirent.name; std::string path(myStrPath + strName); int64_t iSize = 0; bool bIsDir = false; int64_t lTimeDate = 0; //reslove symlinks if(tmpDirent.type == NF3LNK) { CURL linkUrl; //resolve symlink changes tmpDirent and strName if(!ResolveSymlink(strDirName,&tmpDirent,linkUrl)) { continue; } path = linkUrl.Get(); } iSize = tmpDirent.size; bIsDir = tmpDirent.type == NF3DIR; lTimeDate = tmpDirent.mtime.tv_sec; if (!StringUtils::EqualsNoCase(strName,".") && !StringUtils::EqualsNoCase(strName,"..") && !StringUtils::EqualsNoCase(strName,"lost+found")) { if(lTimeDate == 0) // if modification date is missing, use create date { lTimeDate = tmpDirent.ctime.tv_sec; } long long ll = lTimeDate & 0xffffffff; ll *= 10000000ll; ll += 116444736000000000ll; fileTime.dwLowDateTime = (DWORD) (ll & 0xffffffff); fileTime.dwHighDateTime = (DWORD)(ll >> 32); FileTimeToLocalFileTime(&fileTime, &localTime); CFileItemPtr pItem(new CFileItem(tmpDirent.name)); pItem->m_dateTime=localTime; pItem->m_dwSize = iSize; if (bIsDir) { URIUtils::AddSlashAtEnd(path); pItem->m_bIsFolder = true; } else { pItem->m_bIsFolder = false; } if (strName[0] == '.') { pItem->SetProperty("file:hidden", true); } pItem->SetPath(path); items.Add(pItem); } } lock.Enter(); gNfsConnection.GetImpl()->nfs_closedir(gNfsConnection.GetNfsContext(), nfsdir);//close the dir lock.Leave(); return true; }
bool CWin32SMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) { assert(url.GetProtocol() == "smb"); items.Clear(); if (url.GetShareName().empty()) { // empty share name means that requested list of hosts or list of shares if (GetNetworkResources(url, items)) return true; // try to connect and authenticate CURL authConnUrl(url); if (!ConnectAndAuthenticate(authConnUrl, (m_flags & DIR_FLAG_ALLOW_PROMPT) != 0)) return false; items.Clear(); return GetNetworkResources(authConnUrl, items); } if (url.GetHostName().empty()) return false; // share name is set, but host name is empty /* Get file directory content by using standard win32 file API */ std::wstring searchMask(CWIN32Util::ConvertPathToWin32Form("\\\\?\\UNC\\" + url.GetHostName() + '\\' + url.GetFileName())); if (searchMask.empty()) return false; // TODO: support m_strFileMask, require rewrite of internal caching if (searchMask.back() == '\\') searchMask += L'*'; else searchMask += L"\\*"; HANDLE hSearch; WIN32_FIND_DATAW findData = {}; CURL authUrl(url); // ConnectAndAuthenticate may update url with username and password if (g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin7)) hSearch = FindFirstFileExW(searchMask.c_str(), FindExInfoBasic, &findData, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH); else hSearch = FindFirstFileExW(searchMask.c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, 0); if (hSearch == INVALID_HANDLE_VALUE) { DWORD searchErr = GetLastError(); if (ConnectAndAuthenticate(authUrl, (m_flags & DIR_FLAG_ALLOW_PROMPT) != 0)) { if (g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin7)) hSearch = FindFirstFileExW(searchMask.c_str(), FindExInfoBasic, &findData, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH); else hSearch = FindFirstFileExW(searchMask.c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, 0); searchErr = GetLastError(); } if (hSearch == INVALID_HANDLE_VALUE) { if (searchErr == ERROR_ACCESS_DENIED ||searchErr == ERROR_BAD_USERNAME || searchErr == ERROR_INVALID_PASSWORD || searchErr == ERROR_LOGON_FAILURE) { if ((m_flags & DIR_FLAG_ALLOW_PROMPT) != 0) RequireAuthentication(authUrl); return false; } return (searchErr == ERROR_FILE_NOT_FOUND) ? RealExists(url, false) : false; } } std::string pathWithSlash(authUrl.Get()); assert(!pathWithSlash.empty()); if (pathWithSlash.back() != '/') pathWithSlash.push_back('/'); do { std::wstring itemNameW(findData.cFileName); if (itemNameW == L"." || itemNameW == L".." || itemNameW.empty()) continue; std::string itemName; if (!g_charsetConverter.wToUTF8(itemNameW, itemName, true) || itemName.empty()) { CLog::Log(LOGERROR, "%s: Can't convert wide string item name to UTF-8", __FUNCTION__); continue; } CFileItemPtr pItem(new CFileItem(itemName)); pItem->m_bIsFolder = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); if (pItem->m_bIsFolder) pItem->SetPath(pathWithSlash + itemName + '/'); else pItem->SetPath(pathWithSlash + itemName); if ((findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0 || itemName.front() == '.') // mark files starting from dot as hidden pItem->SetProperty("file:hidden", true); // calculation of size and date costs a little on win32 // so DIR_FLAG_NO_FILE_INFO flag is ignored FILETIME localTime; if (FileTimeToLocalFileTime(&findData.ftLastWriteTime, &localTime) == TRUE) pItem->m_dateTime = localTime; else pItem->m_dateTime.SetValid(false); if (!pItem->m_bIsFolder) pItem->m_dwSize = (__int64(findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; items.Add(pItem); } while (FindNextFileW(hSearch, &findData)); FindClose(hSearch); return true; }
bool CWin32SMBDirectory::ConnectAndAuthenticate(CURL& url, bool allowPromptForCredential /*= false*/) { assert(url.GetProtocol() == "smb"); if (url.GetHostName().empty()) return false; // can't connect to empty host name if (url.GetUserName().empty() && url.GetPassWord().empty()) CPasswordManager::GetInstance().AuthenticateURL(url); // set username and password if any /* convert everything to wide strings */ std::wstring serverNameW; if (!g_charsetConverter.utf8ToW(url.GetHostName(), serverNameW, false, false, true)) { CLog::Log(LOGERROR, "%s: Can't convert server name \"%s\" to wide string", __FUNCTION__, url.GetHostName().c_str()); return false; } serverNameW = L"\\\\" + serverNameW; std::string serverShareName; // for error descriptions std::wstring serverShareNameW; if (!url.GetShareName().empty()) { serverShareName = "\\\\" + url.GetHostName() + "\\" + url.GetShareName(); if (!g_charsetConverter.utf8ToW(serverShareName, serverShareNameW, false, false, true)) { CLog::Log(LOGERROR, "%s: Can't convert share name \"%s\" to wide string", __FUNCTION__, serverShareName.c_str()); return false; } } else { serverShareName = "\\\\" + url.GetHostName(); serverShareNameW = serverNameW; } std::wstring usernameW; if (!url.GetUserName().empty() && !g_charsetConverter.utf8ToW(url.GetUserName(), usernameW, false, false, true)) { CLog::Log(LOGERROR, "%s: Can't convert username \"%s\" to wide string", __FUNCTION__, url.GetUserName().c_str()); return false; std::wstring domainW; if (!url.GetDomain().empty() && !g_charsetConverter.utf8ToW(url.GetDomain(), domainW, false, false, true)) { CLog::Log(LOGERROR, "%s: Can't convert domain name \"%s\" to wide string", __FUNCTION__, url.GetDomain().c_str()); return false; } if (!domainW.empty()) usernameW += L'@' + domainW; } std::wstring passwordW; if (!url.GetPassWord().empty() && !g_charsetConverter.utf8ToW(url.GetPassWord(), passwordW, false, false, true)) { CLog::Log(LOGERROR, "%s: Can't convert password to wide string", __FUNCTION__); return false; } std::string loginDescr; if (url.GetUserName().empty()) loginDescr = "without username"; else loginDescr = "with username \"" + url.GetUserName() + (url.GetDomain().empty() ? "" : "@" + url.GetDomain()) + "\""; loginDescr += url.GetPassWord().empty() ? " and without password" : " and with password"; NETRESOURCEW connInfo = {}; connInfo.dwType = RESOURCETYPE_ANY; connInfo.lpRemoteName = (LPWSTR)serverShareNameW.c_str(); DWORD connRes; for (int i = 0; i < 3; i++) // make up to three attempts to connect { connRes = WNetAddConnection2W(&connInfo, passwordW.empty() ? NULL : (LPWSTR)passwordW.c_str(), usernameW.empty() ? NULL : (LPWSTR)usernameW.c_str(), CONNECT_TEMPORARY); if (connRes == NO_ERROR) { CLog::Log(LOGDEBUG, "%s: Connected to \"%s\" %s", __FUNCTION__, serverShareName.c_str(), loginDescr.c_str()); return true; } if (connRes == ERROR_ACCESS_DENIED || connRes == ERROR_BAD_USERNAME || connRes == ERROR_INVALID_PASSWORD || connRes == ERROR_LOGON_FAILURE || connRes == ERROR_LOGON_TYPE_NOT_GRANTED || connRes == ERROR_LOGON_NOT_GRANTED) { if (connRes == ERROR_ACCESS_DENIED) CLog::Log(LOGERROR, "%s: Doesn't have permissions to access \"%s\" %s", __FUNCTION__, serverShareName.c_str(), loginDescr.c_str()); else CLog::Log(LOGERROR, "%s: Username/password combination was not accepted by \"%s\" when trying to connect %s", __FUNCTION__, serverShareName.c_str(), loginDescr.c_str()); if (allowPromptForCredential) RequireAuthentication(url); return false; // don't try any more } else if (connRes == ERROR_BAD_NET_NAME || connRes == ERROR_NO_NET_OR_BAD_PATH || connRes == ERROR_NO_NETWORK) { CLog::Log(LOGERROR, "%s: Can't find \"%s\"", __FUNCTION__, serverShareName.c_str()); return false; // don't try any more } else if (connRes == ERROR_BUSY) CLog::Log(LOGNOTICE, "%s: Network is busy for \"%s\"", __FUNCTION__, serverShareName.c_str()); else if (connRes == ERROR_SESSION_CREDENTIAL_CONFLICT) { CLog::Log(LOGWARNING, "%s: Can't connect to \"%s\" %s because of conflict of credential. Will try to close current connections.", __FUNCTION__, serverShareName.c_str(), loginDescr.c_str()); WNetCancelConnection2W((LPWSTR)serverShareNameW.c_str(), 0, FALSE); WNetCancelConnection2W((LPWSTR)(serverNameW + L"\\IPC$").c_str(), 0, FALSE); WNetCancelConnection2W((LPWSTR)serverNameW.c_str(), 0, FALSE); } } CLog::Log(LOGWARNING, "%s: Can't connect to \"%s\" %s. Error code: %lu", __FUNCTION__, serverShareName.c_str(), loginDescr.c_str(), (unsigned long)connRes); return false; }
// this functions can check for: // * presence of directory on remove share (smb://server/share/dir) // * presence of remote share on server (smb://server/share) // * presence of smb server in network (smb://server) bool CWin32SMBDirectory::RealExists(const CURL& url, bool tryToConnect) { assert(url.GetProtocol() == "smb"); if (url.GetHostName().empty()) return true; // 'root' of network is always exist // TODO: use real caseless string comparison everywhere in this function if (url.GetShareName().empty() || url.GetShareName() == url.GetFileName()) { if (!url.GetShareName().empty()) { std::wstring serverNameW; std::wstring shareNameW; SHARE_INFO_1* info = NULL; // try fast way if (g_charsetConverter.utf8ToW("\\\\" + url.GetHostName(), serverNameW, false, false, true) && g_charsetConverter.utf8ToW(url.GetShareName(), shareNameW, false, false, true) && NetShareGetInfo((LPWSTR)serverNameW.c_str(), (LPWSTR)shareNameW.c_str(), 1, (LPBYTE*)&info) == NERR_Success) { const bool ret = ((info->shi1_type & STYPE_MASK) == STYPE_DISKTREE); NetApiBufferFree(info); return ret; } // fallback to slow check } CFileItemList entries; CURL baseUrl(url); if (url.GetShareName().empty()) baseUrl.SetHostName(""); // scan network for servers else { baseUrl.Reset(); // hack to reset ShareName baseUrl.SetProtocol("smb"); baseUrl.SetHostName(url.GetHostName()); // scan server for shares } if (!GetNetworkResources(baseUrl, entries)) { if (tryToConnect && !url.GetShareName().empty()) { CURL authUrl(url); if (ConnectAndAuthenticate(authUrl)) return RealExists(authUrl, false); } return false; } const std::string& searchStr = (url.GetShareName().empty()) ? url.GetHostName() : url.GetShareName(); const VECFILEITEMS entrVec = entries.GetList(); for (VECFILEITEMS::const_iterator it = entrVec.begin(); it != entrVec.end(); ++it) { if ((*it)->GetLabel() == searchStr) return true; } return false; } // use standard win32 file API std::wstring nameW(prepareWin32SMBDirectoryName(url)); if (nameW.empty()) return false; DWORD fileAttrs = GetFileAttributesW(nameW.c_str()); if (fileAttrs != INVALID_FILE_ATTRIBUTES) return (fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0; // is file or directory? if (tryToConnect) { CURL authUrl(url); if (ConnectAndAuthenticate(authUrl)) return RealExists(authUrl, false); } return false; }
bool CWINSMBDirectory::ConnectToShare(const CURL& url) { NETRESOURCE nr; CURL urlIn(url); DWORD dwRet=-1; CStdString strUNC("\\\\"+url.GetHostName()); if(!url.GetShareName().empty()) strUNC.append("\\"+url.GetShareName()); CStdString strPath; memset(&nr,0,sizeof(nr)); nr.dwType = RESOURCETYPE_ANY; nr.dwScope = RESOURCE_GLOBALNET; nr.lpRemoteName = (char*)strUNC.c_str(); // in general we shouldn't need the password manager as we won't disconnect from shares yet IMAPPASSWORDS it = g_passwordManager.m_mapSMBPasswordCache.find(strUNC); if(it != g_passwordManager.m_mapSMBPasswordCache.end()) { // if share found in cache use it to supply username and password CURL murl(it->second); // map value contains the full url of the originally authenticated share. map key is just the share CStdString strPassword = murl.GetPassWord(); CStdString strUserName = murl.GetUserName(); urlIn.SetPassword(strPassword); urlIn.SetUserName(strUserName); } else if(urlIn.GetUserNameA().empty() && !g_guiSettings.GetString("smb.username").IsEmpty()) { urlIn.SetPassword(g_guiSettings.GetString("smb.password")); urlIn.SetUserName(g_guiSettings.GetString("smb.username")); } CStdString strAuth = URLEncode(urlIn); while(dwRet != NO_ERROR) { strPath = URLEncode(urlIn); LPCTSTR pUser = urlIn.GetUserNameA().empty() ? NULL : (LPCTSTR)urlIn.GetUserNameA().c_str(); LPCTSTR pPass = urlIn.GetPassWord().empty() ? NULL : (LPCTSTR)urlIn.GetPassWord().c_str(); dwRet = WNetAddConnection2(&nr, pPass, pUser, CONNECT_TEMPORARY); CLog::Log(LOGDEBUG,"Trying to connect to %s with username(%s) and password(%s)", strUNC.c_str(), urlIn.GetUserNameA().c_str(), urlIn.GetPassWord().c_str()); if(dwRet == ERROR_ACCESS_DENIED || dwRet == ERROR_INVALID_PASSWORD || dwRet == ERROR_LOGON_FAILURE) { CLog::Log(LOGERROR,"Couldn't connect to %s, access denied", strUNC.c_str()); if (m_allowPrompting) { g_passwordManager.SetSMBShare(strPath); if (!g_passwordManager.GetSMBShareUserPassword()) // Do this bit via a threadmessage? break; CURL urlnew( g_passwordManager.GetSMBShare() ); urlIn.SetUserName(urlnew.GetUserName()); urlIn.SetPassword(urlnew.GetPassWord()); } else break; } else if(dwRet == ERROR_SESSION_CREDENTIAL_CONFLICT) { DWORD dwRet2=-1; CStdString strRN = nr.lpRemoteName; do { dwRet2 = WNetCancelConnection2((LPCSTR)strRN.c_str(), 0, false); strRN.erase(strRN.find_last_of("\\"),CStdString::npos); } while(dwRet2 == ERROR_NOT_CONNECTED && !strRN.Equals("\\\\")); } else if(dwRet != NO_ERROR) { break; } } if(dwRet != NO_ERROR) { CLog::Log(LOGERROR,"Couldn't connect to %s, error code %d", strUNC.c_str(), dwRet); return false; } else if (strPath != strAuth && !strUNC.IsEmpty()) // we succeeded so, if path was changed, return the correct one and cache it { g_passwordManager.m_mapSMBPasswordCache[strUNC] = strPath; } return true; }