diff options
-rw-r--r-- | source3/winbindd/idmap_autorid.c | 313 |
1 files changed, 227 insertions, 86 deletions
diff --git a/source3/winbindd/idmap_autorid.c b/source3/winbindd/idmap_autorid.c index 9048c126b5..ab84104a63 100644 --- a/source3/winbindd/idmap_autorid.c +++ b/source3/winbindd/idmap_autorid.c @@ -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 @@ -28,8 +28,10 @@ #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 */ |