1 /*
2  * Copyright 2004, 2005 Martin Fuchs
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 
20  //
21  // Explorer clone
22  //
23  // ntobjfs.cpp
24  //
25  // Martin Fuchs, 31.01.2004
26  //
27 
28 
29 #include <precomp.h>
30 
31 #include "ntobjfs.h"
32 //#include "winfs.h"
33 #include "regfs.h"
34 
35 
36 #define	CONSTRUCT_NTDLLFCT(x) x(TEXT("NTDLL"), #x)
37 
38 typedef DWORD (__stdcall* NTOBJECTOPENFUNCTIONS)(HANDLE*, DWORD, OpenStruct*);
39 
40 struct NTDLL {
41 	NTDLL()
42 	 :	CONSTRUCT_NTDLLFCT(RtlInitAnsiString),
43 		CONSTRUCT_NTDLLFCT(RtlInitUnicodeString),
44 		CONSTRUCT_NTDLLFCT(RtlFreeAnsiString),
45 		CONSTRUCT_NTDLLFCT(RtlFreeUnicodeString),
46 		CONSTRUCT_NTDLLFCT(RtlAnsiStringToUnicodeString),
47 		CONSTRUCT_NTDLLFCT(RtlUnicodeStringToAnsiString),
48 		CONSTRUCT_NTDLLFCT(NtOpenDirectoryObject),
49 		CONSTRUCT_NTDLLFCT(NtQueryDirectoryObject),
50 		CONSTRUCT_NTDLLFCT(NtOpenFile),
51 		CONSTRUCT_NTDLLFCT(NtOpenSymbolicLinkObject),
52 		CONSTRUCT_NTDLLFCT(NtQuerySymbolicLinkObject),
53 		CONSTRUCT_NTDLLFCT(NtQueryObject),
54 		CONSTRUCT_NTDLLFCT(NtOpenMutant),
55 		CONSTRUCT_NTDLLFCT(NtOpenSection),
56 		CONSTRUCT_NTDLLFCT(NtOpenEvent),
57 		CONSTRUCT_NTDLLFCT(NtOpenEventPair),
58 		CONSTRUCT_NTDLLFCT(NtOpenIoCompletion),
59 		CONSTRUCT_NTDLLFCT(NtOpenSemaphore),
60 		CONSTRUCT_NTDLLFCT(NtOpenTimer),
61 		CONSTRUCT_NTDLLFCT(NtOpenKey),
62 		CONSTRUCT_NTDLLFCT(NtClose),
63 		CONSTRUCT_NTDLLFCT(NtOpenProcess),
64 		CONSTRUCT_NTDLLFCT(NtOpenThread)
65 	{
66 		NTOBJECTOPENFUNCTIONS* p = _ObjectOpenFunctions;
67 
68 		*p++ = *NtOpenDirectoryObject;
69 		*p++ = *NtOpenSymbolicLinkObject;
70 		*p++ = *NtOpenMutant;
71 		*p++ = *NtOpenSection;
72 		*p++ = *NtOpenEvent;
73 		*p++ = *NtOpenSemaphore;
74 		*p++ = *NtOpenTimer;
75 		*p++ = *NtOpenKey;
76 		*p++ = *NtOpenEventPair;
77 		*p++ = *NtOpenIoCompletion;
78 		*p++ = 0/*Device Object*/;
79 		*p++ = 0/*NtOpenFile*/;
80 		*p++ = 0/*CONTROLLER_OBJECT*/;
81 		*p++ = 0/*PROFILE_OBJECT*/;
82 		*p++ = 0/*TYPE_OBJECT*/;
83 		*p++ = 0/*DESKTOP_OBJECT*/;
84 		*p++ = 0/*WINDOWSTATION_OBJECT*/;
85 		*p++ = 0/*DRIVER_OBJECT*/;
86 		*p++ = 0/*TOKEN_OBJECT*/;
87 		*p++ = 0/*PROCESS_OBJECT*/;
88 		*p++ = 0/*THREAD_OBJECT*/;
89 		*p++ = 0/*ADAPTER_OBJECT*/;
90 		*p++ = 0/*PORT_OBJECT*/;
91 	}
92 
93 	NTOBJECTOPENFUNCTIONS _ObjectOpenFunctions[23];
94 	static const LPCWSTR s_ObjectTypes[];
95 
96 	DynamicFct<void (__stdcall*)(RtlAnsiString*, LPCSTR)> RtlInitAnsiString;
97 	DynamicFct<void (__stdcall*)(RtlUnicodeString*, LPCWSTR)> RtlInitUnicodeString;
98 	DynamicFct<DWORD (__stdcall*)(RtlAnsiString*)> RtlFreeAnsiString;
99 	DynamicFct<DWORD (__stdcall*)(RtlUnicodeString*)> RtlFreeUnicodeString;
100 	DynamicFct<DWORD (__stdcall*)(RtlUnicodeString*, const RtlAnsiString*, BOOL)> RtlAnsiStringToUnicodeString;
101 	DynamicFct<DWORD (__stdcall*)(RtlAnsiString*, const RtlUnicodeString*, BOOL)> RtlUnicodeStringToAnsiString;
102 
103 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenDirectoryObject;
104 	DynamicFct<DWORD (__stdcall*)(HANDLE, NtObjectInfo*, DWORD size, BOOL, BOOL, void*, void*)> NtQueryDirectoryObject;
105 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, void*, DWORD*, DWORD, OpenStruct*)> NtOpenFile;
106 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenSymbolicLinkObject;
107 	DynamicFct<DWORD (__stdcall*)(HANDLE, RtlUnicodeString*, DWORD*)> NtQuerySymbolicLinkObject;
108 	DynamicFct<DWORD (__stdcall*)(HANDLE, DWORD, NtObject*, DWORD size, DWORD* read)> NtQueryObject;
109 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenMutant;
110 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenSection;
111 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenEvent;
112 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenEventPair;
113 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenIoCompletion;
114 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenSemaphore;
115 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenTimer;
116 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenKey;
117 	DynamicFct<DWORD (__stdcall*)(HANDLE)> NtClose;
118 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenProcess;
119 	DynamicFct<DWORD (__stdcall*)(HANDLE*, DWORD, OpenStruct*)> NtOpenThread;
120 };
121 
122 const LPCWSTR NTDLL::s_ObjectTypes[] = {
123 	L"Directory", L"SymbolicLink",
124 	L"Mutant", L"Section", L"Event", L"Semaphore",
125 	L"Timer", L"Key", L"EventPair", L"IoCompletion",
126 	L"Device", L"File", L"Controller", L"Profile",
127 	L"Type", L"Desktop", L"WindowStatiom", L"Driver",
128 	L"Token", L"Process", L"Thread", L"Adapter", L"Port",
129 	0
130 };
131 
132 NTDLL* g_NTDLL = NULL;
133 
134 
135 struct UnicodeString : public RtlUnicodeString {
136 	UnicodeString(LPCWSTR str)
137 	{
138 		(*g_NTDLL->RtlInitUnicodeString)(this, str);
139 	}
140 
141 	UnicodeString(size_t len, LPWSTR buffer)
142 	{
143 		alloc_len = (WORD)len;
144 		string_ptr = buffer;
145 	}
146 
147 	operator LPCWSTR() const {return string_ptr;}
148 };
149 
150 
151 static DWORD NtOpenObject(OBJECT_TYPE type, HANDLE* phandle, DWORD access, LPCWSTR path/*, BOOL xflag=FALSE*/)
152 {
153 	UnicodeString ustr(path);
154 	OpenStruct open_struct = {sizeof(OpenStruct), 0x00, &ustr, 0x40};
155 
156 	if (type==DIRECTORY_OBJECT || type==SYMBOLICLINK_OBJECT)
157 		access |= FILE_LIST_DIRECTORY;
158 
159 	/* if (xflag)
160 		access |= GENERIC_READ; */
161 
162 	DWORD ioStatusBlock[2];	// IO_STATUS_BLOCK
163 
164 	if (type>=DIRECTORY_OBJECT && type<=IOCOMPLETITION_OBJECT)
165 		return g_NTDLL->_ObjectOpenFunctions[type](phandle, access|STANDARD_RIGHTS_READ, &open_struct);
166 	else if (type == FILE_OBJECT)
167 		return (*g_NTDLL->NtOpenFile)(phandle, access, &open_struct, ioStatusBlock, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0/*OpenOptions*/);
168 	else
169 		return ERROR_INVALID_FUNCTION;
170 }
171 
172 
173 void NtObjDirectory::read_directory(int scan_flags)
174 {
175 	CONTEXT("NtObjDirectory::read_directory()");
176 
177 	if (!g_NTDLL)
178 		g_NTDLL = new NTDLL();
179 
180 	Entry* first_entry = NULL;
181 	int level = _level + 1;
182 
183 	LPCTSTR path = (LPCTSTR)_path;
184 
185 	TCHAR buffer[MAX_PATH], *p=buffer;
186 #ifndef UNICODE
187 	WCHAR wbuffer[MAX_PATH], *w=wbuffer;
188 #endif
189 
190 	do {
191 		*p++ = *path;
192 #ifndef UNICODE
193 		*w++ = *path;
194 #endif
195 	} while(*path++);
196 	--p;
197 #ifndef UNICODE
198 	--w;
199 #endif
200 
201 	DWORD idx;
202 	HANDLE dir_handle;
203 
204 #ifdef UNICODE
205 	if (NtOpenObject(_type, &dir_handle, 0, buffer))
206 #else
207 	if (NtOpenObject(_type, &dir_handle, 0, wbuffer))
208 #endif
209 		return;
210 
211 #ifdef UNICODE
212 	if (p[-1] != '\\')
213 		*p++ = '\\';
214 #else
215 	if (w[-1] != '\\')
216 		*w++ = '\\';
217 #endif
218 
219 	NtObjectInfo* info = (NtObjectInfo*)alloca(2048);
220 
221 	if (!(*g_NTDLL->NtQueryDirectoryObject)(dir_handle, info, 2048, TRUE, TRUE, &idx, NULL)) {
222 		WIN32_FIND_DATA w32fd;
223 		Entry* last = NULL;
224 		Entry* entry;
225 
226 		do {
227 			memset(&w32fd, 0, sizeof(WIN32_FIND_DATA));
228 
229 #ifdef UNICODE
230 			if (info->name.string_ptr) {
231 				info->name.string_ptr[info->name.string_len / sizeof(WCHAR)] = 0;
232 			} else {
233 				TCHAR empty_string_ptr[] = _T("");
234 				info->name.string_ptr = empty_string_ptr;
235 			}
236 			if (info->type.string_ptr) {
237 				info->type.string_ptr[info->type.string_len / sizeof(WCHAR)] = 0;
238 			} else {
239 				TCHAR empty_string_ptr[] = _T("");
240 				info->type.string_ptr = empty_string_ptr;
241 			}
242 			lstrcpynW(p, info->name.string_ptr, COUNTOF(buffer));
243 #else
244 			WideCharToMultiByte(CP_ACP, 0, info->name.string_ptr, info->name.string_len, p, COUNTOF(buffer), 0, 0);
245 #endif
246 
247 			lstrcpyn(w32fd.cFileName, p, sizeof(w32fd.cFileName) / sizeof(0[w32fd.cFileName]));
248 
249 			const LPCWSTR* tname = NTDLL::s_ObjectTypes;
250 			OBJECT_TYPE type = UNKNOWN_OBJECT_TYPE;
251 
252 			for(; *tname; tname++)
253 				if (!wcsncmp(info->type.string_ptr, *tname, 32))
254 					{type=OBJECT_TYPE(tname-NTDLL::s_ObjectTypes); break;}
255 
256 			if (type == DIRECTORY_OBJECT) {
257 				w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
258 
259 				entry = new NtObjDirectory(this, buffer);
260 			}
261 
262 			else if (type == SYMBOLICLINK_OBJECT) {
263 				w32fd.dwFileAttributes |= ATTRIBUTE_SYMBOLIC_LINK;
264 
265 				entry = NULL;
266 
267 #ifndef _NO_WIN_FS
268 				if (*w32fd.cFileName>='A' &&*w32fd.cFileName<='Z' && w32fd.cFileName[1]==':')
269 					if (!_tcsncmp(buffer,TEXT("\\??\\"),4) ||		// NT4
270 						!_tcsncmp(buffer,TEXT("\\GLOBAL??"),9)) {	// XP
271 						w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
272 						entry = new WinDirectory(this, w32fd.cFileName);
273 					}
274 #endif
275 
276 				if (!entry)
277 					entry = new NtObjDirectory(this, buffer);
278 			}
279 
280 			else if (type == KEY_OBJECT) {
281 				w32fd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
282 
283 				entry = new RegistryRoot(this, buffer);
284 			}
285 			else
286 				entry = new NtObjEntry(this, type);
287 
288 			HANDLE handle;
289 
290 #ifdef UNICODE
291 			lstrcpyW(p, info->name.string_ptr);
292 			if (!NtOpenObject(type, &handle, 0, buffer))
293 #else
294 			lstrcpyW(w, info->name.string_ptr);
295 			if (!NtOpenObject(type, &handle, 0, wbuffer))
296 #endif
297 			{
298 				NtObject object;
299 				DWORD read;
300 
301 				if (!(*g_NTDLL->NtQueryObject)(handle, 0/*ObjectBasicInformation*/, &object, sizeof(NtObject), &read)) {
302 					memcpy(&w32fd.ftCreationTime, &object.creation_time, sizeof(FILETIME));
303 
304 					memset(&entry->_bhfi, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
305 					entry->_bhfi.nNumberOfLinks = object.reference_count - 1;
306 					entry->_bhfi_valid = true;
307 				}
308 
309 				if (type == SYMBOLICLINK_OBJECT) {
310 					WCHAR wbuffer[_MAX_PATH];
311 					UnicodeString link(_MAX_PATH, wbuffer);
312 
313 					if (!(*g_NTDLL->NtQuerySymbolicLinkObject)(handle, &link, NULL)) {
314 						int len = link.string_len/sizeof(WCHAR);
315 						entry->_content = (LPTSTR) malloc((len+1)*sizeof(TCHAR));
316 #ifdef UNICODE
317 						wcsncpy_s(entry->_content, len+1, link, len);
318 #else
319 						U2nA(link, entry->_content, len);
320 #endif
321 						entry->_content[len] = '\0';
322 					}
323 				}
324 
325 				(*g_NTDLL->NtClose)(handle);
326 			}
327 
328 			memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA));
329 
330 #ifdef UNICODE
331 			entry->_type_name = _wcsdup(info->type.string_ptr);
332 #else
333 			char type_name[32];
334 			WideCharToMultiByte(CP_ACP, 0, info->type.string_ptr, info->type.string_len, type_name, 32, 0, 0);
335 			entry->_type_name = _strdup(type_name);
336 #endif
337 
338 			if (!first_entry)
339 				first_entry = entry;
340 
341 			if (last)
342 				last->_next = entry;
343 
344 			entry->_level = level;
345 
346 			last = entry;
347 		} while(!(*g_NTDLL->NtQueryDirectoryObject)(dir_handle, info, 2048, TRUE, FALSE, &idx, NULL));
348 
349 		last->_next = NULL;
350 	}
351 
352 	(*g_NTDLL->NtClose)(dir_handle);
353 
354 	_down = first_entry;
355 	_scanned = true;
356 }
357 
358 
359 Entry* NtObjDirectory::find_entry(const void* p)
360 {
361 	LPCTSTR name = (LPCTSTR)p;
362 
363 	for(Entry*entry=_down; entry; entry=entry->_next) {
364 		LPCTSTR p = name;
365 		LPCTSTR q = entry->_data.cFileName;
366 
367 		do {
368 			if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
369 				return entry;
370 		} while(tolower(*p++) == tolower(*q++));
371 
372 		p = name;
373 		q = entry->_data.cAlternateFileName;
374 
375 		do {
376 			if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
377 				return entry;
378 		} while(tolower(*p++) == tolower(*q++));
379 	}
380 
381 	return NULL;
382 }
383 
384 
385  // get full path of specified directory entry
386 bool NtObjEntry::get_path(PTSTR path, size_t path_count) const
387 {
388 	return get_path_base ( path, path_count, ET_NTOBJS );
389 }
390 
391 BOOL NtObjEntry::launch_entry(HWND hwnd, UINT nCmdShow)
392 {
393 	return FALSE;
394 }
395