pkcs7: Allow for missing optional content field
[strongswan.git] / src / stroke / stroke.c
1 /*
2 * Copyright (C) 2007-2015 Tobias Brunner
3 * Copyright (C) 2006 Martin Willi
4 *
5 * Copyright (C) secunet Security Networks AG
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <getopt.h>
24
25 #include <library.h>
26
27 #include "stroke_msg.h"
28 #include "stroke_keywords.h"
29
30 struct stroke_token {
31 char *name;
32 stroke_keyword_t kw;
33 };
34
35 static char *daemon_name = "charon";
36 static int output_verbosity = 1; /* CONTROL */
37
38 static stroke_msg_t *create_stroke_msg(int type)
39 {
40 stroke_msg_t *msg;
41
42 INIT(msg,
43 .type = type,
44 .length = offsetof(stroke_msg_t, buffer),
45 );
46 return msg;
47 }
48
49 #define push_string(msg, field, str) \
50 push_string_impl(msg, offsetof(stroke_msg_t, field), str)
51
52 static void push_string_impl(stroke_msg_t **msg, size_t offset, char *string)
53 {
54 size_t cur_len = (*msg)->length, str_len;
55
56 if (!string)
57 {
58 return;
59 }
60 str_len = strlen(string) + 1;
61 if (cur_len + str_len >= UINT16_MAX)
62 {
63 (*msg)->length = UINT16_MAX;
64 return;
65 }
66 while (cur_len + str_len > sizeof(stroke_msg_t) + (*msg)->buflen)
67 {
68 *msg = realloc(*msg, sizeof(stroke_msg_t) + (*msg)->buflen +
69 STROKE_BUF_LEN_INC);
70 (*msg)->buflen += STROKE_BUF_LEN_INC;
71 }
72 (*msg)->length += str_len;
73 strcpy((char*)*msg + cur_len, string);
74 *(char**)((char*)*msg + offset) = (char*)cur_len;
75 }
76
77 static int send_stroke_msg(stroke_msg_t *msg)
78 {
79 stream_t *stream;
80 char *uri, buffer[512], *pass;
81 int count;
82
83 if (msg->length == UINT16_MAX)
84 {
85 fprintf(stderr, "stroke message exceeds maximum buffer size");
86 free(msg);
87 return -1;
88 }
89
90 msg->output_verbosity = output_verbosity;
91
92 uri = lib->settings->get_str(lib->settings, "%s.plugins.stroke.socket",
93 "unix://" STROKE_SOCKET, daemon_name);
94 stream = lib->streams->connect(lib->streams, uri);
95 if (!stream)
96 {
97 fprintf(stderr, "failed to connect to stroke socket '%s'\n", uri);
98 free(msg);
99 return -1;
100 }
101
102 if (!stream->write_all(stream, msg, msg->length))
103 {
104 fprintf(stderr, "sending stroke message failed\n");
105 stream->destroy(stream);
106 free(msg);
107 return -1;
108 }
109
110 while ((count = stream->read(stream, buffer, sizeof(buffer)-1, TRUE)) > 0)
111 {
112 buffer[count] = '\0';
113
114 /* we prompt if we receive a magic keyword */
115 if ((count >= 12 && streq(buffer + count - 12, "Passphrase:\n")) ||
116 (count >= 10 && streq(buffer + count - 10, "Password:\n")) ||
117 (count >= 5 && streq(buffer + count - 5, "PIN:\n")))
118 {
119 /* remove trailing newline */
120 pass = strrchr(buffer, '\n');
121 if (pass)
122 {
123 *pass = ' ';
124 }
125 #ifdef HAVE_GETPASS
126 pass = getpass(buffer);
127 #else
128 pass = "";
129 #endif
130 if (pass)
131 {
132 stream->write_all(stream, pass, strlen(pass));
133 memwipe(pass, strlen(pass));
134 stream->write_all(stream, "\n", 1);
135 }
136 }
137 else
138 {
139 printf("%s", buffer);
140 }
141 }
142 if (count < 0)
143 {
144 fprintf(stderr, "reading stroke response failed\n");
145 }
146 stream->destroy(stream);
147 free(msg);
148 return 0;
149 }
150
151 static int add_connection(char *name,
152 char *my_id, char *other_id,
153 char *my_addr, char *other_addr,
154 char *my_nets, char *other_nets)
155 {
156 stroke_msg_t *msg;
157
158 msg = create_stroke_msg(STR_ADD_CONN);
159
160 push_string(&msg, add_conn.name, name);
161 msg->add_conn.version = 2;
162 msg->add_conn.mode = 1;
163 msg->add_conn.mobike = 1;
164 msg->add_conn.dpd.action = 1;
165 msg->add_conn.install_policy = 1;
166
167 push_string(&msg, add_conn.me.id, my_id);
168 push_string(&msg, add_conn.me.address, my_addr);
169 msg->add_conn.me.ikeport = 500;
170 push_string(&msg, add_conn.me.subnets, my_nets);
171 msg->add_conn.me.sendcert = 1;
172 msg->add_conn.me.to_port = 65535;
173
174 push_string(&msg, add_conn.other.id, other_id);
175 push_string(&msg, add_conn.other.address, other_addr);
176 msg->add_conn.other.ikeport = 500;
177 push_string(&msg, add_conn.other.subnets, other_nets);
178 msg->add_conn.other.sendcert = 1;
179 msg->add_conn.other.to_port = 65535;
180
181 return send_stroke_msg(msg);
182 }
183
184 static int del_connection(char *name)
185 {
186 stroke_msg_t *msg;
187
188 msg = create_stroke_msg(STR_DEL_CONN);
189 push_string(&msg, initiate.name, name);
190 return send_stroke_msg(msg);
191 }
192
193 static int initiate_connection(char *name)
194 {
195 stroke_msg_t *msg;
196
197 msg = create_stroke_msg(STR_INITIATE);
198 push_string(&msg, initiate.name, name);
199 return send_stroke_msg(msg);
200 }
201
202 static int terminate_connection(char *name)
203 {
204 stroke_msg_t *msg;
205
206 msg = create_stroke_msg(STR_TERMINATE);
207 push_string(&msg, initiate.name, name);
208 return send_stroke_msg(msg);
209 }
210
211 static int terminate_connection_srcip(char *start, char *end)
212 {
213 stroke_msg_t *msg;
214
215 msg = create_stroke_msg(STR_TERMINATE_SRCIP);
216 push_string(&msg, terminate_srcip.start, start);
217 push_string(&msg, terminate_srcip.end, end);
218 return send_stroke_msg(msg);
219 }
220
221 static int rekey_connection(char *name)
222 {
223 stroke_msg_t *msg;
224
225 msg = create_stroke_msg(STR_REKEY);
226 push_string(&msg, rekey.name, name);
227 return send_stroke_msg(msg);
228 }
229
230 static int route_connection(char *name)
231 {
232 stroke_msg_t *msg;
233
234 msg = create_stroke_msg(STR_ROUTE);
235 push_string(&msg, route.name, name);
236 return send_stroke_msg(msg);
237 }
238
239 static int unroute_connection(char *name)
240 {
241 stroke_msg_t *msg;
242
243 msg = create_stroke_msg(STR_UNROUTE);
244 push_string(&msg, unroute.name, name);
245 return send_stroke_msg(msg);
246 }
247
248 static int show_status(stroke_keyword_t kw, char *connection)
249 {
250 stroke_msg_t *msg;
251
252 switch (kw)
253 {
254 case STROKE_STATUSALL:
255 msg = create_stroke_msg(STR_STATUS_ALL);
256 break;
257 case STROKE_STATUSALL_NOBLK:
258 msg = create_stroke_msg(STR_STATUS_ALL_NOBLK);
259 break;
260 default:
261 msg = create_stroke_msg(STR_STATUS);
262 break;
263 }
264 push_string(&msg, status.name, connection);
265 return send_stroke_msg(msg);
266 }
267
268 static int list_flags[] = {
269 LIST_PUBKEYS,
270 LIST_CERTS,
271 LIST_CACERTS,
272 LIST_OCSPCERTS,
273 LIST_AACERTS,
274 LIST_ACERTS,
275 LIST_GROUPS,
276 LIST_CAINFOS,
277 LIST_CRLS,
278 LIST_OCSP,
279 LIST_ALGS,
280 LIST_PLUGINS,
281 LIST_ALL
282 };
283
284 static int list(stroke_keyword_t kw, bool utc)
285 {
286 stroke_msg_t *msg;
287
288 msg = create_stroke_msg(STR_LIST);
289 msg->list.utc = utc;
290 msg->list.flags = list_flags[kw - STROKE_LIST_FIRST];
291 return send_stroke_msg(msg);
292 }
293
294 static int reread_flags[] = {
295 REREAD_SECRETS,
296 REREAD_CACERTS,
297 REREAD_OCSPCERTS,
298 REREAD_AACERTS,
299 REREAD_ACERTS,
300 REREAD_CRLS,
301 REREAD_ALL
302 };
303
304 static int reread(stroke_keyword_t kw)
305 {
306 stroke_msg_t *msg;
307
308 msg = create_stroke_msg(STR_REREAD);
309 msg->reread.flags = reread_flags[kw - STROKE_REREAD_FIRST];
310 return send_stroke_msg(msg);
311 }
312
313 static int purge_flags[] = {
314 PURGE_OCSP,
315 PURGE_CRLS,
316 PURGE_CERTS,
317 PURGE_IKE,
318 };
319
320 static int purge(stroke_keyword_t kw)
321 {
322 stroke_msg_t *msg;
323
324 msg = create_stroke_msg(STR_PURGE);
325 msg->purge.flags = purge_flags[kw - STROKE_PURGE_FIRST];
326 return send_stroke_msg(msg);
327 }
328
329 static int export_flags[] = {
330 EXPORT_X509,
331 EXPORT_CONN_CERT,
332 EXPORT_CONN_CHAIN,
333 };
334
335 static int export(stroke_keyword_t kw, char *selector)
336 {
337 stroke_msg_t *msg;
338
339 msg = create_stroke_msg(STR_EXPORT);
340 push_string(&msg, export.selector, selector);
341 msg->export.flags = export_flags[kw - STROKE_EXPORT_FIRST];
342 return send_stroke_msg(msg);
343 }
344
345 static int leases(stroke_keyword_t kw, char *pool, char *address)
346 {
347 stroke_msg_t *msg;
348
349 msg = create_stroke_msg(STR_LEASES);
350 push_string(&msg, leases.pool, pool);
351 push_string(&msg, leases.address, address);
352 return send_stroke_msg(msg);
353 }
354
355 static int memusage()
356 {
357 stroke_msg_t *msg;
358
359 msg = create_stroke_msg(STR_MEMUSAGE);
360 return send_stroke_msg(msg);
361 }
362
363 static int user_credentials(char *name, char *user, char *pass)
364 {
365 stroke_msg_t *msg;
366
367 msg = create_stroke_msg(STR_USER_CREDS);
368 push_string(&msg, user_creds.name, name);
369 push_string(&msg, user_creds.username, user);
370 push_string(&msg, user_creds.password, pass);
371 return send_stroke_msg(msg);
372 }
373
374 static int counters(int reset, char *name)
375 {
376 stroke_msg_t *msg;
377
378 msg = create_stroke_msg(STR_COUNTERS);
379 push_string(&msg, counters.name, name);
380 msg->counters.reset = reset;
381 return send_stroke_msg(msg);
382 }
383
384 static int set_loglevel(char *type, u_int level)
385 {
386 stroke_msg_t *msg;
387
388 msg = create_stroke_msg(STR_LOGLEVEL);
389 push_string(&msg, loglevel.type, type);
390 msg->loglevel.level = level;
391 return send_stroke_msg(msg);
392 }
393
394 static int usage(char *error)
395 {
396 FILE *out = error ? stderr : stdout;
397
398 fprintf(out, "stroke [OPTIONS] command [ARGUMENTS]\n\n");
399 fprintf(out, "Options:\n");
400 fprintf(out, " -h, --help print this information.\n");
401 fprintf(out, " -d, --daemon=NAME name of the daemon.\n");
402 fprintf(out, "Commands:\n");
403 fprintf(out, " Add a connection:\n");
404 fprintf(out, " stroke add NAME MY_ID OTHER_ID MY_ADDR OTHER_ADDR\\\n");
405 fprintf(out, " MY_NET OTHER_NET\n");
406 fprintf(out, " where: ID is any IKEv2 ID \n");
407 fprintf(out, " ADDR is a IPv4 address\n");
408 fprintf(out, " NET is a IPv4 subnet in CIDR notation\n");
409 fprintf(out, " Delete a connection:\n");
410 fprintf(out, " stroke delete NAME\n");
411 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
412 fprintf(out, " Initiate a connection:\n");
413 fprintf(out, " stroke up NAME\n");
414 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
415 fprintf(out, " Initiate a connection without blocking:\n");
416 fprintf(out, " stroke up-nb NAME\n");
417 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
418 fprintf(out, " Terminate a connection:\n");
419 fprintf(out, " stroke down NAME\n");
420 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
421 fprintf(out, " Terminate a connection without blocking:\n");
422 fprintf(out, " stroke down-nb NAME\n");
423 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
424 fprintf(out, " Terminate a connection by remote srcip:\n");
425 fprintf(out, " stroke down-srcip START [END]\n");
426 fprintf(out, " where: START and optional END define the clients source IP\n");
427 fprintf(out, " Set loglevel for a logging type:\n");
428 fprintf(out, " stroke loglevel TYPE LEVEL\n");
429 fprintf(out, " where: TYPE is any|dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|esp|lib\n");
430 fprintf(out, " LEVEL is -1|0|1|2|3|4\n");
431 fprintf(out, " Show connection status:\n");
432 fprintf(out, " stroke status\n");
433 fprintf(out, " Show extended status information:\n");
434 fprintf(out, " stroke statusall\n");
435 fprintf(out, " Show extended status information without blocking:\n");
436 fprintf(out, " stroke statusall-nb\n");
437 fprintf(out, " Show list of authority and attribute certificates:\n");
438 fprintf(out, " stroke listcacerts|listocspcerts|listaacerts|listacerts [--utc]\n");
439 fprintf(out, " Show list of end entity certificates, ca info records and crls:\n");
440 fprintf(out, " stroke listcerts|listcainfos|listcrls|listall [--utc]\n");
441 fprintf(out, " Show list of supported algorithms:\n");
442 fprintf(out, " stroke listalgs\n");
443 fprintf(out, " Reload authority and attribute certificates:\n");
444 fprintf(out, " stroke rereadcacerts|rereadocspcerts|rereadaacerts|rereadacerts\n");
445 fprintf(out, " Reload secrets and crls:\n");
446 fprintf(out, " stroke rereadsecrets|rereadcrls|rereadall\n");
447 fprintf(out, " Purge ocsp cache entries:\n");
448 fprintf(out, " stroke purgeocsp\n");
449 fprintf(out, " Purge CRL cache entries:\n");
450 fprintf(out, " stroke purgecrls\n");
451 fprintf(out, " Purge X509 cache entries:\n");
452 fprintf(out, " stroke purgecerts\n");
453 fprintf(out, " Purge IKE_SAs without a CHILD_SA:\n");
454 fprintf(out, " stroke purgeike\n");
455 fprintf(out, " Export credentials to the console:\n");
456 fprintf(out, " stroke exportx509 DN\n");
457 fprintf(out, " stroke exportconncert connname\n");
458 fprintf(out, " stroke exportconnchain connname\n");
459 fprintf(out, " Show current memory usage:\n");
460 fprintf(out, " stroke memusage\n");
461 fprintf(out, " Show leases of a pool:\n");
462 fprintf(out, " stroke leases [POOL [ADDRESS]]\n");
463 fprintf(out, " Set username and password for a connection:\n");
464 fprintf(out, " stroke user-creds NAME USERNAME [PASSWORD]\n");
465 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
466 fprintf(out, " USERNAME is the username\n");
467 fprintf(out, " PASSWORD is the optional password, you'll be asked to enter it if not given\n");
468 fprintf(out, " Show IKE counters:\n");
469 fprintf(out, " stroke listcounters [connection-name]\n");
470
471 if (error)
472 {
473 fprintf(out, "\nError: %s\n", error);
474 return -1;
475 }
476 return 0;
477 }
478
479 int main(int argc, char *argv[])
480 {
481 const stroke_token_t *token;
482 char *cmd;
483 bool utc = FALSE;
484 int res = 0;
485
486 library_init(NULL, "stroke");
487 atexit(library_deinit);
488
489 while (true)
490 {
491 struct option long_opts[] = {
492 {"help", no_argument, NULL, 'h' },
493 {"utc", no_argument, NULL, 'u' },
494 {"daemon", required_argument, NULL, 'd' },
495 {0,0,0,0},
496 };
497 switch (getopt_long(argc, argv, "hd:", long_opts, NULL))
498 {
499 case EOF:
500 break;
501 case 'h':
502 return usage(NULL);
503 case 'd':
504 daemon_name = optarg;
505 continue;
506 case 'u':
507 utc = TRUE;
508 continue;
509 default:
510 return usage("invalid option");
511 }
512 break;
513 }
514
515 if (optind == argc)
516 {
517 return usage("command missing");
518 }
519
520 cmd = argv[optind++];
521 token = in_word_set(cmd, strlen(cmd));
522 if (token == NULL)
523 {
524 return usage("unknown command");
525 }
526
527 /* make argv/argc only cover positional arguments */
528 argv = &argv[optind];
529 argc = argc - optind;
530
531 switch (token->kw)
532 {
533 case STROKE_ADD:
534 if (argc < 7)
535 {
536 return usage("\"add\" needs more arguments...");
537 }
538 res = add_connection(argv[0], argv[1], argv[2], argv[3], argv[4],
539 argv[5], argv[6]);
540 break;
541 case STROKE_DELETE:
542 case STROKE_DEL:
543 if (argc < 1)
544 {
545 return usage("\"delete\" needs a connection name");
546 }
547 res = del_connection(argv[0]);
548 break;
549 case STROKE_UP_NOBLK:
550 output_verbosity = -1;
551 /* fall-through */
552 case STROKE_UP:
553 if (argc < 1)
554 {
555 return usage("\"up\" needs a connection name");
556 }
557 res = initiate_connection(argv[0]);
558 break;
559 case STROKE_DOWN_NOBLK:
560 output_verbosity = -1;
561 /* fall-through */
562 case STROKE_DOWN:
563 if (argc < 1)
564 {
565 return usage("\"down\" needs a connection name");
566 }
567 res = terminate_connection(argv[0]);
568 break;
569 case STROKE_DOWN_SRCIP:
570 if (argc < 1)
571 {
572 return usage("\"down-srcip\" needs start and optional end address");
573 }
574 res = terminate_connection_srcip(argv[0], argc > 1 ? argv[1] : NULL);
575 break;
576 case STROKE_REKEY:
577 if (argc < 1)
578 {
579 return usage("\"rekey\" needs a connection name");
580 }
581 res = rekey_connection(argv[0]);
582 break;
583 case STROKE_ROUTE:
584 if (argc < 1)
585 {
586 return usage("\"route\" needs a connection name");
587 }
588 res = route_connection(argv[0]);
589 break;
590 case STROKE_UNROUTE:
591 if (argc < 1)
592 {
593 return usage("\"unroute\" needs a connection name");
594 }
595 res = unroute_connection(argv[0]);
596 break;
597 case STROKE_LOGLEVEL:
598 if (argc < 2)
599 {
600 return usage("\"logtype\" needs more parameters...");
601 }
602 res = set_loglevel(argv[0], atoi(argv[1]));
603 break;
604 case STROKE_STATUS:
605 case STROKE_STATUSALL:
606 case STROKE_STATUSALL_NOBLK:
607 res = show_status(token->kw, argc ? argv[0] : NULL);
608 break;
609 case STROKE_LIST_PUBKEYS:
610 case STROKE_LIST_CERTS:
611 case STROKE_LIST_CACERTS:
612 case STROKE_LIST_OCSPCERTS:
613 case STROKE_LIST_AACERTS:
614 case STROKE_LIST_ACERTS:
615 case STROKE_LIST_CAINFOS:
616 case STROKE_LIST_CRLS:
617 case STROKE_LIST_OCSP:
618 case STROKE_LIST_ALGS:
619 case STROKE_LIST_PLUGINS:
620 case STROKE_LIST_ALL:
621 res = list(token->kw, utc);
622 break;
623 case STROKE_REREAD_SECRETS:
624 case STROKE_REREAD_CACERTS:
625 case STROKE_REREAD_OCSPCERTS:
626 case STROKE_REREAD_AACERTS:
627 case STROKE_REREAD_ACERTS:
628 case STROKE_REREAD_CRLS:
629 case STROKE_REREAD_ALL:
630 res = reread(token->kw);
631 break;
632 case STROKE_PURGE_OCSP:
633 case STROKE_PURGE_CRLS:
634 case STROKE_PURGE_CERTS:
635 case STROKE_PURGE_IKE:
636 res = purge(token->kw);
637 break;
638 case STROKE_EXPORT_X509:
639 case STROKE_EXPORT_CONN_CERT:
640 case STROKE_EXPORT_CONN_CHAIN:
641 if (argc < 1)
642 {
643 return usage("\"export\" needs a name");
644 }
645 res = export(token->kw, argv[0]);
646 break;
647 case STROKE_LEASES:
648 res = leases(token->kw, argc ? argv[0] : NULL,
649 argc > 1 ? argv[1] : NULL);
650 break;
651 case STROKE_MEMUSAGE:
652 res = memusage();
653 break;
654 case STROKE_USER_CREDS:
655 if (argc < 2)
656 {
657 return usage("\"user-creds\" needs a connection name, "
658 "username and optionally a password");
659 }
660 res = user_credentials(argv[0], argv[1], argc > 2 ? argv[2] : NULL);
661 break;
662 case STROKE_COUNTERS:
663 case STROKE_COUNTERS_RESET:
664 res = counters(token->kw == STROKE_COUNTERS_RESET,
665 argc ? argv[0] : NULL);
666 break;
667 default:
668 return usage(NULL);
669 }
670 return res;
671 }