Map SIDs to unixids and back
Copyright (C) Kai Blin 2008
+ Copyright (C) Andrew Bartlett 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
#include "includes.h"
#include "auth/auth.h"
#include "librpc/gen_ndr/ndr_security.h"
-#include "lib/ldb/include/ldb.h"
-#include "lib/ldb_wrap.h"
+#include <ldb.h>
+#include "ldb_wrap.h"
#include "param/param.h"
#include "winbind/idmap.h"
#include "libcli/security/security.h"
#include "libcli/ldap/ldap_ndr.h"
+#include "dsdb/samdb/samdb.h"
+#include "../libds/common/flags.h"
/**
* Get uid/gid bounds from idmap database
idmap_ctx->lp_ctx = lp_ctx;
- idmap_ctx->ldb_ctx = ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx,
- lp_idmap_url(lp_ctx),
+ idmap_ctx->ldb_ctx = ldb_wrap_connect(idmap_ctx, ev_ctx, lp_ctx,
+ "idmap.ldb",
system_session(lp_ctx),
NULL, 0);
if (idmap_ctx->ldb_ctx == NULL) {
- return NULL;
+ goto fail;
}
- idmap_ctx->unix_groups_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-2");
+ idmap_ctx->unix_groups_sid = dom_sid_parse_talloc(
+ idmap_ctx, "S-1-22-2");
if (idmap_ctx->unix_groups_sid == NULL) {
- return NULL;
+ goto fail;
}
- idmap_ctx->unix_users_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-1");
+ idmap_ctx->unix_users_sid = dom_sid_parse_talloc(
+ idmap_ctx, "S-1-22-1");
if (idmap_ctx->unix_users_sid == NULL) {
- return NULL;
+ goto fail;
+ }
+
+ idmap_ctx->samdb = samdb_connect(idmap_ctx, ev_ctx, lp_ctx, system_session(lp_ctx), 0);
+ if (idmap_ctx->samdb == NULL) {
+ DEBUG(0, ("Failed to load sam.ldb in idmap_init\n"));
+ goto fail;
}
return idmap_ctx;
+fail:
+ TALLOC_FREE(idmap_ctx);
+ return NULL;
}
/**
static NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx,
TALLOC_CTX *mem_ctx,
- const struct unixid *unixid,
+ struct unixid *unixid,
struct dom_sid **sid)
{
int ret;
NTSTATUS status = NT_STATUS_NONE_MAPPED;
struct ldb_context *ldb = idmap_ctx->ldb_ctx;
struct ldb_result *res = NULL;
- struct dom_sid *unix_sid, *new_sid;
+ struct ldb_message *msg;
+ const struct dom_sid *unix_sid;
+ struct dom_sid *new_sid;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
const char *id_type;
+ const char *sam_attrs[] = {"objectSid", NULL};
+
+ /*
+ * First check against our local DB, to see if this user has a
+ * mapping there. This means that the Samba4 AD DC behaves
+ * much like a winbindd member server running idmap_ad
+ */
+
switch (unixid->type) {
case ID_TYPE_UID:
+ if (lpcfg_parm_bool(idmap_ctx->lp_ctx, NULL, "idmap_ldb", "use rfc2307", false)) {
+ ret = dsdb_search_one(idmap_ctx->samdb, tmp_ctx, &msg,
+ ldb_get_default_basedn(idmap_ctx->samdb),
+ LDB_SCOPE_SUBTREE,
+ sam_attrs, 0,
+ "(&(|(sAMaccountType=%u)(sAMaccountType=%u)(sAMaccountType=%u))"
+ "(uidNumber=%u)(objectSid=*))",
+ ATYPE_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST, unixid->id);
+ } else {
+ /* If we are not to use the rfc2307 attributes, we just emulate a non-match */
+ ret = LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
+ DEBUG(1, ("Search for uidNumber=%lu gave duplicate results, failing to map to a SID!\n",
+ (unsigned long)unixid->id));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ } else if (ret == LDB_SUCCESS) {
+ *sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
+ if (*sid == NULL) {
+ DEBUG(1, ("Search for uidNumber=%lu did not return an objectSid!\n",
+ (unsigned long)unixid->id));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+ } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ DEBUG(1, ("Search for uidNumber=%lu gave '%s', failing to map to a SID!\n",
+ (unsigned long)unixid->id, ldb_errstring(idmap_ctx->samdb)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
id_type = "ID_TYPE_UID";
break;
case ID_TYPE_GID:
+ if (lpcfg_parm_bool(idmap_ctx->lp_ctx, NULL, "idmap_ldb", "use rfc2307", false)) {
+ ret = dsdb_search_one(idmap_ctx->samdb, tmp_ctx, &msg,
+ ldb_get_default_basedn(idmap_ctx->samdb),
+ LDB_SCOPE_SUBTREE,
+ sam_attrs, 0,
+ "(&(|(sAMaccountType=%u)(sAMaccountType=%u))(gidNumber=%u))",
+ ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP,
+ unixid->id);
+ } else {
+ /* If we are not to use the rfc2307 attributes, we just emulate a non-match */
+ ret = LDB_ERR_NO_SUCH_OBJECT;
+ }
+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
+ DEBUG(1, ("Search for gidNumber=%lu gave duplicate results, failing to map to a SID!\n",
+ (unsigned long)unixid->id));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ } else if (ret == LDB_SUCCESS) {
+ *sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
+ if (*sid == NULL) {
+ DEBUG(1, ("Search for gidNumber=%lu did not return an objectSid!\n",
+ (unsigned long)unixid->id));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+ } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ DEBUG(1, ("Search for gidNumber=%lu gave '%s', failing to map to a SID!\n",
+ (unsigned long)unixid->id, ldb_errstring(idmap_ctx->samdb)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
id_type = "ID_TYPE_GID";
break;
default:
}
if (res->count == 1) {
+ const char *type = ldb_msg_find_attr_as_string(res->msgs[0],
+ "type", NULL);
+
*sid = idmap_msg_get_dom_sid(mem_ctx, res->msgs[0],
"objectSid");
if (*sid == NULL) {
status = NT_STATUS_NONE_MAPPED;
goto failed;
}
+
+ if (type == NULL) {
+ DEBUG(1, ("Invalid type for mapping entry.\n"));
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ if (strcmp(type, "ID_TYPE_BOTH") == 0) {
+ unixid->type = ID_TYPE_BOTH;
+ } else if (strcmp(type, "ID_TYPE_UID") == 0) {
+ unixid->type = ID_TYPE_UID;
+ } else {
+ unixid->type = ID_TYPE_GID;
+ }
+
talloc_free(tmp_ctx);
return NT_STATUS_OK;
}
/* For local users/groups , we just create a rid = uid/gid */
if (unixid->type == ID_TYPE_UID) {
- unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-1");
+ unix_sid = &global_sid_Unix_Users;
} else {
- unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-2");
- }
- if (unix_sid == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto failed;
+ unix_sid = &global_sid_Unix_Groups;
}
new_sid = dom_sid_add_rid(mem_ctx, unix_sid, unixid->id);
*
* If no mapping exists, a new mapping will be created.
*
- * \todo Check if SIDs can be resolved if lp_idmap_trusted_only() == true
- * \todo Fix backwards compatibility for Samba3
- *
* \param idmap_ctx idmap context to use
* \param mem_ctx talloc context to use
* \param sid SID to map to an unixid struct
NTSTATUS status = NT_STATUS_NONE_MAPPED;
struct ldb_context *ldb = idmap_ctx->ldb_ctx;
struct ldb_dn *dn;
- struct ldb_message *hwm_msg, *map_msg;
+ struct ldb_message *hwm_msg, *map_msg, *sam_msg;
struct ldb_result *res = NULL;
- int trans;
+ int trans = -1;
uint32_t low, high, hwm, new_xid;
char *sid_string, *unixid_string, *hwm_string;
bool hwm_entry_exists;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ const char *sam_attrs[] = {"uidNumber", "gidNumber", "samAccountType", NULL};
if (dom_sid_in_domain(idmap_ctx->unix_users_sid, sid)) {
uint32_t rid;
DEBUG(6, ("This is a local unix uid, just calculate that.\n"));
status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
- if (!NT_STATUS_IS_OK(status)) goto failed;
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
unixid->id = rid;
unixid->type = ID_TYPE_UID;
uint32_t rid;
DEBUG(6, ("This is a local unix gid, just calculate that.\n"));
status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
- if (!NT_STATUS_IS_OK(status)) goto failed;
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
unixid->id = rid;
unixid->type = ID_TYPE_GID;
talloc_free(tmp_ctx);
return NT_STATUS_OK;
- }
+ }
+
+ /*
+ * First check against our local DB, to see if this user has a
+ * mapping there. This means that the Samba4 AD DC behaves
+ * much like a winbindd member server running idmap_ad
+ */
+
+ if (lpcfg_parm_bool(idmap_ctx->lp_ctx, NULL, "idmap_ldb", "use rfc2307", false)) {
+ ret = dsdb_search_one(idmap_ctx->samdb, tmp_ctx, &sam_msg,
+ ldb_get_default_basedn(idmap_ctx->samdb),
+ LDB_SCOPE_SUBTREE, sam_attrs, 0,
+ "(&(objectSid=%s)"
+ "(|(sAMaccountType=%u)(sAMaccountType=%u)(sAMaccountType=%u)"
+ "(sAMaccountType=%u)(sAMaccountType=%u))"
+ "(|(uidNumber=*)(gidNumber=*)))",
+ dom_sid_string(tmp_ctx, sid),
+ ATYPE_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
+ ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
+ } else {
+ /* If we are not to use the rfc2307 attributes, we just emulate a non-match */
+ ret = LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
+ DEBUG(1, ("Search for objectSid=%s gave duplicate results, failing to map to a unix ID!\n",
+ dom_sid_string(tmp_ctx, sid)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ } else if (ret == LDB_SUCCESS) {
+ uint32_t account_type = ldb_msg_find_attr_as_uint(sam_msg, "sAMaccountType", 0);
+ if ((account_type == ATYPE_ACCOUNT) ||
+ (account_type == ATYPE_WORKSTATION_TRUST ) ||
+ (account_type == ATYPE_INTERDOMAIN_TRUST ))
+ {
+ const struct ldb_val *v = ldb_msg_find_ldb_val(sam_msg, "uidNumber");
+ if (v) {
+ unixid->type = ID_TYPE_UID;
+ unixid->id = ldb_msg_find_attr_as_uint(sam_msg, "uidNumber", -1);
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+
+ } else if ((account_type == ATYPE_SECURITY_GLOBAL_GROUP) ||
+ (account_type == ATYPE_SECURITY_LOCAL_GROUP))
+ {
+ const struct ldb_val *v = ldb_msg_find_ldb_val(sam_msg, "gidNumber");
+ if (v) {
+ unixid->type = ID_TYPE_GID;
+ unixid->id = ldb_msg_find_attr_as_uint(sam_msg, "gidNumber", -1);
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+ }
+ } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ DEBUG(1, ("Search for objectSid=%s gave '%s', failing to map to a SID!\n",
+ dom_sid_string(tmp_ctx, sid), ldb_errstring(idmap_ctx->samdb)));
+
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
ret = ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
NULL, "(&(objectClass=sidMap)(objectSid=%s))",
ldap_encode_ndr_dom_sid(tmp_ctx, sid));
if (ret != LDB_SUCCESS) {
DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
- status = NT_STATUS_NONE_MAPPED;
- goto failed;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NONE_MAPPED;
}
if (res->count == 1) {
-1);
if (new_xid == (uint32_t) -1) {
DEBUG(1, ("Invalid xid mapping.\n"));
- status = NT_STATUS_NONE_MAPPED;
- goto failed;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NONE_MAPPED;
}
if (type == NULL) {
DEBUG(1, ("Invalid type for mapping entry.\n"));
- status = NT_STATUS_NONE_MAPPED;
- goto failed;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NONE_MAPPED;
}
unixid->id = new_xid;
goto failed;
}
- /*FIXME: if lp_idmap_trusted_only() == true, check if SID can be
- * resolved here. */
-
ret = idmap_get_bounds(idmap_ctx, &low, &high);
if (ret != LDB_SUCCESS) {
status = NT_STATUS_NONE_MAPPED;