Request object implementation and bug fixes by Luke Howard.
[radsecproxy.git] / lib / request.c
1 /* See the file COPYING for licensing information.  */
2
3 #include <time.h>
4 #include <assert.h>
5 #include <event2/event.h>
6 #include <radsec/radsec.h>
7 #include <radsec/radsec-impl.h>
8 #include <radsec/request.h>
9 #include <radsec/request-impl.h>
10
11 static int
12 _rs_decrypt_mppe(struct rs_request *request, VALUE_PAIR *vp);
13
14 int
15 rs_request_create (struct rs_connection *conn, struct rs_request **req_out)
16 {
17   struct rs_request *req = rs_malloc (conn->ctx, sizeof(*req));
18   if (!req)
19     return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
20   memset (req, 0, sizeof(*req));
21   req->conn = conn;
22   *req_out = req;
23   return RSE_OK;
24 }
25
26 void
27 rs_request_destroy (struct rs_request *request)
28 {
29   rs_packet_destroy (request->req);
30   rs_packet_destroy (request->resp);
31   rs_free (request->conn->ctx, request);
32 }
33
34 #if 0
35 static void
36 _timer_cb(evutil_socket_t fd, short what, void *arg)
37
38 {
39 }
40 #endif
41
42 static void
43 _rs_req_connected(void *user_data)
44 {
45   struct rs_request *request = (struct rs_request *)user_data;
46 }
47
48 static void
49 _rs_req_disconnected(void *user_data)
50 {
51   struct rs_request *request = (struct rs_request *)user_data;
52 }
53
54 static void
55 _rs_req_packet_received(const struct rs_packet *pkt, void *user_data)
56 {
57   struct rs_request *request = (struct rs_request *)user_data;
58   int err;
59   VALUE_PAIR *vp;
60
61   assert (request);
62   assert (request->conn);
63   assert (request->req);
64
65   err = rad_verify(pkt->rpkt, request->req->rpkt,
66                    pkt->conn->active_peer->secret);
67   if (err)
68     return;
69
70   for (vp = pkt->rpkt->vps; vp != NULL; vp = vp->next)
71     {
72       if (VENDOR(vp->attribute) != VENDORPEC_MS)
73         continue;
74
75       switch (vp->attribute & 0xffff)
76         {
77           case PW_MS_MPPE_SEND_KEY:
78           case PW_MS_MPPE_RECV_KEY:
79             err = _rs_decrypt_mppe (request, vp);
80             if (err)
81               return;
82             break;
83           default:
84             break;
85         }
86     }
87
88   request->verified = 1;
89 }
90
91 static void
92 _rs_req_packet_sent(void *user_data)
93 {
94   struct rs_request *request = (struct rs_request *)user_data;
95 }
96
97 int
98 rs_request_send(struct rs_request *request, struct rs_packet *req,
99                 struct rs_packet **resp)
100 {
101   int err;
102   VALUE_PAIR *vp;
103   struct rs_connection *conn;
104
105   assert (request);
106   assert (request->conn);
107   conn = request->conn;
108
109   request->req = req;           /* take ownership */
110   request->saved_cb = conn->callbacks;
111
112   conn->callbacks.connected_cb = _rs_req_connected;
113   conn->callbacks.disconnected_cb = _rs_req_disconnected;
114   conn->callbacks.received_cb = _rs_req_packet_received;
115   conn->callbacks.sent_cb = _rs_req_packet_sent;
116
117   assert(request->verified == 0);
118
119   vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
120   pairadd(&request->req->rpkt->vps, vp);
121
122   err = rs_packet_send(request->req, request);
123   if (err)
124     goto cleanup;
125
126   err = rs_conn_receive_packet(request->conn, resp);
127   if (err)
128     goto cleanup;
129
130   if (!request->verified)
131     {
132       err = rs_err_conn_push_fl (conn, RSE_BADAUTH, __FILE__, __LINE__, NULL);
133       goto cleanup;
134     }
135
136 cleanup:
137   conn->callbacks = request->saved_cb;
138   return err;
139 }
140
141 /*
142  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
143  *
144  * This program is free software; you can redistribute it and/or modify
145  * it under the terms of the GNU General Public License version 2 as
146  * published by the Free Software Foundation.
147  *
148  * Alternatively, this software may be distributed under the terms of BSD
149  * license.
150  *
151  * See README and COPYING for more details.
152  */
153 #include <openssl/md5.h>
154
155 static int
156 _rs_decrypt_mppe(struct rs_request *request, VALUE_PAIR *vp)
157 {
158   unsigned char *key = vp->vp_octets;
159   size_t len = vp->length;
160   unsigned char plain[1 + MAX_STRING_LEN], *ppos = plain, *res;
161   const unsigned char *pos;
162   size_t left, plen;
163   unsigned char hash[MD5_DIGEST_LENGTH];
164   int i, first = 1;
165   const unsigned char *addr[3];
166   struct rs_connection *conn;
167
168   assert (request);
169   assert (request->conn);
170   conn = request->conn;
171
172   if (vp->type != PW_TYPE_OCTETS)
173     return rs_err_conn_push_fl (conn, RSE_BADAUTH, __FILE__, __LINE__, NULL);
174
175   pos = key + 2;
176   left = len - 2;
177   if (left % 16)
178     return rs_err_conn_push_fl (conn, RSE_BADAUTH, __FILE__, __LINE__, NULL);
179
180   plen = left;
181   if (plen > MAX_STRING_LEN)
182     return rs_err_conn_push_fl (conn, RSE_BADAUTH, __FILE__, __LINE__, NULL);
183
184   plain[0] = 0;
185
186   while (left)
187     {
188       MD5_CTX md5;
189
190       MD5_Init (&md5);
191       MD5_Update (&md5, conn->active_peer->secret,
192                   strlen (conn->active_peer->secret));
193       if (first)
194         {
195           MD5_Update (&md5, request->req->rpkt->vector, MD5_DIGEST_LENGTH);
196           MD5_Update (&md5, key, 2);
197           first = 0;
198         }
199       else
200         {
201           MD5_Update (&md5, pos - MD5_DIGEST_LENGTH, MD5_DIGEST_LENGTH);
202         }
203       MD5_Final (hash, &md5);
204
205       for (i = 0; i < MD5_DIGEST_LENGTH; i++)
206         *ppos++ = *pos++ ^ hash[i];
207       left -= MD5_DIGEST_LENGTH;
208     }
209
210   if (plain[0] == 0 || plain[0] > plen - 1)
211     return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
212
213   memcpy (vp->vp_octets, plain + 1, plain[0]);
214   vp->length = plain[0];
215
216   return RSE_OK;
217 }