summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Matthew <jmatthew@cvs.openbsd.org>2012-04-30 21:40:04 +0000
committerJonathan Matthew <jmatthew@cvs.openbsd.org>2012-04-30 21:40:04 +0000
commit3f256269b6f4436798e9759e9f1e4cb545f1375f (patch)
tree03b4be3a4029ac7bebc5aece9a741eb9dd0f4054
parent7c7305753b2e61fde04a85c52ff6d5048e4c9f99 (diff)
Use paged searches so we can handle larger directories. Servers that don't
understand paging, such as ldapd(8), ignore it and return a single set of results as before. from Jim Smith, some tweaks and fixes by me, ok dlg@
-rw-r--r--usr.sbin/ypldap/aldap.c134
-rw-r--r--usr.sbin/ypldap/aldap.h17
-rw-r--r--usr.sbin/ypldap/ldapclient.c68
3 files changed, 180 insertions, 39 deletions
diff --git a/usr.sbin/ypldap/aldap.c b/usr.sbin/ypldap/aldap.c
index 4dabe48dc4e..3d96ae7a36e 100644
--- a/usr.sbin/ypldap/aldap.c
+++ b/usr.sbin/ypldap/aldap.c
@@ -1,5 +1,5 @@
-/* $Id: aldap.c,v 1.29 2012/03/15 03:44:46 jmatthew Exp $ */
-/* $OpenBSD: aldap.c,v 1.29 2012/03/15 03:44:46 jmatthew Exp $ */
+/* $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 $ */
/*
* Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
@@ -31,11 +31,15 @@
#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 **);
+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 *);
@@ -143,17 +147,26 @@ fail:
int
aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter,
- char **attrs, int typesonly, int sizelimit, int timelimit)
+ char **attrs, int typesonly, int sizelimit, int timelimit,
+ struct aldap_page_control *page)
{
- struct ber_element *root = NULL, *ber;
+ 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{tsEEddb", ++ldap->msgid, BER_CLASS_APP,
- (unsigned long)LDAP_REQ_SEARCH, basedn, (long long)scope,
- (long long)LDAP_DEREF_NEVER, sizelimit, timelimit, typesonly);
+ 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;
@@ -172,6 +185,8 @@ aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter,
goto fail;
}
+ aldap_create_page_control(c, 100, page);
+
LDAP_DEBUG("aldap_search", root);
error = ber_write_elements(&ldap->ber, root);
@@ -191,14 +206,53 @@ fail:
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 = 0;
+ int class;
+ unsigned long type;
long long msgid = 0;
- unsigned long type = 0;
struct aldap_message *m;
- struct ber_element *a = NULL;
+ struct ber_element *a = NULL, *ep;
if ((m = calloc(1, sizeof(struct aldap_message))) == NULL)
return NULL;
@@ -228,6 +282,15 @@ aldap_parse(struct aldap *ldap)
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,
@@ -247,6 +310,53 @@ parsefail:
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)
{
diff --git a/usr.sbin/ypldap/aldap.h b/usr.sbin/ypldap/aldap.h
index 7cb76b7e116..8e3a7d8088c 100644
--- a/usr.sbin/ypldap/aldap.h
+++ b/usr.sbin/ypldap/aldap.h
@@ -1,5 +1,5 @@
-/* $Id: aldap.h,v 1.8 2011/08/28 16:37:28 aschrijver Exp $ */
-/* $OpenBSD: aldap.h,v 1.8 2011/08/28 16:37:28 aschrijver Exp $ */
+/* $Id: aldap.h,v 1.9 2012/04/30 21:40:03 jmatthew Exp $ */
+/* $OpenBSD: aldap.h,v 1.9 2012/04/30 21:40:03 jmatthew Exp $ */
/*
* Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
@@ -23,6 +23,7 @@
#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
@@ -34,6 +35,12 @@ struct aldap {
struct ber ber;
};
+struct aldap_page_control {
+ int size;
+ char *cookie;
+ unsigned int cookie_len;
+};
+
struct aldap_message {
int msgid;
int message_type;
@@ -56,6 +63,7 @@ struct aldap_message {
} search;
} body;
struct ber_element *references;
+ struct aldap_page_control *page;
};
enum aldap_protocol {
@@ -188,7 +196,7 @@ 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 *, char **, int, int, int);
+int aldap_search(struct aldap *, char *, enum scope, char *, char **, int, int, int, struct aldap_page_control *);
int aldap_get_errno(struct aldap *, const char **);
int aldap_get_resultcode(struct aldap_message *);
@@ -207,3 +215,6 @@ 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 *);
diff --git a/usr.sbin/ypldap/ldapclient.c b/usr.sbin/ypldap/ldapclient.c
index 3c9fc1440de..ebb2c934597 100644
--- a/usr.sbin/ypldap/ldapclient.c
+++ b/usr.sbin/ypldap/ldapclient.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldapclient.c,v 1.25 2012/04/30 11:28:25 jmatthew Exp $ */
+/* $OpenBSD: ldapclient.c,v 1.26 2012/04/30 21:40:03 jmatthew Exp $ */
/*
* Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
@@ -512,6 +512,7 @@ client_search_idm(struct env *env, struct idm *idm, struct aldap *al,
{
struct idm_req ir;
struct aldap_message *m;
+ struct aldap_page_control *pg = NULL;
const char *errstr;
char *dn;
@@ -519,36 +520,55 @@ client_search_idm(struct env *env, struct idm *idm, struct aldap *al,
if (type == IMSG_GRP_ENTRY && idm->idm_groupdn[0] != '\0')
dn = idm->idm_groupdn;
- if (aldap_search(al, dn, LDAP_SCOPE_SUBTREE,
- filter, attrs, 0, 0, 0) == -1) {
- aldap_get_errno(al, &errstr);
- log_debug("%s", errstr);
- return (-1);
- }
-
- while ((m = aldap_parse(al)) != NULL) {
- if (al->msgid != m->msgid) {
- aldap_freemsg(m);
+ do {
+ if (aldap_search(al, dn, LDAP_SCOPE_SUBTREE,
+ filter, attrs, 0, 0, 0, pg) == -1) {
+ aldap_get_errno(al, &errstr);
+ log_debug("%s", errstr);
return (-1);
}
- /* end of the search result chain */
- if (m->message_type == LDAP_RES_SEARCH_RESULT) {
- aldap_freemsg(m);
- break;
+
+ if (pg != NULL) {
+ aldap_freepage(pg);
+ pg = NULL;
}
- /* search entry; the rest we won't handle */
- if (m->message_type != LDAP_RES_SEARCH_ENTRY) {
- aldap_freemsg(m);
- return (-1);
+
+ while ((m = aldap_parse(al)) != NULL) {
+ if (al->msgid != m->msgid) {
+ goto fail;
+ }
+
+ if (m->message_type == LDAP_RES_SEARCH_RESULT) {
+ if (m->page != NULL && m->page->cookie_len != 0)
+ pg = m->page;
+ else
+ pg = NULL;
+
+ aldap_freemsg(m);
+ break;
+ }
+
+ if (m->message_type != LDAP_RES_SEARCH_ENTRY) {
+ goto fail;
+ }
+
+ if (client_build_req(idm, &ir, m, min_attr, max_attr) == 0)
+ imsg_compose_event(env->sc_iev, type, 0, 0, -1,
+ &ir, sizeof(ir));
+
+ aldap_freemsg(m);
}
+ } while (pg != NULL);
- if (client_build_req(idm, &ir, m, min_attr, max_attr) == 0)
- imsg_compose_event(env->sc_iev, type, 0, 0, -1,
- &ir, sizeof(ir));
- aldap_freemsg(m);
+ return (0);
+
+fail:
+ aldap_freemsg(m);
+ if (pg != NULL) {
+ aldap_freepage(pg);
}
- return (0);
+ return (-1);
}
int