/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2005 The OpenLDAP Foundation.
+ * Copyright 1998-2007 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* ldif_parse_line - takes a line of the form "type:[:] value" and splits it
* into components "type" and "value". if a double colon separates type from
* value, then value is encoded in base 64, and parse_line un-decodes it
- * (in place) before returning.
+ * (in place) before returning. The type and value are stored in malloc'd
+ * memory which must be freed by the caller.
+ *
+ * ldif_parse_line2 - operates in-place on input buffer, returning type
+ * in-place. Will return value in-place if possible, (must malloc for
+ * fetched URLs). If freeval is NULL, all return data will be malloc'd
+ * and the input line will be unmodified. Otherwise freeval is set to
+ * True if the value was malloc'd.
*/
int
char **valuep,
ber_len_t *vlenp
)
+{
+ struct berval type, value;
+ int rc = ldif_parse_line2( (char *)line, &type, &value, NULL );
+
+ *typep = type.bv_val;
+ *valuep = value.bv_val;
+ *vlenp = value.bv_len;
+ return rc;
+}
+
+int
+ldif_parse_line2(
+ char *line,
+ struct berval *type,
+ struct berval *value,
+ int *freeval
+)
{
char *s, *p, *d;
char nib;
int b64, url;
- char *freeme, *type, *value;
- ber_len_t vlen;
- *typep = NULL;
- *valuep = NULL;
- *vlenp = 0;
+ BER_BVZERO( type );
+ BER_BVZERO( value );
/* skip any leading space */
while ( isspace( (unsigned char) *line ) ) {
line++;
}
- freeme = ber_strdup( line );
+ if ( freeval ) {
+ *freeval = 0;
+ } else {
+ line = ber_strdup( line );
- if( freeme == NULL ) {
- ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
- _("ldif_parse_line: line malloc failed\n"));
- return( -1 );
+ if( line == NULL ) {
+ ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
+ _("ldif_parse_line: line malloc failed\n"));
+ return( -1 );
+ }
}
- type = freeme;
+ type->bv_val = line;
- s = strchr( type, ':' );
+ s = strchr( type->bv_val, ':' );
if ( s == NULL ) {
ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
_("ldif_parse_line: missing ':' after %s\n"),
- type );
- ber_memfree( freeme );
+ type->bv_val );
+ if ( !freeval ) ber_memfree( line );
return( -1 );
}
/* trim any space between type and : */
- for ( p = &s[-1]; p > type && isspace( * (unsigned char *) p ); p-- ) {
+ for ( p = &s[-1]; p > type->bv_val && isspace( * (unsigned char *) p ); p-- ) {
*p = '\0';
}
*s++ = '\0';
+ type->bv_len = s - type->bv_val - 1;
url = 0;
b64 = 0;
if ( *s == '\0' ) {
/* no value is present, error out */
ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
- _("ldif_parse_line: %s missing base64 value\n"), type );
- ber_memfree( freeme );
+ _("ldif_parse_line: %s missing base64 value\n"),
+ type->bv_val );
+ if ( !freeval ) ber_memfree( line );
return( -1 );
}
- byte = value = s;
+ byte = value->bv_val = s;
- for ( p = s, vlen = 0; p < d; p += 4, vlen += 3 ) {
+ for ( p = s, value->bv_len = 0; p < d; p += 4, value->bv_len += 3 ) {
int i;
for ( i = 0; i < 4; i++ ) {
if ( p[i] != '=' && (p[i] & 0x80 ||
ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
_("ldif_parse_line: %s: invalid base64 encoding"
" char (%c) 0x%x\n"),
- type, p[i], p[i] );
- ber_memfree( freeme );
+ type->bv_val, p[i], p[i] );
+ if ( !freeval ) ber_memfree( line );
return( -1 );
}
}
byte[1] = (nib & RIGHT4) << 4;
/* third digit */
if ( p[2] == '=' ) {
- vlen += 1;
+ value->bv_len += 1;
break;
}
nib = b642nib[ p[2] & 0x7f ];
byte[2] = (nib & RIGHT2) << 6;
/* fourth digit */
if ( p[3] == '=' ) {
- vlen += 2;
+ value->bv_len += 2;
break;
}
nib = b642nib[ p[3] & 0x7f ];
byte += 3;
}
- s[ vlen ] = '\0';
+ s[ value->bv_len ] = '\0';
} else if ( url ) {
if ( *s == '\0' ) {
/* no value is present, error out */
ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
- _("ldif_parse_line: %s missing URL value\n"), type );
- ber_memfree( freeme );
+ _("ldif_parse_line: %s missing URL value\n"),
+ type->bv_val );
+ if ( !freeval ) ber_memfree( line );
return( -1 );
}
- if( ldif_fetch_url( s, &value, &vlen ) ) {
+ if( ldif_fetch_url( s, &value->bv_val, &value->bv_len ) ) {
ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
_("ldif_parse_line: %s: URL \"%s\" fetch failed\n"),
- type, s );
- ber_memfree( freeme );
+ type->bv_val, s );
+ if ( !freeval ) ber_memfree( line );
return( -1 );
}
+ if ( freeval ) *freeval = 1;
} else {
- value = s;
- vlen = (int) (d - s);
+ value->bv_val = s;
+ value->bv_len = (int) (d - s);
}
- type = ber_strdup( type );
+ if ( !freeval ) {
+ struct berval bv = *type;
- if( type == NULL ) {
- ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
- _("ldif_parse_line: type malloc failed\n"));
- if( url ) ber_memfree( value );
- ber_memfree( freeme );
- return( -1 );
- }
+ ber_dupbv( type, &bv );
- if( !url ) {
- p = ber_memalloc( vlen + 1 );
- if( p == NULL ) {
+ if( BER_BVISNULL( type )) {
ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
- _("ldif_parse_line: value malloc failed\n"));
- ber_memfree( type );
- ber_memfree( freeme );
+ _("ldif_parse_line: type malloc failed\n"));
+ if( url ) ber_memfree( value->bv_val );
+ ber_memfree( line );
return( -1 );
}
- AC_MEMCPY( p, value, vlen );
- p[vlen] = '\0';
- value = p;
- }
- ber_memfree( freeme );
+ if( !url ) {
+ bv = *value;
+ ber_dupbv( value, &bv );
+ if( BER_BVISNULL( value )) {
+ ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
+ _("ldif_parse_line: value malloc failed\n"));
+ ber_memfree( type->bv_val );
+ ber_memfree( line );
+ return( -1 );
+ }
+ }
- *typep = type;
- *valuep = value;
- *vlenp = vlen;
+ ber_memfree( line );
+ }
return( 0 );
}
* which it updates and must be supplied on subsequent calls.
*/
+int
+ldif_countlines( LDAP_CONST char *buf )
+{
+ char *nl;
+ int ret = 0;
+
+ if ( !buf ) return ret;
+
+ for ( nl = strchr(buf, '\n'); nl; nl = strchr(nl, '\n') ) {
+ nl++;
+ if ( *nl != ' ' ) ret++;
+ }
+ return ret;
+}
+
char *
ldif_getline( char **next )
{
return( line );
}
+/*
+ * name and OID of attributeTypes that must be base64 encoded in any case
+ */
+typedef struct must_b64_encode_s {
+ struct berval name;
+ struct berval oid;
+} must_b64_encode_s;
+
+static must_b64_encode_s default_must_b64_encode[] = {
+ { BER_BVC( "userPassword" ), BER_BVC( "2.5.4.35" ) },
+ { BER_BVNULL, BER_BVNULL }
+};
+
+static must_b64_encode_s *must_b64_encode = default_must_b64_encode;
+
+/*
+ * register name and OID of attributeTypes that must always be base64
+ * encoded
+ *
+ * NOTE: this routine mallocs memory in a static struct which must
+ * be explicitly freed when no longer required
+ */
+int
+ldif_must_b64_encode_register( LDAP_CONST char *name, LDAP_CONST char *oid )
+{
+ int i;
+ ber_len_t len;
+
+ assert( must_b64_encode != NULL );
+ assert( name != NULL );
+ assert( oid != NULL );
+
+ len = strlen( name );
+
+ for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
+ if ( len != must_b64_encode[i].name.bv_len ) {
+ continue;
+ }
+
+ if ( strcasecmp( name, must_b64_encode[i].name.bv_val ) == 0 ) {
+ break;
+ }
+ }
+
+ if ( !BER_BVISNULL( &must_b64_encode[i].name ) ) {
+ return 1;
+ }
+
+ for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ )
+ /* just count */ ;
+
+ if ( must_b64_encode == default_must_b64_encode ) {
+ must_b64_encode = ber_memalloc( sizeof( must_b64_encode_s ) * ( i + 2 ) );
+
+ for ( i = 0; !BER_BVISNULL( &default_must_b64_encode[i].name ); i++ ) {
+ ber_dupbv( &must_b64_encode[i].name, &default_must_b64_encode[i].name );
+ ber_dupbv( &must_b64_encode[i].oid, &default_must_b64_encode[i].oid );
+ }
+
+ } else {
+ must_b64_encode_s *tmp;
+
+ tmp = ber_memrealloc( must_b64_encode,
+ sizeof( must_b64_encode_s ) * ( i + 2 ) );
+ if ( tmp == NULL ) {
+ return 1;
+ }
+ must_b64_encode = tmp;
+ }
+
+ ber_str2bv( name, len, 1, &must_b64_encode[i].name );
+ ber_str2bv( oid, 0, 1, &must_b64_encode[i].oid );
+
+ BER_BVZERO( &must_b64_encode[i + 1].name );
+
+ return 0;
+}
+
+void
+ldif_must_b64_encode_release( void )
+{
+ int i;
+
+ assert( must_b64_encode != NULL );
+
+ if ( must_b64_encode == default_must_b64_encode ) {
+ return;
+ }
+
+ for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
+ ber_memfree( must_b64_encode[i].name.bv_val );
+ ber_memfree( must_b64_encode[i].oid.bv_val );
+ }
+
+ ber_memfree( must_b64_encode );
+
+ must_b64_encode = default_must_b64_encode;
+}
+
+/*
+ * returns 1 iff the string corresponds to the name or the OID of any
+ * of the attributeTypes listed in must_b64_encode
+ */
+static int
+ldif_must_b64_encode( LDAP_CONST char *s )
+{
+ int i;
+ struct berval bv;
+
+ assert( must_b64_encode != NULL );
+ assert( s != NULL );
+
+ ber_str2bv( s, 0, 0, &bv );
+
+ for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
+ if ( ber_bvstrcasecmp( &must_b64_encode[i].name, &bv ) == 0
+ || ber_bvcmp( &must_b64_encode[i].oid, &bv ) == 0 )
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/* compatibility with U-Mich off by one bug */
#define LDIF_KLUDGE 1
&& strstr( name, ";binary" ) == NULL
#endif
#ifndef LDAP_PASSWD_DEBUG
- && (namelen != (sizeof("userPassword")-1)
- || strcasecmp( name, "userPassword" ) != 0) /* encode userPassword */
- && (namelen != (sizeof("2.5.4.35")-1)
- || strcasecmp( name, "2.5.4.35" ) != 0) /* encode userPassword */
+ && !ldif_must_b64_encode( name )
#endif
) {
int b64 = 0;
ber_len_t i;
for ( i = 0; val[i]; i++ ) {
- if ( !isascii( val[i] ) || !isprint( val[i] ) ) {
+ if ( !isascii( val[i] ) || !isprint( (unsigned char) val[i] ) ) {
return 1;
}
}
return 1;
}
+LDIFFP *
+ldif_open(
+ LDAP_CONST char *file,
+ LDAP_CONST char *mode
+)
+{
+ FILE *fp = fopen( file, mode );
+ LDIFFP *lfp = NULL;
+
+ if ( fp ) {
+ lfp = ber_memalloc( sizeof( LDIFFP ));
+ lfp->fp = fp;
+ lfp->prev = NULL;
+ }
+ return lfp;
+}
+
+void
+ldif_close(
+ LDIFFP *lfp
+)
+{
+ LDIFFP *prev;
+
+ while ( lfp ) {
+ fclose( lfp->fp );
+ prev = lfp->prev;
+ ber_memfree( lfp );
+ lfp = prev;
+ }
+}
+
+#define LDIF_MAXLINE 4096
+
/*
- * slap_read_ldif - read an ldif record. Return 1 for success, 0 for EOF.
+ * ldif_read_record - read an ldif record. Return 1 for success, 0 for EOF.
*/
int
ldif_read_record(
- FILE *fp,
+ LDIFFP *lfp,
int *lno, /* ptr to line number counter */
char **bufp, /* ptr to malloced output buffer */
int *buflenp ) /* ptr to length of *bufp */
{
- char linebuf[BUFSIZ], *line, *nbufp;
+ char linebuf[LDIF_MAXLINE], *line, *nbufp;
ber_len_t lcur = 0, len, linesize;
int last_ch = '\n', found_entry = 0, stop, top_comment = 0;
line = linebuf;
linesize = sizeof( linebuf );
- for ( stop = feof( fp ); !stop; last_ch = line[len-1] ) {
- if ( fgets( line, linesize, fp ) == NULL ) {
+ for ( stop = 0; !stop; last_ch = line[len-1] ) {
+ /* If we're at the end of this file, see if we should pop
+ * back to a previous file. (return from an include)
+ */
+ while ( feof( lfp->fp )) {
+ if ( lfp->prev ) {
+ LDIFFP *tmp = lfp->prev;
+ fclose( lfp->fp );
+ *lfp = *tmp;
+ ber_memfree( tmp );
+ } else {
+ stop = 1;
+ break;
+ }
+ }
+ if ( stop )
+ break;
+
+ if ( fgets( line, linesize, lfp->fp ) == NULL ) {
stop = 1;
/* Add \n in case the file does not end with newline */
line = "\n";
if ( last_ch == '\n' ) {
(*lno)++;
- if ( line[0] == '\n' ) {
+ if ( line[0] == '\n' ||
+ ( line[0] == '\r' && line[1] == '\n' )) {
if ( !found_entry ) {
lcur = 0;
top_comment = 0;
/* skip index */
continue;
}
+ if ( !strncasecmp( line, "include:",
+ STRLENOF("include:"))) {
+ FILE *fp2;
+ char *ptr;
+ found_entry = 0;
+
+ if ( line[len-1] == '\n' ) {
+ len--;
+ line[len] = '\0';
+ }
+ if ( line[len-1] == '\r' ) {
+ len--;
+ line[len] = '\0';
+ }
+
+ ptr = line + STRLENOF("include:");
+ while (isspace((unsigned char) *ptr)) ptr++;
+ fp2 = ldif_open_url( ptr );
+ if ( fp2 ) {
+ LDIFFP *lnew = ber_memalloc( sizeof( LDIFFP ));
+ if ( lnew == NULL ) {
+ fclose( fp2 );
+ return 0;
+ }
+ lnew->prev = lfp->prev;
+ lnew->fp = lfp->fp;
+ lfp->prev = lnew;
+ lfp->fp = fp2;
+ line[len] = '\n';
+ len++;
+ continue;
+ } else {
+ /* We failed to open the file, this should
+ * be reported as an error somehow.
+ */
+ ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
+ _("ldif_read_record: include %s failed\n"), ptr );
+ return 0;
+ }
+ }
}
}
}
if ( *buflenp - lcur <= len ) {
- *buflenp += len + BUFSIZ;
+ *buflenp += len + LDIF_MAXLINE;
nbufp = ber_memrealloc( *bufp, *buflenp );
if( nbufp == NULL ) {
return 0;