s3:winbindd/autorid use idmap_tdb_common code in autorid
authorChristian Ambach <ambi@samba.org>
Wed, 25 Jan 2012 18:06:16 +0000 (19:06 +0100)
committerChristian Ambach <ambi@samba.org>
Tue, 1 May 2012 07:32:11 +0000 (09:32 +0200)
- use common logic for the allocation pool
- add a idmap_tdb style 1on1 mapping for non-domain SIDs
  like Everyone (S-1-1-0)

source3/winbindd/idmap_autorid.c

index 9048c126b5b28640aafaf17827c19baeb3c9d86a..ab84104a633aef65273f0c896d3851d1cc361560 100644 (file)
@@ -5,7 +5,7 @@
  *  based on the idmap_rid module, but this module defines the ranges
  *  for the domains by automatically allocating a range for each domain
  *
- *  Copyright (C) Christian Ambach, 2010-2011
+ *  Copyright (C) Christian Ambach, 2010-2012
  *
  *  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
 #include "dbwrap/dbwrap.h"
 #include "dbwrap/dbwrap_open.h"
 #include "idmap.h"
+#include "idmap_rw.h"
 #include "../libcli/security/dom_sid.h"
 #include "util_tdb.h"
+#include "winbindd/idmap_tdb_common.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_IDMAP
@@ -154,7 +156,78 @@ static NTSTATUS idmap_autorid_get_domainrange(struct autorid_domain_config *dom)
        return ret;
 }
 
+static NTSTATUS idmap_autorid_allocate_id(struct idmap_domain *dom,
+                                         struct unixid *xid) {
+
+       NTSTATUS ret;
+       struct idmap_tdb_common_context *commoncfg;
+       struct autorid_global_config *globalcfg;
+       struct autorid_domain_config domaincfg;
+
+       commoncfg =
+           talloc_get_type_abort(dom->private_data,
+                                 struct idmap_tdb_common_context);
+
+       globalcfg = talloc_get_type(commoncfg->private_data,
+                                   struct autorid_global_config);
+
+       /* fetch the range for the allocation pool */
+
+       ZERO_STRUCT(domaincfg);
+
+       domaincfg.globalcfg = globalcfg;
+       fstrcpy(domaincfg.sid, ALLOC_RANGE);
+
+       ret = idmap_autorid_get_domainrange(&domaincfg);
+
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(3, ("Could not determine range for allocation pool, "
+                         "check previous messages for reason\n"));
+               return ret;
+       }
+
+       ret = idmap_tdb_common_get_new_id(dom, xid);
+
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(1, ("Fatal error while allocating new ID!\n"));
+               return ret;
+       }
+
+       xid->id = globalcfg->minvalue +
+                 globalcfg->rangesize * domaincfg.domainnum +
+                 xid->id;
+
+       DEBUG(10, ("Returned new %s %d from allocation range\n",
+                  (xid->type==ID_TYPE_UID)?"uid":"gid", xid->id));
+
+       return ret;
+}
+
+/*
+ * map a SID to xid using the idmap_tdb like pool
+ */
+static NTSTATUS idmap_autorid_map_id_to_sid(struct idmap_domain *dom,
+                                           struct id_map *map)
+{
+       NTSTATUS ret;
+
+       /* look out for the mapping */
+       ret = idmap_tdb_common_unixid_to_sid(dom, map);
+
+       if (NT_STATUS_IS_OK(ret)) {
+               map->status = ID_MAPPED;
+               return ret;
+       }
+
+       map->status = ID_UNKNOWN;
+
+       DEBUG(10, ("no ID->SID mapping for %d could be found\n", map->xid.id));
+
+       return ret;
+}
+
 static NTSTATUS idmap_autorid_id_to_sid(struct autorid_global_config *cfg,
+                                       struct idmap_domain *dom,
                                        struct id_map *map)
 {
        uint32_t range;
@@ -201,12 +274,14 @@ static NTSTATUS idmap_autorid_id_to_sid(struct autorid_global_config *cfg,
        if (strncmp((const char *)data.dptr,
                    ALLOC_RANGE,
                    strlen(ALLOC_RANGE)) == 0) {
-               /* this is from the alloc range, there is no mapping back */
-               DEBUG(5, ("id %d belongs to alloc range, cannot map back\n",
+               /*
+                * this is from the alloc range, check if there is a mapping
+                */
+               DEBUG(5, ("id %d belongs to allocation range, "
+                         "checking for mapping\n",
                          map->xid.id));
                TALLOC_FREE(data.dptr);
-               map->status = ID_UNKNOWN;
-               return NT_STATUS_OK;
+               return idmap_autorid_map_id_to_sid(dom, map);
        }
 
        string_to_sid(&sid, (const char *)data.dptr);
@@ -262,21 +337,29 @@ static NTSTATUS idmap_autorid_sid_to_id(struct autorid_global_config *global,
 static NTSTATUS idmap_autorid_unixids_to_sids(struct idmap_domain *dom,
                                              struct id_map **ids)
 {
+       struct idmap_tdb_common_context *commoncfg;
        struct autorid_global_config *globalcfg;
        NTSTATUS ret;
        int i;
+       int num_tomap = 0;
+       int num_mapped = 0;
 
        /* initialize the status to avoid surprise */
        for (i = 0; ids[i]; i++) {
                ids[i]->status = ID_UNKNOWN;
+               num_tomap++;
        }
 
-       globalcfg = talloc_get_type(dom->private_data,
+       commoncfg =
+           talloc_get_type_abort(dom->private_data,
+                                 struct idmap_tdb_common_context);
+
+       globalcfg = talloc_get_type(commoncfg->private_data,
                                    struct autorid_global_config);
 
        for (i = 0; ids[i]; i++) {
 
-               ret = idmap_autorid_id_to_sid(globalcfg, ids[i]);
+               ret = idmap_autorid_id_to_sid(globalcfg, dom, ids[i]);
 
                if ((!NT_STATUS_IS_OK(ret)) &&
                    (!NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED))) {
@@ -285,13 +368,78 @@ static NTSTATUS idmap_autorid_unixids_to_sids(struct idmap_domain *dom,
                                  " (%d)\n", ids[i]->xid.id));
                        goto failure;
                }
+
+               if (NT_STATUS_IS_OK(ret) && ids[i]->status == ID_MAPPED) {
+                       num_mapped++;
+               }
+
        }
-       return NT_STATUS_OK;
+
+       if (num_tomap == num_mapped) {
+               return NT_STATUS_OK;
+       } else if (num_mapped == 0) {
+               return NT_STATUS_NONE_MAPPED;
+       }
+
+       return STATUS_SOME_UNMAPPED;
+
 
       failure:
        return ret;
 }
 
+/*
+ * map a SID to xid using the idmap_tdb like pool
+ */
+static NTSTATUS idmap_autorid_map_sid_to_id(struct idmap_domain *dom,
+                                           struct id_map *map,
+                                           struct idmap_tdb_common_context *ctx)
+{
+       NTSTATUS ret;
+       int res;
+
+       /* see if we already have a mapping */
+       ret = idmap_tdb_common_sid_to_unixid(dom, map);
+
+       if (NT_STATUS_IS_OK(ret)) {
+               map->status = ID_MAPPED;
+               return ret;
+       }
+
+       /* bad things happened */
+       if (!NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
+               DEBUG(1, ("Looking up SID->ID mapping for %s failed\n",
+                         sid_string_dbg(map->sid)));
+               return ret;
+       }
+
+       DEBUG(10, ("Creating new mapping in pool for %s\n",
+                  sid_string_dbg(map->sid)));
+
+       /* create new mapping */
+       dbwrap_transaction_start(ctx->db);
+
+       ret = idmap_tdb_common_new_mapping(dom, map);
+
+       map->status = (NT_STATUS_IS_OK(ret))?ID_MAPPED:ID_UNMAPPED;
+
+       if (!NT_STATUS_IS_OK(ret)) {
+               if (dbwrap_transaction_cancel(ctx->db) != 0) {
+                       smb_panic("Cancelling transaction failed");
+               }
+               return ret;
+       }
+
+       res = dbwrap_transaction_commit(ctx->db);
+       if (res == 0) {
+               return ret;
+       }
+
+       DEBUG(2, ("transaction_commit failed\n"));
+       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+
+}
+
 /**********************************
  lookup a set of sids.
 **********************************/
@@ -299,16 +447,24 @@ static NTSTATUS idmap_autorid_unixids_to_sids(struct idmap_domain *dom,
 static NTSTATUS idmap_autorid_sids_to_unixids(struct idmap_domain *dom,
                                              struct id_map **ids)
 {
+       struct idmap_tdb_common_context *commoncfg;
        struct autorid_global_config *global;
        NTSTATUS ret;
        int i;
+       int num_tomap = 0;
+       int num_mapped = 0;
 
        /* initialize the status to avoid surprise */
        for (i = 0; ids[i]; i++) {
                ids[i]->status = ID_UNKNOWN;
+               num_tomap++;
        }
 
-       global = talloc_get_type(dom->private_data,
+       commoncfg =
+           talloc_get_type_abort(dom->private_data,
+                                 struct idmap_tdb_common_context);
+
+       global = talloc_get_type(commoncfg->private_data,
                                 struct autorid_global_config);
 
        for (i = 0; ids[i]; i++) {
@@ -327,6 +483,29 @@ static NTSTATUS idmap_autorid_sids_to_unixids(struct idmap_domain *dom,
                        continue;
                }
 
+               /* is this a well-known SID? */
+
+               if (sid_check_is_wellknown_domain(&domainsid, NULL)) {
+
+                       DEBUG(10, ("SID %s is well-known, using pool\n",
+                                  sid_string_dbg(ids[i]->sid)));
+
+                       ret = idmap_autorid_map_sid_to_id(dom, ids[i],
+                                                         commoncfg);
+
+                       if (!NT_STATUS_IS_OK(ret) &&
+                           !NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
+                               DEBUG(3, ("Unexpected error resolving "
+                                         "SID (%s)\n",
+                                         sid_string_dbg(ids[i]->sid)));
+                               goto failure;
+                       }
+
+                       num_mapped++;
+
+                       continue;
+               }
+
                /*
                 * Check if the domain is around
                 */
@@ -359,8 +538,19 @@ static NTSTATUS idmap_autorid_sids_to_unixids(struct idmap_domain *dom,
                                  sid_string_dbg(ids[i]->sid)));
                        goto failure;
                }
+
+               if (NT_STATUS_IS_OK(ret)) {
+                       num_mapped++;
+               }
+       }
+
+       if (num_tomap == num_mapped) {
+               return NT_STATUS_OK;
+       } else if (num_mapped == 0) {
+               return NT_STATUS_NONE_MAPPED;
        }
-       return NT_STATUS_OK;
+
+       return STATUS_SOME_UNMAPPED;
 
       failure:
        return ret;
@@ -496,6 +686,7 @@ static NTSTATUS idmap_autorid_saveconfig(struct autorid_global_config *cfg)
 
 static NTSTATUS idmap_autorid_initialize(struct idmap_domain *dom)
 {
+       struct idmap_tdb_common_context *commonconfig;
        struct autorid_global_config *config;
        struct autorid_global_config *storedconfig = NULL;
        NTSTATUS status;
@@ -508,7 +699,19 @@ static NTSTATUS idmap_autorid_initialize(struct idmap_domain *dom)
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       config = talloc_zero(dom, struct autorid_global_config);
+       commonconfig = talloc_zero(dom, struct idmap_tdb_common_context);
+       if (!commonconfig) {
+               DEBUG(0, ("Out of memory!\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       commonconfig->rw_ops = talloc_zero(commonconfig, struct idmap_rw_ops);
+       if (commonconfig->rw_ops == NULL) {
+               DEBUG(0, ("Out of memory!\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       config = talloc_zero(commonconfig, struct autorid_global_config);
        if (!config) {
                DEBUG(0, ("Out of memory!\n"));
                return NT_STATUS_NO_MEMORY;
@@ -520,7 +723,8 @@ static NTSTATUS idmap_autorid_initialize(struct idmap_domain *dom)
        }
 
        config->minvalue = dom->low_id;
-       config->rangesize = lp_parm_int(-1, "idmap config *", "rangesize", 100000);
+       config->rangesize = lp_parm_int(-1, "idmap config *",
+                                       "rangesize", 100000);
 
        if (config->rangesize < 2000) {
                DEBUG(1, ("autorid rangesize must be at least 2000\n"));
@@ -594,7 +798,17 @@ static NTSTATUS idmap_autorid_initialize(struct idmap_domain *dom)
        DEBUG(5, ("%d domain ranges with a size of %d are available\n",
                  config->maxranges, config->rangesize));
 
-       dom->private_data = config;
+       /* fill the TDB common configuration */
+       commonconfig->private_data = config;
+
+       commonconfig->db = autorid_db;
+       commonconfig->max_id = config->rangesize -1;
+       commonconfig->hwmkey_uid = ALLOC_HWM_UID;
+       commonconfig->hwmkey_gid = ALLOC_HWM_GID;
+       commonconfig->rw_ops->get_new_id = idmap_autorid_allocate_id;
+       commonconfig->rw_ops->set_mapping = idmap_tdb_common_set_mapping;
+
+       dom->private_data = commonconfig;
 
        goto done;
 
@@ -607,79 +821,6 @@ done:
        return status;
 }
 
-static NTSTATUS idmap_autorid_allocate_id(struct idmap_domain *dom,
-                                         struct unixid *xid) {
-
-       NTSTATUS ret;
-       struct autorid_global_config *globalcfg;
-       struct autorid_domain_config domaincfg;
-       uint32_t hwm;
-       const char *hwmkey;
-
-       if (!strequal(dom->name, "*")) {
-               DEBUG(3, ("idmap_autorid_allocate_id: "
-                         "Refusing creation of mapping for domain'%s'. "
-                         "Currently only supported for the default "
-                         "domain \"*\".\n",
-                          dom->name));
-               return NT_STATUS_NOT_IMPLEMENTED;
-       }
-
-       if ((xid->type != ID_TYPE_UID) && (xid->type != ID_TYPE_GID)) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-
-       globalcfg = talloc_get_type(dom->private_data,
-                                   struct autorid_global_config);
-
-       /* fetch the range for the allocation pool */
-
-       ZERO_STRUCT(domaincfg);
-
-       domaincfg.globalcfg = globalcfg;
-       fstrcpy(domaincfg.sid, ALLOC_RANGE);
-
-       ret = idmap_autorid_get_domainrange(&domaincfg);
-
-       if (!NT_STATUS_IS_OK(ret)) {
-               DEBUG(3, ("Could not determine range for allocation pool, "
-                         "check previous messages for reason\n"));
-               return ret;
-       }
-
-       /* fetch the current HWM */
-       hwmkey = (xid->type==ID_TYPE_UID)?ALLOC_HWM_UID:ALLOC_HWM_GID;
-
-       ret = dbwrap_fetch_uint32(autorid_db, hwmkey, &hwm);
-
-       if (!NT_STATUS_IS_OK(ret)) {
-               DEBUG(1, ("Failed to fetch current allocation HWM value: %s\n",
-                         nt_errstr(ret)));
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       if (hwm >= globalcfg->rangesize) {
-               DEBUG(1, ("allocation range is depleted!\n"));
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       ret = dbwrap_change_uint32_atomic(autorid_db, hwmkey, &(xid->id), 1);
-       if (!NT_STATUS_IS_OK(ret)) {
-               DEBUG(1, ("Fatal error while allocating new ID!\n"));
-               return ret;
-       }
-
-       xid->id = globalcfg->minvalue +
-                 globalcfg->rangesize * domaincfg.domainnum +
-                 xid->id;
-
-       DEBUG(10, ("Returned new %s %d from allocation range\n",
-                  (xid->type==ID_TYPE_UID)?"uid":"gid", xid->id));
-
-       return ret;
-}
-
 /*
   Close the idmap tdb instance
 */