Example client crafting simple packet using freeradius-libradius.
[radsecproxy.git] / lib / base.c
1 /* See the file COPYING for licensing information.  */
2
3 #include <sys/socket.h>
4 #include <errno.h>
5 #include <stdlib.h>
6 #include <string.h>
7 //#include <unistd.h>
8 #include <stdint.h>
9 #include "../tlv11.h"           /* FIXME: .. */
10 #include "libradsec-base.h"
11
12 static int
13 _do_connect(int type,
14             const struct sockaddr *addr,
15             socklen_t addrlen)
16 {
17   int s;
18
19   s = socket(AF_INET, type, 0); /* FIXME: do AF_INET6 too */
20   if (s >= 0)
21       if (connect(s, addr, addrlen)) {
22           close(s);
23           s = -1;
24       }
25   return s;
26 }
27
28 static struct list *
29 _list_new(const struct rs_handle *ctx)
30 {
31     struct list *list = rs_malloc(ctx, sizeof(struct list));
32     if (list)
33         memset(list, 0, sizeof(struct list));
34     return list;
35 }
36
37 static int
38 _list_push(const struct rs_handle *ctx, /* FIXME: code duplicate, list.c */
39            struct list *list,
40            void *data)
41 {
42     struct list_node *node;
43
44     node = rs_malloc(ctx, sizeof(struct list_node));
45     if (!node)
46         return 0;
47
48     node->next = NULL;
49     node->data = data;
50
51     if (list->first)
52         list->last->next = node;
53     else
54         list->first = node;
55     list->last = node;
56
57     list->count++;
58     return 1;
59 }
60
61 static void
62 _list_destroy(const struct rs_handle *ctx, /* FIXME: code dup */
63               struct list *list)
64 {
65     struct list_node *node, *next;
66
67     if (list) {
68         for (node = list->first; node; node = next) {
69             rs_free(ctx, node->data);
70             next = node->next;
71             rs_free(ctx, node);
72         }
73         free(list);
74     }
75 }
76
77 /* ------------------------------------------------------- */
78 int
79 rs_connect(const struct rs_handle *conf,
80            const struct sockaddr *addr,
81            socklen_t addrlen)
82 {
83     switch (conf->conn_type)
84     {
85     case RS_CONN_TYPE_UDP:
86         return _do_connect(SOCK_DGRAM, addr, addrlen);
87     case RS_CONN_TYPE_TCP:
88         return _do_connect(SOCK_STREAM, addr, addrlen);
89         /* fall thru */
90     case RS_CONN_TYPE_TLS:
91         /* fall thru */
92     case RS_CONN_TYPE_DTLS:
93         /* fall thru */
94     default:
95         errno = ENOSYS;
96         return -1;
97     }
98 }
99
100 int
101 rs_disconnect( const struct rs_handle *conf, int fd)
102 {
103     switch (conf->conn_type)
104     {
105     case RS_CONN_TYPE_UDP:
106         return close(fd);
107     case RS_CONN_TYPE_TCP:
108         shutdown(fd, SHUT_RDWR);
109         return close(fd);
110     case RS_CONN_TYPE_TLS:
111         /* fall thru */
112     case RS_CONN_TYPE_DTLS:
113         /* fall thru */
114     default:
115         errno = ENOSYS;
116         return -1;
117     }
118 }
119
120 struct rs_packet *
121 rs_packet_new(const struct rs_handle *ctx,
122               const uint8_t buf[RS_HEADER_LEN],
123               size_t *count)
124 {
125     struct rs_packet *p = rs_malloc(ctx, sizeof(struct rs_packet));
126     if (p) {
127         p->attrs = _list_new(ctx);
128         if (p->attrs) {
129             p->code = buf[0];
130             p->id = buf[1];
131             if (count)
132                 *count = (buf[2] << 8) + buf[3];
133         }
134         else
135             rs_packet_free(ctx, &p);
136     }
137     return p;
138 }
139
140 struct rs_packet *
141 rs_packet_parse(const struct rs_handle *ctx,
142                 struct rs_packet **packet,
143                 const uint8_t *buf,
144                 size_t buflen)
145 {
146     struct rs_packet *p = *packet;
147     struct tlv *tlv;
148     size_t i;
149     uint8_t atype, alen;
150
151     if (buflen < 16) {
152         errno = EPROTO;
153         rs_packet_free(ctx, &p);
154         return NULL;
155     }
156
157     i = 16;
158     while (i + 2 < buflen) {
159         atype = buf[i++];
160         alen = buf[i++];
161         if (alen < 2) {
162 #if DEBUG
163             fprintf(stderr,
164                     "%s: DEBUG: attribute (type %d, len %d) has an invalid length\n",
165                     __func__, atype, alen);
166 #endif
167             errno = EPROTO;
168             rs_packet_free(ctx, &p);
169             return NULL;
170         }
171         alen -= 2;
172         if (alen + i >= buflen) {
173 #if DEBUG
174             fprintf(stderr,
175                     "%s: DEBUG: attribute (type %d, len %d) wouldn't fit packet\n",
176                     __func__, atype, alen);
177 #endif
178             errno = EPROTO;
179             rs_packet_free(ctx, &p);
180             return NULL;
181         }
182         tlv = maketlv(atype, alen, (void *) (buf + i));
183         if (tlv)
184             _list_push(ctx, p->attrs, tlv);
185         else {
186             errno = ENOMEM;
187             rs_packet_free(ctx, &p);
188         }
189         i += alen;
190     }
191     memcpy(p->auth, buf, 16);
192     return p;
193 }
194
195 void
196 rs_packet_free(const struct rs_handle *ctx,
197                struct rs_packet **packet)
198 {
199     _list_destroy(ctx, (*packet)->attrs);
200     rs_free(ctx, *packet);
201     *packet = NULL;
202 }
203
204 ssize_t
205 rs_packet_serialize(const struct rs_packet *packet,
206                     uint8_t *buf,
207                     size_t buflen)
208 {
209     struct list_node *ln;
210     size_t pktlen;
211     ssize_t i;
212
213     for (ln = list_first(packet->attrs), pktlen = 20; ln; ln = list_next(ln))
214         pktlen += ((struct rs_attribute *)(ln->data))->length;
215     if (pktlen > buflen)
216         return -(pktlen - buflen);
217
218     buf[0] = packet->code;
219     buf[1] = packet->id;
220     buf[2] = (pktlen & 0xff00) >> 8;
221     buf[3] = pktlen & 0xff;
222
223     memcpy(buf + 4, packet->auth, 16);
224
225     for (ln = list_first(packet->attrs), i = 20; ln; ln = list_next(ln)) {
226         struct rs_attribute *a = (struct rs_attribute *)(ln->data);
227         buf[i++] = a->type;
228         buf[i++] = a->length;
229         memcpy(buf + i, a->value, a->length - 2);
230         i += a->length - 2;
231     }
232
233     return i;
234 }
235
236 /* Local Variables: */
237 /* c-file-style: "stroustrup" */
238 /* End: */