summaryrefslogtreecommitdiffstats
path: root/daemons
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2011-11-14 23:09:50 -0500
committerSimo Sorce <ssorce@redhat.com>2011-11-21 18:52:59 -0500
commit046c416e900b6a06124b181ae1d64aea1b863d22 (patch)
tree7dd49908e97806e2820b5da2725b3e3eabf92a77 /daemons
parentd709dcf8f5d9e311b6703cd444ff220809eeff7a (diff)
downloadfreeipa-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.h16
-rw-r--r--daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_worker.c175
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;
}