2018-05-24 11:17:13 +03:00
|
|
|
#include <assert.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "marshal.h"
|
|
|
|
#include "misc.h"
|
|
|
|
|
|
|
|
void BinarySink_put_data(BinarySink *bs, const void *data, size_t len)
|
|
|
|
{
|
|
|
|
bs->write(bs, data, len);
|
|
|
|
}
|
|
|
|
|
2019-01-01 22:00:19 +03:00
|
|
|
void BinarySink_put_datapl(BinarySink *bs, ptrlen pl)
|
|
|
|
{
|
|
|
|
BinarySink_put_data(bs, pl.ptr, pl.len);
|
|
|
|
}
|
|
|
|
|
2018-06-13 21:42:19 +03:00
|
|
|
void BinarySink_put_padding(BinarySink *bs, size_t len, unsigned char padbyte)
|
2018-06-09 11:01:07 +03:00
|
|
|
{
|
|
|
|
char buf[16];
|
|
|
|
memset(buf, padbyte, sizeof(buf));
|
|
|
|
while (len > 0) {
|
|
|
|
size_t thislen = len < sizeof(buf) ? len : sizeof(buf);
|
|
|
|
bs->write(bs, buf, thislen);
|
|
|
|
len -= thislen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-24 11:17:13 +03:00
|
|
|
void BinarySink_put_byte(BinarySink *bs, unsigned char val)
|
|
|
|
{
|
|
|
|
bs->write(bs, &val, 1);
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 22:23:19 +03:00
|
|
|
void BinarySink_put_bool(BinarySink *bs, bool val)
|
2018-05-24 11:17:13 +03:00
|
|
|
{
|
|
|
|
unsigned char cval = val ? 1 : 0;
|
|
|
|
bs->write(bs, &cval, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinarySink_put_uint16(BinarySink *bs, unsigned long val)
|
|
|
|
{
|
|
|
|
unsigned char data[2];
|
|
|
|
PUT_16BIT_MSB_FIRST(data, val);
|
|
|
|
bs->write(bs, data, sizeof(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinarySink_put_uint32(BinarySink *bs, unsigned long val)
|
|
|
|
{
|
|
|
|
unsigned char data[4];
|
|
|
|
PUT_32BIT_MSB_FIRST(data, val);
|
|
|
|
bs->write(bs, data, sizeof(data));
|
|
|
|
}
|
|
|
|
|
2018-10-27 01:08:58 +03:00
|
|
|
void BinarySink_put_uint64(BinarySink *bs, uint64_t val)
|
2018-05-24 11:17:13 +03:00
|
|
|
{
|
2018-10-27 01:08:58 +03:00
|
|
|
unsigned char data[8];
|
|
|
|
PUT_64BIT_MSB_FIRST(data, val);
|
|
|
|
bs->write(bs, data, sizeof(data));
|
2018-05-24 11:17:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void BinarySink_put_string(BinarySink *bs, const void *data, size_t len)
|
|
|
|
{
|
|
|
|
/* Check that the string length fits in a uint32, without doing a
|
|
|
|
* potentially implementation-defined shift of more than 31 bits */
|
|
|
|
assert((len >> 31) < 2);
|
|
|
|
|
|
|
|
BinarySink_put_uint32(bs, len);
|
|
|
|
bs->write(bs, data, len);
|
|
|
|
}
|
|
|
|
|
2018-05-27 18:56:51 +03:00
|
|
|
void BinarySink_put_stringpl(BinarySink *bs, ptrlen pl)
|
|
|
|
{
|
|
|
|
BinarySink_put_string(bs, pl.ptr, pl.len);
|
|
|
|
}
|
|
|
|
|
2018-05-24 11:17:13 +03:00
|
|
|
void BinarySink_put_stringz(BinarySink *bs, const char *str)
|
|
|
|
{
|
|
|
|
BinarySink_put_string(bs, str, strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinarySink_put_stringsb(BinarySink *bs, struct strbuf *buf)
|
|
|
|
{
|
|
|
|
BinarySink_put_string(bs, buf->s, buf->len);
|
|
|
|
strbuf_free(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinarySink_put_asciz(BinarySink *bs, const char *str)
|
|
|
|
{
|
|
|
|
bs->write(bs, str, strlen(str) + 1);
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 22:23:19 +03:00
|
|
|
bool BinarySink_put_pstring(BinarySink *bs, const char *str)
|
2018-05-24 11:17:13 +03:00
|
|
|
{
|
|
|
|
size_t len = strlen(str);
|
|
|
|
if (len > 255)
|
2018-10-29 22:50:29 +03:00
|
|
|
return false; /* can't write a Pascal-style string this long */
|
2018-05-24 11:17:13 +03:00
|
|
|
BinarySink_put_byte(bs, len);
|
|
|
|
bs->write(bs, str, len);
|
2018-10-29 22:50:29 +03:00
|
|
|
return true;
|
2018-05-24 11:17:13 +03:00
|
|
|
}
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 22:23:19 +03:00
|
|
|
static bool BinarySource_data_avail(BinarySource *src, size_t wanted)
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
{
|
|
|
|
if (src->err)
|
2018-10-29 22:50:29 +03:00
|
|
|
return false;
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
|
|
|
|
if (wanted <= src->len - src->pos)
|
2018-10-29 22:50:29 +03:00
|
|
|
return true;
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
|
|
|
|
src->err = BSE_OUT_OF_DATA;
|
2018-10-29 22:50:29 +03:00
|
|
|
return false;
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#define avail(wanted) BinarySource_data_avail(src, wanted)
|
|
|
|
#define advance(dist) (src->pos += dist)
|
|
|
|
#define here ((const void *)((const unsigned char *)src->data + src->pos))
|
|
|
|
#define consume(dist) \
|
|
|
|
((const void *)((const unsigned char *)src->data + \
|
|
|
|
((src->pos += dist) - dist)))
|
|
|
|
|
|
|
|
ptrlen BinarySource_get_data(BinarySource *src, size_t wanted)
|
|
|
|
{
|
|
|
|
if (!avail(wanted))
|
|
|
|
return make_ptrlen("", 0);
|
|
|
|
|
|
|
|
return make_ptrlen(consume(wanted), wanted);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char BinarySource_get_byte(BinarySource *src)
|
|
|
|
{
|
|
|
|
const unsigned char *ucp;
|
|
|
|
|
|
|
|
if (!avail(1))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ucp = consume(1);
|
|
|
|
return *ucp;
|
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 22:23:19 +03:00
|
|
|
bool BinarySource_get_bool(BinarySource *src)
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
{
|
|
|
|
const unsigned char *ucp;
|
|
|
|
|
|
|
|
if (!avail(1))
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 22:23:19 +03:00
|
|
|
return false;
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
|
|
|
|
ucp = consume(1);
|
|
|
|
return *ucp != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned BinarySource_get_uint16(BinarySource *src)
|
|
|
|
{
|
|
|
|
const unsigned char *ucp;
|
|
|
|
|
|
|
|
if (!avail(2))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ucp = consume(2);
|
|
|
|
return GET_16BIT_MSB_FIRST(ucp);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long BinarySource_get_uint32(BinarySource *src)
|
|
|
|
{
|
|
|
|
const unsigned char *ucp;
|
|
|
|
|
|
|
|
if (!avail(4))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ucp = consume(4);
|
|
|
|
return GET_32BIT_MSB_FIRST(ucp);
|
|
|
|
}
|
|
|
|
|
2018-10-27 01:08:58 +03:00
|
|
|
uint64_t BinarySource_get_uint64(BinarySource *src)
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
{
|
|
|
|
const unsigned char *ucp;
|
|
|
|
|
2018-10-27 01:08:58 +03:00
|
|
|
if (!avail(8))
|
|
|
|
return 0;
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
|
|
|
|
ucp = consume(8);
|
2018-10-27 01:08:58 +03:00
|
|
|
return GET_64BIT_MSB_FIRST(ucp);
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ptrlen BinarySource_get_string(BinarySource *src)
|
|
|
|
{
|
|
|
|
const unsigned char *ucp;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (!avail(4))
|
|
|
|
return make_ptrlen("", 0);
|
|
|
|
|
|
|
|
ucp = consume(4);
|
|
|
|
len = GET_32BIT_MSB_FIRST(ucp);
|
|
|
|
|
|
|
|
if (!avail(len))
|
|
|
|
return make_ptrlen("", 0);
|
|
|
|
|
|
|
|
return make_ptrlen(consume(len), len);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *BinarySource_get_asciz(BinarySource *src)
|
|
|
|
{
|
|
|
|
const char *start, *end;
|
|
|
|
|
|
|
|
if (src->err)
|
|
|
|
return "";
|
|
|
|
|
|
|
|
start = here;
|
|
|
|
end = memchr(start, '\0', src->len - src->pos);
|
|
|
|
if (!end) {
|
|
|
|
src->err = BSE_OUT_OF_DATA;
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
advance(end + 1 - start);
|
|
|
|
return start;
|
|
|
|
}
|
|
|
|
|
2020-01-06 22:55:41 +03:00
|
|
|
static ptrlen BinarySource_get_chars_internal(
|
|
|
|
BinarySource *src, const char *set, bool include)
|
|
|
|
{
|
|
|
|
const char *start = here;
|
|
|
|
while (avail(1)) {
|
|
|
|
bool present = NULL != strchr(set, *(const char *)consume(0));
|
|
|
|
if (present != include)
|
|
|
|
break;
|
2020-01-10 22:24:59 +03:00
|
|
|
(void) consume(1);
|
2020-01-06 22:55:41 +03:00
|
|
|
}
|
|
|
|
const char *end = here;
|
|
|
|
return make_ptrlen(start, end - start);
|
|
|
|
}
|
|
|
|
|
|
|
|
ptrlen BinarySource_get_chars(BinarySource *src, const char *include_set)
|
|
|
|
{
|
|
|
|
return BinarySource_get_chars_internal(src, include_set, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
ptrlen BinarySource_get_nonchars(BinarySource *src, const char *exclude_set)
|
|
|
|
{
|
|
|
|
return BinarySource_get_chars_internal(src, exclude_set, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
ptrlen BinarySource_get_chomped_line(BinarySource *src)
|
|
|
|
{
|
|
|
|
const char *start, *end;
|
|
|
|
|
|
|
|
if (src->err)
|
|
|
|
return make_ptrlen(here, 0);
|
|
|
|
|
|
|
|
start = here;
|
|
|
|
end = memchr(start, '\n', src->len - src->pos);
|
|
|
|
if (end)
|
|
|
|
advance(end + 1 - start);
|
|
|
|
else
|
|
|
|
advance(src->len - src->pos);
|
|
|
|
end = here;
|
|
|
|
|
|
|
|
if (end > start && end[-1] == '\n')
|
|
|
|
end--;
|
|
|
|
if (end > start && end[-1] == '\r')
|
|
|
|
end--;
|
|
|
|
|
|
|
|
return make_ptrlen(start, end - start);
|
|
|
|
}
|
|
|
|
|
Introduce a centralised unmarshaller, 'BinarySource'.
This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.
However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.
The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
2018-06-02 10:25:19 +03:00
|
|
|
ptrlen BinarySource_get_pstring(BinarySource *src)
|
|
|
|
{
|
|
|
|
const unsigned char *ucp;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (!avail(1))
|
|
|
|
return make_ptrlen("", 0);
|
|
|
|
|
|
|
|
ucp = consume(1);
|
|
|
|
len = *ucp;
|
|
|
|
|
|
|
|
if (!avail(len))
|
|
|
|
return make_ptrlen("", 0);
|
|
|
|
|
|
|
|
return make_ptrlen(consume(len), len);
|
|
|
|
}
|
2019-02-20 09:52:54 +03:00
|
|
|
|
2020-01-06 22:55:41 +03:00
|
|
|
void BinarySource_REWIND_TO__(BinarySource *src, size_t pos)
|
|
|
|
{
|
|
|
|
if (pos <= src->len) {
|
|
|
|
src->pos = pos;
|
|
|
|
src->err = BSE_NO_ERROR; /* clear any existing error */
|
|
|
|
} else {
|
|
|
|
src->pos = src->len;
|
|
|
|
src->err = BSE_OUT_OF_DATA; /* new error if we rewind out of range */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-20 09:52:54 +03:00
|
|
|
static void stdio_sink_write(BinarySink *bs, const void *data, size_t len)
|
|
|
|
{
|
|
|
|
stdio_sink *sink = BinarySink_DOWNCAST(bs, stdio_sink);
|
|
|
|
fwrite(data, 1, len, sink->fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void stdio_sink_init(stdio_sink *sink, FILE *fp)
|
|
|
|
{
|
|
|
|
sink->fp = fp;
|
|
|
|
BinarySink_INIT(sink, stdio_sink_write);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bufchain_sink_write(BinarySink *bs, const void *data, size_t len)
|
|
|
|
{
|
|
|
|
bufchain_sink *sink = BinarySink_DOWNCAST(bs, bufchain_sink);
|
|
|
|
bufchain_add(sink->ch, data, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bufchain_sink_init(bufchain_sink *sink, bufchain *ch)
|
|
|
|
{
|
|
|
|
sink->ch = ch;
|
|
|
|
BinarySink_INIT(sink, bufchain_sink_write);
|
|
|
|
}
|