/* SSSD ID-mapping library - conversion utilities Authors: Sumit Bose 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 . */ #include #include #include #include #include "lib/idmap/sss_idmap.h" #include "lib/idmap/sss_idmap_private.h" #include "util/util.h" #include "util/sss_endian.h" #define SID_ID_AUTHS 6 #define SID_SUB_AUTHS 15 struct sss_dom_sid { uint8_t sid_rev_num; int8_t num_auths; /* [range(0,15)] */ uint8_t id_auth[SID_ID_AUTHS]; /* highest order byte has index 0 */ uint32_t sub_auths[SID_SUB_AUTHS]; /* host byte-order */ }; enum idmap_error_code sss_idmap_bin_sid_to_dom_sid(struct sss_idmap_ctx *ctx, const uint8_t *bin_sid, size_t length, struct sss_dom_sid **_dom_sid) { enum idmap_error_code err; struct sss_dom_sid *dom_sid; size_t i = 0; size_t p = 0; uint32_t val; CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID); if (length > sizeof(struct sss_dom_sid)) return IDMAP_SID_INVALID; dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt); if (dom_sid == NULL) { return IDMAP_OUT_OF_MEMORY; } memset(dom_sid, 0, sizeof(struct sss_dom_sid)); /* Safely copy in the SID revision number */ dom_sid->sid_rev_num = (uint8_t) *(bin_sid + p); p++; /* Safely copy in the number of sub auth values */ dom_sid->num_auths = (uint8_t) *(bin_sid + p); p++; /* Make sure we aren't being told to read more bin_sid * than can fit in the structure */ if (dom_sid->num_auths > SID_SUB_AUTHS) { err = IDMAP_SID_INVALID; goto done; } /* Safely copy in the id_auth values */ for (i = 0; i < SID_ID_AUTHS; i++) { dom_sid->id_auth[i] = (uint8_t) *(bin_sid + p); p++; } /* Safely copy in the sub_auths values */ for (i = 0; i < dom_sid->num_auths; i++) { /* SID sub auth values in Active Directory are stored little-endian, * we store them in host order */ SAFEALIGN_COPY_UINT32(&val, bin_sid + p, &p); dom_sid->sub_auths[i] = le32toh(val); } *_dom_sid = dom_sid; err = IDMAP_SUCCESS; done: if (err != IDMAP_SUCCESS) { ctx->free_func(dom_sid, ctx->alloc_pvt); } return err; } enum idmap_error_code sss_idmap_dom_sid_to_bin_sid(struct sss_idmap_ctx *ctx, struct sss_dom_sid *dom_sid, uint8_t **_bin_sid, size_t *_length) { enum idmap_error_code err; uint8_t *bin_sid; size_t length; size_t i = 0; size_t p = 0; uint32_t val; CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID); if (dom_sid->num_auths > SID_SUB_AUTHS) { return IDMAP_SID_INVALID; } length = 2 + SID_ID_AUTHS + dom_sid->num_auths * 4; bin_sid = ctx->alloc_func(length, ctx->alloc_pvt); if (bin_sid == NULL) { return IDMAP_OUT_OF_MEMORY; } bin_sid[p] = dom_sid->sid_rev_num; p++; bin_sid[p] = dom_sid->num_auths; p++; for (i = 0; i < SID_ID_AUTHS; i++) { bin_sid[p] = dom_sid->id_auth[i]; p++; } for (i = 0; i < dom_sid->num_auths; i++) { if (p + sizeof(uint32_t) > length) { err = IDMAP_SID_INVALID; goto done; } val = htole32(dom_sid->sub_auths[i]); SAFEALIGN_COPY_UINT32(bin_sid + p, &val, &p); } *_bin_sid = bin_sid; *_length = length; err = IDMAP_SUCCESS; done: if (err != IDMAP_SUCCESS) { ctx->free_func(bin_sid, ctx->alloc_pvt); } return err; } enum idmap_error_code sss_idmap_dom_sid_to_sid(struct sss_idmap_ctx *ctx, struct sss_dom_sid *dom_sid, char **_sid) { enum idmap_error_code err; char *sid_buf; size_t sid_buf_len; char *p; int nc; int8_t i; uint32_t id_auth_val = 0; if (dom_sid->num_auths > SID_SUB_AUTHS) { return IDMAP_SID_INVALID; } sid_buf_len = 25 + dom_sid->num_auths * 11; sid_buf = ctx->alloc_func(sid_buf_len, ctx->alloc_pvt); if (sid_buf == NULL) { return IDMAP_OUT_OF_MEMORY; } memset(sid_buf, 0, sid_buf_len); /* Only 32bits are used for the string representation */ id_auth_val = (dom_sid->id_auth[2] << 24) + (dom_sid->id_auth[3] << 16) + (dom_sid->id_auth[4] << 8) + (dom_sid->id_auth[5]); nc = snprintf(sid_buf, sid_buf_len, "S-%u-%lu", dom_sid->sid_rev_num, (unsigned long) id_auth_val); if (nc < 0 || nc >= sid_buf_len) { err = IDMAP_SID_INVALID; goto done; } /* Loop through the sub-auths, if any, prepending a hyphen * for each one. */ p = sid_buf; for (i = 0; i < dom_sid->num_auths ; i++) { p += nc; sid_buf_len -= nc; nc = snprintf(p, sid_buf_len, "-%lu", (unsigned long) dom_sid->sub_auths[i]); if (nc < 0 || nc >= sid_buf_len) { err = IDMAP_SID_INVALID; goto done; } } *_sid = sid_buf; err = IDMAP_SUCCESS; done: if (err != IDMAP_SUCCESS) { ctx->free_func(sid_buf, ctx->alloc_pvt); } return err; } enum idmap_error_code sss_idmap_sid_to_dom_sid(struct sss_idmap_ctx *ctx, const char *sid, struct sss_dom_sid **_dom_sid) { enum idmap_error_code err; unsigned long ul; char *r; char *end; struct sss_dom_sid *dom_sid; CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID); if (sid == NULL || (sid[0] != 'S' && sid[0] != 's') || sid[1] != '-') { return IDMAP_SID_INVALID; } dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt); if (dom_sid == NULL) { return IDMAP_OUT_OF_MEMORY; } memset(dom_sid, 0, sizeof(struct sss_dom_sid)); if (!isdigit(sid[2])) { err = IDMAP_SID_INVALID; goto done; } errno = 0; ul = strtoul(sid + 2, &r, 10); if (errno != 0 || r == NULL || *r != '-' || ul > UINT8_MAX) { err = IDMAP_SID_INVALID; goto done; } dom_sid->sid_rev_num = (uint8_t) ul; r++; if (!isdigit(*r)) { err = IDMAP_SID_INVALID; goto done; } errno = 0; ul = strtoul(r, &r, 10); if (errno != 0 || r == NULL || ul > UINT32_MAX) { err = IDMAP_SID_INVALID; goto done; } /* id_auth in the string should always be <2^32 in decimal */ /* store values in the same order as the binary representation */ dom_sid->id_auth[0] = 0; dom_sid->id_auth[1] = 0; dom_sid->id_auth[2] = (ul & 0xff000000) >> 24; dom_sid->id_auth[3] = (ul & 0x00ff0000) >> 16; dom_sid->id_auth[4] = (ul & 0x0000ff00) >> 8; dom_sid->id_auth[5] = (ul & 0x000000ff); if (*r == '\0') { /* no sub auths given */ err = IDMAP_SUCCESS; goto done; } if (*r != '-') { err = IDMAP_SID_INVALID; goto done; } do { if (dom_sid->num_auths >= SID_SUB_AUTHS) { err = IDMAP_SID_INVALID; goto done; } r++; if (!isdigit(*r)) { err = IDMAP_SID_INVALID; goto done; } errno = 0; ul = strtoul(r, &end, 10); if (errno != 0 || ul > UINT32_MAX || end == NULL || (*end != '\0' && *end != '-')) { err = IDMAP_SID_INVALID; goto done; } dom_sid->sub_auths[dom_sid->num_auths++] = ul; r = end; } while (*r != '\0'); err = IDMAP_SUCCESS; done: if (err != IDMAP_SUCCESS) { ctx->free_func(dom_sid, ctx->alloc_pvt); } else { *_dom_sid = dom_sid; } return err; } enum idmap_error_code sss_idmap_sid_to_bin_sid(struct sss_idmap_ctx *ctx, const char *sid, uint8_t **_bin_sid, size_t *_length) { enum idmap_error_code err; struct sss_dom_sid *dom_sid = NULL; size_t length; uint8_t *bin_sid = NULL; err = sss_idmap_sid_to_dom_sid(ctx, sid, &dom_sid); if (err != IDMAP_SUCCESS) { goto done; } err = sss_idmap_dom_sid_to_bin_sid(ctx, dom_sid, &bin_sid, &length); if (err != IDMAP_SUCCESS) { goto done; } *_length = length; *_bin_sid = bin_sid; err = IDMAP_SUCCESS; done: ctx->free_func(dom_sid, ctx->alloc_pvt); if (err != IDMAP_SUCCESS) { ctx->free_func(bin_sid, ctx->alloc_pvt); } return err; } enum idmap_error_code sss_idmap_bin_sid_to_sid(struct sss_idmap_ctx *ctx, const uint8_t *bin_sid, size_t length, char **_sid) { enum idmap_error_code err; struct sss_dom_sid *dom_sid = NULL; char *sid = NULL; err = sss_idmap_bin_sid_to_dom_sid(ctx, bin_sid, length, &dom_sid); if (err != IDMAP_SUCCESS) { goto done; } err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid); if (err != IDMAP_SUCCESS) { goto done; } *_sid = sid; err = IDMAP_SUCCESS; done: ctx->free_func(dom_sid, ctx->alloc_pvt); if (err != IDMAP_SUCCESS) { ctx->free_func(sid, ctx->alloc_pvt); } return err; } enum idmap_error_code sss_idmap_sid_to_smb_sid(struct sss_idmap_ctx *ctx, const char *sid, struct dom_sid **_smb_sid) { enum idmap_error_code err; struct sss_dom_sid *dom_sid = NULL; struct dom_sid *smb_sid = NULL; err = sss_idmap_sid_to_dom_sid(ctx, sid, &dom_sid); if (err != IDMAP_SUCCESS) { goto done; } err = sss_idmap_dom_sid_to_smb_sid(ctx, dom_sid, &smb_sid); if (err != IDMAP_SUCCESS) { goto done; } *_smb_sid = smb_sid; err = IDMAP_SUCCESS; done: ctx->free_func(dom_sid, ctx->alloc_pvt); if (err != IDMAP_SUCCESS) { ctx->free_func(smb_sid, ctx->alloc_pvt); } return err; } enum idmap_error_code sss_idmap_smb_sid_to_sid(struct sss_idmap_ctx *ctx, struct dom_sid *smb_sid, char **_sid) { enum idmap_error_code err; struct sss_dom_sid *dom_sid = NULL; char *sid = NULL; err = sss_idmap_smb_sid_to_dom_sid(ctx, smb_sid, &dom_sid); if (err != IDMAP_SUCCESS) { goto done; } err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid); if (err != IDMAP_SUCCESS) { goto done; } *_sid = sid; err = IDMAP_SUCCESS; done: ctx->free_func(dom_sid, ctx->alloc_pvt); if (err != IDMAP_SUCCESS) { ctx->free_func(sid, ctx->alloc_pvt); } return err; } enum idmap_error_code sss_idmap_dom_sid_to_smb_sid(struct sss_idmap_ctx *ctx, struct sss_dom_sid *dom_sid, struct dom_sid **_smb_sid) { struct dom_sid *smb_sid; size_t c; smb_sid = ctx->alloc_func(sizeof(struct dom_sid), ctx->alloc_pvt); if (smb_sid == NULL) { return IDMAP_OUT_OF_MEMORY; } memset(smb_sid, 0, sizeof(struct dom_sid)); smb_sid->sid_rev_num = dom_sid->sid_rev_num; smb_sid->num_auths = dom_sid->num_auths; for (c = 0; c < SID_ID_AUTHS; c++) { smb_sid->id_auth[c] = dom_sid->id_auth[c]; } for (c = 0; c < SID_SUB_AUTHS; c++) { smb_sid->sub_auths[c] = dom_sid->sub_auths[c]; } *_smb_sid = smb_sid; return IDMAP_SUCCESS; } enum idmap_error_code sss_idmap_smb_sid_to_dom_sid(struct sss_idmap_ctx *ctx, struct dom_sid *smb_sid, struct sss_dom_sid **_dom_sid) { struct sss_dom_sid *dom_sid; size_t c; dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt); if (dom_sid == NULL) { return IDMAP_OUT_OF_MEMORY; } memset(dom_sid, 0, sizeof(struct sss_dom_sid)); dom_sid->sid_rev_num = smb_sid->sid_rev_num; dom_sid->num_auths = smb_sid->num_auths; for (c = 0; c < SID_ID_AUTHS; c++) { dom_sid->id_auth[c] = smb_sid->id_auth[c]; } for (c = 0; c < SID_SUB_AUTHS; c++) { dom_sid->sub_auths[c] = smb_sid->sub_auths[c]; } *_dom_sid = dom_sid; return IDMAP_SUCCESS; } enum idmap_error_code sss_idmap_bin_sid_to_smb_sid(struct sss_idmap_ctx *ctx, const uint8_t *bin_sid, size_t length, struct dom_sid **_smb_sid) { enum idmap_error_code err; struct sss_dom_sid *dom_sid = NULL; struct dom_sid *smb_sid = NULL; err = sss_idmap_bin_sid_to_dom_sid(ctx, bin_sid, length, &dom_sid); if (err != IDMAP_SUCCESS) { goto done; } err = sss_idmap_dom_sid_to_smb_sid(ctx, dom_sid, &smb_sid); if (err != IDMAP_SUCCESS) { goto done; } *_smb_sid = smb_sid; err = IDMAP_SUCCESS; done: ctx->free_func(dom_sid, ctx->alloc_pvt); if (err != IDMAP_SUCCESS) { ctx->free_func(smb_sid, ctx->alloc_pvt); } return err; } enum idmap_error_code sss_idmap_smb_sid_to_bin_sid(struct sss_idmap_ctx *ctx, struct dom_sid *smb_sid, uint8_t **_bin_sid, size_t *_length) { enum idmap_error_code err; struct sss_dom_sid *dom_sid = NULL; uint8_t *bin_sid = NULL; size_t length; err = sss_idmap_smb_sid_to_dom_sid(ctx, smb_sid, &dom_sid); if (err != IDMAP_SUCCESS) { goto done; } err = sss_idmap_dom_sid_to_bin_sid(ctx, dom_sid, &bin_sid, &length); if (err != IDMAP_SUCCESS) { goto done; } *_bin_sid = bin_sid; *_length = length; err = IDMAP_SUCCESS; done: ctx->free_func(dom_sid, ctx->alloc_pvt); if (err != IDMAP_SUCCESS) { ctx->free_func(bin_sid, ctx->alloc_pvt); } return err; }