diff options
author | Jonathan Matthew <jmatthew@cvs.openbsd.org> | 2012-04-30 21:40:04 +0000 |
---|---|---|
committer | Jonathan Matthew <jmatthew@cvs.openbsd.org> | 2012-04-30 21:40:04 +0000 |
commit | 3f256269b6f4436798e9759e9f1e4cb545f1375f (patch) | |
tree | 03b4be3a4029ac7bebc5aece9a741eb9dd0f4054 /usr.sbin/ypldap | |
parent | 7c7305753b2e61fde04a85c52ff6d5048e4c9f99 (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@
Diffstat (limited to 'usr.sbin/ypldap')
-rw-r--r-- | usr.sbin/ypldap/aldap.c | 134 | ||||
-rw-r--r-- | usr.sbin/ypldap/aldap.h | 17 | ||||
-rw-r--r-- | usr.sbin/ypldap/ldapclient.c | 68 |
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 |