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

http://wald.intevation.org/projects/trustbridge/