Patch: An updated version of my script idmapping backend for winbind.
Michael Adam
obnox at samba.org
Thu Nov 27 14:51:25 MST 2014
Hi Richard,
please apologize that I did not manage to follow up really.
I've been busy this week (still am) and will be more responsive
again from next week on. I will review and test your module.
Cheers - Michael
On 2014-11-27 at 10:32 -0800, Richard Sharpe wrote:
> Hi folks,
>
> Attached is an updated version that:
>
> 1. Cleans up some unused variables that only the Samba 3 build seemed to find,
> 2. Adds a man page.
>
> Review and push or feedback appreciated.
>
> --
> Regards,
> Richard Sharpe
> (何以解憂?唯有杜康。--曹操)
> From 3cb8258e259fb2f13c3c47d9114d844834b160f4 Mon Sep 17 00:00:00 2001
> From: Richard Sharpe <rsharpe at peaxy.net>
> Date: Tue, 18 Nov 2014 12:50:07 -0800
> Subject: [PATCH] Add a script-only idmap module.
>
> In this second version I have cleaned up some unused variable warnings that
> only the Samba 3 build found and added a man page based on the idmap_tdb2
> man page.
>
> Signed-off-by: Richard Sharpe <rsharpe at samba.org>
> ---
> docs-xml/manpages/idmap_script.8.xml | 154 ++++++++++++++
> source3/winbindd/idmap_script.c | 385 ++++++++++++++++++++++++++++++++++
> source3/winbindd/wscript_build | 8 +
> source3/wscript | 1 +
> 4 files changed, 548 insertions(+), 0 deletions(-)
> create mode 100644 docs-xml/manpages/idmap_script.8.xml
> create mode 100644 source3/winbindd/idmap_script.c
>
> diff --git a/docs-xml/manpages/idmap_script.8.xml b/docs-xml/manpages/idmap_script.8.xml
> new file mode 100644
> index 0000000..a86a149
> --- /dev/null
> +++ b/docs-xml/manpages/idmap_script.8.xml
> @@ -0,0 +1,154 @@
> +<?xml version="1.0" encoding="iso-8859-1"?>
> +<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
> +<refentry id="idmap_script.8">
> +
> +<refmeta>
> + <refentrytitle>idmap_script</refentrytitle>
> + <manvolnum>8</manvolnum>
> + <refmiscinfo class="source">Samba</refmiscinfo>
> + <refmiscinfo class="manual">System Administration tools</refmiscinfo>
> + <refmiscinfo class="version">4.2</refmiscinfo>
> +</refmeta>
> +
> +
> +<refnamediv>
> + <refname>idmap_tdb2</refname>
> + <refpurpose>Samba's idmap_script Backend for Winbind</refpurpose>
> +</refnamediv>
> +
> +<refsynopsisdiv>
> + <title>DESCRIPTION</title>
> +
> + <para>
> + The idmap_script plugin is a substitute for the idmap_tdb2
> + backend used by winbindd for storing SID/uid/gid mapping tables
> + in clustered environments with Samba and CTDB. It is a read only
> + backend that uses a script to perform mapping.
> + </para>
> +
> + <para>
> + It was developed out of the idmap_tdb2 back end and does not store
> + SID/uid/gid mappings in a TDB, since the winbind_cache tdb will
> + store the mappings once they are provided.
> + </para>
> +</refsynopsisdiv>
> +
> +<refsect1>
> + <title>IDMAP OPTIONS</title>
> +
> + <variablelist>
> + <varlistentry>
> + <term>range = low - high</term>
> + <listitem><para>
> + Defines the available matching uid and gid range for which the
> + backend is authoritative.
> + </para></listitem>
> + </varlistentry>
> +
> + <varlistentry>
> + <term>script</term>
> + <listitem><para>
> + This option can be used to configure an external program
> + for performing id mappings.
> + </para></listitem>
> + </varlistentry>
> + </variablelist>
> +</refsect1>
> +
> +<refsect1>
> + <title>IDMAP SCRIPT</title>
> +
> + <para>
> + The tdb2 idmap backend supports an external program for performing id mappings
> + through the smb.conf option <parameter>idmap config * : script</parameter> or
> + its deprecated legacy form <parameter>idmap : script</parameter>.
> + </para>
> +
> + <para>
> + The mappings obtained by the script are then stored in the idmap tdb2
> + database instead of mappings created by the incrementing id counters.
> + It is therefore important that the script covers the complete range of
> + SIDs that can be passed in for SID to Unix ID mapping, since otherwise
> + SIDs unmapped by the script might get mapped to IDs that had
> + previously been mapped by the script.
> + </para>
> +
> + <para>
> + The script should accept the following command line options.
> + </para>
> +
> + <programlisting>
> + SIDTOID S-1-xxxx
> + IDTOSID UID xxxx
> + IDTOSID GID xxxx
> + </programlisting>
> +
> + <para>
> + And it should return one of the following responses as a single line of
> + text.
> + </para>
> +
> + <programlisting>
> + UID:yyyy
> + GID:yyyy
> + SID:yyyy
> + ERR:yyyy
> + </programlisting>
> +</refsect1>
> +
> +<refsect1>
> + <title>EXAMPLES</title>
> +
> + <para>
> + This example shows how script is used as a the default idmap backend
> + using an external program via the script parameter:
> + </para>
> +
> + <programlisting>
> + [global]
> + idmap config * : backend = script
> + idmap config * : range = 1000000-2000000
> + idmap config * : script = /usr/local/samba/bin/idmap_script.sh
> + </programlisting>
> +
> + <para>
> + This shows a simple script to partially perform the task:
> + </para>
> +
> + <programlisting>
> + #!/bin/sh
> + #
> + # Uncomment this if you want some logging
> + #echo $@ >> /tmp/idmap.sh.log
> + if [ "$1" == "SIDTOID" ]
> + then
> + #echo "Sending UID:501" >> /tmp/idmap.sh.log
> + echo "UID:501"
> + exit 0
> + else
> + #echo "Sending ERR: No idea what to do" >> /tmp/idmap.sh.log
> + echo "ERR: No idea what to do"
> + exit 1
> + fi
> + </programlisting>
> +
> + <para>
> + Clearly, this script is not enough, as it should probably use wbinfo
> + to determine if an incoming SID is a user or group SID and then
> + look up the mapping in a table or use some other mechanism for
> + mapping SIDs to UIDs and etc.
> + </para>
> +</refsect1>
> +
> +<refsect1>
> + <title>AUTHOR</title>
> +
> + <para>
> + The original Samba software and related utilities
> + were created by Andrew Tridgell. Samba is now developed
> + by the Samba Team as an Open Source project similar
> + to the way the Linux kernel is developed.
> + </para>
> +</refsect1>
> +
> +</refentry>
> diff --git a/source3/winbindd/idmap_script.c b/source3/winbindd/idmap_script.c
> new file mode 100644
> index 0000000..8321f0b
> --- /dev/null
> +++ b/source3/winbindd/idmap_script.c
> @@ -0,0 +1,385 @@
> +/*
> + Unix SMB/CIFS implementation.
> +
> + idmap script backend, used for Samba setups where you need to map SIDs to
> + specific UIDs/GIDs.
> +
> + Copyright (C) Richard Sharpe 2014.
> +
> + This is heavily based upon idmap_tdb2.c, which is:
> +
> + Copyright (C) Tim Potter 2000
> + Copyright (C) Jim McDonough <jmcd at us.ibm.com> 2003
> + Copyright (C) Jeremy Allison 2006
> + Copyright (C) Simo Sorce 2003-2006
> + Copyright (C) Michael Adam 2009-2010
> +
> + 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 "system/filesys.h"
> +#include "winbindd.h"
> +#include "idmap.h"
> +#include "idmap_rw.h"
> +#include "../libcli/security/dom_sid.h"
> +
> +#undef DBGC_CLASS
> +#define DBGC_CLASS DBGC_IDMAP
> +
> +struct idmap_script_context {
> + const char *script; /* script to provide idmaps */
> +};
> +
> +/*
> + run a script to perform a mapping
> +
> + The script should the following command lines:
> +
> + SIDTOID S-1-xxxx
> + IDTOSID UID xxxx
> + IDTOSID GID xxxx
> +
> + and should return one of the following as a single line of text
> + UID:xxxx
> + GID:xxxx
> + SID:xxxx
> + ERR:xxxx
> +
> + TODO: Needs more validation ... like that we got a UID when we asked for one.
> + */
> +static NTSTATUS idmap_script_script(struct idmap_script_context *ctx,
> + struct id_map *map, const char *fmt, ...)
> +{
> + va_list ap;
> + char *cmd;
> + FILE *p;
> + char line[64];
> + unsigned long v;
> +
> + cmd = talloc_asprintf(ctx, "%s ", ctx->script);
> + NT_STATUS_HAVE_NO_MEMORY(cmd);
> +
> + va_start(ap, fmt);
> + cmd = talloc_vasprintf_append(cmd, fmt, ap);
> + va_end(ap);
> + NT_STATUS_HAVE_NO_MEMORY(cmd);
> +
> + p = popen(cmd, "r");
> + talloc_free(cmd);
> + if (p == NULL) {
> + return NT_STATUS_NONE_MAPPED;
> + }
> +
> + if (fgets(line, sizeof(line)-1, p) == NULL) {
> + pclose(p);
> + return NT_STATUS_NONE_MAPPED;
> + }
> + pclose(p);
> +
> + DEBUG(10,("idmap script gave: %s\n", line));
> +
> + if (sscanf(line, "UID:%lu", &v) == 1) {
> + map->xid.id = v;
> + map->xid.type = ID_TYPE_UID;
> + } else if (sscanf(line, "GID:%lu", &v) == 1) {
> + map->xid.id = v;
> + map->xid.type = ID_TYPE_GID;
> + } else if (strncmp(line, "SID:S-", 6) == 0) {
> + if (!string_to_sid(map->sid, &line[4])) {
> + DEBUG(0,("Bad SID in '%s' from idmap script %s\n",
> + line, ctx->script));
> + return NT_STATUS_NONE_MAPPED;
> + }
> + } else {
> + DEBUG(0,("Bad reply '%s' from idmap script %s\n",
> + line, ctx->script));
> + return NT_STATUS_NONE_MAPPED;
> + }
> +
> + return NT_STATUS_OK;
> +}
> +
> +/*
> + Single id to sid lookup function.
> +*/
> +static NTSTATUS idmap_script_id_to_sid(struct idmap_domain *dom,
> + struct id_map *map)
> +{
> + NTSTATUS ret;
> + char *keystr;
> + char *sidstr;
> + struct idmap_script_context *ctx = dom->private_data;
> +
> + if (!dom || !map) {
> + return NT_STATUS_INVALID_PARAMETER;
> + }
> +
> + /* apply filters before checking */
> + if (!idmap_unix_id_is_in_range(map->xid.id, dom)) {
> + DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
> + map->xid.id, dom->low_id, dom->high_id));
> + return NT_STATUS_NONE_MAPPED;
> + }
> +
> + switch (map->xid.type) {
> +
> + case ID_TYPE_UID:
> + keystr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
> + break;
> +
> + case ID_TYPE_GID:
> + keystr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
> + break;
> +
> + default:
> + DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
> + return NT_STATUS_INVALID_PARAMETER;
> + }
> +
> + if (keystr == NULL) {
> + DEBUG(0, ("Out of memory!\n"));
> + ret = NT_STATUS_NO_MEMORY;
> + goto done;
> + }
> +
> + DEBUG(10,("Running script to fetch mapping %s\n", keystr));
> +
> + ret = idmap_script_script(ctx, map, "IDTOSID %s", keystr);
> + if (!NT_STATUS_IS_OK(ret)) {
> + goto done;
> + }
> +
> + sidstr = sid_string_talloc(keystr, map->sid);
> + if (!sidstr) {
> + ret = NT_STATUS_NO_MEMORY;
> + goto done;
> + }
> +
> + DEBUG(10,("Found id %s:%d -> %s\n", keystr, map->xid.id,
> + (const char *)sidstr));
> + ret = NT_STATUS_OK;
> +
> +done:
> + talloc_free(keystr);
> + return ret;
> +}
> +
> +/*
> + Single sid to id lookup function.
> +*/
> +static NTSTATUS idmap_script_sid_to_id(struct idmap_domain *dom,
> + struct id_map *map)
> +{
> + NTSTATUS ret;
> + char *keystr;
> + struct idmap_script_context *ctx = dom->private_data;
> + TALLOC_CTX *tmp_ctx = talloc_stackframe();
> +
> + keystr = sid_string_talloc(tmp_ctx, map->sid);
> + if (keystr == NULL) {
> + DEBUG(0, ("Out of memory!\n"));
> + ret = NT_STATUS_NO_MEMORY;
> + goto done;
> + }
> +
> + DEBUG(10,("Fetching record %s\n", keystr));
> +
> + if (ctx->script == NULL) {
> + ret = NT_STATUS_NONE_MAPPED;
> + goto done;
> + }
> +
> + ret = idmap_script_script(ctx, map, "SIDTOID %s", keystr);
> + if (!NT_STATUS_IS_OK(ret)) {
> + goto done;
> + }
> +
> + /* apply filters before returning result */
> + if (!idmap_unix_id_is_in_range(map->xid.id, dom)) {
> + DEBUG(5, ("Script returned id (%u) out of range (%u - %u)."
> + " Filtered!\n",
> + map->xid.id, dom->low_id, dom->high_id));
> + ret = NT_STATUS_NONE_MAPPED;
> + goto done;
> + }
> +
> +done:
> + talloc_free(tmp_ctx);
> + return ret;
> +}
> +
> +NTSTATUS idmap_script_unixids_to_sids(struct idmap_domain *dom,
> + struct id_map **ids)
> +{
> + NTSTATUS ret;
> + int i, num_mapped = 0;
> +
> + DEBUG(10, ("%s called ...\n", __func__));
> + /* Init status to avoid surprise ... */
> + for (i = 0; ids[i]; i++) {
> + ids[i]->status = ID_UNKNOWN;
> + }
> +
> + for (i = 0; ids[i]; i++) {
> + ret = idmap_script_id_to_sid(dom, ids[i]);
> + if (!NT_STATUS_IS_OK(ret)) {
> + if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
> + ids[i]->status = ID_UNMAPPED;
> + continue;
> + }
> +
> + /*
> + * We cannot keep going if it is other than mapping
> + * failed.
> + */
> + goto done;
> + }
> +
> + ids[i]->status = ID_MAPPED;
> + num_mapped++;
> + }
> +
> + ret = NT_STATUS_OK;
> +
> +done:
> + if (NT_STATUS_IS_OK(ret)) {
> + if (i == 0 || num_mapped == 0) {
> + ret = NT_STATUS_NONE_MAPPED;
> + }
> + else if (num_mapped < i) {
> + ret = STATUS_SOME_UNMAPPED;
> + } else {
> + DEBUG(10, ("Returning NT_STATUS_OK\n"));
> + ret = NT_STATUS_OK;
> + }
> + }
> +
> + return ret;
> +}
> +
> +NTSTATUS idmap_script_sids_to_unixids(struct idmap_domain *dom,
> + struct id_map **ids)
> +{
> + NTSTATUS ret;
> + int i, num_mapped = 0;
> +
> + DEBUG(10, ("%s called ...\n", __func__));
> + /* Init status to avoid surprise ... */
> + for (i = 0; ids[i]; i++) {
> + ids[i]->status = ID_UNKNOWN;
> + }
> +
> + for (i = 0; ids[i]; i++) {
> + ret = idmap_script_sid_to_id(dom, ids[i]);
> + if (!NT_STATUS_IS_OK(ret)) {
> + if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
> + ids[i]->status = ID_UNMAPPED;
> + continue;
> + }
> +
> + /*
> + * We cannot keep going if it is other than mapping
> + * failed.
> + */
> + goto done;
> + }
> +
> + ids[i]->status = ID_MAPPED;
> + num_mapped++;
> + }
> +
> + ret = NT_STATUS_OK;
> +
> +done:
> + if (NT_STATUS_IS_OK(ret)) {
> + if (i == 0 || num_mapped == 0) {
> + ret = NT_STATUS_NONE_MAPPED;
> + }
> + else if (num_mapped < i) {
> + ret = STATUS_SOME_UNMAPPED;
> + } else {
> + DEBUG(10, ("Returning NT_STATUS_OK\n"));
> + ret = NT_STATUS_OK;
> + }
> + }
> +
> + return ret;
> +}
> +
> +/*
> + * Initialise idmap_script database.
> + */
> +static NTSTATUS idmap_script_db_init(struct idmap_domain *dom)
> +{
> + NTSTATUS ret;
> + struct idmap_script_context *ctx;
> + char *config_option = NULL;
> + const char * idmap_script = NULL;
> +
> + DEBUG(10, ("%s called ...\n", __func__));
> +
> + ctx = talloc_zero(dom, struct idmap_script_context);
> + if (!ctx) {
> + DEBUG(0, ("Out of memory!\n"));
> + ret = NT_STATUS_NO_MEMORY;
> + goto failed;
> + }
> +
> + config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
> + if (config_option == NULL) {
> + DEBUG(0, ("Out of memory!\n"));
> + ret = NT_STATUS_NO_MEMORY;
> + goto failed;
> + }
> + ctx->script = lp_parm_const_string(-1, config_option, "script", NULL);
> + talloc_free(config_option);
> +
> + /* Do we even need to handle this? */
> + idmap_script = lp_parm_const_string(-1, "idmap", "script", NULL);
> + if (idmap_script != NULL) {
> + DEBUG(0, ("Warning: 'idmap:script' is deprecated. "
> + " Please use 'idmap config * : script' instead!\n"));
> + }
> +
> + if (strequal(dom->name, "*") && ctx->script == NULL) {
> + /* fall back to idmap:script for backwards compatibility */
> + ctx->script = idmap_script;
> + }
> +
> + if (ctx->script) {
> + DEBUG(1, ("using idmap script '%s'\n", ctx->script));
> + }
> +
> + dom->private_data = ctx;
> + dom->read_only = true; /* We do not allocate!*/
> +
> + return NT_STATUS_OK;
> +
> +failed:
> + talloc_free(ctx);
> + return ret;
> +}
> +
> +static struct idmap_methods db_methods = {
> + .init = idmap_script_db_init,
> + .unixids_to_sids = idmap_script_unixids_to_sids,
> + .sids_to_unixids = idmap_script_sids_to_unixids,
> +};
> +
> +NTSTATUS idmap_script_init(void)
> +{
> + return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "script", &db_methods);
> +}
> diff --git a/source3/winbindd/wscript_build b/source3/winbindd/wscript_build
> index ea1131c..6675c16 100644
> --- a/source3/winbindd/wscript_build
> +++ b/source3/winbindd/wscript_build
> @@ -160,3 +160,11 @@ bld.SAMBA3_MODULE('nss_info_sfu',
> init_function='',
> internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_ad'),
> enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad') and bld.CONFIG_SET("HAVE_LDAP"))
> +
> +bld.SAMBA3_MODULE('idmap_script',
> + subsystem='idmap',
> + allow_undefined_symbols=True,
> + source='idmap_script.c',
> + init_function='',
> + internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_script'),
> + enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_script'))
> diff --git a/source3/wscript b/source3/wscript
> index f61c049..d805057 100644
> --- a/source3/wscript
> +++ b/source3/wscript
> @@ -1577,6 +1577,7 @@ main() {
> vfs_crossrename vfs_linux_xfs_sgid
> vfs_time_audit idmap_autorid idmap_tdb2
> idmap_ad
> + idmap_script
> idmap_rid idmap_hash idmap_rfc2307'''))
>
> if Options.options.developer:
> --
> 1.7.1
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20141127/56352fe0/attachment.pgp>
More information about the samba-technical
mailing list