c90511b79451b84095566293686c500668840a63
[radsecproxy.git] / lib / packet.c
1 #include <string.h>
2 #include <assert.h>
3 #include <freeradius/libradius.h>
4 #include <event2/event.h>
5 #include <event2/bufferevent.h>
6 #include "libradsec.h"
7 #include "libradsec-impl.h"
8 #if defined DEBUG
9 #include "debug.h"
10 #endif
11
12 static int
13 _packet_create (struct rs_connection *conn, struct rs_packet **pkt_out)
14 {
15   struct rs_packet *p;
16   RADIUS_PACKET *rpkt;
17
18   *pkt_out = NULL;
19
20   rpkt = rad_alloc (1);
21   if (!rpkt)
22     return rs_conn_err_push (conn, RSE_NOMEM, __func__);
23   rpkt->id = -1;
24
25   p = (struct rs_packet *) malloc (sizeof (struct rs_packet));
26   if (!p)
27     {
28       rad_free (&rpkt);
29       return rs_conn_err_push (conn, RSE_NOMEM, __func__);
30     }
31   memset (p, 0, sizeof (struct rs_packet));
32   p->conn = conn;
33   p->rpkt = rpkt;
34
35   *pkt_out = p;
36   return RSE_OK;
37 }
38
39 int
40 rs_packet_create_acc_request (struct rs_connection *conn,
41                               struct rs_packet **pkt_out,
42                               const char *user_name, const char *user_pw)
43 {
44   struct rs_packet *pkt;
45   struct rs_attr *attr;
46
47   if (_packet_create (conn, pkt_out))
48     return -1;
49   pkt = *pkt_out;
50   pkt->rpkt->code = PW_AUTHENTICATION_REQUEST;
51
52   if (rs_attr_create (conn, &attr, "User-Name", user_name))
53     return -1;
54   rs_packet_add_attr (pkt, attr);
55
56   if (rs_attr_create (conn, &attr, "User-Password", user_pw))
57     return -1;
58   /* FIXME: need this too? rad_pwencode(user_pw, &pwlen, SECRET, reqauth) */
59   rs_packet_add_attr (pkt, attr);
60
61   return RSE_OK;
62 }
63
64 static void
65 _event_cb (struct bufferevent *bev, short events, void *ctx)
66 {
67   struct rs_packet *pkt = (struct rs_packet *) ctx;
68   struct rs_connection *conn;
69   struct rs_peer *p;
70
71   assert (pkt);
72   assert (pkt->conn);
73   assert (pkt->conn->active_peer);
74   conn = pkt->conn;
75   p = conn->active_peer;
76
77   p->is_connecting = 0;
78   if (events & BEV_EVENT_CONNECTED)
79     {
80       p->is_connected = 1;
81 #if defined (DEBUG)
82       fprintf (stderr, "%s: connected\n", __func__);
83 #endif
84       rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret);
85       assert (pkt->rpkt);
86 #if defined (DEBUG)
87       fprintf (stderr, "%s: about to send this to %s:\n", __func__, "<fixme>");
88       rs_dump_packet (pkt);
89 #endif
90       if (bufferevent_write(bev, pkt->rpkt->data, pkt->rpkt->data_len))
91         rs_conn_err_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
92                              "bufferevent_write");
93       /* Packet will be freed in write callback.  */
94     }
95   else if (events & BEV_EVENT_ERROR)
96     rs_conn_err_push_fl (pkt->conn, RSE_CONNERR, __FILE__, __LINE__, NULL);
97 }
98
99 void
100 rs_packet_destroy(struct rs_packet *pkt)
101 {
102   rad_free (&pkt->rpkt);
103   rs_free (pkt->conn->ctx, pkt);
104 }
105
106 static void
107 _write_cb (struct bufferevent *bev, void *ctx)
108 {
109   struct rs_packet *pkt = (struct rs_packet *) ctx;
110
111   assert (pkt);
112   assert (pkt->conn);
113 #if defined (DEBUG)
114   fprintf (stderr, "%s: packet written, breaking event loop\n", __func__);
115 #endif
116   if (event_base_loopbreak (pkt->conn->evb) < 0)
117     abort ();                   /* FIXME */
118   rs_packet_destroy (pkt);
119 }
120
121 static void
122 _read_cb (struct bufferevent *bev, void *ctx)
123 {
124   struct rs_packet *pkt = (struct rs_packet *) ctx;
125   size_t n;
126
127   assert (pkt);
128   assert (pkt->conn);
129   if (!pkt->hdr_read_flag)
130     {
131       n = bufferevent_read (pkt->conn->bev, pkt->hdr, 4);
132       if (n == 4)
133         {
134           uint16_t len = (pkt->hdr[2] << 8) + pkt->hdr[3];
135           uint8_t *buf = rs_malloc (pkt->conn->ctx, len);
136
137           pkt->hdr_read_flag = 1;
138           if (!buf)
139             {
140               rs_conn_err_push_fl (pkt->conn, RSE_NOMEM, __FILE__,
141                                    __LINE__, NULL);
142               abort (); /* FIXME: recovering takes reading of packet */
143             }
144           pkt->rpkt->data = buf;
145           pkt->rpkt->data_len = len;
146           bufferevent_setwatermark (pkt->conn->bev, EV_READ, len - 4, 0);
147 #if defined (DEBUG)
148           fprintf (stderr, "%s: packet header read, pkt len=%d\n", __func__,
149                    len);
150 #endif
151         }
152       else if (n < 0)
153         return; /* Buffer frozen, i suppose.  Let's hope it thaws.  */
154       else
155         {
156           assert (n < 4);
157           return;               /* Need more to complete header.  */
158           }
159     }
160
161   printf ("%s: trying to read %d octets of packet data\n", __func__, pkt->rpkt->data_len - 4);
162   n = bufferevent_read (pkt->conn->bev, pkt->rpkt->data, pkt->rpkt->data_len - 4);
163   printf ("%s: read %d octets of packet data\n", __func__, n);
164   if (n == pkt->rpkt->data_len - 4)
165     {
166       bufferevent_disable (pkt->conn->bev, EV_READ);
167       pkt->hdr_read_flag = 0;
168       memset (pkt->hdr, 0, sizeof(*pkt->hdr));
169 #if defined (DEBUG)
170       fprintf (stderr, "%s: complete packet read\n", __func__);
171 #endif
172       if (event_base_loopbreak (pkt->conn->evb) < 0)
173         abort ();               /* FIXME */
174     }
175 }
176
177 static int
178 _init_evb (struct rs_connection *conn)
179 {
180   if (!conn->evb)
181     {
182 #if defined (DEBUG)
183       event_enable_debug_mode ();
184 #endif
185       conn->evb = event_base_new ();
186       if (!conn->evb)
187         return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
188                                     "event_base_new");
189     }
190   return RSE_OK;
191 }
192
193 static int
194 _init_socket (struct rs_connection *conn, struct rs_peer *p)
195 {
196   if (p->s < 0)
197     {
198       assert (p->addr);
199       p->s = socket (p->addr->ai_family, p->addr->ai_socktype,
200                      p->addr->ai_protocol);
201       if (p->s < 0)
202         return rs_conn_err_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
203                                     strerror (errno));
204     }
205   return RSE_OK;
206 }
207
208 static struct rs_peer *
209 _pick_peer (struct rs_connection *conn)
210 {
211   if (!conn->active_peer)
212     conn->active_peer = conn->peers;
213   return conn->active_peer;
214 }
215
216 static int
217 _init_bev (struct rs_connection *conn, struct rs_peer *peer)
218 {
219   if (!conn->bev)
220     {
221       conn->bev = bufferevent_socket_new (conn->evb, peer->s, 0);
222       if (!conn->bev)
223         return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
224                                     "bufferevent_socket_new");
225     }
226   return RSE_OK;
227 }
228
229 static void
230 _do_connect (struct rs_peer *p)
231 {
232   if (bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr,
233                                   p->addr->ai_addrlen) < 0)
234     rs_conn_err_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__,
235                            "bufferevent_socket_connect");
236   else
237     p->is_connecting = 1;
238 }
239
240 static int
241 _conn_open(struct rs_connection *conn, struct rs_packet *pkt)
242 {
243   struct rs_peer *p;
244
245   if (_init_evb (conn))
246     return -1;
247
248   p = _pick_peer (conn);
249   if (!p)
250     return rs_conn_err_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
251
252   if (_init_socket (conn, p))
253     return -1;
254
255   if (_init_bev (conn, p))
256     return -1;
257   bufferevent_setcb (conn->bev, _read_cb, _write_cb, _event_cb, pkt);
258
259   if (!p->is_connected)
260     if (!p->is_connecting)
261       _do_connect (p);
262
263   return RSE_OK;
264 }
265
266 int
267 rs_packet_send (struct rs_connection *conn, struct rs_packet *pkt, void *data)
268 {
269   assert (conn);
270   assert (pkt->rpkt);
271
272   if (_conn_open (conn, pkt))
273     return -1;
274   assert (conn->evb);
275   assert (conn->bev);
276   assert (conn->active_peer);
277   assert (conn->active_peer->s >= 0);
278
279   event_base_dispatch (conn->evb);
280
281 #if defined (DEBUG)
282   fprintf (stderr, "%s: event loop done\n", __func__);
283   assert (event_base_got_break(conn->evb));
284 #endif
285
286   return RSE_OK;
287 }
288
289 int
290 rs_packet_receive(struct rs_connection *conn, struct rs_packet **pkt_out)
291 {
292   struct rs_packet *pkt;
293
294   assert (conn);
295
296   if (_packet_create (conn, pkt_out))
297     return -1;
298   pkt = *pkt_out;
299   pkt->conn = conn;
300
301   if (_conn_open (conn, pkt))
302     return -1;
303   assert (conn->evb);
304   assert (conn->bev);
305   assert (conn->active_peer);
306   assert (conn->active_peer->s >= 0);
307
308   bufferevent_setwatermark (conn->bev, EV_READ, 4, 0);
309   bufferevent_enable (conn->bev, EV_READ);
310   event_base_dispatch (conn->evb);
311 #if defined (DEBUG)
312   fprintf (stderr, "%s: event loop done\n", __func__);
313   assert (event_base_got_break(conn->evb));
314 #endif
315
316 #if defined (DEBUG)
317   fprintf (stderr, "%s: got this:\n", __func__);
318   rs_dump_packet (pkt);
319 #endif
320
321   return RSE_OK;
322 }
323
324 void
325 rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr)
326 {
327   pairadd (&pkt->rpkt->vps, attr->vp);
328   attr->pkt = pkt;
329 }