mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
aba05b7180
The previous platform-dependent ifdefs, switching between a system which tried to cope with spurious callbacks (which I'd observed on Windows) and one which tried to cope with system clock jumps (which can happen on Unix, if you use gettimeofday) have been completely removed, and replaced with a much simpler approach which just copes with system clock jumps by triggering any timers immediately. None of the resulting effects should be catastrophic (the worst thing might be the waste of CPU in a spurious rekey, but as long as the system clock isn't jumping around _all_ the time that's hardly critical) and in any case the Unix port has had a long-standing oddity involving occasional lockups if pterm or PuTTY runs for too long, which hopefully this should replace with a much less bad failure mode. And the code is much simpler, which is not to be sneezed at. [originally from svn r9528]
213 lines
4.5 KiB
C
213 lines
4.5 KiB
C
/*
|
|
* PuTTY miscellaneous Unix stuff
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <pwd.h>
|
|
|
|
#include "putty.h"
|
|
|
|
unsigned long getticks(void)
|
|
{
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
/*
|
|
* We want to use milliseconds rather than microseconds,
|
|
* because we need a decent number of them to fit into a 32-bit
|
|
* word so it can be used for keepalives.
|
|
*/
|
|
return tv.tv_sec * TICKSPERSEC + tv.tv_usec / (1000000 / TICKSPERSEC);
|
|
}
|
|
|
|
Filename *filename_from_str(const char *str)
|
|
{
|
|
Filename *ret = snew(Filename);
|
|
ret->path = dupstr(str);
|
|
return ret;
|
|
}
|
|
|
|
Filename *filename_copy(const Filename *fn)
|
|
{
|
|
return filename_from_str(fn->path);
|
|
}
|
|
|
|
const char *filename_to_str(const Filename *fn)
|
|
{
|
|
return fn->path;
|
|
}
|
|
|
|
int filename_equal(const Filename *f1, const Filename *f2)
|
|
{
|
|
return !strcmp(f1->path, f2->path);
|
|
}
|
|
|
|
int filename_is_null(const Filename *fn)
|
|
{
|
|
return !fn->path[0];
|
|
}
|
|
|
|
void filename_free(Filename *fn)
|
|
{
|
|
sfree(fn->path);
|
|
sfree(fn);
|
|
}
|
|
|
|
int filename_serialise(const Filename *f, void *vdata)
|
|
{
|
|
char *data = (char *)vdata;
|
|
int len = strlen(f->path) + 1; /* include trailing NUL */
|
|
if (data) {
|
|
strcpy(data, f->path);
|
|
}
|
|
return len;
|
|
}
|
|
Filename *filename_deserialise(void *vdata, int maxsize, int *used)
|
|
{
|
|
char *data = (char *)vdata;
|
|
char *end;
|
|
end = memchr(data, '\0', maxsize);
|
|
if (!end)
|
|
return NULL;
|
|
end++;
|
|
*used = end - data;
|
|
return filename_from_str(data);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static FILE *debug_fp = NULL;
|
|
|
|
void dputs(char *buf)
|
|
{
|
|
if (!debug_fp) {
|
|
debug_fp = fopen("debug.log", "w");
|
|
}
|
|
|
|
write(1, buf, strlen(buf));
|
|
|
|
fputs(buf, debug_fp);
|
|
fflush(debug_fp);
|
|
}
|
|
#endif
|
|
|
|
char *get_username(void)
|
|
{
|
|
struct passwd *p;
|
|
uid_t uid = getuid();
|
|
char *user, *ret = NULL;
|
|
|
|
/*
|
|
* First, find who we think we are using getlogin. If this
|
|
* agrees with our uid, we'll go along with it. This should
|
|
* allow sharing of uids between several login names whilst
|
|
* coping correctly with people who have su'ed.
|
|
*/
|
|
user = getlogin();
|
|
setpwent();
|
|
if (user)
|
|
p = getpwnam(user);
|
|
else
|
|
p = NULL;
|
|
if (p && p->pw_uid == uid) {
|
|
/*
|
|
* The result of getlogin() really does correspond to
|
|
* our uid. Fine.
|
|
*/
|
|
ret = user;
|
|
} else {
|
|
/*
|
|
* If that didn't work, for whatever reason, we'll do
|
|
* the simpler version: look up our uid in the password
|
|
* file and map it straight to a name.
|
|
*/
|
|
p = getpwuid(uid);
|
|
if (!p)
|
|
return NULL;
|
|
ret = p->pw_name;
|
|
}
|
|
endpwent();
|
|
|
|
return dupstr(ret);
|
|
}
|
|
|
|
/*
|
|
* Display the fingerprints of the PGP Master Keys to the user.
|
|
* (This is here rather than in uxcons because it's appropriate even for
|
|
* Unix GUI apps.)
|
|
*/
|
|
void pgp_fingerprints(void)
|
|
{
|
|
fputs("These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
|
|
"be used to establish a trust path from this executable to another\n"
|
|
"one. See the manual for more information.\n"
|
|
"(Note: these fingerprints have nothing to do with SSH!)\n"
|
|
"\n"
|
|
"PuTTY Master Key (RSA), 1024-bit:\n"
|
|
" " PGP_RSA_MASTER_KEY_FP "\n"
|
|
"PuTTY Master Key (DSA), 1024-bit:\n"
|
|
" " PGP_DSA_MASTER_KEY_FP "\n", stdout);
|
|
}
|
|
|
|
/*
|
|
* Set FD_CLOEXEC on a file descriptor
|
|
*/
|
|
int cloexec(int fd) {
|
|
int fdflags;
|
|
|
|
fdflags = fcntl(fd, F_GETFD);
|
|
if (fdflags == -1) return -1;
|
|
return fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
|
|
}
|
|
|
|
FILE *f_open(const Filename *filename, char const *mode, int is_private)
|
|
{
|
|
if (!is_private) {
|
|
return fopen(filename->path, mode);
|
|
} else {
|
|
int fd;
|
|
assert(mode[0] == 'w'); /* is_private is meaningless for read,
|
|
and tricky for append */
|
|
fd = open(filename->path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
|
if (fd < 0)
|
|
return NULL;
|
|
return fdopen(fd, mode);
|
|
}
|
|
}
|
|
|
|
FontSpec *fontspec_new(const char *name)
|
|
{
|
|
FontSpec *f = snew(FontSpec);
|
|
f->name = dupstr(name);
|
|
return f;
|
|
}
|
|
FontSpec *fontspec_copy(const FontSpec *f)
|
|
{
|
|
return fontspec_new(f->name);
|
|
}
|
|
void fontspec_free(FontSpec *f)
|
|
{
|
|
sfree(f->name);
|
|
sfree(f);
|
|
}
|
|
int fontspec_serialise(FontSpec *f, void *data)
|
|
{
|
|
int len = strlen(f->name);
|
|
if (data)
|
|
strcpy(data, f->name);
|
|
return len + 1; /* include trailing NUL */
|
|
}
|
|
FontSpec *fontspec_deserialise(void *vdata, int maxsize, int *used)
|
|
{
|
|
char *data = (char *)vdata;
|
|
char *end = memchr(data, '\0', maxsize);
|
|
if (!end)
|
|
return NULL;
|
|
*used = end - data + 1;
|
|
return fontspec_new(data);
|
|
}
|