libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
SecurityDescriptor.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright � 2002 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include "stdafx.h"
20 
22 
23 #include "../../../core/exception.hpp"
24 #include "../../../core/trace.hpp"
25 
26 /////////////////////////////////////////////////////////////////////////////
27 
28 using namespace libjmmcg;
29 using namespace NTUtils;
30 
31 /////////////////////////////////////////////////////////////////////////////
32 
34 
35 /////////////////////////////////////////////////////////////////////////////
36 
37 
38 #ifdef UNICODE
39  const TCHAR LookupAccountName_name[]=_T("LookupAccountNameW");
40 #else
41  const TCHAR LookupAccountName_name[]=_T("LookupAccountNameA");
42 #endif // !UNICODE
43 const TCHAR InitializeAcl_name[]=_T("InitializeAcl");
44 const TCHAR AddAccessAllowedAce_name[]=_T("AddAccessAllowedAce");
45 const TCHAR InitializeSecurityDescriptor_name[]=_T("InitializeSecurityDescriptor");
46 const TCHAR SetSecurityDescriptorDacl_name[]=_T("SetSecurityDescriptorDacl");
47 const TCHAR GetLengthSid_name[]=_T("GetLengthSid");
48 #ifdef _DEBUG
49  const TCHAR IsValidSid_name[]=_T("IsValidSid");
50  const TCHAR IsValidAcl_name[]=_T("IsValidAcl");
51  const TCHAR IsValidSecurityDescriptor_name[]=_T("IsValidSecurityDescriptor");
52 #endif
53 
54 /////////////////////////////////////////////////////////////////////////////
55 
56 inline
57 ACL_wrapper::ACL_wrapper(void)
58  : LoadLibraryWrapper(scm_lib_name),
59  pInitializeAcl(reinterpret_cast<InitializeAclType>(::GetProcAddress(Handle(),InitializeAcl_name))),
60  pAddAccessAllowedAce(reinterpret_cast<AddAccessAllowedAceType>(::GetProcAddress(Handle(),AddAccessAllowedAce_name))),
61 #ifdef _DEBUG
62  pIsValidAcl(reinterpret_cast<IsValidAclType>(::GetProcAddress(Handle(),IsValidAcl_name))),
63 #endif
64  size_(),buff() {
65 }
66 
67 inline
68 ACL_wrapper::ACL_wrapper(const unsigned long acl_size)
69  : LoadLibraryWrapper(scm_lib_name),
70  pInitializeAcl(reinterpret_cast<InitializeAclType>(::GetProcAddress(Handle(),InitializeAcl_name))),
71  pAddAccessAllowedAce(reinterpret_cast<AddAccessAllowedAceType>(::GetProcAddress(Handle(),AddAccessAllowedAce_name))),
72 #ifdef _DEBUG
73  pIsValidAcl(reinterpret_cast<IsValidAclType>(::GetProcAddress(Handle(),IsValidAcl_name))),
74 #endif
75  size_(acl_size),
76  buff(new BYTE[acl_size]) {
77 }
78 
79 inline
80 ACL_wrapper::ACL_wrapper(ACL_wrapper &sw)
81  : LoadLibraryWrapper(scm_lib_name),
82  pInitializeAcl(reinterpret_cast<InitializeAclType>(::GetProcAddress(Handle(),InitializeAcl_name))),
83  pAddAccessAllowedAce(reinterpret_cast<AddAccessAllowedAceType>(::GetProcAddress(Handle(),AddAccessAllowedAce_name))),
84 #ifdef _DEBUG
85  pIsValidAcl(reinterpret_cast<IsValidAclType>(::GetProcAddress(Handle(),IsValidAcl_name))),
86 #endif
87  size_(sw.size_),
88  buff(sw.buff) {
89 }
90 
91 inline
92 ACL_wrapper::~ACL_wrapper(void) {
93 }
94 
95 inline ACL_wrapper &
96 ACL_wrapper::operator=(ACL_wrapper &aw) {
97  size_=aw.size_;
98  buff=aw.buff;
99  return *this;
100 }
101 
102 inline void
103 ACL_wrapper::copy(const ACL_wrapper &aw) {
104  ::memcpy(buff.get(),aw.buff.get(),(size_<aw.size_) ? size_ : aw.size_);
105 }
106 
107 inline bool
108 ACL_wrapper::initialize(void) {
109  const bool ret=!(*pInitializeAcl)(reinterpret_cast<ACL*>(buff.get()),size_,ACL_REVISION);
110  assert((*pIsValidAcl)(reinterpret_cast<ACL *>(buff.get())));
111  return ret;
112 }
113 
114 inline bool
115 ACL_wrapper::add_ACE(const DWORD access_mask,SID *sid) {
116  const bool ret=(*pAddAccessAllowedAce)(reinterpret_cast<ACL *>(buff.get()),ACL_REVISION,access_mask,sid);
117  assert((*pIsValidAcl)(reinterpret_cast<ACL *>(buff.get())));
118  return ret;
119 }
120 
121 inline unsigned long
122 ACL_wrapper::size(void) const {
123  return size_;
124 }
125 
126 inline const ACL *
127 ACL_wrapper::get(void) const {
128  return reinterpret_cast<const ACL *>(buff.get());
129 }
130 
131 inline ACL *
132 ACL_wrapper::get(void) {
133  return reinterpret_cast<ACL *>(buff.get());
134 }
135 
136 SecurityDescriptor::SecurityDescriptor(void) :
137  LoadLibraryWrapper(scm_lib_name),
138  pLookupAccountName(reinterpret_cast<LookupAccountNameType>(::GetProcAddress(Handle(),LookupAccountName_name))),
139  pInitializeSecurityDescriptor(reinterpret_cast<InitializeSecurityDescriptorType>(::GetProcAddress(Handle(),InitializeSecurityDescriptor_name))),
140  pSetSecurityDescriptorDacl(reinterpret_cast<SetSecurityDescriptorDaclType>(::GetProcAddress(Handle(),SetSecurityDescriptorDacl_name))),
141  pGetLengthSid(reinterpret_cast<GetLengthSidType>(::GetProcAddress(Handle(),GetLengthSid_name)))
142 #ifdef _DEBUG
143  ,
144  pIsValidSid(reinterpret_cast<IsValidSidType>(::GetProcAddress(Handle(),IsValidSid_name))),
145  pIsValidSecurityDescriptor(reinterpret_cast<IsValidSecurityDescriptorType>(::GetProcAddress(Handle(),IsValidSecurityDescriptor_name)))
146 #endif
147 {
148  if (!(*pInitializeSecurityDescriptor)(&sd, SECURITY_DESCRIPTOR_REVISION)) {
149  throw exception_type(_T("Failed to initialise security descriptor."),info::function(__LINE__,__PRETTY_FUNCTION__,typeid(*this),info::function::argument(_T(""),_T(""))),__REV_INFO__);
150  }
151 }
152 
153 inline
154 SecurityDescriptor::~SecurityDescriptor(void) {
155  for (std::vector<SID *>::iterator iter(sids.begin());iter!=sids.end();++iter) {
156  try {
157  delete[] reinterpret_cast<BYTE *>(*iter);
158  }
159  catch (const std::exception &err) {
160  JMMCG_TRACE(_T("SecurityDescriptor::~SecurityDescriptor(): Exception '")<<err.what()<<_T("' thrown when trying to delete a SID, attempting to just leak the memory."));
161  assert(NULL);
162  }
163  }
164 }
165 
166 unsigned long
167 SecurityDescriptor::Allow(const TCHAR * const machine,const TCHAR * const username,const DWORD access_mask) {
168  assert(username);
169  const unsigned int SID_SIZE=96;
170  DWORD cbSid = SID_SIZE;
171  SID *sid=reinterpret_cast<SID *>(new BYTE[cbSid]);
172  if (!sid) {
173  JMMCG_TRACE(_T("SecurityDescriptor::Allow(...): SID new error!"));
174  return S_FALSE;
175  }
176  TCHAR RefDomain[DNLEN + 1];
177  DWORD cchDomain = DNLEN + 1;
178  SID_NAME_USE peUse;
179  // get the Sid associated with the supplied user/group name
180  if (!(*pLookupAccountName)(
181  machine, // default lookup logic
182  username, // user/group of interest from commandline
183  sid, // Sid buffer
184  &cbSid, // size of Sid
185  RefDomain, // Domain account found on (unused)
186  &cchDomain, // size of domain in chars
187  &peUse
188  )) {
189  // if the buffer wasn't large enough, try again
190  if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
191  delete[] reinterpret_cast<BYTE *>(sid);
192  sid=reinterpret_cast<SID *>(new BYTE[cbSid]);
193  if (sid) {
194  cchDomain = DNLEN + 1;
195  if (!(*pLookupAccountName)(
196  machine, // default lookup logic
197  username, // user/group of interest from commandline
198  sid, // Sid buffer
199  &cbSid, // size of Sid
200  RefDomain, // Domain account found on (unused)
201  &cchDomain, // size of domain in chars
202  &peUse
203  )) {
204  const unsigned long err=GetLastError();
205  JMMCG_TRACE(_T("SecurityDescriptor::Allow(...): LookupAccountName(...) error! ")<<NTUtils::win_exception::StrFromWinErr(err));
206  delete[] reinterpret_cast<BYTE *>(sid);
207  return err;
208  }
209  } else {
210  const unsigned long err=GetLastError();
211  JMMCG_TRACE(_T("SecurityDescriptor::Allow(...): SID new error!"));
212  delete[] reinterpret_cast<BYTE *>(sid);
213  return err ? err : S_FALSE;
214  }
215  } else {
216  const unsigned long err=GetLastError();
217  JMMCG_TRACE(_T("SecurityDescriptor::Allow(...): LookupAccountName(...) error! ")<<NTUtils::win_exception::StrFromWinErr(err));
218  delete[] reinterpret_cast<BYTE *>(sid);
219  return err;
220  }
221  }
222  assert((*pIsValidSid)(sid));
223  // compute size of new acl
224  unsigned long orig_dwAclSize=sizeof(ACL);
225  for (std::vector<SID *>::const_iterator iter(sids.begin());iter!=sids.end();++iter) {
226  orig_dwAclSize+=sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)+((*pGetLengthSid)(*iter)<<1);
227  }
228  // allocate storage for Acl
229  const ACL_wrapper orig_acl(acl);
230  ACL_wrapper acl_wrap(orig_dwAclSize+sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)+((*pGetLengthSid)(sid)<<1));
231  acl=acl_wrap;
232  if (sids.empty()) {
233  if (acl.initialize()) {
234  const unsigned long err=GetLastError();
235  JMMCG_TRACE(_T("SecurityDescriptor::Allow(...): InitializeAcl(...) error! ")<<NTUtils::win_exception::StrFromWinErr(err));
236  delete[] reinterpret_cast<BYTE *>(sid);
237  return err;
238  }
239  } else {
240  acl.copy(orig_acl);
241  }
242  if (acl.get()) {
243  if (acl.add_ACE(access_mask,sid)) {
244  if ((*pSetSecurityDescriptorDacl)(&sd,true,acl.get(),false)) {
245  assert((*pIsValidSecurityDescriptor)(&sd));
246  JMMCG_TRACE(_T("SecurityDescriptor::Allow(...): Successfully added access allowed ACL to security descriptor for user '")<<username<<_T("' on machine '")<<(machine ? machine : _T("''"))<<_T("' with access mask: 0x")<<std::hex<<access_mask);
247  sids.push_back(sid);
248  return S_OK;
249  }
250  }
251  }
252  delete[] reinterpret_cast<BYTE *>(sid);
253  const unsigned long err=GetLastError();
254  return err ? err : S_FALSE;
255 }