getpass(3) is not supported on Android.
[strongswan.git] / src / whack / whack.c
1 /* command interface to Pluto
2 * Copyright (C) 1997 Angelos D. Keromytis.
3 * Copyright (C) 1998-2001 D. Hugh Redelmeier.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stddef.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <getopt.h>
29 #include <assert.h>
30
31 #include <freeswan.h>
32
33 #include <utils/optionsfrom.h>
34
35 #include "constants.h"
36 #include "defs.h"
37 #include "whack.h"
38
39 static void help(void)
40 {
41 fprintf(stderr
42 , "Usage:\n\n"
43 "all forms:"
44 " [--optionsfrom <filename>]"
45 " [--ctlbase <path>]"
46 " [--label <string>]"
47 "\n\n"
48 "help: whack"
49 " [--help]"
50 " [--version]"
51 "\n\n"
52 "connection: whack"
53 " --name <connection_name>"
54 " \\\n "
55 " [--ipv4 | --ipv6]"
56 " [--tunnelipv4 | --tunnelipv6]"
57 " \\\n "
58 " (--host <ip-address> | --id <identity>)"
59 " \\\n "
60 " [--cert <path>]"
61 " [--ca <distinguished name>]"
62 " [--sendcert <policy>]"
63 " \\\n "
64 " [--groups <access control groups>]"
65 " \\\n "
66 " [--ikeport <port-number>]"
67 " [--nexthop <ip-address>]"
68 " [--srcip <ip-address>]"
69 " \\\n "
70 " [--client <subnet> | --clientwithin <address range>]"
71 " [--clientprotoport <protocol>/<port>]"
72 " \\\n "
73 " [--dnskeyondemand]"
74 " [--updown <updown>]"
75 " \\\n "
76 " --to"
77 " (--host <ip-address> | --id <identity>)"
78 " \\\n "
79 " [--cert <path>]"
80 " [--ca <distinguished name>]"
81 " [--sendcert <policy>]"
82 " \\\n "
83 " [--ikeport <port-number>]"
84 " [--nexthop <ip-address>]"
85 " [--srcip <ip-address>]"
86 " \\\n "
87 " [--client <subnet> | --clientwithin <address range>]"
88 " [--clientprotoport <protocol>/<port>]"
89 " \\\n "
90 " [--dnskeyondemand]"
91 " [--updown <updown>]"
92 " [--psk]"
93 " [--rsasig]"
94 " \\\n "
95 " [--encrypt]"
96 " [--authenticate]"
97 " [--compress]"
98 " [--tunnel]"
99 " [--pfs]"
100 " \\\n "
101 " [--ikelifetime <seconds>]"
102 " [--ipseclifetime <seconds>]"
103 " \\\n "
104 " [--reykeymargin <seconds>]"
105 " [--reykeyfuzz <percentage>]"
106 " \\\n "
107 " [--keyingtries <count>]"
108 " \\\n "
109 " [--esp <esp-algos>]"
110 " \\\n "
111 " [--dontrekey]"
112
113 " [--dpdaction (none|clear|hold|restart)]"
114 " \\\n "
115 " [--dpddelay <seconds> --dpdtimeout <seconds>]"
116 " \\\n "
117 " [--initiateontraffic|--pass|--drop|--reject]"
118 " \\\n "
119 " [--failnone|--failpass|--faildrop|--failreject]"
120 "\n\n"
121 "routing: whack"
122 " (--route | --unroute)"
123 " --name <connection_name>"
124 "\n\n"
125 "initiation:"
126 "\n "
127 " whack"
128 " (--initiate | --terminate)"
129 " --name <connection_name>"
130 " [--asynchronous]"
131 "\n\n"
132 "opportunistic initiation: whack"
133 " [--tunnelipv4 | --tunnelipv6]"
134 " \\\n "
135 " --oppohere <ip-address>"
136 " --oppothere <ip-address>"
137 "\n\n"
138 "delete: whack"
139 " --delete"
140 " (--name <connection_name> | --caname <ca name>)"
141 "\n\n"
142 "deletestate: whack"
143 " --deletestate <state_object_number>"
144 " --crash <ip-address>"
145 "\n\n"
146 "pubkey: whack"
147 " --keyid <id>"
148 " [--addkey]"
149 " [--pubkeyrsa <key>]"
150 "\n\n"
151 "myid: whack"
152 " --myid <id>"
153 "\n\n"
154 "ca: whack"
155 " --caname <name>"
156 " --cacert <path>"
157 " \\\n "
158 " [--ldaphost <hostname>]"
159 " [--ldapbase <base>]"
160 " \\\n "
161 " [--crluri <uri>]"
162 " [--crluri2 <uri>]"
163 " [--ocspuri <uri>]"
164 " [--strictcrlpolicy]"
165 "\n\n"
166 #ifdef DEBUG
167 "debug: whack [--name <connection_name>]"
168 " \\\n "
169 " [--debug-none]"
170 " [--debug-all]"
171 " \\\n "
172 " [--debug-raw]"
173 " [--debug-crypt]"
174 " [--debug-parsing]"
175 " [--debug-emitting]"
176 " \\\n "
177 " [--debug-control]"
178 " [--debug-lifecycle]"
179 " [--debug-kernel]"
180 " [--debug-dns]"
181 " \\\n "
182 " [--debug-natt]"
183 " [--debug-oppo]"
184 " [--debug-controlmore]"
185 " [--debug-private]"
186 "\n\n"
187 #endif
188 "leases: whack --leases"
189 " [--name <connection_name>]"
190 " [--lease-addr <ip-address> | --lease-id <identity>]"
191 "\n\n"
192 "listen: whack"
193 " (--listen | --unlisten)"
194 "\n\n"
195 "list: whack [--utc]"
196 " [--listalgs]"
197 " [--listpubkeys]"
198 " [--listcerts]"
199 " [--listcacerts]"
200 " \\\n "
201 " [--listacerts]"
202 " [--listaacerts]"
203 " [--listocspcerts]"
204 " [--listgroups]"
205 " \\\n "
206 " [--listcainfos]"
207 " [--listcrls]"
208 " [--listocsp]"
209 " [--listcards]"
210 " [--listall]"
211 "\n\n"
212 "purge: whack"
213 " [--purgeocsp]"
214 "\n\n"
215 "reread: whack"
216 " [--rereadsecrets]"
217 " [--rereadcacerts]"
218 " [--rereadaacerts]"
219 " \\\n "
220 " [--rereadocspcerts]"
221 " [--rereadacerts]"
222 " [--rereadcrls]"
223 " [--rereadall]"
224 "\n\n"
225 "status: whack"
226 " [--name <connection_name>] --status|--statusall"
227 "\n\n"
228 "scdecrypt: whack"
229 " --scencrypt|scdecrypt <value>"
230 " [--inbase <base>]"
231 " [--outbase <base>]"
232 " [--keyid <id>]"
233 "\n\n"
234 "shutdown: whack"
235 " --shutdown"
236 "\n\n"
237 "strongSwan "VERSION"\n");
238 }
239
240 static const char *label = NULL; /* --label operand, saved for diagnostics */
241
242 static const char *name = NULL; /* --name operand, saved for diagnostics */
243
244 /* options read by optionsfrom */
245 options_t *options;
246
247 /**
248 * exit whack after cleaning up
249 */
250 static void whack_exit(int status)
251 {
252 options->destroy(options);
253 exit(status);
254 }
255
256 /**
257 * print a string as a diagnostic, then exit whack unhappily
258 */
259 static void diag(const char *mess)
260 {
261 if (mess != NULL)
262 {
263 fprintf(stderr, "whack error: ");
264 if (label != NULL)
265 {
266 fprintf(stderr, "%s ", label);
267 }
268 if (name != NULL)
269 {
270 fprintf(stderr, "\"%s\" ", name);
271 }
272 fprintf(stderr, "%s\n", mess);
273 }
274 whack_exit(RC_WHACK_PROBLEM);
275 }
276
277 /* conditially calls diag; prints second arg, if non-NULL, as quoted string */
278 static void diagq(err_t ugh, const char *this)
279 {
280 if (ugh != NULL)
281 {
282 if (this == NULL)
283 {
284 diag(ugh);
285 }
286 else
287 {
288 char buf[120]; /* arbitrary limit */
289
290 snprintf(buf, sizeof(buf), "%s \"%s\"", ugh, this);
291 diag(buf);
292 }
293 }
294 }
295
296 /* complex combined operands return one of these enumerated values
297 * Note: these become flags in an lset_t. Since there are more than
298 * 32, we partition them into:
299 * - OPT_* options (most random options)
300 * - LST_* options (list various internal data)
301 * - DBGOPT_* option (DEBUG options)
302 * - END_* options (End description options)
303 * - CD_* options (Connection Description options)
304 * - CA_* options (CA description options)
305 */
306 enum {
307 # define OPT_FIRST OPT_CTLBASE
308 OPT_CTLBASE,
309 OPT_NAME,
310
311 OPT_CD,
312
313 OPT_KEYID,
314 OPT_ADDKEY,
315 OPT_PUBKEYRSA,
316
317 OPT_MYID,
318
319 OPT_ROUTE,
320 OPT_UNROUTE,
321
322 OPT_INITIATE,
323 OPT_TERMINATE,
324 OPT_DELETE,
325 OPT_DELETESTATE,
326 OPT_LISTEN,
327 OPT_UNLISTEN,
328
329 OPT_LEASES,
330 OPT_LEASEADDR,
331 OPT_LEASEID,
332
333 OPT_PURGEOCSP,
334
335 OPT_REREADSECRETS,
336 OPT_REREADCACERTS,
337 OPT_REREADAACERTS,
338 OPT_REREADOCSPCERTS,
339 OPT_REREADACERTS,
340 OPT_REREADCRLS,
341 OPT_REREADALL,
342
343 OPT_STATUS,
344 OPT_STATUSALL,
345 OPT_SHUTDOWN,
346
347 OPT_OPPO_HERE,
348 OPT_OPPO_THERE,
349
350 OPT_ASYNC,
351 OPT_DELETECRASH,
352
353 # define OPT_LAST OPT_ASYNC /* last "normal" option */
354
355 /* Smartcard options */
356
357 # define SC_FIRST SC_ENCRYPT /* first smartcard option */
358
359 SC_ENCRYPT,
360 SC_DECRYPT,
361 SC_INBASE,
362 SC_OUTBASE,
363
364 # define SC_LAST SC_OUTBASE /* last "smartcard" option */
365
366 /* List options */
367
368 # define LST_FIRST LST_UTC /* first list option */
369 LST_UTC,
370 LST_ALGS,
371 LST_PUBKEYS,
372 LST_CERTS,
373 LST_CACERTS,
374 LST_ACERTS,
375 LST_AACERTS,
376 LST_OCSPCERTS,
377 LST_GROUPS,
378 LST_CAINFOS,
379 LST_CRLS,
380 LST_OCSP,
381 LST_CARDS,
382 LST_ALL,
383
384 # define LST_LAST LST_ALL /* last list option */
385
386 /* Connection End Description options */
387
388 # define END_FIRST END_HOST /* first end description */
389 END_HOST,
390 END_ID,
391 END_CERT,
392 END_CA,
393 END_SENDCERT,
394 END_GROUPS,
395 END_IKEPORT,
396 END_NEXTHOP,
397 END_CLIENT,
398 END_CLIENTWITHIN,
399 END_CLIENTPROTOPORT,
400 END_DNSKEYONDEMAND,
401 END_SRCIP,
402 END_HOSTACCESS,
403 END_UPDOWN,
404
405 #define END_LAST END_UPDOWN /* last end description*/
406
407 /* Connection Description options -- segregated */
408
409 # define CD_FIRST CD_TO /* first connection description */
410 CD_TO,
411
412 # define CD_POLICY_FIRST CD_PSK
413 CD_PSK, /* same order as POLICY_* */
414 CD_RSASIG, /* same order as POLICY_* */
415 CD_ENCRYPT, /* same order as POLICY_* */
416 CD_AUTHENTICATE, /* same order as POLICY_* */
417 CD_COMPRESS, /* same order as POLICY_* */
418 CD_TUNNEL, /* same order as POLICY_* */
419 CD_PFS, /* same order as POLICY_* */
420 CD_DISABLEARRIVALCHECK, /* same order as POLICY_* */
421 CD_SHUNT0, /* same order as POLICY_* */
422 CD_SHUNT1, /* same order as POLICY_* */
423 CD_FAIL0, /* same order as POLICY_* */
424 CD_FAIL1, /* same order as POLICY_* */
425 CD_DONT_REKEY, /* same order as POLICY_* */
426
427 CD_TUNNELIPV4,
428 CD_TUNNELIPV6,
429 CD_CONNIPV4,
430 CD_CONNIPV6,
431
432 CD_IKELIFETIME,
433 CD_IPSECLIFETIME,
434 CD_RKMARGIN,
435 CD_RKFUZZ,
436 CD_KTRIES,
437 CD_DPDACTION,
438 CD_DPDDELAY,
439 CD_DPDTIMEOUT,
440 CD_IKE,
441 CD_PFSGROUP,
442 CD_ESP,
443
444 # define CD_LAST CD_ESP /* last connection description */
445
446 /* Certificate Authority (CA) description options */
447
448 # define CA_FIRST CA_NAME /* first ca description */
449
450 CA_NAME,
451 CA_CERT,
452 CA_LDAPHOST,
453 CA_LDAPBASE,
454 CA_CRLURI,
455 CA_CRLURI2,
456 CA_OCSPURI,
457 CA_STRICT
458
459 # define CA_LAST CA_STRICT /* last ca description */
460
461 #ifdef DEBUG /* must be last so others are less than 32 to fit in lset_t */
462 # define DBGOPT_FIRST DBGOPT_NONE
463 ,
464 /* NOTE: these definitions must match DBG_* and IMPAIR_* in constants.h */
465 DBGOPT_NONE,
466 DBGOPT_ALL,
467
468 DBGOPT_RAW, /* same order as DBG_* */
469 DBGOPT_CRYPT, /* same order as DBG_* */
470 DBGOPT_PARSING, /* same order as DBG_* */
471 DBGOPT_EMITTING, /* same order as DBG_* */
472 DBGOPT_CONTROL, /* same order as DBG_* */
473 DBGOPT_LIFECYCLE, /* same order as DBG_* */
474 DBGOPT_KERNEL, /* same order as DBG_* */
475 DBGOPT_DNS, /* same order as DBG_* */
476 DBGOPT_NATT, /* same order as DBG_* */
477 DBGOPT_OPPO, /* same order as DBG_* */
478 DBGOPT_CONTROLMORE, /* same order as DBG_* */
479
480 DBGOPT_PRIVATE, /* same order as DBG_* */
481
482 DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER, /* same order as IMPAIR_* */
483 DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER, /* same order as IMPAIR_* */
484 DBGOPT_IMPAIR_BUST_MI2, /* same order as IMPAIR_* */
485 DBGOPT_IMPAIR_BUST_MR2 /* same order as IMPAIR_* */
486
487 # define DBGOPT_LAST DBGOPT_IMPAIR_BUST_MR2
488 #endif
489
490 };
491
492 /* Carve up space for result from getop_long.
493 * Stupidly, the only result is an int.
494 * Numeric arg is bit immediately left of basic value.
495 *
496 */
497 #define OPTION_OFFSET 256 /* to get out of the way of letter options */
498 #define NUMERIC_ARG (1 << 9) /* expect a numeric argument */
499 #define AUX_SHIFT 10 /* amount to shift for aux information */
500
501 static const struct option long_opts[] = {
502 # define OO OPTION_OFFSET
503 /* name, has_arg, flag, val */
504
505 { "help", no_argument, NULL, 'h' },
506 { "version", no_argument, NULL, 'v' },
507 { "optionsfrom", required_argument, NULL, '+' },
508 { "label", required_argument, NULL, 'l' },
509
510 { "ctlbase", required_argument, NULL, OPT_CTLBASE + OO },
511 { "name", required_argument, NULL, OPT_NAME + OO },
512
513 { "keyid", required_argument, NULL, OPT_KEYID + OO },
514 { "addkey", no_argument, NULL, OPT_ADDKEY + OO },
515 { "pubkeyrsa", required_argument, NULL, OPT_PUBKEYRSA + OO },
516
517 { "myid", required_argument, NULL, OPT_MYID + OO },
518
519 { "route", no_argument, NULL, OPT_ROUTE + OO },
520 { "unroute", no_argument, NULL, OPT_UNROUTE + OO },
521
522 { "initiate", no_argument, NULL, OPT_INITIATE + OO },
523 { "terminate", no_argument, NULL, OPT_TERMINATE + OO },
524 { "delete", no_argument, NULL, OPT_DELETE + OO },
525 { "deletestate", required_argument, NULL, OPT_DELETESTATE + OO + NUMERIC_ARG },
526 { "crash", required_argument, NULL, OPT_DELETECRASH + OO },
527 { "listen", no_argument, NULL, OPT_LISTEN + OO },
528 { "unlisten", no_argument, NULL, OPT_UNLISTEN + OO },
529
530 { "leases", no_argument, NULL, OPT_LEASES + OO },
531 { "lease-addr", required_argument, NULL, OPT_LEASEADDR + OO },
532 { "lease-id", required_argument, NULL, OPT_LEASEID + OO },
533
534 { "purgeocsp", no_argument, NULL, OPT_PURGEOCSP + OO },
535
536 { "rereadsecrets", no_argument, NULL, OPT_REREADSECRETS + OO },
537 { "rereadcacerts", no_argument, NULL, OPT_REREADCACERTS + OO },
538 { "rereadaacerts", no_argument, NULL, OPT_REREADAACERTS + OO },
539 { "rereadocspcerts", no_argument, NULL, OPT_REREADOCSPCERTS + OO },
540 { "rereadacerts", no_argument, NULL, OPT_REREADACERTS + OO },
541 { "rereadcrls", no_argument, NULL, OPT_REREADCRLS + OO },
542 { "rereadall", no_argument, NULL, OPT_REREADALL + OO },
543 { "status", no_argument, NULL, OPT_STATUS + OO },
544 { "statusall", no_argument, NULL, OPT_STATUSALL + OO },
545 { "shutdown", no_argument, NULL, OPT_SHUTDOWN + OO },
546
547 { "oppohere", required_argument, NULL, OPT_OPPO_HERE + OO },
548 { "oppothere", required_argument, NULL, OPT_OPPO_THERE + OO },
549
550 { "asynchronous", no_argument, NULL, OPT_ASYNC + OO },
551
552 /* smartcard options */
553
554 { "scencrypt", required_argument, NULL, SC_ENCRYPT + OO },
555 { "scdecrypt", required_argument, NULL, SC_DECRYPT + OO },
556 { "inbase", required_argument, NULL, SC_INBASE + OO },
557 { "outbase", required_argument, NULL, SC_OUTBASE + OO },
558
559 /* list options */
560
561 { "utc", no_argument, NULL, LST_UTC + OO },
562 { "listalgs", no_argument, NULL, LST_ALGS + OO },
563 { "listpubkeys", no_argument, NULL, LST_PUBKEYS + OO },
564 { "listcerts", no_argument, NULL, LST_CERTS + OO },
565 { "listcacerts", no_argument, NULL, LST_CACERTS + OO },
566 { "listacerts", no_argument, NULL, LST_ACERTS + OO },
567 { "listaacerts", no_argument, NULL, LST_AACERTS + OO },
568 { "listocspcerts", no_argument, NULL, LST_OCSPCERTS + OO },
569 { "listgroups", no_argument, NULL, LST_GROUPS + OO },
570 { "listcainfos", no_argument, NULL, LST_CAINFOS + OO },
571 { "listcrls", no_argument, NULL, LST_CRLS + OO },
572 { "listocsp", no_argument, NULL, LST_OCSP + OO },
573 { "listcards", no_argument, NULL, LST_CARDS + OO },
574 { "listall", no_argument, NULL, LST_ALL + OO },
575
576 /* options for an end description */
577
578 { "host", required_argument, NULL, END_HOST + OO },
579 { "id", required_argument, NULL, END_ID + OO },
580 { "cert", required_argument, NULL, END_CERT + OO },
581 { "ca", required_argument, NULL, END_CA + OO },
582 { "sendcert", required_argument, NULL, END_SENDCERT + OO },
583 { "groups", required_argument, NULL, END_GROUPS + OO },
584 { "ikeport", required_argument, NULL, END_IKEPORT + OO + NUMERIC_ARG },
585 { "nexthop", required_argument, NULL, END_NEXTHOP + OO },
586 { "client", required_argument, NULL, END_CLIENT + OO },
587 { "clientwithin", required_argument, NULL, END_CLIENTWITHIN + OO },
588 { "clientprotoport", required_argument, NULL, END_CLIENTPROTOPORT + OO },
589 { "dnskeyondemand", no_argument, NULL, END_DNSKEYONDEMAND + OO },
590 { "srcip", required_argument, NULL, END_SRCIP + OO },
591 { "hostaccess", no_argument, NULL, END_HOSTACCESS + OO },
592 { "updown", required_argument, NULL, END_UPDOWN + OO },
593
594 /* options for a connection description */
595
596 { "to", no_argument, NULL, CD_TO + OO },
597
598 { "psk", no_argument, NULL, CD_PSK + OO },
599 { "rsasig", no_argument, NULL, CD_RSASIG + OO },
600
601 { "encrypt", no_argument, NULL, CD_ENCRYPT + OO },
602 { "authenticate", no_argument, NULL, CD_AUTHENTICATE + OO },
603 { "compress", no_argument, NULL, CD_COMPRESS + OO },
604 { "tunnel", no_argument, NULL, CD_TUNNEL + OO },
605 { "tunnelipv4", no_argument, NULL, CD_TUNNELIPV4 + OO },
606 { "tunnelipv6", no_argument, NULL, CD_TUNNELIPV6 + OO },
607 { "pfs", no_argument, NULL, CD_PFS + OO },
608 { "disablearrivalcheck", no_argument, NULL, CD_DISABLEARRIVALCHECK + OO },
609 { "initiateontraffic", no_argument, NULL
610 , CD_SHUNT0 + (POLICY_SHUNT_TRAP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
611 { "pass", no_argument, NULL
612 , CD_SHUNT0 + (POLICY_SHUNT_PASS >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
613 { "drop", no_argument, NULL
614 , CD_SHUNT0 + (POLICY_SHUNT_DROP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
615 { "reject", no_argument, NULL
616 , CD_SHUNT0 + (POLICY_SHUNT_REJECT >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
617 { "failnone", no_argument, NULL
618 , CD_FAIL0 + (POLICY_FAIL_NONE >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
619 { "failpass", no_argument, NULL
620 , CD_FAIL0 + (POLICY_FAIL_PASS >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
621 { "faildrop", no_argument, NULL
622 , CD_FAIL0 + (POLICY_FAIL_DROP >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
623 { "failreject", no_argument, NULL
624 , CD_FAIL0 + (POLICY_FAIL_REJECT >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
625 { "dontrekey", no_argument, NULL, CD_DONT_REKEY + OO },
626 { "ipv4", no_argument, NULL, CD_CONNIPV4 + OO },
627 { "ipv6", no_argument, NULL, CD_CONNIPV6 + OO },
628
629 { "ikelifetime", required_argument, NULL, CD_IKELIFETIME + OO + NUMERIC_ARG },
630 { "ipseclifetime", required_argument, NULL, CD_IPSECLIFETIME + OO + NUMERIC_ARG },
631 { "rekeymargin", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },
632 { "rekeywindow", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG }, /* OBSOLETE */
633 { "rekeyfuzz", required_argument, NULL, CD_RKFUZZ + OO + NUMERIC_ARG },
634 { "keyingtries", required_argument, NULL, CD_KTRIES + OO + NUMERIC_ARG },
635 { "dpdaction", required_argument, NULL, CD_DPDACTION + OO },
636 { "dpddelay", required_argument, NULL, CD_DPDDELAY + OO + NUMERIC_ARG },
637 { "dpdtimeout", required_argument, NULL, CD_DPDTIMEOUT + OO + NUMERIC_ARG },
638 { "ike", required_argument, NULL, CD_IKE + OO },
639 { "pfsgroup", required_argument, NULL, CD_PFSGROUP + OO },
640 { "esp", required_argument, NULL, CD_ESP + OO },
641
642 /* options for a ca description */
643
644 { "caname", required_argument, NULL, CA_NAME + OO },
645 { "cacert", required_argument, NULL, CA_CERT + OO },
646 { "ldaphost", required_argument, NULL, CA_LDAPHOST + OO },
647 { "ldapbase", required_argument, NULL, CA_LDAPBASE + OO },
648 { "crluri", required_argument, NULL, CA_CRLURI + OO },
649 { "crluri2", required_argument, NULL, CA_CRLURI2 + OO },
650 { "ocspuri", required_argument, NULL, CA_OCSPURI + OO },
651 { "strictcrlpolicy", no_argument, NULL, CA_STRICT + OO },
652
653 #ifdef DEBUG
654 { "debug-none", no_argument, NULL, DBGOPT_NONE + OO },
655 { "debug-all]", no_argument, NULL, DBGOPT_ALL + OO },
656 { "debug-raw", no_argument, NULL, DBGOPT_RAW + OO },
657 { "debug-crypt", no_argument, NULL, DBGOPT_CRYPT + OO },
658 { "debug-parsing", no_argument, NULL, DBGOPT_PARSING + OO },
659 { "debug-emitting", no_argument, NULL, DBGOPT_EMITTING + OO },
660 { "debug-control", no_argument, NULL, DBGOPT_CONTROL + OO },
661 { "debug-lifecycle", no_argument, NULL, DBGOPT_LIFECYCLE + OO },
662 { "debug-klips", no_argument, NULL, DBGOPT_KERNEL + OO },
663 { "debug-kernel", no_argument, NULL, DBGOPT_KERNEL + OO },
664 { "debug-dns", no_argument, NULL, DBGOPT_DNS + OO },
665 { "debug-natt", no_argument, NULL, DBGOPT_NATT + OO },
666 { "debug-oppo", no_argument, NULL, DBGOPT_OPPO + OO },
667 { "debug-controlmore", no_argument, NULL, DBGOPT_CONTROLMORE + OO },
668 { "debug-private", no_argument, NULL, DBGOPT_PRIVATE + OO },
669
670 { "impair-delay-adns-key-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER + OO },
671 { "impair-delay-adns-txt-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER + OO },
672 { "impair-bust-mi2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MI2 + OO },
673 { "impair-bust-mr2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MR2 + OO },
674 #endif
675 # undef OO
676 { 0,0,0,0 }
677 };
678
679 struct sockaddr_un ctl_addr = { AF_UNIX, DEFAULT_CTLBASE CTL_SUFFIX };
680
681 /* helper variables and function to encode strings from whack message */
682
683 static char *next_str,*str_roof;
684
685 static bool pack_str(char **p)
686 {
687 const char *s = *p == NULL? "" : *p; /* note: NULL becomes ""! */
688 size_t len = strlen(s) + 1;
689
690 if (str_roof - next_str < (ptrdiff_t)len)
691 {
692 return FALSE; /* fishy: no end found */
693 }
694 else
695 {
696 strcpy(next_str, s);
697 next_str += len;
698 *p = NULL; /* don't send pointers on the wire! */
699 return TRUE;
700 }
701 }
702
703 static void check_life_time(time_t life, time_t limit, const char *which,
704 const whack_message_t *msg)
705 {
706 time_t mint = msg->sa_rekey_margin * (100 + msg->sa_rekey_fuzz) / 100;
707
708 if (life > limit)
709 {
710 char buf[200]; /* arbitrary limit */
711
712 snprintf(buf, sizeof(buf)
713 , "%s [%lu seconds] must be less than %lu seconds"
714 , which, (unsigned long)life, (unsigned long)limit);
715 diag(buf);
716 }
717 if ((msg->policy & POLICY_DONT_REKEY) == LEMPTY && life <= mint)
718 {
719 char buf[200]; /* arbitrary limit */
720
721 snprintf(buf, sizeof(buf)
722 , "%s [%lu] must be greater than"
723 " rekeymargin*(100+rekeyfuzz)/100 [%lu*(100+%lu)/100 = %lu]"
724 , which
725 , (unsigned long)life
726 , (unsigned long)msg->sa_rekey_margin
727 , (unsigned long)msg->sa_rekey_fuzz
728 , (unsigned long)mint);
729 diag(buf);
730 }
731 }
732
733 static void clear_end(whack_end_t *e)
734 {
735 zero(e);
736 e->id = NULL;
737 e->cert = NULL;
738 e->ca = NULL;
739 e->updown = NULL;
740 e->host_port = IKE_UDP_PORT;
741 }
742
743 static void update_ports(whack_message_t *m)
744 {
745 int port;
746
747 if (m->left.port != 0) {
748 port = htons(m->left.port);
749 setportof(port, &m->left.host_addr);
750 setportof(port, &m->left.client.addr);
751 }
752 if (m->right.port != 0) {
753 port = htons(m->right.port);
754 setportof(port, &m->right.host_addr);
755 setportof(port, &m->right.client.addr);
756 }
757 }
758
759 static void check_end(whack_end_t *this, whack_end_t *that,
760 bool default_nexthop, sa_family_t caf, sa_family_t taf)
761 {
762 if (caf != addrtypeof(&this->host_addr))
763 diag("address family of host inconsistent");
764
765 if (default_nexthop)
766 {
767 if (isanyaddr(&that->host_addr))
768 diag("our nexthop must be specified when other host is a %any or %opportunistic");
769 this->host_nexthop = that->host_addr;
770 }
771
772 if (caf != addrtypeof(&this->host_nexthop))
773 diag("address family of nexthop inconsistent");
774
775 if (this->has_client)
776 {
777 if (taf != subnettypeof(&this->client))
778 diag("address family of client subnet inconsistent");
779 }
780 else
781 {
782 /* fill in anyaddr-anyaddr as (missing) client subnet */
783 ip_address cn;
784
785 diagq(anyaddr(caf, &cn), NULL);
786 diagq(rangetosubnet(&cn, &cn, &this->client), NULL);
787 }
788
789 /* fill in anyaddr if source IP is not defined */
790 if (!this->has_srcip)
791 diagq(anyaddr(caf, &this->host_srcip), optarg);
792
793 /* check protocol */
794 if (this->protocol != that->protocol)
795 diag("the protocol for leftprotoport and rightprotoport must be the same");
796 }
797
798 static void get_secret(int sock)
799 {
800 const char *buf = NULL, *secret;
801 int len;
802
803 fflush(stdout);
804 usleep(20000); /* give fflush time for flushing */
805 #ifdef HAVE_GETPASS
806 buf = getpass("Enter: ");
807 #endif
808 secret = (buf == NULL)? "" : buf;
809
810 /* send the secret to pluto */
811 len = strlen(secret) + 1;
812 if (write(sock, secret, len) != len)
813 {
814 int e = errno;
815
816 fprintf(stderr, "whack: write() failed (%d %s)\n", e, strerror(e));
817 exit(RC_WHACK_PROBLEM);
818 }
819 }
820
821 /* This is a hack for initiating ISAKMP exchanges. */
822
823 int main(int argc, char **argv)
824 {
825 whack_message_t msg;
826 char esp_buf[256]; /* uses snprintf */
827 lset_t
828 opts_seen = LEMPTY,
829 sc_seen = LEMPTY,
830 lst_seen = LEMPTY,
831 cd_seen = LEMPTY,
832 ca_seen = LEMPTY,
833 end_seen = LEMPTY,
834 end_seen_before_to = LEMPTY;
835 const char
836 *af_used_by = NULL,
837 *tunnel_af_used_by = NULL;
838
839 /* check division of numbering space */
840 #ifdef DEBUG
841 assert(OPTION_OFFSET + DBGOPT_LAST < NUMERIC_ARG);
842 #else
843 assert(OPTION_OFFSET + CA_LAST < NUMERIC_ARG);
844 #endif
845 assert(OPT_LAST - OPT_FIRST < (sizeof opts_seen * BITS_PER_BYTE));
846 assert(SC_LAST - SC_FIRST < (sizeof sc_seen * BITS_PER_BYTE));
847 assert(LST_LAST - LST_FIRST < (sizeof lst_seen * BITS_PER_BYTE));
848 assert(END_LAST - END_FIRST < (sizeof end_seen * BITS_PER_BYTE));
849 assert(CD_LAST - CD_FIRST < (sizeof cd_seen * BITS_PER_BYTE));
850 assert(CA_LAST - CA_FIRST < (sizeof ca_seen * BITS_PER_BYTE));
851 #ifdef DEBUG /* must be last so others are less than (sizeof cd_seen * BITS_PER_BYTE) to fit in lset_t */
852 assert(DBGOPT_LAST - DBGOPT_FIRST < (sizeof cd_seen * BITS_PER_BYTE));
853 #endif
854 /* check that POLICY bit assignment matches with CD_ */
855 assert(LELEM(CD_DONT_REKEY - CD_POLICY_FIRST) == POLICY_DONT_REKEY);
856
857 zero(&msg);
858
859 clear_end(&msg.right); /* left set from this after --to */
860
861 msg.name = NULL;
862 msg.keyid = NULL;
863 msg.keyval.ptr = NULL;
864 msg.esp = NULL;
865 msg.ike = NULL;
866 msg.pfsgroup = NULL;
867
868 /* if a connection is added via whack then we assume IKEv1 */
869 msg.ikev1 = TRUE;
870
871 msg.sa_ike_life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT;
872 msg.sa_ipsec_life_seconds = PLUTO_SA_LIFE_DURATION_DEFAULT;
873 msg.sa_rekey_margin = SA_REPLACEMENT_MARGIN_DEFAULT;
874 msg.sa_rekey_fuzz = SA_REPLACEMENT_FUZZ_DEFAULT;
875 msg.sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT;
876
877 msg.addr_family = AF_INET;
878 msg.tunnel_addr_family = AF_INET;
879
880 msg.cacert = NULL;
881 msg.ldaphost = NULL;
882 msg.ldapbase = NULL;
883 msg.crluri = NULL;
884 msg.crluri2 = NULL;
885 msg.ocspuri = NULL;
886
887 options = options_create();
888
889 for (;;)
890 {
891 int long_index;
892 unsigned long opt_whole = 0; /* numeric argument for some flags */
893
894 /* Note: we don't like the way short options get parsed
895 * by getopt_long, so we simply pass an empty string as
896 * the list. It could be "hp:d:c:o:eatfs" "NARXPECK".
897 */
898 int c = getopt_long(argc, argv, "", long_opts, &long_index) - OPTION_OFFSET;
899 int aux = 0;
900
901 /* decode a numeric argument, if expected */
902 if (0 <= c)
903 {
904 if (c & NUMERIC_ARG)
905 {
906 char *endptr;
907
908 c -= NUMERIC_ARG;
909 opt_whole = strtoul(optarg, &endptr, 0);
910
911 if (*endptr != '\0' || endptr == optarg)
912 diagq("badly formed numeric argument", optarg);
913 }
914 if (c >= (1 << AUX_SHIFT))
915 {
916 aux = c >> AUX_SHIFT;
917 c -= aux << AUX_SHIFT;
918 }
919 }
920
921 /* per-class option processing */
922 if (0 <= c && c <= OPT_LAST)
923 {
924 /* OPT_* options get added to opts_seen.
925 * Reject repeated options (unless later code intervenes).
926 */
927 lset_t f = LELEM(c);
928
929 if (opts_seen & f)
930 diagq("duplicated flag", long_opts[long_index].name);
931 opts_seen |= f;
932 }
933 else if (SC_FIRST <= c && c <= SC_LAST)
934 {
935 /* SC_* options get added to sc_seen.
936 * Reject repeated options (unless later code intervenes).
937 */
938 lset_t f = LELEM(c - SC_FIRST);
939
940 if (sc_seen & f)
941 diagq("duplicated flag", long_opts[long_index].name);
942 sc_seen |= f;
943 }
944 else if (LST_FIRST <= c && c <= LST_LAST)
945 {
946 /* LST_* options get added to lst_seen.
947 * Reject repeated options (unless later code intervenes).
948 */
949 lset_t f = LELEM(c - LST_FIRST);
950
951 if (lst_seen & f)
952 diagq("duplicated flag", long_opts[long_index].name);
953 lst_seen |= f;
954 }
955 #ifdef DEBUG
956 else if (DBGOPT_FIRST <= c && c <= DBGOPT_LAST)
957 {
958 msg.whack_options = TRUE;
959 }
960 #endif
961 else if (END_FIRST <= c && c <= END_LAST)
962 {
963 /* END_* options are added to end_seen.
964 * Reject repeated options (unless later code intervenes).
965 */
966 lset_t f = LELEM(c - END_FIRST);
967
968 if (end_seen & f)
969 diagq("duplicated flag", long_opts[long_index].name);
970 end_seen |= f;
971 opts_seen |= LELEM(OPT_CD);
972 }
973 else if (CD_FIRST <= c && c <= CD_LAST)
974 {
975 /* CD_* options are added to cd_seen.
976 * Reject repeated options (unless later code intervenes).
977 */
978 lset_t f = LELEM(c - CD_FIRST);
979
980 if (cd_seen & f)
981 diagq("duplicated flag", long_opts[long_index].name);
982 cd_seen |= f;
983 opts_seen |= LELEM(OPT_CD);
984 }
985 else if (CA_FIRST <= c && c <= CA_LAST)
986 {
987 /* CA_* options are added to ca_seen.
988 * Reject repeated options (unless later code intervenes).
989 */
990 lset_t f = LELEM(c - CA_FIRST);
991
992 if (ca_seen & f)
993 diagq("duplicated flag", long_opts[long_index].name);
994 ca_seen |= f;
995 }
996
997 /* Note: "break"ing from switch terminates loop.
998 * most cases should end with "continue".
999 */
1000 switch (c)
1001 {
1002 case EOF - OPTION_OFFSET: /* end of flags */
1003 break;
1004
1005 case 0 - OPTION_OFFSET: /* long option already handled */
1006 continue;
1007
1008 case ':' - OPTION_OFFSET: /* diagnostic already printed by getopt_long */
1009 case '?' - OPTION_OFFSET: /* diagnostic already printed by getopt_long */
1010 diag(NULL); /* print no additional diagnostic, but exit sadly */
1011 break; /* not actually reached */
1012
1013 case 'h' - OPTION_OFFSET: /* --help */
1014 help();
1015 whack_exit(0); /* GNU coding standards say to stop here */
1016
1017 case 'v' - OPTION_OFFSET: /* --version */
1018 {
1019 const char **sp = ipsec_copyright_notice();
1020
1021 printf("strongSwan "VERSION"\n");
1022 for (; *sp != NULL; sp++)
1023 puts(*sp);
1024 }
1025 whack_exit(0); /* GNU coding standards say to stop here */
1026
1027 case 'l' - OPTION_OFFSET: /* --label <string> */
1028 label = optarg; /* remember for diagnostics */
1029 continue;
1030
1031 case '+' - OPTION_OFFSET: /* --optionsfrom <filename> */
1032 if (!options->from(options, optarg, &argc, &argv, optind))
1033 {
1034 fprintf(stderr, "optionsfrom failed");
1035 whack_exit(RC_WHACK_PROBLEM);
1036 }
1037 continue;
1038
1039 /* the rest of the options combine in complex ways */
1040
1041 case OPT_CTLBASE: /* --port <ctlbase> */
1042 if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path)
1043 , "%s%s", optarg, CTL_SUFFIX) == -1)
1044 diag("<ctlbase>" CTL_SUFFIX " must be fit in a sun_addr");
1045 continue;
1046
1047 case OPT_NAME: /* --name <connection-name> */
1048 name = optarg;
1049 msg.name = optarg;
1050 continue;
1051
1052 case OPT_KEYID: /* --keyid <identity> */
1053 msg.whack_key = !msg.whack_sc_op;
1054 msg.keyid = optarg; /* decoded by Pluto */
1055 continue;
1056
1057 case OPT_MYID: /* --myid <identity> */
1058 msg.whack_myid = TRUE;
1059 msg.myid = optarg; /* decoded by Pluto */
1060 continue;
1061
1062 case OPT_ADDKEY: /* --addkey */
1063 msg.whack_addkey = TRUE;
1064 continue;
1065
1066 case OPT_PUBKEYRSA: /* --pubkeyrsa <key> */
1067 {
1068 static char keyspace[RSA_MAX_ENCODING_BYTES]; /* room for 8K bit key */
1069 char diag_space[TTODATAV_BUF];
1070 const char *ugh = ttodatav(optarg, 0, 0
1071 , keyspace, sizeof(keyspace)
1072 , &msg.keyval.len, diag_space, sizeof(diag_space)
1073 , TTODATAV_SPACECOUNTS);
1074
1075 if (ugh != NULL)
1076 {
1077 char ugh_space[80]; /* perhaps enough space */
1078
1079 snprintf(ugh_space, sizeof(ugh_space)
1080 , "RSA public-key data malformed (%s)", ugh);
1081 diagq(ugh_space, optarg);
1082 }
1083 msg.pubkey_alg = PUBKEY_ALG_RSA;
1084 msg.keyval.ptr = keyspace;
1085 }
1086 continue;
1087
1088 case OPT_ROUTE: /* --route */
1089 msg.whack_route = TRUE;
1090 continue;
1091
1092 case OPT_UNROUTE: /* --unroute */
1093 msg.whack_unroute = TRUE;
1094 continue;
1095
1096 case OPT_INITIATE: /* --initiate */
1097 msg.whack_initiate = TRUE;
1098 continue;
1099
1100 case OPT_TERMINATE: /* --terminate */
1101 msg.whack_terminate = TRUE;
1102 continue;
1103
1104 case OPT_DELETE: /* --delete */
1105 msg.whack_delete = TRUE;
1106 continue;
1107
1108 case OPT_DELETESTATE: /* --deletestate <state_object_number> */
1109 msg.whack_deletestate = TRUE;
1110 msg.whack_deletestateno = opt_whole;
1111 continue;
1112
1113 case OPT_DELETECRASH: /* --crash <ip-address> */
1114 msg.whack_crash = TRUE;
1115 tunnel_af_used_by = long_opts[long_index].name;
1116 diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.whack_crash_peer), optarg);
1117 if (isanyaddr(&msg.whack_crash_peer))
1118 diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg);
1119 continue;
1120
1121 case OPT_LEASES: /* --leases */
1122 msg.whack_leases = TRUE;
1123 continue;
1124
1125 case OPT_LEASEADDR: /* --lease-addr <ip-address> */
1126 msg.whack_lease_ip = optarg; /* decoded by Pluto */
1127 continue;
1128
1129 case OPT_LEASEID: /* --lease-id <identity> */
1130 msg.whack_lease_id = optarg; /* decoded by Pluto */
1131 continue;
1132
1133 case OPT_LISTEN: /* --listen */
1134 msg.whack_listen = TRUE;
1135 continue;
1136
1137 case OPT_UNLISTEN: /* --unlisten */
1138 msg.whack_unlisten = TRUE;
1139 continue;
1140
1141 case OPT_PURGEOCSP: /* --purgeocsp */
1142 msg.whack_purgeocsp = TRUE;
1143 continue;
1144
1145 case OPT_REREADSECRETS: /* --rereadsecrets */
1146 case OPT_REREADCACERTS: /* --rereadcacerts */
1147 case OPT_REREADAACERTS: /* --rereadaacerts */
1148 case OPT_REREADOCSPCERTS: /* --rereadocspcerts */
1149 case OPT_REREADACERTS: /* --rereadacerts */
1150 case OPT_REREADCRLS: /* --rereadcrls */
1151 msg.whack_reread |= LELEM(c-OPT_REREADSECRETS);
1152 continue;
1153
1154 case OPT_REREADALL: /* --rereadall */
1155 msg.whack_reread = REREAD_ALL;
1156 continue;
1157
1158 case OPT_STATUSALL: /* --statusall */
1159 msg.whack_statusall = TRUE;
1160 /* fall through */
1161
1162 case OPT_STATUS: /* --status */
1163 msg.whack_status = TRUE;
1164 continue;
1165
1166 case OPT_SHUTDOWN: /* --shutdown */
1167 msg.whack_shutdown = TRUE;
1168 continue;
1169
1170 case OPT_OPPO_HERE: /* --oppohere <ip-address> */
1171 tunnel_af_used_by = long_opts[long_index].name;
1172 diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.oppo_my_client), optarg);
1173 if (isanyaddr(&msg.oppo_my_client))
1174 diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg);
1175 continue;
1176
1177 case OPT_OPPO_THERE: /* --oppohere <ip-address> */
1178 tunnel_af_used_by = long_opts[long_index].name;
1179 diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.oppo_peer_client), optarg);
1180 if (isanyaddr(&msg.oppo_peer_client))
1181 diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg);
1182 continue;
1183
1184 case OPT_ASYNC:
1185 msg.whack_async = TRUE;
1186 continue;
1187
1188 /* Smartcard options */
1189
1190 case SC_ENCRYPT: /* --scencrypt <plaintext data> */
1191 case SC_DECRYPT: /* --scdecrypt <encrypted data> */
1192 msg.whack_sc_op = 1 + c - SC_ENCRYPT;
1193 msg.whack_key = FALSE;
1194 msg.sc_data = optarg;
1195 continue;
1196
1197 case SC_INBASE: /* --inform <format> */
1198 case SC_OUTBASE: /* --outform <format> */
1199 {
1200 int base = 0;
1201
1202 if (streq(optarg, "16") || strcaseeq(optarg, "hex"))
1203 base = 16;
1204 else if (streq(optarg, "64") || strcaseeq(optarg, "base64"))
1205 base = 64;
1206 else if (streq(optarg, "256") || strcaseeq(optarg, "text")
1207 || strcaseeq(optarg, "ascii"))
1208 base = 256;
1209 else
1210 diagq("not a valid base", optarg);
1211
1212 if (c == SC_INBASE)
1213 msg.inbase = base;
1214 else
1215 msg.outbase = base;
1216 }
1217 continue;
1218
1219 /* List options */
1220
1221 case LST_UTC: /* --utc */
1222 msg.whack_utc = TRUE;
1223 continue;
1224
1225 case LST_ALGS: /* --listalgs */
1226 case LST_PUBKEYS: /* --listpubkeys */
1227 case LST_CERTS: /* --listcerts */
1228 case LST_CACERTS: /* --listcacerts */
1229 case LST_ACERTS: /* --listacerts */
1230 case LST_AACERTS: /* --listaacerts */
1231 case LST_OCSPCERTS: /* --listocspcerts */
1232 case LST_GROUPS: /* --listgroups */
1233 case LST_CAINFOS: /* --listcainfos */
1234 case LST_CRLS: /* --listcrls */
1235 case LST_OCSP: /* --listocsp */
1236 case LST_CARDS: /* --listcards */
1237 msg.whack_list |= LELEM(c - LST_ALGS);
1238 continue;
1239
1240 case LST_ALL: /* --listall */
1241 msg.whack_list = LIST_ALL;
1242 continue;
1243
1244 /* Connection Description options */
1245
1246 case END_HOST: /* --host <ip-address> */
1247 {
1248 lset_t new_policy = LEMPTY;
1249
1250 af_used_by = long_opts[long_index].name;
1251 diagq(anyaddr(msg.addr_family, &msg.right.host_addr), optarg);
1252 if (streq(optarg, "%any"))
1253 {
1254 }
1255 else if (streq(optarg, "%opportunistic"))
1256 {
1257 /* always use tunnel mode; mark as opportunistic */
1258 new_policy |= POLICY_TUNNEL | POLICY_OPPO;
1259 }
1260 else if (streq(optarg, "%group"))
1261 {
1262 /* always use tunnel mode; mark as group */
1263 new_policy |= POLICY_TUNNEL | POLICY_GROUP;
1264 }
1265 else if (streq(optarg, "%opportunisticgroup"))
1266 {
1267 /* always use tunnel mode; mark as opportunistic */
1268 new_policy |= POLICY_TUNNEL | POLICY_OPPO | POLICY_GROUP;
1269 }
1270 else
1271 {
1272 diagq(ttoaddr(optarg, 0, msg.addr_family
1273 , &msg.right.host_addr), optarg);
1274 }
1275
1276 msg.policy |= new_policy;
1277
1278 if (new_policy & (POLICY_OPPO | POLICY_GROUP))
1279 {
1280 if (!LHAS(end_seen, END_CLIENT - END_FIRST))
1281 {
1282 /* set host to 0.0.0 and --client to 0.0.0.0/0
1283 * or IPV6 equivalent
1284 */
1285 ip_address any;
1286
1287 tunnel_af_used_by = optarg;
1288 diagq(anyaddr(msg.tunnel_addr_family, &any), optarg);
1289 diagq(initsubnet(&any, 0, '0', &msg.right.client), optarg);
1290 }
1291 msg.right.has_client = TRUE;
1292 }
1293 if (new_policy & POLICY_GROUP)
1294 {
1295 /* client subnet must not be specified by user:
1296 * it will come from the group's file.
1297 */
1298 if (LHAS(end_seen, END_CLIENT - END_FIRST))
1299 diag("--host %group clashes with --client");
1300
1301 end_seen |= LELEM(END_CLIENT - END_FIRST);
1302 }
1303 if (new_policy & POLICY_OPPO)
1304 msg.right.key_from_DNS_on_demand = TRUE;
1305 continue;
1306 }
1307 case END_ID: /* --id <identity> */
1308 msg.right.id = optarg; /* decoded by Pluto */
1309 continue;
1310
1311 case END_CERT: /* --cert <path> */
1312 msg.right.cert = optarg; /* decoded by Pluto */
1313 continue;
1314
1315 case END_CA: /* --ca <distinguished name> */
1316 msg.right.ca = optarg; /* decoded by Pluto */
1317 continue;
1318
1319 case END_SENDCERT:
1320 if (streq(optarg, "yes") || streq(optarg, "always"))
1321 {
1322 msg.right.sendcert = CERT_ALWAYS_SEND;
1323 }
1324 else if (streq(optarg, "no") || streq(optarg, "never"))
1325 {
1326 msg.right.sendcert = CERT_NEVER_SEND;
1327 }
1328 else if (streq(optarg, "ifasked"))
1329 {
1330 msg.right.sendcert = CERT_SEND_IF_ASKED;
1331 }
1332 else
1333 {
1334 diagq("whack sendcert value is not legal", optarg);
1335 }
1336 continue;
1337
1338 case END_GROUPS:/* --groups <access control groups> */
1339 msg.right.groups = optarg; /* decoded by Pluto */
1340 continue;
1341
1342 case END_IKEPORT: /* --ikeport <port-number> */
1343 if (opt_whole<=0 || opt_whole >= 0x10000)
1344 diagq("<port-number> must be a number between 1 and 65535", optarg);
1345 msg.right.host_port = opt_whole;
1346 continue;
1347
1348 case END_NEXTHOP: /* --nexthop <ip-address> */
1349 af_used_by = long_opts[long_index].name;
1350 if (streq(optarg, "%direct"))
1351 diagq(anyaddr(msg.addr_family
1352 , &msg.right.host_nexthop), optarg);
1353 else
1354 diagq(ttoaddr(optarg, 0, msg.addr_family
1355 , &msg.right.host_nexthop), optarg);
1356 continue;
1357
1358 case END_SRCIP: /* --srcip <ip-address> */
1359 af_used_by = long_opts[long_index].name;
1360 if (streq(optarg, "%modeconfig") || streq(optarg, "%modecfg"))
1361 {
1362 msg.right.modecfg = TRUE;
1363 }
1364 else
1365 {
1366 diagq(ttoaddr(optarg, 0, msg.addr_family
1367 , &msg.right.host_srcip), optarg);
1368 msg.right.has_srcip = TRUE;
1369 }
1370 msg.policy |= POLICY_TUNNEL; /* srcip => tunnel */
1371 continue;
1372
1373 case END_CLIENT: /* --client <subnet> */
1374 if (end_seen & LELEM(END_CLIENTWITHIN - END_FIRST))
1375 diag("--client conflicts with --clientwithin");
1376 tunnel_af_used_by = long_opts[long_index].name;
1377 if ((strlen(optarg) >= 6 && strncmp(optarg,"vhost:",6) == 0)
1378 || (strlen(optarg) >= 5 && strncmp(optarg,"vnet:",5) == 0))
1379 {
1380 msg.right.virt = optarg;
1381 }
1382 else
1383 {
1384 diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg);
1385 msg.right.has_client = TRUE;
1386 }
1387 msg.policy |= POLICY_TUNNEL; /* client => tunnel */
1388 continue;
1389
1390 case END_CLIENTWITHIN: /* --clienwithin <address range> */
1391 if (end_seen & LELEM(END_CLIENT - END_FIRST))
1392 diag("--clientwithin conflicts with --client");
1393 tunnel_af_used_by = long_opts[long_index].name;
1394 diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg);
1395 msg.right.has_client = TRUE;
1396 msg.policy |= POLICY_TUNNEL; /* client => tunnel */
1397 msg.right.has_client_wildcard = TRUE;
1398 continue;
1399
1400 case END_CLIENTPROTOPORT: /* --clientprotoport <protocol>/<port> */
1401 diagq(ttoprotoport(optarg, 0, &msg.right.protocol, &msg.right.port
1402 , &msg.right.has_port_wildcard), optarg);
1403 continue;
1404
1405 case END_DNSKEYONDEMAND: /* --dnskeyondemand */
1406 msg.right.key_from_DNS_on_demand = TRUE;
1407 continue;
1408
1409 case END_HOSTACCESS: /* --hostaccess */
1410 msg.right.hostaccess = TRUE;
1411 continue;
1412
1413 case END_UPDOWN: /* --updown <updown> */
1414 msg.right.updown = optarg;
1415 continue;
1416
1417 case CD_TO: /* --to */
1418 /* process right end, move it to left, reset it */
1419 if (!LHAS(end_seen, END_HOST - END_FIRST))
1420 diag("connection missing --host before --to");
1421 msg.left = msg.right;
1422 clear_end(&msg.right);
1423 end_seen_before_to = end_seen;
1424 end_seen = LEMPTY;
1425 continue;
1426
1427 case CD_PSK: /* --psk */
1428 case CD_RSASIG: /* --rsasig */
1429 case CD_ENCRYPT: /* --encrypt */
1430 case CD_AUTHENTICATE: /* --authenticate */
1431 case CD_COMPRESS: /* --compress */
1432 case CD_TUNNEL: /* --tunnel */
1433 case CD_PFS: /* --pfs */
1434 case CD_DISABLEARRIVALCHECK: /* --disablearrivalcheck */
1435 case CD_DONT_REKEY: /* --donotrekey */
1436 msg.policy |= LELEM(c - CD_POLICY_FIRST);
1437 continue;
1438
1439 /* --initiateontraffic
1440 * --pass
1441 * --drop
1442 * --reject
1443 */
1444 case CD_SHUNT0:
1445 msg.policy = (msg.policy & ~POLICY_SHUNT_MASK)
1446 | ((lset_t)aux << POLICY_SHUNT_SHIFT);
1447 continue;
1448
1449 /* --failnone
1450 * --failpass
1451 * --faildrop
1452 * --failreject
1453 */
1454 case CD_FAIL0:
1455 msg.policy = (msg.policy & ~POLICY_FAIL_MASK)
1456 | ((lset_t)aux << POLICY_FAIL_SHIFT);
1457 continue;
1458
1459 case CD_IKELIFETIME: /* --ikelifetime <seconds> */
1460 msg.sa_ike_life_seconds = opt_whole;
1461 continue;
1462
1463 case CD_IPSECLIFETIME: /* --ipseclifetime <seconds> */
1464 msg.sa_ipsec_life_seconds = opt_whole;
1465 continue;
1466
1467 case CD_RKMARGIN: /* --rekeymargin <seconds> */
1468 msg.sa_rekey_margin = opt_whole;
1469 continue;
1470
1471 case CD_RKFUZZ: /* --rekeyfuzz <percentage> */
1472 msg.sa_rekey_fuzz = opt_whole;
1473 continue;
1474
1475 case CD_KTRIES: /* --keyingtries <count> */
1476 msg.sa_keying_tries = opt_whole;
1477 continue;
1478
1479 case CD_DPDACTION:
1480 if (streq(optarg, "none"))
1481 msg.dpd_action = DPD_ACTION_NONE;
1482 else if (streq(optarg, "clear"))
1483 msg.dpd_action = DPD_ACTION_CLEAR;
1484 else if (streq(optarg, "hold"))
1485 msg.dpd_action = DPD_ACTION_HOLD;
1486 else if (streq(optarg, "restart"))
1487 msg.dpd_action = DPD_ACTION_RESTART;
1488 else
1489 msg.dpd_action = DPD_ACTION_UNKNOWN;
1490 continue;
1491
1492 case CD_DPDDELAY:
1493 msg.dpd_delay = opt_whole;
1494 continue;
1495
1496 case CD_DPDTIMEOUT:
1497 msg.dpd_timeout = opt_whole;
1498 continue;
1499
1500 case CD_IKE: /* --ike <ike_alg1,ike_alg2,...> */
1501 msg.ike = optarg;
1502 continue;
1503
1504 case CD_PFSGROUP: /* --pfsgroup modpXXXX */
1505 msg.pfsgroup = optarg;
1506 continue;
1507
1508 case CD_ESP: /* --esp <esp_alg1,esp_alg2,...> */
1509 msg.esp = optarg;
1510 continue;
1511
1512 case CD_CONNIPV4:
1513 if (LHAS(cd_seen, CD_CONNIPV6 - CD_FIRST))
1514 diag("--ipv4 conflicts with --ipv6");
1515
1516 /* Since this is the default, the flag is redundant.
1517 * So we don't need to set msg.addr_family
1518 * and we don't need to check af_used_by
1519 * and we don't have to consider defaulting tunnel_addr_family.
1520 */
1521 continue;
1522
1523 case CD_CONNIPV6:
1524 if (LHAS(cd_seen, CD_CONNIPV4 - CD_FIRST))
1525 diag("--ipv6 conflicts with --ipv4");
1526
1527 if (af_used_by != NULL)
1528 diagq("--ipv6 must precede", af_used_by);
1529
1530 af_used_by = long_opts[long_index].name;
1531 msg.addr_family = AF_INET6;
1532
1533 /* Consider defaulting tunnel_addr_family to AF_INET6.
1534 * Do so only if it hasn't yet been specified or used.
1535 */
1536 if (LDISJOINT(cd_seen, LELEM(CD_TUNNELIPV4 - CD_FIRST) | LELEM(CD_TUNNELIPV6 - CD_FIRST))
1537 && tunnel_af_used_by == NULL)
1538 msg.tunnel_addr_family = AF_INET6;
1539 continue;
1540
1541 case CD_TUNNELIPV4:
1542 if (LHAS(cd_seen, CD_TUNNELIPV6 - CD_FIRST))
1543 diag("--tunnelipv4 conflicts with --tunnelipv6");
1544
1545 if (tunnel_af_used_by != NULL)
1546 diagq("--tunnelipv4 must precede", af_used_by);
1547
1548 msg.tunnel_addr_family = AF_INET;
1549 continue;
1550
1551 case CD_TUNNELIPV6:
1552 if (LHAS(cd_seen, CD_TUNNELIPV4 - CD_FIRST))
1553 diag("--tunnelipv6 conflicts with --tunnelipv4");
1554
1555 if (tunnel_af_used_by != NULL)
1556 diagq("--tunnelipv6 must precede", af_used_by);
1557
1558 msg.tunnel_addr_family = AF_INET6;
1559 continue;
1560
1561 case CA_NAME: /* --caname <name> */
1562 msg.name = optarg;
1563 msg.whack_ca = TRUE;
1564 continue;
1565 case CA_CERT: /* --cacert <path> */
1566 msg.cacert = optarg;
1567 continue;
1568 case CA_LDAPHOST: /* --ldaphost <hostname> */
1569 msg.ldaphost = optarg;
1570 continue;
1571 case CA_LDAPBASE: /* --ldapbase <base> */
1572 msg.ldapbase = optarg;
1573 continue;
1574 case CA_CRLURI: /* --crluri <uri> */
1575 msg.crluri = optarg;
1576 continue;
1577 case CA_CRLURI2: /* --crluri2 <uri> */
1578 msg.crluri2 = optarg;
1579 continue;
1580 case CA_OCSPURI: /* --ocspuri <uri> */
1581 msg.ocspuri = optarg;
1582 continue;
1583 case CA_STRICT: /* --strictcrlpolicy */
1584 msg.whack_strict = TRUE;
1585 continue;
1586
1587 #ifdef DEBUG
1588 case DBGOPT_NONE: /* --debug-none */
1589 msg.debugging = DBG_NONE;
1590 continue;
1591
1592 case DBGOPT_ALL: /* --debug-all */
1593 msg.debugging |= DBG_ALL; /* note: does not include PRIVATE */
1594 continue;
1595
1596 case DBGOPT_RAW: /* --debug-raw */
1597 case DBGOPT_CRYPT: /* --debug-crypt */
1598 case DBGOPT_PARSING: /* --debug-parsing */
1599 case DBGOPT_EMITTING: /* --debug-emitting */
1600 case DBGOPT_CONTROL: /* --debug-control */
1601 case DBGOPT_LIFECYCLE: /* --debug-lifecycle */
1602 case DBGOPT_KERNEL: /* --debug-kernel, --debug-klips */
1603 case DBGOPT_DNS: /* --debug-dns */
1604 case DBGOPT_NATT: /* --debug-natt */
1605 case DBGOPT_OPPO: /* --debug-oppo */
1606 case DBGOPT_CONTROLMORE: /* --debug-controlmore */
1607 case DBGOPT_PRIVATE: /* --debug-private */
1608 case DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER: /* --impair-delay-adns-key-answer */
1609 case DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER: /* --impair-delay-adns-txt-answer */
1610 case DBGOPT_IMPAIR_BUST_MI2: /* --impair_bust_mi2 */
1611 case DBGOPT_IMPAIR_BUST_MR2: /* --impair_bust_mr2 */
1612 msg.debugging |= LELEM(c-DBGOPT_RAW);
1613 continue;
1614 #endif
1615 default:
1616 assert(FALSE); /* unknown return value */
1617 }
1618 break;
1619 }
1620
1621 if (optind != argc)
1622 {
1623 /* If you see this message unexpectedly, perhaps the
1624 * case for the previous option ended with "break"
1625 * instead of "continue"
1626 */
1627 diagq("unexpected argument", argv[optind]);
1628 }
1629
1630 /* For each possible form of the command, figure out if an argument
1631 * suggests whether that form was intended, and if so, whether all
1632 * required information was supplied.
1633 */
1634
1635 /* check opportunistic initiation simulation request */
1636 switch (opts_seen & (LELEM(OPT_OPPO_HERE) | LELEM(OPT_OPPO_THERE)))
1637 {
1638 case LELEM(OPT_OPPO_HERE):
1639 case LELEM(OPT_OPPO_THERE):
1640 diag("--oppohere and --oppothere must be used together");
1641 /*NOTREACHED*/
1642 case LELEM(OPT_OPPO_HERE) | LELEM(OPT_OPPO_THERE):
1643 msg.whack_oppo_initiate = TRUE;
1644 if (LIN(cd_seen, LELEM(CD_TUNNELIPV4 - CD_FIRST) | LELEM(CD_TUNNELIPV6 - CD_FIRST)))
1645 opts_seen &= ~LELEM(OPT_CD);
1646 break;
1647 }
1648
1649 /* check leases */
1650 if (LHAS(opts_seen, OPT_LEASEADDR) && LHAS(opts_seen, OPT_LEASEID))
1651 {
1652 diag("--lease-addr and --lease-id cannot be used together");
1653 }
1654
1655 /* check connection description */
1656 if (LHAS(opts_seen, OPT_CD))
1657 {
1658 if (!LHAS(cd_seen, CD_TO-CD_FIRST))
1659 diag("connection description option, but no --to");
1660
1661 if (!LHAS(end_seen, END_HOST-END_FIRST))
1662 diag("connection missing --host after --to");
1663
1664 if (isanyaddr(&msg.left.host_addr)
1665 && isanyaddr(&msg.right.host_addr))
1666 diag("hosts cannot both be 0.0.0.0 or 0::0");
1667
1668 if (msg.policy & POLICY_OPPO)
1669 {
1670 if ((msg.policy & (POLICY_PSK | POLICY_PUBKEY)) != POLICY_PUBKEY)
1671 diag("only PUBKEY is supported for opportunism");
1672 if ((msg.policy & POLICY_PFS) == 0)
1673 diag("PFS required for opportunism");
1674 if ((msg.policy & POLICY_ENCRYPT) == 0)
1675 diag("encryption required for opportunism");
1676 }
1677
1678 check_end(&msg.left, &msg.right, !LHAS(end_seen_before_to, END_NEXTHOP-END_FIRST)
1679 , msg.addr_family, msg.tunnel_addr_family);
1680
1681 check_end(&msg.right, &msg.left, !LHAS(end_seen, END_NEXTHOP-END_FIRST)
1682 , msg.addr_family, msg.tunnel_addr_family);
1683
1684 if (subnettypeof(&msg.left.client) != subnettypeof(&msg.right.client))
1685 diag("endpoints clash: one is IPv4 and the other is IPv6");
1686
1687 if (NEVER_NEGOTIATE(msg.policy))
1688 {
1689 /* we think this is just a shunt (because he didn't specify
1690 * a host authentication method). If he didn't specify a
1691 * shunt type, he's probably gotten it wrong.
1692 */
1693 if ((msg.policy & POLICY_SHUNT_MASK) == POLICY_SHUNT_TRAP)
1694 diag("non-shunt connection must have --psk or --rsasig or both");
1695 }
1696 else
1697 {
1698 /* not just a shunt: a real ipsec connection */
1699 if ((msg.policy & POLICY_ID_AUTH_MASK) == LEMPTY)
1700 diag("must specify --rsasig or --psk for a connection");
1701
1702 if (!HAS_IPSEC_POLICY(msg.policy)
1703 && (msg.left.has_client || msg.right.has_client))
1704 diag("must not specify clients for ISAKMP-only connection");
1705 }
1706
1707 msg.whack_connection = TRUE;
1708 }
1709
1710 /* decide whether --name is mandatory or forbidden */
1711 if (!LDISJOINT(opts_seen
1712 , LELEM(OPT_ROUTE) | LELEM(OPT_UNROUTE)
1713 | LELEM(OPT_INITIATE) | LELEM(OPT_TERMINATE)
1714 | LELEM(OPT_DELETE) | LELEM(OPT_CD)))
1715 {
1716 if (!LHAS(opts_seen, OPT_NAME) && !msg.whack_ca)
1717 diag("missing --name <connection_name>");
1718 }
1719 else if (!msg.whack_options && !msg.whack_status && !msg.whack_leases)
1720 {
1721 if (LHAS(opts_seen, OPT_NAME))
1722 diag("no reason for --name");
1723 }
1724
1725 if (!LDISJOINT(opts_seen, LELEM(OPT_PUBKEYRSA) | LELEM(OPT_ADDKEY)))
1726 {
1727 if (!LHAS(opts_seen, OPT_KEYID))
1728 diag("--addkey and --pubkeyrsa require --keyid");
1729 }
1730
1731 if (!(msg.whack_connection || msg.whack_key || msg.whack_myid
1732 || msg.whack_delete || msg.whack_deletestate
1733 || msg.whack_initiate || msg.whack_oppo_initiate || msg.whack_terminate
1734 || msg.whack_route || msg.whack_unroute || msg.whack_listen
1735 || msg.whack_unlisten || msg.whack_list || msg.whack_purgeocsp
1736 || msg.whack_reread || msg.whack_ca || msg.whack_status
1737 || msg.whack_options || msg.whack_shutdown || msg.whack_sc_op
1738 || msg.whack_leases))
1739 {
1740 diag("no action specified; try --help for hints");
1741 }
1742
1743 update_ports(&msg);
1744
1745 /* tricky quick and dirty check for wild values */
1746 if (msg.sa_rekey_margin != 0
1747 && msg.sa_rekey_fuzz * msg.sa_rekey_margin * 4 / msg.sa_rekey_margin / 4
1748 != msg.sa_rekey_fuzz)
1749 diag("rekeymargin or rekeyfuzz values are so large that they cause oveflow");
1750
1751 check_life_time (msg.sa_ike_life_seconds, OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM
1752 , "ikelifetime", &msg);
1753
1754 check_life_time(msg.sa_ipsec_life_seconds, SA_LIFE_DURATION_MAXIMUM
1755 , "ipseclifetime", &msg);
1756
1757 if (msg.dpd_action == DPD_ACTION_UNKNOWN)
1758 diag("dpdaction must be \"none\", \"clear\", \"hold\" or \"restart\"");
1759
1760 if (msg.dpd_action != DPD_ACTION_NONE)
1761 {
1762 if (msg.dpd_delay <= 0)
1763 diag("dpddelay must be larger than zero");
1764
1765 if (msg.dpd_timeout <= 0)
1766 diag("dpdtimeout must be larger than zero");
1767
1768 if (msg.dpd_timeout <= msg.dpd_delay)
1769 diag("dpdtimeout must be larger than dpddelay");
1770 }
1771
1772 /* pack strings for inclusion in message */
1773 next_str = msg.string;
1774 str_roof = &msg.string[sizeof(msg.string)];
1775
1776 /* build esp message as esp="<esp>;<pfsgroup>" */
1777 if (msg.pfsgroup) {
1778 snprintf(esp_buf, sizeof (esp_buf), "%s;%s",
1779 msg.esp ? msg.esp : "",
1780 msg.pfsgroup ? msg.pfsgroup : "");
1781 msg.esp=esp_buf;
1782 }
1783 if (!pack_str(&msg.name) /* string 1 */
1784 || !pack_str(&msg.left.id) /* string 2 */
1785 || !pack_str(&msg.left.cert) /* string 3 */
1786 || !pack_str(&msg.left.ca) /* string 4 */
1787 || !pack_str(&msg.left.groups) /* string 5 */
1788 || !pack_str(&msg.left.updown) /* string 6 */
1789 || !pack_str(&msg.left.sourceip) /* string 7 */
1790 || !pack_str(&msg.left.virt) /* string 8 */
1791 || !pack_str(&msg.right.id) /* string 9 */
1792 || !pack_str(&msg.right.cert) /* string 10 */
1793 || !pack_str(&msg.right.ca) /* string 11 */
1794 || !pack_str(&msg.right.groups) /* string 12 */
1795 || !pack_str(&msg.right.updown) /* string 13 */
1796 || !pack_str(&msg.right.sourceip) /* string 14 */
1797 || !pack_str(&msg.right.virt) /* string 15 */
1798 || !pack_str(&msg.keyid) /* string 16 */
1799 || !pack_str(&msg.myid) /* string 17 */
1800 || !pack_str(&msg.cacert) /* string 18 */
1801 || !pack_str(&msg.ldaphost) /* string 19 */
1802 || !pack_str(&msg.ldapbase) /* string 20 */
1803 || !pack_str(&msg.crluri) /* string 21 */
1804 || !pack_str(&msg.crluri2) /* string 22 */
1805 || !pack_str(&msg.ocspuri) /* string 23 */
1806 || !pack_str(&msg.ike) /* string 24 */
1807 || !pack_str(&msg.esp) /* string 25 */
1808 || !pack_str(&msg.sc_data) /* string 26 */
1809 || !pack_str(&msg.whack_lease_ip) /* string 27 */
1810 || !pack_str(&msg.whack_lease_id) /* string 28 */
1811 || !pack_str(&msg.xauth_identity) /* string 29 */
1812 || str_roof - next_str < (ptrdiff_t)msg.keyval.len)
1813 diag("too many bytes of strings to fit in message to pluto");
1814
1815 memcpy(next_str, msg.keyval.ptr, msg.keyval.len);
1816 msg.keyval.ptr = NULL;
1817 next_str += msg.keyval.len;
1818
1819 msg.magic = ((opts_seen & ~LELEM(OPT_SHUTDOWN))
1820 | sc_seen | lst_seen | cd_seen | ca_seen) != LEMPTY
1821 || msg.whack_options
1822 ? WHACK_MAGIC : WHACK_BASIC_MAGIC;
1823
1824 /* send message to Pluto */
1825 if (access(ctl_addr.sun_path, R_OK | W_OK) < 0)
1826 {
1827 int e = errno;
1828
1829 switch (e)
1830 {
1831 case EACCES:
1832 fprintf(stderr, "whack: no right to communicate with pluto (access(\"%s\"))\n"
1833 , ctl_addr.sun_path);
1834 break;
1835 case ENOENT:
1836 fprintf(stderr, "whack: Pluto is not running (no \"%s\")\n"
1837 , ctl_addr.sun_path);
1838 break;
1839 default:
1840 fprintf(stderr, "whack: access(\"%s\") failed with %d %s\n"
1841 , ctl_addr.sun_path, errno, strerror(e));
1842 break;
1843 }
1844 whack_exit(RC_WHACK_PROBLEM);
1845 }
1846 else
1847 {
1848 int sock = socket(AF_UNIX, SOCK_STREAM, 0);
1849 int exit_status = 0;
1850 ssize_t len = next_str - (char *)&msg;
1851
1852 if (sock == -1)
1853 {
1854 int e = errno;
1855
1856 fprintf(stderr, "whack: socket() failed (%d %s)\n", e, strerror(e));
1857 whack_exit(RC_WHACK_PROBLEM);
1858 }
1859
1860 if (connect(sock, (struct sockaddr *)&ctl_addr
1861 , offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
1862 {
1863 int e = errno;
1864
1865 fprintf(stderr, "whack:%s connect() for \"%s\" failed (%d %s)\n"
1866 , e == ECONNREFUSED? " is Pluto running? " : ""
1867 , ctl_addr.sun_path, e, strerror(e));
1868 whack_exit(RC_WHACK_PROBLEM);
1869 }
1870
1871 if (write(sock, &msg, len) != len)
1872 {
1873 int e = errno;
1874
1875 fprintf(stderr, "whack: write() failed (%d %s)\n", e, strerror(e));
1876 whack_exit(RC_WHACK_PROBLEM);
1877 }
1878
1879 /* for now, just copy reply back to stdout */
1880
1881 {
1882 char buf[4097]; /* arbitrary limit on log line length */
1883 char *be = buf;
1884
1885 for (;;)
1886 {
1887 char *ls = buf;
1888 ssize_t rl = read(sock, be, (buf + sizeof(buf)-1) - be);
1889
1890 if (rl < 0)
1891 {
1892 int e = errno;
1893
1894 fprintf(stderr, "whack: read() failed (%d %s)\n", e, strerror(e));
1895 whack_exit(RC_WHACK_PROBLEM);
1896 }
1897 if (rl == 0)
1898 {
1899 if (be != buf)
1900 fprintf(stderr, "whack: last line from pluto too long or unterminated\n");
1901 break;
1902 }
1903
1904 be += rl;
1905 *be = '\0';
1906
1907 for (;;)
1908 {
1909 char *le = strchr(ls, '\n');
1910
1911 if (le == NULL)
1912 {
1913 /* move last, partial line to start of buffer */
1914 memmove(buf, ls, be-ls);
1915 be -= ls - buf;
1916 break;
1917 }
1918
1919 le++; /* include NL in line */
1920 ignore_result(write(1, ls, le - ls));
1921
1922 /* figure out prefix number
1923 * and how it should affect our exit status
1924 */
1925 {
1926 unsigned long s = strtoul(ls, NULL, 10);
1927
1928 switch (s)
1929 {
1930 case RC_COMMENT:
1931 case RC_LOG:
1932 /* ignore */
1933 break;
1934 case RC_SUCCESS:
1935 /* be happy */
1936 exit_status = 0;
1937 break;
1938 case RC_ENTERSECRET:
1939 get_secret(sock);
1940 break;
1941 /* case RC_LOG_SERIOUS: */
1942 default:
1943 /* pass through */
1944 exit_status = s;
1945 break;
1946 }
1947 }
1948 ls = le;
1949 }
1950 }
1951 }
1952 whack_exit(exit_status);
1953 }
1954 return -1; /* should never be reached */
1955 }