From bb7d2289f7a4f6afbd38501dd33b606cc3942ee4 Mon Sep 17 00:00:00 2001
From: Yassir Elley <yelley@redhat.com>
Date: Tue, 22 Jul 2014 03:02:30 -0400
Subject: [PATCH 1/2] AD-GPO: add sysdb_gpo support for caching gpo version

---
 Makefile.am        |   1 +
 src/db/sysdb.h     |  28 ++++++
 src/db/sysdb_gpo.c | 262 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 291 insertions(+)
 create mode 100644 src/db/sysdb_gpo.c

diff --git a/Makefile.am b/Makefile.am
index e3592868ce29b569a71f6ad74bc24cc617301b34..f60926cc90c729b3c57c20c135c88de66836ee59 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -635,6 +635,7 @@ libsss_util_la_SOURCES = \
     src/db/sysdb_subdomains.c \
     src/db/sysdb_ranges.c \
     src/db/sysdb_idmap.c \
+    src/db/sysdb_gpo.c \
     src/monitor/monitor_sbus.c \
     src/providers/dp_auth_util.c \
     src/providers/dp_pam_data_util.c \
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 17cd5110c9bdafd8d7b18e621188523ed41e5c8a..63f596007cdf53c5ebbdccf37f3c4bcc7830a205 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -864,4 +864,32 @@ errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx,
                                    const char *sid_str,
                                    const char **attrs,
                                    struct ldb_result **msg);
+
+/* === Functions related to GPOs === */
+
+#define SYSDB_GPO_CONTAINER "cn=gpos,cn=ad,cn=custom"
+
+#define SYSDB_GPO_OC "gpo"
+#define SYSDB_GPO_FILTER "(&(objectClass="SYSDB_GPO_OC")("SYSDB_GPO_GUID_ATTR"=%s))"
+#define SYSDB_GPO_GUID_ATTR "gpoGUID"
+#define SYSDB_GPO_VERSION_ATTR "gpoVersion"
+
+#define SYSDB_TMPL_GPO_BASE SYSDB_GPO_CONTAINER","SYSDB_DOM_BASE
+#define SYSDB_TMPL_GPO SYSDB_GPO_GUID_ATTR"=%s,"SYSDB_TMPL_GPO_BASE
+
+#define SYSDB_GPO_ATTRS { \
+        SYSDB_NAME, \
+        SYSDB_GPO_GUID_ATTR, \
+        SYSDB_GPO_VERSION_ATTR, \
+        NULL }
+
+errno_t sysdb_gpo_store_gpo(struct sss_domain_info *domain,
+                            const char *gpo_guid,
+                            int gpo_version);
+
+errno_t sysdb_gpo_get_gpo(TALLOC_CTX *mem_ctx,
+                          struct sss_domain_info *domain,
+                          const char *gpo_guid,
+                          struct ldb_result **_result);
+
 #endif /* __SYS_DB_H__ */
diff --git a/src/db/sysdb_gpo.c b/src/db/sysdb_gpo.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c23c5b8fae6aaa41168b1466f4b3e520231e7e2
--- /dev/null
+++ b/src/db/sysdb_gpo.c
@@ -0,0 +1,262 @@
+/*
+    SSSD
+
+    Authors:
+        Yassir Elley <yelley@redhat.com>
+
+    Copyright (C) 2014 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "db/sysdb.h"
+#include "db/sysdb_private.h"
+
+static struct ldb_dn *
+sysdb_gpo_dn(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain,
+             const char *gpo_guid)
+{
+    errno_t ret;
+    char *clean_gpo_guid;
+    struct ldb_dn *dn;
+
+    ret = sysdb_dn_sanitize(NULL, gpo_guid, &clean_gpo_guid);
+    if (ret != EOK) {
+        return NULL;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, SYSDB_TMPL_GPO"\n", clean_gpo_guid, domain->name);
+
+    dn = ldb_dn_new_fmt(mem_ctx, domain->sysdb->ldb, SYSDB_TMPL_GPO,
+                        clean_gpo_guid, domain->name);
+    talloc_free(clean_gpo_guid);
+
+    return dn;
+}
+
+errno_t
+sysdb_gpo_store_gpo(struct sss_domain_info *domain,
+                    const char *gpo_guid,
+                    int gpo_version)
+{
+    errno_t ret, sret;
+    int lret;
+    struct ldb_message *update_msg;
+    struct ldb_message **msgs;
+    static const char *attrs[] = SYSDB_GPO_ATTRS;
+    size_t count;
+    bool in_transaction = false;
+    TALLOC_CTX *tmp_ctx;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    update_msg = ldb_msg_new(tmp_ctx);
+    if (!update_msg) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    update_msg->dn = sysdb_gpo_dn(update_msg, domain, gpo_guid);
+    if (!update_msg->dn) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_transaction_start(domain->sysdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
+        goto done;
+    }
+
+    in_transaction = true;
+
+    /* Check for an existing gpo_guid entry */
+    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, update_msg->dn,
+                             LDB_SCOPE_BASE, NULL, attrs, &count, &msgs);
+
+    if (ret == ENOENT) {
+        /* Create new GPO */
+        DEBUG(SSSDBG_TRACE_FUNC,
+              "Adding new GPO [gpo_guid:%s][gpo_version:%d]\n",
+              gpo_guid, gpo_version);
+
+        /* Add the objectClass */
+        lret = ldb_msg_add_empty(update_msg, SYSDB_OBJECTCLASS,
+                                 LDB_FLAG_MOD_ADD,
+                                 NULL);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_msg_add_string(update_msg, SYSDB_OBJECTCLASS,
+                                  SYSDB_GPO_OC);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        /* Add the GPO GUID */
+        lret = ldb_msg_add_empty(update_msg, SYSDB_GPO_GUID_ATTR,
+                                 LDB_FLAG_MOD_ADD,
+                                 NULL);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_msg_add_string(update_msg, SYSDB_GPO_GUID_ATTR, gpo_guid);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        /* Add the Version */
+        lret = ldb_msg_add_empty(update_msg, SYSDB_GPO_VERSION_ATTR,
+                                 LDB_FLAG_MOD_ADD,
+                                 NULL);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_msg_add_fmt(update_msg, SYSDB_GPO_VERSION_ATTR,
+                               "%d", gpo_version);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_add(domain->sysdb->ldb, update_msg);
+        if (lret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Failed to add GPO: [%s]\n",
+                   ldb_strerror(lret));
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+    } else if (ret == EOK && count == 1) {
+        /* Update the existing GPO */
+
+        DEBUG(SSSDBG_TRACE_FUNC,
+              "Updating new GPO [%s][%s]\n", domain->name, gpo_guid);
+
+        /* Add the Version */
+        lret = ldb_msg_add_empty(update_msg, SYSDB_GPO_VERSION_ATTR,
+                                 LDB_FLAG_MOD_REPLACE,
+                                 NULL);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_msg_add_fmt(update_msg, SYSDB_GPO_VERSION_ATTR,
+                               "%d", gpo_version);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_modify(domain->sysdb->ldb, update_msg);
+        if (lret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Failed to modify GPO: [%s]\n", ldb_strerror(lret));
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+    } else {
+        ret = EIO;
+        goto done;
+    }
+
+    ret = sysdb_transaction_commit(domain->sysdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Could not commit transaction: [%s]\n", strerror(ret));
+        goto done;
+    }
+    in_transaction = false;
+
+done:
+    if (in_transaction) {
+        sret = sysdb_transaction_cancel(domain->sysdb);
+        if (sret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
+        }
+    }
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t
+sysdb_gpo_get_gpo(TALLOC_CTX *mem_ctx,
+                  struct sss_domain_info *domain,
+                  const char *gpo_guid,
+                  struct ldb_result **_result)
+{
+    errno_t ret;
+    int lret;
+    struct ldb_dn *base_dn;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_result *res;
+
+    const char *attrs[] = SYSDB_GPO_ATTRS;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    DEBUG(SSSDBG_TRACE_FUNC, SYSDB_TMPL_GPO_BASE"\n", domain->name);
+
+    base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
+                             SYSDB_TMPL_GPO_BASE,
+                             domain->name);
+    if (!base_dn) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    lret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
+                      LDB_SCOPE_SUBTREE, attrs, SYSDB_GPO_FILTER, gpo_guid);
+    if (lret) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              "Could not locate GPO: [%s]\n",
+              ldb_strerror(lret));
+        ret = sysdb_error_to_errno(lret);
+        goto done;
+    }
+
+    if (res->count > 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Search for GUID [%s] returned more than " \
+              "one object.\n", gpo_guid);
+        ret = EINVAL;
+        goto done;
+    } else if (res->count == 0) {
+        ret = ENOENT;
+        goto done;
+    }
+    *_result = talloc_steal(mem_ctx, res);
+    ret = EOK;
+done:
+
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_TRACE_ALL, "No such entry.\n");
+    } else if (ret) {
+        DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
-- 
1.8.5.3

