1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-10 01:18:15 +03:00

Add a script-only idmap module.

In this third 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. I have also added support for ID_TYPE_BOTH mappings and replaced
calls to popen with something safer. Also, I removed some non-PC macros.

Signed-off-by: Richard Sharpe <rsharpe@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>

Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Thu Jan  8 04:30:32 CET 2015 on sn-devel-104
This commit is contained in:
Richard Sharpe 2014-12-23 17:33:34 -08:00 committed by Jeremy Allison
parent a5d383cbd5
commit b817ce6d91
4 changed files with 567 additions and 0 deletions

View File

@ -0,0 +1,164 @@
<?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
IDTOSID XID xxxx
</programlisting>
<para>
And it should return one of the following responses as a single line of
text.
</para>
<programlisting>
UID:yyyy
GID:yyyy
XID:yyyy
SID:ssss
ERR:yyyy
</programlisting>
<para>
XID indicates that the ID returned should be both a UID and a GID.
That is, it requests an ID_TYPE_BOTH, but it is ultimately up to
the script whether or not it can honor that request. It can choose
to return a UID or a GID mapping only.
</para>
</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
# Note. The number returned has to be within the range defined
#echo "Sending UID:1000005" >> /tmp/idmap.sh.log
echo "UID:1000005"
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>

View File

@ -0,0 +1,394 @@
/*
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@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 accept the following command lines:
SIDTOID S-1-xxxx -> XID:<id> | ERR:<str>
SIDTOID S-1-xxxx -> UID:<id> | ERR:<str>
SIDTOID S-1-xxxx -> GID:<id> | ERR:<str>
IDTOSID XID xxxx -> SID:<sid> | ERR:<str>
IDTOSID UID xxxx -> SID:<sid> | ERR:<str>
IDTOSID GID xxxx -> SID:<sid> | ERR:<str>
where XID means both a UID and a GID. This is the case for ID_TYPE_BOTH.
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, **lines;
int numlines = 0;
unsigned long v;
cmd = talloc_asprintf(ctx, "%s ", ctx->script);
if (!cmd) {
DEBUG(10, ("Unable to allocate memory for the script command!\n"));
return NT_STATUS_NO_MEMORY;
}
va_start(ap, fmt);
cmd = talloc_vasprintf_append(cmd, fmt, ap);
va_end(ap);
if (!cmd) {
DEBUG(10, ("Unable to allocate memory for the script command!\n"));
return NT_STATUS_NO_MEMORY;
}
lines = file_lines_pload(cmd, &numlines);
talloc_free(cmd);
if (!lines) {
return NT_STATUS_NONE_MAPPED;
}
DEBUG(10,("idmap script gave %d lines, first: %s\n", numlines,
lines[0]));
if (sscanf(lines[0], "XID:%lu", &v) == 1) {
map->xid.id = v;
map->xid.type = ID_TYPE_BOTH;
} else if (sscanf(lines[0], "UID:%lu", &v) == 1) {
map->xid.id = v;
map->xid.type = ID_TYPE_UID;
} else if (sscanf(lines[0], "GID:%lu", &v) == 1) {
map->xid.id = v;
map->xid.type = ID_TYPE_GID;
} else if (strncmp(lines[0], "SID:S-", 6) == 0) {
if (!string_to_sid(map->sid, &lines[0][4])) {
DEBUG(0,("Bad SID in '%s' from idmap script %s\n",
lines[0], ctx->script));
talloc_free(lines);
return NT_STATUS_NONE_MAPPED;
}
} else {
DEBUG(0,("Bad reply '%s' from idmap script %s\n",
lines[0], ctx->script));
talloc_free(lines);
return NT_STATUS_NONE_MAPPED;
}
talloc_free(lines);
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;
case ID_TYPE_BOTH:
keystr = talloc_asprintf(ctx, "XID %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;
}
static 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;
}
static 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);
}

View File

@ -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'))

View File

@ -1578,6 +1578,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: