jni.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636
  1. /*
  2. * OpenConnect (SSL + DTLS) VPN client
  3. *
  4. * Copyright © 2013 Kevin Cernekee <cernekee@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public License
  8. * version 2.1, as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. */
  15. #include <config.h>
  16. #include "openconnect.h"
  17. #include <jni.h>
  18. #include <unistd.h>
  19. #include <sys/types.h>
  20. #include <errno.h>
  21. #include <stdarg.h>
  22. #include <stdint.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. struct libctx {
  27. JNIEnv *jenv;
  28. jobject jobj;
  29. jobject async_lock;
  30. struct openconnect_info *vpninfo;
  31. int cmd_fd;
  32. int loglevel;
  33. };
  34. static void throw_excep(JNIEnv *jenv, const char *exc, int line)
  35. {
  36. jclass excep;
  37. char msg[64];
  38. snprintf(msg, 64, "%s:%d", __FILE__, line);
  39. (*jenv)->ExceptionClear(jenv);
  40. excep = (*jenv)->FindClass(jenv, exc);
  41. if (excep)
  42. (*jenv)->ThrowNew(jenv, excep, msg);
  43. }
  44. #define OOM(jenv) throw_excep(jenv, "java/lang/OutOfMemoryError", __LINE__)
  45. static struct libctx *getctx(JNIEnv *jenv, jobject jobj)
  46. {
  47. jclass jcls = (*jenv)->GetObjectClass(jenv, jobj);
  48. jfieldID jfld = (*jenv)->GetFieldID(jenv, jcls, "libctx", "J");
  49. if (!jfld)
  50. return NULL;
  51. return (void *)(unsigned long)(*jenv)->GetLongField(jenv, jobj, jfld);
  52. }
  53. /*
  54. * GetMethodID() and GetFieldID() and NewStringUTF() will automatically throw exceptions on error
  55. */
  56. static jmethodID get_obj_mid(struct libctx *ctx, jobject jobj, const char *name, const char *sig)
  57. {
  58. jclass jcls = (*ctx->jenv)->GetObjectClass(ctx->jenv, jobj);
  59. jmethodID mid = (*ctx->jenv)->GetMethodID(ctx->jenv, jcls, name, sig);
  60. return mid;
  61. }
  62. static jstring dup_to_jstring(JNIEnv *jenv, const char *in)
  63. {
  64. /*
  65. * Many implementations of NewStringUTF() will return NULL on
  66. * NULL input, but that isn't guaranteed:
  67. * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35979
  68. */
  69. return in ? (*jenv)->NewStringUTF(jenv, in) : NULL;
  70. }
  71. static int get_cstring(JNIEnv *jenv, jstring in, const char **out)
  72. {
  73. const char *tmp;
  74. if (in == NULL) {
  75. *out = NULL;
  76. return 0;
  77. }
  78. tmp = (*jenv)->GetStringUTFChars(jenv, in, NULL);
  79. if (!tmp) {
  80. OOM(jenv);
  81. return -1;
  82. }
  83. *out = tmp;
  84. return 0;
  85. }
  86. static void release_cstring(JNIEnv *jenv, jstring jstr, const char *cstr)
  87. {
  88. if (cstr)
  89. (*jenv)->ReleaseStringUTFChars(jenv, jstr, cstr);
  90. }
  91. static int set_int(struct libctx *ctx, jobject jobj, const char *name, int value)
  92. {
  93. jclass jcls = (*ctx->jenv)->GetObjectClass(ctx->jenv, jobj);
  94. jfieldID jfld = (*ctx->jenv)->GetFieldID(ctx->jenv, jcls, name, "I");
  95. if (!jfld)
  96. return -1;
  97. (*ctx->jenv)->SetIntField(ctx->jenv, jobj, jfld, value);
  98. return 0;
  99. }
  100. static int set_long(struct libctx *ctx, jobject jobj, const char *name, uint64_t value)
  101. {
  102. jclass jcls = (*ctx->jenv)->GetObjectClass(ctx->jenv, jobj);
  103. jfieldID jfld = (*ctx->jenv)->GetFieldID(ctx->jenv, jcls, name, "J");
  104. if (!jfld)
  105. return -1;
  106. (*ctx->jenv)->SetLongField(ctx->jenv, jobj, jfld, (jlong)value);
  107. return 0;
  108. }
  109. static int set_string(struct libctx *ctx, jobject jobj, const char *name, const char *value)
  110. {
  111. jclass jcls = (*ctx->jenv)->GetObjectClass(ctx->jenv, jobj);
  112. jfieldID jfld = (*ctx->jenv)->GetFieldID(ctx->jenv, jcls, name, "Ljava/lang/String;");
  113. jstring jarg;
  114. if (!jfld)
  115. return -1;
  116. jarg = dup_to_jstring(ctx->jenv, value);
  117. if (value && !jarg)
  118. return -1;
  119. (*ctx->jenv)->SetObjectField(ctx->jenv, jobj, jfld, jarg);
  120. return 0;
  121. }
  122. static int add_string(struct libctx *ctx, jclass jcls, jobject jobj,
  123. const char *name, const char *value)
  124. {
  125. jmethodID mid = (*ctx->jenv)->GetMethodID(ctx->jenv, jcls, name, "(Ljava/lang/String;)V");
  126. jstring jarg;
  127. if (!value)
  128. return 0;
  129. if (!mid)
  130. return -1;
  131. jarg = dup_to_jstring(ctx->jenv, value);
  132. if (!jarg)
  133. return -1;
  134. (*ctx->jenv)->CallVoidMethod(ctx->jenv, jobj, mid, jarg);
  135. (*ctx->jenv)->DeleteLocalRef(ctx->jenv, jarg);
  136. return 0;
  137. }
  138. static int add_string_pair(struct libctx *ctx, jclass jcls, jobject jobj,
  139. const char *name, const char *key, const char *value)
  140. {
  141. jmethodID mid = (*ctx->jenv)->GetMethodID(ctx->jenv, jcls, name, "(Ljava/lang/String;Ljava/lang/String;)V");
  142. jstring jarg0, jarg1;
  143. if (!key || !value)
  144. return -1;
  145. if (!mid)
  146. return -1;
  147. jarg0 = dup_to_jstring(ctx->jenv, key);
  148. if (!jarg0)
  149. return -1;
  150. jarg1 = dup_to_jstring(ctx->jenv, value);
  151. if (!jarg1) {
  152. (*ctx->jenv)->DeleteLocalRef(ctx->jenv, jarg0);
  153. return -1;
  154. }
  155. (*ctx->jenv)->CallVoidMethod(ctx->jenv, jobj, mid, jarg0, jarg1);
  156. (*ctx->jenv)->DeleteLocalRef(ctx->jenv, jarg1);
  157. (*ctx->jenv)->DeleteLocalRef(ctx->jenv, jarg0);
  158. return 0;
  159. }
  160. static int validate_peer_cert_cb(void *privdata, const char *reason)
  161. {
  162. struct libctx *ctx = privdata;
  163. jstring jreason;
  164. int ret = -1;
  165. jmethodID mid;
  166. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  167. return -1;
  168. jreason = dup_to_jstring(ctx->jenv, reason);
  169. if (!jreason)
  170. goto out;
  171. mid = get_obj_mid(ctx, ctx->jobj, "onValidatePeerCert", "(Ljava/lang/String;)I");
  172. if (mid)
  173. ret = (*ctx->jenv)->CallIntMethod(ctx->jenv, ctx->jobj, mid, jreason);
  174. out:
  175. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  176. return ret;
  177. }
  178. static int write_new_config_cb(void *privdata, const char *buf, int buflen)
  179. {
  180. struct libctx *ctx = privdata;
  181. jmethodID mid;
  182. jbyteArray jbuf;
  183. int ret = -1;
  184. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  185. return -1;
  186. mid = get_obj_mid(ctx, ctx->jobj, "onWriteNewConfig", "([B)I");
  187. if (!mid)
  188. goto out;
  189. jbuf = (*ctx->jenv)->NewByteArray(ctx->jenv, buflen);
  190. if (!jbuf)
  191. goto out;
  192. (*ctx->jenv)->SetByteArrayRegion(ctx->jenv, jbuf, 0, buflen, (jbyte *)buf);
  193. ret = (*ctx->jenv)->CallIntMethod(ctx->jenv, ctx->jobj, mid, jbuf);
  194. out:
  195. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  196. return ret;
  197. }
  198. static void protect_socket_cb(void *privdata, int fd)
  199. {
  200. struct libctx *ctx = privdata;
  201. jmethodID mid;
  202. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  203. return;
  204. mid = get_obj_mid(ctx, ctx->jobj, "onProtectSocket", "(I)V");
  205. if (mid)
  206. (*ctx->jenv)->CallVoidMethod(ctx->jenv, ctx->jobj, mid, fd);
  207. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  208. }
  209. static void stats_cb(void *privdata, const struct oc_stats *stats)
  210. {
  211. struct libctx *ctx = privdata;
  212. jmethodID mid;
  213. jclass jcls;
  214. jobject jobj = NULL;
  215. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  216. return;
  217. jcls = (*ctx->jenv)->FindClass(ctx->jenv, "org/infradead/libopenconnect/LibOpenConnect$VPNStats");
  218. if (jcls == NULL)
  219. goto out;
  220. mid = (*ctx->jenv)->GetMethodID(ctx->jenv, jcls, "<init>", "()V");
  221. if (!mid)
  222. goto out;
  223. jobj = (*ctx->jenv)->NewObject(ctx->jenv, jcls, mid);
  224. if (!jobj)
  225. goto out;
  226. if (set_long(ctx, jobj, "txPkts", stats->tx_pkts) ||
  227. set_long(ctx, jobj, "txBytes", stats->tx_bytes) ||
  228. set_long(ctx, jobj, "rxPkts", stats->rx_pkts) ||
  229. set_long(ctx, jobj, "rxBytes", stats->rx_bytes))
  230. goto out;
  231. mid = get_obj_mid(ctx, ctx->jobj, "onStatsUpdate",
  232. "(Lorg/infradead/libopenconnect/LibOpenConnect$VPNStats;)V");
  233. if (mid)
  234. (*ctx->jenv)->CallVoidMethod(ctx->jenv, ctx->jobj, mid, jobj);
  235. out:
  236. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  237. }
  238. static void setup_tun_cb(void *privdata)
  239. {
  240. struct libctx *ctx = privdata;
  241. jmethodID mid;
  242. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  243. return;
  244. mid = get_obj_mid(ctx, ctx->jobj, "onSetupTun", "()V");
  245. if (mid)
  246. (*ctx->jenv)->CallVoidMethod(ctx->jenv, ctx->jobj, mid);
  247. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  248. }
  249. static void reconnected_cb(void *privdata)
  250. {
  251. struct libctx *ctx = privdata;
  252. jmethodID mid;
  253. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  254. return;
  255. mid = get_obj_mid(ctx, ctx->jobj, "onReconnected", "()V");
  256. if (mid)
  257. (*ctx->jenv)->CallVoidMethod(ctx->jenv, ctx->jobj, mid);
  258. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  259. }
  260. static jobject new_auth_form(struct libctx *ctx, struct oc_auth_form *form)
  261. {
  262. jmethodID mid;
  263. jclass jcls;
  264. jobject jobj = NULL;
  265. jcls = (*ctx->jenv)->FindClass(ctx->jenv, "org/infradead/libopenconnect/LibOpenConnect$AuthForm");
  266. if (jcls == NULL)
  267. return NULL;
  268. mid = (*ctx->jenv)->GetMethodID(ctx->jenv, jcls, "<init>", "()V");
  269. if (!mid)
  270. return NULL;
  271. jobj = (*ctx->jenv)->NewObject(ctx->jenv, jcls, mid);
  272. if (!jobj)
  273. return NULL;
  274. if (set_string(ctx, jobj, "banner", form->banner) ||
  275. set_string(ctx, jobj, "message", form->message) ||
  276. set_string(ctx, jobj, "error", form->error) ||
  277. set_string(ctx, jobj, "authID", form->auth_id) ||
  278. set_string(ctx, jobj, "method", form->method) ||
  279. set_string(ctx, jobj, "action", form->action) ||
  280. set_int(ctx, jobj, "authgroupSelection", form->authgroup_selection)) {
  281. return NULL;
  282. }
  283. return jobj;
  284. }
  285. static jobject new_form_choice(struct libctx *ctx, struct oc_choice *choice)
  286. {
  287. jmethodID mid;
  288. jclass jcls;
  289. jobject jobj = NULL;
  290. jcls = (*ctx->jenv)->FindClass(ctx->jenv,
  291. "org/infradead/libopenconnect/LibOpenConnect$FormChoice");
  292. if (jcls == NULL)
  293. return NULL;
  294. mid = (*ctx->jenv)->GetMethodID(ctx->jenv, jcls, "<init>", "()V");
  295. if (!mid)
  296. return NULL;
  297. jobj = (*ctx->jenv)->NewObject(ctx->jenv, jcls, mid);
  298. if (!jobj)
  299. return NULL;
  300. if (set_string(ctx, jobj, "name", choice->name) ||
  301. set_string(ctx, jobj, "label", choice->label) ||
  302. set_string(ctx, jobj, "authType", choice->auth_type) ||
  303. set_string(ctx, jobj, "overrideName", choice->override_name) ||
  304. set_string(ctx, jobj, "overrideLabel", choice->override_label)) {
  305. return NULL;
  306. }
  307. return jobj;
  308. }
  309. static int populate_select_choices(struct libctx *ctx, jobject jopt, struct oc_form_opt_select *opt)
  310. {
  311. jmethodID mid;
  312. int i;
  313. mid = get_obj_mid(ctx, jopt, "addChoice",
  314. "(Lorg/infradead/libopenconnect/LibOpenConnect$FormChoice;)V");
  315. if (!mid)
  316. return -1;
  317. for (i = 0; i < opt->nr_choices; i++) {
  318. jobject jformchoice = new_form_choice(ctx, opt->choices[i]);
  319. if (!jformchoice)
  320. return -1;
  321. (*ctx->jenv)->CallVoidMethod(ctx->jenv, jopt, mid, jformchoice);
  322. }
  323. return 0;
  324. }
  325. static int add_form_option(struct libctx *ctx, jobject jform, struct oc_form_opt *opt, int is_authgroup)
  326. {
  327. jmethodID addOpt;
  328. jobject jopt;
  329. addOpt = get_obj_mid(ctx, jform, "addOpt",
  330. "(Z)Lorg/infradead/libopenconnect/LibOpenConnect$FormOpt;");
  331. if (!addOpt)
  332. return -1;
  333. jopt = (*ctx->jenv)->CallObjectMethod(ctx->jenv, jform, addOpt, is_authgroup);
  334. if (jopt == NULL)
  335. return -1;
  336. if (set_int(ctx, jopt, "type", opt->type) ||
  337. set_string(ctx, jopt, "name", opt->name) ||
  338. set_string(ctx, jopt, "label", opt->label) ||
  339. set_string(ctx, jopt, "value", opt->_value) ||
  340. set_long(ctx, jopt, "flags", opt->flags))
  341. return -1;
  342. if (opt->type == OC_FORM_OPT_SELECT &&
  343. populate_select_choices(ctx, jopt, (struct oc_form_opt_select *)opt))
  344. return -1;
  345. return 0;
  346. }
  347. static char *lookup_choice_name(struct oc_form_opt_select *opt, const char *name)
  348. {
  349. int i;
  350. /* opt->_value is NOT a caller-allocated string for OC_FORM_OPT_SELECT */
  351. for (i = 0; i < opt->nr_choices; i++)
  352. if (!strcmp(opt->choices[i]->name, name))
  353. return opt->choices[i]->name;
  354. return NULL;
  355. }
  356. static int process_auth_form_cb(void *privdata, struct oc_auth_form *form)
  357. {
  358. struct libctx *ctx = privdata;
  359. jobject jform;
  360. jmethodID callback, getOptValue;
  361. struct oc_form_opt *opt;
  362. jint ret;
  363. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  364. return -1;
  365. /* create and populate new AuthForm object and option/choice lists */
  366. jform = new_auth_form(ctx, form);
  367. if (!jform)
  368. goto err;
  369. getOptValue = get_obj_mid(ctx, jform, "getOptValue", "(Ljava/lang/String;)Ljava/lang/String;");
  370. if (!getOptValue)
  371. goto err;
  372. for (opt = form->opts; opt; opt = opt->next) {
  373. int is_authgroup = opt == (void *)form->authgroup_opt;
  374. if (add_form_option(ctx, jform, opt, is_authgroup) < 0)
  375. goto err;
  376. }
  377. /* invoke onProcessAuthForm callback */
  378. callback = get_obj_mid(ctx, ctx->jobj, "onProcessAuthForm",
  379. "(Lorg/infradead/libopenconnect/LibOpenConnect$AuthForm;)I");
  380. if (!callback)
  381. goto err;
  382. ret = (*ctx->jenv)->CallIntMethod(ctx->jenv, ctx->jobj, callback, jform);
  383. /* copy any populated form fields back into the C structs */
  384. for (opt = form->opts; opt; opt = opt->next) {
  385. jstring jname, jvalue;
  386. jname = dup_to_jstring(ctx->jenv, opt->name);
  387. if (!jname)
  388. goto err;
  389. jvalue = (*ctx->jenv)->CallObjectMethod(ctx->jenv, jform, getOptValue, jname);
  390. if (jvalue) {
  391. const char *tmp = (*ctx->jenv)->GetStringUTFChars(ctx->jenv, jvalue, NULL);
  392. if (!tmp)
  393. goto err;
  394. if (opt->type == OC_FORM_OPT_SELECT)
  395. opt->_value = lookup_choice_name((void *)opt, tmp);
  396. else {
  397. free(opt->_value);
  398. opt->_value = strdup(tmp);
  399. if (!opt->_value)
  400. OOM(ctx->jenv);
  401. }
  402. (*ctx->jenv)->ReleaseStringUTFChars(ctx->jenv, jvalue, tmp);
  403. }
  404. }
  405. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  406. return ret;
  407. err:
  408. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  409. return -1;
  410. }
  411. static void __attribute__ ((format(printf, 3, 4)))
  412. progress_cb(void *privdata, int level, const char *fmt, ...)
  413. {
  414. struct libctx *ctx = privdata;
  415. va_list ap;
  416. char *msg;
  417. jstring jmsg;
  418. int ret, loglevel;
  419. jmethodID mid;
  420. (*ctx->jenv)->MonitorEnter(ctx->jenv, ctx->async_lock);
  421. loglevel = ctx->loglevel;
  422. (*ctx->jenv)->MonitorExit(ctx->jenv, ctx->async_lock);
  423. if (level > loglevel)
  424. return;
  425. va_start(ap, fmt);
  426. ret = vasprintf(&msg, fmt, ap);
  427. va_end(ap);
  428. if (ret < 0) {
  429. OOM(ctx->jenv);
  430. return;
  431. }
  432. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  433. return;
  434. jmsg = dup_to_jstring(ctx->jenv, msg);
  435. free(msg);
  436. if (!jmsg)
  437. goto out;
  438. mid = get_obj_mid(ctx, ctx->jobj, "onProgress", "(ILjava/lang/String;)V");
  439. if (mid)
  440. (*ctx->jenv)->CallVoidMethod(ctx->jenv, ctx->jobj, mid, level, jmsg);
  441. out:
  442. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  443. }
  444. static int lock_token_cb(void *privdata)
  445. {
  446. struct libctx *ctx = privdata;
  447. jmethodID mid;
  448. int ret = -1;
  449. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  450. return -1;
  451. mid = get_obj_mid(ctx, ctx->jobj, "onTokenLock", "()I");
  452. if (mid)
  453. ret = (*ctx->jenv)->CallIntMethod(ctx->jenv, ctx->jobj, mid);
  454. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  455. return ret;
  456. }
  457. static int unlock_token_cb(void *privdata, const char *new_token)
  458. {
  459. struct libctx *ctx = privdata;
  460. jstring jtoken;
  461. int ret = -1;
  462. jmethodID mid;
  463. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  464. return -1;
  465. jtoken = dup_to_jstring(ctx->jenv, new_token);
  466. if (!jtoken)
  467. goto out;
  468. mid = get_obj_mid(ctx, ctx->jobj, "onTokenUnlock", "(Ljava/lang/String;)I");
  469. if (mid)
  470. ret = (*ctx->jenv)->CallIntMethod(ctx->jenv, ctx->jobj, mid, jtoken);
  471. out:
  472. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  473. return ret;
  474. }
  475. /* Library init/uninit */
  476. static jobject init_async_lock(struct libctx *ctx)
  477. {
  478. jclass jcls = (*ctx->jenv)->GetObjectClass(ctx->jenv, ctx->jobj);
  479. jfieldID jfld = (*ctx->jenv)->GetFieldID(ctx->jenv, jcls, "asyncLock", "Ljava/lang/Object;");
  480. jobject jobj = (*ctx->jenv)->GetObjectField(ctx->jenv, ctx->jobj, jfld);
  481. if (jobj)
  482. jobj = (*ctx->jenv)->NewGlobalRef(ctx->jenv, jobj);
  483. return jobj;
  484. }
  485. JNIEXPORT jlong JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_init(
  486. JNIEnv *jenv, jobject jobj, jstring juseragent)
  487. {
  488. char *useragent;
  489. struct libctx *ctx = calloc(1, sizeof(*ctx));
  490. if (!ctx)
  491. goto bad;
  492. ctx->jenv = jenv;
  493. ctx->jobj = (*jenv)->NewGlobalRef(jenv, jobj);
  494. if (!ctx->jobj)
  495. goto bad_free_ctx;
  496. ctx->async_lock = init_async_lock(ctx);
  497. if (!ctx->async_lock)
  498. goto bad_delete_obj_ref;
  499. useragent = (char *)(*jenv)->GetStringUTFChars(jenv, juseragent, NULL);
  500. if (!useragent)
  501. goto bad_delete_ref;
  502. ctx->vpninfo = openconnect_vpninfo_new(useragent, validate_peer_cert_cb,
  503. write_new_config_cb, process_auth_form_cb,
  504. progress_cb, ctx);
  505. (*jenv)->ReleaseStringUTFChars(jenv, juseragent, useragent);
  506. if (!ctx->vpninfo)
  507. goto bad_delete_ref;
  508. openconnect_set_token_callbacks(ctx->vpninfo, ctx, lock_token_cb,
  509. unlock_token_cb);
  510. openconnect_set_protect_socket_handler(ctx->vpninfo, protect_socket_cb);
  511. openconnect_set_stats_handler(ctx->vpninfo, stats_cb);
  512. openconnect_set_setup_tun_handler(ctx->vpninfo, setup_tun_cb);
  513. openconnect_set_reconnected_handler(ctx->vpninfo, reconnected_cb);
  514. ctx->cmd_fd = openconnect_setup_cmd_pipe(ctx->vpninfo);
  515. if (ctx->cmd_fd < 0)
  516. goto bad_free_vpninfo;
  517. ctx->loglevel = PRG_DEBUG;
  518. return (jlong)(unsigned long)ctx;
  519. bad_free_vpninfo:
  520. openconnect_vpninfo_free(ctx->vpninfo);
  521. bad_delete_ref:
  522. (*jenv)->DeleteGlobalRef(jenv, ctx->async_lock);
  523. bad_delete_obj_ref:
  524. (*jenv)->DeleteGlobalRef(jenv, ctx->jobj);
  525. bad_free_ctx:
  526. free(ctx);
  527. bad:
  528. OOM(jenv);
  529. return 0;
  530. }
  531. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_free(
  532. JNIEnv *jenv, jobject jobj)
  533. {
  534. struct libctx *ctx = getctx(jenv, jobj);
  535. if (!ctx)
  536. return;
  537. openconnect_vpninfo_free(ctx->vpninfo);
  538. (*jenv)->DeleteGlobalRef(jenv, ctx->async_lock);
  539. (*jenv)->DeleteGlobalRef(jenv, ctx->jobj);
  540. free(ctx);
  541. }
  542. static void write_cmd_pipe(JNIEnv *jenv, jobject jobj, char cmd)
  543. {
  544. struct libctx *ctx = getctx(jenv, jobj);
  545. if (!ctx)
  546. return;
  547. if (write(ctx->cmd_fd, &cmd, 1) < 0) {
  548. /* probably dead already */
  549. }
  550. }
  551. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_doCancel(
  552. JNIEnv *jenv, jobject jobj)
  553. {
  554. write_cmd_pipe(jenv, jobj, OC_CMD_CANCEL);
  555. }
  556. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_pause(
  557. JNIEnv *jenv, jobject jobj)
  558. {
  559. write_cmd_pipe(jenv, jobj, OC_CMD_PAUSE);
  560. }
  561. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_requestStats(
  562. JNIEnv *jenv, jobject jobj)
  563. {
  564. write_cmd_pipe(jenv, jobj, OC_CMD_STATS);
  565. }
  566. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_globalInit(
  567. JNIEnv *jenv, jclass jcls)
  568. {
  569. openconnect_init_ssl();
  570. }
  571. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_obtainCookie(
  572. JNIEnv *jenv, jobject jobj)
  573. {
  574. struct libctx *ctx = getctx(jenv, jobj);
  575. if (!ctx)
  576. return 0;
  577. return openconnect_obtain_cookie(ctx->vpninfo);
  578. }
  579. /* special handling: caller-allocated buffer */
  580. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getPeerCertHash(
  581. JNIEnv *jenv, jobject jobj)
  582. {
  583. struct libctx *ctx = getctx(jenv, jobj);
  584. const char *hash;
  585. jstring jresult = NULL;
  586. if (!ctx)
  587. return NULL;
  588. hash = openconnect_get_peer_cert_hash(ctx->vpninfo);
  589. if (!hash)
  590. return NULL;
  591. jresult = dup_to_jstring(ctx->jenv, hash);
  592. if (!jresult)
  593. OOM(ctx->jenv);
  594. return jresult;
  595. }
  596. /* special handling: callee-allocated, caller-freed string */
  597. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getPeerCertDetails(
  598. JNIEnv *jenv, jobject jobj)
  599. {
  600. struct libctx *ctx = getctx(jenv, jobj);
  601. char *buf = NULL;
  602. jstring jresult = NULL;
  603. if (!ctx)
  604. return NULL;
  605. buf = openconnect_get_peer_cert_details(ctx->vpninfo);
  606. if (!buf)
  607. return NULL;
  608. jresult = dup_to_jstring(ctx->jenv, buf);
  609. if (!jresult)
  610. OOM(ctx->jenv);
  611. openconnect_free_cert_info(ctx->vpninfo, buf);
  612. return jresult;
  613. }
  614. /* special handling: callee-allocated, caller-freed binary buffer */
  615. JNIEXPORT jbyteArray JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getPeerCertDER(
  616. JNIEnv *jenv, jobject jobj)
  617. {
  618. struct libctx *ctx = getctx(jenv, jobj);
  619. unsigned char *buf = NULL;
  620. int ret;
  621. jbyteArray jresult = NULL;
  622. if (!ctx)
  623. return NULL;
  624. ret = openconnect_get_peer_cert_DER(ctx->vpninfo, &buf);
  625. if (ret < 0)
  626. return NULL;
  627. jresult = (*ctx->jenv)->NewByteArray(ctx->jenv, ret);
  628. if (jresult)
  629. (*ctx->jenv)->SetByteArrayRegion(ctx->jenv, jresult, 0, ret, (jbyte *) buf);
  630. openconnect_free_cert_info(ctx->vpninfo, buf);
  631. return jresult;
  632. }
  633. /* special handling: callee-allocated, caller-freed binary buffer */
  634. JNIEXPORT jbyteArray JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getPeerCertChain(
  635. JNIEnv *jenv, jobject jobj)
  636. {
  637. struct libctx *ctx = getctx(jenv, jobj);
  638. struct oc_cert *chain = NULL, *p;
  639. int cert_list_size, i;
  640. jobjectArray jresult = NULL;
  641. jclass jcls;
  642. if (!ctx)
  643. goto err;
  644. cert_list_size = openconnect_get_peer_cert_chain(ctx->vpninfo, &chain);
  645. if (cert_list_size <= 0)
  646. goto err;
  647. jcls = (*ctx->jenv)->FindClass(ctx->jenv, "[B");
  648. if (!jcls)
  649. goto err;
  650. jresult = (*ctx->jenv)->NewObjectArray(ctx->jenv, cert_list_size, jcls, NULL);
  651. if (!jresult)
  652. goto err;
  653. if ((*ctx->jenv)->PushLocalFrame(ctx->jenv, 256) < 0)
  654. goto err;
  655. for (i = 0, p = chain; i < cert_list_size; i++, p++) {
  656. jbyteArray cert = (*ctx->jenv)->NewByteArray(ctx->jenv, p->der_len);
  657. if (!cert)
  658. goto err2;
  659. (*ctx->jenv)->SetByteArrayRegion(ctx->jenv, cert, 0, p->der_len, (jbyte *)p->der_data);
  660. (*ctx->jenv)->SetObjectArrayElement(ctx->jenv, jresult, i, cert);
  661. }
  662. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  663. openconnect_free_peer_cert_chain(ctx->vpninfo, chain);
  664. return jresult;
  665. err2:
  666. (*ctx->jenv)->PopLocalFrame(ctx->jenv, NULL);
  667. err:
  668. if (jresult)
  669. (*ctx->jenv)->DeleteLocalRef(ctx->jenv, jresult);
  670. if (chain)
  671. openconnect_free_peer_cert_chain(ctx->vpninfo, chain);
  672. return NULL;
  673. }
  674. /* special handling: two string arguments */
  675. JNIEXPORT int JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setClientCert(
  676. JNIEnv *jenv, jobject jobj, jstring jcert, jstring jsslkey)
  677. {
  678. int ret;
  679. struct libctx *ctx = getctx(jenv, jobj);
  680. const char *cert = NULL, *sslkey = NULL;
  681. if (!ctx)
  682. return -EINVAL;
  683. if (get_cstring(ctx->jenv, jcert, &cert) ||
  684. get_cstring(ctx->jenv, jsslkey, &sslkey))
  685. return -ENOMEM;
  686. ret = openconnect_set_client_cert(ctx->vpninfo, cert, sslkey);
  687. release_cstring(ctx->jenv, jcert, cert);
  688. release_cstring(ctx->jenv, jsslkey, sslkey);
  689. return ret;
  690. }
  691. JNIEXPORT int JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setMCACert(
  692. JNIEnv *jenv, jobject jobj, jstring jcert, jstring jsslkey)
  693. {
  694. int ret;
  695. struct libctx *ctx = getctx(jenv, jobj);
  696. const char *cert = NULL, *sslkey = NULL;
  697. if (!ctx)
  698. return -EINVAL;
  699. if (get_cstring(ctx->jenv, jcert, &cert) ||
  700. get_cstring(ctx->jenv, jsslkey, &sslkey))
  701. return -ENOMEM;
  702. ret = openconnect_set_mca_cert(ctx->vpninfo, cert, sslkey);
  703. release_cstring(ctx->jenv, jcert, cert);
  704. release_cstring(ctx->jenv, jsslkey, sslkey);
  705. return ret;
  706. }
  707. /* special handling: multiple string arguments */
  708. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setupTunDevice(
  709. JNIEnv *jenv, jobject jobj, jstring jarg0, jstring jarg1)
  710. {
  711. struct libctx *ctx = getctx(jenv, jobj);
  712. const char *arg0 = NULL, *arg1 = NULL;
  713. int ret = -ENOMEM;
  714. if (!ctx)
  715. return -EINVAL;
  716. if (!get_cstring(ctx->jenv, jarg0, &arg0) &&
  717. !get_cstring(ctx->jenv, jarg1, &arg1))
  718. ret = openconnect_setup_tun_device(ctx->vpninfo, arg0, arg1);
  719. release_cstring(ctx->jenv, jarg0, arg0);
  720. release_cstring(ctx->jenv, jarg1, arg1);
  721. return ret;
  722. }
  723. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setCSDWrapper(
  724. JNIEnv *jenv, jobject jobj, jstring jarg0, jstring jarg1, jstring jarg2)
  725. {
  726. struct libctx *ctx = getctx(jenv, jobj);
  727. const char *arg0 = NULL, *arg1 = NULL, *arg2 = NULL;
  728. if (!ctx)
  729. return;
  730. if (!get_cstring(ctx->jenv, jarg0, &arg0) &&
  731. !get_cstring(ctx->jenv, jarg1, &arg1) &&
  732. !get_cstring(ctx->jenv, jarg2, &arg2)) {
  733. openconnect_setup_csd(ctx->vpninfo, getuid(), 1, arg0);
  734. if (arg1) openconnect_set_csd_environ(ctx->vpninfo, "TMPDIR", arg1);
  735. if (arg2) openconnect_set_csd_environ(ctx->vpninfo, "PATH", arg2);
  736. }
  737. release_cstring(ctx->jenv, jarg0, arg0);
  738. release_cstring(ctx->jenv, jarg1, arg1);
  739. release_cstring(ctx->jenv, jarg2, arg2);
  740. }
  741. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setMobileInfo(
  742. JNIEnv *jenv, jobject jobj, jstring jarg0, jstring jarg1, jstring jarg2)
  743. {
  744. struct libctx *ctx = getctx(jenv, jobj);
  745. const char *arg0 = NULL, *arg1 = NULL, *arg2 = NULL;
  746. if (!ctx)
  747. return;
  748. if (!get_cstring(ctx->jenv, jarg0, &arg0) &&
  749. !get_cstring(ctx->jenv, jarg1, &arg1) &&
  750. !get_cstring(ctx->jenv, jarg2, &arg2))
  751. openconnect_set_mobile_info(ctx->vpninfo, arg0, arg1, arg2);
  752. release_cstring(ctx->jenv, jarg0, arg0);
  753. release_cstring(ctx->jenv, jarg1, arg1);
  754. release_cstring(ctx->jenv, jarg2, arg2);
  755. }
  756. /* class methods (general library info) */
  757. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getVersion(
  758. JNIEnv *jenv, jclass jcls)
  759. {
  760. return dup_to_jstring(jenv, openconnect_get_version());
  761. }
  762. JNIEXPORT jboolean JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_hasPKCS11Support(
  763. JNIEnv *jenv, jclass jcls)
  764. {
  765. return openconnect_has_pkcs11_support();
  766. }
  767. JNIEXPORT jboolean JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_hasTSSBlobSupport(
  768. JNIEnv *jenv, jclass jcls)
  769. {
  770. return openconnect_has_tss_blob_support();
  771. }
  772. JNIEXPORT jboolean JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_hasTSS2BlobSupport(
  773. JNIEnv *jenv, jclass jcls)
  774. {
  775. return openconnect_has_tss2_blob_support();
  776. }
  777. JNIEXPORT jboolean JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_hasStokenSupport(
  778. JNIEnv *jenv, jclass jcls)
  779. {
  780. return openconnect_has_stoken_support();
  781. }
  782. JNIEXPORT jboolean JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_hasOATHSupport(
  783. JNIEnv *jenv, jclass jcls)
  784. {
  785. return openconnect_has_oath_support();
  786. }
  787. JNIEXPORT jboolean JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_hasYubiOATHSupport(
  788. JNIEnv *jenv, jclass jcls)
  789. {
  790. return openconnect_has_yubioath_support();
  791. }
  792. /* simple cases: void or int params */
  793. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getPort(
  794. JNIEnv *jenv, jobject jobj)
  795. {
  796. struct libctx *ctx = getctx(jenv, jobj);
  797. if (!ctx)
  798. return -EINVAL;
  799. return openconnect_get_port(ctx->vpninfo);
  800. }
  801. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_passphraseFromFSID(
  802. JNIEnv *jenv, jobject jobj)
  803. {
  804. struct libctx *ctx = getctx(jenv, jobj);
  805. if (!ctx)
  806. return -EINVAL;
  807. return openconnect_passphrase_from_fsid(ctx->vpninfo);
  808. }
  809. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_clearCookie(
  810. JNIEnv *jenv, jobject jobj)
  811. {
  812. struct libctx *ctx = getctx(jenv, jobj);
  813. if (!ctx)
  814. return;
  815. openconnect_clear_cookie(ctx->vpninfo);
  816. }
  817. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_resetSSL(
  818. JNIEnv *jenv, jobject jobj)
  819. {
  820. struct libctx *ctx = getctx(jenv, jobj);
  821. if (!ctx)
  822. return;
  823. openconnect_reset_ssl(ctx->vpninfo);
  824. }
  825. JNIEXPORT int JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_disableIPv6(
  826. JNIEnv *jenv, jobject jobj)
  827. {
  828. struct libctx *ctx = getctx(jenv, jobj);
  829. if (!ctx)
  830. return -EINVAL;
  831. return openconnect_disable_ipv6(ctx->vpninfo);
  832. }
  833. JNIEXPORT int JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_disableDTLS(
  834. JNIEnv *jenv, jobject jobj)
  835. {
  836. struct libctx *ctx = getctx(jenv, jobj);
  837. if (!ctx)
  838. return -EINVAL;
  839. return openconnect_disable_dtls(ctx->vpninfo);
  840. }
  841. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setCertExpiryWarning(
  842. JNIEnv *jenv, jobject jobj, jint arg)
  843. {
  844. struct libctx *ctx = getctx(jenv, jobj);
  845. if (!ctx)
  846. return;
  847. openconnect_set_cert_expiry_warning(ctx->vpninfo, arg);
  848. }
  849. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setReqMTU(
  850. JNIEnv *jenv, jobject jobj, jint arg)
  851. {
  852. struct libctx *ctx = getctx(jenv, jobj);
  853. if (!ctx)
  854. return;
  855. openconnect_set_reqmtu(ctx->vpninfo, arg);
  856. }
  857. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setDPD(
  858. JNIEnv *jenv, jobject jobj, jint arg)
  859. {
  860. struct libctx *ctx = getctx(jenv, jobj);
  861. if (!ctx)
  862. return;
  863. openconnect_set_dpd(ctx->vpninfo, arg);
  864. }
  865. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setTrojanInterval(
  866. JNIEnv *jenv, jobject jobj, jint arg)
  867. {
  868. struct libctx *ctx = getctx(jenv, jobj);
  869. if (!ctx)
  870. return;
  871. openconnect_set_trojan_interval(ctx->vpninfo, arg);
  872. }
  873. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setPassTOS(
  874. JNIEnv *jenv, jobject jobj, jboolean arg)
  875. {
  876. struct libctx *ctx = getctx(jenv, jobj);
  877. if (!ctx)
  878. return;
  879. openconnect_set_pass_tos(ctx->vpninfo, arg);
  880. }
  881. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setPFS(
  882. JNIEnv *jenv, jobject jobj, jboolean arg)
  883. {
  884. struct libctx *ctx = getctx(jenv, jobj);
  885. if (!ctx)
  886. return;
  887. openconnect_set_pfs(ctx->vpninfo, arg);
  888. }
  889. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setAllowInsecureCrypto(
  890. JNIEnv *jenv, jobject jobj, jboolean arg)
  891. {
  892. struct libctx *ctx = getctx(jenv, jobj);
  893. if (!ctx)
  894. return -EINVAL;
  895. return openconnect_set_allow_insecure_crypto(ctx->vpninfo, arg);
  896. }
  897. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setSystemTrust(
  898. JNIEnv *jenv, jobject jobj, jboolean arg)
  899. {
  900. struct libctx *ctx = getctx(jenv, jobj);
  901. if (!ctx)
  902. return;
  903. openconnect_set_system_trust(ctx->vpninfo, arg);
  904. }
  905. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_makeCSTPConnection(
  906. JNIEnv *jenv, jobject jobj)
  907. {
  908. struct libctx *ctx = getctx(jenv, jobj);
  909. if (!ctx)
  910. return -EINVAL;
  911. return openconnect_make_cstp_connection(ctx->vpninfo);
  912. }
  913. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setupDTLS(
  914. JNIEnv *jenv, jobject jobj, jint arg)
  915. {
  916. struct libctx *ctx = getctx(jenv, jobj);
  917. if (!ctx)
  918. return -EINVAL;
  919. return openconnect_setup_dtls(ctx->vpninfo, arg);
  920. }
  921. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_mainloop(
  922. JNIEnv *jenv, jobject jobj, jint arg0, jint arg1)
  923. {
  924. struct libctx *ctx = getctx(jenv, jobj);
  925. if (!ctx)
  926. return -EINVAL;
  927. return openconnect_mainloop(ctx->vpninfo, arg0, arg1);
  928. }
  929. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setLogLevel(
  930. JNIEnv *jenv, jobject jobj, jint arg)
  931. {
  932. struct libctx *ctx = getctx(jenv, jobj);
  933. if (!ctx)
  934. return;
  935. (*ctx->jenv)->MonitorEnter(ctx->jenv, ctx->async_lock);
  936. ctx->loglevel = arg;
  937. (*ctx->jenv)->MonitorExit(ctx->jenv, ctx->async_lock);
  938. }
  939. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setupTunFD(
  940. JNIEnv *jenv, jobject jobj, jint arg)
  941. {
  942. struct libctx *ctx = getctx(jenv, jobj);
  943. if (!ctx)
  944. return -EINVAL;
  945. return openconnect_setup_tun_fd(ctx->vpninfo, arg);
  946. }
  947. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setXMLPost(
  948. JNIEnv *jenv, jobject jobj, jboolean arg)
  949. {
  950. struct libctx *ctx = getctx(jenv, jobj);
  951. if (!ctx)
  952. return;
  953. openconnect_set_xmlpost(ctx->vpninfo, arg);
  954. }
  955. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getIdleTimeout(
  956. JNIEnv *jenv, jobject jobj)
  957. {
  958. struct libctx *ctx = getctx(jenv, jobj);
  959. if (!ctx)
  960. return -EINVAL;
  961. return openconnect_get_idle_timeout(ctx->vpninfo);
  962. }
  963. JNIEXPORT jobject JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getAuthExpiration(
  964. JNIEnv *jenv, jobject jobj)
  965. {
  966. struct libctx *ctx = getctx(jenv, jobj);
  967. jmethodID mid;
  968. jobject result;
  969. jclass jcls;
  970. time_t auth_expiration;
  971. if (!ctx)
  972. return NULL;
  973. auth_expiration = openconnect_get_auth_expiration(ctx->vpninfo);
  974. jcls = (*ctx->jenv)->FindClass(ctx->jenv, "java/time/Instant");
  975. if (jcls == NULL)
  976. goto err;
  977. mid = (*jenv)->GetStaticMethodID(jenv, jcls, "ofEpochSecond", "(J)Ljava/time/Instant;");
  978. if (!mid)
  979. goto err;
  980. result = (*jenv)->CallStaticObjectMethod(jenv, jcls, mid, auth_expiration);
  981. if (result == NULL)
  982. goto err;
  983. return result;
  984. err:
  985. return NULL;
  986. }
  987. /* simple cases: return a const string (no need to free it) */
  988. #define RETURN_STRING_START \
  989. struct libctx *ctx = getctx(jenv, jobj); \
  990. const char *buf = NULL; \
  991. jstring jresult = NULL; \
  992. if (!ctx) \
  993. return NULL; \
  994. #define RETURN_STRING_END \
  995. if (!buf) \
  996. return NULL; \
  997. jresult = dup_to_jstring(ctx->jenv, buf); \
  998. if (!jresult) \
  999. OOM(ctx->jenv); \
  1000. return jresult;
  1001. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getHostname(
  1002. JNIEnv *jenv, jobject jobj)
  1003. {
  1004. RETURN_STRING_START
  1005. buf = openconnect_get_hostname(ctx->vpninfo);
  1006. RETURN_STRING_END
  1007. }
  1008. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getDNSName(
  1009. JNIEnv *jenv, jobject jobj)
  1010. {
  1011. RETURN_STRING_START
  1012. buf = openconnect_get_dnsname(ctx->vpninfo);
  1013. RETURN_STRING_END
  1014. }
  1015. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getUrlpath(
  1016. JNIEnv *jenv, jobject jobj)
  1017. {
  1018. RETURN_STRING_START
  1019. buf = openconnect_get_urlpath(ctx->vpninfo);
  1020. RETURN_STRING_END
  1021. }
  1022. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getCookie(
  1023. JNIEnv *jenv, jobject jobj)
  1024. {
  1025. RETURN_STRING_START
  1026. buf = openconnect_get_cookie(ctx->vpninfo);
  1027. RETURN_STRING_END
  1028. }
  1029. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getIFName(
  1030. JNIEnv *jenv, jobject jobj)
  1031. {
  1032. RETURN_STRING_START
  1033. buf = openconnect_get_ifname(ctx->vpninfo);
  1034. RETURN_STRING_END
  1035. }
  1036. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getDTLSCipher(
  1037. JNIEnv *jenv, jobject jobj)
  1038. {
  1039. RETURN_STRING_START
  1040. buf = openconnect_get_dtls_cipher(ctx->vpninfo);
  1041. RETURN_STRING_END
  1042. }
  1043. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getDTLSCompression(
  1044. JNIEnv *jenv, jobject jobj)
  1045. {
  1046. RETURN_STRING_START
  1047. buf = openconnect_get_dtls_compression(ctx->vpninfo);
  1048. RETURN_STRING_END
  1049. }
  1050. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getCSTPCompression(
  1051. JNIEnv *jenv, jobject jobj)
  1052. {
  1053. RETURN_STRING_START
  1054. buf = openconnect_get_cstp_compression(ctx->vpninfo);
  1055. RETURN_STRING_END
  1056. }
  1057. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getCSTPCipher(
  1058. JNIEnv *jenv, jobject jobj)
  1059. {
  1060. RETURN_STRING_START
  1061. buf = openconnect_get_cstp_cipher(ctx->vpninfo);
  1062. RETURN_STRING_END
  1063. }
  1064. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getProtocol(
  1065. JNIEnv *jenv, jobject jobj)
  1066. {
  1067. RETURN_STRING_START
  1068. buf = openconnect_get_protocol(ctx->vpninfo);
  1069. RETURN_STRING_END
  1070. }
  1071. JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getConnectUrl(
  1072. JNIEnv *jenv, jobject jobj)
  1073. {
  1074. RETURN_STRING_START
  1075. buf = openconnect_get_connect_url(ctx->vpninfo);
  1076. RETURN_STRING_END
  1077. }
  1078. #define SET_STRING_START() \
  1079. struct libctx *ctx = getctx(jenv, jobj); \
  1080. const char *arg = NULL; \
  1081. if (!ctx) \
  1082. return -EINVAL; \
  1083. if (get_cstring(ctx->jenv, jarg, &arg)) \
  1084. return -ENOMEM;
  1085. #define SET_STRING_START_VOID() \
  1086. struct libctx *ctx = getctx(jenv, jobj); \
  1087. const char *arg = NULL; \
  1088. if (!ctx) \
  1089. return; \
  1090. if (get_cstring(ctx->jenv, jarg, &arg)) \
  1091. return;
  1092. #define SET_STRING_END() \
  1093. release_cstring(ctx->jenv, jarg, arg)
  1094. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_checkPeerCertHash(
  1095. JNIEnv *jenv, jobject jobj, jstring jarg)
  1096. {
  1097. int ret;
  1098. SET_STRING_START()
  1099. ret = openconnect_check_peer_cert_hash(ctx->vpninfo, arg);
  1100. SET_STRING_END();
  1101. return ret;
  1102. }
  1103. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_parseURL(
  1104. JNIEnv *jenv, jobject jobj, jstring jarg)
  1105. {
  1106. int ret;
  1107. SET_STRING_START()
  1108. ret = openconnect_parse_url(ctx->vpninfo, arg);
  1109. SET_STRING_END();
  1110. return ret;
  1111. }
  1112. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setProxyAuth(
  1113. JNIEnv *jenv, jobject jobj, jstring jarg)
  1114. {
  1115. int ret;
  1116. SET_STRING_START()
  1117. ret = openconnect_set_proxy_auth(ctx->vpninfo, arg);
  1118. SET_STRING_END();
  1119. return ret;
  1120. }
  1121. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setHTTPProxy(
  1122. JNIEnv *jenv, jobject jobj, jstring jarg)
  1123. {
  1124. int ret;
  1125. SET_STRING_START()
  1126. ret = openconnect_set_http_proxy(ctx->vpninfo, arg);
  1127. SET_STRING_END();
  1128. return ret;
  1129. }
  1130. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setProtocol(
  1131. JNIEnv *jenv, jobject jobj, jstring jarg)
  1132. {
  1133. int ret;
  1134. SET_STRING_START()
  1135. ret = openconnect_set_protocol(ctx->vpninfo, arg);
  1136. SET_STRING_END();
  1137. return ret;
  1138. }
  1139. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setXMLSHA1(
  1140. JNIEnv *jenv, jobject jobj, jstring jarg)
  1141. {
  1142. SET_STRING_START_VOID()
  1143. openconnect_set_xmlsha1(ctx->vpninfo, arg, strlen(arg) + 1);
  1144. SET_STRING_END();
  1145. }
  1146. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setHostname(
  1147. JNIEnv *jenv, jobject jobj, jstring jarg)
  1148. {
  1149. SET_STRING_START_VOID()
  1150. openconnect_set_hostname(ctx->vpninfo, arg);
  1151. SET_STRING_END();
  1152. }
  1153. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setVersionString(
  1154. JNIEnv *jenv, jobject jobj, jstring jarg)
  1155. {
  1156. SET_STRING_START_VOID()
  1157. openconnect_set_version_string(ctx->vpninfo, arg);
  1158. SET_STRING_END();
  1159. }
  1160. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setUsergent(
  1161. JNIEnv *jenv, jobject jobj, jstring jarg)
  1162. {
  1163. SET_STRING_START_VOID()
  1164. openconnect_set_useragent(ctx->vpninfo, arg);
  1165. SET_STRING_END();
  1166. }
  1167. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setUrlpath(
  1168. JNIEnv *jenv, jobject jobj, jstring jarg)
  1169. {
  1170. SET_STRING_START_VOID()
  1171. openconnect_set_urlpath(ctx->vpninfo, arg);
  1172. SET_STRING_END();
  1173. }
  1174. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setCookie(
  1175. JNIEnv *jenv, jobject jobj, jstring jarg)
  1176. {
  1177. SET_STRING_START_VOID()
  1178. openconnect_set_cookie(ctx->vpninfo, arg);
  1179. SET_STRING_END();
  1180. }
  1181. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setLocalName(
  1182. JNIEnv *jenv, jobject jobj, jstring jarg)
  1183. {
  1184. SET_STRING_START_VOID()
  1185. openconnect_set_localname(ctx->vpninfo, arg);
  1186. SET_STRING_END();
  1187. }
  1188. JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setCAFile(
  1189. JNIEnv *jenv, jobject jobj, jstring jarg)
  1190. {
  1191. SET_STRING_START_VOID()
  1192. openconnect_set_cafile(ctx->vpninfo, arg);
  1193. SET_STRING_END();
  1194. }
  1195. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setReportedOS(
  1196. JNIEnv *jenv, jobject jobj, jstring jarg)
  1197. {
  1198. SET_STRING_START()
  1199. return openconnect_set_reported_os(ctx->vpninfo, arg);
  1200. SET_STRING_END();
  1201. }
  1202. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setTokenMode(
  1203. JNIEnv *jenv, jobject jobj, jint mode, jstring jarg)
  1204. {
  1205. int ret;
  1206. SET_STRING_START()
  1207. ret = openconnect_set_token_mode(ctx->vpninfo, mode, arg);
  1208. SET_STRING_END();
  1209. return ret;
  1210. }
  1211. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setupTunScript(
  1212. JNIEnv *jenv, jobject jobj, jstring jarg)
  1213. {
  1214. int ret;
  1215. SET_STRING_START()
  1216. ret = openconnect_setup_tun_script(ctx->vpninfo, arg);
  1217. SET_STRING_END();
  1218. return ret;
  1219. }
  1220. JNIEXPORT jobject JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getIPInfo(
  1221. JNIEnv *jenv, jobject jobj)
  1222. {
  1223. struct libctx *ctx = getctx(jenv, jobj);
  1224. jmethodID mid;
  1225. jclass jcls;
  1226. const struct oc_ip_info *ip;
  1227. const struct oc_vpn_option *cstp, *dtls;
  1228. struct oc_split_include *inc;
  1229. int i;
  1230. if (!ctx)
  1231. return NULL;
  1232. if (openconnect_get_ip_info(ctx->vpninfo, &ip, &cstp, &dtls) < 0)
  1233. return NULL;
  1234. if (!ip)
  1235. return NULL;
  1236. jcls = (*ctx->jenv)->FindClass(ctx->jenv,
  1237. "org/infradead/libopenconnect/LibOpenConnect$IPInfo");
  1238. if (jcls == NULL)
  1239. return NULL;
  1240. mid = (*ctx->jenv)->GetMethodID(ctx->jenv, jcls, "<init>", "()V");
  1241. if (!mid)
  1242. return NULL;
  1243. jobj = (*ctx->jenv)->NewObject(ctx->jenv, jcls, mid);
  1244. if (!jobj)
  1245. return NULL;
  1246. if (set_string(ctx, jobj, "addr", ip->addr) ||
  1247. set_string(ctx, jobj, "netmask", ip->netmask) ||
  1248. set_string(ctx, jobj, "addr6", ip->addr6) ||
  1249. set_string(ctx, jobj, "netmask6", ip->netmask6) ||
  1250. set_string(ctx, jobj, "domain", ip->domain) ||
  1251. set_string(ctx, jobj, "proxyPac", ip->proxy_pac) ||
  1252. set_string(ctx, jobj, "gatewayAddr", ip->gateway_addr) ||
  1253. set_int(ctx, jobj, "MTU", ip->mtu))
  1254. return NULL;
  1255. for (i = 0; i < 3; i++) {
  1256. if (ip->dns[i] && add_string(ctx, jcls, jobj, "addDNS", ip->dns[i]))
  1257. return NULL;
  1258. if (ip->nbns[i] && add_string(ctx, jcls, jobj, "addNBNS", ip->nbns[i]))
  1259. return NULL;
  1260. }
  1261. for (inc = ip->split_dns; inc; inc = inc->next)
  1262. if (add_string(ctx, jcls, jobj, "addSplitDNS", inc->route))
  1263. return NULL;
  1264. for (inc = ip->split_includes; inc; inc = inc->next)
  1265. if (add_string(ctx, jcls, jobj, "addSplitInclude", inc->route))
  1266. return NULL;
  1267. for (inc = ip->split_excludes; inc; inc = inc->next)
  1268. if (add_string(ctx, jcls, jobj, "addSplitExclude", inc->route))
  1269. return NULL;
  1270. for (; cstp; cstp = cstp->next)
  1271. if (add_string_pair(ctx, jcls, jobj, "addCSTPOption", cstp->option, cstp->value))
  1272. return NULL;
  1273. for (; dtls; dtls = dtls->next)
  1274. if (add_string_pair(ctx, jcls, jobj, "addDTLSOption", dtls->option, dtls->value))
  1275. return NULL;
  1276. return jobj;
  1277. }
  1278. JNIEXPORT jobjectArray JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getSupportedProtocols(
  1279. JNIEnv *jenv, jclass jcls)
  1280. {
  1281. jmethodID mid;
  1282. jobjectArray result;
  1283. struct libctx ctx = { .jenv = jenv, .jobj = NULL, .async_lock = NULL, .vpninfo = NULL, .cmd_fd = -1, .loglevel = -1 };
  1284. /* call C library */
  1285. struct oc_vpn_proto *protos;
  1286. int np, ii;
  1287. np = openconnect_get_supported_protocols(&protos);
  1288. if (np < 0)
  1289. return NULL;
  1290. /* get VPNProto class, its init method, and create array */
  1291. jcls = (*jenv)->FindClass(jenv,
  1292. "org/infradead/libopenconnect/LibOpenConnect$VPNProto");
  1293. if (jcls == NULL)
  1294. goto err;
  1295. mid = (*jenv)->GetMethodID(jenv, jcls, "<init>", "()V");
  1296. if (!mid)
  1297. goto err;
  1298. result = (*jenv)->NewObjectArray(jenv, np, jcls, NULL);
  1299. if (result == NULL)
  1300. goto nomem;
  1301. for (ii=0; ii<np; ii++) {
  1302. jobject jobj = (*jenv)->NewObject(jenv, jcls, mid);
  1303. if (!jobj)
  1304. goto nomem;
  1305. if (set_string(&ctx, jobj, "name", protos[ii].name) ||
  1306. set_string(&ctx, jobj, "prettyName", protos[ii].pretty_name) ||
  1307. set_string(&ctx, jobj, "description", protos[ii].description) ||
  1308. set_int (&ctx, jobj, "flags", protos[ii].flags))
  1309. goto nomem;
  1310. (*jenv)->SetObjectArrayElement(jenv, result, ii, jobj);
  1311. }
  1312. openconnect_free_supported_protocols(protos);
  1313. return result;
  1314. nomem:
  1315. OOM(jenv);
  1316. err:
  1317. openconnect_free_supported_protocols(protos);
  1318. return NULL;
  1319. }
  1320. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setKeyPassword(
  1321. JNIEnv *jenv, jobject jobj, jstring jarg, jstring jarg2)
  1322. {
  1323. int ret;
  1324. SET_STRING_START();
  1325. ret = openconnect_set_key_password(ctx->vpninfo, arg);
  1326. SET_STRING_END();
  1327. return ret;
  1328. }
  1329. JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setMCAKeyPassword(
  1330. JNIEnv *jenv, jobject jobj, jstring jarg, jstring jarg2)
  1331. {
  1332. int ret;
  1333. SET_STRING_START();
  1334. ret = openconnect_set_mca_key_password(ctx->vpninfo, arg);
  1335. SET_STRING_END();
  1336. return ret;
  1337. }