#include "includes.h"
#include "winbindd.h"
#include "opendirectory.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
#define MODULE_NAME "odsam"
static enum ds_trace_level ds_trace = DS_TRACE_ERRORS;
static int module_debug;
static struct opendirectory_session od_idmap_session;
static NTSTATUS ods_map_sid(struct opendirectory_session *session,
struct id_map *id_entry)
{
CFDictionaryRef sam_record;
char * id_string;
id_entry->status = ID_UNKNOWN;
if (id_entry->xid.type == ID_TYPE_UID) {
sam_record = opendirectory_find_record_from_usersid(session,
id_entry->sid);
if (sam_record) {
id_string = opendirectory_get_record_attribute(NULL,
sam_record, kDS1AttrUniqueID);
goto success;
}
} else {
SMB_ASSERT(id_entry->xid.type == ID_TYPE_GID);
sam_record = opendirectory_find_record_from_groupsid(session,
id_entry->sid);
if (sam_record) {
id_entry->xid.type = ID_TYPE_GID;
id_string = opendirectory_get_record_attribute(NULL,
sam_record, kDS1AttrPrimaryGroupID);
goto success;
}
DEBUG(module_debug, ("%s: no match for %s\n", MODULE_NAME,
sid_string_static(id_entry->sid)));
}
return NT_STATUS_OK;
success:
DEBUG(module_debug, ("%s: mapped %s SID to %s ID %s\n",
MODULE_NAME,
(id_entry->xid.type == ID_TYPE_UID) ? "user" : "group",
sid_string_static(id_entry->sid),
id_string));
id_entry->status = ID_MAPPED;
id_entry->xid.id = strtoul(id_string, NULL, 10 );
TALLOC_FREE(id_string);
CFRelease(sam_record);
return NT_STATUS_OK;
}
static NTSTATUS memberd_map_sid(struct id_map *id_entry)
{
uuid_t uuid;
id_t ugid;
int which;
int err;
id_entry->status = ID_UNMAPPED;
if (!memberd_sid_to_uuid(id_entry->sid, uuid)) {
return NT_STATUS_NONE_MAPPED;
}
err = mbr_uuid_to_id(uuid, &ugid, &which);
if (err != 0) {
if (DEBUGLVL(6)) {
uuid_string_t str;
uuid_unparse(uuid, str);
DEBUGADD(6,
("%s: unable to map UUID %s to a SID: %s\n",
MODULE_NAME, str, strerror(err)));
}
return NT_STATUS_NONE_MAPPED;
}
if (id_entry->xid.type == ID_TYPE_UID && which == MBR_ID_TYPE_UID) {
id_entry->xid.id = ugid;
goto success;
}
if (id_entry->xid.type == ID_TYPE_GID && which == MBR_ID_TYPE_GID) {
id_entry->xid.id = ugid;
goto success;
}
DEBUG(module_debug,
("%s: ID %s SID %s turned out to be of type %d\n",
MODULE_NAME,
(id_entry->xid.type == ID_TYPE_UID) ? "user" : "group",
sid_string_static(id_entry->sid), which));
return NT_STATUS_INVALID_SID;
success:
id_entry->status = ID_MAPPED;
return NT_STATUS_OK;
}
static NTSTATUS memberd_map_unixid(struct id_map *id_entry)
{
uuid_t uuid;
int err;
id_entry->status = ID_UNMAPPED;
if (id_entry->xid.type == ID_TYPE_UID) {
err = mbr_identifier_to_uuid(MBR_ID_TYPE_UID, &id_entry->xid.id,
sizeof(id_entry->xid.id), uuid);
} else {
err = mbr_identifier_to_uuid(MBR_ID_TYPE_GID, &id_entry->xid.id,
sizeof(id_entry->xid.id), uuid);
}
if (err) {
DEBUG(module_debug, ("%s:unable to map %s %d to a UUID: %s\n",
MODULE_NAME,
id_entry->xid.type == ID_TYPE_UID ? "UID" : "GID",
id_entry->xid.id, strerror(err)));
return map_nt_error_from_unix(err);
}
if (!memberd_uuid_to_sid(uuid, id_entry->sid)) {
return NT_STATUS_NONE_MAPPED;
}
id_entry->status = ID_MAPPED;
DEBUG(module_debug, ("%s: mapped %s ID %li to SID %s\n",
MODULE_NAME,
(id_entry->xid.type == ID_TYPE_UID) ? "user" : "group",
(long)id_entry->xid.id,
sid_string_static(id_entry->sid)));
return NT_STATUS_OK;
}
static NTSTATUS ods_map_unixid(struct opendirectory_session *session,
struct id_map *id_entry)
{
CFDictionaryRef sam_record;
id_entry->status = ID_UNKNOWN;
if (id_entry->xid.type == ID_TYPE_UID) {
sam_record = opendirectory_sam_searchugid_first(session,
kDSStdRecordTypeUsers,
kDS1AttrUniqueID,
id_entry->xid.id);
} else {
SMB_ASSERT(id_entry->xid.type == ID_TYPE_GID);
sam_record = opendirectory_sam_searchugid_first(session,
kDSStdRecordTypeGroups,
kDS1AttrPrimaryGroupID,
id_entry->xid.id);
}
if (!sam_record) {
DEBUG(module_debug, ("%s: no match for %s ID %li\n",
MODULE_NAME,
(id_entry->xid.type == ID_TYPE_UID) ? "user" : "group",
(long)id_entry->xid.id));
return NT_STATUS_OK;
}
id_entry->status = ID_UNMAPPED;
if (id_entry->xid.type == ID_TYPE_UID) {
if (opendirectory_find_usersid_from_record(session,
sam_record, id_entry->sid)) {
id_entry->status = ID_MAPPED;
}
} else {
SMB_ASSERT(id_entry->xid.type == ID_TYPE_GID);
if (opendirectory_find_groupsid_from_record(session,
sam_record, id_entry->sid)) {
id_entry->status = ID_MAPPED;
}
}
DEBUG(module_debug, ("%s: mapped %s ID %li to SID %s\n",
MODULE_NAME,
(id_entry->xid.type == ID_TYPE_UID) ? "user" : "group",
(long)id_entry->xid.id,
sid_string_static(id_entry->sid)));
CFRelease(sam_record);
return NT_STATUS_OK;
}
static NTSTATUS idmap_ods_initialize(struct idmap_domain *dom)
{
if (opendirectory_connect(&od_idmap_session) != eDSNoErr) {
return NT_STATUS_INSUFF_SERVER_RESOURCES;
}
return NT_STATUS_OK;
}
static NTSTATUS idmap_ods_close(struct idmap_domain *dom)
{
opendirectory_disconnect(&od_idmap_session);
return NT_STATUS_OK;
}
static NTSTATUS idmap_ods_unixids_to_sids(struct idmap_domain *dom,
struct id_map **ids)
{
struct id_map **current;
if (opendirectory_reconnect(&od_idmap_session) != eDSNoErr) {
return NT_STATUS_INSUFF_SERVER_RESOURCES;
}
for (current = ids; current && *current; ++current) {
NTSTATUS s;
s = memberd_map_unixid(*current);
if (!NT_STATUS_EQUAL(s, NT_STATUS_OK)) {
ods_map_unixid(&od_idmap_session, *current);
}
}
return NT_STATUS_OK;
}
static NTSTATUS idmap_ods_sids_to_unixids(struct idmap_domain *dom,
struct id_map **ids)
{
struct id_map **current;
if (opendirectory_reconnect(&od_idmap_session) != eDSNoErr) {
return NT_STATUS_INSUFF_SERVER_RESOURCES;
}
for (current = ids; current && *current; ++current) {
NTSTATUS s;
s = memberd_map_sid(*current);
if (!NT_STATUS_EQUAL(s, NT_STATUS_OK)) {
ods_map_sid(&od_idmap_session, *current);
}
}
return NT_STATUS_OK;
}
static NTSTATUS ods_alloc_init(const char * compat)
{
return NT_STATUS_OK;
}
static NTSTATUS ods_alloc_close(void)
{
return NT_STATUS_OK;
}
static NTSTATUS ods_alloc_not_supported(struct unixid *id)
{
return NT_STATUS_NOT_SUPPORTED;
}
static struct idmap_methods ods_idmap_methods = {
idmap_ods_initialize,
idmap_ods_unixids_to_sids,
idmap_ods_sids_to_unixids,
NULL,
NULL,
NULL,
idmap_ods_close
};
static struct idmap_alloc_methods ods_alloc_methods = {
ods_alloc_init,
ods_alloc_not_supported,
ods_alloc_not_supported,
ods_alloc_not_supported,
ods_alloc_close
};
NTSTATUS idmap_odsam_init(void)
{
if (lp_parm_bool(GLOBAL_SECTION_SNUM,
MODULE_NAME, "traceall", False)) {
ds_trace = DS_TRACE_ALL;
}
module_debug = lp_parm_int(GLOBAL_SECTION_SNUM,
MODULE_NAME, "msglevel", 100);
smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, MODULE_NAME,
&ods_idmap_methods);
smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, MODULE_NAME,
&ods_alloc_methods);
return NT_STATUS_OK;
}