Hi Omar has sugested to update ber. I have implemented this and rebased my patches to this.
The "update ber and aldap" patch is acually not correct, because the aldap_match_attr() has a changed API. The result might not used after the message was freed. The updated aldap also adds the posibility for ldap+tls (starttls) and ldapi. This is not yet implemented. Philipp
From 68d93d9ca2dd3601d314403c3a035d758f168401 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Mon, 12 Feb 2024 08:38:42 +0100 Subject: [PATCH 1/4] table-ldap update ber and aldap --- configure.ac | 2 +- extras/tables/table-ldap/aldap.c | 609 +++++++++++-------- extras/tables/table-ldap/aldap.h | 69 ++- extras/tables/table-ldap/ber.c | 816 ++++++++++++++++---------- extras/tables/table-ldap/ber.h | 141 +++-- extras/tables/table-ldap/table_ldap.c | 57 +- 6 files changed, 1059 insertions(+), 635 deletions(-) diff --git a/configure.ac b/configure.ac index 7ecc50d..7c4561c 100644 --- a/configure.ac +++ b/configure.ac @@ -579,7 +579,7 @@ AC_ARG_WITH([libssl], ] ) ## XXX chl -lssl manually added -LIBS="-lcrypto -lssl $LIBS" +LIBS="-lcrypto -lssl -ltls $LIBS" AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1], [Define if your ssl headers are included with #include <openssl/header.h>])], diff --git a/extras/tables/table-ldap/aldap.c b/extras/tables/table-ldap/aldap.c index e5b99fa..fca8abc 100644 --- a/extras/tables/table-ldap/aldap.c +++ b/extras/tables/table-ldap/aldap.c @@ -1,3 +1,5 @@ +/* $OpenBSD: aldap.c,v 1.10 2022/03/31 09:03:48 martijn Exp $ */ + /* * Copyright (c) 2008 Alexander Schrijver <aschrij...@openbsd.org> * Copyright (c) 2006, 2007 Marc Balmer <mbal...@openbsd.org> @@ -17,12 +19,16 @@ #include "includes.h" +#include <arpa/inet.h> +#include <ctype.h> #include <errno.h> #include <inttypes.h> #include <string.h> #include <stdlib.h> #include <unistd.h> +#include <event.h> + #include "aldap.h" #if 0 @@ -34,11 +40,15 @@ static struct ber_element *ldap_parse_search_filter(struct ber_element *, char *, const char *); static struct ber_element *ldap_do_parse_search_filter( struct ber_element *, char **, const char *); -char **aldap_get_stringset(struct ber_element *); +struct aldap_stringset *aldap_get_stringset(struct ber_element *); char *utoa(char *); +static int isu8cont(unsigned char); char *parseval(char *, size_t, const char *); int aldap_create_page_control(struct ber_element *, int, struct aldap_page_control *); +int aldap_send(struct aldap *, + struct ber_element *); +unsigned int aldap_application(struct ber_element *); #ifdef DEBUG void ldap_debug_elements(struct ber_element *); @@ -52,13 +62,22 @@ void ldap_debug_elements(struct ber_element *); #define LDAP_DEBUG(x, y) do { } while (0) #endif +unsigned int +aldap_application(struct ber_element *elm) +{ + return BER_TYPE_OCTETSTRING; +} + int aldap_close(struct aldap *al) { - if (close(al->ber.fd) == -1) - return (-1); - - ber_free(&al->ber); + if (al->tls != NULL) { + tls_close(al->tls); + tls_free(al->tls); + } + close(al->fd); + ober_free(&al->ber); + evbuffer_free(al->buf); free(al); return (0); @@ -71,43 +90,142 @@ aldap_init(int fd) if ((a = calloc(1, sizeof(*a))) == NULL) return NULL; - a->ber.fd = fd; + a->buf = evbuffer_new(); + a->fd = fd; + ober_set_application(&a->ber, aldap_application); return a; } +static int +tls_handshake_wrapper(struct tls *ctx) +{ + int ret; + do { + ret = tls_handshake(ctx); + } while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT); + return ret; +} + +int +aldap_tls(struct aldap *ldap, struct tls_config *cfg, const char *name) +{ + ldap->tls = tls_client(); + if (ldap->tls == NULL) { + ldap->err = ALDAP_ERR_OPERATION_FAILED; + return (-1); + } + + if (tls_configure(ldap->tls, cfg) == -1) { + ldap->err = ALDAP_ERR_TLS_ERROR; + return (-1); + } + + if (tls_connect_socket(ldap->tls, ldap->fd, name) == -1) { + ldap->err = ALDAP_ERR_TLS_ERROR; + return (-1); + } + + if (tls_handshake_wrapper(ldap->tls) == -1) { + ldap->err = ALDAP_ERR_TLS_ERROR; + return (-1); + } + + return (0); +} + +int +aldap_send(struct aldap *ldap, struct ber_element *root) +{ + void *ptr; + char *data; + size_t len, done; + ssize_t error, wrote; + + len = ober_calc_len(root); + error = ober_write_elements(&ldap->ber, root); + ober_free_elements(root); + if (error == -1) + return -1; + + ober_get_writebuf(&ldap->ber, &ptr); + done = 0; + data = ptr; + while (len > 0) { + if (ldap->tls != NULL) { + wrote = tls_write(ldap->tls, data + done, len); + if (wrote == TLS_WANT_POLLIN || + wrote == TLS_WANT_POLLOUT) + continue; + } else + wrote = write(ldap->fd, data + done, len); + + if (wrote == -1) + return -1; + + len -= wrote; + done += wrote; + } + + return 0; +} + +int +aldap_req_starttls(struct aldap *ldap) +{ + struct ber_element *root = NULL, *ber; + + if ((root = ober_add_sequence(NULL)) == NULL) + goto fail; + + ber = ober_printf_elements(root, "d{tst", ++ldap->msgid, BER_CLASS_APP, + LDAP_REQ_EXTENDED, LDAP_STARTTLS_OID, BER_CLASS_CONTEXT, 0); + if (ber == NULL) { + ldap->err = ALDAP_ERR_OPERATION_FAILED; + goto fail; + } + + if (aldap_send(ldap, root) == -1) + goto fail; + + return (ldap->msgid); +fail: + if (root != NULL) + ober_free_elements(root); + + ldap->err = ALDAP_ERR_OPERATION_FAILED; + return (-1); +} + int aldap_bind(struct aldap *ldap, char *binddn, char *bindcred) { struct ber_element *root = NULL, *elm; - int error; if (binddn == NULL) binddn = ""; if (bindcred == NULL) bindcred = ""; - if ((root = ber_add_sequence(NULL)) == NULL) + if ((root = ober_add_sequence(NULL)) == NULL) goto fail; - elm = ber_printf_elements(root, "d{tdsst", ++ldap->msgid, BER_CLASS_APP, - (unsigned long)LDAP_REQ_BIND, ALDAP_VERSION, binddn, bindcred, - BER_CLASS_CONTEXT, (unsigned long)LDAP_AUTH_SIMPLE); + elm = ober_printf_elements(root, "d{tdsst", ++ldap->msgid, BER_CLASS_APP, + LDAP_REQ_BIND, ALDAP_VERSION, binddn, bindcred, BER_CLASS_CONTEXT, + LDAP_AUTH_SIMPLE); if (elm == NULL) goto fail; LDAP_DEBUG("aldap_bind", root); - error = ber_write_elements(&ldap->ber, root); - ber_free_elements(root); - root = NULL; - if (error == -1) + if (aldap_send(ldap, root) == -1) { + root = NULL; goto fail; - + } return (ldap->msgid); fail: if (root != NULL) - ber_free_elements(root); + ober_free_elements(root); ldap->err = ALDAP_ERR_OPERATION_FAILED; return (-1); @@ -117,27 +235,24 @@ int aldap_unbind(struct aldap *ldap) { struct ber_element *root = NULL, *elm; - int error; - if ((root = ber_add_sequence(NULL)) == NULL) + if ((root = ober_add_sequence(NULL)) == NULL) goto fail; - elm = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP, + elm = ober_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP, LDAP_REQ_UNBIND_30); if (elm == NULL) goto fail; LDAP_DEBUG("aldap_unbind", root); - error = ber_write_elements(&ldap->ber, root); - ber_free_elements(root); - root = NULL; - if (error == -1) + if (aldap_send(ldap, root) == -1) { + root = NULL; goto fail; - + } return (ldap->msgid); fail: if (root != NULL) - ber_free_elements(root); + ober_free_elements(root); ldap->err = ALDAP_ERR_OPERATION_FAILED; @@ -150,21 +265,21 @@ aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter, struct aldap_page_control *page) { struct ber_element *root = NULL, *ber, *c; - int i, error; + int i; - if ((root = ber_add_sequence(NULL)) == NULL) + if ((root = ober_add_sequence(NULL)) == NULL) goto fail; - ber = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP, - (unsigned long) LDAP_REQ_SEARCH); + ber = ober_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP, + LDAP_REQ_SEARCH); if (ber == NULL) { ldap->err = ALDAP_ERR_OPERATION_FAILED; goto fail; } - c = ber; - ber = ber_printf_elements(ber, "sEEddb", basedn, (long long)scope, - (long long)LDAP_DEREF_NEVER, sizelimit, + c = ber; + ber = ober_printf_elements(ber, "sEEddb", basedn, (long long)scope, + (long long)LDAP_DEREF_NEVER, sizelimit, timelimit, typesonly); if (ber == NULL) { ldap->err = ALDAP_ERR_OPERATION_FAILED; @@ -176,11 +291,11 @@ aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter, goto fail; } - if ((ber = ber_add_sequence(ber)) == NULL) + if ((ber = ober_add_sequence(ber)) == NULL) goto fail; if (attrs != NULL) for (i = 0; attrs[i] != NULL; i++) { - if ((ber = ber_add_string(ber, attrs[i])) == NULL) + if ((ber = ober_add_string(ber, attrs[i])) == NULL) goto fail; } @@ -188,10 +303,8 @@ aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter, LDAP_DEBUG("aldap_search", root); - error = ber_write_elements(&ldap->ber, root); - ber_free_elements(root); - root = NULL; - if (error == -1) { + if (aldap_send(ldap, root) == -1) { + root = NULL; ldap->err = ALDAP_ERR_OPERATION_FAILED; goto fail; } @@ -200,7 +313,7 @@ aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter, fail: if (root != NULL) - ber_free_elements(root); + ober_free_elements(root); return (-1); } @@ -209,37 +322,36 @@ int aldap_create_page_control(struct ber_element *elm, int size, struct aldap_page_control *page) { - int len; + ssize_t len; struct ber c; struct ber_element *ber = NULL; c.br_wbuf = NULL; - c.fd = -1; - ber = ber_add_sequence(NULL); + ber = ober_add_sequence(NULL); if (page == NULL) { - if (ber_printf_elements(ber, "ds", 50, "") == NULL) + if (ober_printf_elements(ber, "ds", 50, "") == NULL) goto fail; } else { - if (ber_printf_elements(ber, "dx", 50, page->cookie, + if (ober_printf_elements(ber, "dx", 50, page->cookie, page->cookie_len) == NULL) goto fail; } - if ((len = ber_write_elements(&c, ber)) < 1) + if ((len = ober_write_elements(&c, ber)) < 1) goto fail; - if (ber_printf_elements(elm, "{t{sx", 2, 0, LDAP_PAGED_OID, + if (ober_printf_elements(elm, "{t{sx", 2, 0, LDAP_PAGED_OID, c.br_wbuf, (size_t)len) == NULL) goto fail; - ber_free_elements(ber); - ber_free(&c); + ober_free_elements(ber); + ober_free(&c); return len; fail: if (ber != NULL) - ber_free_elements(ber); - ber_free(&c); + ober_free_elements(ber); + ober_free(&c); return (-1); } @@ -248,20 +360,52 @@ struct aldap_message * aldap_parse(struct aldap *ldap) { int class; - unsigned long type; + unsigned int type; long long msgid = 0; struct aldap_message *m; struct ber_element *a = NULL, *ep; + char rbuf[512]; + int ret, retry; if ((m = calloc(1, sizeof(struct aldap_message))) == NULL) return NULL; - if ((m->msg = ber_read_elements(&ldap->ber, NULL)) == NULL) - goto parsefail; + retry = 0; + while (m->msg == NULL) { + if (retry || EVBUFFER_LENGTH(ldap->buf) == 0) { + if (ldap->tls) { + ret = tls_read(ldap->tls, rbuf, sizeof(rbuf)); + if (ret == TLS_WANT_POLLIN || + ret == TLS_WANT_POLLOUT) + continue; + } else + ret = read(ldap->fd, rbuf, sizeof(rbuf)); + + if (ret <= 0) { + goto parsefail; + } + + evbuffer_add(ldap->buf, rbuf, ret); + } + + if (EVBUFFER_LENGTH(ldap->buf) > 0) { + ober_set_readbuf(&ldap->ber, EVBUFFER_DATA(ldap->buf), + EVBUFFER_LENGTH(ldap->buf)); + errno = 0; + m->msg = ober_read_elements(&ldap->ber, NULL); + if (errno != 0 && errno != ECANCELED) { + goto parsefail; + } + + retry = 1; + } + } + + evbuffer_drain(ldap->buf, ldap->ber.br_rptr - ldap->ber.br_rbuf); LDAP_DEBUG("message", m->msg); - if (ber_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0) + if (ober_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0) goto parsefail; m->msgid = msgid; m->message_type = type; @@ -275,15 +419,17 @@ aldap_parse(struct aldap *ldap) case LDAP_RES_MODRDN: case LDAP_RES_COMPARE: case LDAP_RES_SEARCH_RESULT: - if (ber_scanf_elements(m->protocol_op, "{EeSeSe", - &m->body.res.rescode, &m->dn, &m->body.res.diagmsg, &a) != 0) + if (ober_scanf_elements(m->protocol_op, "{EeSe", + &m->body.res.rescode, &m->dn, &m->body.res.diagmsg) != 0) goto parsefail; - if (m->body.res.rescode == LDAP_REFERRAL) - if (ber_scanf_elements(a, "{e", &m->references) != 0) + if (m->body.res.rescode == LDAP_REFERRAL) { + a = m->body.res.diagmsg->be_next; + if (ober_scanf_elements(a, "{e", &m->references) != 0) goto parsefail; + } if (m->msg->be_sub) { for (ep = m->msg->be_sub; ep != NULL; ep = ep->be_next) { - ber_scanf_elements(ep, "t", &class, &type); + ober_scanf_elements(ep, "t", &class, &type); if (class == 2 && type == 0) m->page = aldap_parse_page_control(ep->be_sub->be_sub, ep->be_sub->be_sub->be_len); @@ -292,25 +438,32 @@ aldap_parse(struct aldap *ldap) m->page = NULL; break; case LDAP_RES_SEARCH_ENTRY: - if (ber_scanf_elements(m->protocol_op, "{eS{e", &m->dn, + if (ober_scanf_elements(m->protocol_op, "{eS{e", &m->dn, &m->body.search.attrs) != 0) goto parsefail; break; case LDAP_RES_SEARCH_REFERENCE: - if (ber_scanf_elements(m->protocol_op, "{e", &m->references) != 0) + if (ober_scanf_elements(m->protocol_op, "{e", &m->references) != 0) + goto parsefail; + break; + case LDAP_RES_EXTENDED: + if (ober_scanf_elements(m->protocol_op, "{E", + &m->body.res.rescode) != 0) { goto parsefail; + } break; } return m; parsefail: + evbuffer_drain(ldap->buf, EVBUFFER_LENGTH(ldap->buf)); ldap->err = ALDAP_ERR_PARSER_ERROR; aldap_freemsg(m); return NULL; } struct aldap_page_control * -aldap_parse_page_control(struct ber_element *control, size_t len) +aldap_parse_page_control(struct ber_element *control, size_t len) { char *oid, *s; char *encoded; @@ -319,42 +472,38 @@ aldap_parse_page_control(struct ber_element *control, size_t len) struct aldap_page_control *page; b.br_wbuf = NULL; - b.fd = -1; - ber_scanf_elements(control, "ss", &oid, &encoded); - ber_set_readbuf(&b, encoded, control->be_next->be_len); - elm = ber_read_elements(&b, NULL); - if (elm == NULL) { - ber_free(&b); - return NULL; - } + ober_scanf_elements(control, "ss", &oid, &encoded); + ober_set_readbuf(&b, encoded, control->be_next->be_len); + elm = ober_read_elements(&b, NULL); if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) { - ber_free_elements(elm); - ber_free(&b); + if (elm != NULL) + ober_free_elements(elm); + ober_free(&b); return NULL; } - ber_scanf_elements(elm->be_sub, "is", &page->size, &s); + ober_scanf_elements(elm->be_sub, "is", &page->size, &s); page->cookie_len = elm->be_sub->be_next->be_len; if ((page->cookie = malloc(page->cookie_len)) == NULL) { - ber_free_elements(elm); - ber_free(&b); + if (elm != NULL) + ober_free_elements(elm); + ober_free(&b); free(page); return NULL; } memcpy(page->cookie, s, page->cookie_len); - ber_free_elements(elm); - ber_free(&b); + ober_free_elements(elm); + ober_free(&b); return page; } void aldap_freepage(struct aldap_page_control *page) { - if (page->cookie) - free(page->cookie); + free(page->cookie); free(page); } @@ -362,7 +511,7 @@ void aldap_freemsg(struct aldap_message *msg) { if (msg->msg) - ber_free_elements(msg->msg); + ober_free_elements(msg->msg); free(msg); } @@ -380,13 +529,13 @@ aldap_get_dn(struct aldap_message *msg) if (msg->dn == NULL) return NULL; - if (ber_get_string(msg->dn, &dn) == -1) + if (ober_get_string(msg->dn, &dn) == -1) return NULL; return utoa(dn); } -char ** +struct aldap_stringset * aldap_get_references(struct aldap_message *msg) { if (msg->references == NULL) @@ -416,7 +565,7 @@ aldap_get_diagmsg(struct aldap_message *msg) if (msg->body.res.diagmsg == NULL) return NULL; - if (ber_get_string(msg->body.res.diagmsg, &s) == -1) + if (ober_get_string(msg->body.res.diagmsg, &s) == -1) return NULL; return utoa(s); @@ -432,7 +581,7 @@ aldap_count_attrs(struct aldap_message *msg) return (-1); for (i = 0, a = msg->body.search.attrs; - a != NULL && ber_get_eoc(a) != 0; + a != NULL && ober_get_eoc(a) != 0; i++, a = a->be_next) ; @@ -440,17 +589,18 @@ aldap_count_attrs(struct aldap_message *msg) } int -aldap_first_attr(struct aldap_message *msg, char **outkey, char ***outvalues) +aldap_first_attr(struct aldap_message *msg, char **outkey, + struct aldap_stringset **outvalues) { - struct ber_element *b, *c; + struct ber_element *b; char *key; - char **ret; + struct aldap_stringset *ret; if (msg->body.search.attrs == NULL) goto fail; - if (ber_scanf_elements(msg->body.search.attrs, "{s(e)}e", - &key, &b, &c) != 0) + if (ober_scanf_elements(msg->body.search.attrs, "{s(e)}", + &key, &b) != 0) goto fail; msg->body.search.iter = msg->body.search.attrs->be_next; @@ -469,22 +619,22 @@ fail: } int -aldap_next_attr(struct aldap_message *msg, char **outkey, char ***outvalues) +aldap_next_attr(struct aldap_message *msg, char **outkey, + struct aldap_stringset **outvalues) { - struct ber_element *a, *b; + struct ber_element *a; char *key; - char **ret; + struct aldap_stringset *ret; if (msg->body.search.iter == NULL) goto notfound; LDAP_DEBUG("attr", msg->body.search.iter); - if (ber_get_eoc(msg->body.search.iter) == 0) + if (ober_get_eoc(msg->body.search.iter) == 0) goto notfound; - if (ber_scanf_elements(msg->body.search.iter, "{s(e)}e", &key, &a, &b) - != 0) + if (ober_scanf_elements(msg->body.search.iter, "{s(e)}", &key, &a) != 0) goto fail; msg->body.search.iter = msg->body.search.iter->be_next; @@ -504,11 +654,12 @@ notfound: } int -aldap_match_attr(struct aldap_message *msg, char *inkey, char ***outvalues) +aldap_match_attr(struct aldap_message *msg, char *inkey, + struct aldap_stringset **outvalues) { struct ber_element *a, *b; char *descr = NULL; - char **ret; + struct aldap_stringset *ret; if (msg->body.search.attrs == NULL) goto fail; @@ -518,9 +669,9 @@ aldap_match_attr(struct aldap_message *msg, char *inkey, char ***outvalues) for (a = msg->body.search.attrs;;) { if (a == NULL) goto notfound; - if (ber_get_eoc(a) == 0) + if (ober_get_eoc(a) == 0) goto notfound; - if (ber_scanf_elements(a, "{s(e", &descr, &b) != 0) + if (ober_scanf_elements(a, "{s(e", &descr, &b) != 0) goto fail; if (strcasecmp(descr, inkey) == 0) goto attrfound; @@ -541,16 +692,12 @@ notfound: } int -aldap_free_attr(char **values) +aldap_free_attr(struct aldap_stringset *values) { - int i; - if (values == NULL) return -1; - for (i = 0; values[i] != NULL; i++) - free(values[i]); - + free(values->str); free(values); return (1); @@ -569,15 +716,24 @@ aldap_parse_url(const char *url, struct aldap_url *lu) const char *errstr = NULL; int i; - if ((lu->buffer = strdup(url)) == NULL) + if ((lu->buffer = p = strdup(url)) == NULL) return (-1); - p = lu->buffer; /* protocol */ - if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) != 0) - goto fail; - lu->protocol = LDAP; - p += strlen(LDAP_URL); + if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) == 0) { + lu->protocol = LDAP; + p += strlen(LDAP_URL); + } else if (strncasecmp(LDAPS_URL, p, strlen(LDAPS_URL)) == 0) { + lu->protocol = LDAPS; + p += strlen(LDAPS_URL); + } else if (strncasecmp(LDAPTLS_URL, p, strlen(LDAPTLS_URL)) == 0) { + lu->protocol = LDAPTLS; + p += strlen(LDAPTLS_URL); + } else if (strncasecmp(LDAPI_URL, p, strlen(LDAPI_URL)) == 0) { + lu->protocol = LDAPI; + p += strlen(LDAPI_URL); + } else + lu->protocol = -1; /* host and optional port */ if ((forward = strchr(p, '/')) != NULL) @@ -595,6 +751,8 @@ aldap_parse_url(const char *url, struct aldap_url *lu) } } else { lu->port = LDAP_PORT; + if (lu->protocol == LDAPS) + lu->port = LDAPS_PORT; } /* fail if no host is given */ if (strlen(p) == 0) @@ -667,10 +825,9 @@ fail: return (-1); } -#if 0 int aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit, - int timelimit) + int timelimit, struct aldap_page_control *page) { struct aldap_url *lu; @@ -680,8 +837,8 @@ aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit, if (aldap_parse_url(url, lu)) goto fail; - if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, lu->attributes, - typesonly, sizelimit, timelimit) == -1) + if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, NULL, + lu->attributes, typesonly, sizelimit, timelimit, page) == -1) goto fail; aldap_free_url(lu); @@ -690,39 +847,40 @@ fail: aldap_free_url(lu); return (-1); } -#endif /* * internal functions */ -char ** +struct aldap_stringset * aldap_get_stringset(struct ber_element *elm) { struct ber_element *a; int i; - char **ret; - char *s; + struct aldap_stringset *ret; if (elm->be_type != BER_TYPE_OCTETSTRING) return NULL; - for (a = elm, i = 1; i > 0 && a != NULL && a->be_type == - BER_TYPE_OCTETSTRING; a = a->be_next, i++) + if ((ret = malloc(sizeof(*ret))) == NULL) + return NULL; + for (a = elm, ret->len = 0; a != NULL && a->be_type == + BER_TYPE_OCTETSTRING; a = a->be_next, ret->len++) ; - if (i == 1) + if (ret->len == 0) { + free(ret); return NULL; + } - if ((ret = calloc(i + 1, sizeof(char *))) == NULL) + if ((ret->str = reallocarray(NULL, ret->len, + sizeof(*(ret->str)))) == NULL) { + free(ret); return NULL; + } for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING; - a = a->be_next, i++) { - - ber_get_string(a, &s); - ret[i] = utoa(s); - } - ret[i + 1] = NULL; + a = a->be_next, i++) + (void) ober_get_ostring(a, &(ret->str[i])); return ret; } @@ -751,8 +909,8 @@ ldap_parse_search_filter(struct ber_element *ber, char *filter, const char *key) return (NULL); if (*cp != '\0') { - ber_free_elements(elm); - ber_link_elements(ber, NULL); + ober_free_elements(elm); + ober_link_elements(ber, NULL); errno = EINVAL; return (NULL); } @@ -799,10 +957,10 @@ ldap_do_parse_search_filter(struct ber_element *prev, char **cpp, const char *ke else type = LDAP_FILT_OR; - if ((elm = ber_add_set(prev)) == NULL) + if ((elm = ober_add_set(prev)) == NULL) goto callfail; root = elm; - ber_set_header(elm, BER_CLASS_CONTEXT, type); + ober_set_header(elm, BER_CLASS_CONTEXT, type); if (*++cp != '(') /* opening `(` of filter */ goto syntaxfail; @@ -818,12 +976,12 @@ ldap_do_parse_search_filter(struct ber_element *prev, char **cpp, const char *ke break; case '!': /* NOT */ - if ((root = ber_add_sequence(prev)) == NULL) + if ((root = ober_add_sequence(prev)) == NULL) goto callfail; - ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT); + ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT); cp++; /* now points to sub-filter */ - if (ldap_do_parse_search_filter(root, &cp, key) == NULL) + if ((elm = ldap_do_parse_search_filter(root, &cp, key)) == NULL) goto bad; if (*cp != ')') /* trailing `)` of filter */ @@ -862,18 +1020,18 @@ ldap_do_parse_search_filter(struct ber_element *prev, char **cpp, const char *ke if (strncmp(attr_val, "*)", 2) == 0) { cp++; /* point to trailing `)` */ if ((root = - ber_add_nstring(prev, attr_desc, len)) == NULL) + ober_add_nstring(prev, attr_desc, len)) == NULL) goto bad; - ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES); + ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES); break; } - if ((root = ber_add_sequence(prev)) == NULL) + if ((root = ober_add_sequence(prev)) == NULL) goto callfail; - ber_set_header(root, BER_CLASS_CONTEXT, type); + ober_set_header(root, BER_CLASS_CONTEXT, type); - if ((elm = ber_add_nstring(root, attr_desc, len)) == NULL) + if ((elm = ober_add_nstring(root, attr_desc, len)) == NULL) goto callfail; len = strcspn(attr_val, "*)"); @@ -888,9 +1046,9 @@ ldap_do_parse_search_filter(struct ber_element *prev, char **cpp, const char *ke cp = attr_val; - ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS); + ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS); - if ((elm = ber_add_sequence(elm)) == NULL) + if ((elm = ober_add_sequence(elm)) == NULL) goto callfail; for (initial = 1;; cp++, initial = 0) { @@ -917,12 +1075,12 @@ ldap_do_parse_search_filter(struct ber_element *prev, char **cpp, const char *ke if ((parsed_val = parseval(attr_val, len, key)) == NULL) goto callfail; - elm = ber_add_nstring(elm, parsed_val, + elm = ober_add_nstring(elm, parsed_val, strlen(parsed_val)); free(parsed_val); if (elm == NULL) goto callfail; - ber_set_header(elm, BER_CLASS_CONTEXT, type); + ober_set_header(elm, BER_CLASS_CONTEXT, type); if (type == LDAP_FILT_SUBS_FIN) break; } @@ -931,7 +1089,7 @@ ldap_do_parse_search_filter(struct ber_element *prev, char **cpp, const char *ke if ((parsed_val = parseval(attr_val, len, key)) == NULL) goto callfail; - elm = ber_add_nstring(elm, parsed_val, strlen(parsed_val)); + elm = ober_add_nstring(elm, parsed_val, strlen(parsed_val)); free(parsed_val); if (elm == NULL) goto callfail; @@ -947,8 +1105,8 @@ syntaxfail: /* XXX -- error reporting */ callfail: bad: if (root != NULL) - ber_free_elements(root); - ber_link_elements(prev, NULL); + ober_free_elements(root); + ober_link_elements(prev, NULL); return (NULL); } @@ -965,12 +1123,12 @@ ldap_debug_elements(struct ber_element *root) int d; char *buf; size_t len; - unsigned int i; + u_int i; int constructed; struct ber_oid o; /* calculate lengths */ - ber_calc_len(root); + ober_calc_len(root); switch (root->be_encoding) { case BER_TYPE_SEQUENCE: @@ -1077,7 +1235,7 @@ ldap_debug_elements(struct ber_element *root) break; case BER_CLASS_PRIVATE: fprintf(stderr, "class: private(%u) type: ", root->be_class); - fprintf(stderr, "encoding (%lu) type: ", root->be_encoding); + fprintf(stderr, "encoding (%u) type: ", root->be_encoding); break; case BER_CLASS_CONTEXT: /* XXX: this is not correct */ @@ -1092,7 +1250,7 @@ ldap_debug_elements(struct ber_element *root) fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class); break; } - fprintf(stderr, "(%lu) encoding %lu ", + fprintf(stderr, "(%u) encoding %u ", root->be_type, root->be_encoding); if (constructed) @@ -1100,28 +1258,28 @@ ldap_debug_elements(struct ber_element *root) switch (root->be_encoding) { case BER_TYPE_BOOLEAN: - if (ber_get_boolean(root, &d) == -1) { + if (ober_get_boolean(root, &d) == -1) { fprintf(stderr, "<INVALID>\n"); break; } fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d); break; case BER_TYPE_INTEGER: - if (ber_get_integer(root, &v) == -1) { + if (ober_get_integer(root, &v) == -1) { fprintf(stderr, "<INVALID>\n"); break; } fprintf(stderr, "value %lld\n", v); break; case BER_TYPE_ENUMERATED: - if (ber_get_enumerated(root, &v) == -1) { + if (ober_get_enumerated(root, &v) == -1) { fprintf(stderr, "<INVALID>\n"); break; } fprintf(stderr, "value %lld\n", v); break; case BER_TYPE_BITSTRING: - if (ber_get_bitstring(root, (void *)&buf, &len) == -1) { + if (ober_get_bitstring(root, (void *)&buf, &len) == -1) { fprintf(stderr, "<INVALID>\n"); break; } @@ -1131,18 +1289,18 @@ ldap_debug_elements(struct ber_element *root) fprintf(stderr, "\n"); break; case BER_TYPE_OBJECT: - if (ber_get_oid(root, &o) == -1) { + if (ober_get_oid(root, &o) == -1) { fprintf(stderr, "<INVALID>\n"); break; } fprintf(stderr, "\n"); break; case BER_TYPE_OCTETSTRING: - if (ber_get_nstring(root, (void *)&buf, &len) == -1) { + if (ober_get_nstring(root, (void *)&buf, &len) == -1) { fprintf(stderr, "<INVALID>\n"); break; } - fprintf(stderr, "string \"%.*s\"\n", len, buf); + fprintf(stderr, "string \"%.*s\"\n", (int)len, buf); break; case BER_TYPE_NULL: /* no payload */ case BER_TYPE_EOC: @@ -1164,7 +1322,7 @@ ldap_debug_elements(struct ber_element *root) #endif /* - * Convert UTF-8 to ASCII. + * Strip UTF-8 down to ASCII without validation. * notes: * non-ASCII characters are displayed as '?' * the argument u should be a NULL terminated sequence of UTF-8 bytes. @@ -1176,106 +1334,82 @@ utoa(char *u) char *str; /* calculate the length to allocate */ - for (len = 0, i = 0; u[i] != '\0'; ) { - if ((u[i] & 0xF0) == 0xF0) - i += 4; - else if ((u[i] & 0xE0) == 0xE0) - i += 3; - else if ((u[i] & 0xC0) == 0xC0) - i += 2; - else - i += 1; - len++; - } + for (len = 0, i = 0; u[i] != '\0'; i++) + if (!isu8cont(u[i])) + len++; if ((str = calloc(len + 1, sizeof(char))) == NULL) return NULL; /* copy the ASCII characters to the newly allocated string */ - for (i = 0, j = 0; u[i] != '\0'; j++) { - if ((u[i] & 0xF0) == 0xF0) { - str[j] = '?'; - i += 4; - } else if ((u[i] & 0xE0) == 0xE0) { - str[j] = '?'; - i += 3; - } else if ((u[i] & 0xC0) == 0xC0) { - str[j] = '?'; - i += 2; - } else { - str[j] = u[i]; - i += 1; - } - } + for (i = 0, j = 0; u[i] != '\0'; i++) + if (!isu8cont(u[i])) + str[j++] = isascii((unsigned char)u[i]) ? u[i] : '?'; return str; } +static int +isu8cont(unsigned char c) +{ + return (c & (0x80 | 0x40)) == 0x80; +} + /* * Parse a LDAP value * notes: - * the argument u should be a NULL terminated sequence of ASCII bytes. + * the argument p should be a NUL-terminated sequence of ASCII bytes */ char * parseval(char *p, size_t len, const char *key) { char hex[3]; - char *cp = p, *buffer, *newbuffer; - size_t size, newsize, i, j, keylen; - + char *buffer, *newbuffer; + size_t i, j, keylen, size, newsize; size = len + 1; + if ((buffer = calloc(1, size)) == NULL) return NULL; for (i = j = 0; j < len; i++) { - if (i >= size) { - newsize = size + 1024; - if ((newbuffer = realloc(buffer, newsize)) == NULL) { - free(buffer); - return (NULL); - } - buffer = newbuffer; - size = newsize; - } - - if (cp[j] == '\\') { - (void)strlcpy(hex, cp + j + 1, sizeof(hex)); + if (p[j] == '\\') { + strlcpy(hex, p + j + 1, sizeof(hex)); buffer[i] = (char)strtoumax(hex, NULL, 16); j += 3; - } else if (cp[j] == '%') { - switch (cp[j + 1]) { - case '%': - buffer[i] = '%'; - j += 2; - break; - case 's': - if (!key) { - free(buffer); - return NULL; - } - keylen = strlen(key); - if (!keylen) { - j += 2; - break; - } - newsize = size + keylen; - if ((newbuffer = realloc(buffer, newsize)) == NULL) { - free(buffer); - return NULL; - } - buffer = newbuffer; - size = newsize; - memcpy(buffer + i, key, keylen); - i += keylen - 1; - j += 2; - break; - default: - buffer[i] = '%'; - j++; - break; - } + } else if (p[j] == '%') { + switch (p[j + 1]) { + case '%': + buffer[i] = '%'; + j += 2; + break; + case 's': + if (!key) { + free(buffer); + return NULL; + } + keylen = strlen(key); + if (!keylen) { + j += 2; + break; + } + newsize = size + keylen; + if ((newbuffer = realloc(buffer, newsize)) == NULL) { + free(buffer); + return NULL; + } + buffer = newbuffer; + size = newsize; + memcpy(buffer + i, key, keylen); + i += keylen - 1; + j += 2; + break; + default: + buffer[i] = '%'; + j++; + break; + } } else { - buffer[i] = cp[j]; + buffer[i] = p[j]; j++; } } @@ -1300,6 +1434,9 @@ aldap_get_errno(struct aldap *a, const char **estr) case ALDAP_ERR_OPERATION_FAILED: *estr = "operation failed"; break; + case ALDAP_ERR_TLS_ERROR: + *estr = tls_error(a->tls); + break; default: *estr = "unknown"; break; diff --git a/extras/tables/table-ldap/aldap.h b/extras/tables/table-ldap/aldap.h index c1020dd..e297faa 100644 --- a/extras/tables/table-ldap/aldap.h +++ b/extras/tables/table-ldap/aldap.h @@ -1,3 +1,5 @@ +/* $OpenBSD: aldap.h,v 1.4 2019/05/11 17:46:02 rob Exp $ */ + /* * Copyright (c) 2008 Alexander Schrijver <aschrij...@openbsd.org> * Copyright (c) 2006, 2007 Marc Balmer <mbal...@openbsd.org> @@ -15,21 +17,34 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <ber.h> #include <stdio.h> -#include "ber.h" +#include <tls.h> + +#define LDAP_URL "ldap://" +#define LDAPS_URL "ldaps://" +#define LDAPTLS_URL "ldap+tls://" +#define LDAPI_URL "ldapi://" -#define LDAP_URL "ldap://" -#define LDAP_PORT "389" -#define LDAP_PAGED_OID "1.2.840.113556.1.4.319" +#define LDAP_PORT "389" +#define LDAPS_PORT "636" +#define LDAP_PAGED_OID "1.2.840.113556.1.4.319" +#define LDAP_STARTTLS_OID "1.3.6.1.4.1.1466.20037" struct aldap { #define ALDAP_ERR_SUCCESS 0 #define ALDAP_ERR_PARSER_ERROR 1 #define ALDAP_ERR_INVALID_FILTER 2 #define ALDAP_ERR_OPERATION_FAILED 3 - uint8_t err; +#define ALDAP_ERR_TLS_ERROR 4 + u_int8_t err; int msgid; struct ber ber; + + int fd; + struct tls *tls; + + struct evbuffer *buf; }; struct aldap_page_control { @@ -60,18 +75,25 @@ struct aldap_message { } search; } body; struct ber_element *references; - struct aldap_page_control *page; + struct aldap_page_control *page; }; enum aldap_protocol { LDAP, - LDAPS + LDAPS, + LDAPTLS, + LDAPI +}; + +struct aldap_stringset { + size_t len; + struct ber_octetstring *str; }; struct aldap_url { int protocol; char *host; - char *port; + char *port; char *dn; #define MAXATTR 1024 char *attributes[MAXATTR]; @@ -100,6 +122,9 @@ enum protocol_op { LDAP_REQ_ABANDON_30 = 16, LDAP_RES_SEARCH_REFERENCE = 19, + + LDAP_REQ_EXTENDED = 23, + LDAP_RES_EXTENDED = 24 }; enum deref_aliases { @@ -168,7 +193,7 @@ enum result_code { LDAP_OTHER = 80, }; -enum ldap_filter { +enum filter { LDAP_FILT_AND = 0, LDAP_FILT_OR = 1, LDAP_FILT_NOT = 2, @@ -180,17 +205,21 @@ enum ldap_filter { LDAP_FILT_APPR = 8, }; -enum ldap_subfilter { +enum subfilter { LDAP_FILT_SUBS_INIT = 0, LDAP_FILT_SUBS_ANY = 1, LDAP_FILT_SUBS_FIN = 2, }; -struct aldap *aldap_init(int fd); +struct aldap *aldap_init(int); +int aldap_tls(struct aldap *, struct tls_config *, + const char *); int aldap_close(struct aldap *); struct aldap_message *aldap_parse(struct aldap *); void aldap_freemsg(struct aldap_message *); +int aldap_req_starttls(struct aldap *); + int aldap_bind(struct aldap *, char *, char *); int aldap_unbind(struct aldap *); int aldap_search(struct aldap *, char *, enum scope, char *, const char *, char **, int, int, int, struct aldap_page_control *); @@ -199,19 +228,21 @@ int aldap_get_errno(struct aldap *, const char **); int aldap_get_resultcode(struct aldap_message *); char *aldap_get_dn(struct aldap_message *); char *aldap_get_diagmsg(struct aldap_message *); -char **aldap_get_references(struct aldap_message *); +struct aldap_stringset *aldap_get_references(struct aldap_message *); void aldap_free_references(char **values); int aldap_parse_url(const char *, struct aldap_url *); void aldap_free_url(struct aldap_url *); -#if 0 -int aldap_search_url(struct aldap *, char *, int, int, int); -#endif +int aldap_search_url(struct aldap *, char *, int, int, int, + struct aldap_page_control *); int aldap_count_attrs(struct aldap_message *); -int aldap_match_attr(struct aldap_message *, char *, char ***); -int aldap_first_attr(struct aldap_message *, char **, char ***); -int aldap_next_attr(struct aldap_message *, char **, char ***); -int aldap_free_attr(char **); +int aldap_match_attr(struct aldap_message *, char *, + struct aldap_stringset **); +int aldap_first_attr(struct aldap_message *, char **, struct + aldap_stringset **); +int aldap_next_attr(struct aldap_message *, char **, + struct aldap_stringset **); +int aldap_free_attr(struct aldap_stringset *); struct aldap_page_control *aldap_parse_page_control(struct ber_element *, size_t len); void aldap_freepage(struct aldap_page_control *); diff --git a/extras/tables/table-ldap/ber.c b/extras/tables/table-ldap/ber.c index 0f92bb2..3aebd14 100644 --- a/extras/tables/table-ldap/ber.c +++ b/extras/tables/table-ldap/ber.c @@ -1,5 +1,7 @@ +/* $OpenBSD: ber.c,v 1.26 2023/11/10 12:12:02 martijn Exp $ */ + /* - * Copyright (c) 2007 Reyk Floeter <r...@vantronix.net> + * Copyright (c) 2007, 2012 Reyk Floeter <r...@openbsd.org> * Copyright (c) 2006, 2007 Claudio Jeker <clau...@openbsd.org> * Copyright (c) 2006, 2007 Marc Balmer <mbal...@openbsd.org> * @@ -25,14 +27,13 @@ #include <stdlib.h> #include <err.h> /* XXX for debug output */ #include <stdio.h> /* XXX for debug output */ +#include <stdint.h> #include <string.h> #include <unistd.h> #include <stdarg.h> #include "ber.h" -#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) - #define BER_TYPE_CONSTRUCTED 0x20 /* otherwise primitive */ #define BER_TYPE_SINGLE_MAX 30 #define BER_TAG_MASK 0x1f @@ -40,17 +41,16 @@ #define BER_TAG_TYPE_MASK 0x7f #define BER_CLASS_SHIFT 6 -static int ber_dump_element(struct ber *ber, struct ber_element *root); -static void ber_dump_header(struct ber *ber, struct ber_element *root); -static void ber_putc(struct ber *ber, unsigned char c); -static void ber_write(struct ber *ber, void *buf, size_t len); -static ssize_t get_id(struct ber *b, unsigned long *tag, int *class, +static int ober_dump_element(struct ber *ber, struct ber_element *root); +static void ober_dump_header(struct ber *ber, struct ber_element *root); +static void ober_putc(struct ber *ber, u_char c); +static void ober_write(struct ber *ber, void *buf, size_t len); +static ssize_t get_id(struct ber *b, unsigned int *tag, int *class, int *cstruct); static ssize_t get_len(struct ber *b, ssize_t *len); -static ssize_t ber_read_element(struct ber *ber, struct ber_element *elm); -static ssize_t ber_readbuf(struct ber *b, void *buf, size_t nbytes); -static ssize_t ber_getc(struct ber *b, unsigned char *c); -static ssize_t ber_read(struct ber *ber, void *buf, size_t len); +static ssize_t ober_read_element(struct ber *ber, struct ber_element *elm); +static ssize_t ober_getc(struct ber *b, u_char *c); +static ssize_t ober_read(struct ber *ber, void *buf, size_t len); #ifdef DEBUG #define DPRINTF(...) printf(__VA_ARGS__) @@ -59,7 +59,7 @@ static ssize_t ber_read(struct ber *ber, void *buf, size_t len); #endif struct ber_element * -ber_get_element(unsigned long encoding) +ober_get_element(unsigned int encoding) { struct ber_element *elm; @@ -67,13 +67,13 @@ ber_get_element(unsigned long encoding) return NULL; elm->be_encoding = encoding; - ber_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT); + ober_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT); return elm; } void -ber_set_header(struct ber_element *elm, int class, unsigned long type) +ober_set_header(struct ber_element *elm, int class, unsigned int type) { elm->be_class = class & BER_CLASS_MASK; if (type == BER_TYPE_DEFAULT) @@ -82,7 +82,7 @@ ber_set_header(struct ber_element *elm, int class, unsigned long type) } void -ber_link_elements(struct ber_element *prev, struct ber_element *elm) +ober_link_elements(struct ber_element *prev, struct ber_element *elm) { if (prev != NULL) { if ((prev->be_encoding == BER_TYPE_SEQUENCE || @@ -95,7 +95,7 @@ ber_link_elements(struct ber_element *prev, struct ber_element *elm) } struct ber_element * -ber_unlink_elements(struct ber_element *prev) +ober_unlink_elements(struct ber_element *prev) { struct ber_element *elm; @@ -113,53 +113,53 @@ ber_unlink_elements(struct ber_element *prev) } void -ber_replace_elements(struct ber_element *prev, struct ber_element *new) +ober_replace_elements(struct ber_element *prev, struct ber_element *new) { struct ber_element *ber, *next; - ber = ber_unlink_elements(prev); - next = ber_unlink_elements(ber); - ber_link_elements(new, next); - ber_link_elements(prev, new); + ber = ober_unlink_elements(prev); + next = ober_unlink_elements(ber); + ober_link_elements(new, next); + ober_link_elements(prev, new); /* cleanup old element */ - ber_free_elements(ber); + ober_free_elements(ber); } struct ber_element * -ber_add_sequence(struct ber_element *prev) +ober_add_sequence(struct ber_element *prev) { struct ber_element *elm; - if ((elm = ber_get_element(BER_TYPE_SEQUENCE)) == NULL) + if ((elm = ober_get_element(BER_TYPE_SEQUENCE)) == NULL) return NULL; - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return elm; } struct ber_element * -ber_add_set(struct ber_element *prev) +ober_add_set(struct ber_element *prev) { struct ber_element *elm; - if ((elm = ber_get_element(BER_TYPE_SET)) == NULL) + if ((elm = ober_get_element(BER_TYPE_SET)) == NULL) return NULL; - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return elm; } struct ber_element * -ber_add_enumerated(struct ber_element *prev, long long val) +ober_add_enumerated(struct ber_element *prev, long long val) { struct ber_element *elm; - unsigned int i, len = 0; - unsigned char cur, last = 0; + u_int i, len = 0; + u_char cur, last = 0; - if ((elm = ber_get_element(BER_TYPE_ENUMERATED)) == NULL) + if ((elm = ober_get_element(BER_TYPE_ENUMERATED)) == NULL) return NULL; elm->be_numeric = val; @@ -176,19 +176,19 @@ ber_add_enumerated(struct ber_element *prev, long long val) } elm->be_len = len + 1; - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return elm; } struct ber_element * -ber_add_integer(struct ber_element *prev, long long val) +ober_add_integer(struct ber_element *prev, long long val) { struct ber_element *elm; - unsigned int i, len = 0; - unsigned char cur, last = 0; + u_int i, len = 0; + u_char cur, last = 0; - if ((elm = ber_get_element(BER_TYPE_INTEGER)) == NULL) + if ((elm = ober_get_element(BER_TYPE_INTEGER)) == NULL) return NULL; elm->be_numeric = val; @@ -205,157 +205,196 @@ ber_add_integer(struct ber_element *prev, long long val) } elm->be_len = len + 1; - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return elm; } int -ber_get_integer(struct ber_element *elm, long long *n) +ober_get_integer(struct ber_element *elm, long long *n) { if (elm->be_encoding != BER_TYPE_INTEGER) return -1; - *n = elm->be_numeric; + if (n != NULL) + *n = elm->be_numeric; return 0; } int -ber_get_enumerated(struct ber_element *elm, long long *n) +ober_get_enumerated(struct ber_element *elm, long long *n) { if (elm->be_encoding != BER_TYPE_ENUMERATED) return -1; - *n = elm->be_numeric; + if (n != NULL) + *n = elm->be_numeric; return 0; } - struct ber_element * -ber_add_boolean(struct ber_element *prev, int boolean) +ober_add_boolean(struct ber_element *prev, int bool) { struct ber_element *elm; - if ((elm = ber_get_element(BER_TYPE_BOOLEAN)) == NULL) + if ((elm = ober_get_element(BER_TYPE_BOOLEAN)) == NULL) return NULL; - elm->be_numeric = boolean ? 0xff : 0; + elm->be_numeric = bool ? 0xff : 0; elm->be_len = 1; - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return elm; } int -ber_get_boolean(struct ber_element *elm, int *b) +ober_get_boolean(struct ber_element *elm, int *b) { if (elm->be_encoding != BER_TYPE_BOOLEAN) return -1; - *b = !(elm->be_numeric == 0); + if (b != NULL) + *b = !(elm->be_numeric == 0); return 0; } struct ber_element * -ber_add_string(struct ber_element *prev, const char *string) +ober_add_string(struct ber_element *prev, const char *string) { - return ber_add_nstring(prev, string, strlen(string)); + return ober_add_nstring(prev, string, strlen(string)); } struct ber_element * -ber_add_nstring(struct ber_element *prev, const char *string0, size_t len) +ober_add_nstring(struct ber_element *prev, const char *string0, size_t len) { struct ber_element *elm; char *string; - if ((string = calloc(1, len)) == NULL) + if ((string = calloc(1, len + 1)) == NULL) return NULL; - if ((elm = ber_get_element(BER_TYPE_OCTETSTRING)) == NULL) { + if ((elm = ober_get_element(BER_TYPE_OCTETSTRING)) == NULL) { free(string); return NULL; } - memmove(string, string0, len); + bcopy(string0, string, len); elm->be_val = string; elm->be_len = len; elm->be_free = 1; /* free string on cleanup */ - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return elm; } +struct ber_element * +ober_add_ostring(struct ber_element *prev, struct ber_octetstring *s) +{ + return ober_add_nstring(prev, s->ostr_val, s->ostr_len); +} + +int +ober_get_string(struct ber_element *elm, char **s) +{ + if (elm->be_encoding != BER_TYPE_OCTETSTRING) + return -1; + /* XXX some components use getstring on binary data containing \0 */ +#if 0 + if (memchr(elm->be_val, '\0', elm->be_len) != NULL) + return -1; +#endif + + if (s != NULL) + *s = elm->be_val; + return 0; +} + int -ber_get_string(struct ber_element *elm, char **s) +ober_get_nstring(struct ber_element *elm, void **p, size_t *len) { if (elm->be_encoding != BER_TYPE_OCTETSTRING) return -1; - *s = elm->be_val; + if (len != NULL) + *len = elm->be_len; + if (p != NULL) { + if (len != NULL) + *p = elm->be_val; + else + *p = NULL; + } return 0; } int -ber_get_nstring(struct ber_element *elm, void **p, size_t *len) +ober_get_ostring(struct ber_element *elm, struct ber_octetstring *s) { if (elm->be_encoding != BER_TYPE_OCTETSTRING) return -1; - *p = elm->be_val; - *len = elm->be_len; + if (s != NULL) { + s->ostr_val = elm->be_val; + s->ostr_len = elm->be_len; + } return 0; } struct ber_element * -ber_add_bitstring(struct ber_element *prev, const void *v0, size_t len) +ober_add_bitstring(struct ber_element *prev, const void *v0, size_t len) { struct ber_element *elm; void *v; if ((v = calloc(1, len)) == NULL) return NULL; - if ((elm = ber_get_element(BER_TYPE_BITSTRING)) == NULL) { + if ((elm = ober_get_element(BER_TYPE_BITSTRING)) == NULL) { free(v); return NULL; } - memmove(v, v0, len); + bcopy(v0, v, len); elm->be_val = v; elm->be_len = len; elm->be_free = 1; /* free string on cleanup */ - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return elm; } int -ber_get_bitstring(struct ber_element *elm, void **v, size_t *len) +ober_get_bitstring(struct ber_element *elm, void **v, size_t *len) { if (elm->be_encoding != BER_TYPE_BITSTRING) return -1; - *v = elm->be_val; - *len = elm->be_len; + if (len != NULL) + *len = elm->be_len; + if (v != NULL) { + if (len != NULL) + *v = elm->be_val; + else + *v = NULL; + } return 0; } struct ber_element * -ber_add_null(struct ber_element *prev) +ober_add_null(struct ber_element *prev) { struct ber_element *elm; - if ((elm = ber_get_element(BER_TYPE_NULL)) == NULL) + if ((elm = ober_get_element(BER_TYPE_NULL)) == NULL) return NULL; - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return elm; } int -ber_get_null(struct ber_element *elm) +ober_get_null(struct ber_element *elm) { if (elm->be_encoding != BER_TYPE_NULL) return -1; @@ -364,20 +403,20 @@ ber_get_null(struct ber_element *elm) } struct ber_element * -ber_add_eoc(struct ber_element *prev) +ober_add_eoc(struct ber_element *prev) { struct ber_element *elm; - if ((elm = ber_get_element(BER_TYPE_EOC)) == NULL) + if ((elm = ober_get_element(BER_TYPE_EOC)) == NULL) return NULL; - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return elm; } int -ber_get_eoc(struct ber_element *elm) +ober_get_eoc(struct ber_element *elm) { if (elm->be_encoding != BER_TYPE_EOC) return -1; @@ -386,10 +425,10 @@ ber_get_eoc(struct ber_element *elm) } size_t -ber_oid2ber(struct ber_oid *o, uint8_t *buf, size_t len) +ober_oid2ber(struct ber_oid *o, u_int8_t *buf, size_t len) { - uint32_t v; - unsigned int i, j = 0, k; + u_int32_t v; + u_int i, j = 0, k; if (o->bo_n < BER_MIN_OID_LEN || o->bo_n > BER_MAX_OID_LEN || o->bo_id[0] > 2 || o->bo_id[1] > 40) @@ -398,7 +437,7 @@ ber_oid2ber(struct ber_oid *o, uint8_t *buf, size_t len) v = (o->bo_id[0] * 40) + o->bo_id[1]; for (i = 2, j = 0; i <= o->bo_n; v = o->bo_id[i], i++) { for (k = 28; k >= 7; k -= 7) { - if (v >= (unsigned int)(1 << k)) { + if (v >= (u_int)(1 << k)) { if (len) buf[j] = v >> k | BER_TAG_MORE; j++; @@ -413,7 +452,7 @@ ber_oid2ber(struct ber_oid *o, uint8_t *buf, size_t len) } int -ber_string2oid(const char *oidstr, struct ber_oid *o) +ober_string2oid(const char *oidstr, struct ber_oid *o) { char *sp, *p, str[BUFSIZ]; const char *errstr; @@ -434,17 +473,38 @@ ber_string2oid(const char *oidstr, struct ber_oid *o) return (0); } +int +ober_oid_cmp(struct ber_oid *a, struct ber_oid *b) +{ + size_t i, min; + + min = a->bo_n < b->bo_n ? a->bo_n : b->bo_n; + for (i = 0; i < min; i++) { + if (a->bo_id[i] < b->bo_id[i]) + return (-1); + if (a->bo_id[i] > b->bo_id[i]) + return (1); + } + /* a is parent of b */ + if (a->bo_n < b->bo_n) + return (-2); + /* a is child of b */ + if (a->bo_n > b->bo_n) + return 2; + return (0); +} + struct ber_element * -ber_add_oid(struct ber_element *prev, struct ber_oid *o) +ober_add_oid(struct ber_element *prev, struct ber_oid *o) { struct ber_element *elm; - uint8_t *buf; + u_int8_t *buf; size_t len; - if ((elm = ber_get_element(BER_TYPE_OBJECT)) == NULL) + if ((elm = ober_get_element(BER_TYPE_OBJECT)) == NULL) return (NULL); - if ((len = ber_oid2ber(o, NULL, 0)) == 0) + if ((len = ober_oid2ber(o, NULL, 0)) == 0) goto fail; if ((buf = calloc(1, len)) == NULL) @@ -454,57 +514,57 @@ ber_add_oid(struct ber_element *prev, struct ber_oid *o) elm->be_len = len; elm->be_free = 1; - if (ber_oid2ber(o, buf, len) != len) + if (ober_oid2ber(o, buf, len) != len) goto fail; - ber_link_elements(prev, elm); + ober_link_elements(prev, elm); return (elm); fail: - ber_free_elements(elm); + ober_free_elements(elm); return (NULL); } struct ber_element * -ber_add_noid(struct ber_element *prev, struct ber_oid *o, int n) +ober_add_noid(struct ber_element *prev, struct ber_oid *o, int n) { struct ber_oid no; if (n > BER_MAX_OID_LEN) return (NULL); no.bo_n = n; - memmove(&no.bo_id, &o->bo_id, sizeof(no.bo_id)); + bcopy(&o->bo_id, &no.bo_id, sizeof(no.bo_id)); - return (ber_add_oid(prev, &no)); + return (ober_add_oid(prev, &no)); } struct ber_element * -ber_add_oidstring(struct ber_element *prev, const char *oidstr) +ober_add_oidstring(struct ber_element *prev, const char *oidstr) { struct ber_oid o; - if (ber_string2oid(oidstr, &o) == -1) + if (ober_string2oid(oidstr, &o) == -1) return (NULL); - return (ber_add_oid(prev, &o)); + return (ober_add_oid(prev, &o)); } int -ber_get_oid(struct ber_element *elm, struct ber_oid *o) +ober_get_oid(struct ber_element *elm, struct ber_oid *o) { - uint8_t *buf; + u_int8_t *buf; size_t len, i = 0, j = 0; if (elm->be_encoding != BER_TYPE_OBJECT) return (-1); + if (o == NULL) + return 0; + buf = elm->be_val; len = elm->be_len; - if (!buf[i]) - return (-1); - memset(o, 0, sizeof(*o)); o->bo_id[j++] = buf[i] / 40; o->bo_id[j++] = buf[i++] % 40; @@ -519,122 +579,139 @@ ber_get_oid(struct ber_element *elm, struct ber_oid *o) return (0); } +#define _MAX_SEQ 128 struct ber_element * -ber_printf_elements(struct ber_element *ber, char *fmt, ...) +ober_printf_elements(struct ber_element *ber, char *fmt, ...) { va_list ap; - int d, class; + int d, class, level = 0; size_t len; - unsigned long type; + unsigned int type; long long i; char *s; void *p; struct ber_oid *o; - struct ber_element *sub = ber, *e; + struct ber_element *parent[_MAX_SEQ], *e; + struct ber_element *origber = ber, *firstber = NULL; + + memset(parent, 0, sizeof(struct ber_element *) * _MAX_SEQ); va_start(ap, fmt); + while (*fmt) { switch (*fmt++) { case 'B': p = va_arg(ap, void *); len = va_arg(ap, size_t); - if ((ber = ber_add_bitstring(ber, p, len)) == NULL) + if ((ber = ober_add_bitstring(ber, p, len)) == NULL) goto fail; break; case 'b': d = va_arg(ap, int); - if ((ber = ber_add_boolean(ber, d)) == NULL) + if ((ber = ober_add_boolean(ber, d)) == NULL) goto fail; break; case 'd': d = va_arg(ap, int); - if ((ber = ber_add_integer(ber, d)) == NULL) + if ((ber = ober_add_integer(ber, d)) == NULL) goto fail; break; case 'e': e = va_arg(ap, struct ber_element *); - ber_link_elements(ber, e); + ober_link_elements(ber, e); break; case 'E': i = va_arg(ap, long long); - if ((ber = ber_add_enumerated(ber, i)) == NULL) + if ((ber = ober_add_enumerated(ber, i)) == NULL) goto fail; break; case 'i': i = va_arg(ap, long long); - if ((ber = ber_add_integer(ber, i)) == NULL) + if ((ber = ober_add_integer(ber, i)) == NULL) goto fail; break; case 'O': o = va_arg(ap, struct ber_oid *); - if ((ber = ber_add_oid(ber, o)) == NULL) + if ((ber = ober_add_oid(ber, o)) == NULL) goto fail; break; case 'o': s = va_arg(ap, char *); - if ((ber = ber_add_oidstring(ber, s)) == NULL) + if ((ber = ober_add_oidstring(ber, s)) == NULL) goto fail; break; case 's': s = va_arg(ap, char *); - if ((ber = ber_add_string(ber, s)) == NULL) + if ((ber = ober_add_string(ber, s)) == NULL) goto fail; break; case 't': class = va_arg(ap, int); - type = va_arg(ap, unsigned long); - ber_set_header(ber, class, type); + type = va_arg(ap, unsigned int); + ober_set_header(ber, class, type); break; case 'x': s = va_arg(ap, char *); len = va_arg(ap, size_t); - if ((ber = ber_add_nstring(ber, s, len)) == NULL) + if ((ber = ober_add_nstring(ber, s, len)) == NULL) goto fail; break; case '0': - if ((ber = ber_add_null(ber)) == NULL) + if ((ber = ober_add_null(ber)) == NULL) goto fail; break; case '{': - if ((ber = sub = ber_add_sequence(ber)) == NULL) + if (level >= _MAX_SEQ-1) + goto fail; + if ((ber= ober_add_sequence(ber)) == NULL) goto fail; + parent[level++] = ber; break; case '(': - if ((ber = sub = ber_add_set(ber)) == NULL) + if (level >= _MAX_SEQ-1) + goto fail; + if ((ber = ober_add_set(ber)) == NULL) goto fail; + parent[level++] = ber; break; case '}': case ')': - ber = sub; + if (level <= 0 || parent[level - 1] == NULL) + goto fail; + ber = parent[--level]; break; case '.': - if ((e = ber_add_eoc(ber)) == NULL) + if ((e = ober_add_eoc(ber)) == NULL) goto fail; ber = e; break; default: break; } + if (firstber == NULL) + firstber = ber; } va_end(ap); return (ber); fail: - ber_free_elements(ber); + if (origber != NULL) + ober_unlink_elements(origber); + ober_free_elements(firstber); return (NULL); } int -ber_scanf_elements(struct ber_element *ber, char *fmt, ...) +ober_scanf_elements(struct ber_element *ber, char *fmt, ...) { -#define _MAX_SEQ 128 va_list ap; int *d, level = -1; - unsigned long *t; - long long *i; + unsigned int *t; + long long *i, l; void **ptr; size_t *len, ret = 0, n = strlen(fmt); char **s; + off_t *pos; struct ber_oid *o; struct ber_element *parent[_MAX_SEQ], **e; @@ -642,20 +719,35 @@ ber_scanf_elements(struct ber_element *ber, char *fmt, ...) va_start(ap, fmt); while (*fmt) { + if (ber == NULL && *fmt != '$' && *fmt != '}' && *fmt != ')') + goto fail; switch (*fmt++) { + case '$': + if (ber != NULL) + goto fail; + ret++; + continue; case 'B': ptr = va_arg(ap, void **); len = va_arg(ap, size_t *); - if (ber_get_bitstring(ber, ptr, len) == -1) + if (ober_get_bitstring(ber, ptr, len) == -1) goto fail; ret++; break; case 'b': d = va_arg(ap, int *); - if (ber_get_boolean(ber, d) == -1) + if (ober_get_boolean(ber, d) == -1) goto fail; ret++; break; + case 'd': + d = va_arg(ap, int *); + if (ober_get_integer(ber, &l) == -1) + goto fail; + if (d != NULL) + *d = l; + ret++; + break; case 'e': e = va_arg(ap, struct ber_element **); *e = ber; @@ -663,19 +755,19 @@ ber_scanf_elements(struct ber_element *ber, char *fmt, ...) continue; case 'E': i = va_arg(ap, long long *); - if (ber_get_enumerated(ber, i) == -1) + if (ober_get_enumerated(ber, i) == -1) goto fail; ret++; break; case 'i': i = va_arg(ap, long long *); - if (ber_get_integer(ber, i) == -1) + if (ober_get_integer(ber, i) == -1) goto fail; ret++; break; case 'o': o = va_arg(ap, struct ber_oid *); - if (ber_get_oid(ber, o) == -1) + if (ober_get_oid(ber, o) == -1) goto fail; ret++; break; @@ -684,21 +776,23 @@ ber_scanf_elements(struct ber_element *ber, char *fmt, ...) break; case 's': s = va_arg(ap, char **); - if (ber_get_string(ber, s) == -1) + if (ober_get_string(ber, s) == -1) goto fail; ret++; break; case 't': d = va_arg(ap, int *); - t = va_arg(ap, unsigned long *); - *d = ber->be_class; - *t = ber->be_type; + t = va_arg(ap, unsigned int *); + if (d != NULL) + *d = ber->be_class; + if (t != NULL) + *t = ber->be_type; ret++; continue; case 'x': ptr = va_arg(ap, void **); len = va_arg(ap, size_t *); - if (ber_get_nstring(ber, ptr, len) == -1) + if (ober_get_nstring(ber, ptr, len) == -1) goto fail; ret++; break; @@ -712,12 +806,17 @@ ber_scanf_elements(struct ber_element *ber, char *fmt, ...) goto fail; ret++; break; + case 'p': + pos = va_arg(ap, off_t *); + *pos = ober_getpos(ber); + ret++; + continue; case '{': case '(': if (ber->be_encoding != BER_TYPE_SEQUENCE && ber->be_encoding != BER_TYPE_SET) goto fail; - if (ber->be_sub == NULL || level >= _MAX_SEQ-1) + if (level >= _MAX_SEQ-1) goto fail; parent[++level] = ber; ber = ber->be_sub; @@ -725,17 +824,15 @@ ber_scanf_elements(struct ber_element *ber, char *fmt, ...) continue; case '}': case ')': - if (parent[level] == NULL) + if (level < 0 || parent[level] == NULL) goto fail; ber = parent[level--]; ret++; - continue; + break; default: goto fail; } - if (ber->be_next == NULL) - continue; ber = ber->be_next; } va_end(ap); @@ -747,24 +844,33 @@ ber_scanf_elements(struct ber_element *ber, char *fmt, ...) } +ssize_t +ober_get_writebuf(struct ber *b, void **buf) +{ + if (b->br_wbuf == NULL) + return -1; + *buf = b->br_wbuf; + return (b->br_wend - b->br_wbuf); +} + /* - * write ber elements to the socket + * write ber elements to the write buffer * * params: - * ber holds the socket + * ber holds the destination write buffer byte stream * root fully populated element tree * * returns: - * >=0 number of bytes written + * >=0 number of bytes written * -1 on failure and sets errno */ -int -ber_write_elements(struct ber *ber, struct ber_element *root) +ssize_t +ober_write_elements(struct ber *ber, struct ber_element *root) { size_t len; /* calculate length because only the definite form is required */ - len = ber_calc_len(root); + len = ober_calc_len(root); DPRINTF("write ber element of %zd bytes length\n", len); if (ber->br_wbuf != NULL && ber->br_wbuf + len > ber->br_wend) { @@ -780,21 +886,24 @@ ber_write_elements(struct ber *ber, struct ber_element *root) /* reset write pointer */ ber->br_wptr = ber->br_wbuf; - if (ber_dump_element(ber, root) == -1) + if (ober_dump_element(ber, root) == -1) return -1; - /* XXX this should be moved to a different function */ - if (ber->fd != -1) - return write(ber->fd, ber->br_wbuf, len); - return (len); } +void +ober_set_readbuf(struct ber *b, void *buf, size_t len) +{ + b->br_rbuf = b->br_rptr = buf; + b->br_rend = (u_int8_t *)buf + len; +} + /* - * read ber elements from the socket + * read ber elements from the read buffer * * params: - * ber holds the socket and lot more + * ber holds a fully populated read buffer byte stream * root if NULL, build up an element tree from what we receive on * the wire. If not null, use the specified encoding for the * elements received. @@ -804,35 +913,93 @@ ber_write_elements(struct ber *ber, struct ber_element *root) * NULL, type mismatch or read error */ struct ber_element * -ber_read_elements(struct ber *ber, struct ber_element *elm) +ober_read_elements(struct ber *ber, struct ber_element *elm) { struct ber_element *root = elm; if (root == NULL) { - if ((root = ber_get_element(0)) == NULL) + if ((root = ober_get_element(0)) == NULL) return NULL; } DPRINTF("read ber elements, root %p\n", root); - if (ber_read_element(ber, root) == -1) { + if (ober_read_element(ber, root) == -1) { /* Cleanup if root was allocated by us */ if (elm == NULL) - ber_free_elements(root); + ober_free_elements(root); return NULL; } return root; } +off_t +ober_getpos(struct ber_element *elm) +{ + return elm->be_offs; +} + +struct ber_element * +ober_dup(struct ber_element *orig) +{ + struct ber_element *new; + + if ((new = malloc(sizeof(*new))) == NULL) + return NULL; + memcpy(new, orig, sizeof(*new)); + new->be_next = NULL; + new->be_sub = NULL; + + if (orig->be_next != NULL) { + if ((new->be_next = ober_dup(orig->be_next)) == NULL) + goto fail; + } + if (orig->be_encoding == BER_TYPE_SEQUENCE || + orig->be_encoding == BER_TYPE_SET) { + if (orig->be_sub != NULL) { + if ((new->be_sub = ober_dup(orig->be_sub)) == NULL) + goto fail; + } + } else if (orig->be_encoding == BER_TYPE_OCTETSTRING || + orig->be_encoding == BER_TYPE_BITSTRING || + orig->be_encoding == BER_TYPE_OBJECT) { + if (orig->be_val != NULL) { + if ((new->be_val = malloc(orig->be_len)) == NULL) + goto fail; + memcpy(new->be_val, orig->be_val, orig->be_len); + } + } else + new->be_numeric = orig->be_numeric; + return new; + fail: + ober_free_elements(new); + return NULL; +} + +void +ober_free_element(struct ber_element *root) +{ + if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE || + root->be_encoding == BER_TYPE_SET)) + ober_free_elements(root->be_sub); + if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING || + root->be_encoding == BER_TYPE_BITSTRING || + root->be_encoding == BER_TYPE_OBJECT)) + free(root->be_val); + free(root); +} + void -ber_free_elements(struct ber_element *root) +ober_free_elements(struct ber_element *root) { + if (root == NULL) + return; if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE || root->be_encoding == BER_TYPE_SET)) - ber_free_elements(root->be_sub); + ober_free_elements(root->be_sub); if (root->be_next) - ber_free_elements(root->be_next); + ober_free_elements(root->be_next); if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING || root->be_encoding == BER_TYPE_BITSTRING || root->be_encoding == BER_TYPE_OBJECT)) @@ -841,16 +1008,16 @@ ber_free_elements(struct ber_element *root) } size_t -ber_calc_len(struct ber_element *root) +ober_calc_len(struct ber_element *root) { - unsigned long t; + unsigned int t; size_t s; size_t size = 2; /* minimum 1 byte head and 1 byte size */ /* calculate the real length of a sequence or set */ if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE || root->be_encoding == BER_TYPE_SET)) - root->be_len = ber_calc_len(root->be_sub); + root->be_len = ober_calc_len(root->be_sub); /* fix header length for extended types */ if (root->be_type > BER_TYPE_SINGLE_MAX) @@ -862,27 +1029,50 @@ ber_calc_len(struct ber_element *root) /* calculate the length of the following elements */ if (root->be_next) - size += ber_calc_len(root->be_next); + size += ober_calc_len(root->be_next); /* This is an empty element, do not use a minimal size */ - if (root->be_type == BER_TYPE_EOC && root->be_len == 0) + if (root->be_class == BER_CLASS_UNIVERSAL && + root->be_type == BER_TYPE_EOC && root->be_len == 0) return (0); return (root->be_len + size); } +void +ober_set_application(struct ber *b, unsigned int (*cb)(struct ber_element *)) +{ + b->br_application = cb; +} + +void +ober_set_writecallback(struct ber_element *elm, void (*cb)(void *, size_t), + void *arg) +{ + elm->be_cb = cb; + elm->be_cbarg = arg; +} + +void +ober_free(struct ber *b) +{ + free(b->br_wbuf); +} + /* * internal functions */ static int -ber_dump_element(struct ber *ber, struct ber_element *root) +ober_dump_element(struct ber *ber, struct ber_element *root) { unsigned long long l; int i; uint8_t u; - ber_dump_header(ber, root); + ober_dump_header(ber, root); + if (root->be_cb) + root->be_cb(root->be_cbarg, ber->br_wptr - ber->br_wbuf); switch (root->be_encoding) { case BER_TYPE_BOOLEAN: @@ -891,35 +1081,34 @@ ber_dump_element(struct ber *ber, struct ber_element *root) l = (unsigned long long)root->be_numeric; for (i = root->be_len; i > 0; i--) { u = (l >> ((i - 1) * 8)) & 0xff; - ber_putc(ber, u); + ober_putc(ber, u); } break; case BER_TYPE_BITSTRING: - return -1; case BER_TYPE_OCTETSTRING: case BER_TYPE_OBJECT: - ber_write(ber, root->be_val, root->be_len); + ober_write(ber, root->be_val, root->be_len); break; case BER_TYPE_NULL: /* no payload */ case BER_TYPE_EOC: break; case BER_TYPE_SEQUENCE: case BER_TYPE_SET: - if (root->be_sub && ber_dump_element(ber, root->be_sub) == -1) + if (root->be_sub && ober_dump_element(ber, root->be_sub) == -1) return -1; break; } if (root->be_next == NULL) return 0; - return ber_dump_element(ber, root->be_next); + return ober_dump_element(ber, root->be_next); } static void -ber_dump_header(struct ber *ber, struct ber_element *root) +ober_dump_header(struct ber *ber, struct ber_element *root) { - unsigned char id = 0, t, buf[8]; - unsigned long type; + u_char id = 0, t, buf[5]; + unsigned int type; size_t size; /* class universal, type encoding depending on type value */ @@ -930,14 +1119,14 @@ ber_dump_header(struct ber *ber, struct ber_element *root) root->be_encoding == BER_TYPE_SET) id |= BER_TYPE_CONSTRUCTED; - ber_putc(ber, id); + ober_putc(ber, id); } else { id = BER_TAG_MASK | (root->be_class << BER_CLASS_SHIFT); if (root->be_encoding == BER_TYPE_SEQUENCE || root->be_encoding == BER_TYPE_SET) id |= BER_TYPE_CONSTRUCTED; - ber_putc(ber, id); + ober_putc(ber, id); for (t = 0, type = root->be_type; type > 0; type >>= 7) buf[t++] = type & ~BER_TAG_MORE; @@ -945,26 +1134,26 @@ ber_dump_header(struct ber *ber, struct ber_element *root) while (t-- > 0) { if (t > 0) buf[t] |= BER_TAG_MORE; - ber_putc(ber, buf[t]); + ober_putc(ber, buf[t]); } } if (root->be_len < BER_TAG_MORE) { /* short form */ - ber_putc(ber, root->be_len); + ober_putc(ber, root->be_len); } else { for (t = 0, size = root->be_len; size > 0; size >>= 8) buf[t++] = size & 0xff; - ber_putc(ber, t | BER_TAG_MORE); + ober_putc(ber, t | BER_TAG_MORE); while (t > 0) - ber_putc(ber, buf[--t]); + ober_putc(ber, buf[--t]); } } static void -ber_putc(struct ber *ber, unsigned char c) +ober_putc(struct ber *ber, u_char c) { if (ber->br_wptr + 1 <= ber->br_wend) *ber->br_wptr = c; @@ -972,11 +1161,10 @@ ber_putc(struct ber *ber, unsigned char c) } static void -ber_write(struct ber *ber, void *buf, size_t len) +ober_write(struct ber *ber, void *buf, size_t len) { if (ber->br_wptr + len <= ber->br_wend) - memmove(ber->br_wptr, buf, len); - + bcopy(buf, ber->br_wptr, len); ber->br_wptr += len; } @@ -984,13 +1172,13 @@ ber_write(struct ber *ber, void *buf, size_t len) * extract a BER encoded tag. There are two types, a short and long form. */ static ssize_t -get_id(struct ber *b, unsigned long *tag, int *class, int *cstruct) +get_id(struct ber *b, unsigned int *tag, int *class, int *cstruct) { - unsigned char u; + u_char u; size_t i = 0; - unsigned long t = 0; + unsigned int t = 0; - if (ber_getc(b, &u) == -1) + if (ober_getc(b, &u) == -1) return -1; *class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK; @@ -1002,17 +1190,23 @@ get_id(struct ber *b, unsigned long *tag, int *class, int *cstruct) } do { - if (ber_getc(b, &u) == -1) + if (ober_getc(b, &u) == -1) return -1; + + /* enforce minimal number of octets for tag > 30 */ + if (i == 0 && (u & ~BER_TAG_MORE) == 0) { + errno = EINVAL; + return -1; + } + t = (t << 7) | (u & ~BER_TAG_MORE); i++; + if (i > sizeof(unsigned int)) { + errno = ERANGE; + return -1; + } } while (u & BER_TAG_MORE); - if (i > sizeof(unsigned long)) { - errno = ERANGE; - return -1; - } - *tag = t; return i + 1; } @@ -1023,10 +1217,10 @@ get_id(struct ber *b, unsigned long *tag, int *class, int *cstruct) static ssize_t get_len(struct ber *b, ssize_t *len) { - unsigned char u, n; + u_char u, n; ssize_t s, r; - if (ber_getc(b, &u) == -1) + if (ober_getc(b, &u) == -1) return -1; if ((u & BER_TAG_MORE) == 0) { /* short form */ @@ -1034,15 +1228,30 @@ get_len(struct ber *b, ssize_t *len) return 1; } + if (u == 0x80) { + /* Indefinite length not supported. */ + errno = EINVAL; + return -1; + } + + if (u == 0xff) { + /* Reserved for future use. */ + errno = EINVAL; + return -1; + } + n = u & ~BER_TAG_MORE; - if (sizeof(ssize_t) < n) { + /* + * Limit to a decent size that works on all of our architectures. + */ + if (sizeof(int32_t) < n) { errno = ERANGE; return -1; } r = n + 1; for (s = 0; n > 0; n--) { - if (ber_getc(b, &u) == -1) + if (ober_getc(b, &u) == -1) return -1; s = (s << 8) | u; } @@ -1053,38 +1262,52 @@ get_len(struct ber *b, ssize_t *len) return -1; } - if (s == 0) { - /* invalid encoding */ - errno = EINVAL; - return -1; - } - *len = s; return r; } static ssize_t -ber_read_element(struct ber *ber, struct ber_element *elm) +ober_read_element(struct ber *ber, struct ber_element *elm) { long long val = 0; struct ber_element *next; - unsigned long type; - int i, class, cstruct; + unsigned int type; + int i, class, cstruct, elements = 0; ssize_t len, r, totlen = 0; - unsigned char c; + u_char c, last = 0; if ((r = get_id(ber, &type, &class, &cstruct)) == -1) return -1; - DPRINTF("ber read got class %d type %lu, %s\n", - class, type, cstruct ? "constructive" : "primitive"); + DPRINTF("ber read got class %d type %u, %s\n", + class, type, cstruct ? "constructed" : "primitive"); totlen += r; if ((r = get_len(ber, &len)) == -1) return -1; DPRINTF("ber read element size %zd\n", len); totlen += r + len; + /* The encoding of boolean, integer, enumerated, and null values + * must be primitive. */ + if (class == BER_CLASS_UNIVERSAL) + if (type == BER_TYPE_BOOLEAN || + type == BER_TYPE_INTEGER || + type == BER_TYPE_ENUMERATED || + type == BER_TYPE_NULL) + if (cstruct) { + errno = EINVAL; + return -1; + } + + /* If the total size of the element is larger than the buffer + * don't bother to continue. */ + if (len > ber->br_rend - ber->br_rptr) { + errno = ECANCELED; + return -1; + } + elm->be_type = type; elm->be_len = len; + elm->be_offs = ber->br_offs; /* element position within stream */ elm->be_class = class; if (elm->be_encoding == 0) { @@ -1109,20 +1332,40 @@ ber_read_element(struct ber *ber, struct ber_element *elm) case BER_TYPE_EOC: /* End-Of-Content */ break; case BER_TYPE_BOOLEAN: + if (len != 1) { + errno = EINVAL; + return -1; + } case BER_TYPE_INTEGER: case BER_TYPE_ENUMERATED: - if (len > (ssize_t)sizeof(long long)) + if (len < 1) { + errno = EINVAL; return -1; + } + if (len > (ssize_t)sizeof(long long)) { + errno = ERANGE; + return -1; + } for (i = 0; i < len; i++) { - if (ber_getc(ber, &c) != 1) + if (ober_getc(ber, &c) != 1) return -1; + + /* smallest number of contents octets only */ + if ((i == 1 && last == 0 && (c & 0x80) == 0) || + (i == 1 && last == 0xff && (c & 0x80) != 0)) { + errno = EINVAL; + return -1; + } + val <<= 8; val |= c; + last = c; } /* sign extend if MSB is set */ - if (val >> ((i - 1) * 8) & 0x80) - val |= ULLONG_MAX << (i * 8); + if (len < (ssize_t)sizeof(long long) && + (val >> ((len - 1) * 8) & 0x80)) + val |= ULLONG_MAX << (len * 8); elm->be_numeric = val; break; case BER_TYPE_BITSTRING: @@ -1131,7 +1374,7 @@ ber_read_element(struct ber *ber, struct ber_element *elm) return -1; elm->be_free = 1; elm->be_len = len; - ber_read(ber, elm->be_val, len); + ober_read(ber, elm->be_val, len); break; case BER_TYPE_OCTETSTRING: case BER_TYPE_OBJECT: @@ -1140,28 +1383,47 @@ ber_read_element(struct ber *ber, struct ber_element *elm) return -1; elm->be_free = 1; elm->be_len = len; - ber_read(ber, elm->be_val, len); - ((unsigned char *)elm->be_val)[len] = '\0'; + ober_read(ber, elm->be_val, len); + ((u_char *)elm->be_val)[len] = '\0'; break; case BER_TYPE_NULL: /* no payload */ - if (len != 0) + if (len != 0) { + errno = EINVAL; return -1; + } break; case BER_TYPE_SEQUENCE: case BER_TYPE_SET: - if (elm->be_sub == NULL) { - if ((elm->be_sub = ber_get_element(0)) == NULL) + if (len > 0 && elm->be_sub == NULL) { + if ((elm->be_sub = ober_get_element(0)) == NULL) return -1; } next = elm->be_sub; while (len > 0) { - r = ber_read_element(ber, next); - if (r == -1) + /* + * Prevent stack overflow from excessive recursion + * depth in ober_free_elements(). + */ + if (elements >= BER_MAX_SEQ_ELEMENTS) { + errno = ERANGE; + return -1; + } + r = ober_read_element(ber, next); + if (r == -1) { + /* sub-element overflows sequence/set */ + if (errno == ECANCELED) + errno = EINVAL; return -1; + } + if (r > len) { + errno = EINVAL; + return -1; + } + elements++; len -= r; if (len > 0 && next->be_next == NULL) { - if ((next->be_next = ber_get_element(0)) == - NULL) + next->be_next = ober_get_element(0); + if (next->be_next == NULL) return -1; } next = next->be_next; @@ -1172,98 +1434,30 @@ ber_read_element(struct ber *ber, struct ber_element *elm) } static ssize_t -ber_readbuf(struct ber *b, void *buf, size_t nbytes) +ober_getc(struct ber *b, u_char *c) { - size_t sz; - size_t len; - - if (b->br_rbuf == NULL) - return -1; - - sz = b->br_rend - b->br_rptr; - len = MINIMUM(nbytes, sz); - if (len == 0) { - errno = ECANCELED; - return (-1); /* end of buffer and parser wants more data */ - } - - memmove(buf, b->br_rptr, len); - b->br_rptr += len; - - return (len); + return ober_read(b, c, 1); } -void -ber_set_readbuf(struct ber *b, void *buf, size_t len) +static ssize_t +ober_read(struct ber *ber, void *buf, size_t len) { - b->br_rbuf = b->br_rptr = buf; - b->br_rend = (uint8_t *)buf + len; -} + size_t sz; -ssize_t -ber_get_writebuf(struct ber *b, void **buf) -{ - if (b->br_wbuf == NULL) + if (ber->br_rbuf == NULL) { + errno = ENOBUFS; return -1; - *buf = b->br_wbuf; - return (b->br_wend - b->br_wbuf); -} - -void -ber_set_application(struct ber *b, unsigned long (*cb)(struct ber_element *)) -{ - b->br_application = cb; -} - -void -ber_free(struct ber *b) -{ - if (b->br_wbuf != NULL) - free (b->br_wbuf); -} - -static ssize_t -ber_getc(struct ber *b, unsigned char *c) -{ - ssize_t r; - /* - * XXX calling read here is wrong in many ways. The most obvious one - * being that we will block till data arrives. - * But for now it is _good enough_ *gulp* - */ - if (b->fd == -1) - r = ber_readbuf(b, c, 1); - else - r = read(b->fd, c, 1); - return r; -} + } -static ssize_t -ber_read(struct ber *ber, void *buf, size_t len) -{ - unsigned char *b = buf; - ssize_t r, remain = len; + sz = ber->br_rend - ber->br_rptr; + if (len > sz) { + errno = ECANCELED; + return -1; /* parser wants more data than available */ + } - /* - * XXX calling read here is wrong in many ways. The most obvious one - * being that we will block till data arrives. - * But for now it is _good enough_ *gulp* - */ + bcopy(ber->br_rptr, buf, len); + ber->br_rptr += len; + ber->br_offs += len; - while (remain > 0) { - if (ber->fd == -1) - r = ber_readbuf(ber, b, remain); - else - r = read(ber->fd, b, remain); - if (r == -1) { - if (errno == EINTR || errno == EAGAIN) - continue; - return -1; - } - if (r == 0) - return (b - (unsigned char *)buf); - b += r; - remain -= r; - } - return (b - (unsigned char *)buf); + return len; } diff --git a/extras/tables/table-ldap/ber.h b/extras/tables/table-ldap/ber.h index d656508..0bfdb07 100644 --- a/extras/tables/table-ldap/ber.h +++ b/extras/tables/table-ldap/ber.h @@ -1,5 +1,7 @@ +/* $OpenBSD: ber.h,v 1.5 2021/10/31 16:42:08 tb Exp $ */ + /* - * Copyright (c) 2007 Reyk Floeter <r...@vantronix.net> + * Copyright (c) 2007, 2012 Reyk Floeter <r...@openbsd.org> * Copyright (c) 2006, 2007 Claudio Jeker <clau...@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -15,13 +17,24 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifndef _BER_H +#define _BER_H + +struct ber_octetstring { + size_t ostr_len; + const void *ostr_val; +}; + struct ber_element { struct ber_element *be_next; - unsigned long be_type; - unsigned long be_encoding; + unsigned int be_type; + unsigned int be_encoding; size_t be_len; + off_t be_offs; int be_free; - uint8_t be_class; + u_int8_t be_class; + void (*be_cb)(void *, size_t); + void *be_cbarg; union { struct ber_element *bv_sub; void *bv_val; @@ -33,19 +46,19 @@ struct ber_element { }; struct ber { - int fd; - unsigned char *br_wbuf; - unsigned char *br_wptr; - unsigned char *br_wend; - unsigned char *br_rbuf; - unsigned char *br_rptr; - unsigned char *br_rend; + off_t br_offs; + u_char *br_wbuf; + u_char *br_wptr; + u_char *br_wend; + u_char *br_rbuf; + u_char *br_rptr; + u_char *br_rend; - unsigned long (*br_application)(struct ber_element *); + unsigned int (*br_application)(struct ber_element *); }; /* well-known ber_element types */ -#define BER_TYPE_DEFAULT ((unsigned long)-1) +#define BER_TYPE_DEFAULT ((unsigned int)-1) #define BER_TYPE_EOC 0 #define BER_TYPE_BOOLEAN 1 #define BER_TYPE_INTEGER 2 @@ -67,60 +80,74 @@ struct ber { #define BER_CLASS_MASK 0x3 /* common definitions */ -#define BER_MIN_OID_LEN 2 /* OBJECT */ -#define BER_MAX_OID_LEN 32 /* OBJECT */ +#define BER_MIN_OID_LEN 2 /* X.690 section 8.19.5 */ +#define BER_MAX_OID_LEN 128 /* RFC 2578 section 7.1.3 */ +#define BER_MAX_SEQ_ELEMENTS USHRT_MAX /* 65535 */ struct ber_oid { - uint32_t bo_id[BER_MAX_OID_LEN + 1]; + u_int32_t bo_id[BER_MAX_OID_LEN + 1]; size_t bo_n; }; __BEGIN_DECLS -struct ber_element *ber_get_element(unsigned long); -void ber_set_header(struct ber_element *, int, - unsigned long); -void ber_link_elements(struct ber_element *, +struct ber_element *ober_get_element(unsigned int); +void ober_set_header(struct ber_element *, int, + unsigned int); +void ober_link_elements(struct ber_element *, struct ber_element *); -struct ber_element *ber_unlink_elements(struct ber_element *); -void ber_replace_elements(struct ber_element *, +struct ber_element *ober_unlink_elements(struct ber_element *); +void ober_replace_elements(struct ber_element *, struct ber_element *); -struct ber_element *ber_add_sequence(struct ber_element *); -struct ber_element *ber_add_set(struct ber_element *); -struct ber_element *ber_add_integer(struct ber_element *, long long); -int ber_get_integer(struct ber_element *, long long *); -struct ber_element *ber_add_enumerated(struct ber_element *, long long); -int ber_get_enumerated(struct ber_element *, long long *); -struct ber_element *ber_add_boolean(struct ber_element *, int); -int ber_get_boolean(struct ber_element *, int *); -struct ber_element *ber_add_string(struct ber_element *, const char *); -struct ber_element *ber_add_nstring(struct ber_element *, const char *, +struct ber_element *ober_add_sequence(struct ber_element *); +struct ber_element *ober_add_set(struct ber_element *); +struct ber_element *ober_add_integer(struct ber_element *, long long); +int ober_get_integer(struct ber_element *, long long *); +struct ber_element *ober_add_enumerated(struct ber_element *, long long); +int ober_get_enumerated(struct ber_element *, long long *); +struct ber_element *ober_add_boolean(struct ber_element *, int); +int ober_get_boolean(struct ber_element *, int *); +struct ber_element *ober_add_string(struct ber_element *, const char *); +struct ber_element *ober_add_nstring(struct ber_element *, const char *, size_t); -int ber_get_string(struct ber_element *, char **); -int ber_get_nstring(struct ber_element *, void **, +struct ber_element *ober_add_ostring(struct ber_element *, + struct ber_octetstring *); +int ober_get_string(struct ber_element *, char **); +int ober_get_nstring(struct ber_element *, void **, size_t *); -struct ber_element *ber_add_bitstring(struct ber_element *, const void *, +int ober_get_ostring(struct ber_element *, + struct ber_octetstring *); +struct ber_element *ober_add_bitstring(struct ber_element *, const void *, size_t); -int ber_get_bitstring(struct ber_element *, void **, +int ober_get_bitstring(struct ber_element *, void **, size_t *); -struct ber_element *ber_add_null(struct ber_element *); -int ber_get_null(struct ber_element *); -struct ber_element *ber_add_eoc(struct ber_element *); -int ber_get_eoc(struct ber_element *); -struct ber_element *ber_add_oid(struct ber_element *, struct ber_oid *); -struct ber_element *ber_add_noid(struct ber_element *, struct ber_oid *, int); -struct ber_element *ber_add_oidstring(struct ber_element *, const char *); -int ber_get_oid(struct ber_element *, struct ber_oid *); -size_t ber_oid2ber(struct ber_oid *, uint8_t *, size_t); -int ber_string2oid(const char *, struct ber_oid *); -struct ber_element *ber_printf_elements(struct ber_element *, char *, ...); -int ber_scanf_elements(struct ber_element *, char *, ...); -ssize_t ber_get_writebuf(struct ber *, void **); -int ber_write_elements(struct ber *, struct ber_element *); -void ber_set_readbuf(struct ber *, void *, size_t); -struct ber_element *ber_read_elements(struct ber *, struct ber_element *); -void ber_free_elements(struct ber_element *); -size_t ber_calc_len(struct ber_element *); -void ber_set_application(struct ber *, - unsigned long (*)(struct ber_element *)); -void ber_free(struct ber *); +struct ber_element *ober_add_null(struct ber_element *); +int ober_get_null(struct ber_element *); +struct ber_element *ober_add_eoc(struct ber_element *); +int ober_get_eoc(struct ber_element *); +struct ber_element *ober_add_oid(struct ber_element *, struct ber_oid *); +struct ber_element *ober_add_noid(struct ber_element *, struct ber_oid *, int); +struct ber_element *ober_add_oidstring(struct ber_element *, const char *); +int ober_get_oid(struct ber_element *, struct ber_oid *); +size_t ober_oid2ber(struct ber_oid *, u_int8_t *, size_t); +int ober_string2oid(const char *, struct ber_oid *); +struct ber_element *ober_printf_elements(struct ber_element *, char *, ...); +int ober_scanf_elements(struct ber_element *, char *, ...); +ssize_t ober_get_writebuf(struct ber *, void **); +ssize_t ober_write_elements(struct ber *, struct ber_element *); +void ober_set_readbuf(struct ber *, void *, size_t); +struct ber_element *ober_read_elements(struct ber *, struct ber_element *); +off_t ober_getpos(struct ber_element *); +struct ber_element *ober_dup(struct ber_element *); +void ober_free_element(struct ber_element *); +void ober_free_elements(struct ber_element *); +size_t ober_calc_len(struct ber_element *); +void ober_set_application(struct ber *, + unsigned int (*)(struct ber_element *)); +void ober_set_writecallback(struct ber_element *, + void (*)(void *, size_t), void *); +void ober_free(struct ber *); +int ober_oid_cmp(struct ber_oid *, struct ber_oid *); + __END_DECLS + +#endif /* _BER_H */ diff --git a/extras/tables/table-ldap/table_ldap.c b/extras/tables/table-ldap/table_ldap.c index 64f99a8..76d2c90 100644 --- a/extras/tables/table-ldap/table_ldap.c +++ b/extras/tables/table-ldap/table_ldap.c @@ -59,7 +59,7 @@ enum { struct query { char *filter; char *attrs[MAX_ATTRS]; - int attrn; + size_t attrn; }; static int ldap_run_query(int type, const char *, char *, size_t); @@ -347,7 +347,7 @@ table_ldap_lookup(int service, struct dict *params, const char *key, char *dst, } static int -ldap_query(const char *filter, const char *key, char **attributes, char ***outp, size_t n) +ldap_query(const char *filter, const char *key, char **attributes, struct aldap_stringset **outp, size_t n) { struct aldap_message *m = NULL; struct aldap_page_control *pg = NULL; @@ -412,12 +412,36 @@ end: return ret; } +static size_t +ldap_strlcat(char *dst, const struct ber_octetstring str, size_t sz) +{ + size_t ret; + char *s = calloc(str.ostr_len + 1, sizeof(*s)); + if (!s) { + log_warn("can not allocate memory"); + return sz; + } + + if (strlcpy(s, str.ostr_val, str.ostr_len + 1) >= str.ostr_len + 1) { + ret = sz; + goto out; + } + ret = strlcat(dst, s, sz); + +out: + free(s); + return ret; +} + static int ldap_run_query(int type, const char *key, char *dst, size_t sz) { - struct query *q; - char **res[4], filter[MAX_LDAP_FILTERLEN]; - int ret, i; + struct query *q; + struct aldap_stringset *res[MAX_ATTRS]; + char filter[MAX_LDAP_FILTERLEN]; + int ret; + size_t i; + char *r, *user, *pwhash, *uid, *gid, *home; switch (type) { case K_ALIAS: q = &queries[LDAP_ALIAS]; break; @@ -454,12 +478,12 @@ ldap_run_query(int type, const char *key, char *dst, size_t sz) case K_ALIAS: memset(dst, 0, sz); - for (i = 0; res[0][i]; i++) { + for (i = 0; i < res[0]->len; i++) { if (i && strlcat(dst, ", ", sz) >= sz) { ret = -1; break; } - if (strlcat(dst, res[0][i], sz) >= sz) { + if (ldap_strlcat(dst, res[0]->str[i], sz) >= sz) { ret = -1; break; } @@ -468,17 +492,28 @@ ldap_run_query(int type, const char *key, char *dst, size_t sz) case K_DOMAIN: case K_MAILADDR: case K_MAILADDRMAP: - if (strlcpy(dst, res[0][0], sz) >= sz) + r = strndup(res[0]->str[0].ostr_val, res[0]->str[0].ostr_len); + if (!r || strlcpy(dst, r, sz) >= sz) ret = -1; + free(r); break; case K_CREDENTIALS: - if (snprintf(dst, sz, "%s:%s", res[0][0], res[1][0]) >= (int)sz) + user = strndup(res[0]->str[0].ostr_val, res[0]->str[0].ostr_len); + pwhash = strndup(res[1]->str[0].ostr_val, res[1]->str[0].ostr_len); + if (!user || !pwhash || snprintf(dst, sz, "%s:%s", user, pwhash) >= (int)sz) ret = -1; + free(user); + free(pwhash); break; case K_USERINFO: - if (snprintf(dst, sz, "%s:%s:%s", res[0][0], res[1][0], - res[2][0]) >= (int)sz) + uid = strndup(res[0]->str[0].ostr_val, res[0]->str[0].ostr_len); + gid = strndup(res[1]->str[0].ostr_val, res[1]->str[0].ostr_len); + home = strndup(res[2]->str[0].ostr_val, res[2]->str[0].ostr_len); + if (!uid || !gid || !home || snprintf(dst, sz, "%s:%s:%s", uid, gid, home) >= (int)sz) ret = -1; + free(uid); + free(gid); + free(home); break; default: log_warnx("warn: unsupported lookup kind"); -- 2.39.2
From f133d47c5b989b80d8e8890a84ae21447b6838a7 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 18 Feb 2024 17:42:09 +0100 Subject: [PATCH 2/4] table-ldap request only required attributes --- extras/tables/table-ldap/table_ldap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/tables/table-ldap/table_ldap.c b/extras/tables/table-ldap/table_ldap.c index 76d2c90..8aa8b15 100644 --- a/extras/tables/table-ldap/table_ldap.c +++ b/extras/tables/table-ldap/table_ldap.c @@ -366,7 +366,7 @@ ldap_query(const char *filter, const char *key, char **attributes, struct aldap_ found = -1; do { if ((ret = aldap_search(aldap, basedn__, LDAP_SCOPE_SUBTREE, - filter__, key__, NULL, 0, 0, 0, pg)) == -1) { + filter__, key__, attributes, 0, 0, 0, pg)) == -1) { log_debug("ret=%d", ret); return -1; } -- 2.39.2
From 8498921f8e6c106a04c49586f8045867b4902b4f Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 18 Feb 2024 18:55:04 +0100 Subject: [PATCH 3/4] table-ldap handle more then one result --- extras/tables/table-ldap/table_ldap.c | 164 +++++++++++++++----------- 1 file changed, 92 insertions(+), 72 deletions(-) diff --git a/extras/tables/table-ldap/table_ldap.c b/extras/tables/table-ldap/table_ldap.c index 8aa8b15..77af984 100644 --- a/extras/tables/table-ldap/table_ldap.c +++ b/extras/tables/table-ldap/table_ldap.c @@ -62,6 +62,10 @@ struct query { size_t attrn; }; +struct query_result { + char **v[MAX_ATTRS]; +}; + static int ldap_run_query(int type, const char *, char *, size_t); static char *config, *url, *username, *password, *basedn; @@ -347,12 +351,26 @@ table_ldap_lookup(int service, struct dict *params, const char *key, char *dst, } static int -ldap_query(const char *filter, const char *key, char **attributes, struct aldap_stringset **outp, size_t n) +realloc_results(struct query_result **r, size_t *num) +{ + struct query_result *new; + size_t newsize = MAX(1, (*num)*2); + if ((new = reallocarray(*r, newsize, sizeof(**r))) == NULL) + return 0; + *num = newsize; + *r = new; + return 1; +} + +static int +ldap_query(const char *filter, const char *key, char **attributes, size_t attrn, struct query_result **results, size_t *nresults) { struct aldap_message *m = NULL; struct aldap_page_control *pg = NULL; - int ret, found; - size_t i; + struct aldap_stringset *ldap_res; + struct query_result *res = NULL; + int ret; + size_t i, j, k, found = 0, nres = 0; char basedn__[MAX_LDAP_BASELEN]; char filter__[MAX_LDAP_FILTERLEN]; char key__[MAX_LDAP_IDENTIFIER]; @@ -363,12 +381,12 @@ ldap_query(const char *filter, const char *key, char **attributes, struct aldap_ return -1; if (strlcpy(key__, key, sizeof key__) >= sizeof key__) return -1; - found = -1; + do { - if ((ret = aldap_search(aldap, basedn__, LDAP_SCOPE_SUBTREE, - filter__, key__, attributes, 0, 0, 0, pg)) == -1) { - log_debug("ret=%d", ret); - return -1; + ret = -1; + if (aldap_search(aldap, basedn__, LDAP_SCOPE_SUBTREE, + filter__, key__, attributes, 0, 0, 0, pg) == -1) { + goto end; } if (pg != NULL) { aldap_freepage(pg); @@ -377,59 +395,60 @@ ldap_query(const char *filter, const char *key, char **attributes, struct aldap_ while ((m = aldap_parse(aldap)) != NULL) { if (aldap->msgid != m->msgid) - goto error; + goto end; if (m->message_type == LDAP_RES_SEARCH_RESULT) { if (m->page != NULL && m->page->cookie_len) pg = m->page; aldap_freemsg(m); m = NULL; - if (found == -1) - found = 0; + ret = 0; break; } if (m->message_type != LDAP_RES_SEARCH_ENTRY) - goto error; + goto end; - found = 1; - for (i = 0; i < n; ++i) - if (aldap_match_attr(m, attributes[i], &outp[i]) != 1) - goto error; + if (found >= nres) { + if (!realloc_results(&res, &nres)) { + goto end; + } + } + memset(&res[found], 0, sizeof(res[found])); + for (i = 0; i < attrn; ++i) { + if (aldap_match_attr(m, attributes[i], &ldap_res) != 1) { + goto end; + } + res[found].v[i] = calloc(ldap_res->len + 1, sizeof(*res[found].v[i])); + for (j = 0; j < ldap_res->len; j++) { + res[found].v[i][j] = strndup(ldap_res->str[j].ostr_val, ldap_res->str[j].ostr_len); + } + aldap_free_attr(ldap_res); + } aldap_freemsg(m); m = NULL; + found++; } } while (pg != NULL); - ret = found; - goto end; - -error: - ret = -1; - end: - if (m) - aldap_freemsg(m); - log_debug("debug: table_ldap: ldap_query: filter=%s, ret=%d", filter, ret); - return ret; -} - -static size_t -ldap_strlcat(char *dst, const struct ber_octetstring str, size_t sz) -{ - size_t ret; - char *s = calloc(str.ostr_len + 1, sizeof(*s)); - if (!s) { - log_warn("can not allocate memory"); - return sz; - } - - if (strlcpy(s, str.ostr_val, str.ostr_len + 1) >= str.ostr_len + 1) { - ret = sz; - goto out; + if (ret == -1) { + for (i = 0; i < nres; i++) { + for (j = 0; j < attrn; j++) { + for (k = 0; res[i].v[j][k]; k++) { + free(res[i].v[j][k]); + } + free(res[i].v[j]); + } + } + free(res); + } else { + ret = found ? 1 : 0; + *results = res; + *nresults = nres; } - ret = strlcat(dst, s, sz); -out: - free(s); + if (m) + aldap_freemsg(m); + log_debug("debug: table_ldap: ldap_query: filter=%s, key=%s, ret=%d", filter, key, ret); return ret; } @@ -437,10 +456,10 @@ static int ldap_run_query(int type, const char *key, char *dst, size_t sz) { struct query *q; - struct aldap_stringset *res[MAX_ATTRS]; + struct query_result *res = NULL; char filter[MAX_LDAP_FILTERLEN]; int ret; - size_t i; + size_t i, j, k, nres = 0; char *r, *user, *pwhash, *uid, *gid, *home; switch (type) { @@ -469,51 +488,46 @@ ldap_run_query(int type, const char *key, char *dst, size_t sz) return -1; } - memset(res, 0, sizeof(res)); - ret = ldap_query(filter, key, q->attrs, res, q->attrn); + ret = ldap_query(filter, key, q->attrs, q->attrn, &res, &nres); if (ret <= 0 || dst == NULL) goto end; switch (type) { case K_ALIAS: + case K_MAILADDRMAP: memset(dst, 0, sz); - for (i = 0; i < res[0]->len; i++) { - if (i && strlcat(dst, ", ", sz) >= sz) { - ret = -1; - break; - } - if (ldap_strlcat(dst, res[0]->str[i], sz) >= sz) { - ret = -1; - break; + for (i = 0; ret != -1 && i < nres; i++) { + for (j = 0; res[i].v[0][j]; j++) { + if ((i || j) && strlcat(dst, ", ", sz) >= sz) { + ret = -1; + break; + } + if (strlcat(dst, res[i].v[0][j], sz) >= sz) { + ret = -1; + break; + } } } break; case K_DOMAIN: case K_MAILADDR: - case K_MAILADDRMAP: - r = strndup(res[0]->str[0].ostr_val, res[0]->str[0].ostr_len); + r = res[0].v[0][0]; if (!r || strlcpy(dst, r, sz) >= sz) ret = -1; - free(r); break; case K_CREDENTIALS: - user = strndup(res[0]->str[0].ostr_val, res[0]->str[0].ostr_len); - pwhash = strndup(res[1]->str[0].ostr_val, res[1]->str[0].ostr_len); + user = res[0].v[0][0]; + pwhash = res[0].v[1][0]; if (!user || !pwhash || snprintf(dst, sz, "%s:%s", user, pwhash) >= (int)sz) ret = -1; - free(user); - free(pwhash); break; case K_USERINFO: - uid = strndup(res[0]->str[0].ostr_val, res[0]->str[0].ostr_len); - gid = strndup(res[1]->str[0].ostr_val, res[1]->str[0].ostr_len); - home = strndup(res[2]->str[0].ostr_val, res[2]->str[0].ostr_len); + uid = res[0].v[0][0]; + gid = res[0].v[1][0]; + home = res[0].v[2][0]; if (!uid || !gid || !home || snprintf(dst, sz, "%s:%s:%s", uid, gid, home) >= (int)sz) ret = -1; - free(uid); - free(gid); - free(home); break; default: log_warnx("warn: unsupported lookup kind"); @@ -524,9 +538,15 @@ ldap_run_query(int type, const char *key, char *dst, size_t sz) log_warnx("warn: could not format result"); end: - for (i = 0; i < q->attrn; ++i) - if (res[i]) - aldap_free_attr(res[i]); + for (i = 0; i < nres; i++) { + for (j = 0; j < q->attrn; ++j) { + for (k = 0; res[i].v[j][k]; k++) { + free(res[i].v[j][k]); + } + free(res[i].v[i]); + } + } + free(res); return ret; } -- 2.39.2
From 113b58b82eb936d8afed7d8f706575ceaa58d73c Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 18 Feb 2024 15:11:54 +0100 Subject: [PATCH 4/4] add ldaps support --- extras/tables/table-ldap/table_ldap.c | 52 ++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/extras/tables/table-ldap/table_ldap.c b/extras/tables/table-ldap/table_ldap.c index 77af984..167fb42 100644 --- a/extras/tables/table-ldap/table_ldap.c +++ b/extras/tables/table-ldap/table_ldap.c @@ -68,7 +68,7 @@ struct query_result { static int ldap_run_query(int type, const char *, char *, size_t); -static char *config, *url, *username, *password, *basedn; +static char *config, *url, *username, *password, *basedn, *ca_file; static struct aldap *aldap; static struct query queries[LDAP_MAX]; @@ -89,18 +89,29 @@ static struct aldap * ldap_connect(const char *addr) { struct aldap_url lu; + struct aldap *ldap = NULL; + struct tls_config *tls_config = NULL; struct addrinfo hints, *res0, *res; int error, fd = -1; if (aldap_parse_url(addr, &lu) != 1) { log_warnx("warn: ldap_parse_url fail"); - return NULL; + goto out; + } + if (lu.protocol == LDAPI) { + log_warnx("ldapi:// is not suported yet"); + goto out; + } + if (lu.protocol == LDAPTLS) { + log_warnx("ldap+tls:// is not suported yet"); + goto out; } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICSERV; + log_debug("ldap connect to: %s:%s", lu.host, lu.port); error = getaddrinfo(lu.host, lu.port, &hints, &res0); if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME) return NULL; @@ -116,16 +127,45 @@ ldap_connect(const char *addr) continue; if (connect(fd, res->ai_addr, res->ai_addrlen) == 0) { - aldap_free_url(&lu); - return aldap_init(fd); + ldap = aldap_init(fd); + break; } close(fd); fd = -1; } + if (!ldap) { + log_debug("can not connect"); + goto out; + } + + if (lu.protocol == LDAPS || lu.protocol == LDAPTLS) { + tls_config = tls_config_new(); + if (!tls_config) { + log_warn("warn: can not get tls_config"); + aldap_close(ldap); + ldap = NULL; + goto out; + } + if (ca_file && tls_config_set_ca_file(tls_config, ca_file) == -1) { + log_warnx("warn: can't load ca file: %s", tls_config_error(tls_config)); + aldap_close(ldap); + ldap = NULL; + goto out; + } + if (aldap_tls(ldap, tls_config, lu.host) == -1) { + log_warnx("warn: tls connection failed"); + aldap_close(ldap); + ldap = NULL; + goto out; + } + } + +out: + tls_config_free(tls_config); aldap_free_url(&lu); - return NULL; + return ldap; } static int @@ -228,6 +268,8 @@ ldap_config(void) read_value(&password, key, value); else if (!strcmp(key, "basedn")) read_value(&basedn, key, value); + else if (!strcmp(key, "ca_file")) + read_value(&ca_file, key, value); else if (!strcmp(key, "alias_filter")) read_value(&queries[LDAP_ALIAS].filter, key, value); else if (!strcmp(key, "alias_attributes")) { -- 2.39.2