Upgrade ofono to 1.2
[profile/ivi/ofono.git] / gatchat / ppp_auth.c
1 /*
2  *
3  *  PPP library with GLib integration
4  *
5  *  Copyright (C) 2009-2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <termios.h>
31 #include <arpa/inet.h>
32
33 #include <glib.h>
34
35 #include "gatppp.h"
36 #include "ppp.h"
37
38 struct chap_header {
39         guint8 code;
40         guint8 identifier;
41         guint16 length;
42         guint8 data[0];
43 } __attribute__((packed));
44
45 struct  ppp_chap {
46         guint8 method;
47         GAtPPP *ppp;
48 };
49
50 enum chap_code {
51         CHALLENGE = 1,
52         RESPONSE,
53         SUCCESS,
54         FAILURE
55 };
56
57 static void chap_process_challenge(struct ppp_chap *chap, const guint8 *packet)
58 {
59         const struct chap_header *header = (const struct chap_header *) packet;
60         struct chap_header *response;
61         GChecksum *checksum;
62         const char *secret = g_at_ppp_get_password(chap->ppp);
63         const char *username = g_at_ppp_get_username(chap->ppp);
64         guint16 response_length;
65         struct ppp_header *ppp_packet;
66         gsize digest_len;
67
68         /* create a checksum over id, secret, and challenge */
69         checksum = g_checksum_new(chap->method);
70         if (checksum == NULL)
71                 return;
72
73         g_checksum_update(checksum, &header->identifier, 1);
74
75         if (secret)
76                 g_checksum_update(checksum, (guchar *) secret, strlen(secret));
77
78         g_checksum_update(checksum, &header->data[1], header->data[0]);
79
80         /* transmit a response packet */
81         /*
82          * allocate space for the header, the checksum, and the ppp header,
83          * and the value size byte
84          */
85         digest_len = g_checksum_type_get_length(chap->method);
86         response_length = digest_len + sizeof(*header) + 1;
87
88         if (username != NULL)
89                 response_length += strlen(username);
90
91         ppp_packet = ppp_packet_new(response_length, CHAP_PROTOCOL);
92         if (ppp_packet == NULL)
93                 goto challenge_out;
94
95         response = (struct chap_header *) &ppp_packet->info;
96         if (response) {
97                 response->code = RESPONSE;
98                 response->identifier = header->identifier;
99                 response->length = htons(response_length);
100                 g_checksum_get_digest(checksum, response->data + 1,
101                                                         &digest_len);
102                 response->data[0] = digest_len;
103                 /* leave the name empty? */
104         }
105
106         if (username != NULL)
107                 memcpy(response->data + digest_len + 1, username,
108                                 strlen(username));
109
110         /* transmit the packet */
111         ppp_transmit(chap->ppp, (guint8 *) ppp_packet, response_length);
112         g_free(ppp_packet);
113
114 challenge_out:
115         g_checksum_free(checksum);
116 }
117
118 /*
119  * parse the packet
120  */
121 void ppp_chap_process_packet(struct ppp_chap *chap, const guint8 *new_packet,
122                                 gsize len)
123 {
124         guint8 code;
125
126         if (len < sizeof(struct chap_header))
127                 return;
128
129         code = new_packet[0];
130
131         switch (code) {
132         case CHALLENGE:
133                 chap_process_challenge(chap, new_packet);
134                 break;
135         case RESPONSE:
136                 break;
137         case SUCCESS:
138                 ppp_auth_notify(chap->ppp, TRUE);
139                 break;
140         case FAILURE:
141                 ppp_auth_notify(chap->ppp, FALSE);
142                 break;
143         default:
144                 break;
145         }
146 }
147
148 void ppp_chap_free(struct ppp_chap *chap)
149 {
150         g_free(chap);
151 }
152
153 struct ppp_chap *ppp_chap_new(GAtPPP *ppp, guint8 method)
154 {
155         struct ppp_chap *chap;
156
157         if (method != MD5)
158                 return NULL;
159
160         chap = g_try_new0(struct ppp_chap, 1);
161         if (chap == NULL)
162                 return NULL;
163
164         chap->ppp = ppp;
165         chap->method = G_CHECKSUM_MD5;
166
167         return chap;
168 }