X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fslapcommon.c;h=3d77d371cf9b2bacc3617816881814d6462e59f3;hb=c6b5abbfd20567116846ebc38f0005c429284c98;hp=26e36011788421735ce807f4d8138ef139aa4997;hpb=1ed9b5c3bca2a5f536d68956c959aa4ba21f2c90;p=openldap diff --git a/servers/slapd/slapcommon.c b/servers/slapd/slapcommon.c index 26e3601178..3d77d371cf 100644 --- a/servers/slapd/slapcommon.c +++ b/servers/slapd/slapcommon.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2007 The OpenLDAP Foundation. + * Copyright 1998-2012 The OpenLDAP Foundation. * Portions Copyright 1998-2003 Kurt D. Zeilenga. * Portions Copyright 2003 IBM Corporation. * All rights reserved. @@ -80,7 +80,7 @@ usage( int tool, const char *progname ) case SLAPCAT: options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]" - " [-l ldiffile] [-a filter]\n"; + " [-l ldiffile] [-a filter] [-s subtree] [-H url]\n"; break; case SLAPDN: @@ -92,7 +92,12 @@ usage( int tool, const char *progname ) break; case SLAPTEST: - options = " [-u]\n"; + options = " [-n databasenumber] [-u]\n"; + break; + + case SLAPSCHEMA: + options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]" + " [-l errorfile] [-a filter] [-s subtree] [-H url]\n"; break; } @@ -103,7 +108,7 @@ usage( int tool, const char *progname ) } static int -parse_slapopt( void ) +parse_slapopt( int tool, int *mode ) { size_t len = 0; char *p; @@ -187,6 +192,63 @@ parse_slapopt( void ) #endif /* LOG_LOCAL4 */ #endif /* LDAP_DEBUG && LDAP_SYSLOG */ + } else if ( strncasecmp( optarg, "schema-check", len ) == 0 ) { + switch ( tool ) { + case SLAPADD: + if ( strcasecmp( p, "yes" ) == 0 ) { + *mode &= ~SLAP_TOOL_NO_SCHEMA_CHECK; + } else if ( strcasecmp( p, "no" ) == 0 ) { + *mode |= SLAP_TOOL_NO_SCHEMA_CHECK; + } else { + Debug( LDAP_DEBUG_ANY, "unable to parse schema-check=\"%s\".\n", p, 0, 0 ); + return -1; + } + break; + + default: + Debug( LDAP_DEBUG_ANY, "schema-check meaningless for tool.\n", 0, 0, 0 ); + break; + } + + } else if ( strncasecmp( optarg, "value-check", len ) == 0 ) { + switch ( tool ) { + case SLAPADD: + if ( strcasecmp( p, "yes" ) == 0 ) { + *mode |= SLAP_TOOL_VALUE_CHECK; + } else if ( strcasecmp( p, "no" ) == 0 ) { + *mode &= ~SLAP_TOOL_VALUE_CHECK; + } else { + Debug( LDAP_DEBUG_ANY, "unable to parse value-check=\"%s\".\n", p, 0, 0 ); + return -1; + } + break; + + default: + Debug( LDAP_DEBUG_ANY, "value-check meaningless for tool.\n", 0, 0, 0 ); + break; + } + + } else if ( strncasecmp( optarg, "ldif-wrap", len ) == 0 ) { + switch ( tool ) { + case SLAPCAT: + if ( strcasecmp( p, "no" ) == 0 ) { + ldif_wrap = LDIF_LINE_WIDTH_MAX; + + } else { + unsigned int u; + if ( lutil_atou( &u, p ) ) { + Debug( LDAP_DEBUG_ANY, "unable to parse ldif-wrap=\"%s\".\n", p, 0, 0 ); + return -1; + } + ldif_wrap = (ber_len_t)u; + } + break; + + default: + Debug( LDAP_DEBUG_ANY, "value-check meaningless for tool.\n", 0, 0, 0 ); + break; + } + } else { return -1; } @@ -218,15 +280,17 @@ slap_tool_init( char *subtree = NULL; char *ldiffile = NULL; char **debug_unknowns = NULL; - int rc, i, dbnum; + int rc, i; 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 * messages show up; use -d 0 to reset */ slap_debug = LDAP_DEBUG_NONE; + ldif_debug = slap_debug; #endif ldap_syslog = 0; @@ -237,15 +301,20 @@ slap_tool_init( leakfile = stderr; } free( leakfilename ); + leakfilename = NULL; #endif + ldif_wrap = LDIF_LINE_WIDTH; + + scope = LDAP_SCOPE_DEFAULT; + switch( tool ) { case SLAPADD: options = "b:cd:f:F:gj:l:n:o:qsS:uvw"; break; case SLAPCAT: - options = "a:b:cd:f:F:gl:n:o:s:v"; + options = "a:b:cd:f:F:gH:l:n:o:s:v"; mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; break; @@ -254,8 +323,17 @@ slap_tool_init( mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; break; + case SLAPMODIFY: + options = "b:cd:f:F:gj:l:n:o:qsS:uvw"; + break; + + case SLAPSCHEMA: + options = "a:b:cd:f:F:gH:l:n:o:s:v"; + mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; + break; + case SLAPTEST: - options = "d:f:F:o:Quv"; + options = "d:f:F:n:o:Quv"; mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; break; @@ -331,6 +409,52 @@ slap_tool_init( use_glue = 0; break; + case 'H': { + LDAPURLDesc *ludp; + int rc; + + rc = ldap_url_parse_ext( optarg, &ludp, + LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_NOEMPTY_DN ); + if ( rc != LDAP_URL_SUCCESS ) { + usage( tool, progname ); + } + + /* don't accept host, port, attrs, extensions */ + if ( ldap_pvt_url_scheme2proto( ludp->lud_scheme ) != LDAP_PROTO_TCP ) { + usage( tool, progname ); + } + + if ( ludp->lud_host != NULL ) { + usage( tool, progname ); + } + + if ( ludp->lud_port != 0 ) { + usage( tool, progname ); + } + + if ( ludp->lud_attrs != NULL ) { + usage( tool, progname ); + } + + if ( ludp->lud_exts != NULL ) { + usage( tool, progname ); + } + + if ( ludp->lud_dn != NULL && ludp->lud_dn[0] != '\0' ) { + subtree = ludp->lud_dn; + ludp->lud_dn = NULL; + } + + if ( ludp->lud_filter != NULL && ludp->lud_filter[0] != '\0' ) { + filterstr = ludp->lud_filter; + ludp->lud_filter = NULL; + } + + scope = ludp->lud_scope; + + ldap_free_urldesc( ludp ); + } break; + case 'j': /* jump to linenumber */ if ( lutil_atoi( &jumpline, optarg ) ) { usage( tool, progname ); @@ -353,13 +477,13 @@ slap_tool_init( break; case 'n': /* which config file db to index */ - if ( lutil_atoi( &dbnum, optarg ) ) { + if ( lutil_atoi( &dbnum, optarg ) || dbnum < 0 ) { usage( tool, progname ); } break; case 'o': - if ( parse_slapopt() ) { + if ( parse_slapopt( tool, &mode ) ) { usage( tool, progname ); } break; @@ -392,11 +516,20 @@ slap_tool_init( } break; - case 's': /* dump subtree */ - if ( tool == SLAPADD ) + case 's': + switch ( tool ) { + case SLAPADD: + case SLAPMODIFY: + /* no schema check */ mode |= SLAP_TOOL_NO_SCHEMA_CHECK; - else if ( tool == SLAPCAT ) + break; + + case SLAPCAT: + case SLAPSCHEMA: + /* dump subtree */ subtree = ch_strdup( optarg ); + break; + } break; case 't': /* turn on truncate */ @@ -447,13 +580,27 @@ slap_tool_init( #endif #ifdef HAVE_EBCDIC free( logName ); + logName = NULL; #endif } #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 SLAPMODIFY: + case SLAPSCHEMA: if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) { usage( tool, progname ); } @@ -500,10 +647,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 ); @@ -552,6 +699,8 @@ slap_tool_init( case SLAPADD: case SLAPCAT: case SLAPINDEX: + case SLAPMODIFY: + case SLAPSCHEMA: if ( !nbackends ) { fprintf( stderr, "No databases found " "in config file\n" ); @@ -564,7 +713,7 @@ slap_tool_init( } if ( use_glue ) { - rc = glue_sub_attach(); + rc = glue_sub_attach( 0 ); if ( rc != 0 ) { fprintf( stderr, @@ -581,8 +730,11 @@ slap_tool_init( } switch ( tool ) { - case SLAPDN: case SLAPTEST: + if ( dbnum >= 0 ) + goto get_db; + /* FALLTHRU */ + case SLAPDN: case SLAPAUTH: be = NULL; goto startup; @@ -598,6 +750,9 @@ slap_tool_init( fprintf( stderr, "Invalid filter '%s'\n", filterstr ); exit( EXIT_FAILURE ); } + + ch_free( filterstr ); + filterstr = NULL; } if( subtree ) { @@ -613,6 +768,7 @@ slap_tool_init( base = val; } else { free( subtree ); + subtree = NULL; } } @@ -628,6 +784,7 @@ slap_tool_init( be = select_backend( &nbase, 0 ); ber_memfree( nbase.bv_val ); + BER_BVZERO( &nbase ); switch ( tool ) { case SLAPACL: @@ -649,6 +806,9 @@ slap_tool_init( nosubordinates = 1; } + ch_free( base.bv_val ); + BER_BVZERO( &base ); + } else if ( dbnum == -1 ) { /* no suffix and no dbnum specified, just default to * the first available database @@ -689,22 +849,43 @@ slap_tool_init( progname, dbnum, 0 ); } - } else if ( dbnum < 0 || dbnum > (nbackends-1) ) { + } else if ( dbnum >= nbackends ) { fprintf( stderr, "Database number selected via -n is out of range\n" "Must be in the range 0 to %d" - " (number of configured databases)\n", - nbackends-1 ); + " (the number of configured databases)\n", + nbackends - 1 ); exit( EXIT_FAILURE ); } else { +get_db: LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { if ( dbnum == 0 ) break; dbnum--; } } + if ( scope != LDAP_SCOPE_DEFAULT && BER_BVISNULL( &sub_ndn ) ) { + if ( be && be->be_nsuffix ) { + ber_dupbv( &sub_ndn, be->be_nsuffix ); + + } else { + fprintf( stderr, + " needs a DN or a valid database\n" ); + exit( EXIT_FAILURE ); + } + } + startup:; + if ( be ) { + BackendDB *bdtmp; + + dbnum = 0; + LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) { + if ( bdtmp == be ) break; + dbnum++; + } + } #ifdef CSRIMALLOC mal_leaktrace(1); @@ -712,10 +893,17 @@ startup:; if ( conffile != NULL ) { ch_free( conffile ); + conffile = NULL; + } + + if ( confdir != NULL ) { + ch_free( confdir ); + confdir = NULL; } if ( ldiffile != NULL ) { ch_free( ldiffile ); + ldiffile = NULL; } /* slapdn doesn't specify a backend to startup */ @@ -740,13 +928,16 @@ startup:; } } -void slap_tool_destroy( void ) +int slap_tool_destroy( void ) { + int rc = 0; if ( !dryrun ) { if ( need_shutdown ) { - slap_shutdown( be ); + if ( slap_shutdown( be )) + rc = EXIT_FAILURE; } - slap_destroy(); + if ( slap_destroy()) + rc = EXIT_FAILURE; } #ifdef SLAPD_MODULES if ( slapMode == SLAP_SERVER_MODE ) { @@ -767,9 +958,270 @@ void slap_tool_destroy( void ) if ( !BER_BVISNULL( &authcDN ) ) { ch_free( authcDN.bv_val ); + BER_BVZERO( &authcDN ); } if ( ldiffp && ldiffp != &dummy ) { ldif_close( ldiffp ); } + return rc; } + +int +slap_tool_update_ctxcsn( + const char *progname, + unsigned long sid, + struct berval *bvtext ) +{ + struct berval ctxdn; + ID ctxcsn_id; + Entry *ctxcsn_e; + int rc = EXIT_SUCCESS; + + if ( !(update_ctxcsn && !dryrun && sid != SLAP_SYNC_SID_MAX + 1) ) { + return rc; + } + + if ( SLAP_SYNC_SUBENTRY( be )) { + build_new_dn( &ctxdn, &be->be_nsuffix[0], + (struct berval *)&slap_ldapsync_cn_bv, NULL ); + } else { + ctxdn = be->be_nsuffix[0]; + } + ctxcsn_id = be->be_dn2id_get( be, &ctxdn ); + if ( ctxcsn_id == NOID ) { + if ( SLAP_SYNC_SUBENTRY( be )) { + ctxcsn_e = slap_create_context_csn_entry( be, NULL ); + for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) { + if ( maxcsn[ sid ].bv_len ) { + attr_merge_one( ctxcsn_e, slap_schema.si_ad_contextCSN, + &maxcsn[ sid ], NULL ); + } + } + ctxcsn_id = be->be_entry_put( be, ctxcsn_e, bvtext ); + if ( ctxcsn_id == NOID ) { + fprintf( stderr, "%s: couldn't create context entry\n", progname ); + rc = EXIT_FAILURE; + } + } else { + fprintf( stderr, "%s: context entry is missing\n", progname ); + rc = EXIT_FAILURE; + } + } else { + ctxcsn_e = be->be_entry_get( be, ctxcsn_id ); + if ( ctxcsn_e != NULL ) { + Entry *e = entry_dup( ctxcsn_e ); + int change; + Attribute *attr = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN ); + if ( attr ) { + int i; + + change = 0; + + for ( i = 0; !BER_BVISNULL( &attr->a_nvals[ i ] ); i++ ) { + int rc_sid; + int match; + const char *text = NULL; + + rc_sid = slap_parse_csn_sid( &attr->a_nvals[ i ] ); + if ( rc_sid < 0 ) { + Debug( LDAP_DEBUG_ANY, + "%s: unable to extract SID " + "from #%d contextCSN=%s\n", + progname, i, + attr->a_nvals[ i ].bv_val ); + continue; + } + + assert( rc_sid <= SLAP_SYNC_SID_MAX ); + + sid = (unsigned)rc_sid; + + if ( maxcsn[ sid ].bv_len == 0 ) { + match = -1; + + } else { + value_match( &match, slap_schema.si_ad_entryCSN, + slap_schema.si_ad_entryCSN->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &maxcsn[ sid ], &attr->a_nvals[i], &text ); + } + + if ( match > 0 ) { + change = 1; + } else { + AC_MEMCPY( maxcsn[ sid ].bv_val, + attr->a_nvals[ i ].bv_val, + attr->a_nvals[ i ].bv_len ); + maxcsn[ sid ].bv_val[ attr->a_nvals[ i ].bv_len ] = '\0'; + maxcsn[ sid ].bv_len = attr->a_nvals[ i ].bv_len; + } + } + + if ( change ) { + if ( attr->a_nvals != attr->a_vals ) { + ber_bvarray_free( attr->a_nvals ); + } + attr->a_nvals = NULL; + ber_bvarray_free( attr->a_vals ); + attr->a_vals = NULL; + attr->a_numvals = 0; + } + } else { + change = 1; + } + + if ( change ) { + for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) { + if ( maxcsn[ sid ].bv_len ) { + attr_merge_one( e, slap_schema.si_ad_contextCSN, + &maxcsn[ sid], NULL ); + } + } + + ctxcsn_id = be->be_entry_modify( be, e, bvtext ); + if( ctxcsn_id == NOID ) { + fprintf( stderr, "%s: could not modify ctxcsn (%s)\n", + progname, bvtext->bv_val ? bvtext->bv_val : "" ); + rc = EXIT_FAILURE; + } else if ( verbose ) { + fprintf( stderr, "modified: \"%s\" (%08lx)\n", + e->e_dn, (long) ctxcsn_id ); + } + } + entry_free( e ); + } + } + + return rc; +} + +/* + * return value: + * -1: update_ctxcsn == 0 + * SLAP_SYNC_SID_MAX + 1: unable to extract SID + * 0 <= SLAP_SYNC_SID_MAX: the SID + */ +unsigned long +slap_tool_update_ctxcsn_check( + const char *progname, + Entry *e ) +{ + if ( update_ctxcsn ) { + unsigned long sid = SLAP_SYNC_SID_MAX + 1; + int rc_sid; + Attribute *attr; + + attr = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); + assert( attr != NULL ); + + rc_sid = slap_parse_csn_sid( &attr->a_nvals[ 0 ] ); + if ( rc_sid < 0 ) { + Debug( LDAP_DEBUG_ANY, "%s: could not " + "extract SID from entryCSN=%s, entry dn=\"%s\"\n", + progname, attr->a_nvals[ 0 ].bv_val, e->e_name.bv_val ); + return (unsigned long)(-1); + + } else { + int match; + const char *text = NULL; + + assert( rc_sid <= SLAP_SYNC_SID_MAX ); + + sid = (unsigned)rc_sid; + if ( maxcsn[ sid ].bv_len != 0 ) { + match = 0; + value_match( &match, slap_schema.si_ad_entryCSN, + slap_schema.si_ad_entryCSN->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &maxcsn[ sid ], &attr->a_nvals[0], &text ); + } else { + match = -1; + } + if ( match < 0 ) { + strcpy( maxcsn[ sid ].bv_val, attr->a_nvals[0].bv_val ); + maxcsn[ sid ].bv_len = attr->a_nvals[0].bv_len; + } + } + } + + return (unsigned long)(-1); +} + +int +slap_tool_update_ctxcsn_init(void) +{ + if ( update_ctxcsn ) { + unsigned long sid; + maxcsn[ 0 ].bv_val = maxcsnbuf; + for ( sid = 1; sid <= SLAP_SYNC_SID_MAX; sid++ ) { + maxcsn[ sid ].bv_val = maxcsn[ sid - 1 ].bv_val + LDAP_PVT_CSNSTR_BUFSIZE; + maxcsn[ sid ].bv_len = 0; + } + } + + return 0; +} + +int +slap_tool_entry_check( + const char *progname, + Operation *op, + Entry *e, + int lineno, + const char **text, + char *textbuf, + size_t textlen ) +{ + /* NOTE: we may want to conditionally enable manage */ + int manage = 0; + + Attribute *oc = attr_find( e->e_attrs, + slap_schema.si_ad_objectClass ); + + if( oc == NULL ) { + fprintf( stderr, "%s: dn=\"%s\" (line=%d): %s\n", + progname, e->e_dn, lineno, + "no objectClass attribute"); + return LDAP_NO_SUCH_ATTRIBUTE; + } + + /* check schema */ + op->o_bd = be; + + if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) { + int rc = entry_schema_check( op, e, NULL, manage, 1, NULL, + text, textbuf, textlen ); + + if( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n", + progname, e->e_dn, lineno, rc, *text ); + return rc; + } + textbuf[ 0 ] = '\0'; + } + + if ( (slapMode & SLAP_TOOL_VALUE_CHECK) != 0) { + Modifications *ml = NULL; + + int rc = slap_entry2mods( e, &ml, text, textbuf, textlen ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n", + progname, e->e_dn, lineno, rc, *text ); + return rc; + } + textbuf[ 0 ] = '\0'; + + rc = slap_mods_check( op, ml, text, textbuf, textlen, NULL ); + slap_mods_free( ml, 1 ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n", + progname, e->e_dn, lineno, rc, *text ); + return rc; + } + textbuf[ 0 ] = '\0'; + } + + return LDAP_SUCCESS; +} +