diff options
-rw-r--r-- | server/confdb/confdb.c | 44 | ||||
-rw-r--r-- | server/confdb/confdb.h | 3 | ||||
-rw-r--r-- | server/db/sysdb.c | 6 | ||||
-rw-r--r-- | server/db/sysdb.h | 9 | ||||
-rw-r--r-- | server/db/sysdb_ops.c | 289 |
5 files changed, 336 insertions, 15 deletions
diff --git a/server/confdb/confdb.c b/server/confdb/confdb.c index 4c895d5f..f86df6ca 100644 --- a/server/confdb/confdb.c +++ b/server/confdb/confdb.c @@ -333,7 +333,7 @@ int confdb_get_int(struct confdb_ctx *cdb, TALLOC_CTX *ctx, int defval, int *result) { char **values; - long int val; + long val; int ret; ret = confdb_get_param(cdb, ctx, section, attribute, &values); @@ -370,6 +370,43 @@ int confdb_get_int(struct confdb_ctx *cdb, TALLOC_CTX *ctx, return EOK; } +long confdb_get_long(struct confdb_ctx *cdb, TALLOC_CTX *ctx, + const char *section, const char *attribute, + long defval, long *result) +{ + char **values; + long val; + int ret; + + ret = confdb_get_param(cdb, ctx, section, attribute, &values); + if (ret != EOK) { + return ret; + } + + if (values[0]) { + if (values[1] != NULL) { + /* too many values */ + talloc_free(values); + return EINVAL; + } + + errno = 0; + val = strtol(values[0], NULL, 0); + if (errno) { + talloc_free(values); + return errno; + } + + } else { + val = defval; + } + + talloc_free(values); + + *result = val; + return EOK; +} + int confdb_get_bool(struct confdb_ctx *cdb, TALLOC_CTX *ctx, const char *section, const char *attribute, bool defval, bool *result) @@ -680,6 +717,11 @@ int confdb_get_domains(struct confdb_ctx *cdb, domain->legacy = true; } + domain->id_min = ldb_msg_find_attr_as_uint(res->msgs[i], + "minId", SSSD_MIN_ID); + domain->id_max = ldb_msg_find_attr_as_uint(res->msgs[i], + "maxId", 0); + ret = btreemap_set_value(mem_ctx, &domain_map, domain->name, domain, _domain_comparator); diff --git a/server/confdb/confdb.h b/server/confdb/confdb.h index de679035..dbddcecf 100644 --- a/server/confdb/confdb.h +++ b/server/confdb/confdb.h @@ -28,12 +28,15 @@ #include "util/btreemap.h" #define CONFDB_FILE "config.ldb" +#define SSSD_MIN_ID 1000 struct sss_domain_info { char *name; int timeout; int enumerate; bool legacy; + uint32_t id_min; + uint32_t id_max; }; struct confdb_ctx; diff --git a/server/db/sysdb.c b/server/db/sysdb.c index b6558499..bdc7588f 100644 --- a/server/db/sysdb.c +++ b/server/db/sysdb.c @@ -36,6 +36,12 @@ struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, return ldb_dn_new_fmt(memctx, ctx->ldb, SYSDB_TMPL_GROUP, name, domain); } +struct ldb_dn *sysdb_domain_dn(struct sysdb_ctx *ctx, void *memctx, + const char *domain) +{ + return ldb_dn_new_fmt(memctx, ctx->ldb, SYSDB_DOM_BASE, domain); +} + struct ldb_context *sysdb_ctx_get_ldb(struct sysdb_ctx *ctx) { return ctx->ldb; diff --git a/server/db/sysdb.h b/server/db/sysdb.h index c1ae7979..4083edd8 100644 --- a/server/db/sysdb.h +++ b/server/db/sysdb.h @@ -36,6 +36,10 @@ #define SYSDB_USER_CLASS "user" #define SYSDB_GROUP_CLASS "group" +#define SYSDB_NEXTID "nextID" +#define SYSDB_UIDNUM "uidNumber" +#define SYSDB_GIDNUM "gidNumber" + #define SYSDB_PW_NAME "uid" #define SYSDB_PW_PWD "userPassword" #define SYSDB_PW_UIDNUM "uidNumber" @@ -64,6 +68,8 @@ #define SYSDB_LAST_UPDATE "lastUpdate" +#define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)" + #define SYSDB_PWNAM_FILTER "(&(objectclass="SYSDB_USER_CLASS")("SYSDB_PW_NAME"=%s))" #define SYSDB_PWUID_FILTER "(&(objectclass="SYSDB_USER_CLASS")("SYSDB_PW_UIDNUM"=%lu))" #define SYSDB_PWENT_FILTER "(objectclass="SYSDB_USER_CLASS")" @@ -160,9 +166,10 @@ void sysdb_operation_done(struct sysdb_req *req); struct ldb_dn *sysdb_user_dn(struct sysdb_ctx *ctx, void *memctx, const char *domain, const char *name); - struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, const char *domain, const char *name); +struct ldb_dn *sysdb_domain_dn(struct sysdb_ctx *ctx, void *memctx, + const char *domain); int sysdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c index 3a51f435..8e3eb4fa 100644 --- a/server/db/sysdb_ops.c +++ b/server/db/sysdb_ops.c @@ -50,6 +50,28 @@ static int add_ulong(struct ldb_message *msg, int flags, return ret; } +static uint32_t get_attr_as_uint32(struct ldb_message *msg, const char *attr) +{ + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr); + long long int l; + + if (!v || !v->data) { + return 0; + } + + errno = 0; + l = strtoll((const char *)v->data, NULL, 0); + if (errno) { + return (uint32_t)-1; + } + + if (l < 0 || l > ((uint32_t)(-1))) { + return (uint32_t)-1; + } + + return l; +} + /* the following are all SYNCHRONOUS calls * TODO: make these asynchronous */ @@ -268,19 +290,22 @@ static int delete_callback(struct ldb_request *req, struct ldb_reply *rep) switch (rep->type) { case LDB_REPLY_ENTRY: - res->msgs = talloc_realloc(res, res->msgs, - struct ldb_message *, - res->count + 2); + if (res->msgs != NULL) { + DEBUG(1, ("More than one reply for a base search ?! " + "DB seems corrupted, aborting.")); + return_error(cbctx, EFAULT); + return LDB_ERR_OPERATIONS_ERROR; + } + res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, 2); if (!res->msgs) { ret = LDB_ERR_OPERATIONS_ERROR; return_error(cbctx, sysdb_error_to_errno(ret)); return ret; } - res->msgs[res->count + 1] = NULL; - - res->msgs[res->count] = talloc_steal(res->msgs, rep->message); - res->count++; + res->msgs[0] = talloc_steal(res->msgs, rep->message); + res->msgs[1] = NULL; + res->count = 1; break; @@ -291,12 +316,6 @@ static int delete_callback(struct ldb_request *req, struct ldb_reply *rep) return_done(cbctx); break; } - if (res->count > 1) { - DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", - res->count)); - return_error(cbctx, EFAULT); - return LDB_ERR_OPERATIONS_ERROR; - } dn = ldb_dn_copy(del_ctx, res->msgs[0]->dn); if (!dn) { @@ -490,6 +509,250 @@ int sysdb_set_user_attr(struct sysdb_req *sysreq, return EOK; } +struct next_id { + uint32_t id; +}; + +struct next_id_ctx { + struct sysdb_req *sysreq; + struct sss_domain_info *domain; + struct sysdb_cb_ctx *cbctx; + + struct ldb_dn *base_dn; + struct ldb_result *res; + uint32_t tmp_id; + + enum next_step { NEXTID_SEARCH=0, NEXTID_VERIFY, NEXTID_STORE } step; + + struct next_id *result; +}; + +static int nextid_callback(struct ldb_request *req, struct ldb_reply *rep); + +static int sysdb_get_next_available_id(struct sysdb_req *sysreq, + struct sss_domain_info *domain, + struct next_id *result, + sysdb_callback_t fn, void *pvt) +{ + static const char *attrs[] = { SYSDB_NEXTID, NULL }; + struct sysdb_ctx *ctx; + struct next_id_ctx *idctx; + struct ldb_request *req; + int ret; + + if (!sysdb_req_check_running(sysreq)) { + DEBUG(2, ("Invalid request! Not running at this time.\n")); + return EINVAL; + } + + ctx = sysdb_req_get_ctx(sysreq); + + idctx = talloc_zero(sysreq, struct next_id_ctx); + if (!idctx) return ENOMEM; + + idctx->domain = domain; + idctx->result = result; + + idctx->cbctx = talloc_zero(sysreq, struct sysdb_cb_ctx); + if (!idctx->cbctx) return ENOMEM; + + idctx->cbctx->fn = fn; + idctx->cbctx->pvt = pvt; + + idctx->base_dn = sysdb_domain_dn(ctx, idctx, domain->name); + if (!idctx->base_dn) return ENOMEM; + + idctx->res = talloc_zero(idctx, struct ldb_result); + if (!idctx->res) return ENOMEM; + + ret = ldb_build_search_req(&req, ctx->ldb, idctx, + idctx->base_dn, LDB_SCOPE_BASE, + SYSDB_NEXTID_FILTER, attrs, NULL, + idctx, nextid_callback, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); + return sysdb_error_to_errno(ret); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + + return EOK; +} + +static int nextid_callback(struct ldb_request *req, struct ldb_reply *rep) +{ + static const char *attrs[] = { SYSDB_UIDNUM, SYSDB_GIDNUM, NULL }; + struct next_id_ctx *idctx; + struct sysdb_cb_ctx *cbctx; + struct sysdb_ctx *ctx; + struct ldb_request *nreq; + struct ldb_message *msg; + struct ldb_result *res; + char *filter; + int ret; + + idctx = talloc_get_type(req->context, struct next_id_ctx); + ctx = sysdb_req_get_ctx(idctx->sysreq); + cbctx = idctx->cbctx; + res = idctx->res; + + if (!rep) { + return_error(cbctx, EIO); + return LDB_ERR_OPERATIONS_ERROR; + } + if (rep->error != LDB_SUCCESS) { + return_error(cbctx, sysdb_error_to_errno(rep->error)); + return rep->error; + } + + switch (rep->type) { + case LDB_REPLY_ENTRY: + + if (idctx->step == NEXTID_VERIFY) { + res->count++; + break; + } + + /* NEXTID_SEARCH */ + if (res->msgs != NULL) { + DEBUG(1, ("More than one reply for a base search ?! " + "DB seems corrupted, aborting.")); + return_error(cbctx, EFAULT); + return LDB_ERR_OPERATIONS_ERROR; + } + + res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, 2); + if (!res->msgs) { + ret = LDB_ERR_OPERATIONS_ERROR; + return_error(cbctx, sysdb_error_to_errno(ret)); + return ret; + } + + res->msgs[0] = talloc_steal(res->msgs, rep->message); + res->msgs[1] = NULL; + res->count = 1; + + break; + + case LDB_REPLY_DONE: + + switch (idctx->step) { + case NEXTID_SEARCH: + if (res->count == 0) { + DEBUG(4, ("Base search returned no results\n")); + return_done(cbctx); + break; + } + + idctx->tmp_id = get_attr_as_uint32(res->msgs[0], SYSDB_NEXTID); + if (idctx->tmp_id == (uint32_t)(-1)) { + DEBUG(1, ("Invalid Next ID in domain %s\n", + idctx->domain->name)); + return_error(cbctx, ERANGE); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (idctx->tmp_id < idctx->domain->id_min) { + DEBUG(2, ("Initializing domain next id to id min %u\n", + idctx->domain->id_min)); + } + if ((idctx->domain->id_max != 0) && + (idctx->tmp_id > idctx->domain->id_max)) { + DEBUG(0, ("Failed to allocate new id, out of range (%u/%u)\n", + idctx->tmp_id, idctx->domain->id_max)); + return_error(cbctx, ERANGE); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(res->msgs); + res->msgs = NULL; + + idctx->step = NEXTID_VERIFY; + + case NEXTID_VERIFY: + if (res->count) { + /* actually something's using the id, try next */ + idctx->tmp_id++; + } else { + /* ok store new next_id */ + idctx->result->id = idctx->tmp_id; + idctx->tmp_id++; + idctx->step = NEXTID_STORE; + } + + default: + DEBUG(1, ("Invalid step, aborting.\n")); + return_error(cbctx, EFAULT); + return LDB_ERR_OPERATIONS_ERROR; + } + + switch (idctx->step) { + case NEXTID_VERIFY: + filter = talloc_asprintf(idctx, "(|(%s=%u)(%s=%u))", + SYSDB_UIDNUM, idctx->tmp_id, + SYSDB_GIDNUM, idctx->tmp_id); + if (!filter) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = ldb_build_search_req(&nreq, ctx->ldb, idctx, + idctx->base_dn, LDB_SCOPE_SUBTREE, + filter, attrs, NULL, + idctx, nextid_callback, NULL); + break; + + case NEXTID_STORE: + msg = ldb_msg_new(idctx); + if (!msg) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->dn = idctx->base_dn; + + ret = add_ulong(msg, LDB_FLAG_MOD_REPLACE, + SYSDB_NEXTID, idctx->tmp_id); + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_mod_req(&nreq, ctx->ldb, idctx, msg, NULL, + idctx, sysdb_op_callback, NULL); + break; + + default: + DEBUG(1, ("Invalid step, aborting.\n")); + return_error(cbctx, EFAULT); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); + return_error(cbctx, sysdb_error_to_errno(ret)); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_request(ctx->ldb, nreq); + if (ret != LDB_SUCCESS) { + return_error(cbctx, sysdb_error_to_errno(ret)); + return LDB_ERR_OPERATIONS_ERROR; + } + + break; + + default: + return_error(cbctx, EINVAL); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(rep); + return LDB_SUCCESS; +} + |