diff --git a/libraries/liblutil/utils.c b/libraries/liblutil/utils.c
index 7183e2725336aa665fd6cf17496847930501d0b0..f5727fa65614c7633ed2c48eb6d3fa6c821903b5 100644
--- a/libraries/liblutil/utils.c
+++ b/libraries/liblutil/utils.c
@@ -604,18 +604,18 @@ lutil_atoulx( unsigned long *v, const char *s, int x )
 }
 
 /* Multiply an integer by 100000000 and add new */
-typedef struct _decnum {
+typedef struct lutil_int_decnum {
 	unsigned char *buf;
 	int bufsiz;
 	int beg;
 	int len;
-} _decnum;
+} lutil_int_decnum;
 
 #define	FACTOR1	(100000000&0xffff)
 #define FACTOR2 (100000000>>16)
 
 static void
-scale( int new, _decnum *prev, unsigned char *tmp )
+scale( int new, lutil_int_decnum *prev, unsigned char *tmp )
 {
 	int i, j;
 	unsigned char *in = prev->buf+prev->beg;
@@ -648,14 +648,13 @@ scale( int new, _decnum *prev, unsigned char *tmp )
 		new += out[i];
 		out[i] = new & 0xff;
 		new >>= 8;
-		if (!new ) {
-			if ( !prev->len ) {
-				prev->beg += i;
-				prev->len = -i;
-				prev->len++;
-			}
+		if (!new )
 			break;
-		}
+	}
+	if ( !prev->len ) {
+		prev->beg += i;
+		prev->len = -i;
+		prev->len++;
 	}
 	AC_MEMCPY( prev->buf+prev->beg, tmp+prev->beg, prev->len );
 }
@@ -663,6 +662,11 @@ scale( int new, _decnum *prev, unsigned char *tmp )
 /* Convert unlimited length decimal or hex string to binary.
  * Output buffer must be provided, bv_len must indicate buffer size
  * Hex input can be "0x1234" or "'1234'H"
+ *
+ * Note: High bit of binary form is always the sign bit. If the number
+ * is supposed to be positive but has the high bit set, a zero byte
+ * is prepended. It is assumed that this has already been handled on
+ * any hex input.
  */
 int
 lutil_str2bin( struct berval *in, struct berval *out )
@@ -722,14 +726,20 @@ lutil_str2bin( struct berval *in, struct berval *out )
 	} else {
 	/* Decimal */
 		char tmpbuf[64], *tmp;
-		_decnum num;
+		lutil_int_decnum num;
+		int neg = 0;
 
 		len = in->bv_len;
 		pin = in->bv_val;
-		num.buf = out->bv_val;
+		num.buf = (unsigned char *)out->bv_val;
 		num.bufsiz = out->bv_len;
 		num.beg = num.bufsiz-1;
 		num.len = 0;
+		if ( pin[0] == '-' ) {
+			neg = 1;
+			len--;
+			pin++;
+		}
 
 #define	DECMAX	8	/* 8 digits at a time */
 
@@ -752,11 +762,46 @@ lutil_str2bin( struct berval *in, struct berval *out )
 				rc = -1;
 				goto decfail;
 			}
-			scale( l, &num, tmp );
+			scale( l, &num, (unsigned char *)tmp );
 			pin += chunk;
 			len -= chunk;
 			chunk = DECMAX;
 		}
+		/* Negate the result */
+		if ( neg ) {
+			int i, j;
+			unsigned char *ptr;
+
+			ptr = num.buf+num.beg;
+
+			/* flip all bits */
+			for ( i=0; i<num.len; i++ )
+				ptr[i] ^= 0xff;
+
+			/* Add 1, with carry */
+			i--;
+			j = 1;
+			for ( ; i>=0; i-- ) {
+				j += ptr[i];
+				ptr[i] = j & 0xff;
+				j >>= 8;
+				if (!j)
+					break;
+			}
+			/* If we overflowed and there's still room,
+			 * set an explicit sign byte
+			 */
+			if ( !(  ptr[0] & 0x80 ) && num.beg ) {
+				num.beg--;
+				num.len++;
+				num.buf[num.beg] = 0x80;
+			}
+		} else if (( num.buf[num.beg] & 0x80 ) && num.beg ) {
+			/* positive int with high bit set, prepend 0 */
+			num.beg--;
+			num.len++;
+			num.buf[num.beg] = 0;
+		}
 		if ( num.beg )
 			AC_MEMCPY( num.buf, num.buf+num.beg, num.len );
 		out->bv_len = num.len;