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