1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Introduce a new 'ptrlen' type.

This wraps up a (pointer, length) pair into a convenient struct that
lets me return it by value from a function, and also pass it through
to other functions in one go.

Ideally quite a lot of this code base could be switched over to using
ptrlen in place of separate pointer and length variables or function
parameters. (In fact, in my personal ideal conception of C, the usual
string type would be of this form, and all the string.h functions
would operate on ptrlens instead of zero-terminated 'char *'.)

For the moment, I'm just introducing it to make some upcoming
refactoring less inconvenient. Bulk migration of existing code to
ptrlen is a project for another time.

Along with the type itself, I've provided a convenient system of
including the contents of a ptrlen in a printf; a constructor function
that wraps up a pointer and length so you can make a ptrlen on the fly
in mid-expression; a function to compare a ptrlen against an ordinary
C string (which I mostly expect to use with string literals); and a
function 'mkstr' to make a dynamically allocated C string out of one.
That last function replaces a function of the same name in sftp.c,
which I'm promoting to a whole-codebase facility and adjusting its
API.
This commit is contained in:
Simon Tatham 2018-05-27 16:56:51 +01:00
parent 8d882756b8
commit 9e96af59ce
9 changed files with 77 additions and 29 deletions

11
defs.h
View File

@ -11,6 +11,8 @@
#ifndef PUTTY_DEFS_H
#define PUTTY_DEFS_H
#include <stddef.h>
#ifndef FALSE
#define FALSE 0
#endif
@ -50,6 +52,15 @@ typedef struct Plug_vtable Plug_vtable;
typedef const Socket_vtable **Socket;
typedef const Plug_vtable **Plug;
/*
* A small structure wrapping up a (pointer, length) pair so that it
* can be conveniently passed to or from a function.
*/
typedef struct ptrlen {
const void *ptr;
size_t len;
} ptrlen;
/* Do a compile-time type-check of 'to_check' (without evaluating it),
* as a side effect of returning the value 'to_return'. Note that
* although this macro double-*expands* to_return, it always

View File

@ -52,6 +52,11 @@ void BinarySink_put_string(BinarySink *bs, const void *data, size_t len)
bs->write(bs, data, len);
}
void BinarySink_put_stringpl(BinarySink *bs, ptrlen pl)
{
BinarySink_put_string(bs, pl.ptr, pl.len);
}
void BinarySink_put_stringz(BinarySink *bs, const char *str)
{
BinarySink_put_string(bs, str, strlen(str));

View File

@ -88,6 +88,8 @@ struct BinarySink {
* that then gets wrapped into a string container in an outer one). */
#define put_string(bs, val, len) \
BinarySink_put_string(BinarySink_UPCAST(bs),val,len)
#define put_stringpl(bs, ptrlen) \
BinarySink_put_stringpl(BinarySink_UPCAST(bs),ptrlen)
#define put_stringz(bs, val) \
BinarySink_put_stringz(BinarySink_UPCAST(bs), val)
#define put_stringsb(bs, val) \
@ -129,6 +131,7 @@ void BinarySink_put_bool(BinarySink *, int);
void BinarySink_put_uint16(BinarySink *, unsigned long);
void BinarySink_put_uint32(BinarySink *, unsigned long);
void BinarySink_put_string(BinarySink *, const void *data, size_t len);
void BinarySink_put_stringpl(BinarySink *, ptrlen);
void BinarySink_put_stringz(BinarySink *, const char *str);
struct strbuf;
void BinarySink_put_stringsb(BinarySink *, struct strbuf *);

32
misc.c
View File

@ -360,6 +360,16 @@ int toint(unsigned u)
return INT_MIN; /* fallback; should never occur on binary machines */
}
int string_length_for_printf(size_t s)
{
/* Truncate absurdly long strings (should one show up) to fit
* within a positive 'int', which is what the "%.*s" format will
* expect. */
if (s > INT_MAX)
return INT_MAX;
return s;
}
/*
* Do an sprintf(), but into a custom-allocated buffer.
*
@ -1177,6 +1187,28 @@ int match_ssh_id(int stringlen, const void *string, const char *id)
return (idlen == stringlen && !memcmp(string, id, idlen));
}
ptrlen make_ptrlen(const void *ptr, size_t len)
{
ptrlen pl;
pl.ptr = ptr;
pl.len = len;
return pl;
}
int ptrlen_eq_string(ptrlen pl, const char *str)
{
size_t len = strlen(str);
return (pl.len == len && !memcmp(pl.ptr, str, len));
}
char *mkstr(ptrlen pl)
{
char *p = snewn(pl.len + 1, char);
memcpy(p, pl.ptr, pl.len);
p[pl.len] = '\0';
return p;
}
void *get_ssh_string(int *datalen, const void **data, int *stringlen)
{
void *ret;

8
misc.h
View File

@ -87,6 +87,14 @@ int validate_manual_hostkey(char *key);
struct tm ltime(void);
ptrlen make_ptrlen(const void *ptr, size_t len);
int ptrlen_eq_string(ptrlen pl, const char *str);
char *mkstr(ptrlen pl);
int string_length_for_printf(size_t);
/* Derive two printf arguments from a ptrlen, suitable for "%.*s" */
#define PTRLEN_PRINTF(pl) \
string_length_for_printf((pl).len), (const char *)(pl).ptr
/* Wipe sensitive data out of memory that's about to be freed. Simpler
* than memset because we don't need the fill char parameter; also
* attempts (by fiddly use of volatile) to inhibit the compiler from

View File

@ -556,7 +556,7 @@ void pageant_handle_msg(BinarySink *bs,
key = snew(struct ssh2_userkey);
key->data = NULL;
key->comment = NULL;
key->alg = find_pubkey_alg_len(alglen, alg);
key->alg = find_pubkey_alg_len(make_ptrlen(alg, alglen));
if (!key->alg) {
pageant_failure_msg(bs, "algorithm unknown", logctx, logfn);
goto add2_cleanup;

22
sftp.c
View File

@ -341,18 +341,6 @@ struct sftp_request *sftp_find_request(struct sftp_packet *pktin)
return req;
}
/* ----------------------------------------------------------------------
* String handling routines.
*/
static char *mkstr(char *s, int len)
{
char *p = snewn(len + 1, char);
memcpy(p, s, len);
p[len] = '\0';
return p;
}
/* ----------------------------------------------------------------------
* SFTP primitives.
*/
@ -500,7 +488,7 @@ char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req)
sftp_pkt_free(pktin);
return NULL;
}
path = mkstr(path, len);
path = mkstr(make_ptrlen(path, len));
sftp_pkt_free(pktin);
return path;
} else {
@ -548,7 +536,7 @@ struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin,
return NULL;
}
handle = snew(struct fxp_handle);
handle->hstring = mkstr(hstring, len);
handle->hstring = mkstr(make_ptrlen(hstring, len));
handle->hlen = len;
sftp_pkt_free(pktin);
return handle;
@ -590,7 +578,7 @@ struct fxp_handle *fxp_opendir_recv(struct sftp_packet *pktin,
return NULL;
}
handle = snew(struct fxp_handle);
handle->hstring = mkstr(hstring, len);
handle->hstring = mkstr(make_ptrlen(hstring, len));
handle->hlen = len;
sftp_pkt_free(pktin);
return handle;
@ -977,8 +965,8 @@ struct fxp_names *fxp_readdir_recv(struct sftp_packet *pktin,
sfree(pktin);
return NULL;
}
ret->names[i].filename = mkstr(str1, len1);
ret->names[i].longname = mkstr(str2, len2);
ret->names[i].filename = mkstr(make_ptrlen(str1, len1));
ret->names[i].longname = mkstr(make_ptrlen(str2, len2));
}
sftp_pkt_free(pktin);
return ret;

2
ssh.h
View File

@ -736,7 +736,7 @@ int ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
char *passphrase);
const ssh_keyalg *find_pubkey_alg(const char *name);
const ssh_keyalg *find_pubkey_alg_len(int namelen, const char *name);
const ssh_keyalg *find_pubkey_alg_len(ptrlen name);
enum {
SSH_KEYTYPE_UNOPENABLE,

View File

@ -584,19 +584,19 @@ struct ssh2_userkey ssh2_wrong_passphrase = {
NULL, NULL, NULL
};
const ssh_keyalg *find_pubkey_alg_len(int namelen, const char *name)
const ssh_keyalg *find_pubkey_alg_len(ptrlen name)
{
if (match_ssh_id(namelen, name, "ssh-rsa"))
if (ptrlen_eq_string(name, "ssh-rsa"))
return &ssh_rsa;
else if (match_ssh_id(namelen, name, "ssh-dss"))
else if (ptrlen_eq_string(name, "ssh-dss"))
return &ssh_dss;
else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp256"))
else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp256"))
return &ssh_ecdsa_nistp256;
else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp384"))
else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp384"))
return &ssh_ecdsa_nistp384;
else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp521"))
else if (ptrlen_eq_string(name, "ecdsa-sha2-nistp521"))
return &ssh_ecdsa_nistp521;
else if (match_ssh_id(namelen, name, "ssh-ed25519"))
else if (ptrlen_eq_string(name, "ssh-ed25519"))
return &ssh_ecdsa_ed25519;
else
return NULL;
@ -604,7 +604,7 @@ const ssh_keyalg *find_pubkey_alg_len(int namelen, const char *name)
const ssh_keyalg *find_pubkey_alg(const char *name)
{
return find_pubkey_alg_len(strlen(name), name);
return find_pubkey_alg_len(make_ptrlen(name, strlen(name)));
}
struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
@ -1535,7 +1535,7 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen)
* If we can actually identify the algorithm as one we know
* about, get hold of the key's bit count too.
*/
alg = find_pubkey_alg_len(alglen, algstr);
alg = find_pubkey_alg_len(make_ptrlen(algstr, alglen));
if (alg) {
int bits = alg->pubkey_bits(alg, blob, bloblen);
return dupprintf("%.*s %d %s", alglen, algstr,
@ -1600,7 +1600,8 @@ static int key_type_fp(FILE *fp)
(p = p+1 + strspn(p+1, "0123456789"), *p == ' ') &&
(p = p+1 + strspn(p+1, "0123456789"), *p == ' ' || *p == '\n' || !*p))
return SSH_KEYTYPE_SSH1_PUBLIC;
if ((p = buf + strcspn(buf, " "), find_pubkey_alg_len(p-buf, buf)) &&
if ((p = buf + strcspn(buf, " "),
find_pubkey_alg_len(make_ptrlen(buf, p-buf))) &&
(p = p+1 + strspn(p+1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij"
"klmnopqrstuvwxyz+/="),
*p == ' ' || *p == '\n' || !*p))