idmap-module-open-directory [plain text]
Index: samba/source/Makefile.in
===================================================================
--- samba/source/Makefile.in.orig
+++ samba/source/Makefile.in
@@ -456,6 +456,7 @@ AUTH_OBJ = auth/auth.o @AUTH_STATIC@ aut
ODSAM_PDB_OBJ = lib/opendirectory.o lib/opendirectory_sam.o passdb/pdb_odsam.o
ODSAM_AUTH_OBJ = lib/opendirectory.o lib/opendirectory_sam.o auth/auth_odsam.o
+ODSAM_IDMAP_OBJ = lib/opendirectory.o lib/opendirectory_sam.o nsswitch/idmap_odsam.o
MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o
@@ -1352,6 +1353,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
@@ -6227,6 +6227,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,353 @@
+/*
+ Unix SMB/CIFS implementation.
+ ID mapping Open Directory Server backend
+
+ Copyright (c) 2007-2009 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;
+
+/* 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;
+
+ 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 /* base */);
+ 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;
+ }
+
+ /* This is bad. Samba and DirectoryService disagree on what type of
+ * record the SID refers to. Something is messed up ...
+ */
+ 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;
+}
+
+/* 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;
+
+ 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) {
+ /* 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) {
+ 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) {
+ /* XXX should be mapping DS to NT errors */
+ 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 = {
+ /* 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;
+}
+