idmap-module-open-directory [plain text]
Index: samba/source/Makefile.in
===================================================================
--- samba/source/Makefile.in.orig
+++ samba/source/Makefile.in
@@ -455,6 +455,7 @@ AUTH_OBJ = auth/auth.o @AUTH_STATIC@ aut
ODSAM_PDB_OBJ = lib/opendirectory.o passdb/pdb_odsam.o
ODSAM_AUTH_OBJ = lib/opendirectory.o auth/auth_odsam.o
+ODSAM_IDMAP_OBJ = lib/opendirectory.o nsswitch/idmap_odsam.o
MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o
@@ -1351,6 +1352,11 @@ bin/pdb_odsam.@SHLIBEXT@: $(ODSAM_PDB_OB
@$(SHLD_MODULE) $(ODSAM_PDB_OBJ) \
-framework DirectoryService
+bin/idmap_odsam.@SHLIBEXT@: $(ODSAM_IDMAP_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(ODSAM_IDMAP_OBJ) \
+ -framework DirectoryService
+
bin/rid.@SHLIBEXT@: proto_exists nsswitch/idmap_rid.o
@echo "Building plugin $@"
@$(SHLD_MODULE) nsswitch/idmap_rid.o
Index: samba/source/configure.in
===================================================================
--- samba/source/configure.in.orig
+++ samba/source/configure.in
@@ -6166,6 +6166,7 @@ SMB_MODULE(idmap_passdb, nsswitch/idmap_
SMB_MODULE(idmap_nss, nsswitch/idmap_nss.o, "bin/nss.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_rid, nsswitch/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_ad, nsswitch/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP)
+SMB_MODULE(idmap_odsam, \$(ODSAM_IDMAP_OBJ), "bin/idmap_odsam.$SHLIBEXT", IDMAP)
SMB_SUBSYSTEM(IDMAP, nsswitch/idmap.o)
SMB_MODULE(nss_info_template, nsswitch/nss_info_template.o, "bin/template.$SHLIBEXT", NSS_INFO)
Index: samba/source/nsswitch/idmap_odsam.c
===================================================================
--- /dev/null
+++ samba/source/nsswitch/idmap_odsam.c
@@ -0,0 +1,309 @@
+/*
+ Unix SMB/CIFS implementation.
+ ID mapping Open Directory Server backend
+
+ Copyright (c) 2007 Apple Inc. All rights rserved.
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+#include "winbindd.h"
+#include "opendirectory.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+/* NOTE: The Open Directory passdb and idmap modules are tightly coupled, so we
+ * link them into the same DSO and expect them to be used together.
+ */
+#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));
+
+ /* XXX AFAICT there is no way to look up computer accounts via the
+ * Unix UID -- jpeach.
+ */
+
+ if (records) {
+ CFDictionaryRef first =
+ (CFDictionaryRef)CFArrayGetValueAtIndex(records, 0);
+
+ CFRetain(first);
+ CFRelease(records);
+ return first;
+ }
+
+ return NULL;
+}
+
+/* Map a SID to the corresponding Unix UID or GID. */
+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 /* base */);
+ TALLOC_FREE(id_string);
+
+ CFRelease(sam_record);
+ return NT_STATUS_OK;
+}
+
+/* Map a Unix UID or GID to the corresponding SID. */
+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) {
+ /* XXX should be mapping DS to NT errors */
+ 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) {
+ /* XXX should be mapping DS to NT errors */
+ 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) {
+ /* XXX should be mapping DS to NT errors */
+ 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 = {
+ /* init */ idmap_ods_initialize,
+ /* unixids_to_sids */ idmap_ods_unixids_to_sids,
+ /* sids_to_unixids */ idmap_ods_sids_to_unixids,
+ /* set_mapping */ NULL,
+ /* remove_mapping */ NULL,
+ /* dump_data */ NULL,
+ /* close */ idmap_ods_close
+};
+
+/* Any static mappings are controlled in Open Directory using the native tools.
+ * We provide a module that always fails to make it explicit that we can't
+ * manipulate this from the Samba side.
+ */
+static struct idmap_alloc_methods ods_alloc_methods = {
+
+ /* init */ ods_alloc_init,
+ /* allocate_id */ ods_alloc_not_supported,
+ /* get_id_hwm */ ods_alloc_not_supported,
+ /* set_id_hwm */ ods_alloc_not_supported,
+ /* close */ ods_alloc_close
+};
+
+ NTSTATUS idmap_odsam_init(void)
+{
+ /* Use "odsam:traceall = yes" to turn on OD query tracing. */
+ 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;
+}
+