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:
parent
a5d383cbd5
commit
b817ce6d91
164
docs-xml/manpages/idmap_script.8.xml
Normal file
164
docs-xml/manpages/idmap_script.8.xml
Normal 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>
|
394
source3/winbindd/idmap_script.c
Normal file
394
source3/winbindd/idmap_script.c
Normal 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);
|
||||
}
|
@ -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'))
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user