summaryrefslogtreecommitdiff
path: root/server/db
diff options
context:
space:
mode:
Diffstat (limited to 'server/db')
-rw-r--r--server/db/sysdb.c6
-rw-r--r--server/db/sysdb.h9
-rw-r--r--server/db/sysdb_ops.c289
3 files changed, 290 insertions, 14 deletions
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;
+}
+