main.c 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997
  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. * Author: David Woodhouse <dwmw2@infradead.org>
  9. *
  10. * 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. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. */
  19. #include <config.h>
  20. #include "openconnect-internal.h"
  21. #ifdef HAVE_GETLINE
  22. /* Various BSD systems require this for getline() to be visible */
  23. #define _WITH_GETLINE
  24. #endif
  25. #include <getopt.h>
  26. #include <fcntl.h>
  27. #include <unistd.h>
  28. #include <inttypes.h>
  29. #include <sys/types.h>
  30. #include <locale.h>
  31. #ifdef HAVE_STRINGS_H
  32. #include <strings.h>
  33. #endif
  34. #ifdef LIBPROXY_HDR
  35. #include LIBPROXY_HDR
  36. #endif
  37. #ifdef _WIN32
  38. #include <shlwapi.h>
  39. #include <wtypes.h>
  40. #include <wincon.h>
  41. #else
  42. #include <sys/utsname.h>
  43. #include <pwd.h>
  44. #include <termios.h>
  45. #endif
  46. #include <stdio.h>
  47. #include <stdarg.h>
  48. #include <stdlib.h>
  49. #include <signal.h>
  50. #include <string.h>
  51. #include <errno.h>
  52. #include <time.h>
  53. #ifdef HAVE_NL_LANGINFO
  54. #include <langinfo.h>
  55. static const char *legacy_charset;
  56. #endif
  57. static int write_new_config(void *_vpninfo,
  58. const char *buf, int buflen);
  59. static void __attribute__ ((format(printf, 3, 4)))
  60. write_progress(void *_vpninfo, int level, const char *fmt, ...);
  61. static int validate_peer_cert(void *_vpninfo, const char *reason);
  62. static int process_auth_form_cb(void *_vpninfo,
  63. struct oc_auth_form *form);
  64. static void init_token(struct openconnect_info *vpninfo,
  65. oc_token_mode_t token_mode, const char *token_str);
  66. /* A sanity check that the openconnect executable is running against a
  67. library of the same version */
  68. #define openconnect_version_str openconnect_binary_version
  69. #include <version.c>
  70. #undef openconnect_version_str
  71. static int timestamp;
  72. #ifndef _WIN32
  73. static int background;
  74. static int use_syslog; /* static variable initialised to 0 */
  75. static int wrote_pid; /* static variable initialised to 0 */
  76. static char *pidfile; /* static variable initialised to NULL */
  77. #endif
  78. static int do_passphrase_from_fsid;
  79. static int non_inter;
  80. static int cookieonly;
  81. static int allow_stdin_read;
  82. static char *token_filename;
  83. static int allowed_fingerprints;
  84. static char *ext_browser;
  85. struct accepted_cert {
  86. struct accepted_cert *next;
  87. char *fingerprint;
  88. char *host;
  89. int port;
  90. } *accepted_certs;
  91. static char *username;
  92. static char *password;
  93. static char *authgroup;
  94. static int authgroup_set;
  95. static int last_form_empty;
  96. static int sig_cmd_fd;
  97. static struct openconnect_info *sig_vpninfo;
  98. static void add_form_field(char *field);
  99. #ifdef __ANDROID__
  100. #include <android/log.h>
  101. static void __attribute__ ((format(printf, 3, 4)))
  102. syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
  103. {
  104. struct openconnect_info *vpninfo;
  105. static int l[4] = {
  106. ANDROID_LOG_ERROR, /* PRG_ERR */
  107. ANDROID_LOG_INFO, /* PRG_INFO */
  108. ANDROID_LOG_DEBUG, /* PRG_DEBUG */
  109. ANDROID_LOG_DEBUG /* PRG_TRACE */
  110. };
  111. va_list args, args2;
  112. if (vpninfo->verbose >= level) {
  113. va_start(args, fmt);
  114. va_copy(args2, args);
  115. __android_log_vprint(l[level], "openconnect", fmt, args);
  116. /* Android wants it to stderr too, so the GUI can scrape
  117. it and display it as well as going to syslog */
  118. vfprintf(stderr, fmt, args2);
  119. va_end(args);
  120. va_end(args2);
  121. }
  122. }
  123. #define openlog(...) /* */
  124. #elif defined(_WIN32) || defined(__native_client__)
  125. /*
  126. * FIXME: Perhaps we could implement syslog_progress() using these APIs:
  127. * https://docs.microsoft.com/en-us/windows/win32/etw/tracing-events
  128. */
  129. #else /* !__ANDROID__ && !_WIN32 && !__native_client__ */
  130. #include <syslog.h>
  131. static void __attribute__ ((format(printf, 3, 4)))
  132. syslog_progress(void *_vpninfo, int level, const char *fmt, ...)
  133. {
  134. struct openconnect_info *vpninfo = _vpninfo;
  135. int priority = level ? LOG_INFO : LOG_NOTICE;
  136. va_list args;
  137. if (vpninfo->verbose >= level) {
  138. va_start(args, fmt);
  139. vsyslog(priority, fmt, args);
  140. va_end(args);
  141. }
  142. }
  143. #endif
  144. enum {
  145. OPT_AUTHENTICATE = 0x100,
  146. OPT_AUTHGROUP,
  147. OPT_BASEMTU,
  148. OPT_CAFILE,
  149. OPT_COMPRESSION,
  150. OPT_CONFIGFILE,
  151. OPT_COOKIEONLY,
  152. OPT_COOKIE_ON_STDIN,
  153. OPT_CSD_USER,
  154. OPT_CSD_WRAPPER,
  155. OPT_CIPHERSUITES,
  156. OPT_DISABLE_IPV6,
  157. OPT_DTLS_CIPHERS,
  158. OPT_DTLS12_CIPHERS,
  159. OPT_DUMP_HTTP,
  160. OPT_EXT_BROWSER,
  161. OPT_FORCE_DPD,
  162. OPT_FORCE_TROJAN,
  163. OPT_GNUTLS_DEBUG,
  164. OPT_JUNIPER,
  165. OPT_KEY_PASSWORD_FROM_FSID,
  166. OPT_LIBPROXY,
  167. OPT_NO_CERT_CHECK,
  168. OPT_NO_DTLS,
  169. OPT_NO_HTTP_KEEPALIVE,
  170. OPT_NO_SYSTEM_TRUST,
  171. OPT_NO_PASSWD,
  172. OPT_NO_PROXY,
  173. OPT_NO_XMLPOST,
  174. OPT_PIDFILE,
  175. OPT_PASSWORD_ON_STDIN,
  176. OPT_PRINTCOOKIE,
  177. OPT_RECONNECT_TIMEOUT,
  178. OPT_SERVERCERT,
  179. OPT_RESOLVE,
  180. OPT_USERAGENT,
  181. OPT_NON_INTER,
  182. OPT_DTLS_LOCAL_PORT,
  183. OPT_TOKEN_MODE,
  184. OPT_TOKEN_SECRET,
  185. OPT_OS,
  186. OPT_TIMESTAMP,
  187. OPT_PFS,
  188. OPT_ALLOW_INSECURE_CRYPTO,
  189. OPT_PROXY_AUTH,
  190. OPT_HTTP_AUTH,
  191. OPT_LOCAL_HOSTNAME,
  192. OPT_PROTOCOL,
  193. OPT_PASSTOS,
  194. OPT_VERSION,
  195. OPT_SERVER,
  196. OPT_MULTICERT_CERT,
  197. OPT_MULTICERT_KEY,
  198. OPT_MULTICERT_KEY_PASSWORD,
  199. };
  200. #ifdef __sun__
  201. /*
  202. * The 'name' field in Solaris 'struct option' lacks the 'const', and causes
  203. * lots of warnings unless we cast it... https://www.illumos.org/issues/1881
  204. */
  205. #define OPTION(name, arg, abbrev) {(char *)name, arg, NULL, abbrev}
  206. #else
  207. #define OPTION(name, arg, abbrev) {name, arg, NULL, abbrev}
  208. #endif
  209. static const struct option long_options[] = {
  210. #ifndef _WIN32
  211. OPTION("background", 0, 'b'),
  212. OPTION("pid-file", 1, OPT_PIDFILE),
  213. OPTION("setuid", 1, 'U'),
  214. OPTION("script-tun", 0, 'S'),
  215. OPTION("syslog", 0, 'l'),
  216. OPTION("csd-user", 1, OPT_CSD_USER),
  217. OPTION("csd-wrapper", 1, OPT_CSD_WRAPPER),
  218. #endif
  219. #ifdef HAVE_POSIX_SPAWN
  220. OPTION("external-browser", 1, OPT_EXT_BROWSER),
  221. #endif
  222. OPTION("pfs", 0, OPT_PFS),
  223. OPTION("allow-insecure-crypto", 0, OPT_ALLOW_INSECURE_CRYPTO),
  224. OPTION("certificate", 1, 'c'),
  225. OPTION("sslkey", 1, 'k'),
  226. OPTION("cookie", 1, 'C'),
  227. OPTION("compression", 1, OPT_COMPRESSION),
  228. OPTION("deflate", 0, 'd'),
  229. OPTION("juniper", 0, OPT_JUNIPER),
  230. OPTION("no-deflate", 0, 'D'),
  231. OPTION("cert-expire-warning", 1, 'e'),
  232. OPTION("usergroup", 1, 'g'),
  233. OPTION("help", 0, 'h'),
  234. OPTION("http-auth", 1, OPT_HTTP_AUTH),
  235. OPTION("interface", 1, 'i'),
  236. OPTION("mtu", 1, 'm'),
  237. OPTION("base-mtu", 1, OPT_BASEMTU),
  238. OPTION("script", 1, 's'),
  239. OPTION("timestamp", 0, OPT_TIMESTAMP),
  240. OPTION("passtos", 0, OPT_PASSTOS),
  241. OPTION("key-password", 1, 'p'),
  242. OPTION("proxy", 1, 'P'),
  243. OPTION("proxy-auth", 1, OPT_PROXY_AUTH),
  244. OPTION("user", 1, 'u'),
  245. OPTION("verbose", 0, 'v'),
  246. OPTION("version", 0, 'V'),
  247. OPTION("cafile", 1, OPT_CAFILE),
  248. OPTION("config", 1, OPT_CONFIGFILE),
  249. OPTION("no-dtls", 0, OPT_NO_DTLS),
  250. OPTION("authenticate", 0, OPT_AUTHENTICATE),
  251. OPTION("cookieonly", 0, OPT_COOKIEONLY),
  252. OPTION("printcookie", 0, OPT_PRINTCOOKIE),
  253. OPTION("quiet", 0, 'q'),
  254. OPTION("queue-len", 1, 'Q'),
  255. OPTION("xmlconfig", 1, 'x'),
  256. OPTION("cookie-on-stdin", 0, OPT_COOKIE_ON_STDIN),
  257. OPTION("passwd-on-stdin", 0, OPT_PASSWORD_ON_STDIN),
  258. OPTION("no-passwd", 0, OPT_NO_PASSWD),
  259. OPTION("reconnect-timeout", 1, OPT_RECONNECT_TIMEOUT),
  260. OPTION("dtls-ciphers", 1, OPT_DTLS_CIPHERS),
  261. OPTION("dtls12-ciphers", 1, OPT_DTLS12_CIPHERS),
  262. OPTION("authgroup", 1, OPT_AUTHGROUP),
  263. OPTION("servercert", 1, OPT_SERVERCERT),
  264. OPTION("resolve", 1, OPT_RESOLVE),
  265. OPTION("key-password-from-fsid", 0, OPT_KEY_PASSWORD_FROM_FSID),
  266. OPTION("useragent", 1, OPT_USERAGENT),
  267. OPTION("version-string", 1, OPT_VERSION),
  268. OPTION("local-hostname", 1, OPT_LOCAL_HOSTNAME),
  269. OPTION("disable-ipv6", 0, OPT_DISABLE_IPV6),
  270. OPTION("no-proxy", 0, OPT_NO_PROXY),
  271. OPTION("libproxy", 0, OPT_LIBPROXY),
  272. OPTION("no-http-keepalive", 0, OPT_NO_HTTP_KEEPALIVE),
  273. OPTION("no-cert-check", 0, OPT_NO_CERT_CHECK),
  274. OPTION("force-dpd", 1, OPT_FORCE_DPD),
  275. OPTION("force-trojan", 1, OPT_FORCE_TROJAN),
  276. OPTION("non-inter", 0, OPT_NON_INTER),
  277. OPTION("dtls-local-port", 1, OPT_DTLS_LOCAL_PORT),
  278. OPTION("token-mode", 1, OPT_TOKEN_MODE),
  279. OPTION("token-secret", 1, OPT_TOKEN_SECRET),
  280. OPTION("os", 1, OPT_OS),
  281. OPTION("no-xmlpost", 0, OPT_NO_XMLPOST),
  282. OPTION("dump-http-traffic", 0, OPT_DUMP_HTTP),
  283. OPTION("no-system-trust", 0, OPT_NO_SYSTEM_TRUST),
  284. OPTION("protocol", 1, OPT_PROTOCOL),
  285. OPTION("form-entry", 1, 'F'),
  286. #ifdef OPENCONNECT_GNUTLS
  287. OPTION("gnutls-debug", 1, OPT_GNUTLS_DEBUG),
  288. OPTION("gnutls-priority", 1, OPT_CIPHERSUITES),
  289. #elif defined(OPENCONNECT_OPENSSL)
  290. OPTION("openssl-ciphers", 1, OPT_CIPHERSUITES),
  291. #endif
  292. OPTION("server", 1, OPT_SERVER),
  293. OPTION("mca-certificate", 1, OPT_MULTICERT_CERT),
  294. OPTION("mca-key", 1, OPT_MULTICERT_KEY),
  295. OPTION("mca-key-password", 1, OPT_MULTICERT_KEY_PASSWORD),
  296. OPTION(NULL, 0, 0)
  297. };
  298. #ifdef OPENCONNECT_GNUTLS
  299. static void oc_gnutls_log_func(int level, const char *str)
  300. {
  301. fputs(str, stderr);
  302. }
  303. #endif
  304. #ifdef _WIN32
  305. static int __attribute__ ((format(printf, 2, 0)))
  306. vfprintf_utf8(FILE *f, const char *fmt, va_list args)
  307. {
  308. HANDLE h = GetStdHandle(f == stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
  309. wchar_t wbuf[1024];
  310. char buf[1024];
  311. int bytes, wchars;
  312. /* No need to NUL-terminate strings here */
  313. bytes = _vsnprintf(buf, sizeof(buf), fmt, args);
  314. if (bytes < 0)
  315. return bytes;
  316. if (bytes > sizeof(buf))
  317. bytes = sizeof(buf);
  318. wchars = MultiByteToWideChar(CP_UTF8, 0, buf, bytes, wbuf, ARRAY_SIZE(wbuf));
  319. if (!wchars)
  320. return -1;
  321. /*
  322. * If writing to console fails, that's probably due to redirection.
  323. * Convert to console CP and write to the FH, following the example of
  324. * https://github.com/wine-mirror/wine/blob/e909986e6e/programs/whoami/main.c#L33-L49
  325. */
  326. if (!WriteConsoleW(h, wbuf, wchars, NULL, NULL)) {
  327. bytes = WideCharToMultiByte(GetConsoleOutputCP(), 0, wbuf, wchars,
  328. buf, sizeof(buf), NULL, NULL);
  329. if (!bytes)
  330. return -1;
  331. return fwrite(buf, 1, bytes, f);
  332. }
  333. return bytes;
  334. }
  335. static int __attribute__ ((format(printf, 2, 3)))
  336. fprintf_utf8(FILE *f, const char *fmt, ...)
  337. {
  338. va_list args;
  339. int ret;
  340. va_start(args, fmt);
  341. ret = vfprintf_utf8(f, fmt, args);
  342. va_end(args);
  343. return ret;
  344. }
  345. static wchar_t **argv_w;
  346. /* This isn't so much "convert" the arg to UTF-8, as go grubbing
  347. * around in the real UTF-16 command line and find the corresponding
  348. * argument *there*, and convert *that* to UTF-8. Ick. But the
  349. * alternative is to implement wgetopt(), and that's even more horrid. */
  350. static char *convert_arg_to_utf8(char **argv, char *arg)
  351. {
  352. char *utf8;
  353. int chars;
  354. int offset;
  355. if (!argv_w) {
  356. int argc_w;
  357. argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
  358. if (!argv_w) {
  359. char *errstr = openconnect__win32_strerror(GetLastError());
  360. fprintf(stderr, _("CommandLineToArgv() failed: %s\n"),
  361. errstr);
  362. free(errstr);
  363. exit(1);
  364. }
  365. }
  366. offset = arg - argv[optind - 1];
  367. /* Sanity check */
  368. if (offset < 0 || offset >= strlen(argv[optind - 1]) ||
  369. (offset && (argv[optind - 1][offset-1] != '=' ||
  370. argv_w[optind - 1][offset - 1] != '='))) {
  371. fprintf(stderr, _("Fatal error in command line handling\n"));
  372. exit(1);
  373. }
  374. chars = WideCharToMultiByte(CP_UTF8, 0, argv_w[optind-1] + offset, -1,
  375. NULL, 0, NULL, NULL);
  376. utf8 = malloc(chars);
  377. if (!utf8)
  378. return arg;
  379. WideCharToMultiByte(CP_UTF8, 0, argv_w[optind-1] + offset, -1, utf8,
  380. chars, NULL, NULL);
  381. return utf8;
  382. }
  383. #undef fprintf
  384. #undef vfprintf
  385. #define fprintf fprintf_utf8
  386. #define vfprintf vfprintf_utf8
  387. #define is_arg_utf8(str) (0)
  388. static void read_stdin(char **string, int hidden, int allow_fail)
  389. {
  390. CONSOLE_READCONSOLE_CONTROL rcc = { sizeof(rcc), 0, 13, 0 };
  391. HANDLE stdinh = GetStdHandle(STD_INPUT_HANDLE);
  392. DWORD cmode, nr_read, last_error;
  393. wchar_t wbuf[1024];
  394. char *buf;
  395. if (GetConsoleMode(stdinh, &cmode)) {
  396. if (hidden)
  397. SetConsoleMode(stdinh, cmode & (~ENABLE_ECHO_INPUT));
  398. SetLastError(0);
  399. if (!ReadConsoleW(stdinh, wbuf, ARRAY_SIZE(wbuf), &nr_read, &rcc)) {
  400. char *errstr = openconnect__win32_strerror(GetLastError());
  401. fprintf(stderr, _("ReadConsole() failed: %s\n"), errstr);
  402. free(errstr);
  403. *string = NULL;
  404. if (hidden)
  405. SetConsoleMode(stdinh, cmode);
  406. return;
  407. }
  408. last_error = GetLastError();
  409. if (hidden)
  410. SetConsoleMode(stdinh, cmode);
  411. if (!nr_read) {
  412. if (allow_fail) {
  413. *string = NULL;
  414. return;
  415. } else {
  416. if (last_error == ERROR_OPERATION_ABORTED) {
  417. fprintf(stderr, _("Operation aborted by user\n"));
  418. } else {
  419. /* Should never happen */
  420. fprintf(stderr, _("ReadConsole() didn't read any input\n"));
  421. }
  422. exit(1);
  423. }
  424. }
  425. } else {
  426. /* Not a console; maybe reading from a piped stdin? */
  427. if (!fgetws(wbuf, ARRAY_SIZE(wbuf), stdin)) {
  428. perror(_("fgetws (stdin)"));
  429. *string = NULL;
  430. return;
  431. }
  432. nr_read = wcslen(wbuf);
  433. }
  434. if (nr_read >= 2 && wbuf[nr_read - 1] == 10 && wbuf[nr_read - 2] == 13) {
  435. /* remove trailing "\r\n" */
  436. wbuf[nr_read - 2] = 0;
  437. nr_read -= 2;
  438. } else if (nr_read >= 1 && wbuf[nr_read - 1] == 10) {
  439. /* remove trailing "\n" */
  440. wbuf[nr_read - 1] = 0;
  441. nr_read -= 1;
  442. }
  443. nr_read = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL, NULL);
  444. if (!nr_read) {
  445. char *errstr = openconnect__win32_strerror(GetLastError());
  446. fprintf(stderr, _("Error converting console input: %s\n"),
  447. errstr);
  448. free(errstr);
  449. return;
  450. }
  451. buf = malloc(nr_read);
  452. if (!buf) {
  453. perror(_("Allocation failure for string from stdin"));
  454. exit(1);
  455. }
  456. if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, nr_read, NULL, NULL)) {
  457. char *errstr = openconnect__win32_strerror(GetLastError());
  458. fprintf(stderr, _("Error converting console input: %s\n"),
  459. errstr);
  460. free(errstr);
  461. free(buf);
  462. return;
  463. }
  464. *string = buf;
  465. }
  466. #elif defined(HAVE_ICONV)
  467. #include <iconv.h>
  468. static int is_ascii(char *str)
  469. {
  470. while (str && *str) {
  471. if ((unsigned char)*str > 0x7f)
  472. return 0;
  473. str++;
  474. }
  475. return 1;
  476. }
  477. static int __attribute__ ((format(printf, 2, 0)))
  478. vfprintf_utf8(FILE *f, const char *fmt, va_list args)
  479. {
  480. char *utf8_str;
  481. iconv_t ic;
  482. int ret;
  483. char outbuf[80];
  484. ICONV_CONST char *ic_in;
  485. char *ic_out;
  486. size_t insize, outsize;
  487. if (!legacy_charset)
  488. return vfprintf(f, fmt, args);
  489. ret = vasprintf(&utf8_str, fmt, args);
  490. if (ret < 0)
  491. return -1;
  492. if (is_ascii(utf8_str))
  493. return fwrite(utf8_str, 1, strlen(utf8_str), f);
  494. ic = iconv_open(legacy_charset, "UTF-8");
  495. if (ic == (iconv_t) -1) {
  496. /* Better than nothing... */
  497. ret = fprintf(f, "%s", utf8_str);
  498. free(utf8_str);
  499. return ret;
  500. }
  501. ic_in = utf8_str;
  502. insize = strlen(utf8_str);
  503. ret = 0;
  504. while (insize) {
  505. ic_out = outbuf;
  506. outsize = sizeof(outbuf) - 1;
  507. if (iconv(ic, &ic_in, &insize, &ic_out, &outsize) == (size_t)-1) {
  508. if (errno == EILSEQ) {
  509. do {
  510. ic_in++;
  511. insize--;
  512. } while (insize && (ic_in[0] & 0xc0) == 0x80);
  513. ic_out[0] = '?';
  514. outsize--;
  515. } else if (errno != E2BIG)
  516. break;
  517. }
  518. ret += fwrite(outbuf, 1, sizeof(outbuf) - 1 - outsize, f);
  519. }
  520. iconv_close(ic);
  521. return ret;
  522. }
  523. static int __attribute__ ((format(printf, 2, 3)))
  524. fprintf_utf8(FILE *f, const char *fmt, ...)
  525. {
  526. va_list args;
  527. int ret;
  528. va_start(args, fmt);
  529. ret = vfprintf_utf8(f, fmt, args);
  530. va_end(args);
  531. return ret;
  532. }
  533. static char *convert_to_utf8(char *legacy, int free_it)
  534. {
  535. char *utf8_str;
  536. iconv_t ic;
  537. ICONV_CONST char *ic_in;
  538. char *ic_out;
  539. size_t insize, outsize;
  540. if (!legacy_charset || is_ascii(legacy))
  541. return legacy;
  542. ic = iconv_open("UTF-8", legacy_charset);
  543. if (ic == (iconv_t) -1)
  544. return legacy;
  545. insize = strlen(legacy) + 1;
  546. ic_in = legacy;
  547. outsize = insize;
  548. ic_out = utf8_str = malloc(outsize);
  549. if (!utf8_str) {
  550. enomem:
  551. iconv_close(ic);
  552. return legacy;
  553. }
  554. while (insize) {
  555. if (iconv(ic, &ic_in, &insize, &ic_out, &outsize) == (size_t)-1) {
  556. if (errno == E2BIG) {
  557. int outlen = ic_out - utf8_str;
  558. realloc_inplace(utf8_str, outlen + 10);
  559. if (!utf8_str)
  560. goto enomem;
  561. ic_out = utf8_str + outlen;
  562. outsize = 10;
  563. } else {
  564. /* Should never happen */
  565. perror("iconv");
  566. free(utf8_str);
  567. goto enomem;
  568. }
  569. }
  570. }
  571. iconv_close(ic);
  572. if (free_it)
  573. free(legacy);
  574. return utf8_str;
  575. }
  576. #define fprintf fprintf_utf8
  577. #define vfprintf vfprintf_utf8
  578. #define convert_arg_to_utf8(av, l) convert_to_utf8((l), 0)
  579. #define is_arg_utf8(a) (!legacy_charset || is_ascii(a))
  580. #else
  581. #define convert_to_utf8(l,f) (l)
  582. #define convert_arg_to_utf8(av, l) (l)
  583. #define is_arg_utf8(a) (1)
  584. #endif
  585. static void helpmessage(void)
  586. {
  587. printf(_("For assistance with OpenConnect, please see the web page at\n"
  588. " %s\n"),
  589. "https://www.infradead.org/openconnect/mail.html");
  590. }
  591. static void print_build_opts(void)
  592. {
  593. const char comma[] = ", ", *sep = comma + 1;
  594. printf(_("Using %s. Features present:"), openconnect_get_tls_library_version());
  595. if (openconnect_has_tss_blob_support()) {
  596. printf("%sTPM", sep);
  597. sep = comma;
  598. }
  599. if (openconnect_has_tss2_blob_support()) {
  600. printf("%sTPMv2", sep);
  601. sep = comma;
  602. }
  603. #if defined(OPENCONNECT_OPENSSL) && defined(HAVE_ENGINE)
  604. else {
  605. printf("%sTPM (%s)", sep, _("OpenSSL ENGINE not present"));
  606. sep = comma;
  607. }
  608. #endif
  609. if (openconnect_has_pkcs11_support()) {
  610. printf("%sPKCS#11", sep);
  611. sep = comma;
  612. }
  613. if (openconnect_has_stoken_support()) {
  614. printf("%sRSA software token", sep);
  615. sep = comma;
  616. }
  617. switch(openconnect_has_oath_support()) {
  618. case 2:
  619. printf("%sHOTP software token", sep);
  620. sep = comma;
  621. /* fall through */
  622. case 1:
  623. printf("%sTOTP software token", sep);
  624. sep = comma;
  625. }
  626. if (openconnect_has_yubioath_support()) {
  627. printf("%sYubikey OATH", sep);
  628. sep = comma;
  629. }
  630. if (openconnect_has_system_key_support()) {
  631. printf("%sSystem keys", sep);
  632. sep = comma;
  633. }
  634. #ifdef HAVE_DTLS
  635. printf("%sDTLS", sep);
  636. #endif
  637. #ifdef HAVE_ESP
  638. printf("%sESP", sep);
  639. #endif
  640. printf("\n");
  641. #if !defined(HAVE_DTLS) || !defined(HAVE_ESP)
  642. printf(_("WARNING: This binary lacks DTLS and/or ESP support. Performance will be impaired.\n"));
  643. #endif
  644. }
  645. static void print_supported_protocols(void)
  646. {
  647. const char comma[] = ", ", *sep = comma + 1;
  648. struct oc_vpn_proto *protos, *p;
  649. int n;
  650. n = openconnect_get_supported_protocols(&protos);
  651. if (n>=0) {
  652. printf(_("Supported protocols:"));
  653. for (p=protos; n; p++, n--) {
  654. printf("%s%s%s", sep, p->name, p==protos ? _(" (default)") : "");
  655. sep = comma;
  656. }
  657. printf("\n");
  658. free(protos);
  659. }
  660. }
  661. static void print_supported_protocols_usage(void)
  662. {
  663. struct oc_vpn_proto *protos, *p;
  664. int n;
  665. n = openconnect_get_supported_protocols(&protos);
  666. if (n>=0) {
  667. printf("\n%s:\n", _("Set VPN protocol"));
  668. for (p=protos; n; p++, n--)
  669. printf(" --protocol=%-16s %s%s\n",
  670. p->name, p->description, p==protos ? _(" (default)") : "");
  671. openconnect_free_supported_protocols(protos);
  672. }
  673. }
  674. #ifndef _WIN32
  675. static const char default_vpncscript[] = DEFAULT_VPNCSCRIPT;
  676. static void read_stdin(char **string, int hidden, int allow_fail)
  677. {
  678. char *c, *got, *buf = malloc(1025);
  679. int fd = fileno(stdin);
  680. struct termios t;
  681. if (!buf) {
  682. fprintf(stderr, _("Allocation failure for string from stdin\n"));
  683. exit(1);
  684. }
  685. if (hidden) {
  686. tcgetattr(fd, &t);
  687. t.c_lflag &= ~ECHO;
  688. tcsetattr(fd, TCSANOW, &t);
  689. }
  690. got = fgets(buf, 1025, stdin);
  691. if (hidden) {
  692. t.c_lflag |= ECHO;
  693. tcsetattr(fd, TCSANOW, &t);
  694. fprintf(stderr, "\n");
  695. }
  696. if (!got) {
  697. if (allow_fail) {
  698. *string = NULL;
  699. free(buf);
  700. return;
  701. } else {
  702. perror(_("fgets (stdin)"));
  703. exit(1);
  704. }
  705. }
  706. c = strchr(buf, '\n');
  707. if (c)
  708. *c = 0;
  709. *string = convert_to_utf8(buf, 1);
  710. }
  711. static void handle_signal(int sig)
  712. {
  713. char cmd;
  714. switch (sig) {
  715. case SIGTERM:
  716. cmd = OC_CMD_CANCEL;
  717. break;
  718. case SIGHUP:
  719. cmd = OC_CMD_DETACH;
  720. break;
  721. case SIGINT:
  722. #ifdef INSECURE_DEBUGGING
  723. cmd = OC_CMD_DETACH;
  724. #else
  725. cmd = OC_CMD_CANCEL;
  726. #endif
  727. break;
  728. case SIGUSR1:
  729. cmd = OC_CMD_STATS;
  730. break;
  731. case SIGUSR2:
  732. default:
  733. cmd = OC_CMD_PAUSE;
  734. break;
  735. }
  736. if (write(sig_cmd_fd, &cmd, 1) < 0) {
  737. /* suppress warn_unused_result */
  738. }
  739. if (sig_vpninfo)
  740. sig_vpninfo->need_poll_cmd_fd = 1;
  741. }
  742. static int checked_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
  743. {
  744. int ret = sigaction(signum, act, oldact);
  745. if (ret)
  746. fprintf(stderr, _("WARNING: Cannot set handler for signal %d: %s\n"),
  747. signum, strerror(errno));
  748. return ret;
  749. }
  750. #else /* _WIN32 */
  751. static const char *default_vpncscript;
  752. static void set_default_vpncscript(void)
  753. {
  754. if (PathIsRelative(DEFAULT_VPNCSCRIPT)) {
  755. char *c = strrchr(_pgmptr, '\\');
  756. if (!c) {
  757. fprintf(stderr, _("Cannot process this executable path \"%s\""),
  758. _pgmptr);
  759. exit(1);
  760. }
  761. if (asprintf((char **)&default_vpncscript, "%.*s%s",
  762. (int)(c - _pgmptr + 1), _pgmptr,
  763. DEFAULT_VPNCSCRIPT) < 0) {
  764. fprintf(stderr, _("Allocation for vpnc-script path failed\n"));
  765. exit(1);
  766. }
  767. } else {
  768. default_vpncscript = "cscript " DEFAULT_VPNCSCRIPT;
  769. }
  770. }
  771. static BOOL WINAPI console_ctrl_handler(DWORD dwCtrlType)
  772. {
  773. char cmd;
  774. /* Note: this function always runs in a separate thread */
  775. switch (dwCtrlType) {
  776. case CTRL_C_EVENT:
  777. case CTRL_CLOSE_EVENT:
  778. case CTRL_LOGOFF_EVENT:
  779. case CTRL_SHUTDOWN_EVENT:
  780. cmd = OC_CMD_CANCEL;
  781. break;
  782. case CTRL_BREAK_EVENT:
  783. cmd = OC_CMD_DETACH;
  784. break;
  785. default:
  786. return FALSE;
  787. }
  788. /* Use send() here since, on Windows, sig_cmd_fd is a socket descriptor */
  789. send(sig_cmd_fd, &cmd, 1, 0);
  790. if (sig_vpninfo)
  791. sig_vpninfo->need_poll_cmd_fd = 1;
  792. return TRUE;
  793. }
  794. #endif
  795. #ifdef HAVE_POSIX_SPAWN
  796. static int spawn_browser(struct openconnect_info *vpninfo, const char *url, void *cbdata)
  797. {
  798. vpn_progress(vpninfo, PRG_TRACE,
  799. _("Main Spawning external browser '%s'\n"),
  800. ext_browser);
  801. pid_t pid = 0;
  802. char *browser_argv[3] = { ext_browser, (char *)url, NULL };
  803. if (posix_spawn(&pid, ext_browser, NULL, NULL, browser_argv, environ)) {
  804. vpn_perror(vpninfo, _("Spawn browser"));
  805. return -errno;
  806. }
  807. return 0;
  808. }
  809. #endif
  810. static void print_default_vpncscript(void)
  811. {
  812. printf("%s %s\n", _("Default vpnc-script (override with --script):"),
  813. default_vpncscript);
  814. }
  815. static struct oc_vpn_option *gai_overrides;
  816. static int gai_override_cb(void *cbdata, const char *node,
  817. const char *service, const struct addrinfo *hints,
  818. struct addrinfo **res)
  819. {
  820. struct openconnect_info *vpninfo = cbdata;
  821. struct oc_vpn_option *p = gai_overrides;
  822. while (p) {
  823. if (!strcmp(node, p->option)) {
  824. vpn_progress(vpninfo, PRG_TRACE, _("Override hostname '%s' to '%s'\n"),
  825. node, p->value);
  826. node = p->value;
  827. break;
  828. }
  829. p = p->next;
  830. }
  831. return getaddrinfo(node, service, hints, res);
  832. }
  833. static void usage(void)
  834. {
  835. printf(_("Usage: openconnect [options] <server>\n"));
  836. printf(_("Open client for multiple VPN protocols, version %s\n\n"), openconnect_version_str);
  837. print_build_opts();
  838. printf(" --config=CONFIGFILE %s\n", _("Read options from config file"));
  839. printf(" -V, --version %s\n", _("Report version number"));
  840. printf(" -h, --help %s\n", _("Display help text"));
  841. print_supported_protocols_usage();
  842. printf("\n%s:\n", _("Authentication"));
  843. printf(" -u, --user=NAME %s\n", _("Set login username"));
  844. printf(" --no-passwd %s\n", _("Disable password/SecurID authentication"));
  845. printf(" --non-inter %s\n", _("Do not expect user input; exit if it is required"));
  846. printf(" --passwd-on-stdin %s\n", _("Read password from standard input"));
  847. printf(" --authgroup=GROUP %s\n", _("Select GROUP from authentication dropdown (may be known"));
  848. printf(" %s\n", _("as \"realm\", \"domain\", \"gateway\"; protocol-dependent)"));
  849. printf(" -F, --form-entry=FORM:OPT=VALUE %s\n", _("Provide authentication form responses"));
  850. printf(" -c, --certificate=CERT %s\n", _("Use SSL client certificate CERT"));
  851. printf(" -k, --sslkey=KEY %s\n", _("Use SSL private key file KEY"));
  852. printf(" -e, --cert-expire-warning=DAYS %s\n", _("Warn when certificate lifetime < DAYS"));
  853. printf(" -g, --usergroup=GROUP %s\n", _("Set path of initial request URL"));
  854. printf(" -p, --key-password=PASS %s\n", _("Set key passphrase or TPM SRK PIN"));
  855. printf(" --external-browser=BROWSER %s\n", _("Set external browser executable"));
  856. printf(" --key-password-from-fsid %s\n", _("Key passphrase is fsid of file system"));
  857. printf(" --token-mode=MODE %s\n", _("Software token type: rsa, totp, hotp or oidc"));
  858. printf(" --token-secret=STRING %s\n", _("Software token secret or oidc token"));
  859. #ifndef HAVE_LIBSTOKEN
  860. printf(" %s\n", _("(NOTE: libstoken (RSA SecurID) disabled in this build)"));
  861. #endif
  862. #ifndef HAVE_LIBPCSCLITE
  863. printf(" %s\n", _("(NOTE: Yubikey OATH disabled in this build)"));
  864. #endif
  865. printf("\n%s:\n", _("Server validation"));
  866. printf(" --servercert=FINGERPRINT %s\n", _("Accept only server certificate with this fingerprint"));
  867. printf(" --no-system-trust %s\n", _("Disable default system certificate authorities"));
  868. printf(" --cafile=FILE %s\n", _("Cert file for server verification"));
  869. printf("\n%s:\n", _("Internet connectivity"));
  870. printf(" --server=SERVER %s\n", _("Set VPN server"));
  871. printf(" -P, --proxy=URL %s\n", _("Set proxy server"));
  872. printf(" --proxy-auth=METHODS %s\n", _("Set proxy authentication methods"));
  873. printf(" --no-proxy %s\n", _("Disable proxy"));
  874. printf(" --libproxy %s\n", _("Use libproxy to automatically configure proxy"));
  875. #ifndef LIBPROXY_HDR
  876. printf(" %s\n", _("(NOTE: libproxy disabled in this build)"));
  877. #endif
  878. printf(" --reconnect-timeout=SECONDS %s\n", _("Reconnection retry timeout (default is 300 seconds)"));
  879. printf(" --resolve=HOST:IP %s\n", _("Use IP when connecting to HOST"));
  880. printf(" --passtos %s\n", _("Copy TOS / TCLASS field into DTLS and ESP packets"));
  881. printf(" --dtls-local-port=PORT %s\n", _("Set local port for DTLS and ESP datagrams"));
  882. printf("\n%s:\n", _("Authentication (two-phase)"));
  883. printf(" -C, --cookie=COOKIE %s\n", _("Use authentication cookie COOKIE"));
  884. printf(" --cookie-on-stdin %s\n", _("Read cookie from standard input"));
  885. printf(" --authenticate %s\n", _("Authenticate only and print login info"));
  886. printf(" --cookieonly %s\n", _("Fetch and print cookie only; don't connect"));
  887. printf(" --printcookie %s\n", _("Print cookie before connecting"));
  888. #ifndef _WIN32
  889. printf("\n%s:\n", _("Process control"));
  890. printf(" -b, --background %s\n", _("Continue in background after startup"));
  891. printf(" --pid-file=PIDFILE %s\n", _("Write the daemon's PID to this file"));
  892. printf(" -U, --setuid=USER %s\n", _("Drop privileges after connecting"));
  893. #endif
  894. printf("\n%s:\n", _("Logging (two-phase)"));
  895. #ifndef _WIN32
  896. printf(" -l, --syslog %s\n", _("Use syslog for progress messages"));
  897. #endif
  898. printf(" -v, --verbose %s\n", _("More output"));
  899. printf(" -q, --quiet %s\n", _("Less output"));
  900. printf(" --dump-http-traffic %s\n", _("Dump HTTP authentication traffic (implies --verbose)"));
  901. printf(" --timestamp %s\n", _("Prepend timestamp to progress messages"));
  902. printf("\n%s:\n", _("VPN configuration script"));
  903. printf(" -i, --interface=IFNAME %s\n", _("Use IFNAME for tunnel interface"));
  904. printf(" -s, --script=SCRIPT %s\n", _("Shell command line for using a vpnc-compatible config script"));
  905. printf(" %s: \"%s\"\n", _("default"), default_vpncscript);
  906. #ifndef _WIN32
  907. printf(" -S, --script-tun %s\n", _("Pass traffic to 'script' program, not tun"));
  908. #endif
  909. printf("\n%s:\n", _("Tunnel control"));
  910. printf(" --disable-ipv6 %s\n", _("Do not ask for IPv6 connectivity"));
  911. printf(" -x, --xmlconfig=CONFIG %s\n", _("XML config file"));
  912. printf(" -m, --mtu=MTU %s\n", _("Request MTU from server (legacy servers only)"));
  913. printf(" --base-mtu=MTU %s\n", _("Indicate path MTU to/from server"));
  914. printf(" -d, --deflate %s\n", _("Enable stateful compression (default is stateless only)"));
  915. printf(" -D, --no-deflate %s\n", _("Disable all compression"));
  916. printf(" --force-dpd=INTERVAL %s\n", _("Set Dead Peer Detection interval (in seconds)"));
  917. printf(" --pfs %s\n", _("Require perfect forward secrecy"));
  918. printf(" --no-dtls %s\n", _("Disable DTLS and ESP"));
  919. printf(" --dtls-ciphers=LIST %s\n", _("OpenSSL ciphers to support for DTLS"));
  920. printf(" -Q, --queue-len=LEN %s\n", _("Set packet queue limit to LEN pkts"));
  921. printf("\n%s:\n", _("Local system information"));
  922. printf(" --useragent=STRING %s\n", _("HTTP header User-Agent: field"));
  923. printf(" --local-hostname=STRING %s\n", _("Local hostname to advertise to server"));
  924. printf(" --os=STRING %s\n", _("OS type to report. Allowed values are the following:"));
  925. printf(" %s\n", _("linux, linux-64, win, mac-intel, android, apple-ios"));
  926. printf(" --version-string=STRING %s\n", _("reported version string during authentication"));
  927. printf(" (%s %s)\n", _("default:"), openconnect_version_str);
  928. printf("\n%s:\n", _("Trojan binary (CSD) execution"));
  929. #ifndef _WIN32
  930. printf(" --csd-user=USER %s\n", _("Drop privileges during trojan execution"));
  931. printf(" --csd-wrapper=SCRIPT %s\n", _("Run SCRIPT instead of trojan binary"));
  932. #endif
  933. printf(" --force-trojan=INTERVAL %s\n", _("Set minimum interval between trojan runs (in seconds)"));
  934. printf("\n%s:\n", _("Server bugs"));
  935. printf(" --no-http-keepalive %s\n", _("Disable HTTP connection re-use"));
  936. printf(" --no-xmlpost %s\n", _("Do not attempt XML POST authentication"));
  937. printf(" --allow-insecure-crypto %s\n", _("Allow use of the ancient, insecure 3DES and RC4 ciphers"));
  938. printf("\n%s:\n", _("Multiple certificate authentication (MCA)"));
  939. printf(" --mca-certificate=MCACERT %s\n", _("Use MCA certificate MCACERT"));
  940. printf(" --mca-key=MCAKEY %s\n", _("Use MCA key MCAKEY"));
  941. printf(" --mca-key-password=MCAPASS %s\n", _("Passphrase MCAPASS for MCACERT/MCAKEY"));
  942. printf("\n");
  943. helpmessage();
  944. exit(1);
  945. }
  946. static FILE *config_file; /* static variable initialised to NULL */
  947. static int config_line_num; /* static variable initialised to 0 */
  948. static char *xstrdup(const char *arg)
  949. {
  950. char *ret;
  951. if (!arg)
  952. return NULL;
  953. ret = strdup(arg);
  954. if (!ret) {
  955. fprintf(stderr, _("Failed to allocate string\n"));
  956. exit(1);
  957. }
  958. return ret;
  959. }
  960. /* There are three ways to handle config_arg:
  961. *
  962. * 1. We only care about it transiently and it can be lost entirely
  963. * (e.g. vpninfo->reconnect_timeout = atoi(config_arg);
  964. * 2. We need to keep it, but it's a static string and will never be freed
  965. * so when it's part of argv[] we can use it in place (unless it needs
  966. * converting to UTF-8), but when it comes from a file we have to strdup()
  967. * because otherwise it'll be overwritten.
  968. * For this we use the keep_config_arg() macro below.
  969. * 3. It may be freed during normal operation, so we have to use strdup()
  970. * or convert_arg_to_utf8() even when it's an option from argv[].
  971. * (e.g. vpninfo->certinfo[0].password).
  972. * For this we use the dup_config_arg() macro below.
  973. */
  974. #define keep_config_arg() \
  975. (config_file ? xstrdup(config_arg) : convert_arg_to_utf8(argv, config_arg))
  976. #define dup_config_arg() __dup_config_arg(argv, config_arg)
  977. static inline char *__dup_config_arg(char **argv, char *config_arg)
  978. {
  979. char *res;
  980. if (config_file || is_arg_utf8(config_arg))
  981. return xstrdup(config_arg);
  982. res = convert_arg_to_utf8(argv, config_arg);
  983. /* Force a copy, even if conversion failed */
  984. if (res == config_arg)
  985. res = xstrdup(res);
  986. return res;
  987. }
  988. static int next_option(int argc, char **argv, char **config_arg)
  989. {
  990. /* These get re-used */
  991. static char *line_buf; /* static variable initialised to NULL */
  992. static size_t line_size; /* static variable initialised to 0 */
  993. ssize_t llen;
  994. int opt, optlen = 0;
  995. const struct option *this;
  996. char *line;
  997. int ate_equals = 0;
  998. next:
  999. if (!config_file) {
  1000. opt = getopt_long(argc, argv,
  1001. #ifdef _WIN32
  1002. "C:c:Dde:F:g:hi:k:m:P:p:Q:qs:u:Vvx:",
  1003. #else
  1004. "bC:c:Dde:F:g:hi:k:lm:P:p:Q:qSs:U:u:Vvx:",
  1005. #endif
  1006. long_options, NULL);
  1007. *config_arg = optarg;
  1008. return opt;
  1009. }
  1010. llen = getline(&line_buf, &line_size, config_file);
  1011. if (llen < 0) {
  1012. if (feof(config_file)) {
  1013. fclose(config_file);
  1014. config_file = NULL;
  1015. goto next;
  1016. }
  1017. fprintf(stderr, _("Failed to get line from config file: %s\n"),
  1018. strerror(errno));
  1019. exit(1);
  1020. }
  1021. line = line_buf;
  1022. /* Strip the trailing newline (coping with DOS newlines) */
  1023. if (llen && line[llen-1] == '\n')
  1024. line[--llen] = 0;
  1025. if (llen && line[llen-1] == '\r')
  1026. line[--llen] = 0;
  1027. /* Skip and leading whitespace */
  1028. while (line[0] == ' ' || line[0] == '\t' || line[0] == '\r')
  1029. line++;
  1030. /* Ignore comments and empty lines */
  1031. if (!line[0] || line[0] == '#') {
  1032. config_line_num++;
  1033. goto next;
  1034. }
  1035. /* Try to match on a known option... naïvely. This could be improved. */
  1036. for (this = long_options; this->name; this++) {
  1037. optlen = strlen(this->name);
  1038. /* If the option isn't followed by whitespace or NUL, or
  1039. perhaps an equals sign if the option takes an argument,
  1040. then it's not a match */
  1041. if (!strncmp(this->name, line, optlen) &&
  1042. (!line[optlen] || line[optlen] == ' ' || line[optlen] == '\t' ||
  1043. line[optlen] == '='))
  1044. break;
  1045. }
  1046. if (!this->name) {
  1047. char *l;
  1048. for (l = line; *l && *l != ' ' && *l != '\t'; l++)
  1049. ;
  1050. *l = 0;
  1051. fprintf(stderr, _("Unrecognised option at line %d: '%s'\n"),
  1052. config_line_num, line);
  1053. return '?';
  1054. }
  1055. line += optlen;
  1056. while (*line == ' ' || *line == '\t' ||
  1057. (*line == '=' && this->has_arg && !ate_equals && ++ate_equals))
  1058. line++;
  1059. if (!this->has_arg && *line) {
  1060. fprintf(stderr, _("Option '%s' does not take an argument at line %d\n"),
  1061. this->name, config_line_num);
  1062. return '?';
  1063. } else if (this->has_arg == 1 && !*line) {
  1064. fprintf(stderr, _("Option '%s' requires an argument at line %d\n"),
  1065. this->name, config_line_num);
  1066. return '?';
  1067. } else if (this->has_arg == 2 && !*line) {
  1068. line = NULL;
  1069. }
  1070. config_line_num++;
  1071. *config_arg = line;
  1072. return this->val;
  1073. }
  1074. static void assert_nonnull_config_arg(const char *opt, const char *config_arg)
  1075. {
  1076. if (!config_arg) { /* Should never happen */
  1077. fprintf(stderr, _("Internal error; option '%s' unexpectedly yielded null config_arg\n"),
  1078. opt);
  1079. exit(1); /* Shut static analyzer up */
  1080. }
  1081. }
  1082. #ifndef _WIN32
  1083. static void get_uids(const char *config_arg, uid_t *uid, gid_t *gid)
  1084. {
  1085. char *strend;
  1086. struct passwd *pw;
  1087. *uid = strtol(config_arg, &strend, 0);
  1088. if (strend[0]) {
  1089. pw = getpwnam(config_arg);
  1090. if (!pw) {
  1091. fprintf(stderr, _("Invalid user \"%s\": %s\n"),
  1092. config_arg, strerror(errno));
  1093. exit(1);
  1094. }
  1095. *uid = pw->pw_uid;
  1096. *gid = pw->pw_gid;
  1097. } else {
  1098. pw = getpwuid(*uid);
  1099. if (!pw) {
  1100. fprintf(stderr, _("Invalid user ID \"%d\": %s\n"),
  1101. (int)*uid, strerror(errno));
  1102. exit(1);
  1103. }
  1104. *gid = pw->pw_gid;
  1105. }
  1106. }
  1107. #endif
  1108. static int complete_words(const char *comp_opt, int prefixlen, ...)
  1109. {
  1110. int partlen = strlen(comp_opt + prefixlen);
  1111. va_list vl;
  1112. char *check;
  1113. va_start(vl, prefixlen);
  1114. while ( (check = va_arg(vl, char *)) ) {
  1115. if (!strncmp(comp_opt + prefixlen, check, partlen))
  1116. printf("%.*s%s\n", prefixlen, comp_opt, check);
  1117. }
  1118. va_end(vl);
  1119. return 0;
  1120. }
  1121. static int autocomplete_special(const char *verb, const char *prefix,
  1122. int prefixlen, const char *filterpat)
  1123. {
  1124. printf("%s\n", verb);
  1125. printf("%s\n", filterpat ? : "''");
  1126. if (prefixlen)
  1127. printf("%.*s\n", prefixlen, prefix);
  1128. return 0;
  1129. }
  1130. static int autocomplete(int argc, char **argv)
  1131. {
  1132. int opt;
  1133. const char *comp_cword = getenv("COMP_CWORD");
  1134. char *comp_opt;
  1135. int cword, longidx, prefixlen = 0;
  1136. /* Skip over the --autocomplete */
  1137. argc--;
  1138. argv++;
  1139. if (!comp_cword)
  1140. return -EINVAL;
  1141. cword = atoi(comp_cword);
  1142. if (cword <= 0 || cword > argc)
  1143. return -EINVAL;
  1144. comp_opt = argv[cword];
  1145. if (!comp_opt)
  1146. return -EINVAL;
  1147. opterr = 0;
  1148. while (argv[optind]) {
  1149. /* If optind is the one that is being autocompleted, don't
  1150. * let getopt_long() see it; we process it directly. */
  1151. if (argv[optind] == comp_opt) {
  1152. if (!strncmp(comp_opt, "--", 2)) {
  1153. const char *arg = strchr(comp_opt, '=');
  1154. int matchlen;
  1155. if (arg) {
  1156. /* We have --option=... so complete the arg */
  1157. matchlen = arg - comp_opt - 2;
  1158. for (longidx = 0; long_options[longidx].name; longidx++) {
  1159. if (!strncmp(comp_opt + 2, long_options[longidx].name, matchlen)) {
  1160. prefixlen = matchlen + 3;
  1161. opt = long_options[longidx].val;
  1162. goto got_opt;
  1163. }
  1164. }
  1165. } else {
  1166. /* Not --option= just --opt so complete the option name(s) */
  1167. comp_opt += 2;
  1168. autocomplete_optname:
  1169. matchlen = strlen(comp_opt);
  1170. for (longidx = 0; long_options[longidx].name; longidx++) {
  1171. if (!strncmp(comp_opt, long_options[longidx].name, matchlen)) {
  1172. printf("--%s\n", long_options[longidx].name);
  1173. }
  1174. }
  1175. }
  1176. } else if (comp_opt[0] == '-') {
  1177. if (!comp_opt[1]) {
  1178. /* Just a single dash. Autocomplete like '--' with all the (long) options */
  1179. comp_opt++;
  1180. goto autocomplete_optname;
  1181. }
  1182. /* Single-char -X option, with or without an argument. */
  1183. for (longidx = 0; long_options[longidx].name; longidx++) {
  1184. if (comp_opt[1] == long_options[longidx].val) {
  1185. if (comp_opt[2]) {
  1186. if (long_options[longidx].has_arg) {
  1187. prefixlen = 2;
  1188. opt = long_options[longidx].val;
  1189. goto got_opt;
  1190. }
  1191. } else {
  1192. /* Just the option; complete to the long name of same. */
  1193. printf("--%s\n", long_options[longidx].name);
  1194. }
  1195. break;
  1196. }
  1197. }
  1198. } else
  1199. printf("HOSTNAME\n");
  1200. return 0;
  1201. }
  1202. /* Skip over non-option elements, in an attempt to prevent
  1203. * getopt_long() from reordering the array as we go. The problem
  1204. * is that we've seen it *delay* the reordering. So it processes
  1205. * the argv element *after* the non-option, but argv[optind] is
  1206. * still pointing to the non-option. */
  1207. if (argv[optind][0] != '-') {
  1208. optind++;
  1209. continue;
  1210. }
  1211. opt = getopt_long(argc, argv,
  1212. #ifdef _WIN32
  1213. "C:c:Dde:F:g:hi:k:m:P:p:Q:qs:u:Vvx:",
  1214. #else
  1215. "bC:c:Dde:F:g:hi:k:lm:P:p:Q:qSs:U:u:Vvx:",
  1216. #endif
  1217. long_options, &longidx);
  1218. if (opt == -1)
  1219. break;
  1220. if (optarg == comp_opt) {
  1221. prefixlen = 0;
  1222. got_opt:
  1223. switch (opt) {
  1224. case 'k': /* --sslkey */
  1225. case 'c': /* --certificate */
  1226. if (!strncmp(comp_opt + prefixlen, "pkcs11:", 7)) {
  1227. /* We could do clever things here... */
  1228. return 0; /* .. but we don't. */
  1229. }
  1230. autocomplete_special("FILENAME", comp_opt, prefixlen, "!*.@(pem|der|p12|crt)");
  1231. break;
  1232. case OPT_CAFILE: /* --cafile */
  1233. autocomplete_special("FILENAME", comp_opt, prefixlen, "!*.@(pem|der|crt)");
  1234. break;
  1235. case 'x': /* --xmlconfig */
  1236. autocomplete_special("FILENAME", comp_opt, prefixlen, "!*.xml");
  1237. break;
  1238. case OPT_CONFIGFILE: /* --config */
  1239. case OPT_PIDFILE: /* --pid-file */
  1240. autocomplete_special("FILENAME", comp_opt, prefixlen, NULL);
  1241. break;
  1242. case 's': /* --script */
  1243. case OPT_CSD_WRAPPER: /* --csd-wrapper */
  1244. case OPT_EXT_BROWSER: /* --external-browser */
  1245. autocomplete_special("EXECUTABLE", comp_opt, prefixlen, NULL);
  1246. break;
  1247. case OPT_LOCAL_HOSTNAME: /* --local-hostname */
  1248. autocomplete_special("HOSTNAME", comp_opt, prefixlen, NULL);
  1249. break;
  1250. case OPT_CSD_USER: /* --csd-user */
  1251. case 'U': /* --setuid */
  1252. autocomplete_special("USERNAME", comp_opt, prefixlen, NULL);
  1253. break;
  1254. case OPT_OS: /* --os */
  1255. complete_words(comp_opt, prefixlen, "mac-intel", "android",
  1256. "linux-64", "linux", "apple-ios",
  1257. "win", NULL);
  1258. break;
  1259. case OPT_COMPRESSION: /* --compression */
  1260. complete_words(comp_opt, prefixlen, "none", "off", "all",
  1261. "stateless", NULL);
  1262. break;
  1263. case OPT_PROTOCOL: /* --protocol */
  1264. {
  1265. struct oc_vpn_proto *protos, *p;
  1266. int partlen = strlen(comp_opt + prefixlen);
  1267. if (openconnect_get_supported_protocols(&protos) >= 0) {
  1268. for (p = protos; p->name; p++) {
  1269. if(!strncmp(comp_opt + prefixlen, p->name, partlen))
  1270. printf("%.*s%s\n", prefixlen, comp_opt, p->name);
  1271. }
  1272. free(protos);
  1273. }
  1274. break;
  1275. }
  1276. case OPT_HTTP_AUTH: /* --http-auth */
  1277. case OPT_PROXY_AUTH: /* --proxy-auth */
  1278. /* FIXME: Expand latest list item */
  1279. break;
  1280. case OPT_TOKEN_MODE: /* --token-mode */
  1281. complete_words(comp_opt, prefixlen, "totp", "hotp", "oidc", NULL);
  1282. if (openconnect_has_stoken_support())
  1283. complete_words(comp_opt, prefixlen, "rsa", NULL);
  1284. if (openconnect_has_yubioath_support())
  1285. complete_words(comp_opt, prefixlen, "yubioath", NULL);
  1286. break;
  1287. case OPT_TOKEN_SECRET: /* --token-secret */
  1288. switch (comp_opt[prefixlen]) {
  1289. case '@':
  1290. prefixlen++;
  1291. /* Fall through */
  1292. case 0:
  1293. case '/':
  1294. autocomplete_special("FILENAME", comp_opt, prefixlen, NULL);
  1295. break;
  1296. }
  1297. break;
  1298. case OPT_SERVER: /* --server */
  1299. autocomplete_special("HOSTNAME", comp_opt, prefixlen, NULL);
  1300. break;
  1301. case 'i': /* --interface */
  1302. /* FIXME: Enumerate available tun devices */
  1303. break;
  1304. case OPT_SERVERCERT: /* --servercert */
  1305. /* We could do something really evil here and actually
  1306. * connect, then return the result? */
  1307. break;
  1308. /* No autocomplete for these but handle them explicitly so that
  1309. * we can have automatic checking for *accidentally* unhandled
  1310. * options. Right after we do automated checking of man page
  1311. * entries and --help output for all supported options too. */
  1312. case 'e': /* --cert-expire-warning */
  1313. case 'C': /* --cookie */
  1314. case 'g': /* --usergroup */
  1315. case 'm': /* --mtu */
  1316. case OPT_BASEMTU: /* --base-mtu */
  1317. case 'p': /* --key-password */
  1318. case 'P': /* --proxy */
  1319. case 'u': /* --user */
  1320. case 'Q': /* --queue-len */
  1321. case OPT_RECONNECT_TIMEOUT: /* --reconnect-timeout */
  1322. case OPT_AUTHGROUP: /* --authgroup */
  1323. case OPT_RESOLVE: /* --resolve */
  1324. case OPT_USERAGENT: /* --useragent */
  1325. case OPT_VERSION: /* --version-string */
  1326. case OPT_FORCE_DPD: /* --force-dpd */
  1327. case OPT_FORCE_TROJAN: /* --force-trojan */
  1328. case OPT_DTLS_LOCAL_PORT: /* --dtls-local-port */
  1329. case 'F': /* --form-entry */
  1330. case OPT_GNUTLS_DEBUG: /* --gnutls-debug */
  1331. case OPT_CIPHERSUITES: /* --gnutls-priority */
  1332. case OPT_DTLS_CIPHERS: /* --dtls-ciphers */
  1333. case OPT_DTLS12_CIPHERS: /* --dtls12-ciphers */
  1334. break;
  1335. case OPT_MULTICERT_CERT: /* --mca-certificate */
  1336. case OPT_MULTICERT_KEY: /* --mca-key */
  1337. if (!strncmp(comp_opt + prefixlen, "pkcs11:", 7)) {
  1338. /* We could do clever things here... */
  1339. return 0; /* .. but we don't. */
  1340. }
  1341. autocomplete_special("FILENAME", comp_opt, prefixlen, "!*.@(pem|der|p12|crt)");
  1342. break;
  1343. /* disable password autocomplete */
  1344. case OPT_MULTICERT_KEY_PASSWORD: /* --mca-key-password */
  1345. break;
  1346. default:
  1347. fprintf(stderr, _("Unhandled autocomplete for option %d '--%s'. Please report.\n"),
  1348. opt, long_options[longidx].name);
  1349. return -ENOENT;
  1350. }
  1351. return 0;
  1352. }
  1353. }
  1354. /* The only non-option argument we accept is the hostname */
  1355. printf("HOSTNAME\n");
  1356. return 0;
  1357. }
  1358. static void print_connection_info(struct openconnect_info *vpninfo)
  1359. {
  1360. const struct oc_ip_info *ip_info;
  1361. const char *ssl_compr, *udp_compr, *dtls_state, *ssl_state;
  1362. openconnect_get_ip_info(vpninfo, &ip_info, NULL, NULL);
  1363. ssl_state = vpninfo->ssl_fd == -1 ? _("disconnected") : _("connected");
  1364. switch (vpninfo->dtls_state) {
  1365. case DTLS_NOSECRET:
  1366. dtls_state = _("unsuccessful");
  1367. break;
  1368. case DTLS_SLEEPING:
  1369. case DTLS_SECRET:
  1370. case DTLS_CONNECTING:
  1371. dtls_state = _("in progress");
  1372. break;
  1373. case DTLS_DISABLED:
  1374. dtls_state = _("disabled");
  1375. break;
  1376. case DTLS_CONNECTED:
  1377. dtls_state = _("connected");
  1378. break;
  1379. case DTLS_ESTABLISHED:
  1380. dtls_state = _("established");
  1381. break;
  1382. default:
  1383. dtls_state = _("unknown");
  1384. break;
  1385. }
  1386. ssl_compr = openconnect_get_cstp_compression(vpninfo);
  1387. udp_compr = openconnect_get_dtls_compression(vpninfo);
  1388. vpn_progress(vpninfo, PRG_INFO,
  1389. _("Configured as %s%s%s, with SSL%s%s %s and %s%s%s %s\n"),
  1390. ip_info->addr?:"",
  1391. ((ip_info->netmask6 || ip_info->addr6) && ip_info->addr) ? " + " : "",
  1392. ip_info->netmask6 ? : (ip_info->addr6 ? : ""),
  1393. ssl_compr ? " + " : "", ssl_compr ? : "",
  1394. ssl_state,
  1395. vpninfo->proto->udp_protocol ? : "UDP", udp_compr ? " + " : "", udp_compr ? : "",
  1396. dtls_state);
  1397. if (vpninfo->auth_expiration != 0)
  1398. vpn_progress(vpninfo, PRG_INFO, _("Session authentication will expire at %s\n"),
  1399. ctime(&vpninfo->auth_expiration));
  1400. }
  1401. static void print_connection_stats(void *_vpninfo, const struct oc_stats *stats)
  1402. {
  1403. struct openconnect_info *vpninfo = _vpninfo;
  1404. int saved_loglevel = vpninfo->verbose;
  1405. /* XX: print even if loglevel would otherwise suppress */
  1406. openconnect_set_loglevel(vpninfo, PRG_INFO);
  1407. print_connection_info(vpninfo);
  1408. vpn_progress(vpninfo, PRG_INFO,
  1409. _("RX: %"PRIu64" packets (%"PRIu64" B); TX: %"PRIu64" packets (%"PRIu64" B)\n"),
  1410. stats->rx_pkts, stats->rx_bytes, stats->tx_pkts, stats->tx_bytes);
  1411. if (vpninfo->ssl_fd != -1)
  1412. vpn_progress(vpninfo, PRG_INFO, _("SSL ciphersuite: %s\n"), openconnect_get_cstp_cipher(vpninfo));
  1413. if (vpninfo->dtls_state == DTLS_CONNECTED)
  1414. vpn_progress(vpninfo, PRG_INFO, _("%s ciphersuite: %s\n"),
  1415. vpninfo->proto->udp_protocol ? : "UDP", openconnect_get_dtls_cipher(vpninfo));
  1416. if (vpninfo->ssl_times.last_rekey && vpninfo->ssl_times.rekey)
  1417. vpn_progress(vpninfo, PRG_INFO, _("Next SSL rekey in %ld seconds\n"),
  1418. (long)(time(NULL) - vpninfo->ssl_times.last_rekey + vpninfo->ssl_times.rekey));
  1419. if (vpninfo->dtls_times.last_rekey && vpninfo->dtls_times.rekey)
  1420. vpn_progress(vpninfo, PRG_INFO, _("Next %s rekey in %ld seconds\n"),
  1421. vpninfo->proto->udp_protocol ? : "UDP",
  1422. (long)(time(NULL) - vpninfo->ssl_times.last_rekey + vpninfo->ssl_times.rekey));
  1423. if (vpninfo->trojan_interval && vpninfo->last_trojan)
  1424. vpn_progress(vpninfo, PRG_INFO, _("Next Trojan invocation in %ld seconds\n"),
  1425. (long)(time(NULL) - vpninfo->last_trojan + vpninfo->trojan_interval));
  1426. /* XX: restore loglevel */
  1427. openconnect_set_loglevel(vpninfo, saved_loglevel);
  1428. }
  1429. #ifndef _WIN32
  1430. static int background_self(struct openconnect_info *vpninfo, char *pidfile)
  1431. {
  1432. FILE *fp = NULL;
  1433. int pid;
  1434. /* Open the pidfile before forking, so we can report errors
  1435. more sanely. It's *possible* that we'll fail to write to
  1436. it, but very unlikely. */
  1437. if (pidfile != NULL) {
  1438. fp = openconnect_fopen_utf8(vpninfo, pidfile, "w");
  1439. if (!fp) {
  1440. fprintf(stderr, _("Failed to open '%s' for write: %s\n"),
  1441. pidfile, strerror(errno));
  1442. sig_vpninfo = NULL;
  1443. openconnect_vpninfo_free(vpninfo);
  1444. exit(1);
  1445. }
  1446. }
  1447. pid = fork();
  1448. if (pid == -1) {
  1449. vpn_perror(vpninfo, _("Failed to continue in background"));
  1450. exit(1);
  1451. } else if (pid > 0) {
  1452. if (fp) {
  1453. fprintf(fp, "%d\n", pid);
  1454. fclose(fp);
  1455. }
  1456. vpn_progress(vpninfo, PRG_INFO,
  1457. _("Continuing in background; pid %d\n"),
  1458. pid);
  1459. sig_vpninfo = NULL;
  1460. /* Don't invoke EPOLL_CTL_DEL; it'll mess up the real one */
  1461. #ifdef HAVE_EPOLL
  1462. vpninfo->epoll_fd = -1;
  1463. #endif
  1464. openconnect_vpninfo_free(vpninfo);
  1465. exit(0);
  1466. }
  1467. if (fp)
  1468. fclose(fp);
  1469. return !!fp;
  1470. }
  1471. #endif /* _WIN32 */
  1472. static void fully_up_cb(void *_vpninfo)
  1473. {
  1474. struct openconnect_info *vpninfo = _vpninfo;
  1475. print_connection_info(vpninfo);
  1476. #ifndef _WIN32
  1477. if (background)
  1478. wrote_pid = background_self(vpninfo, pidfile);
  1479. #ifndef __native_client__
  1480. if (use_syslog) {
  1481. openlog("openconnect", LOG_PID, LOG_DAEMON);
  1482. vpninfo->progress = syslog_progress;
  1483. }
  1484. #endif /* !__native_client__ */
  1485. #endif /* !_WIN32 */
  1486. }
  1487. int main(int argc, char **argv)
  1488. {
  1489. struct openconnect_info *vpninfo;
  1490. char *urlpath = NULL;
  1491. struct oc_vpn_option *gai;
  1492. struct accepted_cert *newcert;
  1493. char *ip;
  1494. char *proxy = getenv("https_proxy");
  1495. char *vpnc_script = NULL;
  1496. int autoproxy = 0;
  1497. int opt;
  1498. char *config_arg;
  1499. char *config_filename;
  1500. char *token_str = NULL;
  1501. oc_token_mode_t token_mode = OC_TOKEN_MODE_NONE;
  1502. int reconnect_timeout = 300;
  1503. int ret;
  1504. int verbose = PRG_INFO;
  1505. #ifdef HAVE_NL_LANGINFO
  1506. char *charset;
  1507. #endif
  1508. #ifndef _WIN32
  1509. struct sigaction sa;
  1510. struct utsname utsbuf;
  1511. #endif
  1512. #ifdef ENABLE_NLS
  1513. bindtextdomain("openconnect", LOCALEDIR);
  1514. #endif
  1515. if (!setlocale(LC_ALL, ""))
  1516. fprintf(stderr,
  1517. _("WARNING: Cannot set locale: %s\n"), strerror(errno));
  1518. if (argc > 2 && !strcmp(argv[1], "--autocomplete"))
  1519. return autocomplete(argc, argv);
  1520. #ifdef HAVE_NL_LANGINFO
  1521. charset = nl_langinfo(CODESET);
  1522. if (charset && strcmp(charset, "UTF-8"))
  1523. legacy_charset = strdup(charset);
  1524. #ifndef HAVE_ICONV
  1525. if (legacy_charset)
  1526. fprintf(stderr,
  1527. _("WARNING: This version of OpenConnect was built without iconv\n"
  1528. " support but you appear to be using the legacy character\n"
  1529. " set \"%s\". Expect strangeness.\n"), legacy_charset);
  1530. #endif /* !HAVE_ICONV */
  1531. #endif /* HAVE_NL_LANGINFO */
  1532. if (strcmp(openconnect_version_str, openconnect_binary_version)) {
  1533. fprintf(stderr, _("WARNING: This version of OpenConnect is %s but\n"
  1534. " the libopenconnect library is %s\n"),
  1535. openconnect_binary_version, openconnect_version_str);
  1536. }
  1537. #ifdef INSECURE_DEBUGGING
  1538. fprintf(stderr,
  1539. _("WARNING: This build is intended only for debugging purposes and\n"
  1540. " may allow you to establish insecure connections.\n"));
  1541. #endif
  1542. /* Some systems have a crypto policy which completely prevents DTLSv1.0
  1543. * from being used, which is entirely pointless and will just drive
  1544. * users back to the crappy proprietary clients. Or drive OpenConnect
  1545. * to implement its own DTLS instead of using the system crypto libs.
  1546. * We're happy to conform by default to the system policy which is
  1547. * carefully curated to keep up to date with developments in crypto
  1548. * attacks — but we also *need* to be able to override it and connect
  1549. * anyway, when the user asks us to. Just as we *can* continue even
  1550. * when the server has an invalid certificate, based on user input.
  1551. * It was a massive oversight that GnuTLS implemented the system
  1552. * policy *without* that basic override facility, so until/unless
  1553. * it actually gets implemented properly we have to just disable it.
  1554. * We can't do this from openconnect_init_ssl() since that would be
  1555. * calling setenv() from a library in someone else's process. And
  1556. * thankfully we don't really need to since the auth-dialogs don't
  1557. * care; this is mostly for the DTLS connection.
  1558. */
  1559. #ifdef OPENCONNECT_GNUTLS
  1560. setenv("GNUTLS_SYSTEM_PRIORITY_FILE", DEVNULL, 0);
  1561. #else
  1562. setenv("OPENSSL_CONF", DEVNULL, 0);
  1563. #endif
  1564. openconnect_init_ssl();
  1565. vpninfo = openconnect_vpninfo_new("Open AnyConnect VPN Agent",
  1566. validate_peer_cert, NULL, process_auth_form_cb, write_progress, NULL);
  1567. if (!vpninfo) {
  1568. fprintf(stderr, _("Failed to allocate vpninfo structure\n"));
  1569. exit(1);
  1570. }
  1571. vpninfo->cbdata = vpninfo;
  1572. #ifdef _WIN32
  1573. set_default_vpncscript();
  1574. #else
  1575. vpninfo->use_tun_script = 0;
  1576. vpninfo->uid = getuid();
  1577. vpninfo->gid = getgid();
  1578. if (!uname(&utsbuf)) {
  1579. openconnect_set_localname(vpninfo, utsbuf.nodename);
  1580. }
  1581. #endif
  1582. while ((opt = next_option(argc, argv, &config_arg))) {
  1583. if (opt < 0)
  1584. break;
  1585. switch (opt) {
  1586. #ifndef _WIN32
  1587. case 'b':
  1588. background = 1;
  1589. break;
  1590. case 'l':
  1591. use_syslog = 1;
  1592. break;
  1593. case 'S':
  1594. vpninfo->use_tun_script = 1;
  1595. break;
  1596. case 'U':
  1597. assert_nonnull_config_arg("U", config_arg);
  1598. get_uids(config_arg, &vpninfo->uid, &vpninfo->gid);
  1599. break;
  1600. case OPT_CSD_USER:
  1601. assert_nonnull_config_arg("csd-user", config_arg);
  1602. get_uids(config_arg, &vpninfo->uid_csd, &vpninfo->gid_csd);
  1603. vpninfo->uid_csd_given = 1;
  1604. break;
  1605. case OPT_CSD_WRAPPER:
  1606. vpninfo->csd_wrapper = keep_config_arg();
  1607. break;
  1608. #endif /* !_WIN32 */
  1609. case 'F':
  1610. add_form_field(keep_config_arg());
  1611. break;
  1612. case OPT_PROTOCOL:
  1613. if (openconnect_set_protocol(vpninfo, config_arg))
  1614. exit(1);
  1615. break;
  1616. case OPT_JUNIPER:
  1617. fprintf(stderr, "WARNING: Juniper Network Connect support is experimental.\n");
  1618. fprintf(stderr, "It will probably be superseded by Junos Pulse support.\n");
  1619. openconnect_set_protocol(vpninfo, "nc");
  1620. break;
  1621. case OPT_CONFIGFILE:
  1622. if (config_file) {
  1623. fprintf(stderr, _("Cannot use 'config' option inside config file\n"));
  1624. exit(1);
  1625. }
  1626. config_filename = keep_config_arg(); /* Convert to UTF-8 */
  1627. config_file = openconnect_fopen_utf8(vpninfo, config_filename, "r");
  1628. if (config_filename != config_arg)
  1629. free(config_filename);
  1630. if (!config_file) {
  1631. fprintf(stderr, _("Cannot open config file '%s': %s\n"),
  1632. config_arg, strerror(errno));
  1633. exit(1);
  1634. }
  1635. config_line_num = 1;
  1636. /* The next option will come from the file... */
  1637. break;
  1638. case OPT_COMPRESSION:
  1639. assert_nonnull_config_arg("compression", config_arg);
  1640. if (!strcmp(config_arg, "none") ||
  1641. !strcmp(config_arg, "off"))
  1642. openconnect_set_compression_mode(vpninfo, OC_COMPRESSION_MODE_NONE);
  1643. else if (!strcmp(config_arg, "all"))
  1644. openconnect_set_compression_mode(vpninfo, OC_COMPRESSION_MODE_ALL);
  1645. else if (!strcmp(config_arg, "stateless"))
  1646. openconnect_set_compression_mode(vpninfo, OC_COMPRESSION_MODE_STATELESS);
  1647. else {
  1648. fprintf(stderr, _("Invalid compression mode '%s'\n"),
  1649. config_arg);
  1650. exit(1);
  1651. }
  1652. break;
  1653. case OPT_CAFILE:
  1654. openconnect_set_cafile(vpninfo, dup_config_arg());
  1655. break;
  1656. #ifndef _WIN32
  1657. case OPT_PIDFILE:
  1658. pidfile = keep_config_arg();
  1659. break;
  1660. #endif
  1661. case OPT_PFS:
  1662. openconnect_set_pfs(vpninfo, 1);
  1663. break;
  1664. case OPT_ALLOW_INSECURE_CRYPTO:
  1665. if (openconnect_set_allow_insecure_crypto(vpninfo, 1)) {
  1666. fprintf(stderr, _("Cannot enable insecure 3DES or RC4 ciphers, because the library\n"
  1667. "%s no longer supports them.\n"), openconnect_get_tls_library_version());
  1668. exit(1);
  1669. }
  1670. break;
  1671. case OPT_SERVERCERT:
  1672. newcert = malloc(sizeof(*newcert));
  1673. if (!newcert) {
  1674. fprintf(stderr, _("Failed to allocate memory\n"));
  1675. exit(1);
  1676. }
  1677. newcert->next = accepted_certs;
  1678. accepted_certs = newcert;
  1679. newcert->fingerprint = keep_config_arg();
  1680. newcert->host = NULL;
  1681. newcert->port = 0;
  1682. openconnect_set_system_trust(vpninfo, 0);
  1683. allowed_fingerprints++;
  1684. break;
  1685. case OPT_RESOLVE:
  1686. assert_nonnull_config_arg("resolve", config_arg);
  1687. ip = strchr(config_arg, ':');
  1688. if (!ip) {
  1689. fprintf(stderr, _("Missing colon in resolve option\n"));
  1690. exit(1);
  1691. }
  1692. gai = malloc(sizeof(*gai) + strlen(config_arg) + 1);
  1693. if (!gai) {
  1694. fprintf(stderr, _("Failed to allocate memory\n"));
  1695. exit(1);
  1696. }
  1697. gai->next = gai_overrides;
  1698. gai_overrides = gai;
  1699. gai->option = (void *)(gai + 1);
  1700. memcpy(gai->option, config_arg, strlen(config_arg) + 1);
  1701. gai->option[ip - config_arg] = 0;
  1702. gai->value = gai->option + (ip - config_arg) + 1;
  1703. break;
  1704. case OPT_NO_DTLS:
  1705. openconnect_disable_dtls(vpninfo);
  1706. break;
  1707. case OPT_COOKIEONLY:
  1708. cookieonly = 1;
  1709. break;
  1710. case OPT_PRINTCOOKIE:
  1711. cookieonly = 2;
  1712. break;
  1713. case OPT_AUTHENTICATE:
  1714. cookieonly = 3;
  1715. break;
  1716. case OPT_COOKIE_ON_STDIN:
  1717. read_stdin(&vpninfo->cookie, 0, 0);
  1718. /* If the cookie is empty, ignore it */
  1719. if (!*vpninfo->cookie)
  1720. vpninfo->cookie = NULL;
  1721. break;
  1722. case OPT_PASSWORD_ON_STDIN:
  1723. read_stdin(&password, 0, 0);
  1724. allow_stdin_read = 1;
  1725. break;
  1726. case OPT_NO_PASSWD:
  1727. vpninfo->nopasswd = 1;
  1728. break;
  1729. case OPT_NO_XMLPOST:
  1730. openconnect_set_xmlpost(vpninfo, 0);
  1731. break;
  1732. case OPT_NON_INTER:
  1733. non_inter = 1;
  1734. break;
  1735. case OPT_RECONNECT_TIMEOUT:
  1736. assert_nonnull_config_arg("reconnect-timeout", config_arg);
  1737. reconnect_timeout = atoi(config_arg);
  1738. break;
  1739. case OPT_DTLS_CIPHERS:
  1740. vpninfo->dtls_ciphers = keep_config_arg();
  1741. break;
  1742. case OPT_DTLS12_CIPHERS:
  1743. vpninfo->dtls12_ciphers = keep_config_arg();
  1744. break;
  1745. case OPT_AUTHGROUP:
  1746. authgroup = keep_config_arg();
  1747. break;
  1748. case 'C':
  1749. vpninfo->cookie = dup_config_arg();
  1750. break;
  1751. case 'c':
  1752. vpninfo->certinfo[0].cert = dup_config_arg();
  1753. break;
  1754. case 'e':
  1755. assert_nonnull_config_arg("e", config_arg);
  1756. vpninfo->cert_expire_warning = 86400 * atoi(config_arg);
  1757. break;
  1758. case 'k':
  1759. vpninfo->certinfo[0].key = dup_config_arg();
  1760. break;
  1761. case 'd':
  1762. vpninfo->req_compr = COMPR_ALL;
  1763. break;
  1764. case 'D':
  1765. vpninfo->req_compr = 0;
  1766. break;
  1767. case 'g':
  1768. free(urlpath);
  1769. urlpath = dup_config_arg();
  1770. break;
  1771. case 'h':
  1772. usage();
  1773. break;
  1774. case 'i':
  1775. vpninfo->ifname = dup_config_arg();
  1776. break;
  1777. case 'm': {
  1778. assert_nonnull_config_arg("m", config_arg);
  1779. int mtu = atol(config_arg);
  1780. if (mtu < 576) {
  1781. fprintf(stderr, _("MTU %d too small\n"), mtu);
  1782. mtu = 576;
  1783. }
  1784. openconnect_set_reqmtu(vpninfo, mtu);
  1785. break;
  1786. }
  1787. case OPT_BASEMTU:
  1788. assert_nonnull_config_arg("base-mtu", config_arg);
  1789. vpninfo->basemtu = atol(config_arg);
  1790. if (vpninfo->basemtu < 576) {
  1791. fprintf(stderr, _("MTU %d too small\n"), vpninfo->basemtu);
  1792. vpninfo->basemtu = 576;
  1793. }
  1794. break;
  1795. case 'p':
  1796. vpninfo->certinfo[0].password = dup_config_arg();
  1797. break;
  1798. case 'P':
  1799. proxy = keep_config_arg();
  1800. autoproxy = 0;
  1801. break;
  1802. case OPT_PROXY_AUTH:
  1803. openconnect_set_proxy_auth(vpninfo, config_arg);
  1804. break;
  1805. case OPT_HTTP_AUTH:
  1806. openconnect_set_http_auth(vpninfo, config_arg);
  1807. break;
  1808. case OPT_NO_PROXY:
  1809. autoproxy = 0;
  1810. proxy = NULL;
  1811. break;
  1812. case OPT_NO_SYSTEM_TRUST:
  1813. openconnect_set_system_trust(vpninfo, 0);
  1814. break;
  1815. case OPT_LIBPROXY:
  1816. autoproxy = 1;
  1817. proxy = NULL;
  1818. break;
  1819. case OPT_NO_HTTP_KEEPALIVE:
  1820. fprintf(stderr,
  1821. _("Disabling all HTTP connection re-use due to --no-http-keepalive option.\n"
  1822. "If this helps, please report to <%s>.\n"),
  1823. "openconnect-devel@lists.infradead.org");
  1824. vpninfo->no_http_keepalive = 1;
  1825. break;
  1826. case OPT_NO_CERT_CHECK:
  1827. fprintf(stderr,
  1828. _("The --no-cert-check option was insecure and has been removed.\n"
  1829. "Fix your server's certificate or use --servercert to trust it.\n"));
  1830. exit(1);
  1831. break;
  1832. case 's':
  1833. vpnc_script = dup_config_arg();
  1834. break;
  1835. case OPT_EXT_BROWSER:
  1836. ext_browser = dup_config_arg();
  1837. break;
  1838. case 'u':
  1839. free(username);
  1840. username = dup_config_arg();
  1841. break;
  1842. case OPT_DISABLE_IPV6:
  1843. openconnect_disable_ipv6(vpninfo);
  1844. break;
  1845. case 'Q':
  1846. assert_nonnull_config_arg("Q", config_arg);
  1847. vpninfo->max_qlen = atol(config_arg);
  1848. if (!vpninfo->max_qlen) {
  1849. fprintf(stderr, _("Queue length zero not permitted; using 1\n"));
  1850. vpninfo->max_qlen = 1;
  1851. }
  1852. break;
  1853. case 'q':
  1854. verbose = PRG_ERR;
  1855. break;
  1856. case OPT_DUMP_HTTP:
  1857. vpninfo->dump_http_traffic = 1;
  1858. break;
  1859. case 'v':
  1860. verbose++;
  1861. break;
  1862. case 'V':
  1863. printf(_("OpenConnect version %s\n"), openconnect_version_str);
  1864. print_build_opts();
  1865. print_supported_protocols();
  1866. print_default_vpncscript();
  1867. exit(0);
  1868. case 'x':
  1869. vpninfo->xmlconfig = keep_config_arg();
  1870. vpninfo->write_new_config = write_new_config;
  1871. break;
  1872. case OPT_KEY_PASSWORD_FROM_FSID:
  1873. do_passphrase_from_fsid = 1;
  1874. break;
  1875. case OPT_USERAGENT:
  1876. free(vpninfo->useragent);
  1877. vpninfo->useragent = dup_config_arg();
  1878. break;
  1879. case OPT_VERSION:
  1880. free(vpninfo->version_string);
  1881. vpninfo->version_string = dup_config_arg();
  1882. break;
  1883. case OPT_LOCAL_HOSTNAME:
  1884. openconnect_set_localname(vpninfo, config_arg);
  1885. break;
  1886. case OPT_FORCE_DPD:
  1887. assert_nonnull_config_arg("force-dpd", config_arg);
  1888. openconnect_set_dpd(vpninfo, atoi(config_arg));
  1889. break;
  1890. case OPT_FORCE_TROJAN:
  1891. assert_nonnull_config_arg("force-trojan", config_arg);
  1892. openconnect_set_trojan_interval(vpninfo, atoi(config_arg));
  1893. break;
  1894. case OPT_DTLS_LOCAL_PORT:
  1895. assert_nonnull_config_arg("dtls-local-port", config_arg);
  1896. vpninfo->dtls_local_port = atoi(config_arg);
  1897. break;
  1898. case OPT_TOKEN_MODE:
  1899. assert_nonnull_config_arg("token-mode", config_arg);
  1900. if (strcasecmp(config_arg, "rsa") == 0) {
  1901. token_mode = OC_TOKEN_MODE_STOKEN;
  1902. } else if (strcasecmp(config_arg, "totp") == 0) {
  1903. token_mode = OC_TOKEN_MODE_TOTP;
  1904. } else if (strcasecmp(config_arg, "hotp") == 0) {
  1905. token_mode = OC_TOKEN_MODE_HOTP;
  1906. } else if (strcasecmp(config_arg, "yubioath") == 0) {
  1907. token_mode = OC_TOKEN_MODE_YUBIOATH;
  1908. } else if (strcasecmp(config_arg, "oidc") == 0) {
  1909. token_mode = OC_TOKEN_MODE_OIDC;
  1910. } else {
  1911. fprintf(stderr, _("Invalid software token mode \"%s\"\n"),
  1912. config_arg);
  1913. exit(1);
  1914. }
  1915. break;
  1916. case OPT_TOKEN_SECRET:
  1917. token_str = keep_config_arg();
  1918. break;
  1919. case OPT_OS:
  1920. assert_nonnull_config_arg("os", config_arg);
  1921. if (openconnect_set_reported_os(vpninfo, config_arg)) {
  1922. fprintf(stderr, _("Invalid OS identity \"%s\"\n"
  1923. "Allowed values: linux, linux-64, win, mac-intel, android, apple-ios\n"),
  1924. config_arg);
  1925. exit(1);
  1926. }
  1927. if (!strcmp(config_arg, "android") || !strcmp(config_arg, "apple-ios")) {
  1928. /* generic defaults */
  1929. openconnect_set_mobile_info(vpninfo,
  1930. xstrdup("1.0"),
  1931. dup_config_arg(),
  1932. xstrdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
  1933. }
  1934. break;
  1935. case OPT_PASSTOS:
  1936. openconnect_set_pass_tos(vpninfo, 1);
  1937. break;
  1938. case OPT_TIMESTAMP:
  1939. timestamp = 1;
  1940. break;
  1941. #ifdef OPENCONNECT_GNUTLS
  1942. case OPT_GNUTLS_DEBUG:
  1943. assert_nonnull_config_arg("gnutls-debug", config_arg);
  1944. gnutls_global_set_log_level(atoi(config_arg));
  1945. gnutls_global_set_log_function(oc_gnutls_log_func);
  1946. break;
  1947. #endif
  1948. case OPT_CIPHERSUITES:
  1949. fprintf(stderr,
  1950. _("WARNING: You specified %s. This should not be\n"
  1951. " necessary; please report cases where a priority string\n"
  1952. " override is necessary to connect to a server\n"
  1953. " to <%s>.\n"),
  1954. #ifdef OPENCONNECT_GNUTLS
  1955. "--gnutls-priority",
  1956. #elif defined(OPENCONNECT_OPENSSL)
  1957. "--openssl-ciphers",
  1958. #endif
  1959. "openconnect-devel@lists.infradead.org");
  1960. vpninfo->ciphersuite_config = dup_config_arg();
  1961. break;
  1962. case OPT_MULTICERT_CERT:
  1963. free(vpninfo->certinfo[1].cert);
  1964. vpninfo->certinfo[1].cert = dup_config_arg();
  1965. break;
  1966. case OPT_MULTICERT_KEY:
  1967. free(vpninfo->certinfo[1].key);
  1968. vpninfo->certinfo[1].key = dup_config_arg();
  1969. break;
  1970. case OPT_MULTICERT_KEY_PASSWORD:
  1971. free(vpninfo->certinfo[1].password);
  1972. vpninfo->certinfo[1].password = dup_config_arg();
  1973. break;
  1974. case OPT_SERVER:
  1975. if (openconnect_parse_url(vpninfo, config_arg))
  1976. exit(1);
  1977. break;
  1978. default:
  1979. usage();
  1980. }
  1981. }
  1982. if (gai_overrides)
  1983. openconnect_override_getaddrinfo(vpninfo, gai_override_cb);
  1984. if (optind < argc - (vpninfo->hostname ? 0 : 1)) {
  1985. fprintf(stderr, _("Too many arguments on command line\n"));
  1986. usage();
  1987. } else if (optind > argc - (vpninfo->hostname ? 0 : 1)) {
  1988. fprintf(stderr, _("No server specified\n"));
  1989. usage();
  1990. }
  1991. if (!vpninfo->certinfo[0].key)
  1992. vpninfo->certinfo[0].key = vpninfo->certinfo[0].cert;
  1993. if (!vpninfo->certinfo[1].key)
  1994. vpninfo->certinfo[1].key = vpninfo->certinfo[1].cert;
  1995. if (vpninfo->dump_http_traffic && verbose < PRG_DEBUG)
  1996. verbose = PRG_DEBUG;
  1997. openconnect_set_loglevel(vpninfo, verbose);
  1998. if (autoproxy) {
  1999. #ifdef LIBPROXY_HDR
  2000. vpninfo->proxy_factory = px_proxy_factory_new();
  2001. #else
  2002. fprintf(stderr, _("This version of OpenConnect was built without libproxy support\n"));
  2003. exit(1);
  2004. #endif
  2005. }
  2006. if (token_mode != OC_TOKEN_MODE_NONE)
  2007. init_token(vpninfo, token_mode, token_str);
  2008. if (proxy && openconnect_set_http_proxy(vpninfo, strdup(proxy)))
  2009. exit(1);
  2010. #ifdef HAVE_POSIX_SPAWN
  2011. if (ext_browser)
  2012. openconnect_set_external_browser_callback(vpninfo, spawn_browser);
  2013. #endif
  2014. #ifndef _WIN32
  2015. memset(&sa, 0, sizeof(sa));
  2016. sa.sa_handler = handle_signal;
  2017. checked_sigaction(SIGTERM, &sa, NULL);
  2018. checked_sigaction(SIGINT, &sa, NULL);
  2019. checked_sigaction(SIGHUP, &sa, NULL);
  2020. checked_sigaction(SIGUSR1, &sa, NULL);
  2021. checked_sigaction(SIGUSR2, &sa, NULL);
  2022. #else /* _WIN32 */
  2023. SetConsoleCtrlHandler(console_ctrl_handler, TRUE /* Add */);
  2024. #endif
  2025. sig_vpninfo = vpninfo;
  2026. sig_cmd_fd = openconnect_setup_cmd_pipe(vpninfo);
  2027. if (sig_cmd_fd < 0) {
  2028. #ifdef _WIN32
  2029. char *errstr = openconnect__win32_strerror(GetLastError());
  2030. #else
  2031. const char *errstr = strerror(errno);
  2032. #endif /* _WIN32 */
  2033. fprintf(stderr, _("Error opening cmd pipe: %s\n"), errstr);
  2034. #ifdef _WIN32
  2035. free(errstr);
  2036. #endif /* _WIN32 */
  2037. exit(1);
  2038. }
  2039. vpninfo->cmd_fd_internal = 1;
  2040. if (vpninfo->certinfo[0].key && do_passphrase_from_fsid)
  2041. openconnect_passphrase_from_fsid(vpninfo);
  2042. if (config_lookup_host(vpninfo, argv[optind]))
  2043. exit(1);
  2044. if (!vpninfo->hostname) {
  2045. char *url = strdup(argv[optind]);
  2046. if (openconnect_parse_url(vpninfo, url))
  2047. exit(1);
  2048. free(url);
  2049. }
  2050. /* Historically, the path in the URL superseded the one in the
  2051. * --usergroup argument, just because of the order in which they
  2052. * were processed. Preserve that behaviour. */
  2053. if (urlpath && !vpninfo->urlpath) {
  2054. vpninfo->urlpath = urlpath;
  2055. urlpath = NULL;
  2056. }
  2057. free(urlpath);
  2058. if (!vpninfo->cookie && openconnect_obtain_cookie(vpninfo)) {
  2059. if (vpninfo->csd_scriptname) {
  2060. unlink(vpninfo->csd_scriptname);
  2061. vpninfo->csd_scriptname = NULL;
  2062. }
  2063. fprintf(stderr, _("Failed to complete authentication\n"));
  2064. exit(1);
  2065. }
  2066. if (cookieonly == 3) {
  2067. /* --authenticate */
  2068. printf("COOKIE='%s'\n", vpninfo->cookie);
  2069. printf("HOST='%s'\n", openconnect_get_hostname(vpninfo));
  2070. printf("CONNECT_URL='%s'\n", openconnect_get_connect_url(vpninfo));
  2071. printf("FINGERPRINT='%s'\n",
  2072. openconnect_get_peer_cert_hash(vpninfo));
  2073. if (vpninfo->unique_hostname) {
  2074. char *p = vpninfo->unique_hostname;
  2075. int l = strlen(p);
  2076. if (vpninfo->unique_hostname[0] == '[' &&
  2077. vpninfo->unique_hostname[l-1] == ']') {
  2078. p++;
  2079. l -=2;
  2080. }
  2081. printf("RESOLVE='%s:%.*s'\n", vpninfo->hostname, l, p);
  2082. } else
  2083. printf("RESOLVE=");
  2084. sig_vpninfo = NULL;
  2085. openconnect_vpninfo_free(vpninfo);
  2086. exit(0);
  2087. } else if (cookieonly) {
  2088. printf("%s\n", vpninfo->cookie);
  2089. if (cookieonly == 1) {
  2090. /* We use cookieonly=2 for 'print it and continue' */
  2091. sig_vpninfo = NULL;
  2092. openconnect_vpninfo_free(vpninfo);
  2093. exit(0);
  2094. }
  2095. }
  2096. if ((ret = openconnect_make_cstp_connection(vpninfo)) != 0) {
  2097. fprintf(stderr, _("Creating SSL connection failed\n"));
  2098. goto out;
  2099. }
  2100. if (!vpnc_script)
  2101. vpnc_script = xstrdup(default_vpncscript);
  2102. vpninfo->vpnc_script = vpnc_script;
  2103. if (vpninfo->dtls_state != DTLS_DISABLED &&
  2104. openconnect_setup_dtls(vpninfo, 60)) {
  2105. /* Disable DTLS if we cannot set it up, otherwise
  2106. * reconnects end up in infinite loop trying to connect
  2107. * to non existing DTLS */
  2108. vpninfo->dtls_state = DTLS_DISABLED;
  2109. fprintf(stderr, _("Set up UDP failed; using SSL instead\n"));
  2110. }
  2111. if (!vpninfo->vpnc_script) {
  2112. vpn_progress(vpninfo, PRG_INFO,
  2113. _("No --script argument provided; DNS and routing are not configured\n"));
  2114. vpn_progress(vpninfo, PRG_INFO,
  2115. _("See %s\n"),
  2116. "https://www.infradead.org/openconnect/vpnc-script.html");
  2117. }
  2118. openconnect_set_setup_tun_handler(vpninfo, fully_up_cb);
  2119. openconnect_set_stats_handler(vpninfo, print_connection_stats);
  2120. while (1) {
  2121. ret = openconnect_mainloop(vpninfo, reconnect_timeout, RECONNECT_INTERVAL_MIN);
  2122. if (ret)
  2123. break;
  2124. vpn_progress(vpninfo, PRG_INFO, _("User requested reconnect\n"));
  2125. }
  2126. #ifndef _WIN32
  2127. if (wrote_pid)
  2128. unlink(pidfile);
  2129. #endif
  2130. out:
  2131. switch (ret) {
  2132. case -EPERM:
  2133. vpn_progress(vpninfo, PRG_ERR, _("Cookie was rejected by server; exiting.\n"));
  2134. ret = 2;
  2135. break;
  2136. case -EPIPE:
  2137. vpn_progress(vpninfo, PRG_ERR, _("Session terminated by server; exiting.\n"));
  2138. ret = 1;
  2139. break;
  2140. case -EINTR:
  2141. vpn_progress(vpninfo, PRG_INFO, _("User cancelled (%s); exiting.\n"),
  2142. #ifdef INSECURE_DEBUGGING
  2143. "SIGTERM"
  2144. #else
  2145. "SIGINT/SIGTERM"
  2146. #endif
  2147. );
  2148. ret = 0;
  2149. break;
  2150. case -ECONNABORTED:
  2151. vpn_progress(vpninfo, PRG_INFO, _("User detached from session (%s); exiting.\n"),
  2152. #ifdef INSECURE_DEBUGGING
  2153. "SIGHUP/SIGINT"
  2154. #else
  2155. "SIGHUP"
  2156. #endif
  2157. );
  2158. ret = 0;
  2159. break;
  2160. case -EIO:
  2161. vpn_progress(vpninfo, PRG_INFO, _("Unrecoverable I/O error; exiting.\n"));
  2162. ret = 1;
  2163. break;
  2164. default:
  2165. if (vpninfo->quit_reason)
  2166. vpn_progress(vpninfo, PRG_ERR, "%s; exiting\n", vpninfo->quit_reason);
  2167. else
  2168. vpn_progress(vpninfo, PRG_ERR, _("Unknown error; exiting.\n"));
  2169. ret = 1;
  2170. break;
  2171. }
  2172. sig_vpninfo = NULL;
  2173. openconnect_vpninfo_free(vpninfo);
  2174. exit(ret);
  2175. }
  2176. static int write_new_config(void *_vpninfo, const char *buf, int buflen)
  2177. {
  2178. struct openconnect_info *vpninfo = _vpninfo;
  2179. int config_fd;
  2180. int err;
  2181. config_fd = openconnect_open_utf8(vpninfo, vpninfo->xmlconfig,
  2182. O_WRONLY|O_TRUNC|O_CREAT|O_BINARY);
  2183. if (config_fd < 0) {
  2184. err = errno;
  2185. fprintf(stderr, _("Failed to open %s for write: %s\n"),
  2186. vpninfo->xmlconfig, strerror(err));
  2187. return -err;
  2188. }
  2189. /* FIXME: We should actually write to a new tempfile, then rename */
  2190. if (write(config_fd, buf, buflen) != buflen) {
  2191. err = errno;
  2192. fprintf(stderr, _("Failed to write config to %s: %s\n"),
  2193. vpninfo->xmlconfig, strerror(err));
  2194. close(config_fd);
  2195. return -err;
  2196. }
  2197. close(config_fd);
  2198. return 0;
  2199. }
  2200. static void __attribute__ ((format(printf, 3, 4)))
  2201. write_progress(void *_vpninfo, int level, const char *fmt, ...)
  2202. {
  2203. struct openconnect_info *vpninfo = _vpninfo;
  2204. FILE *outf = level ? stdout : stderr;
  2205. va_list args;
  2206. if (cookieonly)
  2207. outf = stderr;
  2208. if (vpninfo->verbose >= level) {
  2209. if (timestamp) {
  2210. char ts[64];
  2211. time_t t = time(NULL);
  2212. struct tm *tm = localtime(&t);
  2213. strftime(ts, 64, "[%Y-%m-%d %H:%M:%S] ", tm);
  2214. fprintf(outf, "%s", ts);
  2215. }
  2216. va_start(args, fmt);
  2217. vfprintf(outf, fmt, args);
  2218. va_end(args);
  2219. fflush(outf);
  2220. }
  2221. }
  2222. static int validate_peer_cert(void *_vpninfo, const char *reason)
  2223. {
  2224. struct openconnect_info *vpninfo = _vpninfo;
  2225. const char *fingerprint;
  2226. struct accepted_cert *this;
  2227. fingerprint = openconnect_get_peer_cert_hash(vpninfo);
  2228. for (this = accepted_certs; this; this = this->next) {
  2229. #ifdef INSECURE_DEBUGGING
  2230. if (this->port == 0 && this->host == NULL && !strcasecmp(this->fingerprint, "ACCEPT")) {
  2231. fprintf(stderr, _("Insecurely accepting certificate from VPN server \"%s\" because you ran with --servercert=ACCEPT.\n"),
  2232. vpninfo->hostname);
  2233. return 0;
  2234. } else
  2235. #endif
  2236. /* XX: if set by --servercert argument (port 0 and host NULL), accept for any host/port */
  2237. if ((this->host == NULL || !strcasecmp(this->host, vpninfo->hostname)) &&
  2238. (this->port == 0 || this->port == vpninfo->port)) {
  2239. int err = openconnect_check_peer_cert_hash(vpninfo, this->fingerprint);
  2240. if (!err)
  2241. return 0;
  2242. else if (err < 0) {
  2243. vpn_progress(vpninfo, PRG_ERR,
  2244. _("Could not check server's certificate against %s\n"),
  2245. this->fingerprint);
  2246. }
  2247. }
  2248. }
  2249. if (allowed_fingerprints) {
  2250. vpn_progress(vpninfo, PRG_ERR,
  2251. _("None of the %d fingerprint(s) specified via --servercert match server's certificate: %s\n"),
  2252. allowed_fingerprints, fingerprint);
  2253. return -EINVAL;
  2254. }
  2255. while (1) {
  2256. char *details;
  2257. char *response = NULL;
  2258. fprintf(stderr, _("\nCertificate from VPN server \"%s\" failed verification.\n"
  2259. "Reason: %s\n"), vpninfo->hostname, reason);
  2260. fprintf(stderr, _("To trust this server in future, perhaps add this to your command line:\n"));
  2261. fprintf(stderr, _(" --servercert %s\n"), fingerprint);
  2262. if (non_inter)
  2263. return -EINVAL;
  2264. fprintf(stderr, _("Enter '%s' to accept, '%s' to abort; anything else to view: "),
  2265. _("yes"), _("no"));
  2266. read_stdin(&response, 0, 0);
  2267. if (!response)
  2268. return -EINVAL;
  2269. if (!strcasecmp(response, _("yes"))) {
  2270. struct accepted_cert *newcert;
  2271. newcert = malloc(sizeof(*newcert));
  2272. if (newcert) {
  2273. newcert->next = accepted_certs;
  2274. accepted_certs = newcert;
  2275. newcert->fingerprint = strdup(fingerprint);
  2276. newcert->host = strdup(vpninfo->hostname);
  2277. newcert->port = vpninfo->port;
  2278. }
  2279. free(response);
  2280. return 0;
  2281. }
  2282. if (!strcasecmp(response, _("no"))) {
  2283. free(response);
  2284. return -EINVAL;
  2285. }
  2286. free(response);
  2287. details = openconnect_get_peer_cert_details(vpninfo);
  2288. fputs(details, stderr);
  2289. openconnect_free_cert_info(vpninfo, details);
  2290. fprintf(stderr, _("Server key hash: %s\n"), fingerprint);
  2291. }
  2292. }
  2293. static int match_choice_label(struct openconnect_info *vpninfo,
  2294. struct oc_form_opt_select *select_opt,
  2295. char *label)
  2296. {
  2297. int i, input_len, partial_matches = 0;
  2298. char *match = NULL;
  2299. input_len = strlen(label);
  2300. if (input_len < 1)
  2301. return -EINVAL;
  2302. for (i = 0; i < select_opt->nr_choices; i++) {
  2303. struct oc_choice *choice = select_opt->choices[i];
  2304. if (!strncasecmp(label, choice->label, input_len)) {
  2305. if (strlen(choice->label) == input_len) {
  2306. select_opt->form._value = choice->name;
  2307. return 0;
  2308. } else {
  2309. match = choice->name;
  2310. partial_matches++;
  2311. }
  2312. }
  2313. }
  2314. if (partial_matches == 1) {
  2315. select_opt->form._value = match;
  2316. return 0;
  2317. } else if (partial_matches > 1) {
  2318. vpn_progress(vpninfo, PRG_ERR,
  2319. _("Auth choice \"%s\" matches multiple options\n"), label);
  2320. return -EINVAL;
  2321. } else {
  2322. vpn_progress(vpninfo, PRG_ERR, _("Auth choice \"%s\" not available\n"), label);
  2323. return -EINVAL;
  2324. }
  2325. }
  2326. static char *prompt_for_input(const char *prompt,
  2327. struct openconnect_info *vpninfo,
  2328. int hidden)
  2329. {
  2330. char *response = NULL;
  2331. fprintf(stderr, "%s", prompt);
  2332. fflush(stderr);
  2333. if (non_inter) {
  2334. if (allow_stdin_read) {
  2335. read_stdin(&response, hidden, 1);
  2336. }
  2337. if (response == NULL) {
  2338. fprintf(stderr, "***\n");
  2339. vpn_progress(vpninfo, PRG_ERR,
  2340. _("User input required in non-interactive mode\n"));
  2341. }
  2342. return response;
  2343. }
  2344. read_stdin(&response, hidden, 0);
  2345. return response;
  2346. }
  2347. static int prompt_opt_select(struct openconnect_info *vpninfo,
  2348. struct oc_form_opt_select *select_opt,
  2349. char **saved_response)
  2350. {
  2351. int i;
  2352. char *response;
  2353. if (!select_opt->nr_choices)
  2354. return -EINVAL;
  2355. retry:
  2356. fprintf(stderr, "%s [", select_opt->form.label);
  2357. for (i = 0; i < select_opt->nr_choices; i++) {
  2358. struct oc_choice *choice = select_opt->choices[i];
  2359. if (i)
  2360. fprintf(stderr, "|");
  2361. fprintf(stderr, "%s", choice->label);
  2362. }
  2363. fprintf(stderr, "]:");
  2364. if (select_opt->nr_choices == 1) {
  2365. response = strdup(select_opt->choices[0]->label);
  2366. fprintf(stderr, "%s\n", response);
  2367. } else
  2368. response = prompt_for_input("", vpninfo, 0);
  2369. if (!response)
  2370. return -EINVAL;
  2371. if (match_choice_label(vpninfo, select_opt, response) < 0) {
  2372. free(response);
  2373. goto retry;
  2374. }
  2375. if (saved_response)
  2376. *saved_response = response;
  2377. else
  2378. free(response);
  2379. return 0;
  2380. }
  2381. struct form_field {
  2382. struct form_field *next;
  2383. char *form_id;
  2384. char *opt_id;
  2385. char *value;
  2386. };
  2387. static struct form_field *form_fields; /* static variable initialised to NULL */
  2388. static void add_form_field(char *arg)
  2389. {
  2390. struct form_field *ff;
  2391. char *opt, *value = strchr(arg, '=');
  2392. if (!value || value == arg) {
  2393. bad_field:
  2394. fprintf(stderr, "Form field invalid. Use --form-entry=FORM_ID:OPT_NAME=VALUE\n");
  2395. exit(1);
  2396. }
  2397. *(value++) = 0;
  2398. opt = strchr(arg, ':');
  2399. if (!opt || opt == arg)
  2400. goto bad_field;
  2401. *(opt++) = 0;
  2402. ff = malloc(sizeof(*ff));
  2403. if (!ff) {
  2404. fprintf(stderr, "Out of memory for form field\n");
  2405. exit(1);
  2406. }
  2407. ff->form_id = arg;
  2408. ff->opt_id = opt;
  2409. ff->value = value;
  2410. ff->next = form_fields;
  2411. form_fields = ff;
  2412. }
  2413. static char *saved_form_field(struct openconnect_info *vpninfo, const char *form_id, const char *opt_id)
  2414. {
  2415. struct form_field *ff = form_fields;
  2416. while (ff) {
  2417. if (!strcmp(form_id, ff->form_id) && !strcmp(ff->opt_id, opt_id))
  2418. return strdup(ff->value);
  2419. ff = ff->next;
  2420. }
  2421. return NULL;
  2422. }
  2423. /* Return value:
  2424. * < 0, on error
  2425. * = 0, when form was parsed and POST required
  2426. * = 1, when response was cancelled by user
  2427. */
  2428. static int process_auth_form_cb(void *_vpninfo,
  2429. struct oc_auth_form *form)
  2430. {
  2431. struct openconnect_info *vpninfo = _vpninfo;
  2432. struct oc_form_opt *opt;
  2433. int empty = 1;
  2434. if (!form->auth_id)
  2435. return -EINVAL;
  2436. if (form->banner && vpninfo->verbose > PRG_ERR)
  2437. fprintf(stderr, "%s\n", form->banner);
  2438. if (form->error)
  2439. fprintf(stderr, "%s\n", form->error);
  2440. if (form->message && vpninfo->verbose > PRG_ERR)
  2441. fprintf(stderr, "%s\n", form->message);
  2442. /* Special handling for GROUP: field if present, as different group
  2443. selections can make other fields disappear/reappear */
  2444. if (form->authgroup_opt) {
  2445. if (!authgroup)
  2446. authgroup = saved_form_field(vpninfo, form->auth_id, form->authgroup_opt->form.name);
  2447. if (!authgroup ||
  2448. match_choice_label(vpninfo, form->authgroup_opt, authgroup) != 0) {
  2449. if (prompt_opt_select(vpninfo, form->authgroup_opt, &authgroup) < 0)
  2450. goto err;
  2451. }
  2452. if (!authgroup_set) {
  2453. authgroup_set = 1;
  2454. return OC_FORM_RESULT_NEWGROUP;
  2455. }
  2456. }
  2457. for (opt = form->opts; opt; opt = opt->next) {
  2458. if (opt->flags & OC_FORM_OPT_IGNORE)
  2459. continue;
  2460. /* I haven't actually seen a non-authgroup dropdown in the wild, but
  2461. the Cisco clients do support them */
  2462. if (opt->type == OC_FORM_OPT_SELECT) {
  2463. struct oc_form_opt_select *select_opt = (void *)opt;
  2464. char *opt_response;
  2465. if (select_opt == form->authgroup_opt)
  2466. continue;
  2467. opt_response = saved_form_field(vpninfo, form->auth_id, select_opt->form.name);
  2468. if (opt_response &&
  2469. match_choice_label(vpninfo, select_opt, opt_response) == 0) {
  2470. free(opt_response);
  2471. continue;
  2472. }
  2473. free(opt_response);
  2474. if (prompt_opt_select(vpninfo, select_opt, NULL) < 0)
  2475. goto err;
  2476. empty = 0;
  2477. } else if (opt->type == OC_FORM_OPT_TEXT) {
  2478. if (username &&
  2479. (!strncasecmp(opt->name, "user", 4) ||
  2480. !strncasecmp(opt->name, "uname", 5))) {
  2481. opt->_value = strdup(username);
  2482. } else {
  2483. opt->_value = saved_form_field(vpninfo, form->auth_id, opt->name);
  2484. if (!opt->_value)
  2485. opt->_value = prompt_for_input(opt->label, vpninfo, 0);
  2486. }
  2487. if (!opt->_value)
  2488. goto err;
  2489. empty = 0;
  2490. } else if (opt->type == OC_FORM_OPT_PASSWORD) {
  2491. if (password) {
  2492. opt->_value = password;
  2493. password = NULL;
  2494. } else {
  2495. opt->_value = saved_form_field(vpninfo, form->auth_id, opt->name);
  2496. if (!opt->_value)
  2497. opt->_value = prompt_for_input(opt->label, vpninfo, 1);
  2498. }
  2499. if (!opt->_value)
  2500. goto err;
  2501. empty = 0;
  2502. } else if (opt->type == OC_FORM_OPT_TOKEN ||
  2503. opt->type == OC_FORM_OPT_HIDDEN) {
  2504. /* Nothing to do here, but if the tokencode is being
  2505. * automatically generated then don't treat it as an
  2506. * empty form for the purpose of loop avoidance. */
  2507. empty = 0;
  2508. }
  2509. }
  2510. /* prevent infinite loops if the authgroup requires certificate auth only */
  2511. if (last_form_empty && empty)
  2512. return OC_FORM_RESULT_CANCELLED;
  2513. last_form_empty = empty;
  2514. return OC_FORM_RESULT_OK;
  2515. err:
  2516. return OC_FORM_RESULT_ERR;
  2517. }
  2518. static int lock_token(void *tokdata)
  2519. {
  2520. struct openconnect_info *vpninfo = tokdata;
  2521. char *file_token;
  2522. int err;
  2523. /* FIXME: Actually lock the file */
  2524. err = openconnect_read_file(vpninfo, token_filename, &file_token);
  2525. if (err < 0)
  2526. return err;
  2527. err = openconnect_set_token_mode(vpninfo, vpninfo->token_mode, file_token);
  2528. free(file_token);
  2529. return err;
  2530. }
  2531. static int unlock_token(void *tokdata, const char *new_tok)
  2532. {
  2533. struct openconnect_info *vpninfo = tokdata;
  2534. int tok_fd;
  2535. int err;
  2536. if (!new_tok)
  2537. return 0;
  2538. tok_fd = openconnect_open_utf8(vpninfo, token_filename,
  2539. O_WRONLY|O_TRUNC|O_CREAT|O_BINARY);
  2540. if (tok_fd < 0) {
  2541. err = errno;
  2542. fprintf(stderr, _("Failed to open token file for write: %s\n"),
  2543. strerror(err));
  2544. return -err;
  2545. }
  2546. /* FIXME: We should actually write to a new tempfile, then rename */
  2547. if (write(tok_fd, new_tok, strlen(new_tok)) != strlen(new_tok)) {
  2548. err = errno;
  2549. fprintf(stderr, _("Failed to write token: %s\n"),
  2550. strerror(err));
  2551. close(tok_fd);
  2552. return -err;
  2553. }
  2554. close(tok_fd);
  2555. return 0;
  2556. }
  2557. static void init_token(struct openconnect_info *vpninfo,
  2558. oc_token_mode_t token_mode, const char *token_str)
  2559. {
  2560. int ret;
  2561. char *file_token = NULL;
  2562. if (token_str && (token_mode == OC_TOKEN_MODE_TOTP ||
  2563. token_mode == OC_TOKEN_MODE_HOTP)) {
  2564. switch(token_str[0]) {
  2565. case '@':
  2566. token_str++;
  2567. /* fall through... */
  2568. case '/':
  2569. if (openconnect_read_file(vpninfo, token_str,
  2570. &file_token) < 0)
  2571. exit(1);
  2572. break;
  2573. default:
  2574. /* Use token_str as raw data */
  2575. break;
  2576. }
  2577. }
  2578. ret = openconnect_set_token_mode(vpninfo, token_mode,
  2579. file_token ? : token_str);
  2580. if (file_token) {
  2581. token_filename = strdup(token_str);
  2582. openconnect_set_token_callbacks(vpninfo, vpninfo,
  2583. lock_token, unlock_token);
  2584. free(file_token);
  2585. }
  2586. switch (token_mode) {
  2587. case OC_TOKEN_MODE_STOKEN:
  2588. switch (ret) {
  2589. case 0:
  2590. return;
  2591. case -EINVAL:
  2592. fprintf(stderr, _("Soft token string is invalid\n"));
  2593. exit(1);
  2594. case -ENOENT:
  2595. if (token_str)
  2596. fprintf(stderr, _("Can't open stoken file\n"));
  2597. else
  2598. fprintf(stderr, _("Can't open ~/.stokenrc file\n"));
  2599. exit(1);
  2600. case -EOPNOTSUPP:
  2601. fprintf(stderr, _("OpenConnect was not built with libstoken support\n"));
  2602. exit(1);
  2603. default:
  2604. fprintf(stderr, _("General failure in libstoken\n"));
  2605. exit(1);
  2606. }
  2607. break;
  2608. case OC_TOKEN_MODE_TOTP:
  2609. case OC_TOKEN_MODE_HOTP:
  2610. switch (ret) {
  2611. case 0:
  2612. return;
  2613. case -EINVAL:
  2614. fprintf(stderr, _("Soft token string is invalid\n"));
  2615. exit(1);
  2616. case -EOPNOTSUPP:
  2617. fprintf(stderr, _("OpenConnect was not built with liboath support\n"));
  2618. exit(1);
  2619. default:
  2620. fprintf(stderr, _("General failure in liboath\n"));
  2621. exit(1);
  2622. }
  2623. break;
  2624. case OC_TOKEN_MODE_YUBIOATH:
  2625. switch(ret) {
  2626. case 0:
  2627. return;
  2628. case -ENOENT:
  2629. fprintf(stderr, _("Yubikey token not found\n"));
  2630. exit(1);
  2631. case -EOPNOTSUPP:
  2632. fprintf(stderr, _("OpenConnect was not built with Yubikey support\n"));
  2633. exit(1);
  2634. default:
  2635. fprintf(stderr, _("General Yubikey failure: %s\n"), strerror(-ret));
  2636. exit(1);
  2637. }
  2638. case OC_TOKEN_MODE_OIDC:
  2639. switch (ret) {
  2640. case 0:
  2641. return;
  2642. case -ENOENT:
  2643. fprintf(stderr, _("Can't open oidc file\n"));
  2644. exit(1);
  2645. default:
  2646. fprintf(stderr, _("General failure in oidc token\n"));
  2647. exit(1);
  2648. }
  2649. break;
  2650. case OC_TOKEN_MODE_NONE:
  2651. /* No-op */
  2652. break;
  2653. /* Option parsing already checked for invalid modes. */
  2654. }
  2655. }