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