freebsd-skq/usr.sbin/ypldap/aldap.c
truckman 610c8f37ed Fix Coverity CIDs 1340544 Resource leak and 1340543 Use after free
At line 479 of ldapclient.c in client_build_req(), the error return
leaks ldap_attrs (CID 1340544).  It looks like this can happen if
the first utoa() call in aldap_get_stringset() fails.  It looks
like other leaks can happen if other utoa() calls fail since scanning
this array when it is freed stops when the first NULL is encountered.
Fix these problems by not storing NULL in the array when utoa()
fails, and by freeing ret and returning NULL if nothing is stored
in the array.  That way the caller will never see the
ldap_attrs[0] == NULL case, so delete that check.

The ber_printf_element() calls ber_free_elements() on its ber
argument and returns NULL on failure.  When each of its callers
detects failure, they do a goto fail, which then calls ber_free_elements()
with the same pointer (CID 1340543).  Fix is to delete the
ber_free_elements() from ber_printf_element()

Reported by:	Coverity
CID:		1340543, 1340544
Reviewed by:	araujo
Differential Revision:	https://reviews.freebsd.org/D6550
2016-05-25 01:37:25 +00:00

1269 lines
25 KiB
C

/* $FreeBSD$ */
/* $Id: aldap.c,v 1.32 2016/04/27 10:53:27 schwarze Exp $ */
/* $OpenBSD: aldap.c,v 1.32 2016/04/27 10:53:27 schwarze Exp $ */
/*
* Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
* Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
*
* 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 <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "aldap.h"
#if 0
#define DEBUG
#endif
#define VERSION 3
static struct ber_element *ldap_parse_search_filter(struct ber_element *,
char *);
static struct ber_element *ldap_do_parse_search_filter(
struct ber_element *, char **);
char **aldap_get_stringset(struct ber_element *);
char *utoa(char *);
static int isu8cont(unsigned char);
char *parseval(char *, size_t);
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, 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,
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)) == 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 ((page = malloc(sizeof(struct aldap_page_control))) == NULL) {
if (elm != 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) {
if (elm != 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)
{
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);
}
#if 0
void
aldap_free_url(struct aldap_url *lu)
{
free(lu->buffer);
free(lu->filter);
}
int
aldap_parse_url(char *url, struct aldap_url *lu)
{
char *p, *forward, *forward2;
const char *errstr = NULL;
int i;
if ((lu->buffer = p = strdup(url)) == NULL)
return (-1);
/* 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
lu->port = strtonum(++forward2, 0, PORT_MAX, &errstr);
if (errstr)
goto fail;
}
}
/* 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:
free(url);
return (1);
fail:
free(lu->buffer);
lu->buffer = NULL;
return (-1);
}
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 /* 0 */
/*
* 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) {
ber_get_string(a, &s);
ret[i] = utoa(s);
if (ret[i] != NULL)
i++;
}
if (i == 0) {
free(ret);
return NULL;
}
ret[i] = 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)
{
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)) == 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)
{
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)) == 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 ((elm = ldap_do_parse_search_filter(root, &cp)) == 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)) ==
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)) == 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;
u_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: <INVALID>(%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, "<INVALID>\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, "<INVALID>\n");
break;
}
fprintf(stderr, "value %lld\n", v);
break;
case BER_TYPE_ENUMERATED:
if (ber_get_enumerated(root, &v) == -1) {
fprintf(stderr, "<INVALID>\n");
break;
}
fprintf(stderr, "value %lld\n", v);
break;
case BER_TYPE_BITSTRING:
if (ber_get_bitstring(root, (void *)&buf, &len) == -1) {
fprintf(stderr, "<INVALID>\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, "<INVALID>\n");
break;
}
fprintf(stderr, "\n");
break;
case BER_TYPE_OCTETSTRING:
if (ber_get_nstring(root, (void *)&buf, &len) == -1) {
fprintf(stderr, "<INVALID>\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
/*
* Strip UTF-8 down to ASCII without validation.
* notes:
* non-ASCII characters are displayed as '?'
* the argument u should be a NULL terminated sequence of UTF-8 bytes.
*/
char *
utoa(char *u)
{
int len, i, j;
char *str;
/* calculate the length to allocate */
for (len = 0, i = 0; u[i] != '\0'; i++)
if (!isu8cont(u[i]))
len++;
if ((str = calloc(len + 1, sizeof(char))) == NULL)
return NULL;
/* copy the ASCII characters to the newly allocated string */
for (i = 0, j = 0; u[i] != '\0'; i++)
if (!isu8cont(u[i]))
str[j++] = isascii((unsigned char)u[i]) ? u[i] : '?';
return str;
}
static int
isu8cont(unsigned char c)
{
return (c & (0x80 | 0x40)) == 0x80;
}
/*
* Parse a LDAP value
* notes:
* the argument u should be a NULL terminated sequence of ASCII bytes.
*/
char *
parseval(char *p, size_t len)
{
char hex[3];
char *cp = p, *buffer, *newbuffer;
size_t size, newsize, i, j;
size = 50;
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] == '\\') {
strlcpy(hex, cp + j + 1, sizeof(hex));
buffer[i] = (char)strtoumax(hex, NULL, 16);
j += 3;
} else {
buffer[i] = cp[j];
j++;
}
}
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);
}