comparison cinst/certificate-installer.c @ 1176:c8f698ca6355

(issue128) Rename cinst to trustbridge-certificate-installer
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 22 Sep 2014 11:34:06 +0200
parents cinst/main.c@2a1206932f53
children 12ed0b72e9f5
comparison
equal deleted inserted replaced
1175:e210ecc32d69 1176:c8f698ca6355
1 /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
2 * Software engineering by Intevation GmbH
3 *
4 * This file is Free Software under the GNU GPL (v>=2)
5 * and comes with ABSOLUTELY NO WARRANTY!
6 * See LICENSE.txt for details.
7 */
8 /**
9 * @file certificate-installer.c
10 * @brief Main entry point for the certificate install process.
11 *
12 * The certificate installer process may or may not be run with elevated
13 * privileges. When run with elevated privileges this
14 * process will modify system wide certificate stores.
15 * Otherwise only the users certificate stores are modified.
16 *
17 * The first parameter to this process should be list=\<file_name\>
18 * of the certificate list to work on. The second parameter should
19 * be choices=\<choices_file_name\>|uninstall
20 *
21 * choices_file_name should be the absolute path to an
22 * choices file formatted as:
23 *
24 * I:\<certificate\><BR>
25 * R:\<certificate\>
26 *
27 * Line breaks can be system dependent in the Choices file.
28 *
29 * It will only execute the choices if the
30 * I and R choices are also part of the signed
31 * certificate list. The signature is validated with the
32 * built in key.
33 *
34 * The special instruction "uninstall" will cause the installer
35 * to remove all certificates (Even those marked with I) that
36 * are part of the list.
37 *
38 * For more verbose debug output add --debug to the call.
39 *
40 **/
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <assert.h>
45 #include <stdbool.h>
46
47 #include "strhelp.h"
48 #include "listutil.h"
49 #include "logging.h"
50 #include "errorcodes.h"
51 #include "windowsstore.h"
52 #include "nssstore.h"
53 #include "portpath.h"
54
55 /* The certificate list + choices may only be so long as
56 * twice the accepted certificatelist size */
57 #define MAX_INPUT_SIZE MAX_LINE_LENGTH * MAX_LINES * 2
58
59 /* @brief Read stdin into data structures.
60 *
61 * Reads choices from an input file into the to_install
62 * and to_remove buffers.
63 *
64 * Lines starting with I: are treated as install choices.
65 * Lines starting with R: are treated as remove choices.
66 * Other lines are ignored.
67 *
68 * Terminates in OOM conditions.
69 *
70 * The caller needs to free the memory allocated by this function
71 * even when an error is returned.
72 *
73 * @param[in] file_name absolute path to the choices file.
74 * @param[out] to_install strv of installation choices or NULL
75 * @param[out] to_remove strv of remove choices or NULL
76 *
77 * @returns: 0 on success. An error code otherwise.
78 */
79 static int
80 read_choices_file (char *file_name, char ***to_install,
81 char ***to_remove)
82 {
83 int lines_read = 0;
84 char buf[MAX_LINE_LENGTH + 2];
85 FILE *f = NULL;
86 long file_size;
87
88 if (*to_install || *to_remove)
89 {
90 ERRORPRINTF ("Error invalid parameters.\n");
91 return -1;
92 }
93
94 f = port_fopen_rb(file_name, false);
95 if (f == NULL)
96 {
97 ERRORPRINTF ("Failed to open file: %s\n", file_name);
98 return ERR_NO_INSTRUCTIONS;
99 }
100
101 fseek (f, 0, SEEK_END);
102 file_size = ftell (f);
103 if (file_size <= 0)
104 {
105 fclose (f);
106 ERRORPRINTF ("File size error: %s\n", file_name);
107 return ERR_NO_INSTRUCTIONS;
108 }
109
110 fseek (f, 0, SEEK_SET);
111
112 if (file_size + 1 == 0)
113 {
114 fclose (f);
115 ERRORPRINTF ("File seek error: %s\n", file_name);
116 return ERR_INVALID_INSTRUCTIONS;
117 }
118
119 while (fgets (buf, MAX_LINE_LENGTH + 1, f) )
120 {
121 size_t len = strlen (buf); /* fgets ensures buf is terminated */
122 if (len <= 3)
123 {
124 ERRORPRINTF ("Line too short.\n");
125 fclose (f);
126 return ERR_INVALID_INPUT;
127 }
128 if (lines_read++ > MAX_LINES)
129 {
130 ERRORPRINTF ("Too many lines\n");
131 fclose (f);
132 return ERR_TOO_MUCH_INPUT;
133 }
134 if (*buf == 'I')
135 {
136 char *trimmed = buf+2;
137 /* Remove leading I: and trailing whitespace */
138 str_trim(&trimmed);
139 strv_append (to_install, trimmed, strlen(trimmed));
140 continue;
141 }
142 if (*buf == 'R')
143 {
144 char *trimmed = buf+2;
145 /* Remove leading R: and trailing whitespace */
146 str_trim(&trimmed);
147 strv_append (to_remove, trimmed, strlen(trimmed));
148 continue;
149 }
150 }
151
152 fclose (f);
153 return 0;
154 }
155
156 /** @brief Check that the insturctions match to the list
157 *
158 * Only certificates part of the certificate_list are allowed
159 * for installation.
160 *
161 * @param[in] all_certs strv of all valid certificates in a list
162 * @param[in] to_validate strv of choices
163 *
164 * @returns 0 on success, an error otherwise
165 */
166 int
167 validate_choices (char **all_certs, char **to_validate)
168 {
169 int i = 0, j = 0;
170
171 if (!all_certs || strv_length (all_certs) < 1)
172 {
173 /* Invalid parameters */
174 return -1;
175 }
176
177 if (to_validate == NULL)
178 {
179 /* Nothing is valid */
180 return 0;
181 }
182
183 for (i = 0; to_validate[i]; i++)
184 {
185 bool found = false;
186 for (j = 0; all_certs[j]; j++)
187 {
188 if (strncmp (to_validate[i], all_certs[j], MAX_LINE_LENGTH) ==
189 0)
190 {
191 found = true;
192 break;
193 }
194 }
195 if (!found)
196 {
197 DEBUGPRINTF ("Failed to find certificate; \n%s\n", to_validate[i]);
198 return ERR_INVALID_INSTRUCTIONS;
199 }
200 }
201
202 return 0;
203 }
204
205 #ifdef DO_RELEASE_BUILD
206 bool g_debug = false;
207 #else
208 bool g_debug = true;
209 #endif
210
211 int
212 main (int argc, char **argv)
213 {
214 char **to_install = NULL,
215 **to_remove = NULL,
216 **all_valid_certs = NULL;
217 int ret = -1;
218
219 char *certificate_list = NULL,
220 *certificate_file_name = NULL,
221 *choices_file_name = NULL;
222 size_t list_len = 0;
223 list_status_t list_status;
224 bool do_uninstall = false;
225
226 /* Some very static argument parsing. list= and choices= is only
227 added to make it more transparent how this programm is called if
228 a user looks at the detailed uac dialog. */
229 if ((argc != 3 && argc != 4) || strncmp(argv[1], "list=", 5) != 0 ||
230 strncmp(argv[2], "choices=", 8) != 0)
231 {
232 ERRORPRINTF ("Invalid arguments.\n"
233 "Expected arguments: list=<certificate_list> \n"
234 " choices=<choices_file>|uninstall\n"
235 "Optional: --debug\n");
236 return ERR_INVALID_PARAMS;
237 }
238
239 certificate_file_name = strchr(argv[1], '=') + 1;
240 choices_file_name = strchr(argv[2], '=') + 1;
241
242 if (argc == 4 && strncmp(argv[3], "--debug", 7) == 0)
243 {
244 g_debug = true;
245 }
246
247 if (!certificate_file_name || !choices_file_name)
248 {
249 ERRORPRINTF ("Invalid arguments.\n"
250 "Expected arguments: list=<certificate_list> \n"
251 " choices=<choices_file>|uninstall\n");
252 return ERR_INVALID_PARAMS;
253 }
254
255 if (strncmp(choices_file_name, "uninstall", 9) == 0)
256 {
257 do_uninstall = true;
258 choices_file_name = NULL;
259 }
260
261 list_status = read_and_verify_list (certificate_file_name, &certificate_list,
262 &list_len);
263
264 if (list_status != Valid)
265 {
266 if (list_status == InvalidSignature)
267 {
268 ERRORPRINTF ("Failed to verify signature.\n");
269 return ERR_INVALID_SIGNATURE;
270 }
271
272 ERRORPRINTF ("Failed to read certificate list.\n");
273 return ERR_INVALID_INPUT_NO_LIST;
274 }
275
276 all_valid_certs = get_certs_from_list (certificate_list, list_len);
277 free (certificate_list);
278
279 if (!all_valid_certs)
280 {
281 /* Impossible */
282 return -1;
283 }
284
285
286 /* For uninstall we are done now */
287 if (do_uninstall)
288 {
289 #ifdef WIN32
290 ret = write_stores_win (NULL, all_valid_certs);
291 if (ret != 0)
292 {
293 ERRORPRINTF ("Failed to write windows stores retval: %i\n", ret);
294 }
295 #endif
296 ret = write_stores_nss (NULL, all_valid_certs);
297 strv_free (all_valid_certs);
298 return ret;
299 }
300
301 ret = read_choices_file (choices_file_name, &to_install,
302 &to_remove);
303
304 if (ret)
305 {
306 ERRORPRINTF ("Failed to read choices file\n");
307 return ret;
308 }
309
310 if (!strv_length (to_install) && !strv_length (to_remove) )
311 {
312 ERRORPRINTF ("Failed to read choices file\n");
313 return ERR_NO_INSTRUCTIONS;
314 }
315
316 /* Check that the choices are ok to execute */
317 if (to_install)
318 {
319 ret = validate_choices (all_valid_certs, to_install);
320 if (ret)
321 {
322 ERRORPRINTF ("Failed to validate choices\n");
323 return ret;
324 }
325 }
326
327 if (to_remove)
328 {
329 ret = validate_choices (all_valid_certs, to_remove);
330 if (ret)
331 {
332 ERRORPRINTF ("Failed to validate removal choices\n");
333 return ret;
334 }
335 }
336
337 strv_free (all_valid_certs);
338
339 #ifdef WIN32
340 ret = write_stores_win (to_install, to_remove);
341 if (ret != 0)
342 {
343 ERRORPRINTF ("Failed to write windows stores retval: %i\n", ret);
344 }
345 #endif
346 ret = write_stores_nss (to_install, to_remove);
347 if (ret != 0)
348 {
349 ERRORPRINTF ("Failed to write nss stores");
350 }
351
352 /* Make valgrind happy */
353 strv_free (to_install);
354 strv_free (to_remove);
355
356 return 0;
357 }

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