diff --git a/defs.h b/defs.h index 3946e1ed..87b48499 100644 --- a/defs.h +++ b/defs.h @@ -11,6 +11,8 @@ #ifndef PUTTY_DEFS_H #define PUTTY_DEFS_H +#include + #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 diff --git a/marshal.c b/marshal.c index 4c1f1bcc..48bbef78 100644 --- a/marshal.c +++ b/marshal.c @@ -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)); diff --git a/marshal.h b/marshal.h index 95ec3769..ca5a009f 100644 --- a/marshal.h +++ b/marshal.h @@ -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 *); diff --git a/misc.c b/misc.c index b14f45d2..30bfec90 100644 --- a/misc.c +++ b/misc.c @@ -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; diff --git a/misc.h b/misc.h index c4da3d6d..de662a87 100644 --- a/misc.h +++ b/misc.h @@ -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 diff --git a/pageant.c b/pageant.c index c541101f..8528cc02 100644 --- a/pageant.c +++ b/pageant.c @@ -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; diff --git a/sftp.c b/sftp.c index 77162157..ad153396 100644 --- a/sftp.c +++ b/sftp.c @@ -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; diff --git a/ssh.h b/ssh.h index de31df4a..7a1c5766 100644 --- a/ssh.h +++ b/ssh.h @@ -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, diff --git a/sshpubk.c b/sshpubk.c index 7ff7c081..68cf6945 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -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))