summaryrefslogtreecommitdiff
path: root/src/sexp.c
diff options
context:
space:
mode:
authorMoritz Schulte <mo@g10code.com>2003-10-27 22:13:43 +0000
committerMoritz Schulte <mo@g10code.com>2003-10-27 22:13:43 +0000
commit0337b1e8dcc96bd5ac157e181f9d44290c3767b4 (patch)
tree2e7f57970407958b3c5feab8159a40fb5414676c /src/sexp.c
parent3cde789241ee07bcf7643cd80ba6a743e34437a8 (diff)
downloadlibgcrypt-0337b1e8dcc96bd5ac157e181f9d44290c3767b4.tar.gz
2003-10-27 Moritz Schulte <mo@g10code.com>
* sexp.c (sexp_sscan): Cleaned up, deallocate scanned sexp on error.
Diffstat (limited to 'src/sexp.c')
-rw-r--r--src/sexp.c653
1 files changed, 364 insertions, 289 deletions
diff --git a/src/sexp.c b/src/sexp.c
index f4a7e0b2..bde7dc56 100644
--- a/src/sexp.c
+++ b/src/sexp.c
@@ -838,6 +838,7 @@ sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
const char *buffer, size_t length, int argflag,
va_list arg_ptr, void **arg_list)
{
+ gcry_err_code_t err = GPG_ERR_NO_ERROR;
static const char tokenchars[] = "\
abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ\
@@ -859,6 +860,8 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ\
int arg_counter = 0;
int level = 0;
+ /* FIXME: invent better error codes (?). */
+
if (! erroff)
erroff = &dummy_erroff;
@@ -875,9 +878,6 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ\
} \
while (0)
- /* FIXME: replace all the returns by a jump to the leave label and
- * invent better error codes. FIXME: Make sure that everything is
- * cleaned up. */
#define MAKE_SPACE(n) do { make_space ( &c, (n) ); } while (0)
#define STORE_LEN(p,n) do { \
DATALEN ashort = (n); \
@@ -889,308 +889,383 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ\
* than the provided one. However, we add space for one extra datalen
* so that the code which does the ST_CLOSE can use MAKE_SPACE */
c.allocated = length + sizeof(DATALEN);
- c.sexp = gcry_xmalloc ( sizeof *c.sexp + c.allocated - 1 );
+ c.sexp = gcry_xmalloc (sizeof *c.sexp + c.allocated - 1);
c.pos = c.sexp->d;
- for(p=buffer,n=length; n; p++, n-- ) {
- if( tokenp && !hexfmt ) {
- if( strchr( tokenchars, *p ) )
- continue;
- datalen = p - tokenp;
- MAKE_SPACE ( datalen );
- *c.pos++ = ST_DATA;
- STORE_LEN ( c.pos, datalen );
- memcpy ( c.pos, tokenp, datalen );
- c.pos += datalen;
- tokenp = NULL;
- }
- if( quoted ) {
- if( quoted_esc ) {
- switch( *p ) {
- case 'b': case 't': case 'v': case 'n': case 'f':
- case 'r': case '"': case '\'': case '\\':
- quoted_esc = 0;
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7':
- if( !(n > 2 && p[1] >= '0' && p[1] <= '7'
- && p[2] >= '0' && p[2] <= '7') ) {
- *erroff = p - buffer;
- /* Invalid octal value. */
- return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
- }
- p += 2; n -= 2;
- quoted_esc = 0;
- break;
- case 'x':
- if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) {
- *erroff = p - buffer;
- /* Invalid hex value. */
- return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
- }
- p += 2; n -= 2;
- quoted_esc = 0;
- break;
- case '\r': /* ignore CR[,LF] */
- if( n && p[1] == '\n' ) {
- p++; n--;
- }
- quoted_esc = 0;
- break;
- case '\n': /* ignore LF[,CR] */
- if( n && p[1] == '\r' ) {
- p++; n--;
- }
- quoted_esc = 0;
- break;
- default:
- *erroff = p - buffer;
- /* Invalid quoted string escape. */
- return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
+ for (p = buffer, n = length; n; p++, n--)
+ {
+ if (tokenp && (! hexfmt))
+ {
+ if (strchr (tokenchars, *p))
+ continue;
+ else
+ {
+ datalen = p - tokenp;
+ MAKE_SPACE (datalen);
+ *c.pos++ = ST_DATA;
+ STORE_LEN (c.pos, datalen);
+ memcpy (c.pos, tokenp, datalen);
+ c.pos += datalen;
+ tokenp = NULL;
+ }
}
- }
- else if( *p == '\\' )
- quoted_esc = 1;
- else if( *p == '\"' ) {
- /* keep it easy - we know that the unquoted string will
- never be larger */
- char *save;
- size_t len;
-
- quoted++; /* skip leading quote */
- MAKE_SPACE (p - quoted);
- *c.pos++ = ST_DATA;
- save = c.pos;
- STORE_LEN (c.pos, 0); /* will be fixed up later */
- len = unquote_string (quoted, p - quoted, c.pos);
- c.pos += len;
- STORE_LEN (save, len);
- quoted = NULL;
- }
- }
- else if( hexfmt ) {
- if( isxdigit( *p ) )
- hexcount++;
- else if( *p == '#' ) {
- if( (hexcount & 1) ) {
- *erroff = p - buffer;
- return gcry_error (GPG_ERR_SEXP_ODD_HEX_NUMBERS);
+
+ if (quoted)
+ {
+ if (quoted_esc)
+ {
+ switch (*p)
+ {
+ case 'b': case 't': case 'v': case 'n': case 'f':
+ case 'r': case '"': case '\'': case '\\':
+ quoted_esc = 0;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ if (! ((n > 2)
+ && (p[1] >= '0') && (p[1] <= '7')
+ && (p[2] >= '0') && (p[2] <= '7')))
+ {
+ *erroff = p - buffer;
+ /* Invalid octal value. */
+ err = GPG_ERR_SEXP_BAD_QUOTATION;
+ //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
+ }
+ p += 2;
+ n -= 2;
+ quoted_esc = 0;
+ break;
+
+ case 'x':
+ if (! ((n > 2) && isxdigit(p[1]) && isxdigit(p[2])))
+ {
+ *erroff = p - buffer;
+ /* Invalid hex value. */
+ err = GPG_ERR_SEXP_BAD_QUOTATION;
+ //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
+ }
+ p += 2;
+ n -= 2;
+ quoted_esc = 0;
+ break;
+
+ case '\r':
+ /* ignore CR[,LF] */
+ if (n && (p[1] == '\n'))
+ {
+ p++;
+ n--;
+ }
+ quoted_esc = 0;
+ break;
+
+ case '\n':
+ /* ignore LF[,CR] */
+ if (n && (p[1] == '\r'))
+ {
+ p++;
+ n--;
+ }
+ quoted_esc = 0;
+ break;
+
+ default:
+ *erroff = p - buffer;
+ /* Invalid quoted string escape. */
+ err = GPG_ERR_SEXP_BAD_QUOTATION;
+ }
+ }
+ else if (*p == '\\')
+ quoted_esc = 1;
+ else if (*p == '\"')
+ {
+ /* keep it easy - we know that the unquoted string will
+ never be larger */
+ char *save;
+ size_t len;
+
+ quoted++; /* Skip leading quote. */
+ MAKE_SPACE (p - quoted);
+ *c.pos++ = ST_DATA;
+ save = c.pos;
+ STORE_LEN (c.pos, 0); /* Will be fixed up later. */
+ len = unquote_string (quoted, p - quoted, c.pos);
+ c.pos += len;
+ STORE_LEN (save, len);
+ quoted = NULL;
+ }
}
+ else if (hexfmt)
+ {
+ if (isxdigit (*p))
+ hexcount++;
+ else if (*p == '#')
+ {
+ if ((hexcount & 1))
+ {
+ *erroff = p - buffer;
+ err = GPG_ERR_SEXP_ODD_HEX_NUMBERS;
+ }
+
+ datalen = hexcount / 2;
+ MAKE_SPACE (datalen);
+ *c.pos++ = ST_DATA;
+ STORE_LEN (c.pos, datalen);
+ for (hexfmt++; hexfmt < p; hexfmt++)
+ {
+ if (isspace (*hexfmt))
+ continue;
+ *c.pos++ = hextobyte (hexfmt);
+ hexfmt++;
+ }
+ hexfmt = NULL;
+ }
+ else if (! isspace (*p))
+ {
+ *erroff = p - buffer;
+ err = GPG_ERR_SEXP_BAD_HEX_CHAR;
+ }
+ }
+ else if (base64)
+ {
+ if (*p == '|')
+ base64 = NULL;
+ }
+ else if (digptr)
+ {
+ if (isdigit (*p))
+ ;
+ else if (*p == ':')
+ {
+ datalen = atoi (digptr); /* FIXME: check for overflow. */
+ digptr = NULL;
+ if (datalen > n - 1)
+ {
+ *erroff = p - buffer;
+ /* Buffer too short. */
+ err = GPG_ERR_SEXP_STRING_TOO_LONG;
+ }
+ /* Make a new list entry. */
+ MAKE_SPACE (datalen);
+ *c.pos++ = ST_DATA;
+ STORE_LEN (c.pos, datalen);
+ memcpy (c.pos, p + 1, datalen);
+ c.pos += datalen;
+ n -= datalen;
+ p += datalen;
+ }
+ else if (*p == '\"')
+ {
+ digptr = NULL; /* We ignore the optional length. */
+ quoted = p;
+ quoted_esc = 0;
+ }
+ else if (*p == '#')
+ {
+ digptr = NULL; /* We ignore the optional length. */
+ hexfmt = p;
+ hexcount = 0;
+ }
+ else if (*p == '|')
+ {
+ digptr = NULL; /* We ignore the optional length. */
+ base64 = p;
+ }
+ else
+ {
+ *erroff = p - buffer;
+ err = GPG_ERR_SEXP_INV_LEN_SPEC;
+ }
+ }
+ else if (percent)
+ {
+ if (*p == 'm')
+ {
+ /* Insert an MPI. */
+ gcry_mpi_t m;
+ size_t nm = 0;
+
+ ARG_NEXT (m, gcry_mpi_t);
+
+ if (gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &nm, m))
+ BUG ();
- datalen = hexcount/2;
- MAKE_SPACE (datalen);
- *c.pos++ = ST_DATA;
- STORE_LEN (c.pos, datalen);
- for( hexfmt++; hexfmt < p; hexfmt++ ) {
- if( isspace( *hexfmt ) )
- continue;
- *c.pos++ = hextobyte( hexfmt );
- hexfmt++;
+ MAKE_SPACE (nm);
+ if ((! gcry_is_secure (c.sexp->d))
+ && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE))
+ {
+ /* We have to switch to secure allocation. */
+ gcry_sexp_t newsexp;
+ byte *newhead;
+
+ newsexp = gcry_xmalloc_secure (sizeof *newsexp
+ + c.allocated - 1);
+ newhead = newsexp->d;
+ memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d));
+ c.pos = newhead + (c.pos - c.sexp->d);
+ gcry_free (c.sexp);
+ c.sexp = newsexp;
+ }
+
+ *c.pos++ = ST_DATA;
+ STORE_LEN (c.pos, nm);
+ if (gcry_mpi_print (GCRYMPI_FMT_STD, c.pos, nm, &nm, m))
+ BUG ();
+ c.pos += nm;
+ }
+ else if (*p == 's')
+ {
+ /* Insert an string. */
+ const char *astr;
+ size_t alen;
+
+ ARG_NEXT (astr, const char *);
+ alen = strlen (astr);
+
+ MAKE_SPACE (alen);
+ *c.pos++ = ST_DATA;
+ STORE_LEN (c.pos, alen);
+ memcpy (c.pos, astr, alen);
+ c.pos += alen;
+ }
+ else if (*p == 'd')
+ {
+ /* Insert an integer as string. */
+ int aint;
+ size_t alen;
+ char buf[20];
+
+ ARG_NEXT (aint, int);
+ sprintf (buf, "%d", aint);
+ alen = strlen (buf);
+ MAKE_SPACE (alen);
+ *c.pos++ = ST_DATA;
+ STORE_LEN (c.pos, alen);
+ memcpy (c.pos, buf, alen);
+ c.pos += alen;
+ }
+ else
+ {
+ *erroff = p - buffer;
+ /* Invalid format specifier. */
+ err = GPG_ERR_SEXP_INV_LEN_SPEC;
+ }
+ percent = NULL;
}
- hexfmt = NULL;
- }
- else if( !isspace( *p ) ) {
- *erroff = p - buffer;
- return gcry_error (GPG_ERR_SEXP_BAD_HEX_CHAR);
- }
- }
- else if( base64 ) {
- if( *p == '|' )
- base64 = NULL;
- }
- else if( digptr ) {
- if( isdigit(*p) )
+ else if (*p == '(')
+ {
+ if (disphint)
+ {
+ *erroff = p - buffer;
+ /* Open display hint. */
+ err = GPG_ERR_SEXP_UNMATCHED_DH;
+ }
+ MAKE_SPACE (0);
+ *c.pos++ = ST_OPEN;
+ level++;
+ }
+ else if (*p == ')')
+ {
+ /* Walk up. */
+ if (disphint)
+ {
+ *erroff = p - buffer;
+ /* Open display hint. */
+ err = GPG_ERR_SEXP_UNMATCHED_DH;
+ }
+ MAKE_SPACE (0);
+ *c.pos++ = ST_CLOSE;
+ level--;
+ }
+ else if (*p == '\"')
+ {
+ quoted = p;
+ quoted_esc = 0;
+ }
+ else if (*p == '#')
+ {
+ hexfmt = p;
+ hexcount = 0;
+ }
+ else if (*p == '|')
+ base64 = p;
+ else if (*p == '[')
+ {
+ if (disphint)
+ {
+ *erroff = p - buffer;
+ /* Open display hint. */
+ err = GPG_ERR_SEXP_NESTED_DH;
+ }
+ disphint = p;
+ }
+ else if (*p == ']')
+ {
+ if (! disphint)
+ {
+ *erroff = p - buffer;
+ /* Open display hint. */
+ err = GPG_ERR_SEXP_UNMATCHED_DH;
+ }
+ disphint = NULL;
+ }
+ else if (isdigit (*p))
+ {
+ if (*p == '0')
+ {
+ /* A length may not begin with zero. */
+ *erroff = p - buffer;
+ err = GPG_ERR_SEXP_ZERO_PREFIX;
+ }
+ digptr = p;
+ }
+ else if (strchr (tokenchars, *p))
+ tokenp = p;
+ else if (isspace (*p))
;
- else if( *p == ':' ) {
- datalen = atoi( digptr ); /* fixme: check for overflow */
- digptr = NULL;
- if( datalen > n-1 ) {
+ else if (*p == '{')
+ {
+ /* fixme: handle rescanning: we can do this by saving our
+ current state and start over at p+1 -- Hmmm. At this
+ point here we are in a well defined state, so we don't
+ need to save it. Great. */
*erroff = p - buffer;
- /* Buffer too short. */
- return gcry_error (GPG_ERR_SEXP_STRING_TOO_LONG);
+ err = GPG_ERR_SEXP_UNEXPECTED_PUNC;
}
- /* make a new list entry */
- MAKE_SPACE (datalen);
- *c.pos++ = ST_DATA;
- STORE_LEN (c.pos, datalen);
- memcpy (c.pos, p+1, datalen );
- c.pos += datalen;
- n -= datalen;
- p += datalen;
- }
- else if( *p == '\"' ) {
- digptr = NULL; /* we ignore the optional length */
- quoted = p;
- quoted_esc = 0;
- }
- else if( *p == '#' ) {
- digptr = NULL; /* we ignore the optional length */
- hexfmt = p;
- hexcount = 0;
- }
- else if( *p == '|' ) {
- digptr = NULL; /* we ignore the optional length */
- base64 = p;
- }
- else {
- *erroff = p - buffer;
- return gcry_error (GPG_ERR_SEXP_INV_LEN_SPEC);
- }
- }
- else if ( percent ) {
- if ( *p == 'm' ) { /* insert an MPI */
- gcry_mpi_t m;
- size_t nm = 0;
-
- ARG_NEXT (m, gcry_mpi_t);
-
- if ( gcry_mpi_print( GCRYMPI_FMT_STD, NULL, 0, &nm, m ) )
- BUG ();
-
- MAKE_SPACE (nm);
- if ( !gcry_is_secure ( c.sexp->d )
- && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE ) ) {
- /* we have to switch to secure allocation */
- gcry_sexp_t newsexp;
- byte *newhead;
-
- newsexp = gcry_xmalloc_secure ( sizeof *newsexp
- + c.allocated - 1 );
- newhead = newsexp->d;
- memcpy ( newhead, c.sexp->d, (c.pos - c.sexp->d) );
- c.pos = newhead + ( c.pos - c.sexp->d );
- gcry_free ( c.sexp );
- c.sexp = newsexp;
+ else if (strchr ("&\\", *p))
+ {
+ /* Reserved punctuation. */
+ *erroff = p - buffer;
+ err = GPG_ERR_SEXP_UNEXPECTED_PUNC;
+ }
+ else if (argflag && (*p == '%'))
+ percent = p;
+ else
+ {
+ /* Bad or unavailable. */
+ *erroff = p - buffer;
+ err = GPG_ERR_SEXP_BAD_CHARACTER;
}
-
- *c.pos++ = ST_DATA;
- STORE_LEN (c.pos, nm);
- if ( gcry_mpi_print( GCRYMPI_FMT_STD, c.pos, nm, &nm, m ) )
- BUG ();
- c.pos += nm;
- }
- else if ( *p == 's' ) { /* insert an string */
- const char *astr;
- size_t alen;
-
- ARG_NEXT (astr, const char *);
- alen = strlen (astr);
-
- MAKE_SPACE (alen);
- *c.pos++ = ST_DATA;
- STORE_LEN (c.pos, alen);
- memcpy ( c.pos, astr, alen );
- c.pos += alen;
- }
- else if ( *p == 'd' ) { /* insert an integer as string */
- int aint;
- size_t alen;
- char buf[20];
-
- ARG_NEXT (aint, int);
- sprintf ( buf, "%d", aint );
- alen = strlen ( buf );
- MAKE_SPACE (alen);
- *c.pos++ = ST_DATA;
- STORE_LEN (c.pos, alen);
- memcpy ( c.pos, buf, alen );
- c.pos += alen;
- }
- else {
- *erroff = p - buffer;
- /* Invalid format specifier. */
- return gcry_error (GPG_ERR_SEXP_INV_LEN_SPEC);
- }
- percent = NULL;
- }
- else if( *p == '(' ) {
- if( disphint ) {
- *erroff = p - buffer;
- /* Open display hint. */
- return gcry_error (GPG_ERR_SEXP_UNMATCHED_DH);
- }
- MAKE_SPACE (0);
- *c.pos++ = ST_OPEN;
- level++;
- }
- else if( *p == ')' ) { /* walk up */
- if( disphint ) {
- *erroff = p - buffer;
- /* Open display hint. */
- return gcry_error (GPG_ERR_SEXP_UNMATCHED_DH);
- }
- MAKE_SPACE (0);
- *c.pos++ = ST_CLOSE;
- level--;
- }
- else if( *p == '\"' ) {
- quoted = p;
- quoted_esc = 0;
- }
- else if( *p == '#' ) {
- hexfmt = p;
- hexcount = 0;
- }
- else if( *p == '|' )
- base64 = p;
- else if( *p == '[' ) {
- if( disphint ) {
- *erroff = p - buffer;
- /* Open display hint. */
- return gcry_error (GPG_ERR_SEXP_NESTED_DH);
- }
- disphint = p;
- }
- else if( *p == ']' ) {
- if( !disphint ) {
- *erroff = p - buffer;
- /* Open display hint. */
- return gcry_error (GPG_ERR_SEXP_UNMATCHED_DH);
- }
- disphint = NULL;
- }
- else if( isdigit(*p) ) {
- if( *p == '0' ) { /* a length may not begin with zero */
- *erroff = p - buffer;
- return gcry_error (GPG_ERR_SEXP_ZERO_PREFIX);
- }
- digptr = p;
- }
- else if( strchr( tokenchars, *p ) )
- tokenp = p;
- else if( isspace(*p) )
- ;
- else if( *p == '{' ) {
- /* fixme: handle rescanning:
- * we can do this by saving our current state
- * and start over at p+1 -- Hmmm. At this point here
- * we are in a well defined state, so we don't need to save
- * it. Great.
- */
- *erroff = p - buffer;
- return gcry_error (GPG_ERR_SEXP_UNEXPECTED_PUNC);
- }
- else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/
- *erroff = p - buffer;
- return gcry_error (GPG_ERR_SEXP_UNEXPECTED_PUNC);
- }
- else if( argflag && *p == '%' ) {
- percent = p;
- }
- else { /* bad or unavailable*/
- *erroff = p - buffer;
- return gcry_error (GPG_ERR_SEXP_BAD_CHARACTER);
}
-
- }
MAKE_SPACE (0);
*c.pos++ = ST_STOP;
if (level)
- return gcry_error (GPG_ERR_SEXP_UNMATCHED_PAREN);
+ err = GPG_ERR_SEXP_UNMATCHED_PAREN;
- *retsexp = normalize ( c.sexp );
- return gcry_error (GPG_ERR_NO_ERROR);
+ if (err)
+ {
+ /* Error -> deallocate. */
+ if (c.sexp)
+ gcry_free (c.sexp);
+ /* This might be expected by existing code... */
+ *retsexp = NULL;
+ }
+ else
+ *retsexp = normalize (c.sexp);
+
+ return gcry_error (err);
#undef MAKE_SPACE
#undef STORE_LEN
}