Example #1
0
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);
}
Example #2
0
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;
}
Example #3
0
// 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;
}
Example #4
0
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;
}
Example #5
0
    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();
    }
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
0
CStdString CPasswordManager::GetLookupPath(const CURL &url) const
{
  return "smb://" + url.GetHostName() + "/" + url.GetShareName();
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
0
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;
}
Example #12
0
// 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;
}
Example #13
0
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;
}