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);

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