Mercurial > trustbridge
comparison cinst/main.c @ 289:9ad00a3255f4
Change cinst from stdin input to use arguments.
As we have to execute this process on Windows over the
shell a stdin / stdout communication is not really possible
without some major hacks. So you now have to supply an
instructions file and the path to the certificatelist as arguments when
this process is called
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Wed, 02 Apr 2014 13:52:02 +0000 |
parents | 4de97f74d038 |
children | b460d2cf088d |
comparison
equal
deleted
inserted
replaced
288:c4a989a0d6cf | 289:9ad00a3255f4 |
---|---|
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" |
39 | 43 |
40 /* The certificate list + instructions may only be so long as | 44 /* The certificate list + instructions may only be so long as |
41 * twice the accepted certificatelist size */ | 45 * twice the accepted certificatelist size */ |
42 #define MAX_INPUT_SIZE MAX_LINE_LENGTH * MAX_LINES * 2 | 46 #define MAX_INPUT_SIZE MAX_LINE_LENGTH * MAX_LINES * 2 |
43 | 47 |
44 /* @brief Read stdin into data structures. | 48 /* @brief Read stdin into data structures. |
45 * | 49 * |
46 * Reads from stdin and sorts the input into the respective | 50 * Reads instructions from an input file into the to_install |
47 * variables. The pointers returned need to be freed by the caller. | 51 * and to_remove buffers. |
52 * | |
53 * Lines starting with I: are treated as install instructions. | |
54 * Lines starting with R: are treated as remove instructions. | |
55 * Other lines are ignored. | |
56 * | |
48 * Terminates in OOM conditions. | 57 * Terminates in OOM conditions. |
49 * | 58 * |
50 * The caller needs to free the memory allocated by this function | 59 * The caller needs to free the memory allocated by this function |
51 * even when an error is returned. | 60 * even when an error is returned. |
52 * | 61 * |
53 * Uninstall certificates are all certificates that are pa | 62 * @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 | 63 * @param[out] to_install strv of installation instructions or NULL |
57 * @param[out] to_remove strv of remove instructions or NULL | 64 * @param[out] to_remove strv of remove instructions or NULL |
58 * @param[out] all_certs strv of uninstallation instructions or NULL | |
59 * | 65 * |
60 * @returns: 0 on success. An error code otherwise. | 66 * @returns: 0 on success. An error code otherwise. |
61 */ | 67 */ |
62 int | 68 static int |
63 readInput (char **certificate_list, char ***to_install, | 69 read_instructions_file (char *file_name, char ***to_install, |
64 char ***to_remove, char ***all_certs) | 70 char ***to_remove) |
65 { | 71 { |
66 int lines_read = 0; | 72 int lines_read = 0; |
67 int readingList = 0; | |
68 size_t list_size = 0; | |
69 char buf[MAX_LINE_LENGTH + 2]; | 73 char buf[MAX_LINE_LENGTH + 2]; |
70 | 74 FILE *f = NULL; |
71 if (*certificate_list || *to_install || *to_remove) | 75 long file_size; |
72 { | 76 |
73 printf ("Error invalid parameters\n"); | 77 if (*to_install || *to_remove) |
78 { | |
79 printf ("Error invalid parameters.\n"); | |
74 return -1; | 80 return -1; |
75 } | 81 } |
76 | 82 |
77 while (fgets (buf, MAX_LINE_LENGTH + 1, stdin) ) | 83 f = fopen (file_name, "rb"); |
78 { | 84 if (f == NULL) |
79 size_t len = strlen (buf); /* fgets ensures buf is terminated */ | 85 return ERR_NO_INSTRUCTIONS; |
86 | |
87 fseek (f, 0, SEEK_END); | |
88 file_size = ftell (f); | |
89 if (file_size <= 0) | |
90 { | |
91 fclose (f); | |
92 return ERR_NO_INSTRUCTIONS; | |
93 } | |
94 | |
95 fseek (f, 0, SEEK_SET); | |
96 | |
97 if (file_size + 1 == 0) | |
98 { | |
99 fclose (f); | |
100 return ERR_INVALID_INSTRUCTIONS; | |
101 } | |
102 | |
103 while (fgets (buf, MAX_LINE_LENGTH + 1, f) ) | |
104 { | |
105 size_t len = strlen (buf); /* fgets ensures buf is terminated */ | |
80 if (len <= 3) | 106 if (len <= 3) |
81 { | 107 { |
82 printf ("Line too short.\n"); | 108 printf ("Line too short.\n"); |
83 return ERR_INVALID_INPUT; | 109 return ERR_INVALID_INPUT; |
84 } | 110 } |
85 if (lines_read++ > MAX_LINES) | 111 if (lines_read++ > MAX_LINES) |
86 { | 112 { |
87 printf ("Too many lines\n"); | 113 printf ("Too many lines\n"); |
88 return ERR_TOO_MUCH_INPUT; | 114 return ERR_TOO_MUCH_INPUT; |
89 } | 115 } |
90 | 116 if (*buf == 'I') |
91 if (buf[len - 2] != '\r') | 117 { |
92 { | 118 /* Remove leading I: and trailing \n */ |
93 if (buf[len - 1] != '\n') | 119 strv_append (to_install, buf + 2, len - 3); |
94 { | |
95 printf ("Line too long.\n"); | |
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; | 120 continue; |
108 } | 121 } |
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') | 122 if (*buf == 'R') |
131 { | 123 { |
132 /* Remove leading R: and trailing \r\n */ | 124 /* Remove leading R: and trailing \n */ |
133 strv_append (readingList ? all_certs : to_remove, buf + 2, len - 4); | 125 strv_append (to_remove, buf + 2, len - 3); |
134 continue; | 126 continue; |
135 } | 127 } |
136 } | 128 } |
137 | 129 |
138 return 0; | 130 return 0; |
187 return 0; | 179 return 0; |
188 } | 180 } |
189 | 181 |
190 | 182 |
191 int | 183 int |
192 main () | 184 main (int argc, char **argv) |
193 { | 185 { |
194 char **to_install = NULL; | 186 /* TODO handle wchar arguments on Windows or do conversion dance */ |
195 char **to_remove = NULL; | 187 char **to_install = NULL, |
196 char **all_certs = NULL; | 188 **to_remove = NULL, |
197 char *certificate_list = NULL; | 189 **all_valid_certs = NULL; |
190 int ret = -1; | |
191 | |
192 char *certificate_list = NULL, | |
193 *certificate_file_name = NULL, | |
194 *instruction_file_name = NULL; | |
198 size_t list_len = 0; | 195 size_t list_len = 0; |
199 int ret = -1; | 196 list_status_t list_status; |
200 bool uninstall = false; | 197 bool do_uninstall = false; |
201 | 198 |
202 ret = readInput (&certificate_list, &to_install, &to_remove, &all_certs); | 199 /* Some very static argument parsing. list= and instructions= is only |
200 added to make it more transparent how this programm is called if | |
201 a user looks at the detailed uac dialog. */ | |
202 if (argc != 3 || strncmp(argv[1], "list=", 5) != 0 || | |
203 strncmp(argv[2], "instructions=", 13) != 0) | |
204 { | |
205 ERRORPRINTF ("Invalid arguments.\n" | |
206 "Expected arguments: list=<certificate_list> \n" | |
207 " instructions=<instructions_file>|uninstall\n"); | |
208 return ERR_INVALID_PARAMS; | |
209 } | |
210 | |
211 certificate_file_name = strchr(argv[1], '=') + 1; | |
212 instruction_file_name = strchr(argv[2], '=') + 1; | |
213 | |
214 if (!certificate_file_name || !instruction_file_name) | |
215 { | |
216 ERRORPRINTF ("Invalid arguments.\n" | |
217 "Expected arguments: list=<certificate_list> \n" | |
218 " instructions=<instructions_file>|uninstall\n"); | |
219 return ERR_INVALID_PARAMS; | |
220 } | |
221 | |
222 if (strncmp(instruction_file_name, "uninstall", 9) == 0) | |
223 { | |
224 do_uninstall = true; | |
225 instruction_file_name = NULL; | |
226 } | |
227 | |
228 list_status = read_and_verify_list (certificate_file_name, &certificate_list, | |
229 &list_len); | |
230 | |
231 if (list_status != Valid) | |
232 { | |
233 if (list_status == InvalidSignature) | |
234 { | |
235 return ERR_INVALID_SIGNATURE; | |
236 } | |
237 | |
238 return ERR_INVALID_INPUT_NO_LIST; | |
239 } | |
240 | |
241 all_valid_certs = get_certs_from_list (certificate_list, list_len); | |
242 | |
243 if (!all_valid_certs) | |
244 { | |
245 /* Impossible */ | |
246 return -1; | |
247 } | |
248 | |
249 | |
250 #ifdef WIN32 | |
251 /* For uninstall we are done now */ | |
252 if (do_uninstall) | |
253 { | |
254 return write_stores_win (NULL, all_valid_certs); | |
255 } | |
256 #endif | |
257 | |
258 ret = read_instructions_file (instruction_file_name, &to_install, | |
259 &to_remove); | |
203 | 260 |
204 if (ret) | 261 if (ret) |
205 { | 262 { |
206 return ret; | 263 return ret; |
207 } | 264 } |
208 | 265 |
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) ) | 266 if (!strv_length (to_install) && !strv_length (to_remove) ) |
224 { | 267 { |
225 return ERR_NO_INSTRUCTIONS; | 268 return ERR_NO_INSTRUCTIONS; |
226 } | 269 } |
227 | |
228 | 270 |
229 /* Check that the instructions are ok to execute */ | 271 /* Check that the instructions are ok to execute */ |
230 if (to_install) | 272 if (to_install) |
231 { | 273 { |
232 ret = validate_instructions (all_certs, to_install); | 274 ret = validate_instructions (all_valid_certs, to_install); |
233 if (ret) | 275 if (ret) |
234 { | 276 { |
235 return ret; | 277 return ret; |
236 } | 278 } |
237 } | 279 } |
238 | 280 |
239 if (to_remove) | 281 if (to_remove) |
240 { | 282 { |
241 if (to_remove[0] | 283 ret = validate_instructions (all_valid_certs, to_remove); |
242 && strncmp ("UNINSTALL", to_remove[0], MAX_LINE_LENGTH) == 0) | 284 if (ret) |
243 { | 285 { |
244 uninstall = true; | 286 return ret; |
245 strv_free (to_remove); | 287 } |
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 } | 288 } |
269 | 289 |
270 #ifdef WIN32 | 290 #ifdef WIN32 |
271 return write_stores_win (to_install, to_remove); | 291 return write_stores_win (to_install, to_remove); |
272 #endif | 292 #endif |