Author: rodrigc
Date: Mon Nov 16 16:48:43 2015
New Revision: 290931
URL: https://svnweb.freebsd.org/changeset/base/290931

Log:
  Import ypldap from OpenBSD.
  
  ypldap -- Intended to be a drop-in replacement for ypserv, gluing in a
  LDAP directory and thus providing support for users and groups stored in
  LDAP for the get{pw,gr}ent family of functions.

Added:
  head/usr.sbin/ypldap/
  head/usr.sbin/ypldap/Makefile   (contents, props changed)
  head/usr.sbin/ypldap/aldap.c   (contents, props changed)
  head/usr.sbin/ypldap/aldap.h   (contents, props changed)
  head/usr.sbin/ypldap/ber.c   (contents, props changed)
  head/usr.sbin/ypldap/ber.h   (contents, props changed)
  head/usr.sbin/ypldap/entries.c   (contents, props changed)
  head/usr.sbin/ypldap/ldapclient.c   (contents, props changed)
  head/usr.sbin/ypldap/log.c   (contents, props changed)
  head/usr.sbin/ypldap/parse.y   (contents, props changed)
  head/usr.sbin/ypldap/yp.c   (contents, props changed)
  head/usr.sbin/ypldap/ypldap.8   (contents, props changed)
  head/usr.sbin/ypldap/ypldap.c   (contents, props changed)
  head/usr.sbin/ypldap/ypldap.conf.5   (contents, props changed)
  head/usr.sbin/ypldap/ypldap.h   (contents, props changed)
  head/usr.sbin/ypldap/ypldap_dns.c   (contents, props changed)

Added: head/usr.sbin/ypldap/Makefile
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.sbin/ypldap/Makefile       Mon Nov 16 16:48:43 2015        
(r290931)
@@ -0,0 +1,21 @@
+# $OpenBSD: Makefile,v 1.8 2015/09/09 15:33:18 deraadt Exp $
+# $FreeBSD$
+
+PROG=          ypldap
+SRCS=          parse.y ypldap.c log.c  \
+               ldapclient.c entries.c yp.c \
+               aldap.c ber.c \
+               ypldap_dns.c
+
+MAN=           ypldap.8 ypldap.conf.5
+
+DPADD=         ${LIBEVENT} ${LIBUTIL} ${LIBRPCSVC}
+LDADD=         -levent -lutil -lrpcsvc
+CFLAGS+=       -I${.CURDIR}
+CFLAGS+=       -Wall
+CFLAGS+=       -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+=       -Wmissing-declarations
+CFLAGS+=       -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+=       -Wsign-compare
+
+.include <bsd.prog.mk>

Added: head/usr.sbin/ypldap/aldap.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.sbin/ypldap/aldap.c        Mon Nov 16 16:48:43 2015        
(r290931)
@@ -0,0 +1,1273 @@
+/*     $Id: aldap.c,v 1.30 2012/04/30 21:40:03 jmatthew Exp $ */
+/*     $OpenBSD: aldap.c,v 1.30 2012/04/30 21:40:03 jmatthew Exp $ */
+/*     $FreeBSD$ */
+
+/*
+ * Copyright (c) 2008 Alexander Schrijver <[email protected]>
+ * Copyright (c) 2006, 2007 Marc Balmer <[email protected]>
+ *
+ * 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 <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 *);
+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)
+{
+       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);
+}
+
+#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, 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)
+{
+       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) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to