/
main.c
2257 lines (1993 loc) · 58.5 KB
1
/*
2
* OpenConnect (SSL + DTLS) VPN client
3
*
4
* Copyright © 2008-2015 Intel Corporation.
5
* Copyright © 2008 Nick Andrew <nick@nick-andrew.net>
6
* Copyright © 2013 John Morrissey <jwm@horde.net>
7
*
8
9
10
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Lesser General Public License
12
* version 2.1, as published by the Free Software Foundation.
13
*
14
* This program is distributed in the hope that it will be useful, but
15
16
17
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
18
19
*/
20
21
#include <config.h>
22
23
24
25
26
#ifdef HAVE_GETLINE
/* Various BSD systems require this for getline() to be visible */
#define _WITH_GETLINE
#endif
27
#include <stdio.h>
28
#include <stdarg.h>
29
#include <stdlib.h>
30
#include <signal.h>
31
#include <string.h>
32
33
34
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
35
36
37
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
38
39
#include <sys/types.h>
#include <getopt.h>
40
#include <time.h>
41
#include <locale.h>
42
43
44
#ifdef LIBPROXY_HDR
#include LIBPROXY_HDR
45
#endif
46
47
#include "openconnect-internal.h"
48
49
#ifdef _WIN32
50
#include <shlwapi.h>
51
52
#include <wtypes.h>
#include <wincon.h>
53
54
55
56
#else
#include <sys/utsname.h>
#include <pwd.h>
#include <termios.h>
57
#endif
58
59
60
61
62
63
64
#ifdef HAVE_NL_LANGINFO
#include <langinfo.h>
static const char *legacy_charset;
#endif
65
static int write_new_config(void *_vpninfo,
66
const char *buf, int buflen);
67
68
static void __attribute__ ((format(printf, 3, 4)))
write_progress(void *_vpninfo, int level, const char *fmt, ...);
69
static int validate_peer_cert(void *_vpninfo, const char *reason);
70
71
static int process_auth_form_cb(void *_vpninfo,
struct oc_auth_form *form);
72
73
static void init_token(struct openconnect_info *vpninfo,
oc_token_mode_t token_mode, const char *token_str);
74
75
76
/* A sanity check that the openconnect executable is running against a
library of the same version */
77
#define openconnect_version_str openconnect_binary_version
78
#include <version.c>
79
#undef openconnect_version_str
80
81
82
static int verbose = PRG_INFO;
static int timestamp;
83
int background;
84
85
86
static int do_passphrase_from_fsid;
static int non_inter;
static int cookieonly;
87
static int allow_stdin_read;
88
89
static char *token_filename;
90
static char *server_cert = NULL;
91
92
93
94
95
96
97
98
static char *username;
static char *password;
static char *authgroup;
static int authgroup_set;
static int last_form_empty;
static int sig_cmd_fd;
99
100
101
static void add_form_field(char *field);
102
103
#ifdef __ANDROID__
#include <android/log.h>
104
105
static void __attribute__ ((format(printf, 3, 4)))
syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
{
static int l[4] = {
ANDROID_LOG_ERROR, /* PRG_ERR */
ANDROID_LOG_INFO, /* PRG_INFO */
ANDROID_LOG_DEBUG, /* PRG_DEBUG */
ANDROID_LOG_DEBUG /* PRG_TRACE */
};
va_list args, args2;
if (verbose >= level) {
va_start(args, fmt);
va_copy(args2, args);
__android_log_vprint(l[level], "openconnect", fmt, args);
/* Android wants it to stderr too, so the GUI can scrape
it and display it as well as going to syslog */
vfprintf(stderr, fmt, args2);
va_end(args);
va_end(args2);
}
}
126
#define openlog(...) /* */
127
#elif defined(_WIN32) || defined(__native_client__)
128
129
130
131
/*
* FIXME: Perhaps we could implement syslog_progress() using these APIs:
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa364148%28v=vs.85%29.aspx
*/
132
#else /* !__ANDROID__ && !_WIN32 && !__native_client__ */
133
#include <syslog.h>
134
135
static void __attribute__ ((format(printf, 3, 4)))
syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
136
137
138
139
140
141
142
143
144
145
146
147
{
int priority = level ? LOG_INFO : LOG_NOTICE;
va_list args;
if (verbose >= level) {
va_start(args, fmt);
vsyslog(priority, fmt, args);
va_end(args);
}
}
#endif
148
enum {
149
150
OPT_AUTHENTICATE = 0x100,
OPT_AUTHGROUP,
151
OPT_BASEMTU,
152
OPT_CAFILE,
153
OPT_COMPRESSION,
154
OPT_CONFIGFILE,
155
156
157
OPT_COOKIEONLY,
OPT_COOKIE_ON_STDIN,
OPT_CSD_USER,
158
OPT_CSD_WRAPPER,
159
160
OPT_DISABLE_IPV6,
OPT_DTLS_CIPHERS,
161
OPT_DTLS12_CIPHERS,
162
OPT_DUMP_HTTP,
163
OPT_FORCE_DPD,
164
OPT_GNUTLS_DEBUG,
165
OPT_JUNIPER,
166
167
168
169
170
OPT_KEY_PASSWORD_FROM_FSID,
OPT_LIBPROXY,
OPT_NO_CERT_CHECK,
OPT_NO_DTLS,
OPT_NO_HTTP_KEEPALIVE,
171
OPT_NO_SYSTEM_TRUST,
172
173
OPT_NO_PASSWD,
OPT_NO_PROXY,
174
OPT_NO_XMLPOST,
175
OPT_PIDFILE,
176
177
178
179
OPT_PASSWORD_ON_STDIN,
OPT_PRINTCOOKIE,
OPT_RECONNECT_TIMEOUT,
OPT_SERVERCERT,
180
OPT_RESOLVE,
181
OPT_USERAGENT,
182
OPT_NON_INTER,
183
OPT_DTLS_LOCAL_PORT,
184
185
OPT_TOKEN_MODE,
OPT_TOKEN_SECRET,
186
OPT_OS,
187
OPT_TIMESTAMP,
188
OPT_PFS,
189
OPT_PROXY_AUTH,
190
OPT_HTTP_AUTH,
191
OPT_LOCAL_HOSTNAME,
192
OPT_PROTOCOL,
193
OPT_PASSTOS,
194
OPT_VERSION,
195
196
};
197
198
199
200
201
202
203
204
205
206
#ifdef __sun__
/*
* The 'name' field in Solaris 'struct option' lacks the 'const', and causes
* lots of warnings unless we cast it... https://www.illumos.org/issues/1881
*/
#define OPTION(name, arg, abbrev) {(char *)name, arg, NULL, abbrev}
#else
#define OPTION(name, arg, abbrev) {name, arg, NULL, abbrev}
#endif
207
static const struct option long_options[] = {
208
#ifndef _WIN32
209
210
OPTION("background", 0, 'b'),
OPTION("pid-file", 1, OPT_PIDFILE),
211
212
213
214
215
OPTION("setuid", 1, 'U'),
OPTION("script-tun", 0, 'S'),
OPTION("syslog", 0, 'l'),
OPTION("csd-user", 1, OPT_CSD_USER),
OPTION("csd-wrapper", 1, OPT_CSD_WRAPPER),
216
217
#endif
OPTION("pfs", 0, OPT_PFS),
218
219
220
OPTION("certificate", 1, 'c'),
OPTION("sslkey", 1, 'k'),
OPTION("cookie", 1, 'C'),
221
OPTION("compression", 1, OPT_COMPRESSION),
222
OPTION("deflate", 0, 'd'),
223
OPTION("juniper", 0, OPT_JUNIPER),
224
225
226
227
OPTION("no-deflate", 0, 'D'),
OPTION("cert-expire-warning", 1, 'e'),
OPTION("usergroup", 1, 'g'),
OPTION("help", 0, 'h'),
228
OPTION("http-auth", 1, OPT_HTTP_AUTH),
229
230
OPTION("interface", 1, 'i'),
OPTION("mtu", 1, 'm'),
231
OPTION("base-mtu", 1, OPT_BASEMTU),
232
OPTION("script", 1, 's'),
233
OPTION("timestamp", 0, OPT_TIMESTAMP),
234
OPTION("passtos", 0, OPT_PASSTOS),
235
236
OPTION("key-password", 1, 'p'),
OPTION("proxy", 1, 'P'),
237
OPTION("proxy-auth", 1, OPT_PROXY_AUTH),
238
239
240
241
OPTION("user", 1, 'u'),
OPTION("verbose", 0, 'v'),
OPTION("version", 0, 'V'),
OPTION("cafile", 1, OPT_CAFILE),
242
OPTION("config", 1, OPT_CONFIGFILE),
243
OPTION("no-dtls", 0, OPT_NO_DTLS),
244
OPTION("authenticate", 0, OPT_AUTHENTICATE),
245
246
247
248
249
250
251
252
253
254
OPTION("cookieonly", 0, OPT_COOKIEONLY),
OPTION("printcookie", 0, OPT_PRINTCOOKIE),
OPTION("quiet", 0, 'q'),
OPTION("queue-len", 1, 'Q'),
OPTION("xmlconfig", 1, 'x'),
OPTION("cookie-on-stdin", 0, OPT_COOKIE_ON_STDIN),
OPTION("passwd-on-stdin", 0, OPT_PASSWORD_ON_STDIN),
OPTION("no-passwd", 0, OPT_NO_PASSWD),
OPTION("reconnect-timeout", 1, OPT_RECONNECT_TIMEOUT),
OPTION("dtls-ciphers", 1, OPT_DTLS_CIPHERS),
255
OPTION("dtls12-ciphers", 1, OPT_DTLS12_CIPHERS),
256
257
OPTION("authgroup", 1, OPT_AUTHGROUP),
OPTION("servercert", 1, OPT_SERVERCERT),
258
OPTION("resolve", 1, OPT_RESOLVE),
259
260
OPTION("key-password-from-fsid", 0, OPT_KEY_PASSWORD_FROM_FSID),
OPTION("useragent", 1, OPT_USERAGENT),
261
OPTION("version-string", 1, OPT_VERSION),
262
OPTION("local-hostname", 1, OPT_LOCAL_HOSTNAME),
263
264
265
266
267
268
269
OPTION("disable-ipv6", 0, OPT_DISABLE_IPV6),
OPTION("no-proxy", 0, OPT_NO_PROXY),
OPTION("libproxy", 0, OPT_LIBPROXY),
OPTION("no-http-keepalive", 0, OPT_NO_HTTP_KEEPALIVE),
OPTION("no-cert-check", 0, OPT_NO_CERT_CHECK),
OPTION("force-dpd", 1, OPT_FORCE_DPD),
OPTION("non-inter", 0, OPT_NON_INTER),
270
OPTION("dtls-local-port", 1, OPT_DTLS_LOCAL_PORT),
271
OPTION("token-mode", 1, OPT_TOKEN_MODE),
272
OPTION("token-secret", 1, OPT_TOKEN_SECRET),
273
OPTION("os", 1, OPT_OS),
274
OPTION("no-xmlpost", 0, OPT_NO_XMLPOST),
275
OPTION("dump-http-traffic", 0, OPT_DUMP_HTTP),
276
OPTION("no-system-trust", 0, OPT_NO_SYSTEM_TRUST),
277
OPTION("protocol", 1, OPT_PROTOCOL),
278
OPTION("form-entry", 1, 'F'),
279
280
281
#ifdef OPENCONNECT_GNUTLS
OPTION("gnutls-debug", 1, OPT_GNUTLS_DEBUG),
#endif
282
OPTION(NULL, 0, 0)
283
284
};
285
286
287
288
289
290
291
#ifdef OPENCONNECT_GNUTLS
static void oc_gnutls_log_func(int level, const char *str)
{
fputs(str, stderr);
}
#endif
292
#ifdef _WIN32
293
294
static int __attribute__ ((format(printf, 2, 0)))
vfprintf_utf8(FILE *f, const char *fmt, va_list args)
295
296
297
298
299
300
301
302
303
304
305
306
307
308
{
HANDLE h = GetStdHandle(f == stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
wchar_t wbuf[1024];
char buf[1024];
int chars, wchars;
buf[sizeof(buf) - 1] = 0;
chars = _vsnprintf(buf, sizeof(buf) - 1, fmt, args);
wchars = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)/2);
WriteConsoleW(h, wbuf, wchars, NULL, NULL);
return chars;
}
309
310
static int __attribute__ ((format(printf, 2, 3)))
fprintf_utf8(FILE *f, const char *fmt, ...)
311
312
313
314
315
316
317
318
319
320
{
va_list args;
int ret;
va_start(args, fmt);
ret = vfprintf_utf8(f, fmt, args);
va_end(args);
return ret;
}
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
static wchar_t **argv_w;
/* This isn't so much "convert" the arg to UTF-8, as go grubbing
* around in the real UTF-16 command line and find the corresponding
* argument *there*, and convert *that* to UTF-8. Ick. But the
* alternative is to implement wgetopt(), and that's even more horrid. */
static char *convert_arg_to_utf8(char **argv, char *arg)
{
char *utf8;
int chars;
int offset;
if (!argv_w) {
int argc_w;
argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
if (!argv_w) {
339
340
341
342
char *errstr = openconnect__win32_strerror(GetLastError());
fprintf(stderr, _("CommandLineToArgvW() failed: %s\n"),
errstr);
free(errstr);
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
exit(1);
}
}
offset = arg - argv[optind - 1];
/* Sanity check */
if (offset < 0 || offset >= strlen(argv[optind - 1]) ||
(offset && (argv[optind - 1][offset-1] != '=' ||
argv_w[optind - 1][offset - 1] != '='))) {
fprintf(stderr, _("Fatal error in command line handling\n"));
exit(1);
}
chars = WideCharToMultiByte(CP_UTF8, 0, argv_w[optind-1] + offset, -1,
NULL, 0, NULL, NULL);
utf8 = malloc(chars);
if (!utf8)
return arg;
WideCharToMultiByte(CP_UTF8, 0, argv_w[optind-1] + offset, -1, utf8,
chars, NULL, NULL);
return utf8;
}
368
369
370
371
#undef fprintf
#undef vfprintf
#define fprintf fprintf_utf8
#define vfprintf vfprintf_utf8
372
#define is_arg_utf8(str) (0)
373
374
static void read_stdin(char **string, int hidden, int allow_fail)
375
376
{
CONSOLE_READCONSOLE_CONTROL rcc = { sizeof(rcc), 0, 13, 0 };
377
HANDLE stdinh = GetStdHandle(STD_INPUT_HANDLE);
378
379
380
381
DWORD cmode, nr_read;
wchar_t wbuf[1024];
char *buf;
382
383
384
385
386
if (GetConsoleMode(stdinh, &cmode)) {
if (hidden)
SetConsoleMode(stdinh, cmode & (~ENABLE_ECHO_INPUT));
if (!ReadConsoleW(stdinh, wbuf, sizeof(wbuf)/2, &nr_read, &rcc)) {
387
char *errstr = openconnect__win32_strerror(GetLastError());
388
fprintf(stderr, _("ReadConsole() failed: %s\n"), errstr);
389
390
free(errstr);
*string = NULL;
391
392
393
if (hidden)
SetConsoleMode(stdinh, cmode);
return;
394
}
395
396
397
398
399
400
401
402
403
404
405
406
if (hidden)
SetConsoleMode(stdinh, cmode);
} else {
/* Not a console; maybe reading from a piped stdin? */
if (!fgetws(wbuf, sizeof(wbuf)/2, stdin)) {
char *errstr = openconnect__win32_strerror(GetLastError());
fprintf(stderr, _("fgetws() failed: %s\n"), errstr);
free(errstr);
*string = NULL;
return;
}
nr_read = wcslen(wbuf);
407
}
408
409
410
411
412
413
414
if (nr_read >= 2 && wbuf[nr_read - 1] == 10 && wbuf[nr_read - 2] == 13) {
wbuf[nr_read - 2] = 0;
nr_read -= 2;
}
nr_read = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL, NULL);
if (!nr_read) {
415
char *errstr = openconnect__win32_strerror(GetLastError());
416
fprintf(stderr, _("Error converting console input: %s\n"),
417
418
errstr);
free(errstr);
419
return;
420
421
422
423
424
425
426
427
}
buf = malloc(nr_read);
if (!buf) {
fprintf(stderr, _("Allocation failure for string from stdin\n"));
exit(1);
}
if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, nr_read, NULL, NULL)) {
428
429
430
431
char *errstr = openconnect__win32_strerror(GetLastError());
fprintf(stderr, _("Error converting console input: %s\n"),
errstr);
free(errstr);
432
free(buf);
433
return;
434
435
436
437
438
}
*string = buf;
}
439
#elif defined(HAVE_ICONV)
440
441
#include <iconv.h>
442
443
444
445
446
447
448
449
450
451
452
static int is_ascii(char *str)
{
while (str && *str) {
if ((unsigned char)*str > 0x7f)
return 0;
str++;
}
return 1;
}
453
454
static int __attribute__ ((format(printf, 2, 0)))
vfprintf_utf8(FILE *f, const char *fmt, va_list args)
455
456
457
458
459
{
char *utf8_str;
iconv_t ic;
int ret;
char outbuf[80];
460
461
ICONV_CONST char *ic_in;
char *ic_out;
462
463
464
465
466
467
468
469
470
size_t insize, outsize;
if (!legacy_charset)
return vfprintf(f, fmt, args);
ret = vasprintf(&utf8_str, fmt, args);
if (ret < 0)
return -1;
471
472
473
if (is_ascii(utf8_str))
return fwrite(utf8_str, 1, strlen(utf8_str), f);
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
ic = iconv_open(legacy_charset, "UTF-8");
if (ic == (iconv_t) -1) {
/* Better than nothing... */
ret = fprintf(f, "%s", utf8_str);
free(utf8_str);
return ret;
}
ic_in = utf8_str;
insize = strlen(utf8_str);
ret = 0;
while (insize) {
ic_out = outbuf;
outsize = sizeof(outbuf) - 1;
490
if (iconv(ic, &ic_in, &insize, &ic_out, &outsize) == (size_t)-1) {
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
if (errno == EILSEQ) {
do {
ic_in++;
insize--;
} while (insize && (ic_in[0] & 0xc0) == 0x80);
ic_out[0] = '?';
outsize--;
} else if (errno != E2BIG)
break;
}
ret += fwrite(outbuf, 1, sizeof(outbuf) - 1 - outsize, f);
}
iconv_close(ic);
return ret;
}
509
510
static int __attribute__ ((format(printf, 2, 3)))
fprintf_utf8(FILE *f, const char *fmt, ...)
511
512
513
514
515
516
517
518
519
520
521
{
va_list args;
int ret;
va_start(args, fmt);
ret = vfprintf_utf8(f, fmt, args);
va_end(args);
return ret;
}
522
static char *convert_to_utf8(char *legacy, int free_it)
523
524
525
{
char *utf8_str;
iconv_t ic;
526
527
ICONV_CONST char *ic_in;
char *ic_out;
528
529
size_t insize, outsize;
530
if (!legacy_charset || is_ascii(legacy))
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
return legacy;
ic = iconv_open("UTF-8", legacy_charset);
if (ic == (iconv_t) -1)
return legacy;
insize = strlen(legacy) + 1;
ic_in = legacy;
outsize = insize;
ic_out = utf8_str = malloc(outsize);
if (!utf8_str) {
enomem:
iconv_close(ic);
return legacy;
}
while (insize) {
549
if (iconv(ic, &ic_in, &insize, &ic_out, &outsize) == (size_t)-1) {
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
if (errno == E2BIG) {
int outlen = ic_out - utf8_str;
realloc_inplace(utf8_str, outlen + 10);
if (!utf8_str)
goto enomem;
ic_out = utf8_str + outlen;
outsize = 10;
} else {
/* Should never happen */
perror("iconv");
free(utf8_str);
goto enomem;
}
}
}
iconv_close(ic);
567
568
if (free_it)
free(legacy);
569
570
571
return utf8_str;
}
572
573
#define fprintf fprintf_utf8
#define vfprintf vfprintf_utf8
574
575
#define convert_arg_to_utf8(av, l) convert_to_utf8((l), 0)
#define is_arg_utf8(a) (!legacy_charset || is_ascii(a))
576
#else
577
578
579
#define convert_to_utf8(l,f) (l)
#define convert_arg_to_utf8(av, l) (l)
#define is_arg_utf8(a) (1)
580
581
#endif
582
583
584
585
586
587
static void helpmessage(void)
{
printf(_("For assistance with OpenConnect, please see the web page at\n"
" http://www.infradead.org/openconnect/mail.html\n"));
}
588
589
static void print_build_opts(void)
{
590
591
const char *comma = ", ", *sep = comma + 1;
592
#if defined(OPENCONNECT_OPENSSL)
593
printf(_("Using OpenSSL. Features present:"));
594
#elif defined(OPENCONNECT_GNUTLS)
595
596
597
598
599
600
601
printf(_("Using GnuTLS. Features present:"));
#endif
if (openconnect_has_tss_blob_support()) {
printf("%sTPM", sep);
sep = comma;
}
602
603
604
605
if (openconnect_has_tss2_blob_support()) {
printf("%sTPMv2", sep);
sep = comma;
}
606
#if defined(OPENCONNECT_OPENSSL) && defined(HAVE_ENGINE)
607
608
609
610
611
612
613
614
615
else {
printf("%sTPM (%s)", sep, _("OpenSSL ENGINE not present"));
sep = comma;
}
#endif
if (openconnect_has_pkcs11_support()) {
printf("%sPKCS#11", sep);
sep = comma;
}
616
if (openconnect_has_stoken_support()) {
617
618
619
printf("%sRSA software token", sep);
sep = comma;
}
620
621
622
623
switch(openconnect_has_oath_support()) {
case 2:
printf("%sHOTP software token", sep);
sep = comma;
624
/* fall through */
625
case 1:
626
printf("%sTOTP software token", sep);
627
628
sep = comma;
}
629
630
631
632
if (openconnect_has_yubioath_support()) {
printf("%sYubikey OATH", sep);
sep = comma;
}
633
634
635
636
if (openconnect_has_system_key_support()) {
printf("%sSystem keys", sep);
sep = comma;
}
637
638
#ifdef HAVE_DTLS
639
640
641
642
643
644
645
646
647
printf("%sDTLS", sep);
#endif
#ifdef HAVE_ESP
printf("%sESP", sep);
#endif
printf("\n");
#if !defined(HAVE_DTLS) || !defined(HAVE_ESP)
printf(_("WARNING: This binary lacks DTLS and/or ESP support. Performance will be impaired.\n"));
648
649
650
#endif
}
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
static void print_supported_protocols(void)
{
const char *comma = ", ", *sep = comma + 1;
struct oc_vpn_proto *protos, *p;
if (openconnect_get_supported_protocols(&protos)>=0) {
printf(_("Supported protocols:"));
for (p=protos; p->name; p++) {
printf("%s%s%s", sep, p->name, p==protos ? _(" (default)") : "");
sep = comma;
}
printf("\n");
free(protos);
}
}
static void print_supported_protocols_usage(void)
{
struct oc_vpn_proto *protos, *p;
if (openconnect_get_supported_protocols(&protos)>=0) {
672
printf("\n%s:\n", _("Set VPN protocol"));
673
674
675
676
677
678
679
for (p=protos; p->name; p++)
printf(" --protocol=%-16s %s%s\n",
p->name, p->description, p==protos ? _(" (default)") : "");
openconnect_free_supported_protocols(protos);
}
}
680
681
#ifndef _WIN32
static const char default_vpncscript[] = DEFAULT_VPNCSCRIPT;
682
static void read_stdin(char **string, int hidden, int allow_fail)
683
{
684
char *c, *buf = malloc(1025);
685
int fd = fileno(stdin);
686
struct termios t;
687
688
689
690
691
if (!buf) {
fprintf(stderr, _("Allocation failure for string from stdin\n"));
exit(1);
}
692
693
694
695
696
697
698
if (hidden) {
tcgetattr(fd, &t);
t.c_lflag &= ~ECHO;
tcsetattr(fd, TCSANOW, &t);
}
699
buf = fgets(buf, 1025, stdin);
700
701
702
703
704
705
706
if (hidden) {
t.c_lflag |= ECHO;
tcsetattr(fd, TCSANOW, &t);
fprintf(stderr, "\n");
}
707
if (!buf) {
708
709
710
711
712
713
714
715
if (allow_fail) {
*string = NULL;
free(buf);
return;
} else {
perror(_("fgets (stdin)"));
exit(1);
}
716
717
}
718
719
720
c = strchr(buf, '\n');
if (c)
*c = 0;
721
722
*string = convert_to_utf8(buf, 1);
723
724
725
726
727
728
729
}
static void handle_signal(int sig)
{
char cmd;
switch (sig) {
730
case SIGTERM:
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
case SIGINT:
cmd = OC_CMD_CANCEL;
break;
case SIGHUP:
cmd = OC_CMD_DETACH;
break;
case SIGUSR2:
default:
cmd = OC_CMD_PAUSE;
break;
}
if (write(sig_cmd_fd, &cmd, 1) < 0) {
/* suppress warn_unused_result */
}
}
#else /* _WIN32 */
748
749
750
751
752
753
754
755
756
757
static const char *default_vpncscript;
static void set_default_vpncscript(void)
{
if (PathIsRelative(DEFAULT_VPNCSCRIPT)) {
char *c = strrchr(_pgmptr, '\\');
if (!c) {
fprintf(stderr, _("Cannot process this executable path \"%s\""),
_pgmptr);
exit(1);
}
758
if (asprintf((char **)&default_vpncscript, "%.*s%s",
759
760
761
762
763
764
765
766
767
768
(c - _pgmptr + 1), _pgmptr, DEFAULT_VPNCSCRIPT) < 0) {
fprintf(stderr, _("Allocation for vpnc-script path failed\n"));
exit(1);
}
} else {
default_vpncscript = "cscript " DEFAULT_VPNCSCRIPT;
}
}
#endif
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
static struct oc_vpn_option *gai_overrides;
static int gai_override_cb(void *cbdata, const char *node,
const char *service, const struct addrinfo *hints,
struct addrinfo **res)
{
struct openconnect_info *vpninfo = cbdata;
struct oc_vpn_option *p = gai_overrides;
while (p) {
if (!strcmp(node, p->option)) {
vpn_progress(vpninfo, PRG_TRACE, _("Override hostname '%s' to '%s'\n"),
node, p->value);
node = p->value;
break;
}
p = p->next;
}
return getaddrinfo(node, service, hints, res);
}
791
static void usage(void)
792
{
793
printf(_("Usage: openconnect [options] <server>\n"));
794
printf(_("Open client for multiple VPN protocols, version %s\n\n"), openconnect_version_str);
795
print_build_opts();
796
printf(" --config=CONFIGFILE %s\n", _("Read options from config file"));
797
798
printf(" -V, --version %s\n", _("Report version number"));
printf(" -h, --help %s\n", _("Display help text"));
799
800
print_supported_protocols_usage();
801
802
printf("\n%s:\n", _("Authentication"));
803
804
805
806
807
printf(" -u, --user=NAME %s\n", _("Set login username"));
printf(" --no-passwd %s\n", _("Disable password/SecurID authentication"));
printf(" --non-inter %s\n", _("Do not expect user input; exit if it is required"));
printf(" --passwd-on-stdin %s\n", _("Read password from standard input"));
printf(" --authgroup=GROUP %s\n", _("Choose authentication login selection"));
808
printf(" -F, --form-field=FORM:OPT=VALUE %s\n", _("Provide authentication form responses"));
809
810
printf(" -c, --certificate=CERT %s\n", _("Use SSL client certificate CERT"));
printf(" -k, --sslkey=KEY %s\n", _("Use SSL private key file KEY"));
811
printf(" -e, --cert-expire-warning=DAYS %s\n", _("Warn when certificate lifetime < DAYS"));
812
813
814
printf(" -g, --usergroup=GROUP %s\n", _("Set login usergroup"));
printf(" -p, --key-password=PASS %s\n", _("Set key passphrase or TPM SRK PIN"));
printf(" --key-password-from-fsid %s\n", _("Key passphrase is fsid of file system"));
815
816
817
818
819
820
821
822
printf(" --token-mode=MODE %s\n", _("Software token type: rsa, totp or hotp"));
printf(" --token-secret=STRING %s\n", _("Software token secret"));
#ifndef HAVE_LIBSTOKEN
printf(" %s\n", _("(NOTE: libstoken (RSA SecurID) disabled in this build)"));
#endif
#ifndef HAVE_LIBPCSCLITE
printf(" %s\n", _("(NOTE: Yubikey OATH disabled in this build)"));
#endif
823
824
printf("\n%s:\n", _("Server validation"));
825
826
827
828
printf(" --servercert=FINGERPRINT %s\n", _("Server's certificate SHA1 fingerprint"));
printf(" --no-cert-check %s\n", _("Do not require server SSL cert to be valid"));
printf(" --no-system-trust %s\n", _("Disable default system certificate authorities"));
printf(" --cafile=FILE %s\n", _("Cert file for server verification"));
829
830
printf("\n%s:\n", _("Internet connectivity"));
831
printf(" -P, --proxy=URL %s\n", _("Set proxy server"));
832
printf(" --proxy-auth=METHODS %s\n", _("Set proxy authentication methods"));
833
834
printf(" --no-proxy %s\n", _("Disable proxy"));
printf(" --libproxy %s\n", _("Use libproxy to automatically configure proxy"));
835
#ifndef LIBPROXY_HDR
836
printf(" %s\n", _("(NOTE: libproxy disabled in this build)"));
837
#endif
838
839
840
printf(" --reconnect-timeout %s\n", _("Connection retry timeout in seconds"));
printf(" --resolve=HOST:IP %s\n", _("Use IP when connecting to HOST"));
printf(" --passtos %s\n", _("copy TOS / TCLASS when using DTLS"));
841
printf(" --dtls-local-port=PORT %s\n", _("Set local port for DTLS and ESP datagrams"));
842
843
printf("\n%s:\n", _("Authentication (two-phase)"));
844
printf(" -C, --cookie=COOKIE %s\n", _("Use authentication cookie COOKIE"));
845
846
printf(" --cookie-on-stdin %s\n", _("Read cookie from standard input"));
printf(" --authenticate %s\n", _("Authenticate only and print login info"));
847
848
849
printf(" --cookieonly %s\n", _("Fetch and print cookie only; don't connect"));
printf(" --printcookie %s\n", _("Print cookie before connecting"));
850
#ifndef _WIN32
851
printf("\n%s:\n", _("Process control"));
852
853
854
855
printf(" -b, --background %s\n", _("Continue in background after startup"));
printf(" --pid-file=PIDFILE %s\n", _("Write the daemon's PID to this file"));
printf(" -U, --setuid=USER %s\n", _("Drop privileges after connecting"));
#endif
856
857
printf("\n%s:\n", _("Logging (two-phase)"));
858
859
860
861
#ifndef _WIN32
printf(" -l, --syslog %s\n", _("Use syslog for progress messages"));
#endif
printf(" -v, --verbose %s\n", _("More output"));
862
printf(" -q, --quiet %s\n", _("Less output"));
863
864
printf(" --dump-http-traffic %s\n", _("Dump HTTP authentication traffic (implies --verbose"));
printf(" --timestamp %s\n", _("Prepend timestamp to progress messages"));
865
866
printf("\n%s:\n", _("VPN configuration script"));
867
printf(" -i, --interface=IFNAME %s\n", _("Use IFNAME for tunnel interface"));
868
printf(" -s, --script=SCRIPT %s\n", _("Shell command line for using a vpnc-compatible config script"));
869
printf(" %s: \"%s\"\n", _("default"), default_vpncscript);
870
#ifndef _WIN32
871
printf(" -S, --script-tun %s\n", _("Pass traffic to 'script' program, not tun"));
872
#endif
873
874
printf("\n%s:\n", _("Tunnel control"));
875
printf(" --disable-ipv6 %s\n", _("Do not ask for IPv6 connectivity"));
876
877
878
printf(" -x, --xmlconfig=CONFIG %s\n", _("XML config file"));
printf(" -m, --mtu=MTU %s\n", _("Request MTU from server (legacy servers only)"));
printf(" --base-mtu=MTU %s\n", _("Indicate path MTU to/from server"));
879
880
printf(" -d, --deflate %s\n", _("Enable stateful compression (default is stateless only)"));
printf(" -D, --no-deflate %s\n", _("Disable all compression"));
881
882
printf(" --force-dpd=INTERVAL %s\n", _("Set minimum Dead Peer Detection interval"));
printf(" --pfs %s\n", _("Require perfect forward secrecy"));
883
printf(" --no-dtls %s\n", _("Disable DTLS and ESP"));
884
885
printf(" --dtls-ciphers=LIST %s\n", _("OpenSSL ciphers to support for DTLS"));
printf(" -Q, --queue-len=LEN %s\n", _("Set packet queue limit to LEN pkts"));
886
887
printf("\n%s:\n", _("Local system information"));
888
printf(" --useragent=STRING %s\n", _("HTTP header User-Agent: field"));
889
printf(" --local-hostname=STRING %s\n", _("Local hostname to advertise to server"));
890
printf(" --os=STRING %s\n", _("OS type (linux,linux-64,win,...) to report"));
891
892
printf(" --version-string=STRING %s\n", _("reported version string during authentication"));
printf(" (%s %s)\n", _("default:"), openconnect_version_str);
893
894
#ifndef _WIN32
895
printf("\n%s:\n", _("Trojan binary (CSD) execution"));
896
897
printf(" --csd-user=USER %s\n", _("Drop privileges during trojan execution"));
printf(" --csd-wrapper=SCRIPT %s\n", _("Run SCRIPT instead of trojan binary"));
898
#endif
899
900
printf("\n%s:\n", _("Server bugs"));
901
902
printf(" --no-http-keepalive %s\n", _("Disable HTTP connection re-use"));
printf(" --no-xmlpost %s\n", _("Do not attempt XML POST authentication"));
903
904
905
906
printf("\n");
helpmessage();
907
908
909
exit(1);
}
910
911
912
913
static FILE *config_file = NULL;
static int config_line_num = 0;
914
915
static char *xstrdup(const char *arg)
{
916
917
918
919
920
921
char *ret;
if (!arg)
return NULL;
ret = strdup(arg);
922
923
924
925
926
927
928
929
if (!ret) {
fprintf(stderr, _("Failed to allocate string\n"));
exit(1);
}
return ret;
}
930
931
932
933
/* There are three ways to handle config_arg:
*
* 1. We only care about it transiently and it can be lost entirely
* (e.g. vpninfo->reconnect_timeout = atoi(config_arg);
934
* 2. We need to keep it, but it's a static string and will never be freed
935
936
937
* so when it's part of argv[] we can use it in place (unless it needs
* converting to UTF-8), but when it comes from a file we have to strdup()
* because otherwise it'll be overwritten.
938
939
* For this we use the keep_config_arg() macro below.
* 3. It may be freed during normal operation, so we have to use strdup()
940
941
942
* or convert_arg_to_utf8() even when it's an option from argv[].
* (e.g. vpninfo->cert_password).
* For this we use the dup_config_arg() macro below.
943
*/
944
945
946
947
#define keep_config_arg() \
(config_file ? xstrdup(config_arg) : convert_arg_to_utf8(argv, config_arg))
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
#define dup_config_arg() __dup_config_arg(argv, config_arg)
static inline char *__dup_config_arg(char **argv, char *config_arg)
{
char *res;
if (config_file || is_arg_utf8(config_arg))
return xstrdup(config_arg);
res = convert_arg_to_utf8(argv, config_arg);
/* Force a copy, even if conversion failed */
if (res == config_arg)
res = xstrdup(res);
return res;
}
963
964
965
static int next_option(int argc, char **argv, char **config_arg)
{
966
967
968
969
970
/* These get re-used */
static char *line_buf = NULL;
static size_t line_size = 0;
ssize_t llen;
971
int opt, optlen = 0;
972
const struct option *this;
973
974
975
976
977
978
char *line;
int ate_equals = 0;
next:
if (!config_file) {
opt = getopt_long(argc, argv,
979
#ifdef _WIN32
980
"C:c:Dde:F:g:hi:k:m:P:p:Q:qs:u:Vvx:",
981
#else
982
"bC:c:Dde:F:g:hi:k:lm:P:p:Q:qSs:U:u:Vvx:",
983
#endif
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
long_options, NULL);
*config_arg = optarg;
return opt;
}
llen = getline(&line_buf, &line_size, config_file);
if (llen < 0) {
if (feof(config_file)) {
fclose(config_file);
config_file = NULL;
goto next;
}
fprintf(stderr, _("Failed to get line from config file: %s\n"),
strerror(errno));
exit(1);
}