]> git.sur5r.net Git - openldap/blobdiff - libraries/liblutil/ldif.c
Sync with HEAD
[openldap] / libraries / liblutil / ldif.c
index 9d67b3cf75056ff54eb004c5b9b332a4d2de3136..bb5ab7e1a1da65cce3f9708ab4d44417f143571b 100644 (file)
@@ -2,7 +2,7 @@
 /* $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
@@ -86,7 +86,9 @@ static const unsigned char b642nib[0x80] = {
  *
  * 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).
+ * 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
@@ -97,35 +99,37 @@ ldif_parse_line(
     ber_len_t *vlenp
 )
 {
-       return ldif_parse_line2( line, typep, valuep, vlenp, NULL );
+       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(
-    LDAP_CONST char    *line,
-    char       **typep,
-    char       **valuep,
-    ber_len_t *vlenp,
-       int             *alloc
+    char       *line,
+       struct berval *type,
+       struct berval *value,
+       int             *freeval
 )
 {
        char    *s, *p, *d; 
        char    nib;
        int     b64, url;
-       char    *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++;
        }
 
-       if ( alloc ) {
-               *alloc = 0;
+       if ( freeval ) {
+               *freeval = 0;
        } else {
                line = ber_strdup( line );
 
@@ -136,23 +140,24 @@ ldif_parse_line2(
                }
        }
 
-       type = line;
+       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 );
-               if ( !alloc ) ber_memfree( line );
+                       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;
@@ -185,14 +190,15 @@ ldif_parse_line2(
                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 );
-                       if ( !alloc ) ber_memfree( line );
+                               _("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 ||
@@ -200,8 +206,8 @@ ldif_parse_line2(
                                        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] );
-                                       if ( !alloc ) ber_memfree( line );
+                                           type->bv_val, p[i], p[i] );
+                                       if ( !freeval ) ber_memfree( line );
                                        return( -1 );
                                }
                        }
@@ -215,7 +221,7 @@ ldif_parse_line2(
                        byte[1] = (nib & RIGHT4) << 4;
                        /* third digit */
                        if ( p[2] == '=' ) {
-                               vlen += 1;
+                               value->bv_len += 1;
                                break;
                        }
                        nib = b642nib[ p[2] & 0x7f ];
@@ -223,7 +229,7 @@ ldif_parse_line2(
                        byte[2] = (nib & RIGHT2) << 6;
                        /* fourth digit */
                        if ( p[3] == '=' ) {
-                               vlen += 2;
+                               value->bv_len += 2;
                                break;
                        }
                        nib = b642nib[ p[3] & 0x7f ];
@@ -231,63 +237,60 @@ ldif_parse_line2(
 
                        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 );
-                       if ( !alloc ) ber_memfree( line );
+                               _("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 );
-                       if ( !alloc ) ber_memfree( line );
+                               type->bv_val, s );
+                       if ( !freeval ) ber_memfree( line );
                        return( -1 );
                }
-               if ( alloc ) *alloc = 1;
+               if ( freeval ) *freeval = 1;
 
        } else {
-               value = s;
-               vlen = (int) (d - s);
+               value->bv_val = s;
+               value->bv_len = (int) (d - s);
        }
 
-       if ( !alloc ) {
-               type = ber_strdup( type );
+       if ( !freeval ) {
+               struct berval bv = *type;
+
+               ber_dupbv( type, &bv );
 
-               if( type == NULL ) {
+               if( BER_BVISNULL( type )) {
                        ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
                                _("ldif_parse_line: type malloc failed\n"));
-                       if( url ) ber_memfree( value );
+                       if( url ) ber_memfree( value->bv_val );
                        ber_memfree( line );
                        return( -1 );
                }
 
                if( !url ) {
-                       p = ber_memalloc( vlen + 1 );
-                       if( p == NULL ) {
+                       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 );
+                               ber_memfree( type->bv_val );
                                ber_memfree( line );
                                return( -1 );
                        }
-                       AC_MEMCPY( p, value, vlen );
-                       p[vlen] = '\0';
-                       value = p;
                }
 
                ber_memfree( line );
        }
 
-       *typep = type;
-       *valuep = value;
-       *vlenp = vlen;
-
        return( 0 );
 }
 
@@ -307,6 +310,21 @@ ldif_parse_line2(
  * 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 )
 {
@@ -343,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
 
@@ -463,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;
@@ -594,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;
                        }
                }
@@ -605,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";
@@ -633,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;
@@ -653,12 +845,52 @@ 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 ));
+                                                       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;