1 /*
2  * regexpl - Console Registry Explorer
3  *
4  * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; see the file COPYING.  If not, write to
18  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
22 // ShellCommandDACL.cpp: implementation of the CShellCommandDACL class.
23 //
24 //////////////////////////////////////////////////////////////////////
25 
26 #include "ph.h"
27 #include "ShellCommandDACL.h"
28 #include "RegistryExplorer.h"
29 #include "SecurityDescriptor.h"
30 
31 #define DACL_CMD			_T("DACL")
32 #define DACL_CMD_LENGTH		COMMAND_LENGTH(DACL_CMD)
33 #define DACL_CMD_SHORT_DESC	DACL_CMD _T(" command is used to view")/*"/edit"*/_T(" key's DACL.\n")
34 
35 //////////////////////////////////////////////////////////////////////
36 // Construction/Destruction
37 //////////////////////////////////////////////////////////////////////
38 
39 CShellCommandDACL::CShellCommandDACL(CRegistryTree& rTree):m_rTree(rTree)
40 {
41 
42 }
43 
44 CShellCommandDACL::~CShellCommandDACL()
45 {
46 
47 }
48 
49 BOOL CShellCommandDACL::Match(const TCHAR *pchCommand)
50 {
51 	if (_tcsicmp(pchCommand,DACL_CMD) == 0)
52 		return TRUE;
53 	if (_tcsnicmp(pchCommand,DACL_CMD _T(".."),DACL_CMD_LENGTH+2*sizeof(TCHAR)) == 0)
54 		return TRUE;
55 	if (_tcsnicmp(pchCommand,DACL_CMD _T("/") ,DACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
56 		return TRUE;
57 	if (_tcsnicmp(pchCommand,DACL_CMD _T("\\"),DACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
58 		return TRUE;
59 	return FALSE;
60 }
61 
62 int CShellCommandDACL::Execute(CConsole &rConsole, CArgumentParser& rArguments)
63 {
64 	rArguments.ResetArgumentIteration();
65 
66 	const TCHAR *pszKey = NULL;
67 	BOOL blnDo = TRUE;
68 	BOOL blnBadParameter = FALSE;
69 	BOOL blnHelp = FALSE;
70 	const TCHAR *pchParameter;
71 	const TCHAR *pchCommandItself = rArguments.GetNextArgument();
72 	LONG nError;
73 
74 	if ((_tcsnicmp(pchCommandItself,DACL_CMD _T(".."),DACL_CMD_LENGTH+2*sizeof(TCHAR)) == 0)||
75 		(_tcsnicmp(pchCommandItself,DACL_CMD _T("\\"),DACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0))
76 	{
77 		pszKey = pchCommandItself + DACL_CMD_LENGTH;
78 	}
79 	else if (_tcsnicmp(pchCommandItself,DACL_CMD _T("/"),DACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
80 	{
81 		pchParameter = pchCommandItself + DACL_CMD_LENGTH;
82 		goto CheckDACLArgument;
83 	}
84 
85 	while((pchParameter = rArguments.GetNextArgument()) != NULL)
86 	{
87 CheckDACLArgument:
88 		blnBadParameter = FALSE;
89 		if ((_tcsicmp(pchParameter,_T("/?")) == 0)
90 			||(_tcsicmp(pchParameter,_T("-?")) == 0))
91 		{
92 			blnHelp = TRUE;
93 			blnDo = pszKey != NULL;
94 		}
95 		else if (!pszKey)
96 		{
97 			pszKey = pchParameter;
98 			blnDo = TRUE;
99 		}
100 		else
101 		{
102 			blnBadParameter = TRUE;
103 		}
104 		if (blnBadParameter)
105 		{
106 			rConsole.Write(_T("Bad parameter: "));
107 			rConsole.Write(pchParameter);
108 			rConsole.Write(_T("\n"));
109 		}
110 	}
111 
112 	CRegistryKey Key;
113 
114   if (!m_rTree.GetKey(pszKey?pszKey:_T("."),KEY_QUERY_VALUE|READ_CONTROL,Key))
115   {
116     rConsole.Write(m_rTree.GetLastErrorDescription());
117     blnDo = FALSE;
118   }
119 
120 	if (blnHelp)
121 	{
122 		rConsole.Write(GetHelpString());
123 	}
124 
125 	if (blnDo&&blnHelp) rConsole.Write(_T("\n"));
126 
127 	if (!blnDo)
128     return 0;
129 
130   if (Key.IsRoot())
131 	{	// root key
132     rConsole.Write(DACL_CMD COMMAND_NA_ON_ROOT);
133     return 0;
134   }
135 
136   DWORD dwSecurityDescriptorLength;
137   rConsole.Write(_T("Key : "));
138   rConsole.Write(_T("\\"));
139   rConsole.Write(Key.GetKeyName());
140   rConsole.Write(_T("\n"));
141   PISECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
142   TCHAR *pchName = NULL, *pchDomainName = NULL;
143   try
144   {
145     nError = Key.GetSecurityDescriptorLength(&dwSecurityDescriptorLength);
146     if (nError != ERROR_SUCCESS)
147       throw nError;
148 
149     pSecurityDescriptor = (PISECURITY_DESCRIPTOR) new unsigned char [dwSecurityDescriptorLength];
150     DWORD dwSecurityDescriptorLength1 = dwSecurityDescriptorLength;
151     nError = Key.GetSecurityDescriptor((SECURITY_INFORMATION)DACL_SECURITY_INFORMATION,pSecurityDescriptor,&dwSecurityDescriptorLength1);
152     if (nError != ERROR_SUCCESS)
153       throw nError;
154     CSecurityDescriptor sd;
155     sd.AssociateDescriptor(pSecurityDescriptor);
156 
157     sd.BeginDACLInteration();
158     ASSERT(sd.DescriptorContainsDACL());
159     if (sd.HasNULLDACL())
160     {
161       rConsole.Write(_T("Key has not DACL.\n(This allows all access)\n"));
162     }
163     else
164     {
165       if (!sd.HasValidDACL())
166       {
167         rConsole.Write(_T("Invalid DACL.\n"));
168       }
169       else
170       {
171         DWORD nACECount = sd.GetDACLEntriesCount();
172         rConsole.Write(_T("DACL has "));
173         TCHAR Buffer[256];
174         rConsole.Write(_itoa(nACECount,Buffer,10));
175         rConsole.Write(_T(" ACEs.\n"));
176         if (nACECount == 0)
177         {
178           rConsole.Write(_T("(This denies all access)\n"));
179         }
180         else
181         {
182           for (DWORD i = 0 ; i < nACECount ; i++)
183           {
184             rConsole.Write(_T("\n"));
185             rConsole.Write(_T("\tACE Index: "));
186             rConsole.Write(_itoa(i,Buffer,10));
187             rConsole.Write(_T("\n"));
188             rConsole.Write(_T("\tACE Type: "));
189             switch (sd.GetDACLEntry(i))
190             {
191             case CSecurityDescriptor::AccessAlowed:
192               rConsole.Write(_T("Access-allowed\n"));
193               break;
194             case CSecurityDescriptor::AccessDenied:
195               rConsole.Write(_T("Access-denied\n"));
196               break;
197             default:
198               rConsole.Write(_T("Unknown.\nCannot continue dumping of the ACE list.\n"));
199               goto AbortDumpDACL;
200             }
201             PSID pSID = sd.GetCurrentACE_SID();
202             if ((pSID == NULL)||(!IsValidSid(pSID)))
203             {
204               rConsole.Write(_T("\tInvalid SID.\n"));
205             }
206             else
207             {
208               DWORD dwSIDStringSize = 0;
209               BOOL blnRet = GetTextualSid(pSID,NULL,&dwSIDStringSize);
210               ASSERT(!blnRet);
211               ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
212               TCHAR *pchSID = new TCHAR[dwSIDStringSize];
213               if(!GetTextualSid(pSID,pchSID,&dwSIDStringSize))
214               {
215                 DWORD dwError = GetLastError();
216                 ASSERT(dwError != ERROR_INSUFFICIENT_BUFFER);
217                 rConsole.Write(_T("Error "));
218                 TCHAR Buffer[256];
219                 rConsole.Write(_itoa(dwError,Buffer,10));
220                 rConsole.Write(_T("\nGetting string representation of SID\n"));
221               }
222               else
223               {
224                 rConsole.Write(_T("\tSID: "));
225                 rConsole.Write(pchSID);
226                 rConsole.Write(_T("\n"));
227               }
228               delete[] pchSID;
229               DWORD dwNameBufferLength, dwDomainNameBufferLength;
230               dwNameBufferLength = 1024;
231               dwDomainNameBufferLength = 1024;
232               pchName = new TCHAR [dwNameBufferLength];
233               pchDomainName = new TCHAR [dwDomainNameBufferLength];
234               DWORD dwNameLength = dwNameBufferLength, dwDomainNameLength = dwDomainNameBufferLength;
235               SID_NAME_USE Use;
236               if (!LookupAccountSid(NULL,pSID,pchName,&dwNameLength,pchDomainName,&dwDomainNameLength,&Use))
237               {
238                 rConsole.Write(_T("Error "));
239                 TCHAR Buffer[256];
240                 rConsole.Write(_itoa(GetLastError(),Buffer,10));
241                 rConsole.Write(_T("\n"));
242               }
243               else
244               {
245                 rConsole.Write(_T("\tTrustee Domain: "));
246                 rConsole.Write(pchDomainName);
247                 rConsole.Write(_T("\n"));
248                 rConsole.Write(_T("\tTrustee Name: "));
249                 rConsole.Write(pchName);
250                 rConsole.Write(_T("\n\tSID type: "));
251                 rConsole.Write(GetSidTypeName(Use));
252                 rConsole.Write(_T("\n"));
253               }
254               delete [] pchName;
255               pchName = NULL;
256               delete [] pchDomainName;
257               pchDomainName = NULL;
258             }
259 
260             BYTE bFlags;
261             sd.GetCurrentACE_Flags(bFlags);
262             wsprintf(Buffer,_T("\tFlags: 0x%02lX\n"),bFlags);
263             rConsole.Write(Buffer);
264             if (bFlags & CONTAINER_INHERIT_ACE)
265             {
266               rConsole.Write(_T("\t\tCONTAINER_INHERIT_ACE\n"));
267             }
268             if (bFlags & INHERIT_ONLY_ACE)
269             {
270               rConsole.Write(_T("\t\tINHERIT_ONLY_ACE\n"));
271             }
272             if (bFlags & INHERITED_ACE)
273             {
274               rConsole.Write(_T("\t\tINHERITED_ACE\n"));
275             }
276             if (bFlags & NO_PROPAGATE_INHERIT_ACE)
277             {
278               rConsole.Write(_T("\t\tNO_PROPAGATE_INHERIT_ACE\n"));
279             }
280             if (bFlags & OBJECT_INHERIT_ACE)
281             {
282               rConsole.Write(_T("\t\tOBJECT_INHERIT_ACE\n"));
283             }
284 
285             DWORD dwAccessMask;
286             sd.GetCurrentACE_AccessMask(dwAccessMask);
287             wsprintf(Buffer,_T("\tAccess Mask: 0x%08lX\n"),dwAccessMask);
288             rConsole.Write(Buffer);
289             if (dwAccessMask & GENERIC_READ)
290             {
291               rConsole.Write(_T("\t\tGENERIC_READ\n"));
292             }
293             if (dwAccessMask & GENERIC_WRITE)
294             {
295               rConsole.Write(_T("\t\tGENERIC_WRITE\n"));
296             }
297             if (dwAccessMask & GENERIC_EXECUTE)
298             {
299               rConsole.Write(_T("\t\tGENERIC_EXECUTE\n"));
300             }
301             if (dwAccessMask & GENERIC_ALL)
302             {
303               rConsole.Write(_T("\t\tGENERIC_ALL\n"));
304             }
305             if (dwAccessMask & SYNCHRONIZE)
306             {
307               rConsole.Write(_T("\t\tSYNCHRONIZE\n"));
308             }
309             if (dwAccessMask & WRITE_OWNER)
310             {
311               rConsole.Write(_T("\t\tWRITE_OWNER\n"));
312             }
313             if (dwAccessMask & WRITE_DAC)
314             {
315               rConsole.Write(_T("\t\tWRITE_DAC\n"));
316             }
317             if (dwAccessMask & READ_CONTROL)
318             {
319               rConsole.Write(_T("\t\tREAD_CONTROL\n"));
320             }
321             if (dwAccessMask & DELETE)
322             {
323               rConsole.Write(_T("\t\tDELETE\n"));
324             }
325             if (dwAccessMask & KEY_CREATE_LINK)
326             {
327               rConsole.Write(_T("\t\tKEY_CREATE_LINK\n"));
328             }
329             if (dwAccessMask & KEY_NOTIFY)
330             {
331               rConsole.Write(_T("\t\tKEY_NOTIFY\n"));
332             }
333             if (dwAccessMask & KEY_ENUMERATE_SUB_KEYS)
334             {
335               rConsole.Write(_T("\t\tKEY_ENUMERATE_SUB_KEYS\n"));
336             }
337             if (dwAccessMask & KEY_CREATE_SUB_KEY)
338             {
339               rConsole.Write(_T("\t\tKEY_CREATE_SUB_KEY\n"));
340             }
341             if (dwAccessMask & KEY_SET_VALUE)
342             {
343               rConsole.Write(_T("\t\tKEY_SET_VALUE\n"));
344             }
345             if (dwAccessMask & KEY_QUERY_VALUE)
346             {
347               rConsole.Write(_T("\t\tKEY_QUERY_VALUE\n"));
348             }
349           } // for
350         } // else (nACECount == 0)
351       } // else (!sd.HasValidDACL())
352     } // else (sd.HasNULLDACL())
353 AbortDumpDACL:
354     delete [] pSecurityDescriptor;
355   }  // try
356   catch (DWORD dwError)
357   {
358     rConsole.Write(_T("Error "));
359     TCHAR Buffer[256];
360     rConsole.Write(_itoa(dwError,Buffer,10));
361     rConsole.Write(_T("\n"));
362     if (pchName) delete [] pchName;
363     if (pchDomainName) delete [] pchDomainName;
364     if (pSecurityDescriptor) delete [] pSecurityDescriptor;
365   }
366 
367 	return 0;
368 }
369 
370 const TCHAR * CShellCommandDACL::GetHelpString()
371 {
372 	return DACL_CMD_SHORT_DESC
373 			_T("Syntax: ") DACL_CMD _T(" [<KEY>] [/?]\n\n")
374 			_T("    <KEY> - Optional relative path of desired key.\n")
375 			_T("    /?    - This help.\n\n")
376 			_T("Without parameters, command displays DACL of current key.\n");
377 }
378 
379 const TCHAR * CShellCommandDACL::GetHelpShortDescriptionString()
380 {
381 	return DACL_CMD_SHORT_DESC;
382 }
383