New function ERR_error_string_n.
authorBodo Möller <bodo@openssl.org>
Fri, 14 Apr 2000 23:36:15 +0000 (23:36 +0000)
committerBodo Möller <bodo@openssl.org>
Fri, 14 Apr 2000 23:36:15 +0000 (23:36 +0000)
CHANGES
STATUS
apps/errstr.c
crypto/bio/b_print.c
crypto/bio/bio.h
crypto/err/err.c
crypto/err/err.h
crypto/err/err_prn.c
doc/crypto/ERR_error_string.pod
util/libeay.num

diff --git a/CHANGES b/CHANGES
index 698ac30..4688929 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
 
  Changes between 0.9.5a and 0.9.6  [xx XXX 2000]
 
+  *) New function ERR_error_string_n(e, buf, len) which is like
+     ERR_error_string(e, buf), but writes at most 'len' bytes
+     including the 0 terminator.  For ERR_error_string_n, 'buf'
+     may not be NULL.
+     [Damien Miller <djm@mindrot.org>, Bodo Moeller]
+
   *) CONF library reworked to become more general.  A new CONF
      configuration file reader "class" is implemented as well as a
      new functions (NCONF_*, for "New CONF") to handle it.  The now
diff --git a/STATUS b/STATUS
index 99f2aec..410739c 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -1,6 +1,6 @@
 
   OpenSSL STATUS                           Last modified at
-  ______________                           $Date: 2000/04/01 12:32:10 $
+  ______________                           $Date: 2000/04/14 23:35:50 $
 
   DEVELOPMENT STATE
 
       use a key length decided by the size of the RSA encrypted key and expect
       RC2 to adapt).
 
-    o ERR_error_string(..., buf) does not know how large buf is,
-      there should be ERR_error_string_n(..., buf, bufsize)
-      or similar.
-
   WISHES
 
     o 
index 4650379..2c62046 100644 (file)
@@ -104,7 +104,10 @@ int MAIN(int argc, char **argv)
        for (i=1; i<argc; i++)
                {
                if (sscanf(argv[i],"%lx",&l))
-                       printf("%s\n",ERR_error_string(l,buf));
+                       {
+                       ERR_error_string_n(l, buf, sizeof buf);
+                       printf("%s\n",buf);
+                       }
                else
                        {
                        printf("%s: bad error code\n",argv[i]);
index b11b501..33fa27a 100644 (file)
 # endif
 #endif
 
-static void dopr (char *buffer, size_t maxlen, size_t *retlen,
-       const char *format, va_list args);
-#ifdef USE_ALLOCATING_PRINT
-static void doapr (char **buffer, size_t *retlen,
-       const char *format, va_list args);
-#endif
-
-int BIO_printf (BIO *bio, ...)
-       {
-       va_list args;
-       char *format;
-       int ret;
-       size_t retlen;
-#ifdef USE_ALLOCATING_PRINT
-       char *hugebuf;
-#else
-       MS_STATIC char hugebuf[1024*2]; /* 10k in one chunk is the limit */
-#endif
-
-       va_start(args, bio);
-       format=va_arg(args, char *);
-
-#ifndef USE_ALLOCATING_PRINT
-       hugebuf[0]='\0';
-       dopr(hugebuf, sizeof(hugebuf), &retlen, format, args);
-#else
-       hugebuf = NULL;
-       CRYPTO_push_info("doapr()");
-       doapr(&hugebuf, &retlen, format, args);
-       if (hugebuf)
-               {
-#endif
-               ret=BIO_write(bio, hugebuf, (int)retlen);
-
-#ifdef USE_ALLOCATING_PRINT
-               Free(hugebuf);
-               }
-       CRYPTO_pop_info();
-#endif
-       va_end(args);
-       return(ret);
-       }
+/***************************************************************************/
 
 /*
  * Copyright Patrick Powell 1995
@@ -140,6 +99,7 @@ int BIO_printf (BIO *bio, ...)
  * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
  * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
  * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
+ * o ...                                       (for OpenSSL)
  */
 
 #if HAVE_LONG_DOUBLE
@@ -161,18 +121,17 @@ static void fmtint     (void (*)(char **, size_t *, size_t *, int),
                        char **, size_t *, size_t *, LLONG, int, int, int, int);
 static void fmtfp      (void (*)(char **, size_t *, size_t *, int),
                        char **, size_t *, size_t *, LDOUBLE, int, int, int);
-#ifndef USE_ALLOCATING_PRINT
 static int dopr_isbig (size_t, size_t);
 static int dopr_copy (size_t);
 static void dopr_outch (char **, size_t *, size_t *, int);
-#else
+#ifdef USE_ALLOCATING_PRINT
 static int doapr_isbig (size_t, size_t);
 static int doapr_copy (size_t);
 static void doapr_outch (char **, size_t *, size_t *, int);
 #endif
 static void _dopr(void (*)(char **, size_t *, size_t *, int),
                  int (*)(size_t, size_t), int (*)(size_t),
-                 char **buffer, size_t *maxlen, size_t *retlen,
+                 char **buffer, size_t *maxlen, size_t *retlen, int *truncated,
                  const char *format, va_list args);
 
 /* format read states */
@@ -213,8 +172,9 @@ dopr(
     const char *format,
     va_list args)
 {
+    int ignored;
     _dopr(dopr_outch, dopr_isbig, dopr_copy,
-         &buffer, &maxlen, retlen, format, args);
+        &buffer, &maxlen, retlen, &ignored, format, args);
 }
 
 #else
@@ -226,8 +186,9 @@ doapr(
     va_list args)
 {
     size_t dummy_maxlen = 0;
+    int ignored;
     _dopr(doapr_outch, doapr_isbig, doapr_copy,
-         buffer, &dummy_maxlen, retlen, format, args);
+        buffer, &dummy_maxlen, retlen, &ignored, format, args);
 }
 #endif
 
@@ -239,6 +200,7 @@ _dopr(
     char **buffer,
     size_t *maxlen,
     size_t *retlen,
+    int *truncated,
     const char *format,
     va_list args)
 {
@@ -374,7 +336,7 @@ _dopr(
                     break;
                 }
                 fmtint(outch_fn, buffer, &currlen, maxlen,
-                      value, 10, min, max, flags);
+                       value, 10, min, max, flags);
                 break;
             case 'X':
                 flags |= DP_F_UP;
@@ -409,7 +371,7 @@ _dopr(
                 else
                     fvalue = va_arg(args, double);
                 fmtfp(outch_fn, buffer, &currlen, maxlen,
-                     fvalue, min, max, flags);
+                      fvalue, min, max, flags);
                 break;
             case 'E':
                 flags |= DP_F_UP;
@@ -436,7 +398,7 @@ _dopr(
                 if (max < 0)
                     max = (*copy_fn)(*maxlen);
                 fmtstr(outch_fn, buffer, &currlen, maxlen, strvalue,
-                      flags, min, max);
+                       flags, min, max);
                 break;
             case 'p':
                 value = (long)va_arg(args, void *);
@@ -484,7 +446,8 @@ _dopr(
             break;
         }
     }
-    if (currlen >= *maxlen - 1)
+    *truncated = (currlen > *maxlen - 1);
+    if (*truncated)
         currlen = *maxlen - 1;
     (*buffer)[currlen] = '\0';
     *retlen = currlen;
@@ -842,3 +805,62 @@ doapr_outch(
     return;
 }
 #endif
+
+/***************************************************************************/
+
+int BIO_printf (BIO *bio, const char *format, ...)
+       {
+       va_list args;
+       int ret;
+       size_t retlen;
+#ifdef USE_ALLOCATING_PRINT
+       char *hugebuf;
+#else
+       MS_STATIC char hugebuf[1024*2]; /* 10k in one chunk is the limit */
+#endif
+
+       va_start(args, format);
+
+#ifndef USE_ALLOCATING_PRINT
+       hugebuf[0]='\0';
+       dopr(hugebuf, sizeof(hugebuf), &retlen, format, args);
+#else
+       hugebuf = NULL;
+       CRYPTO_push_info("doapr()");
+       doapr(&hugebuf, &retlen, format, args);
+       if (hugebuf)
+               {
+#endif
+               ret=BIO_write(bio, hugebuf, (int)retlen);
+
+#ifdef USE_ALLOCATING_PRINT
+               Free(hugebuf);
+               }
+       CRYPTO_pop_info();
+#endif
+       va_end(args);
+       return(ret);
+       }
+
+/* As snprintf is not available everywhere, we provide our own implementation.
+ * This function has nothing to do with BIOs, but it's closely related
+ * to BIO_printf, and we need *some* name prefix ...
+ * (XXX  the function should be renamed, but to what?) */
+int BIO_snprintf(char *buf, size_t n, const char *format, ...)
+       {
+       va_list args;
+       size_t retlen;
+       int truncated;
+
+       va_start(args, format);
+       _dopr(dopr_outch, dopr_isbig, dopr_copy,
+               &buf, &n, &retlen, &truncated, format, args);
+       if (truncated)
+               /* In case of truncation, return -1 like traditional snprintf.
+                * (Current drafts for ISO/IEC 9899 say snprintf should return
+                * the number of characters that would have been written,
+                * had the buffer been large enough.) */
+               return -1;
+       else
+               return (retlen <= INT_MAX) ? retlen : -1;
+       }
index ebdb181..dd3cc3f 100644 (file)
@@ -592,7 +592,8 @@ void BIO_copy_next_retry(BIO *b);
 
 long BIO_ghbn_ctrl(int cmd,int iarg,char *parg);
 
-int BIO_printf(BIO *bio, ...);
+int BIO_printf(BIO *bio, const char *format, ...);
+int BIO_snprintf(char *buf, size_t n, const char *format, ...);
 
 /* BEGIN ERROR CODES */
 /* The following lines are auto generated by the script mkerr.pl. Any changes
index cbbd326..a013557 100644 (file)
 #include <openssl/buffer.h>
 #include <openssl/err.h>
 #include <openssl/crypto.h>
+#include <openssl/bio.h>
 
 
 static LHASH *error_hash=NULL;
@@ -477,13 +478,11 @@ static unsigned long get_error_values(int inc, const char **file, int *line,
        return(ret);
        }
 
-/* BAD for multi-threaded, uses a local buffer if ret == NULL */
-char *ERR_error_string(unsigned long e, char *ret)
+void ERR_error_string_n(unsigned long e, char *buf, size_t len)
        {
-       static char buf[256];
+       char lsbuf[64], fsbuf[64], rsbuf[64];
        const char *ls,*fs,*rs;
        unsigned long l,f,r;
-       int i;
 
        l=ERR_GET_LIB(e);
        f=ERR_GET_FUNC(e);
@@ -493,21 +492,50 @@ char *ERR_error_string(unsigned long e, char *ret)
        fs=ERR_func_error_string(e);
        rs=ERR_reason_error_string(e);
 
-       if (ret == NULL) ret=buf;
-
-       sprintf(&(ret[0]),"error:%08lX:",e);
-       i=strlen(ret);
-       if (ls == NULL)
-               sprintf(&(ret[i]),":lib(%lu) ",l);
-       else    sprintf(&(ret[i]),"%s",ls);
-       i=strlen(ret);
+       if (ls == NULL) 
+               BIO_snprintf(lsbuf, sizeof(lsbuf), "lib(%lu)", l);
        if (fs == NULL)
-               sprintf(&(ret[i]),":func(%lu) ",f);
-       else    sprintf(&(ret[i]),":%s",fs);
-       i=strlen(ret);
+               BIO_snprintf(fsbuf, sizeof(fsbuf), "func(%lu)", f);
        if (rs == NULL)
-               sprintf(&(ret[i]),":reason(%lu)",r);
-       else    sprintf(&(ret[i]),":%s",rs);
+               BIO_snprintf(rsbuf, sizeof(rsbuf), "reason(%lu)", r);
+
+       BIO_snprintf(buf, len,"error:%08lX:%s:%s:%s", e, ls?ls:lsbuf, 
+               fs?fs:fsbuf, rs?rs:rsbuf);
+       if (strlen(buf) == len-1)
+               {
+               /* output may be truncated; make sure we always have 5 
+                * colon-separated fields, i.e. 4 colons ... */
+#define NUM_COLONS 4
+               if (len > NUM_COLONS) /* ... if possible */
+                       {
+                       int i;
+                       char *s = buf;
+                       
+                       for (i = 0; i < NUM_COLONS; i++)
+                               {
+                               char *colon = strchr(s, ':');
+                               if (colon == NULL || colon > &buf[len-1] - NUM_COLONS + i)
+                                       {
+                                       /* set colon no. i at last possible position
+                                        * (buf[len-1] is the terminating 0)*/
+                                       colon = &buf[len-1] - NUM_COLONS + i;
+                                       *colon = ':';
+                                       }
+                               s = colon + 1;
+                               }
+                       }
+               }
+       }
+
+/* BAD for multi-threading: uses a local buffer if ret == NULL */
+/* ERR_error_string_n should be used instead for ret != NULL
+ * as ERR_error_string cannot know how large the buffer is */
+char *ERR_error_string(unsigned long e, char *ret)
+       {
+       static char buf[256];
+
+       if (ret == NULL) ret=buf;
+       ERR_error_string_n(e, buf, 256);
 
        return(ret);
        }
index 35c4d97..e3984bb 100644 (file)
@@ -233,6 +233,7 @@ unsigned long ERR_peek_error_line_data(const char **file,int *line,
                                       const char **data,int *flags);
 void ERR_clear_error(void );
 char *ERR_error_string(unsigned long e,char *buf);
+void ERR_error_string_n(unsigned long e, char *buf, size_t len);
 const char *ERR_lib_error_string(unsigned long e);
 const char *ERR_func_error_string(unsigned long e);
 const char *ERR_reason_error_string(unsigned long e);
index 0999ff2..6f60b01 100644 (file)
@@ -76,7 +76,8 @@ void ERR_print_errors_fp(FILE *fp)
        es=CRYPTO_thread_id();
        while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
                {
-               fprintf(fp,"%lu:%s:%s:%d:%s\n",es,ERR_error_string(l,buf),
+               ERR_error_string_n(l, buf, sizeof buf);
+               fprintf(fp,"%lu:%s:%s:%d:%s\n",es,buf,
                        file,line,(flags&ERR_TXT_STRING)?data:"");
                }
        }
@@ -94,7 +95,8 @@ void ERR_print_errors(BIO *bp)
        es=CRYPTO_thread_id();
        while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
                {
-               sprintf(buf2,"%lu:%s:%s:%d:",es,ERR_error_string(l,buf),
+               ERR_error_string_n(l, buf, sizeof buf);
+               sprintf(buf2,"%lu:%s:%s:%d:",es,buf,
                        file,line);
                BIO_write(bp,buf2,strlen(buf2));
                if (flags & ERR_TXT_STRING)
index 0d24175..3518033 100644 (file)
@@ -9,6 +9,7 @@ ERR_error_string - obtain human-readable error message
  #include <openssl/err.h>
 
  char *ERR_error_string(unsigned long e, char *buf);
+ char *ERR_error_string_n(unsigned long e, char *buf, size_t len);
 
  const char *ERR_lib_error_string(unsigned long e);
  const char *ERR_func_error_string(unsigned long e);
@@ -17,9 +18,13 @@ ERR_error_string - obtain human-readable error message
 =head1 DESCRIPTION
 
 ERR_error_string() generates a human-readable string representing the
-error code B<e>, and places it at B<buf>. B<buf> must be at least 120
-bytes long. If B<buf> is B<NULL>, the error string is placed in a
+error code I<e>, and places it at I<buf>. I<buf> must be at least 120
+bytes long. If I<buf> is B<NULL>, the error string is placed in a
 static buffer.
+ERR_error_string_n() is a variant of ERR_error_string() that writes
+at most I<len> characters (including the terminating 0)
+and truncates the resulting string if necessary.
+For ERR_error_string_n(), I<buf> may not be B<NULL>.
 
 The string will have the following format:
 
@@ -45,7 +50,7 @@ all error codes currently in the queue.
 =head1 RETURN VALUES
 
 ERR_error_string() returns a pointer to a static buffer containing the
-string if B<buf == NULL>, B<buf> otherwise.
+string if I<buf> B<== NULL>, I<buf> otherwise.
 
 ERR_lib_error_string(), ERR_func_error_string() and
 ERR_reason_error_string() return the strings, and B<NULL> if
@@ -61,5 +66,6 @@ L<ERR_print_errors(3)|ERR_print_errors(3)>
 =head1 HISTORY
 
 ERR_error_string() is available in all versions of SSLeay and OpenSSL.
+ERR_error_string_n() was added in OpenSSL 0.9.6.
 
 =cut
index cde9bf4..781c63d 100755 (executable)
@@ -2262,3 +2262,5 @@ NCONF_dump_bio                          2287
 CONF_dump_bio                           2288
 NCONF_free_data                         2289
 CONF_set_default_method                 2290
+ERR_error_string_n                      2291
+BIO_snprintf                            2292