From 961fe42bbd7eaa3700238476c484e5b28da6e44d Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Tue, 4 Jan 2011 19:57:26 +0000
Subject: [PATCH] ITS#6645

---
 CHANGES                    |  1 +
 doc/man/man8/slapcat.8     |  7 ++++++-
 include/ldif.h             | 26 +++++++++++++++++++++++++-
 libraries/liblutil/ldif.c  | 38 +++++++++++++++++++++++++++++++++-----
 servers/slapd/entry.c      | 16 +++++++++++++---
 servers/slapd/proto-slap.h |  1 +
 servers/slapd/slapcat.c    |  2 +-
 servers/slapd/slapcommon.c | 23 +++++++++++++++++++++++
 servers/slapd/slapcommon.h |  3 +++
 9 files changed, 106 insertions(+), 11 deletions(-)

diff --git a/CHANGES b/CHANGES
index 79c06e8170..35064db935 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,7 @@
 OpenLDAP 2.4 Change Log
 
 OpenLDAP 2.4.24 Engineering
+	Added LDIF line wrapping setting (ITS#6645)
 	Added libldap MozNSS non-blocking support (ITS#6714)
 	Added slapadd attribute value checking (ITS#6592)
 	Added slapcat continue mode for problematic DBs (ITS#6482)
diff --git a/doc/man/man8/slapcat.8 b/doc/man/man8/slapcat.8
index 02e64c8988..96950514b4 100644
--- a/doc/man/man8/slapcat.8
+++ b/doc/man/man8/slapcat.8
@@ -149,7 +149,12 @@ Possible generic options/values are:
               syslog\-level=<level> (see `\-S' in slapd(8))
               syslog\-user=<user>   (see `\-l' in slapd(8))
 
-.fi
+              ldif-wrap={no|<n>}
+
+.in
+\fIn\fP is the number of columns allowed for the LDIF output
+(\fIn\fP equal to \fI0\fP uses the default, corresponding to 76).
+Use \fIno\fP for no wrap.
 .TP
 .BI \-s \ subtree-dn
 Only dump entries in the subtree specified by this DN.
diff --git a/include/ldif.h b/include/ldif.h
index 09c70b956f..87fe9ab159 100644
--- a/include/ldif.h
+++ b/include/ldif.h
@@ -33,7 +33,9 @@ LDAP_BEGIN_DECL
 /* This is NOT a bogus extern declaration (unlike ldap_debug) */
 LDAP_LDIF_V (int) ldif_debug;
 
-#define LDIF_LINE_WIDTH      76      /* maximum length of LDIF lines */
+#define LDIF_LINE_WIDTH      76      /* default maximum length of LDIF lines */
+#define LDIF_LINE_WIDTH_MAX  ((ber_len_t)-1) /* maximum length of LDIF lines */
+#define LDIF_LINE_WIDTH_WRAP(wrap) ((wrap) == 0 ? LDIF_LINE_WIDTH : (wrap))
 
 /*
  * Macro to calculate maximum number of bytes that the base64 equivalent
@@ -52,6 +54,11 @@ LDAP_LDIF_V (int) ldif_debug;
     ((nlen) + 4 + LDIF_BASE64_LEN(vlen) \
     + ((LDIF_BASE64_LEN(vlen) + (nlen) + 3) / LDIF_LINE_WIDTH * 2 ))
 
+#define LDIF_SIZE_NEEDED_WRAP(nlen,vlen,wrap) \
+    ((nlen) + 4 + LDIF_BASE64_LEN(vlen) \
+    + ((wrap) == 0 ? ((LDIF_BASE64_LEN(vlen) + (nlen) + 3) / ( LDIF_LINE_WIDTH ) * 2 ) : \
+	((wrap) == LDIF_LINE_WIDTH_MAX ? 0 : ((LDIF_BASE64_LEN(vlen) + (nlen) + 3) / (wrap) * 2 ))))
+
 LDAP_LDIF_F( int )
 ldif_parse_line LDAP_P((
 	LDAP_CONST char *line,
@@ -128,6 +135,15 @@ ldif_sput LDAP_P((
 	LDAP_CONST char *val,
 	ber_len_t vlen ));
 
+LDAP_LDIF_F( void )
+ldif_sput_wrap LDAP_P((
+	char **out,
+	int type,
+	LDAP_CONST char *name,
+	LDAP_CONST char *val,
+	ber_len_t vlen,
+        ber_len_t wrap ));
+
 LDAP_LDIF_F( char * )
 ldif_put LDAP_P((
 	int type,
@@ -135,6 +151,14 @@ ldif_put LDAP_P((
 	LDAP_CONST char *val,
 	ber_len_t vlen ));
 
+LDAP_LDIF_F( char * )
+ldif_put_wrap LDAP_P((
+	int type,
+	LDAP_CONST char *name,
+	LDAP_CONST char *val,
+	ber_len_t vlen,
+	ber_len_t wrap ));
+
 LDAP_LDIF_F( int )
 ldif_is_not_printable LDAP_P((
 	LDAP_CONST char *val,
diff --git a/libraries/liblutil/ldif.c b/libraries/liblutil/ldif.c
index 6994a060ca..c080199151 100644
--- a/libraries/liblutil/ldif.c
+++ b/libraries/liblutil/ldif.c
@@ -489,6 +489,7 @@ ldif_must_b64_encode( LDAP_CONST char *s )
 /* compatibility with U-Mich off by one bug */
 #define LDIF_KLUDGE 1
 
+/* NOTE: only preserved for binary compatibility */
 void
 ldif_sput(
 	char **out,
@@ -496,6 +497,18 @@ ldif_sput(
 	LDAP_CONST char *name,
 	LDAP_CONST char *val,
 	ber_len_t vlen )
+{
+	ldif_sput_wrap( out, type, name, val, vlen, LDIF_LINE_WIDTH );
+}
+
+void
+ldif_sput_wrap(
+	char **out,
+	int type,
+	LDAP_CONST char *name,
+	LDAP_CONST char *val,
+	ber_len_t vlen,
+        ber_len_t wrap )
 {
 	const unsigned char *byte, *stop;
 	unsigned char	buf[3];
@@ -508,6 +521,8 @@ ldif_sput(
 	ber_len_t len=0;
 	ber_len_t i;
 
+	wrap = LDIF_LINE_WIDTH_WRAP( wrap );
+
 	/* prefix */
 	switch( type ) {
 	case LDIF_PUT_COMMENT:
@@ -578,7 +593,7 @@ ldif_sput(
 	case LDIF_PUT_COMMENT:
 		/* pre-encoded names */
 		for ( i=0; i < vlen; i++ ) {
-			if ( len > LDIF_LINE_WIDTH ) {
+			if ( len > wrap ) {
 				*(*out)++ = '\n';
 				*(*out)++ = ' ';
 				len = 1;
@@ -618,7 +633,7 @@ ldif_sput(
 				b64 = 1;
 				break;
 			}
-			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
+			if ( len - LDIF_KLUDGE > wrap ) {
 				*(*out)++ = '\n';
 				*(*out)++ = ' ';
 				len = 1;
@@ -647,7 +662,7 @@ ldif_sput(
 		bits |= (byte[2] & 0xff);
 
 		for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
-			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
+			if ( len - LDIF_KLUDGE > wrap ) {
 				*(*out)++ = '\n';
 				*(*out)++ = ' ';
 				len = 1;
@@ -672,7 +687,7 @@ ldif_sput(
 		bits |= (byte[2] & 0xff);
 
 		for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
-			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
+			if ( len - LDIF_KLUDGE > wrap ) {
 				*(*out)++ = '\n';
 				*(*out)++ = ' ';
 				len = 1;
@@ -693,19 +708,32 @@ ldif_sput(
 /*
  * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line
  */
+
+/* NOTE: only preserved for binary compatibility */
 char *
 ldif_put(
 	int type,
 	LDAP_CONST char *name,
 	LDAP_CONST char *val,
 	ber_len_t vlen )
+{
+	return ldif_put_wrap( type, name, val, vlen, LDIF_LINE_WIDTH );
+}
+
+char *
+ldif_put_wrap(
+	int type,
+	LDAP_CONST char *name,
+	LDAP_CONST char *val,
+	ber_len_t vlen,
+	ber_len_t wrap )
 {
     char	*buf, *p;
     ber_len_t nlen;
 
     nlen = ( name != NULL ) ? strlen( name ) : 0;
 
-	buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED( nlen, vlen ) + 1 );
+	buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED_WRAP( nlen, vlen, wrap ) + 1 );
 
     if ( buf == NULL ) {
 		ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
diff --git a/servers/slapd/entry.c b/servers/slapd/entry.c
index 07ee458113..542db90165 100644
--- a/servers/slapd/entry.c
+++ b/servers/slapd/entry.c
@@ -426,10 +426,20 @@ fail:
 		} \
 	}
 
+/* NOTE: only preserved for binary compatibility */
 char *
 entry2str(
 	Entry	*e,
 	int		*len )
+{
+	return entry2str_wrap( e, len, LDIF_LINE_WIDTH );
+}
+
+char *
+entry2str_wrap(
+	Entry		*e,
+	int			*len,
+	ber_len_t	wrap )
 {
 	Attribute	*a;
 	struct berval	*bv;
@@ -451,7 +461,7 @@ entry2str(
 		/* put "dn: <dn>" */
 		tmplen = e->e_name.bv_len;
 		MAKE_SPACE( LDIF_SIZE_NEEDED( 2, tmplen ));
-		ldif_sput( &ecur, LDIF_PUT_VALUE, "dn", e->e_dn, tmplen );
+		ldif_sput_wrap( &ecur, LDIF_PUT_VALUE, "dn", e->e_dn, tmplen, wrap );
 	}
 
 	/* put the attributes */
@@ -461,9 +471,9 @@ entry2str(
 			bv = &a->a_vals[i];
 			tmplen = a->a_desc->ad_cname.bv_len;
 			MAKE_SPACE( LDIF_SIZE_NEEDED( tmplen, bv->bv_len ));
-			ldif_sput( &ecur, LDIF_PUT_VALUE,
+			ldif_sput_wrap( &ecur, LDIF_PUT_VALUE,
 				a->a_desc->ad_cname.bv_val,
-				bv->bv_val, bv->bv_len );
+				bv->bv_val, bv->bv_len, wrap );
 		}
 	}
 	MAKE_SPACE( 1 );
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index e95abef2c7..d7d7153bf3 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -988,6 +988,7 @@ LDAP_SLAPD_F (int) entry_destroy LDAP_P((void));
 LDAP_SLAPD_F (Entry *) str2entry LDAP_P(( char	*s ));
 LDAP_SLAPD_F (Entry *) str2entry2 LDAP_P(( char	*s, int checkvals ));
 LDAP_SLAPD_F (char *) entry2str LDAP_P(( Entry *e, int *len ));
+LDAP_SLAPD_F (char *) entry2str_wrap LDAP_P(( Entry *e, int *len, ber_len_t wrap ));
 
 LDAP_SLAPD_F (ber_len_t) entry_flatsize LDAP_P(( Entry *e, int norm ));
 LDAP_SLAPD_F (void) entry_partsize LDAP_P(( Entry *e, ber_len_t *len,
diff --git a/servers/slapd/slapcat.c b/servers/slapd/slapcat.c
index c4e7a7d658..56cfd60426 100644
--- a/servers/slapd/slapcat.c
+++ b/servers/slapd/slapcat.c
@@ -148,7 +148,7 @@ slapcat( int argc, char **argv )
 			printf( "# id=%08lx\n", (long) id );
 		}
 
-		data = entry2str( e, &len );
+		data = entry2str_wrap( e, &len, ldif_wrap );
 		be_entry_release_r( &op, e );
 
 		if ( data == NULL ) {
diff --git a/servers/slapd/slapcommon.c b/servers/slapd/slapcommon.c
index 6fd9341beb..1e5746df26 100644
--- a/servers/slapd/slapcommon.c
+++ b/servers/slapd/slapcommon.c
@@ -228,6 +228,27 @@ parse_slapopt( int tool, int *mode )
 			break;
 		}
 
+	} else if ( strncasecmp( optarg, "ldif-wrap", len ) == 0 ) {
+		switch ( tool ) {
+		case SLAPCAT:
+			if ( strcasecmp( p, "no" ) == 0 ) {
+				ldif_wrap = LDIF_LINE_WIDTH_MAX;
+
+			} else {
+				unsigned int u;
+				if ( lutil_atou( &u, p ) ) {
+					Debug( LDAP_DEBUG_ANY, "unable to parse ldif-wrap=\"%s\".\n", p, 0, 0 );
+					return -1;
+				}
+				ldif_wrap = (ber_len_t)u;
+			}
+			break;
+
+		default:
+			Debug( LDAP_DEBUG_ANY, "value-check meaningless for tool.\n", 0, 0, 0 );
+			break;
+		}
+
 	} else {
 		return -1;
 	}
@@ -283,6 +304,8 @@ slap_tool_init(
 	leakfilename = NULL;
 #endif
 
+	ldif_wrap = LDIF_LINE_WIDTH;
+
 	scope = LDAP_SCOPE_DEFAULT;
 
 	switch( tool ) {
diff --git a/servers/slapd/slapcommon.h b/servers/slapd/slapcommon.h
index dae63cd012..462eed133a 100644
--- a/servers/slapd/slapcommon.h
+++ b/servers/slapd/slapcommon.h
@@ -64,6 +64,7 @@ typedef struct tool_vars {
 	slap_ssf_t tv_sasl_ssf;
 	unsigned tv_dn_mode;
 	unsigned int tv_csnsid;
+	ber_len_t tv_ldif_wrap;
 } tool_vars;
 
 extern tool_vars tool_globals;
@@ -98,6 +99,8 @@ extern tool_vars tool_globals;
 #define sasl_ssf tool_globals.tv_sasl_ssf
 #define dn_mode tool_globals.tv_dn_mode
 #define csnsid tool_globals.tv_csnsid
+#define ldif_wrap tool_globals.tv_ldif_wrap
+
 #define SLAP_TOOL_LDAPDN_PRETTY		SLAP_LDAPDN_PRETTY
 #define SLAP_TOOL_LDAPDN_NORMAL		(SLAP_LDAPDN_PRETTY << 1)
 
-- 
GitLab