summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am17
-rw-r--r--src/external/pac_responder.m43
-rw-r--r--src/responder/pac/pacsrv.c19
-rw-r--r--src/responder/pac/pacsrv.h20
-rw-r--r--src/responder/pac/pacsrv_cmd.c649
-rw-r--r--src/responder/pac/pacsrv_utils.c66
-rw-r--r--src/tests/pac_responder-tests.c106
7 files changed, 703 insertions, 177 deletions
diff --git a/Makefile.am b/Makefile.am
index fc796eddb..3b3c0fb51 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -122,7 +122,8 @@ if HAVE_CHECK
util-tests \
debug-tests \
ipa_hbac-tests \
- sss_idmap-tests
+ sss_idmap-tests \
+ pac_responder-tests
endif
check_PROGRAMS = \
@@ -599,6 +600,7 @@ endif
sssd_pac_SOURCES = \
src/responder/pac/pacsrv.c \
src/responder/pac/pacsrv_cmd.c \
+ src/responder/pac/pacsrv_utils.c \
$(SSSD_UTIL_OBJ) \
$(SSSD_RESPONDER_OBJ)
sssd_pac_CFLAGS = \
@@ -608,6 +610,7 @@ sssd_pac_LDADD = \
$(NDR_KRB5PAC_LIBS) \
$(TDB_LIBS) \
$(SSSD_LIBS) \
+ libsss_idmap.la \
libsss_util.la
sssd_be_SOURCES = \
@@ -994,6 +997,18 @@ sss_idmap_tests_LDADD = \
libsss_test_common.la \
libsss_idmap.la
+pac_responder_tests_SOURCES = \
+ src/tests/pac_responder-tests.c \
+ src/responder/pac/pacsrv_utils.c
+pac_responder_tests_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(NDR_KRB5PAC_CFLAGS) \
+ $(CHECK_CFLAGS)
+pac_responder_tests_LDADD = \
+ $(CHECK_LIBS) \
+ $(TALLOC_LIBS) \
+ libsss_debug.la \
+ libsss_test_common.la
endif
stress_tests_SOURCES = \
diff --git a/src/external/pac_responder.m4 b/src/external/pac_responder.m4
index e157910dc..fbad267e2 100644
--- a/src/external/pac_responder.m4
+++ b/src/external/pac_responder.m4
@@ -21,7 +21,8 @@ then
AC_MSG_CHECKING(for supported MIT krb5 version)
KRB5_VERSION="`$KRB5_CONFIG --version`"
case $KRB5_VERSION in
- Kerberos\ 5\ release\ 1.9*)
+ Kerberos\ 5\ release\ 1.9* | \
+ Kerberos\ 5\ release\ 1.10*)
AC_MSG_RESULT(yes)
;;
*)
diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
index 98d1aabff..6421fee93 100644
--- a/src/responder/pac/pacsrv.c
+++ b/src/responder/pac/pacsrv.c
@@ -103,6 +103,16 @@ static void pac_dp_reconnect_init(struct sbus_connection *conn,
/* nss_shutdown(rctx); */
}
+static void *idmap_talloc(size_t size, void *pvt)
+{
+ return talloc_size(pvt, size);
+}
+
+static void idmap_free(void *ptr, void *pvt)
+{
+ talloc_free(ptr);
+}
+
int pac_process_init(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct confdb_ctx *cdb)
@@ -111,6 +121,7 @@ int pac_process_init(TALLOC_CTX *mem_ctx,
struct be_conn *iter;
struct pac_ctx *pac_ctx;
int ret, max_retries;
+ enum idmap_error_code err;
pac_ctx = talloc_zero(mem_ctx, struct pac_ctx);
if (!pac_ctx) {
@@ -149,6 +160,14 @@ int pac_process_init(TALLOC_CTX *mem_ctx,
pac_dp_reconnect_init, iter);
}
+
+ err = sss_idmap_init(idmap_talloc, pac_ctx, idmap_free,
+ &pac_ctx->idmap_ctx);
+ if (err != IDMAP_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("sss_idmap_init failed.\n"));
+ return EFAULT;
+ }
+
DEBUG(SSSDBG_TRACE_FUNC, ("PAC Initialization complete\n"));
return EOK;
diff --git a/src/responder/pac/pacsrv.h b/src/responder/pac/pacsrv.h
index 1b28254de..1400074fc 100644
--- a/src/responder/pac/pacsrv.h
+++ b/src/responder/pac/pacsrv.h
@@ -32,6 +32,7 @@
#include "sbus/sssd_dbus.h"
#include "responder/common/responder_packet.h"
#include "responder/common/responder.h"
+#include "lib/idmap/sss_idmap.h"
#define PAC_SBUS_SERVICE_VERSION 0x0001
#define PAC_SBUS_SERVICE_NAME "pac"
@@ -39,13 +40,32 @@
#define PAC_PACKET_MAX_RECV_SIZE 1024
struct getent_ctx;
+struct dom_sid;
struct pac_ctx {
struct resp_ctx *rctx;
+ struct sss_idmap_ctx *idmap_ctx;
+ struct dom_sid *my_dom_sid;
+ struct local_mapping_ranges *range_map;
+};
+
+struct range {
+ uint32_t min;
+ uint32_t max;
+};
+
+struct local_mapping_ranges {
+ struct range local_ids;
+ struct range primary_rids;
+ struct range secondary_rids;
};
int pac_cmd_execute(struct cli_ctx *cctx);
struct sss_cmd_table *get_pac_cmds(void);
+errno_t get_rid(struct dom_sid *sid, uint32_t *rid);
+
+errno_t local_sid_to_id(struct local_mapping_ranges *map, struct dom_sid *sid,
+ uint32_t *id);
#endif /* __PACSRV_H__ */
diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c
index 3f2420273..f4fec85f8 100644
--- a/src/responder/pac/pacsrv_cmd.c
+++ b/src/responder/pac/pacsrv_cmd.c
@@ -19,18 +19,18 @@
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 <stdbool.h>
+#include <util/data_blob.h>
+#include <ndr.h>
+#include <gen_ndr/krb5pac.h>
+#include <gen_ndr/ndr_krb5pac.h>
#include "util/util.h"
+#include "util/sss_nss.h"
#include "responder/pac/pacsrv.h"
#include "confdb/confdb.h"
#include "db/sysdb.h"
-#include <util/data_blob.h>
-#include <ndr.h>
-
-#include "gen_ndr/krb5pac.h"
-#include "gen_ndr/ndr_krb5pac.h"
-
#define PAC_USER_OFFSET 200000
#define PAC_HOME_PATH "/home/"
#define PAC_DEFAULT_SHELL "/bin/bash"
@@ -59,39 +59,301 @@ static errno_t pac_cmd_done(struct cli_ctx *cctx, int cmd_ret)
return EOK;
}
-static errno_t domsid_rid_to_uid(struct dom_sid2 *domsid, uint32_t rid,
- uid_t *uid)
+static void *idmap_talloc(size_t size, void *pvt)
{
- /* Replace with a proper mapping */
- *uid = (uid_t) rid + PAC_USER_OFFSET;
- return EOK;
+ return talloc_size(pvt, size);
+}
+
+static void idmap_free(void *ptr, void *pvt)
+{
+ talloc_free(ptr);
}
-static errno_t domsid_rid_to_gid(struct dom_sid2 *domsid, uint32_t rid,
- gid_t *gid)
+static errno_t add_idmap_domain(struct sss_idmap_ctx *idmap_ctx,
+ struct sysdb_ctx *sysdb,
+ const char *domain_name,
+ const char *dom_sid_str)
{
- /* Replace with a proper mapping */
- *gid = (gid_t) rid + PAC_USER_OFFSET;
+ struct sss_idmap_range range;
+ enum idmap_error_code err;
+
+ /* TODO: read range form sysdb if
+ * https://fedorahosted.org/freeipa/ticket/2185 is fixed */
+ range.min = 200000;
+ range.max = 400000;
+
+ err = sss_idmap_add_domain(idmap_ctx, domain_name, dom_sid_str, &range);
+ if (err != IDMAP_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_add_domain failed.\n"));
+ return EFAULT;
+ }
+
return EOK;
}
+static errno_t domsid_rid_to_uid(struct pac_ctx *pac_ctx,
+ struct sysdb_ctx *sysdb,
+ const char *domain_name,
+ struct dom_sid2 *domsid, uint32_t rid,
+ uid_t *uid)
+{
+ enum idmap_error_code err;
+ char *sid_str = NULL;
+ char *dom_sid_str = NULL;
+ uint32_t id;
+ int ret;
+
+ if (pac_ctx->idmap_ctx == NULL) {
+ err = sss_idmap_init(idmap_talloc, pac_ctx, idmap_free,
+ &pac_ctx->idmap_ctx);
+ if (err != IDMAP_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("sss_idmap_init failed.\n"));
+ return EFAULT;
+ }
+ }
+
+ err = sss_idmap_smb_sid_to_sid(pac_ctx->idmap_ctx, domsid,
+ &dom_sid_str);
+ if (err != IDMAP_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_smb_sid_to_sid failed.\n"));
+ ret = EFAULT;
+ goto done;
+ }
+
+ sid_str = talloc_asprintf(NULL, "%s-%lu", dom_sid_str, (unsigned long) rid);
+ if (sid_str == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("dom_sid_and_rid_string failed.\n"));
+ return ENOMEM;
+ }
+
+ err = sss_idmap_smb_sid_to_sid(pac_ctx->idmap_ctx, domsid, &sid_str);
+ if (err != IDMAP_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_smb_sid_to_sid failed.\n"));
+ ret = EFAULT;
+ goto done;
+ }
+
+ err = sss_idmap_sid_to_unix(pac_ctx->idmap_ctx, sid_str, &id);
+ if (err == IDMAP_NO_DOMAIN) {
+ ret = add_idmap_domain(pac_ctx->idmap_ctx, sysdb, domain_name,
+ dom_sid_str);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("add_idmap_domain failed.\n"));
+ goto done;
+ }
+
+ err = sss_idmap_sid_to_unix(pac_ctx->idmap_ctx, sid_str, &id);
+ if (err != IDMAP_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("sss_idmap_sid_to_unix failed "
+ "even in the second attempt.\n"));
+ ret = ENOENT;
+ goto done;
+ }
+ } else if (err != IDMAP_SUCCESS && err != IDMAP_NO_DOMAIN) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_sid_to_unix failed.\n"));
+ ret = EFAULT;
+ goto done;
+ }
+
+ *uid = (uid_t) id;
+
+ ret = EOK;
+
+done:
+ talloc_free(dom_sid_str);
+ talloc_free(sid_str);
+ return ret;
+}
+
+static errno_t get_my_domain_sid(struct pac_ctx *pac_ctx,
+ struct sss_domain_info *dom,
+ struct dom_sid **_sid)
+{
+ struct sysdb_ctx *sysdb;
+ int ret;
+ struct ldb_dn *basedn;
+ const char *attrs[] = {SYSDB_SUBDOMAIN_ID,
+ NULL};
+ size_t msgs_count;
+ const char *sid_str;
+ struct ldb_message **msgs;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct dom_sid *sid = NULL;
+ char *dom_name;
+ enum idmap_error_code err;
+
+ if (pac_ctx->my_dom_sid == NULL) {
+ if (dom->parent != NULL) {
+ sysdb = dom->parent->sysdb;
+ dom_name = dom->parent->name;
+ } else {
+ sysdb = dom->sysdb;
+ dom_name = dom->name;
+ }
+
+ if (sysdb == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("Missing sysdb context.\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
+ ret = ENOMEM;
+ goto done;
+ }
+
+ basedn = sysdb_domain_dn(sysdb, tmp_ctx, dom_name);
+ if (basedn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_search_entry(tmp_ctx, sysdb, basedn, LDB_SCOPE_BASE, NULL,
+ attrs, &msgs_count, &msgs);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ if (msgs_count != 1) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Base search returned [%d] results, "
+ "expected 1.\n", msgs_count));
+ ret = EINVAL;
+ goto done;
+ }
+
+ sid_str = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUBDOMAIN_ID, NULL);
+ if (sid_str == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("SID of my domain is not available.\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ err = sss_idmap_sid_to_smb_sid(pac_ctx->idmap_ctx, sid_str, &sid);
+ if (err != IDMAP_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_sid_to_smb_sid failed.\n"));
+ ret = EFAULT;
+ goto done;
+ }
+
+ pac_ctx->my_dom_sid = talloc_memdup(pac_ctx, sid,
+ sizeof(struct dom_sid));
+ if (pac_ctx->my_dom_sid == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("talloc_memdup failed.\n"));
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ *_sid = pac_ctx->my_dom_sid;
+
+ ret = EOK;
+
+done:
+ talloc_free(sid);
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static bool dom_sid_in_domain(const struct dom_sid *domain_sid,
+ const struct dom_sid *sid)
+{
+ size_t c;
+
+ if (!domain_sid || !sid) {
+ return false;
+ }
+
+ if (domain_sid->sid_rev_num != sid->sid_rev_num) {
+ return false;
+ }
+
+ for (c = 0; c < 6; c++) {
+ if (domain_sid->id_auth[c] != sid->id_auth[c]) {
+ return false;
+ }
+ }
+
+ if (domain_sid->num_auths > sid->num_auths) {
+ return false;
+ }
+
+ for (c = 0; c < domain_sid->num_auths-1; c++) {
+ if (domain_sid->sub_auths[c] != sid->sub_auths[c]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static errno_t get_gids_from_pac(TALLOC_CTX *mem_ctx,
+ struct local_mapping_ranges *range_map,
+ struct dom_sid *domain_sid,
+ struct PAC_LOGON_INFO *logon_info,
+ size_t *_gid_count, gid_t **_gids)
+{
+ int ret;
+ size_t g;
+ size_t s;
+ struct netr_SamInfo3 *info3;
+ gid_t *gids = NULL;
+
+ info3 = &logon_info->info3;
+
+ g = 0;
+ if (info3->sidcount == 0) {
+ DEBUG(SSSDBG_TRACE_ALL, ("No extra groups found.\n"));
+ ret = EOK;
+ goto done;
+ }
+
+ gids = talloc_array(mem_ctx, gid_t, info3->sidcount);
+ if (gids == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("talloc_array failed.\n"));
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for(s = 0; s < info3->sidcount; s++) {
+ if (dom_sid_in_domain(domain_sid, info3->sids[s].sid)) {
+ ret = local_sid_to_id(range_map, info3->sids[s].sid, &gids[g]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_rid failed.\n"));
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_ALL, ("Found extra group "
+ "with gid [%d].\n", gids[g]));
+ g++;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ if (ret == EOK) {
+ *_gid_count = g;
+ *_gids = gids;
+ } else {
+ talloc_free(gids);
+ }
+
+ return ret;
+}
+
static errno_t get_data_from_pac(TALLOC_CTX *mem_ctx,
- uint8_t *pac_blob, size_t pac_len,
- struct passwd **_pwd, char **domain,
- struct dom_sid2 **domain_sid,
- int *_rid_count, uint32_t **_rids)
+ uint8_t *pac_blob, size_t pac_len,
+ struct PAC_LOGON_INFO **_logon_info)
{
DATA_BLOB blob;
struct ndr_pull *ndr_pull;
struct PAC_DATA *pac_data;
enum ndr_err_code ndr_err;
- struct passwd *pwd = NULL;
size_t c;
- struct netr_SamBaseInfo *base_info;
int ret;
- int i, j;
- uint32_t *rids;
- uint32_t attrs;
blob.data = pac_blob;
blob.length = pac_len;
@@ -106,7 +368,6 @@ static errno_t get_data_from_pac(TALLOC_CTX *mem_ctx,
pac_data = talloc_zero(mem_ctx, struct PAC_DATA);
if (pac_data == NULL) {
DEBUG(SSSDBG_OP_FAILURE, ("talloc_zero failed.\n"));
- return EOK;
return ENOMEM;
}
@@ -116,146 +377,126 @@ static errno_t get_data_from_pac(TALLOC_CTX *mem_ctx,
return EBADMSG;
}
- pwd = talloc_zero(mem_ctx, struct passwd);
- if (pwd == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, ("talloc_zero failed.\n"));
- return ENOMEM;
- }
-
for(c = 0; c < pac_data->num_buffers; c++) {
if (pac_data->buffers[c].type == PAC_TYPE_LOGON_INFO) {
- base_info = &pac_data->buffers[c].info->logon_info.info->info3.base;
-
- if (base_info->account_name.size != 0) {
- pwd->pw_name = talloc_strdup(pwd,
- base_info->account_name.string);
- if (pwd->pw_name == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
- ret = ENOMEM;
- goto done;
- }
- } else {
- DEBUG(SSSDBG_OP_FAILURE, ("Missing account name in PAC.\n"));
- ret = EINVAL;
- goto done;
- }
+ *_logon_info = pac_data->buffers[c].info->logon_info.info;
- if (base_info->rid > 0) {
- ret = domsid_rid_to_uid(base_info->domain_sid,
- base_info->rid,
- &pwd->pw_uid);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, ("domsid_rid_to_uid failed.\n"));
- goto done;
- }
- } else {
- DEBUG(SSSDBG_OP_FAILURE, ("Missing user RID in PAC.\n"));
- ret = EINVAL;
- goto done;
- }
+ return EOK;
+ }
+ }
- if (base_info->primary_gid > 0) {
- ret = domsid_rid_to_gid(base_info->domain_sid,
- base_info->primary_gid,
- &pwd->pw_gid);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, ("domsid_rid_to_gid failed.\n"));
- goto done;
- }
- } else {
- DEBUG(SSSDBG_OP_FAILURE, ("Missing primary GID in PAC.\n"));
- ret = EINVAL;
- goto done;
- }
+ ret = EINVAL;
- if (base_info->full_name.size != 0) {
- pwd->pw_gecos = talloc_strdup(pwd, base_info->full_name.string);
- } else {
- DEBUG(SSSDBG_OP_FAILURE, ("Missing full name in PAC "
- "using account name for gecos.\n"));
- pwd->pw_gecos = talloc_strdup(pwd,
- base_info->account_name.string);
- }
- if (pwd->pw_gecos == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
- ret = ENOMEM;
- goto done;
- }
+ talloc_free(pac_data);
+ return ret;
+}
- pwd->pw_dir = talloc_asprintf(mem_ctx, PAC_HOME_PATH"%s",
- base_info->account_name.string);
- if (pwd->pw_dir == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, ("talloc_asprintf failed.\n"));
- ret = ENOMEM;
- goto done;
- }
+static errno_t get_pwd_from_pac(TALLOC_CTX *mem_ctx,
+ struct pac_ctx *pac_ctx,
+ struct sss_domain_info *dom,
+ struct PAC_LOGON_INFO *logon_info,
+ struct passwd **_pwd)
+{
+ struct passwd *pwd = NULL;
+ struct netr_SamBaseInfo *base_info;
+ int ret;
- pwd->pw_shell = talloc_strdup(pwd, PAC_DEFAULT_SHELL);
- if (pwd->pw_shell == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
- ret = ENOMEM;
- goto done;
- }
+ pwd = talloc_zero(mem_ctx, struct passwd);
+ if (pwd == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("talloc_zero failed.\n"));
+ return ENOMEM;
+ }
- *domain = talloc_strdup(mem_ctx, base_info->logon_domain.string);
- if (*domain == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
- ret = ENOMEM;
- goto done;
- }
+ base_info = &logon_info->info3.base;
- *_pwd = pwd;
+ if (base_info->account_name.size != 0) {
+ pwd->pw_name = talloc_strdup(pwd,
+ base_info->account_name.string);
+ if (pwd->pw_name == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
+ ret = ENOMEM;
+ goto done;
+ }
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, ("Missing account name in PAC.\n"));
+ ret = EINVAL;
+ goto done;
+ }
- rids = talloc_array(mem_ctx, uint32_t, base_info->groups.count);
- if (rids == NULL) {
- ret = ENOMEM;
- goto done;
- }
+ if (base_info->rid > 0) {
+ ret = domsid_rid_to_uid(pac_ctx, dom->sysdb, dom->name,
+ base_info->domain_sid,
+ base_info->rid, &pwd->pw_uid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("domsid_rid_to_uid failed.\n"));
+ goto done;
+ }
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, ("Missing user RID in PAC.\n"));
+ ret = EINVAL;
+ goto done;
+ }
- j = 0;
- for (i = 0; i < base_info->groups.count; i++) {
- attrs = base_info->groups.rids[i].attributes;
- if (((attrs & SE_GROUP_ENABLED) != 0 ||
- (attrs & SE_GROUP_MANDATORY) != 0) &&
- (attrs & SE_GROUP_RESOURCE) == 0) {
- rids[j] = base_info->groups.rids[i].rid;
- j++;
- }
- }
+ pwd->pw_gid = 0; /* We use MPGs for sub-domains */
+
+ if (base_info->full_name.size != 0) {
+ pwd->pw_gecos = talloc_strdup(pwd, base_info->full_name.string);
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, ("Missing full name in PAC "
+ "using account name for gecos.\n"));
+ pwd->pw_gecos = talloc_strdup(pwd,
+ base_info->account_name.string);
+ }
+ if (pwd->pw_gecos == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
+ ret = ENOMEM;
+ goto done;
+ }
- *_rids = rids;
- *_rid_count = j;
- return EOK;
+ if (dom->subdomain_homedir) {
+ pwd->pw_dir = expand_homedir_template(pwd, dom->subdomain_homedir,
+ pwd->pw_name, pwd->pw_uid,
+ dom->name);
+ if (pwd->pw_dir == NULL) {
+ ret = ENOMEM;
+ goto done;
}
}
- ret = EINVAL;
+ pwd->pw_shell = NULL; /* Using default */
done:
- talloc_free(pwd);
+ if (ret != EOK) {
+ talloc_free(pwd);
+ }
+
return ret;
}
struct pac_req_ctx {
struct cli_ctx *cctx;
- struct passwd *pwd;
- char *domain_name;
+ struct pac_ctx *pac_ctx;
+ const char *domain_name;
+ const char *user_name;
struct sss_domain_info *dom;
- int rid_count;
- uint32_t *rids;
+ struct PAC_LOGON_INFO *logon_info;
struct dom_sid2 *domain_sid;
+
+ size_t gid_count;
+ gid_t *gids;
};
+static errno_t pac_add_user_next(struct pac_req_ctx *pr_ctx);
static void pac_get_domains_done(struct tevent_req *req);
-errno_t save_pac_user(struct pac_req_ctx *pr_ctx);
+static errno_t save_pac_user(struct pac_req_ctx *pr_ctx);
static void pac_get_group_done(struct tevent_req *subreq);
static errno_t pac_save_memberships_next(struct tevent_req *req);
static errno_t pac_store_memberships(struct pac_req_ctx *pr_ctx,
struct sysdb_ctx *group_sysdb,
struct ldb_dn *user_dn,
- int rid_iter);
+ int gid_iter);
struct tevent_req *pac_save_memberships_send(struct pac_req_ctx *pr_ctx);
static void pac_save_memberships_done(struct tevent_req *req);
@@ -278,20 +519,34 @@ static errno_t pac_add_pac_user(struct cli_ctx *cctx)
pr_ctx->cctx = cctx;
+ pr_ctx->pac_ctx = talloc_get_type(cctx->rctx->pvt_ctx, struct pac_ctx);
+ if (pr_ctx->pac_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("Cannot find pac responder context.\n"));
+ return EINVAL;
+ }
+
ret = get_data_from_pac(pr_ctx, body, blen,
- &pr_ctx->pwd, &pr_ctx->domain_name,
- &pr_ctx->domain_sid,
- &pr_ctx->rid_count, &pr_ctx->rids);
+ &pr_ctx->logon_info);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, ("get_pwd_from_pac failed.\n"));
+ DEBUG(SSSDBG_OP_FAILURE, ("get_data_from_pac failed.\n"));
goto done;
}
+
+ pr_ctx->domain_name = pr_ctx->logon_info->info3.base.logon_domain.string;
if (pr_ctx->domain_name == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE, ("No domain name in PAC"));
ret = EINVAL;
goto done;
}
+ pr_ctx->user_name = pr_ctx->logon_info->info3.base.account_name.string;
+ if (pr_ctx->user_name == NULL) {
+ ret = EINVAL;
+ DEBUG(SSSDBG_FATAL_FAILURE, ("Missing account name in PAC.\n"));
+ goto done;
+ }
+
+
pr_ctx->dom = responder_get_domain(pr_ctx, cctx->rctx, pr_ctx->domain_name);
if (pr_ctx->dom == NULL) {
req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true,
@@ -305,23 +560,7 @@ static errno_t pac_add_pac_user(struct cli_ctx *cctx)
goto done;
}
- ret = save_pac_user(pr_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, ("save_pac_user failed.\n"));
- goto done;
- }
-
-
- req = pac_save_memberships_send(pr_ctx);
- if (req == NULL) {
- ret = ENOMEM;
- goto done;
- }
-
- tevent_req_set_callback(req, pac_save_memberships_done, pr_ctx);
-
-
- ret = EAGAIN;
+ ret = pac_add_user_next(pr_ctx);
done:
return pac_cmd_done(cctx, ret);
@@ -346,12 +585,38 @@ static void pac_get_domains_done(struct tevent_req *req)
goto done;
}
+ ret = pac_add_user_next(pr_ctx);
+
+done:
+ pac_cmd_done(cctx, ret);
+}
+
+static errno_t pac_add_user_next(struct pac_req_ctx *pr_ctx)
+{
+ int ret;
+ struct tevent_req *req;
+ struct dom_sid *my_dom_sid;
+
ret = save_pac_user(pr_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("save_pac_user failed.\n"));
goto done;
}
+ ret = get_my_domain_sid(pr_ctx->pac_ctx, pr_ctx->dom, &my_dom_sid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_my_domain_sid failed.\n"));
+ goto done;
+ }
+
+ ret = get_gids_from_pac(pr_ctx, pr_ctx->pac_ctx->range_map, my_dom_sid,
+ pr_ctx->logon_info, &pr_ctx->gid_count,
+ &pr_ctx->gids);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_gids_from_pac failed.\n"));
+ goto done;
+ }
+
req = pac_save_memberships_send(pr_ctx);
if (req == NULL) {
ret = ENOMEM;
@@ -360,18 +625,20 @@ static void pac_get_domains_done(struct tevent_req *req)
tevent_req_set_callback(req, pac_save_memberships_done, pr_ctx);
- return;
+ ret = EAGAIN;
done:
- pac_cmd_done(cctx, ret);
+ return ret;
}
-errno_t save_pac_user(struct pac_req_ctx *pr_ctx)
+static errno_t save_pac_user(struct pac_req_ctx *pr_ctx)
{
struct sysdb_ctx *sysdb;
- struct passwd *pwd = pr_ctx->pwd;
- struct cli_ctx *cctx = pr_ctx->cctx;
int ret;
+ const char *attrs[] = {SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM, NULL};
+ struct ldb_message *msg;
+ struct passwd *pwd = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
sysdb = pr_ctx->dom->sysdb;
if (sysdb == NULL) {
@@ -380,21 +647,49 @@ errno_t save_pac_user(struct pac_req_ctx *pr_ctx)
goto done;
}
- ret = sysdb_store_user(sysdb, pwd->pw_name, NULL,
- pwd->pw_uid, pwd->pw_gid, pwd->pw_gecos, pwd->pw_dir,
- pwd->pw_shell, NULL, NULL, 3600, 0); /* FIXME: cache_timeout */
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, ("sysdb_store_user failed [%d][%s].\n",
- ret, strerror(ret)));
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
+ goto done;
+ }
+
+ ret = sysdb_search_user_by_name(tmp_ctx, sysdb, pr_ctx->user_name, attrs,
+ &msg);
+ if (ret == EOK) {
+ /* TODO: check id uid and gid are equal. */
+ } else if (ret == ENOENT) {
+ ret = get_pwd_from_pac(tmp_ctx, pr_ctx->pac_ctx, pr_ctx->dom,
+ pr_ctx->logon_info, &pwd);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_pwd_from_pac failed.\n"));
+ goto done;
+ }
+
+ ret = sysdb_store_user(sysdb, pwd->pw_name, NULL,
+ pwd->pw_uid, pwd->pw_gid, pwd->pw_gecos,
+ pwd->pw_dir,
+ pwd->pw_shell, NULL, NULL,
+ 3600, 0); /* FIXME: cache_timeout */
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_store_user failed [%d][%s].\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_search_user_by_name failed.\n"));
goto done;
}
+ ret = EOK;
+
done:
- return pac_cmd_done(cctx, ret);
+ talloc_free(tmp_ctx);
+ return ret;
}
struct pac_save_memberships_state {
- int rid_iter;
+ int gid_iter;
struct ldb_dn *user_dn;
struct pac_req_ctx *pr_ctx;
@@ -413,9 +708,9 @@ struct tevent_req *pac_save_memberships_send(struct pac_req_ctx *pr_ctx)
return NULL;
}
- state->rid_iter = 0;
+ state->gid_iter = 0;
state->user_dn = sysdb_user_dn(dom->sysdb, state, dom->name,
- pr_ctx->pwd->pw_name);
+ pr_ctx->user_name);
if (state->user_dn == NULL) {
ret = ENOMEM;
goto done;
@@ -430,6 +725,10 @@ struct tevent_req *pac_save_memberships_send(struct pac_req_ctx *pr_ctx)
}
ret = pac_save_memberships_next(req);
+ if (ret == EOK) {
+ tevent_req_done(req);
+ tevent_req_post(req, pr_ctx->cctx->ev);
+ }
done:
if (ret != EOK && ret != EAGAIN) {
@@ -452,18 +751,18 @@ errno_t pac_save_memberships_next(struct tevent_req *req)
state = tevent_req_data(req, struct pac_save_memberships_state);
pr_ctx = state->pr_ctx;
- while (state->rid_iter < pr_ctx->rid_count) {
- gid = pr_ctx->rids[state->rid_iter];
+ while (state->gid_iter < pr_ctx->gid_count) {
+ gid = pr_ctx->gids[state->gid_iter];
ret = sysdb_search_group_by_gid(pr_ctx, state->group_dom->sysdb,
gid, NULL, &group);
if (ret == EOK) {
ret = pac_store_memberships(state->pr_ctx, state->group_dom->sysdb,
- state->user_dn, state->rid_iter);
+ state->user_dn, state->gid_iter);
if (ret != EOK) {
goto done;
}
- state->rid_iter++;
+ state->gid_iter++;
continue;
} else if (ret != ENOENT) {
goto done;
@@ -510,11 +809,11 @@ static void pac_get_group_done(struct tevent_req *subreq)
}
ret = pac_store_memberships(state->pr_ctx, state->group_dom->sysdb,
- state->user_dn, state->rid_iter);
+ state->user_dn, state->gid_iter);
if (ret != EOK) {
goto error;
}
- state->rid_iter++;
+ state->gid_iter++;
ret = pac_save_memberships_next(req);
if (ret == EOK) {
@@ -533,7 +832,7 @@ static errno_t
pac_store_memberships(struct pac_req_ctx *pr_ctx,
struct sysdb_ctx *group_sysdb,
struct ldb_dn *user_dn,
- int rid_iter)
+ int gid_iter)
{
TALLOC_CTX *tmp_ctx;
const char *group_name;
@@ -547,7 +846,7 @@ pac_store_memberships(struct pac_req_ctx *pr_ctx,
return ENOMEM;
}
- gid = pr_ctx->rids[rid_iter];
+ gid = pr_ctx->gids[gid_iter];
ret = sysdb_search_group_by_gid(tmp_ctx, group_sysdb,
gid, NULL, &group);
diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c
new file mode 100644
index 000000000..9f2932be9
--- /dev/null
+++ b/src/responder/pac/pacsrv_utils.c
@@ -0,0 +1,66 @@
+/*
+ SSSD
+
+ PAC Responder - utility finctions
+
+ Copyright (C) Sumit Bose <sbose@redhat.com> 2012
+
+ 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 <stdbool.h>
+#include <util/data_blob.h>
+#include <gen_ndr/security.h>
+
+#include "util/util.h"
+#include "responder/pac/pacsrv.h"
+
+errno_t get_rid(struct dom_sid *sid, uint32_t *rid)
+{
+ if (sid == NULL || sid->num_auths < 1 || rid == NULL) {
+ return EINVAL;
+ }
+
+ *rid = sid->sub_auths[sid->num_auths - 1];
+
+ return EOK;
+}
+
+errno_t local_sid_to_id(struct local_mapping_ranges *map, struct dom_sid *sid,
+ uint32_t *id)
+{
+ int ret;
+ uint32_t rid;
+
+ if (map == NULL || sid == NULL || id == NULL) {
+ return EINVAL;
+ }
+
+ ret = get_rid(sid, &rid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_rid failed.\n"));
+ return ret;
+ }
+
+ if (rid >= map->primary_rids.min && rid <= map->primary_rids.max) {
+ *id = map->local_ids.min + (rid - map->primary_rids.min);
+ } else if (rid >= map->secondary_rids.min &&
+ rid <= map->secondary_rids.max) {
+ *id = map->local_ids.min + (rid - map->secondary_rids.min);
+ } else {
+ return ENOENT;
+ }
+
+ return EOK;
+}
+
diff --git a/src/tests/pac_responder-tests.c b/src/tests/pac_responder-tests.c
new file mode 100644
index 000000000..720793cc6
--- /dev/null
+++ b/src/tests/pac_responder-tests.c
@@ -0,0 +1,106 @@
+/*
+ SSSD - Test for PAC reponder functions
+
+ 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 <check.h>
+
+#include <stdbool.h>
+#include <util/data_blob.h>
+#include <gen_ndr/security.h>
+
+#include "tests/common.h"
+#include "responder/pac/pacsrv.h"
+
+struct dom_sid test_smb_sid = {1, 5, {0, 0, 0, 0, 0, 5},
+ {21, 2127521184, 1604012920, 1887927527, 1123,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+const uint32_t test_id = 1200123;
+
+struct dom_sid test_smb_sid_2nd = {1, 5, {0, 0, 0, 0, 0, 5},
+ {21, 2127521184, 1604012920, 1887927527, 201456,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+const uint32_t test_id_2nd = 1200456;
+
+struct local_mapping_ranges test_map = {{1200000, 1399999},
+ {1000, 200999},
+ {201000, 400999}};
+
+
+START_TEST(pac_test_local_sid_to_id)
+{
+ int ret;
+ uint32_t id;
+
+ ret = local_sid_to_id(&test_map, &test_smb_sid, &id);
+ fail_unless(ret == EOK,
+ "Failed to convert local sid to id.");
+ fail_unless(id == test_id, "Wrong id returne, expected [%d], got [%d].",
+ test_id, id);
+}
+END_TEST
+
+START_TEST(pac_test_seondary_local_sid_to_id)
+{
+ int ret;
+ uint32_t id;
+
+ ret = local_sid_to_id(&test_map, &test_smb_sid_2nd, &id);
+ fail_unless(ret == EOK,
+ "Failed to convert local sid to id.");
+ fail_unless(id == test_id_2nd, "Wrong id returne, expected [%d], got [%d].",
+ test_id_2nd, id);
+}
+END_TEST
+
+
+Suite *idmap_test_suite (void)
+{
+ Suite *s = suite_create ("PAC responder");
+
+ TCase *tc_pac = tcase_create("PAC responder tests");
+ /*tcase_add_checked_fixture(tc_init,
+ leak_check_setup,
+ leak_check_teardown);*/
+
+ tcase_add_test(tc_pac, pac_test_local_sid_to_id);
+ tcase_add_test(tc_pac, pac_test_seondary_local_sid_to_id);
+
+ suite_add_tcase(s, tc_pac);
+
+ return s;
+}
+
+int main(int argc, const char *argv[])
+{
+ int number_failed;
+
+ tests_set_cwd();
+
+ Suite *s = idmap_test_suite();
+ SRunner *sr = srunner_create(s);
+
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ number_failed = srunner_ntests_failed (sr);
+ srunner_free (sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}