library.c 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754
  1. /*
  2. * OpenConnect (SSL + DTLS) VPN client
  3. *
  4. * Copyright © 2008-2015 Intel Corporation.
  5. * Copyright © 2013 John Morrissey <jwm@horde.net>
  6. *
  7. * Authors: David Woodhouse <dwmw2@infradead.org>
  8. *
  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.
  12. *
  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.
  17. */
  18. #include <config.h>
  19. #include "openconnect-internal.h"
  20. #if defined(OPENCONNECT_GNUTLS)
  21. #include "gnutls.h"
  22. #endif
  23. #ifdef HAVE_LIBSTOKEN
  24. #include <stoken.h>
  25. #endif
  26. #include <libxml/tree.h>
  27. #include <zlib.h>
  28. #if defined(OPENCONNECT_OPENSSL)
  29. #include <openssl/bio.h>
  30. #endif
  31. #include <unistd.h>
  32. #include <fcntl.h>
  33. #include <string.h>
  34. #include <errno.h>
  35. #include <stdlib.h>
  36. #include <ctype.h>
  37. struct openconnect_info *openconnect_vpninfo_new(const char *useragent,
  38. openconnect_validate_peer_cert_vfn validate_peer_cert,
  39. openconnect_write_new_config_vfn write_new_config,
  40. openconnect_process_auth_form_vfn process_auth_form,
  41. openconnect_progress_vfn progress,
  42. void *privdata)
  43. {
  44. struct openconnect_info *vpninfo = calloc(sizeof(*vpninfo), 1);
  45. #ifdef HAVE_ICONV
  46. char *charset = nl_langinfo(CODESET);
  47. #endif
  48. if (!vpninfo)
  49. return NULL;
  50. #ifdef HAVE_ICONV
  51. if (charset && strcmp(charset, "UTF-8")) {
  52. vpninfo->ic_utf8_to_legacy = iconv_open(charset, "UTF-8");
  53. vpninfo->ic_legacy_to_utf8 = iconv_open("UTF-8", charset);
  54. } else {
  55. vpninfo->ic_utf8_to_legacy = (iconv_t)-1;
  56. vpninfo->ic_legacy_to_utf8 = (iconv_t)-1;
  57. }
  58. #endif
  59. #ifdef HAVE_VHOST
  60. vpninfo->vhost_fd = vpninfo->vhost_call_fd = vpninfo->vhost_kick_fd = -1;
  61. #endif
  62. #ifndef _WIN32
  63. vpninfo->tun_fd = -1;
  64. #endif
  65. init_pkt_queue(&vpninfo->free_queue);
  66. init_pkt_queue(&vpninfo->incoming_queue);
  67. init_pkt_queue(&vpninfo->outgoing_queue);
  68. init_pkt_queue(&vpninfo->tcp_control_queue);
  69. vpninfo->dtls_tos_current = 0;
  70. vpninfo->dtls_pass_tos = 0;
  71. vpninfo->ssl_fd = vpninfo->dtls_fd = -1;
  72. vpninfo->cmd_fd = vpninfo->cmd_fd_write = -1;
  73. vpninfo->tncc_fd = -1;
  74. vpninfo->cert_expire_warning = 60 * 86400;
  75. vpninfo->req_compr = COMPR_STATELESS;
  76. vpninfo->max_qlen = 10;
  77. vpninfo->localname = strdup("localhost");
  78. vpninfo->port = 443;
  79. vpninfo->useragent = openconnect_create_useragent(useragent);
  80. vpninfo->validate_peer_cert = validate_peer_cert;
  81. vpninfo->write_new_config = write_new_config;
  82. vpninfo->process_auth_form = process_auth_form;
  83. vpninfo->progress = progress;
  84. vpninfo->cbdata = privdata ? : vpninfo;
  85. vpninfo->xmlpost = 1;
  86. vpninfo->verbose = PRG_TRACE;
  87. vpninfo->try_http_auth = 1;
  88. vpninfo->proxy_auth[AUTH_TYPE_BASIC].state = AUTH_DEFAULT_DISABLED;
  89. vpninfo->http_auth[AUTH_TYPE_BASIC].state = AUTH_DEFAULT_DISABLED;
  90. openconnect_set_reported_os(vpninfo, NULL);
  91. #ifdef HAVE_EPOLL
  92. vpninfo->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
  93. #endif
  94. if (!vpninfo->localname || !vpninfo->useragent)
  95. goto err;
  96. #ifdef ENABLE_NLS
  97. bindtextdomain("openconnect", LOCALEDIR);
  98. #endif
  99. openconnect_set_protocol(vpninfo, "anyconnect");
  100. return vpninfo;
  101. err:
  102. free(vpninfo->localname);
  103. free(vpninfo->useragent);
  104. free(vpninfo);
  105. return NULL;
  106. }
  107. static const struct vpn_proto openconnect_protos[] = {
  108. {
  109. .name = "anyconnect",
  110. .pretty_name = N_("Cisco AnyConnect or OpenConnect"),
  111. .description = N_("Compatible with Cisco AnyConnect SSL VPN, as well as ocserv"),
  112. .proto = PROTO_ANYCONNECT,
  113. .flags = OC_PROTO_PROXY | OC_PROTO_CSD | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN | OC_PROTO_AUTH_MCA,
  114. .vpn_close_session = cstp_bye,
  115. .tcp_connect = cstp_connect,
  116. .tcp_mainloop = cstp_mainloop,
  117. .add_http_headers = cstp_common_headers,
  118. .obtain_cookie = cstp_obtain_cookie,
  119. .sso_detect_done = cstp_sso_detect_done,
  120. .secure_cookie = "webvpn",
  121. .udp_protocol = "DTLS",
  122. #ifdef HAVE_DTLS
  123. .udp_setup = dtls_setup,
  124. .udp_mainloop = dtls_mainloop,
  125. .udp_close = dtls_close,
  126. .udp_shutdown = dtls_shutdown,
  127. #endif
  128. }, {
  129. .name = "nc",
  130. .pretty_name = N_("Juniper Network Connect"),
  131. .description = N_("Compatible with Juniper Network Connect"),
  132. .proto = PROTO_NC,
  133. .flags = OC_PROTO_PROXY | OC_PROTO_CSD | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN | OC_PROTO_PERIODIC_TROJAN,
  134. .vpn_close_session = oncp_bye,
  135. .tcp_connect = oncp_connect,
  136. .tcp_mainloop = oncp_mainloop,
  137. .add_http_headers = oncp_common_headers,
  138. .obtain_cookie = oncp_obtain_cookie,
  139. .secure_cookie = "DSID",
  140. .udp_protocol = "ESP",
  141. #ifdef HAVE_ESP
  142. .udp_setup = esp_setup,
  143. .udp_mainloop = esp_mainloop,
  144. .udp_close = oncp_esp_close,
  145. .udp_shutdown = esp_shutdown,
  146. .udp_send_probes = oncp_esp_send_probes,
  147. .udp_catch_probe = oncp_esp_catch_probe,
  148. #endif
  149. }, {
  150. .name = "gp",
  151. .pretty_name = N_("Palo Alto Networks GlobalProtect"),
  152. .description = N_("Compatible with Palo Alto Networks (PAN) GlobalProtect SSL VPN"),
  153. .proto = PROTO_GPST,
  154. .flags = OC_PROTO_PROXY | OC_PROTO_CSD | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN | OC_PROTO_PERIODIC_TROJAN,
  155. .vpn_close_session = gpst_bye,
  156. .tcp_connect = gpst_setup,
  157. .tcp_mainloop = gpst_mainloop,
  158. .add_http_headers = gpst_common_headers,
  159. .obtain_cookie = gpst_obtain_cookie,
  160. .sso_detect_done = gpst_sso_detect_done,
  161. .udp_protocol = "ESP",
  162. #ifdef HAVE_ESP
  163. .udp_setup = esp_setup,
  164. .udp_mainloop = esp_mainloop,
  165. .udp_close = esp_close,
  166. .udp_shutdown = esp_shutdown,
  167. .udp_send_probes = gpst_esp_send_probes,
  168. .udp_catch_probe = gpst_esp_catch_probe,
  169. #endif
  170. }, {
  171. .name = "pulse",
  172. .pretty_name = N_("Pulse Connect Secure"),
  173. .description = N_("Compatible with Pulse Connect Secure SSL VPN"),
  174. .proto = PROTO_PULSE,
  175. .flags = OC_PROTO_PROXY | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN,
  176. .vpn_close_session = pulse_bye,
  177. .tcp_connect = pulse_connect,
  178. .tcp_mainloop = pulse_mainloop,
  179. .add_http_headers = http_common_headers,
  180. .obtain_cookie = pulse_obtain_cookie,
  181. .udp_protocol = "ESP",
  182. #ifdef HAVE_ESP
  183. .udp_setup = esp_setup,
  184. .udp_mainloop = esp_mainloop,
  185. .udp_close = esp_close,
  186. .udp_shutdown = esp_shutdown,
  187. .udp_send_probes = oncp_esp_send_probes,
  188. .udp_catch_probe = oncp_esp_catch_probe,
  189. #endif
  190. }, {
  191. .name = "f5",
  192. .pretty_name = N_("F5 BIG-IP SSL VPN"),
  193. .description = N_("Compatible with F5 BIG-IP SSL VPN"),
  194. .proto = PROTO_F5,
  195. .flags = OC_PROTO_PROXY | OC_PROTO_AUTH_CERT,
  196. .vpn_close_session = f5_bye,
  197. .tcp_connect = f5_connect,
  198. .tcp_mainloop = ppp_tcp_mainloop,
  199. .add_http_headers = http_common_headers,
  200. .obtain_cookie = f5_obtain_cookie,
  201. .secure_cookie = "MRHSession",
  202. .udp_protocol = "DTLS",
  203. #ifdef HAVE_DTLS
  204. .udp_setup = dtls_setup,
  205. .udp_mainloop = ppp_udp_mainloop,
  206. .udp_close = dtls_close,
  207. .udp_shutdown = dtls_shutdown,
  208. .udp_catch_probe = f5_dtls_catch_probe,
  209. #endif
  210. }, {
  211. .name = "fortinet",
  212. .pretty_name = N_("Fortinet SSL VPN"),
  213. .description = N_("Compatible with FortiGate SSL VPN"),
  214. .proto = PROTO_FORTINET,
  215. .flags = OC_PROTO_PROXY | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN,
  216. .vpn_close_session = fortinet_bye,
  217. .tcp_connect = fortinet_connect,
  218. .tcp_mainloop = ppp_tcp_mainloop,
  219. .add_http_headers = fortinet_common_headers,
  220. .obtain_cookie = fortinet_obtain_cookie,
  221. .secure_cookie = "SVPNCOOKIE",
  222. .udp_protocol = "DTLS",
  223. #ifdef HAVE_DTLS
  224. .udp_setup = dtls_setup,
  225. .udp_mainloop = ppp_udp_mainloop,
  226. .udp_close = dtls_close,
  227. .udp_shutdown = dtls_shutdown,
  228. .udp_catch_probe = fortinet_dtls_catch_svrhello,
  229. #endif
  230. }, {
  231. .name = "nullppp",
  232. .pretty_name = N_("PPP over TLS"),
  233. .description = N_("Unauthenticated RFC1661/RFC1662 PPP over TLS, for testing"),
  234. .proto = PROTO_NULLPPP,
  235. .flags = OC_PROTO_PROXY | OC_PROTO_HIDDEN,
  236. .tcp_connect = nullppp_connect,
  237. .tcp_mainloop = nullppp_mainloop,
  238. .add_http_headers = http_common_headers,
  239. .obtain_cookie = nullppp_obtain_cookie,
  240. }, {
  241. .name = "array",
  242. .pretty_name = N_("Array SSL VPN"),
  243. .description = N_("Compatible with Array Networks SSL VPN"),
  244. .proto = PROTO_ARRAY,
  245. .flags = OC_PROTO_PROXY,
  246. .vpn_close_session = array_bye,
  247. .tcp_connect = array_connect,
  248. .tcp_mainloop = array_mainloop,
  249. .add_http_headers = http_common_headers,
  250. .obtain_cookie = array_obtain_cookie,
  251. .udp_protocol = "DTLS",
  252. #ifdef HAVE_DTLS
  253. .udp_setup = dtls_setup,
  254. .udp_mainloop = array_dtls_mainloop,
  255. .udp_close = dtls_close,
  256. .udp_shutdown = dtls_shutdown,
  257. #endif
  258. }, {
  259. .name = "h3c",
  260. .pretty_name = N_("H3C TLS VPN"),
  261. .description = N_("H3C TLS VPN compatible with iNode SSL VPN client"),
  262. .proto = PROTO_H3C,
  263. .flags = 0, /* do we need this? */
  264. .vpn_close_session = h3c_bye,
  265. .tcp_connect = h3c_connect,
  266. .tcp_mainloop = h3c_mainloop,
  267. .add_http_headers = h3c_http_headers,
  268. .obtain_cookie = h3c_obtain_cookie,
  269. },
  270. };
  271. #define NR_PROTOS ARRAY_SIZE(openconnect_protos)
  272. int openconnect_get_supported_protocols(struct oc_vpn_proto **protos)
  273. {
  274. struct oc_vpn_proto *pr;
  275. int i, j;
  276. /* The original version of this function included an all-zero
  277. * sentinel value at the end of the array, so we must continue
  278. * to do so for ABI compatibility even though it's
  279. * functionally redundant as a marker of the array's length,
  280. * along with the explicit length in the return value.
  281. */
  282. *protos = pr = calloc(NR_PROTOS + 1, sizeof(*pr));
  283. if (!pr)
  284. return -ENOMEM;
  285. for (i = j = 0; i < NR_PROTOS; i++) {
  286. if (!(openconnect_protos[i].flags & OC_PROTO_HIDDEN)) {
  287. pr[j].name = openconnect_protos[i].name;
  288. pr[j].pretty_name = _(openconnect_protos[i].pretty_name);
  289. pr[j].description = _(openconnect_protos[i].description);
  290. pr[j].flags = openconnect_protos[i].flags;
  291. j++;
  292. }
  293. }
  294. return j;
  295. }
  296. void openconnect_free_supported_protocols(struct oc_vpn_proto *protos)
  297. {
  298. free((void *)protos);
  299. }
  300. const char *openconnect_get_protocol(struct openconnect_info *vpninfo)
  301. {
  302. return vpninfo->proto->name;
  303. }
  304. int openconnect_set_protocol(struct openconnect_info *vpninfo, const char *protocol)
  305. {
  306. const struct vpn_proto *p;
  307. int i;
  308. for (i = 0; i < NR_PROTOS; i++) {
  309. p = &openconnect_protos[i];
  310. if (strcasecmp(p->name, protocol))
  311. continue;
  312. vpninfo->proto = p;
  313. if (!p->udp_setup)
  314. vpninfo->dtls_state = DTLS_DISABLED;
  315. return 0;
  316. }
  317. vpn_progress(vpninfo, PRG_ERR,
  318. _("Unknown VPN protocol '%s'\n"), protocol);
  319. return -EINVAL;
  320. }
  321. void openconnect_set_pass_tos(struct openconnect_info *vpninfo, int enable)
  322. {
  323. vpninfo->dtls_pass_tos = enable;
  324. }
  325. void openconnect_set_loglevel(struct openconnect_info *vpninfo, int level)
  326. {
  327. vpninfo->verbose = level;
  328. }
  329. int openconnect_setup_dtls(struct openconnect_info *vpninfo,
  330. int attempt_period)
  331. {
  332. vpninfo->dtls_attempt_period = attempt_period;
  333. if (vpninfo->proto->udp_setup)
  334. return vpninfo->proto->udp_setup(vpninfo);
  335. vpn_progress(vpninfo, PRG_ERR,
  336. _("Built against SSL library with no Cisco DTLS support\n"));
  337. return -EINVAL;
  338. }
  339. int openconnect_obtain_cookie(struct openconnect_info *vpninfo)
  340. {
  341. #ifdef HAVE_LIBSTOKEN
  342. int ret;
  343. if (vpninfo->token_mode == OC_TOKEN_MODE_STOKEN) {
  344. ret = prepare_stoken(vpninfo);
  345. if (ret)
  346. return ret;
  347. }
  348. #endif
  349. return vpninfo->proto->obtain_cookie(vpninfo);
  350. }
  351. int openconnect_make_cstp_connection(struct openconnect_info *vpninfo)
  352. {
  353. int result = vpninfo->proto->tcp_connect(vpninfo);
  354. /* ssl_times.last_tx should be set to show that a connection has been setup */
  355. if (result == 0 && vpninfo->ssl_times.last_tx == 0)
  356. vpninfo->ssl_times.last_tx = time(NULL);
  357. return result;
  358. }
  359. int openconnect_set_reported_os(struct openconnect_info *vpninfo,
  360. const char *os)
  361. {
  362. static const char * const allowed[] = {"linux", "linux-64", "win", "mac-intel", "android", "apple-ios"};
  363. if (!os) {
  364. #if defined(__APPLE__)
  365. # include <TargetConditionals.h>
  366. # if TARGET_OS_IOS
  367. /* We need to use Apple's boolean "target" defines to distinguish iOS from
  368. * desktop MacOS. See https://stackoverflow.com/a/5920028 and
  369. * https://github.com/mstg/iOS-full-sdk/blob/master/iPhoneOS9.3.sdk/usr/include/TargetConditionals.h#L64-L71
  370. */
  371. os = "apple-ios";
  372. # else
  373. os = "mac-intel";
  374. # endif
  375. #elif defined(__ANDROID__)
  376. os = "android";
  377. #elif defined(_WIN32)
  378. os = "win";
  379. #else
  380. os = sizeof(long) > 4 ? "linux-64" : "linux";
  381. #endif
  382. }
  383. for (int i = 0; i < ARRAY_SIZE(allowed); i++) {
  384. if (!strcmp(os, allowed[i])) {
  385. STRDUP(vpninfo->platname, os);
  386. return 0;
  387. }
  388. }
  389. return -EINVAL;
  390. }
  391. int openconnect_set_mobile_info(struct openconnect_info *vpninfo,
  392. const char *mobile_platform_version,
  393. const char *mobile_device_type,
  394. const char *mobile_device_uniqueid)
  395. {
  396. STRDUP(vpninfo->mobile_platform_version, mobile_platform_version);
  397. STRDUP(vpninfo->mobile_device_type, mobile_device_type);
  398. STRDUP(vpninfo->mobile_device_uniqueid, mobile_device_uniqueid);
  399. return 0;
  400. }
  401. int openconnect_set_version_string(struct openconnect_info *vpninfo,
  402. const char *version_string)
  403. {
  404. STRDUP(vpninfo->version_string, version_string);
  405. return 0;
  406. }
  407. const char *add_option_dup(struct oc_vpn_option **list,
  408. const char *opt,
  409. const char *val, int val_len)
  410. {
  411. const char *ret;
  412. char *new_val;
  413. if (val_len >= 0)
  414. new_val = strndup(val, val_len);
  415. else
  416. new_val = strdup(val);
  417. ret = add_option_steal(list, opt, &new_val);
  418. free(new_val);
  419. return ret;
  420. }
  421. const char *add_option_steal(struct oc_vpn_option **list,
  422. const char *opt, char **val)
  423. {
  424. struct oc_vpn_option *new = malloc(sizeof(*new));
  425. if (!new)
  426. return NULL;
  427. new->option = strdup(opt);
  428. if (!new->option) {
  429. free(new);
  430. return NULL;
  431. }
  432. new->value = *val;
  433. *val = NULL;
  434. new->next = *list;
  435. *list = new;
  436. return new->value;
  437. }
  438. const char *add_option_ipaddr(struct oc_vpn_option **list,
  439. const char *opt, int af, void *addr)
  440. {
  441. char buf[40];
  442. if (!inet_ntop(af, addr, buf, sizeof(buf)))
  443. return NULL;
  444. return add_option_dup(list, opt, buf, -1);
  445. }
  446. void free_optlist(struct oc_vpn_option *opt)
  447. {
  448. struct oc_vpn_option *next;
  449. for (; opt; opt = next) {
  450. next = opt->next;
  451. free(opt->option);
  452. free(opt->value);
  453. free(opt);
  454. }
  455. }
  456. int install_vpn_opts(struct openconnect_info *vpninfo, struct oc_vpn_option *opt,
  457. struct oc_ip_info *ip_info)
  458. {
  459. /* XX: remove protocol-specific exceptions here, once we can test them
  460. * with F5 reconnections in addition to Juniper reconnections. See:
  461. * https://gitlab.com/openconnect/openconnect/-/merge_requests/293#note_702388182
  462. */
  463. if (!ip_info->addr && !ip_info->addr6 && !ip_info->netmask6) {
  464. if (vpninfo->proto->proto == PROTO_F5) {
  465. /* F5 doesn't get its IP address until it actually establishes the
  466. * PPP connection. */
  467. } else if (vpninfo->proto->proto == PROTO_NC && vpninfo->ip_info.addr) {
  468. /* Juniper doesn't necessarily resend the Legacy IP address in the
  469. * event of a rekey/reconnection. */
  470. ip_info->addr = add_option_dup(&opt, "ipaddr", vpninfo->ip_info.addr, -1);
  471. if (!ip_info->netmask && vpninfo->ip_info.netmask)
  472. ip_info->netmask = add_option_dup(&opt, "netmask", vpninfo->ip_info.netmask, -1);
  473. vpn_progress(vpninfo, PRG_DEBUG,
  474. _("No IP address received with Juniper rekey/reconnection.\n"));
  475. goto after_ip_checks;
  476. } else {
  477. /* For all other protocols, not receiving any IP address is an error */
  478. vpn_progress(vpninfo, PRG_ERR,
  479. _("No IP address received. Aborting\n"));
  480. return -EINVAL;
  481. }
  482. }
  483. if (vpninfo->ip_info.addr) {
  484. if (!ip_info->addr || strcmp(ip_info->addr, vpninfo->ip_info.addr)) {
  485. vpn_progress(vpninfo, PRG_ERR,
  486. _("Reconnect gave different Legacy IP address (%s != %s)\n"),
  487. ip_info->addr, vpninfo->ip_info.addr);
  488. /* EPERM means that the retry loop will abort and won't keep trying. */
  489. return -EPERM;
  490. }
  491. }
  492. if (vpninfo->ip_info.netmask) {
  493. if (!ip_info->netmask || strcmp(ip_info->netmask, vpninfo->ip_info.netmask)) {
  494. vpn_progress(vpninfo, PRG_ERR,
  495. _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
  496. ip_info->netmask, vpninfo->ip_info.netmask);
  497. return -EPERM;
  498. }
  499. }
  500. if (vpninfo->ip_info.addr6) {
  501. if (!ip_info->addr6 || strcmp(ip_info->addr6, vpninfo->ip_info.addr6)) {
  502. vpn_progress(vpninfo, PRG_ERR,
  503. _("Reconnect gave different IPv6 address (%s != %s)\n"),
  504. ip_info->addr6, vpninfo->ip_info.addr6);
  505. return -EPERM;
  506. }
  507. }
  508. if (vpninfo->ip_info.netmask6) {
  509. if (!ip_info->netmask6 || strcmp(ip_info->netmask6, vpninfo->ip_info.netmask6)) {
  510. vpn_progress(vpninfo, PRG_ERR,
  511. _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
  512. ip_info->netmask6, vpninfo->ip_info.netmask6);
  513. return -EPERM;
  514. }
  515. }
  516. after_ip_checks:
  517. /* Preserve gateway_addr and MTU if they were set */
  518. ip_info->gateway_addr = vpninfo->ip_info.gateway_addr;
  519. if (!ip_info->mtu)
  520. ip_info->mtu = vpninfo->ip_info.mtu;
  521. if (ip_info->mtu && ip_info->mtu < 1280 &&
  522. (ip_info->addr6 || ip_info->netmask6)) {
  523. vpn_progress(vpninfo, PRG_ERR,
  524. _("IPv6 configuration received but MTU %d is too small.\n"),
  525. ip_info->mtu);
  526. }
  527. /* Free the original options */
  528. free_split_routes(&vpninfo->ip_info);
  529. free_optlist(vpninfo->cstp_options);
  530. /* Install the new options */
  531. vpninfo->cstp_options = opt;
  532. vpninfo->ip_info = *ip_info;
  533. return 0;
  534. }
  535. static void free_certinfo(struct cert_info *certinfo)
  536. {
  537. /**
  538. * Ensure resources are released
  539. */
  540. unload_certificate(certinfo, 1);
  541. /* These are const in openconnect itself, but for consistency of
  542. the library API we do take ownership of the strings we're given,
  543. and thus we have to free them too. */
  544. if (certinfo->cert != certinfo->key)
  545. free((void *)certinfo->key);
  546. free((void *)certinfo->cert);
  547. free_pass(&certinfo->password);
  548. }
  549. void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
  550. {
  551. openconnect_close_https(vpninfo, 1);
  552. if (vpninfo->proto->udp_shutdown)
  553. vpninfo->proto->udp_shutdown(vpninfo);
  554. if (vpninfo->tncc_fd != -1)
  555. closesocket(vpninfo->tncc_fd);
  556. if (vpninfo->cmd_fd_write != -1) {
  557. closesocket(vpninfo->cmd_fd);
  558. closesocket(vpninfo->cmd_fd_write);
  559. }
  560. #ifdef HAVE_HPKE_SUPPORT
  561. free_strap_keys(vpninfo);
  562. free(vpninfo->strap_pubkey);
  563. free(vpninfo->strap_dh_pubkey);
  564. #endif /* HAVE_HPKE_SUPPORT */
  565. free(vpninfo->sso_username);
  566. free(vpninfo->sso_cookie_value);
  567. free(vpninfo->sso_browser_mode);
  568. free(vpninfo->sso_login);
  569. free(vpninfo->sso_login_final);
  570. free(vpninfo->sso_error_cookie);
  571. free(vpninfo->sso_token_cookie);
  572. free(vpninfo->ppp);
  573. buf_free(vpninfo->ppp_tls_connect_req);
  574. buf_free(vpninfo->ppp_dtls_connect_req);
  575. #ifdef HAVE_ICONV
  576. if (vpninfo->ic_utf8_to_legacy != (iconv_t)-1)
  577. iconv_close(vpninfo->ic_utf8_to_legacy);
  578. if (vpninfo->ic_legacy_to_utf8 != (iconv_t)-1)
  579. iconv_close(vpninfo->ic_legacy_to_utf8);
  580. #endif
  581. #ifdef _WIN32
  582. if (vpninfo->cmd_event)
  583. CloseHandle(vpninfo->cmd_event);
  584. if (vpninfo->ssl_event)
  585. CloseHandle(vpninfo->ssl_event);
  586. if (vpninfo->dtls_event)
  587. CloseHandle(vpninfo->dtls_event);
  588. free(vpninfo->ifname_w);
  589. #endif
  590. free(vpninfo->peer_addr);
  591. free(vpninfo->ip_info.gateway_addr);
  592. free_optlist(vpninfo->csd_env);
  593. free_optlist(vpninfo->script_env);
  594. free_optlist(vpninfo->cookies);
  595. free_optlist(vpninfo->cstp_options);
  596. free_optlist(vpninfo->dtls_options);
  597. free_split_routes(&vpninfo->ip_info);
  598. free(vpninfo->hostname);
  599. free(vpninfo->unique_hostname);
  600. buf_free(vpninfo->connect_urlbuf);
  601. free(vpninfo->urlpath);
  602. free(vpninfo->redirect_url);
  603. free_pass(&vpninfo->cookie);
  604. free(vpninfo->proxy_type);
  605. free(vpninfo->proxy);
  606. free(vpninfo->proxy_user);
  607. free_pass(&vpninfo->proxy_pass);
  608. free(vpninfo->vpnc_script);
  609. free(vpninfo->cafile);
  610. free(vpninfo->ifname);
  611. free(vpninfo->dtls_cipher);
  612. free(vpninfo->peer_cert_hash);
  613. free(vpninfo->ciphersuite_config);
  614. #if defined(OPENCONNECT_OPENSSL)
  615. free(vpninfo->cstp_cipher);
  616. #if defined(HAVE_BIO_METH_FREE)
  617. if (vpninfo->ttls_bio_meth)
  618. BIO_meth_free(vpninfo->ttls_bio_meth);
  619. #endif
  620. #ifdef HAVE_DTLS
  621. free(vpninfo->dtls_cipher_desc);
  622. #endif
  623. #elif defined(OPENCONNECT_GNUTLS)
  624. gnutls_free(vpninfo->cstp_cipher);
  625. #ifdef HAVE_DTLS
  626. gnutls_free(vpninfo->dtls_cipher_desc);
  627. #endif
  628. #endif
  629. free(vpninfo->dtls_addr);
  630. if (vpninfo->csd_scriptname) {
  631. unlink(vpninfo->csd_scriptname);
  632. free(vpninfo->csd_scriptname);
  633. }
  634. free(vpninfo->mobile_platform_version);
  635. free(vpninfo->mobile_device_type);
  636. free(vpninfo->mobile_device_uniqueid);
  637. free(vpninfo->csd_token);
  638. free(vpninfo->csd_ticket);
  639. free(vpninfo->csd_stuburl);
  640. free(vpninfo->csd_starturl);
  641. free(vpninfo->csd_waiturl);
  642. free(vpninfo->csd_preurl);
  643. free(vpninfo->platname);
  644. if (vpninfo->opaque_srvdata)
  645. xmlFreeNode(vpninfo->opaque_srvdata);
  646. free(vpninfo->profile_url);
  647. free(vpninfo->profile_sha1);
  648. free_certinfo(&vpninfo->certinfo[0]);
  649. free_certinfo(&vpninfo->certinfo[1]);
  650. if (vpninfo->peer_cert) {
  651. #if defined(OPENCONNECT_OPENSSL)
  652. X509_free(vpninfo->peer_cert);
  653. #elif defined(OPENCONNECT_GNUTLS)
  654. gnutls_x509_crt_deinit(vpninfo->peer_cert);
  655. #endif
  656. vpninfo->peer_cert = NULL;
  657. }
  658. while (vpninfo->pin_cache) {
  659. struct pin_cache *cache = vpninfo->pin_cache;
  660. free(cache->token);
  661. memset(cache->pin, 0x5a, strlen(cache->pin));
  662. free(cache->pin);
  663. vpninfo->pin_cache = cache->next;
  664. free(cache);
  665. }
  666. free(vpninfo->localname);
  667. free(vpninfo->useragent);
  668. free(vpninfo->authgroup);
  669. #ifdef HAVE_LIBSTOKEN
  670. if (vpninfo->stoken_pin)
  671. free_pass(&vpninfo->stoken_pin);
  672. if (vpninfo->stoken_ctx)
  673. stoken_destroy(vpninfo->stoken_ctx);
  674. #endif
  675. if (vpninfo->oath_secret) {
  676. #ifdef HAVE_LIBPSKC
  677. if (vpninfo->pskc)
  678. pskc_done(vpninfo->pskc);
  679. else
  680. #endif /* HAVE_LIBPSKC */
  681. free_pass(&vpninfo->oath_secret);
  682. }
  683. #ifdef HAVE_LIBPCSCLITE
  684. release_pcsc_ctx(vpninfo);
  685. #endif
  686. #ifdef HAVE_LIBP11
  687. if (vpninfo->pkcs11_ctx) {
  688. if (vpninfo->pkcs11_slot_list)
  689. PKCS11_release_all_slots(vpninfo->pkcs11_ctx,
  690. vpninfo->pkcs11_slot_list,
  691. vpninfo->pkcs11_slot_count);
  692. PKCS11_CTX_unload(vpninfo->pkcs11_ctx);
  693. PKCS11_CTX_free(vpninfo->pkcs11_ctx);
  694. }
  695. free(vpninfo->pkcs11_cert_id);
  696. #endif
  697. /* These check strm->state so they are safe to call multiple times */
  698. inflateEnd(&vpninfo->inflate_strm);
  699. deflateEnd(&vpninfo->deflate_strm);
  700. #ifdef HAVE_EPOLL
  701. if (vpninfo->epoll_fd >= 0)
  702. close(vpninfo->epoll_fd);
  703. #endif
  704. free_pkt(vpninfo, vpninfo->deflate_pkt);
  705. free_pkt(vpninfo, vpninfo->tun_pkt);
  706. free_pkt(vpninfo, vpninfo->dtls_pkt);
  707. free_pkt(vpninfo, vpninfo->cstp_pkt);
  708. struct pkt *pkt;
  709. while ((pkt = dequeue_packet(&vpninfo->free_queue)))
  710. free(pkt);
  711. free(vpninfo->bearer_token);
  712. free(vpninfo);
  713. }
  714. const char *openconnect_get_connect_url(struct openconnect_info *vpninfo)
  715. {
  716. struct oc_text_buf *urlbuf = vpninfo->connect_urlbuf;
  717. if (!urlbuf)
  718. urlbuf = buf_alloc();
  719. buf_append(urlbuf, "https://%s", vpninfo->hostname);
  720. if (vpninfo->port != 443)
  721. buf_append(urlbuf, ":%d", vpninfo->port);
  722. buf_append(urlbuf, "/");
  723. /* Other protocols don't care and just leave noise from the
  724. * authentication process in ->urlpath. Pulse does care, and
  725. * you have to *connect* to a given usergroup at the correct
  726. * path, not just authenticate.
  727. *
  728. * https://gitlab.gnome.org/GNOME/NetworkManager-openconnect/-/issues/53
  729. * https://gitlab.gnome.org/GNOME/NetworkManager-openconnect/-/merge_requests/22
  730. */
  731. if (vpninfo->proto->proto == PROTO_PULSE)
  732. buf_append(urlbuf, "%s", vpninfo->urlpath);
  733. if (buf_error(urlbuf)) {
  734. buf_free(urlbuf);
  735. vpninfo->connect_urlbuf = NULL;
  736. return NULL;
  737. }
  738. vpninfo->connect_urlbuf = urlbuf;
  739. return urlbuf->data;
  740. }
  741. const char *openconnect_get_hostname(struct openconnect_info *vpninfo)
  742. {
  743. return vpninfo->unique_hostname?:vpninfo->hostname;
  744. }
  745. const char *openconnect_get_dnsname(struct openconnect_info *vpninfo)
  746. {
  747. return vpninfo->hostname;
  748. }
  749. int openconnect_set_hostname(struct openconnect_info *vpninfo,
  750. const char *hostname)
  751. {
  752. UTF8CHECK(hostname);
  753. STRDUP(vpninfo->hostname, hostname);
  754. free(vpninfo->unique_hostname);
  755. vpninfo->unique_hostname = NULL;
  756. free(vpninfo->peer_addr);
  757. vpninfo->peer_addr = NULL;
  758. free(vpninfo->ip_info.gateway_addr);
  759. vpninfo->ip_info.gateway_addr = NULL;
  760. return 0;
  761. }
  762. char *openconnect_get_urlpath(struct openconnect_info *vpninfo)
  763. {
  764. return vpninfo->urlpath;
  765. }
  766. int openconnect_set_useragent(struct openconnect_info *vpninfo,
  767. const char *useragent)
  768. {
  769. UTF8CHECK(useragent);
  770. STRDUP(vpninfo->useragent, useragent);
  771. return 0;
  772. }
  773. int openconnect_set_urlpath(struct openconnect_info *vpninfo,
  774. const char *urlpath)
  775. {
  776. UTF8CHECK(urlpath);
  777. STRDUP(vpninfo->urlpath, urlpath);
  778. return 0;
  779. }
  780. int openconnect_set_localname(struct openconnect_info *vpninfo,
  781. const char *localname)
  782. {
  783. UTF8CHECK(localname);
  784. STRDUP(vpninfo->localname, localname);
  785. return 0;
  786. }
  787. void openconnect_set_xmlsha1(struct openconnect_info *vpninfo,
  788. const char *xmlsha1, int size)
  789. {
  790. if (size != sizeof(vpninfo->xmlsha1))
  791. return;
  792. memcpy(&vpninfo->xmlsha1, xmlsha1, size);
  793. }
  794. int openconnect_disable_ipv6(struct openconnect_info *vpninfo)
  795. {
  796. /* This prevents disabling IPv6 when the connection is
  797. * currently connected or has been connected previously.
  798. *
  799. * XX: It would be better to allow it when currently
  800. * disconnected, but we currently have no way to indicate
  801. * a state in which IP and routing configuration are
  802. * unconfigured state. (Neither a closed TLS socket
  803. * nor tunnel socket is a reliable indicator.)
  804. */
  805. if (!vpninfo->disable_ipv6 &&
  806. vpninfo->ssl_times.last_tx != 0)
  807. return -EINVAL;
  808. vpninfo->disable_ipv6 = 1;
  809. return 0;
  810. }
  811. int openconnect_disable_dtls(struct openconnect_info *vpninfo)
  812. {
  813. /* This disables DTLS or ESP. It is prevented when the
  814. * connection is currently connected or has been
  815. * connected previously.
  816. *
  817. * XX: It would be better to allow it when DTLS is not
  818. * in use, but other than DTLS already being disabled,
  819. * we currently do not have a reliable indicator of
  820. * this.
  821. */
  822. if (vpninfo->dtls_state != DTLS_NOSECRET
  823. || vpninfo->ssl_times.last_tx != 0)
  824. return -EINVAL;
  825. vpninfo->dtls_state = DTLS_DISABLED;
  826. return 0;
  827. }
  828. int openconnect_set_cafile(struct openconnect_info *vpninfo, const char *cafile)
  829. {
  830. UTF8CHECK(cafile);
  831. STRDUP(vpninfo->cafile, cafile);
  832. return 0;
  833. }
  834. void openconnect_set_system_trust(struct openconnect_info *vpninfo, unsigned val)
  835. {
  836. vpninfo->no_system_trust = !val;
  837. }
  838. const char *openconnect_get_ifname(struct openconnect_info *vpninfo)
  839. {
  840. return vpninfo->ifname;
  841. }
  842. void openconnect_set_reqmtu(struct openconnect_info *vpninfo, int reqmtu)
  843. {
  844. vpninfo->reqmtu = reqmtu;
  845. }
  846. void openconnect_set_dpd(struct openconnect_info *vpninfo, int min_seconds)
  847. {
  848. /* Make sure (ka->dpd / 2), our computed midway point, isn't 0 */
  849. if (!min_seconds || min_seconds >= 2)
  850. vpninfo->dtls_times.dpd = vpninfo->ssl_times.dpd = min_seconds;
  851. else if (min_seconds == 1)
  852. vpninfo->dtls_times.dpd = vpninfo->ssl_times.dpd = 2;
  853. }
  854. void openconnect_set_trojan_interval(struct openconnect_info *vpninfo, int seconds)
  855. {
  856. vpninfo->trojan_interval = seconds;
  857. }
  858. int openconnect_get_idle_timeout(struct openconnect_info *vpninfo)
  859. {
  860. return vpninfo->idle_timeout;
  861. }
  862. time_t openconnect_get_auth_expiration(struct openconnect_info *vpninfo)
  863. {
  864. return vpninfo->auth_expiration;
  865. }
  866. int openconnect_get_ip_info(struct openconnect_info *vpninfo,
  867. const struct oc_ip_info **info,
  868. const struct oc_vpn_option **cstp_options,
  869. const struct oc_vpn_option **dtls_options)
  870. {
  871. if (info)
  872. *info = &vpninfo->ip_info;
  873. if (cstp_options)
  874. *cstp_options = vpninfo->cstp_options;
  875. if (dtls_options)
  876. *dtls_options = vpninfo->dtls_options;
  877. return 0;
  878. }
  879. int openconnect_setup_csd(struct openconnect_info *vpninfo, uid_t uid,
  880. int silent, const char *wrapper)
  881. {
  882. #ifndef _WIN32
  883. vpninfo->uid_csd = uid;
  884. vpninfo->uid_csd_given = silent ? 2 : 1;
  885. #endif
  886. STRDUP(vpninfo->csd_wrapper, wrapper);
  887. return 0;
  888. }
  889. void openconnect_set_xmlpost(struct openconnect_info *vpninfo, int enable)
  890. {
  891. vpninfo->xmlpost = enable;
  892. }
  893. int openconnect_set_client_cert(struct openconnect_info *vpninfo,
  894. const char *cert, const char *sslkey)
  895. {
  896. UTF8CHECK(cert);
  897. UTF8CHECK(sslkey);
  898. /* Avoid freeing it twice if it's the same */
  899. if (vpninfo->certinfo[0].key == vpninfo->certinfo[0].cert)
  900. vpninfo->certinfo[0].key = NULL;
  901. STRDUP(vpninfo->certinfo[0].cert, cert);
  902. if (sslkey) {
  903. STRDUP(vpninfo->certinfo[0].key, sslkey);
  904. } else {
  905. vpninfo->certinfo[0].key = vpninfo->certinfo[0].cert;
  906. }
  907. return 0;
  908. }
  909. int openconnect_set_mca_cert(struct openconnect_info *vpninfo,
  910. const char *cert, const char *key)
  911. {
  912. UTF8CHECK(cert);
  913. UTF8CHECK(key);
  914. /* Avoid freeing it twice if it's the same */
  915. if (vpninfo->certinfo[1].key == vpninfo->certinfo[1].cert)
  916. vpninfo->certinfo[1].key = NULL;
  917. STRDUP(vpninfo->certinfo[1].cert, cert);
  918. if (key) {
  919. STRDUP(vpninfo->certinfo[1].key, key);
  920. } else {
  921. vpninfo->certinfo[1].key = vpninfo->certinfo[1].cert;
  922. }
  923. return 0;
  924. }
  925. int openconnect_set_mca_key_password(struct openconnect_info *vpninfo, const char *pass)
  926. {
  927. STRDUP(vpninfo->certinfo[1].password, pass);
  928. return 0;
  929. }
  930. int openconnect_get_port(struct openconnect_info *vpninfo)
  931. {
  932. return vpninfo->port;
  933. }
  934. const char *openconnect_get_cookie(struct openconnect_info *vpninfo)
  935. {
  936. return vpninfo->cookie;
  937. }
  938. void openconnect_clear_cookie(struct openconnect_info *vpninfo)
  939. {
  940. if (vpninfo->cookie)
  941. memset(vpninfo->cookie, 0, strlen(vpninfo->cookie));
  942. }
  943. int openconnect_set_cookie(struct openconnect_info *vpninfo,
  944. const char *cookie)
  945. {
  946. UTF8CHECK(cookie);
  947. STRDUP(vpninfo->cookie, cookie);
  948. return 0;
  949. }
  950. void openconnect_reset_ssl(struct openconnect_info *vpninfo)
  951. {
  952. vpninfo->got_cancel_cmd = 0;
  953. openconnect_close_https(vpninfo, 0);
  954. free(vpninfo->peer_addr);
  955. vpninfo->peer_addr = NULL;
  956. vpninfo->dtls_tos_optname = 0;
  957. free(vpninfo->ip_info.gateway_addr);
  958. vpninfo->ip_info.gateway_addr = NULL;
  959. openconnect_clear_cookies(vpninfo);
  960. }
  961. int openconnect_parse_url(struct openconnect_info *vpninfo, const char *url)
  962. {
  963. char *scheme = NULL;
  964. int ret;
  965. UTF8CHECK(url);
  966. openconnect_set_hostname(vpninfo, NULL);
  967. free(vpninfo->urlpath);
  968. vpninfo->urlpath = NULL;
  969. ret = internal_parse_url(url, &scheme, &vpninfo->hostname,
  970. &vpninfo->port, &vpninfo->urlpath, 443);
  971. if (ret) {
  972. vpn_progress(vpninfo, PRG_ERR,
  973. _("Failed to parse server URL '%s'\n"),
  974. url);
  975. return ret;
  976. }
  977. if (scheme && strcmp(scheme, "https")) {
  978. vpn_progress(vpninfo, PRG_ERR,
  979. _("Only https:// permitted for server URL\n"));
  980. ret = -EINVAL;
  981. }
  982. free(scheme);
  983. return ret;
  984. }
  985. void openconnect_set_cert_expiry_warning(struct openconnect_info *vpninfo,
  986. int seconds)
  987. {
  988. vpninfo->cert_expire_warning = seconds;
  989. }
  990. int openconnect_set_key_password(struct openconnect_info *vpninfo, const char *pass)
  991. {
  992. STRDUP(vpninfo->certinfo[0].password, pass);
  993. return 0;
  994. }
  995. void openconnect_set_pfs(struct openconnect_info *vpninfo, unsigned val)
  996. {
  997. vpninfo->pfs = val;
  998. }
  999. int openconnect_set_allow_insecure_crypto(struct openconnect_info *vpninfo, unsigned val)
  1000. {
  1001. int ret = can_enable_insecure_crypto();
  1002. if (ret)
  1003. return ret;
  1004. vpninfo->allow_insecure_crypto = val;
  1005. return 0;
  1006. }
  1007. void openconnect_set_cancel_fd(struct openconnect_info *vpninfo, int fd)
  1008. {
  1009. vpninfo->cmd_fd = fd;
  1010. }
  1011. #ifdef _WIN32
  1012. # define CMD_PIPE_ERR INVALID_SOCKET
  1013. #else
  1014. # define CMD_PIPE_ERR -EIO
  1015. #endif
  1016. OPENCONNECT_CMD_SOCKET openconnect_setup_cmd_pipe(struct openconnect_info *vpninfo)
  1017. {
  1018. OPENCONNECT_CMD_SOCKET pipefd[2];
  1019. #ifdef _WIN32
  1020. if (dumb_socketpair(pipefd, 0))
  1021. return CMD_PIPE_ERR;
  1022. #else
  1023. if (pipe(pipefd) < 0)
  1024. return CMD_PIPE_ERR;
  1025. #endif
  1026. if (set_sock_nonblock(pipefd[0]) || set_sock_nonblock(pipefd[1])) {
  1027. closesocket(pipefd[0]);
  1028. closesocket(pipefd[1]);
  1029. return CMD_PIPE_ERR;
  1030. }
  1031. vpninfo->cmd_fd = pipefd[0];
  1032. vpninfo->cmd_fd_write = pipefd[1];
  1033. vpninfo->need_poll_cmd_fd = 1;
  1034. return vpninfo->cmd_fd_write;
  1035. }
  1036. const char *openconnect_get_version(void)
  1037. {
  1038. return openconnect_version_str;
  1039. }
  1040. int openconnect_has_pkcs11_support(void)
  1041. {
  1042. #if defined(OPENCONNECT_GNUTLS) && defined(HAVE_P11KIT)
  1043. return 1;
  1044. #elif defined(OPENCONNECT_OPENSSL) && defined(HAVE_LIBP11)
  1045. return 1;
  1046. #else
  1047. return 0;
  1048. #endif
  1049. }
  1050. #if defined(OPENCONNECT_OPENSSL) && defined(HAVE_ENGINE)
  1051. #include <openssl/engine.h>
  1052. #endif
  1053. int openconnect_has_tss_blob_support(void)
  1054. {
  1055. #if defined(OPENCONNECT_OPENSSL) && defined(HAVE_ENGINE)
  1056. ENGINE *e;
  1057. ENGINE_load_builtin_engines();
  1058. e = ENGINE_by_id("tpm");
  1059. if (e) {
  1060. ENGINE_free(e);
  1061. return 1;
  1062. }
  1063. #elif defined(OPENCONNECT_GNUTLS) && defined(HAVE_TROUSERS)
  1064. return 1;
  1065. #endif
  1066. return 0;
  1067. }
  1068. int openconnect_has_tss2_blob_support(void)
  1069. {
  1070. #if defined(OPENCONNECT_OPENSSL) && defined(HAVE_ENGINE)
  1071. ENGINE *e;
  1072. ENGINE_load_builtin_engines();
  1073. e = ENGINE_by_id("tpm2");
  1074. if (e) {
  1075. ENGINE_free(e);
  1076. return 1;
  1077. }
  1078. #elif defined(OPENCONNECT_GNUTLS) && defined(HAVE_TSS2)
  1079. return 1;
  1080. #endif
  1081. return 0;
  1082. }
  1083. int openconnect_has_stoken_support(void)
  1084. {
  1085. #ifdef HAVE_LIBSTOKEN
  1086. return 1;
  1087. #else
  1088. return 0;
  1089. #endif
  1090. }
  1091. int openconnect_has_oath_support(void)
  1092. {
  1093. return 2;
  1094. }
  1095. int openconnect_has_yubioath_support(void)
  1096. {
  1097. #ifdef HAVE_LIBPCSCLITE
  1098. return 1;
  1099. #else
  1100. return 0;
  1101. #endif
  1102. }
  1103. int openconnect_has_system_key_support(void)
  1104. {
  1105. #ifdef HAVE_GNUTLS_SYSTEM_KEYS
  1106. return 1;
  1107. #else
  1108. return 0;
  1109. #endif
  1110. }
  1111. int openconnect_set_token_callbacks(struct openconnect_info *vpninfo,
  1112. void *tokdata,
  1113. openconnect_lock_token_vfn lock,
  1114. openconnect_unlock_token_vfn unlock)
  1115. {
  1116. vpninfo->lock_token = lock;
  1117. vpninfo->unlock_token = unlock;
  1118. vpninfo->tok_cbdata = tokdata;
  1119. return 0;
  1120. }
  1121. /*
  1122. * Enable software token generation.
  1123. *
  1124. * If token_mode is OC_TOKEN_MODE_STOKEN and token_str is NULL,
  1125. * read the token data from ~/.stokenrc.
  1126. *
  1127. * Return value:
  1128. * = -EILSEQ, if token_str is not valid UTF-8
  1129. * = -EOPNOTSUPP, if the underlying library (libstoken, liboath) is not
  1130. * available or an invalid token_mode was provided
  1131. * = -EINVAL, if the token string is invalid (token_str was provided)
  1132. * = -ENOENT, if token_mode is OC_TOKEN_MODE_STOKEN and ~/.stokenrc is
  1133. * missing (token_str was NULL)
  1134. * = -EIO, for other failures in the underlying library (libstoken, liboath)
  1135. * = 0, on success
  1136. */
  1137. int openconnect_set_token_mode(struct openconnect_info *vpninfo,
  1138. oc_token_mode_t token_mode,
  1139. const char *token_str)
  1140. {
  1141. vpninfo->token_mode = OC_TOKEN_MODE_NONE;
  1142. UTF8CHECK(token_str);
  1143. switch (token_mode) {
  1144. case OC_TOKEN_MODE_NONE:
  1145. return 0;
  1146. case OC_TOKEN_MODE_TOTP:
  1147. case OC_TOKEN_MODE_HOTP:
  1148. return set_oath_mode(vpninfo, token_str, token_mode);
  1149. #ifdef HAVE_LIBSTOKEN
  1150. case OC_TOKEN_MODE_STOKEN:
  1151. return set_libstoken_mode(vpninfo, token_str);
  1152. #endif
  1153. #ifdef HAVE_LIBPCSCLITE
  1154. case OC_TOKEN_MODE_YUBIOATH:
  1155. return set_yubikey_mode(vpninfo, token_str);
  1156. #endif
  1157. case OC_TOKEN_MODE_OIDC:
  1158. return set_oidc_token(vpninfo, token_str);
  1159. default:
  1160. return -EOPNOTSUPP;
  1161. }
  1162. }
  1163. /*
  1164. * Enable libstoken token generation if use_stoken == 1.
  1165. *
  1166. * If token_str is not NULL, try to parse the string. Otherwise, try to read
  1167. * the token data from ~/.stokenrc
  1168. *
  1169. * DEPRECATED: use openconnect_set_stoken_mode() instead.
  1170. *
  1171. * Return value:
  1172. * = -EILSEQ, if token_str is not valid UTF-8
  1173. * = -EOPNOTSUPP, if libstoken is not available
  1174. * = -EINVAL, if the token string is invalid (token_str was provided)
  1175. * = -ENOENT, if ~/.stokenrc is missing (token_str was NULL)
  1176. * = -EIO, for other libstoken failures
  1177. * = 0, on success
  1178. */
  1179. int openconnect_set_stoken_mode(struct openconnect_info *vpninfo,
  1180. int use_stoken, const char *token_str)
  1181. {
  1182. oc_token_mode_t token_mode = OC_TOKEN_MODE_NONE;
  1183. if (use_stoken)
  1184. token_mode = OC_TOKEN_MODE_STOKEN;
  1185. return openconnect_set_token_mode(vpninfo, token_mode, token_str);
  1186. }
  1187. void openconnect_set_protect_socket_handler(struct openconnect_info *vpninfo,
  1188. openconnect_protect_socket_vfn protect_socket)
  1189. {
  1190. vpninfo->protect_socket = protect_socket;
  1191. }
  1192. void openconnect_override_getaddrinfo(struct openconnect_info *vpninfo, openconnect_getaddrinfo_vfn gai_fn)
  1193. {
  1194. vpninfo->getaddrinfo_override = gai_fn;
  1195. }
  1196. void openconnect_set_setup_tun_handler(struct openconnect_info *vpninfo,
  1197. openconnect_setup_tun_vfn setup_tun)
  1198. {
  1199. vpninfo->setup_tun = setup_tun;
  1200. }
  1201. void openconnect_set_reconnected_handler(struct openconnect_info *vpninfo,
  1202. openconnect_reconnected_vfn reconnected)
  1203. {
  1204. vpninfo->reconnected = reconnected;
  1205. }
  1206. void openconnect_set_stats_handler(struct openconnect_info *vpninfo,
  1207. openconnect_stats_vfn stats_handler)
  1208. {
  1209. vpninfo->stats_handler = stats_handler;
  1210. }
  1211. /* Set up a traditional OS-based tunnel device, optionally specified in 'ifname'. */
  1212. int openconnect_setup_tun_device(struct openconnect_info *vpninfo,
  1213. const char *vpnc_script, const char *ifname)
  1214. {
  1215. intptr_t tun_fd;
  1216. char *legacy_ifname;
  1217. UTF8CHECK(vpnc_script);
  1218. UTF8CHECK(ifname);
  1219. STRDUP(vpninfo->vpnc_script, vpnc_script);
  1220. STRDUP(vpninfo->ifname, ifname);
  1221. prepare_script_env(vpninfo);
  1222. /* XX: vpninfo->ifname will only be non-NULL here if set by the -i option,
  1223. which only works on some platforms (see os_setup_tun implementations) */
  1224. legacy_ifname = vpninfo->ifname ? openconnect_utf8_to_legacy(vpninfo, vpninfo->ifname) : NULL;
  1225. script_setenv(vpninfo, "TUNDEV", legacy_ifname, 0, 0);
  1226. if (legacy_ifname != vpninfo->ifname)
  1227. free(legacy_ifname);
  1228. script_config_tun(vpninfo, "pre-init");
  1229. tun_fd = os_setup_tun(vpninfo);
  1230. if (tun_fd < 0)
  1231. return tun_fd;
  1232. #ifdef _WIN32
  1233. if (vpninfo->tun_idx != -1)
  1234. script_setenv_int(vpninfo, "TUNIDX", vpninfo->tun_idx);
  1235. #endif
  1236. /* XX: os_setup_tun has set (or even changed) ifname */
  1237. legacy_ifname = openconnect_utf8_to_legacy(vpninfo, vpninfo->ifname);
  1238. script_setenv(vpninfo, "TUNDEV", legacy_ifname, 0, 0);
  1239. if (legacy_ifname != vpninfo->ifname)
  1240. free(legacy_ifname);
  1241. script_config_tun(vpninfo, "connect");
  1242. return openconnect_setup_tun_fd(vpninfo, tun_fd);
  1243. }
  1244. static const char * const compr_name_map[] = {
  1245. [COMPR_DEFLATE] = "Deflate",
  1246. [COMPR_LZS] = "LZS",
  1247. [COMPR_LZ4] = "LZ4",
  1248. [COMPR_LZO] = "LZO",
  1249. };
  1250. const char *openconnect_get_cstp_compression(struct openconnect_info *vpninfo)
  1251. {
  1252. if (vpninfo->cstp_compr <= 0 || vpninfo->cstp_compr > COMPR_MAX)
  1253. return NULL;
  1254. return compr_name_map[vpninfo->cstp_compr];
  1255. }
  1256. const char *openconnect_get_dtls_compression(struct openconnect_info *vpninfo)
  1257. {
  1258. if (vpninfo->dtls_compr <= 0 || vpninfo->dtls_compr > COMPR_MAX)
  1259. return NULL;
  1260. return compr_name_map[vpninfo->dtls_compr];
  1261. }
  1262. const char *openconnect_get_dtls_cipher(struct openconnect_info *vpninfo)
  1263. {
  1264. if (vpninfo->dtls_state < DTLS_CONNECTED || !vpninfo->dtls_ssl) {
  1265. #if defined(OPENCONNECT_GNUTLS)
  1266. gnutls_free(vpninfo->dtls_cipher_desc);
  1267. #else
  1268. free(vpninfo->dtls_cipher_desc);
  1269. #endif
  1270. vpninfo->dtls_cipher_desc = NULL;
  1271. return NULL;
  1272. }
  1273. /* in DTLS rehandshakes don't switch the ciphersuite as only
  1274. * one is enabled. */
  1275. if (vpninfo->dtls_cipher_desc == NULL) {
  1276. #if defined(OPENCONNECT_GNUTLS)
  1277. vpninfo->dtls_cipher_desc = get_gnutls_cipher(vpninfo->dtls_ssl);
  1278. #else
  1279. if (asprintf(&vpninfo->dtls_cipher_desc, "%s-%s",
  1280. SSL_get_version(vpninfo->dtls_ssl), SSL_get_cipher_name(vpninfo->dtls_ssl)) < 0)
  1281. return NULL;
  1282. #endif
  1283. }
  1284. return vpninfo->dtls_cipher_desc;
  1285. }
  1286. int openconnect_set_csd_environ(struct openconnect_info *vpninfo,
  1287. const char *name, const char *value)
  1288. {
  1289. struct oc_vpn_option *p;
  1290. if (!name) {
  1291. free_optlist(vpninfo->csd_env);
  1292. vpninfo->csd_env = NULL;
  1293. return 0;
  1294. }
  1295. for (p = vpninfo->csd_env; p; p = p->next) {
  1296. if (!strcmp(name, p->option)) {
  1297. char *valdup = strdup(value);
  1298. if (!valdup)
  1299. return -ENOMEM;
  1300. free(p->value);
  1301. p->value = valdup;
  1302. return 0;
  1303. }
  1304. }
  1305. p = malloc(sizeof(*p));
  1306. if (!p)
  1307. return -ENOMEM;
  1308. p->option = strdup(name);
  1309. if (!p->option) {
  1310. free(p);
  1311. return -ENOMEM;
  1312. }
  1313. p->value = strdup(value);
  1314. if (!p->value) {
  1315. free(p->option);
  1316. free(p);
  1317. return -ENOMEM;
  1318. }
  1319. p->next = vpninfo->csd_env;
  1320. vpninfo->csd_env = p;
  1321. return 0;
  1322. }
  1323. int openconnect_check_peer_cert_hash(struct openconnect_info *vpninfo,
  1324. const char *old_hash)
  1325. {
  1326. char *fingerprint = NULL;
  1327. const unsigned min_match_len = 4;
  1328. unsigned old_len, fingerprint_len;
  1329. int case_sensitive = 0;
  1330. int ret = 0;
  1331. if (strchr(old_hash, ':')) {
  1332. /* These are hashes of the public key not the full cert. */
  1333. if (strncmp(old_hash, "sha1:", 5) == 0) {
  1334. old_hash += 5;
  1335. fingerprint = openconnect_bin2hex(NULL, vpninfo->peer_cert_sha1_raw, sizeof(vpninfo->peer_cert_sha1_raw));
  1336. } else if (strncmp(old_hash, "sha256:", 7) == 0) {
  1337. old_hash += 7;
  1338. fingerprint = openconnect_bin2hex(NULL, vpninfo->peer_cert_sha256_raw, sizeof(vpninfo->peer_cert_sha256_raw));
  1339. } else if (strncmp(old_hash, "pin-sha256:", 11) == 0) {
  1340. old_hash += 11;
  1341. fingerprint = openconnect_bin2base64(NULL, vpninfo->peer_cert_sha256_raw, sizeof(vpninfo->peer_cert_sha256_raw));
  1342. case_sensitive = 1;
  1343. } else {
  1344. vpn_progress(vpninfo, PRG_ERR, _("Unknown certificate hash: %s.\n"), old_hash);
  1345. return -EIO;
  1346. }
  1347. } else {
  1348. /* Not the same as the sha1: case above, because this hashes the full cert */
  1349. unsigned char *cert;
  1350. int len;
  1351. unsigned char sha1_bin[SHA1_SIZE];
  1352. len = openconnect_get_peer_cert_DER(vpninfo, &cert);
  1353. if (len < 0)
  1354. return len;
  1355. if (openconnect_sha1(sha1_bin, cert, len)) {
  1356. free(cert);
  1357. return -EIO;
  1358. }
  1359. free(cert);
  1360. fingerprint = openconnect_bin2hex(NULL, sha1_bin, sizeof(sha1_bin));
  1361. }
  1362. if (!fingerprint)
  1363. return -EIO;
  1364. old_len = strlen(old_hash);
  1365. fingerprint_len = strlen(fingerprint);
  1366. if (old_len > fingerprint_len)
  1367. ret = 1;
  1368. else if (case_sensitive ? strncmp(old_hash, fingerprint, old_len) :
  1369. strncasecmp(old_hash, fingerprint, old_len))
  1370. ret = 1;
  1371. else if (old_len < min_match_len) {
  1372. vpn_progress(vpninfo, PRG_ERR, _("The size of the provided fingerprint is less than the minimum required (%u).\n"), min_match_len);
  1373. ret = 1;
  1374. }
  1375. free(fingerprint);
  1376. return ret;
  1377. }
  1378. const char *openconnect_get_cstp_cipher(struct openconnect_info *vpninfo)
  1379. {
  1380. return vpninfo->cstp_cipher;
  1381. }
  1382. const char *openconnect_get_peer_cert_hash(struct openconnect_info *vpninfo)
  1383. {
  1384. if (vpninfo->peer_cert_hash == NULL)
  1385. vpninfo->peer_cert_hash = openconnect_bin2base64("pin-sha256:", vpninfo->peer_cert_sha256_raw, sizeof(vpninfo->peer_cert_sha256_raw));
  1386. return vpninfo->peer_cert_hash;
  1387. }
  1388. int openconnect_set_compression_mode(struct openconnect_info *vpninfo,
  1389. oc_compression_mode_t mode)
  1390. {
  1391. switch(mode) {
  1392. case OC_COMPRESSION_MODE_NONE:
  1393. vpninfo->req_compr = 0;
  1394. return 0;
  1395. case OC_COMPRESSION_MODE_STATELESS:
  1396. vpninfo->req_compr = COMPR_STATELESS;
  1397. return 0;
  1398. case OC_COMPRESSION_MODE_ALL:
  1399. vpninfo->req_compr = COMPR_ALL;
  1400. return 0;
  1401. default:
  1402. return -EINVAL;
  1403. }
  1404. }
  1405. void nuke_opt_values(struct oc_form_opt *opt)
  1406. {
  1407. for (; opt; opt = opt->next) {
  1408. if (opt->type == OC_FORM_OPT_TEXT ||
  1409. opt->type == OC_FORM_OPT_PASSWORD) {
  1410. free(opt->_value);
  1411. opt->_value = NULL;
  1412. }
  1413. }
  1414. }
  1415. int process_auth_form(struct openconnect_info *vpninfo, struct oc_auth_form *form)
  1416. {
  1417. int ret, do_sso = 0;
  1418. struct oc_form_opt_select *grp = form->authgroup_opt;
  1419. struct oc_choice *auth_choice;
  1420. struct oc_form_opt *opt;
  1421. if (!vpninfo->process_auth_form) {
  1422. vpn_progress(vpninfo, PRG_ERR, _("No form handler; cannot authenticate.\n"));
  1423. return OC_FORM_RESULT_ERR;
  1424. }
  1425. if (!form->auth_id) {
  1426. vpn_progress(vpninfo, PRG_ERR, _("No form ID. This is a bug in OpenConnect's authentication code.\n"));
  1427. return OC_FORM_RESULT_ERR;
  1428. }
  1429. retry:
  1430. auth_choice = NULL;
  1431. if (grp && grp->nr_choices) {
  1432. /* Set group selection from authgroup */
  1433. if (vpninfo->authgroup) {
  1434. int i;
  1435. for (i = 0; i < grp->nr_choices; i++)
  1436. if (!strcmp(grp->choices[i]->name, vpninfo->authgroup))
  1437. form->authgroup_selection = i;
  1438. }
  1439. auth_choice = grp->choices[form->authgroup_selection];
  1440. }
  1441. for (opt = form->opts; opt; opt = opt->next) {
  1442. int second_auth = opt->flags & OC_FORM_OPT_SECOND_AUTH;
  1443. opt->flags &= ~OC_FORM_OPT_IGNORE;
  1444. if (opt->type == OC_FORM_OPT_SSO_TOKEN) {
  1445. do_sso = 1;
  1446. continue;
  1447. }
  1448. if (!auth_choice ||
  1449. (opt->type != OC_FORM_OPT_TEXT && opt->type != OC_FORM_OPT_PASSWORD))
  1450. continue;
  1451. if (auth_choice->noaaa ||
  1452. (!auth_choice->second_auth && second_auth))
  1453. opt->flags |= OC_FORM_OPT_IGNORE;
  1454. else if (!strcmp(opt->name, "secondary_username") && second_auth) {
  1455. if (auth_choice->secondary_username) {
  1456. free(opt->_value);
  1457. opt->_value = strdup(auth_choice->secondary_username);
  1458. }
  1459. if (!auth_choice->secondary_username_editable)
  1460. opt->flags |= OC_FORM_OPT_IGNORE;
  1461. }
  1462. }
  1463. ret = vpninfo->process_auth_form(vpninfo->cbdata, form);
  1464. if (ret == OC_FORM_RESULT_NEWGROUP &&
  1465. form->authgroup_opt &&
  1466. form->authgroup_opt->form._value) {
  1467. free(vpninfo->authgroup);
  1468. vpninfo->authgroup = strdup(form->authgroup_opt->form._value);
  1469. if (!vpninfo->xmlpost)
  1470. goto retry;
  1471. }
  1472. if (ret == OC_FORM_RESULT_CANCELLED || ret < 0)
  1473. nuke_opt_values(form->opts);
  1474. if (do_sso) {
  1475. free(vpninfo->sso_cookie_value);
  1476. free(vpninfo->sso_username);
  1477. vpninfo->sso_cookie_value = NULL;
  1478. vpninfo->sso_username = NULL;
  1479. /* Handle the special Cisco external browser mode */
  1480. if (vpninfo->sso_browser_mode && !strcmp(vpninfo->sso_browser_mode, "external")) {
  1481. ret = handle_external_browser(vpninfo);
  1482. } else if (vpninfo->open_webview) {
  1483. ret = vpninfo->open_webview(vpninfo, vpninfo->sso_login, vpninfo->cbdata);
  1484. } else {
  1485. vpn_progress(vpninfo, PRG_ERR,
  1486. _("No SSO handler\n")); /* XX: print more debugging info */
  1487. ret = -EINVAL;
  1488. }
  1489. if (!ret) {
  1490. for (opt = form->opts; opt; opt = opt->next) {
  1491. if (opt->type == OC_FORM_OPT_SSO_TOKEN) {
  1492. free(opt->_value);
  1493. opt->_value = vpninfo->sso_cookie_value;
  1494. vpninfo->sso_cookie_value = NULL;
  1495. } else if (opt->type == OC_FORM_OPT_SSO_USER) {
  1496. free(opt->_value);
  1497. opt->_value = vpninfo->sso_username;
  1498. vpninfo->sso_username = NULL;
  1499. }
  1500. }
  1501. }
  1502. free(vpninfo->sso_username);
  1503. vpninfo->sso_username = NULL;
  1504. free(vpninfo->sso_cookie_value);
  1505. vpninfo->sso_cookie_value = NULL;
  1506. free(vpninfo->sso_browser_mode);
  1507. vpninfo->sso_browser_mode = NULL;
  1508. }
  1509. return ret;
  1510. }
  1511. void openconnect_set_webview_callback(struct openconnect_info *vpninfo,
  1512. openconnect_open_webview_vfn webview_fn)
  1513. {
  1514. vpninfo->open_webview = webview_fn;
  1515. vpninfo->try_http_auth = 0;
  1516. }
  1517. void openconnect_set_external_browser_callback(struct openconnect_info *vpninfo,
  1518. openconnect_open_webview_vfn browser_fn)
  1519. {
  1520. vpninfo->open_ext_browser = browser_fn;
  1521. vpninfo->try_http_auth = 0;
  1522. }
  1523. int openconnect_webview_load_changed(struct openconnect_info *vpninfo,
  1524. const struct oc_webview_result *result)
  1525. {
  1526. if (!vpninfo || !result)
  1527. return -EINVAL;
  1528. if (vpninfo->proto->sso_detect_done)
  1529. return (vpninfo->proto->sso_detect_done)(vpninfo, result);
  1530. return -EOPNOTSUPP;
  1531. }