From: Quanah Gibson-Mount Date: Wed, 3 Jun 2009 00:36:17 +0000 (+0000) Subject: ITS#6150 X-Git-Tag: OPENLDAP_REL_ENG_2_4_17~76 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=a7f4102bbfd42681ac505f2adb3ff35d8aba3d88;p=openldap ITS#6150 --- diff --git a/CHANGES b/CHANGES index e5b29d3ffe..22ea83b96d 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,7 @@ OpenLDAP 2.4.17 Engineering Fixed liblutil opendir/closedir on windows (ITS#6041) Fixed liblutil for _GNU_SOURCE (ITS#5464,ITS#5666) Added slapd sasl auxprop support (ITS#6147) + Added slapd schema checking tool (ITS#6150) Fixed slapd assert with closing connections (ITS#6111) Fixed slapd cert validation (ITS#6098) Fixed slapd errno handling (ITS#6037) diff --git a/doc/man/man8/slapschema.8 b/doc/man/man8/slapschema.8 new file mode 100644 index 0000000000..26ca7c73b7 --- /dev/null +++ b/doc/man/man8/slapschema.8 @@ -0,0 +1,175 @@ +.TH SLAPSCHEMA 8C "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 1998-2009 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.\" $OpenLDAP$ +.SH NAME +slapschema \- SLAPD in-database schema checking utility +.SH SYNOPSIS +.B SBINDIR/slapschema +.B [\-a filter] +.B [\-b suffix] +.B [\-c] +.B [\-d level] +.B [\-f slapd.conf] +.B [\-F confdir] +.B [\-g] +.B [\-l error-file] +.B [\-n dbnum] +.B [\-o name[=value]] +.B [\-s subtree-dn] +.B [\-v] +.B +.LP +.SH DESCRIPTION +.LP +.B Slapschema +is used to check schema compliance of the contents of a +.BR slapd (8) +database. +It opens the given database determined by the database number or +suffix and checks the compliance of its contents with the corresponding +schema. Errors are written to standard output or the specified file. +Databases configured as +.B subordinate +of this one are also output, unless \fB-g\fP is specified. +.LP +Administrators may need to modify existing schema items, including +adding new required attributes to objectClasses, +removing existing required or allowed attributes from objectClasses, +entirely removing objectClasses, +or any other change that may result in making perfectly valid entries +no longer compliant with the modified schema. +The execution of the +.B slapschema tool after modifying the schema can point out +inconsistencies that would otherwise surface only as soon as +inconsistent entries need to be modified. + +.LP +The entry records are checked in database order, not superior first +order. The entry records will be checked considering all +(user and operational) attributes stored in the database. +Dynamically generated attributes (such as subschemaSubentry) +will not be considered. +.SH OPTIONS +.TP +.BI \-a " filter" +Only check entries matching the asserted filter. +For example + +slapschema -a \\ + "(!(entryDN:dnSubtreeMatch:=ou=People,dc=example,dc=com))" + +will check all but the "ou=People,dc=example,dc=com" subtree +of the "dc=example,dc=com" database. +.TP +.BI \-b " suffix" +Use the specified \fIsuffix\fR to determine which database to +check. The \-b cannot be used in conjunction +with the +.B \-n +option. +.TP +.B \-c +Enable continue (ignore errors) mode. +.TP +.BI \-d " level" +Enable debugging messages as defined by the specified +.IR level ; +see +.BR slapd (8) +for details. +.TP +.BI \-f " slapd.conf" +Specify an alternative +.BR slapd.conf (5) +file. +.TP +.BI \-F " confdir" +specify a config directory. +If both +.B -f +and +.B -F +are specified, the config file will be read and converted to +config directory format and written to the specified directory. +If neither option is specified, an attempt to read the +default config directory will be made before trying to use the default +config file. If a valid config directory exists then the +default config file is ignored. +.TP +.B \-g +disable subordinate gluing. Only the specified database will be +processed, and not its glued subordinates (if any). +.TP +.BI \-l " error-file" +Write errors to specified file instead of standard output. +.TP +.BI \-n " dbnum" +Check the \fIdbnum\fR\-th database listed in the +configuration file. The config database +.BR slapd-config (5), +is always the first database, so use +.B \-n 0 + +The +.B \-n +cannot be used in conjunction with the +.B \-b +option. +.TP +.BI \-o " option[=value]" +Specify an +.BR option +with a(n optional) +.BR value . +Possible generic options/values are: +.LP +.nf + syslog= (see `\-s' in slapd(8)) + syslog-level= (see `\-S' in slapd(8)) + syslog-user= (see `\-l' in slapd(8)) + +.fi +.TP +.BI \-s " subtree-dn" +Only check entries in the subtree specified by this DN. +Implies `-b subtree-dn' if no +.B \-b +nor +.B \-n +option is given. +.TP +.B \-v +Enable verbose mode. +.SH LIMITATIONS +For some backend types, your +.BR slapd (8) +should not be running (at least, not in read-write +mode) when you do this to ensure consistency of the database. It is +always safe to run +.B slapschema +with the +.BR slapd-bdb (5), +.BR slapd-hdb (5), +and +.BR slapd-null (5) +backends. +.SH EXAMPLES +To check the schema compliance of your SLAPD database after modifications +to the schema, and put any error in a file called +.BR errors.ldif , +give the command: +.LP +.nf +.ft tt + SBINDIR/slapcat -l errors.ldif +.ft +.fi +.SH "SEE ALSO" +.BR ldap (3), +.BR ldif (5), +.BR slapd (8) +.LP +"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) +.SH ACKNOWLEDGEMENTS +.so ../Project diff --git a/servers/slapd/Makefile.in b/servers/slapd/Makefile.in index e310dfcf01..ee784e4282 100644 --- a/servers/slapd/Makefile.in +++ b/servers/slapd/Makefile.in @@ -13,7 +13,7 @@ ## top-level directory of the distribution or, alternatively, at ## . -SLAPTOOLS=slapadd slapcat slapdn slapindex slappasswd slaptest slapauth slapacl +SLAPTOOLS=slapadd slapcat slapdn slapindex slappasswd slaptest slapauth slapacl slapschema PROGRAMS=slapd $(SLAPTOOLS) XPROGRAMS=sslapd libbackends.a .backend liboverlays.a XSRCS=version.c @@ -38,7 +38,7 @@ SRCS = main.c globals.c bconfig.c config.c daemon.c \ backglue.c backover.c ctxcsn.c ldapsync.c frontend.c \ slapadd.c slapcat.c slapcommon.c slapdn.c slapindex.c \ slappasswd.c slaptest.c slapauth.c slapacl.c component.c \ - aci.c alock.c txn.c \ + aci.c alock.c txn.c slapschema.c \ $(@PLAT@_SRCS) OBJS = main.o globals.o bconfig.o config.o daemon.o \ @@ -56,7 +56,7 @@ OBJS = main.o globals.o bconfig.o config.o daemon.o \ backglue.o backover.o ctxcsn.o ldapsync.o frontend.o \ slapadd.o slapcat.o slapcommon.o slapdn.o slapindex.o \ slappasswd.o slaptest.o slapauth.o slapacl.o component.o \ - aci.o alock.o txn.o \ + aci.o alock.o txn.o slapschema.o \ $(@PLAT@_OBJS) LDAP_INCDIR= ../../include -I$(srcdir) -I$(srcdir)/slapi -I. diff --git a/servers/slapd/main.c b/servers/slapd/main.c index b22e8b70f1..e2ffda2c7c 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -65,7 +65,7 @@ static struct sockaddr_in bind_addr; typedef int (MainFunc) LDAP_P(( int argc, char *argv[] )); extern MainFunc slapadd, slapcat, slapdn, slapindex, slappasswd, - slaptest, slapauth, slapacl; + slaptest, slapauth, slapacl, slapschema; static struct { char *name; @@ -76,6 +76,7 @@ static struct { {"slapdn", slapdn}, {"slapindex", slapindex}, {"slappasswd", slappasswd}, + {"slapschema", slapschema}, {"slaptest", slaptest}, {"slapauth", slapauth}, {"slapacl", slapacl}, diff --git a/servers/slapd/slapcommon.c b/servers/slapd/slapcommon.c index 8d4527c9fc..74b9e1b332 100644 --- a/servers/slapd/slapcommon.c +++ b/servers/slapd/slapcommon.c @@ -94,6 +94,11 @@ usage( int tool, const char *progname ) case SLAPTEST: options = " [-u]\n"; break; + + case SLAPSCHEMA: + options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]" + " [-l errorfile] [-a filter] [-s subtree]\n"; + break; } if ( options != NULL ) { @@ -222,6 +227,7 @@ slap_tool_init( int mode = SLAP_TOOL_MODE; int truncatemode = 0; int use_glue = 1; + int writer; #ifdef LDAP_DEBUG /* tools default to "none", so that at least LDAP_DEBUG_ANY @@ -255,6 +261,11 @@ slap_tool_init( mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; break; + case SLAPSCHEMA: + options = "a:b:cd:f:F:gl:n:o:s:v"; + mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; + break; + case SLAPTEST: options = "d:f:F:o:Quv"; mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; @@ -396,7 +407,7 @@ slap_tool_init( case 's': /* dump subtree */ if ( tool == SLAPADD ) mode |= SLAP_TOOL_NO_SCHEMA_CHECK; - else if ( tool == SLAPCAT ) + else if ( tool == SLAPCAT || tool == SLAPSCHEMA ) subtree = ch_strdup( optarg ); break; @@ -453,9 +464,21 @@ slap_tool_init( } #endif /* LDAP_DEBUG && LDAP_SYSLOG */ + switch ( tool ) { + case SLAPCAT: + case SLAPSCHEMA: + writer = 1; + break; + + default: + writer = 0; + break; + } + switch ( tool ) { case SLAPADD: case SLAPCAT: + case SLAPSCHEMA: if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) { usage( tool, progname ); } @@ -502,10 +525,10 @@ slap_tool_init( } if ( ldiffile == NULL ) { - dummy.fp = tool == SLAPCAT ? stdout : stdin; + dummy.fp = writer ? stdout : stdin; ldiffp = &dummy; - } else if ((ldiffp = ldif_open( ldiffile, tool == SLAPCAT ? "w" : "r" )) + } else if ((ldiffp = ldif_open( ldiffile, writer ? "w" : "r" )) == NULL ) { perror( ldiffile ); @@ -554,6 +577,7 @@ slap_tool_init( case SLAPADD: case SLAPCAT: case SLAPINDEX: + case SLAPSCHEMA: if ( !nbackends ) { fprintf( stderr, "No databases found " "in config file\n" ); diff --git a/servers/slapd/slapcommon.h b/servers/slapd/slapcommon.h index b030da2874..56b21cd648 100644 --- a/servers/slapd/slapcommon.h +++ b/servers/slapd/slapcommon.h @@ -26,6 +26,7 @@ enum slaptool { SLAPDN, /* DN check w/ syntax tool */ SLAPINDEX, /* database index tool */ SLAPPASSWD, /* password generation tool */ + SLAPSCHEMA, /* schema checking tool */ SLAPTEST, /* slapd.conf test tool */ SLAPAUTH, /* test authz-regexp and authc/authz stuff */ SLAPACL, /* test acl */ diff --git a/servers/slapd/slapschema.c b/servers/slapd/slapschema.c new file mode 100644 index 0000000000..6a00be85c7 --- /dev/null +++ b/servers/slapd/slapschema.c @@ -0,0 +1,142 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2009 The OpenLDAP Foundation. + * Portions Copyright 1998-2003 Kurt D. Zeilenga. + * Portions Copyright 2003 IBM Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion + * in OpenLDAP Software. Code portions borrowed from slapcat.c; + * contributors are Kurt Zeilenga and Jong Hyuk Choi + */ + +#include "portable.h" + +#include + +#include "ac/stdlib.h" +#include "ac/ctype.h" +#include "ac/socket.h" +#include "ac/string.h" + +#include "slapcommon.h" +#include "ldif.h" + +static volatile sig_atomic_t gotsig; + +static RETSIGTYPE +slapcat_sig( int sig ) +{ + gotsig=1; +} + +int +slapschema( int argc, char **argv ) +{ + ID id; + int rc = EXIT_SUCCESS; + const char *progname = "slapschema"; + Connection conn = { 0 }; + OperationBuffer opbuf; + Operation *op = NULL; + + slap_tool_init( progname, SLAPCAT, argc, argv ); + +#ifdef SIGPIPE + (void) SIGNAL( SIGPIPE, slapcat_sig ); +#endif +#ifdef SIGHUP + (void) SIGNAL( SIGHUP, slapcat_sig ); +#endif + (void) SIGNAL( SIGINT, slapcat_sig ); + (void) SIGNAL( SIGTERM, slapcat_sig ); + + if( !be->be_entry_open || + !be->be_entry_close || + !be->be_entry_first || + !be->be_entry_next || + !be->be_entry_get ) + { + fprintf( stderr, "%s: database doesn't support necessary operations.\n", + progname ); + exit( EXIT_FAILURE ); + } + + if( be->be_entry_open( be, 0 ) != 0 ) { + fprintf( stderr, "%s: could not open database.\n", + progname ); + exit( EXIT_FAILURE ); + } + + connection_fake_init( &conn, &opbuf, &conn ); + op = &opbuf.ob_op; + op->o_tmpmemctx = NULL; + op->o_bd = be; + + for ( id = be->be_entry_first( be ); + id != NOID; + id = be->be_entry_next( be ) ) + { + Entry* e; + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof(textbuf); + const char *text = NULL; + + if ( gotsig ) + break; + + e = be->be_entry_get( be, id ); + if ( e == NULL ) { + printf("# no data for entry id=%08lx\n\n", (long) id ); + rc = EXIT_FAILURE; + if( continuemode ) continue; + break; + } + + if( sub_ndn.bv_len && !dnIsSuffix( &e->e_nname, &sub_ndn ) ) { + be_entry_release_r( op, e ); + continue; + } + + if( filter != NULL ) { + int rc = test_filter( NULL, e, filter ); + if( rc != LDAP_COMPARE_TRUE ) { + be_entry_release_r( op, e ); + continue; + } + } + + if( verbose ) { + printf( "# id=%08lx\n", (long) id ); + } + + rc = entry_schema_check( op, e, NULL, 0, 0, NULL, + &text, textbuf, textlen ); + if ( rc != LDAP_SUCCESS ) { + fprintf( ldiffp->fp, "# (%d) %s%s%s\n", + rc, ldap_err2string( rc ), + text ? ": " : "", + text ? text : "" ); + fprintf( ldiffp->fp, "dn: %s\n\n", e->e_name.bv_val ); + } + + be_entry_release_r( op, e ); + } + + be->be_entry_close( be ); + + if ( slap_tool_destroy() ) + rc = EXIT_FAILURE; + + return rc; +}