655 lines
16 KiB
C
655 lines
16 KiB
C
#ifdef CYGTERMPORT
|
|
|
|
#include <stdio.h> /* sprintf */
|
|
#include <string.h>
|
|
#include <limits.h> /* INT_MAX */
|
|
#include "putty.h"
|
|
#include "cthelper/cthelper.h"
|
|
#include "cthelper/message.h"
|
|
|
|
void SearchCtHelper( void ) ;
|
|
|
|
#define CYGTERM_MAX_BACKLOG 16384
|
|
|
|
#define CYGTERM_NAME "Cygterm"
|
|
|
|
#ifdef __INTERIX
|
|
#define CTHELPER "posix.exe /u /c cthelper.exe"
|
|
#define CTHELPER64 "posix.exe /u /c cthelper64.exe"
|
|
#else
|
|
#define CTHELPER "cthelper"
|
|
#define CTHELPER64 "cthelper64"
|
|
#endif
|
|
|
|
#if !defined(DEBUG)
|
|
#define cygterm_debug(f,...)
|
|
#elif !defined(cygterm_debug)
|
|
#define cygterm_debug(f,...) debug(("%s:%d:%s: "f"\n",__FILE__,__LINE__,__FUNCTION__,##__VA_ARGS__))
|
|
#endif
|
|
|
|
#define putenv _putenv
|
|
|
|
size_t win_seat_output_local(Seat *seat, bool is_stderr, const void *data, size_t len) ;
|
|
|
|
typedef struct cygterm_backend_data {
|
|
//const struct plug_function_table *fn;
|
|
//void *frontend;
|
|
|
|
Socket *a;
|
|
Socket *s;
|
|
Seat *seat;
|
|
LogContext *logctx;
|
|
PROCESS_INFORMATION pi;
|
|
HANDLE ctl;
|
|
Conf * conf;
|
|
Plug plug;
|
|
Backend backend;
|
|
int bufsize;
|
|
int editing, echoing;
|
|
int exitcode;
|
|
} Local;
|
|
|
|
/* Plug functions for cthelper data connection */
|
|
static void cygterm_log(Plug *p, int type, SockAddr *addr, int port, const char *error_msg, int error_code)
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
|
|
|
|
static int cygterm_closing(Plug *plug, const char *error_msg, int error_code, bool calling_back)
|
|
{
|
|
//Local local = (Local)plug;
|
|
Local *local = container_of(plug,Local,plug);
|
|
|
|
cygterm_debug("top");
|
|
if (local->s) {
|
|
sk_close(local->s);
|
|
local->s = NULL;
|
|
}
|
|
/* check for errors from cthelper */
|
|
CloseHandle(local->ctl);
|
|
/* wait for cthelper */
|
|
if (local->pi.hProcess != INVALID_HANDLE_VALUE) {
|
|
if (WAIT_OBJECT_0 == WaitForSingleObject(local->pi.hProcess, 2000)) {
|
|
DWORD status;
|
|
GetExitCodeProcess(local->pi.hProcess, &status);
|
|
switch (status) {
|
|
case CthelperSuccess:
|
|
break;
|
|
case CthelperInvalidUsage:
|
|
case CthelperInvalidPort:
|
|
case CthelperConnectFailed:
|
|
local->exitcode = INT_MAX;
|
|
error_msg = "Internal error";
|
|
break;
|
|
case CthelperPtyforkFailure:
|
|
local->exitcode = INT_MAX;
|
|
error_msg = "Failed to allocate pseudoterminal";
|
|
break;
|
|
case CthelperExecFailure:
|
|
local->exitcode = INT_MAX;
|
|
error_msg = "Failed to execute command";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* this calls cygterm_exitcode() */
|
|
//notify_remote_exit(local->frontend);
|
|
seat_notify_remote_exit(local->seat);
|
|
if (error_msg) {
|
|
cygterm_debug("error_msg: %s", error_msg);
|
|
//connection_fatal(local->frontend, "%s", error_msg);
|
|
seat_connection_fatal(local->seat, "%s", error_msg);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int cygterm_receive(Plug * plug, int urgent, const char *data, size_t len)
|
|
{
|
|
//Local local = (Local)plug;
|
|
Local *local = container_of(plug,Local,plug);
|
|
|
|
int backlog;
|
|
cygterm_debug("backend -> display %u", len);
|
|
// dmemdump(data, len);
|
|
//backlog = from_backend(local->frontend, 0, data, len);
|
|
backlog = win_seat_output_local(local->seat,false,data,len);
|
|
// dmemdumpl(data, len);
|
|
sk_set_frozen(local->s, backlog > CYGTERM_MAX_BACKLOG);
|
|
cygterm_debug("OK");
|
|
return 1;
|
|
}
|
|
|
|
static void cygterm_sent(Plug * plug, size_t bufsize)
|
|
{
|
|
//Local local = (Local)plug;
|
|
Local *local = container_of(plug,Local,plug);
|
|
local->bufsize = bufsize;
|
|
}
|
|
|
|
static void
|
|
cygterm_size(void *handle, int width, int height);
|
|
|
|
|
|
Socket sk_tcp_accept(accept_ctx_t ctx, Plug plug);
|
|
static int
|
|
cygterm_accepting(Plug * plug, accept_fn_t constructor, accept_ctx_t ctx)
|
|
{
|
|
//Local local = (Local)plug;
|
|
Local *local = container_of(plug,Local,plug);
|
|
cygterm_debug("top");
|
|
local->s = constructor(ctx, plug);
|
|
sk_set_frozen(local->s, 0);
|
|
// Reset terminal size
|
|
cygterm_size(local, conf_get_int(local->conf,CONF_width), conf_get_int(local->conf,CONF_height));
|
|
cygterm_debug("OK");
|
|
return 0;
|
|
}
|
|
|
|
|
|
static char *getCygwinBin(int use64);
|
|
void appendPath(const char *append);
|
|
static size_t makeAttributes(char *buf, Conf *conf);
|
|
static const char *spawnChild(char *cmd, Conf *conf, LPPROCESS_INFORMATION ppi, PHANDLE pin);
|
|
|
|
/* Backend functions for the cygterm backend */
|
|
void RunCommand( HWND hwnd, char * cmd ) ;
|
|
|
|
|
|
static const struct PlugVtable Cygterm_plugvt = {
|
|
cygterm_log,
|
|
cygterm_closing,
|
|
cygterm_receive,
|
|
cygterm_sent,
|
|
};
|
|
|
|
/*
|
|
static const char * cygterm_init(void *frontend_handle, void **backend_handle,
|
|
Conf *conf,
|
|
const char *unused_host, int unused_port,
|
|
char **realhost, int nodelay, int keepalive)
|
|
*/
|
|
static const char * cygterm_init(Seat *seat, Backend **backend_handle,
|
|
LogContext *logctx,
|
|
Conf *conf,
|
|
const char *unused_host, int unused_port,
|
|
char **realhost, int nodelay, int keepalive)
|
|
{
|
|
/* XXX: I'm not sure if it is OK to overload Plug like this.
|
|
* cygterm_accepting should only be used for the listening socket
|
|
* (local->a) while the cygterm_closing, cygterm_receive, and cygterm_sent
|
|
* should be used only for the actual connection (local->s).
|
|
*/
|
|
|
|
Local *local;
|
|
const char *command;
|
|
char cmdline[2 * MAX_PATH];
|
|
int cport;
|
|
const char *err;
|
|
int cmdlinelen;
|
|
|
|
cygterm_debug("top");
|
|
|
|
local = snew(Local);
|
|
//local->fn = &fn_table;
|
|
local->plug.vt = &Cygterm_plugvt;
|
|
local->backend.vt = &cygterm_backend;
|
|
local->a = NULL;
|
|
local->s = NULL;
|
|
local->conf = conf;
|
|
local->editing = 0;
|
|
local->echoing = 0;
|
|
local->exitcode = 0;
|
|
*backend_handle = &local->backend;
|
|
|
|
local->seat = seat;
|
|
local->logctx = logctx;
|
|
|
|
//local->frontend = frontend_handle;
|
|
|
|
/* set up listen socket for communication with child */
|
|
cygterm_debug("setupCygTerm");
|
|
|
|
/* let sk use INADDR_LOOPBACK and let WinSock choose a port */
|
|
//local->a = sk_newlistener(0, 0, (Plug)local, 1, ADDRTYPE_IPV4);
|
|
local->a = sk_newlistener(0, 0, (Plug*)local, 1, ADDRTYPE_IPV4); // local-> ou seat ou local tout court
|
|
|
|
if ((err = sk_socket_error(local->a)) != NULL)
|
|
goto fail_free;
|
|
|
|
/* now, get the port that WinSock chose */
|
|
/* XXX: Is there another function in PuTTY to do this? */
|
|
cygterm_debug("getting port");
|
|
cport = sk_getport(local->a);
|
|
if (cport == -1) {
|
|
err = "Failed to get port number for cthelper";
|
|
goto fail_close;
|
|
}
|
|
|
|
if (strchr(conf_get_str(local->conf,CONF_termtype), ' ')) {
|
|
err = "term type contains spaces";
|
|
goto fail_close;
|
|
}
|
|
|
|
/* Build cthelper command line */
|
|
char * CTHELPER_PATH = getenv( "CTHELPER_PATH" ) ;
|
|
if( CTHELPER_PATH==NULL ) { SearchCtHelper() ; CTHELPER_PATH = getenv( "CTHELPER_PATH" ) ; }
|
|
if( CTHELPER_PATH!=NULL ) cmdlinelen = sprintf(cmdline, "\"%s\" %u %s ", CTHELPER_PATH, cport, conf_get_str(local->conf,CONF_termtype));
|
|
else {
|
|
//cmdlinelen = sprintf(cmdline, CTHELPER" %u %s ", cport,conf_get_str(local->conf,CONF_termtype));
|
|
if(conf_get_int(conf, CONF_cygterm64)) {
|
|
cmdlinelen = sprintf(cmdline, CTHELPER64" %u %s ", cport, conf_get_str(local->conf, CONF_termtype));
|
|
}
|
|
else {
|
|
cmdlinelen = sprintf(cmdline, CTHELPER" %u %s ", cport, conf_get_str(local->conf, CONF_termtype));
|
|
}
|
|
}
|
|
cmdlinelen += makeAttributes(cmdline + cmdlinelen, local->conf);
|
|
|
|
command = conf_get_str(conf,CONF_cygcmd);
|
|
|
|
if( command[0]=='?' ) {
|
|
RunCommand(NULL,(char*)(command+1));
|
|
exit(0);
|
|
}
|
|
else {
|
|
cygterm_debug("command is :%s:", command);
|
|
/* A command of "." or "-" tells us to pass no command arguments to
|
|
* cthelper which will then run the user's shell under Cygwin. */
|
|
if ((command[0]=='-'||command[0]=='.') && command[1]=='\0')
|
|
;
|
|
else if (cmdlinelen + strlen(command) + 2 > sizeof cmdline) {
|
|
err = "command is too long";
|
|
goto fail_close;
|
|
}
|
|
else {
|
|
cmdlinelen += sprintf(cmdline + cmdlinelen, " %s", command);
|
|
}
|
|
|
|
/* Add the Cygwin /bin path to the PATH. */
|
|
if (conf_get_int(conf,CONF_cygautopath)) {
|
|
char *cygwinBinPath = getCygwinBin(conf_get_int(conf, CONF_cygterm64));
|
|
if (!cygwinBinPath) {
|
|
/* we'll try anyway */
|
|
cygterm_debug("cygwin bin directory not found");
|
|
}
|
|
else {
|
|
cygterm_debug("found cygwin directory: %s", cygwinBinPath);
|
|
appendPath(cygwinBinPath);
|
|
sfree(cygwinBinPath);
|
|
}
|
|
}
|
|
|
|
cygterm_debug("starting cthelper: %s", cmdline);
|
|
{ char buffer[1024] ; sprintf( buffer,"starting cthelper: %s", cmdline ) ; logevent( NULL,buffer ) ; }
|
|
if ((err = spawnChild(cmdline, conf, &local->pi, &local->ctl)))
|
|
goto fail_close;
|
|
|
|
/* This should be set to the local hostname, Apparently, realhost is used
|
|
* only to set the window title.
|
|
*/
|
|
strcpy(*realhost = smalloc(sizeof CYGTERM_NAME), CYGTERM_NAME);
|
|
cygterm_debug("OK");
|
|
}
|
|
|
|
return 0;
|
|
|
|
fail_close:
|
|
sk_close(local->a);
|
|
fail_free:
|
|
sfree(local);
|
|
return err;
|
|
}
|
|
|
|
static void
|
|
cygterm_free(void *handle)
|
|
{
|
|
//Local local = handle;
|
|
Local *local = container_of(handle, Local, backend);
|
|
cygterm_debug("top");
|
|
sfree(local);
|
|
}
|
|
|
|
static void
|
|
cygterm_reconfig(void *handle, Conf *conf)
|
|
{
|
|
//Local local = handle;
|
|
Local *local = container_of(handle, Local, backend);
|
|
cygterm_debug("top");
|
|
local->conf = conf;
|
|
}
|
|
|
|
static int
|
|
cygterm_send(void *handle, const char *buf, int len)
|
|
{
|
|
//Local local = handle;
|
|
Local *local = container_of(handle, Local, backend);
|
|
cygterm_debug("frontend -> pty %u", len);
|
|
// dmemdump(buf, len);
|
|
#if 0
|
|
/* HACK */
|
|
{
|
|
int i;
|
|
for (i = 0; i < len - 1; i++)
|
|
if (buf[i] == 033 && !(buf[i+1]&0x80)) {
|
|
memmove(buf + i, buf + i + 1, --len - i);
|
|
buf[i] |= 0x80;
|
|
}
|
|
}
|
|
#endif
|
|
if (local->s != 0)
|
|
local->bufsize = sk_write(local->s, buf, len);
|
|
cygterm_debug("OK");
|
|
return local->bufsize;
|
|
}
|
|
|
|
static int
|
|
cygterm_sendbuffer(void *handle)
|
|
{
|
|
//Local local = handle;
|
|
Local *local = container_of(handle, Local, backend);
|
|
cygterm_debug("top");
|
|
return local->bufsize;
|
|
}
|
|
|
|
static void
|
|
cygterm_size(void *handle, int width, int height)
|
|
{
|
|
//Local local = handle;
|
|
Local *local = container_of(handle, Local, backend);
|
|
cygterm_debug("top");
|
|
cygterm_debug("size=%d,%d (last=%d,%d)",
|
|
width, height, conf_get_int(local->conf,CONF_width), conf_get_int(local->conf,CONF_height));
|
|
conf_set_int(local->conf,CONF_width,width);
|
|
conf_set_int(local->conf,CONF_height,height);
|
|
if (local->s) {
|
|
DWORD n;
|
|
Message m;
|
|
m.size = MESSAGE_MIN + sizeof(m.msg);
|
|
m.type = MSG_RESIZE;
|
|
m.msg.resize.width = width;
|
|
m.msg.resize.height = height;
|
|
cygterm_debug("WriteFile %p %p:%u", local->ctl, &m, m.size);
|
|
WriteFile(local->ctl, (const char *)&m, m.size, &n, 0);
|
|
cygterm_debug("WriteFile returns %d");
|
|
}
|
|
}
|
|
|
|
//static void cygterm_special(void *handle, Telnet_Special code)
|
|
static void cygterm_special(void *handle, SessionSpecialCode code)
|
|
{
|
|
cygterm_debug("top");
|
|
}
|
|
|
|
static const struct telnet_special * cygterm_get_specials(void *handle)
|
|
{
|
|
cygterm_debug("top");
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
cygterm_connected(void *handle)
|
|
{
|
|
//Local local = handle;
|
|
Local *local = container_of(handle, Local, backend);
|
|
cygterm_debug("top");
|
|
return local->s != NULL;
|
|
}
|
|
|
|
static int
|
|
cygterm_exitcode(void *handle)
|
|
{
|
|
//Local local = handle;
|
|
Local *local = container_of(handle, Local, backend);
|
|
cygterm_debug("top");
|
|
return local->exitcode;
|
|
}
|
|
|
|
static int
|
|
cygterm_sendok(void *handle)
|
|
{
|
|
cygterm_debug("top");
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
cygterm_unthrottle(void *handle, int backlog)
|
|
{
|
|
//Local local = handle;
|
|
Local *local = container_of(handle, Local, backend);
|
|
cygterm_debug("top");
|
|
sk_set_frozen(local->s, backlog > CYGTERM_MAX_BACKLOG);
|
|
}
|
|
|
|
static int
|
|
cygterm_ldisc(void *handle, int option)
|
|
{
|
|
//Local local = handle;
|
|
Local *local = container_of(handle, Local, backend);
|
|
cygterm_debug("cygterm_ldisc: %d", option);
|
|
switch (option) {
|
|
case LD_EDIT:
|
|
return local->editing;
|
|
case LD_ECHO:
|
|
return local->echoing;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
cygterm_provide_ldisc(void *handle, void *ldisc)
|
|
{
|
|
cygterm_debug("top");
|
|
}
|
|
|
|
static void
|
|
cygterm_provide_logctx(void *handle, void *logctx)
|
|
{
|
|
cygterm_debug("top");
|
|
}
|
|
|
|
static int
|
|
cygterm_cfg_info(void *handle)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const struct BackendVtable cygterm_backend = {
|
|
cygterm_init,
|
|
cygterm_free,
|
|
cygterm_reconfig,
|
|
cygterm_send,
|
|
cygterm_sendbuffer,
|
|
cygterm_size,
|
|
cygterm_special,
|
|
cygterm_get_specials,
|
|
cygterm_connected,
|
|
cygterm_exitcode,
|
|
cygterm_sendok,
|
|
cygterm_ldisc,
|
|
cygterm_provide_logctx,
|
|
cygterm_unthrottle,
|
|
cygterm_cfg_info,
|
|
NULL /* test_for_upstream */,
|
|
"cygterm",
|
|
PROT_CYGTERM,
|
|
1
|
|
};
|
|
|
|
/* like strcpy(), but return pointer to terminating null character */
|
|
static char *
|
|
strecpy(char *d,const char *s)
|
|
{
|
|
while ((*d = *s++))
|
|
d++;
|
|
return d;
|
|
}
|
|
|
|
/* Make cthelper attribute string from PuTTY Config */
|
|
static size_t
|
|
makeAttributes(char *buf, Conf *conf)
|
|
{
|
|
char *e = buf;
|
|
|
|
if (conf_get_int(conf,CONF_bksp_is_delete))
|
|
e = strecpy(e, ":erase=^?");
|
|
else
|
|
e = strecpy(e, ":erase=^H");
|
|
|
|
e += sprintf(e, ":size=%d,%d", conf_get_int(conf,CONF_height), conf_get_int(conf,CONF_width));
|
|
|
|
/* TODO: other options? localedit? localecho? */
|
|
|
|
return e - buf;
|
|
}
|
|
|
|
#ifndef KEY_WOW64_64KEY
|
|
#define KEY_WOW64_64KEY 0x0100
|
|
#endif
|
|
#ifndef KEY_WOW64_32KEY
|
|
#define KEY_WOW64_32KEY 0x0200
|
|
#endif
|
|
|
|
/* Utility functions for spawning cthelper process */
|
|
static BOOL
|
|
getRegistry(char *valueData, LPDWORD psize, HKEY key, const char *subKey, const char *valueName, int use64)
|
|
{
|
|
HKEY k;
|
|
LONG ret;
|
|
|
|
if (ERROR_SUCCESS != (ret = RegOpenKeyEx(key, subKey, 0, KEY_READ | (use64 ? KEY_WOW64_64KEY : KEY_WOW64_32KEY), &k )))
|
|
return ret;
|
|
|
|
ERROR_SUCCESS == (ret = RegQueryInfoKey(k, 0, 0, 0, 0, 0, 0, 0, 0, psize, 0, 0))
|
|
&& ERROR_SUCCESS == (ret = RegQueryValueEx(k, valueName, 0, 0, (LPBYTE)valueData, psize)) ;
|
|
|
|
RegCloseKey(k);
|
|
return ret;
|
|
}
|
|
|
|
/* Cygwin 1.5 definition */
|
|
#define CYGWIN_SYS_ROOT_MOUNT \
|
|
HKEY_LOCAL_MACHINE,\
|
|
"Software\\Cygnus Solutions\\Cygwin\\mounts v2\\/",\
|
|
"native"
|
|
#define CYGWIN_USER_ROOT_MOUNT \
|
|
HKEY_CURRENT_USER,\
|
|
"Software\\Cygnus Solutions\\Cygwin\\mounts v2\\/",\
|
|
"native"
|
|
|
|
/* As of Cygwin 1.7, one of these keys contains the Cygwin install root. */
|
|
#define CYGWIN_U_SETUP_ROOTDIR \
|
|
HKEY_CURRENT_USER,\
|
|
"Software\\Cygwin\\setup",\
|
|
"rootdir"
|
|
#define CYGWIN_S_SETUP_ROOTDIR \
|
|
HKEY_LOCAL_MACHINE,\
|
|
"Software\\Cygwin\\setup",\
|
|
"rootdir"
|
|
|
|
static char *
|
|
getCygwinBin(int use64)
|
|
{
|
|
char *dir;
|
|
DWORD size = MAX_PATH;
|
|
|
|
dir = smalloc(size);
|
|
dir[0] = '\0';
|
|
|
|
if (ERROR_SUCCESS == getRegistry(dir, &size, CYGWIN_U_SETUP_ROOTDIR, use64) || ERROR_SUCCESS == getRegistry(dir, &size, CYGWIN_S_SETUP_ROOTDIR, use64))
|
|
{
|
|
strcat(dir, "\\bin");
|
|
}
|
|
else if (ERROR_SUCCESS == getRegistry(dir, &size, CYGWIN_SYS_ROOT_MOUNT, use64) || ERROR_SUCCESS == getRegistry(dir, &size, CYGWIN_USER_ROOT_MOUNT, use64))
|
|
{
|
|
strcat(dir, "\\bin");
|
|
}
|
|
else
|
|
{
|
|
sfree(dir);
|
|
dir = 0;
|
|
}
|
|
|
|
return dir;
|
|
}
|
|
|
|
void
|
|
appendPath(const char *append)
|
|
{
|
|
char *path;
|
|
char *newPath;
|
|
|
|
cygterm_debug("getting PATH");
|
|
if (!(path = getenv("PATH"))) {
|
|
cygterm_debug("hmm.. PATH not set");
|
|
path = "";
|
|
}
|
|
cygterm_debug("alloc newPath");
|
|
newPath = smalloc(5 + strlen(append) + 1 + strlen(path) + 1);
|
|
cygterm_debug("init newPath");
|
|
sprintf(newPath, "PATH=%s;%s", path, append);
|
|
cygterm_debug("set newPath");
|
|
putenv(newPath);
|
|
cygterm_debug("free newPath");
|
|
sfree(newPath);
|
|
}
|
|
|
|
static const char *
|
|
spawnChild(char *cmd, Conf *conf, LPPROCESS_INFORMATION ppi, PHANDLE pin)
|
|
{
|
|
STARTUPINFO si = {sizeof(si)};
|
|
SECURITY_ATTRIBUTES sa = {sizeof(sa)};
|
|
HANDLE in;
|
|
|
|
/* Create an anonymous pipe over which to send events such as resize */
|
|
sa.lpSecurityDescriptor = NULL;
|
|
sa.bInheritHandle = TRUE;
|
|
if (!CreatePipe(&in, pin, &sa, 1))
|
|
return "failed to create event pipe";
|
|
|
|
/* cthelper will use stdin to get event messages */
|
|
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
|
si.hStdInput = in;
|
|
si.wShowWindow = SW_HIDE;
|
|
|
|
/* Add the Cygwin /bin path to the PATH env var. */
|
|
if (!getenv("NOCYGWIN")) {
|
|
char *cygwinBinPath = getCygwinBin(conf_get_int(conf, CONF_cygterm64));
|
|
if (!cygwinBinPath) {
|
|
/* we'll try anyway */
|
|
cygterm_debug("cygwin bin directory not found");
|
|
}
|
|
else {
|
|
cygterm_debug("found cygwin directory: %s", cygwinBinPath);
|
|
appendPath(cygwinBinPath);
|
|
sfree(cygwinBinPath);
|
|
}
|
|
}
|
|
{ char buffer[1024] ; sprintf(buffer, "Create process %s", cmd ) ; logevent(NULL,buffer); }
|
|
/* We allow cthelper to inherit handles. I have no idea if there are
|
|
* other inheritable handles in PuTTY that this will effect. cthelper
|
|
* will attempt to close all open descriptors.
|
|
*/
|
|
if (!CreateProcess(
|
|
NULL, cmd, /* command line */
|
|
NULL, NULL, /* no process or thread security attributes */
|
|
TRUE, /* inherit handles */
|
|
CREATE_NEW_CONSOLE, /* create a new console window */
|
|
NULL, /* use parent environment */
|
|
0, /* use parent working directory */
|
|
&si, /* STARTUPINFO sets stdin to read end of pipe */
|
|
ppi))
|
|
{
|
|
CloseHandle(in);
|
|
CloseHandle(*pin);
|
|
*pin = INVALID_HANDLE_VALUE;
|
|
return "failed to run cthelper";
|
|
}
|
|
|
|
/* close the read end of the pipe */
|
|
CloseHandle(in);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|