#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 CFDictionaryRef find_group_by_id(
struct opendirectory_session *session,
uint32_t groupid)
{
CFMutableArrayRef records = NULL;
fstring gid_string;
tDirStatus status;
snprintf(gid_string, sizeof(gid_string) - 1, "%i", groupid);
status = opendirectory_sam_searchattr(session,
&records, kDSStdRecordTypeGroups,
kDS1AttrPrimaryGroupID, gid_string);
LOG_DS_ERROR_MSG(ds_trace, status,
"opendirectory_sam_searchattr[StdRecordTypeGroups]",
("GroupID=%u\n", groupid));
if (records) {
CFDictionaryRef first =
(CFDictionaryRef)CFArrayGetValueAtIndex(records, 0);
CFRetain(first);
CFRelease(records);
return first;
}
return NULL;
}
static CFDictionaryRef find_user_by_id(
struct opendirectory_session *session,
uint32_t userid)
{
CFMutableArrayRef records = NULL;
fstring uid_string;
tDirStatus status;
snprintf(uid_string, sizeof(uid_string) - 1, "%i", userid);
status = opendirectory_sam_searchattr(session,
&records, kDSStdRecordTypeUsers,
kDS1AttrUniqueID, uid_string);
LOG_DS_ERROR_MSG(ds_trace, status,
"opendirectory_sam_searchattr[StdRecordTypeUsers]",
("UniqueID=%u\n", userid));
if (records) {
CFDictionaryRef first =
(CFDictionaryRef)CFArrayGetValueAtIndex(records, 0);
CFRetain(first);
CFRelease(records);
return first;
}
return NULL;
}
static NTSTATUS ods_map_sid(struct opendirectory_session *session,
struct id_map *id_entry)
{
CFDictionaryRef sam_record;
char * id_string;
fstring sid_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_to_string(sid_string, 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_to_string(sid_string, 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 ods_map_unixid(struct opendirectory_session *session,
struct id_map *id_entry)
{
CFDictionaryRef sam_record;
fstring sid_string;
id_entry->status = ID_UNKNOWN;
if (id_entry->xid.type == ID_TYPE_UID) {
sam_record = find_user_by_id(session, id_entry->xid.id);
} else {
SMB_ASSERT(id_entry->xid.type == ID_TYPE_GID);
sam_record = find_group_by_id(session, 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_to_string(sid_string, 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) {
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) {
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;
}