[patch] idmap backend = external

Matthew Mastracci matt at aclaro.com
Sat Apr 8 19:48:25 GMT 2006


I've been working on implementing a new idmap backend that would 
delegate all id-mapping work to an external script invoked for the 
various get_id_from_sid/allocate_XXX methods.

Why
===

I've been playing around with the smbldap scripts which manage 
posixAccount uids and gids internally, but winbind always wants to 
create new mappings under the Idmap container.  Rather than implement a 
custom backend to do what I wanted, I figured it would be better to open 
the door so that anyone with non-standard mapping needs (ie: non-samba 
managed uids/gids) could more easily implement their own methods.

I just tested this with our LDAP setup and it works perfectly with 
winbind running (all name<->uid/gid<->sid resolution was working perfectly).

The Patch
=========

This is my first Samba patch, so I tried to copy the style and structure 
from some of the other idmap backends.  I also use the enumports code in 
the server to figure out how to call external programs and get results back.

I'd like to submit this patch for review and possible inclusion in the 
next 3.0.x release.  I've looked over it for possible memory/file 
descriptor leaks and other fun errors, but it would be great if people 
more familiar with the codebase could check it over and make sure there 
aren't any fatal mistakes or leaks.

If this isn't something that the Samba team is interested in, I can 
always try to maintain it as an external module.

The Scripts
===========

Basically, this backend points at a script or executable and passes the 
name of the function (ie: "allocate_id" or "get_sid_from_id"), followed 
by each of the idmap function arguments.

The script is expected to either return 0 for success - translated to 
NT_STATUS_OK in the functions, or any other number for failure - 
translated to NT_STATUS_UNSUCCESSFUL.  For the functions that require 
the script to "do something", the script outputs the return values on 
stdout in the order that the function would be returning them.

NOTE: You must always return "0" from the init call otherwise the 
backend will fail to initialize!

I've also attached a basic script that does a naive uid/gid<->sid mapping.

Matt.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: idmap-example.sh
Type: application/x-shellscript
Size: 1082 bytes
Desc: not available
Url : http://lists.samba.org/archive/samba-technical/attachments/20060408/0aef46e4/idmap-example.bin
-------------- next part --------------
--- samba-orig/source/configure	2006-03-29 21:53:13.000000000 -0700
+++ samba-3.0.22/source/configure	2006-04-08 08:17:35.019836640 -0600
@@ -32033,7 +32033,7 @@
 _ACEOF
 
     CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED"
-    default_static_modules="$default_static_modules pdb_ldap idmap_ldap";
+    default_static_modules="$default_static_modules pdb_ldap idmap_ldap idmap_smbldap idmap_external";
     default_shared_modules="$default_shared_modules";
     SMBLDAP="lib/smbldap.o"
     SMBLDAPUTIL="lib/smbldap_util.o"
@@ -45538,6 +45538,7 @@
 MODULE_rpc_spoolss=STATIC
 MODULE_rpc_srv=STATIC
 MODULE_idmap_tdb=STATIC
+MODULE_idmap_external=STATIC
 
 
 # Check whether --with-static-modules or --without-static-modules was given.
@@ -46314,6 +46315,42 @@
 
 
 
+	echo "$as_me:$LINENO: checking how to build idmap_external" >&5
+echo $ECHO_N "checking how to build idmap_external... $ECHO_C" >&6
+	if test "$MODULE_idmap_external"; then
+		DEST=$MODULE_idmap_external
+	elif test "$MODULE_idmap" -a "$MODULE_DEFAULT_idmap_external"; then
+		DEST=$MODULE_idmap
+	else
+		DEST=$MODULE_DEFAULT_idmap_external
+	fi
+
+	if test x"$DEST" = xSHARED; then
+
+cat >>confdefs.h <<\_ACEOF
+#define idmap_external_init init_module
+_ACEOF
+
+		IDMAP_MODULES="$IDMAP_MODULES "bin/external.$SHLIBEXT""
+		echo "$as_me:$LINENO: result: shared" >&5
+echo "${ECHO_T}shared" >&6
+
+		string_shared_modules="$string_shared_modules idmap_external"
+	elif test x"$DEST" = xSTATIC; then
+		init_static_modules_idmap="$init_static_modules_idmap idmap_external_init();"
+		string_static_modules="$string_static_modules idmap_external"
+		IDMAP_STATIC="$IDMAP_STATIC sam/idmap_external.o"
+
+
+		echo "$as_me:$LINENO: result: static" >&5
+echo "${ECHO_T}static" >&6
+	else
+	    string_ignored_modules="$string_ignored_modules idmap_external"
+		echo "$as_me:$LINENO: result: not" >&5
+echo "${ECHO_T}not" >&6
+	fi
+
+
 	echo "$as_me:$LINENO: checking how to build idmap_ldap" >&5
 echo $ECHO_N "checking how to build idmap_ldap... $ECHO_C" >&6
 	if test "$MODULE_idmap_ldap"; then
diff -ur samba-orig/source/configure.in samba-3.0.22/source/configure.in
--- samba-orig/source/configure.in	2006-02-20 13:33:23.000000000 -0700
+++ samba-3.0.22/source/configure.in	2006-04-08 08:16:29.006872136 -0600
@@ -2852,7 +2852,7 @@
   if test x"$ac_cv_lib_ext_ldap_ldap_init" = x"yes"; then
     AC_DEFINE(HAVE_LDAP,1,[Whether ldap is available])
     CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED"
-    default_static_modules="$default_static_modules pdb_ldap idmap_ldap";
+    default_static_modules="$default_static_modules pdb_ldap idmap_ldap idmap_smbldap idmap_external";
     default_shared_modules="$default_shared_modules";
     SMBLDAP="lib/smbldap.o"
     SMBLDAPUTIL="lib/smbldap_util.o"
@@ -5108,6 +5108,7 @@
 MODULE_rpc_spoolss=STATIC
 MODULE_rpc_srv=STATIC
 MODULE_idmap_tdb=STATIC
+MODULE_idmap_external=STATIC
 
 AC_ARG_WITH(static-modules,
 [  --with-static-modules=MODULES  Comma-seperated list of names of modules to statically link in],
@@ -5163,6 +5164,7 @@
 SMB_MODULE(rpc_echo, \$(RPC_ECHO_OBJ), "bin/librpc_echo.$SHLIBEXT", RPC)
 SMB_SUBSYSTEM(RPC,smbd/server.o)
 
+SMB_MODULE(idmap_external, sam/idmap_external.o, "bin/external.$SHLIBEXT", IDMAP)
 SMB_MODULE(idmap_ldap, sam/idmap_ldap.o, "bin/ldap.$SHLIBEXT", IDMAP)
 SMB_MODULE(idmap_tdb, sam/idmap_tdb.o, "bin/tdb.$SHLIBEXT", IDMAP)
 SMB_MODULE(idmap_rid, sam/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
diff -ur samba-orig/source/include/config.h.in samba-3.0.22/source/include/config.h.in
--- samba-orig/source/include/config.h.in	2006-03-29 21:53:11.000000000 -0700
+++ samba-3.0.22/source/include/config.h.in	2006-04-08 08:17:31.134427312 -0600
@@ -2157,6 +2157,9 @@
 /* Whether to build idmap_ad as shared module */
 #undef idmap_ad_init
 
+/* Whether to build idmap_external as shared module */
+#undef idmap_external_init
+
 /* Whether to build idmap_ldap as shared module */
 #undef idmap_ldap_init
 
--- /dev/null	2005-04-07 12:00:38.604651250 -0400
+++ samba-3.0.22/source/sam/idmap_external.c	2006-04-09 15:03:59.000000000 -0400
@@ -0,0 +1,260 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   idmap external backend
+
+   Copyright (C) Matthew Mastracci 		2006
+
+   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"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+
+struct external_idmap_state {
+	pstring script;
+};
+
+static struct external_idmap_state external_state;
+
+/***********************************************************************
+ This function cannot be called to modify a mapping, only set a new one
+***********************************************************************/
+
+static NTSTATUS external_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
+{
+	pstring commandline;
+	int ret;
+
+	pstr_sprintf(commandline, "%s %s %ld %ld", 
+		external_state.script, "set_mapping", 
+		((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid),
+		id_type);
+	ret = smbrun(commandline, NULL);
+	if (ret != 0)
+		return NT_STATUS_UNSUCCESSFUL;
+
+	DEBUG(0, ("external_set_mapping: script returned %d\n", ret));
+
+	return NT_STATUS_OK;
+}
+
+/*****************************************************************************
+ Allocate a new RID
+*****************************************************************************/
+
+static NTSTATUS external_allocate_rid(uint32 *rid, int rid_type)
+{
+	pstring commandline;
+	int ret;
+	int numlines;
+        char **qlines;
+	int fd;
+
+	pstr_sprintf(commandline, "%s %s %ld", external_state.script, 
+		"allocate_rid", rid_type);
+
+	ret = smbrun(commandline, &fd);
+	DEBUG(0, ("external_allocate_rid: script returned %d\n", ret));
+        if (fd != -1) {
+		qlines = fd_lines_load(fd, &numlines);
+		DEBUG(0, ("external_allocate_rid: script output %d line(s)\n", numlines));
+		if (numlines == 1) {
+			*rid = atol(qlines[0]);
+		} 
+		else {
+			ret = -1;
+		}	
+
+		file_lines_free(qlines);
+		close(fd);
+	}
+
+	return (ret) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_OK;
+}
+
+/*****************************************************************************
+ Allocate a new uid or gid
+*****************************************************************************/
+
+static NTSTATUS external_allocate_id(unid_t *id, int id_type)
+{
+	pstring commandline;
+	int ret;
+	int numlines;
+        char **qlines;
+	int fd;
+
+	pstr_sprintf(commandline, "%s %s %ld %ld", 
+		external_state.script, "allocate_id", 
+		id_type);
+
+	ret = smbrun(commandline, &fd);
+	DEBUG(0, ("external_allocate_id: script returned %d\n", ret));
+        if (fd != -1) {
+		qlines = fd_lines_load(fd, &numlines);
+		DEBUG(0, ("external_allocate_id: script output %d line(s)\n", numlines));
+		if (numlines == 1) {
+			if (id_type & ID_USERID)
+				id->uid = atol(qlines[0]);
+			else
+				id->gid = atol(qlines[0]);
+		} 
+		else {
+			ret = -1;
+		}	
+
+		file_lines_free(qlines);
+		close(fd);
+	}
+
+	return (ret) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_OK;
+}
+
+/*****************************************************************************
+ get a sid from an id
+*****************************************************************************/
+
+static NTSTATUS external_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
+{
+	pstring commandline;
+	int ret;
+	int numlines;
+        char **qlines;
+	int fd;
+
+        pstr_sprintf(commandline, "%s %s %ld %ld", 
+		external_state.script, "get_sid_from_id",
+                ((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid),
+                id_type);
+
+	ret = smbrun(commandline, &fd);
+	DEBUG(0, ("external_get_sid_from_id: script returned %d\n", ret));
+        if (fd != -1) {
+		qlines = fd_lines_load(fd, &numlines);
+		DEBUG(0, ("external_get_sid_from_id: script output %d line(s)\n", numlines));
+		if (numlines == 1) {
+			if (!string_to_sid(sid, qlines[0])) {
+				DEBUG(0, ("external_get_sid_from_id: script returned invalid SID: %s\n", qlines[0]));
+				ret = -1;
+			}
+		} 
+		else {
+			ret = -1;
+		}	
+
+		file_lines_free(qlines);
+		close(fd);
+	}
+
+	return (ret) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_OK;
+}
+
+/***********************************************************************
+ Get an id from a sid 
+***********************************************************************/
+
+static NTSTATUS external_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
+{
+	pstring commandline;
+	int ret;
+	int numlines;
+        char **qlines;
+	int fd;
+	pstring sid_str;
+
+	sid_to_string(sid_str, sid);
+	pstr_sprintf(commandline, "%s %s %s", external_state.script, 
+		"get_id_from_sid", sid_str);
+
+	ret = smbrun(commandline, &fd);
+	DEBUG(0, ("external_get_id_from_sid: script returned %d\n", ret));
+        if (fd != -1) {
+		qlines = fd_lines_load(fd, &numlines);
+		DEBUG(0, ("external_get_id_from_sid: script output %d line(s)\n", numlines));
+		if (numlines == 2) {
+			*id_type = atoi(qlines[1]);
+			if (*id_type & ID_USERID)
+				id->uid = atol(qlines[0]);
+			else
+				id->gid = atol(qlines[0]);
+		} 
+		else {
+			ret = -1;
+		}	
+
+		file_lines_free(qlines);
+		close(fd);
+	}
+
+	return (ret) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_OK;
+}
+
+/*****************************************************************************
+ Initialise idmap database. 
+*****************************************************************************/
+
+static NTSTATUS external_idmap_init( char *params )
+{
+	pstring commandline;
+	int ret;
+
+	/* assume script is the only parameter */
+	pstr_sprintf(external_state.script, "%s", params);
+	
+	pstr_sprintf(commandline, "%s %s", external_state.script, "init");
+	ret = smbrun(commandline, NULL);
+	if (ret != 0)
+		return NT_STATUS_UNSUCCESSFUL;
+
+	DEBUG(0, ("external_idmap_init: script returned %d\n", ret));
+
+	return NT_STATUS_OK;
+}
+
+/*****************************************************************************
+ End the session
+*****************************************************************************/
+
+static NTSTATUS external_idmap_close(void)
+{
+	return NT_STATUS_OK;
+}
+
+
+static void external_idmap_status(void)
+{
+	DEBUG(0, ("External IDMAP Status not available\n"));
+}
+
+static struct idmap_methods external_methods = {
+	external_idmap_init,
+	external_allocate_rid,
+	external_allocate_id,
+	external_get_sid_from_id,
+	external_get_id_from_sid,
+	external_set_mapping,
+	external_idmap_close,
+	external_idmap_status
+};
+
+NTSTATUS idmap_external_init(void)
+{
+	return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "external", &external_methods);
+}




More information about the samba-technical mailing list