diff options
-rw-r--r-- | src/man/include/ldap_id_mapping.xml | 35 | ||||
-rw-r--r-- | src/responder/nss/nsssrv_cmd.c | 134 | ||||
-rw-r--r-- | src/tests/cmocka/test_nss_srv.c | 192 |
3 files changed, 361 insertions, 0 deletions
diff --git a/src/man/include/ldap_id_mapping.xml b/src/man/include/ldap_id_mapping.xml index 71ff248f1..9dda39924 100644 --- a/src/man/include/ldap_id_mapping.xml +++ b/src/man/include/ldap_id_mapping.xml @@ -189,4 +189,39 @@ ldap_schema = ad </refsect3> </refsect2> + <refsect2 id='well_known_sids'> + <title>Well-Known SIDs</title> + <para> + SSSD supports to look up the names of Well-Known SIDs, i.e. SIDs + with a special hardcoded meaning. Since the generic users and groups + related to those Well-Known SIDs have no equivalent in a Linux/UNIX + environment no POSIX IDs are available for those objects. + </para> + <para> + The SID name space is organized in authorities which can be seen as + different domains. The authorities for the Well-Known SIDs are + <itemizedlist> + <listitem><para>Null Authority</para></listitem> + <listitem><para>World Authority</para></listitem> + <listitem><para>Local Authority</para></listitem> + <listitem><para>Creator Authority</para></listitem> + <listitem><para>NT Authority</para></listitem> + <listitem><para>Built-in</para></listitem> + </itemizedlist> + The capitalized version of these names are used as domain names when + returning the fully qualified name of a Well-Known SID. + </para> + <para> + Since some utilities allow to modify SID based access control + information with the help of a name instead of using the SID + directly SSSD supports to look up the SID by the name as well. To + avoid collisions only the fully qualified names are excepted to look + up Well-Known SIDs. As a result the domain names <quote>NULL + AUTHORITY</quote>, <quote>WORLD AUTHORITY</quote>, <quote> LOCAL + AUTHORITY</quote>, <quote>CREATOR AUTHORITY</quote>, <quote>NT + AUTHORITY</quote> and <quote>BUILTIN</quote> should not be used as + domain names in <filename>sssd.conf</filename>. + </para> + </refsect2> + </refsect1> diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c index d9fc7155b..64bb9bc9f 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -973,6 +973,57 @@ done: } } +static int nss_check_name_of_well_known_sid(struct nss_cmd_ctx *cmdctx, + const char *full_name) +{ + char *wk_name = NULL; + char *wk_dom_name = NULL; + const char *wk_sid; + int ret; + struct sized_string sid; + uint8_t *body; + size_t blen; + struct cli_ctx *cctx; + struct nss_ctx *nss_ctx; + + nss_ctx = talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct nss_ctx); + ret = sss_parse_name(cmdctx, nss_ctx->global_names, full_name, + &wk_dom_name, &wk_name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("sss_parse_name failed.\n")); + return ret; + } + + ret = name_to_well_known_sid(wk_dom_name, wk_name, &wk_sid); + talloc_free(wk_dom_name); + talloc_free(wk_name); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_ALL, ("Name [%s] is not the name of a " \ + "Well-Known SID.\n", full_name)); + return ret; + } + + to_sized_string(&sid, wk_sid); + + cctx = cmdctx->cctx; + ret = sss_packet_new(cctx->creq, sid.len + 3 * sizeof(uint32_t), + sss_packet_get_cmd(cctx->creq->in), + &cctx->creq->out); + if (ret != EOK) { + return ENOMEM; + } + + sss_packet_get_body(cctx->creq->out, &body, &blen); + ((uint32_t *)body)[0] = 1; /* num results */ + ((uint32_t *)body)[1] = 0; /* reserved */ + ((uint32_t *)body)[2] = (uint32_t) SSS_ID_TYPE_GID; + memcpy(&body[3*sizeof(uint32_t)], sid.str, sid.len); + + sss_packet_set_error(cctx->creq->out, EOK); + sss_cmd_done(cctx, cmdctx); + return EOK; +} + static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx); static void nss_cmd_getbynam_done(struct tevent_req *req); static int nss_cmd_getpwnam(struct cli_ctx *cctx) @@ -1037,6 +1088,20 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx) DEBUG(SSSDBG_TRACE_FUNC, ("Running command [%d] with input [%s].\n", dctx->cmdctx->cmd, rawname)); + if (dctx->cmdctx->cmd == SSS_NSS_GETSIDBYNAME) { + ret = nss_check_name_of_well_known_sid(cmdctx, rawname); + if (ret != ENOENT) { + if (ret == EOK) { + DEBUG(SSSDBG_TRACE_ALL, ("Name [%s] is the name of a " \ + "Well-Known SID.\n", rawname)); + } else { + DEBUG(SSSDBG_OP_FAILURE, + ("nss_check_name_of_well_known_sid failed.\n")); + } + goto done; + } + } + /* We need to attach to subdomain request, if the first one is not * finished yet. We may not be able to lookup object in AD otherwise. */ if (cctx->rctx->get_domains_last_call.tv_sec == 0) { @@ -4278,6 +4343,64 @@ static errno_t nss_cmd_getbysid_send_reply(struct nss_dom_ctx *dctx) return EOK; } +static int nss_check_well_known_sid(struct nss_cmd_ctx *cmdctx) +{ + const char *wk_name; + const char *wk_dom_name; + int ret; + char *fq_name = NULL; + struct sized_string name; + uint8_t *body; + size_t blen; + struct cli_ctx *cctx; + struct nss_ctx *nss_ctx; + + ret = well_known_sid_to_name(cmdctx->secid, &wk_dom_name, &wk_name); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_ALL, ("SID [%s] is not a Well-Known SID.\n", + cmdctx->secid)); + return ret; + } + + if (cmdctx->cmd != SSS_NSS_GETNAMEBYSID) { + DEBUG(SSSDBG_TRACE_ALL, + ("Well-Known SIDs can only be translated to names.\n")); + return EINVAL; + } + + if (wk_dom_name != NULL) { + nss_ctx = talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct nss_ctx); + fq_name = sss_tc_fqname2(cmdctx, nss_ctx->global_names, + wk_dom_name, wk_dom_name, wk_name); + if (fq_name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("sss_tc_fqname2 failed.\n")); + return ENOMEM; + } + to_sized_string(&name, fq_name); + } else { + to_sized_string(&name, wk_name); + } + + cctx = cmdctx->cctx; + ret = sss_packet_new(cctx->creq, name.len + 3 * sizeof(uint32_t), + sss_packet_get_cmd(cctx->creq->in), + &cctx->creq->out); + if (ret != EOK) { + talloc_free(fq_name); + return ENOMEM; + } + + sss_packet_get_body(cctx->creq->out, &body, &blen); + ((uint32_t *)body)[0] = 1; /* num results */ + ((uint32_t *)body)[1] = 0; /* reserved */ + ((uint32_t *)body)[2] = (uint32_t) SSS_ID_TYPE_GID; + memcpy(&body[3*sizeof(uint32_t)], name.str, name.len); + + sss_packet_set_error(cctx->creq->out, EOK); + sss_cmd_done(cctx, cmdctx); + return EOK; +} + static int nss_cmd_getbysid(enum sss_cli_command cmd, struct cli_ctx *cctx) { @@ -4346,6 +4469,17 @@ static int nss_cmd_getbysid(enum sss_cli_command cmd, struct cli_ctx *cctx) goto done; } + ret = nss_check_well_known_sid(cmdctx); + if (ret != ENOENT) { + if (ret == EOK) { + DEBUG(SSSDBG_TRACE_ALL, ("SID [%s] is a Well-Known SID.\n", + cmdctx->secid)); + } else { + DEBUG(SSSDBG_OP_FAILURE, ("nss_check_well_known_sid failed.\n")); + } + goto done; + } + ret = responder_get_domain_by_id(cctx->rctx, cmdctx->secid, &dctx->domain); if (ret == EAGAIN || ret == ENOENT) { req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, NULL); diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c index b5b4565e9..d1a4d4bd8 100644 --- a/src/tests/cmocka/test_nss_srv.c +++ b/src/tests/cmocka/test_nss_srv.c @@ -30,6 +30,8 @@ #include "responder/common/negcache.h" #include "responder/nss/nsssrv.h" #include "responder/nss/nsssrv_private.h" +#include "sss_client/idmap/sss_nss_idmap.h" +#include "util/util_sss_idmap.h" #define TESTS_PATH "tests_nss" #define TEST_CONF_DB "test_nss_conf.ldb" @@ -58,6 +60,7 @@ mock_nctx(TALLOC_CTX *mem_ctx) { struct nss_ctx *nctx; errno_t ret; + enum idmap_error_code err; nctx = talloc_zero(mem_ctx, struct nss_ctx); if (!nctx) { @@ -72,6 +75,14 @@ mock_nctx(TALLOC_CTX *mem_ctx) nctx->neg_timeout = 10; nctx->pwfield = discard_const("*"); + err = sss_idmap_init(sss_idmap_talloc, nctx, sss_idmap_talloc_free, + &nctx->idmap_ctx); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_FATAL_FAILURE, ("sss_idmap_init failed.\n")); + talloc_free(nctx); + return NULL; + } + return nctx; } @@ -605,6 +616,11 @@ void test_nss_setup(struct sss_test_conf_param params[], nss_test_ctx->nctx = mock_nctx(nss_test_ctx); assert_non_null(nss_test_ctx->nctx); + ret = sss_names_init(nss_test_ctx->nctx, nss_test_ctx->tctx->confdb, + NULL, &nss_test_ctx->nctx->global_names); + assert_int_equal(ret, EOK); + assert_non_null(nss_test_ctx->nctx->global_names); + nss_test_ctx->rctx = mock_rctx(nss_test_ctx, nss_test_ctx->tctx->ev, nss_test_ctx->tctx->dom, nss_test_ctx->nctx); assert_non_null(nss_test_ctx->rctx); @@ -1075,6 +1091,168 @@ void test_nss_getgrnam_mix_subdom(void **state) assert_int_equal(ret, EOK); } +static int test_nss_well_known_sid_check(uint32_t status, + uint8_t *body, size_t blen) +{ + const char *name; + enum sss_id_type type; + size_t rp = 2 * sizeof(uint32_t); + char *expected_result = sss_mock_ptr_type(char *); + + if (expected_result == NULL) { + assert_int_equal(status, EINVAL); + assert_int_equal(blen, 0); + } else { + assert_int_equal(status, EOK); + + SAFEALIGN_COPY_UINT32(&type, body+rp, &rp); + + name = (char *) body+rp; + + assert_int_equal(type, SSS_ID_TYPE_GID); + assert_string_equal(name, expected_result); + } + + return EOK; +} + +void test_nss_well_known_getnamebysid(void **state) +{ + errno_t ret; + + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); + will_return(__wrap_sss_packet_get_body, "S-1-5-32-550"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYSID); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + will_return(test_nss_well_known_sid_check, "Print Operators@BUILTIN"); + + set_cmd_cb(test_nss_well_known_sid_check); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + +void test_nss_well_known_getnamebysid_special(void **state) +{ + errno_t ret; + + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); + will_return(__wrap_sss_packet_get_body, "S-1-2-0"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYSID); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + will_return(test_nss_well_known_sid_check, "LOCAL@LOCAL AUTHORITY"); + + set_cmd_cb(test_nss_well_known_sid_check); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + +void test_nss_well_known_getnamebysid_non_existing(void **state) +{ + errno_t ret; + + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); + will_return(__wrap_sss_packet_get_body, "S-1-5-32-123"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYSID); + will_return(test_nss_well_known_sid_check, NULL); + + set_cmd_cb(test_nss_well_known_sid_check); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + +void test_nss_well_known_getidbysid_failure(void **state) +{ + errno_t ret; + + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); + will_return(__wrap_sss_packet_get_body, "S-1-5-32-550"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETIDBYSID); + will_return(test_nss_well_known_sid_check, NULL); + + set_cmd_cb(test_nss_well_known_sid_check); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETIDBYSID, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + +void test_nss_well_known_getsidbyname(void **state) +{ + errno_t ret; + + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); + will_return(__wrap_sss_packet_get_body, "Cryptographic Operators@BUILTIN"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + will_return(test_nss_well_known_sid_check, "S-1-5-32-569"); + + set_cmd_cb(test_nss_well_known_sid_check); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + +void test_nss_well_known_getsidbyname_nonexisting(void **state) +{ + errno_t ret; + + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); + will_return(__wrap_sss_packet_get_body, "Abc@BUILTIN"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME); + will_return(test_nss_well_known_sid_check, NULL); + + set_cmd_cb(test_nss_well_known_sid_check); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + +void test_nss_well_known_getsidbyname_special(void **state) +{ + errno_t ret; + + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); + will_return(__wrap_sss_packet_get_body, "CREATOR OWNER@CREATOR AUTHORITY"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + will_return(test_nss_well_known_sid_check, "S-1-3-0"); + + set_cmd_cb(test_nss_well_known_sid_check); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + void nss_test_setup(void **state) { struct sss_test_conf_param params[] = { @@ -1177,6 +1355,20 @@ int main(int argc, const char *argv[]) nss_subdom_test_setup, nss_test_teardown), unit_test_setup_teardown(test_nss_getgrnam_mix_subdom, nss_subdom_test_setup, nss_test_teardown), + unit_test_setup_teardown(test_nss_well_known_getnamebysid, + nss_test_setup, nss_test_teardown), + unit_test_setup_teardown(test_nss_well_known_getnamebysid_special, + nss_test_setup, nss_test_teardown), + unit_test_setup_teardown(test_nss_well_known_getnamebysid_non_existing, + nss_test_setup, nss_test_teardown), + unit_test_setup_teardown(test_nss_well_known_getidbysid_failure, + nss_test_setup, nss_test_teardown), + unit_test_setup_teardown(test_nss_well_known_getsidbyname, + nss_test_setup, nss_test_teardown), + unit_test_setup_teardown(test_nss_well_known_getsidbyname_nonexisting, + nss_test_setup, nss_test_teardown), + unit_test_setup_teardown(test_nss_well_known_getsidbyname_special, + nss_test_setup, nss_test_teardown), }; /* Set debug level to invalid value so we can deside if -d 0 was used. */ |