diff options
Diffstat (limited to 'lib/base.c')
-rw-r--r-- | lib/base.c | 161 |
1 files changed, 142 insertions, 19 deletions
@@ -1,12 +1,16 @@ #include <sys/socket.h> #include <errno.h> #include <stdlib.h> +#include <string.h> +//#include <unistd.h> +#include <stdint.h> +#include "../tlv11.h" /* FIXME: .. */ #include "libradsec-base.h" static int -do_connect(int type, - const struct sockaddr *addr, - socklen_t addrlen) +_do_connect(int type, + const struct sockaddr *addr, + socklen_t addrlen) { int s; @@ -19,6 +23,56 @@ do_connect(int type, return s; } +static struct list * +_list_new(const struct rs_config *ctx) +{ + struct list *list = rs_malloc(ctx, sizeof(struct list)); + if (list) + memset(list, 0, sizeof(struct list)); + return list; +} + +static int +_list_push(const struct rs_config *ctx, /* FIXME: code duplicate, list.c */ + struct list *list, + void *data) +{ + struct list_node *node; + + node = rs_malloc(ctx, sizeof(struct list_node)); + if (!node) + return 0; + + node->next = NULL; + node->data = data; + + if (list->first) + list->last->next = node; + else + list->first = node; + list->last = node; + + list->count++; + return 1; +} + +static void +_list_destroy(const struct rs_config *ctx, /* FIXME: code dup */ + struct list *list) +{ + struct list_node *node, *next; + + if (list) { + for (node = list->first; node; node = next) { + rs_free(ctx, node->data); + next = node->next; + rs_free(ctx, node); + } + free(list); + } +} + +/* ------------------------------------------------------- */ int rs_connect(const struct rs_config *conf, const struct sockaddr *addr, @@ -27,9 +81,9 @@ rs_connect(const struct rs_config *conf, switch (conf->conn_type) { case RS_CONN_TYPE_UDP: - return do_connect(SOCK_DGRAM, addr, addrlen); + return _do_connect(SOCK_DGRAM, addr, addrlen); case RS_CONN_TYPE_TCP: - return do_connect(SOCK_STREAM, addr, addrlen); + return _do_connect(SOCK_STREAM, addr, addrlen); /* fall thru */ case RS_CONN_TYPE_TLS: /* fall thru */ @@ -66,38 +120,83 @@ rs_packet_new(const struct rs_config *ctx, const uint8_t buf[RS_HEADER_LEN], size_t *count) { - struct rs_packet *p = - (ctx->alloc_scheme.malloc ? ctx->alloc_scheme.malloc : malloc)(20); + struct rs_packet *p = rs_malloc(ctx, sizeof(struct rs_packet)); if (p) { - p->code = buf[0]; - p->id = buf[1]; - if (count) - *count = 256 * buf[2] + buf[3]; + p->attrs = _list_new(ctx); + if (p->attrs) { + p->code = buf[0]; + p->id = buf[1]; + if (count) + *count = (buf[2] << 8) + buf[3]; + } + else + rs_packet_free(ctx, &p); } return p; } struct rs_packet * rs_packet_parse(const struct rs_config *ctx, - struct rs_packet *packet, + struct rs_packet **packet, const uint8_t *buf, size_t buflen) { + struct rs_packet *p = *packet; + struct tlv *tlv; + size_t i; + uint8_t atype, alen; + if (buflen < 16) { - rs_packet_free(ctx, packet); errno = EPROTO; + rs_packet_free(ctx, &p); return NULL; } - memcpy(packet->auth, buf, 16); - /* TODO: copy attributes starting at buf[16]. */ - return packet; + + i = 16; + while (i + 2 < buflen) { + atype = buf[i++]; + alen = buf[i++]; + if (alen < 2) { +#if DEBUG + fprintf(stderr, + "%s: DEBUG: attribute (type %d, len %d) has an invalid length\n", + __func__, atype, alen); +#endif + errno = EPROTO; + rs_packet_free(ctx, &p); + return NULL; + } + alen -= 2; + if (alen + i >= buflen) { +#if DEBUG + fprintf(stderr, + "%s: DEBUG: attribute (type %d, len %d) wouldn't fit packet\n", + __func__, atype, alen); +#endif + errno = EPROTO; + rs_packet_free(ctx, &p); + return NULL; + } + tlv = maketlv(atype, alen, (void *) (buf + i)); + if (tlv) + _list_push(ctx, p->attrs, tlv); + else { + errno = ENOMEM; + rs_packet_free(ctx, &p); + } + i += alen; + } + memcpy(p->auth, buf, 16); + return p; } void rs_packet_free(const struct rs_config *ctx, - struct rs_packet *packet) + struct rs_packet **packet) { - (ctx->alloc_scheme.free ? ctx->alloc_scheme.free : free)(packet); + _list_destroy(ctx, (*packet)->attrs); + rs_free(ctx, *packet); + *packet = NULL; } ssize_t @@ -105,7 +204,31 @@ rs_packet_serialize(const struct rs_packet *packet, uint8_t *buf, size_t buflen) { - fixme; + struct list_node *ln; + size_t pktlen; + ssize_t i; + + for (ln = list_first(packet->attrs), pktlen = 20; ln; ln = list_next(ln)) + pktlen += ((struct rs_attribute *)(ln->data))->length; + if (pktlen > buflen) + return -(pktlen - buflen); + + buf[0] = packet->code; + buf[1] = packet->id; + buf[2] = (pktlen & 0xff00) >> 8; + buf[3] = pktlen & 0xff; + + memcpy(buf + 4, packet->auth, 16); + + for (ln = list_first(packet->attrs), i = 20; ln; ln = list_next(ln)) { + struct rs_attribute *a = (struct rs_attribute *)(ln->data); + buf[i++] = a->type; + buf[i++] = a->length; + memcpy(buf + i, a->value, a->length - 2); + i += a->length - 2; + } + + return i; } /* Local Variables: */ |