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

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