From: Denis Kenzior <denkenz@gmail.com>
To: ofono@ofono.org
Subject: Re: [PATCH 1/3] gatchat: implement PAP authentication
Date: Wed, 18 Jun 2014 17:20:48 -0500 [thread overview]
Message-ID: <53A210C0.9020501@gmail.com> (raw)
In-Reply-To: <1403042279-20598-2-git-send-email-philip@paeps.cx>
[-- Attachment #1: Type: text/plain, Size: 14021 bytes --]
Hi Philip,
On 06/17/2014 04:57 PM, Philip Paeps wrote:
> 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)
In theory this is because CHAP authentication should always be accepted
by the network operator, but it seems there are still a few out there
that do not do this properly.
>
> 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.
>
> Signed-off-by: Philip Paeps <philip@paeps.cx>
We do not use Signed-off-by, so please drop this one on your next
submission.
> ---
> gatchat/gatppp.c | 50 ++++++++++++++++++-
> gatchat/gatppp.h | 8 +++
> gatchat/ppp.h | 9 ++++
> gatchat/ppp_auth.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> gatchat/ppp_lcp.c | 68 ++++++++++++++++++-------
> 5 files changed, 253 insertions(+), 21 deletions(-)
>
> diff --git a/gatchat/gatppp.c b/gatchat/gatppp.c
> index f767f4a..c75d7f5 100644
> --- a/gatchat/gatppp.c
> +++ b/gatchat/gatppp.c
> @@ -64,11 +64,13 @@ struct _GAtPPP {
> struct pppcp_data *ipcp;
> struct ppp_net *net;
> struct ppp_chap *chap;
> + struct ppp_pap *pap;
> GAtHDLC *hdlc;
> gint mru;
> gint mtu;
> char username[256];
> char password[256];
> + GAtPPPAuthMethod auth_method;
> GAtPPPConnectFunc connect_cb;
> gpointer connect_data;
> GAtPPPDisconnectFunc disconnect_cb;
> @@ -150,13 +152,15 @@ static inline gboolean ppp_drop_packet(GAtPPP *ppp, guint16 protocol)
> return TRUE;
> break;
> case PPP_PHASE_AUTHENTICATION:
> - if (protocol != LCP_PROTOCOL && protocol != CHAP_PROTOCOL)
> + if (protocol != LCP_PROTOCOL && protocol != CHAP_PROTOCOL &&
> + protocol != PAP_PROTOCOL)
> return TRUE;
> break;
> case PPP_PHASE_DEAD:
> return TRUE;
> case PPP_PHASE_NETWORK:
> if (protocol != LCP_PROTOCOL && protocol != CHAP_PROTOCOL &&
> + protocol != PAP_PROTOCOL &&
> protocol != IPCP_PROTO)
> return TRUE;
> break;
> @@ -222,6 +226,12 @@ static void ppp_receive(const unsigned char *buf, gsize len, void *data)
> case IPCP_PROTO:
> pppcp_process_packet(ppp->ipcp, packet, len - offset);
> break;
> + case PAP_PROTOCOL:
> + if (ppp->pap)
> + ppp_pap_process_packet(ppp->pap, packet, len - offset);
> + else
> + pppcp_send_protocol_reject(ppp->lcp, buf, len);
> + break;
> case CHAP_PROTOCOL:
> if (ppp->chap) {
> ppp_chap_process_packet(ppp->chap, packet,
> @@ -359,6 +369,12 @@ void ppp_set_auth(GAtPPP *ppp, const guint8* auth_data)
> guint16 proto = get_host_short(auth_data);
>
> switch (proto) {
> + case PAP_PROTOCOL:
> + if (ppp->pap)
> + ppp_pap_free(ppp->pap);
> +
> + ppp->pap = ppp_pap_new(ppp);
> + break;
> case CHAP_PROTOCOL:
> if (ppp->chap)
> ppp_chap_free(ppp->chap);
> @@ -437,10 +453,18 @@ void ppp_ipcp_finished_notify(GAtPPP *ppp)
>
> void ppp_lcp_up_notify(GAtPPP *ppp)
> {
> - /* Wait for the peer to send us a challenge if we expect auth */
> if (ppp->chap != NULL) {
> + /* Wait for the peer to send us a challenge. */
> ppp_enter_phase(ppp, PPP_PHASE_AUTHENTICATION);
> return;
> + } else if (ppp->pap != NULL) {
> + /* Try to send an Authenticate-Request and wait for reply. */
> + if (ppp_pap_start(ppp->pap) == TRUE)
> + ppp_enter_phase(ppp, PPP_PHASE_AUTHENTICATION);
> + else
> + /* It'll never work out. */
> + ppp_auth_notify(ppp, FALSE);
> + return;
> }
>
> /* Otherwise proceed as if auth succeeded */
> @@ -588,6 +612,22 @@ const char *g_at_ppp_get_password(GAtPPP *ppp)
> return ppp->password;
> }
>
> +gboolean g_at_ppp_set_auth_method(GAtPPP *ppp, GAtPPPAuthMethod method)
> +{
> + if (method != G_AT_PPP_AUTH_METHOD_CHAP &&
> + method != G_AT_PPP_AUTH_METHOD_PAP)
Please don't use spaces for indentation
> + return FALSE;
> +
> + ppp->auth_method = method;
> +
> + return TRUE;
> +}
> +
> +GAtPPPAuthMethod g_at_ppp_get_auth_method(GAtPPP *ppp)
> +{
> + return ppp->auth_method;
> +}
> +
> void g_at_ppp_set_recording(GAtPPP *ppp, const char *filename)
> {
> if (ppp == NULL)
> @@ -727,6 +767,9 @@ void g_at_ppp_unref(GAtPPP *ppp)
> else if (ppp->fd >= 0)
> close(ppp->fd);
>
> + if (ppp->pap)
> + ppp_pap_free(ppp->pap);
> +
> if (ppp->chap)
> ppp_chap_free(ppp->chap);
>
> @@ -794,6 +837,9 @@ static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip)
> /* initialize IPCP state */
> ppp->ipcp = ipcp_new(ppp, is_server, ip);
>
> + /* chap authentication by default */
> + ppp->auth_method = G_AT_PPP_AUTH_METHOD_CHAP;
> +
> return ppp;
> }
>
> diff --git a/gatchat/gatppp.h b/gatchat/gatppp.h
> index b5a2234..dab75a8 100644
> --- a/gatchat/gatppp.h
> +++ b/gatchat/gatppp.h
> @@ -74,6 +74,14 @@ gboolean g_at_ppp_set_credentials(GAtPPP *ppp, const char *username,
> const char *g_at_ppp_get_username(GAtPPP *ppp);
> const char *g_at_ppp_get_password(GAtPPP *ppp);
>
> +typedef enum _GAtPPPAuthMethod {
> + G_AT_PPP_AUTH_METHOD_CHAP,
> + G_AT_PPP_AUTH_METHOD_PAP,
> +} GAtPPPAuthMethod;
> +
Please refer to doc/coding-style.txt item M9 for the preferred order of
declarations.
> +gboolean g_at_ppp_set_auth_method(GAtPPP *ppp, GAtPPPAuthMethod method);
> +GAtPPPAuthMethod g_at_ppp_get_auth_method(GAtPPP *ppp);
> +
> void g_at_ppp_set_recording(GAtPPP *ppp, const char *filename);
>
> void g_at_ppp_set_server_info(GAtPPP *ppp, const char *remote_ip,
> diff --git a/gatchat/ppp.h b/gatchat/ppp.h
> index 718575b..ac1a7ef 100644
> --- a/gatchat/ppp.h
> +++ b/gatchat/ppp.h
> @@ -22,6 +22,7 @@
> #include "ppp_cp.h"
>
> #define LCP_PROTOCOL 0xc021
> +#define PAP_PROTOCOL 0xc023
> #define CHAP_PROTOCOL 0xc223
> #define IPCP_PROTO 0x8021
> #define IPV6CP_PROTO 0x8057
> @@ -38,6 +39,7 @@
>
> struct ppp_chap;
> struct ppp_net;
> +struct ppp_pap;
>
> struct ppp_header {
> guint8 address;
> @@ -109,6 +111,13 @@ void ppp_chap_free(struct ppp_chap *chap);
> void ppp_chap_process_packet(struct ppp_chap *chap, const guint8 *new_packet,
> gsize len);
>
> +/* PAP related functions */
> +struct ppp_pap *ppp_pap_new(GAtPPP *ppp);
> +void ppp_pap_free(struct ppp_pap *pap);
> +gboolean ppp_pap_start(struct ppp_pap *pap);
> +void ppp_pap_process_packet(struct ppp_pap *pap, const guint8 *new_packet,
> + gsize len);
> +
> /* TUN / Network related functions */
> struct ppp_net *ppp_net_new(GAtPPP *ppp, int fd);
> const char *ppp_net_get_interface(struct ppp_net *net);
> diff --git a/gatchat/ppp_auth.c b/gatchat/ppp_auth.c
> index 1ddf762..46bbc65 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 {
There should be a single space between struct and 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 = g_random_int() % G_MAXUINT8;
Is this sufficient to fulfill the requirement stated in the comment? It
would be highly unlikely, but the identifier might still be repeated,
no? Would it be easier to simply use a counter?
> +
> + 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 = g_random_int() % G_MAXUINT8;
> + authreq->length = htons(length);
> +
> + authreq->data[0] = (char)strlen(username);
This cast seems fishy. Shouldn't it be to an unsigned char or guint8?
> + memcpy(authreq->data + 1, username, strlen(username));
> + authreq->data[strlen(username) + 1] = (char)strlen(password);
Same as above.
> + memcpy(authreq->data + 1 + strlen(username) + 1, password,
> + strlen(password));
No spaces for indentation please
> +
> + /* 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;
> +}
> diff --git a/gatchat/ppp_lcp.c b/gatchat/ppp_lcp.c
> index 4f420f1..1fdcb24 100644
> --- a/gatchat/ppp_lcp.c
> +++ b/gatchat/ppp_lcp.c
> @@ -238,25 +238,55 @@ static enum rcr_result lcp_rcr(struct pppcp_data *pppcp,
> guint8 method = option_data[2];
> guint8 *option;
>
> - if ((proto == CHAP_PROTOCOL) && (method == MD5))
> - break;
> -
> - /*
> - * try to suggest CHAP & MD5. If we are out
> - * of memory, just reject.
> - */
> -
> - option = g_try_malloc0(5);
> - if (option == NULL)
> - return RCR_REJECT;
> -
> - option[0] = AUTH_PROTO;
> - option[1] = 5;
> - put_network_short(&option[2], CHAP_PROTOCOL);
> - option[4] = MD5;
> - *new_options = option;
> - *new_len = 5;
> - return RCR_NAK;
> + switch (g_at_ppp_get_auth_method(ppp)) {
> + case G_AT_PPP_AUTH_METHOD_CHAP:
> + if (proto == CHAP_PROTOCOL && method == MD5)
> + break;
> +
> + /*
> + * Try to suggest CHAP/MD5.
> + * Just reject if we run out of memory.
> + */
> + option = g_try_malloc0(5);
> + if (option == NULL)
> + return RCR_REJECT;
> +
> + option[0] = AUTH_PROTO;
> + option[1] = 5;
> + put_network_short(&option[2], CHAP_PROTOCOL);
> + option[4] = MD5;
> + *new_options = option;
> + *new_len = 5;
> +
> + return RCR_NAK;
> +
> + case G_AT_PPP_AUTH_METHOD_PAP:
> + if (proto == PAP_PROTOCOL)
> + break;
> +
> + /*
> + * Try to suggest PAP.
> + * Just reject if we run out of memory.
> + */
> + option = g_try_malloc0(4);
> + if (option == NULL)
> + return RCR_REJECT;
> +
> + option[0] = AUTH_PROTO;
> + option[1] = 4;
> + put_network_short(&option[2], PAP_PROTOCOL);
> + *new_options = option;
> + *new_len = 4;
> +
> + return RCR_NAK;
> + default:
> + /*
> + * We only support CHAP and PAP.
> + * Tough luck!
> + */
> + return RCR_NAK;
Since this can never happen, we should probably not even include this
statement.
> + }
> + break;
> }
> case ACCM:
> case PFC:
>
Regards,
-Denis
next prev parent reply other threads:[~2014-06-18 22:20 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-06-17 21:57 [PATCH] Add support for PAP authentication Philip Paeps
2014-06-17 21:57 ` [PATCH 1/3] gatchat: implement " Philip Paeps
2014-06-18 22:20 ` Denis Kenzior [this message]
2014-06-19 8:29 ` Philip Paeps
2014-06-19 9:41 ` Philip Paeps
2014-06-17 21:57 ` [PATCH 2/3] gprs: make PPP authentication method configurable Philip Paeps
2014-06-18 22:27 ` Denis Kenzior
2014-06-17 21:57 ` [PATCH 3/3] mbpi: add authentication methods to provisioning Philip Paeps
2014-06-18 22:33 ` Denis Kenzior
2014-06-19 8:34 ` Philip Paeps
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53A210C0.9020501@gmail.com \
--to=denkenz@gmail.com \
--cc=ofono@ofono.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox