s4:s3compat Add pdb_samba4
authorAndrew Bartlett <abartlet@samba.org>
Sun, 23 May 2010 15:12:02 +0000 (01:12 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 3 Jun 2010 11:57:31 +0000 (21:57 +1000)
pdb_samba4 is a passdb module based on the work Volker did on pdb_ads,
but written directly against the LDB and DSDB APIs used in the source4
code.

In particular, the SID-based extended DN and dsdb_ helper functions
are used to make this a much smaller module.  It contains some write
support, but as the first customer is winbindd, this is unfinished.

The idmap fucntions link to Samba4's idmap API

Andrew Bartlett

source4/s3compat/pdb_samba4.c [new file with mode: 0644]
source4/s3compat/s3compat.c
source4/s3compat/s3compat_authenticate.c
source4/s3compat/wscript_build

diff --git a/source4/s3compat/pdb_samba4.c b/source4/s3compat/pdb_samba4.c
new file mode 100644 (file)
index 0000000..36312d3
--- /dev/null
@@ -0,0 +1,1748 @@
+/*
+   Unix SMB/CIFS implementation.
+   pdb glue module for samba4
+   Copyright (C) Volker Lendecke 2009
+   Copyright (C) Andrew Bartlett 2010
+   Copyright (C) Matthias Dieter Wallnöfer                 2009
+
+   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/>.
+*/
+
+/* This module, is a port of Volker's pdb_ads to ldb and DSDB APIs */
+
+#include "includes.h"
+#include "dsdb/samdb/samdb.h"
+#include "ldb_errors.h"
+#include "libcli/security/dom_sid.h"
+#include "s3compat/s3compat_authenticate.h"
+#include "../winbind/idmap.h"
+
+struct pdb_samba4_state {
+       struct ldb_context *ldb;
+       struct idmap_context *idmap_ctx;
+};
+
+static NTSTATUS pdb_samba4_getsampwsid(struct pdb_methods *m,
+                                   struct samu *sam_acct,
+                                   const struct dom_sid *sid);
+static NTSTATUS pdb_samba4_getsamupriv(struct pdb_samba4_state *state,
+                                   const char *filter,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct ldb_message **pmsg);
+static bool pdb_samba4_sid_to_id(struct pdb_methods *m, const struct dom_sid *sid,
+                                union unid_t *id, enum lsa_SidType *type);
+
+static bool pdb_samba4_pull_time(struct ldb_message *msg, const char *attr,
+                             time_t *ptime)
+{
+       uint64_t tmp;
+       if (! ldb_msg_find_element(msg, attr)) {
+               return false;
+       }
+       tmp = ldb_msg_find_attr_as_uint64(msg, attr, 0);
+       *ptime = uint64s_nt_time_to_unix_abs(&tmp);
+       return true;
+}
+
+static struct ldb_message *pdb_samba4_get_samu_private(
+       struct pdb_methods *m, struct samu *sam)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct ldb_message *msg;
+       char *sidstr, *filter;
+       NTSTATUS status;
+
+       msg = (struct ldb_message *)
+               pdb_get_backend_private_data(sam, m);
+
+       if (msg != NULL) {
+               return talloc_get_type_abort(msg, struct ldb_message);
+       }
+
+       sidstr = dom_sid_string(talloc_tos(), pdb_get_user_sid(sam));
+       if (sidstr == NULL) {
+               return NULL;
+       }
+
+       filter = talloc_asprintf(
+               talloc_tos(), "(&(objectsid=%s)(objectclass=user))", sidstr);
+       TALLOC_FREE(sidstr);
+       if (filter == NULL) {
+               return NULL;
+       }
+
+       status = pdb_samba4_getsamupriv(state, filter, sam, &msg);
+       TALLOC_FREE(filter);
+       if (!NT_STATUS_IS_OK(status)) {
+               return NULL;
+       }
+
+       return msg;
+}
+
+static NTSTATUS pdb_samba4_init_sam_from_priv(struct pdb_methods *m,
+                                          struct samu *sam,
+                                          struct ldb_message *msg)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       TALLOC_CTX *frame = talloc_stackframe();
+       NTSTATUS status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+       const char *str;
+       time_t tmp_time;
+       struct dom_sid *sid, group_sid;
+       uint64_t n;
+       const DATA_BLOB *blob;
+
+       str = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
+       if (str == NULL) {
+               DEBUG(10, ("no samAccountName\n"));
+               goto fail;
+       }
+       pdb_set_username(sam, str, PDB_SET);
+
+       if (pdb_samba4_pull_time(msg, "lastLogon", &tmp_time)) {
+               pdb_set_logon_time(sam, tmp_time, PDB_SET);
+       }
+       if (pdb_samba4_pull_time(msg, "lastLogoff", &tmp_time)) {
+               pdb_set_logoff_time(sam, tmp_time, PDB_SET);
+       }
+       if (pdb_samba4_pull_time(msg, "pwdLastSet", &tmp_time)) {
+               pdb_set_pass_last_set_time(sam, tmp_time, PDB_SET);
+       }
+       if (pdb_samba4_pull_time(msg, "accountExpires", &tmp_time)) {
+               pdb_set_kickoff_time(sam, tmp_time, PDB_SET);
+       }
+
+       str = ldb_msg_find_attr_as_string(msg, "displayName",
+                                           NULL);
+       if (str != NULL) {
+               pdb_set_fullname(sam, str, PDB_SET);
+       }
+
+       str = ldb_msg_find_attr_as_string(msg, "homeDirectory",
+                                           NULL);
+       if (str != NULL) {
+               pdb_set_homedir(sam, str, PDB_SET);
+       }
+
+       str = ldb_msg_find_attr_as_string(msg, "homeDrive", NULL);
+       if (str != NULL) {
+               pdb_set_dir_drive(sam, str, PDB_SET);
+       }
+
+       str = ldb_msg_find_attr_as_string(msg, "scriptPath", NULL);
+       if (str != NULL) {
+               pdb_set_logon_script(sam, str, PDB_SET);
+       }
+
+       str = ldb_msg_find_attr_as_string(msg, "profilePath",
+                                           NULL);
+       if (str != NULL) {
+               pdb_set_profile_path(sam, str, PDB_SET);
+       }
+
+       str = ldb_msg_find_attr_as_string(msg, "profilePath",
+                                           NULL);
+       if (str != NULL) {
+               pdb_set_profile_path(sam, str, PDB_SET);
+       }
+
+       sid = samdb_result_dom_sid(talloc_tos(), msg, "objectSid");
+       if (!sid) {
+               DEBUG(10, ("Could not pull SID\n"));
+               goto fail;
+       }
+       pdb_set_user_sid(sam, sid, PDB_SET);
+
+       n = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
+       if (n == 0) {
+               DEBUG(10, ("Could not pull userAccountControl\n"));
+               goto fail;
+       }
+       pdb_set_acct_ctrl(sam, ds_uf2acb(n), PDB_SET);
+
+       blob = ldb_msg_find_ldb_val(msg, "unicodePwd");
+       if (blob) {
+               if (blob->length != NT_HASH_LEN) {
+                       DEBUG(0, ("Got NT hash of length %d, expected %d\n",
+                                 (int)blob->length, NT_HASH_LEN));
+                       goto fail;
+               }
+               pdb_set_nt_passwd(sam, blob->data, PDB_SET);
+       }
+       
+       blob = ldb_msg_find_ldb_val(msg, "dBCSPwd");
+       if (blob) {
+               if (blob->length != LM_HASH_LEN) {
+                       DEBUG(0, ("Got LM hash of length %d, expected %d\n",
+                                 (int)blob->length, LM_HASH_LEN));
+                       goto fail;
+               }
+               pdb_set_lanman_passwd(sam, blob->data, PDB_SET);
+       }
+       
+       n = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", 0);
+       if (n == 0) {
+               DEBUG(10, ("Could not pull primaryGroupID\n"));
+               goto fail;
+       }
+       sid_compose(&group_sid, samdb_domain_sid(state->ldb), n);
+       pdb_set_group_sid(sam, &group_sid, PDB_SET);
+
+       status = NT_STATUS_OK;
+fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+#if 0
+static bool pdb_samba4_init_samba4_from_sam(struct pdb_samba4_state *state,
+                                     struct ldb_message *existing,
+                                     TALLOC_CTX *mem_ctx,
+                                     int *pnum_mods, struct tldap_mod **pmods,
+                                     struct samu *sam)
+{
+       bool ret = true;
+       DATA_BLOB blob;
+
+       /* TODO: All fields :-) */
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pnum_mods, pmods, "displayName",
+               "%s", pdb_get_fullname(sam));
+
+       blob = data_blob_const(pdb_get_nt_passwd(sam), NT_HASH_LEN);
+       if (blob.data != NULL) {
+               ret &= tldap_add_mod_blobs(mem_ctx, pmods, TLDAP_MOD_REPLACE,
+                                          "unicodePwd", 1, &blob);
+       }
+
+       blob = data_blob_const(pdb_get_lanman_passwd(sam), NT_HASH_LEN);
+       if (blob.data != NULL) {
+               ret &= tldap_add_mod_blobs(mem_ctx, pmods, TLDAP_MOD_REPLACE,
+                                          "dBCSPwd", 1, &blob);
+       }
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pnum_mods, pmods, "userAccountControl",
+               "%d", ds_acb2uf(pdb_get_acct_ctrl(sam)));
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pnum_mods, pmods, "homeDirectory",
+               "%s", pdb_get_homedir(sam));
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pnum_mods, pmods, "homeDrive",
+               "%s", pdb_get_dir_drive(sam));
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pnum_mods, pmods, "scriptPath",
+               "%s", pdb_get_logon_script(sam));
+
+       ret &= tldap_make_mod_fmt(
+               existing, mem_ctx, pnum_mods, pmods, "profilePath",
+               "%s", pdb_get_profile_path(sam));
+
+       return ret;
+}
+#endif
+static NTSTATUS pdb_samba4_getsamupriv(struct pdb_samba4_state *state,
+                                   const char *filter,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct ldb_message **msg)
+{
+       const char * attrs[] = {
+               "lastLogon", "lastLogoff", "pwdLastSet", "accountExpires",
+               "sAMAccountName", "displayName", "homeDirectory",
+               "homeDrive", "scriptPath", "profilePath", "description",
+               "userWorkstations", "comment", "userParameters", "objectSid",
+               "primaryGroupID", "userAccountControl", "logonHours",
+               "badPwdCount", "logonCount", "countryCode", "codePage",
+               "unicodePwd", "dBCSPwd", NULL };
+
+       int rc = dsdb_search_one(state->ldb, mem_ctx, msg, NULL, LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter); 
+       if (rc != LDB_SUCCESS) {
+               DEBUG(10, ("ldap_search failed %s\n",
+                          ldb_errstring(state->ldb)));
+               return NT_STATUS_LDAP(rc);
+       }
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_getsampwfilter(struct pdb_methods *m,
+                                         struct pdb_samba4_state *state,
+                                         struct samu *sam_acct,
+                                         const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(4, 5)
+{
+       struct ldb_message *priv;
+       NTSTATUS status;
+       va_list ap;
+       char *expression = NULL;
+       TALLOC_CTX *tmp_ctx = talloc_new(state);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       va_start(ap, exp_fmt);
+       expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
+       va_end(ap);
+       
+       if (!expression) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = pdb_samba4_getsamupriv(state, expression, sam_acct, &priv);
+       talloc_free(tmp_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("pdb_samba4_getsamupriv failed: %s\n",
+                          nt_errstr(status)));
+               return status;
+       }
+
+       status = pdb_samba4_init_sam_from_priv(m, sam_acct, priv);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("pdb_samba4_init_sam_from_priv failed: %s\n",
+                          nt_errstr(status)));
+               TALLOC_FREE(priv);
+               return status;
+       }
+
+       pdb_set_backend_private_data(sam_acct, priv, NULL, m, PDB_SET);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_getsampwnam(struct pdb_methods *m,
+                                   struct samu *sam_acct,
+                                   const char *username)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+
+       return pdb_samba4_getsampwfilter(m, state, sam_acct, 
+                                        "(&(samaccountname=%s)(objectclass=user))",
+                                        username);
+}
+
+static NTSTATUS pdb_samba4_getsampwsid(struct pdb_methods *m,
+                                   struct samu *sam_acct,
+                                   const struct dom_sid *sid)
+{
+       NTSTATUS status;
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       char *sidstr;
+
+       sidstr = dom_sid_string(talloc_tos(), sid);
+       NT_STATUS_HAVE_NO_MEMORY(sidstr);
+
+       status = pdb_samba4_getsampwfilter(m, state, sam_acct,  
+                                          "(&(objectsid=%s)(objectclass=user))", 
+                                          sidstr);
+       talloc_free(sidstr);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_create_user(struct pdb_methods *m,
+                                   TALLOC_CTX *mem_ctx,
+                                   const char *name, uint32 acct_flags,
+                                   uint32 *rid)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct dom_sid *sid;
+       struct ldb_dn *dn;
+       NTSTATUS status;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       status = dsdb_add_user(state->ldb, tmp_ctx, name, acct_flags, &sid, &dn);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return status;
+       }
+       sid_peek_rid(sid, rid);
+       talloc_free(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_delete_user(struct pdb_methods *m,
+                                      TALLOC_CTX *mem_ctx,
+                                      struct samu *sam)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct ldb_dn *dn;
+       int rc;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, pdb_get_user_sid(sam)));
+       if (!dn || !ldb_dn_validate(dn)) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       rc = ldb_delete(state->ldb, dn);
+
+       if (rc != LDB_SUCCESS) {
+               DEBUG(10, ("ldb_delete for %s failed: %s\n", ldb_dn_get_linearized(dn),
+                          ldb_errstring(state->ldb)));
+               talloc_free(tmp_ctx);
+               return NT_STATUS_LDAP(rc);
+       }
+       talloc_free(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_add_sam_account(struct pdb_methods *m,
+                                       struct samu *sampass)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+#if 0
+static NTSTATUS pdb_samba4_update_sam_account(struct pdb_methods *m,
+                                          struct samu *sam)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct pdb_samba4_samu_private *priv = pdb_samba4_get_samu_private(m, sam);
+       struct tldap_context *ld;
+       struct tldap_mod *mods = NULL;
+       int rc, num_mods = 0;
+
+       ld = pdb_samba4_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
+       if (!pdb_samba4_init_samba4_from_sam(state, priv->ldapmsg, talloc_tos(),
+                                      &num_mods, &mods, sam)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (num_mods == 0) {
+               /* Nothing to do, just return success */
+               return NT_STATUS_OK;
+       }
+
+       rc = tldap_modify(ld, priv->dn, num_mods, mods, NULL, 0,
+                         NULL, 0);
+       TALLOC_FREE(mods);
+       if (rc != LDB_SUCCESS) {
+               DEBUG(10, ("ldap_modify for %s failed: %s\n", priv->dn,
+                          tldap_errstr(talloc_tos(), ld, rc)));
+               return NT_STATUS_LDAP(rc);
+       }
+
+       return NT_STATUS_OK;
+}
+#endif
+
+static NTSTATUS pdb_samba4_delete_sam_account(struct pdb_methods *m,
+                                          struct samu *username)
+{
+       NTSTATUS status;
+       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+       status = pdb_samba4_delete_user(m, tmp_ctx, username);
+       talloc_free(tmp_ctx);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_rename_sam_account(struct pdb_methods *m,
+                                          struct samu *oldname,
+                                          const char *newname)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba4_update_login_attempts(struct pdb_methods *m,
+                                             struct samu *sam_acct,
+                                             bool success)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba4_getgrfilter(struct pdb_methods *m, GROUP_MAP *map,
+                                   const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(4, 5)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       const char *attrs[] = { "objectSid", "description", "samAccountName",
+                               NULL };
+       struct ldb_message *msg;
+       va_list ap;
+       char *expression = NULL;
+       struct dom_sid *sid;
+       const char *str;
+       int rc;
+       union unid_t id;
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+       
+       va_start(ap, exp_fmt);
+       expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
+       va_end(ap);
+       
+       if (!expression) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       rc = dsdb_search_one(state->ldb, tmp_ctx, &msg, NULL, LDB_SCOPE_SUBTREE, attrs, 0, "%s", expression);
+       if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_SUCH_GROUP;
+       } else if (rc != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               DEBUG(10, ("dsdb_search_one failed %s\n",
+                          ldb_errstring(state->ldb)));
+               return NT_STATUS_LDAP(rc);
+       }
+
+       sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
+       if (!sid) {
+               talloc_free(tmp_ctx);
+               DEBUG(10, ("Could not pull SID\n"));
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+       
+       map->sid = *sid;
+       
+       if (!pdb_samba4_sid_to_id(m, sid, &id, &map->sid_name_use)) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_SUCH_GROUP;
+       }
+       if (map->sid_name_use == SID_NAME_USER) {
+               DEBUG(1, (__location__ "Got SID_NAME_USER when searching for a group with %s", expression));
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+       map->gid = id.gid;
+
+       str = ldb_msg_find_attr_as_string(msg, "samAccountName",
+                                         NULL);
+       if (str == NULL) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+       fstrcpy(map->nt_name, str);
+
+       str = ldb_msg_find_attr_as_string(msg, "description",
+                                           NULL);
+       if (str != NULL) {
+               fstrcpy(map->comment, str);
+       } else {
+               map->comment[0] = '\0';
+       }
+
+       talloc_free(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_getgrsid(struct pdb_methods *m, GROUP_MAP *map,
+                                struct dom_sid sid)
+{
+       char *filter;
+       NTSTATUS status;
+
+       filter = talloc_asprintf(talloc_tos(),
+                                "(&(objectsid=%s)(objectclass=group))",
+                                sid_string_talloc(talloc_tos(), &sid));
+       if (filter == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = pdb_samba4_getgrfilter(m, map, filter);
+       TALLOC_FREE(filter);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_getgrgid(struct pdb_methods *m, GROUP_MAP *map,
+                                gid_t gid)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       NTSTATUS status;
+       struct id_map id_map;
+       struct id_map *id_maps[2];
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       id_map.xid.id = gid;
+       id_map.xid.type = ID_TYPE_GID;
+       id_maps[0] = &id_map;
+       id_maps[1] = NULL;
+
+       status = idmap_xids_to_sids(state->idmap_ctx, tmp_ctx, id_maps);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       status = pdb_samba4_getgrsid(m, map, *id_map.sid);
+       talloc_free(tmp_ctx);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_getgrnam(struct pdb_methods *m, GROUP_MAP *map,
+                                const char *name)
+{
+       char *filter;
+       NTSTATUS status;
+
+       filter = talloc_asprintf(talloc_tos(),
+                                "(&(samaccountname=%s)(objectclass=group))",
+                                name);
+       if (filter == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = pdb_samba4_getgrfilter(m, map, filter);
+       TALLOC_FREE(filter);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_create_dom_group(struct pdb_methods *m,
+                                        TALLOC_CTX *mem_ctx, const char *name,
+                                        uint32 *rid)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       NTSTATUS status;
+       struct dom_sid *sid;
+       struct ldb_dn *dn;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       status = dsdb_add_domain_group(state->ldb, tmp_ctx, name, &sid, &dn);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return status;
+       }
+
+       sid_peek_rid(sid, rid);
+       talloc_free(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_delete_dom_group(struct pdb_methods *m,
+                                        TALLOC_CTX *mem_ctx, uint32 rid)
+{
+       const char *attrs[] = { NULL };
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct dom_sid sid;
+       struct ldb_message *msg;
+       struct ldb_dn *dn;
+       int rc;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       sid_compose(&sid, samdb_domain_sid(state->ldb), rid);
+
+       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, &sid));
+       if (!dn || !ldb_dn_validate(dn)) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       rc = dsdb_search_one(state->ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "objectclass=group");
+       if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_SUCH_GROUP;
+       }
+       rc = ldb_delete(state->ldb, dn);
+       if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_SUCH_GROUP;
+       } else if (rc != LDB_SUCCESS) {
+               DEBUG(10, ("ldb_delete failed %s\n",
+                          ldb_errstring(state->ldb)));
+               return NT_STATUS_LDAP(rc);
+       }
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_add_group_mapping_entry(struct pdb_methods *m,
+                                               GROUP_MAP *map)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba4_update_group_mapping_entry(struct pdb_methods *m,
+                                                  GROUP_MAP *map)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba4_delete_group_mapping_entry(struct pdb_methods *m,
+                                                  struct dom_sid sid)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba4_enum_group_mapping(struct pdb_methods *m,
+                                          const struct dom_sid *sid,
+                                          enum lsa_SidType sid_name_use,
+                                          GROUP_MAP **pp_rmap,
+                                          size_t *p_num_entries,
+                                          bool unix_only)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba4_enum_group_members(struct pdb_methods *m,
+                                          TALLOC_CTX *mem_ctx,
+                                          const struct dom_sid *group,
+                                          uint32_t **pmembers,
+                                          size_t *pnum_members)
+{
+       size_t i, num_sids, num_members;
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct dom_sid *members_as_sids;
+       struct dom_sid *dom_sid;
+       uint32_t *members;
+       struct ldb_dn *dn;
+       NTSTATUS status;
+
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, group));
+       if (!dn || !ldb_dn_validate(dn)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = dsdb_enum_group_mem(state->ldb, tmp_ctx, dn, &members_as_sids, &num_sids);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return status;
+       }
+       status = dom_sid_split_rid(tmp_ctx, group, &dom_sid, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return status;
+       }
+
+       *pmembers = members = talloc_array(mem_ctx, uint32_t, num_sids);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(*pmembers, tmp_ctx);
+       num_members = 0;
+
+       for (i = 0; i < num_sids; i++) {
+               if (!dom_sid_in_domain(dom_sid, &members_as_sids[i])) {
+                       continue;
+               }
+               status = dom_sid_split_rid(NULL, &members_as_sids[i], 
+                                          NULL, &members[num_members]);
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_free(tmp_ctx);
+                       return status;
+               }
+               num_members++;
+       }
+       *pnum_members = num_members;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_enum_group_memberships(struct pdb_methods *m,
+                                              TALLOC_CTX *mem_ctx,
+                                              struct samu *user,
+                                              struct dom_sid **pp_sids,
+                                              gid_t **pp_gids,
+                                              size_t *p_num_groups)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct ldb_message *msg = pdb_samba4_get_samu_private(
+               m, user);
+       const char *attrs[] = { "tokenGroups", NULL};
+       struct ldb_message *tokengroups_msg;
+       struct ldb_message_element *tokengroups;
+       int i, rc;
+       NTSTATUS status;
+       unsigned int count = 0;
+       size_t num_groups;
+       struct dom_sid *group_sids;
+       gid_t *gids;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       rc = dsdb_search_one(state->ldb, tmp_ctx, &tokengroups_msg, msg->dn, LDB_SCOPE_BASE, attrs, 0, NULL);
+
+       if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_SUCH_USER;
+       } else if (rc != LDB_SUCCESS) {
+               DEBUG(10, ("dsdb_search_one failed %s\n",
+                          ldb_errstring(state->ldb)));
+               talloc_free(tmp_ctx);
+               return NT_STATUS_LDAP(rc);
+       }
+
+       tokengroups = ldb_msg_find_element(tokengroups_msg, "tokenGroups");
+
+       if (tokengroups) {
+               count = tokengroups->num_values;
+       }
+       group_sids = talloc_array(tmp_ctx, struct dom_sid, count);
+       if (group_sids == NULL) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       gids = talloc_array(tmp_ctx, gid_t, count);
+       if (gids == NULL) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       num_groups = 0;
+
+       for (i=0; i<count; i++) {
+               struct id_map *id_maps[2];
+               struct id_map id_map;
+               struct ldb_val *v = &tokengroups->values[i];
+               enum ndr_err_code ndr_err
+                       = ndr_pull_struct_blob(v, group_sids, &group_sids[num_groups],
+                                              (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       talloc_free(tmp_ctx);
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+               
+               ZERO_STRUCT(id_map);
+               id_map.sid = &group_sids[num_groups];
+               id_maps[0] = &id_map;
+               id_maps[1] = NULL;
+
+               status = idmap_sids_to_xids(state->idmap_ctx, tmp_ctx, id_maps);
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_free(tmp_ctx);
+                       return status;
+               }
+               if (id_map.xid.type == ID_TYPE_GID || id_map.xid.type == ID_TYPE_BOTH) {
+                       gids[num_groups] = id_map.xid.id;
+               } else {
+                       DEBUG(1, (__location__ 
+                                 "Group %s, of which %s is a member, could not be converted to a GID\n",
+                                 dom_sid_string(tmp_ctx, &group_sids[num_groups]),
+                                 ldb_dn_get_linearized(msg->dn)));
+                       talloc_free(tmp_ctx);
+                       /* We must error out, otherwise a user might
+                        * avoid a DENY acl based on a group they
+                        * missed out on */
+                       return NT_STATUS_NO_SUCH_GROUP;
+               }
+
+               num_groups += 1;
+               if (num_groups == count) {
+                       break;
+               }
+       }
+
+       *pp_sids = talloc_steal(mem_ctx, group_sids);
+       *pp_gids = talloc_steal(mem_ctx, gids);
+       *p_num_groups = num_groups;
+       talloc_free(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_set_unix_primary_group(struct pdb_methods *m,
+                                              TALLOC_CTX *mem_ctx,
+                                              struct samu *user)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba4_mod_groupmem_by_sid(struct pdb_methods *m,
+                                              TALLOC_CTX *mem_ctx,
+                                              const struct dom_sid *groupsid, 
+                                              const struct dom_sid *membersid,
+                                              int mod_op)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct ldb_message *msg;
+       int ret;
+       struct ldb_message_element *el;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+       msg = ldb_msg_new(tmp_ctx);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(msg, tmp_ctx);
+
+       msg->dn = ldb_dn_new_fmt(msg, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, groupsid));
+       if (!msg->dn || !ldb_dn_validate(msg->dn)) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       ret = ldb_msg_add_fmt(msg, "member", "<SID=%s>", dom_sid_string(tmp_ctx, membersid));
+       if (ret != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       el = ldb_msg_find_element(msg, "member");
+       el->flags = mod_op;
+
+       ret = ldb_modify(state->ldb, msg);
+       talloc_free(tmp_ctx);
+       if (ret != LDB_SUCCESS) {
+               DEBUG(10, ("ldb_modify failed: %s\n",
+                          ldb_errstring(state->ldb)));
+               if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
+                       return NT_STATUS_MEMBER_IN_GROUP;
+               }
+               if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+                       return NT_STATUS_MEMBER_NOT_IN_GROUP;
+               }
+               return NT_STATUS_LDAP(ret);
+       }
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_mod_groupmem(struct pdb_methods *m,
+                                    TALLOC_CTX *mem_ctx,
+                                    uint32 grouprid, uint32 memberrid,
+                                    int mod_op)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       const struct dom_sid *dom_sid, *groupsid, *membersid;
+       NTSTATUS status;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       dom_sid = samdb_domain_sid(state->ldb);
+
+       groupsid = dom_sid_add_rid(tmp_ctx, dom_sid, grouprid);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(groupsid, tmp_ctx);
+       membersid = dom_sid_add_rid(tmp_ctx, dom_sid, memberrid);
+       NT_STATUS_HAVE_NO_MEMORY_AND_FREE(membersid, tmp_ctx);
+       status = pdb_samba4_mod_groupmem_by_sid(m, tmp_ctx, groupsid, membersid, mod_op);
+       talloc_free(tmp_ctx);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_add_groupmem(struct pdb_methods *m,
+                                    TALLOC_CTX *mem_ctx,
+                                    uint32 group_rid, uint32 member_rid)
+{
+       return pdb_samba4_mod_groupmem(m, mem_ctx, group_rid, member_rid,
+                                   LDB_FLAG_MOD_ADD);
+}
+
+static NTSTATUS pdb_samba4_del_groupmem(struct pdb_methods *m,
+                                    TALLOC_CTX *mem_ctx,
+                                    uint32 group_rid, uint32 member_rid)
+{
+       return pdb_samba4_mod_groupmem(m, mem_ctx, group_rid, member_rid,
+                                      LDB_FLAG_MOD_DELETE);
+}
+
+static NTSTATUS pdb_samba4_create_alias(struct pdb_methods *m,
+                                    const char *name, uint32 *rid)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct dom_sid *sid;
+
+       struct ldb_dn *dn;
+       NTSTATUS status;
+       
+       status = dsdb_add_domain_alias(state->ldb, frame, name, &sid, &dn);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
+       }
+
+       sid_peek_rid(sid, rid);
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_delete_alias(struct pdb_methods *m,
+                                    const struct dom_sid *sid)
+{
+       const char *attrs[] = { NULL };
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct ldb_message *msg;
+       struct ldb_dn *dn;
+       int rc;
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, sid));
+       if (!dn || !ldb_dn_validate(dn)) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       rc = dsdb_search_one(state->ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "(objectclass=group)"
+                            "(|(grouptype=%d)(grouptype=%d)))",
+                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
+                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
+       if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_SUCH_ALIAS;
+       }
+       rc = ldb_delete(state->ldb, dn);
+       if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_SUCH_ALIAS;
+       } else if (rc != LDB_SUCCESS) {
+               DEBUG(10, ("ldb_delete failed %s\n",
+                          ldb_errstring(state->ldb)));
+               return NT_STATUS_LDAP(rc);
+       }
+       return NT_STATUS_OK;
+}
+
+#if 0
+static NTSTATUS pdb_samba4_set_aliasinfo(struct pdb_methods *m,
+                                     const struct dom_sid *sid,
+                                     struct acct_info *info)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct tldap_context *ld;
+       const char *attrs[3] = { "objectSid", "description",
+                                "samAccountName" };
+       struct ldb_message **msg;
+       char *sidstr, *dn;
+       int rc;
+       struct tldap_mod *mods;
+       int num_mods;
+       bool ok;
+
+       ld = pdb_samba4_ld(state);
+       if (ld == NULL) {
+               return NT_STATUS_LDAP(TLDAP_SERVER_DOWN);
+       }
+
+       sidstr = sid_binstring(talloc_tos(), sid);
+       NT_STATUS_HAVE_NO_MEMORY(sidstr);
+
+       rc = pdb_samba4_search_fmt(state, state->domaindn, TLDAP_SCOPE_SUB,
+                               attrs, ARRAY_SIZE(attrs), 0, talloc_tos(),
+                               &msg, "(&(objectSid=%s)(objectclass=group)"
+                               "(|(grouptype=%d)(grouptype=%d)))",
+                               sidstr, GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
+                               GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
+       TALLOC_FREE(sidstr);
+       if (rc != LDB_SUCCESS) {
+               DEBUG(10, ("ldap_search failed %s\n",
+                          ldb_errstring(state->ldb)));
+               return NT_STATUS_LDAP(rc);
+       }
+       switch talloc_array_length(msg) {
+       case 0:
+               return NT_STATUS_NO_SUCH_ALIAS;
+       case 1:
+               break;
+       default:
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       if (!tldap_entry_dn(msg[0], &dn)) {
+               TALLOC_FREE(msg);
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       mods = NULL;
+       num_mods = 0;
+       ok = true;
+
+       ok &= tldap_make_mod_fmt(
+               msg[0], msg, &num_mods, &mods, "description",
+               "%s", info->acct_desc);
+       ok &= tldap_make_mod_fmt(
+               msg[0], msg, &num_mods, &mods, "samAccountName",
+               "%s", info->acct_name);
+       if (!ok) {
+               TALLOC_FREE(msg);
+               return NT_STATUS_NO_MEMORY;
+       }
+       if (num_mods == 0) {
+               /* no change */
+               TALLOC_FREE(msg);
+               return NT_STATUS_OK;
+       }
+
+       rc = tldap_modify(ld, dn, num_mods, mods, NULL, 0, NULL, 0);
+       TALLOC_FREE(msg);
+       if (rc != LDB_SUCCESS) {
+               DEBUG(10, ("ldap_modify failed: %s\n",
+                          ldb_errstring(state->ldb)));
+               return NT_STATUS_LDAP(rc);
+       }
+       return NT_STATUS_OK;
+}
+#endif
+static NTSTATUS pdb_samba4_add_aliasmem(struct pdb_methods *m,
+                                    const struct dom_sid *alias,
+                                    const struct dom_sid *member)
+{
+       NTSTATUS status;
+       TALLOC_CTX *frame = talloc_stackframe();
+       status = pdb_samba4_mod_groupmem_by_sid(m, frame, alias, member, LDB_FLAG_MOD_ADD);
+       talloc_free(frame);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_del_aliasmem(struct pdb_methods *m,
+                                    const struct dom_sid *alias,
+                                    const struct dom_sid *member)
+{
+       NTSTATUS status;
+       TALLOC_CTX *frame = talloc_stackframe();
+       status = pdb_samba4_mod_groupmem_by_sid(m, frame, alias, member, LDB_FLAG_MOD_DELETE);
+       talloc_free(frame);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_enum_aliasmem(struct pdb_methods *m,
+                                     const struct dom_sid *alias,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct dom_sid **pmembers,
+                                     size_t *pnum_members)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct ldb_dn *dn;
+       NTSTATUS status;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, alias));
+       if (!dn || !ldb_dn_validate(dn)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = dsdb_enum_group_mem(state->ldb, mem_ctx, dn, pmembers, pnum_members);
+       if (NT_STATUS_IS_OK(status)) {
+               talloc_steal(mem_ctx, pmembers);
+       }
+       talloc_free(tmp_ctx);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_enum_alias_memberships(struct pdb_methods *m,
+                                              TALLOC_CTX *mem_ctx,
+                                              const struct dom_sid *domain_sid,
+                                              const struct dom_sid *members,
+                                              size_t num_members,
+                                              uint32_t **palias_rids,
+                                              size_t *pnum_alias_rids)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       uint32_t *alias_rids = NULL;
+       size_t num_alias_rids = 0;
+       int i;
+       struct dom_sid **groupSIDs = NULL;
+       unsigned int num_groupSIDs = 0;
+       char *filter;
+       NTSTATUS status;
+       const char *sid_string;
+       const char *sid_dn;
+       DATA_BLOB sid_blob;
+
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+       /*
+        * TODO: Get the filter right so that we only get the aliases from
+        * either the SAM or BUILTIN
+        */
+
+       filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:1.2.840.113556.1.4.803:=%u))",
+                                GROUP_TYPE_BUILTIN_LOCAL_GROUP);
+       if (filter == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i = 0; i < num_members; i++) {
+               sid_string = dom_sid_string(tmp_ctx, &members[i]);
+               NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sid_string, tmp_ctx);
+
+               sid_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", sid_string);
+               NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sid_dn, tmp_ctx);
+               
+               sid_blob = data_blob_string_const(sid_dn);
+               
+               status = s3compat_authsam_expand_nested_groups(state->ldb, &sid_blob, true, filter,
+                                                              tmp_ctx, &groupSIDs, &num_groupSIDs);
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_free(tmp_ctx);
+                       return status;
+               }
+       }
+
+       alias_rids = talloc_array(mem_ctx, uint32_t, num_groupSIDs);
+       if (alias_rids == NULL) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i=0; i<num_groupSIDs; i++) {
+               if (sid_peek_check_rid(domain_sid, groupSIDs[i],
+                                      &alias_rids[num_alias_rids])) {
+                       num_alias_rids++;;
+               }
+       }
+
+       *palias_rids = alias_rids;
+       *pnum_alias_rids = num_alias_rids;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS pdb_samba4_lookup_rids(struct pdb_methods *m,
+                                   const struct dom_sid *domain_sid,
+                                   int num_rids,
+                                   uint32 *rids,
+                                   const char **names,
+                                   enum lsa_SidType *lsa_attrs)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       NTSTATUS status;
+
+       TALLOC_CTX *tmp_ctx;
+
+       if (num_rids == 0) {
+               return NT_STATUS_NONE_MAPPED;
+       }
+
+       tmp_ctx = talloc_stackframe();
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+       
+       status = dsdb_lookup_rids(state->ldb, tmp_ctx, domain_sid, num_rids, rids, names, lsa_attrs);
+       talloc_free(tmp_ctx);
+       return status;
+}
+
+static NTSTATUS pdb_samba4_lookup_names(struct pdb_methods *m,
+                                    const struct dom_sid *domain_sid,
+                                    int num_names,
+                                    const char **pp_names,
+                                    uint32 *rids,
+                                    enum lsa_SidType *attrs)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS pdb_samba4_get_account_policy(struct pdb_methods *m,
+                                          enum pdb_policy_type type,
+                                          uint32_t *value)
+{
+       return account_policy_get(type, value)
+               ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS pdb_samba4_set_account_policy(struct pdb_methods *m,
+                                          enum pdb_policy_type type,
+                                          uint32_t value)
+{
+       return account_policy_set(type, value)
+               ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS pdb_samba4_get_seq_num(struct pdb_methods *m,
+                                   time_t *seq_num_out)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       uint64_t seq_num;
+       int ret = ldb_sequence_number(state->ldb, LDB_SEQ_HIGHEST_SEQ, &seq_num);
+       if (ret == LDB_SUCCESS) {
+               *seq_num_out = seq_num;
+               return NT_STATUS_OK;
+       } else {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+}
+
+struct pdb_samba4_search_state {
+       uint32_t acct_flags;
+       struct samr_displayentry *entries;
+       uint32_t num_entries;
+       ssize_t array_size;
+       uint32_t current;
+};
+
+static bool pdb_samba4_next_entry(struct pdb_search *search,
+                              struct samr_displayentry *entry)
+{
+       struct pdb_samba4_search_state *state = talloc_get_type_abort(
+               search->private_data, struct pdb_samba4_search_state);
+
+       if (state->current == state->num_entries) {
+               return false;
+       }
+
+       entry->idx = state->entries[state->current].idx;
+       entry->rid = state->entries[state->current].rid;
+       entry->acct_flags = state->entries[state->current].acct_flags;
+
+       entry->account_name = talloc_steal(
+               search, state->entries[state->current].account_name);
+       entry->fullname = talloc_steal(
+               search, state->entries[state->current].fullname);
+       entry->description = talloc_steal(
+               search, state->entries[state->current].description);
+
+       state->current += 1;
+       return true;
+}
+
+static void pdb_samba4_search_end(struct pdb_search *search)
+{
+       struct pdb_samba4_search_state *state = talloc_get_type_abort(
+               search->private_data, struct pdb_samba4_search_state);
+       talloc_free(state);
+}
+
+static bool pdb_samba4_search_filter(struct pdb_methods *m,
+                                    struct pdb_search *search,
+                                    struct pdb_samba4_search_state **pstate,
+                                    const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(4, 5)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct pdb_samba4_search_state *sstate;
+       const char * attrs[] = { "objectSid", "sAMAccountName", "displayName",
+                                "userAccountControl", "description", NULL };
+       struct ldb_result *res;
+       int i, rc, num_users;
+
+       va_list ap;
+       char *expression = NULL;
+
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       if (!tmp_ctx) {
+               return false;
+       }
+
+       va_start(ap, exp_fmt);
+       expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
+       va_end(ap);
+       
+       if (!expression) {
+               talloc_free(tmp_ctx);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       sstate = talloc_zero(tmp_ctx, struct pdb_samba4_search_state);
+       if (sstate == NULL) {
+               talloc_free(tmp_ctx);
+               return false;
+       }
+
+       rc = dsdb_search(state->ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs, 0, "%s", expression);
+       if (rc != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               DEBUG(10, ("dsdb_search failed: %s\n",
+                          ldb_errstring(state->ldb)));
+               return false;
+       }
+
+       num_users = res->count;
+
+       sstate->entries = talloc_array(sstate, struct samr_displayentry,
+                                      num_users);
+       if (sstate->entries == NULL) {
+               talloc_free(tmp_ctx);
+               DEBUG(10, ("talloc failed\n"));
+               return false;
+       }
+
+       sstate->num_entries = 0;
+
+       for (i=0; i<num_users; i++) {
+               struct samr_displayentry *e;
+               struct dom_sid *sid;
+
+               e = &sstate->entries[sstate->num_entries];
+
+               e->idx = sstate->num_entries;
+               sid = samdb_result_dom_sid(tmp_ctx, res->msgs[i], "objectSid");
+               if (!sid) {
+                       talloc_free(tmp_ctx);
+                       DEBUG(10, ("Could not pull SID\n"));
+                       return false;
+               }
+               sid_peek_rid(sid, &e->rid);
+       
+               e->acct_flags = samdb_result_acct_flags(state->ldb, tmp_ctx,
+                                                       res->msgs[i], 
+                                                       ldb_get_default_basedn(state->ldb));
+               e->account_name = ldb_msg_find_attr_as_string(
+                       res->msgs[i], "samAccountName", NULL);
+               if (e->account_name == NULL) {
+                       talloc_free(tmp_ctx);
+                       return false;
+               }
+               e->fullname = ldb_msg_find_attr_as_string(
+                        res->msgs[i], "displayName", "");
+               e->description = ldb_msg_find_attr_as_string(
+                        res->msgs[i], "description", "");
+
+               sstate->num_entries += 1;
+               if (sstate->num_entries >= num_users) {
+                       break;
+               }
+       }
+       talloc_steal(sstate->entries, res->msgs);
+       search->private_data = talloc_steal(search, sstate);
+       search->next_entry = pdb_samba4_next_entry;
+       search->search_end = pdb_samba4_search_end;
+       *pstate = sstate;
+       talloc_free(tmp_ctx);
+       return true;
+}
+
+static bool pdb_samba4_search_users(struct pdb_methods *m,
+                                struct pdb_search *search,
+                                uint32 acct_flags)
+{
+       struct pdb_samba4_search_state *sstate;
+       bool ret;
+
+       ret = pdb_samba4_search_filter(m, search, &sstate, "(objectclass=user)");
+       if (!ret) {
+               return false;
+       }
+       sstate->acct_flags = acct_flags;
+       return true;
+}
+
+static bool pdb_samba4_search_groups(struct pdb_methods *m,
+                                 struct pdb_search *search)
+{
+       struct pdb_samba4_search_state *sstate;
+       bool ret;
+
+       ret = pdb_samba4_search_filter(m, search, &sstate, 
+                                      "(&(grouptype=%d)(objectclass=group))",
+                                      GTYPE_SECURITY_GLOBAL_GROUP);
+       if (!ret) {
+               return false;
+       }
+       sstate->acct_flags = 0;
+       return true;
+}
+
+static bool pdb_samba4_search_aliases(struct pdb_methods *m,
+                                  struct pdb_search *search,
+                                  const struct dom_sid *sid)
+{
+       struct pdb_samba4_search_state *sstate;
+       bool ret;
+
+       ret = pdb_samba4_search_filter(m, search, &sstate, 
+                                      "(&(grouptype=%d)(objectclass=group))",
+                                      sid_check_is_builtin(sid)
+                                      ? GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
+                                      : GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
+       if (!ret) {
+               return false;
+       }
+       sstate->acct_flags = 0;
+       return true;
+}
+
+static bool pdb_samba4_uid_to_sid(struct pdb_methods *m, uid_t uid,
+                              struct dom_sid *sid)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       NTSTATUS status;
+       struct id_map id_map;
+       struct id_map *id_maps[2];
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       if (!tmp_ctx) {
+               return false;
+       }
+
+       id_map.xid.id = uid;
+       id_map.xid.type = ID_TYPE_UID;
+       id_maps[0] = &id_map;
+       id_maps[1] = NULL;
+
+       status = idmap_xids_to_sids(state->idmap_ctx, tmp_ctx, id_maps);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return false;
+       }
+       *sid = *id_map.sid;
+       talloc_free(tmp_ctx);
+       return true;
+}
+
+static bool pdb_samba4_gid_to_sid(struct pdb_methods *m, gid_t gid,
+                              struct dom_sid *sid)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       NTSTATUS status;
+       struct id_map id_map;
+       struct id_map *id_maps[2];
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       if (!tmp_ctx) {
+               return false;
+       }
+
+       id_map.xid.id = gid;
+       id_map.xid.type = ID_TYPE_GID;
+       id_maps[0] = &id_map;
+       id_maps[1] = NULL;
+
+       status = idmap_xids_to_sids(state->idmap_ctx, tmp_ctx, id_maps);
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
+       }
+       *sid = *id_map.sid;
+       talloc_free(tmp_ctx);
+       return true;
+}
+
+static bool pdb_samba4_sid_to_id(struct pdb_methods *m, const struct dom_sid *sid,
+                                union unid_t *id, enum lsa_SidType *type)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               m->private_data, struct pdb_samba4_state);
+       struct id_map id_map;
+       struct id_map *id_maps[2];
+       const char *attrs[] = { "objectClass", "groupType", NULL };
+       struct ldb_message *msg;
+       struct ldb_dn *dn;
+       NTSTATUS status;
+       int rc;
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       if (!tmp_ctx) {
+               return false;
+       }
+
+       ZERO_STRUCT(id_map);
+
+       dn = ldb_dn_new_fmt(tmp_ctx, state->ldb, "<SID=%s>", dom_sid_string(tmp_ctx, sid));
+       if (!dn || !ldb_dn_validate(dn)) {
+               talloc_free(tmp_ctx);
+               return false;
+       }
+       rc = dsdb_search_one(state->ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, NULL);
+       if (rc == LDB_ERR_NO_SUCH_OBJECT) {
+               DEBUG(5, (__location__ "SID to Unix ID lookup failed because SID %s could not be found in the samdb\n", dom_sid_string(tmp_ctx, sid)));
+               talloc_free(tmp_ctx);
+               return false;
+       }
+       if (samdb_find_attribute(state->ldb, msg, "objectClass", "group")) {
+               uint32_t grouptype = ldb_msg_find_attr_as_uint(msg, "groupType", 0);
+               switch (grouptype) {
+               case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
+               case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
+                       *type = SID_NAME_ALIAS;
+                       break;
+               case GTYPE_SECURITY_GLOBAL_GROUP:
+                       *type = SID_NAME_DOM_GRP;
+                       break;
+               default:
+                       talloc_free(tmp_ctx);
+                       DEBUG(10, ("Could not pull groupType\n"));
+                       return false;
+               }
+
+               *type = SID_NAME_DOM_GRP;
+
+               ZERO_STRUCT(id_map);
+               id_map.sid = sid;
+               id_maps[0] = &id_map;
+               id_maps[1] = NULL;
+               
+               status = idmap_sids_to_xids(state->idmap_ctx, tmp_ctx, id_maps);
+               talloc_free(tmp_ctx);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return false;
+               }
+               if (id_map.xid.type == ID_TYPE_GID || id_map.xid.type == ID_TYPE_BOTH) {
+                       id->gid = id_map.xid.id;
+                       return true;
+               }
+               return false;
+       } else if (samdb_find_attribute(state->ldb, msg, "objectClass", "user")) {
+               *type = SID_NAME_USER;
+               ZERO_STRUCT(id_map);
+               id_map.sid = sid;
+               id_maps[0] = &id_map;
+               id_maps[1] = NULL;
+               
+               status = idmap_sids_to_xids(state->idmap_ctx, tmp_ctx, id_maps);
+               talloc_free(tmp_ctx);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return false;
+               }
+               if (id_map.xid.type == ID_TYPE_UID || id_map.xid.type == ID_TYPE_BOTH) {
+                       id->uid = id_map.xid.id;
+                       return true;
+               }
+               return false;
+       }
+       DEBUG(5, (__location__ "SID to Unix ID lookup failed because SID %s was found, but was not a user or group\n", dom_sid_string(tmp_ctx, sid)));
+       talloc_free(tmp_ctx);
+       return false;
+}
+
+static uint32_t pdb_samba4_capabilities(struct pdb_methods *m)
+{
+       return PDB_CAP_STORE_RIDS;
+}
+
+static bool pdb_samba4_new_rid(struct pdb_methods *m, uint32 *rid)
+{
+       return false;
+}
+
+static bool pdb_samba4_get_trusteddom_pw(struct pdb_methods *m,
+                                     const char *domain, char** pwd,
+                                     struct dom_sid *sid,
+                                     time_t *pass_last_set_time)
+{
+       return false;
+}
+
+static bool pdb_samba4_set_trusteddom_pw(struct pdb_methods *m,
+                                     const char* domain, const char* pwd,
+                                     const struct dom_sid *sid)
+{
+       return false;
+}
+
+static bool pdb_samba4_del_trusteddom_pw(struct pdb_methods *m,
+                                     const char *domain)
+{
+       return false;
+}
+
+static NTSTATUS pdb_samba4_enum_trusteddoms(struct pdb_methods *m,
+                                        TALLOC_CTX *mem_ctx,
+                                        uint32 *num_domains,
+                                        struct trustdom_info ***domains)
+{
+       *num_domains = 0;
+       *domains = NULL;
+       return NT_STATUS_OK;
+}
+
+static void pdb_samba4_init_methods(struct pdb_methods *m)
+{
+       m->name = "samba4";
+       m->get_domain_info = NULL;
+       m->getsampwnam = pdb_samba4_getsampwnam;
+       m->getsampwsid = pdb_samba4_getsampwsid;
+       m->create_user = pdb_samba4_create_user;
+       m->delete_user = pdb_samba4_delete_user;
+       m->add_sam_account = pdb_samba4_add_sam_account;
+       m->delete_sam_account = pdb_samba4_delete_sam_account;
+       m->rename_sam_account = pdb_samba4_rename_sam_account;
+       m->update_login_attempts = pdb_samba4_update_login_attempts;
+       m->getgrsid = pdb_samba4_getgrsid;
+       m->getgrgid = pdb_samba4_getgrgid;
+       m->getgrnam = pdb_samba4_getgrnam;
+       m->create_dom_group = pdb_samba4_create_dom_group;
+       m->delete_dom_group = pdb_samba4_delete_dom_group;
+       m->add_group_mapping_entry = pdb_samba4_add_group_mapping_entry;
+       m->update_group_mapping_entry = pdb_samba4_update_group_mapping_entry;
+       m->delete_group_mapping_entry = pdb_samba4_delete_group_mapping_entry;
+       m->enum_group_mapping = pdb_samba4_enum_group_mapping;
+       m->enum_group_members = pdb_samba4_enum_group_members;
+       m->enum_group_memberships = pdb_samba4_enum_group_memberships;
+       m->set_unix_primary_group = pdb_samba4_set_unix_primary_group;
+       m->add_groupmem = pdb_samba4_add_groupmem;
+       m->del_groupmem = pdb_samba4_del_groupmem;
+       m->create_alias = pdb_samba4_create_alias;
+       m->delete_alias = pdb_samba4_delete_alias;
+       m->get_aliasinfo = pdb_default_get_aliasinfo;
+       m->add_aliasmem = pdb_samba4_add_aliasmem;
+       m->del_aliasmem = pdb_samba4_del_aliasmem;
+       m->enum_aliasmem = pdb_samba4_enum_aliasmem;
+       m->enum_alias_memberships = pdb_samba4_enum_alias_memberships;
+       m->lookup_rids = pdb_samba4_lookup_rids;
+       m->lookup_names = pdb_samba4_lookup_names;
+       m->get_account_policy = pdb_samba4_get_account_policy;
+       m->set_account_policy = pdb_samba4_set_account_policy;
+       m->get_seq_num = pdb_samba4_get_seq_num;
+       m->search_users = pdb_samba4_search_users;
+       m->search_groups = pdb_samba4_search_groups;
+       m->search_aliases = pdb_samba4_search_aliases;
+       m->uid_to_sid = pdb_samba4_uid_to_sid;
+       m->gid_to_sid = pdb_samba4_gid_to_sid;
+       m->sid_to_id = pdb_samba4_sid_to_id;
+       m->capabilities = pdb_samba4_capabilities;
+       m->new_rid = pdb_samba4_new_rid;
+       m->get_trusteddom_pw = pdb_samba4_get_trusteddom_pw;
+       m->set_trusteddom_pw = pdb_samba4_set_trusteddom_pw;
+       m->del_trusteddom_pw = pdb_samba4_del_trusteddom_pw;
+       m->enum_trusteddoms = pdb_samba4_enum_trusteddoms;
+}
+
+static void free_private_data(void **vp)
+{
+       struct pdb_samba4_state *state = talloc_get_type_abort(
+               *vp, struct pdb_samba4_state);
+       talloc_unlink(state, state->ldb);
+       return;
+}
+
+static NTSTATUS pdb_init_samba4(struct pdb_methods **pdb_method,
+                            const char *location)
+{
+       struct pdb_methods *m;
+       struct pdb_samba4_state *state;
+       NTSTATUS status;
+
+       if ( !NT_STATUS_IS_OK(status = make_pdb_method( &m )) ) {
+               return status;
+       }
+
+       state = talloc_zero(m, struct pdb_samba4_state);
+       if (state == NULL) {
+               goto nomem;
+       }
+       m->private_data = state;
+       m->free_private_data = free_private_data;
+       pdb_samba4_init_methods(m);
+
+       state->ldb = s3compat_samdb_connect(state);
+       if (!state->ldb) {
+               DEBUG(10, ("samdb_connect failed\n"));
+               goto fail;
+       }
+
+       state->idmap_ctx = s3compat_idmap_init(state);
+       if (!state->idmap_ctx) {
+               DEBUG(10, ("samdb_connect failed\n"));
+               goto fail;
+       }
+
+       *pdb_method = m;
+       return NT_STATUS_OK;
+nomem:
+       status = NT_STATUS_NO_MEMORY;
+fail:
+       TALLOC_FREE(m);
+       return status;
+}
+
+NTSTATUS pdb_samba4_init(void);
+NTSTATUS pdb_samba4_init(void)
+{
+       return smb_register_passdb(PASSDB_INTERFACE_VERSION, "samba4",
+                                  pdb_init_samba4);
+}
index fcd9b505f8cd46db5356ee41e6ac780a6354c640..feb5aefbe30b460d3a2e822b008eff410d44b67a 100644 (file)
@@ -54,6 +54,7 @@ void s3compat_initialise(const char *config_file, bool interactive)
 
        /* Register our 'imposter' auth module, which redirects to samba4 */
        auth_samba4_init();
+       pdb_samba4_init();
 
        DEBUG(0,("s3compat: initialised samba3 version: %s\n",
                 samba_version_string()));
index 8ecd2973b0d4a9543d98fa38b47ffb79f31f422a..003082278a2b7493c0b85c89685c751f3fd03986 100644 (file)
@@ -31,6 +31,7 @@
 #include "auth/gensec/gensec.h"
 #include "libcli/security/dom_sid.h"
 #include "dsdb/samdb/samdb.h"
+#include "winbind/idmap.h"
 
 NTSTATUS s3compat_authenticate(TALLOC_CTX *mem_ctx, uint8_t chall[8], const struct auth_usersupplied_info *user_info, struct netr_SamInfo3 **info3) 
 {
@@ -256,6 +257,12 @@ struct ldb_context *s3compat_samdb_connect(TALLOC_CTX *mem_ctx)
                             system_session(s3compat_get_lp_ctx()));
 }
 
+struct idmap_context *s3compat_idmap_init(TALLOC_CTX *mem_ctx)
+{
+       return idmap_init(mem_ctx, s3compat_get_tevent_ctx(), 
+                         s3compat_get_lp_ctx());
+}
+
 NTSTATUS s3compat_authsam_expand_nested_groups(struct ldb_context *sam_ctx,
                                               struct ldb_val *dn_val, const bool only_childs, const char *filter,
                                               TALLOC_CTX *res_sids_ctx, struct dom_sid ***res_sids,
index ebae6d258dd0bf005eef0252b2f40e94076b8d24..0e6b01573b0107e17dd9d96f4624b9553c7c6a9e 100644 (file)
@@ -850,8 +850,8 @@ bld.SAMBA_SUBSYSTEM('s3_winbind',
 bld.SAMBA_SUBSYSTEM('s3compat_wrapper',
                     includes=SAMBA3_INCLUDES,
                     autoproto='s3compat_wrapper_proto.h',
-                    source='s3compat.c s3compat_winbindd.c auth_samba4.c',
-                    deps='tdb tevent',
+                    source='s3compat.c s3compat_winbindd.c auth_samba4.c pdb_samba4.c',
+                    deps='tdb tevent ldb SAMDB_COMMON',
                     hide_symbols=True)
 
 bld.SAMBA_SUBSYSTEM('s3replace',