Mercurial > trustbridge
comparison cinst/nssstore_win.c @ 324:eff8e7ce4dae
Add first compiling implementation of nssstore_win.c
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Mon, 07 Apr 2014 13:34:50 +0000 |
parents | |
children | b1059360a0c7 |
comparison
equal
deleted
inserted
replaced
323:31ba7ed4d50f | 324:eff8e7ce4dae |
---|---|
1 #ifdef WIN32 | |
2 | |
3 /* @file | |
4 @brief Windows implementation of nssstore process control. | |
5 */ | |
6 | |
7 #include <windows.h> | |
8 #include <stdio.h> | |
9 #include <strsafe.h> | |
10 #include <stdbool.h> | |
11 #include <userenv.h> | |
12 | |
13 #include "logging.h" | |
14 #include "util.h" | |
15 | |
16 #define PROCESS_TIMEOUT 30000 /* In milliseconds */ | |
17 | |
18 #define BUFSIZE 4096 /* used for reading childs stdout */ | |
19 | |
20 #define PRINTLASTERROR(msg) \ | |
21 char *my_error = getLastErrorMsg(); \ | |
22 if (my_error) { \ | |
23 DEBUGMSG(msg " :"); \ | |
24 DEBUGMSG(my_error); \ | |
25 ERRORPRINTF(msg" : %s\n", my_error); \ | |
26 free (my_error); \ | |
27 } \ | |
28 DEBUGMSG ("Failed to get error information\n"); | |
29 | |
30 /**@brief Write strv of instructions to a handle | |
31 * | |
32 * Writes the null terminated list of instructions to | |
33 * the handle. | |
34 * | |
35 * @param [in] instructions instructions to write | |
36 * @param [in] write_handle to write to | |
37 * | |
38 * @returns true on success, false on failure | |
39 */ | |
40 static bool | |
41 write_instructions(char **instructions, HANDLE write_handle) | |
42 { | |
43 bool retval = false; | |
44 int i = 0; | |
45 const char *line_end = "\n\0"; | |
46 | |
47 if (!instructions) | |
48 { | |
49 return true; | |
50 } | |
51 | |
52 for (i = 0; instructions[i]; i++) | |
53 { | |
54 DWORD written = 0; | |
55 DWORD inst_len = strlen (instructions[i]); | |
56 retval = WriteFile (write_handle, (LPCVOID) instructions[i], inst_len, &written, NULL); | |
57 if (!retval) | |
58 { | |
59 PRINTLASTERROR ("Failed to write\n"); | |
60 return false; | |
61 } | |
62 if (inst_len != written) | |
63 { | |
64 ERRORPRINTF ("Failed to write everything\n"); | |
65 retval = false; | |
66 return false; | |
67 } | |
68 written = 0; | |
69 retval = WriteFile (write_handle, (LPCVOID) line_end, 2, &written, NULL); | |
70 if (!retval) | |
71 { | |
72 PRINTLASTERROR ("Failed to write line end\n"); | |
73 return false; | |
74 } | |
75 if (inst_len != written) | |
76 { | |
77 ERRORPRINTF ("Failed to write full line end\n"); | |
78 retval = false; | |
79 return false; | |
80 } | |
81 } | |
82 return true; | |
83 } | |
84 | |
85 /**@brief Start the process to install / remove | |
86 * | |
87 * Creates a child process with the Security handle specified in hToken | |
88 * sends the instructions and then waits for the process to finish. | |
89 * | |
90 * If the process is not done in PROCESS_TIMEOUT seconds this assumes an | |
91 * unknown error happened. | |
92 * | |
93 * @param [in] to_install strv of DER encoded certificates to be added. | |
94 * @param [in] to_remove strv of DER encoded certificates to be remvoed. | |
95 * @param [in] hToken handle to the primary token that is used to install | |
96 * certificates. | |
97 * | |
98 * @returns true on success, false on error. | |
99 */ | |
100 static bool | |
101 start_procces_for_user (char **to_install, char **to_remove, | |
102 HANDLE hToken) | |
103 { | |
104 HANDLE h_stdin_child_r = NULL, | |
105 h_stdin_child_w = NULL, | |
106 h_stdout_child_r = NULL, | |
107 h_stdout_child_w = NULL; | |
108 SECURITY_ATTRIBUTES saAttr = {0}; | |
109 /* TODO get this as absolute path based on current module location */ | |
110 LPWSTR lpApplicationName = L"mozilla.exe"; | |
111 PROCESS_INFORMATION piProcInfo = {0}; | |
112 STARTUPINFOW siStartInfo = {0}; | |
113 LPVOID lpEnvironment = NULL; | |
114 BOOL success = FALSE; | |
115 int retval = -1; | |
116 | |
117 saAttr.nLength = sizeof (SECURITY_ATTRIBUTES); | |
118 saAttr.bInheritHandle = TRUE; | |
119 saAttr.lpSecurityDescriptor = NULL; /* Use default */ | |
120 | |
121 /* Create a pipe for the child process's STDIN. */ | |
122 if (!CreatePipe (&h_stdin_child_r, &h_stdin_child_w, &saAttr, 0)) | |
123 { | |
124 PRINTLASTERROR ("Create pipe failed.\n"); | |
125 return -1; | |
126 } | |
127 | |
128 /* Create a pipe for the child process's STDOUT. */ | |
129 if (!CreatePipe (&h_stdout_child_r, &h_stdout_child_w, &saAttr, 0)) | |
130 { | |
131 PRINTLASTERROR ("Create pipe failed.\n"); | |
132 return -1; | |
133 } | |
134 | |
135 /* Ensure that read/write is properly inherited */ | |
136 if (!SetHandleInformation (h_stdin_child_w, HANDLE_FLAG_INHERIT, 0) || | |
137 !SetHandleInformation (h_stdout_child_r, HANDLE_FLAG_INHERIT, 0)) | |
138 { | |
139 PRINTLASTERROR ("SetHandleInformation failed.\n"); | |
140 goto closepipes; | |
141 } | |
142 | |
143 /* Create the environment for the user */ | |
144 if (!CreateEnvironmentBlock (&lpEnvironment, hToken, FALSE)) | |
145 { | |
146 PRINTLASTERROR ("Failed to create the environment.\n"); | |
147 goto closepipes; | |
148 } | |
149 | |
150 /* set up handles. stdin and stdout go to the same stdout*/ | |
151 siStartInfo.cb = sizeof (STARTUPINFO); | |
152 siStartInfo.hStdError = h_stdout_child_w; | |
153 siStartInfo.hStdOutput = h_stdout_child_w; | |
154 siStartInfo.hStdInput = h_stdin_child_w; | |
155 siStartInfo.dwFlags = STARTF_USESTDHANDLES; | |
156 | |
157 success = CreateProcessAsUserW (hToken, | |
158 lpApplicationName, | |
159 NULL, /* Commandline */ | |
160 NULL, /* Process attributes. Take hToken */ | |
161 NULL, /* Thread attribues. Take hToken */ | |
162 TRUE, /* Inherit Handles */ | |
163 0, /* Creation flags. Use default */ | |
164 lpEnvironment, | |
165 NULL, /* Current working directory */ | |
166 &siStartInfo, | |
167 &piProcInfo); | |
168 if (!success) | |
169 { | |
170 PRINTLASTERROR ("Failed to create process.\n"); | |
171 goto closepipes; | |
172 } | |
173 | |
174 if (!write_instructions (to_install, h_stdin_child_w)) | |
175 { | |
176 ERRORPRINTF ("Failed to write install instructions.\n"); | |
177 goto closepipes; | |
178 } | |
179 if (!write_instructions (to_remove, h_stdin_child_w)) | |
180 { | |
181 ERRORPRINTF ("Failed to write remove instructions.\n"); | |
182 goto closepipes; | |
183 } | |
184 | |
185 /* Close the Handle so that the child knows we are finished | |
186 telling it what to do */ | |
187 CloseHandle (h_stdin_child_w); | |
188 h_stdin_child_w = NULL; | |
189 | |
190 #ifndef RELEASE_BUILD | |
191 /* print childs stdout / stderr to parents stdout */ | |
192 { | |
193 HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); | |
194 DWORD read_bytes = 0; | |
195 DWORD written = 0; | |
196 bool success; | |
197 char buf[BUFSIZE]; | |
198 | |
199 if (!stdout_handle || stdout_handle == INVALID_HANDLE_VALUE) | |
200 { | |
201 /* Should not happen */ | |
202 ERRORPRINTF("Failed to get stdout handle.\n"); | |
203 goto closeprocess; | |
204 } | |
205 | |
206 for (;;) | |
207 { | |
208 success = ReadFile (h_stdout_child_r, buf, BUFSIZE, &read_bytes, NULL); | |
209 if(!success || read_bytes == 0) | |
210 break; | |
211 | |
212 success = WriteFile (stdout_handle, buf, | |
213 read_bytes, &written, NULL); | |
214 if (!success || written != read_bytes) | |
215 break; | |
216 } | |
217 } | |
218 #endif | |
219 | |
220 if (WaitForSingleObject (piProcInfo.hProcess, PROCESS_TIMEOUT) != WAIT_OBJECT_0) | |
221 { | |
222 /* Should not happen... */ | |
223 ERRORPRINTF ("Failed to wait for process.\n"); | |
224 } | |
225 | |
226 closeprocess: | |
227 if (piProcInfo.hProcess) | |
228 CloseHandle(piProcInfo.hProcess); | |
229 if (piProcInfo.hThread) | |
230 CloseHandle(piProcInfo.hThread); | |
231 | |
232 closepipes: | |
233 if (h_stdin_child_w) | |
234 CloseHandle(h_stdin_child_w); | |
235 if (h_stdin_child_r) | |
236 CloseHandle(h_stdin_child_r); | |
237 if (h_stdout_child_w) | |
238 CloseHandle(h_stdout_child_w); | |
239 if (h_stdout_child_r) | |
240 CloseHandle(h_stdout_child_r); | |
241 | |
242 return retval; | |
243 } | |
244 | |
245 int | |
246 write_stores_nss (char **to_install, char **to_remove) | |
247 { | |
248 HANDLE hToken = NULL; | |
249 OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken); | |
250 | |
251 /* TODO loop over all users */ | |
252 if (!start_procces_for_user (to_install, to_remove, hToken)) | |
253 { | |
254 ERRORPRINTF ("Failed to run NSS installation process.\n"); | |
255 return -1; | |
256 } | |
257 return 0; | |
258 } | |
259 | |
260 #endif |