You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

462 lines
11 KiB

  1. /*
  2. * WPA module for netcfg
  3. *
  4. * Copyright (C) 2008 Glenn Saberton <gsaberton@foomagic.org>
  5. *
  6. * Licensed under the terms of the GNU General Public License version 2
  7. *
  8. */
  9. #include "netcfg.h"
  10. #include <errno.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <debian-installer.h>
  14. #ifdef WIRELESS
  15. #include "wpa_ctrl.h"
  16. #include <iwlib.h>
  17. pid_t wpa_supplicant_pid = -1;
  18. struct wpa_ctrl *ctrl;
  19. static int wpa_is_running = 0;
  20. int init_wpa_supplicant_support(struct netcfg_interface *interface)
  21. {
  22. if (access("/sbin/wpa_supplicant", F_OK) == 0)
  23. interface->wpa_supplicant_status = WPA_OK;
  24. else {
  25. interface->wpa_supplicant_status = WPA_UNAVAIL;
  26. di_info("Wpasupplicant not found on the system. Disabling WPA options");
  27. }
  28. return 0;
  29. }
  30. int kill_wpa_supplicant(void)
  31. {
  32. pid_t wpa_pid;
  33. FILE *fp;
  34. fp = (fopen(WPAPID, "r"));
  35. if (fp == NULL) {
  36. di_warning("Couldn't read Wpasupplicant pid file, not trying to kill.");
  37. return 0;
  38. }
  39. else {
  40. if (fscanf(fp, "%d", &wpa_pid) != 1) {
  41. di_warning("Couldn't read pid from Wpasupplicant pid file, not trying to kill.");
  42. return 0;
  43. }
  44. fclose(fp);
  45. }
  46. if ((kill(wpa_pid, SIGTERM)) == 0)
  47. return 0;
  48. else {
  49. kill(wpa_pid, SIGKILL);
  50. unlink(WPAPID);
  51. return 0;
  52. }
  53. }
  54. int wireless_security_type (struct debconfclient *client, const char *if_name)
  55. {
  56. debconf_subst(client, "netcfg/wireless_security_type", "iface", if_name);
  57. debconf_input(client, "high", "netcfg/wireless_security_type");
  58. if (debconf_go(client) == CMD_GOBACK)
  59. return GO_BACK;
  60. debconf_get(client, "netcfg/wireless_security_type");
  61. if (!strcmp(client->value, "wep/open"))
  62. return REPLY_WEP;
  63. else
  64. return REPLY_WPA;
  65. }
  66. int netcfg_set_passphrase (struct debconfclient *client, struct netcfg_interface *interface)
  67. {
  68. debconf_subst(client, "netcfg/wireless_wpa", "iface", interface->name);
  69. debconf_input(client, "high", "netcfg/wireless_wpa");
  70. if (debconf_go(client) == CMD_GOBACK)
  71. return GO_BACK;
  72. if (interface->passphrase != NULL)
  73. free(interface->passphrase);
  74. debconf_get(client, "netcfg/wireless_wpa");
  75. interface->passphrase = strdup(client->value);
  76. while (strlen(interface->passphrase) < WPA_MIN || strlen(interface->passphrase) > WPA_MAX) {
  77. debconf_subst(client, "netcfg/invalid_pass", "passphrase", interface->passphrase);
  78. debconf_input(client, "critical", "netcfg/invalid_pass");
  79. debconf_go(client);
  80. free(interface->passphrase);
  81. debconf_input(client, "high", "netcfg/wireless_wpa");
  82. if (debconf_go(client) == CMD_GOBACK)
  83. return GO_BACK;
  84. debconf_get(client, "netcfg/wireless_wpa");
  85. interface->passphrase = strdup(client->value);
  86. }
  87. return 0;
  88. }
  89. static int start_wpa_daemon(struct debconfclient *client, const char *if_name)
  90. {
  91. wpa_supplicant_pid = fork();
  92. if (wpa_supplicant_pid == 0) {
  93. fclose(client->out);
  94. if (execlp("wpa_supplicant", "wpa_supplicant", "-i", if_name, "-C",
  95. WPASUPP_CTRL, "-P", WPAPID, "-B", NULL) == -1) {
  96. di_error("could not exec wpasupplicant: %s", strerror(errno));
  97. return 1;
  98. }
  99. else
  100. return 0;
  101. }
  102. else {
  103. waitpid(wpa_supplicant_pid, NULL, 0);
  104. return 0;
  105. }
  106. }
  107. void wpa_daemon_running(void)
  108. {
  109. FILE *fp = fopen(WPAPID, "r");
  110. if (fp) {
  111. wpa_is_running = 1;
  112. fclose(fp);
  113. }
  114. }
  115. static int wpa_connect(const char *if_name)
  116. {
  117. char *cfile;
  118. int flen, res;
  119. flen = (strlen(WPASUPP_CTRL) + strlen(if_name) + 2);
  120. cfile = malloc(flen);
  121. if (cfile == NULL) {
  122. di_info("Can't allocate memory for WPA control interface.");
  123. return 1;
  124. }
  125. res = snprintf(cfile, flen, "%s/%s", WPASUPP_CTRL, if_name);
  126. if ((res < 0) || (res >= flen)) {
  127. free(cfile);
  128. return 1;
  129. }
  130. ctrl = wpa_ctrl_open(cfile);
  131. free(cfile);
  132. if (ctrl == NULL) {
  133. di_info("Couldn't connect to wpasupplicant");
  134. return 1;
  135. }
  136. else
  137. return 0;
  138. }
  139. static int netcfg_wpa_cmd (char *cmd)
  140. {
  141. char buf[256];
  142. size_t len;
  143. int ret;
  144. len = sizeof(buf) -1;
  145. ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL);
  146. if (ret < 0) {
  147. di_info("Sending %s to wpasupplicant failed", cmd);
  148. return 1;
  149. }
  150. return 0;
  151. }
  152. static int wpa_set_ssid (char *ssid)
  153. {
  154. int ret, res;
  155. size_t len;
  156. char cmd[256];
  157. char buf[256];
  158. res = snprintf(cmd, sizeof(cmd), "SET_NETWORK 0 %s \"%s\"", "ssid", ssid);
  159. if (res < 0)
  160. return 1;
  161. len = sizeof(buf) -1;
  162. ret = wpa_ctrl_request(ctrl, cmd, sizeof(cmd), buf, &len, NULL);
  163. if (ret != 0) {
  164. di_info("Failed to set the ssid with wpasupplicant");
  165. return 1;
  166. }
  167. return 0;
  168. }
  169. static int wpa_set_psk(char *passphrase)
  170. {
  171. int ret, res;
  172. size_t len;
  173. char buf[256];
  174. char cmd[256];
  175. res = snprintf(cmd, sizeof(cmd), "SET_NETWORK 0 %s \"%s\"", "psk", passphrase);
  176. if (res < 0)
  177. return 1;
  178. len = sizeof(buf) -1;
  179. ret = wpa_ctrl_request(ctrl, cmd, sizeof(cmd), buf, &len, NULL);
  180. if (ret != 0)
  181. return 1;
  182. return 0;
  183. }
  184. static int wpa_status(void)
  185. {
  186. int ret;
  187. size_t len;
  188. char buf[2048];
  189. const char *success = "wpa_state=COMPLETED";
  190. len = sizeof(buf) -1;
  191. ret = wpa_ctrl_request(ctrl, "STATUS", 7, buf, &len, NULL);
  192. if (ret == 0) {
  193. buf[len] = '\0';
  194. di_info("buf = %s", buf);
  195. }
  196. else
  197. return 1;
  198. if (strstr(buf, success) == NULL)
  199. return 1;
  200. else {
  201. di_info("success");
  202. return 0;
  203. }
  204. }
  205. int poll_wpa_supplicant(struct debconfclient *client)
  206. {
  207. int wpa_timeout = 60;
  208. int seconds_slept = 0;
  209. int state = 1;
  210. debconf_capb(client, "backup progresscancel");
  211. debconf_progress_start(client, 0, wpa_timeout, "netcfg/wpa_progress");
  212. for (seconds_slept = 0; seconds_slept <= wpa_timeout; seconds_slept++) {
  213. if (debconf_progress_info(client, "netcfg/wpa_progress_note") ==
  214. CMD_PROGRESSCANCELLED)
  215. goto stop;
  216. if (debconf_progress_step(client, 1) == CMD_PROGRESSCANCELLED)
  217. goto stop;
  218. sleep(1);
  219. if ((seconds_slept <= wpa_timeout) && (seconds_slept % 5) == 0) {
  220. if (!wpa_status()) {
  221. debconf_progress_set(client, wpa_timeout);
  222. debconf_progress_info(client, "netcfg/wpa_success_note");
  223. state = 0;
  224. sleep(2);
  225. goto stop;
  226. }
  227. }
  228. if (seconds_slept == wpa_timeout) {
  229. debconf_progress_stop(client);
  230. debconf_capb(client, "backup");
  231. debconf_capb(client, "");
  232. debconf_input(client, "critical", "netcfg/wpa_supplicant_failed");
  233. debconf_go(client);
  234. debconf_capb(client, "backup");
  235. return 1;
  236. }
  237. }
  238. stop:
  239. debconf_progress_stop(client);
  240. debconf_capb(client, "backup");
  241. if (!state)
  242. return 0;
  243. else
  244. return 1;
  245. }
  246. int wpa_supplicant_start(struct debconfclient *client, const struct netcfg_interface *interface)
  247. {
  248. int retry = 0;
  249. enum { CHECK_DAEMON,
  250. START_DAEMON,
  251. CONNECT,
  252. PING,
  253. ADD_NETWORK,
  254. SET_ESSID,
  255. SET_PSK,
  256. SET_SCAN_SSID,
  257. ENABLE_NETWORK,
  258. POLL,
  259. ABORT,
  260. SUCCESS } state = CHECK_DAEMON;
  261. for (;;) {
  262. switch(state) {
  263. case CHECK_DAEMON:
  264. wpa_daemon_running();
  265. if (wpa_is_running)
  266. state = CONNECT;
  267. else
  268. state = START_DAEMON;
  269. break;
  270. case START_DAEMON:
  271. if (!start_wpa_daemon(client, interface->name))
  272. state = CONNECT;
  273. else
  274. state = ABORT;
  275. break;
  276. case CONNECT:
  277. if (wpa_connect(interface->name) == 0)
  278. state = PING;
  279. else
  280. state = ABORT;
  281. break;
  282. case PING:
  283. /* if the daemon doesn't respond, try and ping
  284. * it and increment retry. If we have done
  285. * this 4 times, something must be wrong
  286. * so bail out. */
  287. retry++;
  288. if (retry > 4)
  289. state = ABORT;
  290. else if (netcfg_wpa_cmd("PING")) {
  291. kill_wpa_supplicant();
  292. state = START_DAEMON;
  293. break;
  294. }
  295. else
  296. state = ADD_NETWORK;
  297. break;
  298. case ADD_NETWORK:
  299. if (wpa_is_running) {
  300. state = SET_ESSID;
  301. break;
  302. }
  303. if (netcfg_wpa_cmd("ADD_NETWORK"))
  304. state = PING;
  305. else
  306. state = SET_ESSID;
  307. break;
  308. case SET_ESSID:
  309. if (wpa_set_ssid(interface->essid))
  310. state = PING;
  311. else
  312. state = SET_PSK;
  313. break;
  314. case SET_PSK:
  315. if (wpa_set_psk(interface->passphrase))
  316. state = PING;
  317. else
  318. state = SET_SCAN_SSID;
  319. break;
  320. case SET_SCAN_SSID:
  321. if (netcfg_wpa_cmd("SET_NETWORK 0 scan_ssid 1"))
  322. state = PING;
  323. else
  324. state = ENABLE_NETWORK;
  325. break;
  326. case ENABLE_NETWORK:
  327. if (netcfg_wpa_cmd("ENABLE_NETWORK 0"))
  328. state = PING;
  329. else
  330. state = POLL;
  331. break;
  332. case POLL:
  333. if (poll_wpa_supplicant(client))
  334. state = ABORT;
  335. else
  336. state = SUCCESS;
  337. break;
  338. case ABORT:
  339. if (ctrl == NULL)
  340. return GO_BACK;
  341. else {
  342. wpa_ctrl_close(ctrl);
  343. ctrl = NULL;
  344. return GO_BACK;
  345. }
  346. case SUCCESS:
  347. if (ctrl == NULL)
  348. return 0;
  349. else {
  350. wpa_ctrl_close(ctrl);
  351. ctrl = NULL;
  352. return 0;
  353. }
  354. }
  355. }
  356. }
  357. #else /* Non-WIRELESS stubs of public API */
  358. int init_wpa_supplicant_support(struct netcfg_interface *interface)
  359. {
  360. (void)interface;
  361. return 0;
  362. }
  363. int kill_wpa_supplicant(void)
  364. {
  365. return 0;
  366. }
  367. int wireless_security_type(struct debconfclient *client, const char *if_name)
  368. {
  369. (void)client;
  370. (void)if_name;
  371. return 0;
  372. }
  373. int netcfg_set_passphrase(struct debconfclient *client, struct netcfg_interface *interface)
  374. {
  375. (void)client;
  376. (void)interface;
  377. return 0;
  378. }
  379. int wpa_supplicant_start(struct debconfclient *client, const struct netcfg_interface *interface)
  380. {
  381. (void)client;
  382. (void)interface;
  383. return 0;
  384. }
  385. #endif /* WIRELESS */