From 74abfcf0c3ba7cd6ce36540c70699fc1719248b3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 2 Oct 2014 10:50:57 +0200 Subject: Add GPG_ERR_BOGUS_STRING and an experimental gpgrt_pending. * src/visibility.c (gpgrt_pending, gpgrt_pending_unlocked): New. * src/estream.c (_gpgrt_pending, _gpgrt_pending_unlocked): New. (check_pending): new. (check_pending_fbf, check_pending_nbf): New. (es_func_mem_read, es_func_fd_read, es_func_w32_read) (es_func_fp_read, es_fill): Take care of the special 0 value for SIZE. --- NEWS | 3 ++ doc/errorref.txt | 22 +++++++++- src/err-codes.h.in | 4 +- src/estream.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/gpg-error.def.in | 3 ++ src/gpg-error.h.in | 4 ++ src/gpg-error.vers | 2 + src/gpgrt-int.h | 2 + src/visibility.c | 12 ++++++ src/visibility.h | 4 ++ 10 files changed, 160 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 2e49b0c..4330408 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,9 @@ Noteworthy changes in version 1.17 (unreleased) [C12/A12/R_] GPG_ERR_BAD_HS_FINISHED NEW. GPG_ERR_BAD_HS_SERVER_KEX NEW. GPG_ERR_BAD_HS_CLIENT_KEX NEW. + GPG_ERR_BOGUS_STRING NEW. + gpgrt_pending NEW. + gpgrt_pending_unlocked NEW. Noteworthy changes in version 1.16 (2014-09-18) [C12/A12/R2] diff --git a/doc/errorref.txt b/doc/errorref.txt index 666dca6..07b7cd4 100644 --- a/doc/errorref.txt +++ b/doc/errorref.txt @@ -219,7 +219,12 @@ GPG_ERR_INV_ARG Invalid argument 52 GPG_ERR_NOT_PROCESSED Data not processed 53 GPG_ERR_UNUSABLE_PUBKEY Unusable public key 54 GPG_ERR_UNUSABLE_SECKEY Unusable secret key -55 GPG_ERR_INV_VALUE Invalid value + +GPG_ERR_INV_VALUE Invalid value + + NTBTLS: - A DH parameter is out of range + + 56 GPG_ERR_BAD_CERT_CHAIN Bad certificate chain GPG_ERR_MISSING_CERT Missing certificate @@ -516,7 +521,13 @@ GPG_ERR_LIMIT_REACHED Limit reached GnuPG: gpgtar: Extract directory can't be created because too many of directories with a similar name are already existing. -184 GPG_ERR_NOT_INITIALIZED Not initialized +GPG_ERR_NOT_INITIALIZED Not initialized + + An operation can't be performed because something has not been + initialized. This might be a missing initialization of an entire + subsystems or a prerequisite for using a function is not + fulfilled. + 185 GPG_ERR_MISSING_ISSUER_CERT Missing issuer certificate 186 GPG_ERR_NO_KEYSERVER No keyserver available @@ -699,6 +710,13 @@ GPG_ERR_BAD_HS_CLIENT_KEX Bad client key exchange message in handshake NTBTLS: - As the description says. +GPG_ERR_BOGUS_STRING Bogus string + + Used if a protocol sends length prefixed strings which contain a + Nul byte and further processing would discard the rest of the + string. May also be used if a string contains unexpected and + possible dangerous characters (e.g. control characters in a domain + name). GPG_ERR_KEY_DISABLED Key disabled diff --git a/src/err-codes.h.in b/src/err-codes.h.in index 9274530..704049c 100644 --- a/src/err-codes.h.in +++ b/src/err-codes.h.in @@ -273,8 +273,8 @@ 247 GPG_ERR_BAD_HS_FINISHED Bad finished message in handshake 248 GPG_ERR_BAD_HS_SERVER_KEX Bad server key exchange message in handshake 249 GPG_ERR_BAD_HS_CLIENT_KEX Bad client key exchange message in handshake - -# 250 and 251 are free to be used. +250 GPG_ERR_BOGUS_STRING Bogus string +# 251 is free to be used. 252 GPG_ERR_KEY_DISABLED Key disabled 253 GPG_ERR_KEY_ON_CARD Not possible with a card based key diff --git a/src/estream.c b/src/estream.c index 46be363..2537141 100644 --- a/src/estream.c +++ b/src/estream.c @@ -625,6 +625,9 @@ es_func_mem_read (void *cookie, void *buffer, size_t size) estream_cookie_mem_t mem_cookie = cookie; gpgrt_ssize_t ret; + if (!size) /* Just the pending data check. */ + return (mem_cookie->data_len - mem_cookie->offset)? 0 : -1; + if (size > mem_cookie->data_len - mem_cookie->offset) size = mem_cookie->data_len - mem_cookie->offset; @@ -898,7 +901,9 @@ es_func_fd_read (void *cookie, void *buffer, size_t size) estream_cookie_fd_t file_cookie = cookie; gpgrt_ssize_t bytes_read; - if (IS_INVALID_FD (file_cookie->fd)) + if (!size) + bytes_read = -1; /* We don't know whether anything is pending. */ + else if (IS_INVALID_FD (file_cookie->fd)) { _gpgrt_yield (); bytes_read = 0; @@ -1057,7 +1062,9 @@ es_func_w32_read (void *cookie, void *buffer, size_t size) estream_cookie_w32_t w32_cookie = cookie; gpgrt_ssize_t bytes_read; - if (w32_cookie->hd == INVALID_HANDLE_VALUE) + if (!size) + bytes_to_read = -1; /* We don't know whether anything is pending. */ + else if (w32_cookie->hd == INVALID_HANDLE_VALUE) { _gpgrt_yield (); bytes_read = 0; @@ -1273,6 +1280,9 @@ es_func_fp_read (void *cookie, void *buffer, size_t size) estream_cookie_fp_t file_cookie = cookie; gpgrt_ssize_t bytes_read; + if (!size) + return -1; /* We don't know whether anything is pending. */ + if (file_cookie->fp) { if (pre_syscall_func) @@ -1602,6 +1612,8 @@ es_fill (estream_t stream) _set_errno (EOPNOTSUPP); err = -1; } + else if (!stream->buffer_size) + err = 0; else { gpgrt_cookie_read_function_t func_read = stream->intern->func_read; @@ -1937,6 +1949,18 @@ es_read_nbf (estream_t _GPGRT__RESTRICT stream, return err; } +static int +check_pending_nbf (estream_t _GPGRT__RESTRICT stream) +{ + gpgrt_cookie_read_function_t func_read = stream->intern->func_read; + char buffer[1]; + + if (!(*func_read) (stream->intern->cookie, buffer, 0)) + return 1; /* Pending bytes. */ + return 0; /* No pending bytes or error. */ +} + + /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in fully-buffered-mode, storing the amount of bytes read in *BYTES_READ. */ @@ -1987,6 +2011,26 @@ es_read_fbf (estream_t _GPGRT__RESTRICT stream, return err; } + +static int +check_pending_fbf (estream_t _GPGRT__RESTRICT stream) +{ + gpgrt_cookie_read_function_t func_read = stream->intern->func_read; + char buffer[1]; + + if (stream->data_offset == stream->data_len) + { + /* Nothing more to read in current container, check whetehr it + would be possible to fill the container with new data. */ + if (!(*func_read) (stream->intern->cookie, buffer, 0)) + return 1; /* Pending bytes. */ + } + else + return 1; + return 0; +} + + /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in line-buffered-mode, storing the amount of bytes read in *BYTES_READ. */ @@ -2003,7 +2047,7 @@ es_read_lbf (estream_t _GPGRT__RESTRICT stream, } /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing - *the amount of bytes read in BYTES_READ. */ + the amount of bytes read in BYTES_READ. */ static int es_readn (estream_t _GPGRT__RESTRICT stream, void *_GPGRT__RESTRICT buffer_arg, @@ -2062,6 +2106,39 @@ es_readn (estream_t _GPGRT__RESTRICT stream, return err; } + +/* Return true if at least one byte is pending for read. This is a + best effort check and it it possible that bytes are still pending + even if false is returned. If the stream is in writing mode it is + switched to read mode. */ +static int +check_pending (estream_t _GPGRT__RESTRICT stream) +{ + if (stream->flags.writing) + { + /* Switching to reading mode -> flush output. */ + if (es_flush (stream)) + return 0; /* Better return 0 on error. */ + stream->flags.writing = 0; + } + + /* Check unread data first. */ + if (stream->unread_data_len) + return 1; + + switch (stream->intern->strategy) + { + case _IONBF: + return check_pending_nbf (stream); + case _IOLBF: + case _IOFBF: + return check_pending_fbf (stream); + } + + return 0; +} + + /* Try to unread DATA_N bytes from DATA into STREAM, storing the amount of bytes successfully unread in *BYTES_UNREAD. */ static void @@ -3393,6 +3470,34 @@ _gpgrt_syshd (estream_t stream, es_syshd_t *syshd) } +int +_gpgrt_pending_unlocked (estream_t stream) +{ + return check_pending (stream); +} + + +/* Return true if there is at least one byte pending for read on + STREAM. This does only work if the backend supports checking for + pending bytes and is thus mostly useful with cookie based backends. + + Note that if this function is used with cookie based functions, the + read cookie may be called with 0 for the SIZE argument. If bytes + are pending the function is expected to return -1 in this case and + thus deviates from the standard behavior of read(2). */ +int +_gpgrt_pending (estream_t stream) +{ + int ret; + + lock_stream (stream); + ret = _gpgrt_pending_unlocked (stream); + unlock_stream (stream); + + return ret; +} + + int _gpgrt_feof_unlocked (estream_t stream) { diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in index ac20a69..f17522e 100644 --- a/src/gpg-error.def.in +++ b/src/gpg-error.def.in @@ -137,4 +137,7 @@ EXPORTS gpg_err_deinit @102 gpgrt_set_alloc_func @103 + gpgrt_pending @104 + gpgrt_pending_unlocked @105 + ;; end of file with public symbols for Windows. diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in index 80ce391..6ac6e0a 100644 --- a/src/gpg-error.h.in +++ b/src/gpg-error.h.in @@ -496,6 +496,8 @@ int gpgrt_ferror (gpgrt_stream_t stream); int gpgrt_ferror_unlocked (gpgrt_stream_t stream); void gpgrt_clearerr (gpgrt_stream_t stream); void gpgrt_clearerr_unlocked (gpgrt_stream_t stream); +int gpgrt_pending (gpgrt_stream_t stream); +int gpgrt_pending_unlocked (gpgrt_stream_t stream); int gpgrt_fflush (gpgrt_stream_t stream); int gpgrt_fseek (gpgrt_stream_t stream, long int offset, int whence); @@ -648,6 +650,8 @@ int gpgrt_vsnprintf (char *buf,size_t bufsize, # define es_ferror_unlocked gpgrt_ferror_unlocked # define es_clearerr gpgrt_clearerr # define es_clearerr_unlocked gpgrt_clearerr_unlocked +# define es_pending gpgrt_pending +# define es_pending_unlocked gpgrt_pending_unlocked # define es_fflush gpgrt_fflush # define es_fseek gpgrt_fseek # define es_fseeko gpgrt_fseeko diff --git a/src/gpg-error.vers b/src/gpg-error.vers index 43becea..c0e599a 100644 --- a/src/gpg-error.vers +++ b/src/gpg-error.vers @@ -64,6 +64,8 @@ GPG_ERROR_1.0 { gpgrt_flockfile; gpgrt_ftrylockfile; gpgrt_funlockfile; + gpgrt_pending; + gpgrt_pending_unlocked; gpgrt_feof; gpgrt_feof_unlocked; gpgrt_ferror; diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h index f97166f..8907835 100644 --- a/src/gpgrt-int.h +++ b/src/gpgrt-int.h @@ -102,6 +102,8 @@ int _gpgrt_ferror (gpgrt_stream_t stream); int _gpgrt_ferror_unlocked (gpgrt_stream_t stream); void _gpgrt_clearerr (gpgrt_stream_t stream); void _gpgrt_clearerr_unlocked (gpgrt_stream_t stream); +int _gpgrt_pending (gpgrt_stream_t stream); +int _gpgrt_pending_unlocked (gpgrt_stream_t stream); int _gpgrt_fflush (gpgrt_stream_t stream); int _gpgrt_fseek (gpgrt_stream_t stream, long int offset, int whence); diff --git a/src/visibility.c b/src/visibility.c index f0d7fd1..f26f58c 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -297,6 +297,18 @@ gpgrt_funlockfile (estream_t stream) _gpgrt_funlockfile (stream); } +int +gpgrt_pending (estream_t stream) +{ + return _gpgrt_pending (stream); +} + +int +gpgrt_pending_unlocked (estream_t stream) +{ + return _gpgrt_pending_unlocked (stream); +} + int gpgrt_feof (estream_t stream) { diff --git a/src/visibility.h b/src/visibility.h index feeb8d1..35878d7 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -87,6 +87,8 @@ MARK_VISIBLE (_gpgrt_get_std_stream) MARK_VISIBLE (gpgrt_flockfile) MARK_VISIBLE (gpgrt_ftrylockfile) MARK_VISIBLE (gpgrt_funlockfile) +MARK_VISIBLE (gpgrt_pending) +MARK_VISIBLE (gpgrt_pending_unlocked) MARK_VISIBLE (gpgrt_feof) MARK_VISIBLE (gpgrt_feof_unlocked) MARK_VISIBLE (gpgrt_ferror) @@ -190,6 +192,8 @@ MARK_VISIBLE (gpgrt_set_alloc_func) #define gpgrt_flockfile _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_ftrylockfile _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_funlockfile _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_pending _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_pending_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_feof _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_feof_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION #define gpgrt_ferror _gpgrt_USE_UNDERSCORED_FUNCTION -- cgit v1.2.3