2013-11-17 14:05:41 +00:00
|
|
|
/*
|
|
|
|
* Unix implementation of SSH connection-sharing IPC setup.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
2014-09-09 12:47:39 +00:00
|
|
|
#include <limits.h>
|
2013-11-17 14:05:41 +00:00
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
|
|
|
|
#include "tree234.h"
|
|
|
|
#include "putty.h"
|
|
|
|
#include "network.h"
|
|
|
|
#include "proxy.h"
|
|
|
|
#include "ssh.h"
|
|
|
|
|
|
|
|
#define CONNSHARE_SOCKETDIR_PREFIX "/tmp/putty-connshare"
|
2014-09-09 12:47:39 +00:00
|
|
|
#define SALT_FILENAME "salt"
|
|
|
|
#define SALT_SIZE 64
|
2019-03-20 13:09:34 +00:00
|
|
|
#ifndef PIPE_BUF
|
|
|
|
#define PIPE_BUF _POSIX_PIPE_BUF
|
|
|
|
#endif
|
2013-11-17 14:05:41 +00:00
|
|
|
|
2014-09-09 12:47:39 +00:00
|
|
|
static char *make_parentdir_name(void)
|
2013-11-17 14:05:41 +00:00
|
|
|
{
|
2014-09-09 12:47:39 +00:00
|
|
|
char *username, *parent;
|
2013-11-17 14:05:41 +00:00
|
|
|
|
|
|
|
username = get_username();
|
|
|
|
parent = dupprintf("%s.%s", CONNSHARE_SOCKETDIR_PREFIX, username);
|
|
|
|
sfree(username);
|
|
|
|
assert(*parent == '/');
|
|
|
|
|
2014-09-09 12:47:39 +00:00
|
|
|
return parent;
|
2013-11-17 14:05:41 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 12:47:39 +00:00
|
|
|
static char *make_dirname(const char *pi_name, char **logtext)
|
2013-11-17 14:05:41 +00:00
|
|
|
{
|
2014-09-09 12:47:39 +00:00
|
|
|
char *name, *parentdirname, *dirname, *err;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First, create the top-level directory for all shared PuTTY
|
|
|
|
* connections owned by this user.
|
|
|
|
*/
|
|
|
|
parentdirname = make_parentdir_name();
|
|
|
|
if ((err = make_dir_and_check_ours(parentdirname)) != NULL) {
|
|
|
|
*logtext = err;
|
|
|
|
sfree(parentdirname);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-11-17 14:05:41 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Transform the platform-independent version of the connection
|
2014-09-09 12:47:39 +00:00
|
|
|
* identifier into the name we'll actually use for the directory
|
|
|
|
* containing the Unix socket.
|
|
|
|
*
|
|
|
|
* We do this by hashing the identifier with some user-specific
|
|
|
|
* secret information, to avoid the privacy leak of having
|
|
|
|
* "user@host" strings show up in 'netstat -x'. (Irritatingly, the
|
|
|
|
* full pathname of a Unix-domain socket _does_ show up in the
|
|
|
|
* 'netstat -x' output, at least on Linux, even if that socket is
|
|
|
|
* in a directory not readable to the user running netstat. You'd
|
|
|
|
* think putting things inside an 0700 directory would hide their
|
|
|
|
* names from other users, but no.)
|
|
|
|
*
|
|
|
|
* The secret information we use to salt the hash lives in a file
|
|
|
|
* inside the top-level directory we just created, so we must
|
|
|
|
* first create that file (with some fresh random data in it) if
|
|
|
|
* it's not already been done by a previous PuTTY.
|
2013-11-17 14:05:41 +00:00
|
|
|
*/
|
|
|
|
{
|
2014-09-09 12:47:39 +00:00
|
|
|
unsigned char saltbuf[SALT_SIZE];
|
|
|
|
char *saltname;
|
|
|
|
int saltfd, i, ret;
|
|
|
|
|
|
|
|
saltname = dupprintf("%s/%s", parentdirname, SALT_FILENAME);
|
|
|
|
saltfd = open(saltname, O_RDONLY);
|
|
|
|
if (saltfd < 0) {
|
|
|
|
char *tmpname;
|
|
|
|
int pid;
|
|
|
|
|
|
|
|
if (errno != ENOENT) {
|
|
|
|
*logtext = dupprintf("%s: open: %s", saltname,
|
|
|
|
strerror(errno));
|
|
|
|
sfree(saltname);
|
|
|
|
sfree(parentdirname);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The salt file doesn't already exist, so try to create
|
|
|
|
* it. Another process may be attempting the same thing
|
|
|
|
* simultaneously, so we must do this carefully: we write
|
|
|
|
* a salt file under a different name, then hard-link it
|
|
|
|
* into place, which guarantees that we won't change the
|
|
|
|
* contents of an existing salt file.
|
|
|
|
*/
|
|
|
|
pid = getpid();
|
|
|
|
for (i = 0;; i++) {
|
|
|
|
tmpname = dupprintf("%s/%s.tmp.%d.%d",
|
|
|
|
parentdirname, SALT_FILENAME, pid, i);
|
|
|
|
saltfd = open(tmpname, O_WRONLY | O_EXCL | O_CREAT, 0400);
|
|
|
|
if (saltfd >= 0)
|
|
|
|
break;
|
|
|
|
if (errno != EEXIST) {
|
|
|
|
*logtext = dupprintf("%s: open: %s", tmpname,
|
|
|
|
strerror(errno));
|
|
|
|
sfree(tmpname);
|
|
|
|
sfree(saltname);
|
|
|
|
sfree(parentdirname);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
sfree(tmpname); /* go round and try again with i+1 */
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Invent some random data.
|
|
|
|
*/
|
Replace random_byte() with random_read().
This is in preparation for a PRNG revamp which will want to have a
well defined boundary for any given request-for-randomness, so that it
can destroy the evidence afterwards. So no more looping round calling
random_byte() and then stopping when we feel like it: now you say up
front how many random bytes you want, and call random_read() which
gives you that many in one go.
Most of the call sites that had to be fixed are fairly mechanical, and
quite a few ended up more concise afterwards. A few became more
cumbersome, such as mp_random_bits, in which the new API doesn't let
me load the random bytes directly into the target integer without
triggering undefined behaviour, so instead I have to allocate a
separate temporary buffer.
The _most_ interesting call site was in the PKCS#1 v1.5 padding code
in sshrsa.c (used in SSH-1), in which you need a stream of _nonzero_
random bytes. The previous code just looped on random_byte, retrying
if it got a zero. Now I'm doing a much more interesting thing with an
mpint, essentially scaling a binary fraction repeatedly to extract a
number in the range [0,255) and then adding 1 to it.
2019-01-22 19:43:27 +00:00
|
|
|
random_read(saltbuf, SALT_SIZE);
|
2014-09-09 12:47:39 +00:00
|
|
|
ret = write(saltfd, saltbuf, SALT_SIZE);
|
|
|
|
/* POSIX atomicity guarantee: because we wrote less than
|
|
|
|
* PIPE_BUF bytes, the write either completed in full or
|
|
|
|
* failed. */
|
|
|
|
assert(SALT_SIZE < PIPE_BUF);
|
|
|
|
assert(ret < 0 || ret == SALT_SIZE);
|
|
|
|
if (ret < 0) {
|
|
|
|
close(saltfd);
|
|
|
|
*logtext = dupprintf("%s: write: %s", tmpname,
|
|
|
|
strerror(errno));
|
|
|
|
sfree(tmpname);
|
|
|
|
sfree(saltname);
|
|
|
|
sfree(parentdirname);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (close(saltfd) < 0) {
|
|
|
|
*logtext = dupprintf("%s: close: %s", tmpname,
|
|
|
|
strerror(errno));
|
|
|
|
sfree(tmpname);
|
|
|
|
sfree(saltname);
|
|
|
|
sfree(parentdirname);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-11-17 14:05:41 +00:00
|
|
|
|
2014-09-09 12:47:39 +00:00
|
|
|
/*
|
|
|
|
* Now attempt to hard-link our temp file into place. We
|
|
|
|
* tolerate EEXIST as an outcome, because that just means
|
|
|
|
* another PuTTY got their attempt in before we did (and
|
|
|
|
* we only care that there is a valid salt file we can
|
|
|
|
* agree on, no matter who created it).
|
|
|
|
*/
|
|
|
|
if (link(tmpname, saltname) < 0 && errno != EEXIST) {
|
|
|
|
*logtext = dupprintf("%s: link: %s", saltname,
|
|
|
|
strerror(errno));
|
|
|
|
sfree(tmpname);
|
|
|
|
sfree(saltname);
|
|
|
|
sfree(parentdirname);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Whether that succeeded or not, get rid of our temp file.
|
|
|
|
*/
|
|
|
|
if (unlink(tmpname) < 0) {
|
|
|
|
*logtext = dupprintf("%s: unlink: %s", tmpname,
|
|
|
|
strerror(errno));
|
|
|
|
sfree(tmpname);
|
|
|
|
sfree(saltname);
|
|
|
|
sfree(parentdirname);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-11-17 14:05:41 +00:00
|
|
|
|
2014-09-09 12:47:39 +00:00
|
|
|
/*
|
|
|
|
* And now we've arranged for there to be a salt file, so
|
|
|
|
* we can try to open it for reading again and this time
|
|
|
|
* expect it to work.
|
|
|
|
*/
|
|
|
|
sfree(tmpname);
|
|
|
|
|
|
|
|
saltfd = open(saltname, O_RDONLY);
|
|
|
|
if (saltfd < 0) {
|
|
|
|
*logtext = dupprintf("%s: open: %s", saltname,
|
|
|
|
strerror(errno));
|
|
|
|
sfree(saltname);
|
|
|
|
sfree(parentdirname);
|
|
|
|
return NULL;
|
2013-11-17 14:05:41 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-09 12:47:39 +00:00
|
|
|
|
|
|
|
for (i = 0; i < SALT_SIZE; i++) {
|
|
|
|
ret = read(saltfd, saltbuf, SALT_SIZE);
|
|
|
|
if (ret <= 0) {
|
|
|
|
close(saltfd);
|
|
|
|
*logtext = dupprintf("%s: read: %s", saltname,
|
|
|
|
ret == 0 ? "unexpected EOF" :
|
|
|
|
strerror(errno));
|
|
|
|
sfree(saltname);
|
|
|
|
sfree(parentdirname);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
assert(0 < ret && ret <= SALT_SIZE - i);
|
|
|
|
i += ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(saltfd);
|
|
|
|
sfree(saltname);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we've got our salt, hash it with the connection
|
|
|
|
* identifier to produce our actual socket name.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
unsigned char digest[32];
|
|
|
|
char retbuf[65];
|
|
|
|
|
2019-01-20 16:15:14 +00:00
|
|
|
ssh_hash *h = ssh_hash_new(&ssh_sha256);
|
|
|
|
put_string(h, saltbuf, SALT_SIZE);
|
|
|
|
put_stringz(h, pi_name);
|
|
|
|
ssh_hash_final(h, digest);
|
2014-09-09 12:47:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* And make it printable.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
sprintf(retbuf + 2*i, "%02x", digest[i]);
|
|
|
|
/* the last of those will also write the trailing NUL */
|
|
|
|
}
|
|
|
|
|
|
|
|
name = dupstr(retbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
smemclr(saltbuf, sizeof(saltbuf));
|
2013-11-17 14:05:41 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 12:47:39 +00:00
|
|
|
dirname = dupprintf("%s/%s", parentdirname, name);
|
|
|
|
sfree(parentdirname);
|
|
|
|
sfree(name);
|
|
|
|
|
|
|
|
return dirname;
|
|
|
|
}
|
|
|
|
|
|
|
|
int platform_ssh_share(const char *pi_name, Conf *conf,
|
Get rid of lots of implicit pointer types.
All the main backend structures - Ssh, Telnet, Pty, Serial etc - now
describe structure types themselves rather than pointers to them. The
same goes for the codebase-wide trait types Socket and Plug, and the
supporting types SockAddr and Pinger.
All those things that were typedefed as pointers are older types; the
newer ones have the explicit * at the point of use, because that's
what I now seem to be preferring. But whichever one of those is
better, inconsistently using a mixture of the two styles is worse, so
let's make everything consistent.
A few types are still implicitly pointers, such as Bignum and some of
the GSSAPI types; generally this is either because they have to be
void *, or because they're typedefed differently on different
platforms and aren't always pointers at all. Can't be helped. But I've
got rid of the main ones, at least.
2018-10-04 18:10:23 +00:00
|
|
|
Plug *downplug, Plug *upplug, Socket **sock,
|
2014-09-09 12:47:39 +00:00
|
|
|
char **logtext, char **ds_err, char **us_err,
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool can_upstream, bool can_downstream)
|
2014-09-09 12:47:39 +00:00
|
|
|
{
|
|
|
|
char *dirname, *lockname, *sockname, *err;
|
|
|
|
int lockfd;
|
Get rid of lots of implicit pointer types.
All the main backend structures - Ssh, Telnet, Pty, Serial etc - now
describe structure types themselves rather than pointers to them. The
same goes for the codebase-wide trait types Socket and Plug, and the
supporting types SockAddr and Pinger.
All those things that were typedefed as pointers are older types; the
newer ones have the explicit * at the point of use, because that's
what I now seem to be preferring. But whichever one of those is
better, inconsistently using a mixture of the two styles is worse, so
let's make everything consistent.
A few types are still implicitly pointers, such as Bignum and some of
the GSSAPI types; generally this is either because they have to be
void *, or because they're typedefed differently on different
platforms and aren't always pointers at all. Can't be helped. But I've
got rid of the main ones, at least.
2018-10-04 18:10:23 +00:00
|
|
|
Socket *retsock;
|
2014-09-09 12:47:39 +00:00
|
|
|
|
2013-11-17 14:05:41 +00:00
|
|
|
/*
|
2014-09-09 12:47:39 +00:00
|
|
|
* Sort out what we're going to call the directory in which we
|
|
|
|
* keep the socket. This has the side effect of potentially
|
|
|
|
* creating its top-level containing dir and/or the salt file
|
|
|
|
* within that, if they don't already exist.
|
2013-11-17 14:05:41 +00:00
|
|
|
*/
|
2014-09-09 12:47:39 +00:00
|
|
|
dirname = make_dirname(pi_name, logtext);
|
|
|
|
if (!dirname) {
|
2013-11-17 14:05:41 +00:00
|
|
|
return SHARE_NONE;
|
|
|
|
}
|
2014-09-09 12:47:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now make sure the subdirectory exists.
|
|
|
|
*/
|
2013-11-17 14:05:41 +00:00
|
|
|
if ((err = make_dir_and_check_ours(dirname)) != NULL) {
|
|
|
|
*logtext = err;
|
|
|
|
sfree(dirname);
|
|
|
|
return SHARE_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Acquire a lock on a file in that directory.
|
|
|
|
*/
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
lockname = dupcat(dirname, "/lock");
|
2013-11-17 14:05:41 +00:00
|
|
|
lockfd = open(lockname, O_CREAT | O_RDWR | O_TRUNC, 0600);
|
|
|
|
if (lockfd < 0) {
|
|
|
|
*logtext = dupprintf("%s: open: %s", lockname, strerror(errno));
|
|
|
|
sfree(dirname);
|
|
|
|
sfree(lockname);
|
|
|
|
return SHARE_NONE;
|
|
|
|
}
|
|
|
|
if (flock(lockfd, LOCK_EX) < 0) {
|
|
|
|
*logtext = dupprintf("%s: flock(LOCK_EX): %s",
|
|
|
|
lockname, strerror(errno));
|
|
|
|
sfree(dirname);
|
|
|
|
sfree(lockname);
|
|
|
|
close(lockfd);
|
|
|
|
return SHARE_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
sockname = dupprintf("%s/socket", dirname);
|
|
|
|
|
|
|
|
*logtext = NULL;
|
|
|
|
|
|
|
|
if (can_downstream) {
|
|
|
|
retsock = new_connection(unix_sock_addr(sockname),
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
"", 0, false, true, false, false,
|
|
|
|
downplug, conf);
|
2013-11-17 14:05:41 +00:00
|
|
|
if (sk_socket_error(retsock) == NULL) {
|
|
|
|
sfree(*logtext);
|
|
|
|
*logtext = sockname;
|
|
|
|
*sock = retsock;
|
|
|
|
sfree(dirname);
|
|
|
|
sfree(lockname);
|
|
|
|
close(lockfd);
|
|
|
|
return SHARE_DOWNSTREAM;
|
|
|
|
}
|
|
|
|
sfree(*ds_err);
|
|
|
|
*ds_err = dupprintf("%s: %s", sockname, sk_socket_error(retsock));
|
|
|
|
sk_close(retsock);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (can_upstream) {
|
|
|
|
retsock = new_unix_listener(unix_sock_addr(sockname), upplug);
|
|
|
|
if (sk_socket_error(retsock) == NULL) {
|
|
|
|
sfree(*logtext);
|
|
|
|
*logtext = sockname;
|
|
|
|
*sock = retsock;
|
|
|
|
sfree(dirname);
|
|
|
|
sfree(lockname);
|
|
|
|
close(lockfd);
|
|
|
|
return SHARE_UPSTREAM;
|
|
|
|
}
|
|
|
|
sfree(*us_err);
|
|
|
|
*us_err = dupprintf("%s: %s", sockname, sk_socket_error(retsock));
|
|
|
|
sk_close(retsock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* One of the above clauses ought to have happened. */
|
|
|
|
assert(*logtext || *ds_err || *us_err);
|
|
|
|
|
|
|
|
sfree(dirname);
|
|
|
|
sfree(lockname);
|
|
|
|
sfree(sockname);
|
|
|
|
close(lockfd);
|
|
|
|
return SHARE_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void platform_ssh_share_cleanup(const char *name)
|
|
|
|
{
|
2014-09-09 12:47:39 +00:00
|
|
|
char *dirname, *filename, *logtext;
|
2013-11-17 14:05:41 +00:00
|
|
|
|
2014-09-09 12:47:39 +00:00
|
|
|
dirname = make_dirname(name, &logtext);
|
|
|
|
if (!dirname) {
|
|
|
|
sfree(logtext); /* we can't do much with this */
|
|
|
|
return;
|
|
|
|
}
|
2013-11-17 14:05:41 +00:00
|
|
|
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
filename = dupcat(dirname, "/socket");
|
2013-11-17 14:05:41 +00:00
|
|
|
remove(filename);
|
|
|
|
sfree(filename);
|
|
|
|
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
filename = dupcat(dirname, "/lock");
|
2013-11-17 14:05:41 +00:00
|
|
|
remove(filename);
|
|
|
|
sfree(filename);
|
|
|
|
|
|
|
|
rmdir(dirname);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We deliberately _don't_ clean up the parent directory
|
|
|
|
* /tmp/putty-connshare.<username>, because if we leave it around
|
|
|
|
* then it reduces the ability for other users to be a nuisance by
|
2014-09-09 12:47:39 +00:00
|
|
|
* putting their own directory in the way of it. Also, the salt
|
|
|
|
* file in it can be reused.
|
2013-11-17 14:05:41 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
sfree(dirname);
|
|
|
|
}
|