|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 * http://creativecommons.org/publicdomain/zero/1.0/ |
|
3 */ |
|
4 |
|
5 #ifdef XP_WIN |
|
6 # include <windows.h> |
|
7 # include <wintrust.h> |
|
8 # include <tlhelp32.h> |
|
9 # include <softpub.h> |
|
10 # include <direct.h> |
|
11 # include <io.h> |
|
12 typedef WCHAR NS_tchar; |
|
13 # define NS_main wmain |
|
14 # define F_OK 00 |
|
15 # define W_OK 02 |
|
16 # define R_OK 04 |
|
17 # define stat _stat |
|
18 # define NS_T(str) L ## str |
|
19 # define NS_tsnprintf(dest, count, fmt, ...) \ |
|
20 { \ |
|
21 int _count = count - 1; \ |
|
22 _snwprintf(dest, _count, fmt, ##__VA_ARGS__); \ |
|
23 dest[_count] = L'\0'; \ |
|
24 } |
|
25 # define NS_taccess _waccess |
|
26 # define NS_tchdir _wchdir |
|
27 # define NS_tfopen _wfopen |
|
28 # define NS_tstrcmp wcscmp |
|
29 # define NS_ttoi _wtoi |
|
30 # define NS_tstat _wstat |
|
31 # define NS_tgetcwd _wgetcwd |
|
32 # define LOG_S "%S" |
|
33 |
|
34 #include "../common/updatehelper.h" |
|
35 |
|
36 #else |
|
37 # include <unistd.h> |
|
38 # define NS_main main |
|
39 typedef char NS_tchar; |
|
40 # define NS_T(str) str |
|
41 # define NS_tsnprintf snprintf |
|
42 # define NS_taccess access |
|
43 # define NS_tchdir chdir |
|
44 # define NS_tfopen fopen |
|
45 # define NS_tstrcmp strcmp |
|
46 # define NS_ttoi atoi |
|
47 # define NS_tstat stat |
|
48 # define NS_tgetcwd getcwd |
|
49 # define NS_tfputs fputs |
|
50 # define LOG_S "%s" |
|
51 #endif |
|
52 |
|
53 #include "mozilla/NullPtr.h" |
|
54 #include <stdlib.h> |
|
55 #include <stdio.h> |
|
56 #include <string.h> |
|
57 #include <sys/types.h> |
|
58 #include <sys/stat.h> |
|
59 |
|
60 #ifndef MAXPATHLEN |
|
61 # ifdef PATH_MAX |
|
62 # define MAXPATHLEN PATH_MAX |
|
63 # elif defined(MAX_PATH) |
|
64 # define MAXPATHLEN MAX_PATH |
|
65 # elif defined(_MAX_PATH) |
|
66 # define MAXPATHLEN _MAX_PATH |
|
67 # elif defined(CCHMAXPATH) |
|
68 # define MAXPATHLEN CCHMAXPATH |
|
69 # else |
|
70 # define MAXPATHLEN 1024 |
|
71 # endif |
|
72 #endif |
|
73 |
|
74 static void |
|
75 WriteMsg(const NS_tchar *path, const char *status) |
|
76 { |
|
77 FILE* outFP = NS_tfopen(path, NS_T("wb")); |
|
78 if (!outFP) |
|
79 return; |
|
80 |
|
81 fprintf(outFP, "%s\n", status); |
|
82 fclose(outFP); |
|
83 outFP = nullptr; |
|
84 } |
|
85 |
|
86 static bool |
|
87 CheckMsg(const NS_tchar *path, const char *expected) |
|
88 { |
|
89 if (NS_taccess(path, F_OK)) { |
|
90 return false; |
|
91 } |
|
92 |
|
93 FILE *inFP = NS_tfopen(path, NS_T("rb")); |
|
94 if (!inFP) { |
|
95 return false; |
|
96 } |
|
97 |
|
98 struct stat ms; |
|
99 if (fstat(fileno(inFP), &ms)) { |
|
100 return false; |
|
101 } |
|
102 |
|
103 char *mbuf = (char *) malloc(ms.st_size + 1); |
|
104 if (!mbuf) { |
|
105 return false; |
|
106 } |
|
107 |
|
108 size_t r = ms.st_size; |
|
109 char *rb = mbuf; |
|
110 size_t c = fread(rb, sizeof(char), 50, inFP); |
|
111 r -= c; |
|
112 rb += c; |
|
113 if (c == 0 && r) { |
|
114 return false; |
|
115 } |
|
116 mbuf[ms.st_size] = '\0'; |
|
117 rb = mbuf; |
|
118 |
|
119 fclose(inFP); |
|
120 inFP = nullptr; |
|
121 return strcmp(rb, expected) == 0; |
|
122 } |
|
123 |
|
124 #ifdef XP_WIN |
|
125 /** |
|
126 * Verifies the trust of the specified file path. |
|
127 * |
|
128 * @param filePath The file path to check. |
|
129 * @return ERROR_SUCCESS if successful, or the last error code otherwise. |
|
130 */ |
|
131 DWORD |
|
132 VerifyCertificateTrustForFile(LPCWSTR filePath) |
|
133 { |
|
134 // Setup the file to check. |
|
135 WINTRUST_FILE_INFO fileToCheck; |
|
136 ZeroMemory(&fileToCheck, sizeof(fileToCheck)); |
|
137 fileToCheck.cbStruct = sizeof(WINTRUST_FILE_INFO); |
|
138 fileToCheck.pcwszFilePath = filePath; |
|
139 |
|
140 // Setup what to check, we want to check it is signed and trusted. |
|
141 WINTRUST_DATA trustData; |
|
142 ZeroMemory(&trustData, sizeof(trustData)); |
|
143 trustData.cbStruct = sizeof(trustData); |
|
144 trustData.pPolicyCallbackData = nullptr; |
|
145 trustData.pSIPClientData = nullptr; |
|
146 trustData.dwUIChoice = WTD_UI_NONE; |
|
147 trustData.fdwRevocationChecks = WTD_REVOKE_NONE; |
|
148 trustData.dwUnionChoice = WTD_CHOICE_FILE; |
|
149 trustData.dwStateAction = 0; |
|
150 trustData.hWVTStateData = nullptr; |
|
151 trustData.pwszURLReference = nullptr; |
|
152 // no UI |
|
153 trustData.dwUIContext = 0; |
|
154 trustData.pFile = &fileToCheck; |
|
155 |
|
156 GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2; |
|
157 // Check if the file is signed by something that is trusted. |
|
158 return WinVerifyTrust(nullptr, &policyGUID, &trustData); |
|
159 } |
|
160 |
|
161 #endif |
|
162 |
|
163 int NS_main(int argc, NS_tchar **argv) |
|
164 { |
|
165 |
|
166 if (argc < 3) { |
|
167 fprintf(stderr, \ |
|
168 "\n" \ |
|
169 "Application Update Service Test Helper\n" \ |
|
170 "\n" \ |
|
171 "Usage: WORKINGDIR INFILE OUTFILE -s SECONDS [FILETOLOCK]\n" \ |
|
172 " or: WORKINGDIR LOGFILE [ARG2 ARG3...]\n" \ |
|
173 " or: signature-check filepath\n" \ |
|
174 " or: setup-symlink dir1 dir2 file symlink\n" \ |
|
175 " or: remove-symlink dir1 dir2 file symlink\n" \ |
|
176 " or: check-symlink symlink\n" \ |
|
177 "\n" \ |
|
178 " WORKINGDIR \tThe relative path to the working directory to use.\n" \ |
|
179 " INFILE \tThe relative path from the working directory for the file to\n" \ |
|
180 " \tread actions to perform such as finish.\n" \ |
|
181 " OUTFILE \tThe relative path from the working directory for the file to\n" \ |
|
182 " \twrite status information.\n" \ |
|
183 " SECONDS \tThe number of seconds to sleep.\n" \ |
|
184 " FILETOLOCK \tThe relative path from the working directory to an existing\n" \ |
|
185 " \tfile to open exlusively.\n" \ |
|
186 " \tOnly available on Windows platforms and silently ignored on\n" \ |
|
187 " \tother platforms.\n" \ |
|
188 " LOGFILE \tThe relative path from the working directory to log the\n" \ |
|
189 " \tcommand line arguments.\n" \ |
|
190 " ARG2 ARG3...\tArguments to write to the LOGFILE after the preceding command\n" \ |
|
191 " \tline arguments.\n" \ |
|
192 "\n" \ |
|
193 "Note: All paths must be relative.\n" \ |
|
194 "\n"); |
|
195 return 1; |
|
196 } |
|
197 |
|
198 if (!NS_tstrcmp(argv[1], NS_T("check-signature"))) { |
|
199 #ifdef XP_WIN |
|
200 if (ERROR_SUCCESS == VerifyCertificateTrustForFile(argv[2])) { |
|
201 return 0; |
|
202 } else { |
|
203 return 1; |
|
204 } |
|
205 #else |
|
206 // Not implemented on non-Windows platforms |
|
207 return 1; |
|
208 #endif |
|
209 } |
|
210 |
|
211 if (!NS_tstrcmp(argv[1], NS_T("setup-symlink"))) { |
|
212 #ifdef XP_UNIX |
|
213 NS_tchar path[MAXPATHLEN]; |
|
214 NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), |
|
215 NS_T("%s/%s"), NS_T("/tmp"), argv[2]); |
|
216 mkdir(path, 0755); |
|
217 NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), |
|
218 NS_T("%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3]); |
|
219 mkdir(path, 0755); |
|
220 NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), |
|
221 NS_T("%s/%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3], argv[4]); |
|
222 FILE * file = NS_tfopen(path, NS_T("w")); |
|
223 if (file) { |
|
224 NS_tfputs(NS_T("test"), file); |
|
225 fclose(file); |
|
226 } |
|
227 symlink(path, argv[5]); |
|
228 NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), |
|
229 NS_T("%s/%s"), NS_T("/tmp"), argv[2]); |
|
230 if (argc > 6 && !NS_tstrcmp(argv[6], NS_T("change-perm"))) { |
|
231 chmod(path, 0644); |
|
232 } |
|
233 return 0; |
|
234 #else |
|
235 // Not implemented on non-Unix platforms |
|
236 return 1; |
|
237 #endif |
|
238 } |
|
239 |
|
240 if (!NS_tstrcmp(argv[1], NS_T("remove-symlink"))) { |
|
241 #ifdef XP_UNIX |
|
242 NS_tchar path[MAXPATHLEN]; |
|
243 NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), |
|
244 NS_T("%s/%s"), NS_T("/tmp"), argv[2]); |
|
245 chmod(path, 0755); |
|
246 NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), |
|
247 NS_T("%s/%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3], argv[4]); |
|
248 unlink(path); |
|
249 NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), |
|
250 NS_T("%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3]); |
|
251 rmdir(path); |
|
252 NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), |
|
253 NS_T("%s/%s"), NS_T("/tmp"), argv[2]); |
|
254 rmdir(path); |
|
255 return 0; |
|
256 #else |
|
257 // Not implemented on non-Unix platforms |
|
258 return 1; |
|
259 #endif |
|
260 } |
|
261 |
|
262 if (!NS_tstrcmp(argv[1], NS_T("check-symlink"))) { |
|
263 #ifdef XP_UNIX |
|
264 struct stat ss; |
|
265 lstat(argv[2], &ss); |
|
266 return S_ISLNK(ss.st_mode) ? 0 : 1; |
|
267 #else |
|
268 // Not implemented on non-Unix platforms |
|
269 return 1; |
|
270 #endif |
|
271 } |
|
272 |
|
273 if (!NS_tstrcmp(argv[1], NS_T("wait-for-service-stop"))) { |
|
274 #ifdef XP_WIN |
|
275 const int maxWaitSeconds = NS_ttoi(argv[3]); |
|
276 LPCWSTR serviceName = argv[2]; |
|
277 DWORD serviceState = WaitForServiceStop(serviceName, maxWaitSeconds); |
|
278 if (SERVICE_STOPPED == serviceState) { |
|
279 return 0; |
|
280 } else { |
|
281 return serviceState; |
|
282 } |
|
283 #else |
|
284 // Not implemented on non-Windows platforms |
|
285 return 1; |
|
286 #endif |
|
287 } |
|
288 |
|
289 if (!NS_tstrcmp(argv[1], NS_T("wait-for-application-exit"))) { |
|
290 #ifdef XP_WIN |
|
291 const int maxWaitSeconds = NS_ttoi(argv[3]); |
|
292 LPCWSTR application = argv[2]; |
|
293 DWORD ret = WaitForProcessExit(application, maxWaitSeconds); |
|
294 if (ERROR_SUCCESS == ret) { |
|
295 return 0; |
|
296 } else if (WAIT_TIMEOUT == ret) { |
|
297 return 1; |
|
298 } else { |
|
299 return 2; |
|
300 } |
|
301 #else |
|
302 // Not implemented on non-Windows platforms |
|
303 return 1; |
|
304 #endif |
|
305 } |
|
306 |
|
307 int i = 0; |
|
308 |
|
309 if (NS_tchdir(argv[1]) != 0) { |
|
310 return 1; |
|
311 } |
|
312 |
|
313 // File in use test helper section |
|
314 if (!NS_tstrcmp(argv[4], NS_T("-s"))) { |
|
315 NS_tchar *cwd = NS_tgetcwd(nullptr, 0); |
|
316 NS_tchar inFilePath[MAXPATHLEN]; |
|
317 NS_tsnprintf(inFilePath, sizeof(inFilePath)/sizeof(inFilePath[0]), |
|
318 NS_T("%s/%s"), cwd, argv[2]); |
|
319 NS_tchar outFilePath[MAXPATHLEN]; |
|
320 NS_tsnprintf(outFilePath, sizeof(outFilePath)/sizeof(outFilePath[0]), |
|
321 NS_T("%s/%s"), cwd, argv[3]); |
|
322 |
|
323 int seconds = NS_ttoi(argv[5]); |
|
324 #ifdef XP_WIN |
|
325 HANDLE hFile = INVALID_HANDLE_VALUE; |
|
326 if (argc == 7) { |
|
327 hFile = CreateFileW(argv[6], |
|
328 DELETE | GENERIC_WRITE, 0, |
|
329 nullptr, OPEN_EXISTING, 0, nullptr); |
|
330 if (hFile == INVALID_HANDLE_VALUE) { |
|
331 WriteMsg(outFilePath, "error_locking"); |
|
332 return 1; |
|
333 } |
|
334 } |
|
335 |
|
336 WriteMsg(outFilePath, "sleeping"); |
|
337 while (!CheckMsg(inFilePath, "finish\n") && i++ <= seconds) { |
|
338 Sleep(1000); |
|
339 } |
|
340 |
|
341 if (argc == 7) { |
|
342 CloseHandle(hFile); |
|
343 } |
|
344 #else |
|
345 WriteMsg(outFilePath, "sleeping"); |
|
346 while (!CheckMsg(inFilePath, "finish\n") && i++ <= seconds) { |
|
347 sleep(1); |
|
348 } |
|
349 #endif |
|
350 WriteMsg(outFilePath, "finished"); |
|
351 return 0; |
|
352 } |
|
353 |
|
354 // Command line argument test helper section |
|
355 NS_tchar logFilePath[MAXPATHLEN]; |
|
356 NS_tsnprintf(logFilePath, sizeof(logFilePath)/sizeof(logFilePath[0]), |
|
357 NS_T("%s"), argv[2]); |
|
358 |
|
359 FILE* logFP = NS_tfopen(logFilePath, NS_T("wb")); |
|
360 for (i = 1; i < argc; ++i) { |
|
361 fprintf(logFP, LOG_S "\n", argv[i]); |
|
362 } |
|
363 |
|
364 fclose(logFP); |
|
365 logFP = nullptr; |
|
366 |
|
367 return 0; |
|
368 } |