2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2011 Intel Corporation.
5 * Copyright © 2008 Nick Andrew <nick@nick-andrew.net>
7 * Author: David Woodhouse <dwmw2@infradead.org>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * version 2.1, as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to:
21 * Free Software Foundation, Inc.
22 * 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301 USA
28 #include <android/log.h>
43 #include <sys/utsname.h>
44 #include <sys/types.h>
45 #include <openssl/ui.h>
52 #include "openconnect-internal.h"
54 static int write_new_config(void *_vpninfo,
55 char *buf, int buflen);
56 static void write_progress(void *_vpninfo,
57 int level, const char *fmt, ...);
58 static void syslog_progress(void *_vpninfo,
59 int level, const char *fmt, ...);
60 static int validate_peer_cert(void *_vpninfo,
61 X509 *peer_cert, const char *reason);
63 /* A sanity check that the openconnect executable is running against a
64 library of the same version */
65 #define openconnect_version openconnect_binary_version
67 #undef openconnect_version
69 int verbose = PRG_INFO;
71 int do_passphrase_from_fsid;
76 OPT_AUTHGROUP = 0x100,
86 OPT_KEY_PASSWORD_FROM_FSID,
90 OPT_NO_HTTP_KEEPALIVE,
94 OPT_PASSWORD_ON_STDIN,
96 OPT_RECONNECT_TIMEOUT,
104 * The 'name' field in Solaris 'struct option' lacks the 'const', and causes
105 * lots of warnings unless we cast it... https://www.illumos.org/issues/1881
107 #define OPTION(name, arg, abbrev) {(char *)name, arg, NULL, abbrev}
109 #define OPTION(name, arg, abbrev) {name, arg, NULL, abbrev}
112 static struct option long_options[] = {
113 OPTION("background", 0, 'b'),
114 OPTION("pid-file", 1, OPT_PIDFILE),
115 OPTION("certificate", 1, 'c'),
116 OPTION("sslkey", 1, 'k'),
117 OPTION("cookie", 1, 'C'),
118 OPTION("deflate", 0, 'd'),
119 OPTION("no-deflate", 0, 'D'),
120 OPTION("cert-expire-warning", 1, 'e'),
121 OPTION("usergroup", 1, 'g'),
122 OPTION("help", 0, 'h'),
123 OPTION("interface", 1, 'i'),
124 OPTION("mtu", 1, 'm'),
125 OPTION("setuid", 1, 'U'),
126 OPTION("script", 1, 's'),
127 OPTION("script-tun", 0, 'S'),
128 OPTION("syslog", 0, 'l'),
129 OPTION("key-type", 1, 'K'),
130 OPTION("key-password", 1, 'p'),
131 OPTION("proxy", 1, 'P'),
132 OPTION("user", 1, 'u'),
133 OPTION("verbose", 0, 'v'),
134 OPTION("version", 0, 'V'),
135 OPTION("cafile", 1, OPT_CAFILE),
136 OPTION("config", 1, OPT_CONFIGFILE),
137 OPTION("no-dtls", 0, OPT_NO_DTLS),
138 OPTION("cookieonly", 0, OPT_COOKIEONLY),
139 OPTION("printcookie", 0, OPT_PRINTCOOKIE),
140 OPTION("quiet", 0, 'q'),
141 OPTION("queue-len", 1, 'Q'),
142 OPTION("xmlconfig", 1, 'x'),
143 OPTION("cookie-on-stdin", 0, OPT_COOKIE_ON_STDIN),
144 OPTION("passwd-on-stdin", 0, OPT_PASSWORD_ON_STDIN),
145 OPTION("no-passwd", 0, OPT_NO_PASSWD),
146 OPTION("reconnect-timeout", 1, OPT_RECONNECT_TIMEOUT),
147 OPTION("dtls-ciphers", 1, OPT_DTLS_CIPHERS),
148 OPTION("authgroup", 1, OPT_AUTHGROUP),
149 OPTION("servercert", 1, OPT_SERVERCERT),
150 OPTION("key-password-from-fsid", 0, OPT_KEY_PASSWORD_FROM_FSID),
151 OPTION("useragent", 1, OPT_USERAGENT),
152 OPTION("csd-user", 1, OPT_CSD_USER),
153 OPTION("csd-wrapper", 1, OPT_CSD_WRAPPER),
154 OPTION("disable-ipv6", 0, OPT_DISABLE_IPV6),
155 OPTION("no-proxy", 0, OPT_NO_PROXY),
156 OPTION("libproxy", 0, OPT_LIBPROXY),
157 OPTION("no-http-keepalive", 0, OPT_NO_HTTP_KEEPALIVE),
158 OPTION("no-cert-check", 0, OPT_NO_CERT_CHECK),
159 OPTION("force-dpd", 1, OPT_FORCE_DPD),
160 OPTION("non-inter", 0, OPT_NON_INTER),
164 static void helpmessage(void)
166 printf(_("For assistance with OpenConnect, please see the web page at\n"
167 " http://www.infradead.org/openconnect/mail.html\n"));
170 static void usage(void)
172 printf(_("Usage: openconnect [options] <server>\n"));
173 printf(_("Open client for Cisco AnyConnect VPN, version %s\n\n"), openconnect_version);
174 printf(" --config=CONFIGFILE %s\n", _("Read options from config file"));
175 printf(" -b, --background %s\n", _("Continue in background after startup"));
176 printf(" --pid-file=PIDFILE %s\n", _("Write the daemons pid to this file"));
177 printf(" -c, --certificate=CERT %s\n", _("Use SSL client certificate CERT"));
178 printf(" -e, --cert-expire-warning=DAYS %s\n", _("Warn when certificate lifetime < DAYS"));
179 printf(" -k, --sslkey=KEY %s\n", _("Use SSL private key file KEY"));
180 printf(" -K, --key-type=TYPE %s\n", _("Private key type (PKCS#12 / TPM / PEM)"));
181 printf(" -C, --cookie=COOKIE %s\n", _("Use WebVPN cookie COOKIE"));
182 printf(" --cookie-on-stdin %s\n", _("Read cookie from standard input"));
183 printf(" -d, --deflate %s\n", _("Enable compression (default)"));
184 printf(" -D, --no-deflate %s\n", _("Disable compression"));
185 printf(" --force-dpd=INTERVAL %s\n", _("Set minimum Dead Peer Detection interval"));
186 printf(" -g, --usergroup=GROUP %s\n", _("Set login usergroup"));
187 printf(" -h, --help %s\n", _("Display help text"));
188 printf(" -i, --interface=IFNAME %s\n", _("Use IFNAME for tunnel interface"));
189 printf(" -l, --syslog %s\n", _("Use syslog for progress messages"));
190 printf(" -U, --setuid=USER %s\n", _("Drop privileges after connecting"));
191 printf(" --csd-user=USER %s\n", _("Drop privileges during CSD execution"));
192 printf(" --csd-wrapper=SCRIPT %s\n", _("Run SCRIPT instead of CSD binary"));
193 printf(" -m, --mtu=MTU %s\n", _("Request MTU from server"));
194 printf(" -p, --key-password=PASS %s\n", _("Set key passphrase or TPM SRK PIN"));
195 printf(" --key-password-from-fsid %s\n", _("Key passphrase is fsid of file system"));
196 printf(" -P, --proxy=URL %s\n", _("Set proxy server"));
197 printf(" --no-proxy %s\n", _("Disable proxy"));
198 printf(" --libproxy %s\n", _("Use libproxy to automatically configure proxy"));
200 printf(" %s\n", _("(NOTE: libproxy disabled in this build)"));
202 printf(" -q, --quiet %s\n", _("Less output"));
203 printf(" -Q, --queue-len=LEN %s\n", _("Set packet queue limit to LEN pkts"));
204 printf(" -s, --script=SCRIPT %s\n", _("Shell command line for using a vpnc-compatible config script"));
205 printf(" %s: \"%s\"\n", _("default"), DEFAULT_VPNCSCRIPT);
206 printf(" -S, --script-tun %s\n", _("Pass traffic to 'script' program, not tun"));
207 printf(" -u, --user=NAME %s\n", _("Set login username"));
208 printf(" -V, --version %s\n", _("Report version number"));
209 printf(" -v, --verbose %s\n", _("More output"));
210 printf(" -x, --xmlconfig=CONFIG %s\n", _("XML config file"));
211 printf(" --authgroup=GROUP %s\n", _("Choose authentication login selection"));
212 printf(" --cookieonly %s\n", _("Fetch webvpn cookie only; don't connect"));
213 printf(" --printcookie %s\n", _("Print webvpn cookie before connecting"));
214 printf(" --cafile=FILE %s\n", _("Cert file for server verification"));
215 printf(" --disable-ipv6 %s\n", _("Do not ask for IPv6 connectivity"));
216 printf(" --dtls-ciphers=LIST %s\n", _("OpenSSL ciphers to support for DTLS"));
217 printf(" --no-dtls %s\n", _("Disable DTLS"));
218 printf(" --no-http-keepalive %s\n", _("Disable HTTP connection re-use"));
219 printf(" --no-passwd %s\n", _("Disable password/SecurID authentication"));
220 printf(" --no-cert-check %s\n", _("Do not require server SSL cert to be valid"));
221 printf(" --non-inter %s\n", _("Do not expect user input; exit if it is required"));
222 printf(" --passwd-on-stdin %s\n", _("Read password from standard input"));
223 printf(" --reconnect-timeout %s\n", _("Connection retry timeout in seconds"));
224 printf(" --servercert=FINGERPRINT %s\n", _("Server's certificate SHA1 fingerprint"));
225 printf(" --useragent=STRING %s\n", _("HTTP header User-Agent: field"));
232 static void read_stdin(char **string)
234 char *c = malloc(100);
236 fprintf(stderr, _("Allocation failure for string from stdin\n"));
239 if (!fgets(c, 100, stdin)) {
240 perror(_("fgets (stdin)"));
246 c = strchr(*string, '\n');
250 static void handle_sigusr(int sig)
254 else if (sig == SIGUSR2)
258 static FILE *config_file = NULL;
259 static int config_line_num = 0;
261 #define keep_config_arg() (config_arg)
263 static int next_option(int argc, char **argv, char **config_arg)
265 /* These get re-used */
266 static char *line_buf = NULL;
267 static size_t line_size = 0;
277 opt = getopt_long(argc, argv,
278 "bC:c:e:Ddg:hi:k:K:lpP:Q:qSs:U:u:Vvx:",
281 *config_arg = optarg;
285 llen = getline(&line_buf, &line_size, config_file);
287 if (feof(config_file)) {
292 fprintf(stderr, _("Failed to get line from config file: %s\n"),
298 /* Strip the trailing newline (coping with DOS newlines) */
299 if (llen && line[llen-1] == '\n')
301 if (llen && line[llen-1] == '\r')
304 /* Skip and leading whitespace */
305 while (line[0] == ' ' || line[0] == '\t' || line[0] == '\r')
308 /* Ignore comments and empty lines */
309 if (!line[0] || line[0] == '#') {
314 /* Try to match on a known option... naïvely. This could be improved. */
315 for (this = long_options; this->name; this++) {
316 optlen = strlen(this->name);
317 /* If the option isn't followed by whitespace or NUL, or
318 perhaps an equals sign if the option takes an argument,
319 then it's not a match */
320 if (!strncmp(this->name, line, optlen) &&
321 (!line[optlen] || line[optlen] == ' ' || line[optlen] == '\t' ||
322 line[optlen] == '='))
328 for (l = line; *l && *l != ' ' && *l != '\t'; l++)
332 fprintf(stderr, _("Unrecognised option at line %d: '%s'\n"),
333 config_line_num, line);
337 while (*line == ' ' || *line == '\t' ||
338 (*line == '=' && this->has_arg && !ate_equals && ++ate_equals))
341 if (!this->has_arg && *line) {
342 fprintf(stderr, _("Option '%s' does not take an argument at line %d\n"),
343 this->name, config_line_num);
345 } else if (this->has_arg && !*line) {
346 fprintf(stderr, _("Option '%s' requires an argument at line %d\n"),
347 this->name, config_line_num);
357 int main(int argc, char **argv)
359 struct openconnect_info *vpninfo;
360 struct utsname utsbuf;
364 char *proxy = getenv("https_proxy");
366 uid_t uid = getuid();
368 char *pidfile = NULL;
373 bindtextdomain("openconnect", LOCALEDIR);
374 setlocale(LC_ALL, "");
377 if (strcmp(openconnect_version, openconnect_binary_version)) {
378 fprintf(stderr, _("WARNING: This version of openconnect is %s but\n"
379 " the libopenconnect library is %s\n"),
380 openconnect_binary_version, openconnect_version);
383 openconnect_init_openssl();
385 vpninfo = malloc(sizeof(*vpninfo));
387 fprintf(stderr, _("Failed to allocate vpninfo structure\n"));
390 memset(vpninfo, 0, sizeof(*vpninfo));
392 /* Set up some defaults */
393 vpninfo->tun_fd = vpninfo->ssl_fd = vpninfo->dtls_fd = vpninfo->new_dtls_fd = -1;
394 vpninfo->useragent = openconnect_create_useragent("Open AnyConnect VPN Agent");
396 vpninfo->deflate = 1;
397 vpninfo->dtls_attempt_period = 60;
398 vpninfo->max_qlen = 10;
399 vpninfo->reconnect_interval = RECONNECT_INTERVAL_MIN;
400 vpninfo->reconnect_timeout = 300;
401 vpninfo->uid_csd = 0;
402 vpninfo->uid_csd_given = 0;
403 vpninfo->validate_peer_cert = validate_peer_cert;
404 vpninfo->cbdata = vpninfo;
405 vpninfo->cert_expire_warning = 60 * 86400;
406 vpninfo->vpnc_script = DEFAULT_VPNCSCRIPT;
407 vpninfo->cancel_fd = -1;
410 vpninfo->localname = utsbuf.nodename;
412 vpninfo->localname = "localhost";
414 while ((opt = next_option(argc, argv, &config_arg))) {
422 fprintf(stderr, _("Cannot use 'config' option inside config file\n"));
425 config_file = fopen(config_arg, "r");
427 fprintf(stderr, _("Cannot open config file '%s': %s\n"),
428 config_arg, strerror(errno));
432 /* The next option will come from the file... */
435 vpninfo->cafile = keep_config_arg();
438 pidfile = keep_config_arg();
441 vpninfo->servercert = keep_config_arg();
444 vpninfo->dtls_attempt_period = 0;
449 case OPT_PRINTCOOKIE:
452 case OPT_COOKIE_ON_STDIN:
453 read_stdin(&vpninfo->cookie);
454 /* If the cookie is empty, ignore it */
455 if (! *vpninfo->cookie) {
456 vpninfo->cookie = NULL;
459 case OPT_PASSWORD_ON_STDIN:
460 read_stdin(&vpninfo->password);
463 vpninfo->nopasswd = 1;
467 vpninfo->nopasswd = 1;
469 case OPT_RECONNECT_TIMEOUT:
470 vpninfo->reconnect_timeout = atoi(config_arg);
472 case OPT_DTLS_CIPHERS:
473 vpninfo->dtls_ciphers = keep_config_arg();
476 vpninfo->authgroup = keep_config_arg();
482 vpninfo->cookie = keep_config_arg();
485 vpninfo->cert = keep_config_arg();
488 vpninfo->cert_expire_warning = 86400 * atoi(config_arg);
491 vpninfo->sslkey = keep_config_arg();
494 if (!strcasecmp(config_arg, "PKCS#12") ||
495 !strcasecmp(config_arg, "PKCS12")) {
496 vpninfo->cert_type = CERT_TYPE_PKCS12;
497 } else if (!strcasecmp(config_arg, "TPM")) {
498 vpninfo->cert_type = CERT_TYPE_TPM;
499 } else if (!strcasecmp(config_arg, "PEM")) {
500 vpninfo->cert_type = CERT_TYPE_PEM;
502 fprintf(stderr, _("Unknown certificate type '%s'\n"),
507 vpninfo->deflate = 1;
510 vpninfo->deflate = 0;
513 free(vpninfo->urlpath);
514 vpninfo->urlpath = strdup(config_arg);
519 vpninfo->ifname = keep_config_arg();
525 vpninfo->mtu = atol(config_arg);
526 if (vpninfo->mtu < 576) {
527 fprintf(stderr, _("MTU %d too small\n"), vpninfo->mtu);
532 vpninfo->cert_password = keep_config_arg();
535 proxy = keep_config_arg();
545 case OPT_NO_HTTP_KEEPALIVE:
547 _("Disabling all HTTP connection re-use due to --no-http-keepalive option.\n"
548 "If this helps, please report to <openconnect-devel@lists.infradead.org>.\n"));
549 vpninfo->no_http_keepalive = 1;
551 case OPT_NO_CERT_CHECK:
555 vpninfo->vpnc_script = keep_config_arg();
558 vpninfo->script_tun = 1;
561 vpninfo->username = keep_config_arg();
565 uid = strtol(config_arg, &strend, 0);
567 struct passwd *pw = getpwnam(config_arg);
569 fprintf(stderr, _("Invalid user \"%s\"\n"),
579 vpninfo->uid_csd = strtol(config_arg, &strend, 0);
581 struct passwd *pw = getpwnam(config_arg);
583 fprintf(stderr, _("Invalid user \"%s\"\n"),
587 vpninfo->uid_csd = pw->pw_uid;
589 vpninfo->uid_csd_given = 1;
592 case OPT_CSD_WRAPPER:
593 vpninfo->csd_wrapper = keep_config_arg();
595 case OPT_DISABLE_IPV6:
596 vpninfo->disable_ipv6 = 1;
599 vpninfo->max_qlen = atol(config_arg);
600 if (!vpninfo->max_qlen) {
601 fprintf(stderr, _("Queue length zero not permitted; using 1\n"));
602 vpninfo->max_qlen = 1;
612 printf(_("OpenConnect version %s\n"), openconnect_version);
615 vpninfo->xmlconfig = keep_config_arg();
616 vpninfo->write_new_config = write_new_config;
618 case OPT_KEY_PASSWORD_FROM_FSID:
619 do_passphrase_from_fsid = 1;
622 free(vpninfo->useragent);
623 vpninfo->useragent = strdup(config_arg);
626 vpninfo->dtls_times.dpd = vpninfo->ssl_times.dpd = atoi(config_arg);
633 if (optind != argc - 1) {
634 fprintf(stderr, _("No server specified\n"));
638 if (!vpninfo->sslkey)
639 vpninfo->sslkey = vpninfo->cert;
641 vpninfo->progress = write_progress;
645 vpninfo->proxy_factory = px_proxy_factory_new();
647 fprintf(stderr, _("This version of openconnect was built without libproxy support\n"));
652 if (proxy && openconnect_set_http_proxy(vpninfo, strdup(proxy)))
657 openlog("openconnect", LOG_PID, LOG_DAEMON);
659 vpninfo->progress = syslog_progress;
662 memset(&sa, 0, sizeof(sa));
663 sa.sa_handler = handle_sigusr;
665 sigaction(SIGUSR1, &sa, NULL);
666 sigaction(SIGUSR2, &sa, NULL);
668 if (vpninfo->sslkey && do_passphrase_from_fsid)
669 openconnect_passphrase_from_fsid(vpninfo);
671 if (config_lookup_host(vpninfo, argv[optind]))
674 if (!vpninfo->hostname) {
675 char *url = strdup(argv[optind]);
679 if (internal_parse_url(url, &scheme, &vpninfo->hostname, &vpninfo->port,
681 fprintf(stderr, _("Failed to parse server URL '%s'\n"),
685 if (scheme && strcmp(scheme, "https")) {
686 fprintf(stderr, _("Only https:// permitted for server URL\n"));
690 free(vpninfo->urlpath);
691 vpninfo->urlpath = group;
701 if (!vpninfo->cookie && openconnect_obtain_cookie(vpninfo)) {
702 fprintf(stderr, _("Failed to obtain WebVPN cookie\n"));
707 printf("%s\n", vpninfo->cookie);
709 /* We use cookieonly=2 for 'print it and continue' */
712 if (make_cstp_connection(vpninfo)) {
713 fprintf(stderr, _("Creating SSL connection failed\n"));
717 if (setup_tun(vpninfo)) {
718 fprintf(stderr, _("Set up tun device failed\n"));
722 if (uid != getuid()) {
724 fprintf(stderr, _("Failed to set uid %ld\n"),
730 if (vpninfo->dtls_attempt_period && setup_dtls(vpninfo))
731 fprintf(stderr, _("Set up DTLS failed; using SSL instead\n"));
733 vpn_progress(vpninfo, PRG_INFO,
734 _("Connected %s as %s%s%s, using %s\n"), vpninfo->ifname,
735 vpninfo->vpn_addr?:"",
736 (vpninfo->vpn_addr6 && vpninfo->vpn_addr)?" + ":"",
737 vpninfo->vpn_addr6?:"",
738 (vpninfo->dtls_fd == -1) ?
739 (vpninfo->deflate ? "SSL + deflate" : "SSL")
742 if (!vpninfo->vpnc_script) {
743 vpn_progress(vpninfo, PRG_INFO,
744 _("No --script argument provided; DNS and routing are not configured\n"));
745 vpn_progress(vpninfo, PRG_INFO,
746 _("See http://www.infradead.org/openconnect/vpnc-script.html\n"));
752 /* Open the pidfile before forking, so we can report errors
753 more sanely. It's *possible* that we'll fail to write to
754 it, but very unlikely. */
755 if (pidfile != NULL) {
756 fp = fopen(pidfile, "w");
758 fprintf(stderr, _("Failed to open '%s' for write: %s\n"),
759 pidfile, strerror(errno));
763 if ((pid = fork())) {
765 fprintf(fp, "%d\n", pid);
768 vpn_progress(vpninfo, PRG_INFO,
769 _("Continuing in background; pid %d\n"),
776 vpn_mainloop(vpninfo);
782 static int write_new_config(void *_vpninfo, char *buf, int buflen)
784 struct openconnect_info *vpninfo = _vpninfo;
788 config_fd = open(vpninfo->xmlconfig, O_WRONLY|O_TRUNC|O_CREAT, 0644);
791 fprintf(stderr, _("Failed to open %s for write: %s\n"),
792 vpninfo->xmlconfig, strerror(err));
796 /* FIXME: We should actually write to a new tempfile, then rename */
797 if(write(config_fd, buf, buflen) != buflen) {
799 fprintf(stderr, _("Failed to write config to %s: %s\n"),
800 vpninfo->xmlconfig, strerror(err));
808 void write_progress(void *_vpninfo, int level, const char *fmt, ...)
810 FILE *outf = level ? stdout : stderr;
813 if (verbose >= level) {
815 vfprintf(outf, fmt, args);
822 void syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
825 ANDROID_LOG_ERROR, /* PRG_ERR */
826 ANDROID_LOG_INFO, /* PRG_INFO */
827 ANDROID_LOG_DEBUG, /* PRG_DEBUG */
828 ANDROID_LOG_DEBUG /* PRG_TRACE */
832 if (verbose >= level) {
834 va_copy(args2, args);
835 __android_log_vprint(l[level], "openconnect", fmt, args);
836 /* Android wants it to stderr too, so the GUI can scrape
837 it and display it as well as going to syslog */
838 vfprintf(stderr, fmt, args2);
844 void syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
846 int priority = level ? LOG_INFO : LOG_NOTICE;
849 if (verbose >= level) {
851 vsyslog(priority, fmt, args);
857 struct accepted_cert {
858 struct accepted_cert *next;
859 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
863 static int validate_peer_cert(void *_vpninfo, X509 *peer_cert,
866 struct openconnect_info *vpninfo = _vpninfo;
867 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
868 struct accepted_cert *this;
874 ret = openconnect_get_cert_sha1(vpninfo, peer_cert, fingerprint);
878 for (this = accepted_certs; this; this = this->next) {
879 if (!strcasecmp(this->host, vpninfo->hostname) &&
880 !strcasecmp(this->fingerprint, fingerprint))
890 _("\nCertificate from VPN server \"%s\" failed verification.\n"
891 "Reason: %s\n"), vpninfo->hostname, reason);
898 UI_add_input_string(ui, _("Enter 'yes' to accept, 'no' to abort; anything else to view: "),
899 UI_INPUT_FLAG_ECHO, buf, 2, 5);
900 ret = UI_process(ui);
907 if (!strcasecmp(buf, _("yes"))) {
908 struct accepted_cert *newcert = malloc(sizeof(*newcert) +
909 strlen(vpninfo->hostname) + 1);
911 newcert->next = accepted_certs;
912 accepted_certs = newcert;
913 strcpy(newcert->fingerprint, fingerprint);
914 strcpy(newcert->host, vpninfo->hostname);
918 if (!strcasecmp(buf, _("no")))
921 X509_print_fp(stderr, peer_cert);
922 fprintf(stderr, _("SHA1 fingerprint: %s\n"), fingerprint);