[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[RFC v5] [PATCH 3/3] Add WPA support to netcfg



OK, maybe I get it right this time. So sorry for the noise I am generating on the list, seems I am a slow learner.

Add support to netcfg. This patch add functionality to choose to install from a WPA PSK protected wifi network. If wpasupplicant is not available, fall
back to previous behaviour.

Fixes bug #327309
---
 packages/netcfg/Makefile                       |    4 +-
 packages/netcfg/base-installer                 |    2 +-
 packages/netcfg/debian/netcfg-common.templates |   21 +++++
 packages/netcfg/debian/rules                   |    2 +-
 packages/netcfg/dhcp.c                         |   57 +++++++++++---
 packages/netcfg/netcfg-static.c                |   37 +++++++++-
 packages/netcfg/netcfg.c                       |   43 ++++++++++-
 packages/netcfg/netcfg.h                       |   16 ++++-
 packages/netcfg/static.c                       |   18 +++--
 packages/netcfg/wireless.c                     |   66 ++++++++++++++++-
 packages/netcfg/wpa.c                          |   97 ++++++++++++++++++++++++
 11 files changed, 332 insertions(+), 31 deletions(-)
 create mode 100644 packages/netcfg/wpa.c

diff --git a/packages/netcfg/Makefile b/packages/netcfg/Makefile
index 4753350..15d2f67 100644
--- a/packages/netcfg/Makefile
+++ b/packages/netcfg/Makefile
@@ -17,8 +17,8 @@ endif
 
 all: $(TARGETS)
 
-netcfg-static: netcfg-static.o static.o
-netcfg: netcfg.o dhcp.o static.o ethtool-lite.o
+netcfg-static: netcfg-static.o static.o wpa.o
+netcfg: netcfg.o dhcp.o static.o ethtool-lite.o wpa.o
 
 $(TARGETS): $(COMMON_OBJS)
 	$(CC) -o $@ $^ $(LDOPTS)
diff --git a/packages/netcfg/base-installer b/packages/netcfg/base-installer
index da51feb..9ae7a56 100644
--- a/packages/netcfg/base-installer
+++ b/packages/netcfg/base-installer
@@ -1,7 +1,7 @@
 #!/bin/sh -e
 # Copy all relevant networking-related files to /target.
 
-for file in /etc/network/interfaces /etc/networks /etc/hostname /etc/resolv.conf /etc/hosts; do
+for file in /etc/network/interfaces /etc/networks /etc/hostname /etc/resolv.conf /etc/hosts /etc/wpa_supplicant/wpa_supplicant.conf; do
 	if [ -f "$file" ]; then
 		mkdir /target/$(dirname $file) -p
 		cp $file /target/$file
diff --git a/packages/netcfg/debian/netcfg-common.templates b/packages/netcfg/debian/netcfg-common.templates
index 973411e..8ac6f09 100644
--- a/packages/netcfg/debian/netcfg-common.templates
+++ b/packages/netcfg/debian/netcfg-common.templates
@@ -56,6 +56,14 @@ _Description: Wireless ESSID for ${iface}:
  of the wireless network you would like ${iface} to use. To skip wireless
  configuration and continue, leave this field blank.
 
+Template: netcfg/wireless_security_type
+Type: select
+__Choices: WEP/Open, WPA PSK
+# :sl2:
+_Description: Wireless Network Type for ${iface}:
+ Choose WEP/Open if the network is open or secured with WEP.
+ Choose WPA if the network is a WPA PSK protected network.
+
 Template: netcfg/wireless_wep
 Type: string
 # :sl1:
@@ -80,6 +88,19 @@ _Description: Invalid WEP key
  the next screen carefully on how to enter your WEP key correctly, and try
  again.
 
+Template: netcfg/invalid_pass
+Type: error
+# :sl2:
+_Description: Invalid passphrase
+ The WPA PSK passphrase was either too long (more than 64 characters)
+ or too short (less than 8 characters).
+
+Template: netcfg/wireless_wpa
+Type: string
+# :sl1:
+_Description: WPA passphrase for wireless device ${iface}:
+ Enter a passphrase for WPA PSK authentication.
+
 Template: netcfg/invalid_essid
 Type: error
 # :sl2:
diff --git a/packages/netcfg/debian/rules b/packages/netcfg/debian/rules
index 21b5f13..fdc2ff3 100755
--- a/packages/netcfg/debian/rules
+++ b/packages/netcfg/debian/rules
@@ -26,7 +26,7 @@ install: build
 	dh_testdir
 	dh_testroot
 	dh_clean -k
-	dh_installdirs -A usr/lib/base-installer.d etc/network bin
+	dh_installdirs -A usr/lib/base-installer.d etc/network etc/wpa_supplicant bin
 	# Install files that are the same in all packages
 	$(foreach PACKAGE, $(PACKAGES), \
 		install -m 755 $(PACKAGE) debian/$(PACKAGE)/bin/netcfg; \
diff --git a/packages/netcfg/dhcp.c b/packages/netcfg/dhcp.c
index a98981f..0c84429 100644
--- a/packages/netcfg/dhcp.c
+++ b/packages/netcfg/dhcp.c
@@ -50,13 +50,17 @@ static void netcfg_write_dhcp (char *iface, char *dhostname)
             fprintf(fp, "\thostname %s\n", dhostname);
         }
         if (is_wireless_iface(iface)) {
-            fprintf(fp, "\t# wireless-* options are implemented by the wireless-tools package\n");
-            fprintf(fp, "\twireless-mode %s\n",
-                    (mode == MANAGED) ? "managed" : "ad-hoc");
-            fprintf(fp, "\twireless-essid %s\n",
-                    (essid && *essid) ? essid : "any");
-            if (wepkey != NULL)
-                fprintf(fp, "\twireless-key1 %s\n", wepkey);
+            if (requested_wpa_supplicant == 1)
+                fprintf(fp, "\twpa-conf /etc/wpa_supplicant/wpa_supplicant.conf\n");
+            else {
+                fprintf(fp, "\t# wireless-* options are implemented by the wireless-tools package\n");
+                fprintf(fp, "\twireless-mode %s\n",
+                       (mode == MANAGED) ? "managed" : "ad-hoc");
+                fprintf(fp, "\twireless-essid %s\n",
+                        (essid && *essid) ? essid : "any");
+                if (wepkey != NULL)
+                    fprintf(fp, "\twireless-key1 %s\n", wepkey);
+	    }
         }
         fclose(fp);
     }
@@ -306,16 +310,45 @@ int ask_dhcp_options (struct debconfclient *client)
 
 int ask_wifi_configuration (struct debconfclient *client)
 {
-    enum { ABORT, DONE, ESSID, WEP } wifistate = ESSID;
+    enum { ABORT, ESSID, SECURITY, WEP, WPA, DONE } wifistate = ESSID;
+
+    extern int requested_wpa_supplicant;
+    if (requested_wpa_supplicant != 2)
+        kill_wpa_supplicant();
+
     for (;;) {
         switch (wifistate) {
         case ESSID:
-            wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
-                ABORT : WEP;
+            if (requested_wpa_supplicant == 2)
+                wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
+                    ABORT : WEP;
+            else
+                wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
+                    ABORT : SECURITY;
             break;
+        case SECURITY:
+            {
+            int ret;
+            ret = netcfg_wireless_set_security(client, interface);
+            if (ret == GO_BACK)
+                wifistate = ESSID;
+            else if (ret == REPLY_WPA)
+                wifistate = WPA;
+            else
+                wifistate = WEP;
+            break;
+        }
         case WEP:
-            wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
-                ESSID : DONE;
+            if (requested_wpa_supplicant == 2)
+                wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
+                    ESSID : DONE;
+            else
+                wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
+                    SECURITY : DONE;
+            break;
+        case WPA:
+            wifistate = (netcfg_set_passphrase(client, interface) == GO_BACK) ?
+                SECURITY : DONE;
             break;
         case ABORT:
             return REPLY_ASK_OPTIONS;
diff --git a/packages/netcfg/netcfg-static.c b/packages/netcfg/netcfg-static.c
index 285f26f..8e761c4 100644
--- a/packages/netcfg/netcfg-static.c
+++ b/packages/netcfg/netcfg-static.c
@@ -32,6 +32,7 @@ int main(int argc, char** argv)
     int num_interfaces = 0;
     static struct debconfclient *client;
     static int requested_wireless_tools = 0;
+    extern int requested_wpa_supplicant;
     
     enum { BACKUP,
            GET_INTERFACE,
@@ -39,7 +40,9 @@ int main(int argc, char** argv)
            GET_STATIC,
            WCONFIG,
            WCONFIG_ESSID,
+           WCONFIG_SECURITY,
            WCONFIG_WEP,
+           WCONFIG_WPA,
            QUIT } state = GET_INTERFACE;
     
     /* initialize libd-i */
@@ -98,11 +101,41 @@ int main(int argc, char** argv)
             if (netcfg_wireless_set_essid(client, interface, NULL))
                 state = BACKUP;
             else
-                state = WCONFIG_WEP;
+                if (requested_wpa_supplicant == 2)
+                    state = WCONFIG_WEP;
+                else
+                    state = WCONFIG_SECURITY;
+            break;
+            
+        case WCONFIG_SECURITY:
+            if (netcfg_wireless_set_security (client, interface) == GO_BACK)
+                state = WCONFIG_ESSID;
+            else
+                if (netcfg_wireless_set_security (client, interface) == REPLY_WPA)
+                    state = WCONFIG_WPA;
+                else
+                    state = WCONFIG_WEP;
             break;
             
         case WCONFIG_WEP:
-            if (netcfg_wireless_set_wep(client, interface))
+            if (netcfg_wireless_set_wep(client, interface)) {
+                have_wpa_supplicant();
+                if (requested_wpa_supplicant == 2)
+                    state = WCONFIG_ESSID;
+                else
+                    state = WCONFIG_SECURITY;
+            }
+            else
+                state = GET_STATIC;
+            break;
+            
+        case WCONFIG_WPA:
+            if (requested_wpa_supplicant == 0) {
+                di_exec_shell_log("apt-install wpasupplicant");
+                requested_wpa_supplicant = 1;
+            }
+
+            if (netcfg_set_passphrase(client, interface) == GO_BACK)
                 state = WCONFIG_ESSID;
             else
                 state = GET_STATIC;
diff --git a/packages/netcfg/netcfg.c b/packages/netcfg/netcfg.c
index 3c638aa..b5274e0 100644
--- a/packages/netcfg/netcfg.c
+++ b/packages/netcfg/netcfg.c
@@ -69,11 +69,14 @@ int main(int argc, char *argv[])
            GET_STATIC,
            WCONFIG,
            WCONFIG_ESSID,
+           WCONFIG_SECURITY,
            WCONFIG_WEP,
+           WCONFIG_WPA,
            QUIT } state = GET_INTERFACE;
     
     static struct debconfclient *client;
     static int requested_wireless_tools = 0;
+    extern int requested_wpa_supplicant;
     char **ifaces;
     char *defiface = NULL, *defwireless = NULL;
     response_t res;
@@ -251,19 +254,53 @@ int main(int argc, char *argv[])
         case WCONFIG_ESSID:
             if (netcfg_wireless_set_essid(client, interface, NULL) == GO_BACK)
                 state = BACKUP;
-            else
-                state = WCONFIG_WEP;
+            else {
+                have_wpa_supplicant();
+                if (requested_wpa_supplicant == 2)
+                    state = WCONFIG_WEP;
+                else
+                    state = WCONFIG_SECURITY;
+            }
             break;
             
+        case WCONFIG_SECURITY:
+            {
+                int ret;
+                ret = netcfg_wireless_set_security(client, interface);
+                if (ret == GO_BACK)
+                    state = WCONFIG_ESSID;
+                else if (ret == REPLY_WPA)
+                    state = WCONFIG_WPA;
+                else
+                    state = WCONFIG_WEP;
+                break;
+            }
+
         case WCONFIG_WEP:
             if (netcfg_wireless_set_wep(client, interface) == GO_BACK)
-                state = WCONFIG_ESSID;
+                if (requested_wpa_supplicant == 2)
+                    state = WCONFIG_ESSID;
+                else
+                    state = WCONFIG_SECURITY;
             else
                 state = GET_METHOD;
             break;
             
+        case WCONFIG_WPA:
+            if (requested_wpa_supplicant == 0) {
+                di_exec_shell_log("apt-install wpasupplicant");
+                requested_wpa_supplicant = 1;
+            }
+
+            if (netcfg_set_passphrase(client, interface) == GO_BACK)
+                state = WCONFIG_SECURITY;
+            else
+                state = GET_METHOD;
+            break;
+
         case QUIT:
             return 0;
         }
     }
 }
+
diff --git a/packages/netcfg/netcfg.h b/packages/netcfg/netcfg.h
index a7bc8a9..aa181e4 100644
--- a/packages/netcfg/netcfg.h
+++ b/packages/netcfg/netcfg.h
@@ -10,11 +10,16 @@
 #define DHCLIENT3_CONF	"/etc/dhcp3/dhclient.conf"
 #define DOMAIN_FILE     "/tmp/domain_name"
 #define NTP_SERVER_FILE "/tmp/dhcp-ntp-servers"
+#define WPASUPP_CONF    "/etc/wpa_supplicant/wpa_supplicant.conf"
+#define WPAPID	 	"/var/run/wpa_supplicant/wpa_supplicant.pid"
 
 #define DEVNAMES	"/etc/network/devnames"
 #define DEVHOTPLUG	"/etc/network/devhotplug"
 #define STAB		"/var/run/stab"
 
+#define WPA_MIN         8
+#define WPA_MAX         64
+
 #define _GNU_SOURCE
 
 #include <sys/types.h>
@@ -41,7 +46,7 @@
 "ff02::2 ip6-allrouters\n" \
 "ff02::3 ip6-allhosts\n"
 
-typedef enum { NOT_ASKED = 30, GO_BACK } response_t;
+typedef enum { NOT_ASKED = 30, GO_BACK, REPLY_WEP, REPLY_WPA } response_t;
 typedef enum { DHCP, STATIC, DUNNO } method_t;
 typedef enum { ADHOC = 1, MANAGED = 2 } wifimode_t;
 
@@ -49,6 +54,7 @@ extern int netcfg_progress_displayed;
 extern int wfd, skfd;
 extern int input_result;
 extern int have_domain;
+extern int requested_wpa_supplicant;
 
 /* network config */
 extern char *interface;
@@ -64,7 +70,7 @@ extern struct in_addr gateway;
 extern struct in_addr pointopoint;
 
 /* wireless */
-extern char *essid, *wepkey;
+extern char *essid, *wepkey, *passphrase;
 extern wifimode_t mode;
 
 /* common functions */
@@ -111,7 +117,13 @@ extern int is_wireless_iface (const char* iface);
 
 extern int netcfg_wireless_set_essid (struct debconfclient *client, char* iface, char* priority);
 extern int netcfg_wireless_set_wep (struct debconfclient *client, char* iface);
+extern int netcfg_wireless_set_security (struct debconfclient *client, char* iface);
+extern int netcfg_set_passphrase (struct debconfclient *client, char* iface);
+extern int have_wpa_supplicant (void);
+extern int kill_wpa_supplicant (void);
 
+extern int netcfg_write_wpa (char *essid, char *passphrase);
+extern int start_wpa_supplicant (struct debconfclient *client);
 extern int iface_is_hotpluggable(const char *iface);
 extern short find_in_stab (const char *iface);
 extern void deconfigure_network(void);
diff --git a/packages/netcfg/static.c b/packages/netcfg/static.c
index 41a9368..fa339b7 100644
--- a/packages/netcfg/static.c
+++ b/packages/netcfg/static.c
@@ -198,14 +198,18 @@ static int netcfg_write_static(char *domain, struct in_addr nameservers[])
          * Write wireless-tools options
          */
         if (is_wireless_iface(interface)) {
-            fprintf(fp, "\t# wireless-* options are implemented by the wireless-tools package\n");
-            fprintf(fp, "\twireless-mode %s\n",
-                    (mode == MANAGED) ? "managed" : "ad-hoc");
-            fprintf(fp, "\twireless-essid %s\n",
-                    (essid && *essid) ? essid : "any");
+            if (requested_wpa_supplicant == 1)
+                fprintf(fp, "\twpa-conf /etc/wpa_supplicant/wpa_supplicant.conf\n");
+            else {
+                fprintf(fp, "\t# wireless-* options are implemented by the wireless-tools package\n");
+                fprintf(fp, "\twireless-mode %s\n",
+                        (mode == MANAGED) ? "managed" : "ad-hoc");
+                fprintf(fp, "\twireless-essid %s\n",
+                        (essid && *essid) ? essid : "any");
             
-            if (wepkey != NULL)
-                fprintf(fp, "\twireless-key1 %s\n", wepkey);
+                if (wepkey != NULL)
+                    fprintf(fp, "\twireless-key1 %s\n", wepkey);
+            }
         }
         /*
          * Write resolvconf options
diff --git a/packages/netcfg/wireless.c b/packages/netcfg/wireless.c
index ed07b8a..f5d87f1 100644
--- a/packages/netcfg/wireless.c
+++ b/packages/netcfg/wireless.c
@@ -19,6 +19,7 @@ wifimode_t mode = MANAGED;
 /* wireless config */
 char* wepkey = NULL;
 char* essid = NULL;
+char* passphrase = NULL;
 
 #ifdef WIRELESS
 
@@ -53,7 +54,7 @@ int netcfg_wireless_set_essid (struct debconfclient * client, char *iface, char*
     wconf.has_mode = 1;
     wconf.mode = mode;
     
-    debconf_input(client, priority ? priority : "low", "netcfg/wireless_essid");
+    debconf_input(client, priority ? priority : "high", "netcfg/wireless_essid");
     
     if (debconf_go(client) == 30)
         return GO_BACK;
@@ -189,6 +190,25 @@ static void unset_wep_key (char* iface)
     ret = iw_set_basic_config (wfd, iface, &wconf);
 }
 
+int netcfg_wireless_set_security (struct debconfclient *client, char *iface)
+{
+    int ret = 0 ;
+    debconf_subst (client, "netcfg/wireless_security_type", "iface", iface);
+    debconf_input (client, "high", "netcfg/wireless_security_type");
+    ret = debconf_go(client);
+
+    if (ret == 30)
+        return GO_BACK;
+
+    debconf_get (client, "netcfg/wireless_security_type");
+
+    if (!strcmp(client->value, "WEP/Open Network"))
+        return REPLY_WEP;
+    else
+        return REPLY_WPA;
+
+}
+
 int netcfg_wireless_set_wep (struct debconfclient * client, char* iface)
 {
     wireless_config wconf;
@@ -250,6 +270,50 @@ int netcfg_wireless_set_wep (struct debconfclient * client, char* iface)
     return 0;
 }
 
+int netcfg_set_passphrase (struct debconfclient *client, char *iface)
+{
+    wireless_config wconf;
+    int ret;
+
+    iw_get_basic_config(wfd, iface, &wconf);
+
+    unset_wep_key(iface);
+
+    debconf_subst(client, "netcfg/wireless_wpa", "iface", iface);
+    debconf_input(client, "high", "netcfg/wireless_wpa");
+    ret = debconf_go(client);
+
+    if (ret == 30)
+        return GO_BACK;
+
+    debconf_get(client, "netcfg/wireless_wpa");
+    passphrase = client->value;
+
+    while (strlen(passphrase) < WPA_MIN || strlen(passphrase) > WPA_MAX) {
+          debconf_subst(client, "netcfg/invalid_pass", "passphrase", passphrase);
+          debconf_input(client, "critical", "netcfg/invalid_pass");
+          debconf_go(client);
+
+          debconf_input(client, "high", "netcfg/wireless_wpa");
+          ret = debconf_go (client);
+
+
+          if (ret == 30)
+              return GO_BACK;
+
+          debconf_get (client, "netcfg/wireless_wpa");
+          passphrase = client->value;
+    }
+
+    if (netcfg_write_wpa(essid, passphrase)) {
+        di_warning("Failed to write wpasupplicant config file");
+        return -1;
+    }
+    else
+        start_wpa_supplicant(client);
+    return 0;
+}
+
 #else
 
 int is_wireless_iface (const char *iface)
diff --git a/packages/netcfg/wpa.c b/packages/netcfg/wpa.c
new file mode 100644
index 0000000..f0a99b7
--- /dev/null
+++ b/packages/netcfg/wpa.c
@@ -0,0 +1,97 @@
+/*
+* WPA module for netcfg
+*
+* Copyright (C) 2008 Glenn Saberton <gsaberton@foomagic.org>
+*
+* Licensed under the terms of the GNU General Public License version 2
+*
+*/
+
+#include "netcfg.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <debian-installer.h>
+
+pid_t wpa_supplicant_pid = -1;
+int requested_wpa_supplicant = 0;
+
+/*
+* Build an /etc/wpa_supplicant.conf
+* file.
+*/
+
+int netcfg_write_wpa (char *essid, char *passphrase)
+{
+    FILE *fp;
+
+    if ((fp = file_open (WPASUPP_CONF, "w"))) {
+        fprintf (fp, "\n# wpa_supplicant.conf generated during install\n"
+      		     "ctrl_interface=/var/run/wpa_supplicant\n"
+    		     "ctrl_interface_group=0\n"
+    		     "eapol_version=1\n"
+    		     "ap_scan=1\n\n"	/* So we can associate to hidden ssid's  */
+	    	     "network={\n");
+        fprintf (fp, "\t\tssid=\"%s\"\n", essid);
+        fprintf (fp, "\t\tpsk=\"%s\"\n", passphrase);
+        fprintf (fp, "\t\tscan_ssid=1\n" "}\n");
+    }
+    fclose (fp);
+    return 0;
+}
+
+int have_wpa_supplicant(void)
+{
+    extern int requested_wpa_supplicant;
+
+    if (access("/sbin/wpa_supplicant", F_OK) == 0)
+        requested_wpa_supplicant = 0;
+    else {
+        requested_wpa_supplicant = 2;
+        di_info("Wpasupplicant not found on the system. Disabling WPA options");
+    }
+    return 0;
+}
+
+int kill_wpa_supplicant(void)
+{
+    int ret;
+    pid_t wpa_pid;
+    FILE *fp;
+
+    fp = (file_open (WPAPID, "r"));
+    if (fp == NULL) {
+        di_warning ("Couldn't read Wpasupplicant pid file, not trying to kill.");
+        return 0;
+    }
+    else {
+        fscanf (fp, "%d", &wpa_pid);
+        fclose (fp);
+    }
+      if ((ret = kill(wpa_pid, SIGTERM)) == 0)
+          return 0;
+      else {
+          kill(wpa_pid, SIGKILL);
+          return 0;
+      }
+}
+
+int start_wpa_supplicant (struct debconfclient *client)
+{
+    wpa_supplicant_pid = fork();
+
+    if (wpa_supplicant_pid == 0) {
+        fclose(client->out);
+        if (execlp ("wpa_supplicant", "wpa_supplicant", "-i", interface, "-c",
+                    WPASUPP_CONF, "-P", WPAPID, "-B", NULL) == -1) {
+            di_error("could not exec wpasupplicant: %s", strerror(errno));
+            return 1;
+        }
+        else
+            return 0;
+    }
+    else {
+        waitpid(wpa_supplicant_pid, NULL, 0);
+        return 0;
+    }
+}
-- 
1.5.5.1


Reply to: