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