mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-15 03:01:09 +08:00
b73b0c6158
ldapsearch: use draft guidelines for determining when to use -t only writes binary attributes to files -tt writes all attributes to files output now lists URL instead of path to such files -T dir can be used to specify directory to create temp files in -V urlprefix can be used to change the URL prefix LDIF is now commented (can be disabled using -LL) LDIF now contains version attribute (can be disabled with -LLL) LDIF: put interface changed to allow caller to specify how to encode put interface uses draft guidelines for determine when to base64 encode wrapping kludged to match old off by one bug Tests: removed trailing space from some attributes (to avoid base64 encoding) enabled -LLL in defines.sh (should sed output to remove wrapping/comments/redundant separators) Misc: updated codes outputting LDIF to use new put interface TODO: handling of version attribute on input handling of URLs on input (ie: fetch URL)
273 lines
5.7 KiB
C
273 lines
5.7 KiB
C
/* entry.c - routines for dealing with entries */
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ac/ctype.h>
|
|
#include <ac/errno.h>
|
|
#include <ac/socket.h>
|
|
#include <ac/string.h>
|
|
|
|
#include "slap.h"
|
|
|
|
static unsigned char *ebuf; /* buf returned by entry2str */
|
|
static unsigned char *ecur; /* pointer to end of currently used ebuf */
|
|
static int emaxsize;/* max size of ebuf */
|
|
|
|
Entry *
|
|
str2entry( char *s )
|
|
{
|
|
int id = 0;
|
|
Entry *e;
|
|
Attribute **a;
|
|
char *type;
|
|
char *value;
|
|
char *next;
|
|
ber_len_t vlen;
|
|
int nvals, maxvals;
|
|
struct berval bval;
|
|
struct berval *vals[2];
|
|
char ptype[64];
|
|
|
|
/*
|
|
* In string format, an entry looks like this:
|
|
*
|
|
* <id>\n
|
|
* dn: <dn>\n
|
|
* [<attr>:[:] <value>\n]
|
|
* [<tab><continuedvalue>\n]*
|
|
* ...
|
|
*
|
|
* If a double colon is used after a type, it means the
|
|
* following value is encoded as a base 64 string. This
|
|
* happens if the value contains a non-printing character
|
|
* or newline.
|
|
*/
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "=> str2entry\n",
|
|
s ? s : "NULL", 0, 0 );
|
|
|
|
/* check to see if there's an id included */
|
|
next = s;
|
|
if ( isdigit( (unsigned char) *s ) ) {
|
|
id = atoi( s );
|
|
if ( (s = ldif_getline( &next )) == NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"<= str2entry NULL (missing newline after id)\n",
|
|
0, 0, 0 );
|
|
return( NULL );
|
|
}
|
|
}
|
|
|
|
/* initialize reader/writer lock */
|
|
e = (Entry *) ch_calloc( 1, sizeof(Entry) );
|
|
|
|
if( e == NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"<= str2entry NULL (entry allocation failed)\n",
|
|
0, 0, 0 );
|
|
return( NULL );
|
|
}
|
|
|
|
e->e_id = id;
|
|
e->e_private = NULL;
|
|
|
|
/* dn + attributes */
|
|
e->e_attrs = NULL;
|
|
vals[0] = &bval;
|
|
vals[1] = NULL;
|
|
ptype[0] = '\0';
|
|
while ( (s = ldif_getline( &next )) != NULL ) {
|
|
if ( *s == '\n' || *s == '\0' ) {
|
|
break;
|
|
}
|
|
|
|
if ( ldif_parse_line( s, &type, &value, &vlen ) != 0 ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"<= str2entry NULL (parse_line)\n", 0, 0, 0 );
|
|
continue;
|
|
}
|
|
|
|
if ( strcasecmp( type, ptype ) != 0 ) {
|
|
strncpy( ptype, type, sizeof(ptype) - 1 );
|
|
nvals = 0;
|
|
maxvals = 0;
|
|
a = NULL;
|
|
}
|
|
|
|
if ( strcasecmp( type, "dn" ) == 0 ) {
|
|
if ( e->e_dn != NULL ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"str2entry: entry %ld has multiple dns \"%s\" and \"%s\" (second ignored)\n",
|
|
e->e_id, e->e_dn, value );
|
|
continue;
|
|
}
|
|
e->e_dn = ch_strdup( value );
|
|
|
|
if ( e->e_ndn != NULL ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"str2entry: entry %ld already has a normalized dn \"%s\" for \"%s\" (first ignored)\n",
|
|
e->e_id, e->e_ndn, value );
|
|
free( e->e_ndn );
|
|
}
|
|
e->e_ndn = ch_strdup( value );
|
|
(void) dn_normalize_case( e->e_ndn );
|
|
continue;
|
|
}
|
|
|
|
bval.bv_val = value;
|
|
bval.bv_len = vlen;
|
|
if ( attr_merge_fast( e, type, vals, nvals, 1, &maxvals, &a )
|
|
!= 0 ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"<= str2entry NULL (attr_merge)\n", 0, 0, 0 );
|
|
entry_free( e );
|
|
return( NULL );
|
|
}
|
|
nvals++;
|
|
}
|
|
|
|
/* check to make sure there was a dn: line */
|
|
if ( e->e_dn == NULL ) {
|
|
Debug( LDAP_DEBUG_ANY, "str2entry: entry %ld has no dn\n",
|
|
e->e_id, 0, 0 );
|
|
entry_free( e );
|
|
return( NULL );
|
|
}
|
|
|
|
if ( e->e_ndn == NULL ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"str2entry: entry %ld (\"%s\") has no normalized dn\n",
|
|
e->e_id, e->e_dn, 0 );
|
|
entry_free( e );
|
|
return( NULL );
|
|
}
|
|
|
|
Debug(LDAP_DEBUG_TRACE, "<= str2entry(%s) -> %ld (0x%lx)\n",
|
|
e->e_dn, e->e_id, (unsigned long)e );
|
|
|
|
return( e );
|
|
}
|
|
|
|
#define GRABSIZE BUFSIZ
|
|
|
|
#define MAKE_SPACE( n ) { \
|
|
while ( ecur + (n) > ebuf + emaxsize ) { \
|
|
int offset; \
|
|
offset = (int) (ecur - ebuf); \
|
|
ebuf = (unsigned char *) ch_realloc( (char *) ebuf, \
|
|
emaxsize + GRABSIZE ); \
|
|
emaxsize += GRABSIZE; \
|
|
ecur = ebuf + offset; \
|
|
} \
|
|
}
|
|
|
|
char *
|
|
entry2str(
|
|
Entry *e,
|
|
int *len,
|
|
int printid
|
|
)
|
|
{
|
|
Attribute *a;
|
|
struct berval *bv;
|
|
int i, tmplen;
|
|
|
|
/*
|
|
* In string format, an entry looks like this:
|
|
* <id>\n
|
|
* dn: <dn>\n
|
|
* [<attr>: <value>\n]*
|
|
*/
|
|
|
|
ecur = ebuf;
|
|
|
|
if ( printid ) {
|
|
/* id + newline */
|
|
MAKE_SPACE( 10 );
|
|
sprintf( (char *) ecur, "%ld\n", e->e_id );
|
|
ecur = (unsigned char *) strchr( (char *) ecur, '\0' );
|
|
}
|
|
|
|
/* put the dn */
|
|
if ( e->e_dn != NULL ) {
|
|
/* put "dn: <dn>" */
|
|
tmplen = strlen( e->e_dn );
|
|
MAKE_SPACE( LDIF_SIZE_NEEDED( 2, tmplen ));
|
|
ldif_sput( (char **) &ecur, LDIF_PUT_VALUE, "dn", e->e_dn, tmplen );
|
|
}
|
|
|
|
/* put the attributes */
|
|
for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
|
|
/* put "<type>:[:] <value>" line for each value */
|
|
for ( i = 0; a->a_vals[i] != NULL; i++ ) {
|
|
bv = a->a_vals[i];
|
|
tmplen = strlen( a->a_type );
|
|
MAKE_SPACE( LDIF_SIZE_NEEDED( tmplen, bv->bv_len ));
|
|
ldif_sput( (char **) &ecur, LDIF_PUT_VALUE, a->a_type,
|
|
bv->bv_val, bv->bv_len );
|
|
}
|
|
}
|
|
MAKE_SPACE( 1 );
|
|
*ecur = '\0';
|
|
*len = ecur - ebuf;
|
|
|
|
return( (char *) ebuf );
|
|
}
|
|
|
|
void
|
|
entry_free( Entry *e )
|
|
{
|
|
Attribute *a, *next;
|
|
|
|
if ( e->e_dn != NULL ) {
|
|
free( e->e_dn );
|
|
e->e_dn = NULL;
|
|
}
|
|
if ( e->e_ndn != NULL ) {
|
|
free( e->e_ndn );
|
|
e->e_ndn = NULL;
|
|
}
|
|
for ( a = e->e_attrs; a != NULL; a = next ) {
|
|
next = a->a_next;
|
|
attr_free( a );
|
|
}
|
|
e->e_attrs = NULL;
|
|
e->e_private = NULL;
|
|
free( e );
|
|
}
|
|
|
|
/*
|
|
* These routines are used only by Backend.
|
|
*
|
|
* the Entry has three entry points (ways to find things):
|
|
*
|
|
* by entry e.g., if you already have an entry from the cache
|
|
* and want to delete it. (really by entry ptr)
|
|
* by dn e.g., when looking for the base object of a search
|
|
* by id e.g., for search candidates
|
|
*
|
|
* these correspond to three different avl trees that are maintained.
|
|
*/
|
|
|
|
int
|
|
entry_cmp( Entry *e1, Entry *e2 )
|
|
{
|
|
return( e1 < e2 ? -1 : (e1 > e2 ? 1 : 0) );
|
|
}
|
|
|
|
int
|
|
entry_dn_cmp( Entry *e1, Entry *e2 )
|
|
{
|
|
/* compare their normalized UPPERCASED dn's */
|
|
return( strcmp( e1->e_ndn, e2->e_ndn ) );
|
|
}
|
|
|
|
int
|
|
entry_id_cmp( Entry *e1, Entry *e2 )
|
|
{
|
|
return( e1->e_id < e2->e_id ? -1 : (e1->e_id > e2->e_id ? 1 : 0) );
|
|
}
|
|
|