97f62e6632fbad3a8e6d8fe9783ba61a0c867196
[radsecproxy.git] / lib / radsec.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <string.h>
5 #include <libgen.h>
6
7 #include <freeradius/libradius.h>
8 #include <event2/util.h>
9 #include "libradsec.h"
10 #include "libradsec-impl.h"
11
12 int
13 rs_context_create(struct rs_handle **ctx, const char *dict)
14 {
15   struct rs_handle *h;
16
17   if (ctx)
18     *ctx = NULL;
19   h = (struct rs_handle *) malloc (sizeof(struct rs_handle));
20   if (h)
21     {
22       char *buf1 = NULL, *buf2 = NULL;
23       char *dir, *fn;
24
25       buf1 = malloc (strlen (dict) + 1);
26       buf2 = malloc (strlen (dict) + 1);
27       if (!buf1 || !buf2)
28         {
29           free (h);
30           if (buf1)
31             free (buf1);
32           if (buf2)
33             free (buf2);
34           return RSE_NOMEM;
35         }
36       strcpy (buf1, dict);
37       dir = dirname (buf1);
38       strcpy (buf2, dict);
39       fn = basename (buf2);
40       if (dict_init (dir, fn) < 0)
41         {
42           free (h);
43           return RSE_SOME_ERROR;
44         }
45       free (buf1);
46       free (buf2);
47 #if defined (DEBUG)
48       fr_log_fp = stderr;
49       fr_debug_flag = 1;
50 #endif
51
52       memset (h, 0, sizeof(struct rs_handle));
53       fr_randinit (&h->fr_randctx, 0);
54       fr_rand_seed (NULL, 0);
55
56       if (ctx)
57         *ctx = h;
58     }
59   return h ? RSE_OK : RSE_NOMEM;
60 }
61
62 void rs_context_destroy(struct rs_handle *ctx)
63 {
64   free (ctx);
65 }
66
67 int rs_context_set_alloc_scheme(struct rs_handle *ctx, struct rs_alloc_scheme *scheme)
68 {
69   return rs_ctx_err_push_fl (ctx, RSE_NOSYS, __FILE__, __LINE__,
70                              "%s: NYI", __func__);
71 }
72
73 int rs_context_config_read(struct rs_handle *ctx, const char *config_file)
74 {
75   return rs_ctx_err_push_fl (ctx, RSE_NOSYS, __FILE__, __LINE__,
76                              "%s: NYI", __func__);
77 }
78
79 int rs_conn_create(struct rs_handle *ctx, struct rs_connection **conn)
80 {
81   struct rs_connection *c;
82
83   c = (struct rs_connection *) malloc (sizeof(struct rs_connection));
84   if (c)
85     {
86       memset (c, 0, sizeof(struct rs_connection));
87       c->ctx = ctx;
88     }
89   if (conn)
90     *conn = c;
91   return c ? RSE_OK : rs_ctx_err_push (ctx, RSE_NOMEM, NULL);
92 }
93
94 struct addrinfo *
95 _resolv (struct rs_connection *conn, const char *hostname, int port)
96 {
97   int err;
98   char portstr[6];
99   struct evutil_addrinfo hints, *res = NULL;
100
101   snprintf (portstr, sizeof(portstr), "%d", port);
102   memset (&hints, 0, sizeof(struct evutil_addrinfo));
103   //hints.ai_family = AF_UNSPEC;        /* v4 or v6.  */
104   hints.ai_family = AF_INET;    /* FIXME: v4 only, while debuging */
105   hints.ai_flags = AI_ADDRCONFIG;
106   switch (conn->type)
107     {
108     case RS_CONN_TYPE_NONE:
109       rs_conn_err_push_fl (conn, RSE_INVALID_CONN, __FILE__, __LINE__, NULL);
110       return NULL;
111     case RS_CONN_TYPE_TCP:
112     case RS_CONN_TYPE_TLS:
113       hints.ai_socktype = SOCK_STREAM;
114       hints.ai_protocol = IPPROTO_TCP;
115       break;
116     case RS_CONN_TYPE_UDP:
117     case RS_CONN_TYPE_DTLS:
118       hints.ai_socktype = SOCK_DGRAM;
119       hints.ai_protocol = IPPROTO_UDP;
120       break;
121     }
122   err = evutil_getaddrinfo (hostname, portstr, &hints, &res);
123   if (err)
124     rs_conn_err_push_fl (conn, RSE_BADADDR, __FILE__, __LINE__,
125                          " %s:%d: bad host name or port (%s)",
126                          hostname, port, evutil_gai_strerror(err));
127   return res;                   /* Simply use first result.  */
128 }
129
130 int
131 rs_conn_add_server(struct rs_connection *conn, struct rs_peer **server,
132                    rs_conn_type_t type, const char *hostname, int port)
133 {
134   struct rs_peer *srv;
135   struct evutil_addrinfo *addr;
136
137   if (conn->type == RS_CONN_TYPE_NONE)
138     conn->type = type;
139   else if (conn->type != type)
140     return rs_conn_err_push (conn, RSE_CONN_TYPE_MISMATCH, NULL);
141
142   addr = _resolv (conn, hostname, port);
143   if (!addr)
144     return -1;
145
146   srv = (struct rs_peer *) malloc (sizeof(struct rs_peer));
147   if (srv)
148     {
149       memset (srv, 0, sizeof(struct rs_peer));
150       srv->conn = conn;
151       srv->addr = addr;
152       srv->timeout = 10;
153       srv->tries = 3;
154       srv->next = conn->peers;
155       if (conn->peers)
156         conn->peers->next = srv;
157       else
158         conn->peers = srv;
159     }
160   if (*server)
161     *server = srv;
162   return srv ? RSE_OK : rs_conn_err_push (conn, RSE_NOMEM, NULL);
163 }
164
165 void rs_server_set_timeout(struct rs_peer *server, int timeout)
166 {
167   server->timeout = timeout;
168 }
169 void rs_server_set_tries(struct rs_peer *server, int tries)
170 {
171   server->tries = tries;
172 }
173 int rs_server_set_secret(struct rs_peer *server, const char *secret)
174 {
175   if (server->secret)
176     free (server->secret);
177   server->secret = (char *) malloc (strlen(secret) + 1);
178   if (!server->secret)
179     return rs_conn_err_push (server->conn, RSE_NOMEM, NULL);
180   strcpy (server->secret, secret);
181   return RSE_OK;
182 }
183
184 int rs_conn_add_listener(struct rs_connection *conn, rs_conn_type_t type, const char *hostname, int port)
185 {
186   return rs_conn_err_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
187                               "%s: NYI", __func__);
188 }
189
190
191 void
192 rs_conn_destroy(struct rs_connection *conn)
193 {
194   struct rs_peer *p;
195
196 #warning "TODO: Disconnect active_peer."
197
198   for (p = conn->peers; p; p = p->next)
199     {
200       if (p->addr)
201         evutil_freeaddrinfo (p->addr);
202       if (p->secret)
203         rs_free (conn->ctx, p->secret);
204     }
205 }
206
207 int rs_conn_set_eventbase(struct rs_connection *conn, struct event_base *eb)
208 {
209   return rs_conn_err_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
210                               "%s: NYI", __func__);
211 }
212
213 int rs_conn_set_callbacks(struct rs_connection *conn, struct rs_conn_callbacks *cb)
214 {
215   return rs_conn_err_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
216                               "%s: NYI", __func__);
217 }
218
219 int rs_conn_set_server(struct rs_connection *conn, const char *name)
220 {
221   return rs_conn_err_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
222                               "%s: NYI", __func__);
223 }
224
225 int rs_conn_get_current_server(struct rs_connection *conn, const char *name, size_t buflen)
226 {
227   return rs_conn_err_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
228                               "%s: NYI", __func__);
229 }
230
231 /* Non-public.  */
232 int
233 rs_conn_open(struct rs_connection *conn)
234 {
235   int s;
236   struct rs_peer *p;
237
238   if (conn->active_peer)
239     return RSE_OK;
240   p = conn->peers;
241   if (!p)
242     return rs_conn_err_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
243
244   s = socket (p->addr->ai_family, p->addr->ai_socktype, p->addr->ai_protocol);
245   if (s < 0)
246     return rs_conn_err_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
247                                 strerror (errno));
248   if (connect (s, p->addr->ai_addr, p->addr->ai_addrlen))
249     {
250       /* TODO: handle nonblocking sockets (EINTR, EAGAIN).  */
251       EVUTIL_CLOSESOCKET (s);
252       return rs_conn_err_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
253                                   strerror (errno));
254     }
255   p->s = s;
256   conn->active_peer = p;
257   return RSE_OK;
258 }