2004-04-27 16:31:57 +04:00
|
|
|
/*
|
|
|
|
* Platform-independent routines shared between all PuTTY programs.
|
|
|
|
*/
|
|
|
|
|
1999-01-08 16:02:13 +03:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2002-10-09 22:09:42 +04:00
|
|
|
#include <stdarg.h>
|
2005-02-20 13:30:05 +03:00
|
|
|
#include <limits.h>
|
2002-11-07 22:49:03 +03:00
|
|
|
#include <ctype.h>
|
2001-08-25 21:09:23 +04:00
|
|
|
#include <assert.h>
|
1999-01-08 16:02:13 +03:00
|
|
|
#include "putty.h"
|
2015-04-27 22:48:29 +03:00
|
|
|
#include "misc.h"
|
1999-01-08 16:02:13 +03:00
|
|
|
|
2004-12-24 16:39:32 +03:00
|
|
|
/*
|
|
|
|
* Parse a string block size specification. This is approximately a
|
|
|
|
* subset of the block size specs supported by GNU fileutils:
|
|
|
|
* "nk" = n kilobytes
|
|
|
|
* "nM" = n megabytes
|
|
|
|
* "nG" = n gigabytes
|
|
|
|
* All numbers are decimal, and suffixes refer to powers of two.
|
|
|
|
* Case-insensitive.
|
|
|
|
*/
|
|
|
|
unsigned long parse_blocksize(const char *bs)
|
|
|
|
{
|
|
|
|
char *suf;
|
|
|
|
unsigned long r = strtoul(bs, &suf, 10);
|
|
|
|
if (*suf != '\0') {
|
2005-03-21 16:46:16 +03:00
|
|
|
while (*suf && isspace((unsigned char)*suf)) suf++;
|
2004-12-24 16:39:32 +03:00
|
|
|
switch (*suf) {
|
|
|
|
case 'k': case 'K':
|
|
|
|
r *= 1024ul;
|
|
|
|
break;
|
|
|
|
case 'm': case 'M':
|
|
|
|
r *= 1024ul * 1024ul;
|
|
|
|
break;
|
|
|
|
case 'g': case 'G':
|
|
|
|
r *= 1024ul * 1024ul * 1024ul;
|
|
|
|
break;
|
|
|
|
case '\0':
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-04-19 22:58:29 +04:00
|
|
|
/*
|
|
|
|
* Parse a ^C style character specification.
|
|
|
|
* Returns NULL in `next' if we didn't recognise it as a control character,
|
|
|
|
* in which case `c' should be ignored.
|
|
|
|
* The precise current parsing is an oddity inherited from the terminal
|
2005-04-19 23:18:14 +04:00
|
|
|
* answerback-string parsing code. All sequences start with ^; all except
|
|
|
|
* ^<123> are two characters. The ones that are worth keeping are probably:
|
2005-04-19 22:58:29 +04:00
|
|
|
* ^? 127
|
|
|
|
* ^@A-Z[\]^_ 0-31
|
|
|
|
* a-z 1-26
|
2005-04-19 23:18:14 +04:00
|
|
|
* <num> specified by number (decimal, 0octal, 0xHEX)
|
2005-04-19 22:58:29 +04:00
|
|
|
* ~ ^ escape
|
|
|
|
*/
|
|
|
|
char ctrlparse(char *s, char **next)
|
|
|
|
{
|
|
|
|
char c = 0;
|
|
|
|
if (*s != '^') {
|
|
|
|
*next = NULL;
|
|
|
|
} else {
|
|
|
|
s++;
|
|
|
|
if (*s == '\0') {
|
|
|
|
*next = NULL;
|
2005-04-19 23:18:14 +04:00
|
|
|
} else if (*s == '<') {
|
|
|
|
s++;
|
|
|
|
c = (char)strtol(s, next, 0);
|
|
|
|
if ((*next == s) || (**next != '>')) {
|
|
|
|
c = 0;
|
|
|
|
*next = NULL;
|
|
|
|
} else
|
|
|
|
(*next)++;
|
2005-04-19 22:58:29 +04:00
|
|
|
} else if (*s >= 'a' && *s <= 'z') {
|
|
|
|
c = (*s - ('a' - 1));
|
2005-04-19 23:18:14 +04:00
|
|
|
*next = s+1;
|
2005-04-19 22:58:29 +04:00
|
|
|
} else if ((*s >= '@' && *s <= '_') || *s == '?' || (*s & 0x80)) {
|
|
|
|
c = ('@' ^ *s);
|
2005-04-19 23:18:14 +04:00
|
|
|
*next = s+1;
|
2005-04-19 22:58:29 +04:00
|
|
|
} else if (*s == '~') {
|
|
|
|
c = '^';
|
2005-04-19 23:18:14 +04:00
|
|
|
*next = s+1;
|
2005-04-19 22:58:29 +04:00
|
|
|
}
|
|
|
|
}
|
2005-04-19 23:18:14 +04:00
|
|
|
return c;
|
2005-04-19 22:58:29 +04:00
|
|
|
}
|
|
|
|
|
2014-01-25 19:58:47 +04:00
|
|
|
/*
|
|
|
|
* Find a character in a string, unless it's a colon contained within
|
|
|
|
* square brackets. Used for untangling strings of the form
|
|
|
|
* 'host:port', where host can be an IPv6 literal.
|
|
|
|
*
|
|
|
|
* We provide several variants of this function, with semantics like
|
|
|
|
* various standard string.h functions.
|
|
|
|
*/
|
|
|
|
static const char *host_strchr_internal(const char *s, const char *set,
|
|
|
|
int first)
|
|
|
|
{
|
|
|
|
int brackets = 0;
|
|
|
|
const char *ret = NULL;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (!*s)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (*s == '[')
|
|
|
|
brackets++;
|
|
|
|
else if (*s == ']' && brackets > 0)
|
|
|
|
brackets--;
|
|
|
|
else if (brackets && *s == ':')
|
|
|
|
/* never match */ ;
|
|
|
|
else if (strchr(set, *s)) {
|
|
|
|
ret = s;
|
|
|
|
if (first)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
size_t host_strcspn(const char *s, const char *set)
|
|
|
|
{
|
|
|
|
const char *answer = host_strchr_internal(s, set, TRUE);
|
|
|
|
if (answer)
|
|
|
|
return answer - s;
|
|
|
|
else
|
|
|
|
return strlen(s);
|
|
|
|
}
|
|
|
|
char *host_strchr(const char *s, int c)
|
|
|
|
{
|
|
|
|
char set[2];
|
|
|
|
set[0] = c;
|
|
|
|
set[1] = '\0';
|
|
|
|
return (char *) host_strchr_internal(s, set, TRUE);
|
|
|
|
}
|
|
|
|
char *host_strrchr(const char *s, int c)
|
|
|
|
{
|
|
|
|
char set[2];
|
|
|
|
set[0] = c;
|
|
|
|
set[1] = '\0';
|
|
|
|
return (char *) host_strchr_internal(s, set, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TEST_HOST_STRFOO
|
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
int passes = 0, fails = 0;
|
|
|
|
|
|
|
|
#define TEST1(func, string, arg2, suffix, result) do \
|
|
|
|
{ \
|
|
|
|
const char *str = string; \
|
|
|
|
unsigned ret = func(string, arg2) suffix; \
|
|
|
|
if (ret == result) { \
|
|
|
|
passes++; \
|
|
|
|
} else { \
|
|
|
|
printf("fail: %s(%s,%s)%s = %u, expected %u\n", \
|
2017-06-20 09:05:39 +03:00
|
|
|
#func, #string, #arg2, #suffix, ret, \
|
|
|
|
(unsigned)result); \
|
2014-01-25 19:58:47 +04:00
|
|
|
fails++; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
TEST1(host_strchr, "[1:2:3]:4:5", ':', -str, 7);
|
|
|
|
TEST1(host_strrchr, "[1:2:3]:4:5", ':', -str, 9);
|
|
|
|
TEST1(host_strcspn, "[1:2:3]:4:5", "/:",, 7);
|
|
|
|
TEST1(host_strchr, "[1:2:3]", ':', == NULL, 1);
|
|
|
|
TEST1(host_strrchr, "[1:2:3]", ':', == NULL, 1);
|
|
|
|
TEST1(host_strcspn, "[1:2:3]", "/:",, 7);
|
|
|
|
TEST1(host_strcspn, "[1:2/3]", "/:",, 4);
|
|
|
|
TEST1(host_strcspn, "[1:2:3]/", "/:",, 7);
|
|
|
|
|
|
|
|
printf("passed %d failed %d total %d\n", passes, fails, passes+fails);
|
|
|
|
return fails != 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
/* Stubs to stop the rest of this module causing compile failures. */
|
2015-05-15 13:15:42 +03:00
|
|
|
void modalfatalbox(const char *fmt, ...) {}
|
2014-01-25 19:58:47 +04:00
|
|
|
int conf_get_int(Conf *conf, int primary) { return 0; }
|
|
|
|
char *conf_get_str(Conf *conf, int primary) { return NULL; }
|
|
|
|
#endif /* TEST_HOST_STRFOO */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Trim square brackets off the outside of an IPv6 address literal.
|
|
|
|
* Leave all other strings unchanged. Returns a fresh dynamically
|
|
|
|
* allocated string.
|
|
|
|
*/
|
|
|
|
char *host_strduptrim(const char *s)
|
|
|
|
{
|
|
|
|
if (s[0] == '[') {
|
|
|
|
const char *p = s+1;
|
|
|
|
int colons = 0;
|
|
|
|
while (*p && *p != ']') {
|
|
|
|
if (isxdigit((unsigned char)*p))
|
|
|
|
/* OK */;
|
|
|
|
else if (*p == ':')
|
|
|
|
colons++;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (*p == ']' && !p[1] && colons > 1) {
|
|
|
|
/*
|
|
|
|
* This looks like an IPv6 address literal (hex digits and
|
|
|
|
* at least two colons, contained in square brackets).
|
|
|
|
* Trim off the brackets.
|
|
|
|
*/
|
|
|
|
return dupprintf("%.*s", (int)(p - (s+1)), s+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Any other shape of string is simply duplicated.
|
|
|
|
*/
|
|
|
|
return dupstr(s);
|
|
|
|
}
|
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 21:58:42 +03:00
|
|
|
void seat_connection_fatal(Seat *seat, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
char *msg;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
msg = dupvprintf(fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
seat->vt->connection_fatal(seat, msg);
|
|
|
|
sfree(msg); /* if we return */
|
|
|
|
}
|
|
|
|
|
|
|
|
prompts_t *new_prompts(void)
|
2005-10-30 23:24:09 +03:00
|
|
|
{
|
|
|
|
prompts_t *p = snew(prompts_t);
|
|
|
|
p->prompts = NULL;
|
|
|
|
p->n_prompts = 0;
|
|
|
|
p->data = NULL;
|
|
|
|
p->to_server = TRUE; /* to be on the safe side */
|
|
|
|
p->name = p->instruction = NULL;
|
|
|
|
p->name_reqd = p->instr_reqd = FALSE;
|
|
|
|
return p;
|
|
|
|
}
|
2011-10-02 15:50:45 +04:00
|
|
|
void add_prompt(prompts_t *p, char *promptstr, int echo)
|
2005-10-30 23:24:09 +03:00
|
|
|
{
|
|
|
|
prompt_t *pr = snew(prompt_t);
|
|
|
|
pr->prompt = promptstr;
|
|
|
|
pr->echo = echo;
|
2011-10-02 15:50:45 +04:00
|
|
|
pr->result = NULL;
|
|
|
|
pr->resultsize = 0;
|
2005-10-30 23:24:09 +03:00
|
|
|
p->n_prompts++;
|
|
|
|
p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *);
|
|
|
|
p->prompts[p->n_prompts-1] = pr;
|
|
|
|
}
|
2011-10-02 15:50:45 +04:00
|
|
|
void prompt_ensure_result_size(prompt_t *pr, int newlen)
|
|
|
|
{
|
|
|
|
if ((int)pr->resultsize < newlen) {
|
|
|
|
char *newbuf;
|
|
|
|
newlen = newlen * 5 / 4 + 512; /* avoid too many small allocs */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't use sresize / realloc here, because we will be
|
|
|
|
* storing sensitive stuff like passwords in here, and we want
|
|
|
|
* to make sure that the data doesn't get copied around in
|
|
|
|
* memory without the old copy being destroyed.
|
|
|
|
*/
|
|
|
|
newbuf = snewn(newlen, char);
|
|
|
|
memcpy(newbuf, pr->result, pr->resultsize);
|
2012-07-22 23:51:50 +04:00
|
|
|
smemclr(pr->result, pr->resultsize);
|
2011-10-02 15:50:45 +04:00
|
|
|
sfree(pr->result);
|
|
|
|
pr->result = newbuf;
|
|
|
|
pr->resultsize = newlen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void prompt_set_result(prompt_t *pr, const char *newstr)
|
|
|
|
{
|
|
|
|
prompt_ensure_result_size(pr, strlen(newstr) + 1);
|
|
|
|
strcpy(pr->result, newstr);
|
|
|
|
}
|
2005-10-30 23:24:09 +03:00
|
|
|
void free_prompts(prompts_t *p)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
for (i=0; i < p->n_prompts; i++) {
|
|
|
|
prompt_t *pr = p->prompts[i];
|
2012-07-22 23:51:50 +04:00
|
|
|
smemclr(pr->result, pr->resultsize); /* burn the evidence */
|
2005-10-30 23:24:09 +03:00
|
|
|
sfree(pr->result);
|
|
|
|
sfree(pr->prompt);
|
|
|
|
sfree(pr);
|
|
|
|
}
|
|
|
|
sfree(p->prompts);
|
|
|
|
sfree(p->name);
|
|
|
|
sfree(p->instruction);
|
|
|
|
sfree(p);
|
|
|
|
}
|
|
|
|
|
2001-08-26 19:31:29 +04:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* String handling routines.
|
|
|
|
*/
|
|
|
|
|
2002-11-07 22:49:03 +03:00
|
|
|
char *dupstr(const char *s)
|
2001-08-26 19:31:29 +04:00
|
|
|
{
|
2003-08-30 02:14:04 +04:00
|
|
|
char *p = NULL;
|
|
|
|
if (s) {
|
|
|
|
int len = strlen(s);
|
|
|
|
p = snewn(len + 1, char);
|
|
|
|
strcpy(p, s);
|
|
|
|
}
|
2001-08-26 19:31:29 +04:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate the concatenation of N strings. Terminate arg list with NULL. */
|
2002-11-07 22:49:03 +03:00
|
|
|
char *dupcat(const char *s1, ...)
|
2001-08-26 19:31:29 +04:00
|
|
|
{
|
|
|
|
int len;
|
|
|
|
char *p, *q, *sn;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
len = strlen(s1);
|
|
|
|
va_start(ap, s1);
|
|
|
|
while (1) {
|
|
|
|
sn = va_arg(ap, char *);
|
|
|
|
if (!sn)
|
|
|
|
break;
|
|
|
|
len += strlen(sn);
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
|
2003-03-29 19:14:26 +03:00
|
|
|
p = snewn(len + 1, char);
|
2001-08-26 19:31:29 +04:00
|
|
|
strcpy(p, s1);
|
|
|
|
q = p + strlen(p);
|
|
|
|
|
|
|
|
va_start(ap, s1);
|
|
|
|
while (1) {
|
|
|
|
sn = va_arg(ap, char *);
|
|
|
|
if (!sn)
|
|
|
|
break;
|
|
|
|
strcpy(q, sn);
|
|
|
|
q += strlen(q);
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2011-10-02 18:03:47 +04:00
|
|
|
void burnstr(char *string) /* sfree(str), only clear it first */
|
|
|
|
{
|
|
|
|
if (string) {
|
2012-07-22 23:51:50 +04:00
|
|
|
smemclr(string, strlen(string));
|
2011-10-02 18:03:47 +04:00
|
|
|
sfree(string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-14 14:45:54 +04:00
|
|
|
int toint(unsigned u)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Convert an unsigned to an int, without running into the
|
|
|
|
* undefined behaviour which happens by the strict C standard if
|
|
|
|
* the value overflows. You'd hope that sensible compilers would
|
|
|
|
* do the sensible thing in response to a cast, but actually I
|
|
|
|
* don't trust modern compilers not to do silly things like
|
|
|
|
* assuming that _obviously_ you wouldn't have caused an overflow
|
|
|
|
* and so they can elide an 'if (i < 0)' test immediately after
|
|
|
|
* the cast.
|
|
|
|
*
|
|
|
|
* Sensible compilers ought of course to optimise this entire
|
|
|
|
* function into 'just return the input value'!
|
|
|
|
*/
|
|
|
|
if (u <= (unsigned)INT_MAX)
|
|
|
|
return (int)u;
|
|
|
|
else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */
|
|
|
|
return INT_MIN + (int)(u - (unsigned)INT_MIN);
|
|
|
|
else
|
|
|
|
return INT_MIN; /* fallback; should never occur on binary machines */
|
|
|
|
}
|
|
|
|
|
2018-05-27 18:56:51 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2002-11-07 22:49:03 +03:00
|
|
|
/*
|
|
|
|
* Do an sprintf(), but into a custom-allocated buffer.
|
|
|
|
*
|
2004-08-16 18:43:29 +04:00
|
|
|
* Currently I'm doing this via vsnprintf. This has worked so far,
|
2006-12-29 19:38:52 +03:00
|
|
|
* but it's not good, because vsnprintf is not available on all
|
|
|
|
* platforms. There's an ifdef to use `_vsnprintf', which seems
|
|
|
|
* to be the local name for it on Windows. Other platforms may
|
|
|
|
* lack it completely, in which case it'll be time to rewrite
|
|
|
|
* this function in a totally different way.
|
2004-08-16 18:43:29 +04:00
|
|
|
*
|
|
|
|
* The only `properly' portable solution I can think of is to
|
|
|
|
* implement my own format string scanner, which figures out an
|
|
|
|
* upper bound for the length of each formatting directive,
|
|
|
|
* allocates the buffer as it goes along, and calls sprintf() to
|
|
|
|
* actually process each directive. If I ever need to actually do
|
|
|
|
* this, some caveats:
|
|
|
|
*
|
|
|
|
* - It's very hard to find a reliable upper bound for
|
|
|
|
* floating-point values. %f, in particular, when supplied with
|
|
|
|
* a number near to the upper or lower limit of representable
|
|
|
|
* numbers, could easily take several hundred characters. It's
|
|
|
|
* probably feasible to predict this statically using the
|
|
|
|
* constants in <float.h>, or even to predict it dynamically by
|
|
|
|
* looking at the exponent of the specific float provided, but
|
|
|
|
* it won't be fun.
|
|
|
|
*
|
|
|
|
* - Don't forget to _check_, after calling sprintf, that it's
|
|
|
|
* used at most the amount of space we had available.
|
|
|
|
*
|
|
|
|
* - Fault any formatting directive we don't fully understand. The
|
|
|
|
* aim here is to _guarantee_ that we never overflow the buffer,
|
|
|
|
* because this is a security-critical function. If we see a
|
|
|
|
* directive we don't know about, we should panic and die rather
|
|
|
|
* than run any risk.
|
2002-11-07 22:49:03 +03:00
|
|
|
*/
|
2017-02-20 23:30:14 +03:00
|
|
|
static char *dupvprintf_inner(char *buf, int oldlen, int *oldsize,
|
2017-01-21 17:55:53 +03:00
|
|
|
const char *fmt, va_list ap)
|
2002-11-07 22:49:03 +03:00
|
|
|
{
|
2017-02-20 23:30:14 +03:00
|
|
|
int len, size, newsize;
|
2002-11-07 22:49:03 +03:00
|
|
|
|
2017-02-20 23:30:14 +03:00
|
|
|
assert(*oldsize >= oldlen);
|
|
|
|
size = *oldsize - oldlen;
|
2017-01-21 17:55:53 +03:00
|
|
|
if (size == 0) {
|
|
|
|
size = 512;
|
2017-02-20 23:30:14 +03:00
|
|
|
newsize = oldlen + size;
|
|
|
|
buf = sresize(buf, newsize, char);
|
|
|
|
} else {
|
|
|
|
newsize = *oldsize;
|
2017-01-21 17:55:53 +03:00
|
|
|
}
|
2002-11-07 22:49:03 +03:00
|
|
|
|
|
|
|
while (1) {
|
2017-02-15 02:19:13 +03:00
|
|
|
#if defined _WINDOWS && !defined __WINE__ && _MSC_VER < 1900 /* 1900 == VS2015 has real snprintf */
|
2002-11-07 22:49:03 +03:00
|
|
|
#define vsnprintf _vsnprintf
|
|
|
|
#endif
|
2006-12-29 19:38:52 +03:00
|
|
|
#ifdef va_copy
|
|
|
|
/* Use the `va_copy' macro mandated by C99, if present.
|
|
|
|
* XXX some environments may have this as __va_copy() */
|
|
|
|
va_list aq;
|
|
|
|
va_copy(aq, ap);
|
2017-01-21 17:55:53 +03:00
|
|
|
len = vsnprintf(buf + oldlen, size, fmt, aq);
|
2006-12-29 19:38:52 +03:00
|
|
|
va_end(aq);
|
|
|
|
#else
|
|
|
|
/* Ugh. No va_copy macro, so do something nasty.
|
|
|
|
* Technically, you can't reuse a va_list like this: it is left
|
|
|
|
* unspecified whether advancing a va_list pointer modifies its
|
|
|
|
* value or something it points to, so on some platforms calling
|
|
|
|
* vsnprintf twice on the same va_list might fail hideously
|
|
|
|
* (indeed, it has been observed to).
|
|
|
|
* XXX the autoconf manual suggests that using memcpy() will give
|
|
|
|
* "maximum portability". */
|
2017-01-21 17:55:53 +03:00
|
|
|
len = vsnprintf(buf + oldlen, size, fmt, ap);
|
2006-12-29 19:38:52 +03:00
|
|
|
#endif
|
2002-11-07 22:49:03 +03:00
|
|
|
if (len >= 0 && len < size) {
|
|
|
|
/* This is the C99-specified criterion for snprintf to have
|
|
|
|
* been completely successful. */
|
2017-02-20 23:30:14 +03:00
|
|
|
*oldsize = newsize;
|
2002-11-07 22:49:03 +03:00
|
|
|
return buf;
|
|
|
|
} else if (len > 0) {
|
|
|
|
/* This is the C99 error condition: the returned length is
|
|
|
|
* the required buffer size not counting the NUL. */
|
|
|
|
size = len + 1;
|
|
|
|
} else {
|
|
|
|
/* This is the pre-C99 glibc error condition: <0 means the
|
|
|
|
* buffer wasn't big enough, so we enlarge it a bit and hope. */
|
|
|
|
size += 512;
|
|
|
|
}
|
2017-02-20 23:30:14 +03:00
|
|
|
newsize = oldlen + size;
|
|
|
|
buf = sresize(buf, newsize, char);
|
2002-11-07 22:49:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-21 17:55:53 +03:00
|
|
|
char *dupvprintf(const char *fmt, va_list ap)
|
|
|
|
{
|
2017-02-20 23:30:14 +03:00
|
|
|
int size = 0;
|
|
|
|
return dupvprintf_inner(NULL, 0, &size, fmt, ap);
|
2017-01-21 17:55:53 +03:00
|
|
|
}
|
|
|
|
char *dupprintf(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
ret = dupvprintf(fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-05-24 16:55:10 +03:00
|
|
|
struct strbuf_impl {
|
|
|
|
int size;
|
|
|
|
struct strbuf visible;
|
2017-01-21 17:55:53 +03:00
|
|
|
};
|
2018-05-24 16:55:10 +03:00
|
|
|
|
|
|
|
#define STRBUF_SET_PTR(buf, ptr) \
|
|
|
|
((buf)->visible.s = (ptr), \
|
|
|
|
(buf)->visible.u = (unsigned char *)(buf)->visible.s)
|
|
|
|
|
2018-06-08 21:07:47 +03:00
|
|
|
void *strbuf_append(strbuf *buf_o, size_t len)
|
2018-05-24 16:55:10 +03:00
|
|
|
{
|
2018-10-06 01:49:08 +03:00
|
|
|
struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible);
|
2018-05-24 16:55:10 +03:00
|
|
|
char *toret;
|
|
|
|
if (buf->size < buf->visible.len + len + 1) {
|
|
|
|
buf->size = (buf->visible.len + len + 1) * 5 / 4 + 512;
|
|
|
|
STRBUF_SET_PTR(buf, sresize(buf->visible.s, buf->size, char));
|
|
|
|
}
|
|
|
|
toret = buf->visible.s + buf->visible.len;
|
|
|
|
buf->visible.len += len;
|
|
|
|
buf->visible.s[buf->visible.len] = '\0';
|
|
|
|
return toret;
|
|
|
|
}
|
|
|
|
|
2018-05-24 11:17:13 +03:00
|
|
|
static void strbuf_BinarySink_write(
|
|
|
|
BinarySink *bs, const void *data, size_t len)
|
|
|
|
{
|
|
|
|
strbuf *buf_o = BinarySink_DOWNCAST(bs, strbuf);
|
|
|
|
memcpy(strbuf_append(buf_o, len), data, len);
|
|
|
|
}
|
|
|
|
|
2017-01-21 17:55:53 +03:00
|
|
|
strbuf *strbuf_new(void)
|
|
|
|
{
|
2018-05-24 16:55:10 +03:00
|
|
|
struct strbuf_impl *buf = snew(struct strbuf_impl);
|
2018-05-24 11:17:13 +03:00
|
|
|
BinarySink_INIT(&buf->visible, strbuf_BinarySink_write);
|
2018-05-24 16:55:10 +03:00
|
|
|
buf->visible.len = 0;
|
2017-01-21 17:55:53 +03:00
|
|
|
buf->size = 512;
|
2018-05-24 16:55:10 +03:00
|
|
|
STRBUF_SET_PTR(buf, snewn(buf->size, char));
|
|
|
|
*buf->visible.s = '\0';
|
|
|
|
return &buf->visible;
|
2017-01-21 17:55:53 +03:00
|
|
|
}
|
2018-05-24 16:55:10 +03:00
|
|
|
void strbuf_free(strbuf *buf_o)
|
2017-01-21 17:55:53 +03:00
|
|
|
{
|
2018-10-06 01:49:08 +03:00
|
|
|
struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible);
|
2018-05-24 16:55:10 +03:00
|
|
|
if (buf->visible.s) {
|
|
|
|
smemclr(buf->visible.s, buf->size);
|
|
|
|
sfree(buf->visible.s);
|
|
|
|
}
|
2017-01-21 17:55:53 +03:00
|
|
|
sfree(buf);
|
|
|
|
}
|
2018-05-24 16:55:10 +03:00
|
|
|
char *strbuf_to_str(strbuf *buf_o)
|
2017-01-21 17:55:53 +03:00
|
|
|
{
|
2018-10-06 01:49:08 +03:00
|
|
|
struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible);
|
2018-05-24 16:55:10 +03:00
|
|
|
char *ret = buf->visible.s;
|
2017-01-21 17:55:53 +03:00
|
|
|
sfree(buf);
|
|
|
|
return ret;
|
|
|
|
}
|
2018-05-24 16:55:10 +03:00
|
|
|
void strbuf_catfv(strbuf *buf_o, const char *fmt, va_list ap)
|
2017-01-21 17:55:53 +03:00
|
|
|
{
|
2018-10-06 01:49:08 +03:00
|
|
|
struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible);
|
2018-05-24 16:55:10 +03:00
|
|
|
STRBUF_SET_PTR(buf, dupvprintf_inner(buf->visible.s, buf->visible.len,
|
|
|
|
&buf->size, fmt, ap));
|
|
|
|
buf->visible.len += strlen(buf->visible.s + buf->visible.len);
|
2017-01-21 17:55:53 +03:00
|
|
|
}
|
2018-05-24 16:55:10 +03:00
|
|
|
void strbuf_catf(strbuf *buf_o, const char *fmt, ...)
|
2017-01-21 17:55:53 +03:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2018-05-24 16:55:10 +03:00
|
|
|
strbuf_catfv(buf_o, fmt, ap);
|
2017-01-21 17:55:53 +03:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2018-05-24 15:18:13 +03:00
|
|
|
strbuf *strbuf_new_for_agent_query(void)
|
|
|
|
{
|
|
|
|
strbuf *buf = strbuf_new();
|
|
|
|
put_uint32(buf, 0); /* reserve space for length field */
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
void strbuf_finalise_agent_query(strbuf *buf_o)
|
|
|
|
{
|
2018-10-06 01:49:08 +03:00
|
|
|
struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible);
|
2018-05-24 15:18:13 +03:00
|
|
|
assert(buf->visible.len >= 5);
|
|
|
|
PUT_32BIT_MSB_FIRST(buf->visible.u, buf->visible.len - 4);
|
|
|
|
}
|
|
|
|
|
2004-11-27 16:20:21 +03:00
|
|
|
/*
|
|
|
|
* Read an entire line of text from a file. Return a buffer
|
|
|
|
* malloced to be as big as necessary (caller must free).
|
|
|
|
*/
|
|
|
|
char *fgetline(FILE *fp)
|
|
|
|
{
|
|
|
|
char *ret = snewn(512, char);
|
|
|
|
int size = 512, len = 0;
|
|
|
|
while (fgets(ret + len, size - len, fp)) {
|
|
|
|
len += strlen(ret + len);
|
2015-11-10 21:49:09 +03:00
|
|
|
if (len > 0 && ret[len-1] == '\n')
|
2004-11-27 16:20:21 +03:00
|
|
|
break; /* got a newline, we're done */
|
|
|
|
size = len + 512;
|
|
|
|
ret = sresize(ret, size, char);
|
|
|
|
}
|
|
|
|
if (len == 0) { /* first fgets returned NULL */
|
|
|
|
sfree(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ret[len] = '\0';
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-05-12 12:47:33 +03:00
|
|
|
/*
|
|
|
|
* Perl-style 'chomp', for a line we just read with fgetline. Unlike
|
|
|
|
* Perl chomp, however, we're deliberately forgiving of strange
|
|
|
|
* line-ending conventions. Also we forgive NULL on input, so you can
|
|
|
|
* just write 'line = chomp(fgetline(fp));' and not bother checking
|
|
|
|
* for NULL until afterwards.
|
|
|
|
*/
|
|
|
|
char *chomp(char *str)
|
|
|
|
{
|
|
|
|
if (str) {
|
|
|
|
int len = strlen(str);
|
|
|
|
while (len > 0 && (str[len-1] == '\r' || str[len-1] == '\n'))
|
|
|
|
len--;
|
|
|
|
str[len] = '\0';
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2002-09-21 18:03:05 +04:00
|
|
|
/* ----------------------------------------------------------------------
|
2014-09-09 15:46:10 +04:00
|
|
|
* Core base64 encoding and decoding routines.
|
2002-09-21 18:03:05 +04:00
|
|
|
*/
|
|
|
|
|
2015-05-12 16:00:04 +03:00
|
|
|
void base64_encode_atom(const unsigned char *data, int n, char *out)
|
2002-09-21 18:03:05 +04:00
|
|
|
{
|
|
|
|
static const char base64_chars[] =
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
|
|
|
|
unsigned word;
|
|
|
|
|
|
|
|
word = data[0] << 16;
|
|
|
|
if (n > 1)
|
|
|
|
word |= data[1] << 8;
|
|
|
|
if (n > 2)
|
|
|
|
word |= data[2];
|
|
|
|
out[0] = base64_chars[(word >> 18) & 0x3F];
|
|
|
|
out[1] = base64_chars[(word >> 12) & 0x3F];
|
|
|
|
if (n > 1)
|
|
|
|
out[2] = base64_chars[(word >> 6) & 0x3F];
|
|
|
|
else
|
|
|
|
out[2] = '=';
|
|
|
|
if (n > 2)
|
|
|
|
out[3] = base64_chars[word & 0x3F];
|
|
|
|
else
|
|
|
|
out[3] = '=';
|
|
|
|
}
|
|
|
|
|
2015-05-12 16:00:04 +03:00
|
|
|
int base64_decode_atom(const char *atom, unsigned char *out)
|
2014-09-09 15:46:10 +04:00
|
|
|
{
|
|
|
|
int vals[4];
|
|
|
|
int i, v, len;
|
|
|
|
unsigned word;
|
|
|
|
char c;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
c = atom[i];
|
|
|
|
if (c >= 'A' && c <= 'Z')
|
|
|
|
v = c - 'A';
|
|
|
|
else if (c >= 'a' && c <= 'z')
|
|
|
|
v = c - 'a' + 26;
|
|
|
|
else if (c >= '0' && c <= '9')
|
|
|
|
v = c - '0' + 52;
|
|
|
|
else if (c == '+')
|
|
|
|
v = 62;
|
|
|
|
else if (c == '/')
|
|
|
|
v = 63;
|
|
|
|
else if (c == '=')
|
|
|
|
v = -1;
|
|
|
|
else
|
|
|
|
return 0; /* invalid atom */
|
|
|
|
vals[i] = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vals[0] == -1 || vals[1] == -1)
|
|
|
|
return 0;
|
|
|
|
if (vals[2] == -1 && vals[3] != -1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (vals[3] != -1)
|
|
|
|
len = 3;
|
|
|
|
else if (vals[2] != -1)
|
|
|
|
len = 2;
|
|
|
|
else
|
|
|
|
len = 1;
|
|
|
|
|
|
|
|
word = ((vals[0] << 18) |
|
|
|
|
(vals[1] << 12) | ((vals[2] & 0x3F) << 6) | (vals[3] & 0x3F));
|
|
|
|
out[0] = (word >> 16) & 0xFF;
|
|
|
|
if (len > 1)
|
|
|
|
out[1] = (word >> 8) & 0xFF;
|
|
|
|
if (len > 2)
|
|
|
|
out[2] = word & 0xFF;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2001-08-26 19:31:29 +04:00
|
|
|
/* ----------------------------------------------------------------------
|
2001-08-25 21:09:23 +04:00
|
|
|
* Generic routines to deal with send buffers: a linked list of
|
|
|
|
* smallish blocks, with the operations
|
|
|
|
*
|
|
|
|
* - add an arbitrary amount of data to the end of the list
|
|
|
|
* - remove the first N bytes from the list
|
|
|
|
* - return a (pointer,length) pair giving some initial data in
|
|
|
|
* the list, suitable for passing to a send or write system
|
|
|
|
* call
|
2002-09-21 20:52:21 +04:00
|
|
|
* - retrieve a larger amount of initial data from the list
|
2001-08-25 21:09:23 +04:00
|
|
|
* - return the current size of the buffer chain in bytes
|
|
|
|
*/
|
|
|
|
|
2012-08-11 13:10:31 +04:00
|
|
|
#define BUFFER_MIN_GRANULE 512
|
2001-08-25 21:09:23 +04:00
|
|
|
|
|
|
|
struct bufchain_granule {
|
|
|
|
struct bufchain_granule *next;
|
2012-08-11 13:10:31 +04:00
|
|
|
char *bufpos, *bufend, *bufmax;
|
2001-08-25 21:09:23 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
void bufchain_init(bufchain *ch)
|
|
|
|
{
|
|
|
|
ch->head = ch->tail = NULL;
|
|
|
|
ch->buffersize = 0;
|
2018-09-22 10:13:41 +03:00
|
|
|
ch->ic = NULL;
|
2001-08-25 21:09:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void bufchain_clear(bufchain *ch)
|
|
|
|
{
|
|
|
|
struct bufchain_granule *b;
|
|
|
|
while (ch->head) {
|
|
|
|
b = ch->head;
|
|
|
|
ch->head = ch->head->next;
|
|
|
|
sfree(b);
|
|
|
|
}
|
|
|
|
ch->tail = NULL;
|
|
|
|
ch->buffersize = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bufchain_size(bufchain *ch)
|
|
|
|
{
|
|
|
|
return ch->buffersize;
|
|
|
|
}
|
|
|
|
|
2003-01-10 21:33:35 +03:00
|
|
|
void bufchain_add(bufchain *ch, const void *data, int len)
|
2001-08-25 21:09:23 +04:00
|
|
|
{
|
2003-01-10 21:33:35 +03:00
|
|
|
const char *buf = (const char *)data;
|
2001-08-25 21:09:23 +04:00
|
|
|
|
2003-10-12 17:16:39 +04:00
|
|
|
if (len == 0) return;
|
|
|
|
|
2001-08-25 21:09:23 +04:00
|
|
|
ch->buffersize += len;
|
|
|
|
|
|
|
|
while (len > 0) {
|
2012-08-11 13:10:31 +04:00
|
|
|
if (ch->tail && ch->tail->bufend < ch->tail->bufmax) {
|
|
|
|
int copylen = min(len, ch->tail->bufmax - ch->tail->bufend);
|
|
|
|
memcpy(ch->tail->bufend, buf, copylen);
|
|
|
|
buf += copylen;
|
|
|
|
len -= copylen;
|
|
|
|
ch->tail->bufend += copylen;
|
|
|
|
}
|
|
|
|
if (len > 0) {
|
|
|
|
int grainlen =
|
|
|
|
max(sizeof(struct bufchain_granule) + len, BUFFER_MIN_GRANULE);
|
|
|
|
struct bufchain_granule *newbuf;
|
|
|
|
newbuf = smalloc(grainlen);
|
|
|
|
newbuf->bufpos = newbuf->bufend =
|
|
|
|
(char *)newbuf + sizeof(struct bufchain_granule);
|
|
|
|
newbuf->bufmax = (char *)newbuf + grainlen;
|
|
|
|
newbuf->next = NULL;
|
|
|
|
if (ch->tail)
|
|
|
|
ch->tail->next = newbuf;
|
|
|
|
else
|
|
|
|
ch->head = newbuf;
|
|
|
|
ch->tail = newbuf;
|
|
|
|
}
|
2001-08-25 21:09:23 +04:00
|
|
|
}
|
2018-09-22 10:13:41 +03:00
|
|
|
|
|
|
|
if (ch->ic)
|
|
|
|
queue_idempotent_callback(ch->ic);
|
2001-08-25 21:09:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void bufchain_consume(bufchain *ch, int len)
|
|
|
|
{
|
2002-09-21 20:52:21 +04:00
|
|
|
struct bufchain_granule *tmp;
|
|
|
|
|
2001-08-25 21:09:23 +04:00
|
|
|
assert(ch->buffersize >= len);
|
2002-09-21 20:52:21 +04:00
|
|
|
while (len > 0) {
|
|
|
|
int remlen = len;
|
|
|
|
assert(ch->head != NULL);
|
2012-08-11 13:10:31 +04:00
|
|
|
if (remlen >= ch->head->bufend - ch->head->bufpos) {
|
|
|
|
remlen = ch->head->bufend - ch->head->bufpos;
|
2002-09-21 20:52:21 +04:00
|
|
|
tmp = ch->head;
|
|
|
|
ch->head = tmp->next;
|
|
|
|
if (!ch->head)
|
|
|
|
ch->tail = NULL;
|
2012-08-11 13:10:31 +04:00
|
|
|
sfree(tmp);
|
2002-09-21 20:52:21 +04:00
|
|
|
} else
|
|
|
|
ch->head->bufpos += remlen;
|
|
|
|
ch->buffersize -= remlen;
|
|
|
|
len -= remlen;
|
2001-08-25 21:09:23 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bufchain_prefix(bufchain *ch, void **data, int *len)
|
|
|
|
{
|
2012-08-11 13:10:31 +04:00
|
|
|
*len = ch->head->bufend - ch->head->bufpos;
|
|
|
|
*data = ch->head->bufpos;
|
2001-08-25 21:09:23 +04:00
|
|
|
}
|
|
|
|
|
2002-09-21 20:52:21 +04:00
|
|
|
void bufchain_fetch(bufchain *ch, void *data, int len)
|
|
|
|
{
|
|
|
|
struct bufchain_granule *tmp;
|
|
|
|
char *data_c = (char *)data;
|
|
|
|
|
|
|
|
tmp = ch->head;
|
|
|
|
|
|
|
|
assert(ch->buffersize >= len);
|
|
|
|
while (len > 0) {
|
|
|
|
int remlen = len;
|
|
|
|
|
|
|
|
assert(tmp != NULL);
|
2012-08-11 13:10:31 +04:00
|
|
|
if (remlen >= tmp->bufend - tmp->bufpos)
|
|
|
|
remlen = tmp->bufend - tmp->bufpos;
|
|
|
|
memcpy(data_c, tmp->bufpos, remlen);
|
2002-09-21 20:52:21 +04:00
|
|
|
|
|
|
|
tmp = tmp->next;
|
|
|
|
len -= remlen;
|
|
|
|
data_c += remlen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-18 09:22:57 +03:00
|
|
|
void bufchain_fetch_consume(bufchain *ch, void *data, int len)
|
|
|
|
{
|
|
|
|
bufchain_fetch(ch, data, len);
|
|
|
|
bufchain_consume(ch, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int bufchain_try_fetch_consume(bufchain *ch, void *data, int len)
|
|
|
|
{
|
|
|
|
if (ch->buffersize >= len) {
|
|
|
|
bufchain_fetch_consume(ch, data, len);
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-19 20:22:36 +03:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Sanitise terminal output that we have reason not to trust, e.g.
|
|
|
|
* because it appears in the login banner or password prompt from a
|
|
|
|
* server, which we'd rather not permit to use arbitrary escape
|
|
|
|
* sequences.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void sanitise_term_data(bufchain *out, const void *vdata, int len)
|
|
|
|
{
|
|
|
|
const char *data = (const char *)vdata;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: this method of sanitisation is ASCII-centric. It would
|
|
|
|
* be nice to permit SSH banners and the like to contain printable
|
|
|
|
* Unicode, but that would need a lot more complicated code here
|
|
|
|
* (not to mention knowing what character set it should interpret
|
|
|
|
* the data as).
|
|
|
|
*/
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
if (data[i] == '\n')
|
|
|
|
bufchain_add(out, "\r\n", 2);
|
|
|
|
else if (data[i] >= ' ' && data[i] < 0x7F)
|
|
|
|
bufchain_add(out, data + i, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-08-26 19:31:29 +04:00
|
|
|
/* ----------------------------------------------------------------------
|
2000-12-12 13:57:34 +03:00
|
|
|
* My own versions of malloc, realloc and free. Because I want
|
|
|
|
* malloc and realloc to bomb out and exit the program if they run
|
|
|
|
* out of memory, realloc to reliably call malloc if passed a NULL
|
|
|
|
* pointer, and free to reliably do nothing if passed a NULL
|
|
|
|
* pointer. We can also put trace printouts in, if we need to; and
|
|
|
|
* we can also replace the allocator with an ElectricFence-like
|
|
|
|
* one.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef MINEFIELD
|
2003-03-06 16:24:02 +03:00
|
|
|
void *minefield_c_malloc(size_t size);
|
|
|
|
void minefield_c_free(void *p);
|
|
|
|
void *minefield_c_realloc(void *p, size_t size);
|
|
|
|
#endif
|
1999-01-08 16:02:13 +03:00
|
|
|
|
|
|
|
#ifdef MALLOC_LOG
|
|
|
|
static FILE *fp = NULL;
|
|
|
|
|
2001-12-15 17:09:51 +03:00
|
|
|
static char *mlog_file = NULL;
|
|
|
|
static int mlog_line = 0;
|
|
|
|
|
2001-05-06 18:35:20 +04:00
|
|
|
void mlog(char *file, int line)
|
|
|
|
{
|
2001-12-15 17:09:51 +03:00
|
|
|
mlog_file = file;
|
|
|
|
mlog_line = line;
|
1999-01-15 14:27:36 +03:00
|
|
|
if (!fp) {
|
1999-01-08 16:02:13 +03:00
|
|
|
fp = fopen("putty_mem.log", "w");
|
1999-01-15 14:27:36 +03:00
|
|
|
setvbuf(fp, NULL, _IONBF, BUFSIZ);
|
|
|
|
}
|
1999-01-08 16:02:13 +03:00
|
|
|
if (fp)
|
2001-05-06 18:35:20 +04:00
|
|
|
fprintf(fp, "%s:%d: ", file, line);
|
1999-01-08 16:02:13 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-02-20 13:30:05 +03:00
|
|
|
void *safemalloc(size_t n, size_t size)
|
2001-05-06 18:35:20 +04:00
|
|
|
{
|
2000-12-12 13:57:34 +03:00
|
|
|
void *p;
|
2005-02-20 13:30:05 +03:00
|
|
|
|
|
|
|
if (n > INT_MAX / size) {
|
|
|
|
p = NULL;
|
|
|
|
} else {
|
|
|
|
size *= n;
|
2005-09-14 00:17:10 +04:00
|
|
|
if (size == 0) size = 1;
|
2000-12-12 13:57:34 +03:00
|
|
|
#ifdef MINEFIELD
|
2005-02-20 13:30:05 +03:00
|
|
|
p = minefield_c_malloc(size);
|
2000-12-12 13:57:34 +03:00
|
|
|
#else
|
2005-02-20 13:30:05 +03:00
|
|
|
p = malloc(size);
|
2000-12-12 13:57:34 +03:00
|
|
|
#endif
|
2005-02-20 13:30:05 +03:00
|
|
|
}
|
|
|
|
|
1999-01-08 16:02:13 +03:00
|
|
|
if (!p) {
|
2001-12-15 17:09:51 +03:00
|
|
|
char str[200];
|
|
|
|
#ifdef MALLOC_LOG
|
|
|
|
sprintf(str, "Out of memory! (%s:%d, size=%d)",
|
|
|
|
mlog_file, mlog_line, size);
|
2002-02-28 01:20:03 +03:00
|
|
|
fprintf(fp, "*** %s\n", str);
|
|
|
|
fclose(fp);
|
2001-12-15 17:09:51 +03:00
|
|
|
#else
|
|
|
|
strcpy(str, "Out of memory!");
|
|
|
|
#endif
|
2015-05-01 16:55:37 +03:00
|
|
|
modalfatalbox("%s", str);
|
1999-01-08 16:02:13 +03:00
|
|
|
}
|
|
|
|
#ifdef MALLOC_LOG
|
|
|
|
if (fp)
|
|
|
|
fprintf(fp, "malloc(%d) returns %p\n", size, p);
|
|
|
|
#endif
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2005-02-20 13:30:05 +03:00
|
|
|
void *saferealloc(void *ptr, size_t n, size_t size)
|
2001-05-06 18:35:20 +04:00
|
|
|
{
|
1999-01-08 16:02:13 +03:00
|
|
|
void *p;
|
2005-02-20 13:30:05 +03:00
|
|
|
|
|
|
|
if (n > INT_MAX / size) {
|
|
|
|
p = NULL;
|
|
|
|
} else {
|
|
|
|
size *= n;
|
|
|
|
if (!ptr) {
|
2000-12-12 13:57:34 +03:00
|
|
|
#ifdef MINEFIELD
|
2005-02-20 13:30:05 +03:00
|
|
|
p = minefield_c_malloc(size);
|
2000-12-12 13:57:34 +03:00
|
|
|
#else
|
2005-02-20 13:30:05 +03:00
|
|
|
p = malloc(size);
|
2000-12-12 13:57:34 +03:00
|
|
|
#endif
|
2005-02-20 13:30:05 +03:00
|
|
|
} else {
|
2000-12-12 13:57:34 +03:00
|
|
|
#ifdef MINEFIELD
|
2005-02-20 13:30:05 +03:00
|
|
|
p = minefield_c_realloc(ptr, size);
|
2000-12-12 13:57:34 +03:00
|
|
|
#else
|
2005-02-20 13:30:05 +03:00
|
|
|
p = realloc(ptr, size);
|
2000-12-12 13:57:34 +03:00
|
|
|
#endif
|
2005-02-20 13:30:05 +03:00
|
|
|
}
|
2000-12-12 13:57:34 +03:00
|
|
|
}
|
2005-02-20 13:30:05 +03:00
|
|
|
|
1999-01-08 16:02:13 +03:00
|
|
|
if (!p) {
|
2001-12-15 17:09:51 +03:00
|
|
|
char str[200];
|
|
|
|
#ifdef MALLOC_LOG
|
|
|
|
sprintf(str, "Out of memory! (%s:%d, size=%d)",
|
|
|
|
mlog_file, mlog_line, size);
|
2002-02-28 01:20:03 +03:00
|
|
|
fprintf(fp, "*** %s\n", str);
|
|
|
|
fclose(fp);
|
2001-12-15 17:09:51 +03:00
|
|
|
#else
|
|
|
|
strcpy(str, "Out of memory!");
|
|
|
|
#endif
|
2015-05-01 16:55:37 +03:00
|
|
|
modalfatalbox("%s", str);
|
1999-01-08 16:02:13 +03:00
|
|
|
}
|
|
|
|
#ifdef MALLOC_LOG
|
|
|
|
if (fp)
|
|
|
|
fprintf(fp, "realloc(%p,%d) returns %p\n", ptr, size, p);
|
|
|
|
#endif
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2001-05-06 18:35:20 +04:00
|
|
|
void safefree(void *ptr)
|
|
|
|
{
|
1999-01-08 16:02:13 +03:00
|
|
|
if (ptr) {
|
|
|
|
#ifdef MALLOC_LOG
|
|
|
|
if (fp)
|
|
|
|
fprintf(fp, "free(%p)\n", ptr);
|
|
|
|
#endif
|
2000-12-12 13:57:34 +03:00
|
|
|
#ifdef MINEFIELD
|
2001-05-06 18:35:20 +04:00
|
|
|
minefield_c_free(ptr);
|
2000-12-12 13:57:34 +03:00
|
|
|
#else
|
2001-05-06 18:35:20 +04:00
|
|
|
free(ptr);
|
2000-12-12 13:57:34 +03:00
|
|
|
#endif
|
1999-01-08 16:02:13 +03:00
|
|
|
}
|
|
|
|
#ifdef MALLOC_LOG
|
|
|
|
else if (fp)
|
|
|
|
fprintf(fp, "freeing null pointer - no action taken\n");
|
|
|
|
#endif
|
|
|
|
}
|
2000-11-01 22:54:46 +03:00
|
|
|
|
2001-08-26 19:31:29 +04:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Debugging routines.
|
|
|
|
*/
|
|
|
|
|
2000-11-01 22:54:46 +03:00
|
|
|
#ifdef DEBUG
|
2015-05-15 13:15:42 +03:00
|
|
|
extern void dputs(const char *); /* defined in per-platform *misc.c */
|
2001-04-28 13:24:19 +04:00
|
|
|
|
2015-05-09 17:02:45 +03:00
|
|
|
void debug_printf(const char *fmt, ...)
|
2001-05-06 18:35:20 +04:00
|
|
|
{
|
2002-11-07 22:49:03 +03:00
|
|
|
char *buf;
|
2001-04-28 13:24:19 +04:00
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
2002-11-07 22:49:03 +03:00
|
|
|
buf = dupvprintf(fmt, ap);
|
2001-05-06 18:35:20 +04:00
|
|
|
dputs(buf);
|
2002-11-07 22:49:03 +03:00
|
|
|
sfree(buf);
|
2000-11-01 22:54:46 +03:00
|
|
|
va_end(ap);
|
|
|
|
}
|
2001-04-28 13:24:19 +04:00
|
|
|
|
|
|
|
|
2015-05-09 17:02:45 +03:00
|
|
|
void debug_memdump(const void *buf, int len, int L)
|
2001-05-06 18:35:20 +04:00
|
|
|
{
|
2001-04-28 13:24:19 +04:00
|
|
|
int i;
|
2015-05-09 17:02:45 +03:00
|
|
|
const unsigned char *p = buf;
|
2001-04-28 21:35:18 +04:00
|
|
|
char foo[17];
|
2001-04-28 13:24:19 +04:00
|
|
|
if (L) {
|
|
|
|
int delta;
|
2003-03-06 16:24:02 +03:00
|
|
|
debug_printf("\t%d (0x%x) bytes:\n", len, len);
|
2015-08-11 15:01:02 +03:00
|
|
|
delta = 15 & (uintptr_t)p;
|
2001-04-28 13:24:19 +04:00
|
|
|
p -= delta;
|
|
|
|
len += delta;
|
|
|
|
}
|
|
|
|
for (; 0 < len; p += 16, len -= 16) {
|
2001-05-06 18:35:20 +04:00
|
|
|
dputs(" ");
|
|
|
|
if (L)
|
2003-03-06 16:24:02 +03:00
|
|
|
debug_printf("%p: ", p);
|
2001-05-06 18:35:20 +04:00
|
|
|
strcpy(foo, "................"); /* sixteen dots */
|
2001-04-28 13:24:19 +04:00
|
|
|
for (i = 0; i < 16 && i < len; ++i) {
|
|
|
|
if (&p[i] < (unsigned char *) buf) {
|
2001-05-06 18:35:20 +04:00
|
|
|
dputs(" "); /* 3 spaces */
|
2001-04-28 21:35:18 +04:00
|
|
|
foo[i] = ' ';
|
2001-04-28 13:24:19 +04:00
|
|
|
} else {
|
2003-03-06 16:24:02 +03:00
|
|
|
debug_printf("%c%02.2x",
|
2001-05-06 18:35:20 +04:00
|
|
|
&p[i] != (unsigned char *) buf
|
|
|
|
&& i % 4 ? '.' : ' ', p[i]
|
|
|
|
);
|
2001-04-28 21:35:18 +04:00
|
|
|
if (p[i] >= ' ' && p[i] <= '~')
|
2001-05-06 18:35:20 +04:00
|
|
|
foo[i] = (char) p[i];
|
2001-04-28 13:24:19 +04:00
|
|
|
}
|
|
|
|
}
|
2001-04-28 21:35:18 +04:00
|
|
|
foo[i] = '\0';
|
2003-03-06 16:24:02 +03:00
|
|
|
debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo);
|
2001-04-28 13:24:19 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-06 18:35:20 +04:00
|
|
|
#endif /* def DEBUG */
|
2006-08-28 14:35:12 +04:00
|
|
|
|
|
|
|
/*
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 22:52:21 +04:00
|
|
|
* Determine whether or not a Conf represents a session which can
|
|
|
|
* sensibly be launched right now.
|
2006-08-28 14:35:12 +04:00
|
|
|
*/
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 22:52:21 +04:00
|
|
|
int conf_launchable(Conf *conf)
|
2006-08-28 14:35:12 +04:00
|
|
|
{
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 22:52:21 +04:00
|
|
|
if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
|
|
|
|
return conf_get_str(conf, CONF_serline)[0] != 0;
|
2006-08-28 14:35:12 +04:00
|
|
|
else
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 22:52:21 +04:00
|
|
|
return conf_get_str(conf, CONF_host)[0] != 0;
|
2006-08-28 14:35:12 +04:00
|
|
|
}
|
|
|
|
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 22:52:21 +04:00
|
|
|
char const *conf_dest(Conf *conf)
|
2006-08-28 14:35:12 +04:00
|
|
|
{
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 22:52:21 +04:00
|
|
|
if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
|
|
|
|
return conf_get_str(conf, CONF_serline);
|
2006-08-28 14:35:12 +04:00
|
|
|
else
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 22:52:21 +04:00
|
|
|
return conf_get_str(conf, CONF_host);
|
2006-08-28 14:35:12 +04:00
|
|
|
}
|
2012-07-22 23:51:50 +04:00
|
|
|
|
|
|
|
#ifndef PLATFORM_HAS_SMEMCLR
|
|
|
|
/*
|
|
|
|
* Securely wipe memory.
|
|
|
|
*
|
|
|
|
* The actual wiping is no different from what memset would do: the
|
|
|
|
* point of 'securely' is to try to be sure over-clever compilers
|
|
|
|
* won't optimise away memsets on variables that are about to be freed
|
|
|
|
* or go out of scope. See
|
|
|
|
* https://buildsecurityin.us-cert.gov/bsi-rules/home/g1/771-BSI.html
|
|
|
|
*
|
|
|
|
* Some platforms (e.g. Windows) may provide their own version of this
|
|
|
|
* function.
|
|
|
|
*/
|
|
|
|
void smemclr(void *b, size_t n) {
|
|
|
|
volatile char *vp;
|
|
|
|
|
|
|
|
if (b && n > 0) {
|
|
|
|
/*
|
|
|
|
* Zero out the memory.
|
|
|
|
*/
|
|
|
|
memset(b, 0, n);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform a volatile access to the object, forcing the
|
|
|
|
* compiler to admit that the previous memset was important.
|
|
|
|
*
|
|
|
|
* This while loop should in practice run for zero iterations
|
|
|
|
* (since we know we just zeroed the object out), but in
|
|
|
|
* theory (as far as the compiler knows) it might range over
|
|
|
|
* the whole object. (If we had just written, say, '*vp =
|
|
|
|
* *vp;', a compiler could in principle have 'helpfully'
|
|
|
|
* optimised the memset into only zeroing out the first byte.
|
|
|
|
* This should be robust.)
|
|
|
|
*/
|
|
|
|
vp = b;
|
|
|
|
while (*vp) vp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
New option to manually configure the expected host key(s).
This option is available from the command line as '-hostkey', and is
also configurable through the GUI. When enabled, it completely
replaces all of the automated host key management: the server's host
key will be checked against the manually configured list, and the
connection will be allowed or disconnected on that basis, and the host
key store in the registry will not be either consulted or updated.
The main aim is to provide a means of automatically running Plink,
PSCP or PSFTP deep inside Windows services where HKEY_CURRENT_USER
isn't available to have stored the right host key in. But it also
permits you to specify a list of multiple host keys, which means a
second use case for the same mechanism will probably be round-robin
DNS names that select one of several servers with different host keys.
Host keys can be specified as the standard MD5 fingerprint or as an
SSH-2 base64 blob, and are canonicalised on input. (The base64 blob is
more unwieldy, especially with Windows command-line length limits, but
provides a means of specifying the _whole_ public key in case you
don't trust MD5. I haven't bothered to provide an analogous mechanism
for SSH-1, on the basis that anyone worrying about MD5 should have
stopped using SSH-1 already!)
[originally from svn r10220]
2014-09-09 15:46:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate a manual host key specification (either entered in the
|
|
|
|
* GUI, or via -hostkey). If valid, we return TRUE, and update 'key'
|
|
|
|
* to contain a canonicalised version of the key string in 'key'
|
|
|
|
* (which is guaranteed to take up at most as much space as the
|
|
|
|
* original version), suitable for putting into the Conf. If not
|
|
|
|
* valid, we return FALSE.
|
|
|
|
*/
|
|
|
|
int validate_manual_hostkey(char *key)
|
|
|
|
{
|
|
|
|
char *p, *q, *r, *s;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Step through the string word by word, looking for a word that's
|
|
|
|
* in one of the formats we like.
|
|
|
|
*/
|
|
|
|
p = key;
|
|
|
|
while ((p += strspn(p, " \t"))[0]) {
|
|
|
|
q = p;
|
|
|
|
p += strcspn(p, " \t");
|
2014-11-22 13:12:47 +03:00
|
|
|
if (*p) *p++ = '\0';
|
New option to manually configure the expected host key(s).
This option is available from the command line as '-hostkey', and is
also configurable through the GUI. When enabled, it completely
replaces all of the automated host key management: the server's host
key will be checked against the manually configured list, and the
connection will be allowed or disconnected on that basis, and the host
key store in the registry will not be either consulted or updated.
The main aim is to provide a means of automatically running Plink,
PSCP or PSFTP deep inside Windows services where HKEY_CURRENT_USER
isn't available to have stored the right host key in. But it also
permits you to specify a list of multiple host keys, which means a
second use case for the same mechanism will probably be round-robin
DNS names that select one of several servers with different host keys.
Host keys can be specified as the standard MD5 fingerprint or as an
SSH-2 base64 blob, and are canonicalised on input. (The base64 blob is
more unwieldy, especially with Windows command-line length limits, but
provides a means of specifying the _whole_ public key in case you
don't trust MD5. I haven't bothered to provide an analogous mechanism
for SSH-1, on the basis that anyone worrying about MD5 should have
stopped using SSH-1 already!)
[originally from svn r10220]
2014-09-09 15:46:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now q is our word.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (strlen(q) == 16*3 - 1 &&
|
|
|
|
q[strspn(q, "0123456789abcdefABCDEF:")] == 0) {
|
|
|
|
/*
|
|
|
|
* Might be a key fingerprint. Check the colons are in the
|
|
|
|
* right places, and if so, return the same fingerprint
|
|
|
|
* canonicalised into lowercase.
|
|
|
|
*/
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
if (q[3*i] == ':' || q[3*i+1] == ':')
|
|
|
|
goto not_fingerprint; /* sorry */
|
|
|
|
for (i = 0; i < 15; i++)
|
|
|
|
if (q[3*i+2] != ':')
|
|
|
|
goto not_fingerprint; /* sorry */
|
|
|
|
for (i = 0; i < 16*3 - 1; i++)
|
|
|
|
key[i] = tolower(q[i]);
|
|
|
|
key[16*3 - 1] = '\0';
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
not_fingerprint:;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Before we check for a public-key blob, trim newlines out of
|
|
|
|
* the middle of the word, in case someone's managed to paste
|
|
|
|
* in a public-key blob _with_ them.
|
|
|
|
*/
|
|
|
|
for (r = s = q; *r; r++)
|
|
|
|
if (*r != '\n' && *r != '\r')
|
|
|
|
*s++ = *r;
|
|
|
|
*s = '\0';
|
|
|
|
|
|
|
|
if (strlen(q) % 4 == 0 && strlen(q) > 2*4 &&
|
|
|
|
q[strspn(q, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
"abcdefghijklmnopqrstuvwxyz+/=")] == 0) {
|
|
|
|
/*
|
|
|
|
* Might be a base64-encoded SSH-2 public key blob. Check
|
|
|
|
* that it starts with a sensible algorithm string. No
|
|
|
|
* canonicalisation is necessary for this string type.
|
|
|
|
*
|
|
|
|
* The algorithm string must be at most 64 characters long
|
|
|
|
* (RFC 4251 section 6).
|
|
|
|
*/
|
|
|
|
unsigned char decoded[6];
|
|
|
|
unsigned alglen;
|
|
|
|
int minlen;
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
len += base64_decode_atom(q, decoded+len);
|
|
|
|
if (len < 3)
|
|
|
|
goto not_ssh2_blob; /* sorry */
|
|
|
|
len += base64_decode_atom(q+4, decoded+len);
|
|
|
|
if (len < 4)
|
|
|
|
goto not_ssh2_blob; /* sorry */
|
|
|
|
|
|
|
|
alglen = GET_32BIT_MSB_FIRST(decoded);
|
|
|
|
if (alglen > 64)
|
|
|
|
goto not_ssh2_blob; /* sorry */
|
|
|
|
|
|
|
|
minlen = ((alglen + 4) + 2) / 3;
|
|
|
|
if (strlen(q) < minlen)
|
|
|
|
goto not_ssh2_blob; /* sorry */
|
|
|
|
|
|
|
|
strcpy(key, q);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
not_ssh2_blob:;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-04-27 01:31:11 +03:00
|
|
|
|
|
|
|
int smemeq(const void *av, const void *bv, size_t len)
|
|
|
|
{
|
|
|
|
const unsigned char *a = (const unsigned char *)av;
|
|
|
|
const unsigned char *b = (const unsigned char *)bv;
|
|
|
|
unsigned val = 0;
|
|
|
|
|
|
|
|
while (len-- > 0) {
|
|
|
|
val |= *a++ ^ *b++;
|
|
|
|
}
|
|
|
|
/* Now val is 0 iff we want to return 1, and in the range
|
|
|
|
* 0x01..0xFF iff we want to return 0. So subtracting from 0x100
|
|
|
|
* will clear bit 8 iff we want to return 0, and leave it set iff
|
|
|
|
* we want to return 1, so then we can just shift down. */
|
|
|
|
return (0x100 - val) >> 8;
|
|
|
|
}
|
2015-04-27 22:48:29 +03:00
|
|
|
|
2018-09-14 19:04:39 +03:00
|
|
|
int nullstrcmp(const char *a, const char *b)
|
|
|
|
{
|
|
|
|
if (a == NULL && b == NULL)
|
|
|
|
return 0;
|
|
|
|
if (a == NULL)
|
|
|
|
return -1;
|
|
|
|
if (b == NULL)
|
|
|
|
return +1;
|
|
|
|
return strcmp(a, b);
|
|
|
|
}
|
|
|
|
|
2018-05-27 18:56:51 +03:00
|
|
|
ptrlen make_ptrlen(const void *ptr, size_t len)
|
|
|
|
{
|
|
|
|
ptrlen pl;
|
|
|
|
pl.ptr = ptr;
|
|
|
|
pl.len = len;
|
|
|
|
return pl;
|
|
|
|
}
|
|
|
|
|
2018-10-13 18:30:59 +03:00
|
|
|
ptrlen ptrlen_from_asciz(const char *str)
|
|
|
|
{
|
|
|
|
return make_ptrlen(str, strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
ptrlen ptrlen_from_strbuf(strbuf *sb)
|
|
|
|
{
|
|
|
|
return make_ptrlen(sb->u, sb->len);
|
|
|
|
}
|
|
|
|
|
2018-05-27 18:56:51 +03:00
|
|
|
int ptrlen_eq_string(ptrlen pl, const char *str)
|
|
|
|
{
|
|
|
|
size_t len = strlen(str);
|
|
|
|
return (pl.len == len && !memcmp(pl.ptr, str, len));
|
|
|
|
}
|
|
|
|
|
2018-10-13 19:03:27 +03:00
|
|
|
int ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2)
|
|
|
|
{
|
|
|
|
return (pl1.len == pl2.len && !memcmp(pl1.ptr, pl2.ptr, pl1.len));
|
|
|
|
}
|
|
|
|
|
|
|
|
int ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail)
|
|
|
|
{
|
|
|
|
if (whole.len >= prefix.len &&
|
|
|
|
!memcmp(whole.ptr, prefix.ptr, prefix.len)) {
|
|
|
|
if (tail) {
|
|
|
|
tail->ptr = (const char *)whole.ptr + prefix.len;
|
|
|
|
tail->len = whole.len - prefix.len;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-05-27 18:56:51 +03:00
|
|
|
char *mkstr(ptrlen pl)
|
|
|
|
{
|
|
|
|
char *p = snewn(pl.len + 1, char);
|
|
|
|
memcpy(p, pl.ptr, pl.len);
|
|
|
|
p[pl.len] = '\0';
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2015-11-10 21:47:55 +03:00
|
|
|
int strstartswith(const char *s, const char *t)
|
|
|
|
{
|
|
|
|
return !memcmp(s, t, strlen(t));
|
|
|
|
}
|
|
|
|
|
|
|
|
int strendswith(const char *s, const char *t)
|
|
|
|
{
|
|
|
|
size_t slen = strlen(s), tlen = strlen(t);
|
|
|
|
return slen >= tlen && !strcmp(s + (slen - tlen), t);
|
|
|
|
}
|
2017-01-21 17:55:53 +03:00
|
|
|
|
|
|
|
char *buildinfo(const char *newline)
|
|
|
|
{
|
|
|
|
strbuf *buf = strbuf_new();
|
2017-01-21 17:55:53 +03:00
|
|
|
extern const char commitid[]; /* in commitid.c */
|
2017-01-21 17:55:53 +03:00
|
|
|
|
|
|
|
strbuf_catf(buf, "Build platform: %d-bit %s",
|
|
|
|
(int)(CHAR_BIT * sizeof(void *)),
|
|
|
|
BUILDINFO_PLATFORM);
|
|
|
|
|
|
|
|
#ifdef __clang_version__
|
2017-05-31 00:49:25 +03:00
|
|
|
#define FOUND_COMPILER
|
2017-01-21 17:55:53 +03:00
|
|
|
strbuf_catf(buf, "%sCompiler: clang %s", newline, __clang_version__);
|
|
|
|
#elif defined __GNUC__ && defined __VERSION__
|
2017-05-31 00:49:25 +03:00
|
|
|
#define FOUND_COMPILER
|
2017-01-21 17:55:53 +03:00
|
|
|
strbuf_catf(buf, "%sCompiler: gcc %s", newline, __VERSION__);
|
2017-05-31 00:49:25 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined _MSC_VER
|
|
|
|
#ifndef FOUND_COMPILER
|
|
|
|
#define FOUND_COMPILER
|
|
|
|
strbuf_catf(buf, "%sCompiler: ", newline);
|
|
|
|
#else
|
|
|
|
strbuf_catf(buf, ", emulating ");
|
|
|
|
#endif
|
|
|
|
strbuf_catf(buf, "Visual Studio", newline);
|
2017-01-21 17:55:53 +03:00
|
|
|
#if _MSC_VER == 1900
|
|
|
|
strbuf_catf(buf, " 2015 / MSVC++ 14.0");
|
2018-04-25 18:27:10 +03:00
|
|
|
#elif _MSC_VER == 1912
|
|
|
|
strbuf_catf(buf, " 2017 / MSVC++ 14.12");
|
2017-01-21 17:55:53 +03:00
|
|
|
#elif _MSC_VER == 1800
|
|
|
|
strbuf_catf(buf, " 2013 / MSVC++ 12.0");
|
|
|
|
#elif _MSC_VER == 1700
|
|
|
|
strbuf_catf(buf, " 2012 / MSVC++ 11.0");
|
|
|
|
#elif _MSC_VER == 1600
|
|
|
|
strbuf_catf(buf, " 2010 / MSVC++ 10.0");
|
2017-05-31 00:49:25 +03:00
|
|
|
#elif _MSC_VER == 1500
|
2017-01-21 17:55:53 +03:00
|
|
|
strbuf_catf(buf, " 2008 / MSVC++ 9.0");
|
2017-05-31 00:49:25 +03:00
|
|
|
#elif _MSC_VER == 1400
|
2017-01-21 17:55:53 +03:00
|
|
|
strbuf_catf(buf, " 2005 / MSVC++ 8.0");
|
2017-05-31 00:49:25 +03:00
|
|
|
#elif _MSC_VER == 1310
|
2017-01-21 17:55:53 +03:00
|
|
|
strbuf_catf(buf, " 2003 / MSVC++ 7.1");
|
2017-05-31 00:49:25 +03:00
|
|
|
#elif _MSC_VER == 1300
|
|
|
|
strbuf_catf(buf, " 2003 / MSVC++ 7.0");
|
2017-01-21 17:55:53 +03:00
|
|
|
#else
|
|
|
|
strbuf_catf(buf, ", unrecognised version");
|
|
|
|
#endif
|
|
|
|
strbuf_catf(buf, " (_MSC_VER=%d)", (int)_MSC_VER);
|
|
|
|
#endif
|
|
|
|
|
2017-02-15 22:29:05 +03:00
|
|
|
#ifdef BUILDINFO_GTK
|
|
|
|
{
|
|
|
|
char *gtk_buildinfo = buildinfo_gtk_version();
|
|
|
|
if (gtk_buildinfo) {
|
|
|
|
strbuf_catf(buf, "%sCompiled against GTK version %s",
|
|
|
|
newline, gtk_buildinfo);
|
|
|
|
sfree(gtk_buildinfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-07-03 09:27:05 +03:00
|
|
|
#if defined _WINDOWS && defined MINEFIELD
|
|
|
|
strbuf_catf(buf, "%sBuild option: MINEFIELD", newline);
|
|
|
|
#endif
|
2017-01-21 17:55:53 +03:00
|
|
|
#ifdef NO_SECURITY
|
|
|
|
strbuf_catf(buf, "%sBuild option: NO_SECURITY", newline);
|
|
|
|
#endif
|
|
|
|
#ifdef NO_SECUREZEROMEMORY
|
|
|
|
strbuf_catf(buf, "%sBuild option: NO_SECUREZEROMEMORY", newline);
|
|
|
|
#endif
|
|
|
|
#ifdef NO_IPV6
|
|
|
|
strbuf_catf(buf, "%sBuild option: NO_IPV6", newline);
|
|
|
|
#endif
|
|
|
|
#ifdef NO_GSSAPI
|
|
|
|
strbuf_catf(buf, "%sBuild option: NO_GSSAPI", newline);
|
|
|
|
#endif
|
|
|
|
#ifdef STATIC_GSSAPI
|
|
|
|
strbuf_catf(buf, "%sBuild option: STATIC_GSSAPI", newline);
|
|
|
|
#endif
|
|
|
|
#ifdef UNPROTECT
|
|
|
|
strbuf_catf(buf, "%sBuild option: UNPROTECT", newline);
|
|
|
|
#endif
|
|
|
|
#ifdef FUZZING
|
|
|
|
strbuf_catf(buf, "%sBuild option: FUZZING", newline);
|
|
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
|
|
strbuf_catf(buf, "%sBuild option: DEBUG", newline);
|
|
|
|
#endif
|
|
|
|
|
2017-01-21 17:55:53 +03:00
|
|
|
strbuf_catf(buf, "%sSource commit: %s", newline, commitid);
|
|
|
|
|
2017-01-21 17:55:53 +03:00
|
|
|
return strbuf_to_str(buf);
|
|
|
|
}
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 21:58:42 +03:00
|
|
|
|
|
|
|
int nullseat_output(
|
|
|
|
Seat *seat, int is_stderr, const void *data, int len) { return 0; }
|
|
|
|
int nullseat_eof(Seat *seat) { return TRUE; }
|
|
|
|
int nullseat_get_userpass_input(
|
|
|
|
Seat *seat, prompts_t *p, bufchain *input) { return 0; }
|
|
|
|
void nullseat_notify_remote_exit(Seat *seat) {}
|
|
|
|
void nullseat_connection_fatal(Seat *seat, const char *message) {}
|
|
|
|
void nullseat_update_specials_menu(Seat *seat) {}
|
|
|
|
char *nullseat_get_ttymode(Seat *seat, const char *mode) { return NULL; }
|
|
|
|
void nullseat_set_busy_status(Seat *seat, BusyStatus status) {}
|
|
|
|
int nullseat_verify_ssh_host_key(
|
|
|
|
Seat *seat, const char *host, int port,
|
|
|
|
const char *keytype, char *keystr, char *key_fingerprint,
|
|
|
|
void (*callback)(void *ctx, int result), void *ctx) { return 0; }
|
|
|
|
int nullseat_confirm_weak_crypto_primitive(
|
|
|
|
Seat *seat, const char *algtype, const char *algname,
|
|
|
|
void (*callback)(void *ctx, int result), void *ctx) { return 0; }
|
|
|
|
int nullseat_confirm_weak_cached_hostkey(
|
|
|
|
Seat *seat, const char *algname, const char *betteralgs,
|
|
|
|
void (*callback)(void *ctx, int result), void *ctx) { return 0; }
|
|
|
|
int nullseat_is_never_utf8(Seat *seat) { return FALSE; }
|
|
|
|
int nullseat_is_always_utf8(Seat *seat) { return TRUE; }
|
|
|
|
void nullseat_echoedit_update(Seat *seat, int echoing, int editing) {}
|
|
|
|
const char *nullseat_get_x_display(Seat *seat) { return NULL; }
|
|
|
|
int nullseat_get_windowid(Seat *seat, long *id_out) { return FALSE; }
|
2018-10-13 09:37:24 +03:00
|
|
|
int nullseat_get_window_pixel_size(
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 21:58:42 +03:00
|
|
|
Seat *seat, int *width, int *height) { return FALSE; }
|
2018-10-18 22:06:42 +03:00
|
|
|
|
|
|
|
void sk_free_peer_info(SocketPeerInfo *pi)
|
|
|
|
{
|
|
|
|
if (pi) {
|
|
|
|
sfree((char *)pi->addr_text);
|
|
|
|
sfree((char *)pi->log_text);
|
|
|
|
sfree(pi);
|
|
|
|
}
|
|
|
|
}
|