home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 217 / DPCS0306DVD.ISO / Toolkit / Internet / FileZilla / Server / FileZilla_Server-0.9.11.exe / source / Permissions.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-11-01  |  64.1 KB  |  2,456 lines

  1. // FileZilla Server - a Windows ftp server
  2.  
  3. // Copyright (C) 2002-2004 - Tim Kosse <tim.kosse@gmx.de>
  4.  
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9.  
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14.  
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. // Permissions.cpp: Implementierung der Klasse CPermissions.
  20. //
  21. //////////////////////////////////////////////////////////////////////
  22.  
  23. #include "stdafx.h"
  24. #include "misc\md5.h"
  25. #include "Permissions.h"
  26. #include "misc\MarkupSTL.h"
  27. #include "options.h"
  28. #include "iputils.h"
  29.  
  30. #ifdef _DEBUG
  31. #undef THIS_FILE
  32. static char THIS_FILE[]=__FILE__;
  33. #endif
  34.  
  35. /////////////////////////////////////////////////////////////////////////////
  36. // CPermissionsHelperWindow
  37.  
  38. class CPermissionsHelperWindow
  39. {
  40. public:
  41.     CPermissionsHelperWindow(CPermissions *pPermissions)
  42.     {
  43.         ASSERT(pPermissions);
  44.         m_pPermissions = pPermissions;
  45.  
  46.         //Create window
  47.         WNDCLASSEX wndclass;
  48.         wndclass.cbSize = sizeof wndclass;
  49.         wndclass.style = 0;
  50.         wndclass.lpfnWndProc = WindowProc;
  51.         wndclass.cbClsExtra = 0;
  52.         wndclass.cbWndExtra = 0;
  53.         wndclass.hInstance = GetModuleHandle(0);
  54.         wndclass.hIcon = 0;
  55.         wndclass.hCursor = 0;
  56.         wndclass.hbrBackground = 0;
  57.         wndclass.lpszMenuName = 0;
  58.         wndclass.lpszClassName = _T("CPermissions Helper Window");
  59.         wndclass.hIconSm = 0;
  60.  
  61.         RegisterClassEx(&wndclass);
  62.  
  63.         m_hWnd=CreateWindow(_T("CPermissions Helper Window"), _T("CPermissions Helper Window"), 0, 0, 0, 0, 0, 0, 0, 0, GetModuleHandle(0));
  64.         ASSERT(m_hWnd);
  65.         SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG)this);
  66.     };
  67.  
  68.     virtual ~CPermissionsHelperWindow()
  69.     {
  70.         //Destroy window
  71.         if (m_hWnd)
  72.         {
  73.             DestroyWindow(m_hWnd);
  74.             m_hWnd = 0;
  75.         }
  76.     }
  77.  
  78.     HWND GetHwnd()
  79.     {
  80.         return m_hWnd;
  81.     }
  82.  
  83. protected:
  84.     static LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  85.     {
  86.         if (message==WM_USER)
  87.         {
  88.             /* If receiving WM_USER, update the permission data of the instance with the permission
  89.              * data from the global data
  90.              */
  91.  
  92.             // Get own instance
  93.             CPermissionsHelperWindow *pWnd=(CPermissionsHelperWindow *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  94.             if (!pWnd)
  95.                 return 0;
  96.             if (!pWnd->m_pPermissions)
  97.                 return 0;
  98.     
  99.             EnterCritSection(pWnd->m_pPermissions->m_sync);
  100.     
  101.             // Clear old group data and copy over the new data
  102.             pWnd->m_pPermissions->m_GroupsList.clear();
  103.             for (CPermissions::t_GroupsList::iterator groupiter=pWnd->m_pPermissions->m_sGroupsList.begin(); groupiter!=pWnd->m_pPermissions->m_sGroupsList.end(); groupiter++)
  104.                 pWnd->m_pPermissions->m_GroupsList.push_back(*groupiter);
  105.     
  106.             // Clear old user data and copy over the new data
  107.             pWnd->m_pPermissions->m_UsersList.clear();
  108.             for (CPermissions::t_UsersList::iterator iter=pWnd->m_pPermissions->m_sUsersList.begin(); iter!=pWnd->m_pPermissions->m_sUsersList.end(); iter++)
  109.             {
  110.                 CUser user = *iter;
  111.                 user.pOwner = NULL;
  112.                 if (user.group != _T(""))
  113.                 {    // Set owner
  114.                     for (CPermissions::t_GroupsList::iterator groupiter=pWnd->m_pPermissions->m_GroupsList.begin(); groupiter!=pWnd->m_pPermissions->m_GroupsList.end(); groupiter++)
  115.                         if (groupiter->group == user.group)
  116.                         {
  117.                             user.pOwner = &(*groupiter);
  118.                             break;
  119.                         }
  120.                 }
  121.                 pWnd->m_pPermissions->m_UsersList.push_back(user);
  122.             }
  123.     
  124.             LeaveCritSection(pWnd->m_pPermissions->m_sync);
  125.         }
  126.         return ::DefWindowProc(hWnd, message, wParam, lParam);
  127.     }
  128.  
  129. protected:
  130.     CPermissions *m_pPermissions;
  131.  
  132. private:
  133.     HWND m_hWnd;
  134. };
  135.  
  136. /////////////////////////////////////////////////////////////////////////////
  137. // CPermissions
  138.  
  139. CCriticalSectionWrapper CPermissions::m_sync;
  140. CPermissions::t_UsersList CPermissions::m_sUsersList;
  141. CPermissions::t_GroupsList CPermissions::m_sGroupsList;
  142. std::list<CPermissions *> CPermissions::m_sInstanceList;
  143.  
  144. //////////////////////////////////////////////////////////////////////
  145. // Konstruktion/Destruktion
  146. //////////////////////////////////////////////////////////////////////
  147.  
  148. CPermissions::CPermissions()
  149. {
  150.     Init();
  151.  
  152.     m_pPermissionsHelperWindow = new CPermissionsHelperWindow(this);
  153. }
  154.  
  155. CPermissions::~CPermissions()
  156. {
  157.     EnterCritSection(m_sync);
  158.     std::list<CPermissions *>::iterator instanceIter;
  159.     for (instanceIter=m_sInstanceList.begin(); instanceIter!=m_sInstanceList.end(); instanceIter++)
  160.         if (*instanceIter==this)
  161.             break;
  162.     ASSERT(instanceIter!=m_sInstanceList.end());
  163.     m_sInstanceList.erase(instanceIter);
  164.     LeaveCritSection(m_sync);
  165.     if (m_pPermissionsHelperWindow)
  166.         delete m_pPermissionsHelperWindow;
  167. }
  168.  
  169. void CPermissions::AddListingEntry(t_dirlisting *&pDir, CStdString name, bool dir, _int64 size, FILETIME *pTime, const t_directory &perms)
  170. {
  171.     // This wastes some memory but keeps the whole thing fast
  172.     if ((8192 - pDir->len) < (60 + 2 * MAX_PATH))
  173.     {
  174.         pDir->pNext = new t_dirlisting;
  175.         pDir = pDir->pNext;
  176.         pDir->len = 0;
  177.         pDir->pNext = NULL;
  178.     }
  179.  
  180.     if (dir)
  181.     {
  182.         memcpy(pDir->buffer + pDir->len, "drwxr-xr-x", 10);
  183.         pDir->len += 10;
  184.     }
  185.     else
  186.     {
  187.         pDir->buffer[pDir->len++] = '-';
  188.         pDir->buffer[pDir->len++] = perms.bFileRead ? 'r' : '-';
  189.         pDir->buffer[pDir->len++] = perms.bFileWrite ? 'w' : '-';
  190.  
  191.         BOOL isexe = FALSE;
  192.         CStdString ext = name.Right(4);
  193.         ext.MakeLower();
  194.         if (ext.ReverseFind('.')!=-1)
  195.         {
  196.             if (ext == ".exe")
  197.                 isexe = TRUE;
  198.             else if (ext == ".bat")
  199.                 isexe = TRUE;
  200.             else if (ext == ".com")
  201.                 isexe = TRUE;
  202.         }
  203.         pDir->buffer[pDir->len++] = isexe ? 'x' : '-';
  204.         pDir->buffer[pDir->len++] = perms.bFileRead ? 'r' : '-';
  205.         pDir->buffer[pDir->len++] = '-';
  206.         pDir->buffer[pDir->len++] = isexe ? 'x' : '-';
  207.         pDir->buffer[pDir->len++] = perms.bFileRead ? 'r' : '-';
  208.         pDir->buffer[pDir->len++] = '-';
  209.         pDir->buffer[pDir->len++] = isexe ? 'x' : '-';
  210.     }
  211.  
  212.     memcpy(pDir->buffer + pDir->len, " 1 ftp ftp ", 11);
  213.     pDir->len += 11;
  214.  
  215.     pDir->len += sprintf(pDir->buffer + pDir->len, "% 14I64d", size);
  216.  
  217.     // Adjust time zone info and output file date/time
  218.     SYSTEMTIME sLocalTime;
  219.     GetLocalTime(&sLocalTime);
  220.     FILETIME fTime;
  221.     VERIFY(SystemTimeToFileTime(&sLocalTime, &fTime));
  222.  
  223.     FILETIME mtime;
  224.     if (pTime)
  225.         mtime = *pTime;
  226.     else
  227.         mtime = fTime;
  228.  
  229.     TIME_ZONE_INFORMATION tzInfo;
  230.     int tzRes = GetTimeZoneInformation(&tzInfo);
  231.     _int64 offset = tzInfo.Bias+((tzRes==TIME_ZONE_ID_DAYLIGHT)?tzInfo.DaylightBias:tzInfo.StandardBias);
  232.     offset *= 60 * 10000000;
  233.  
  234.     _int64 t1 = ((_int64)mtime.dwHighDateTime<<32) + mtime.dwLowDateTime;
  235.     t1 -= offset;
  236.     mtime.dwHighDateTime = (DWORD)(t1>>32);
  237.     mtime.dwLowDateTime = (DWORD)(t1%0xFFFFFFFF);
  238.  
  239.     SYSTEMTIME sFileTime;
  240.     FileTimeToSystemTime(&mtime, &sFileTime);
  241.  
  242.     _int64 t2 = ((_int64)fTime.dwHighDateTime<<32) + fTime.dwLowDateTime;
  243.     const char months[][4]={"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  244.     pDir->len += sprintf(pDir->buffer + pDir->len, " %s %02d ", months[sFileTime.wMonth-1], sFileTime.wDay);
  245.     if (t1 > t2 || (t2-t1) > ((_int64)1000000*60*60*24*350))
  246.         pDir->len += sprintf(pDir->buffer + pDir->len, " %d ", sFileTime.wYear);
  247.     else
  248.         pDir->len += sprintf(pDir->buffer + pDir->len, "%02d:%02d ", sFileTime.wHour, sFileTime.wMinute);
  249.  
  250.     int len = name.GetLength();
  251.     memcpy(pDir->buffer + pDir->len, name.c_str(), len);
  252.     pDir->len += len;
  253.     pDir->buffer[pDir->len++] = '\r';
  254.     pDir->buffer[pDir->len++] = '\n';
  255. }
  256.  
  257. int CPermissions::GetDirectoryListing(LPCTSTR username, CStdString currentDir, CStdString dirToDisplay, t_dirlisting *&pResult, CStdString& physicalDir, CStdString& logicalDir)
  258. {
  259.     // Get user
  260.     CUser user;
  261.     if (!GetUser(username, user))
  262.         return PERMISSION_DENIED;
  263.  
  264.     CStdString dir = CanonifyServerDir(currentDir, dirToDisplay);
  265.     if (dir == "")
  266.         return PERMISSION_INVALIDNAME;
  267.     logicalDir = dir;
  268.  
  269.     // Get directory from directory name
  270.     t_directory directory;
  271.     BOOL bTruematch;
  272.     int res = GetRealDirectory(dir, user, directory, bTruematch);
  273.     CStdString sFileSpec = "*"; // Which files to list in the directory
  274.     if (res == PERMISSION_FILENOTDIR || res == PERMISSION_NOTFOUND) // Try listing using a direct wildcard filespec instead?
  275.     {
  276.         // Check dirToDisplay if we are allowed to go back a directory
  277.         dirToDisplay.Replace('\\', '/');
  278.         while (dirToDisplay.Replace("//", "/"));
  279.         if (dirToDisplay.Right(1) == "/")
  280.             return res;
  281.         int pos = dirToDisplay.ReverseFind('/');
  282.         if (res != PERMISSION_FILENOTDIR && dirToDisplay.Mid(pos + 1).Find('*') == -1)
  283.             return res;
  284.         dirToDisplay = dirToDisplay.Left(pos + 1);
  285.  
  286.         if (dir == "/")
  287.             return res;
  288.         
  289.         pos = dir.ReverseFind('/');
  290.         sFileSpec = dir.Mid(pos + 1);
  291.         if (pos)
  292.             dir = dir.Left(pos);
  293.         else
  294.             dir = "/";
  295.  
  296.  
  297.         if (sFileSpec.Find("*") == -1 && res != PERMISSION_FILENOTDIR)
  298.             return res;
  299.  
  300.         res = GetRealDirectory(dir, user, directory, bTruematch);
  301.     }
  302.     if (res)
  303.         return res;
  304.  
  305.     // Check permissions
  306.     if (!directory.bDirList)
  307.         return PERMISSION_DENIED;
  308.  
  309.     WIN32_FIND_DATA FindFileData;
  310.     WIN32_FIND_DATA NextFindFileData;
  311.     HANDLE hFind;
  312.     TIME_ZONE_INFORMATION tzInfo;
  313.     int tzRes = GetTimeZoneInformation(&tzInfo);
  314.     _int64 offset = tzInfo.Bias+((tzRes==TIME_ZONE_ID_DAYLIGHT)?tzInfo.DaylightBias:tzInfo.StandardBias);
  315.     offset *= 60 * 10000000;
  316.  
  317.     t_dirlisting *pDir = new t_dirlisting;
  318.     pDir->len = 0;
  319.     pDir->pNext = NULL;
  320.     pResult = pDir;
  321.  
  322.     CStdString curDir = directory.dir;
  323.     curDir.MakeLower();
  324.         
  325.     // List aliases in current directory
  326.     for (std::multimap<CStdString, CUser::t_alias>::const_iterator iter = user.aliasMap.find(curDir);
  327.          iter != user.aliasMap.end() && iter->first == curDir; iter++)
  328.     {
  329.         t_directory directory;
  330.         BOOL truematch = false;
  331.         if (GetRealDirectory(dir + "/" + iter->second.name, user, directory, truematch))
  332.             continue;
  333.         if (!directory.bDirList)
  334.             continue;
  335.         if (!truematch && !directory.bDirSubdirs)
  336.             continue;
  337.  
  338.         if (sFileSpec != "*.*" && sFileSpec != "*")
  339.         {
  340.             // Do a really primitive wildcard check, does even ignore ?
  341.             CStdString name = iter->second.name;
  342.             CStdString spec = sFileSpec;
  343.             name.MakeLower();
  344.             spec.MakeLower();
  345.  
  346.             bool match = true;
  347.             while (spec != "")
  348.             {
  349.                 int pos = spec.Find('*');
  350.                 if (pos == -1)
  351.                 {
  352.                     if (spec != name)
  353.                     {
  354.                         match = false;
  355.                         break;
  356.                     }
  357.                     break;
  358.                 }
  359.                 else if (!pos)
  360.                 {
  361.                     spec = spec.Mid(1);
  362.                 }
  363.                 else
  364.                 {
  365.                     int npos = name.Find(spec.Left(pos));
  366.                     if (npos == -1)
  367.                     {
  368.                         match = false;
  369.                         break;
  370.                     }
  371.                     spec = spec.Mid(pos + 1);
  372.                     name = name.Mid(npos + 1);
  373.                 }
  374.             }
  375.             if (!match)
  376.                 continue;
  377.         }
  378.         CFileStatus64 status;
  379.         if (GetStatus64(directory.dir, status))
  380.             AddListingEntry(pDir, iter->second.name, true, status.m_size, &status.m_mtime, directory);
  381.         else
  382.             AddListingEntry(pDir, iter->second.name, true, 0, 0, directory);
  383.     }
  384.  
  385.     physicalDir = directory.dir;
  386.     if (sFileSpec != "*" && sFileSpec != "*.*")
  387.         physicalDir += sFileSpec;
  388.  
  389.     hFind = FindFirstFile(directory.dir + "\\" + sFileSpec, &NextFindFileData);
  390.     while (hFind != INVALID_HANDLE_VALUE)
  391.     {
  392.         FindFileData = NextFindFileData;
  393.         if (!FindNextFile(hFind, &NextFindFileData))
  394.         {
  395.             FindClose(hFind);
  396.             hFind = INVALID_HANDLE_VALUE;
  397.         }
  398.  
  399.         if (!_tcscmp(FindFileData.cFileName, _T(".")) || !_tcscmp(FindFileData.cFileName, _T("..")))
  400.             continue;
  401.  
  402.         CStdString fn = FindFileData.cFileName;
  403.  
  404.         if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  405.         {
  406.             // Check permissions of subdir. If we don't have LIST permission,
  407.             // don't display the subdir.
  408.             BOOL truematch;
  409.             t_directory subDir;
  410.             if (GetRealDirectory(dir + "/" + fn, user, subDir, truematch))
  411.                 continue;
  412.  
  413.             if (subDir.bDirList)
  414.                 AddListingEntry(pDir, fn, true, FindFileData.nFileSizeLow + ((_int64)FindFileData.nFileSizeHigh<<32), &FindFileData.ftLastWriteTime, directory);
  415.         }
  416.         else
  417.             AddListingEntry(pDir, fn, false, FindFileData.nFileSizeLow + ((_int64)FindFileData.nFileSizeHigh<<32), &FindFileData.ftLastWriteTime, directory);
  418.     }
  419.  
  420.     return 0;
  421. }
  422.  
  423. int CPermissions::CheckDirectoryPermissions(LPCTSTR username, CStdString dirname, CStdString currentdir, int op, CStdString& physicalDir, CStdString& logicalDir)
  424. {
  425.     //Get user from username
  426.     CUser user;
  427.     if (!GetUser(username, user))
  428.         return PERMISSION_DENIED; // No user found
  429.  
  430.     CStdString dir = CanonifyServerDir(currentdir, dirname);
  431.     if (dir == "")
  432.         return PERMISSION_INVALIDNAME;
  433.     if (dir == "/")
  434.         return PERMISSION_NOTFOUND;
  435.  
  436.     int pos = dir.ReverseFind('/');
  437.     if (pos == -1 || !dir[pos + 1])
  438.         return PERMISSION_NOTFOUND;
  439.     logicalDir = dir;
  440.     dirname = dir.Mid(pos + 1);
  441.     if (!pos)
  442.         dir = "/";
  443.     else
  444.         dir = dir.Left(pos);
  445.     
  446.     // dir now is the absolute path (logical server path of course)
  447.     // awhile dirname is the pure dirname without the full path
  448.  
  449.     CStdString realDir;
  450.     CStdString realDirname;
  451.  
  452.     //Get the physical path, only of dir to get the right permissions
  453.     t_directory directory;
  454.     BOOL truematch;
  455.     int res;
  456.  
  457.     CStdString dir2 = dir;
  458.     CStdString dirname2 = dirname;
  459.     do
  460.     {
  461.         res = GetRealDirectory(dir2, user, directory, truematch);
  462.         if (res & PERMISSION_NOTFOUND && op == DOP_CREATE)
  463.         { //that path could not be found. Maybe more than one directory level has to be created, check that
  464.             if (dir2 == "/")
  465.                 return res;
  466.  
  467.             int pos = dir2.ReverseFind('/');
  468.             if (pos == -1)
  469.                 return res;
  470.  
  471.             dirname2 = dir2.Mid(pos+1) + "/" + dirname2;
  472.             if (pos)
  473.                 dir2 = dir2.Left(pos);
  474.             else
  475.                 dir2 = "/";
  476.  
  477.             continue;
  478.         }
  479.         else if (res)
  480.             return res;
  481.         
  482.         realDir = directory.dir;
  483.         realDirname = dirname2;
  484.         if (!directory.bDirDelete && op & DOP_DELETE)
  485.             res |= PERMISSION_DENIED;
  486.         if (!directory.bDirCreate && op & DOP_CREATE)
  487.             res |= PERMISSION_DENIED;
  488.         break;
  489.     } while (TRUE);
  490.  
  491.     realDirname.Replace("/", "\\");
  492.     physicalDir = realDir + "\\" + realDirname;
  493.  
  494.     //Check if dir + dirname is a valid path
  495.     int res2 = GetRealDirectory(dir + "/" + dirname, user, directory, truematch);
  496.     if (!res2 && op&DOP_CREATE)
  497.         res |= PERMISSION_DOESALREADYEXIST;
  498.     else if (!(res2 & PERMISSION_NOTFOUND))
  499.         return res | res2;
  500.     
  501.     // check dir attributes
  502.     DWORD nAttributes = GetFileAttributes(physicalDir);
  503.     if (nAttributes==0xFFFFFFFF && !(op&DOP_CREATE))
  504.         res |= PERMISSION_NOTFOUND;
  505.     else if (!(nAttributes&FILE_ATTRIBUTE_DIRECTORY))
  506.         res |= PERMISSION_FILENOTDIR;
  507.  
  508.     //Finally, a valid path+dirname!
  509.     return res;
  510. }
  511.  
  512. int CPermissions::CheckFilePermissions(LPCTSTR username, CStdString filename, CStdString currentdir, int op, CStdString& physicalFile, CStdString& logicalFile)
  513. {
  514.     //Get user from username
  515.     CUser user;
  516.     if (!GetUser(username, user))
  517.         return PERMISSION_DENIED; // No user found
  518.  
  519.     CStdString dir = CanonifyServerDir(currentdir, filename);
  520.     if (dir == "")
  521.         return PERMISSION_INVALIDNAME;
  522.     if (dir == "/")
  523.         return PERMISSION_NOTFOUND;
  524.  
  525.     int pos = dir.ReverseFind('/');
  526.     if (pos == -1)
  527.         return PERMISSION_NOTFOUND;
  528.  
  529.     logicalFile = dir;
  530.     
  531.     filename = dir.Mid(pos + 1);
  532.     if (pos)
  533.         dir = dir.Left(pos);
  534.     else
  535.         dir = "/";
  536.  
  537.     // dir now is the absolute path (logical server path of course)
  538.     // while filename is the filename
  539.  
  540.     //Get the physical path
  541.     t_directory directory;
  542.     BOOL truematch;
  543.     int res = GetRealDirectory(dir, user, directory, truematch);
  544.  
  545.     if (res)
  546.         return res;
  547.     if (!directory.bFileRead && op&FOP_READ)
  548.         res |= PERMISSION_DENIED;
  549.     if (!directory.bFileDelete && op&FOP_DELETE)
  550.         res |= PERMISSION_DENIED;
  551.     if (!directory.bFileWrite && op&(FOP_CREATENEW|FOP_WRITE|FOP_APPEND))
  552.         res |= PERMISSION_DENIED;
  553.  
  554.     physicalFile = directory.dir + "\\" + filename;
  555.     DWORD nAttributes = GetFileAttributes(physicalFile);
  556.     if (nAttributes == 0xFFFFFFFF)
  557.     {
  558.         if (!(op&(FOP_WRITE|FOP_APPEND|FOP_CREATENEW)))
  559.             res |= PERMISSION_NOTFOUND;
  560.     }
  561.     else
  562.     {
  563.         if (nAttributes&FILE_ATTRIBUTE_DIRECTORY)
  564.             res |= PERMISSION_DIRNOTFILE;
  565.         if (!directory.bFileAppend && op&FOP_APPEND)
  566.             res |= PERMISSION_DENIED;
  567.         if (!directory.bFileDelete && op&FOP_WRITE)
  568.             res |= PERMISSION_DENIED;
  569.         if (op & FOP_CREATENEW)
  570.             res |= PERMISSION_DOESALREADYEXIST;
  571.     }
  572.  
  573.     //If res is 0 we finally have a valid path+filename!
  574.     return res;
  575. }
  576.  
  577. CStdString CPermissions::GetHomeDir(const CUser &user, bool physicalPath /*=false*/) const
  578. {
  579.     if (user.homedir == "")
  580.         return "";
  581.  
  582.     if (!physicalPath)
  583.         return "/";
  584.     
  585.     CStdString path;
  586.     path = user.homedir;
  587.     
  588.     user.DoReplacements(path);
  589.     
  590.     return path;
  591. }
  592.  
  593. CStdString CPermissions::GetHomeDir(LPCTSTR username, bool physicalPath /*=false*/) const
  594. {
  595.     CUser user;
  596.     if (!GetUser(username, user))
  597.         return "";
  598.  
  599.     return GetHomeDir(user, physicalPath);
  600. }
  601.  
  602. int CPermissions::GetRealDirectory(CStdString directory, const CUser &user, t_directory &ret, BOOL &truematch)
  603. {
  604.     /*
  605.      * This function translates pathnames from absolute server paths
  606.      * into absolute local paths.
  607.      * The given server directory is already an absolute canonified path, so
  608.      * parsing it is very quick.
  609.      * To find the absolute local path, we go though each segment of the server
  610.      * path. For the local path, we start form the homedir and append segments 
  611.      * sequentially or resolve aliases if required.
  612.      */
  613.  
  614.     directory.TrimLeft("/");
  615.     
  616.     // Split server path
  617.     // --------------------
  618.  
  619.     //Split dir into pieces
  620.     std::list<CStdString> PathPieces;
  621.     int pos;
  622.  
  623.     while((pos = directory.Find('/')) != -1)
  624.     {
  625.         PathPieces.push_back(directory.Left(pos));
  626.         directory = directory.Mid(pos + 1);
  627.     }
  628.     if (directory != "")
  629.         PathPieces.push_back(directory);
  630.  
  631.     // Get absolute local path
  632.     // -----------------------
  633.  
  634.     //First get the home dir
  635.     CStdString homepath = GetHomeDir(user, true);
  636.     if (homepath == "") //No homedir found
  637.         return PERMISSION_DENIED;
  638.     
  639.     // Reassamble path to get local path
  640.     CStdString path = homepath; // Start with homedir as root
  641.  
  642.     // Go through all pieces
  643.     for (std::list<CStdString>::iterator iter = PathPieces.begin(); iter != PathPieces.end(); iter++)
  644.     {
  645.         //Check if piece exists
  646.         CStdString piece = *iter;
  647.         DWORD nAttributes = GetFileAttributes(path + "\\" + piece);
  648.         if (nAttributes != 0xFFFFFFFF)
  649.         {
  650.             if (!(nAttributes&FILE_ATTRIBUTE_DIRECTORY))
  651.                 return PERMISSION_FILENOTDIR;
  652.             path += "\\" + piece;
  653.             continue;
  654.         }
  655.         else
  656.         {
  657.             CStdString target = user.GetAliasTarget(path, piece);
  658.             if (target != "")
  659.             {
  660.                 if (target.Right(1) != ":")
  661.                 {
  662.                     nAttributes = GetFileAttributes(target);
  663.                     if (nAttributes == 0xFFFFFFFF)
  664.                         return PERMISSION_NOTFOUND;
  665.                     else if (!(nAttributes & FILE_ATTRIBUTE_DIRECTORY))
  666.                         return PERMISSION_FILENOTDIR;
  667.                 }
  668.                 path = target;
  669.                 continue;
  670.             }
  671.         }
  672.         return PERMISSION_NOTFOUND;
  673.     }
  674.     CStdString realpath = path;
  675.  
  676.     // Check permissions
  677.     // -----------------
  678.  
  679.     /* We got a valid local path, now find the closest matching path within the
  680.      * permissions.
  681.      * We do this by sequentially comparing the path with all permissions and
  682.      * sequentially removing the last path segment until we found a match or
  683.      * all path segments have been removed
  684.      * Distinguish the case
  685.      */
  686.     truematch = TRUE;
  687.     
  688.     path.MakeLower();
  689.     while (path != "")
  690.     {
  691.         BOOL bFoundMatch = FALSE;
  692.         unsigned int i;
  693.     
  694.         // Check user permissions
  695.         for (i = 0; i < user.permissions.size(); i++)
  696.         {
  697.             CStdString permissionPath = user.permissions[i].dir;
  698.             user.DoReplacements(permissionPath);
  699.             permissionPath.MakeLower();
  700.             if (permissionPath == path)
  701.             {
  702.                 bFoundMatch = TRUE;
  703.                 ret = user.permissions[i];
  704.                 break;
  705.             }
  706.         }
  707.  
  708.         // Check owner (group) permissions
  709.         if (!bFoundMatch && user.pOwner)
  710.             for (i = 0; i < user.pOwner->permissions.size(); i++)
  711.             {
  712.                 CStdString permissionPath = user.pOwner->permissions[i].dir;
  713.                 user.DoReplacements(permissionPath);
  714.                 permissionPath.MakeLower();
  715.                 if (permissionPath == path)
  716.                 {
  717.                     bFoundMatch = TRUE;
  718.                     ret = user.pOwner->permissions[i];
  719.                     break;
  720.                 }
  721.             }
  722.  
  723.         if (!bFoundMatch)
  724.         {
  725.             // No match found, remove last segment and try again
  726.             int pos = path.ReverseFind('\\');
  727.             if (pos != -1)
  728.                 path = path.Left(pos);
  729.             else
  730.                 return PERMISSION_DENIED;
  731.             truematch = FALSE;
  732.             continue;
  733.         }
  734.         ret.dir = realpath;
  735.  
  736.         // We can check the bDirSubdirs permission right here
  737.         if (!truematch && !ret.bDirSubdirs)
  738.             return PERMISSION_DENIED;
  739.  
  740.         return 0;
  741.     }
  742.     return PERMISSION_NOTFOUND;
  743. }
  744.  
  745. int CPermissions::ChangeCurrentDir(LPCTSTR username, CStdString ¤tdir, CStdString &dir)
  746. {
  747.     //Get user from username
  748.     CUser user;
  749.     if (!GetUser(username, user))
  750.         return PERMISSION_DENIED; // No user found
  751.  
  752.     CStdString canonifiedDir = CanonifyServerDir(currentdir, dir);
  753.     if (canonifiedDir == "")
  754.         return PERMISSION_INVALIDNAME;
  755.     dir = canonifiedDir;
  756.  
  757.     //Get the physical path
  758.     t_directory directory;
  759.     BOOL truematch;
  760.     int res = GetRealDirectory(dir, user, directory, truematch);
  761.     if (res)
  762.         return res;
  763.     if (!directory.bDirList)
  764.     {
  765.         if (!directory.bFileRead && !directory.bFileWrite)
  766.             return PERMISSION_DENIED;
  767.     }
  768.  
  769.     //Finally, a valid path!
  770.     currentdir = dir; //Server paths are relative, so we can use the absolute server path
  771.  
  772.     return 0;
  773. }
  774.  
  775. BOOL CPermissions::GetUser(CStdString username, CUser &userdata) const
  776. {
  777.     // Get user from username
  778.     for (unsigned int i=0; i<m_UsersList.size(); i++)
  779.     {
  780.         if (!username.CompareNoCase(m_UsersList[i].user))
  781.         {
  782.             userdata = m_UsersList[i];
  783.             return TRUE;
  784.         }
  785.     }
  786.     return FALSE;
  787. }
  788.  
  789. int CPermissions::GetShortDirectoryListing(LPCTSTR username, CStdString currentDir, CStdString dirToDisplay, t_dirlisting *&pResult, CStdString& physicalDir, CStdString& logicalDir)
  790. {
  791.     // Get user from username
  792.     CUser user;
  793.     if (!GetUser(username, user))
  794.         return PERMISSION_DENIED; // No user found
  795.  
  796.     CStdString dir = CanonifyServerDir(currentDir, dirToDisplay);
  797.     if (dir == "")
  798.         return PERMISSION_INVALIDNAME;
  799.     logicalDir = dir;
  800.  
  801.     t_directory directory;
  802.     BOOL bTruematch;
  803.     int res = GetRealDirectory(dir, user, directory, bTruematch);
  804.     CStdString sFileSpec = "*";
  805.     if (res == PERMISSION_FILENOTDIR || res == PERMISSION_NOTFOUND) // Try listing using a direct wildcard filespec instead?
  806.     {
  807.         // Check dirToDisplay if we are allowed to go back a directory
  808.         dirToDisplay.Replace('\\', '/');
  809.         while (dirToDisplay.Replace("//", "/"));
  810.         if (dirToDisplay.Right(1) == "/")
  811.             return res;
  812.         int pos = dirToDisplay.ReverseFind('/');
  813.         if (res != PERMISSION_FILENOTDIR && dirToDisplay.Mid(pos + 1).Find('*') == -1)
  814.             return res;
  815.         dirToDisplay = dirToDisplay.Left(pos + 1);
  816.  
  817.         if (dir == "/")
  818.             return res;
  819.         
  820.         pos = dir.ReverseFind('/');
  821.         sFileSpec = dir.Mid(pos + 1);
  822.         if (pos)
  823.             dir = dir.Left(pos);
  824.         else
  825.             dir = "/";
  826.  
  827.         if (sFileSpec.Find("*") == -1 && res != PERMISSION_FILENOTDIR)
  828.             return res;
  829.  
  830.         res = GetRealDirectory(dir, user, directory, bTruematch);
  831.     }
  832.     if (res)
  833.         return res;
  834.  
  835.     if (!directory.bDirList)
  836.         return PERMISSION_DENIED;
  837.  
  838.     if (dirToDisplay != "" && dirToDisplay.Right(1) != "/")
  839.         dirToDisplay += "/";
  840.  
  841.     t_dirlisting *pDir = new t_dirlisting;
  842.     pDir->len = 0;
  843.     pDir->pNext = NULL;
  844.     pResult = pDir;
  845.  
  846.     CStdString curDir = directory.dir;
  847.     curDir.MakeLower();
  848.  
  849.     physicalDir = directory.dir;
  850.         
  851.     for (std::multimap<CStdString, CUser::t_alias>::const_iterator iter = user.aliasMap.find(curDir);
  852.          iter != user.aliasMap.end() && iter->first == curDir; iter++)
  853.     {
  854.         t_directory directory;
  855.         BOOL truematch = false;
  856.         if (GetRealDirectory(dir + "/" + iter->second.name, user, directory, truematch))
  857.             continue;
  858.         if (!directory.bDirList)
  859.             continue;
  860.         if (!truematch && !directory.bDirSubdirs)
  861.             continue;
  862.  
  863.         if (sFileSpec != "*.*" && sFileSpec != "*")
  864.         {
  865.             // Do a really primitive wildcard check, does even ignore ?
  866.             CStdString name = iter->second.name;
  867.             CStdString spec = sFileSpec;
  868.             name.MakeLower();
  869.             spec.MakeLower();
  870.  
  871.             bool match = true;
  872.             while (spec != "")
  873.             {
  874.                 int pos = spec.Find('*');
  875.                 if (pos == -1)
  876.                 {
  877.                     if (spec != name)
  878.                     {
  879.                         match = false;
  880.                         break;
  881.                     }
  882.                     break;
  883.                 }
  884.                 else if (!pos)
  885.                 {
  886.                     spec = spec.Mid(1);
  887.                 }
  888.                 else
  889.                 {
  890.                     int npos = name.Find(spec.Left(pos));
  891.                     if (npos == -1)
  892.                     {
  893.                         match = false;
  894.                         break;
  895.                     }
  896.                     spec = spec.Mid(pos + 1);
  897.                     name = name.Mid(npos + 1);
  898.                 }
  899.             }
  900.             if (!match)
  901.                 continue;
  902.         }
  903.         
  904.         // This wastes some memory but keeps the whole thing fast
  905.         if ((8192 - pDir->len) < (10 + 2 * MAX_PATH))
  906.         {
  907.             pDir->pNext = new t_dirlisting;
  908.             pDir = pDir->pNext;
  909.             pDir->len = 0;
  910.             pDir->pNext = NULL;
  911.         }
  912.     
  913.         int len = dirToDisplay.GetLength();
  914.         memcpy(pDir->buffer + pDir->len, dirToDisplay.c_str(), len);
  915.         pDir->len += len;
  916.         len = iter->second.name.GetLength();
  917.         memcpy(pDir->buffer + pDir->len, iter->second.name, len);
  918.         pDir->len += len;
  919.         pDir->buffer[pDir->len++] = '\r';
  920.         pDir->buffer[pDir->len++] = '\n';
  921.     }
  922.  
  923.     if (sFileSpec != "*" && sFileSpec != "*.*")
  924.         physicalDir += sFileSpec;
  925.  
  926.     WIN32_FIND_DATA FindFileData;
  927.     WIN32_FIND_DATA NextFindFileData;
  928.     HANDLE hFind;
  929.     hFind = FindFirstFile(directory.dir + "\\" + sFileSpec, &NextFindFileData);
  930.     while (hFind != INVALID_HANDLE_VALUE)
  931.     {
  932.         FindFileData = NextFindFileData;
  933.         if (!FindNextFile(hFind, &NextFindFileData))
  934.         {
  935.             FindClose(hFind);
  936.             hFind = INVALID_HANDLE_VALUE;
  937.         }
  938.     
  939.         if (!_tcscmp(FindFileData.cFileName, _T(".")) || !_tcscmp(FindFileData.cFileName, _T("..")))
  940.             continue;
  941.     
  942.         CStdString fn = FindFileData.cFileName;
  943.  
  944.         if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  945.         {
  946.             // Check permissions of subdir. If we don't have LIST permission,
  947.             // don't display the subdir.
  948.             BOOL truematch;
  949.             t_directory subDir;
  950.             if (GetRealDirectory(dir + "/" + fn, user, subDir, truematch))
  951.                 continue;
  952.  
  953.             if (!subDir.bDirList)
  954.                 continue;
  955.         }
  956.     
  957.         // This wastes some memory but keeps the whole thing fast
  958.         if ((8192 - pDir->len) < (10 + 2 * MAX_PATH))
  959.         {
  960.             pDir->pNext = new t_dirlisting;
  961.             pDir = pDir->pNext;
  962.             pDir->len = 0;
  963.             pDir->pNext = NULL;
  964.         }
  965.     
  966.         int len = dirToDisplay.GetLength();
  967.         memcpy(pDir->buffer + pDir->len, dirToDisplay.c_str(), len);
  968.         pDir->len += len;
  969.         len = fn.GetLength();
  970.         memcpy(pDir->buffer + pDir->len, fn.c_str(), len);
  971.         pDir->len += len;
  972.         pDir->buffer[pDir->len++] = '\r';
  973.         pDir->buffer[pDir->len++] = '\n';
  974.     }
  975.  
  976.     return 0;
  977. }
  978.  
  979. BOOL CPermissions::CheckUserLogin(LPCTSTR username, LPCTSTR pass, CUser &userdata, BOOL noPasswordCheck /*=FALSE*/)
  980. {
  981.     const char *tmp = pass;
  982.     MD5 md5;
  983.     md5.update((unsigned char *)tmp, _tcslen(pass));
  984.     md5.finalize();
  985.     char *res = md5.hex_digest();
  986.     CStdString hash=res;
  987.     delete [] res;
  988.  
  989.     CUser user;
  990.     if (!GetUser(username, user))
  991.         return FALSE;
  992.  
  993.     if (noPasswordCheck || user.password == hash || user.password == "")
  994.     {
  995.         userdata = user;
  996.         return TRUE;
  997.     }
  998.  
  999.     return FALSE;
  1000. }
  1001.  
  1002. void CPermissions::UpdateInstances()
  1003. {
  1004.     EnterCritSection(m_sync);
  1005.     for (std::list<CPermissions *>::iterator iter=m_sInstanceList.begin(); iter!=m_sInstanceList.end(); iter++)
  1006.     {
  1007.         if (*iter!=this)
  1008.         {
  1009.             ASSERT((*iter)->m_pPermissionsHelperWindow);
  1010.             ::PostMessage((*iter)->m_pPermissionsHelperWindow->GetHwnd(), WM_USER, 0, 0);
  1011.         }
  1012.     }
  1013.     LeaveCritSection(m_sync);
  1014. }
  1015.  
  1016. void CPermissions::SetKey(CMarkupSTL *pXML, LPCTSTR name, LPCTSTR value)
  1017. {
  1018.     ASSERT(pXML);
  1019.     pXML->AddChildElem(_T("Option"), value);
  1020.     pXML->AddChildAttrib(_T("Name"), name);
  1021. }
  1022.  
  1023. void CPermissions::SetKey(CMarkupSTL *pXML, LPCTSTR name, int value)
  1024. {
  1025.     ASSERT(pXML);
  1026.     CStdString str;
  1027.     str.Format("%d", value);
  1028.     SetKey(pXML, name, str);
  1029. }
  1030.  
  1031. void CPermissions::SavePermissions(CMarkupSTL *pXML, const t_group &user)
  1032. {
  1033.     pXML->AddChildElem(_T("Permissions"));
  1034.     pXML->IntoElem();
  1035.     for (unsigned int i=0; i<user.permissions.size(); i++)
  1036.     {
  1037.         pXML->AddChildElem(_T("Permission"));
  1038.         pXML->AddChildAttrib(_T("Dir"), user.permissions[i].dir);
  1039.         pXML->IntoElem();
  1040.         if (!user.permissions[i].aliases.empty())
  1041.         {
  1042.             pXML->AddChildElem(_T("Aliases"));
  1043.             pXML->IntoElem();
  1044.             for (std::list<CStdString>::const_iterator iter = user.permissions[i].aliases.begin(); iter != user.permissions[i].aliases.end(); iter++)
  1045.             {
  1046.                 pXML->AddChildElem(_T("Alias"));
  1047.                 pXML->SetChildData(*iter);
  1048.             }
  1049.             pXML->OutOfElem();
  1050.         }
  1051.         SetKey(pXML, "FileRead", user.permissions[i].bFileRead ? "1":"0");
  1052.         SetKey(pXML, "FileWrite", user.permissions[i].bFileWrite ? "1":"0");
  1053.         SetKey(pXML, "FileDelete", user.permissions[i].bFileDelete ?"1":"0");
  1054.         SetKey(pXML, "FileAppend", user.permissions[i].bFileAppend ? "1":"0");
  1055.         SetKey(pXML, "DirCreate", user.permissions[i].bDirCreate ? "1":"0");
  1056.         SetKey(pXML, "DirDelete", user.permissions[i].bDirDelete ? "1":"0");
  1057.         SetKey(pXML, "DirList", user.permissions[i].bDirList ? "1":"0");
  1058.         SetKey(pXML, "DirSubdirs", user.permissions[i].bDirSubdirs ? "1":"0");
  1059.         SetKey(pXML, "IsHome", user.permissions[i].bIsHome ? "1":"0");
  1060.         SetKey(pXML, "AutoCreate", user.permissions[i].bAutoCreate ? "1":"0");
  1061.         pXML->OutOfElem();
  1062.     }
  1063.     pXML->OutOfElem();
  1064. }
  1065.  
  1066. BOOL CPermissions::GetAsCommand(char **pBuffer, DWORD *nBufferLength)
  1067. {
  1068.     // This function returns all account data as a command string which will be 
  1069.     // sent to the user interface.
  1070.     if (!pBuffer || !nBufferLength)
  1071.         return FALSE;
  1072.  
  1073.     EnterCritSection(m_sync);
  1074.  
  1075.     // First calculate the required buffer length
  1076.     DWORD len = 4;
  1077.     t_GroupsList::iterator groupiter;
  1078.     for (groupiter = m_sGroupsList.begin(); groupiter != m_sGroupsList.end(); groupiter++)
  1079.         len += groupiter->GetRequiredBufferLen();
  1080.  
  1081.     t_UsersList::iterator iter;
  1082.     for (iter = m_sUsersList.begin(); iter != m_sUsersList.end(); iter++)
  1083.         len += iter->GetRequiredBufferLen();
  1084.  
  1085.     // Allocate memory
  1086.     *pBuffer = new char[len];
  1087.     char* p  = *pBuffer;
  1088.  
  1089.     // Write groups to buffer
  1090.     *p++ = m_sGroupsList.size()/256;
  1091.     *p++ = m_sGroupsList.size()%256;
  1092.     for (groupiter = m_sGroupsList.begin(); groupiter != m_sGroupsList.end(); groupiter++)
  1093.     {
  1094.         p = groupiter->FillBuffer(p);
  1095.         if (!p)
  1096.         {
  1097.             delete [] *pBuffer;
  1098.             *pBuffer = NULL;
  1099.             LeaveCritSection(m_sync);
  1100.             return FALSE;
  1101.         }
  1102.     }
  1103.  
  1104.     // Write users to buffer
  1105.     *p++ = m_sUsersList.size()/256;
  1106.     *p++ = m_sUsersList.size()%256;
  1107.     for (iter = m_sUsersList.begin(); iter != m_sUsersList.end(); iter++)
  1108.     {
  1109.         p = iter->FillBuffer(p);
  1110.         if (!p)
  1111.         {
  1112.             delete [] *pBuffer;
  1113.             *pBuffer = NULL;
  1114.             LeaveCritSection(m_sync);
  1115.             return FALSE;
  1116.         }
  1117.     }
  1118.  
  1119.     LeaveCritSection(m_sync);
  1120.     *nBufferLength = len;
  1121.  
  1122.     return TRUE;
  1123. }
  1124.  
  1125. BOOL CPermissions::ParseUsersCommand(unsigned char *pData, DWORD dwDataLength)
  1126. {
  1127.     m_GroupsList.clear();
  1128.     m_UsersList.clear();
  1129.     unsigned char *p = pData;
  1130.     unsigned char* endMarker = pData + dwDataLength;
  1131.  
  1132.     if (dwDataLength < 2)
  1133.         return FALSE;
  1134.     int num = *p * 256 + p[1];
  1135.     p+=2;
  1136.  
  1137.     int i;
  1138.     for (i = 0; i < num; i++)
  1139.     {
  1140.         t_group group;
  1141.         p = group.ParseBuffer(p, endMarker - p);
  1142.         if (!p)
  1143.             return FALSE;
  1144.     
  1145.         if (group.group != _T(""))
  1146.         {
  1147.             //Set a home dir if no home dir could be read
  1148.             BOOL bGotHome = FALSE;
  1149.             for (unsigned int dir = 0; dir < group.permissions.size(); dir++)
  1150.                 if (group.permissions[dir].bIsHome)
  1151.                 {
  1152.                     bGotHome = TRUE;
  1153.                     break;
  1154.                 }
  1155.  
  1156.             if (!bGotHome && !group.permissions.empty())
  1157.                 group.permissions.begin()->bIsHome = TRUE;
  1158.  
  1159.             m_GroupsList.push_back(group);
  1160.         }
  1161.     }
  1162.  
  1163.     if ((endMarker - p) < 2)
  1164.         return FALSE;
  1165.  
  1166.     num = *p * 256 + p[1];
  1167.     p+=2;
  1168.     for (i = 0; i < num; i++)
  1169.     {
  1170.         CUser user;
  1171.     
  1172.         p = user.ParseBuffer(p, endMarker - p);
  1173.         if (!p)
  1174.             return FALSE;
  1175.     
  1176.         if (user.user != _T(""))
  1177.         {
  1178.             user.pOwner = NULL;
  1179.             if (user.group != _T(""))
  1180.             {
  1181.                 for (t_GroupsList::iterator groupiter = m_GroupsList.begin(); groupiter != m_GroupsList.end(); groupiter++)
  1182.                     if (groupiter->group == user.group)
  1183.                     {
  1184.                         user.pOwner = &(*groupiter);
  1185.                         break;
  1186.                     }
  1187.                 if (!user.pOwner)
  1188.                     user.group = "";
  1189.             }
  1190.  
  1191.             if (!user.pOwner)
  1192.             {
  1193.                 //Set a home dir if no home dir could be read
  1194.                 BOOL bGotHome = FALSE;
  1195.                 for (unsigned int dir = 0; dir < user.permissions.size(); dir++)
  1196.                     if (user.permissions[dir].bIsHome)
  1197.                     {
  1198.                         bGotHome = TRUE;
  1199.                         break;
  1200.                     }
  1201.  
  1202.                 if (!bGotHome && !user.permissions.empty())
  1203.                     user.permissions.begin()->bIsHome = TRUE;
  1204.             }
  1205.  
  1206.             std::vector<t_directory>::iterator iter;
  1207.             for (iter = user.permissions.begin(); iter != user.permissions.end(); iter++)
  1208.             {
  1209.                 if (iter->bIsHome)
  1210.                 {
  1211.                     user.homedir = iter->dir;
  1212.                     break;
  1213.                 }
  1214.             }
  1215.             if (user.homedir=="" && user.pOwner)
  1216.             {
  1217.                 for (iter = user.pOwner->permissions.begin(); iter != user.pOwner->permissions.end(); iter++)
  1218.                 {
  1219.                     if (iter->bIsHome)
  1220.                     {
  1221.                         user.homedir = iter->dir;
  1222.                         break;
  1223.                     }
  1224.                 }
  1225.             }
  1226.  
  1227.             user.PrepareAliasMap();
  1228.             m_UsersList.push_back(user);
  1229.         }
  1230.     }
  1231.  
  1232.     // Update the account list
  1233.     EnterCritSection(m_sync);
  1234.  
  1235.     m_sGroupsList.clear();
  1236.     for (t_GroupsList::const_iterator groupiter=m_GroupsList.begin(); groupiter!=m_GroupsList.end(); groupiter++)
  1237.         m_sGroupsList.push_back(*groupiter);
  1238.  
  1239.     m_sUsersList.clear();
  1240.     for (t_UsersList::const_iterator iter=m_UsersList.begin(); iter!=m_UsersList.end(); iter++)
  1241.         m_sUsersList.push_back(*iter);
  1242.  
  1243.     UpdateInstances();
  1244.  
  1245.     LeaveCritSection(m_sync);
  1246.  
  1247.     // Write the new account data into xml file
  1248.  
  1249.     CMarkupSTL *pXML=COptions::GetXML();
  1250.     if (pXML)
  1251.     {
  1252.         while(pXML->FindChildElem(_T("Groups")))
  1253.             pXML->RemoveChildElem();
  1254.         pXML->AddChildElem(_T("Groups"));
  1255.         pXML->IntoElem();
  1256.     
  1257.         //Save the changed user details
  1258.         for (t_GroupsList::const_iterator groupiter=m_GroupsList.begin(); groupiter!=m_GroupsList.end(); groupiter++)
  1259.         {
  1260.             pXML->AddChildElem(_T("Group"));
  1261.             pXML->AddChildAttrib(_T("Name"), groupiter->group);
  1262.             pXML->IntoElem();
  1263.         
  1264.             SetKey(pXML, "Bypass server userlimit", groupiter->nBypassUserLimit);
  1265.             SetKey(pXML, "User Limit", groupiter->nUserLimit);
  1266.             SetKey(pXML, "IP Limit", groupiter->nIpLimit);
  1267.             SetKey(pXML, "Enabled", groupiter->nEnabled);
  1268.             SetKey(pXML, "Comments", groupiter->comment);
  1269.             SetKey(pXML, "ForceSsl", groupiter->forceSsl);
  1270.  
  1271.             SaveIpFilter(pXML, *groupiter);        
  1272.             SavePermissions(pXML, *groupiter);
  1273.             SaveSpeedLimits(pXML, *groupiter);
  1274.  
  1275.             pXML->OutOfElem();
  1276.         }
  1277.         pXML->OutOfElem();
  1278.         pXML->ResetChildPos();
  1279.  
  1280.         while(pXML->FindChildElem(_T("Users")))
  1281.             pXML->RemoveChildElem();
  1282.         pXML->AddChildElem(_T("Users"));
  1283.         pXML->IntoElem();
  1284.     
  1285.         //Save the changed user details
  1286.         for (t_UsersList::const_iterator iter=m_UsersList.begin(); iter!=m_UsersList.end(); iter++)
  1287.         {
  1288.             pXML->AddChildElem(_T("User"));
  1289.             pXML->AddChildAttrib(_T("Name"), iter->user);
  1290.             pXML->IntoElem();
  1291.         
  1292.             SetKey(pXML, "Pass", iter->password);
  1293.             SetKey(pXML, "Group", iter->group);
  1294.             SetKey(pXML, "Bypass server userlimit", iter->nBypassUserLimit);
  1295.             SetKey(pXML, "User Limit", iter->nUserLimit);
  1296.             SetKey(pXML, "IP Limit", iter->nIpLimit);
  1297.             SetKey(pXML, "Enabled", iter->nEnabled);
  1298.             SetKey(pXML, "Comments", iter->comment);
  1299.             SetKey(pXML, "ForceSsl", iter->forceSsl);
  1300.         
  1301.             SaveIpFilter(pXML, *iter);
  1302.             SavePermissions(pXML, *iter);
  1303.             SaveSpeedLimits(pXML, *iter);
  1304.  
  1305.             pXML->OutOfElem();
  1306.         }
  1307.         if (!COptions::FreeXML(pXML))
  1308.             return FALSE;
  1309.     }
  1310.     else
  1311.         return FALSE;
  1312.  
  1313.     return TRUE;
  1314. }
  1315.  
  1316. bool CPermissions::Init()
  1317. {
  1318.     EnterCritSection(m_sync);
  1319.     if (m_sInstanceList.empty() && m_sUsersList.empty() && m_sGroupsList.empty())
  1320.     {
  1321.         // It's the first time Init gets called after application start, read
  1322.         // permissions from xml file.
  1323.  
  1324.         ReadSettings();
  1325.     }
  1326.     else
  1327.     {
  1328.         m_GroupsList.clear();
  1329.         for (t_GroupsList::iterator groupiter=m_sGroupsList.begin(); groupiter!=m_sGroupsList.end(); groupiter++)
  1330.             m_GroupsList.push_back(*groupiter);
  1331.  
  1332.         m_UsersList.clear();
  1333.         for (t_UsersList::iterator iter = m_sUsersList.begin(); iter != m_sUsersList.end(); iter++)
  1334.         {
  1335.             CUser user = *iter;
  1336.             user.pOwner = NULL;
  1337.             if (user.group != _T(""))
  1338.             {
  1339.                 for (t_GroupsList::iterator groupiter=m_GroupsList.begin(); groupiter!=m_GroupsList.end(); groupiter++)
  1340.                     if (groupiter->group == user.group)
  1341.                     {
  1342.                         user.pOwner = &(*groupiter);
  1343.                         break;
  1344.                     }
  1345.             }
  1346.             m_UsersList.push_back(user);
  1347.         }
  1348.     }
  1349.  
  1350.     std::list<CPermissions *>::iterator instanceIter;
  1351.     for (instanceIter = m_sInstanceList.begin(); instanceIter != m_sInstanceList.end(); instanceIter++)
  1352.         if (*instanceIter==this)
  1353.             break;
  1354.     if (instanceIter == m_sInstanceList.end())
  1355.         m_sInstanceList.push_back(this);
  1356.     LeaveCritSection(m_sync);
  1357.  
  1358.     return TRUE;
  1359. }
  1360.  
  1361. void CPermissions::ReadPermissions(CMarkupSTL *pXML, t_group &user, BOOL &bGotHome)
  1362. {
  1363.     bGotHome = FALSE;
  1364.     pXML->ResetChildPos();
  1365.     while (pXML->FindChildElem(_T("Permissions")))
  1366.     {
  1367.         pXML->IntoElem();
  1368.         while (pXML->FindChildElem(_T("Permission")))
  1369.         {
  1370.             t_directory dir;
  1371.             dir.dir = pXML->GetChildAttrib(_T("Dir"));
  1372.             if (dir.dir != _T(""))
  1373.             {
  1374.                 dir.dir.Replace('/', '\\');
  1375.                 dir.dir.TrimRight('\\');
  1376.  
  1377.                 pXML->IntoElem();
  1378.                 while (pXML->FindChildElem(_T("Aliases")))
  1379.                 {
  1380.                     pXML->IntoElem();
  1381.                     while (pXML->FindChildElem(_T("Alias")))
  1382.                     {
  1383.                         CStdString alias = pXML->GetChildData();
  1384.                         alias.Replace("/", "\\");
  1385.                         while (alias.Replace("\\\\", "\\"));
  1386.                         alias.TrimRight('\\');
  1387.                         if (alias[0] != '\\' && alias != "")
  1388.                             dir.aliases.push_back(alias);
  1389.                     }
  1390.                     pXML->OutOfElem();
  1391.                 }
  1392.                 pXML->ResetChildPos();
  1393.                 while (pXML->FindChildElem(_T("Option")))
  1394.                 {
  1395.                     CStdString name = pXML->GetChildAttrib(_T("Name"));
  1396.                     CStdString value = pXML->GetChildData();
  1397.                     if (name == _T("FileRead"))
  1398.                         dir.bFileRead = value == _T("1");
  1399.                     else if (name == _T("FileWrite"))
  1400.                         dir.bFileWrite = value == _T("1");
  1401.                     else if (name == _T("FileDelete"))
  1402.                         dir.bFileDelete = value == _T("1");
  1403.                     else if (name == _T("FileAppend"))
  1404.                         dir.bFileAppend = value == _T("1");
  1405.                     else if (name == _T("DirCreate"))
  1406.                         dir.bDirCreate = value == _T("1");
  1407.                     else if (name == _T("DirDelete"))
  1408.                         dir.bDirDelete = value == _T("1");
  1409.                     else if (name == _T("DirList"))
  1410.                         dir.bDirList = value == _T("1");
  1411.                     else if (name == _T("DirSubdirs"))
  1412.                         dir.bDirSubdirs = value == _T("1");
  1413.                     else if (name == _T("IsHome"))
  1414.                         dir.bIsHome = value == _T("1");
  1415.                     else if (name == _T("AutoCreate"))
  1416.                         dir.bAutoCreate = value == _T("1");
  1417.                 }
  1418.             
  1419.                 //Avoid multiple home dirs
  1420.                 if (dir.bIsHome)
  1421.                     if (!bGotHome)
  1422.                         bGotHome = TRUE;
  1423.                     else
  1424.                         dir.bIsHome = FALSE;
  1425.             
  1426.                 if (user.permissions.size() < 20000)
  1427.                     user.permissions.push_back(dir);
  1428.                 pXML->OutOfElem();
  1429.             }                            
  1430.         }
  1431.         pXML->OutOfElem();
  1432.     }
  1433. }
  1434.  
  1435. void CPermissions::AutoCreateDirs(const char *username)
  1436. {
  1437.     // Create missing directores after a user has logged on
  1438.     CUser user;
  1439.     if (!GetUser(username, user))
  1440.         return;
  1441.     for (std::vector<t_directory>::iterator permissioniter = user.permissions.begin(); permissioniter != user.permissions.end(); permissioniter++)
  1442.         if (permissioniter->bAutoCreate)
  1443.         {
  1444.             CStdString dir = permissioniter->dir;
  1445.             user.DoReplacements(dir);
  1446.             
  1447.             dir += "\\";
  1448.             CStdString str;
  1449.             while (dir != "")
  1450.             {
  1451.                 int pos = dir.Find("\\");
  1452.                 CStdString piece = dir.Left(pos + 1);
  1453.                 dir = dir.Mid(pos + 1);
  1454.                 
  1455.                 str += piece;
  1456.                 CreateDirectory(str, 0);
  1457.             }
  1458.         }
  1459.     if (user.pOwner)
  1460.         for (std::vector<t_directory>::iterator permissioniter = user.pOwner->permissions.begin(); permissioniter != user.pOwner->permissions.end(); permissioniter++)
  1461.             if (permissioniter->bAutoCreate)
  1462.             {
  1463.                 CStdString dir = permissioniter->dir;
  1464.                 user.DoReplacements(dir);
  1465.  
  1466.                 dir += "\\";
  1467.                 CStdString str;
  1468.                 while (dir != "")
  1469.                 {
  1470.                     int pos = dir.Find("\\");
  1471.                     CStdString piece = dir.Left(pos + 1);
  1472.                     dir = dir.Mid(pos + 1);
  1473.                 
  1474.                     str += piece;
  1475.                     CreateDirectory(str, 0);
  1476.                 }
  1477.             }
  1478. }
  1479.  
  1480. void CPermissions::ReadSpeedLimits(CMarkupSTL *pXML, t_group &group)
  1481. {
  1482.     pXML->ResetChildPos();
  1483.     
  1484.     const CStdString prefixes[] = { "Dl", "Ul" };
  1485.     const CStdString names[] = { "Download", "Upload" };
  1486.  
  1487.     while (pXML->FindChildElem(_T("SpeedLimits")))
  1488.     {
  1489.         CStdString str;
  1490.         int n;
  1491.  
  1492.         for (int i = 0; i < 2; i++)
  1493.         {
  1494.             str = pXML->GetChildAttrib(prefixes[i] + "Type");
  1495.             n = _ttoi(str);
  1496.             if (n >= 0 && n < 4)
  1497.                 group.nSpeedLimitType[i] = n;
  1498.             str = pXML->GetChildAttrib(prefixes[i] + "Limit");
  1499.             n = _ttoi(str);
  1500.             if (n > 0 && n < 65536)
  1501.                 group.nSpeedLimit[i] = n;
  1502.  
  1503.             str = pXML->GetChildAttrib("Server" + prefixes[i] + "LimitBypass");
  1504.             n = _ttoi(str);
  1505.             if (n >= 0 && n < 4)
  1506.                 group.nBypassServerSpeedLimit[i] = n;
  1507.  
  1508.             pXML->IntoElem();
  1509.  
  1510.             while (pXML->FindChildElem(names[i]))
  1511.             {
  1512.                 pXML->IntoElem();
  1513.  
  1514.                 while (pXML->FindChildElem(_T("Rule")))
  1515.                 {
  1516.                     CSpeedLimit limit;
  1517.                     str = pXML->GetChildAttrib("Speed");
  1518.                     n = _ttoi(str);
  1519.                     if (n < 0 || n > 65535)
  1520.                         n = 10;
  1521.                     limit.m_Speed = n;
  1522.             
  1523.                     pXML->IntoElem();
  1524.             
  1525.                     if (pXML->FindChildElem("Days"))
  1526.                     {
  1527.                         str = pXML->GetChildData();
  1528.                         if (str != "")
  1529.                             n = _ttoi(str);
  1530.                         else
  1531.                             n = 0x7F;
  1532.                         limit.m_Day = n & 0x7F;
  1533.                     }
  1534.                     pXML->ResetChildPos();
  1535.             
  1536.                     limit.m_DateCheck = FALSE;
  1537.                     if (pXML->FindChildElem("Date"))
  1538.                     {
  1539.                         limit.m_DateCheck = TRUE;
  1540.                         str = pXML->GetChildAttrib("Year");
  1541.                         n = _ttoi(str);
  1542.                         if (n < 1900 || n > 3000)
  1543.                             n = 2003;
  1544.                         limit.m_Date.y = n;
  1545.                         str = pXML->GetChildAttrib("Month");
  1546.                         n = _ttoi(str);
  1547.                         if (n < 1 || n > 12)
  1548.                             n = 1;
  1549.                         limit.m_Date.m = n;
  1550.                         str = pXML->GetChildAttrib("Day");
  1551.                         n = _ttoi(str);
  1552.                         if (n < 1 || n > 31)
  1553.                             n = 1;
  1554.                         limit.m_Date.d = n;
  1555.                     }
  1556.                     pXML->ResetChildPos();
  1557.             
  1558.                     limit.m_FromCheck = FALSE;
  1559.                     if (pXML->FindChildElem("From"))
  1560.                     {
  1561.                         limit.m_FromCheck = TRUE;
  1562.                         str = pXML->GetChildAttrib("Hour");
  1563.                         n = _ttoi(str);
  1564.                         if (n < 0 || n > 23)
  1565.                             n = 0;
  1566.                         limit.m_FromTime.h = n;
  1567.                         str = pXML->GetChildAttrib("Minute");
  1568.                         n = _ttoi(str);
  1569.                         if (n < 0 || n > 59)
  1570.                             n = 0;
  1571.                         limit.m_FromTime.m = n;
  1572.                         str = pXML->GetChildAttrib("Second");
  1573.                         n = _ttoi(str);
  1574.                         if (n < 0 || n > 59)
  1575.                             n = 0;
  1576.                         limit.m_FromTime.s = n;
  1577.                     }
  1578.                     pXML->ResetChildPos();
  1579.  
  1580.                     limit.m_ToCheck = FALSE;
  1581.                     if (pXML->FindChildElem("To"))
  1582.                     {
  1583.                         limit.m_ToCheck = TRUE;
  1584.                         str = pXML->GetChildAttrib("Hour");
  1585.                         n = _ttoi(str);
  1586.                         if (n < 0 || n > 23)
  1587.                             n = 0;
  1588.                         limit.m_ToTime.h = n;
  1589.                         str = pXML->GetChildAttrib("Minute");
  1590.                         n = _ttoi(str);
  1591.                         if (n < 0 || n > 59)
  1592.                             n = 0;
  1593.                         limit.m_ToTime.m = n;
  1594.                         str = pXML->GetChildAttrib("Second");
  1595.                         n = _ttoi(str);
  1596.                         if (n < 0 || n > 59)
  1597.                             n = 0;
  1598.                         limit.m_ToTime.s = n;
  1599.                     }
  1600.                     pXML->ResetChildPos();
  1601.             
  1602.                     pXML->OutOfElem();
  1603.  
  1604.                     if (group.SpeedLimits[i].size() < 20000)
  1605.                         group.SpeedLimits[i].push_back(limit);
  1606.                 }
  1607.                 pXML->OutOfElem();
  1608.             }
  1609.             pXML->ResetChildPos();
  1610.             pXML->OutOfElem();
  1611.         }
  1612.     }
  1613. }
  1614.  
  1615. void CPermissions::SaveSpeedLimits(CMarkupSTL *pXML, const t_group &group)
  1616. {
  1617.     pXML->AddChildElem(_T("SpeedLimits"));
  1618.  
  1619.     CStdString str;
  1620.  
  1621.     const CStdString prefixes[] = { "Dl", "Ul" };
  1622.     const CStdString names[] = { "Download", "Upload" };
  1623.  
  1624.     for (int i = 0; i < 2; i++)
  1625.     {
  1626.         pXML->SetChildAttrib(prefixes[i] + "Type", group.nSpeedLimitType[i]);
  1627.         pXML->SetChildAttrib(prefixes[i] + "Limit", group.nSpeedLimit[i]);
  1628.         pXML->SetChildAttrib("Server" + prefixes[i] + "LimitBypass", group.nBypassServerSpeedLimit[i]);
  1629.     
  1630.         pXML->IntoElem();
  1631.  
  1632.         pXML->AddChildElem(names[i]);
  1633.         pXML->IntoElem();
  1634.         for (unsigned int j = 0; j < group.SpeedLimits[i].size(); j++)
  1635.         {
  1636.             CSpeedLimit limit = group.SpeedLimits[i][j];
  1637.             pXML->AddChildElem(_T("Rule"));
  1638.  
  1639.             pXML->SetChildAttrib(_T("Speed"), limit.m_Speed);
  1640.  
  1641.             pXML->IntoElem();
  1642.  
  1643.             str.Format("%d", limit.m_Day);
  1644.             pXML->AddChildElem(_T("Days"), str);
  1645.  
  1646.             if (limit.m_DateCheck)
  1647.             {
  1648.                 pXML->AddChildElem(_T("Date"));
  1649.                 pXML->SetChildAttrib(_T("Year"), limit.m_Date.y);
  1650.                 pXML->SetChildAttrib(_T("Month"), limit.m_Date.m);
  1651.                 pXML->SetChildAttrib(_T("Day"), limit.m_Date.d);
  1652.             }
  1653.  
  1654.             if (limit.m_FromCheck)
  1655.             {
  1656.                 pXML->AddChildElem(_T("From"));
  1657.                 pXML->SetChildAttrib(_T("Hour"), limit.m_FromTime.h);
  1658.                 pXML->SetChildAttrib(_T("Minute"), limit.m_FromTime.m);
  1659.                 pXML->SetChildAttrib(_T("Second"), limit.m_FromTime.s);
  1660.             }
  1661.     
  1662.             if (limit.m_ToCheck)
  1663.             {
  1664.                 pXML->AddChildElem(_T("To"));
  1665.                 pXML->SetChildAttrib(_T("Hour"), limit.m_ToTime.h);
  1666.                 pXML->SetChildAttrib(_T("Minute"), limit.m_ToTime.m);
  1667.                 pXML->SetChildAttrib(_T("Second"), limit.m_ToTime.s);
  1668.             }
  1669.  
  1670.             pXML->OutOfElem();
  1671.         }
  1672.         pXML->OutOfElem();
  1673.         pXML->OutOfElem();
  1674.     }
  1675. }
  1676.  
  1677. void CPermissions::ReloadConfig()
  1678. {
  1679.     m_UsersList.clear();
  1680.     m_GroupsList.clear();
  1681.  
  1682.     EnterCritSection(m_sync);
  1683.  
  1684.     ReadSettings();
  1685.  
  1686.     UpdateInstances();
  1687.  
  1688.     LeaveCritSection(m_sync);
  1689.  
  1690.     return;
  1691. }
  1692.  
  1693. void CPermissions::ReadIpFilter(CMarkupSTL *pXML, t_group &group)
  1694. {
  1695.     pXML->ResetChildPos();
  1696.     while (pXML->FindChildElem(_T("IpFilter")))
  1697.     {
  1698.         pXML->IntoElem();
  1699.         while (pXML->FindChildElem(_T("Disallowed")))
  1700.         {
  1701.             pXML->IntoElem();
  1702.             while (pXML->FindChildElem(_T("IP")))
  1703.             {
  1704.                 CStdString ip = pXML->GetChildData();
  1705.                 if (group.disallowedIPs.size() >= 20000)
  1706.                     break;
  1707.  
  1708.                 if (ip == "*")
  1709.                     group.disallowedIPs.push_back(ip);
  1710.                 else
  1711.                 {
  1712.                     if (IsValidAddressFilter(ip))
  1713.                         group.disallowedIPs.push_back(ip);
  1714.                 }
  1715.             }
  1716.             pXML->OutOfElem();
  1717.         }
  1718.         pXML->ResetChildPos();
  1719.         while (pXML->FindChildElem(_T("Allowed")))
  1720.         {
  1721.             pXML->IntoElem();
  1722.             while (pXML->FindChildElem(_T("IP")))
  1723.             {
  1724.                 CStdString ip = pXML->GetChildData();
  1725.                 if (group.allowedIPs.size() >= 20000)
  1726.                     break;
  1727.  
  1728.                 if (ip == "*")
  1729.                     group.allowedIPs.push_back(ip);
  1730.                 else
  1731.                 {
  1732.                     if (IsValidAddressFilter(ip))
  1733.                         group.allowedIPs.push_back(ip);
  1734.                 }
  1735.             }
  1736.             pXML->OutOfElem();
  1737.         }
  1738.         pXML->OutOfElem();
  1739.     }
  1740. }
  1741.  
  1742. void CPermissions::SaveIpFilter(CMarkupSTL *pXML, const t_group &group)
  1743. {
  1744.     pXML->AddChildElem(_T("IpFilter"));
  1745.     pXML->IntoElem();
  1746.     pXML->AddChildElem(_T("Disallowed"));
  1747.     pXML->IntoElem();
  1748.     std::list<CStdString>::const_iterator iter;
  1749.     for (iter = group.disallowedIPs.begin(); iter != group.disallowedIPs.end(); iter++)
  1750.     {
  1751.         pXML->AddChildElem(_T("IP"));
  1752.         pXML->SetChildData(*iter);
  1753.     }
  1754.     pXML->OutOfElem();
  1755.  
  1756.     pXML->AddChildElem(_T("Allowed"));
  1757.     pXML->IntoElem();
  1758.     for (iter = group.allowedIPs.begin(); iter != group.allowedIPs.end(); iter++)
  1759.     {
  1760.         pXML->AddChildElem(_T("IP"));
  1761.         pXML->SetChildData(*iter);
  1762.     }
  1763.     pXML->OutOfElem();
  1764.  
  1765.     pXML->OutOfElem();
  1766. }
  1767.  
  1768. CStdString CPermissions::CanonifyServerDir(CStdString currentDir, CStdString newDir) const
  1769. {
  1770.     /*
  1771.      * CanonifyPath takes the current and the new server dir as parameter,
  1772.      * concats the paths if neccessary and canonifies the dir:
  1773.      * - remove dot-segments
  1774.      * - convert backslashes into slashes
  1775.      * - remove double slashes
  1776.      */
  1777.  
  1778.     if (newDir == "")
  1779.         return currentDir;
  1780.  
  1781.     // Make segment separators pretty
  1782.     newDir.Replace("\\", "/");
  1783.     while (newDir.Replace("//", "/"));
  1784.     
  1785.     if (newDir == "/")
  1786.         return newDir;
  1787.     
  1788.     // This list will hold the individual path segments
  1789.     std::list<CStdString> piecelist;
  1790.     
  1791.     /*
  1792.      * Check the type of the path: Absolute or relative?
  1793.      * On relative paths, use currentDir as base, else use
  1794.      * only dir.
  1795.      */
  1796.     if (newDir.Left(1) != "/")
  1797.     {
  1798.         // New relative path, split currentDir and add it to the piece list.
  1799.         currentDir.TrimLeft("/");
  1800.         int pos;
  1801.         while((pos = currentDir.Find("/")) != -1)
  1802.         {
  1803.             piecelist.push_back(currentDir.Left(pos));
  1804.             currentDir = currentDir.Mid(pos + 1);
  1805.         }
  1806.         if (currentDir != "")
  1807.             piecelist.push_back(currentDir);
  1808.     }
  1809.     
  1810.     /*
  1811.      * Now split up the new dir into individual segments. Here we
  1812.      * check for dot segments and remove the proper number of segments
  1813.      * from the piece list on dots.
  1814.      */
  1815.     
  1816.     int pos;
  1817.     newDir.TrimLeft("/");
  1818.     if (newDir.Right(1) != "/")
  1819.         newDir += "/";
  1820.     while ((pos = newDir.Find("/")) != -1)
  1821.     {
  1822.         CStdString piece = newDir.Left(pos);
  1823.         newDir = newDir.Mid(pos + 1);
  1824.  
  1825.         if (piece == _T(""))
  1826.             continue;
  1827.  
  1828.         bool allDots = true;
  1829.         int dotCount = 0;
  1830.         for (int i = 0; i < piece.GetLength(); i++)
  1831.             if (piece[i] != '.')
  1832.             {
  1833.                 allDots = false;
  1834.                 break;
  1835.             }
  1836.             else
  1837.                 dotCount++;
  1838.  
  1839.         if (allDots)
  1840.         {
  1841.             while (--dotCount)
  1842.             {
  1843.                 if (!piecelist.empty())
  1844.                     piecelist.pop_back();
  1845.             }
  1846.         }
  1847.         else
  1848.             piecelist.push_back(piece);
  1849.     }
  1850.  
  1851.     // Reassemble the directory
  1852.     CStdString result;
  1853.  
  1854.     if (piecelist.empty())
  1855.         return "/";
  1856.  
  1857.     const char *(x[23]) = { "OK", "k", "k" };
  1858.     // List of reserved filenames which may not be used on a Windows system
  1859.     const char *reservedNames[] = { "CON", "PRN", "AUX", "CLOCK$", "NUL",
  1860.                                     "COM1", "COM2", "COM3", "COM4", "COM5",
  1861.                                     "COM6", "COM7", "COM8", "COM9",
  1862.                                     "LPT1", "LPT2", "LPT3", "LPT4", "LPT5",
  1863.                                     "LPT6", "LPT7", "LPT8", "LPT9", "" };
  1864.  
  1865.     for (std::list<CStdString>::iterator iter = piecelist.begin(); iter != piecelist.end(); iter++)
  1866.     {
  1867.         // Check for reserved filenames
  1868.         CStdString piece = *iter;
  1869.         piece.MakeUpper();
  1870.         for (const char **reserved = reservedNames; **reserved; reserved++)
  1871.         {
  1872.             if (piece == *reserved)
  1873.                 return "";
  1874.         }
  1875.         int pos = piece.Find(".");
  1876.         if (pos >= 3)
  1877.         {
  1878.             piece = piece.Left(pos);
  1879.             for (const char **reserved = reservedNames; **reserved; reserved++)
  1880.             {
  1881.                 if (piece == *reserved)
  1882.                     return "";
  1883.             }
  1884.         }
  1885.  
  1886.         result += "/" + *iter;
  1887.     }
  1888.  
  1889.     // Now dir is the canonified absolute server path.
  1890.     return result;
  1891. }
  1892.  
  1893. int CPermissions::GetFact(LPCTSTR username, CStdString currentDir, CStdString file, CStdString& fact, CStdString& logicalName)
  1894. {
  1895.     // Get user from username
  1896.     CUser user;
  1897.     if (!GetUser(username, user))
  1898.         return PERMISSION_DENIED; // No user found
  1899.  
  1900.     CStdString dir = CanonifyServerDir(currentDir, file);
  1901.     if (dir == "")
  1902.         return PERMISSION_INVALIDNAME;
  1903.     logicalName = dir;
  1904.  
  1905.     t_directory directory;
  1906.     BOOL bTruematch;
  1907.     int res = GetRealDirectory(dir, user, directory, bTruematch);
  1908.     if (res == PERMISSION_FILENOTDIR)
  1909.     {
  1910.         if (dir == "/")
  1911.             return res;
  1912.  
  1913.         int pos = dir.ReverseFind('/');
  1914.         if (pos == -1)
  1915.             return res;
  1916.  
  1917.         CStdString dir2;
  1918.         if (pos)
  1919.             dir2 = dir.Left(pos);
  1920.         else
  1921.             dir2 = "/";
  1922.  
  1923.         CStdString fn = dir.Mid(pos + 1);
  1924.         int res = GetRealDirectory(dir2, user, directory, bTruematch);
  1925.         if (res)
  1926.             return res | PERMISSION_FILENOTDIR;
  1927.  
  1928.         if (!directory.bFileRead)
  1929.             return PERMISSION_DENIED;
  1930.  
  1931.         file = directory.dir + "\\" + fn;
  1932.         
  1933.         fact = "type=file;";
  1934.     }
  1935.     else if (res)
  1936.         return res;
  1937.     else
  1938.     {
  1939.         if (!directory.bDirList)
  1940.             return PERMISSION_DENIED;
  1941.  
  1942.         if (!bTruematch && !directory.bDirSubdirs)
  1943.             return PERMISSION_DENIED;
  1944.  
  1945.         file = directory.dir;
  1946.  
  1947.         fact = "type=dir;";
  1948.     }
  1949.  
  1950.     CFileStatus64 status;
  1951.     if (GetStatus64(file, status))
  1952.     {
  1953.         if (!(status.m_attribute & FILE_ATTRIBUTE_DIRECTORY))
  1954.         {
  1955.             CStdString str;
  1956.             str.Format("size=%I64d;", status.m_size);
  1957.             fact += str;
  1958.         }
  1959.  
  1960.         // Get last modification time
  1961.         FILETIME ftime = status.m_mtime;
  1962.         if (!ftime.dwHighDateTime && !ftime.dwLowDateTime)
  1963.             ftime = status.m_ctime;
  1964.         if (ftime.dwHighDateTime || ftime.dwLowDateTime)
  1965.         {
  1966.             SYSTEMTIME time;
  1967.             FileTimeToSystemTime(&ftime, &time);
  1968.             CStdString str;
  1969.             str.Format("modify=%04d%02d%02d%02d%02d%02d;",
  1970.                 time.wYear,
  1971.                 time.wMonth,
  1972.                 time.wDay,
  1973.                 time.wHour,
  1974.                 time.wMinute,
  1975.                 time.wSecond);
  1976.  
  1977.             fact += str;
  1978.         }
  1979.     }
  1980.  
  1981.     fact += " " + logicalName;
  1982.  
  1983.     return 0;
  1984. }
  1985.  
  1986. int CPermissions::GetFacts(LPCTSTR username, CStdString currentDir, CStdString file, t_dirlisting *&pResult, CStdString &physicalDir, CStdString &logicalDir)
  1987. {
  1988.     // Get user from username
  1989.     CUser user;
  1990.     if (!GetUser(username, user))
  1991.         return PERMISSION_DENIED; // No user found
  1992.  
  1993.     CStdString dir = CanonifyServerDir(currentDir, file);
  1994.     if (dir == "")
  1995.         return PERMISSION_INVALIDNAME;
  1996.  
  1997.     t_directory directory;
  1998.     BOOL bTruematch;
  1999.     int res = GetRealDirectory(dir, user, directory, bTruematch);
  2000.     if (res)
  2001.         return res;
  2002.  
  2003.     if (!directory.bDirList)
  2004.         return PERMISSION_DENIED;
  2005.  
  2006.     logicalDir = dir;
  2007.     physicalDir = directory.dir;
  2008.  
  2009.     t_dirlisting *pDir = new t_dirlisting;
  2010.     pDir->len = 0;
  2011.     pDir->pNext = NULL;
  2012.     pResult = pDir;
  2013.  
  2014.     CStdString curDir = directory.dir;
  2015.     curDir.MakeLower();
  2016.  
  2017.     // List aliases in current directory
  2018.     for (std::multimap<CStdString, CUser::t_alias>::const_iterator iter = user.aliasMap.find(curDir);
  2019.          iter != user.aliasMap.end() && iter->first == curDir; iter++)
  2020.     {
  2021.         t_directory directory;
  2022.         BOOL truematch = false;
  2023.         if (GetRealDirectory(dir + "/" + iter->second.name, user, directory, truematch))
  2024.             continue;
  2025.         if (!directory.bDirList)
  2026.             continue;
  2027.         if (!truematch && !directory.bDirSubdirs)
  2028.             continue;
  2029.  
  2030.         // This wastes some memory but keeps the whole thing fast
  2031.         if ((8192 - pDir->len) < (60 + MAX_PATH))
  2032.         {
  2033.             pDir->pNext = new t_dirlisting;
  2034.             pDir = pDir->pNext;
  2035.             pDir->len = 0;
  2036.             pDir->pNext = NULL;
  2037.         }
  2038.  
  2039.         memcpy(pDir->buffer + pDir->len, "type=dir;", 9);
  2040.             pDir->len += 9;
  2041.  
  2042.         CFileStatus64 status;
  2043.         if (GetStatus64(directory.dir, status))
  2044.         {
  2045.             // Get last modification time
  2046.             FILETIME ftime = status.m_mtime;
  2047.             if (!ftime.dwHighDateTime && !ftime.dwLowDateTime)
  2048.                 ftime = status.m_ctime;
  2049.             if (ftime.dwHighDateTime || ftime.dwLowDateTime)
  2050.             {
  2051.                 SYSTEMTIME time;
  2052.                 FileTimeToSystemTime(&ftime, &time);
  2053.                 CStdString str;
  2054.                 str.Format("modify=%04d%02d%02d%02d%02d%02d;",
  2055.                             time.wYear,
  2056.                             time.wMonth,
  2057.                             time.wDay,
  2058.                             time.wHour,
  2059.                             time.wMinute,
  2060.                             time.wSecond);
  2061.  
  2062.                 memcpy(pDir->buffer + pDir->len, str.c_str(), str.GetLength());
  2063.                 pDir->len += str.GetLength();
  2064.             }
  2065.         }
  2066.  
  2067.         pDir->buffer[pDir->len++] = ' ';
  2068.         memcpy(pDir->buffer + pDir->len, iter->second.name.c_str(), iter->second.name.GetLength());
  2069.         pDir->len += iter->second.name.GetLength();
  2070.         pDir->buffer[pDir->len++] = '\r';
  2071.         pDir->buffer[pDir->len++] = '\n';
  2072.     }
  2073.  
  2074.     WIN32_FIND_DATA FindFileData;
  2075.     WIN32_FIND_DATA NextFindFileData;
  2076.     HANDLE hFind;
  2077.     hFind = FindFirstFile(directory.dir + "\\*", &NextFindFileData);
  2078.     while (hFind != INVALID_HANDLE_VALUE)
  2079.     {
  2080.         FindFileData = NextFindFileData;
  2081.         if (!FindNextFile(hFind, &NextFindFileData))
  2082.         {
  2083.             FindClose(hFind);
  2084.             hFind = INVALID_HANDLE_VALUE;
  2085.         }
  2086.  
  2087.         if (!_tcscmp(FindFileData.cFileName, _T(".")) || !_tcscmp(FindFileData.cFileName, _T("..")))
  2088.             continue;
  2089.  
  2090.         // This wastes some memory but keeps the whole thing fast
  2091.         if ((8192 - pDir->len) < (60 + MAX_PATH))
  2092.         {
  2093.             pDir->pNext = new t_dirlisting;
  2094.             pDir = pDir->pNext;
  2095.             pDir->len = 0;
  2096.             pDir->pNext = NULL;
  2097.         }
  2098.  
  2099.         bool file;
  2100.         if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  2101.         {
  2102.             // Check permissions of subdir. If we don't have LIST permission,
  2103.             // don't display the subdir.
  2104.             BOOL truematch;
  2105.             t_directory subDir;
  2106.             if (GetRealDirectory(dir + "/" + FindFileData.cFileName, user, subDir, truematch))
  2107.                 continue;
  2108.  
  2109.             if (!subDir.bDirList)
  2110.                 continue;
  2111.  
  2112.             file = false;
  2113.  
  2114.             memcpy(pDir->buffer + pDir->len, "type=dir;", 9);
  2115.             pDir->len += 9;
  2116.         }
  2117.         else
  2118.         {
  2119.             file = true;
  2120.             memcpy(pDir->buffer + pDir->len, "type=file;", 10);
  2121.             pDir->len += 10;
  2122.         }
  2123.  
  2124.         // Get last modification time
  2125.         FILETIME ftime = FindFileData.ftLastWriteTime;
  2126.         if (!ftime.dwHighDateTime && !ftime.dwLowDateTime)
  2127.             ftime = FindFileData.ftCreationTime;
  2128.         if (ftime.dwHighDateTime || ftime.dwLowDateTime)
  2129.         {
  2130.             SYSTEMTIME time;
  2131.             FileTimeToSystemTime(&ftime, &time);
  2132.             CStdString str;
  2133.             str.Format("modify=%04d%02d%02d%02d%02d%02d;",
  2134.                         time.wYear,
  2135.                         time.wMonth,
  2136.                         time.wDay,
  2137.                         time.wHour,
  2138.                         time.wMinute,
  2139.                         time.wSecond);
  2140.  
  2141.             memcpy(pDir->buffer + pDir->len, str.c_str(), str.GetLength());
  2142.             pDir->len += str.GetLength();
  2143.         }
  2144.         if (file)
  2145.         {
  2146.             CStdString size;
  2147.             size.Format("size=%I64d;", FindFileData.nFileSizeLow + ((_int64)FindFileData.nFileSizeHigh<<32));
  2148.             memcpy(pDir->buffer + pDir->len, size.c_str(), size.GetLength());
  2149.             pDir->len += size.GetLength();
  2150.         }
  2151.  
  2152.         pDir->buffer[pDir->len++] = ' ';
  2153.         memcpy(pDir->buffer + pDir->len, FindFileData.cFileName, strlen(FindFileData.cFileName));
  2154.         pDir->len += strlen(FindFileData.cFileName);
  2155.         pDir->buffer[pDir->len++] = '\r';
  2156.         pDir->buffer[pDir->len++] = '\n';
  2157.     }
  2158.  
  2159.     return 0;
  2160. }
  2161.  
  2162. void CUser::PrepareAliasMap()
  2163. {
  2164.     /*
  2165.      * Prepare the alias map.
  2166.      * For fast access, aliases are stored as key/value pairs.
  2167.      * The key is the folder part of the alias.
  2168.      * The value is a structure containing the name of the alias
  2169.      * and the target folder.
  2170.      * Example:
  2171.      * Shared folder c:\myfolder, alias d:\myotherfolder\myalias
  2172.      * Key: d:\myotherfolder, Value = myalias, c:\myfolder
  2173.      */
  2174.  
  2175.     aliasMap.clear();
  2176.     std::vector<t_directory>::const_iterator permIter;
  2177.     std::list<CStdString>::const_iterator aliasIter;
  2178.     for (permIter = permissions.begin(); permIter != permissions.end(); permIter++)
  2179.     {
  2180.         for (aliasIter = permIter->aliases.begin(); aliasIter != permIter->aliases.end(); aliasIter++)
  2181.         {
  2182.             CStdString alias = *aliasIter;
  2183.             DoReplacements(alias);
  2184.             int pos = alias.ReverseFind('\\');
  2185.             if (pos == -1)
  2186.                 continue;
  2187.             t_alias aliasStruct;
  2188.             aliasStruct.name = alias.Mid(pos + 1);
  2189.             if (aliasStruct.name == "")
  2190.                 continue;
  2191.             alias = alias.Left(pos);
  2192.             alias.MakeLower();
  2193.  
  2194.             aliasStruct.targetFolder = permIter->dir;
  2195.             DoReplacements(aliasStruct.targetFolder);
  2196.  
  2197.             aliasMap.insert(std::pair<CStdString, t_alias>(alias, aliasStruct));
  2198.         }
  2199.     }
  2200.  
  2201.     if (!pOwner)
  2202.         return;
  2203.  
  2204.     for (permIter = pOwner->permissions.begin(); permIter != pOwner->permissions.end(); permIter++)
  2205.     {
  2206.         for (aliasIter = permIter->aliases.begin(); aliasIter != permIter->aliases.end(); aliasIter++)
  2207.         {
  2208.             CStdString alias = *aliasIter;
  2209.             DoReplacements(alias);
  2210.             int pos = alias.ReverseFind('\\');
  2211.             if (pos == -1)
  2212.                 continue;
  2213.             t_alias aliasStruct;
  2214.             aliasStruct.name = alias.Mid(pos + 1);
  2215.             if (aliasStruct.name == "")
  2216.                 continue;
  2217.             alias = alias.Left(pos);
  2218.             alias.MakeLower();
  2219.  
  2220.             aliasStruct.targetFolder = permIter->dir;
  2221.             DoReplacements(aliasStruct.targetFolder);
  2222.         
  2223.             aliasMap.insert(std::pair<CStdString, t_alias>(alias, aliasStruct));
  2224.         }
  2225.     }
  2226. }
  2227.  
  2228. CStdString CUser::GetAliasTarget(CStdString path, CStdString name) const
  2229. {
  2230.     // Find the target for the alias with the specified path and name
  2231.  
  2232.     path.MakeLower();
  2233.  
  2234.     std::multimap<CStdString, CUser::t_alias>::const_iterator iter = aliasMap.find(path);
  2235.     bool foundAlias = false;
  2236.     while (iter != aliasMap.end() && iter->first == path)
  2237.     {
  2238.         if (!iter->second.name.CompareNoCase(name))
  2239.             return iter->second.targetFolder;
  2240.  
  2241.         iter++;
  2242.     }
  2243.  
  2244.     return "";
  2245. }
  2246.  
  2247. void CPermissions::ReadSettings()
  2248. {
  2249.     CMarkupSTL *pXML = COptions::GetXML();
  2250.     if (!pXML)
  2251.         return;
  2252.     
  2253.     if (!pXML->FindChildElem(_T("Groups")))
  2254.         pXML->AddChildElem(_T("Groups"));
  2255.     pXML->IntoElem();
  2256.     while (pXML->FindChildElem(_T("Group")))
  2257.     {
  2258.         t_group group;
  2259.         group.nIpLimit = group.nIpLimit = group.nUserLimit = 0;
  2260.         group.nBypassUserLimit = 2;
  2261.         group.group = pXML->GetChildAttrib(_T("Name"));
  2262.         if (group.group!="")
  2263.         {
  2264.             pXML->IntoElem();
  2265.         
  2266.             while (pXML->FindChildElem(_T("Option")))
  2267.             {
  2268.                 CStdString name = pXML->GetChildAttrib(_T("Name"));
  2269.                 CStdString value = pXML->GetChildData();
  2270.                 if (name == _T("Bypass server userlimit"))
  2271.                     group.nBypassUserLimit = _ttoi(value);
  2272.                 else if (name == _T("User Limit"))
  2273.                     group.nUserLimit = _ttoi(value);
  2274.                 else if (name == _T("IP Limit"))
  2275.                     group.nIpLimit = _ttoi(value);
  2276.                 else if (name == _T("Enabled"))
  2277.                     group.nEnabled = _ttoi(value);
  2278.                 else if (name == _T("Comments"))
  2279.                     group.comment = value;
  2280.                 else if (name == _T("ForceSsl"))
  2281.                     group.forceSsl = _ttoi(value);
  2282.  
  2283.                 if (group.nUserLimit<0 || group.nUserLimit>999999999)
  2284.                     group.nUserLimit=0;
  2285.                 if (group.nIpLimit<0 || group.nIpLimit>999999999)
  2286.                     group.nIpLimit=0;
  2287.             }
  2288.  
  2289.             ReadIpFilter(pXML, group);
  2290.                 
  2291.             BOOL bGotHome = FALSE;
  2292.             ReadPermissions(pXML, group, bGotHome);
  2293.             //Set a home dir if no home dir could be read
  2294.             if (!bGotHome && !group.permissions.empty())
  2295.                 group.permissions.begin()->bIsHome = TRUE;
  2296.  
  2297.             ReadSpeedLimits(pXML, group);
  2298.                 
  2299.             if (m_GroupsList.size() < 20000)
  2300.                 m_GroupsList.push_back(group);
  2301.             pXML->OutOfElem();
  2302.         }
  2303.     }
  2304.     pXML->OutOfElem();
  2305.     pXML->ResetChildPos();
  2306.         
  2307.     if (!pXML->FindChildElem(_T("Users")))
  2308.         pXML->AddChildElem(_T("Users"));
  2309.     pXML->IntoElem();
  2310.  
  2311.     while (pXML->FindChildElem(_T("User")))
  2312.     {
  2313.         CUser user;
  2314.         user.nIpLimit = user.nIpLimit = user.nUserLimit = 0;
  2315.         user.nBypassUserLimit = 2;
  2316.         user.user=pXML->GetChildAttrib(_T("Name"));
  2317.         if (user.user == "")
  2318.             continue;
  2319.  
  2320.         pXML->IntoElem();
  2321.  
  2322.         while (pXML->FindChildElem(_T("Option")))
  2323.         {
  2324.             CStdString name = pXML->GetChildAttrib(_T("Name"));
  2325.             CStdString value = pXML->GetChildData();
  2326.             if (name == _T("Pass"))
  2327.             {
  2328.                 // If provided password is not a MD5 has, convert it into a MD5 hash
  2329.                 if (value != "" && value.GetLength() != 32)
  2330.                 {
  2331.                     const char *tmp = value;
  2332.                     MD5 md5;
  2333.                     md5.update((unsigned char *)tmp, _tcslen(tmp));
  2334.                     md5.finalize();
  2335.                     char *res = md5.hex_digest();
  2336.                     pXML->SetChildData(res);
  2337.                     user.password = res;
  2338.                     delete [] res;
  2339.                 }
  2340.                 else
  2341.                     user.password = value;
  2342.             }
  2343.             else if (name == _T("Bypass server userlimit"))
  2344.                 user.nBypassUserLimit = _ttoi(value);
  2345.             else if (name == _T("User Limit"))
  2346.                 user.nUserLimit = _ttoi(value);
  2347.             else if (name == _T("IP Limit"))
  2348.                 user.nIpLimit = _ttoi(value);
  2349.             else if (name == _T("Group"))
  2350.                 user.group = value;
  2351.             else if (name == _T("Enabled"))
  2352.                 user.nEnabled = _ttoi(value);
  2353.             else if (name == _T("Comments"))
  2354.                 user.comment = value;
  2355.             else if (name == _T("ForceSsl"))
  2356.                 user.forceSsl = _ttoi(value);
  2357.  
  2358.             if (user.nUserLimit < 0 || user.nUserLimit > 999999999)
  2359.                 user.nUserLimit = 0;
  2360.             if (user.nIpLimit < 0 || user.nIpLimit > 999999999)
  2361.                 user.nIpLimit = 0;
  2362.         }
  2363.  
  2364.         if (user.group != _T(""))
  2365.         {
  2366.             for (t_GroupsList::iterator groupiter = m_GroupsList.begin(); groupiter != m_GroupsList.end(); groupiter++)
  2367.                 if (groupiter->group == user.group)
  2368.                 {
  2369.                     user.pOwner = &(*groupiter);
  2370.                     break;
  2371.                 }
  2372.         
  2373.             if (!user.pOwner)
  2374.                 user.group = "";
  2375.         }
  2376.             
  2377.         ReadIpFilter(pXML, user);
  2378.  
  2379.         BOOL bGotHome = FALSE;
  2380.         ReadPermissions(pXML, user, bGotHome);
  2381.         user.PrepareAliasMap();
  2382.                 
  2383.         //Set a home dir if no home dir could be read
  2384.         if (!bGotHome && !user.pOwner)
  2385.         {
  2386.             if (!user.permissions.empty())
  2387.                 user.permissions.begin()->bIsHome = TRUE;
  2388.         }
  2389.             
  2390.         std::vector<t_directory>::iterator iter;
  2391.         for (iter = user.permissions.begin(); iter != user.permissions.end(); iter++)
  2392.         {
  2393.             if (iter->bIsHome)
  2394.             {
  2395.                 user.homedir = iter->dir;
  2396.                 break;
  2397.             }
  2398.         }
  2399.         if (user.homedir == "" && user.pOwner)
  2400.         {
  2401.             for (iter = user.pOwner->permissions.begin(); iter != user.pOwner->permissions.end(); iter++)
  2402.             {
  2403.                 if (iter->bIsHome)
  2404.                 {
  2405.                     user.homedir = iter->dir;
  2406.                     break;
  2407.                 }
  2408.             }
  2409.         }
  2410.             
  2411.         ReadSpeedLimits(pXML, user);
  2412.  
  2413.         if (m_UsersList.size() < 20000)
  2414.             m_UsersList.push_back(user);
  2415.         pXML->OutOfElem();
  2416.     }
  2417.     COptions::FreeXML(pXML);
  2418.  
  2419.     EnterCritSection(m_sync);
  2420.  
  2421.     m_sGroupsList.clear();
  2422.     for (t_GroupsList::iterator groupiter = m_GroupsList.begin(); groupiter != m_GroupsList.end(); groupiter++)
  2423.         m_sGroupsList.push_back(*groupiter);
  2424.  
  2425.     m_sUsersList.clear();
  2426.     for (t_UsersList::iterator iter = m_UsersList.begin(); iter != m_UsersList.end(); iter++)
  2427.     {
  2428.         CUser user = *iter;
  2429.         user.pOwner = NULL;
  2430.         if (user.group != _T(""))
  2431.         {
  2432.             for (t_GroupsList::iterator groupiter = m_GroupsList.begin(); groupiter != m_GroupsList.end(); groupiter++)
  2433.                 if (groupiter->group == user.group)
  2434.                 {
  2435.                     user.pOwner = &(*groupiter);
  2436.                     break;
  2437.                 }
  2438.         }
  2439.         m_sUsersList.push_back(user);
  2440.     }
  2441.  
  2442.     LeaveCritSection(m_sync);
  2443. }
  2444.  
  2445. // Replace :u and :g (if a group it exists)
  2446. void CUser::DoReplacements(CStdString& path) const
  2447. {
  2448.     path.Replace(":u", user);
  2449.     path.Replace(":U", user);
  2450.     if (group != _T(""))
  2451.     {
  2452.         path.Replace(":g", group);
  2453.         path.Replace(":G", group);
  2454.     }
  2455. }
  2456.