summaryrefslogtreecommitdiffstats
path: root/gatchat/ppp_auth.c
diff options
context:
space:
mode:
authorPhilip Paeps <philip@paeps.cx>2014-06-19 12:07:05 +0200
committerDenis Kenzior <denkenz@gmail.com>2014-06-21 11:50:34 -0500
commita88662d23c45f49d9af5a508d4d0a778950b2420 (patch)
tree493246fd2c2789995a6530ca8f379e6a4ed402c8 /gatchat/ppp_auth.c
parent1dd85809307b200bfe87e6a71c68fa244cb15bc6 (diff)
downloadofono-a88662d23c45f49d9af5a508d4d0a778950b2420.tar.bz2
gatchat: implement PAP authentication
Make the authentication method configurable, CHAP or PAP, defaulting to CHAP (i.e.: previous behaviour). Implementation details: o If PAP is configured, we NAK the CHAP authentication protocol option in LCP configuration requests and suggest PAP instead. This works around the amusing requirement of 3GPP TS 29.061 that modems must send a forced positive acknowledgement of the authentication method tried (i.e.: the modem will successfully accept any CHAP handshake, but if the network only supports PAP, the modem will hang up when it tries and fails to activate the PDP context) o The PAP Authenticate-Request is resent a hard-coded three times at ten-second intervals. This may be a bit too persistent. Chances are if it doesn't work the first time, it'll never work, but the RFC insists that we MUST retry.
Diffstat (limited to 'gatchat/ppp_auth.c')
-rw-r--r--gatchat/ppp_auth.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/gatchat/ppp_auth.c b/gatchat/ppp_auth.c
index 1ddf7624..84cd861d 100644
--- a/gatchat/ppp_auth.c
+++ b/gatchat/ppp_auth.c
@@ -54,6 +54,38 @@ enum chap_code {
FAILURE
};
+struct pap_header {
+ guint8 code;
+ guint8 identifier;
+ guint16 length;
+ guint8 data[0];
+} __attribute__((packed));
+
+struct ppp_pap {
+ GAtPPP *ppp;
+ struct ppp_header *authreq;
+ guint16 authreq_len;
+ guint retry_timer;
+ guint retries;
+};
+
+enum pap_code {
+ PAP_REQUEST = 1,
+ PAP_ACK,
+ PAP_NAK
+};
+
+/*
+ * RFC 1334 2.1.1:
+ * The Authenticate-Request packet MUST be repeated until a valid
+ * reply packet is received, or an optional retry counter expires.
+ *
+ * If we don't get a reply after this many attempts, we can safely
+ * assume we're never going to get one.
+ */
+#define PAP_MAX_RETRY 3 /* attempts */
+#define PAP_TIMEOUT 10 /* seconds */
+
static void chap_process_challenge(struct ppp_chap *chap, const guint8 *packet)
{
const struct chap_header *header = (const struct chap_header *) packet;
@@ -166,3 +198,110 @@ struct ppp_chap *ppp_chap_new(GAtPPP *ppp, guint8 method)
return chap;
}
+
+void ppp_pap_process_packet(struct ppp_pap *pap, const guint8 *new_packet,
+ gsize len)
+{
+ guint8 code;
+
+ if (len < sizeof(struct pap_header))
+ return;
+
+ code = new_packet[0];
+
+ switch (code) {
+ case PAP_ACK:
+ g_source_remove(pap->retry_timer);
+ pap->retry_timer = 0;
+ ppp_auth_notify(pap->ppp, TRUE);
+ break;
+ case PAP_NAK:
+ g_source_remove(pap->retry_timer);
+ pap->retry_timer = 0;
+ ppp_auth_notify(pap->ppp, FALSE);
+ break;
+ default:
+ break;
+ }
+}
+
+static gboolean ppp_pap_timeout(gpointer user_data)
+{
+ struct ppp_pap *pap = (struct ppp_pap *)user_data;
+ struct pap_header *authreq;
+
+ if (++pap->retries >= PAP_MAX_RETRY) {
+ pap->retry_timer = 0;
+ ppp_auth_notify(pap->ppp, FALSE);
+ return FALSE;
+ }
+
+ /*
+ * RFC 1334 2.2.1:
+ * The Identifier field MUST be changed each time an
+ * Authenticate-Request packet is issued.
+ */
+ authreq = (struct pap_header *)&pap->authreq->info;
+ authreq->identifier++;
+
+ ppp_transmit(pap->ppp, (guint8 *)pap->authreq, pap->authreq_len);
+
+ return TRUE;
+}
+
+gboolean ppp_pap_start(struct ppp_pap *pap)
+{
+ struct pap_header *authreq;
+ struct ppp_header *packet;
+ const char *username = g_at_ppp_get_username(pap->ppp);
+ const char *password = g_at_ppp_get_password(pap->ppp);
+ guint16 length;
+
+ length = sizeof(*authreq) + strlen(username) + strlen(password) + 2;
+ packet = ppp_packet_new(length, PAP_PROTOCOL);
+ if (packet == NULL)
+ return FALSE;
+ pap->authreq = packet;
+ pap->authreq_len = length;
+
+ authreq = (struct pap_header *)&packet->info;
+ authreq->code = PAP_REQUEST;
+ authreq->identifier = 1;
+ authreq->length = htons(length);
+
+ authreq->data[0] = (unsigned char) strlen(username);
+ memcpy(authreq->data + 1, username, strlen(username));
+ authreq->data[strlen(username) + 1] = (unsigned char)strlen(password);
+ memcpy(authreq->data + 1 + strlen(username) + 1, password,
+ strlen(password));
+
+ /* Transmit the packet and schedule a retry. */
+ ppp_transmit(pap->ppp, (guint8 *)packet, length);
+ pap->retries = 0;
+ pap->retry_timer = g_timeout_add_seconds(PAP_TIMEOUT,
+ ppp_pap_timeout, pap);
+
+ return TRUE;
+}
+
+void ppp_pap_free(struct ppp_pap *pap)
+{
+ if (pap->retry_timer != 0)
+ g_source_remove(pap->retry_timer);
+ if (pap->authreq != NULL)
+ g_free(pap->authreq);
+ g_free(pap);
+}
+
+struct ppp_pap *ppp_pap_new(GAtPPP *ppp)
+{
+ struct ppp_pap *pap;
+
+ pap = g_try_new0(struct ppp_pap, 1);
+ if (pap == NULL)
+ return NULL;
+
+ pap->ppp = ppp;
+
+ return pap;
+}