Пример #1
0
static int
OpenLDAPaciPrettyNormal(
	struct berval	*val,
	struct berval	*out,
	void		*ctx,
	int		normalize )
{
	struct berval	oid = BER_BVNULL,
			scope = BER_BVNULL,
			rights = BER_BVNULL,
			nrights = BER_BVNULL,
			type = BER_BVNULL,
			ntype = BER_BVNULL,
			subject = BER_BVNULL,
			nsubject = BER_BVNULL;
	int		idx,
			rc = LDAP_SUCCESS,
			freesubject = 0,
			freetype = 0;
	char		*ptr;

	BER_BVZERO( out );

	if ( BER_BVISEMPTY( val ) ) {
		Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: value is empty\n" );
		return LDAP_INVALID_SYNTAX;
	}

	/* oid: if valid, it's already normalized */
	if ( acl_get_part( val, 0, '#', &oid ) < 0 ||
		numericoidValidate( NULL, &oid ) != LDAP_SUCCESS )
	{
		Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid oid '%s'\n", oid.bv_val );
		return LDAP_INVALID_SYNTAX;
	}

	/* scope: normalize by replacing with OpenLDAPaciscopes */
	if ( acl_get_part( val, 1, '#', &scope ) < 0 ) {
		Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing scope in '%s'\n", val->bv_val );
		return LDAP_INVALID_SYNTAX;
	}
	idx = bv_getcaseidx( &scope, OpenLDAPaciscopes );
	if ( idx == -1 ) {
		Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid scope '%s'\n", scope.bv_val );
		return LDAP_INVALID_SYNTAX;
	}
	scope = *OpenLDAPaciscopes[ idx ];

	/* rights */
	if ( acl_get_part( val, 2, '#', &rights ) < 0 ) {
		Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing rights in '%s'\n", val->bv_val );
		return LDAP_INVALID_SYNTAX;
	}
	if ( OpenLDAPaciNormalizeRights( &rights, &nrights, ctx )
		!= LDAP_SUCCESS )
	{
		return LDAP_INVALID_SYNTAX;
	}

	/* type */
	if ( acl_get_part( val, 3, '#', &type ) < 0 ) {
		Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing type in '%s'\n", val->bv_val );
		rc = LDAP_INVALID_SYNTAX;
		goto cleanup;
	}
	idx = bv_getcaseidx( &type, OpenLDAPacitypes );
	if ( idx == -1 ) {
		struct berval	isgr;

		if ( acl_get_part( &type, 0, '/', &isgr ) < 0 ) {
		        Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid type '%s'\n", type.bv_val );
			rc = LDAP_INVALID_SYNTAX;
			goto cleanup;
		}

		idx = bv_getcaseidx( &isgr, OpenLDAPacitypes );
		if ( idx == -1 || idx >= LAST_OPTIONAL ) {
		        Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid type '%s'\n", isgr.bv_val );
			rc = LDAP_INVALID_SYNTAX;
			goto cleanup;
		}
	}
	ntype = *OpenLDAPacitypes[ idx ];

	/* subject */
	bv_get_tail( val, &type, &subject );

	if ( BER_BVISEMPTY( &subject ) || subject.bv_val[ 0 ] != '#' ) {
	        Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: missing subject in '%s'\n", val->bv_val );
		rc = LDAP_INVALID_SYNTAX;
		goto cleanup;
	}

	subject.bv_val++;
	subject.bv_len--;

	if ( idx < LAST_DNVALUED ) {
		/* FIXME: pass DN syntax? */
		if ( normalize ) {
			rc = dnNormalize( 0, NULL, NULL,
				&subject, &nsubject, ctx );
		} else {
			rc = dnPretty( NULL, &subject, &nsubject, ctx );
		}

		if ( rc == LDAP_SUCCESS ) {
			freesubject = 1;

		} else {
	                Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid subject dn '%s'\n", subject.bv_val );
			goto cleanup;
		}

		if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_GROUP ]
			|| OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_ROLE ] )
		{
			/* do {group|role}/oc/at check */
			struct berval	ocbv = BER_BVNULL,
					atbv = BER_BVNULL;

			ocbv.bv_val = ber_bvchr( &type, '/' );
			if ( ocbv.bv_val != NULL ) {
				ObjectClass		*oc = NULL;
				AttributeDescription	*ad = NULL;
				const char		*text = NULL;
				int			rc;
				struct berval		bv;

				bv.bv_len = ntype.bv_len;

				ocbv.bv_val++;
				ocbv.bv_len = type.bv_len - ( ocbv.bv_val - type.bv_val );

				atbv.bv_val = ber_bvchr( &ocbv, '/' );
				if ( atbv.bv_val != NULL ) {
					atbv.bv_val++;
					atbv.bv_len = type.bv_len
						- ( atbv.bv_val - type.bv_val );
					ocbv.bv_len = atbv.bv_val - ocbv.bv_val - 1;

					rc = slap_bv2ad( &atbv, &ad, &text );
					if ( rc != LDAP_SUCCESS ) {
	                                        Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: unknown group attribute '%s'\n", atbv.bv_val );
						rc = LDAP_INVALID_SYNTAX;
						goto cleanup;
					}

					bv.bv_len += STRLENOF( "/" ) + ad->ad_cname.bv_len;
				}

				oc = oc_bvfind( &ocbv );
				if ( oc == NULL ) {
                                        Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: invalid group '%s'\n", ocbv.bv_val );
					rc = LDAP_INVALID_SYNTAX;
					goto cleanup;
				}

				bv.bv_len += STRLENOF( "/" ) + oc->soc_cname.bv_len;
				bv.bv_val = ber_memalloc_x( bv.bv_len + 1, ctx );

				ptr = bv.bv_val;
				ptr = lutil_strncopy( ptr, ntype.bv_val, ntype.bv_len );
				ptr[ 0 ] = '/';
				ptr++;
				ptr = lutil_strncopy( ptr,
					oc->soc_cname.bv_val,
					oc->soc_cname.bv_len );
				if ( ad != NULL ) {
					ptr[ 0 ] = '/';
					ptr++;
					ptr = lutil_strncopy( ptr,
						ad->ad_cname.bv_val,
						ad->ad_cname.bv_len );
				}
				ptr[ 0 ] = '\0';

				ntype = bv;
				freetype = 1;
			}
		}

	} else if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_DNATTR ] ) {
		AttributeDescription	*ad = NULL;
		const char		*text = NULL;
		int			rc;

		rc = slap_bv2ad( &subject, &ad, &text );
		if ( rc != LDAP_SUCCESS ) {
                        Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: unknown dn attribute '%s'\n", subject.bv_val );
			rc = LDAP_INVALID_SYNTAX;
			goto cleanup;
		}

		if ( ad->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
			/* FIXME: allow nameAndOptionalUID? */
                        Debug( LDAP_DEBUG_ACL, "aciPrettyNormal: wrong syntax for dn attribute '%s'\n", subject.bv_val );
			rc = LDAP_INVALID_SYNTAX;
			goto cleanup;
		}

		nsubject = ad->ad_cname;

	} else if ( OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_SET ]
		|| OpenLDAPacitypes[ idx ] == &aci_bv[ ACI_BV_SET_REF ] )
	{
		/* NOTE: dunno how to normalize it... */
		nsubject = subject;
	}


	out->bv_len =
		oid.bv_len + STRLENOF( "#" )
		+ scope.bv_len + STRLENOF( "#" )
		+ nrights.bv_len + STRLENOF( "#" )
		+ ntype.bv_len + STRLENOF( "#" )
		+ nsubject.bv_len;

	out->bv_val = ber_memalloc_x( out->bv_len + 1, ctx );
	ptr = lutil_strncopy( out->bv_val, oid.bv_val, oid.bv_len );
	ptr[ 0 ] = '#';
	ptr++;
	ptr = lutil_strncopy( ptr, scope.bv_val, scope.bv_len );
	ptr[ 0 ] = '#';
	ptr++;
	ptr = lutil_strncopy( ptr, nrights.bv_val, nrights.bv_len );
	ptr[ 0 ] = '#';
	ptr++;
	ptr = lutil_strncopy( ptr, ntype.bv_val, ntype.bv_len );
	ptr[ 0 ] = '#';
	ptr++;
	if ( !BER_BVISNULL( &nsubject ) ) {
		ptr = lutil_strncopy( ptr, nsubject.bv_val, nsubject.bv_len );
	}
	ptr[ 0 ] = '\0';

cleanup:;
	if ( freesubject ) {
		ber_memfree_x( nsubject.bv_val, ctx );
	}

	if ( freetype ) {
		ber_memfree_x( ntype.bv_val, ctx );
	}

	if ( !BER_BVISNULL( &nrights ) ) {
		ber_memfree_x( nrights.bv_val, ctx );
	}

	return rc;
}
Пример #2
0
struct berbuf *
backsql_strfcat_x( struct berbuf *dest, void *memctx, const char *fmt, ... )
{
	va_list		strs;
	ber_len_t	cdlen;

	assert( dest != NULL );
	assert( fmt != NULL );
	assert( dest->bb_len == 0 || dest->bb_len > dest->bb_val.bv_len );
	assert( dest->bb_val.bv_val == NULL 
			|| dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) );
 
#ifdef BACKSQL_TRACE
	Debug( LDAP_DEBUG_TRACE, "==>backsql_strfcat()\n", 0, 0, 0 );
#endif /* BACKSQL_TRACE */

	va_start( strs, fmt );
	if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) {
		dest->bb_val.bv_val = (char *)ber_memalloc_x( BACKSQL_STR_GROW * sizeof( char ), memctx );
		dest->bb_val.bv_len = 0;
		dest->bb_len = BACKSQL_STR_GROW;
	}

	cdlen = dest->bb_val.bv_len;
	for ( ; fmt[0]; fmt++ ) {
		ber_len_t	cslen, grow;
		char		*cstr, cc[ 2 ] = { '\0', '\0' };
		struct berval	*cbv;

		switch ( fmt[ 0 ] ) {

		/* berval */
		case 'b':
			cbv = va_arg( strs, struct berval * );
			cstr = cbv->bv_val;
			cslen = cbv->bv_len;
			break;

		/* length + string */
		case 'l':
			cslen = va_arg( strs, ber_len_t );
			cstr = va_arg( strs, char * );
			break;

		/* string */
		case 's':
			cstr = va_arg( strs, char * );
			cslen = strlen( cstr );
			break;

		/* char */
		case 'c':
			/* 
			 * `char' is promoted to `int' when passed through `...'
			 */
			cc[0] = va_arg( strs, int );
			cstr = cc;
			cslen = 1;
			break;

		default:
			assert( 0 );
		}

		grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen );
		if ( dest->bb_len - cdlen <= cslen ) {
			char	*tmp_dest;

#ifdef BACKSQL_TRACE
			Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
				"buflen=%d, cdlen=%d, cslen=%d "
				"-- reallocating dest\n",
				dest->bb_len, cdlen + 1, cslen );
#endif /* BACKSQL_TRACE */

			tmp_dest = (char *)ber_memrealloc_x( dest->bb_val.bv_val,
					( dest->bb_len ) + grow * sizeof( char ), memctx );
			if ( tmp_dest == NULL ) {
				Debug( LDAP_DEBUG_ANY, "backsql_strfcat(): "
					"could not reallocate string buffer.\n",
					0, 0, 0 );
				return NULL;
			}
			dest->bb_val.bv_val = tmp_dest;
			dest->bb_len += grow * sizeof( char );

#ifdef BACKSQL_TRACE
			Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
				"new buflen=%d, dest=%p\n", dest->bb_len, dest, 0 );
#endif /* BACKSQL_TRACE */
		}

		assert( cstr != NULL );
		
		AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 );
		cdlen += cslen;
	}

	va_end( strs );

#ifdef BACKSQL_TRACE
	Debug( LDAP_DEBUG_TRACE, "<==backsql_strfcat() (dest=\"%s\")\n", 
			dest->bb_val.bv_val, 0, 0 );
#endif /* BACKSQL_TRACE */

	dest->bb_val.bv_len = cdlen;

	return dest;
} 
Пример #3
0
struct berbuf *
backsql_strcat_x( struct berbuf *dest, void *memctx, ... )
{
	va_list		strs;
	ber_len_t	cdlen, cslen, grow;
	char		*cstr;

	assert( dest != NULL );
	assert( dest->bb_val.bv_val == NULL 
			|| dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) );
 
#ifdef BACKSQL_TRACE
	Debug( LDAP_DEBUG_TRACE, "==>backsql_strcat()\n", 0, 0, 0 );
#endif /* BACKSQL_TRACE */

	va_start( strs, memctx );
	if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) {
		dest->bb_val.bv_val = (char *)ber_memalloc_x( BACKSQL_STR_GROW * sizeof( char ), memctx );
		dest->bb_val.bv_len = 0;
		dest->bb_len = BACKSQL_STR_GROW;
	}
	cdlen = dest->bb_val.bv_len;
	while ( ( cstr = va_arg( strs, char * ) ) != NULL ) {
		cslen = strlen( cstr );
		grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen );
		if ( dest->bb_len - cdlen <= cslen ) {
			char	*tmp_dest;

#ifdef BACKSQL_TRACE
			Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
				"buflen=%d, cdlen=%d, cslen=%d "
				"-- reallocating dest\n",
				dest->bb_len, cdlen + 1, cslen );
#endif /* BACKSQL_TRACE */

			tmp_dest = (char *)ber_memrealloc_x( dest->bb_val.bv_val,
					dest->bb_len + grow * sizeof( char ), memctx );
			if ( tmp_dest == NULL ) {
				Debug( LDAP_DEBUG_ANY, "backsql_strcat(): "
					"could not reallocate string buffer.\n",
					0, 0, 0 );
				return NULL;
			}
			dest->bb_val.bv_val = tmp_dest;
			dest->bb_len += grow;

#ifdef BACKSQL_TRACE
			Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
				"new buflen=%d, dest=%p\n",
				dest->bb_len, dest, 0 );
#endif /* BACKSQL_TRACE */
		}
		AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 );
		cdlen += cslen;
	}
	va_end( strs );

#ifdef BACKSQL_TRACE
	Debug( LDAP_DEBUG_TRACE, "<==backsql_strcat() (dest=\"%s\")\n", 
			dest->bb_val.bv_val, 0, 0 );
#endif /* BACKSQL_TRACE */

	dest->bb_val.bv_len = cdlen;

	return dest;
} 
Пример #4
0
int
asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc, int candidate)
{
	a_metainfo_t	*mi;
	a_metatarget_t	*mt;
	a_metasingleconn_t *msc;
	Operation *op = bc->op;
	SlapReply *rs;
	int	   i, rc = LDAP_SUCCESS, sres;
	SlapReply *candidates;
	char		**references = NULL;
	LDAPControl	**ctrls = NULL;
	a_dncookie dc;
	LDAPMessage *msg;
	ber_int_t id;

	rs = &bc->rs;
	mi = mc->mc_info;
	mt = mi->mi_targets[ candidate ];
	msc = &mc->mc_conns[ candidate ];
	dc.op = op;
	dc.target = mt;
	dc.to_from = MASSAGE_REP;
	id = ldap_msgid(res);


	candidates = bc->candidates;
	i = candidate;

	while (res && !META_BACK_CONN_INVALID(msc)) {
	for (msg = ldap_first_message(msc->msc_ldr, res); msg; msg = ldap_next_message(msc->msc_ldr, msg)) {
		switch(ldap_msgtype(msg)) {
		case LDAP_RES_SEARCH_ENTRY:
			Debug( LDAP_DEBUG_TRACE,
				"%s asyncmeta_handle_search_msg: msc %p entry\n",
				op->o_log_prefix, msc );
			if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
				/* don't retry any more... */
				candidates[ i ].sr_type = REP_RESULT;
			}
			/* count entries returned by target */
			candidates[ i ].sr_nentries++;
			if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !op->o_abandon) {
				rs->sr_err = asyncmeta_send_entry( &bc->copy_op, rs, mc, i, msg );
			} else {
				goto err_cleanup;
			}
			switch ( rs->sr_err ) {
			case LDAP_SIZELIMIT_EXCEEDED:
				asyncmeta_send_ldap_result(bc, op, rs);
				rs->sr_err = LDAP_SUCCESS;
				goto err_cleanup;
			case LDAP_UNAVAILABLE:
				rs->sr_err = LDAP_OTHER;
				break;
			default:
				break;
			}
			bc->is_ok++;
			break;

		case LDAP_RES_SEARCH_REFERENCE:
			if ( META_BACK_TGT_NOREFS( mt ) ) {
				rs->sr_err = LDAP_OTHER;
				asyncmeta_send_ldap_result(bc, op, rs);
				goto err_cleanup;
			}
			if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
				/* don't retry any more... */
				candidates[ i ].sr_type = REP_RESULT;
			}
			bc->is_ok++;
			rc = ldap_parse_reference( msc->msc_ldr, msg,
				   &references, &rs->sr_ctrls, 0 );

			if ( rc != LDAP_SUCCESS || references == NULL ) {
				rs->sr_err = LDAP_OTHER;
				asyncmeta_send_ldap_result(bc, op, rs);
				goto err_cleanup;
			}

			/* FIXME: merge all and return at the end */

			{
				int cnt;
				for ( cnt = 0; references[ cnt ]; cnt++ )
					;

				rs->sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
								 op->o_tmpmemctx );

				for ( cnt = 0; references[ cnt ]; cnt++ ) {
					ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ],
							  op->o_tmpmemctx );
				}
				BER_BVZERO( &rs->sr_ref[ cnt ] );
			}

			{
				dc.memctx = op->o_tmpmemctx;
				( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref );
			}

			if ( rs->sr_ref != NULL ) {
				if (!BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
					/* ignore return value by now */
					( void )send_search_reference( op, rs );
				}

				ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx );
				rs->sr_ref = NULL;
			}

			/* cleanup */
			if ( references ) {
				ber_memvfree( (void **)references );
			}

			if ( rs->sr_ctrls ) {
				ldap_controls_free( rs->sr_ctrls );
				rs->sr_ctrls = NULL;
			}
			break;

		case LDAP_RES_INTERMEDIATE:
			if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
				/* don't retry any more... */
				candidates[ i ].sr_type = REP_RESULT;
			}
			bc->is_ok++;

			/* FIXME: response controls
			 * are passed without checks */
			rs->sr_err = ldap_parse_intermediate( msc->msc_ldr,
								  msg,
								  (char **)&rs->sr_rspoid,
								  &rs->sr_rspdata,
								  &rs->sr_ctrls,
								  0 );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				candidates[ i ].sr_type = REP_RESULT;
				rs->sr_err = LDAP_OTHER;
				asyncmeta_send_ldap_result(bc, op, rs);
				goto err_cleanup;
			}

			slap_send_ldap_intermediate( op, rs );

			if ( rs->sr_rspoid != NULL ) {
				ber_memfree( (char *)rs->sr_rspoid );
				rs->sr_rspoid = NULL;
			}

			if ( rs->sr_rspdata != NULL ) {
				ber_bvfree( rs->sr_rspdata );
				rs->sr_rspdata = NULL;
			}

			if ( rs->sr_ctrls != NULL ) {
				ldap_controls_free( rs->sr_ctrls );
				rs->sr_ctrls = NULL;
			}
			break;

		case LDAP_RES_SEARCH_RESULT:
			if ( mi->mi_idle_timeout != 0 ) {
				asyncmeta_set_msc_time(msc);
			}
			Debug( LDAP_DEBUG_TRACE,
			       "%s asyncmeta_handle_search_msg: msc %p result\n",
			       op->o_log_prefix, msc );
			candidates[ i ].sr_type = REP_RESULT;
			candidates[ i ].sr_msgid = META_MSGID_IGNORE;
			/* NOTE: ignores response controls
			 * (and intermediate response controls
			 * as well, except for those with search
			 * references); this may not be correct,
			 * but if they're not ignored then
			 * back-meta would need to merge them
			 * consistently (think of pagedResults...)
			 */
			/* FIXME: response controls? */
			rs->sr_err = ldap_parse_result( msc->msc_ldr,
							msg,
							&candidates[ i ].sr_err,
								(char **)&candidates[ i ].sr_matched,
							(char **)&candidates[ i ].sr_text,
							&references,
							&ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
							0 );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				candidates[ i ].sr_err = rs->sr_err;
				sres = slap_map_api2result( &candidates[ i ] );
				candidates[ i ].sr_type = REP_RESULT;
				goto finish;
			}

			rs->sr_err = candidates[ i ].sr_err;

			/* massage matchedDN if need be */
			if ( candidates[ i ].sr_matched != NULL ) {
				struct berval	match, mmatch;

				ber_str2bv( candidates[ i ].sr_matched,
						0, 0, &match );
				candidates[ i ].sr_matched = NULL;

				dc.memctx = NULL;
				asyncmeta_dn_massage( &dc, &match, &mmatch );
				if ( mmatch.bv_val == match.bv_val ) {
					candidates[ i ].sr_matched
						= ch_strdup( mmatch.bv_val );

				} else {
					candidates[ i ].sr_matched = mmatch.bv_val;
				}

				bc->candidate_match++;
				ldap_memfree( match.bv_val );
			}

			/* add references to array */
			/* RFC 4511: referrals can only appear
			 * if result code is LDAP_REFERRAL */
			if ( references != NULL
				 && references[ 0 ] != NULL
				 && references[ 0 ][ 0 ] != '\0' )
			{
				if ( rs->sr_err != LDAP_REFERRAL ) {
					Debug( LDAP_DEBUG_ANY,
						   "%s asncmeta_search_result[%d]: "
						   "got referrals with err=%d\n",
						   op->o_log_prefix,
						   i, rs->sr_err );

				} else {
					BerVarray	sr_ref;
					int		cnt;

					for ( cnt = 0; references[ cnt ]; cnt++ )
						;

					sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
								 op->o_tmpmemctx );

					for ( cnt = 0; references[ cnt ]; cnt++ ) {
						ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ],
								  op->o_tmpmemctx );
					}
					BER_BVZERO( &sr_ref[ cnt ] );

					dc.memctx = op->o_tmpmemctx;
					( void )asyncmeta_referral_result_rewrite( &dc, sr_ref );

					if ( rs->sr_v2ref == NULL ) {
						rs->sr_v2ref = sr_ref;

					} else {
						for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
							ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ],
									   op->o_tmpmemctx );
						}
						ber_memfree_x( sr_ref, op->o_tmpmemctx );
					}
				}

			} else if ( rs->sr_err == LDAP_REFERRAL ) {
				Debug( LDAP_DEBUG_TRACE,
					   "%s asyncmeta_search_result[%d]: "
					   "got err=%d with null "
					   "or empty referrals\n",
					   op->o_log_prefix,
					   i, rs->sr_err );

				rs->sr_err = LDAP_NO_SUCH_OBJECT;
			}

			/* cleanup */
			ber_memvfree( (void **)references );

			sres = slap_map_api2result( rs );

			if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d] "
				       "match=\"%s\" err=%ld",
				       op->o_log_prefix, i,
				       candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
				       (long) candidates[ i ].sr_err );
			} else {
					Debug( LDAP_DEBUG_ANY,  "%s asyncmeta_search_result[%d] "
				       "match=\"%s\" err=%ld (%s)",
				       op->o_log_prefix, i,
				       candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
					       (long) candidates[ i ].sr_err, ldap_err2string( candidates[ i ].sr_err ) );
			}

			switch ( sres ) {
			case LDAP_NO_SUCH_OBJECT:
				/* is_ok is touched any time a valid
				 * (even intermediate) result is
				 * returned; as a consequence, if
				 * a candidate returns noSuchObject
				 * it is ignored and the candidate
				 * is simply demoted. */
				if ( bc->is_ok ) {
					sres = LDAP_SUCCESS;
				}
				break;

			case LDAP_SUCCESS:
				if ( ctrls != NULL && ctrls[0] != NULL ) {
#ifdef SLAPD_META_CLIENT_PR
					LDAPControl *pr_c;

					pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
					if ( pr_c != NULL ) {
						BerElementBuffer berbuf;
						BerElement *ber = (BerElement *)&berbuf;
						ber_tag_t tag;
						ber_int_t prsize;
						struct berval prcookie;

						/* unsolicited, do not accept */
						if ( mt->mt_ps == 0 ) {
							rs->sr_err = LDAP_OTHER;
							goto err_pr;
						}

						ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );

						tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
						if ( tag == LBER_ERROR ) {
							rs->sr_err = LDAP_OTHER;
							goto err_pr;
						}

						/* more pages? new search request */
						if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
							if ( mt->mt_ps > 0 ) {
								/* ignore size if specified */
								prsize = 0;

							} else if ( prsize == 0 ) {
								/* guess the page size from the entries returned so far */
								prsize = candidates[ i ].sr_nentries;
							}

							candidates[ i ].sr_nentries = 0;
							candidates[ i ].sr_msgid = META_MSGID_IGNORE;
							candidates[ i ].sr_type = REP_INTERMEDIATE;

							assert( candidates[ i ].sr_matched == NULL );
							assert( candidates[ i ].sr_text == NULL );
							assert( candidates[ i ].sr_ref == NULL );

							switch ( asyncmeta_back_search_start( &bc->copy_op, rs, mc, bc, i, &prcookie, prsize, 1 ) )
							{
							case META_SEARCH_CANDIDATE:
								assert( candidates[ i ].sr_msgid >= 0 );
								ldap_controls_free( ctrls );
								//	goto free_message;

							case META_SEARCH_ERR:
							case META_SEARCH_NEED_BIND:
err_pr:;
								candidates[ i ].sr_err = rs->sr_err;
								candidates[ i ].sr_type = REP_RESULT;
								if ( META_BACK_ONERR_STOP( mi ) ) {
									asyncmeta_send_ldap_result(bc, op, rs);
									ldap_controls_free( ctrls );
									goto err_cleanup;
								}
								/* fallthru */

							case META_SEARCH_NOT_CANDIDATE:
								/* means that asyncmeta_back_search_start()
								 * failed but onerr == continue */
								candidates[ i ].sr_msgid = META_MSGID_IGNORE;
								candidates[ i ].sr_type = REP_RESULT;
								break;

							default:
								/* impossible */
								assert( 0 );
								break;
							}
							break;
						}
					}
#endif /* SLAPD_META_CLIENT_PR */

					ldap_controls_free( ctrls );
				}
				/* fallthru */

			case LDAP_REFERRAL:
				bc->is_ok++;
				break;

			case LDAP_SIZELIMIT_EXCEEDED:
				/* if a target returned sizelimitExceeded
				 * and the entry count is equal to the
				 * proxy's limit, the target would have
				 * returned more, and the error must be
				 * propagated to the client; otherwise,
				 * the target enforced a limit lower
				 * than what requested by the proxy;
				 * ignore it */
				candidates[ i ].sr_err = rs->sr_err;
				if ( rs->sr_nentries == op->ors_slimit
					 || META_BACK_ONERR_STOP( mi ) )
				{
					const char *save_text;
got_err:
					save_text = rs->sr_text;
					rs->sr_text = candidates[ i ].sr_text;
					asyncmeta_send_ldap_result(bc, op, rs);
					if (candidates[ i ].sr_text != NULL) {
						ch_free( (char *)candidates[ i ].sr_text );
						candidates[ i ].sr_text = NULL;
					}
					rs->sr_text = save_text;
					ldap_controls_free( ctrls );
					goto err_cleanup;
				}
				break;

			default:
				candidates[ i ].sr_err = rs->sr_err;
				if ( META_BACK_ONERR_STOP( mi ) ) {
					goto got_err;
				}
				break;
			}
			/* if this is the last result we will ever receive, send it back  */
			rc = rs->sr_err;
			if (asyncmeta_is_last_result(mc, bc, i) == 0) {
				Debug( LDAP_DEBUG_TRACE,
					"%s asyncmeta_handle_search_msg: msc %p last result\n",
					op->o_log_prefix, msc );
				asyncmeta_search_last_result(mc, bc, i, sres);
err_cleanup:
				rc = rs->sr_err;
				ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
				asyncmeta_drop_bc( mc, bc);
				asyncmeta_clear_bm_context(bc);
				ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
				ldap_msgfree(res);
				return rc;
			}
finish:
			break;

		default:
			continue;
		}
	}
		ldap_msgfree(res);
		res = NULL;
		if (candidates[ i ].sr_type != REP_RESULT) {
			struct timeval	tv = {0};
			rc = ldap_result( msc->msc_ldr, id, LDAP_MSG_RECEIVED, &tv, &res );
			if (res != NULL) {
				msc->msc_result_time = slap_get_time();
			}
		}
	}
	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
	bc->bc_active--;
	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );

	return rc;
}
Пример #5
0
/*
 * Do basic attribute type checking and syntax validation.
 */
int slap_mods_check(
	Operation *op,
	Modifications *ml,
	const char **text,
	char *textbuf,
	size_t textlen,
	void *ctx )
{
	int rc;

	for( ; ml != NULL; ml = ml->sml_next ) {
		AttributeDescription *ad = NULL;

		/* convert to attribute description */
		if ( ml->sml_desc == NULL ) {
			rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
			if( rc != LDAP_SUCCESS ) {
				if ( get_no_schema_check( op )) {
					rc = slap_bv2undef_ad( &ml->sml_type, &ml->sml_desc,
						text, 0 );
				}
			}
			if( rc != LDAP_SUCCESS ) {
				snprintf( textbuf, textlen, "%s: %s",
					ml->sml_type.bv_val, *text );
				*text = textbuf;
				return rc;
			}
		}

		ad = ml->sml_desc;

		if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
			&& !slap_ad_is_binary( ad ))
		{
			/* attribute requires binary transfer */
			snprintf( textbuf, textlen,
				"%s: requires ;binary transfer",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_UNDEFINED_TYPE;
		}

		if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
			&& slap_ad_is_binary( ad ))
		{
			/* attribute does not require binary transfer */
			snprintf( textbuf, textlen,
				"%s: disallows ;binary transfer",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_UNDEFINED_TYPE;
		}

		if( slap_ad_is_tag_range( ad )) {
			/* attribute requires binary transfer */
			snprintf( textbuf, textlen,
				"%s: inappropriate use of tag range option",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_UNDEFINED_TYPE;
		}

#if 0
		if ( is_at_obsolete( ad->ad_type ) &&
			(( ml->sml_op != LDAP_MOD_REPLACE &&
				ml->sml_op != LDAP_MOD_DELETE ) ||
					ml->sml_values != NULL ))
		{
			/*
			 * attribute is obsolete,
			 * only allow replace/delete with no values
			 */
			snprintf( textbuf, textlen,
				"%s: attribute is obsolete",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_CONSTRAINT_VIOLATION;
		}
#endif

		if ( ml->sml_op == LDAP_MOD_INCREMENT &&
#ifdef SLAPD_REAL_SYNTAX
			!is_at_syntax( ad->ad_type, SLAPD_REAL_SYNTAX ) &&
#endif
			!is_at_syntax( ad->ad_type, SLAPD_INTEGER_SYNTAX ) )
		{
			/*
			 * attribute values must be INTEGER or REAL
			 */
			snprintf( textbuf, textlen,
				"%s: attribute syntax inappropriate for increment",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_CONSTRAINT_VIOLATION;
		}

		/*
		 * check values
		 */
		if( ml->sml_values != NULL ) {
			ber_len_t nvals;
			slap_syntax_validate_func *validate =
				ad->ad_type->sat_syntax->ssyn_validate;
			slap_syntax_transform_func *pretty =
				ad->ad_type->sat_syntax->ssyn_pretty;
 
			if( !pretty && !validate ) {
				*text = "no validator for syntax";
				snprintf( textbuf, textlen,
					"%s: no validator for syntax %s",
					ml->sml_type.bv_val,
					ad->ad_type->sat_syntax->ssyn_oid );
				*text = textbuf;
				return LDAP_INVALID_SYNTAX;
			}

			/*
			 * check that each value is valid per syntax
			 *	and pretty if appropriate
			 */
			for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
				struct berval pval;

				if ( pretty ) {
					rc = ordered_value_pretty( ad,
						&ml->sml_values[nvals], &pval, ctx );
				} else {
					rc = ordered_value_validate( ad,
						&ml->sml_values[nvals], ml->sml_op );
				}

				if( rc != 0 ) {
					snprintf( textbuf, textlen,
						"%s: value #%ld invalid per syntax",
						ml->sml_type.bv_val, (long) nvals );
					*text = textbuf;
					return LDAP_INVALID_SYNTAX;
				}

				if( pretty ) {
					ber_memfree_x( ml->sml_values[nvals].bv_val, ctx );
					ml->sml_values[nvals] = pval;
				}
			}
			ml->sml_values[nvals].bv_len = 0;
			ml->sml_numvals = nvals;

			/*
			 * a rough single value check... an additional check is needed
			 * to catch add of single value to existing single valued attribute
			 */
			if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
				&& nvals > 1 && is_at_single_value( ad->ad_type ))
			{
				snprintf( textbuf, textlen,
					"%s: multiple values provided",
					ml->sml_type.bv_val );
				*text = textbuf;
				return LDAP_CONSTRAINT_VIOLATION;
			}

			/* if the type has a normalizer, generate the
			 * normalized values. otherwise leave them NULL.
			 *
			 * this is different from the rule for attributes
			 * in an entry - in an attribute list, the normalized
			 * value is set equal to the non-normalized value
			 * when there is no normalizer.
			 */
			if( nvals && ad->ad_type->sat_equality &&
				ad->ad_type->sat_equality->smr_normalize )
			{
				ml->sml_nvalues = ber_memalloc_x(
					(nvals+1)*sizeof(struct berval), ctx );

				for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
					rc = ordered_value_normalize(
						SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
						ad,
						ad->ad_type->sat_equality,
						&ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx );
					if ( rc ) {
						Debug( LDAP_DEBUG_ANY,
							"<= str2entry NULL (ssyn_normalize %d)\n",
							rc, 0, 0 );
						snprintf( textbuf, textlen,
							"%s: value #%ld normalization failed",
							ml->sml_type.bv_val, (long) nvals );
						*text = textbuf;
						BER_BVZERO( &ml->sml_nvalues[nvals] );
						return rc;
					}
				}

				BER_BVZERO( &ml->sml_nvalues[nvals] );
			}

			/* check for duplicates, but ignore Deletes.
			 */
			if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) {
				int i;
				rc = slap_sort_vals( ml, text, &i, ctx );
				if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
					/* value exists already */
					snprintf( textbuf, textlen,
						"%s: value #%d provided more than once",
						ml->sml_desc->ad_cname.bv_val, i );
					*text = textbuf;
				}
				if ( rc )
					return rc;
			}
		} else {
			ml->sml_numvals = 0;
		}
	}

	return LDAP_SUCCESS;
}
Пример #6
0
static int
ldap_back_int_filter_map_rewrite(
		dncookie		*dc,
		Filter			*f,
		struct berval	*fstr,
		int				remap,
		void			*memctx )
{
	int		i;
	Filter		*p;
	struct berval	atmp,
			vtmp,
			*tmp;
	static struct berval
			/* better than nothing... */
			ber_bvfalse = BER_BVC( "(!(objectClass=*))" ),
			ber_bvtf_false = BER_BVC( "(|)" ),
			/* better than nothing... */
			ber_bvtrue = BER_BVC( "(objectClass=*)" ),
			ber_bvtf_true = BER_BVC( "(&)" ),
#if 0
			/* no longer needed; preserved for completeness */
			ber_bvundefined = BER_BVC( "(?=undefined)" ),
#endif
			ber_bverror = BER_BVC( "(?=error)" ),
			ber_bvunknown = BER_BVC( "(?=unknown)" ),
			ber_bvnone = BER_BVC( "(?=none)" );
	ber_len_t	len;

	assert( fstr != NULL );
	BER_BVZERO( fstr );

	if ( f == NULL ) {
		ber_dupbv_x( fstr, &ber_bvnone, memctx );
		return LDAP_OTHER;
	}

	switch ( ( f->f_choice & SLAPD_FILTER_MASK ) ) {
	case LDAP_FILTER_EQUALITY:
		if ( map_attr_value( dc, f->f_av_desc, &atmp,
					&f->f_av_value, &vtmp, remap, memctx ) )
		{
			goto computed;
		}

		fstr->bv_len = atmp.bv_len + vtmp.bv_len
			+ ( sizeof("(=)") - 1 );
		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );

		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );

		ber_memfree_x( vtmp.bv_val, memctx );
		break;

	case LDAP_FILTER_GE:
		if ( map_attr_value( dc, f->f_av_desc, &atmp,
					&f->f_av_value, &vtmp, remap, memctx ) )
		{
			goto computed;
		}

		fstr->bv_len = atmp.bv_len + vtmp.bv_len
			+ ( sizeof("(>=)") - 1 );
		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );

		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );

		ber_memfree_x( vtmp.bv_val, memctx );
		break;

	case LDAP_FILTER_LE:
		if ( map_attr_value( dc, f->f_av_desc, &atmp,
					&f->f_av_value, &vtmp, remap, memctx ) )
		{
			goto computed;
		}

		fstr->bv_len = atmp.bv_len + vtmp.bv_len
			+ ( sizeof("(<=)") - 1 );
		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );

		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );

		ber_memfree_x( vtmp.bv_val, memctx );
		break;

	case LDAP_FILTER_APPROX:
		if ( map_attr_value( dc, f->f_av_desc, &atmp,
					&f->f_av_value, &vtmp, remap, memctx ) )
		{
			goto computed;
		}

		fstr->bv_len = atmp.bv_len + vtmp.bv_len
			+ ( sizeof("(~=)") - 1 );
		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );

		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );

		ber_memfree_x( vtmp.bv_val, memctx );
		break;

	case LDAP_FILTER_SUBSTRINGS:
		if ( map_attr_value( dc, f->f_sub_desc, &atmp,
					NULL, NULL, remap, memctx ) )
		{
			goto computed;
		}

		/* cannot be a DN ... */

		fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128 ? */

		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
			atmp.bv_val );

		if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
			len = fstr->bv_len;

			filter_escape_value_x( &f->f_sub_initial, &vtmp, memctx );

			fstr->bv_len += vtmp.bv_len;
			fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );

			snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
				/* "(attr=" */ "%s*)",
				vtmp.bv_len ? vtmp.bv_val : "" );

			ber_memfree_x( vtmp.bv_val, memctx );
		}

		if ( f->f_sub_any != NULL ) {
			for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
				len = fstr->bv_len;
				filter_escape_value_x( &f->f_sub_any[i], &vtmp, memctx );

				fstr->bv_len += vtmp.bv_len + 1;
				fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );

				snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
					/* "(attr=[init]*[any*]" */ "%s*)",
					vtmp.bv_len ? vtmp.bv_val : "" );
				ber_memfree_x( vtmp.bv_val, memctx );
			}
		}

		if ( !BER_BVISNULL( &f->f_sub_final ) ) {
			len = fstr->bv_len;

			filter_escape_value_x( &f->f_sub_final, &vtmp, memctx );

			fstr->bv_len += vtmp.bv_len;
			fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );

			snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
				/* "(attr=[init*][any*]" */ "%s)",
				vtmp.bv_len ? vtmp.bv_val : "" );

			ber_memfree_x( vtmp.bv_val, memctx );
		}

		break;

	case LDAP_FILTER_PRESENT:
		if ( map_attr_value( dc, f->f_desc, &atmp,
					NULL, NULL, remap, memctx ) )
		{
			goto computed;
		}

		fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );

		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
			atmp.bv_val );
		break;

	case LDAP_FILTER_AND:
	case LDAP_FILTER_OR:
	case LDAP_FILTER_NOT:
		fstr->bv_len = STRLENOF( "(%)" );
		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx );	/* FIXME: why 128? */

		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
			f->f_choice == LDAP_FILTER_AND ? '&' :
			f->f_choice == LDAP_FILTER_OR ? '|' : '!' );

		for ( p = f->f_list; p != NULL; p = p->f_next ) {
			int	rc;

			len = fstr->bv_len;

			rc = ldap_back_int_filter_map_rewrite( dc, p, &vtmp, remap, memctx );
			if ( rc != LDAP_SUCCESS ) {
				return rc;
			}
			
			fstr->bv_len += vtmp.bv_len;
			fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );

			snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2, 
				/*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" );

			ber_memfree_x( vtmp.bv_val, memctx );
		}

		break;

	case LDAP_FILTER_EXT:
		if ( f->f_mr_desc ) {
			if ( map_attr_value( dc, f->f_mr_desc, &atmp,
						&f->f_mr_value, &vtmp, remap, memctx ) )
			{
				goto computed;
			}

		} else {
			BER_BVSTR( &atmp, "" );
			filter_escape_value_x( &f->f_mr_value, &vtmp, memctx );
		}

		/* FIXME: cleanup (less ?: operators...) */
		fstr->bv_len = atmp.bv_len +
			( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
			( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
			vtmp.bv_len + ( STRLENOF( "(:=)" ) );
		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );

		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
			atmp.bv_val,
			f->f_mr_dnattrs ? ":dn" : "",
			!BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
			!BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
			vtmp.bv_len ? vtmp.bv_val : "" );
		ber_memfree_x( vtmp.bv_val, memctx );
		break;

	case SLAPD_FILTER_COMPUTED:
		switch ( f->f_result ) {
		/* FIXME: treat UNDEFINED as FALSE */
		case SLAPD_COMPARE_UNDEFINED:
computed:;
			if ( META_BACK_TGT_NOUNDEFFILTER( dc->target ) ) {
				return LDAP_COMPARE_FALSE;
			}
			/* fallthru */

		case LDAP_COMPARE_FALSE:
			if ( META_BACK_TGT_T_F( dc->target ) ) {
				tmp = &ber_bvtf_false;
				break;
			}
			tmp = &ber_bvfalse;
			break;

		case LDAP_COMPARE_TRUE:
			if ( META_BACK_TGT_T_F( dc->target ) ) {
				tmp = &ber_bvtf_true;
				break;
			}

			tmp = &ber_bvtrue;
			break;

		default:
			tmp = &ber_bverror;
			break;
		}

		ber_dupbv_x( fstr, tmp, memctx );
		break;

	default:
		ber_dupbv_x( fstr, &ber_bvunknown, memctx );
		break;
	}

	return 0;
}
Пример #7
0
struct berval * UTF8bvnormalize(
	struct berval *bv,
	struct berval *newbv,
	unsigned flags,
	void *ctx )
{
	int i, j, len, clen, outpos, ucsoutlen, outsize, last;
	int didnewbv = 0;
	char *out, *outtmp, *s;
	ac_uint4 *ucs, *p, *ucsout;

	static unsigned char mask[] = {
		0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };

	unsigned casefold = flags & LDAP_UTF8_CASEFOLD;
	unsigned approx = flags & LDAP_UTF8_APPROX;

	if ( bv == NULL ) {
		return NULL;
	}

	s = bv->bv_val;
	len = bv->bv_len;

	if ( len == 0 ) {
		return ber_dupbv_x( newbv, bv, ctx );
	}

	if ( !newbv ) {
		newbv = ber_memalloc_x( sizeof(struct berval), ctx );
		if ( !newbv ) return NULL;
		didnewbv = 1;
	}

	/* Should first check to see if string is already in proper
	 * normalized form. This is almost as time consuming as
	 * the normalization though.
	 */

	/* finish off everything up to character before first non-ascii */
	if ( LDAP_UTF8_ISASCII( s ) ) {
		if ( casefold ) {
			outsize = len + 7;
			out = (char *) ber_memalloc_x( outsize, ctx );
			if ( out == NULL ) {
fail:
				if ( didnewbv )
					ber_memfree_x( newbv, ctx );
				return NULL;
			}
			outpos = 0;

			for ( i = 1; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) {
				out[outpos++] = TOLOWER( s[i-1] );
			}
			if ( i == len ) {
				out[outpos++] = TOLOWER( s[len-1] );
				out[outpos] = '\0';
				newbv->bv_val = out;
				newbv->bv_len = outpos;
				return newbv;
			}
		} else {
			for ( i = 1; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) {
				/* empty */
			}

			if ( i == len ) {
				return ber_str2bv_x( s, len, 1, newbv, ctx );
			}
				
			outsize = len + 7;
			out = (char *) ber_memalloc_x( outsize, ctx );
			if ( out == NULL ) {
				goto fail;
			}
			outpos = i - 1;
			memcpy(out, s, outpos);
		}
	} else {
		outsize = len + 7;
		out = (char *) ber_memalloc_x( outsize, ctx );
		if ( out == NULL ) {
			goto fail;
		}
		outpos = 0;
		i = 0;
	}

	p = ucs = ber_memalloc_x( len * sizeof(*ucs), ctx );
	if ( ucs == NULL ) {
		ber_memfree_x(out, ctx);
		goto fail;
	}

	/* convert character before first non-ascii to ucs-4 */
	if ( i > 0 ) {
		*p = casefold ? TOLOWER( s[i-1] ) : s[i-1];
		p++;
	}

	/* s[i] is now first non-ascii character */
	for (;;) {
		/* s[i] is non-ascii */
		/* convert everything up to next ascii to ucs-4 */
		while ( i < len ) {
			clen = LDAP_UTF8_CHARLEN2( s + i, clen );
			if ( clen == 0 ) {
				ber_memfree_x( ucs, ctx );
				ber_memfree_x( out, ctx );
				goto fail;
			}
			if ( clen == 1 ) {
				/* ascii */
				break;
			}
			*p = s[i] & mask[clen];
			i++;
			for( j = 1; j < clen; j++ ) {
				if ( (s[i] & 0xc0) != 0x80 ) {
					ber_memfree_x( ucs, ctx );
					ber_memfree_x( out, ctx );
					goto fail;
				}
				*p <<= 6;
				*p |= s[i] & 0x3f;
				i++;
			}
			if ( casefold ) {
				*p = uctolower( *p );
			}
			p++;
		}
		/* normalize ucs of length p - ucs */
		uccompatdecomp( ucs, p - ucs, &ucsout, &ucsoutlen, ctx );
		if ( approx ) {
			for ( j = 0; j < ucsoutlen; j++ ) {
				if ( ucsout[j] < 0x80 ) {
					out[outpos++] = ucsout[j];
				}
			}
		} else {
			ucsoutlen = uccanoncomp( ucsout, ucsoutlen );
			/* convert ucs to utf-8 and store in out */
			for ( j = 0; j < ucsoutlen; j++ ) {
				/* allocate more space if not enough room for
				   6 bytes and terminator */
				if ( outsize - outpos < 7 ) {
					outsize = ucsoutlen - j + outpos + 6;
					outtmp = (char *) ber_memrealloc_x( out, outsize, ctx );
					if ( outtmp == NULL ) {
						ber_memfree_x( ucsout, ctx );
						ber_memfree_x( ucs, ctx );
						ber_memfree_x( out, ctx );
						goto fail;
					}
					out = outtmp;
				}
				outpos += ldap_x_ucs4_to_utf8( ucsout[j], &out[outpos] );
			}
		}

		ber_memfree_x( ucsout, ctx );
		ucsout = NULL;
		
		if ( i == len ) {
			break;
		}

		last = i;

		/* Allocate more space in out if necessary */
		if (len - i >= outsize - outpos) {
			outsize += 1 + ((len - i) - (outsize - outpos));
			outtmp = (char *) ber_memrealloc_x(out, outsize, ctx);
			if (outtmp == NULL) {
				ber_memfree_x( ucs, ctx );
				ber_memfree_x( out, ctx );
				goto fail;
			}
			out = outtmp;
		}

		/* s[i] is ascii */
		/* finish off everything up to char before next non-ascii */
		for ( i++; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) {
			out[outpos++] = casefold ? TOLOWER( s[i-1] ) : s[i-1];
		}
		if ( i == len ) {
			out[outpos++] = casefold ? TOLOWER( s[len-1] ) : s[len-1];
			break;
		}

		/* convert character before next non-ascii to ucs-4 */
		*ucs = casefold ? TOLOWER( s[i-1] ) : s[i-1];
		p = ucs + 1;
	}

	ber_memfree_x( ucs, ctx );
	out[outpos] = '\0';
	newbv->bv_val = out;
	newbv->bv_len = outpos;
	return newbv;
}
Пример #8
0
/*
 * ldap_parse_ldif_record_x() will convert an LDIF record read with ldif_read_record()
 * into an array of LDAPMod* and an array of LDAPControl*, suitable for passing
 * directly to any other LDAP API function that takes LDAPMod** and LDAPControl**
 * arguments, such as ldap_modify_s().
 *
 * rbuf - the ldif record buffer returned from ldif_read_record - rbuf.bv_val must be
 *        writable - will use ldif_getline to read from it
 * linenum - the ldif line number returned from ldif_read_record
 *         - used for logging errors (e.g. error at line N)
 * lr - holds the data to return
 * errstr - a string used for logging (usually the program name e.g. "ldapmodify"
 * flags - 0 or some combination of LDIF_DEFAULT_ADD LDIF_ENTRIES_ONLY LDIF_NO_CONTROLS
 * ctx is the memory allocation context - if NULL, use the standard memory allocator
 */
int
ldap_parse_ldif_record_x(
	struct berval *rbuf,
	unsigned long linenum,
	LDIFRecord *lr,
	const char *errstr,
	unsigned int flags,
	void *ctx )
{
	char	*line, *dn;
	int		rc, modop;
	int		expect_modop, expect_sep;
	int		ldapadd, new_entry, delete_entry, got_all;
	LDAPMod	**pmods;
	int version;
	LDAPControl **pctrls;
	int i, j, k, idn, nmods;
	struct berval **bvl, bv;

	assert( lr != NULL );
	assert( rbuf != NULL );
	memset( lr, 0, sizeof(LDIFRecord) );
	lr->lr_ctx = ctx; /* save memory context for later */
	ldapadd = flags & LDIF_DEFAULT_ADD;
	new_entry = ldapadd;

	rc = got_all = delete_entry = modop = expect_modop = 0;
	expect_sep = 0;
	version = 0;
	pmods = NULL;
	pctrls = NULL;
	dn = NULL;

	lr->lr_lines = ldif_countlines( rbuf->bv_val );
	lr->lr_btype = ber_memcalloc_x( 1, (lr->lr_lines+1)*2*sizeof(struct berval)+lr->lr_lines, ctx );
	if ( !lr->lr_btype )
		return LDAP_NO_MEMORY;

	lr->lr_vals = lr->lr_btype+lr->lr_lines+1;
	lr->lr_freeval = (char *)(lr->lr_vals+lr->lr_lines+1);
	i = -1;

	while ( rc == 0 && ( line = ldif_getline( &rbuf->bv_val )) != NULL ) {
		int freev;

		if ( *line == '\n' || *line == '\0' ) {
			break;
		}

		++i;

		if ( line[0] == '-' && !line[1] ) {
			BER_BVZERO( lr->lr_btype+i );
			lr->lr_freeval[i] = 0;
			continue;
		}
	
		if ( ( rc = ldif_parse_line2( line, lr->lr_btype+i, lr->lr_vals+i, &freev ) ) < 0 ) {
			fprintf( stderr, _("%s: invalid format (line %lu) entry: \"%s\"\n"),
				errstr, linenum+i, dn == NULL ? "" : dn );
			rc = LDAP_PARAM_ERROR;
			goto leave;
		}
		lr->lr_freeval[i] = freev;

		if ( dn == NULL ) {
			if ( linenum+i == 1 && BV_CASEMATCH( lr->lr_btype+i, &BV_VERSION )) {
				/* lutil_atoi() introduces a dependence of libldap
				 * on liblutil; we only allow version 1 by now (ITS#6654)
				 */
#if 0
				int	v;
				if( lr->lr_vals[i].bv_len == 0 || lutil_atoi( &v, lr->lr_vals[i].bv_val) != 0 || v != 1 )
#endif
				static const struct berval version1 = { 1, "1" };
				if ( lr->lr_vals[i].bv_len != version1.bv_len || strncmp( lr->lr_vals[i].bv_val, version1.bv_val, version1.bv_len ) != 0 )
				{
					fprintf( stderr,
						_("%s: invalid version %s, line %lu (ignored)\n"),
						errstr, lr->lr_vals[i].bv_val, linenum );
				}
				version++;

			} else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_DN )) {
				lr->lr_dn = lr->lr_vals[i];
				dn = lr->lr_dn.bv_val; /* primarily for logging */
				idn = i;
			}
			/* skip all lines until we see "dn:" */
		}
	}

	/* check to make sure there was a dn: line */
	if ( !dn ) {
		rc = 0;
		goto leave;
	}

	lr->lr_lines = i+1;

	if( lr->lr_lines == 0 ) {
		rc = 0;
		goto leave;
	}

	if( version && lr->lr_lines == 1 ) {
		rc = 0;
		goto leave;
	}

	i = idn+1;
	/* Check for "control" tag after dn and before changetype. */
	if ( BV_CASEMATCH( lr->lr_btype+i, &BV_CONTROL )) {
		/* Parse and add it to the list of controls */
		if ( !( flags & LDIF_NO_CONTROLS ) ) {
			rc = parse_ldif_control( lr->lr_vals+i, &pctrls );
			if (rc != 0) {
				fprintf( stderr,
						 _("%s: Error processing %s line, line %lu: %s\n"),
						 errstr, BV_CONTROL.bv_val, linenum+i, ldap_err2string(rc) );
			}
		}
		i++;
		if ( i>= lr->lr_lines ) {
short_input:
			fprintf( stderr,
				_("%s: Expecting more input after %s line, line %lu\n"),
				errstr, lr->lr_btype[i-1].bv_val, linenum+i );
			
			rc = LDAP_PARAM_ERROR;
			goto leave;
		}
	}

	/* Check for changetype */
	if ( BV_CASEMATCH( lr->lr_btype+i, &BV_CHANGETYPE )) {
#ifdef LIBERAL_CHANGETYPE_MODOP
		/* trim trailing spaces (and log warning ...) */
		int icnt;
		for ( icnt = lr->lr_vals[i].bv_len; --icnt > 0; ) {
			if ( !isspace( (unsigned char) lr->lr_vals[i].bv_val[icnt] ) ) {
				break;
			}
		}

		if ( ++icnt != lr->lr_vals[i].bv_len ) {
			fprintf( stderr, _("%s: illegal trailing space after"
				" \"%s: %s\" trimmed (line %lu, entry \"%s\")\n"),
				errstr, BV_CHANGETYPE.bv_val, lr->lr_vals[i].bv_val, linenum+i, dn );
			lr->lr_vals[i].bv_val[icnt] = '\0';
		}
#endif /* LIBERAL_CHANGETYPE_MODOP */

		/* if LDIF_ENTRIES_ONLY, then either the changetype must be add, or
		   there must be no changetype, and the flag LDIF_DEFAULT_ADD must be set */
		if ( flags & LDIF_ENTRIES_ONLY ) {
			if ( !( BV_CASEMATCH( lr->lr_vals+i, &BV_ADDCT )) ) {
				ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
									_("%s: skipping LDIF record beginning at line %lu: "
									  "changetype '%.*s' found but entries only was requested\n"),
									errstr, linenum,
									(int)lr->lr_vals[i].bv_len,
									(const char *)lr->lr_vals[i].bv_val );
				goto leave;
			}
		}

		if ( BV_CASEMATCH( lr->lr_vals+i, &BV_MODIFYCT )) {
			new_entry = 0;
			expect_modop = 1;
		} else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_ADDCT )) {
			new_entry = 1;
			modop = LDAP_MOD_ADD;
		} else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_MODRDNCT )
			|| BV_CASEMATCH( lr->lr_vals+i, &BV_MODDNCT )
			|| BV_CASEMATCH( lr->lr_vals+i, &BV_RENAMECT ))
		{
			i++;
			if ( i >= lr->lr_lines )
				goto short_input;
			if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_NEWRDN )) {
				fprintf( stderr, _("%s: expecting \"%s:\" but saw"
					" \"%s:\" (line %lu, entry \"%s\")\n"),
					errstr, BV_NEWRDN.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn );
				rc = LDAP_PARAM_ERROR;
				goto leave;
			}
			lr->lrop_newrdn = lr->lr_vals[i];
			i++;
			if ( i >= lr->lr_lines )
				goto short_input;
			if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_DELETEOLDRDN )) {
				fprintf( stderr, _("%s: expecting \"%s:\" but saw"
					" \"%s:\" (line %lu, entry \"%s\")\n"),
					errstr, BV_DELETEOLDRDN.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn );
				rc = LDAP_PARAM_ERROR;
				goto leave;
			}
			lr->lrop_delold = ( lr->lr_vals[i].bv_val[0] == '0' ) ? 0 : 1;
			i++;
			if ( i < lr->lr_lines ) {
				if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_NEWSUP )) {
					fprintf( stderr, _("%s: expecting \"%s:\" but saw"
						" \"%s:\" (line %lu, entry \"%s\")\n"),
						errstr, BV_NEWSUP.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn );
					rc = LDAP_PARAM_ERROR;
					goto leave;
				}
				lr->lrop_newsup = lr->lr_vals[i];
				i++;
			}
			got_all = 1;
		} else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_DELETECT )) {
			got_all = delete_entry = 1;
		} else {
			fprintf( stderr,
				_("%s:  unknown %s \"%s\" (line %lu, entry \"%s\")\n"),
				errstr, BV_CHANGETYPE.bv_val, lr->lr_vals[i].bv_val, linenum+i, dn );
			rc = LDAP_PARAM_ERROR;
			goto leave;
		}
		i++;
	} else if ( ldapadd ) {		/*  missing changetype => add */
		new_entry = 1;
		modop = LDAP_MOD_ADD;
	} else {
		/* if LDIF_ENTRIES_ONLY, then either the changetype must be add, or
		   there must be no changetype, and the flag LDIF_DEFAULT_ADD must be set */
		if ( flags & LDIF_ENTRIES_ONLY ) {
			ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
								_("%s: skipping LDIF record beginning at line %lu: "
								  "no changetype found but entries only was requested and "
								  "the default setting for missing changetype is modify\n"),
								errstr, linenum );
			goto leave;
		}
		expect_modop = 1;	/* missing changetype => modify */
	}

	if ( got_all ) {
		if ( i < lr->lr_lines ) {
			fprintf( stderr,
				_("%s: extra lines at end (line %lu, entry \"%s\")\n"),
				errstr, linenum+i, dn );
			rc = LDAP_PARAM_ERROR;
			goto leave;
		}
		goto doit;
	}

	nmods = lr->lr_lines - i;
	idn = i;

	if ( new_entry ) {
		int fv;

		/* Make sure all attributes with multiple values are contiguous */
		for (; i<lr->lr_lines; i++) {
			for (j=i+1; j<lr->lr_lines; j++) {
				if ( !lr->lr_btype[j].bv_val ) {
					fprintf( stderr,
						_("%s: missing attributeDescription (line %lu, entry \"%s\")\n"),
						errstr, linenum+j, dn );
					rc = LDAP_PARAM_ERROR;
					goto leave;
				}
				if ( BV_CASEMATCH( lr->lr_btype+i, lr->lr_btype+j )) {
					nmods--;
					/* out of order, move intervening attributes down */
					if ( j != i+1 ) {
						bv = lr->lr_vals[j];
						fv = lr->lr_freeval[j];
						for (k=j; k>i; k--) {
							lr->lr_btype[k] = lr->lr_btype[k-1];
							lr->lr_vals[k] = lr->lr_vals[k-1];
							lr->lr_freeval[k] = lr->lr_freeval[k-1];
						}
						k++;
						lr->lr_btype[k] = lr->lr_btype[i];
						lr->lr_vals[k] = bv;
						lr->lr_freeval[k] = fv;
					}
					i++;
				}
			}
		}
		/* Allocate space for array of mods, array of pointers to mods,
		 * and array of pointers to values, allowing for NULL terminators
		 * for the pointer arrays...
		 */
		lr->lr_lm = ber_memalloc_x( nmods * sizeof(LDAPMod) +
			(nmods+1) * sizeof(LDAPMod*) +
			(lr->lr_lines + nmods - idn) * sizeof(struct berval *), ctx );
		pmods = (LDAPMod **)(lr->lr_lm+nmods);
		bvl = (struct berval **)(pmods+nmods+1);

		j = 0;
		k = -1;
		BER_BVZERO(&bv);
		for (i=idn; i<lr->lr_lines; i++) {
			if ( BV_CASEMATCH( lr->lr_btype+i, &BV_DN )) {
				fprintf( stderr, _("%s: attributeDescription \"%s\":"
					" (possible missing newline"
						" after line %lu, entry \"%s\"?)\n"),
					errstr, lr->lr_btype[i].bv_val, linenum+i - 1, dn );
			}
			if ( !BV_CASEMATCH( lr->lr_btype+i, &bv )) {
				bvl[k++] = NULL;
				bv = lr->lr_btype[i];
				lr->lr_lm[j].mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
				lr->lr_lm[j].mod_type = bv.bv_val;
				lr->lr_lm[j].mod_bvalues = bvl+k;
				pmods[j] = lr->lr_lm+j;
				j++;
			}
			bvl[k++] = lr->lr_vals+i;
		}
		bvl[k] = NULL;
		pmods[j] = NULL;
		goto doit;
	}

	lr->lr_mops = ber_memalloc_x( lr->lr_lines+1, ctx );
	lr->lr_mops[lr->lr_lines] = M_SEP;
	lr->lr_mops[i-1] = M_SEP;

	for ( ; i<lr->lr_lines; i++ ) {
		if ( expect_modop ) {
#ifdef LIBERAL_CHANGETYPE_MODOP
			/* trim trailing spaces (and log warning ...) */
		    int icnt;
		    for ( icnt = lr->lr_vals[i].bv_len; --icnt > 0; ) {
				if ( !isspace( (unsigned char) lr->lr_vals[i].bv_val[icnt] ) ) break;
			}
    
			if ( ++icnt != lr->lr_vals[i].bv_len ) {
				fprintf( stderr, _("%s: illegal trailing space after"
					" \"%s: %s\" trimmed (line %lu, entry \"%s\")\n"),
					errstr, type, lr->lr_vals[i].bv_val, linenum+i, dn );
				lr->lr_vals[i].bv_val[icnt] = '\0';
			}
#endif /* LIBERAL_CHANGETYPE_MODOP */

			expect_modop = 0;
			expect_sep = 1;
			if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPADD )) {
				modop = LDAP_MOD_ADD;
				lr->lr_mops[i] = M_SEP;
				nmods--;
			} else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPREPLACE )) {
			/* defer handling these since they might have no values.
			 * Use the BVALUES flag to signal that these were
			 * deferred. If values are provided later, this
			 * flag will be switched off.
			 */
				modop = LDAP_MOD_REPLACE;
				lr->lr_mops[i] = modop | LDAP_MOD_BVALUES;
				lr->lr_btype[i] = lr->lr_vals[i];
			} else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPDELETE )) {
				modop = LDAP_MOD_DELETE;
				lr->lr_mops[i] = modop | LDAP_MOD_BVALUES;
				lr->lr_btype[i] = lr->lr_vals[i];
			} else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPINCREMENT )) {
				modop = LDAP_MOD_INCREMENT;
				lr->lr_mops[i] = M_SEP;
				nmods--;
			} else {	/* no modify op: invalid LDIF */
				fprintf( stderr, _("%s: modify operation type is missing at"
					" line %lu, entry \"%s\"\n"),
					errstr, linenum+i, dn );
				rc = LDAP_PARAM_ERROR;
				goto leave;
			}
			bv = lr->lr_vals[i];
		} else if ( expect_sep && BER_BVISEMPTY( lr->lr_btype+i )) {
			lr->lr_mops[i] = M_SEP;
			expect_sep = 0;
			expect_modop = 1;
			nmods--;
		} else {
			if ( !BV_CASEMATCH( lr->lr_btype+i, &bv )) {
				fprintf( stderr, _("%s: wrong attributeType at"
					" line %lu, entry \"%s\"\n"),
					errstr, linenum+i, dn );
				rc = LDAP_PARAM_ERROR;
				goto leave;
			}
			lr->lr_mops[i] = modop;
			/* If prev op was deferred and matches this type,
			 * clear the flag
			 */
			if ( (lr->lr_mops[i-1] & LDAP_MOD_BVALUES)
				&& BV_CASEMATCH( lr->lr_btype+i, lr->lr_btype+i-1 ))
			{
				lr->lr_mops[i-1] = M_SEP;
				nmods--;
			}
		}
	}

	/* Allocate space for array of mods, array of pointers to mods,
	 * and array of pointers to values, allowing for NULL terminators
	 * for the pointer arrays...
	 */
	lr->lr_lm = ber_memalloc_x( nmods * sizeof(LDAPMod) +
		(nmods+1) * sizeof(LDAPMod*) +
		(lr->lr_lines + nmods - idn) * sizeof(struct berval *), ctx );
	pmods = (LDAPMod **)(lr->lr_lm+nmods);
	bvl = (struct berval **)(pmods+nmods+1);

	j = 0;
	k = -1;
	BER_BVZERO(&bv);
	lr->lr_mops[idn-1] = M_SEP;
	for (i=idn; i<lr->lr_lines; i++) {
		if ( lr->lr_mops[i] == M_SEP )
			continue;
		if ( lr->lr_mops[i] != lr->lr_mops[i-1] || !BV_CASEMATCH( lr->lr_btype+i, &bv )) {
			bvl[k++] = NULL;
			bv = lr->lr_btype[i];
			lr->lr_lm[j].mod_op = lr->lr_mops[i] | LDAP_MOD_BVALUES;
			lr->lr_lm[j].mod_type = bv.bv_val;
			if ( lr->lr_mops[i] & LDAP_MOD_BVALUES ) {
				lr->lr_lm[j].mod_bvalues = NULL;
			} else {
				lr->lr_lm[j].mod_bvalues = bvl+k;
			}
			pmods[j] = lr->lr_lm+j;
			j++;
		}
		bvl[k++] = lr->lr_vals+i;
	}
	bvl[k] = NULL;
	pmods[j] = NULL;

doit:
	/* first, set the common fields */
	lr->lr_ctrls = pctrls;
	/* next, set the op */
	if ( delete_entry ) {
		lr->lr_op = LDAP_REQ_DELETE;
	} else if ( lr->lrop_newrdn.bv_val != NULL ) {
		lr->lr_op = LDAP_REQ_MODDN;
	} else {
		/* for now, either add or modify */
		lr->lrop_mods = pmods;
		if ( new_entry ) {
			lr->lr_op = LDAP_REQ_ADD;
		} else {
			lr->lr_op = LDAP_REQ_MODIFY;
		}
	}

leave:
	if ( rc != LDAP_SUCCESS ) {
		ldap_ldif_record_done( lr );
	}

	return( rc );
}