]> git.sur5r.net Git - openldap/commitdiff
ITS#6150
authorQuanah Gibson-Mount <quanah@openldap.org>
Wed, 3 Jun 2009 00:36:17 +0000 (00:36 +0000)
committerQuanah Gibson-Mount <quanah@openldap.org>
Wed, 3 Jun 2009 00:36:17 +0000 (00:36 +0000)
CHANGES
doc/man/man8/slapschema.8 [new file with mode: 0644]
servers/slapd/Makefile.in
servers/slapd/main.c
servers/slapd/slapcommon.c
servers/slapd/slapcommon.h
servers/slapd/slapschema.c [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index e5b29d3ffe439fa1bbab193822c7ff1a29f60597..22ea83b96da2b6c4f622451843e8977ca764cc57 100644 (file)
--- 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 (file)
index 0000000..26ca7c7
--- /dev/null
@@ -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=<subsystems>  (see `\-s' in slapd(8))
+              syslog-level=<level> (see `\-S' in slapd(8))
+              syslog-user=<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
index e310dfcf0176cbf106c5d273f51a49147aff2fb7..ee784e4282eab6024f13f3c3567ee8243849c94e 100644 (file)
@@ -13,7 +13,7 @@
 ## top-level directory of the distribution or, alternatively, at
 ## <http://www.OpenLDAP.org/license.html>.
 
-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.
index b22e8b70f139c65beb1c76d52e92689e134126ce..e2ffda2c7c0d1582f3b27b0e13a3551fdd14b6c9 100644 (file)
@@ -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},
index 8d4527c9fc2a6bce2dba95f7571042ddf6cef363..74b9e1b332b468b2bb695fd5047253fee20013f2 100644 (file)
@@ -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" );
index b030da2874768225bc1082b066be7abcac6ec4f3..56b21cd6481030b839d7891958d990ddf1e3a84f 100644 (file)
@@ -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 (file)
index 0000000..6a00be8
--- /dev/null
@@ -0,0 +1,142 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * 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
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* 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 <stdio.h>
+
+#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;
+}