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