diff --git a/CHANGES b/CHANGES
index 0221258a0ea212440f7887d118a01b69e17bafa1..b6394125a13dd2b49e25f2fbd311e509a5d8379c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,7 @@
 OpenLDAP 2.4 Change Log
 
 OpenLDAP 2.4.14 Engineering
+	Fixed libldap deref handling (ITS#5768)
 	Fixed libldap peer cert memory leak (ITS#5849)
 	Fixed libldap_r deref building (ITS#5768)
 	Fixed slapd syncrepl rename handling (ITS#5809)
diff --git a/clients/tools/common.c b/clients/tools/common.c
index cda39c9f8caa3706e1630ea6f7540d87cc9afa20..82ad17403d33bdfedadc0b3c0112df6887323136 100644
--- a/clients/tools/common.c
+++ b/clients/tools/common.c
@@ -249,6 +249,14 @@ tool_destroy( void )
 		pr_cookie.bv_val = NULL;
 		pr_cookie.bv_len = 0;
 	}
+
+	if ( binddn != NULL ) {
+		ber_memfree( binddn );
+	}
+
+	if ( passwd.bv_val != NULL ) {
+		ber_memfree( passwd.bv_val );
+	}
 }
 
 void
@@ -1927,11 +1935,11 @@ print_deref( LDAP *ld, LDAPControl *ctrl )
 				ber_len_t tlen = strlen(dv->type);
 
 				for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
-					len += STRLENOF("<=>;") + tlen + dv->vals[ j ].bv_len;
+					len += STRLENOF("<:=>;") + tlen + 4*((dv->vals[ j ].bv_len - 1)/3 + 1);
 				}
 			}
 		}
-		len += dr->derefVal.bv_len;
+		len += dr->derefVal.bv_len + STRLENOF("\n");
 		buf = ldap_memalloc( len + 1 );
 		if ( buf == NULL ) {
 			rc = LDAP_NO_MEMORY;
@@ -1946,19 +1954,40 @@ print_deref( LDAP *ld, LDAPControl *ctrl )
 			if ( dv->vals != NULL ) {
 				int j;
 				for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
+					int k;
+
+					for ( k = 0; k < dv->vals[ j ].bv_len; k++ ) {
+						if ( !isprint( dv->vals[ j ].bv_val[k] ) ) {
+							k = -1;
+							break;
+						}
+					}
+
 					*ptr++ = '<';
 					ptr = lutil_strcopy( ptr, dv->type );
+					if ( k == -1 ) {
+						*ptr++ = ':';
+					}
 					*ptr++ = '=';
-					ptr = lutil_strncopy( ptr, dv->vals[ j ].bv_val, dv->vals[ j ].bv_len );
+					if ( k == -1 ) {
+						k = lutil_b64_ntop( dv->vals[ j ].bv_val, dv->vals[ j ].bv_len, ptr, buf + len - ptr );
+						assert( k >= 0 );
+						ptr += k;
+						
+					} else {
+						ptr = lutil_memcopy( ptr, dv->vals[ j ].bv_val, dv->vals[ j ].bv_len );
+					}
 					*ptr++ = '>';
 					*ptr++ = ';';
 				}
 			}
 		}
 		ptr = lutil_strncopy( ptr, dr->derefVal.bv_val, dr->derefVal.bv_len );
+		*ptr++ = '\n';
 		*ptr++ = '\0';
+		assert( ptr <= buf + len );
 
-		tool_write_ldif( LDIF_PUT_COMMENT, NULL, buf, len );
+		tool_write_ldif( LDIF_PUT_COMMENT, NULL, buf, ptr - buf);
 
 		ldap_memfree( buf );
 	}
diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c
index 8a60f7d80402d4fecb8f66cc40c44ec6320aaf4e..735fc809387d4cdcd9656d476b3d6ad0d1561336 100644
--- a/clients/tools/ldapsearch.c
+++ b/clients/tools/ldapsearch.c
@@ -511,12 +511,18 @@ handle_private_option( int i )
 			 */
 
 			specs = ldap_str2charray( cvalue, ";" );
+			if ( specs == NULL ) {
+				fprintf( stderr, _("deref specs \"%s\" invalid\n"),
+					cvalue );
+				exit( EXIT_FAILURE );
+			}
 			for ( ispecs = 0; specs[ ispecs ] != NULL; ispecs++ )
 				/* count'em */
 
 			ds = ldap_memcalloc( ispecs + 1, sizeof( LDAPDerefSpec ) );
 			if ( ds == NULL ) {
-				/* error */
+				perror( "malloc" );
+				exit( EXIT_FAILURE );
 			}
 
 			for ( ispecs = 0; specs[ ispecs ] != NULL; ispecs++ ) {
@@ -524,7 +530,9 @@ handle_private_option( int i )
 
 				ptr = strchr( specs[ ispecs ], ':' );
 				if ( ptr == NULL ) {
-					/* error */
+					fprintf( stderr, _("deref specs \"%s\" invalid\n"),
+						cvalue );
+					exit( EXIT_FAILURE );
 				}
 
 				ds[ ispecs ].derefAttr = specs[ ispecs ];
@@ -984,9 +992,12 @@ getNextPage:
 		}
 
 #ifdef LDAP_CONTROL_X_DEREF
-		if ( ds ) {
+		if ( derefcrit ) {
 			if ( derefval.bv_val == NULL ) {
 				int i;
+
+				assert( ds != NULL );
+
 				if ( ldap_create_deref_control_value( ld, ds, &derefval ) != LDAP_SUCCESS ) {
 					return EXIT_FAILURE;
 				}
@@ -996,6 +1007,7 @@ getNextPage:
 					ldap_charray_free( ds[ i ].attributes );
 				}
 				ldap_memfree( ds );
+				ds = NULL;
 			}
 
 			if ( ctrl_add() ) {
@@ -1186,6 +1198,9 @@ getNextPage:
 	if ( sss_keys != NULL ) {
 		ldap_free_sort_keylist( sss_keys );
 	}
+	if ( derefval.bv_val != NULL ) {
+		ldap_memfree( derefval.bv_val );
+	}
 
 	if ( c ) {
 		for ( ; save_nctrls-- > 0; ) {
diff --git a/include/lutil.h b/include/lutil.h
index b20be1d70f1678d279d0cfdd9bc1bb72d0b87049..75a2612bcaaf3e93e79a0e777869733541db336c 100644
--- a/include/lutil.h
+++ b/include/lutil.h
@@ -195,6 +195,9 @@ lutil_strcopy LDAP_P(( char *dst, const char *src ));
 LDAP_LUTIL_F( char* )
 lutil_strncopy LDAP_P(( char *dst, const char *src, size_t n ));
 
+LDAP_LUTIL_F( char* )
+lutil_memcopy LDAP_P(( char *dst, const char *src, size_t n ));
+
 struct tm;
 
 /* use this macro to statically allocate buffer for lutil_gentime */
diff --git a/libraries/liblutil/utils.c b/libraries/liblutil/utils.c
index afda235d81fcb9225de0b4a6216b9d831e2ed22b..462df73613dab1a2c12985a81ce8c27edd81d875 100644
--- a/libraries/liblutil/utils.c
+++ b/libraries/liblutil/utils.c
@@ -439,6 +439,21 @@ lutil_strncopy(
 	return a-1;
 }
 
+/* memcopy is like memcpy except it returns a pointer to the byte past
+ * the end of the result buffer, set to NULL. This allows fast construction
+ * of catenated buffers.  Provided for API consistency with lutil_str*copy().
+ */
+char *
+lutil_memcopy(
+	char *a,
+	const char *b,
+	size_t n
+)
+{
+	AC_MEMCPY(a, b, n);
+	return a + n;
+}
+
 #ifndef HAVE_MKSTEMP
 int mkstemp( char * template )
 {
diff --git a/servers/slapd/overlays/deref.c b/servers/slapd/overlays/deref.c
index c3d4e7d8ed7f06eb559c43b451e3bbe7346ecf41..346bcf15c60919da3d72a9df350cdf66845f95ee 100644
--- a/servers/slapd/overlays/deref.c
+++ b/servers/slapd/overlays/deref.c
@@ -466,7 +466,7 @@ deref_response( Operation *op, SlapReply *rs )
 		ctrl->ldctl_oid = LDAP_CONTROL_X_DEREF;
 		ctrl->ldctl_iscritical = 0;
 		ctrl->ldctl_value.bv_len = ctrlval.bv_len;
-		lutil_strncopy( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len );
+		AC_MEMCPY( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len );
 		ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0';
 
 		ber_free_buf( ber );