• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/Permissions.cpp

00001 /* Ported to SPL, original attribution below. */
00002 /* ---------------------------------------------------------------------------
00003    commonc++ - A C++ Common Class Library
00004    Copyright (C) 2005-2009  Mark A Lindner
00005 
00006    Ported from commonc++.
00007 
00008    This library is free software; you can redistribute it and/or
00009    modify it under the terms of the GNU Library General Public
00010    License as published by the Free Software Foundation; either
00011    version 2 of the License, or (at your option) any later version.
00012 
00013    This library is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016    Library General Public License for more details.
00017 
00018    You should have received a copy of the GNU Library General Public
00019    License along with this library; if not, write to the Free
00020    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021    ---------------------------------------------------------------------------
00022 */
00023 #include <spl/Environment.h>
00024 #include <spl/io/Permissions.h>
00025 #include <spl/text/StringBuffer.h>
00026 #include <spl/io/WinPerm.h>
00027 
00028 #ifdef _WINDOWS
00029 
00030 #include <Tchar.h>
00031 #include <Lmcons.h>
00032 #include <aclapi.h>
00033 #include <accctrl.h>
00034 
00035 #define S_IRUSR 0400
00036 #define S_IWUSR 0200
00037 #define S_IXUSR 0100
00038 #define S_IRGRP 0040
00039 #define S_IWGRP 0020
00040 #define S_IXGRP 0010
00041 #define S_IROTH 0004
00042 #define S_IWOTH 0002
00043 #define S_IXOTH 0001
00044 
00045 #ifndef SECURITY_MAX_SID_SIZE
00046 #define SECURITY_MAX_SID_SIZE 68
00047 #endif
00048 
00049 #else
00050 
00051 #include <sys/stat.h>
00052 
00053 #endif
00054 
00055 const int Permissions::USER_READ = S_IRUSR,
00056   Permissions::USER_WRITE = S_IWUSR,
00057   Permissions::USER_READ_WRITE = (S_IRUSR | S_IWUSR),
00058   Permissions::USER_EXECUTE = S_IXUSR,
00059   Permissions::USER_ALL = (S_IRUSR | S_IWUSR | S_IXUSR),
00060   Permissions::GROUP_READ = S_IRGRP,
00061   Permissions::GROUP_WRITE = S_IWGRP,
00062   Permissions::GROUP_READ_WRITE = (S_IRGRP | S_IWGRP),
00063   Permissions::GROUP_EXECUTE = S_IXGRP,
00064   Permissions::GROUP_ALL = (S_IRGRP | S_IWGRP | S_IXGRP),
00065   Permissions::OTHERS_READ = S_IROTH,
00066   Permissions::OTHERS_WRITE = S_IWOTH,
00067   Permissions::OTHERS_READ_WRITE = (S_IROTH | S_IWOTH),
00068   Permissions::OTHERS_EXECUTE = S_IXOTH,
00069   Permissions::OTHERS_ALL = (S_IROTH | S_IWOTH | S_IXOTH),
00070   Permissions::ALL_READ_WRITE = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
00071                                  | S_IROTH | S_IWOTH),
00072   Permissions::ALLBITS = (USER_ALL | GROUP_ALL | OTHERS_ALL);
00073 
00074 /*
00075  */
00076 
00077 const Permissions Permissions::DefaultFilePerms(Permissions::USER_ALL
00078                                                 | Permissions::GROUP_READ);
00079 
00080 const Permissions Permissions::DefaultDirPerms(Permissions::USER_ALL
00081                                                | Permissions::GROUP_READ
00082                                                | Permissions::GROUP_EXECUTE);
00083 
00084 /*
00085  */
00086 
00087 Permissions::Permissions(uint32 mask /* = 0 */) throw()
00088   : _mask(mask & ALLBITS)
00089 {
00090 }
00091 
00092 /*
00093  */
00094 
00095 Permissions::Permissions(const Permissions& other) throw()
00096   : _mask(other._mask)
00097 {
00098 }
00099 
00100 /*
00101  */
00102 
00103 Permissions::~Permissions() throw()
00104 {
00105 }
00106 
00107 /*
00108  */
00109 
00110 Permissions& Permissions::operator=(const Permissions& other) throw()
00111 {
00112   _mask = other._mask;
00113   return(*this);
00114 }
00115 
00116 /*
00117  */
00118 
00119 StringPtr Permissions::ToString() const
00120 {
00121   StringBuffer s;
00122   s.Append("---------");
00123 
00124   for(int i = 2, x = 0; i >=0; --i)
00125   {
00126     unsigned int b = ((_mask >> (i * 3)) & 0x07);
00127 
00128     if(b & 4)
00129       s.SetCharAt(x, 'r');
00130     ++x;
00131 
00132     if(b & 2)
00133       s.SetCharAt(x, 'w');
00134     ++x;
00135 
00136     if(b & 1)
00137       s.SetCharAt(x, 'x');
00138     ++x;
00139   }
00140 
00141   return s.ToString();
00142 }
00143 
00144 #ifdef _WINDOWS
00145 
00146 #define LUSIZE 1024
00147 #define ACCT_NAME_SIZE LUSIZE
00148 #define ACL_SIZE 1024
00149 #define SID_SIZE LUSIZE  /* See support.h */
00150 #define DOM_SIZE LUSIZE
00151 
00152 // The commonc++ guy got this from http://fmgroup.polito.it/murciano/teachings/sp/CHAPTR15/InitUnFp.c
00153 bool FindPrimaryGroup(LPTSTR name)
00154 {
00155   /* Experimentation shows that the groups entered are as follows:
00156      0        -      None
00157      1        -      Everyone
00158      2        -      The first non-trivial group
00159      3...     -  Keep looking up to the count, which is part
00160      of the structure - see the documentation! */
00161 
00162         TCHAR RefDomain[DOM_SIZE];
00163         DWORD RefDomCnt = DOM_SIZE;
00164         SID_NAME_USE nameuse  = SidTypeGroup;
00165         HANDLE tHandle;
00166         TOKEN_GROUPS TokenG[512]; /* You need some space for this. */
00167         DWORD TISize, AcctSize = UNLEN + 1;
00168 
00169         if(! ::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS, &tHandle))
00170                 return false;
00171 
00172         if(! ::GetTokenInformation(tHandle, TokenGroups, &TokenG, sizeof(TokenG), &TISize))
00173         {
00174                 ::CloseHandle(tHandle);
00175                 return false;
00176         }
00177 
00178         if(! ::LookupAccountSid(NULL, TokenG[0].Groups[2].Sid, name, &AcctSize, RefDomain, &RefDomCnt, &nameuse))
00179         {
00180                 ::CloseHandle(tHandle);
00181                 return false;
00182         }
00183 
00184         ::CloseHandle(tHandle);
00185         return true;
00186 }
00187 
00188 // sets wperm from perm
00189 bool EncodePermissions(const Permissions& perm, _WinPerms &wperm)
00190 {
00191         if (NULL != wperm.pdesc)
00192         {
00193                 ::LocalFree(wperm.pdesc);
00194                 wperm.pdesc = NULL;
00195         }
00196 
00197         static uint32 masks[9] = { Permissions::USER_READ,
00198                                                          Permissions::USER_WRITE,
00199                                                          Permissions::USER_EXECUTE,
00200                                                          Permissions::GROUP_READ,
00201                                                          Permissions::GROUP_WRITE,
00202                                                          Permissions::GROUP_EXECUTE,
00203                                                          Permissions::OTHERS_READ,
00204                                                          Permissions::OTHERS_WRITE,
00205                                                          Permissions::OTHERS_EXECUTE };
00206 
00207         static int types[3] = { (FILE_READ_DATA | READ_CONTROL
00208                                                    | FILE_READ_ATTRIBUTES | FILE_READ_EA),
00209 
00210                                                   (FILE_WRITE_DATA | FILE_APPEND_DATA
00211                                                    | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA
00212                                                    | DELETE | FILE_DELETE_CHILD
00213                                                    | WRITE_DAC | WRITE_OWNER),
00214 
00215                                                   FILE_EXECUTE };
00216 
00218         
00219         bool status = false;
00220         int i;
00221 
00222         wperm.pdesc = (PSECURITY_DESCRIPTOR)::LocalAlloc(0, sizeof(SECURITY_DESCRIPTOR));
00223 
00224         if(! ::InitializeSecurityDescriptor(wperm.pdesc, SECURITY_DESCRIPTOR_REVISION))
00225                 return false;
00226 
00227         PACL pAcl = NULL;
00228         LPTSTR GrpNms[3] = { "", "", "Everyone" };
00229         PSID sids[3] = { NULL, NULL, NULL };
00230         SID_NAME_USE nameuse [] = { SidTypeUser, SidTypeGroup, SidTypeWellKnownGroup };
00231         TCHAR RefDomain[3][DOM_SIZE];
00232         TCHAR user[UNLEN + 1];
00233         DWORD RefDomSize[3] = { DOM_SIZE, DOM_SIZE, DOM_SIZE };
00234         DWORD sidSize[3] = { SECURITY_MAX_SID_SIZE, SECURITY_MAX_SID_SIZE,
00235                                                 SECURITY_MAX_SID_SIZE };
00236         DWORD sz = UNLEN + 1;
00237 
00238         if(! ::GetUserName(user, &sz))
00239                 return false;
00240 
00241         GrpNms[0] = user;
00242 
00243         // Get the user's primary group. 
00244 
00245         GrpNms[1] = (LPTSTR)::HeapAlloc(wperm.heap, 0, UNLEN + 1);
00246         if(GrpNms[1] == NULL)
00247                 return false;
00248 
00249         GrpNms[1][0] = 0;
00250         if (!FindPrimaryGroup(GrpNms[1]))
00251         {
00252                 return false;
00253         }
00254 
00255         for(i = 0; i < 3; i++)
00256         {
00257                 sids[i] = ::HeapAlloc(wperm.heap, 0, SECURITY_MAX_SID_SIZE);
00258                 if(sids[i] == NULL)
00259                         return false;
00260 
00261                 if(! ::LookupAccountName(NULL, GrpNms[i], sids[i], &sidSize[i],
00262                                                                  RefDomain[i], &RefDomSize[i], &nameuse[i]))
00263                 return false;
00264         }
00265 
00266         pAcl = (PACL)::HeapAlloc(wperm.heap, 0, ACL_SIZE);
00267         if(pAcl == NULL)
00268                 return false;
00269 
00270         if(! ::InitializeAcl(pAcl, ACL_SIZE, ACL_REVISION))
00271                 return false;
00272 
00273         // Add all the ACEs. Scan the permission bits, adding an allowed ACE when
00274         // the bit is set and a denied ACE when the bit is reset.
00275         for(i = 0; i < 9; i++)
00276         {
00277                 bool f = 0 != (perm & masks[i]);
00278                 bool ok;
00279 
00280                 if(f)
00281                         ok = 0 != ::AddAccessAllowedAce(pAcl, ACL_REVISION, types[i % 3], sids[i / 3]);
00282                 else
00283                         ok = 0 != ::AddAccessDeniedAce(pAcl, ACL_REVISION, types[i % 3], sids[i / 3]);
00284 
00285                 if(! ok)
00286                         return false;
00287         }
00288 
00289         // Add a final deny all to everyone ACE
00290 
00291         if(! ::AddAccessDeniedAce(pAcl, ACL_REVISION,
00292                                                         STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
00293                                                         sids[2]))
00294                 return false;
00295 
00296         // The ACL is now complete. Associate it with the security descriptor.
00297 
00298         if(! ::SetSecurityDescriptorDacl(wperm.pdesc, TRUE, pAcl, FALSE))
00299                 return false;
00300 
00301         if(! ::IsValidSecurityDescriptor(wperm.pdesc))
00302                 return false;
00303 
00304         return true;
00305 }
00306 
00307 // sets perm from wperm
00308 bool DecodePermissions(_WinPerms &wperm, Permissions &perm)
00309 {
00310         PSID _worldSID = NULL;
00311         TRUSTEE ident = { NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID };
00312         ACCESS_MASK mask;
00313 
00314         // user
00315 
00316         ident.TrusteeType = TRUSTEE_IS_USER;
00317         ident.ptstrName = (LPTSTR)wperm.user;
00318 
00319         if(::GetEffectiveRightsFromAcl(wperm.dacl, &ident, &mask) != ERROR_SUCCESS)
00320         {
00321                 return false;
00322         }
00323 
00324         (mask & FILE_READ_DATA) ? perm.SetUserRead() : perm.ClearUserRead();
00325         (mask & FILE_WRITE_DATA) ? perm.SetUserWrite() : perm.ClearUserWrite();
00326         (mask & FILE_EXECUTE) ? perm.SetUserExecute() : perm.ClearUserExecute();
00327 
00328         // group
00329 
00330         ident.TrusteeType = TRUSTEE_IS_GROUP;
00331         ident.ptstrName = (LPTSTR)wperm.group;
00332 
00333         if(::GetEffectiveRightsFromAcl(wperm.dacl, &ident, &mask) != ERROR_SUCCESS)
00334         {
00335                 return false;
00336         }
00337 
00338         (mask & FILE_READ_DATA) ? perm.SetGroupRead() : perm.ClearGroupRead();
00339         (mask & FILE_WRITE_DATA) ? perm.SetGroupWrite() : perm.ClearGroupWrite();
00340         (mask & FILE_EXECUTE) ? perm.SetGroupExecute() : perm.ClearGroupExecute();
00341 
00342         // world
00343         SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_WORLD_SID_AUTHORITY;
00344         ::AllocateAndInitializeSid(&sidAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &_worldSID);
00345 
00346         ident.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
00347         ident.ptstrName = (LPTSTR)_worldSID;
00348 
00349         if(::GetEffectiveRightsFromAcl(wperm.dacl, &ident, &mask) != ERROR_SUCCESS)
00350         {
00351             ::FreeSid(_worldSID);
00352                 return false;
00353         }
00354     ::FreeSid(_worldSID);
00355 
00356         (mask & FILE_READ_DATA) ? perm.SetOthersRead() : perm.ClearOthersRead();
00357         (mask & FILE_WRITE_DATA) ? perm.SetOthersWrite() : perm.ClearOthersWrite();
00358         (mask & FILE_EXECUTE) ? perm.SetOthersExecute() : perm.ClearOthersExecute();
00359 
00360         return true;
00361 }
00362 
00363 #else
00364 
00365 void EncodePermissions(const Permissions& perm, mode_t& mode)
00366 {
00367         mode = (mode_t)perm.GetMask();
00368 }
00369 
00370 
00371 void DecodePermissions(const mode_t mode, Permissions& perm)
00372 {
00373         perm = (uint32)(mode & 0777);
00374 }
00375 
00376 #endif
00377 
00378 /* end of source file */