summaryrefslogtreecommitdiffstats
path: root/src/lib/idmap/sss_idmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/idmap/sss_idmap.c')
-rw-r--r--src/lib/idmap/sss_idmap.c375
1 files changed, 375 insertions, 0 deletions
diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
new file mode 100644
index 000000000..11f934bf5
--- /dev/null
+++ b/src/lib/idmap/sss_idmap.c
@@ -0,0 +1,375 @@
+/*
+ SSSD
+
+ ID-mapping library
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ 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/>.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "lib/idmap/sss_idmap.h"
+
+#define DOM_SID_PREFIX "S-1-5-21-"
+#define DOM_SID_PREFIX_LEN (sizeof(DOM_SID_PREFIX) - 1)
+#define SID_FMT "%s-%d"
+#define SID_STR_MAX_LEN 1024
+
+#define CHECK_IDMAP_CTX(ctx, ret) do { \
+ if (ctx == NULL || ctx->alloc_func == NULL || ctx->free_func == NULL) { \
+ return ret; \
+ } \
+} while(0)
+
+struct idmap_domain_info {
+ char *name;
+ char *sid;
+ struct sss_idmap_range *range;
+ struct idmap_domain_info *next;
+};
+
+struct sss_idmap_ctx {
+ idmap_alloc_func *alloc_func;
+ void *alloc_pvt;
+ idmap_free_func *free_func;
+ struct idmap_domain_info *idmap_domain_info;
+};
+
+static void *default_alloc(size_t size, void *pvt)
+{
+ return malloc(size);
+}
+
+static void default_free(void *ptr, void *pvt)
+{
+ free(ptr);
+}
+
+static char *idmap_strdup(struct sss_idmap_ctx *ctx, const char *str)
+{
+ char *new = NULL;
+ size_t len;
+
+ CHECK_IDMAP_CTX(ctx, NULL);
+
+ len = strlen(str) + 1;
+
+ new = ctx->alloc_func(len, ctx->alloc_pvt);
+ if (new == NULL) {
+ return NULL;
+ }
+
+ memcpy(new, str, len);
+
+ return new;
+}
+
+static struct sss_idmap_range *idmap_range_dup(struct sss_idmap_ctx *ctx,
+ struct sss_idmap_range *range)
+{
+ struct sss_idmap_range *new = NULL;
+
+ CHECK_IDMAP_CTX(ctx, NULL);
+
+
+ new = ctx->alloc_func(sizeof(struct sss_idmap_range), ctx->alloc_pvt);
+ if (new == NULL) {
+ return NULL;
+ }
+
+ memset(new, 0, sizeof(struct sss_idmap_range));
+
+ new->min = range->min;
+ new->max = range->max;
+
+ return new;
+}
+
+static bool id_is_in_range(uint32_t id, struct sss_idmap_range *range,
+ uint32_t *rid)
+{
+ if (id == 0 || range == NULL) {
+ return false;
+ }
+
+ if (id >= range->min && id <= range->max) {
+ if (rid != NULL) {
+ *rid = id - range->min;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+const char *idmap_error_string(enum idmap_error_code err)
+{
+ switch (err) {
+ case IDMAP_SUCCESS:
+ return "IDMAP operation successful";
+ break;
+ case IDMAP_NOT_IMPLEMENTED:
+ return "IDMAP Function is not yet implemented";
+ break;
+ case IDMAP_ERROR:
+ return "IDMAP general error";
+ break;
+ case IDMAP_OUT_OF_MEMORY:
+ return "IDMAP operation ran out of memory";
+ break;
+ case IDMAP_NO_DOMAIN:
+ return "IDMAP domain not found";
+ break;
+ case IDMAP_CONTEXT_INVALID:
+ return "IDMAP context is invalid";
+ break;
+ case IDMAP_SID_INVALID:
+ return "IDMAP SID is invalid";
+ break;
+ case IDMAP_SID_UNKNOWN:
+ return "IDMAP SID not found";
+ break;
+ case IDMAP_NO_RANGE:
+ return "IDMAP range not found";
+ default:
+ return "IDMAP unknown error code";
+ }
+}
+
+bool is_domain_sid(const char *sid)
+{
+ const char *p;
+ long long a;
+ char *endptr;
+ size_t c;
+
+ if (sid == NULL || strncmp(sid, DOM_SID_PREFIX, DOM_SID_PREFIX_LEN) != 0) {
+ return false;
+ }
+
+ p = sid + DOM_SID_PREFIX_LEN;
+ c = 0;
+
+ do {
+ errno = 0;
+ a = strtoull(p, &endptr, 10);
+ if (errno != 0 || a > UINT32_MAX) {
+ return false;
+ }
+
+ if (*endptr == '-') {
+ p = endptr + 1;
+ } else if (*endptr != '\0') {
+ return false;
+ }
+ c++;
+ } while(c < 3 && *endptr != '\0');
+
+ if (c != 3 || *endptr != '\0') {
+ return false;
+ }
+
+ return true;
+}
+
+enum idmap_error_code sss_idmap_init(idmap_alloc_func *alloc_func,
+ void *alloc_pvt,
+ idmap_free_func *free_func,
+ struct sss_idmap_ctx **_ctx)
+{
+ struct sss_idmap_ctx *ctx;
+
+ if (alloc_func == NULL) {
+ alloc_func = default_alloc;
+ }
+
+ ctx = alloc_func(sizeof(struct sss_idmap_ctx), alloc_pvt);
+ if (ctx == NULL) {
+ return IDMAP_OUT_OF_MEMORY;
+ }
+ memset(ctx, 0, sizeof(struct sss_idmap_ctx));
+
+ ctx->alloc_func = alloc_func;
+ ctx->alloc_pvt = alloc_pvt;
+ ctx->free_func = (free_func == NULL) ? default_free : free_func;
+
+ *_ctx = ctx;
+
+ return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_free(struct sss_idmap_ctx *ctx)
+{
+ struct idmap_domain_info *dom;
+ struct idmap_domain_info *next;
+
+ CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+ next = ctx->idmap_domain_info;
+ while (next) {
+ dom = next;
+ next = dom->next;
+ ctx->free_func(dom->range, ctx->alloc_pvt);
+ ctx->free_func(dom->name, ctx->alloc_pvt);
+ ctx->free_func(dom->sid, ctx->alloc_pvt);
+ ctx->free_func(dom, ctx->alloc_pvt);
+ }
+
+ ctx->free_func(ctx, ctx->alloc_pvt);
+
+ return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
+ const char *domain_name,
+ const char *domain_sid,
+ struct sss_idmap_range *range)
+{
+ struct idmap_domain_info *dom = NULL;
+
+ CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+ if (domain_name == NULL) {
+ return IDMAP_NO_DOMAIN;
+ }
+
+ if (range == NULL) {
+ return IDMAP_NO_RANGE;
+ }
+
+ if (!is_domain_sid(domain_sid)) {
+ return IDMAP_SID_INVALID;
+ }
+
+ dom = ctx->alloc_func(sizeof(struct idmap_domain_info), ctx->alloc_pvt);
+ if (dom == NULL) {
+ return IDMAP_OUT_OF_MEMORY;
+ }
+ memset(dom, 0, sizeof(struct idmap_domain_info));
+
+ dom->name = idmap_strdup(ctx, domain_name);
+ if (dom->name == NULL) {
+ goto fail;
+ }
+
+ dom->sid = idmap_strdup(ctx, domain_sid);
+ if (dom->sid == NULL) {
+ goto fail;
+ }
+
+ dom->range = idmap_range_dup(ctx, range);
+ if (dom->range == NULL) {
+ goto fail;
+ }
+
+ dom->next = ctx->idmap_domain_info;
+ ctx->idmap_domain_info = dom;
+
+ return IDMAP_SUCCESS;
+
+fail:
+ ctx->free_func(dom->sid, ctx->alloc_pvt);
+ ctx->free_func(dom->name, ctx->alloc_pvt);
+ ctx->free_func(dom, ctx->alloc_pvt);
+
+ return IDMAP_OUT_OF_MEMORY;
+}
+
+enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
+ const char *sid,
+ uint32_t *id)
+{
+ struct idmap_domain_info *idmap_domain_info;
+ size_t dom_len;
+ long long rid;
+ char *endptr;
+
+ CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+ idmap_domain_info = ctx->idmap_domain_info;
+
+ while (idmap_domain_info != NULL) {
+ dom_len = strlen(idmap_domain_info->sid);
+ if (strlen(sid) > dom_len && sid[dom_len] == '-' &&
+ strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
+ errno = 0;
+ rid = strtoull(sid + dom_len + 1, &endptr, 10);
+ if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
+ return IDMAP_SID_INVALID;
+ }
+
+ if (rid + idmap_domain_info->range->min >
+ idmap_domain_info->range->max) {
+ return IDMAP_NO_RANGE;
+ }
+
+ *id = rid + idmap_domain_info->range->min;
+ return IDMAP_SUCCESS;
+ }
+
+ idmap_domain_info = idmap_domain_info->next;
+ }
+
+ return IDMAP_NO_DOMAIN;
+}
+
+enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
+ uint32_t id,
+ char **_sid)
+{
+ struct idmap_domain_info *idmap_domain_info;
+ int len;
+ int ret;
+ uint32_t rid;
+ char *sid = NULL;
+
+ CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+ idmap_domain_info = ctx->idmap_domain_info;
+
+ while (idmap_domain_info != NULL) {
+ if (id_is_in_range(id, idmap_domain_info->range, &rid)) {
+ len = snprintf(NULL, 0, SID_FMT, idmap_domain_info->sid, rid);
+ if (len <= 0 || len > SID_STR_MAX_LEN) {
+ return IDMAP_ERROR;
+ }
+
+ sid = ctx->alloc_func(len + 1, ctx->alloc_pvt);
+ if (sid == NULL) {
+ return IDMAP_OUT_OF_MEMORY;
+ }
+
+ ret = snprintf(sid, len + 1, SID_FMT, idmap_domain_info->sid, rid);
+ if (ret != len) {
+ ctx->free_func(sid, ctx->alloc_pvt);
+ return IDMAP_ERROR;
+ }
+
+ *_sid = sid;
+ return IDMAP_SUCCESS;
+ }
+
+ idmap_domain_info = idmap_domain_info->next;
+ }
+
+ return IDMAP_NO_DOMAIN;
+}