diff options
author | Simo Sorce <ssorce@redhat.com> | 2011-11-14 23:09:50 -0500 |
---|---|---|
committer | Simo Sorce <ssorce@redhat.com> | 2011-11-21 18:52:59 -0500 |
commit | 046c416e900b6a06124b181ae1d64aea1b863d22 (patch) | |
tree | 7dd49908e97806e2820b5da2725b3e3eabf92a77 /daemons | |
parent | d709dcf8f5d9e311b6703cd444ff220809eeff7a (diff) | |
download | freeipa-046c416e900b6a06124b181ae1d64aea1b863d22.tar.gz freeipa-046c416e900b6a06124b181ae1d64aea1b863d22.tar.xz freeipa-046c416e900b6a06124b181ae1d64aea1b863d22.zip |
ipa-cldap: Decode CLDAP request.
Diffstat (limited to 'daemons')
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h | 16 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c | 175 |
2 files changed, 191 insertions, 0 deletions
diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h index ff9818a64..8484749f5 100644 --- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h +++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h @@ -68,6 +68,17 @@ struct ipa_cldap_ctx { int sd; }; +struct kvp { + struct berval attr; + struct berval value; +}; + +struct kvp_list { + struct kvp *pairs; + int allocated; + int top; +}; + struct ipa_cldap_req { int fd; @@ -76,6 +87,11 @@ struct ipa_cldap_req { char dgram[MAX_DG_SIZE]; size_t dgsize; + + ber_int_t id; + + /* filter members */ + struct kvp_list kvps; }; void *ipa_cldap_worker(struct ipa_cldap_ctx *ctx); diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c index 474c5327c..57c3ffce7 100644 --- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c +++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c @@ -39,10 +39,185 @@ #include "ipa_cldap.h" #include <poll.h> +#include <lber.h> + +/* pre allocate some space for answers, default to increment 3 at a time */ +static int ipa_cldap_more_kvps(struct kvp_list *kvps) +{ + struct kvp *pairs; + + if (kvps->allocated - kvps->top > 0) { + return 0; + } + + pairs = realloc(kvps->pairs, (kvps->allocated + 3) * sizeof(struct kvp)); + if (!pairs) { + return ENOMEM; + } + kvps->pairs = pairs; + kvps->allocated += 3; + + return 0; +} + +static void ipa_cldap_free_kvps(struct kvp_list *kvps) +{ + free(kvps->pairs); + kvps->pairs = NULL; + kvps->allocated = 0; + kvps->top = 0; +} + +static int ipa_cldap_get_kvp(BerElement *be, struct kvp_list *kvps) +{ + ber_tag_t tag; + int ret; + + ret = ipa_cldap_more_kvps(kvps); + if (ret) { + return ret; + } + + tag = ber_scanf(be, "{mm}", + &(kvps->pairs[kvps->top].attr), + &(kvps->pairs[kvps->top].value)); + if (tag == LBER_ERROR) { + LOG_TRACE("Invalid filter\n"); + ret = EINVAL; + } else { + kvps->top++; + } + + return ret; +} + +static int ipa_cldap_get_tree(BerElement *be, struct kvp_list *kvps) +{ + ber_tag_t tag; + ber_tag_t len; + char *cookie; + int ret; + + tag = ber_first_element(be, &len, &cookie); + while (tag != LBER_DEFAULT) { + tag = ber_peek_tag(be, &len); + switch (tag) { + case LDAP_FILTER_EQUALITY: + ret = ipa_cldap_get_kvp(be, kvps); + break; + case LDAP_FILTER_AND: + ret = ipa_cldap_get_tree(be, kvps); + break; + default: + LOG_TRACE("Unsupported filter\n"); + ret = EINVAL; + break; + } + + if (ret) { + return ret; + } + + tag = ber_next_element(be, &len, cookie); + } + + return 0; +} + +static int ipa_cldap_decode(struct ipa_cldap_req *req) +{ + struct berval bv; + BerElement *be; + ber_tag_t tag; + ber_len_t len; + ber_int_t scope; + ber_int_t deref; + ber_int_t sizelimit; + ber_int_t timelimit; + ber_int_t typesonly; + struct berval base; + struct berval attr; + int ret = EINVAL; + + bv.bv_val = req->dgram; + bv.bv_len = req->dgsize; + + be = ber_alloc_t(0); + if (!be) { + LOG_FATAL("Out of memory!\n"); + goto done; + } + + ber_init2(be, &bv, 0); + + tag = ber_skip_tag(be, &len); + if (tag != LDAP_TAG_MESSAGE) { + LOG_TRACE("Invalid message (%d)\n", (int)tag); + goto done; + } + + tag = ber_get_int(be, &req->id); + if (tag != LDAP_TAG_MSGID) { + LOG_TRACE("Failed to get id\n"); + goto done; + } + + tag = ber_peek_tag(be, &len); + if (tag != LDAP_REQ_SEARCH) { + LOG_TRACE("Unexpected message type (%d)\n", (int)tag); + goto done; + } + + tag = ber_scanf(be, "{meeiib", + &base, &scope, &deref, &sizelimit, &timelimit, &typesonly); + if (tag == LBER_ERROR) { + LOG_TRACE("Failed to parse message\n"); + goto done; + } + + if ((base.bv_len != 0) || + (scope != 0) || + (typesonly != 0)){ + LOG_TRACE("Unexpected request\n"); + goto done; + } + + ret = ipa_cldap_get_tree(be, &req->kvps); + if (ret) { + LOG_TRACE("Failed to parse filter\n"); + goto done; + } + + tag = ber_scanf(be, "{m}}", &attr); + if (tag == LBER_ERROR) { + LOG_TRACE("Failed to parse message\n"); + goto done; + } + + if (strncasecmp(attr.bv_val, "netlogon", attr.bv_len) != 0) { + LOG_TRACE("Unexpected request\n"); + goto done; + } + +done: + ber_free(be, 0); + return ret; +} static void ipa_cldap_process(struct ipa_cldap_ctx *ctx, struct ipa_cldap_req *req) { + int ret; + + ret = ipa_cldap_decode(req); + if (ret) { + goto done; + } + + LOG_TRACE("CLDAP Request received"); + +done: + ipa_cldap_free_kvps(&req->kvps); free(req); return; } |