pax_global_header00006660000000000000000000000064146141645640014525gustar00rootroot0000000000000052 comment=8c7afe76dae38ef9192cb85043c8d20d8f891f48 OpenSMTPD-table-ldap-5d756da/000077500000000000000000000000001461416456400156625ustar00rootroot00000000000000OpenSMTPD-table-ldap-5d756da/.gitignore000066400000000000000000000003051461416456400176500ustar00rootroot00000000000000**/*~ **/*.d **/*.o **/.deps **/Makefile **/Makefile.in **/aclocal.m4 **/.dirstamp **/autom4te.cache **/config.h **/config.h.in **/config.log **/config.status **/configure **/stamp-h1 table-ldap OpenSMTPD-table-ldap-5d756da/Makefile.am000066400000000000000000000007361461416456400177240ustar00rootroot00000000000000noinst_PROGRAMS = table-ldap table_ldap_SOURCES = table_ldap.c aldap.c ber.c dict.c log.c table_stdio.c util.c LDADD = $(LIBOBJS) EXTRA_DIST = aldap.h ber.h compat.h config.h.in \ dict.h log.h table_stdio.h util.h smtpdir = ${prefix}/libexec/smtpd install-exec-local: $(noinst_PROGRAMS) $(MKDIR_P) $(DESTDIR)$(smtpdir) $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $(noinst_PROGRAMS) $(DESTDIR)$(smtpdir) uninstall-local: rm $(DESTDIR)$(smtpdir)/$(noinst_PROGRAMS) OpenSMTPD-table-ldap-5d756da/aldap.c000066400000000000000000000641261461416456400171200ustar00rootroot00000000000000/* * Copyright (c) 2008 Alexander Schrijver * Copyright (c) 2006, 2007 Marc Balmer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "compat.h" #include #include #include #include #include #include "aldap.h" #if 0 #define DEBUG #endif #define ALDAP_VERSION 3 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 *); char *utoa(char *); char *parseval(char *, size_t, const char *); int aldap_create_page_control(struct ber_element *, int, struct aldap_page_control *); #ifdef DEBUG void ldap_debug_elements(struct ber_element *); #endif #ifdef DEBUG #define DPRINTF(x...) printf(x) #define LDAP_DEBUG(x, y) do { fprintf(stderr, "*** " x "\n"); ldap_debug_elements(y); } while (0) #else #define DPRINTF(x...) do { } while (0) #define LDAP_DEBUG(x, y) do { } while (0) #endif int aldap_close(struct aldap *al) { if (close(al->ber.fd) == -1) return (-1); ber_free(&al->ber); free(al); return (0); } struct aldap * aldap_init(int fd) { struct aldap *a; if ((a = calloc(1, sizeof(*a))) == NULL) return NULL; a->ber.fd = fd; return a; } 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) 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); 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) goto fail; return (ldap->msgid); fail: if (root != NULL) ber_free_elements(root); ldap->err = ALDAP_ERR_OPERATION_FAILED; return (-1); } int aldap_unbind(struct aldap *ldap) { struct ber_element *root = NULL, *elm; int error; if ((root = ber_add_sequence(NULL)) == NULL) goto fail; elm = ber_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) goto fail; return (ldap->msgid); fail: if (root != NULL) ber_free_elements(root); ldap->err = ALDAP_ERR_OPERATION_FAILED; return (-1); } int aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter, const char *key, char **attrs, int typesonly, int sizelimit, int timelimit, struct aldap_page_control *page) { struct ber_element *root = NULL, *ber, *c; int i, error; if ((root = ber_add_sequence(NULL)) == NULL) goto fail; ber = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP, (unsigned long) 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, timelimit, typesonly); if (ber == NULL) { ldap->err = ALDAP_ERR_OPERATION_FAILED; goto fail; } if ((ber = ldap_parse_search_filter(ber, filter, key)) == NULL) { ldap->err = ALDAP_ERR_PARSER_ERROR; goto fail; } if ((ber = ber_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) goto fail; } aldap_create_page_control(c, 100, page); LDAP_DEBUG("aldap_search", root); error = ber_write_elements(&ldap->ber, root); ber_free_elements(root); root = NULL; if (error == -1) { ldap->err = ALDAP_ERR_OPERATION_FAILED; goto fail; } return (ldap->msgid); fail: if (root != NULL) ber_free_elements(root); return (-1); } int aldap_create_page_control(struct ber_element *elm, int size, struct aldap_page_control *page) { int len; struct ber c; struct ber_element *ber = NULL; c.br_wbuf = NULL; c.fd = -1; ber = ber_add_sequence(NULL); if (page == NULL) { if (ber_printf_elements(ber, "ds", 50, "") == NULL) goto fail; } else { if (ber_printf_elements(ber, "dx", 50, page->cookie, page->cookie_len) == NULL) goto fail; } if ((len = ber_write_elements(&c, ber)) < 1) goto fail; if (ber_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); return len; fail: if (ber != NULL) ber_free_elements(ber); ber_free(&c); return (-1); } struct aldap_message * aldap_parse(struct aldap *ldap) { int class; unsigned long type; long long msgid = 0; struct aldap_message *m; struct ber_element *a = NULL, *ep; if ((m = calloc(1, sizeof(struct aldap_message))) == NULL) return NULL; if ((m->msg = ber_read_elements(&ldap->ber, NULL)) == NULL) goto parsefail; LDAP_DEBUG("message", m->msg); if (ber_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0) goto parsefail; m->msgid = msgid; m->message_type = type; m->protocol_op = a; switch (m->message_type) { case LDAP_RES_BIND: case LDAP_RES_MODIFY: case LDAP_RES_ADD: case LDAP_RES_DELETE: 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) goto parsefail; if (m->body.res.rescode == LDAP_REFERRAL) if (ber_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); if (class == 2 && type == 0) m->page = aldap_parse_page_control(ep->be_sub->be_sub, ep->be_sub->be_sub->be_len); } } else m->page = NULL; break; case LDAP_RES_SEARCH_ENTRY: if (ber_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) goto parsefail; break; } return m; parsefail: 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) { char *oid, *s; char *encoded; struct ber b; struct ber_element *elm; 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; } if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) { ber_free_elements(elm); ber_free(&b); return NULL; } ber_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); free(page); return NULL; } memcpy(page->cookie, s, page->cookie_len); ber_free_elements(elm); ber_free(&b); return page; } void aldap_freepage(struct aldap_page_control *page) { if (page->cookie) free(page->cookie); free(page); } void aldap_freemsg(struct aldap_message *msg) { if (msg->msg) ber_free_elements(msg->msg); free(msg); } int aldap_get_resultcode(struct aldap_message *msg) { return msg->body.res.rescode; } char * aldap_get_dn(struct aldap_message *msg) { char *dn; if (msg->dn == NULL) return NULL; if (ber_get_string(msg->dn, &dn) == -1) return NULL; return utoa(dn); } char ** aldap_get_references(struct aldap_message *msg) { if (msg->references == NULL) return NULL; return aldap_get_stringset(msg->references); } void aldap_free_references(char **values) { int i; if (values == NULL) return; for (i = 0; values[i] != NULL; i++) free(values[i]); free(values); } char * aldap_get_diagmsg(struct aldap_message *msg) { char *s; if (msg->body.res.diagmsg == NULL) return NULL; if (ber_get_string(msg->body.res.diagmsg, &s) == -1) return NULL; return utoa(s); } int aldap_count_attrs(struct aldap_message *msg) { int i; struct ber_element *a; if (msg->body.search.attrs == NULL) return (-1); for (i = 0, a = msg->body.search.attrs; a != NULL && ber_get_eoc(a) != 0; i++, a = a->be_next) ; return i; } int aldap_first_attr(struct aldap_message *msg, char **outkey, char ***outvalues) { struct ber_element *b, *c; char *key; char **ret; if (msg->body.search.attrs == NULL) goto fail; if (ber_scanf_elements(msg->body.search.attrs, "{s(e)}e", &key, &b, &c) != 0) goto fail; msg->body.search.iter = msg->body.search.attrs->be_next; if ((ret = aldap_get_stringset(b)) == NULL) goto fail; (*outvalues) = ret; (*outkey) = utoa(key); return (1); fail: (*outkey) = NULL; (*outvalues) = NULL; return (-1); } int aldap_next_attr(struct aldap_message *msg, char **outkey, char ***outvalues) { struct ber_element *a, *b; char *key; char **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) goto notfound; if (ber_scanf_elements(msg->body.search.iter, "{s(e)}e", &key, &a, &b) != 0) goto fail; msg->body.search.iter = msg->body.search.iter->be_next; if ((ret = aldap_get_stringset(a)) == NULL) goto fail; (*outvalues) = ret; (*outkey) = utoa(key); return (1); fail: notfound: (*outkey) = NULL; (*outvalues) = NULL; return (-1); } int aldap_match_attr(struct aldap_message *msg, char *inkey, char ***outvalues) { struct ber_element *a, *b; char *descr = NULL; char **ret; if (msg->body.search.attrs == NULL) goto fail; LDAP_DEBUG("attr", msg->body.search.attrs); for (a = msg->body.search.attrs;;) { if (a == NULL) goto notfound; if (ber_get_eoc(a) == 0) goto notfound; if (ber_scanf_elements(a, "{s(e", &descr, &b) != 0) goto fail; if (strcasecmp(descr, inkey) == 0) goto attrfound; a = a->be_next; } attrfound: if ((ret = aldap_get_stringset(b)) == NULL) goto fail; (*outvalues) = ret; return (1); fail: notfound: (*outvalues) = NULL; return (-1); } int aldap_free_attr(char **values) { int i; if (values == NULL) return -1; for (i = 0; values[i] != NULL; i++) free(values[i]); free(values); return (1); } void aldap_free_url(struct aldap_url *lu) { free(lu->buffer); } int aldap_parse_url(const char *url, struct aldap_url *lu) { char *p, *forward, *forward2; const char *errstr = NULL; int i; if ((lu->buffer = 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); /* host and optional port */ if ((forward = strchr(p, '/')) != NULL) *forward = '\0'; /* find the optional port */ if ((forward2 = strchr(p, ':')) != NULL) { *forward2 = '\0'; /* if a port is given */ if (*(forward2+1) != '\0') { #define PORT_MAX UINT16_MAX strtonum(++forward2, 0, PORT_MAX, &errstr); if (errstr) goto fail; lu->port = forward2; } } else { lu->port = LDAP_PORT; } /* fail if no host is given */ if (strlen(p) == 0) goto fail; lu->host = p; if (forward == NULL) goto done; /* p is assigned either a pointer to a character or to '\0' */ p = ++forward; if (strlen(p) == 0) goto done; /* dn */ if ((forward = strchr(p, '?')) != NULL) *forward = '\0'; lu->dn = p; if (forward == NULL) goto done; /* p is assigned either a pointer to a character or to '\0' */ p = ++forward; if (strlen(p) == 0) goto done; /* attributes */ if ((forward = strchr(p, '?')) != NULL) *forward = '\0'; for (i = 0; i < MAXATTR; i++) { if ((forward2 = strchr(p, ',')) == NULL) { if (strlen(p) == 0) break; lu->attributes[i] = p; break; } *forward2 = '\0'; lu->attributes[i] = p; p = ++forward2; } if (forward == NULL) goto done; /* p is assigned either a pointer to a character or to '\0' */ p = ++forward; if (strlen(p) == 0) goto done; /* scope */ if ((forward = strchr(p, '?')) != NULL) *forward = '\0'; if (strcmp(p, "base") == 0) lu->scope = LDAP_SCOPE_BASE; else if (strcmp(p, "one") == 0) lu->scope = LDAP_SCOPE_ONELEVEL; else if (strcmp(p, "sub") == 0) lu->scope = LDAP_SCOPE_SUBTREE; else goto fail; if (forward == NULL) goto done; p = ++forward; if (strlen(p) == 0) goto done; /* filter */ if (p) lu->filter = p; done: return (1); fail: free(lu->buffer); lu->buffer = NULL; return (-1); } #if 0 int aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit, int timelimit) { struct aldap_url *lu; if ((lu = calloc(1, sizeof(*lu))) == NULL) return (-1); if (aldap_parse_url(url, lu)) goto fail; if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, lu->attributes, typesonly, sizelimit, timelimit) == -1) goto fail; aldap_free_url(lu); return (ldap->msgid); fail: aldap_free_url(lu); return (-1); } #endif /* * internal functions */ char ** aldap_get_stringset(struct ber_element *elm) { struct ber_element *a; int i; char **ret; char *s; 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 (i == 1) return NULL; if ((ret = calloc(i + 1, sizeof(char *))) == NULL) 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; return ret; } /* * Base case for ldap_do_parse_search_filter * * returns: * struct ber_element *, ber_element tree * NULL, parse failed */ static struct ber_element * ldap_parse_search_filter(struct ber_element *ber, char *filter, const char *key) { struct ber_element *elm; char *cp; cp = filter; if (cp == NULL || *cp == '\0') { errno = EINVAL; return (NULL); } if ((elm = ldap_do_parse_search_filter(ber, &cp, key)) == NULL) return (NULL); if (*cp != '\0') { ber_free_elements(elm); ber_link_elements(ber, NULL); errno = EINVAL; return (NULL); } return (elm); } /* * Translate RFC4515 search filter string into ber_element tree * * returns: * struct ber_element *, ber_element tree * NULL, parse failed * * notes: * when cp is passed to a recursive invocation, it is updated * to point one character beyond the filter that was passed * i.e., cp jumps to "(filter)" upon return * ^ * goto's used to discriminate error-handling based on error type * doesn't handle extended filters (yet) * */ static struct ber_element * ldap_do_parse_search_filter(struct ber_element *prev, char **cpp, const char *key) { struct ber_element *elm, *root = NULL; char *attr_desc, *attr_val, *parsed_val, *cp; size_t len; unsigned long type; root = NULL; /* cpp should pass in pointer to opening parenthesis of "(filter)" */ cp = *cpp; if (*cp != '(') goto syntaxfail; switch (*++cp) { case '&': /* AND */ case '|': /* OR */ if (*cp == '&') type = LDAP_FILT_AND; else type = LDAP_FILT_OR; if ((elm = ber_add_set(prev)) == NULL) goto callfail; root = elm; ber_set_header(elm, BER_CLASS_CONTEXT, type); if (*++cp != '(') /* opening `(` of filter */ goto syntaxfail; while (*cp == '(') { if ((elm = ldap_do_parse_search_filter(elm, &cp, key)) == NULL) goto bad; } if (*cp != ')') /* trailing `)` of filter */ goto syntaxfail; break; case '!': /* NOT */ if ((root = ber_add_sequence(prev)) == NULL) goto callfail; ber_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) goto bad; if (*cp != ')') /* trailing `)` of filter */ goto syntaxfail; break; default: /* SIMPLE || PRESENCE */ attr_desc = cp; len = strcspn(cp, "()<>~="); cp += len; switch (*cp) { case '~': type = LDAP_FILT_APPR; cp++; break; case '<': type = LDAP_FILT_LE; cp++; break; case '>': type = LDAP_FILT_GE; cp++; break; case '=': type = LDAP_FILT_EQ; /* assume EQ until disproven */ break; case '(': case ')': default: goto syntaxfail; } attr_val = ++cp; /* presence filter */ if (strncmp(attr_val, "*)", 2) == 0) { cp++; /* point to trailing `)` */ if ((root = ber_add_nstring(prev, attr_desc, len)) == NULL) goto bad; ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES); break; } if ((root = ber_add_sequence(prev)) == NULL) goto callfail; ber_set_header(root, BER_CLASS_CONTEXT, type); if ((elm = ber_add_nstring(root, attr_desc, len)) == NULL) goto callfail; len = strcspn(attr_val, "*)"); if (len == 0 && *cp != '*') goto syntaxfail; cp += len; if (*cp == '\0') goto syntaxfail; if (*cp == '*') { /* substring filter */ int initial; cp = attr_val; ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS); if ((elm = ber_add_sequence(elm)) == NULL) goto callfail; for (initial = 1;; cp++, initial = 0) { attr_val = cp; len = strcspn(attr_val, "*)"); if (len == 0) { if (*cp == ')') break; else continue; } cp += len; if (*cp == '\0') goto syntaxfail; if (initial) type = LDAP_FILT_SUBS_INIT; else if (*cp == ')') type = LDAP_FILT_SUBS_FIN; else type = LDAP_FILT_SUBS_ANY; if ((parsed_val = parseval(attr_val, len, key)) == NULL) goto callfail; elm = ber_add_nstring(elm, parsed_val, strlen(parsed_val)); free(parsed_val); if (elm == NULL) goto callfail; ber_set_header(elm, BER_CLASS_CONTEXT, type); if (type == LDAP_FILT_SUBS_FIN) break; } break; } if ((parsed_val = parseval(attr_val, len, key)) == NULL) goto callfail; elm = ber_add_nstring(elm, parsed_val, strlen(parsed_val)); free(parsed_val); if (elm == NULL) goto callfail; break; } cp++; /* now points one char beyond the trailing `)` */ *cpp = cp; return (root); syntaxfail: /* XXX -- error reporting */ callfail: bad: if (root != NULL) ber_free_elements(root); ber_link_elements(prev, NULL); return (NULL); } #ifdef DEBUG /* * Display a list of ber elements. * */ void ldap_debug_elements(struct ber_element *root) { static int indent = 0; long long v; int d; char *buf; size_t len; unsigned int i; int constructed; struct ber_oid o; /* calculate lengths */ ber_calc_len(root); switch (root->be_encoding) { case BER_TYPE_SEQUENCE: case BER_TYPE_SET: constructed = root->be_encoding; break; default: constructed = 0; break; } fprintf(stderr, "%*slen %lu ", indent, "", root->be_len); switch (root->be_class) { case BER_CLASS_UNIVERSAL: fprintf(stderr, "class: universal(%u) type: ", root->be_class); switch (root->be_type) { case BER_TYPE_EOC: fprintf(stderr, "end-of-content"); break; case BER_TYPE_BOOLEAN: fprintf(stderr, "boolean"); break; case BER_TYPE_INTEGER: fprintf(stderr, "integer"); break; case BER_TYPE_BITSTRING: fprintf(stderr, "bit-string"); break; case BER_TYPE_OCTETSTRING: fprintf(stderr, "octet-string"); break; case BER_TYPE_NULL: fprintf(stderr, "null"); break; case BER_TYPE_OBJECT: fprintf(stderr, "object"); break; case BER_TYPE_ENUMERATED: fprintf(stderr, "enumerated"); break; case BER_TYPE_SEQUENCE: fprintf(stderr, "sequence"); break; case BER_TYPE_SET: fprintf(stderr, "set"); break; } break; case BER_CLASS_APPLICATION: fprintf(stderr, "class: application(%u) type: ", root->be_class); switch (root->be_type) { case LDAP_REQ_BIND: fprintf(stderr, "bind"); break; case LDAP_RES_BIND: fprintf(stderr, "bind"); break; case LDAP_REQ_UNBIND_30: break; case LDAP_REQ_SEARCH: fprintf(stderr, "search"); break; case LDAP_RES_SEARCH_ENTRY: fprintf(stderr, "search_entry"); break; case LDAP_RES_SEARCH_RESULT: fprintf(stderr, "search_result"); break; case LDAP_REQ_MODIFY: fprintf(stderr, "modify"); break; case LDAP_RES_MODIFY: fprintf(stderr, "modify"); break; case LDAP_REQ_ADD: fprintf(stderr, "add"); break; case LDAP_RES_ADD: fprintf(stderr, "add"); break; case LDAP_REQ_DELETE_30: fprintf(stderr, "delete"); break; case LDAP_RES_DELETE: fprintf(stderr, "delete"); break; case LDAP_REQ_MODRDN: fprintf(stderr, "modrdn"); break; case LDAP_RES_MODRDN: fprintf(stderr, "modrdn"); break; case LDAP_REQ_COMPARE: fprintf(stderr, "compare"); break; case LDAP_RES_COMPARE: fprintf(stderr, "compare"); break; case LDAP_REQ_ABANDON_30: fprintf(stderr, "abandon"); break; } break; case BER_CLASS_PRIVATE: fprintf(stderr, "class: private(%u) type: ", root->be_class); fprintf(stderr, "encoding (%lu) type: ", root->be_encoding); break; case BER_CLASS_CONTEXT: /* XXX: this is not correct */ fprintf(stderr, "class: context(%u) type: ", root->be_class); switch(root->be_type) { case LDAP_AUTH_SIMPLE: fprintf(stderr, "auth simple"); break; } break; default: fprintf(stderr, "class: (%u) type: ", root->be_class); break; } fprintf(stderr, "(%lu) encoding %lu ", root->be_type, root->be_encoding); if (constructed) root->be_encoding = constructed; switch (root->be_encoding) { case BER_TYPE_BOOLEAN: if (ber_get_boolean(root, &d) == -1) { fprintf(stderr, "\n"); break; } fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d); break; case BER_TYPE_INTEGER: if (ber_get_integer(root, &v) == -1) { fprintf(stderr, "\n"); break; } fprintf(stderr, "value %lld\n", v); break; case BER_TYPE_ENUMERATED: if (ber_get_enumerated(root, &v) == -1) { fprintf(stderr, "\n"); break; } fprintf(stderr, "value %lld\n", v); break; case BER_TYPE_BITSTRING: if (ber_get_bitstring(root, (void *)&buf, &len) == -1) { fprintf(stderr, "\n"); break; } fprintf(stderr, "hexdump "); for (i = 0; i < len; i++) fprintf(stderr, "%02x", buf[i]); fprintf(stderr, "\n"); break; case BER_TYPE_OBJECT: if (ber_get_oid(root, &o) == -1) { fprintf(stderr, "\n"); break; } fprintf(stderr, "\n"); break; case BER_TYPE_OCTETSTRING: if (ber_get_nstring(root, (void *)&buf, &len) == -1) { fprintf(stderr, "\n"); break; } fprintf(stderr, "string \"%.*s\"\n", len, buf); break; case BER_TYPE_NULL: /* no payload */ case BER_TYPE_EOC: case BER_TYPE_SEQUENCE: case BER_TYPE_SET: default: fprintf(stderr, "\n"); break; } if (constructed && root->be_sub) { indent += 2; ldap_debug_elements(root->be_sub); indent -= 2; } if (root->be_next) ldap_debug_elements(root->be_next); } #endif /* * Convert UTF-8 to ASCII. * notes: * non-ASCII characters are displayed as '?' * the argument u should be a NULL terminated sequence of UTF-8 bytes. */ char * utoa(char *u) { int len, i, j; 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++; } 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; } } return str; } /* * Parse a LDAP value * notes: * the argument u should be a NULL 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; 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)); 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 { buffer[i] = cp[j]; j++; } } buffer[i] = 0; return buffer; } int aldap_get_errno(struct aldap *a, const char **estr) { switch (a->err) { case ALDAP_ERR_SUCCESS: *estr = "success"; break; case ALDAP_ERR_PARSER_ERROR: *estr = "parser failed"; break; case ALDAP_ERR_INVALID_FILTER: *estr = "invalid filter"; break; case ALDAP_ERR_OPERATION_FAILED: *estr = "operation failed"; break; default: *estr = "unknown"; break; } return (a->err); } OpenSMTPD-table-ldap-5d756da/aldap.h000066400000000000000000000125611461416456400171210ustar00rootroot00000000000000/* * Copyright (c) 2008 Alexander Schrijver * Copyright (c) 2006, 2007 Marc Balmer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include "ber.h" #define LDAP_URL "ldap://" #define LDAP_PORT "389" #define LDAP_PAGED_OID "1.2.840.113556.1.4.319" 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; int msgid; struct ber ber; }; struct aldap_page_control { int size; char *cookie; unsigned int cookie_len; }; struct aldap_message { int msgid; int message_type; struct ber_element *msg; struct ber_element *header; struct ber_element *protocol_op; struct ber_element *dn; union { struct { long long rescode; struct ber_element *diagmsg; } res; struct { struct ber_element *iter; struct ber_element *attrs; } search; } body; struct ber_element *references; struct aldap_page_control *page; }; enum aldap_protocol { LDAP, LDAPS }; struct aldap_url { int protocol; char *host; char *port; char *dn; #define MAXATTR 1024 char *attributes[MAXATTR]; int scope; char *filter; char *buffer; }; enum protocol_op { LDAP_REQ_BIND = 0, LDAP_RES_BIND = 1, LDAP_REQ_UNBIND_30 = 2, LDAP_REQ_SEARCH = 3, LDAP_RES_SEARCH_ENTRY = 4, LDAP_RES_SEARCH_RESULT = 5, LDAP_REQ_MODIFY = 6, LDAP_RES_MODIFY = 7, LDAP_REQ_ADD = 8, LDAP_RES_ADD = 9, LDAP_REQ_DELETE_30 = 10, LDAP_RES_DELETE = 11, LDAP_REQ_MODRDN = 12, LDAP_RES_MODRDN = 13, LDAP_REQ_COMPARE = 14, LDAP_RES_COMPARE = 15, LDAP_REQ_ABANDON_30 = 16, LDAP_RES_SEARCH_REFERENCE = 19, }; enum deref_aliases { LDAP_DEREF_NEVER = 0, LDAP_DEREF_SEARCHING = 1, LDAP_DEREF_FINDING = 2, LDAP_DEREF_ALWAYS = 3, }; enum authentication_choice { LDAP_AUTH_SIMPLE = 0, }; enum scope { LDAP_SCOPE_BASE = 0, LDAP_SCOPE_ONELEVEL = 1, LDAP_SCOPE_SUBTREE = 2, }; enum result_code { LDAP_SUCCESS = 0, LDAP_OPERATIONS_ERROR = 1, LDAP_PROTOCOL_ERROR = 2, LDAP_TIMELIMIT_EXCEEDED = 3, LDAP_SIZELIMIT_EXCEEDED = 4, LDAP_COMPARE_FALSE = 5, LDAP_COMPARE_TRUE = 6, LDAP_STRONG_AUTH_NOT_SUPPORTED = 7, LDAP_STRONG_AUTH_REQUIRED = 8, LDAP_REFERRAL = 10, LDAP_ADMINLIMIT_EXCEEDED = 11, LDAP_UNAVAILABLE_CRITICAL_EXTENSION = 12, LDAP_CONFIDENTIALITY_REQUIRED = 13, LDAP_SASL_BIND_IN_PROGRESS = 14, LDAP_NO_SUCH_ATTRIBUTE = 16, LDAP_UNDEFINED_TYPE = 17, LDAP_INAPPROPRIATE_MATCHING = 18, LDAP_CONSTRAINT_VIOLATION = 19, LDAP_TYPE_OR_VALUE_EXISTS = 20, LDAP_INVALID_SYNTAX = 21, LDAP_NO_SUCH_OBJECT = 32, LDAP_ALIAS_PROBLEM = 33, LDAP_INVALID_DN_SYNTAX = 34, LDAP_ALIAS_DEREF_PROBLEM = 36, LDAP_INAPPROPRIATE_AUTH = 48, LDAP_INVALID_CREDENTIALS = 49, LDAP_INSUFFICIENT_ACCESS = 50, LDAP_BUSY = 51, LDAP_UNAVAILABLE = 52, LDAP_UNWILLING_TO_PERFORM = 53, LDAP_LOOP_DETECT = 54, LDAP_NAMING_VIOLATION = 64, LDAP_OBJECT_CLASS_VIOLATION = 65, LDAP_NOT_ALLOWED_ON_NONLEAF = 66, LDAP_NOT_ALLOWED_ON_RDN = 67, LDAP_ALREADY_EXISTS = 68, LDAP_NO_OBJECT_CLASS_MODS = 69, LDAP_AFFECTS_MULTIPLE_DSAS = 71, LDAP_OTHER = 80, }; enum ldap_filter { LDAP_FILT_AND = 0, LDAP_FILT_OR = 1, LDAP_FILT_NOT = 2, LDAP_FILT_EQ = 3, LDAP_FILT_SUBS = 4, LDAP_FILT_GE = 5, LDAP_FILT_LE = 6, LDAP_FILT_PRES = 7, LDAP_FILT_APPR = 8, }; enum ldap_subfilter { LDAP_FILT_SUBS_INIT = 0, LDAP_FILT_SUBS_ANY = 1, LDAP_FILT_SUBS_FIN = 2, }; struct aldap *aldap_init(int fd); int aldap_close(struct aldap *); struct aldap_message *aldap_parse(struct aldap *); void aldap_freemsg(struct aldap_message *); 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 *); 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 *); 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_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 **); struct aldap_page_control *aldap_parse_page_control(struct ber_element *, size_t len); void aldap_freepage(struct aldap_page_control *); OpenSMTPD-table-ldap-5d756da/ber.c000066400000000000000000000630211461416456400166000ustar00rootroot00000000000000/* * Copyright (c) 2007 Reyk Floeter * Copyright (c) 2006, 2007 Claudio Jeker * Copyright (c) 2006, 2007 Marc Balmer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "compat.h" #include #include #include #include #include #include /* XXX for debug output */ #include /* XXX for debug output */ #include #include #include #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 #define BER_TAG_MORE 0x80 /* more subsequent octets */ #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, 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); #ifdef DEBUG #define DPRINTF(...) printf(__VA_ARGS__) #else #define DPRINTF(...) do { } while (0) #endif struct ber_element * ber_get_element(unsigned long encoding) { struct ber_element *elm; if ((elm = calloc(1, sizeof(*elm))) == NULL) return NULL; elm->be_encoding = encoding; ber_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT); return elm; } void ber_set_header(struct ber_element *elm, int class, unsigned long type) { elm->be_class = class & BER_CLASS_MASK; if (type == BER_TYPE_DEFAULT) type = elm->be_encoding; elm->be_type = type; } void ber_link_elements(struct ber_element *prev, struct ber_element *elm) { if (prev != NULL) { if ((prev->be_encoding == BER_TYPE_SEQUENCE || prev->be_encoding == BER_TYPE_SET) && prev->be_sub == NULL) prev->be_sub = elm; else prev->be_next = elm; } } struct ber_element * ber_unlink_elements(struct ber_element *prev) { struct ber_element *elm; if ((prev->be_encoding == BER_TYPE_SEQUENCE || prev->be_encoding == BER_TYPE_SET) && prev->be_sub != NULL) { elm = prev->be_sub; prev->be_sub = NULL; } else { elm = prev->be_next; prev->be_next = NULL; } return (elm); } void ber_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); /* cleanup old element */ ber_free_elements(ber); } struct ber_element * ber_add_sequence(struct ber_element *prev) { struct ber_element *elm; if ((elm = ber_get_element(BER_TYPE_SEQUENCE)) == NULL) return NULL; ber_link_elements(prev, elm); return elm; } struct ber_element * ber_add_set(struct ber_element *prev) { struct ber_element *elm; if ((elm = ber_get_element(BER_TYPE_SET)) == NULL) return NULL; ber_link_elements(prev, elm); return elm; } struct ber_element * ber_add_enumerated(struct ber_element *prev, long long val) { struct ber_element *elm; unsigned int i, len = 0; unsigned char cur, last = 0; if ((elm = ber_get_element(BER_TYPE_ENUMERATED)) == NULL) return NULL; elm->be_numeric = val; for (i = 0; i < sizeof(long long); i++) { cur = val & 0xff; if (cur != 0 && cur != 0xff) len = i; if ((cur == 0 && last & 0x80) || (cur == 0xff && (last & 0x80) == 0)) len = i; val >>= 8; last = cur; } elm->be_len = len + 1; ber_link_elements(prev, elm); return elm; } struct ber_element * ber_add_integer(struct ber_element *prev, long long val) { struct ber_element *elm; unsigned int i, len = 0; unsigned char cur, last = 0; if ((elm = ber_get_element(BER_TYPE_INTEGER)) == NULL) return NULL; elm->be_numeric = val; for (i = 0; i < sizeof(long long); i++) { cur = val & 0xff; if (cur != 0 && cur != 0xff) len = i; if ((cur == 0 && last & 0x80) || (cur == 0xff && (last & 0x80) == 0)) len = i; val >>= 8; last = cur; } elm->be_len = len + 1; ber_link_elements(prev, elm); return elm; } int ber_get_integer(struct ber_element *elm, long long *n) { if (elm->be_encoding != BER_TYPE_INTEGER) return -1; *n = elm->be_numeric; return 0; } int ber_get_enumerated(struct ber_element *elm, long long *n) { if (elm->be_encoding != BER_TYPE_ENUMERATED) return -1; *n = elm->be_numeric; return 0; } struct ber_element * ber_add_boolean(struct ber_element *prev, int boolean) { struct ber_element *elm; if ((elm = ber_get_element(BER_TYPE_BOOLEAN)) == NULL) return NULL; elm->be_numeric = boolean ? 0xff : 0; elm->be_len = 1; ber_link_elements(prev, elm); return elm; } int ber_get_boolean(struct ber_element *elm, int *b) { if (elm->be_encoding != BER_TYPE_BOOLEAN) return -1; *b = !(elm->be_numeric == 0); return 0; } struct ber_element * ber_add_string(struct ber_element *prev, const char *string) { return ber_add_nstring(prev, string, strlen(string)); } struct ber_element * ber_add_nstring(struct ber_element *prev, const char *string0, size_t len) { struct ber_element *elm; char *string; if ((string = calloc(1, len)) == NULL) return NULL; if ((elm = ber_get_element(BER_TYPE_OCTETSTRING)) == NULL) { free(string); return NULL; } memmove(string, string0, len); elm->be_val = string; elm->be_len = len; elm->be_free = 1; /* free string on cleanup */ ber_link_elements(prev, elm); return elm; } int ber_get_string(struct ber_element *elm, char **s) { if (elm->be_encoding != BER_TYPE_OCTETSTRING) return -1; *s = elm->be_val; return 0; } int ber_get_nstring(struct ber_element *elm, void **p, size_t *len) { if (elm->be_encoding != BER_TYPE_OCTETSTRING) return -1; *p = elm->be_val; *len = elm->be_len; return 0; } struct ber_element * ber_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) { free(v); return NULL; } memmove(v, v0, len); elm->be_val = v; elm->be_len = len; elm->be_free = 1; /* free string on cleanup */ ber_link_elements(prev, elm); return elm; } int ber_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; return 0; } struct ber_element * ber_add_null(struct ber_element *prev) { struct ber_element *elm; if ((elm = ber_get_element(BER_TYPE_NULL)) == NULL) return NULL; ber_link_elements(prev, elm); return elm; } int ber_get_null(struct ber_element *elm) { if (elm->be_encoding != BER_TYPE_NULL) return -1; return 0; } struct ber_element * ber_add_eoc(struct ber_element *prev) { struct ber_element *elm; if ((elm = ber_get_element(BER_TYPE_EOC)) == NULL) return NULL; ber_link_elements(prev, elm); return elm; } int ber_get_eoc(struct ber_element *elm) { if (elm->be_encoding != BER_TYPE_EOC) return -1; return 0; } size_t ber_oid2ber(struct ber_oid *o, uint8_t *buf, size_t len) { uint32_t v; unsigned 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) return (0); 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 (len) buf[j] = v >> k | BER_TAG_MORE; j++; } } if (len) buf[j] = v & BER_TAG_TYPE_MASK; j++; } return (j); } int ber_string2oid(const char *oidstr, struct ber_oid *o) { char *sp, *p, str[BUFSIZ]; const char *errstr; if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str)) return (-1); memset(o, 0, sizeof(*o)); /* Parse OID strings in the common forms n.n.n, n_n_n_n, or n-n-n */ for (p = sp = str; p != NULL; sp = p) { if ((p = strpbrk(p, "._-")) != NULL) *p++ = '\0'; o->bo_id[o->bo_n++] = strtonum(sp, 0, UINT_MAX, &errstr); if (errstr || o->bo_n > BER_MAX_OID_LEN) return (-1); } return (0); } struct ber_element * ber_add_oid(struct ber_element *prev, struct ber_oid *o) { struct ber_element *elm; uint8_t *buf; size_t len; if ((elm = ber_get_element(BER_TYPE_OBJECT)) == NULL) return (NULL); if ((len = ber_oid2ber(o, NULL, 0)) == 0) goto fail; if ((buf = calloc(1, len)) == NULL) goto fail; elm->be_val = buf; elm->be_len = len; elm->be_free = 1; if (ber_oid2ber(o, buf, len) != len) goto fail; ber_link_elements(prev, elm); return (elm); fail: ber_free_elements(elm); return (NULL); } struct ber_element * ber_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)); return (ber_add_oid(prev, &no)); } struct ber_element * ber_add_oidstring(struct ber_element *prev, const char *oidstr) { struct ber_oid o; if (ber_string2oid(oidstr, &o) == -1) return (NULL); return (ber_add_oid(prev, &o)); } int ber_get_oid(struct ber_element *elm, struct ber_oid *o) { uint8_t *buf; size_t len, i = 0, j = 0; if (elm->be_encoding != BER_TYPE_OBJECT) return (-1); 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; for (; i < len && j < BER_MAX_OID_LEN; i++) { o->bo_id[j] = (o->bo_id[j] << 7) + (buf[i] & ~0x80); if (buf[i] & 0x80) continue; j++; } o->bo_n = j; return (0); } struct ber_element * ber_printf_elements(struct ber_element *ber, char *fmt, ...) { va_list ap; int d, class; size_t len; unsigned long type; long long i; char *s; void *p; struct ber_oid *o; struct ber_element *sub = ber, *e; 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) goto fail; break; case 'b': d = va_arg(ap, int); if ((ber = ber_add_boolean(ber, d)) == NULL) goto fail; break; case 'd': d = va_arg(ap, int); if ((ber = ber_add_integer(ber, d)) == NULL) goto fail; break; case 'e': e = va_arg(ap, struct ber_element *); ber_link_elements(ber, e); break; case 'E': i = va_arg(ap, long long); if ((ber = ber_add_enumerated(ber, i)) == NULL) goto fail; break; case 'i': i = va_arg(ap, long long); if ((ber = ber_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) goto fail; break; case 'o': s = va_arg(ap, char *); if ((ber = ber_add_oidstring(ber, s)) == NULL) goto fail; break; case 's': s = va_arg(ap, char *); if ((ber = ber_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); break; case 'x': s = va_arg(ap, char *); len = va_arg(ap, size_t); if ((ber = ber_add_nstring(ber, s, len)) == NULL) goto fail; break; case '0': if ((ber = ber_add_null(ber)) == NULL) goto fail; break; case '{': if ((ber = sub = ber_add_sequence(ber)) == NULL) goto fail; break; case '(': if ((ber = sub = ber_add_set(ber)) == NULL) goto fail; break; case '}': case ')': ber = sub; break; case '.': if ((e = ber_add_eoc(ber)) == NULL) goto fail; ber = e; break; default: break; } } va_end(ap); return (ber); fail: ber_free_elements(ber); return (NULL); } int ber_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; void **ptr; size_t *len, ret = 0, n = strlen(fmt); char **s; struct ber_oid *o; struct ber_element *parent[_MAX_SEQ], **e; memset(parent, 0, sizeof(struct ber_element *) * _MAX_SEQ); va_start(ap, fmt); while (*fmt) { switch (*fmt++) { case 'B': ptr = va_arg(ap, void **); len = va_arg(ap, size_t *); if (ber_get_bitstring(ber, ptr, len) == -1) goto fail; ret++; break; case 'b': d = va_arg(ap, int *); if (ber_get_boolean(ber, d) == -1) goto fail; ret++; break; case 'e': e = va_arg(ap, struct ber_element **); *e = ber; ret++; continue; case 'E': i = va_arg(ap, long long *); if (ber_get_enumerated(ber, i) == -1) goto fail; ret++; break; case 'i': i = va_arg(ap, long long *); if (ber_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) goto fail; ret++; break; case 'S': ret++; break; case 's': s = va_arg(ap, char **); if (ber_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; ret++; continue; case 'x': ptr = va_arg(ap, void **); len = va_arg(ap, size_t *); if (ber_get_nstring(ber, ptr, len) == -1) goto fail; ret++; break; case '0': if (ber->be_encoding != BER_TYPE_NULL) goto fail; ret++; break; case '.': if (ber->be_encoding != BER_TYPE_EOC) goto fail; ret++; break; 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) goto fail; parent[++level] = ber; ber = ber->be_sub; ret++; continue; case '}': case ')': if (parent[level] == NULL) goto fail; ber = parent[level--]; ret++; continue; default: goto fail; } if (ber->be_next == NULL) continue; ber = ber->be_next; } va_end(ap); return (ret == n ? 0 : -1); fail: va_end(ap); return (-1); } /* * write ber elements to the socket * * params: * ber holds the socket * root fully populated element tree * * returns: * >=0 number of bytes written * -1 on failure and sets errno */ int ber_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); DPRINTF("write ber element of %zd bytes length\n", len); if (ber->br_wbuf != NULL && ber->br_wbuf + len > ber->br_wend) { free(ber->br_wbuf); ber->br_wbuf = NULL; } if (ber->br_wbuf == NULL) { if ((ber->br_wbuf = malloc(len)) == NULL) return -1; ber->br_wend = ber->br_wbuf + len; } /* reset write pointer */ ber->br_wptr = ber->br_wbuf; if (ber_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); } /* * read ber elements from the socket * * params: * ber holds the socket and lot more * 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. * * returns: * !=NULL, elements read and store in the ber_element tree * NULL, type mismatch or read error */ struct ber_element * ber_read_elements(struct ber *ber, struct ber_element *elm) { struct ber_element *root = elm; if (root == NULL) { if ((root = ber_get_element(0)) == NULL) return NULL; } DPRINTF("read ber elements, root %p\n", root); if (ber_read_element(ber, root) == -1) { /* Cleanup if root was allocated by us */ if (elm == NULL) ber_free_elements(root); return NULL; } return root; } void ber_free_elements(struct ber_element *root) { if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE || root->be_encoding == BER_TYPE_SET)) ber_free_elements(root->be_sub); if (root->be_next) ber_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)) free(root->be_val); free(root); } size_t ber_calc_len(struct ber_element *root) { unsigned long 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); /* fix header length for extended types */ if (root->be_type > BER_TYPE_SINGLE_MAX) for (t = root->be_type; t > 0; t >>= 7) size++; if (root->be_len >= BER_TAG_MORE) for (s = root->be_len; s > 0; s >>= 8) size++; /* calculate the length of the following elements */ if (root->be_next) size += ber_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) return (0); return (root->be_len + size); } /* * internal functions */ static int ber_dump_element(struct ber *ber, struct ber_element *root) { unsigned long long l; int i; uint8_t u; ber_dump_header(ber, root); switch (root->be_encoding) { case BER_TYPE_BOOLEAN: case BER_TYPE_INTEGER: case BER_TYPE_ENUMERATED: 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); } break; case BER_TYPE_BITSTRING: return -1; case BER_TYPE_OCTETSTRING: case BER_TYPE_OBJECT: ber_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) return -1; break; } if (root->be_next == NULL) return 0; return ber_dump_element(ber, root->be_next); } static void ber_dump_header(struct ber *ber, struct ber_element *root) { unsigned char id = 0, t, buf[8]; unsigned long type; size_t size; /* class universal, type encoding depending on type value */ /* length encoding */ if (root->be_type <= BER_TYPE_SINGLE_MAX) { id = root->be_type | (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); } 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); for (t = 0, type = root->be_type; type > 0; type >>= 7) buf[t++] = type & ~BER_TAG_MORE; while (t-- > 0) { if (t > 0) buf[t] |= BER_TAG_MORE; ber_putc(ber, buf[t]); } } if (root->be_len < BER_TAG_MORE) { /* short form */ ber_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); while (t > 0) ber_putc(ber, buf[--t]); } } static void ber_putc(struct ber *ber, unsigned char c) { if (ber->br_wptr + 1 <= ber->br_wend) *ber->br_wptr = c; ber->br_wptr++; } static void ber_write(struct ber *ber, void *buf, size_t len) { if (ber->br_wptr + len <= ber->br_wend) memmove(ber->br_wptr, buf, len); ber->br_wptr += 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) { unsigned char u; size_t i = 0; unsigned long t = 0; if (ber_getc(b, &u) == -1) return -1; *class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK; *cstruct = (u & BER_TYPE_CONSTRUCTED) == BER_TYPE_CONSTRUCTED; if ((u & BER_TAG_MASK) != BER_TAG_MASK) { *tag = u & BER_TAG_MASK; return 1; } do { if (ber_getc(b, &u) == -1) return -1; t = (t << 7) | (u & ~BER_TAG_MORE); i++; } while (u & BER_TAG_MORE); if (i > sizeof(unsigned long)) { errno = ERANGE; return -1; } *tag = t; return i + 1; } /* * extract length of a ber object -- if length is unknown an error is returned. */ static ssize_t get_len(struct ber *b, ssize_t *len) { unsigned char u, n; ssize_t s, r; if (ber_getc(b, &u) == -1) return -1; if ((u & BER_TAG_MORE) == 0) { /* short form */ *len = u; return 1; } n = u & ~BER_TAG_MORE; if (sizeof(ssize_t) < n) { errno = ERANGE; return -1; } r = n + 1; for (s = 0; n > 0; n--) { if (ber_getc(b, &u) == -1) return -1; s = (s << 8) | u; } if (s < 0) { /* overflow */ errno = ERANGE; 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) { long long val = 0; struct ber_element *next; unsigned long type; int i, class, cstruct; ssize_t len, r, totlen = 0; unsigned char c; 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"); totlen += r; if ((r = get_len(ber, &len)) == -1) return -1; DPRINTF("ber read element size %zd\n", len); totlen += r + len; elm->be_type = type; elm->be_len = len; elm->be_class = class; if (elm->be_encoding == 0) { /* try to figure out the encoding via class, type and cstruct */ if (cstruct) elm->be_encoding = BER_TYPE_SEQUENCE; else if (class == BER_CLASS_UNIVERSAL) elm->be_encoding = type; else if (ber->br_application != NULL) { /* * Ask the application to map the encoding to a * universal type. For example, a SMI IpAddress * type is defined as 4 byte OCTET STRING. */ elm->be_encoding = (*ber->br_application)(elm); } else /* last resort option */ elm->be_encoding = BER_TYPE_NULL; } switch (elm->be_encoding) { case BER_TYPE_EOC: /* End-Of-Content */ break; case BER_TYPE_BOOLEAN: case BER_TYPE_INTEGER: case BER_TYPE_ENUMERATED: if (len > (ssize_t)sizeof(long long)) return -1; for (i = 0; i < len; i++) { if (ber_getc(ber, &c) != 1) return -1; val <<= 8; val |= c; } /* sign extend if MSB is set */ if (val >> ((i - 1) * 8) & 0x80) val |= ULLONG_MAX << (i * 8); elm->be_numeric = val; break; case BER_TYPE_BITSTRING: elm->be_val = malloc(len); if (elm->be_val == NULL) return -1; elm->be_free = 1; elm->be_len = len; ber_read(ber, elm->be_val, len); break; case BER_TYPE_OCTETSTRING: case BER_TYPE_OBJECT: elm->be_val = malloc(len + 1); if (elm->be_val == NULL) return -1; elm->be_free = 1; elm->be_len = len; ber_read(ber, elm->be_val, len); ((unsigned char *)elm->be_val)[len] = '\0'; break; case BER_TYPE_NULL: /* no payload */ if (len != 0) 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) return -1; } next = elm->be_sub; while (len > 0) { r = ber_read_element(ber, next); if (r == -1) return -1; len -= r; if (len > 0 && next->be_next == NULL) { if ((next->be_next = ber_get_element(0)) == NULL) return -1; } next = next->be_next; } break; } return totlen; } static ssize_t ber_readbuf(struct ber *b, void *buf, size_t nbytes) { 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); } void ber_set_readbuf(struct ber *b, void *buf, size_t len) { b->br_rbuf = b->br_rptr = buf; b->br_rend = (uint8_t *)buf + len; } ssize_t ber_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); } 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; /* * 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* */ 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); } OpenSMTPD-table-ldap-5d756da/ber.h000066400000000000000000000112511461416456400166030ustar00rootroot00000000000000/* * Copyright (c) 2007 Reyk Floeter * Copyright (c) 2006, 2007 Claudio Jeker * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct ber_element { struct ber_element *be_next; unsigned long be_type; unsigned long be_encoding; size_t be_len; int be_free; uint8_t be_class; union { struct ber_element *bv_sub; void *bv_val; long long bv_numeric; } be_union; #define be_sub be_union.bv_sub #define be_val be_union.bv_val #define be_numeric be_union.bv_numeric }; 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; unsigned long (*br_application)(struct ber_element *); }; /* well-known ber_element types */ #define BER_TYPE_DEFAULT ((unsigned long)-1) #define BER_TYPE_EOC 0 #define BER_TYPE_BOOLEAN 1 #define BER_TYPE_INTEGER 2 #define BER_TYPE_BITSTRING 3 #define BER_TYPE_OCTETSTRING 4 #define BER_TYPE_NULL 5 #define BER_TYPE_OBJECT 6 #define BER_TYPE_ENUMERATED 10 #define BER_TYPE_SEQUENCE 16 #define BER_TYPE_SET 17 /* ber classes */ #define BER_CLASS_UNIVERSAL 0x0 #define BER_CLASS_UNIV BER_CLASS_UNIVERSAL #define BER_CLASS_APPLICATION 0x1 #define BER_CLASS_APP BER_CLASS_APPLICATION #define BER_CLASS_CONTEXT 0x2 #define BER_CLASS_PRIVATE 0x3 #define BER_CLASS_MASK 0x3 /* common definitions */ #define BER_MIN_OID_LEN 2 /* OBJECT */ #define BER_MAX_OID_LEN 32 /* OBJECT */ struct ber_oid { uint32_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 *); struct ber_element *ber_unlink_elements(struct ber_element *); void ber_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 *, size_t); int ber_get_string(struct ber_element *, char **); int ber_get_nstring(struct ber_element *, void **, size_t *); struct ber_element *ber_add_bitstring(struct ber_element *, const void *, size_t); int ber_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 *); __END_DECLS OpenSMTPD-table-ldap-5d756da/bootstrap000077500000000000000000000000341461416456400176220ustar00rootroot00000000000000#! /bin/sh autoreconf -vfi OpenSMTPD-table-ldap-5d756da/compat.h000066400000000000000000000012521461416456400173160ustar00rootroot00000000000000#include "config.h" #include #include #ifndef UID_MAX #define UID_MAX UINT_MAX #endif #ifndef GID_MAX #define GID_MAX UINT_MAX #endif #ifndef __dead #define __dead __attribute__((noreturn)) #endif #ifndef HAVE_ASPRINTF int asprintf(char **, const char *, ...); #endif #ifndef HAVE_GETPROGNAME const char *getprogname(void); #endif #ifndef HAVE_STRLCAT size_t strlcat(char *, const char *, size_t); #endif #ifndef HAVE_STRLCPY size_t strlcpy(char *, const char *, size_t); #endif #ifndef HAVE_STRSEP char *strsep(char **, const char *); #endif #ifndef HAVE_STRTONUM long long strtonum(const char *, long long, long long, const char **); #endif OpenSMTPD-table-ldap-5d756da/configure.ac000066400000000000000000000011031461416456400201430ustar00rootroot00000000000000AC_INIT([table-ldap], [1.0], [bugs@opensmtpd.org]) AC_CONFIG_AUX_DIR(etc) AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) AC_CONFIG_LIBOBJ_DIR(openbsd-compat) AC_PROG_CC AC_USE_SYSTEM_EXTENSIONS AC_REPLACE_FUNCS([ \ asprintf \ getprogname \ err \ strlcat \ strlcpy \ strsep \ strtonum \ ]) AC_SEARCH_LIBS([tls_init], [tls], [], [ AC_MSG_ERROR([requires libtls]) ]) CFLAGS="$CFLAGS -I$srcdir/openbsd-compat" AC_CHECK_HEADER([sys/tree.h], [], [ CFLAGS="$CFLAGS -I$srcdir/openbsd-compat/tree" ]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([ Makefile ]) AC_OUTPUT OpenSMTPD-table-ldap-5d756da/dict.c000066400000000000000000000123351461416456400167550ustar00rootroot00000000000000/* $OpenBSD: dict.c,v 1.8 2021/06/14 17:58:15 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade * Copyright (c) 2012 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "compat.h" #include #include #include #include #include "dict.h" #include "log.h" struct dictentry { SPLAY_ENTRY(dictentry) entry; const char *key; void *data; }; static int dictentry_cmp(struct dictentry *, struct dictentry *); SPLAY_PROTOTYPE(_dict, dictentry, entry, dictentry_cmp); int dict_check(struct dict *d, const char *k) { struct dictentry key; key.key = k; return (SPLAY_FIND(_dict, &d->dict, &key) != NULL); } static inline struct dictentry * dict_alloc(const char *k, void *data) { struct dictentry *e; size_t s = strlen(k) + 1; void *t; if ((e = malloc(sizeof(*e) + s)) == NULL) return NULL; e->key = t = (char*)(e) + sizeof(*e); e->data = data; memmove(t, k, s); return (e); } void * dict_set(struct dict *d, const char *k, void *data) { struct dictentry *entry, key; char *old; key.key = k; if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) { if ((entry = dict_alloc(k, data)) == NULL) fatal("dict_set: malloc"); SPLAY_INSERT(_dict, &d->dict, entry); old = NULL; d->count += 1; } else { old = entry->data; entry->data = data; } return (old); } void dict_xset(struct dict *d, const char * k, void *data) { struct dictentry *entry; if ((entry = dict_alloc(k, data)) == NULL) fatal("dict_xset: malloc"); if (SPLAY_INSERT(_dict, &d->dict, entry)) fatalx("dict_xset(%p, %s)", d, k); d->count += 1; } void * dict_get(struct dict *d, const char *k) { struct dictentry key, *entry; key.key = k; if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) return (NULL); return (entry->data); } void * dict_xget(struct dict *d, const char *k) { struct dictentry key, *entry; key.key = k; if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) fatalx("dict_xget(%p, %s)", d, k); return (entry->data); } void * dict_pop(struct dict *d, const char *k) { struct dictentry key, *entry; void *data; key.key = k; if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) return (NULL); data = entry->data; SPLAY_REMOVE(_dict, &d->dict, entry); free(entry); d->count -= 1; return (data); } void * dict_xpop(struct dict *d, const char *k) { struct dictentry key, *entry; void *data; key.key = k; if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) fatalx("dict_xpop(%p, %s)", d, k); data = entry->data; SPLAY_REMOVE(_dict, &d->dict, entry); free(entry); d->count -= 1; return (data); } int dict_poproot(struct dict *d, void **data) { struct dictentry *entry; entry = SPLAY_ROOT(&d->dict); if (entry == NULL) return (0); if (data) *data = entry->data; SPLAY_REMOVE(_dict, &d->dict, entry); free(entry); d->count -= 1; return (1); } int dict_root(struct dict *d, const char **k, void **data) { struct dictentry *entry; entry = SPLAY_ROOT(&d->dict); if (entry == NULL) return (0); if (k) *k = entry->key; if (data) *data = entry->data; return (1); } int dict_iter(struct dict *d, void **hdl, const char **k, void **data) { struct dictentry *curr = *hdl; if (curr == NULL) curr = SPLAY_MIN(_dict, &d->dict); else curr = SPLAY_NEXT(_dict, &d->dict, curr); if (curr) { *hdl = curr; if (k) *k = curr->key; if (data) *data = curr->data; return (1); } return (0); } int dict_iterfrom(struct dict *d, void **hdl, const char *kfrom, const char **k, void **data) { struct dictentry *curr = *hdl, key; if (curr == NULL) { if (kfrom == NULL) curr = SPLAY_MIN(_dict, &d->dict); else { key.key = kfrom; curr = SPLAY_FIND(_dict, &d->dict, &key); if (curr == NULL) { SPLAY_INSERT(_dict, &d->dict, &key); curr = SPLAY_NEXT(_dict, &d->dict, &key); SPLAY_REMOVE(_dict, &d->dict, &key); } } } else curr = SPLAY_NEXT(_dict, &d->dict, curr); if (curr) { *hdl = curr; if (k) *k = curr->key; if (data) *data = curr->data; return (1); } return (0); } void dict_merge(struct dict *dst, struct dict *src) { struct dictentry *entry; while (!SPLAY_EMPTY(&src->dict)) { entry = SPLAY_ROOT(&src->dict); SPLAY_REMOVE(_dict, &src->dict, entry); if (SPLAY_INSERT(_dict, &dst->dict, entry)) fatalx("dict_merge: duplicate"); } dst->count += src->count; src->count = 0; } static int dictentry_cmp(struct dictentry *a, struct dictentry *b) { return strcmp(a->key, b->key); } SPLAY_GENERATE(_dict, dictentry, entry, dictentry_cmp); OpenSMTPD-table-ldap-5d756da/dict.h000066400000000000000000000034511461416456400167610ustar00rootroot00000000000000/* $OpenBSD: dict.h,v 1.1 2018/12/23 16:06:24 gilles Exp $ */ /* * Copyright (c) 2013 Eric Faurot * Copyright (c) 2011 Gilles Chehade * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _DICT_H_ #define _DICT_H_ SPLAY_HEAD(_dict, dictentry); struct dict { struct _dict dict; size_t count; }; /* dict.c */ #define dict_init(d) do { SPLAY_INIT(&((d)->dict)); (d)->count = 0; } while(0) #define dict_empty(d) SPLAY_EMPTY(&((d)->dict)) #define dict_count(d) ((d)->count) int dict_check(struct dict *, const char *); void *dict_set(struct dict *, const char *, void *); void dict_xset(struct dict *, const char *, void *); void *dict_get(struct dict *, const char *); void *dict_xget(struct dict *, const char *); void *dict_pop(struct dict *, const char *); void *dict_xpop(struct dict *, const char *); int dict_poproot(struct dict *, void **); int dict_root(struct dict *, const char **, void **); int dict_iter(struct dict *, void **, const char **, void **); int dict_iterfrom(struct dict *, void **, const char *, const char **, void **); void dict_merge(struct dict *, struct dict *); #endif OpenSMTPD-table-ldap-5d756da/log.c000066400000000000000000000072331461416456400166140ustar00rootroot00000000000000/* $OpenBSD$ */ /* * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "compat.h" #include #include #include #include #include #include #include #include #include #include "log.h" #define TRACE_DEBUG 0x1 static int foreground; static int verbose; void vlog(int, const char *, va_list); void logit(int, const char *, ...) __attribute__((format (printf, 2, 3))); void log_init(int n_foreground) { foreground = n_foreground; if (!foreground) openlog(getprogname(), LOG_PID | LOG_NDELAY, LOG_MAIL); tzset(); } void log_setverbose(int v) { verbose = v; } void logit(int pri, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vlog(pri, fmt, ap); va_end(ap); } void vlog(int pri, const char *fmt, va_list ap) { char *nfmt; if (foreground) { /* best effort in out of mem situations */ if (asprintf(&nfmt, "%s[%u]: %s\n", getprogname(), getpid(), fmt) == -1) { fprintf(stderr, "%s[%u]: ", getprogname(), getpid()); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); } else { vfprintf(stderr, nfmt, ap); free(nfmt); } fflush(stderr); } else vsyslog(pri, fmt, ap); } void log_warn(const char *emsg, ...) { char *nfmt; va_list ap; /* best effort to even work in out of memory situations */ if (emsg == NULL) logit(LOG_CRIT, "%s", strerror(errno)); else { va_start(ap, emsg); if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) { /* we tried it... */ vlog(LOG_CRIT, emsg, ap); logit(LOG_CRIT, "%s", strerror(errno)); } else { vlog(LOG_CRIT, nfmt, ap); free(nfmt); } va_end(ap); } } void log_warnx(const char *emsg, ...) { va_list ap; va_start(ap, emsg); vlog(LOG_CRIT, emsg, ap); va_end(ap); } void log_info(const char *emsg, ...) { va_list ap; va_start(ap, emsg); vlog(LOG_INFO, emsg, ap); va_end(ap); } void log_debug(const char *emsg, ...) { va_list ap; if (verbose & TRACE_DEBUG) { va_start(ap, emsg); vlog(LOG_DEBUG, emsg, ap); va_end(ap); } } void log_trace(int mask, const char *emsg, ...) { va_list ap; if (verbose & mask) { va_start(ap, emsg); vlog(LOG_DEBUG, emsg, ap); va_end(ap); } } static void fatal_arg(const char *emsg, va_list ap) { #define FATALBUFSIZE 1024 static char ebuffer[FATALBUFSIZE]; if (emsg == NULL) (void)strlcpy(ebuffer, strerror(errno), sizeof ebuffer); else { if (errno) { (void)vsnprintf(ebuffer, sizeof ebuffer, emsg, ap); (void)strlcat(ebuffer, ": ", sizeof ebuffer); (void)strlcat(ebuffer, strerror(errno), sizeof ebuffer); } else (void)vsnprintf(ebuffer, sizeof ebuffer, emsg, ap); } logit(LOG_CRIT, "fatal: %s", ebuffer); } void fatal(const char *emsg, ...) { va_list ap; va_start(ap, emsg); fatal_arg(emsg, ap); va_end(ap); exit(1); } void fatalx(const char *emsg, ...) { va_list ap; errno = 0; va_start(ap, emsg); fatal_arg(emsg, ap); va_end(ap); exit(1); } OpenSMTPD-table-ldap-5d756da/log.h000066400000000000000000000032621461416456400166170ustar00rootroot00000000000000/* $OpenBSD: log.h,v 1.9 2021/12/13 18:28:40 deraadt Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LOG_H #define LOG_H #include void log_init(int); void log_procinit(const char *); void log_setverbose(int); int log_getverbose(void); void log_warn(const char *, ...) __attribute__((__format__ (printf, 1, 2))); void log_warnx(const char *, ...) __attribute__((__format__ (printf, 1, 2))); void log_info(const char *, ...) __attribute__((__format__ (printf, 1, 2))); void log_debug(const char *, ...) __attribute__((__format__ (printf, 1, 2))); void logit(int, const char *, ...) __attribute__((__format__ (printf, 2, 3))); void vlog(int, const char *, va_list) __attribute__((__format__ (printf, 2, 0))); __dead void fatal(const char *, ...) __attribute__((__format__ (printf, 1, 2))); __dead void fatalx(const char *, ...) __attribute__((__format__ (printf, 1, 2))); #endif /* LOG_H */ OpenSMTPD-table-ldap-5d756da/openbsd-compat/000077500000000000000000000000001461416456400205755ustar00rootroot00000000000000OpenSMTPD-table-ldap-5d756da/openbsd-compat/asprintf.c000066400000000000000000000027011461416456400225670ustar00rootroot00000000000000/* * Copyright (c) 2006 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "../compat.h" #include #include #include #include #include static int vasprintf(char **ret, const char *fmt, va_list ap) { int n; va_list ap2; va_copy(ap2, ap); if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0) goto error; if ((*ret = malloc(n + 1)) == NULL) goto error; if ((n = vsnprintf(*ret, n + 1, fmt, ap2)) < 0) { free(*ret); goto error; } va_end(ap2); return (n); error: va_end(ap2); *ret = NULL; return (-1); } int asprintf(char **ret, const char *fmt, ...) { va_list ap; int n; va_start(ap, fmt); n = vasprintf(ret, fmt, ap); va_end(ap); return (n); } OpenSMTPD-table-ldap-5d756da/openbsd-compat/err.c000066400000000000000000000033261461416456400215350ustar00rootroot00000000000000/* * Copyright (c) 2021 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "compat.h" static void vwarn(const char*, va_list); static void vwarnx(const char*, va_list); static void vwarn(const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); vfprintf(stderr, fmt, ap); fprintf(stderr, ": %s\n", strerror(errno)); } static void vwarnx(const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); } void err(int ret, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarn(fmt, ap); va_end(ap); exit(ret); } void errx(int ret, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarnx(fmt, ap); va_end(ap); exit(ret); } void warn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarn(fmt, ap); va_end(ap); } void warnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarnx(fmt, ap); va_end(ap); } OpenSMTPD-table-ldap-5d756da/openbsd-compat/err.h000066400000000000000000000003421461416456400215350ustar00rootroot00000000000000#include "../compat.h" #ifdef HAVE_ERR # include_next #else __dead void err(int, const char *, ...); __dead void errx(int, const char *, ...); void warn(const char *, ...); void warnx(const char *, ...); #endif OpenSMTPD-table-ldap-5d756da/openbsd-compat/getprogname.c000066400000000000000000000020511461416456400232470ustar00rootroot00000000000000/* * Copyright (c) 2021 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "../compat.h" #if HAVE_PROGRAM_INVOCATION_SHORT_NAME #include extern char *program_invocation_short_name; const char * getprogname(void) { return program_invocation_short_name; } #else const char * getprogname(void) { return "table-passwd"; } #endif OpenSMTPD-table-ldap-5d756da/openbsd-compat/strlcat.c000066400000000000000000000032401461416456400224140ustar00rootroot00000000000000/* * Copyright (c) 1998, 2015 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "../compat.h" #include #include /* * Appends src to string dst of size dsize (unlike strncat, dsize is the * full size of dst, not space left). At most dsize-1 characters * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). * Returns strlen(src) + MIN(dsize, strlen(initial dst)). * If retval >= dsize, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t dsize) { const char *odst = dst; const char *osrc = src; size_t n = dsize; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end. */ while (n-- != 0 && *dst != '\0') dst++; dlen = dst - odst; n = dsize - dlen; if (n-- == 0) return(dlen + strlen(src)); while (*src != '\0') { if (n != 0) { *dst++ = *src; n--; } src++; } *dst = '\0'; return(dlen + (src - osrc)); /* count does not include NUL */ } OpenSMTPD-table-ldap-5d756da/openbsd-compat/strlcpy.c000066400000000000000000000030151461416456400224400ustar00rootroot00000000000000/* * Copyright (c) 1998, 2015 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "../compat.h" #include #include /* * Copy string src to buffer dst of size dsize. At most dsize-1 * chars will be copied. Always NUL terminates (unless dsize == 0). * Returns strlen(src); if retval >= dsize, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t dsize) { const char *osrc = src; size_t nleft = dsize; /* Copy as many bytes as will fit. */ if (nleft != 0) { while (--nleft != 0) { if ((*dst++ = *src++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src. */ if (nleft == 0) { if (dsize != 0) *dst = '\0'; /* NUL-terminate dst */ while (*src++) ; } return(src - osrc - 1); /* count does not include NUL */ } OpenSMTPD-table-ldap-5d756da/openbsd-compat/strsep.c000066400000000000000000000050371461416456400222660ustar00rootroot00000000000000/* $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* OPENBSD ORIGINAL: lib/libc/string/strsep.c */ #include "../compat.h" #include #include /* * Get next token from string *stringp, where tokens are possibly-empty * strings separated by characters from delim. * * Writes NULs into the string at *stringp to end tokens. * delim need not remain constant from call to call. * On return, *stringp points past the last NUL written (if there might * be further tokens), or is NULL (if there are definitely no more tokens). * * If *stringp is NULL, strsep returns NULL. */ char * strsep(char **stringp, const char *delim) { char *s; const char *spanp; int c, sc; char *tok; if ((s = *stringp) == NULL) return (NULL); for (tok = s;;) { c = *s++; spanp = delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; *stringp = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ } OpenSMTPD-table-ldap-5d756da/openbsd-compat/strtonum.c000066400000000000000000000034041461416456400226350ustar00rootroot00000000000000/* $OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $ */ /* * Copyright (c) 2004 Ted Unangst and Todd Miller * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "../compat.h" #include #include #include #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; int error = 0; char *ep; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "invalid", EINVAL }, { "too small", ERANGE }, { "too large", ERANGE }, }; ev[0].err = errno; errno = 0; if (minval > maxval) { error = INVALID; } else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = INVALID; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = TOOSMALL; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = TOOLARGE; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } OpenSMTPD-table-ldap-5d756da/openbsd-compat/tree/000077500000000000000000000000001461416456400215345ustar00rootroot00000000000000OpenSMTPD-table-ldap-5d756da/openbsd-compat/tree/sys/000077500000000000000000000000001461416456400223525ustar00rootroot00000000000000OpenSMTPD-table-ldap-5d756da/openbsd-compat/tree/sys/tree.h000066400000000000000000001017461461416456400234730ustar00rootroot00000000000000/* $OpenBSD: tree.h,v 1.30 2020/10/10 18:03:41 otto Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ #include /* * Local modifications: * - dropped __unused * - __inline -> inline */ /* * This file defines data structures for different types of trees: * splay trees and red-black trees. * * A splay tree is a self-organizing data structure. Every operation * on the tree causes a splay to happen. The splay moves the requested * node to the root of the tree and partly rebalances it. * * This has the benefit that request locality causes faster lookups as * the requested nodes move to the top of the tree. On the other hand, * every lookup causes memory writes. * * The Balance Theorem bounds the total access time for m operations * and n inserts on an initially empty tree as O((m + n)lg n). The * amortized cost for a sequence of m accesses to a splay tree is O(lg n); * * A red-black tree is a binary search tree with the node color as an * extra attribute. It fulfills a set of conditions: * - every search path from the root to a leaf consists of the * same number of black nodes, * - each red node (except for the root) has a black parent, * - each leaf node is black. * * Every operation on a red-black tree is bounded as O(lg n). * The maximum height of a red-black tree is 2lg (n+1). */ #define SPLAY_HEAD(name, type) \ struct name { \ struct type *sph_root; /* root of the tree */ \ } #define SPLAY_INITIALIZER(root) \ { NULL } #define SPLAY_INIT(root) do { \ (root)->sph_root = NULL; \ } while (0) #define SPLAY_ENTRY(type) \ struct { \ struct type *spe_left; /* left element */ \ struct type *spe_right; /* right element */ \ } #define SPLAY_LEFT(elm, field) (elm)->field.spe_left #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right #define SPLAY_ROOT(head) (head)->sph_root #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_LINKLEFT(head, tmp, field) do { \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ } while (0) #define SPLAY_LINKRIGHT(head, tmp, field) do { \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ } while (0) #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ } while (0) /* Generates prototypes and inline functions */ #define SPLAY_PROTOTYPE(name, type, field, cmp) \ void name##_SPLAY(struct name *, struct type *); \ void name##_SPLAY_MINMAX(struct name *, int); \ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ \ /* Finds the node with the same key as elm */ \ static inline struct type * \ name##_SPLAY_FIND(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) \ return(NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) \ return (head->sph_root); \ return (NULL); \ } \ \ static inline struct type * \ name##_SPLAY_NEXT(struct name *head, struct type *elm) \ { \ name##_SPLAY(head, elm); \ if (SPLAY_RIGHT(elm, field) != NULL) { \ elm = SPLAY_RIGHT(elm, field); \ while (SPLAY_LEFT(elm, field) != NULL) { \ elm = SPLAY_LEFT(elm, field); \ } \ } else \ elm = NULL; \ return (elm); \ } \ \ static inline struct type * \ name##_SPLAY_MIN_MAX(struct name *head, int val) \ { \ name##_SPLAY_MINMAX(head, val); \ return (SPLAY_ROOT(head)); \ } /* Main splay operation. * Moves node close to the key of elm to top */ #define SPLAY_GENERATE(name, type, field, cmp) \ struct type * \ name##_SPLAY_INSERT(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) { \ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ } else { \ int __comp; \ name##_SPLAY(head, elm); \ __comp = (cmp)(elm, (head)->sph_root); \ if(__comp < 0) { \ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ SPLAY_RIGHT(elm, field) = (head)->sph_root; \ SPLAY_LEFT((head)->sph_root, field) = NULL; \ } else if (__comp > 0) { \ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT(elm, field) = (head)->sph_root; \ SPLAY_RIGHT((head)->sph_root, field) = NULL; \ } else \ return ((head)->sph_root); \ } \ (head)->sph_root = (elm); \ return (NULL); \ } \ \ struct type * \ name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ { \ struct type *__tmp; \ if (SPLAY_EMPTY(head)) \ return (NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) { \ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ } else { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ name##_SPLAY(head, elm); \ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ } \ return (elm); \ } \ return (NULL); \ } \ \ void \ name##_SPLAY(struct name *head, struct type *elm) \ { \ struct type __node, *__left, *__right, *__tmp; \ int __comp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while ((__comp = (cmp)(elm, (head)->sph_root))) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) > 0){ \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } \ \ /* Splay with either the minimum or the maximum element \ * Used to find minimum or maximum element in tree. \ */ \ void name##_SPLAY_MINMAX(struct name *head, int __comp) \ { \ struct type __node, *__left, *__right, *__tmp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while (1) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp > 0) { \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } #define SPLAY_NEGINF -1 #define SPLAY_INF 1 #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) #define SPLAY_FOREACH(x, name, head) \ for ((x) = SPLAY_MIN(name, head); \ (x) != NULL; \ (x) = SPLAY_NEXT(name, head, x)) /* Macros that define a red-black tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ } #define RB_INITIALIZER(root) \ { NULL } #define RB_INIT(root) do { \ (root)->rbh_root = NULL; \ } while (0) #define RB_BLACK 0 #define RB_RED 1 #define RB_ENTRY(type) \ struct { \ struct type *rbe_left; /* left element */ \ struct type *rbe_right; /* right element */ \ struct type *rbe_parent; /* parent element */ \ int rbe_color; /* node color */ \ } #define RB_LEFT(elm, field) (elm)->field.rbe_left #define RB_RIGHT(elm, field) (elm)->field.rbe_right #define RB_PARENT(elm, field) (elm)->field.rbe_parent #define RB_COLOR(elm, field) (elm)->field.rbe_color #define RB_ROOT(head) (head)->rbh_root #define RB_EMPTY(head) (RB_ROOT(head) == NULL) #define RB_SET(elm, parent, field) do { \ RB_PARENT(elm, field) = parent; \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ RB_COLOR(elm, field) = RB_RED; \ } while (0) #define RB_SET_BLACKRED(black, red, field) do { \ RB_COLOR(black, field) = RB_BLACK; \ RB_COLOR(red, field) = RB_RED; \ } while (0) #ifndef RB_AUGMENT #define RB_AUGMENT(x) do {} while (0) #endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ (tmp) = RB_RIGHT(elm, field); \ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_LEFT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ (tmp) = RB_LEFT(elm, field); \ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_RIGHT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) /* Generates prototypes and inline functions */ #define RB_PROTOTYPE(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ attr struct type *name##_RB_INSERT(struct name *, struct type *); \ attr struct type *name##_RB_FIND(struct name *, struct type *); \ attr struct type *name##_RB_NFIND(struct name *, struct type *); \ attr struct type *name##_RB_NEXT(struct type *); \ attr struct type *name##_RB_PREV(struct type *); \ attr struct type *name##_RB_MINMAX(struct name *, int); \ \ /* Main rb operation. * Moves node close to the key of elm to top */ #define RB_GENERATE(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp,) #define RB_GENERATE_STATIC(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ attr void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ struct type *parent, *gparent, *tmp; \ while ((parent = RB_PARENT(elm, field)) && \ RB_COLOR(parent, field) == RB_RED) { \ gparent = RB_PARENT(parent, field); \ if (parent == RB_LEFT(gparent, field)) { \ tmp = RB_RIGHT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_RIGHT(parent, field) == elm) { \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_RIGHT(head, gparent, tmp, field); \ } else { \ tmp = RB_LEFT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_LEFT(parent, field) == elm) { \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_LEFT(head, gparent, tmp, field); \ } \ } \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \ } \ \ attr void \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ { \ struct type *tmp; \ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ elm != RB_ROOT(head)) { \ if (RB_LEFT(parent, field) == elm) { \ tmp = RB_RIGHT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = RB_RIGHT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ struct type *oleft; \ if ((oleft = RB_LEFT(tmp, field)))\ RB_COLOR(oleft, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_RIGHT(head, tmp, oleft, field);\ tmp = RB_RIGHT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_RIGHT(tmp, field)) \ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_LEFT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } else { \ tmp = RB_LEFT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = RB_LEFT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ struct type *oright; \ if ((oright = RB_RIGHT(tmp, field)))\ RB_COLOR(oright, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_LEFT(head, tmp, oright, field);\ tmp = RB_LEFT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_LEFT(tmp, field)) \ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_RIGHT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } \ } \ if (elm) \ RB_COLOR(elm, field) = RB_BLACK; \ } \ \ attr struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ struct type *child, *parent, *old = elm; \ int color; \ if (RB_LEFT(elm, field) == NULL) \ child = RB_RIGHT(elm, field); \ else if (RB_RIGHT(elm, field) == NULL) \ child = RB_LEFT(elm, field); \ else { \ struct type *left; \ elm = RB_RIGHT(elm, field); \ while ((left = RB_LEFT(elm, field))) \ elm = left; \ child = RB_RIGHT(elm, field); \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ if (RB_PARENT(elm, field) == old) \ parent = elm; \ (elm)->field = (old)->field; \ if (RB_PARENT(old, field)) { \ if (RB_LEFT(RB_PARENT(old, field), field) == old)\ RB_LEFT(RB_PARENT(old, field), field) = elm;\ else \ RB_RIGHT(RB_PARENT(old, field), field) = elm;\ RB_AUGMENT(RB_PARENT(old, field)); \ } else \ RB_ROOT(head) = elm; \ RB_PARENT(RB_LEFT(old, field), field) = elm; \ if (RB_RIGHT(old, field)) \ RB_PARENT(RB_RIGHT(old, field), field) = elm; \ if (parent) { \ left = parent; \ do { \ RB_AUGMENT(left); \ } while ((left = RB_PARENT(left, field))); \ } \ goto color; \ } \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ color: \ if (color == RB_BLACK) \ name##_RB_REMOVE_COLOR(head, parent, child); \ return (old); \ } \ \ /* Inserts a node into the RB tree */ \ attr struct type * \ name##_RB_INSERT(struct name *head, struct type *elm) \ { \ struct type *tmp; \ struct type *parent = NULL; \ int comp = 0; \ tmp = RB_ROOT(head); \ while (tmp) { \ parent = tmp; \ comp = (cmp)(elm, parent); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ RB_SET(elm, parent, field); \ if (parent != NULL) { \ if (comp < 0) \ RB_LEFT(parent, field) = elm; \ else \ RB_RIGHT(parent, field) = elm; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = elm; \ name##_RB_INSERT_COLOR(head, elm); \ return (NULL); \ } \ \ /* Finds the node with the same key as elm */ \ attr struct type * \ name##_RB_FIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (NULL); \ } \ \ /* Finds the first node greater than or equal to the search key */ \ attr struct type * \ name##_RB_NFIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *res = NULL; \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) { \ res = tmp; \ tmp = RB_LEFT(tmp, field); \ } \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (res); \ } \ \ /* ARGSUSED */ \ attr struct type * \ name##_RB_NEXT(struct type *elm) \ { \ if (RB_RIGHT(elm, field)) { \ elm = RB_RIGHT(elm, field); \ while (RB_LEFT(elm, field)) \ elm = RB_LEFT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ /* ARGSUSED */ \ attr struct type * \ name##_RB_PREV(struct type *elm) \ { \ if (RB_LEFT(elm, field)) { \ elm = RB_LEFT(elm, field); \ while (RB_RIGHT(elm, field)) \ elm = RB_RIGHT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ attr struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *parent = NULL; \ while (tmp) { \ parent = tmp; \ if (val < 0) \ tmp = RB_LEFT(tmp, field); \ else \ tmp = RB_RIGHT(tmp, field); \ } \ return (parent); \ } #define RB_NEGINF -1 #define RB_INF 1 #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) #define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y) #define RB_PREV(name, x, y) name##_RB_PREV(y) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) #define RB_FOREACH(x, name, head) \ for ((x) = RB_MIN(name, head); \ (x) != NULL; \ (x) = name##_RB_NEXT(x)) #define RB_FOREACH_SAFE(x, name, head, y) \ for ((x) = RB_MIN(name, head); \ ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \ (x) = (y)) #define RB_FOREACH_REVERSE(x, name, head) \ for ((x) = RB_MAX(name, head); \ (x) != NULL; \ (x) = name##_RB_PREV(x)) #define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ for ((x) = RB_MAX(name, head); \ ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \ (x) = (y)) /* * Copyright (c) 2016 David Gwynne * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct rb_type { int (*t_compare)(const void *, const void *); void (*t_augment)(void *); unsigned int t_offset; /* offset of rb_entry in type */ }; struct rb_tree { struct rb_entry *rbt_root; }; struct rb_entry { struct rb_entry *rbt_parent; struct rb_entry *rbt_left; struct rb_entry *rbt_right; unsigned int rbt_color; }; #define RBT_HEAD(_name, _type) \ struct _name { \ struct rb_tree rbh_root; \ } #define RBT_ENTRY(_type) struct rb_entry static inline void _rb_init(struct rb_tree *rbt) { rbt->rbt_root = NULL; } static inline int _rb_empty(struct rb_tree *rbt) { return (rbt->rbt_root == NULL); } void *_rb_insert(const struct rb_type *, struct rb_tree *, void *); void *_rb_remove(const struct rb_type *, struct rb_tree *, void *); void *_rb_find(const struct rb_type *, struct rb_tree *, const void *); void *_rb_nfind(const struct rb_type *, struct rb_tree *, const void *); void *_rb_root(const struct rb_type *, struct rb_tree *); void *_rb_min(const struct rb_type *, struct rb_tree *); void *_rb_max(const struct rb_type *, struct rb_tree *); void *_rb_next(const struct rb_type *, void *); void *_rb_prev(const struct rb_type *, void *); void *_rb_left(const struct rb_type *, void *); void *_rb_right(const struct rb_type *, void *); void *_rb_parent(const struct rb_type *, void *); void _rb_set_left(const struct rb_type *, void *, void *); void _rb_set_right(const struct rb_type *, void *, void *); void _rb_set_parent(const struct rb_type *, void *, void *); void _rb_poison(const struct rb_type *, void *, unsigned long); int _rb_check(const struct rb_type *, void *, unsigned long); #define RBT_INITIALIZER(_head) { { NULL } } #define RBT_PROTOTYPE(_name, _type, _field, _cmp) \ extern const struct rb_type *const _name##_RBT_TYPE; \ \ static inline void \ _name##_RBT_INIT(struct _name *head) \ { \ _rb_init(&head->rbh_root); \ } \ \ static inline struct _type * \ _name##_RBT_INSERT(struct _name *head, struct _type *elm) \ { \ return _rb_insert(_name##_RBT_TYPE, &head->rbh_root, elm); \ } \ \ static inline struct _type * \ _name##_RBT_REMOVE(struct _name *head, struct _type *elm) \ { \ return _rb_remove(_name##_RBT_TYPE, &head->rbh_root, elm); \ } \ \ static inline struct _type * \ _name##_RBT_FIND(struct _name *head, const struct _type *key) \ { \ return _rb_find(_name##_RBT_TYPE, &head->rbh_root, key); \ } \ \ static inline struct _type * \ _name##_RBT_NFIND(struct _name *head, const struct _type *key) \ { \ return _rb_nfind(_name##_RBT_TYPE, &head->rbh_root, key); \ } \ \ static inline struct _type * \ _name##_RBT_ROOT(struct _name *head) \ { \ return _rb_root(_name##_RBT_TYPE, &head->rbh_root); \ } \ \ static inline int \ _name##_RBT_EMPTY(struct _name *head) \ { \ return _rb_empty(&head->rbh_root); \ } \ \ static inline struct _type * \ _name##_RBT_MIN(struct _name *head) \ { \ return _rb_min(_name##_RBT_TYPE, &head->rbh_root); \ } \ \ static inline struct _type * \ _name##_RBT_MAX(struct _name *head) \ { \ return _rb_max(_name##_RBT_TYPE, &head->rbh_root); \ } \ \ static inline struct _type * \ _name##_RBT_NEXT(struct _type *elm) \ { \ return _rb_next(_name##_RBT_TYPE, elm); \ } \ \ static inline struct _type * \ _name##_RBT_PREV(struct _type *elm) \ { \ return _rb_prev(_name##_RBT_TYPE, elm); \ } \ \ static inline struct _type * \ _name##_RBT_LEFT(struct _type *elm) \ { \ return _rb_left(_name##_RBT_TYPE, elm); \ } \ \ static inline struct _type * \ _name##_RBT_RIGHT(struct _type *elm) \ { \ return _rb_right(_name##_RBT_TYPE, elm); \ } \ \ static inline struct _type * \ _name##_RBT_PARENT(struct _type *elm) \ { \ return _rb_parent(_name##_RBT_TYPE, elm); \ } \ \ static inline void \ _name##_RBT_SET_LEFT(struct _type *elm, struct _type *left) \ { \ _rb_set_left(_name##_RBT_TYPE, elm, left); \ } \ \ static inline void \ _name##_RBT_SET_RIGHT(struct _type *elm, struct _type *right) \ { \ _rb_set_right(_name##_RBT_TYPE, elm, right); \ } \ \ static inline void \ _name##_RBT_SET_PARENT(struct _type *elm, struct _type *parent) \ { \ _rb_set_parent(_name##_RBT_TYPE, elm, parent); \ } \ \ static inline void \ _name##_RBT_POISON(struct _type *elm, unsigned long poison) \ { \ _rb_poison(_name##_RBT_TYPE, elm, poison); \ } \ \ static inline int \ _name##_RBT_CHECK(struct _type *elm, unsigned long poison) \ { \ return _rb_check(_name##_RBT_TYPE, elm, poison); \ } #define RBT_GENERATE_INTERNAL(_name, _type, _field, _cmp, _aug) \ static int \ _name##_RBT_COMPARE(const void *lptr, const void *rptr) \ { \ const struct _type *l = lptr, *r = rptr; \ return _cmp(l, r); \ } \ static const struct rb_type _name##_RBT_INFO = { \ _name##_RBT_COMPARE, \ _aug, \ offsetof(struct _type, _field), \ }; \ const struct rb_type *const _name##_RBT_TYPE = &_name##_RBT_INFO #define RBT_GENERATE_AUGMENT(_name, _type, _field, _cmp, _aug) \ static void \ _name##_RBT_AUGMENT(void *ptr) \ { \ struct _type *p = ptr; \ return _aug(p); \ } \ RBT_GENERATE_INTERNAL(_name, _type, _field, _cmp, _name##_RBT_AUGMENT) #define RBT_GENERATE(_name, _type, _field, _cmp) \ RBT_GENERATE_INTERNAL(_name, _type, _field, _cmp, NULL) #define RBT_INIT(_name, _head) _name##_RBT_INIT(_head) #define RBT_INSERT(_name, _head, _elm) _name##_RBT_INSERT(_head, _elm) #define RBT_REMOVE(_name, _head, _elm) _name##_RBT_REMOVE(_head, _elm) #define RBT_FIND(_name, _head, _key) _name##_RBT_FIND(_head, _key) #define RBT_NFIND(_name, _head, _key) _name##_RBT_NFIND(_head, _key) #define RBT_ROOT(_name, _head) _name##_RBT_ROOT(_head) #define RBT_EMPTY(_name, _head) _name##_RBT_EMPTY(_head) #define RBT_MIN(_name, _head) _name##_RBT_MIN(_head) #define RBT_MAX(_name, _head) _name##_RBT_MAX(_head) #define RBT_NEXT(_name, _elm) _name##_RBT_NEXT(_elm) #define RBT_PREV(_name, _elm) _name##_RBT_PREV(_elm) #define RBT_LEFT(_name, _elm) _name##_RBT_LEFT(_elm) #define RBT_RIGHT(_name, _elm) _name##_RBT_RIGHT(_elm) #define RBT_PARENT(_name, _elm) _name##_RBT_PARENT(_elm) #define RBT_SET_LEFT(_name, _elm, _l) _name##_RBT_SET_LEFT(_elm, _l) #define RBT_SET_RIGHT(_name, _elm, _r) _name##_RBT_SET_RIGHT(_elm, _r) #define RBT_SET_PARENT(_name, _elm, _p) _name##_RBT_SET_PARENT(_elm, _p) #define RBT_POISON(_name, _elm, _p) _name##_RBT_POISON(_elm, _p) #define RBT_CHECK(_name, _elm, _p) _name##_RBT_CHECK(_elm, _p) #define RBT_FOREACH(_e, _name, _head) \ for ((_e) = RBT_MIN(_name, (_head)); \ (_e) != NULL; \ (_e) = RBT_NEXT(_name, (_e))) #define RBT_FOREACH_SAFE(_e, _name, _head, _n) \ for ((_e) = RBT_MIN(_name, (_head)); \ (_e) != NULL && ((_n) = RBT_NEXT(_name, (_e)), 1); \ (_e) = (_n)) #define RBT_FOREACH_REVERSE(_e, _name, _head) \ for ((_e) = RBT_MAX(_name, (_head)); \ (_e) != NULL; \ (_e) = RBT_PREV(_name, (_e))) #define RBT_FOREACH_REVERSE_SAFE(_e, _name, _head, _n) \ for ((_e) = RBT_MAX(_name, (_head)); \ (_e) != NULL && ((_n) = RBT_PREV(_name, (_e)), 1); \ (_e) = (_n)) #endif /* _SYS_TREE_H_ */ OpenSMTPD-table-ldap-5d756da/shell.nix000066400000000000000000000002561461416456400175140ustar00rootroot00000000000000{ pkgs ? import {} }: pkgs.mkShell { nativeBuildInputs = with pkgs; [ autoreconfHook pkg-config gdb mandoc ]; buildInputs = with pkgs; [ libbsd libressl ]; } OpenSMTPD-table-ldap-5d756da/table-ldap.conf.example000066400000000000000000000032451461416456400221740ustar00rootroot00000000000000# basic ldap config: url username password basedn url: ldap://ldap.example.com username: cn=smtpd,cn=sysaccounts,cn=etc,dc=example,dc=com password: totalsecure basedn: cn=users,cn=accounts,dc=example,dc=com # filter/atributes for alias / virtual table usage # key will be the user / mailaddr # attributes is the destintion. in this example a user, but can also be an other mailaddress alias_filter: (&(objectclass=person)(mail=%s)) alias_attributes: uid # key is the username (supplide by the client) # attributes are the username and the hashed password # problem with this is, it needs to be able to read the hashed password credentials_filter: (&(objectclass=posixaccount)(uid=%s)) credentials_attributes: uid, authPassword # domain table (list) # used in match for domain # atribute not realy intresting but need to be set domain_filter: (&(objectclass=dnsdomain)(cn=%s)) domain_attributes: cn # userinfo # for extra userinfo # search for a username # attributes uid gid homedir userinfo_filter: (&(objectclass=posixaccount)(uid=%s)) userinfo_attributes: uidNumber, gidNumber, homedir # mailaddr info # list of mailaddresses for a match statement # attribute will be ignored, but needed for ldap mailaddr_filter: (&(objectclass=posixaccount)(mail=%s)) mailaddr_attributes: mail # mailaddrmap # used for listen on ... sender # maps the auth user to allowed mail addresses mailaddrmap_filter: (&(objectclass=posixaccount)(uid=%s)) mailaddrmap_attributes: mail # netaddr info # used for "match from src # propaly not that usefull because the key is the ip address and cidr mapping is not done netaddr_filter: (&(objectclass=host)(ipaddr=%s)) netaddr_attributes: ipaddr OpenSMTPD-table-ldap-5d756da/table_ldap.c000066400000000000000000000310751461416456400201230ustar00rootroot00000000000000/* * Copyright (c) 2013 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "compat.h" #include #include #include #include #include #include #include #include #include #include #include "aldap.h" #include "dict.h" #include "log.h" #include "table_stdio.h" #include "util.h" #define MAX_LDAP_IDENTIFIER 32 #define MAX_LDAP_URL 256 #define MAX_LDAP_USERNAME 256 #define MAX_LDAP_PASSWORD 256 #define MAX_LDAP_BASELEN 128 #define MAX_LDAP_FILTERLEN 1024 #define MAX_LDAP_FIELDLEN 128 enum { LDAP_ALIAS = 0, LDAP_DOMAIN, LDAP_CREDENTIALS, LDAP_NETADDR, LDAP_USERINFO, LDAP_SOURCE, LDAP_MAILADDR, LDAP_MAILADDRMAP, LDAP_ADDRNAME, LDAP_MAX }; #define MAX_ATTRS 6 struct query { char *filter; char *attrs[MAX_ATTRS]; int attrn; }; static int ldap_run_query(int type, const char *, char *, size_t); static char *config, *url, *username, *password, *basedn; static struct aldap *aldap; static struct query queries[LDAP_MAX]; static int table_ldap_update(void) { return 1; } static int table_ldap_fetch(int service, struct dict *params, char *dst, size_t sz) { return -1; } static struct aldap * ldap_connect(const char *addr) { struct aldap_url lu; 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; } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICSERV; error = getaddrinfo(lu.host, lu.port, &hints, &res0); if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME) return NULL; if (error) { log_warnx("warn: could not parse \"%s:%s\": %s", lu.host, lu.port, gai_strerror(error)); return NULL; } for (res = res0; res; res = res->ai_next) { fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (fd == -1) continue; if (connect(fd, res->ai_addr, res->ai_addrlen) == 0) { aldap_free_url(&lu); return aldap_init(fd); } close(fd); fd = -1; } aldap_free_url(&lu); return NULL; } static int read_value(char **store, const char *key, const char *value) { log_debug("debug: reading key \"%s\" -> \"%s\"", key, value); if (*store) { log_warnx("warn: duplicate key %s", key); return 0; } if ((*store = strdup(value)) == NULL) { log_warn("warn: strdup"); return 0; } return 1; } static int ldap_parse_attributes(struct query *query, const char *key, const char *line, size_t expect) { char buffer[1024]; char *p; size_t m, n; log_debug("debug: parsing attribute \"%s\" (%zu) -> \"%s\"", key, expect, line); if (strlcpy(buffer, line, sizeof buffer) >= sizeof buffer) return 0; m = 1; for (p = buffer; *p; ++p) { if (*p == ',') { *p = 0; m++; } } if (expect != m) return 0; p = buffer; for (n = 0; n < expect; ++n) query->attrs[n] = NULL; for (n = 0; n < m; ++n) { query->attrs[n] = strdup(p); if (query->attrs[n] == NULL) { log_warnx("warn: strdup"); return 0; /* XXX cleanup */ } p += strlen(p) + 1; query->attrn++; } return 1; } static int ldap_config(void) { size_t sz = 0; ssize_t flen; FILE *fp; char *key, *value, *buf = NULL; if ((fp = fopen(config, "r")) == NULL) { log_warn("warn: \"%s\"", config); return 0; } while ((flen = getline(&buf, &sz, fp)) != -1) { if (buf[flen - 1] == '\n') buf[flen - 1] = '\0'; key = strip(buf); if (*key == '\0' || *key == '#') continue; value = key; strsep(&value, " \t:"); if (value) { while (*value) { if (!isspace((unsigned char)*value) && !(*value == ':' && isspace((unsigned char)*(value + 1)))) break; ++value; } if (*value == '\0') value = NULL; } if (value == NULL) { log_warnx("warn: missing value for key %s", key); continue; } if (!strcmp(key, "url")) read_value(&url, key, value); else if (!strcmp(key, "username")) read_value(&username, key, value); else if (!strcmp(key, "password")) read_value(&password, key, value); else if (!strcmp(key, "basedn")) read_value(&basedn, key, value); else if (!strcmp(key, "alias_filter")) read_value(&queries[LDAP_ALIAS].filter, key, value); else if (!strcmp(key, "alias_attributes")) { ldap_parse_attributes(&queries[LDAP_ALIAS], key, value, 1); } else if (!strcmp(key, "credentials_filter")) read_value(&queries[LDAP_CREDENTIALS].filter, key, value); else if (!strcmp(key, "credentials_attributes")) { ldap_parse_attributes(&queries[LDAP_CREDENTIALS], key, value, 2); } else if (!strcmp(key, "domain_filter")) read_value(&queries[LDAP_DOMAIN].filter, key, value); else if (!strcmp(key, "domain_attributes")) { ldap_parse_attributes(&queries[LDAP_DOMAIN], key, value, 1); } else if (!strcmp(key, "userinfo_filter")) read_value(&queries[LDAP_USERINFO].filter, key, value); else if (!strcmp(key, "userinfo_attributes")) { ldap_parse_attributes(&queries[LDAP_USERINFO], key, value, 3); } else if (!strcmp(key, "mailaddr_filter")) read_value(&queries[LDAP_MAILADDR].filter, key, value); else if (!strcmp(key, "mailaddr_attributes")) { ldap_parse_attributes(&queries[LDAP_MAILADDR], key, value, 1); } else if (!strcmp(key, "mailaddrmap_filter")) read_value(&queries[LDAP_MAILADDRMAP].filter, key, value); else if (!strcmp(key, "mailaddrmap_attributes")) { ldap_parse_attributes(&queries[LDAP_MAILADDRMAP], key, value, 1); } else if (!strcmp(key, "netaddr_filter")) read_value(&queries[LDAP_NETADDR].filter, key, value); else if (!strcmp(key, "netaddr_attributes")) { ldap_parse_attributes(&queries[LDAP_NETADDR], key, value, 1); } else log_warnx("warn: bogus entry \"%s\"", key); } free(buf); fclose(fp); return 1; } static int ldap_open(void) { struct aldap_message *amsg = NULL; if (aldap) { aldap_close(aldap); log_info("info: table-ldap: closed previous connection"); } aldap = ldap_connect(url); if (aldap == NULL) { log_warnx("warn: ldap_connect error"); goto err; } if (aldap_bind(aldap, username, password) == -1) { log_warnx("warn: aldap_bind error"); goto err; } if ((amsg = aldap_parse(aldap)) == NULL) { log_warnx("warn: aldap_parse"); goto err; } switch (aldap_get_resultcode(amsg)) { case LDAP_SUCCESS: log_debug("debug: ldap server accepted credentials"); break; case LDAP_INVALID_CREDENTIALS: log_warnx("warn: ldap server refused credentials"); goto err; default: log_warnx("warn: failed to bind, result #%d", aldap_get_resultcode(amsg)); goto err; } if (amsg) aldap_freemsg(amsg); return 1; err: if (aldap) aldap_close(aldap); if (amsg) aldap_freemsg(amsg); return 0; } static int table_ldap_lookup(int service, struct dict *params, const char *key, char *dst, size_t sz) { int ret; switch(service) { case K_ALIAS: case K_DOMAIN: case K_CREDENTIALS: case K_USERINFO: case K_MAILADDR: case K_MAILADDRMAP: case K_NETADDR: if ((ret = ldap_run_query(service, key, dst, sz)) >= 0) { return ret; } log_debug("debug: table-ldap: reconnecting"); if (!ldap_open()) { log_warnx("warn: table-ldap: failed to connect"); return -1; } return ldap_run_query(service, key, dst, sz); default: return -1; } } static int ldap_query(const char *filter, const char *key, char **attributes, char ***outp, size_t n) { struct aldap_message *m = NULL; struct aldap_page_control *pg = NULL; int ret, found; size_t i; char basedn__[MAX_LDAP_BASELEN]; char filter__[MAX_LDAP_FILTERLEN]; char key__[MAX_LDAP_IDENTIFIER]; if (strlcpy(basedn__, basedn, sizeof basedn__) >= sizeof basedn__) return -1; if (strlcpy(filter__, filter, sizeof filter__) >= sizeof filter__) 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__, NULL, 0, 0, 0, pg)) == -1) { log_debug("ret=%d", ret); return -1; } if (pg != NULL) { aldap_freepage(pg); pg = NULL; } while ((m = aldap_parse(aldap)) != NULL) { if (aldap->msgid != m->msgid) goto error; 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; break; } if (m->message_type != LDAP_RES_SEARCH_ENTRY) goto error; found = 1; for (i = 0; i < n; ++i) if (aldap_match_attr(m, attributes[i], &outp[i]) != 1) goto error; aldap_freemsg(m); m = NULL; } } 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 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; switch (type) { case K_ALIAS: q = &queries[LDAP_ALIAS]; break; case K_DOMAIN: q = &queries[LDAP_DOMAIN]; break; case K_CREDENTIALS: q = &queries[LDAP_CREDENTIALS]; break; case K_NETADDR: q = &queries[LDAP_NETADDR]; break; case K_USERINFO: q = &queries[LDAP_USERINFO]; break; case K_SOURCE: q = &queries[LDAP_SOURCE]; break; case K_MAILADDR: q = &queries[LDAP_MAILADDR]; break; case K_MAILADDRMAP: q = &queries[LDAP_MAILADDRMAP]; break; case K_ADDRNAME: q = &queries[LDAP_ADDRNAME]; break; default: return -1; } if (!q->filter) { /* XXX get the string of the type */ log_warnx("warn: query %d without a filter configured", type); return -1; } if (snprintf(filter, sizeof(filter), "%s", q->filter) >= (int)sizeof(filter)) { log_warnx("warn: filter too large"); return -1; } memset(res, 0, sizeof(res)); ret = ldap_query(filter, key, q->attrs, res, q->attrn); if (ret <= 0 || dst == NULL) goto end; switch (type) { case K_ALIAS: memset(dst, 0, sz); for (i = 0; res[0][i]; i++) { if (i && strlcat(dst, ", ", sz) >= sz) { ret = -1; break; } if (strlcat(dst, res[0][i], sz) >= sz) { ret = -1; break; } } break; case K_DOMAIN: case K_MAILADDR: case K_MAILADDRMAP: if (strlcpy(dst, res[0][0], sz) >= sz) ret = -1; break; case K_CREDENTIALS: if (snprintf(dst, sz, "%s:%s", res[0][0], res[1][0]) >= (int)sz) ret = -1; break; case K_USERINFO: if (snprintf(dst, sz, "%s:%s:%s", res[0][0], res[1][0], res[2][0]) >= (int)sz) ret = -1; break; default: log_warnx("warn: unsupported lookup kind"); ret = -1; } if (ret == -1) log_warnx("warn: could not format result"); end: for (i = 0; i < q->attrn; ++i) if (res[i]) aldap_free_attr(res[i]); return ret; } static int table_ldap_check(int service, struct dict *params, const char *key) { int ret; switch(service) { case K_ALIAS: case K_DOMAIN: case K_CREDENTIALS: case K_USERINFO: case K_MAILADDR: case K_MAILADDRMAP: case K_NETADDR: if ((ret = ldap_run_query(service, key, NULL, 0)) >= 0) { return ret; } log_debug("debug: table-ldap: reconnecting"); if (!ldap_open()) { log_warnx("warn: table-ldap: failed to connect"); return -1; } return ldap_run_query(service, key, NULL, 0); default: return -1; } } int main(int argc, char **argv) { int ch; log_init(1); log_setverbose(~0); while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: fatalx("bad option"); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) fatalx("bogus argument(s)"); config = argv[0]; if (!ldap_config()) fatalx("could not parse config"); log_debug("debug: done reading config"); if (!ldap_open()) fatalx("failed to connect"); log_debug("debug: connected"); table_api_on_update(table_ldap_update); table_api_on_check(table_ldap_check); table_api_on_lookup(table_ldap_lookup); table_api_on_fetch(table_ldap_fetch); table_api_dispatch(); return 0; } OpenSMTPD-table-ldap-5d756da/table_stdio.c000066400000000000000000000135371461416456400203300ustar00rootroot00000000000000/* $OpenBSD$ */ /* * Copyright (c) 2024 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" #include #include #include #include #include #include "dict.h" #include "table_stdio.h" static int (*handler_update)(void); static int (*handler_check)(int, struct dict *, const char *); static int (*handler_lookup)(int, struct dict *, const char *, char *, size_t); static int (*handler_fetch)(int, struct dict *, char *, size_t); static char tablename[128]; /* Dummy; just kept for backward compatibility */ static struct dict params; static int service_id(const char *service) { if (!strcmp(service, "alias")) return (K_ALIAS); if (!strcmp(service, "domain")) return (K_DOMAIN); if (!strcmp(service, "credentials")) return (K_CREDENTIALS); if (!strcmp(service, "netaddr")) return (K_NETADDR); if (!strcmp(service, "userinfo")) return (K_USERINFO); if (!strcmp(service, "source")) return (K_SOURCE); if (!strcmp(service, "mailaddr")) return (K_MAILADDR); if (!strcmp(service, "addrname")) return (K_ADDRNAME); if (!strcmp(service, "mailaddrmap")) return (K_MAILADDRMAP); errx(1, "unknown service %s", service); } void table_api_on_update(int(*cb)(void)) { handler_update = cb; } void table_api_on_check(int(*cb)(int, struct dict *, const char *)) { handler_check = cb; } void table_api_on_lookup(int(*cb)(int, struct dict *, const char *, char *, size_t)) { handler_lookup = cb; } void table_api_on_fetch(int(*cb)(int, struct dict *, char *, size_t)) { handler_fetch = cb; } const char * table_api_get_name(void) { return tablename; } int table_api_dispatch(void) { char buf[LINE_MAX]; char *t, *vers, *tname, *type, *service, *id, *key; char *line = NULL; size_t linesize = 0; ssize_t linelen; int i, r, configured = 0; dict_init(¶ms); while ((linelen = getline(&line, &linesize, stdin)) != -1) { if (line[linelen - 1] == '\n') line[--linelen] = '\0'; t = line; if (!configured) { if (strncmp(t, "config|", 7) != 0) errx(1, "unexpected config line: %s", line); t += 7; if (!strcmp(t, "ready")) { configured = 1; /* * XXX register all the services since * we don't have a clue what the table * will do. */ puts("register|alias"); puts("register|domain"); puts("register|credentials"); puts("register|netaddr"); puts("register|userinfo"); puts("register|source");; puts("register|mailaddr"); puts("register|addrname"); puts("register|mailaddrmap"); puts("register|ready"); if (fflush(stdout) == EOF) err(1, "fflush"); continue; } continue; } if (strncmp(t, "table|", 6)) errx(1, "malformed line"); t += 6; vers = t; if ((t = strchr(t, '|')) == NULL) errx(1, "malformed line: missing version"); *t++ = '\0'; if (strcmp(vers, "0.1") != 0) errx(1, "unsupported protocol version: %s", vers); /* skip timestamp */ if ((t = strchr(t, '|')) == NULL) errx(1, "malformed line: missing timestamp"); *t++ = '\0'; tname = t; if ((t = strchr(t, '|')) == NULL) errx(1, "malformed line: missing table name"); *t++ = '\0'; strlcpy(tablename, tname, sizeof(tablename)); type = t; if ((t = strchr(t, '|')) == NULL) errx(1, "malformed line: missing type"); *t++ = '\0'; if (!strcmp(type, "update")) { if (handler_update == NULL) errx(1, "no update handler registered"); id = t; r = handler_update(); printf("update-result|%s|%s\n", id, r == -1 ? "error" : "ok"); if (fflush(stdout) == EOF) err(1, "fflush"); continue; } service = t; if ((t = strchr(t, '|')) == NULL) errx(1, "malformed line: missing service"); *t++ = '\0'; id = t; if (!strcmp(type, "fetch")) { if (handler_fetch == NULL) errx(1, "no fetch handler registered"); r = handler_fetch(service_id(service), ¶ms, buf, sizeof(buf)); if (r == 1) printf("fetch-result|%s|found|%s\n", id, buf); else if (r == 0) printf("fetch-result|%s|not-found\n", id); else printf("fetch-result|%s|error\n", id); if (fflush(stdout) == EOF) err(1, "fflush"); memset(buf, 0, sizeof(buf)); continue; } if ((t = strchr(t, '|')) == NULL) errx(1, "malformed line: missing key"); *t++ = '\0'; key = t; if (!strcmp(type, "check")) { if (handler_check == NULL) errx(1, "no check handler registered"); r = handler_check(service_id(service), ¶ms, key); if (r == 1) printf("check-result|%s|found\n", id); else if (r == 0) printf("check-result|%s|not-found\n", id); else printf("check-result|%s|error\n", id); } else if (!strcmp(type, "lookup")) { if (handler_lookup == NULL) errx(1, "no lookup handler registered"); r = handler_lookup(service_id(service), ¶ms, key, buf, sizeof(buf)); if (r == 1) printf("lookup-result|%s|found|%s\n", id, buf); else if (r == 0) printf("lookup-result|%s|not-found\n", id); else printf("lookup-result|%s|error\n", id); memset(buf, 0, sizeof(buf)); } else errx(1, "unknown action %s", type); if (fflush(stdout) == EOF) err(1, "fflush"); } if (ferror(stdin)) err(1, "getline"); return (0); } OpenSMTPD-table-ldap-5d756da/table_stdio.h000066400000000000000000000032241461416456400203250ustar00rootroot00000000000000/* * Copyright (c) 2013 Eric Faurot * Copyright (c) 2011 Gilles Chehade * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ enum table_service { K_ALIAS = 0x001, /* returns struct expand */ K_DOMAIN = 0x002, /* returns struct destination */ K_CREDENTIALS = 0x004, /* returns struct credentials */ K_NETADDR = 0x008, /* returns struct netaddr */ K_USERINFO = 0x010, /* returns struct userinfo */ K_SOURCE = 0x020, /* returns struct source */ K_MAILADDR = 0x040, /* returns struct mailaddr */ K_ADDRNAME = 0x080, /* returns struct addrname */ K_MAILADDRMAP = 0x100, /* returns struct mailaddr */ K_ANY = 0xfff, }; void table_api_on_update(int(*)(void)); void table_api_on_check(int(*)(int, struct dict *, const char *)); void table_api_on_lookup(int(*)(int, struct dict *, const char *, char *, size_t)); void table_api_on_fetch(int(*)(int, struct dict *, char *, size_t)); int table_api_dispatch(void); const char *table_api_get_name(void); OpenSMTPD-table-ldap-5d756da/util.c000066400000000000000000000045641461416456400170140ustar00rootroot00000000000000/* $OpenBSD: util.c,v 1.127 2016/05/16 17:43:18 gilles Exp $ */ /* * Copyright (c) 2000,2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Gilles Chehade * Copyright (c) 2009 Jacek Masiulaniec * Copyright (c) 2012 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "compat.h" #include #include #include #include #include #include #include "log.h" void * xmalloc(size_t size, const char *where) { void *r; if ((r = malloc(size)) == NULL) { log_warnx("%s: malloc(%zu)", where, size); fatalx("exiting"); } return (r); } void * xcalloc(size_t nmemb, size_t size, const char *where) { void *r; if ((r = calloc(nmemb, size)) == NULL) { log_warnx("%s: calloc(%zu, %zu)", where, nmemb, size); fatalx("exiting"); } return (r); } char * xstrdup(const char *str, const char *where) { char *r; if ((r = strdup(str)) == NULL) { log_warnx("%s: strdup(%p)", where, str); fatalx("exiting"); } return (r); } void * xmemdup(const void *ptr, size_t size, const char *where) { void *r; if ((r = malloc(size)) == NULL) { log_warnx("%s: malloc(%zu)", where, size); fatalx("exiting"); } memmove(r, ptr, size); return (r); } char * strip(char *s) { size_t l; while (isspace((unsigned char)*s)) s++; for (l = strlen(s); l; l--) { if (!isspace((unsigned char)s[l-1])) break; s[l-1] = '\0'; } return (s); } int lowercase(char *buf, const char *s, size_t len) { if (len == 0) return 0; if (strlcpy(buf, s, len) >= len) return 0; while (*buf != '\0') { *buf = tolower((unsigned char)*buf); buf++; } return 1; } OpenSMTPD-table-ldap-5d756da/util.h000066400000000000000000000003631461416456400170120ustar00rootroot00000000000000void *xmalloc(size_t, const char *); void *xcalloc(size_t, size_t, const char *); char *xstrdup(const char *, const char *); void *xmemdup(const char *, size_t, const char *); char *strip(char *); int lowercase(char *, const char *, size_t);