From 0337b1e8dcc96bd5ac157e181f9d44290c3767b4 Mon Sep 17 00:00:00 2001 From: Moritz Schulte Date: Mon, 27 Oct 2003 22:13:43 +0000 Subject: 2003-10-27 Moritz Schulte * sexp.c (sexp_sscan): Cleaned up, deallocate scanned sexp on error. --- src/sexp.c | 653 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 364 insertions(+), 289 deletions(-) (limited to 'src/sexp.c') 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 } -- cgit v1.2.1