CHAP with MD5 authentication support
authorKristen Carlson Accardi <kristen@linux.intel.com>
Tue, 23 Mar 2010 00:05:59 +0000 (17:05 -0700)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 23 Mar 2010 00:28:23 +0000 (17:28 -0700)
Authentication support with CHAP and MD5

Makefile.am
gatchat/gatppp.c
gatchat/gatppp.h
gatchat/ppp.c
gatchat/ppp.h
gatchat/ppp_auth.c [new file with mode: 0644]

index 1a444ca..df89ef5 100644 (file)
@@ -58,7 +58,8 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
                                gatchat/gatserver.h gatchat/gatserver.c \
                                gatchat/gatppp.c gatchat/gatppp.h \
                                gatchat/ppp.c gatchat/ppp.h gatchat/ppp_cp.h \
-                               gatchat/ppp_cp.c gatchat/ppp_lcp.c
+                               gatchat/ppp_cp.c gatchat/ppp_lcp.c \
+                               gatchat/ppp_auth.c
 
 udev_files = plugins/ofono.rules
 
index f083842..2b682f8 100644 (file)
@@ -43,6 +43,12 @@ void g_at_ppp_open(GAtPPP *ppp)
        lcp_open(ppp->lcp);
 }
 
+void g_at_ppp_set_credentials(GAtPPP *ppp, const char *username,
+                               const char *passwd)
+{
+       auth_set_credentials(ppp->auth, username, passwd);
+}
+
 void g_at_ppp_set_connect_function(GAtPPP *ppp,
                               GAtPPPConnectFunc callback, gpointer user_data)
 {
@@ -73,6 +79,9 @@ void g_at_ppp_shutdown(GAtPPP *ppp)
 
        /* remove lcp */
        lcp_free(ppp->lcp);
+
+       /* remove auth */
+       auth_free(ppp->auth);
 }
 
 void g_at_ppp_ref(GAtPPP *ppp)
@@ -124,7 +133,7 @@ GAtPPP *g_at_ppp_new(GIOChannel *modem)
        ppp->lcp = lcp_new(ppp);
 
        /* initialize the autentication state */
-
+       ppp->auth = auth_new(ppp);
 
        /* intialize the network state */
 
index 0d5d5cc..8db26c9 100644 (file)
@@ -51,6 +51,8 @@ void g_at_ppp_set_disconnect_function(GAtPPP *ppp,
 void g_at_ppp_shutdown(GAtPPP *ppp);
 void g_at_ppp_ref(GAtPPP *ppp);
 void g_at_ppp_unref(GAtPPP *ppp);
+void g_at_ppp_set_credentials(GAtPPP *ppp, const char *username,
+                               const char *passwd);
 #ifdef __cplusplus
 }
 #endif
index 2399ed4..0b3221b 100644 (file)
@@ -463,6 +463,7 @@ void ppp_set_auth(GAtPPP *ppp, guint8* auth_data)
        switch (proto) {
        case CHAP_PROTOCOL:
                /* get the algorithm */
+               auth_set_proto(ppp->auth, proto, auth_data[2]);
                break;
        default:
                g_printerr("unknown authentication proto\n");
index 7753a39..53d5274 100644 (file)
@@ -95,10 +95,20 @@ static inline guint16 __get_unaligned_short(const gpointer p)
 #define ppp_proto(packet) \
        (get_host_short(packet + 2))
 
+struct auth_data {
+       guint16 proto;
+       gpointer proto_data;
+       void (*process_packet)(struct auth_data *data, guint8 *packet);
+       char *username;
+       char *passwd;
+       GAtPPP *ppp;
+};
+
 struct _GAtPPP {
        gint ref_count;
        enum ppp_phase phase;
        struct pppcp_data *lcp;
+       struct auth_data *auth;
        guint8 buffer[BUFFERSZ];
        int index;
        gint mru;
@@ -137,3 +147,8 @@ void lcp_open(struct pppcp_data *data);
 void lcp_close(struct pppcp_data *data);
 void lcp_establish(struct pppcp_data *data);
 void lcp_terminate(struct pppcp_data *data);
+void auth_set_credentials(struct auth_data *data, const char *username,
+                               const char *passwd);
+void auth_set_proto(struct auth_data *data, guint16 proto, guint8 method);
+struct auth_data *auth_new(GAtPPP *ppp);
+void auth_free(struct auth_data *auth);
diff --git a/gatchat/ppp_auth.c b/gatchat/ppp_auth.c
new file mode 100644 (file)
index 0000000..c23d9ad
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+
+#include "gatppp.h"
+#include "ppp.h"
+
+struct chap_header {
+       guint8 code;
+       guint8 identifier;
+       guint16 length;
+       guint8 data[0];
+} __attribute__((packed));
+
+struct chap_data {
+       guint8 method;
+       struct auth_data *auth;
+};
+
+enum chap_code {
+       CHALLENGE=1,
+       RESPONSE,
+       SUCCESS,
+       FAILURE
+};
+
+void auth_set_credentials(struct auth_data *data, const char *username,
+                               const char *passwd)
+{
+       if (data == NULL)
+               return;
+
+       if (data->username)
+               g_free(data->username);
+       if (data->passwd)
+               g_free(data->passwd);
+
+       data->username = g_strdup(username);
+       data->passwd = g_strdup(passwd);
+}
+
+static void chap_process_challenge(struct auth_data *auth, guint8 *packet)
+{
+       struct chap_header *header = (struct chap_header *) packet;
+       struct chap_header *response;
+       struct chap_data *data = auth->proto_data;
+       GChecksum *checksum;
+       gchar *secret = data->auth->passwd;
+       guint16 response_length;
+       struct ppp_header *ppp_packet;
+       gsize digest_len;
+
+       /* create a checksum over id, secret, and challenge */
+       checksum = g_checksum_new(data->method);
+       if (!checksum)
+               return;
+       g_checksum_update(checksum, &header->identifier, 1);
+       g_checksum_update(checksum, (guchar *) secret, strlen(secret));
+       g_checksum_update(checksum, &header->data[1], header->data[0]);
+
+       /* transmit a response packet */
+       /*
+        * allocate space for the header, the checksum, and the ppp header,
+        * and the value size byte
+        */
+       digest_len = g_checksum_type_get_length(data->method);
+       response_length = digest_len + sizeof(*header) + 1;
+       ppp_packet = g_try_malloc0(response_length + 2);
+       if (!ppp_packet)
+               goto challenge_out;
+
+       /* add our protocol information */
+       ppp_packet->proto = htons(CHAP_PROTOCOL);
+       response = (struct chap_header *) &ppp_packet->info;
+       if (response) {
+               response->code = RESPONSE;
+               response->identifier = header->identifier;
+               response->length = htons(response_length);
+               response->data[0] = digest_len;
+               g_checksum_get_digest(checksum, &response->data[1],
+                                       (gsize *) &response->data[0]);
+               /* leave the name empty? */
+       }
+
+       /* transmit the packet */
+       ppp_transmit(auth->ppp, (guint8 *) ppp_packet, response_length);
+
+challenge_out:
+       g_checksum_free(checksum);
+}
+
+static void chap_process_success(struct auth_data *data, guint8 *packet)
+{
+       ppp_generate_event(data->ppp, PPP_SUCCESS);
+}
+
+static void chap_process_failure(struct auth_data *data, guint8 *packet)
+{
+       struct chap_header *header = (struct chap_header *) packet;
+
+       g_print("Failed to authenticate, message %s\n", header->data);
+}
+
+/*
+ * parse the packet
+ */
+static void chap_process_packet(gpointer priv, guint8 *new_packet)
+{
+       struct auth_data *data = priv;
+       guint8 code = new_packet[0];
+
+       switch (code) {
+       case CHALLENGE:
+               chap_process_challenge(data, new_packet);
+               break;
+       case RESPONSE:
+               g_print("Oops, received RESPONSE, but I've not implemented\n");
+               break;
+       case SUCCESS:
+               chap_process_success(data, new_packet);
+               break;
+       case FAILURE:
+               chap_process_failure(data, new_packet);
+               break;
+       default:
+               g_print("unknown auth code\n");
+               break;
+       }
+}
+
+struct ppp_packet_handler chap_packet_handler = {
+       .proto = CHAP_PROTOCOL,
+       .handler = chap_process_packet,
+};
+
+static void chap_free(struct auth_data *auth)
+{
+       /* TBD unregister protocol handler */
+
+       g_free(auth->proto_data);
+}
+
+static struct chap_data *chap_new(struct auth_data *auth, guint8 method)
+{
+       struct chap_data *data;
+
+       data = g_try_malloc0(sizeof(*data));
+       if (!data)
+               return NULL;
+
+       data->auth = auth;
+       switch (method) {
+       case MD5:
+               data->method = G_CHECKSUM_MD5;
+               break;
+       default:
+               g_print("Unknown method\n");
+       }
+
+       /* register packet handler for CHAP protocol */
+       chap_packet_handler.priv = auth;
+       ppp_register_packet_handler(&chap_packet_handler);
+       return data;
+}
+
+void auth_set_proto(struct auth_data *data, guint16 proto, guint8 method)
+{
+       if (data == NULL)
+               return;
+
+       switch (proto) {
+       case CHAP_PROTOCOL:
+               data->proto_data = (gpointer) chap_new(data, method);
+               break;
+       default:
+               g_print("Unknown auth protocol 0x%x\n", proto);
+       }
+}
+
+void auth_free(struct auth_data *data)
+{
+       if (data == NULL)
+               return;
+
+       chap_free(data);
+       g_free(data);
+}
+
+struct auth_data *auth_new(GAtPPP *ppp)
+{
+       struct auth_data *data;
+
+       data = g_try_malloc0(sizeof(*data));
+       if (!data)
+               return NULL;
+
+       data->ppp = ppp;
+       return data;
+}