X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Fliblutil%2Fldif.c;h=2af75fb73236caec40a64534769da10db1b26c6e;hb=c3e28a5488a8011ef0352f48fca85c48679205ba;hp=05220b09472bbc1c12fe02e114cd4cf576e73883;hpb=dc0eacd40b625258355eea866d62188e5aa7ce3b;p=openldap diff --git a/libraries/liblutil/ldif.c b/libraries/liblutil/ldif.c index 05220b0947..2af75fb732 100644 --- a/libraries/liblutil/ldif.c +++ b/libraries/liblutil/ldif.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * 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 @@ -81,7 +81,14 @@ static const unsigned char b642nib[0x80] = { * 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 @@ -91,47 +98,66 @@ ldif_parse_line( 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; @@ -164,14 +190,15 @@ ldif_parse_line( 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 || @@ -179,8 +206,8 @@ ldif_parse_line( 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 ); } } @@ -194,7 +221,7 @@ ldif_parse_line( byte[1] = (nib & RIGHT4) << 4; /* third digit */ if ( p[2] == '=' ) { - vlen += 1; + value->bv_len += 1; break; } nib = b642nib[ p[2] & 0x7f ]; @@ -202,7 +229,7 @@ ldif_parse_line( byte[2] = (nib & RIGHT2) << 6; /* fourth digit */ if ( p[3] == '=' ) { - vlen += 2; + value->bv_len += 2; break; } nib = b642nib[ p[3] & 0x7f ]; @@ -210,59 +237,59 @@ ldif_parse_line( 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 ); } @@ -283,6 +310,21 @@ ldif_parse_line( * 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 ) { @@ -319,6 +361,131 @@ 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 @@ -439,10 +606,7 @@ ldif_sput( && 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; @@ -570,7 +734,7 @@ int ldif_is_not_printable( 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; } } @@ -581,25 +745,76 @@ int ldif_is_not_printable( 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"; @@ -609,7 +824,8 @@ ldif_read_record( 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; @@ -629,12 +845,46 @@ ldif_read_record( /* 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 )); + 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. + */ + break; + } + } } } } if ( *buflenp - lcur <= len ) { - *buflenp += len + BUFSIZ; + *buflenp += len + LDIF_MAXLINE; nbufp = ber_memrealloc( *bufp, *buflenp ); if( nbufp == NULL ) { return 0;