From b986ab58a7f38771fbb860ca57c6ffd0a25917b9 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 9 Oct 2014 15:13:55 +0200 Subject: [PATCH 1/2] nss: add SSS_NSS_GETORIGBYNAME request This patch adds a new request to the nss responder which follows the same flow as a SSS_NSSGETSIDBYNAME request but returns more data than just the SID. The data is returned as pairs of \0-terminated strings where the first string is the sysdb attribute name and the second the corresponding value. The main use case is on the FreeIPA server to make additional user and group data available to the extdom plugin which then send this data to SSSD running on FreeIPA clients. --- src/db/sysdb.h | 7 ++++ src/providers/ldap/sdap.h | 2 - src/responder/nss/nsssrv_cmd.c | 91 ++++++++++++++++++++++++++++++++++++++++- src/sss_client/sss_cli.h | 7 ++++ src/tests/cmocka/test_nss_srv.c | 88 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 191 insertions(+), 4 deletions(-) diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 03aac15..c93119c 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -138,6 +138,13 @@ #define SYSDB_DOMAIN_ID "domainID" #define SYSDB_ID_RANGE_TYPE "idRangeType" +#define ORIGINALAD_PREFIX "originalAD" +#define OVERRIDE_PREFIX "override" +#define SYSDB_DEFAULT_OVERRIDE_NAME "defaultOverrideName" + +#define SYSDB_AD_ACCOUNT_EXPIRES "adAccountExpires" +#define SYSDB_AD_USER_ACCOUNT_CONTROL "adUserAccountControl" + #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)" #define SYSDB_UC "objectclass="SYSDB_USER_CLASS diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index 7eb7cff..e9e2356 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -122,8 +122,6 @@ struct sdap_ppolicy_data { #define SYSDB_PWD_ATTRIBUTE "pwdAttribute" -#define SYSDB_AD_ACCOUNT_EXPIRES "adAccountExpires" -#define SYSDB_AD_USER_ACCOUNT_CONTROL "adUserAccountControl" #define SYSDB_NDS_LOGIN_DISABLED "ndsLoginDisabled" #define SYSDB_NDS_LOGIN_EXPIRATION_TIME "ndsLoginExpirationTime" #define SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP "ndsLoginAllowedTimeMap" diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c index 256c26b..78ef1c5 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -982,6 +982,7 @@ static void nss_cmd_getby_dp_callback(uint16_t err_maj, uint32_t err_min, case SSS_NSS_GETNAMEBYSID: case SSS_NSS_GETIDBYSID: case SSS_NSS_GETSIDBYNAME: + case SSS_NSS_GETORIGBYNAME: case SSS_NSS_GETSIDBYID: ret = nss_cmd_getbysid_send_reply(dctx); break; @@ -1064,6 +1065,7 @@ static void nss_cmd_getby_dp_callback(uint16_t err_maj, uint32_t err_min, } break; case SSS_NSS_GETSIDBYNAME: + case SSS_NSS_GETORIGBYNAME: ret = nss_cmd_getsidby_search(dctx); if (ret == EOK) { ret = nss_cmd_getbysid_send_reply(dctx); @@ -1172,6 +1174,7 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx) case SSS_NSS_GETGRNAM: case SSS_NSS_INITGR: case SSS_NSS_GETSIDBYNAME: + case SSS_NSS_GETORIGBYNAME: break; default: DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command type [%d].\n", cmd); @@ -1322,6 +1325,7 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx) } break; case SSS_NSS_GETSIDBYNAME: + case SSS_NSS_GETORIGBYNAME: ret = nss_cmd_getsidby_search(dctx); if (ret == EOK) { ret = nss_cmd_getbysid_send_reply(dctx); @@ -1417,6 +1421,7 @@ static void nss_cmd_getbynam_done(struct tevent_req *req) } break; case SSS_NSS_GETSIDBYNAME: + case SSS_NSS_GETORIGBYNAME: ret = nss_cmd_getsidby_search(dctx); if (ret == EOK) { ret = nss_cmd_getbysid_send_reply(dctx); @@ -3996,7 +4001,18 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx) struct nss_ctx *nctx; int ret; int err; - const char *attrs[] = {SYSDB_NAME, SYSDB_OBJECTCLASS, SYSDB_SID_STR, NULL}; + const char *attrs[] = {SYSDB_NAME, SYSDB_OBJECTCLASS, SYSDB_SID_STR, + ORIGINALAD_PREFIX SYSDB_NAME, + ORIGINALAD_PREFIX SYSDB_UIDNUM, + ORIGINALAD_PREFIX SYSDB_GIDNUM, + ORIGINALAD_PREFIX SYSDB_GECOS, + ORIGINALAD_PREFIX SYSDB_HOMEDIR, + ORIGINALAD_PREFIX SYSDB_SHELL, + SYSDB_UPN, + SYSDB_DEFAULT_OVERRIDE_NAME, + SYSDB_AD_ACCOUNT_EXPIRES, + SYSDB_AD_USER_ACCOUNT_CONTROL, + SYSDB_DEFAULT_ATTRS, NULL}; bool user_found = false; bool group_found = false; struct ldb_message *msg = NULL; @@ -4195,7 +4211,8 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx) } if (dctx->res->count == 0 && !dctx->check_provider) { - if (cmdctx->cmd == SSS_NSS_GETSIDBYNAME) { + if (cmdctx->cmd == SSS_NSS_GETSIDBYNAME + || cmdctx->cmd == SSS_NSS_GETORIGBYNAME) { ret = sss_ncache_set_user(nctx->ncache, false, dom, name); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, @@ -4428,6 +4445,67 @@ static errno_t fill_sid(struct sss_packet *packet, return EOK; } +static errno_t fill_orig(struct sss_packet *packet, + enum sss_id_type id_type, + struct ldb_message *msg) +{ + int ret; + const char *tmp_str; + uint8_t *body; + size_t blen; + size_t pctr = 0; + size_t c; + size_t sum; + const char *orig_attr_list[] = {SYSDB_SID_STR, + ORIGINALAD_PREFIX SYSDB_NAME, + ORIGINALAD_PREFIX SYSDB_UIDNUM, + ORIGINALAD_PREFIX SYSDB_GIDNUM, + ORIGINALAD_PREFIX SYSDB_HOMEDIR, + ORIGINALAD_PREFIX SYSDB_GECOS, + ORIGINALAD_PREFIX SYSDB_SHELL, + SYSDB_UPN, + SYSDB_DEFAULT_OVERRIDE_NAME, + SYSDB_AD_ACCOUNT_EXPIRES, + SYSDB_AD_USER_ACCOUNT_CONTROL, + NULL}; + struct sized_string keys[sizeof(orig_attr_list)]; + struct sized_string vals[sizeof(orig_attr_list)]; + + sum = 0; + for (c = 0; orig_attr_list[c] != NULL; c++) { + tmp_str = ldb_msg_find_attr_as_string(msg, orig_attr_list[c], NULL); + if (tmp_str != NULL) { + to_sized_string(&keys[c], orig_attr_list[c]); + sum += keys[c].len; + to_sized_string(&vals[c], tmp_str); + sum += vals[c].len; + } else { + vals[c].len = 0; + } + } + + ret = sss_packet_grow(packet, sum + 3 * sizeof(uint32_t)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n"); + return ret; + } + + sss_packet_get_body(packet, &body, &blen); + SAFEALIGN_SETMEM_UINT32(body, 1, &pctr); /* Num results */ + SAFEALIGN_SETMEM_UINT32(body + pctr, 0, &pctr); /* reserved */ + SAFEALIGN_COPY_UINT32(body + pctr, &id_type, &pctr); + for (c = 0; orig_attr_list[c] != NULL; c++) { + if (vals[c].len != 0) { + memcpy(&body[pctr], keys[c].str, keys[c].len); + pctr+= keys[c].len; + memcpy(&body[pctr], vals[c].str, vals[c].len); + pctr+= vals[c].len; + } + } + + return EOK; +} + static errno_t fill_name(struct sss_packet *packet, struct sss_domain_info *dom, enum sss_id_type id_type, @@ -4572,6 +4650,9 @@ static errno_t nss_cmd_getbysid_send_reply(struct nss_dom_ctx *dctx) case SSS_NSS_GETSIDBYID: ret = fill_sid(cctx->creq->out, id_type, dctx->res->msgs[0]); break; + case SSS_NSS_GETORIGBYNAME: + ret = fill_orig(cctx->creq->out, id_type, dctx->res->msgs[0]); + break; default: DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported request type.\n"); return EINVAL; @@ -4774,6 +4855,11 @@ static int nss_cmd_getidbysid(struct cli_ctx *cctx) return nss_cmd_getbysid(SSS_NSS_GETIDBYSID, cctx); } +static int nss_cmd_getorigbyname(struct cli_ctx *cctx) +{ + return nss_cmd_getbynam(SSS_NSS_GETORIGBYNAME, cctx); +} + struct cli_protocol_version *register_cli_protocol_version(void) { static struct cli_protocol_version nss_cli_protocol_version[] = { @@ -4809,6 +4895,7 @@ static struct sss_cmd_table nss_cmds[] = { {SSS_NSS_GETSIDBYID, nss_cmd_getsidbyid}, {SSS_NSS_GETNAMEBYSID, nss_cmd_getnamebysid}, {SSS_NSS_GETIDBYSID, nss_cmd_getidbysid}, + {SSS_NSS_GETORIGBYNAME, nss_cmd_getorigbyname}, {SSS_CLI_NULL, NULL} }; diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h index edb520c..2d90931 100644 --- a/src/sss_client/sss_cli.h +++ b/src/sss_client/sss_cli.h @@ -244,6 +244,13 @@ SSS_NSS_GETIDBYSID = 0x0114, /**< Takes the zero terminated string another unsigned 32bit integer value indicating the type (unknown, user, group, both) of the object. */ +SSS_NSS_GETORIGBYNAME = 0x0115, /**< Takes a zero terminated fully qualified + name and returns a list of zero + terminated strings with key-value pairs + where the first string is the key and + second the value. Hence the list should + have an even number of strings, if not + the whole list is invalid. */ }; /** diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c index 644468d..65298cd 100644 --- a/src/tests/cmocka/test_nss_srv.c +++ b/src/tests/cmocka/test_nss_srv.c @@ -1741,6 +1741,92 @@ void test_nss_well_known_getsidbyname_special(void **state) assert_int_equal(ret, EOK); } +static int test_nss_getorigbyname_check(uint32_t status, uint8_t *body, + size_t blen) +{ + const char *s; + enum sss_id_type id_type; + size_t rp = 2 * sizeof(uint32_t); + + assert_int_equal(status, EOK); + + SAFEALIGN_COPY_UINT32(&id_type, body+rp, &rp); + assert_int_equal(id_type, SSS_ID_TYPE_UID); + + /* Sequence of null terminated strings */ + s = (char *) body+rp; + assert_string_equal(s, SYSDB_SID_STR); + rp += strlen(s) + 1; + assert_true(rp < blen); + + s = (char *) body+rp; + assert_string_equal(s, "S-1-2-3-4"); + rp += strlen(s) + 1; + assert_true(rp < blen); + + s = (char *) body+rp; + assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_NAME); + rp += strlen(s) + 1; + assert_true(rp < blen); + + s = (char *) body+rp; + assert_string_equal(s, "orig_name"); + rp += strlen(s) + 1; + assert_true(rp < blen); + + s = (char *) body+rp; + assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_UIDNUM); + rp += strlen(s) + 1; + assert_true(rp < blen); + + s = (char *) body+rp; + assert_string_equal(s, "1234"); + rp += strlen(s) + 1; + assert_int_equal(rp, blen); + + return EOK; +} + +void test_nss_getorigbyname(void **state) +{ + errno_t ret; + struct sysdb_attrs *attrs; + + attrs = sysdb_new_attrs(nss_test_ctx); + assert_non_null(attrs); + + ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, "S-1-2-3-4"); + assert_int_equal(ret, EOK); + + ret = sysdb_attrs_add_string(attrs, ORIGINALAD_PREFIX SYSDB_NAME, + "orig_name"); + assert_int_equal(ret, EOK); + + ret = sysdb_attrs_add_uint32(attrs, ORIGINALAD_PREFIX SYSDB_UIDNUM, 1234); + assert_int_equal(ret, EOK); + + /* Prime the cache with a valid user */ + ret = sysdb_add_user(nss_test_ctx->tctx->dom, + "testuserorig", 1234, 5689, "test user orig", + "/home/testuserorig", "/bin/sh", NULL, + attrs, 300, 0); + assert_int_equal(ret, EOK); + + mock_input_user_or_group("testuserorig"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETORIGBYNAME); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + /* Query for that user, call a callback when command finishes */ + set_cmd_cb(test_nss_getorigbyname_check); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETORIGBYNAME, + 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[] = { @@ -1875,6 +1961,8 @@ int main(int argc, const char *argv[]) nss_test_setup, nss_test_teardown), unit_test_setup_teardown(test_nss_well_known_getsidbyname_special, nss_test_setup, nss_test_teardown), + unit_test_setup_teardown(test_nss_getorigbyname, + nss_test_setup, nss_test_teardown), }; /* Set debug level to invalid value so we can deside if -d 0 was used. */ -- 1.8.3.1