Merge branch 'libradsec' of /tmp/radsecproxy into libradsec
[radsecproxy.git] / lib / packet.c
1 /* See the file COPYING for licensing information.  */
2
3 #if defined HAVE_CONFIG_H
4 #include <config.h>
5 #endif
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <freeradius/libradius.h>
11 #include <event2/event.h>
12 #include <event2/bufferevent.h>
13 #if defined RS_ENABLE_TLS
14 #include <event2/bufferevent_ssl.h>
15 #include <openssl/err.h>
16 #endif
17 #include <radsec/radsec.h>
18 #include <radsec/radsec-impl.h>
19 #include "tls.h"
20 #include "debug.h"
21 #if defined DEBUG
22 #include <netdb.h>
23 #include <sys/socket.h>
24 #endif
25
26 static int
27 _do_send (struct rs_packet *pkt)
28 {
29   int err;
30   VALUE_PAIR *vp;
31
32   assert (pkt->rpkt);
33   assert (!pkt->original);
34
35   vp = paircreate (PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
36   if (!vp)
37     return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__,
38                                 "paircreate: %s", fr_strerror ());
39   pairadd (&pkt->rpkt->vps, vp);
40
41   if (rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret))
42     return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
43                                 "rad_encode: %s", fr_strerror ());
44   if (rad_sign (pkt->rpkt, NULL, pkt->conn->active_peer->secret))
45     return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
46                                 "rad_sign: %s", fr_strerror ());
47 #if defined (DEBUG)
48   {
49     char host[80], serv[80];
50
51     getnameinfo (pkt->conn->active_peer->addr->ai_addr,
52                  pkt->conn->active_peer->addr->ai_addrlen,
53                  host, sizeof(host), serv, sizeof(serv),
54                  0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);
55     rs_debug ("%s: about to send this to %s:%s:\n", __func__, host, serv);
56     rs_dump_packet (pkt);
57   }
58 #endif
59
60   err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data,
61                            pkt->rpkt->data_len);
62   if (err < 0)
63     return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
64                                 "bufferevent_write: %s",
65                                 evutil_gai_strerror(err));
66   return RSE_OK;
67 }
68
69 static void
70 _event_cb (struct bufferevent *bev, short events, void *ctx)
71 {
72   struct rs_packet *pkt = (struct rs_packet *)ctx;
73   struct rs_connection *conn;
74   struct rs_peer *p;
75 #if defined RS_ENABLE_TLS
76   unsigned long err;
77 #endif
78
79   assert (pkt);
80   assert (pkt->conn);
81   assert (pkt->conn->active_peer);
82   conn = pkt->conn;
83   p = conn->active_peer;
84
85   p->is_connecting = 0;
86   if (events & BEV_EVENT_CONNECTED)
87     {
88       p->is_connected = 1;
89       if (conn->callbacks.connected_cb)
90         conn->callbacks.connected_cb (conn->user_data);
91       rs_debug ("%s: connected\n", __func__);
92       if (_do_send (pkt))
93         return;
94       if (conn->callbacks.sent_cb)
95         conn->callbacks.sent_cb (conn->user_data);
96       /* Packet will be freed in write callback.  */
97     }
98   else if (events & BEV_EVENT_ERROR)
99     {
100 #if defined RS_ENABLE_TLS
101       if (conn->tls_ssl)        /* FIXME: correct check?  */
102         {
103           for (err = bufferevent_get_openssl_error (conn->bev);
104                err;
105                err = bufferevent_get_openssl_error (conn->bev))
106             {
107               fprintf (stderr, "%s: DEBUG: openssl error: %s\n", __func__,
108                        ERR_error_string (err, NULL)); /* FIXME: DEBUG, until verified that pushed errors will actually be handled  */
109               rs_err_conn_push_fl (pkt->conn, RSE_SSLERR, __FILE__, __LINE__,
110                                    "%d", err);
111             }
112         }
113 #endif  /* RS_ENABLE_TLS */
114
115       rs_err_conn_push_fl (pkt->conn, RSE_CONNERR, __FILE__, __LINE__, NULL);
116       fprintf (stderr, "%s: DEBUG: BEV_EVENT_ERROR\n", __func__); /* FIXME: DEBUG, until verified that pushed errors will actually be handled  */
117     }
118 }
119
120 static void
121 _write_cb (struct bufferevent *bev, void *ctx)
122 {
123   struct rs_packet *pkt = (struct rs_packet *) ctx;
124   int err;
125
126   assert (pkt);
127   assert (pkt->conn);
128
129   rs_debug ("%s: packet written, breaking event loop\n", __func__);
130   err = event_base_loopbreak (pkt->conn->evb);
131   if (err < 0)
132     rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
133                          "event_base_loopbreak: %s",
134                          evutil_gai_strerror(err));
135 }
136
137 static void
138 _read_cb (struct bufferevent *bev, void *ctx)
139 {
140   struct rs_packet *pkt = (struct rs_packet *)ctx;
141   int err;
142   size_t n;
143
144   assert (pkt);
145   assert (pkt->conn);
146   assert (pkt->rpkt);
147
148   pkt->rpkt->sockfd = pkt->conn->active_peer->fd; /* FIXME: Why?  */
149   pkt->rpkt->vps = NULL;                          /* FIXME: Why?  */
150
151   if (!pkt->hdr_read_flag)
152     {
153       n = bufferevent_read (pkt->conn->bev, pkt->hdr, RS_HEADER_LEN);
154       if (n == RS_HEADER_LEN)
155         {
156           pkt->hdr_read_flag = 1;
157           pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3];
158           if (pkt->rpkt->data_len < 20 /* || len > 4096 */)
159             abort ();   /* FIXME: Read and discard invalid packet.  */
160           pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len);
161           if (!pkt->rpkt->data)
162             {
163               rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__,
164                                    NULL);
165               abort ();         /* FIXME: handle ENOMEM.  */
166             }
167           memcpy (pkt->rpkt->data, pkt->hdr, RS_HEADER_LEN);
168           bufferevent_setwatermark (pkt->conn->bev, EV_READ,
169                                     pkt->rpkt->data_len - RS_HEADER_LEN, 0);
170           rs_debug ("%s: packet header read, total pkt len=%d\n",
171                     __func__, pkt->rpkt->data_len);
172         }
173       else if (n < 0)
174         return;  /* Buffer frozen.  FIXME: Properly handled above?  */
175       else
176         {
177           assert (!"short header");
178           abort ();             /* FIXME: handle short header */
179         }
180     }
181
182   rs_debug ("%s: trying to read %d octets of packet data\n", __func__,
183             pkt->rpkt->data_len - RS_HEADER_LEN);
184   n = bufferevent_read (pkt->conn->bev,
185                         pkt->rpkt->data + RS_HEADER_LEN,
186                         pkt->rpkt->data_len - RS_HEADER_LEN);
187   rs_debug ("%s: read %ld octets of packet data\n", __func__, n);
188
189   if (n == pkt->rpkt->data_len - RS_HEADER_LEN)
190     {
191       bufferevent_disable (pkt->conn->bev, EV_READ);
192       rs_debug ("%s: complete packet read\n", __func__);
193       pkt->hdr_read_flag = 0;
194       memset (pkt->hdr, 0, sizeof(*pkt->hdr));
195       if (!rad_packet_ok (pkt->rpkt, 0) != 0)
196         {
197           rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
198                                "rad_packet_ok: %s", fr_strerror ());
199           return;
200         }
201       assert (pkt->original); /* FIXME: where's the bug if this fires?  */
202
203       /* Verify header and message authenticator.  */
204       if (rad_verify (pkt->rpkt, pkt->original->rpkt,
205                       pkt->conn->active_peer->secret))
206         {
207           rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
208                                "rad_verify: %s", fr_strerror ());
209           return;
210         }
211
212       /* Decode and decrypt.  */
213       if (rad_decode (pkt->rpkt, pkt->original->rpkt,
214                       pkt->conn->active_peer->secret))
215         {
216           rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
217                                "rad_decode: %s", fr_strerror ());
218           return;
219         }
220
221       if (pkt->conn->callbacks.received_cb)
222         pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data);
223
224       err = event_base_loopbreak (pkt->conn->evb);
225       if (err < 0)
226         {
227           rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
228                                "event_base_loopbreak: %s",
229                                evutil_gai_strerror(err));
230           return;
231         }
232     }
233   else if (n < 0)
234     return;            /* Buffer frozen.  FIXME: Properly handled?  */
235   else
236     {
237       assert (!"short packet");
238       abort ();                 /* FIXME: handle short packet */
239     }
240 }
241
242 static void
243 _evlog_cb (int severity, const char *msg)
244 {
245   const char *sevstr;
246   switch (severity)
247     {
248     case _EVENT_LOG_DEBUG:
249 #if !defined (DEBUG_LEVENT)
250       return;
251 #endif
252       sevstr = "debug";
253       break;
254     case _EVENT_LOG_MSG:
255       sevstr = "msg";
256       break;
257     case _EVENT_LOG_WARN:
258       sevstr = "warn";
259       break;
260     case _EVENT_LOG_ERR:
261       sevstr = "err";
262       break;
263     default:
264       sevstr = "???";
265       break;
266     }
267   fprintf (stderr, "libevent: [%s] %s\n", sevstr, msg); /* FIXME: stderr?  */
268 }
269
270 static int
271 _init_evb (struct rs_connection *conn)
272 {
273   if (!conn->evb)
274     {
275 #if defined (DEBUG)
276       event_enable_debug_mode ();
277 #endif
278       event_set_log_callback (_evlog_cb);
279       conn->evb = event_base_new ();
280       if (!conn->evb)
281         return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
282                                     "event_base_new");
283     }
284   return RSE_OK;
285 }
286
287 static int
288 _init_socket (struct rs_connection *conn, struct rs_peer *p)
289 {
290   if (p->fd != -1)
291     return RSE_OK;
292
293   assert (p->addr);
294   p->fd = socket (p->addr->ai_family, p->addr->ai_socktype,
295                   p->addr->ai_protocol);
296   if (p->fd < 0)
297     return rs_err_conn_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
298                                 strerror (errno));
299   if (evutil_make_socket_nonblocking (p->fd) < 0)
300     {
301       evutil_closesocket (p->fd);
302       return rs_err_conn_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
303                                   strerror (errno));
304     }
305   return RSE_OK;
306 }
307
308 static struct rs_peer *
309 _pick_peer (struct rs_connection *conn)
310 {
311   if (!conn->active_peer)
312     conn->active_peer = conn->peers;
313   return conn->active_peer;
314 }
315
316 static int
317 _init_bev (struct rs_connection *conn, struct rs_peer *peer)
318 {
319   if (conn->bev)
320     return RSE_OK;
321
322   switch (conn->type)
323     {
324     case RS_CONN_TYPE_UDP:
325     case RS_CONN_TYPE_TCP:
326       conn->bev = bufferevent_socket_new (conn->evb, peer->fd, 0);
327       if (!conn->bev)
328         return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
329                                     "bufferevent_socket_new");
330       break;
331 #if defined RS_ENABLE_TLS
332     case RS_CONN_TYPE_TLS:
333       if (rs_tls_init (conn))
334         return -1;
335       /* Would be convenient to pass BEV_OPT_CLOSE_ON_FREE but things
336          seem to break when be_openssl_ctrl() (in libevent) calls
337          SSL_set_bio() after BIO_new_socket() with flag=1.  */
338       conn->bev =
339         bufferevent_openssl_socket_new (conn->evb, peer->fd, conn->tls_ssl,
340                                         BUFFEREVENT_SSL_CONNECTING, 0);
341       if (!conn->bev)
342         return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
343                                     "bufferevent_openssl_socket_new");
344
345       break;
346     case RS_CONN_TYPE_DTLS:
347       return rs_err_conn_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
348                                   "%s: NYI", __func__);
349 #endif  /* RS_ENABLE_TLS */
350     default:
351       return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__,
352                                   "%s: unknown connection type: %d", __func__,
353                                   conn->type);
354     }
355
356   return RSE_OK;
357 }
358
359 static void
360 _do_connect (struct rs_peer *p)
361 {
362   int err;
363
364   err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr,
365                                     p->addr->ai_addrlen);
366   if (err < 0)
367     rs_err_conn_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__,
368                          "bufferevent_socket_connect: %s",
369                          evutil_gai_strerror(err));
370   else
371     p->is_connecting = 1;
372 }
373
374 static int
375 _conn_open(struct rs_connection *conn, struct rs_packet *pkt)
376 {
377   struct rs_peer *p;
378
379   if (_init_evb (conn))
380     return -1;
381
382   p = _pick_peer (conn);
383   if (!p)
384     return rs_err_conn_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
385
386   if (_init_socket (conn, p))
387     return -1;
388
389   if (_init_bev (conn, p))
390     return -1;
391
392   if (!p->is_connected)
393     if (!p->is_connecting)
394       _do_connect (p);
395
396   return RSE_OK;
397 }
398
399 static int
400 _conn_is_open_p (struct rs_connection *conn)
401 {
402   return conn->active_peer && conn->active_peer->is_connected;
403 }
404
405 /* Public functions.  */
406 int
407 rs_packet_create (struct rs_connection *conn, struct rs_packet **pkt_out)
408 {
409   struct rs_packet *p;
410   RADIUS_PACKET *rpkt;
411
412   *pkt_out = NULL;
413
414   rpkt = rad_alloc (1);
415   if (!rpkt)
416     return rs_err_conn_push (conn, RSE_NOMEM, __func__);
417   rpkt->id = conn->nextid++;
418
419   p = (struct rs_packet *) malloc (sizeof (struct rs_packet));
420   if (!p)
421     {
422       rad_free (&rpkt);
423       return rs_err_conn_push (conn, RSE_NOMEM, __func__);
424     }
425   memset (p, 0, sizeof (struct rs_packet));
426   p->conn = conn;
427   p->rpkt = rpkt;
428
429   *pkt_out = p;
430   return RSE_OK;
431 }
432
433 int
434 rs_packet_create_auth_request (struct rs_connection *conn,
435                                struct rs_packet **pkt_out,
436                                const char *user_name, const char *user_pw)
437 {
438   struct rs_packet *pkt;
439   struct rs_attr *attr;
440
441   if (rs_packet_create (conn, pkt_out))
442     return -1;
443   pkt = *pkt_out;
444   pkt->rpkt->code = PW_AUTHENTICATION_REQUEST;
445
446   if (user_name)
447     {
448       if (rs_attr_create (conn, &attr, "User-Name", user_name))
449         return -1;
450       rs_packet_add_attr (pkt, attr);
451
452       if (user_pw)
453         {
454           if (rs_attr_create (conn, &attr, "User-Password", user_pw))
455             return -1;
456           rs_packet_add_attr (pkt, attr);
457         }
458     }
459
460   return RSE_OK;
461 }
462
463 int
464 rs_packet_send (struct rs_packet *pkt, void *user_data)
465 {
466   struct rs_connection *conn;
467   int err;
468
469   assert (pkt);
470   conn = pkt->conn;
471
472   if (_conn_is_open_p (conn))
473     _do_send (pkt);
474   else
475     if (_conn_open (conn, pkt))
476       return RSE_SOME_ERROR; /* FIXME: inconsistent with all the return -1 */
477
478   assert (conn->evb);
479   assert (conn->bev);
480   assert (conn->active_peer);
481   assert (conn->active_peer->fd >= 0);
482
483   conn->user_data = user_data;
484   bufferevent_setcb (conn->bev, _read_cb, _write_cb, _event_cb, pkt);
485
486   /* Do dispatch, unless the user wants to do it herself.  */
487   if (!conn->user_dispatch_flag)
488     {
489       err = event_base_dispatch (conn->evb);
490       if (err < 0)
491         return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
492                                     "event_base_dispatch: %s",
493                                     evutil_gai_strerror(err));
494
495       rs_debug ("%s: event loop done\n", __func__);
496       if (!event_base_got_break(conn->evb))
497         {
498           /* Something went wrong -- we never reached loopbreak in
499              _write_cb().  FIXME: Pull error/errors?  */
500           return RSE_SOME_ERROR; /* FIXME */
501         }
502     }
503
504   return RSE_OK;
505 }
506
507 int
508 rs_conn_receive_packet (struct rs_connection *conn,
509                         struct rs_packet *request,
510                         struct rs_packet **pkt_out)
511 {
512   struct rs_packet *pkt;
513
514   assert (conn);
515
516   if (rs_packet_create (conn, pkt_out))
517     return -1;
518   pkt = *pkt_out;
519   pkt->conn = conn;
520   pkt->original = request;
521
522   if (_conn_open (conn, pkt))
523     return -1;
524   assert (conn->evb);
525   assert (conn->bev);
526   assert (conn->active_peer);
527   assert (conn->active_peer->fd >= 0);
528
529   bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0);
530   bufferevent_enable (conn->bev, EV_READ);
531   bufferevent_setcb (conn->bev, _read_cb, _write_cb, _event_cb, pkt);
532
533   /* Do dispatch, unless the user wants to do it herself.  */
534   if (!conn->user_dispatch_flag)
535     {
536       event_base_dispatch (conn->evb);
537       rs_debug ("%s: event loop done", __func__);
538       if (event_base_got_break (conn->evb))
539         {
540           rs_debug (", got this:\n");
541 #if defined DEBUG
542           rs_dump_packet (pkt);
543 #endif
544         }
545       else
546         {
547           rs_debug (", no reply\n");
548           /* Something went wrong -- we never reached loopbreak in
549              _read_cb().  FIXME: Pull error/errors?  */
550           return RSE_SOME_ERROR; /* FIXME */
551         }
552     }
553
554   pkt->original = NULL;
555
556   return RSE_OK;
557 }
558
559 void
560 rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr)
561 {
562   pairadd (&pkt->rpkt->vps, attr->vp);
563   attr->pkt = pkt;
564 }
565
566 struct radius_packet *
567 rs_packet_frpkt(struct rs_packet *pkt)
568 {
569   assert (pkt);
570   return pkt->rpkt;
571 }
572
573 void
574 rs_packet_destroy(struct rs_packet *pkt)
575 {
576   if (pkt)
577     {
578       // FIXME: memory leak! TODO: free all attributes
579       rad_free (&pkt->rpkt);
580       rs_free (pkt->conn->ctx, pkt);
581     }
582 }