From e130c2f6a7c6eebc3a18ca37792f3f01af15513a Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 6 Nov 2013 09:58:35 +0100 Subject: [PATCH 5/7] Add utility to handle Well-Known SIDs --- Makefile.am | 3 +- src/tests/cmocka/test_utils.c | 111 ++++++++++++++++ src/util/util.h | 7 + src/util/well_known_sids.c | 301 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 src/util/well_known_sids.c diff --git a/Makefile.am b/Makefile.am index a27bb51..244160d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -591,7 +591,8 @@ libsss_util_la_SOURCES = \ src/util/util_errors.c \ src/util/sss_ini.c \ src/util/io.c \ - src/util/util_sss_idmap.c + src/util/util_sss_idmap.c \ + src/util/well_known_sids.c libsss_util_la_LIBADD = \ $(SSSD_LIBS) \ $(UNICODE_LIBS) diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c index f659b96..4566c49 100644 --- a/src/tests/cmocka/test_utils.c +++ b/src/tests/cmocka/test_utils.c @@ -547,6 +547,114 @@ void test_sss_names_init(void **state) talloc_free(names_ctx); } +void test_well_known_sid_to_name(void **state) +{ + int ret; + const char *name; + const char *dom; + + ret = well_known_sid_to_name(NULL, NULL, NULL); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("abc", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-0", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-0-", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-0-0", &dom, &name); + assert_int_equal(ret, EOK); + assert_null(dom); + assert_string_equal(name, "NULL SID"); + + ret = well_known_sid_to_name("S-1-0-0-", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-5", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-5-", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-5-6", &dom, &name); + assert_int_equal(ret, EOK); + assert_string_equal(dom, "NT AUTHORITY"); + assert_string_equal(name, "SERVICE"); + + ret = well_known_sid_to_name("S-1-5-6-", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-5-21", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-5-21-", &dom, &name); + assert_int_equal(ret, ENOENT); + + ret = well_known_sid_to_name("S-1-5-21-abc", &dom, &name); + assert_int_equal(ret, ENOENT); + + ret = well_known_sid_to_name("S-1-5-32", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-5-32-", &dom, &name); + assert_int_equal(ret, EINVAL); + + ret = well_known_sid_to_name("S-1-5-32-551", &dom, &name); + assert_int_equal(ret, EOK); + assert_string_equal(dom, "BUILTIN"); + assert_string_equal(name, "Backup Operators"); + + ret = well_known_sid_to_name("S-1-5-32-551-", &dom, &name); + assert_int_equal(ret, EINVAL); + +} + +void test_name_to_well_known_sid(void **state) +{ + int ret; + const char *sid; + + ret = name_to_well_known_sid(NULL, NULL, NULL); + assert_int_equal(ret, EINVAL); + + ret = name_to_well_known_sid("abc", "def", &sid); + assert_int_equal(ret, ENOENT); + + ret = name_to_well_known_sid("", "def", &sid); + assert_int_equal(ret, EINVAL); + + ret = name_to_well_known_sid("BUILTIN", "def", &sid); + assert_int_equal(ret, EINVAL); + + ret = name_to_well_known_sid("NT AUTHORITY", "def", &sid); + assert_int_equal(ret, EINVAL); + + ret = name_to_well_known_sid("", "LOCAL", &sid); + assert_int_equal(ret, EOK); + assert_string_equal(sid, "S-1-2-0"); + + ret = name_to_well_known_sid(NULL, "LOCAL", &sid); + assert_int_equal(ret, EOK); + assert_string_equal(sid, "S-1-2-0"); + + ret = name_to_well_known_sid("BUILTIN", "Cryptographic Operators", &sid); + assert_int_equal(ret, EOK); + assert_string_equal(sid, "S-1-5-32-569"); + + ret = name_to_well_known_sid("NT AUTHORITY", "DIALUP", &sid); + assert_int_equal(ret, EOK); + assert_string_equal(sid, "S-1-5-1"); +} + int main(int argc, const char *argv[]) { poptContext pc; @@ -577,6 +685,9 @@ int main(int argc, const char *argv[]) unit_test_setup_teardown(test_sss_names_init, confdb_test_setup, confdb_test_teardown), + + unit_test(test_well_known_sid_to_name), + unit_test(test_name_to_well_known_sid), }; /* Set debug level to invalid value so we can deside if -d 0 was used. */ diff --git a/src/util/util.h b/src/util/util.h index 2f2eadb..1451fe3 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -618,4 +618,11 @@ errno_t sss_br_lock_file(int fd, size_t start, size_t len, #define BUILD_WITH_PAC_RESPONDER false #endif +/* from well_known_sids.c */ +errno_t well_known_sid_to_name(const char *sid, const char **dom, + const char **name); + +errno_t name_to_well_known_sid(const char *dom, const char *name, + const char **sid); + #endif /* __SSSD_UTIL_H__ */ diff --git a/src/util/well_known_sids.c b/src/util/well_known_sids.c new file mode 100644 index 0000000..12027d4 --- /dev/null +++ b/src/util/well_known_sids.c @@ -0,0 +1,301 @@ +/* + Authors: + Sumit Bose + + Copyright (C) 2013 Red Hat + + Translate well-known SIDs to domains and names + + 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 "util/util.h" +#include "util/strtonum.h" + +/* Well-Known SIDs are documented in section 2.4.2.4 "Well-Known SID + * Structures" of the "[MS-DTYP]: Windows Data Types" document. */ + +#define DOM_SID_PREFIX "S-1-5-21-" +#define DOM_SID_PREFIX_LEN (sizeof(DOM_SID_PREFIX) - 1) + +#define BUILTIN_SID_PREFIX "S-1-5-32-" +#define BUILTIN_SID_PREFIX_LEN (sizeof(BUILTIN_SID_PREFIX) - 1) +#define BUILTIN_DOM_NAME "BUILTIN" + +#define NT_SID_PREFIX "S-1-5-" +#define NT_SID_PREFIX_LEN (sizeof(NT_SID_PREFIX) - 1) +#define NT_DOM_NAME "NT AUTHORITY" + +#define SPECIAL_SID_PREFIX "S-1-" +#define SPECIAL_SID_PREFIX_LEN (sizeof(SPECIAL_SID_PREFIX) - 1) + +#define NT_MAP_ENTRY(rid, name) {rid, NT_SID_PREFIX #rid, name} +#define BUILTIN_MAP_ENTRY(rid, name) {rid, BUILTIN_SID_PREFIX #rid, name} +#define SPECIAL_MAP_ENTRY(id_auth, rid, name) \ + {(48 + id_auth), (48 + rid), SPECIAL_SID_PREFIX #id_auth "-" #rid, name} + +struct rid_sid_name { + uint32_t rid; + const char *sid; + const char *name; +}; + +struct special_map { + const char id_auth; + char rid; + const char *sid; + const char *name; +}; + +struct rid_sid_name builtin_map[] = { + BUILTIN_MAP_ENTRY(544, "Administrators"), + BUILTIN_MAP_ENTRY(545, "Users"), + BUILTIN_MAP_ENTRY(546, "Guests"), + BUILTIN_MAP_ENTRY(547, "Power Users"), + BUILTIN_MAP_ENTRY(548, "Account Operators"), + BUILTIN_MAP_ENTRY(549, "Server Operators"), + BUILTIN_MAP_ENTRY(550, "Print Operators"), + BUILTIN_MAP_ENTRY(551, "Backup Operators"), + BUILTIN_MAP_ENTRY(552, "Replicator"), + BUILTIN_MAP_ENTRY(554, "Pre-Windows 2000 Compatible Access"), + BUILTIN_MAP_ENTRY(555, "Remote Desktop Users"), + BUILTIN_MAP_ENTRY(556, "Network Configuration Operators"), + BUILTIN_MAP_ENTRY(557, "Incoming Forest Trust Builders"), + BUILTIN_MAP_ENTRY(558, "Performance Monitor Users"), + BUILTIN_MAP_ENTRY(559, "Performance Log Users"), + BUILTIN_MAP_ENTRY(560, "Windows Authorization Access Group"), + BUILTIN_MAP_ENTRY(561, "Terminal Server License Servers"), + BUILTIN_MAP_ENTRY(562, "Distributed COM Users"), + BUILTIN_MAP_ENTRY(568, "IIS_IUSRS"), + BUILTIN_MAP_ENTRY(569, "Cryptographic Operators"), + BUILTIN_MAP_ENTRY(573, "Event Log Readers"), + BUILTIN_MAP_ENTRY(574, "Certificate Service DCOM Access"), + BUILTIN_MAP_ENTRY(575, "RDS Remote Access Servers"), + BUILTIN_MAP_ENTRY(576, "RDS Endpoint Servers"), + BUILTIN_MAP_ENTRY(577, "RDS Management Servers"), + BUILTIN_MAP_ENTRY(578, "Hyper-V Admins"), + BUILTIN_MAP_ENTRY(579, "Access Control Assistance OPS"), + BUILTIN_MAP_ENTRY(580, "Remote Management Users"), + + {UINT32_MAX, NULL, NULL} +}; + +struct rid_sid_name nt_map[] = { + NT_MAP_ENTRY(1, "DIALUP"), + NT_MAP_ENTRY(2, "NETWORK"), + NT_MAP_ENTRY(3, "BATCH"), + NT_MAP_ENTRY(4, "INTERACTIVE"), + NT_MAP_ENTRY(6, "SERVICE"), + NT_MAP_ENTRY(7, "ANONYMOUS LOGON"), + NT_MAP_ENTRY(8, "PROXY"), + NT_MAP_ENTRY(9, "ENTERPRISE DOMAIN CONTROLLERS"), + NT_MAP_ENTRY(10, "SELF"), + NT_MAP_ENTRY(11, "Authenticated Users"), + NT_MAP_ENTRY(12, "RESTRICTED"), + NT_MAP_ENTRY(13, "TERMINAL SERVER USER"), + NT_MAP_ENTRY(14, "REMOTE INTERACTIVE LOGON"), + NT_MAP_ENTRY(15, "This Organization"), + NT_MAP_ENTRY(17, "IUSR"), + NT_MAP_ENTRY(18, "SYSTEM"), + NT_MAP_ENTRY(19, "LOCAL SERVICE"), + NT_MAP_ENTRY(20, "NETWORK SERVICE"), + + {UINT32_MAX, NULL, NULL} +}; + +/* The code to handle the SIDs of the Null, World, Local and Creator + * Authorities (id_auth=0,1,2,3 respectively) is optimized to handle only + * single digit id_auth and rid. */ + +struct special_map sp_map[] = { + SPECIAL_MAP_ENTRY(0, 0, "NULL SID"), + SPECIAL_MAP_ENTRY(1, 0, "Everyone"), + SPECIAL_MAP_ENTRY(2, 0, "LOCAL"), + SPECIAL_MAP_ENTRY(2, 1, "CONSOLE LOGON"), + SPECIAL_MAP_ENTRY(3, 0, "CREATOR OWNER"), + SPECIAL_MAP_ENTRY(3, 1, "CREATOR GROUP"), + SPECIAL_MAP_ENTRY(3, 2, "CREATOR OWNER SERVER"), + SPECIAL_MAP_ENTRY(3, 3, "CREATOR GROUP SERVER"), + SPECIAL_MAP_ENTRY(3, 4, "OWNER RIGHTS"), + + {'\0', '\0', NULL, NULL} +}; + +static errno_t handle_special_sids(const char *sid, const char **dom, + const char **name) +{ + size_t c; + + if (!isdigit(sid[SPECIAL_SID_PREFIX_LEN]) + || sid[SPECIAL_SID_PREFIX_LEN + 1] != '-' + || !isdigit(sid[SPECIAL_SID_PREFIX_LEN + 2]) + || sid[SPECIAL_SID_PREFIX_LEN + 3] != '\0' ) { + return EINVAL; + } + + for (c = 0; sp_map[c].name != NULL; c++) { + if (sid[SPECIAL_SID_PREFIX_LEN] == sp_map[c].id_auth + && sid[SPECIAL_SID_PREFIX_LEN + 2] == sp_map[c].rid) { + *name = sp_map[c].name; + *dom = NULL; + return EOK; + } + } + + return EINVAL; +} + +static errno_t handle_special_names(const char *name, const char **sid) +{ + size_t c; + + for (c = 0; sp_map[c].name != NULL; c++) { + if (strcmp(name, sp_map[c].name) == 0) { + *sid = sp_map[c].sid; + return EOK; + } + } + + return EINVAL; +} + +static errno_t handle_rid_to_name_map(const char *sid, size_t prefix_len, + struct rid_sid_name *map, + const char* dom_name, const char **dom, + const char **name) +{ + uint32_t rid; + char *endptr; + size_t c; + + errno = 0; + rid = (uint32_t) strtouint32(sid + prefix_len, &endptr, 10); + if (errno != 0 || *endptr != '\0') { + return EINVAL; + } + + for (c = 0; map[c].name != NULL; c++) { + if (rid == map[c].rid) { + *name = map[c].name; + *dom = dom_name; + return EOK; + } + } + + return EINVAL; +} + +static errno_t handle_name_to_sid_map(const char *name, + struct rid_sid_name *map, + const char **sid) +{ + size_t c; + + for (c = 0; map[c].name != NULL; c++) { + if (strcmp(name, map[c].name) == 0) { + *sid = map[c].sid; + return EOK; + } + } + + return EINVAL; +} + +static errno_t handle_nt_sids(const char *sid, const char **dom, + const char **name) +{ + return handle_rid_to_name_map(sid, NT_SID_PREFIX_LEN, nt_map, NT_DOM_NAME, + dom, name); +} + +static errno_t handle_nt_names(const char *name, const char **sid) +{ + return handle_name_to_sid_map(name, nt_map, sid); +} + +static errno_t handle_builtin_sids(const char *sid, const char **dom, + const char **name) +{ + return handle_rid_to_name_map(sid, BUILTIN_SID_PREFIX_LEN, builtin_map, + BUILTIN_DOM_NAME, dom, name); +} + +static errno_t handle_builtin_names(const char *name, const char **sid) +{ + return handle_name_to_sid_map(name, builtin_map, sid); +} + +errno_t well_known_sid_to_name(const char *sid, const char **dom, + const char **name) +{ + int ret; + + if (sid == NULL || dom == NULL || name == NULL) { + return EINVAL; + } + + if (strncmp(sid, DOM_SID_PREFIX, DOM_SID_PREFIX_LEN) == 0) { + ret = ENOENT; + } else if (strncmp(sid, BUILTIN_SID_PREFIX, BUILTIN_SID_PREFIX_LEN) == 0) { + ret = handle_builtin_sids(sid, dom, name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("handle_builtin_sids failed.\n")); + } + } else if (strncmp(sid, NT_SID_PREFIX, NT_SID_PREFIX_LEN) == 0) { + ret = handle_nt_sids(sid, dom, name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("handle_nt_sids failed.\n")); + } + } else if (strncmp(sid, SPECIAL_SID_PREFIX, SPECIAL_SID_PREFIX_LEN) == 0) { + ret = handle_special_sids(sid, dom, name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("handle_special_sids failed.\n")); + } + } else { + ret = EINVAL; + } + + return ret; +} + +errno_t name_to_well_known_sid(const char *dom, const char *name, + const char **sid) +{ + int ret; + + if (sid == NULL || name == NULL) { + return EINVAL; + } + + if (dom == NULL || *dom == '\0') { + ret = handle_special_names(name, sid); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("handle_special_name failed.\n")); + } + } else if (strcmp(dom, NT_DOM_NAME) == 0) { + ret = handle_nt_names(name, sid); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("handle_nt_name failed.\n")); + } + } else if (strcmp(dom, BUILTIN_DOM_NAME) == 0) { + ret = handle_builtin_names(name, sid); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("handle_builtin_name failed.\n")); + } + } else { + ret = ENOENT; + } + + return ret; +} -- 1.8.3.1