1
0
mirror of https://github.com/samba-team/samba.git synced 2025-07-27 07:42:04 +03:00

Remove ad2oLschema, insted call it directly from provision-backend

This removes a level of indirection via external binaries in the
provision-backend code, and also makes better use of our internal code
for loading schema from an LDIF file.

Remaining to do: Sort the output again, as the load from LDIF is
unsorted (also needed because the normal LDB load from sorted input is too slow
anyway, and is only needed here).

Andrew Bartlett
This commit is contained in:
Andrew Bartlett
2009-03-05 16:52:11 +11:00
parent 41760c18bd
commit 17aac8cad2
7 changed files with 113 additions and 225 deletions

View File

@ -37,7 +37,8 @@ SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \
schema_set.o \ schema_set.o \
schema_query.o \ schema_query.o \
schema_syntax.o \ schema_syntax.o \
schema_description.o) schema_description.o \
schema_convert_to_ol.o)
$(eval $(call proto_header_template,$(dsdbsrcdir)/schema/proto.h,$(SAMDB_SCHEMA_OBJ_FILES:.o=.c))) $(eval $(call proto_header_template,$(dsdbsrcdir)/schema/proto.h,$(SAMDB_SCHEMA_OBJ_FILES:.o=.c)))
# PUBLIC_HEADERS += dsdb/schema/schema.h # PUBLIC_HEADERS += dsdb/schema/schema.h

View File

@ -1,124 +1,50 @@
/* /*
ldb database library schema conversion routines
Copyright (C) Andrew Bartlett 2006-2008 Copyright (C) Andrew Bartlett 2006-2008
** NOTE! The following LGPL license applies to the ldb This program is free software; you can redistribute it and/or modify
** library. This does NOT imply that all of Samba is released it under the terms of the GNU General Public License as published by
** under the LGPL the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This library is free software; you can redistribute it and/or This program is distributed in the hope that it will be useful,
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser General Public License for more details. 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, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
/*
* Name: ldb
*
* Component: ad2oLschema
*
* Description: utility to convert an AD schema into the format required by OpenLDAP
*
* Author: Andrew Bartlett
*/
#include "includes.h" #include "includes.h"
#include "ldb.h" #include "ldb.h"
#include "system/locale.h"
#include "lib/ldb/tools/cmdline.h"
#include "param/param.h"
#include "lib/cmdline/popt_common.h"
#include "dsdb/samdb/samdb.h" #include "dsdb/samdb/samdb.h"
#include "system/locale.h"
struct schema_conv { /* Routine to linearise our internal schema into the format that
int count; OpenLDAP and Fedora DS use for their backend.
int skipped;
int failures; The 'mappings' are of a format like:
};
#Standard OpenLDAP attributes
labeledURI
#The memberOf plugin provides this attribute
memberOf
#These conflict with OpenLDAP builtins
attributeTypes:samba4AttributeTypes
2.5.21.5:1.3.6.1.4.1.7165.4.255.7
*/
static void usage(void) char *dsdb_convert_schema_to_openldap(struct ldb_context *ldb, char *target_str, const char *mappings)
{
printf("Usage: ad2oLschema <options>\n");
printf("\nConvert AD-like LDIF to OpenLDAP schema format\n\n");
printf("Options:\n");
printf(" -I inputfile inputfile of mapped OIDs and skipped attributes/ObjectClasses");
printf(" -H url LDB or LDAP server to read schmea from\n");
printf(" -O outputfile outputfile otherwise STDOUT\n");
printf(" -o options pass options like modules to activate\n");
printf(" e.g: -o modules:timestamps\n");
printf("\n");
printf("Converts records from an AD-like LDIF schema into an openLdap formatted schema\n\n");
exit(1);
}
static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
{
const char *rootdse_attrs[] = {"schemaNamingContext", NULL};
struct ldb_dn *schemadn;
struct ldb_dn *basedn = ldb_dn_new(mem_ctx, ldb, NULL);
struct ldb_result *rootdse_res;
struct ldb_result *schema_res;
int ldb_ret;
if (!basedn) {
return NULL;
}
/* Search for rootdse */
ldb_ret = ldb_search(ldb, mem_ctx, &rootdse_res,
basedn, LDB_SCOPE_BASE, rootdse_attrs, NULL);
if (ldb_ret != LDB_SUCCESS) {
ldb_ret = ldb_search(ldb, mem_ctx, &schema_res, basedn, LDB_SCOPE_SUBTREE,
NULL, "(&(objectClass=dMD)(cn=Schema))");
if (ldb_ret) {
printf("cn=Schema Search failed: %s\n", ldb_errstring(ldb));
return NULL;
}
if (schema_res->count != 1) {
talloc_free(schema_res);
printf("Failed to find rootDSE");
return NULL;
}
schemadn = talloc_steal(mem_ctx, schema_res->msgs[0]->dn);
talloc_free(schema_res);
return schemadn;
}
if (rootdse_res->count != 1) {
printf("Failed to find rootDSE");
talloc_free(rootdse_res);
return NULL;
}
/* Locate schema */
schemadn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
talloc_free(rootdse_res);
if (!schemadn) {
return NULL;
}
return schemadn;
}
static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_schema_convert_target target, FILE *in, FILE *out)
{ {
/* Read list of attributes to skip, OIDs to map */ /* Read list of attributes to skip, OIDs to map */
TALLOC_CTX *mem_ctx = talloc_new(ldb); TALLOC_CTX *mem_ctx = talloc_new(ldb);
char *line; char *line;
char *out;
const char **attrs_skip = NULL; const char **attrs_skip = NULL;
int num_skip = 0; int num_skip = 0;
struct oid_map { struct oid_map {
@ -133,19 +59,31 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_sch
int num_attr_maps = 0; int num_attr_maps = 0;
struct dsdb_class *objectclass; struct dsdb_class *objectclass;
struct dsdb_attribute *attribute; struct dsdb_attribute *attribute;
struct ldb_dn *schemadn;
struct schema_conv ret;
struct dsdb_schema *schema; struct dsdb_schema *schema;
const char *seperator; const char *seperator;
char *error_string; enum dsdb_schema_convert_target target;
int ldb_ret; char *next_line = talloc_strdup(mem_ctx, mappings);
ret.count = 0; if (!target_str || strcasecmp(target_str, "openldap") == 0) {
ret.skipped = 0; target = TARGET_OPENLDAP;
ret.failures = 0; } else if (strcasecmp(target_str, "fedora-ds") == 0) {
target = TARGET_FEDORA_DS;
} else {
DEBUG(0, ("Invalid target type for schema conversion %s\n", target_str));
return NULL;
}
/* The mappings are line-seperated, and specify details such as OIDs to skip etc */
while (1) {
line = next_line;
next_line = strchr(line, '\n');
if (!next_line) {
break;
}
next_line[0] = '\0';
next_line++;
while ((line = afdgets(fileno(in), mem_ctx, 0))) {
/* Blank Line */ /* Blank Line */
if (line[0] == '\0') { if (line[0] == '\0') {
continue; continue;
@ -154,17 +92,18 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_sch
if (line[0] == '#') { if (line[0] == '#') {
continue; continue;
} }
if (isdigit(line[0])) { if (isdigit(line[0])) {
char *p = strchr(line, ':'); char *p = strchr(line, ':');
if (!p) { if (!p) {
ret.failures++; DEBUG(0, ("schema mapping file line has OID but no OID to map to: %s\n", line));
return ret; return NULL;
} }
p[0] = '\0'; p[0] = '\0';
p++; p++;
oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2); oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
trim_string(line, " ", " "); trim_string(line, " ", " ");
oid_map[num_oid_maps].old_oid = talloc_move(oid_map, &line); oid_map[num_oid_maps].old_oid = talloc_strdup(oid_map, line);
trim_string(p, " ", " "); trim_string(p, " ", " ");
oid_map[num_oid_maps].new_oid = p; oid_map[num_oid_maps].new_oid = p;
num_oid_maps++; num_oid_maps++;
@ -177,7 +116,7 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_sch
p++; p++;
attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2); attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2);
trim_string(line, " ", " "); trim_string(line, " ", " ");
attr_map[num_attr_maps].old_attr = talloc_move(attr_map, &line); attr_map[num_attr_maps].old_attr = talloc_strdup(attr_map, line);
trim_string(p, " ", " "); trim_string(p, " ", " ");
attr_map[num_attr_maps].new_attr = p; attr_map[num_attr_maps].new_attr = p;
num_attr_maps++; num_attr_maps++;
@ -186,36 +125,26 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_sch
/* skip attribute/objectClass */ /* skip attribute/objectClass */
attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2); attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
trim_string(line, " ", " "); trim_string(line, " ", " ");
attrs_skip[num_skip] = talloc_move(attrs_skip, &line); attrs_skip[num_skip] = talloc_strdup(attrs_skip, line);
num_skip++; num_skip++;
attrs_skip[num_skip] = NULL; attrs_skip[num_skip] = NULL;
} }
} }
} }
schemadn = find_schema_dn(ldb, mem_ctx); schema = dsdb_get_schema(ldb);
if (!schemadn) { if (!schema) {
printf("Failed to find schema DN: %s\n", ldb_errstring(ldb)); DEBUG(0, ("No schema on ldb to convert!\n"));
ret.failures = 1; return NULL;
return ret;
} }
ldb_ret = dsdb_schema_from_schema_dn(mem_ctx, ldb,
lp_iconv_convenience(cmdline_lp_ctx),
schemadn, &schema, &error_string);
if (ldb_ret != LDB_SUCCESS) {
printf("Failed to load schema: %s\n", error_string);
ret.failures = 1;
return ret;
}
switch (target) { switch (target) {
case TARGET_OPENLDAP: case TARGET_OPENLDAP:
seperator = "\n "; seperator = "\n ";
out = talloc_strdup(mem_ctx, "");
break; break;
case TARGET_FEDORA_DS: case TARGET_FEDORA_DS:
seperator = "\n "; seperator = "\n ";
fprintf(out, "dn: cn=schema\n"); out = talloc_strdup(mem_ctx, "dn: cn=schema\n");
break; break;
} }
@ -231,7 +160,6 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_sch
/* We have been asked to skip some attributes/objectClasses */ /* We have been asked to skip some attributes/objectClasses */
if (attrs_skip && str_list_check_ci(attrs_skip, name)) { if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
ret.skipped++;
continue; continue;
} }
@ -283,19 +211,18 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_sch
false, false); false, false);
if (schema_entry == NULL) { if (schema_entry == NULL) {
ret.failures++; DEBUG(0, ("failed to generate attribute description for %s\n", name));
return ret; return NULL;
} }
switch (target) { switch (target) {
case TARGET_OPENLDAP: case TARGET_OPENLDAP:
fprintf(out, "attributetype %s\n\n", schema_entry); out = talloc_asprintf_append(out, "attributetype %s\n\n", schema_entry);
break; break;
case TARGET_FEDORA_DS: case TARGET_FEDORA_DS:
fprintf(out, "attributeTypes: %s\n", schema_entry); out = talloc_asprintf_append(out, "attributeTypes: %s\n", schema_entry);
break; break;
} }
ret.count++;
} }
/* This is already sorted to have 'top' and similar classes first */ /* This is already sorted to have 'top' and similar classes first */
@ -316,7 +243,6 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_sch
/* We have been asked to skip some attributes/objectClasses */ /* We have been asked to skip some attributes/objectClasses */
if (attrs_skip && str_list_check_ci(attrs_skip, name)) { if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
ret.skipped++;
continue; continue;
} }
@ -371,72 +297,20 @@ static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_sch
may, may,
NULL); NULL);
if (schema_entry == NULL) { if (schema_entry == NULL) {
ret.failures++; DEBUG(0, ("failed to generate schema description for %s\n", name));
return ret; return NULL;
} }
switch (target) { switch (target) {
case TARGET_OPENLDAP: case TARGET_OPENLDAP:
fprintf(out, "objectclass %s\n\n", schema_entry); out = talloc_asprintf_append(out, "objectclass %s\n\n", schema_entry);
break; break;
case TARGET_FEDORA_DS: case TARGET_FEDORA_DS:
fprintf(out, "objectClasses: %s\n", schema_entry); out = talloc_asprintf_append(out, "objectClasses: %s\n", schema_entry);
break; break;
} }
ret.count++;
} }
return ret; return out;
} }
int main(int argc, const char **argv)
{
TALLOC_CTX *ctx;
struct ldb_cmdline *options;
FILE *in = stdin;
FILE *out = stdout;
struct ldb_context *ldb;
struct schema_conv ret;
const char *target_str;
enum dsdb_schema_convert_target target;
ctx = talloc_new(NULL);
ldb = ldb_init(ctx, NULL);
options = ldb_cmdline_process(ldb, argc, argv, usage);
if (options->input) {
in = fopen(options->input, "r");
if (!in) {
perror(options->input);
exit(1);
}
}
if (options->output) {
out = fopen(options->output, "w");
if (!out) {
perror(options->output);
exit(1);
}
}
target_str = lp_parm_string(cmdline_lp_ctx, NULL, "convert", "target");
if (!target_str || strcasecmp(target_str, "openldap") == 0) {
target = TARGET_OPENLDAP;
} else if (strcasecmp(target_str, "fedora-ds") == 0) {
target = TARGET_FEDORA_DS;
} else {
printf("Unsupported target: %s\n", target_str);
exit(1);
}
ret = process_convert(ldb, target, in, out);
fclose(in);
fclose(out);
printf("Converted %d records (skipped %d) with %d failures\n", ret.count, ret.skipped, ret.failures);
return 0;
}

View File

@ -277,7 +277,7 @@ void dsdb_make_schema_global(struct ldb_context *ldb)
* schema itself to the directory. * schema itself to the directory.
*/ */
WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df) WERROR dsdb_attach_schema_from_ldif(struct ldb_context *ldb, const char *pf, const char *df)
{ {
struct ldb_ldif *ldif; struct ldb_ldif *ldif;
struct ldb_message *msg; struct ldb_message *msg;

View File

@ -212,7 +212,7 @@ static PyObject *py_dsdb_set_global_schema(PyObject *self, PyObject *args)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject *py_dsdb_attach_schema_from_ldif_file(PyObject *self, PyObject *args) static PyObject *py_dsdb_attach_schema_from_ldif(PyObject *self, PyObject *args)
{ {
WERROR result; WERROR result;
char *pf, *df; char *pf, *df;
@ -224,12 +224,35 @@ static PyObject *py_dsdb_attach_schema_from_ldif_file(PyObject *self, PyObject *
PyErr_LDB_OR_RAISE(py_ldb, ldb); PyErr_LDB_OR_RAISE(py_ldb, ldb);
result = dsdb_attach_schema_from_ldif_file(ldb, pf, df); result = dsdb_attach_schema_from_ldif(ldb, pf, df);
PyErr_WERROR_IS_ERR_RAISE(result); PyErr_WERROR_IS_ERR_RAISE(result);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject *py_dsdb_convert_schema_to_openldap(PyObject *self, PyObject *args)
{
char *target_str, *mapping;
PyObject *py_ldb;
struct ldb_context *ldb;
PyObject *ret;
char *retstr;
if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &target_str, &mapping))
return NULL;
PyErr_LDB_OR_RAISE(py_ldb, ldb);
retstr = dsdb_convert_schema_to_openldap(ldb, target_str, mapping);
if (!retstr) {
PyErr_SetString(PyExc_RuntimeError, "dsdb_convert_schema_to_openldap failed");
return NULL;
}
ret = PyString_FromString(retstr);
talloc_free(retstr);
return ret;
}
static PyMethodDef py_misc_methods[] = { static PyMethodDef py_misc_methods[] = {
{ "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS, { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
"random_password(len) -> string\n" "random_password(len) -> string\n"
@ -255,7 +278,9 @@ static PyMethodDef py_misc_methods[] = {
NULL }, NULL },
{ "dsdb_set_global_schema", (PyCFunction)py_dsdb_set_global_schema, METH_VARARGS, { "dsdb_set_global_schema", (PyCFunction)py_dsdb_set_global_schema, METH_VARARGS,
NULL }, NULL },
{ "dsdb_attach_schema_from_ldif_file", (PyCFunction)py_dsdb_attach_schema_from_ldif_file, METH_VARARGS, { "dsdb_attach_schema_from_ldif", (PyCFunction)py_dsdb_attach_schema_from_ldif, METH_VARARGS,
NULL },
{ "dsdb_convert_schema_to_openldap", (PyCFunction)py_dsdb_convert_schema_to_openldap, METH_VARARGS,
NULL }, NULL },
{ NULL } { NULL }
}; };

View File

@ -1245,7 +1245,7 @@ def provision_backend(setup_dir=None, message=None,
except OSError: except OSError:
pass pass
schemadb = Ldb(schemadb_path, lp=lp) schemadb = SamDB(schemadb_path, lp=lp)
prefixmap = open(setup_path("prefixMap.txt"), 'r').read() prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
@ -1263,10 +1263,8 @@ def provision_backend(setup_dir=None, message=None,
"PREFIXMAP_B64": b64encode(prefixmap) "PREFIXMAP_B64": b64encode(prefixmap)
}) })
setup_add_ldif(schemadb, setup_path("schema_samba4.ldif"), data = load_schema(setup_path, schemadb, names.schemadn, names.netbiosname,
{"SCHEMADN": names.schemadn }) names.configdn, DEFAULTSITE, names.serverdn)
data = get_schema_data(setup_path, {"SCHEMADN": names.schemadn})
schemadb.add_ldif(data) schemadb.add_ldif(data)
if ldap_backend_type == "fedora-ds": if ldap_backend_type == "fedora-ds":
@ -1481,9 +1479,9 @@ def provision_backend(setup_dir=None, message=None,
ldapuser = "--username=samba-admin" ldapuser = "--username=samba-admin"
schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema) backend_schema_data = schemadb.convert_schema_to_openldap(ldap_backend_type, open(setup_path(mapping), 'r').read())
assert backend_schema_data is not None
os.system(schema_command) open(os.path.join(paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type) message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type)
message("Server Role: %s" % serverrole) message("Server Role: %s" % serverrole)
@ -1646,7 +1644,7 @@ def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename, def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename,
serverdn, servername): serverdn):
"""Load schema for the SamDB. """Load schema for the SamDB.
:param samdb: Load a schema into a SamDB. :param samdb: Load a schema into a SamDB.
@ -1655,7 +1653,6 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename,
:param netbiosname: NetBIOS name of the host. :param netbiosname: NetBIOS name of the host.
:param configdn: DN of the configuration :param configdn: DN of the configuration
:param serverdn: DN of the server :param serverdn: DN of the server
:param servername: Host name of the server
Returns the schema data loaded, to avoid double-parsing when then needing to add it to the db Returns the schema data loaded, to avoid double-parsing when then needing to add it to the db
""" """
@ -1674,7 +1671,6 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename,
"DEFAULTSITE": sitename, "DEFAULTSITE": sitename,
"PREFIXMAP_B64": prefixmap, "PREFIXMAP_B64": prefixmap,
"SERVERDN": serverdn, "SERVERDN": serverdn,
"SERVERNAME": servername,
}) })
check_all_substituted(head_data) check_all_substituted(head_data)
samdb.attach_schema_from_ldif(head_data, schema_data) samdb.attach_schema_from_ldif(head_data, schema_data)
@ -1685,6 +1681,8 @@ def get_schema_data(setup_path, subst_vars = None):
:param setup_path: Setup path function. :param setup_path: Setup path function.
:param subst_vars: Optional variables to substitute in the file. :param subst_vars: Optional variables to substitute in the file.
Returns the schema data after substitution
""" """
# this data used to be read from schema.ldif # this data used to be read from schema.ldif

View File

@ -198,7 +198,10 @@ userAccountControl: %u
glue.samdb_set_domain_sid(self, sid) glue.samdb_set_domain_sid(self, sid)
def attach_schema_from_ldif(self, pf, df): def attach_schema_from_ldif(self, pf, df):
glue.dsdb_attach_schema_from_ldif_file(self, pf, df) glue.dsdb_attach_schema_from_ldif(self, pf, df)
def convert_schema_to_openldap(self, target, mapping):
return glue.dsdb_convert_schema_to_openldap(self, target, mapping)
def set_invocation_id(self, invocation_id): def set_invocation_id(self, invocation_id):
"""Set the invocation id for this SamDB handle. """Set the invocation id for this SamDB handle.

View File

@ -92,16 +92,3 @@ oLschema2ldif_OBJ_FILES = $(addprefix $(utilssrcdir)/, oLschema2ldif.o)
MANPAGES += $(utilssrcdir)/man/oLschema2ldif.1 MANPAGES += $(utilssrcdir)/man/oLschema2ldif.1
################################################
# Start BINARY ad2oLschema
[BINARY::ad2oLschema]
INSTALLDIR = BINDIR
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE SAMDB
# End BINARY ad2oLschema
################################################
ad2oLschema_OBJ_FILES = $(addprefix $(utilssrcdir)/, ad2oLschema.o)
MANPAGES += $(utilssrcdir)/man/ad2oLschema.1