Mercurial > trustbridge
comparison cinst/main.c @ 310:f758460ca437
Merged
author | Sascha Wilde <wilde@intevation.de> |
---|---|
date | Fri, 04 Apr 2014 09:54:19 +0200 |
parents | fac7e1b0e558 |
children | f17226aa2e09 |
comparison
equal
deleted
inserted
replaced
309:fa37384b86b6 | 310:f758460ca437 |
---|---|
5 * The cinst process may or may not be run with elevated | 5 * The cinst process may or may not be run with elevated |
6 * privileges. When run with elevated privileges this | 6 * privileges. When run with elevated privileges this |
7 * process will modify system wide certificate stores. | 7 * process will modify system wide certificate stores. |
8 * Otherwise only the users certificate stores are modified. | 8 * Otherwise only the users certificate stores are modified. |
9 * | 9 * |
10 * It expects a certificatelist on stdin enclosed in a | 10 * The first parameter to this process should be list=<file_name> |
11 * -----BEGIN CERTIFICATE LIST----- | 11 * of the certificate list to work on. The second parameter should |
12 * ... | 12 * be instruction=<instruction_file_name>|uninstall |
13 * -----END CERTIFICATE LIST----- | 13 * |
14 * | 14 * instruction_file_name should be the absolute path to an |
15 * Followed by additional instruction lines of: | 15 * instructions file formatted as: |
16 * | |
16 * I:<certificate> | 17 * I:<certificate> |
17 * R:<certificate> | 18 * R:<certificate> |
19 * | |
20 * Line breaks can be system dependent in the Instructions file. | |
18 * | 21 * |
19 * It will only execute the instructions if the | 22 * It will only execute the instructions if the |
20 * I and R instructions are also part of the signed | 23 * I and R instructions are also part of the signed |
21 * certificate list. The signature is validated with the | 24 * certificate list. The signature is validated with the |
22 * built in key. | 25 * built in key. |
23 * | 26 * |
24 * The special instruction "UNINSTALL" will cause the installer | 27 * The special instruction "uninstall" will cause the installer |
25 * to remove all certificates (Even those marked with I) that | 28 * to remove all certificates (Even those marked with I) that |
26 * are part of the list to be removed. | 29 * are part of the list. |
27 * | 30 * |
28 **/ | 31 **/ |
29 #include <stdio.h> | 32 #include <stdio.h> |
30 #include <stdlib.h> | 33 #include <stdlib.h> |
31 #include <string.h> | 34 #include <string.h> |
32 #include <assert.h> | 35 #include <assert.h> |
33 #include <stdbool.h> | 36 #include <stdbool.h> |
34 | 37 |
35 #include "strhelp.h" | 38 #include "strhelp.h" |
36 #include "listutil.h" | 39 #include "listutil.h" |
40 #include "logging.h" | |
37 #include "errorcodes.h" | 41 #include "errorcodes.h" |
38 #include "windowsstore.h" | 42 #include "windowsstore.h" |
43 #include "nssstore.h" | |
39 | 44 |
40 /* The certificate list + instructions may only be so long as | 45 /* The certificate list + instructions may only be so long as |
41 * twice the accepted certificatelist size */ | 46 * twice the accepted certificatelist size */ |
42 #define MAX_INPUT_SIZE MAX_LINE_LENGTH * MAX_LINES * 2 | 47 #define MAX_INPUT_SIZE MAX_LINE_LENGTH * MAX_LINES * 2 |
43 | 48 |
44 /* @brief Read stdin into data structures. | 49 /* @brief Read stdin into data structures. |
45 * | 50 * |
46 * Reads from stdin and sorts the input into the respective | 51 * Reads instructions from an input file into the to_install |
47 * variables. The pointers returned need to be freed by the caller. | 52 * and to_remove buffers. |
53 * | |
54 * Lines starting with I: are treated as install instructions. | |
55 * Lines starting with R: are treated as remove instructions. | |
56 * Other lines are ignored. | |
57 * | |
48 * Terminates in OOM conditions. | 58 * Terminates in OOM conditions. |
49 * | 59 * |
50 * The caller needs to free the memory allocated by this function | 60 * The caller needs to free the memory allocated by this function |
51 * even when an error is returned. | 61 * even when an error is returned. |
52 * | 62 * |
53 * Uninstall certificates are all certificates that are pa | 63 * @param[in] file_name absolute path to the instructions file. |
54 * | |
55 * @param[out] certificate_list the parsed certificate list | |
56 * @param[out] to_install strv of installation instructions or NULL | 64 * @param[out] to_install strv of installation instructions or NULL |
57 * @param[out] to_remove strv of remove instructions or NULL | 65 * @param[out] to_remove strv of remove instructions or NULL |
58 * @param[out] all_certs strv of uninstallation instructions or NULL | |
59 * | 66 * |
60 * @returns: 0 on success. An error code otherwise. | 67 * @returns: 0 on success. An error code otherwise. |
61 */ | 68 */ |
62 int | 69 static int |
63 readInput (char **certificate_list, char ***to_install, | 70 read_instructions_file (char *file_name, char ***to_install, |
64 char ***to_remove, char ***all_certs) | 71 char ***to_remove) |
65 { | 72 { |
66 int lines_read = 0; | 73 int lines_read = 0; |
67 int readingList = 0; | |
68 size_t list_size = 0; | |
69 char buf[MAX_LINE_LENGTH + 2]; | 74 char buf[MAX_LINE_LENGTH + 2]; |
70 | 75 FILE *f = NULL; |
71 if (*certificate_list || *to_install || *to_remove) | 76 long file_size; |
72 { | 77 |
73 printf ("Error invalid parameters\n"); | 78 if (*to_install || *to_remove) |
79 { | |
80 printf ("Error invalid parameters.\n"); | |
74 return -1; | 81 return -1; |
75 } | 82 } |
76 | 83 |
77 while (fgets (buf, MAX_LINE_LENGTH + 1, stdin) ) | 84 f = fopen (file_name, "rb"); |
78 { | 85 if (f == NULL) |
79 size_t len = strlen (buf); /* fgets ensures buf is terminated */ | 86 return ERR_NO_INSTRUCTIONS; |
87 | |
88 fseek (f, 0, SEEK_END); | |
89 file_size = ftell (f); | |
90 if (file_size <= 0) | |
91 { | |
92 fclose (f); | |
93 return ERR_NO_INSTRUCTIONS; | |
94 } | |
95 | |
96 fseek (f, 0, SEEK_SET); | |
97 | |
98 if (file_size + 1 == 0) | |
99 { | |
100 fclose (f); | |
101 return ERR_INVALID_INSTRUCTIONS; | |
102 } | |
103 | |
104 while (fgets (buf, MAX_LINE_LENGTH + 1, f) ) | |
105 { | |
106 size_t len = strlen (buf); /* fgets ensures buf is terminated */ | |
80 if (len <= 3) | 107 if (len <= 3) |
81 { | 108 { |
82 printf ("Line too short.\n"); | 109 printf ("Line too short.\n"); |
83 return ERR_INVALID_INPUT; | 110 return ERR_INVALID_INPUT; |
84 } | 111 } |
85 if (lines_read++ > MAX_LINES) | 112 if (lines_read++ > MAX_LINES) |
86 { | 113 { |
87 printf ("Too many lines\n"); | 114 printf ("Too many lines\n"); |
88 return ERR_TOO_MUCH_INPUT; | 115 return ERR_TOO_MUCH_INPUT; |
89 } | 116 } |
90 | 117 if (*buf == 'I') |
91 if (buf[len - 2] != '\r') | 118 { |
92 { | 119 char *trimmed = buf+2; |
93 if (buf[len - 1] != '\n') | 120 /* Remove leading I: and trailing whitespace */ |
94 { | 121 str_trim(&trimmed); |
95 printf ("Line too long.\n"); | 122 strv_append (to_install, trimmed, strlen(trimmed)); |
96 return ERR_INVALID_INPUT; | |
97 } | |
98 buf[len - 1] = '\r'; | |
99 buf[len] = '\n'; | |
100 buf[len + 1] = '\0'; | |
101 len++; | |
102 } | |
103 | |
104 if (strcmp ("-----BEGIN CERTIFICATE LIST-----\r\n", buf) == 0) | |
105 { | |
106 readingList = 1; | |
107 continue; | 123 continue; |
108 } | 124 } |
109 if (strcmp ("-----END CERTIFICATE LIST-----\r\n", buf) == 0) | |
110 { | |
111 readingList = 0; | |
112 continue; | |
113 } | |
114 if (readingList) | |
115 { | |
116 str_append_str (certificate_list, &list_size, buf, len); | |
117 } | |
118 else if (strcmp ("UNINSTALL\r\n", buf) == 0) | |
119 { | |
120 /* Remove trailing \r\n */ | |
121 strv_append (to_remove, buf, len - 2); | |
122 continue; | |
123 } | |
124 if (*buf == 'I') | |
125 { | |
126 /* Remove leading I: and trailing \r\n */ | |
127 strv_append (readingList ? all_certs : to_install, buf + 2, len - 4); | |
128 continue; | |
129 } | |
130 if (*buf == 'R') | 125 if (*buf == 'R') |
131 { | 126 { |
132 /* Remove leading R: and trailing \r\n */ | 127 char *trimmed = buf+2; |
133 strv_append (readingList ? all_certs : to_remove, buf + 2, len - 4); | 128 /* Remove leading R: and trailing whitespace */ |
129 str_trim(&trimmed); | |
130 strv_append (to_remove, trimmed, strlen(trimmed)); | |
134 continue; | 131 continue; |
135 } | 132 } |
136 } | 133 } |
137 | 134 |
138 return 0; | 135 return 0; |
168 for (i = 0; to_validate[i]; i++) | 165 for (i = 0; to_validate[i]; i++) |
169 { | 166 { |
170 bool found = false; | 167 bool found = false; |
171 for (j = 0; all_certs[j]; j++) | 168 for (j = 0; all_certs[j]; j++) |
172 { | 169 { |
173 if (strncmp (to_validate[i], all_certs[j], MAX_LINE_LENGTH - 2) == | 170 if (strncmp (to_validate[i], all_certs[j], MAX_LINE_LENGTH) == |
174 0) | 171 0) |
175 { | 172 { |
176 found = true; | 173 found = true; |
177 break; | 174 break; |
178 } | 175 } |
179 } | 176 } |
180 if (!found) | 177 if (!found) |
181 { | 178 { |
182 printf ("Install instruction with invalid certificate\n."); | 179 DEBUGPRINTF ("Failed to find certificate; \n%s\n", to_validate[i]); |
183 return ERR_INVALID_INSTRUCTIONS; | 180 return ERR_INVALID_INSTRUCTIONS; |
184 } | 181 } |
185 } | 182 } |
186 | 183 |
187 return 0; | 184 return 0; |
188 } | 185 } |
189 | 186 |
190 | 187 |
191 int | 188 int |
192 main () | 189 main (int argc, char **argv) |
193 { | 190 { |
194 char **to_install = NULL; | 191 /* TODO handle wchar arguments on Windows or do conversion dance */ |
195 char **to_remove = NULL; | 192 char **to_install = NULL, |
196 char **all_certs = NULL; | 193 **to_remove = NULL, |
197 char *certificate_list = NULL; | 194 **all_valid_certs = NULL; |
195 int ret = -1; | |
196 | |
197 char *certificate_list = NULL, | |
198 *certificate_file_name = NULL, | |
199 *instruction_file_name = NULL; | |
198 size_t list_len = 0; | 200 size_t list_len = 0; |
199 int ret = -1; | 201 list_status_t list_status; |
200 bool uninstall = false; | 202 bool do_uninstall = false; |
201 | 203 |
202 ret = readInput (&certificate_list, &to_install, &to_remove, &all_certs); | 204 /* Some very static argument parsing. list= and instructions= is only |
205 added to make it more transparent how this programm is called if | |
206 a user looks at the detailed uac dialog. */ | |
207 if (argc != 3 || strncmp(argv[1], "list=", 5) != 0 || | |
208 strncmp(argv[2], "instructions=", 13) != 0) | |
209 { | |
210 ERRORPRINTF ("Invalid arguments.\n" | |
211 "Expected arguments: list=<certificate_list> \n" | |
212 " instructions=<instructions_file>|uninstall\n"); | |
213 return ERR_INVALID_PARAMS; | |
214 } | |
215 | |
216 certificate_file_name = strchr(argv[1], '=') + 1; | |
217 instruction_file_name = strchr(argv[2], '=') + 1; | |
218 | |
219 if (!certificate_file_name || !instruction_file_name) | |
220 { | |
221 ERRORPRINTF ("Invalid arguments.\n" | |
222 "Expected arguments: list=<certificate_list> \n" | |
223 " instructions=<instructions_file>|uninstall\n"); | |
224 return ERR_INVALID_PARAMS; | |
225 } | |
226 | |
227 if (strncmp(instruction_file_name, "uninstall", 9) == 0) | |
228 { | |
229 do_uninstall = true; | |
230 instruction_file_name = NULL; | |
231 } | |
232 | |
233 list_status = read_and_verify_list (certificate_file_name, &certificate_list, | |
234 &list_len); | |
235 | |
236 if (list_status != Valid) | |
237 { | |
238 if (list_status == InvalidSignature) | |
239 { | |
240 return ERR_INVALID_SIGNATURE; | |
241 } | |
242 | |
243 return ERR_INVALID_INPUT_NO_LIST; | |
244 } | |
245 | |
246 all_valid_certs = get_certs_from_list (certificate_list, list_len); | |
247 | |
248 if (!all_valid_certs) | |
249 { | |
250 /* Impossible */ | |
251 return -1; | |
252 } | |
253 | |
254 | |
255 /* For uninstall we are done now */ | |
256 if (do_uninstall) | |
257 { | |
258 #ifdef WIN32 | |
259 ret = write_stores_win (NULL, all_valid_certs); | |
260 if (ret != 0) | |
261 { | |
262 ERRORPRINTF ("Failed to write windows stores retval: %i\n", ret); | |
263 } | |
264 #endif | |
265 ret = write_stores_nss (NULL, all_valid_certs); | |
266 return ret; | |
267 } | |
268 | |
269 ret = read_instructions_file (instruction_file_name, &to_install, | |
270 &to_remove); | |
203 | 271 |
204 if (ret) | 272 if (ret) |
205 { | 273 { |
206 return ret; | 274 return ret; |
207 } | 275 } |
208 | 276 |
209 if (!certificate_list) | |
210 { | |
211 return ERR_INVALID_INPUT_NO_LIST; | |
212 } | |
213 | |
214 list_len = strnlen (certificate_list, MAX_INPUT_SIZE); | |
215 | |
216 ret = verify_list (certificate_list, list_len); | |
217 | |
218 if (ret) | |
219 { | |
220 return ERR_INVALID_SIGNATURE; | |
221 } | |
222 | |
223 if (!strv_length (to_install) && !strv_length (to_remove) ) | 277 if (!strv_length (to_install) && !strv_length (to_remove) ) |
224 { | 278 { |
225 return ERR_NO_INSTRUCTIONS; | 279 return ERR_NO_INSTRUCTIONS; |
226 } | 280 } |
227 | |
228 | 281 |
229 /* Check that the instructions are ok to execute */ | 282 /* Check that the instructions are ok to execute */ |
230 if (to_install) | 283 if (to_install) |
231 { | 284 { |
232 ret = validate_instructions (all_certs, to_install); | 285 ret = validate_instructions (all_valid_certs, to_install); |
233 if (ret) | 286 if (ret) |
234 { | 287 { |
235 return ret; | 288 return ret; |
236 } | 289 } |
237 } | 290 } |
238 | 291 |
239 if (to_remove) | 292 if (to_remove) |
240 { | 293 { |
241 if (to_remove[0] | 294 ret = validate_instructions (all_valid_certs, to_remove); |
242 && strncmp ("UNINSTALL", to_remove[0], MAX_LINE_LENGTH) == 0) | 295 if (ret) |
243 { | 296 { |
244 uninstall = true; | 297 return ret; |
245 strv_free (to_remove); | 298 } |
246 to_remove = NULL; | |
247 } | |
248 else | |
249 { | |
250 ret = validate_instructions (all_certs, to_remove); | |
251 if (ret) | |
252 { | |
253 return ret; | |
254 } | |
255 } | |
256 } | |
257 | |
258 if (uninstall) | |
259 { | |
260 /* To uninstall does not have to be verified as it part of the | |
261 * signed list.*/ | |
262 to_remove = all_certs; | |
263 } | |
264 else | |
265 { | |
266 strv_free (all_certs); | |
267 all_certs = NULL; | |
268 } | 299 } |
269 | 300 |
270 #ifdef WIN32 | 301 #ifdef WIN32 |
271 return write_stores_win (to_install, to_remove); | 302 ret = write_stores_win (to_install, to_remove); |
303 if (ret != 0) | |
304 { | |
305 ERRORPRINTF ("Failed to write windows stores retval: %i\n", ret); | |
306 } | |
272 #endif | 307 #endif |
308 ret = write_stores_nss (to_install, to_remove); | |
309 | |
310 if (ret != 0) | |
311 { | |
312 ERRORPRINTF ("Failed to write nss stores"); | |
313 } | |
273 | 314 |
274 /* Make valgrind happy */ | 315 /* Make valgrind happy */ |
275 strv_free (to_install); | 316 strv_free (to_install); |
276 strv_free (to_remove); | 317 strv_free (to_remove); |
277 free (certificate_list); | 318 free (certificate_list); |