📄 plink.c
字号:
/* * PLink - a Windows command-line (stdin/stdout) variant of PuTTY. */#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <stdarg.h>#define PUTTY_DO_GLOBALS /* actually _define_ globals */#include "putty.h"#include "storage.h"#include "tree234.h"#define WM_AGENT_CALLBACK (WM_XUSER + 4)#define MAX_STDIN_BACKLOG 4096struct agent_callback { void (*callback)(void *, void *, int); void *callback_ctx; void *data; int len;};void fatalbox(char *p, ...){ va_list ap; fprintf(stderr, "FATAL ERROR: "); va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fputc('\n', stderr); cleanup_exit(1);}void modalfatalbox(char *p, ...){ va_list ap; fprintf(stderr, "FATAL ERROR: "); va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fputc('\n', stderr); cleanup_exit(1);}void connection_fatal(void *frontend, char *p, ...){ va_list ap; fprintf(stderr, "FATAL ERROR: "); va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fputc('\n', stderr); cleanup_exit(1);}void cmdline_error(char *p, ...){ va_list ap; fprintf(stderr, "plink: "); va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fputc('\n', stderr); exit(1);}HANDLE inhandle, outhandle, errhandle;DWORD orig_console_mode;WSAEVENT netevent;static const Backend *back;static void *backhandle;static Config cfg;int term_ldisc(Terminal *term, int mode){ return FALSE;}void ldisc_update(void *frontend, int echo, int edit){ /* Update stdin read mode to reflect changes in line discipline. */ DWORD mode; mode = ENABLE_PROCESSED_INPUT; if (echo) mode = mode | ENABLE_ECHO_INPUT; else mode = mode & ~ENABLE_ECHO_INPUT; if (edit) mode = mode | ENABLE_LINE_INPUT; else mode = mode & ~ENABLE_LINE_INPUT; SetConsoleMode(inhandle, mode);}struct input_data { DWORD len; char buffer[4096]; HANDLE event, eventback;};static DWORD WINAPI stdin_read_thread(void *param){ struct input_data *idata = (struct input_data *) param; HANDLE inhandle; inhandle = GetStdHandle(STD_INPUT_HANDLE); while (ReadFile(inhandle, idata->buffer, sizeof(idata->buffer), &idata->len, NULL) && idata->len > 0) { SetEvent(idata->event); WaitForSingleObject(idata->eventback, INFINITE); } idata->len = 0; SetEvent(idata->event); return 0;}struct output_data { DWORD len, lenwritten; int writeret; char *buffer; int is_stderr, done; HANDLE event, eventback; int busy;};static DWORD WINAPI stdout_write_thread(void *param){ struct output_data *odata = (struct output_data *) param; HANDLE outhandle, errhandle; outhandle = GetStdHandle(STD_OUTPUT_HANDLE); errhandle = GetStdHandle(STD_ERROR_HANDLE); while (1) { WaitForSingleObject(odata->eventback, INFINITE); if (odata->done) break; odata->writeret = WriteFile(odata->is_stderr ? errhandle : outhandle, odata->buffer, odata->len, &odata->lenwritten, NULL); SetEvent(odata->event); } return 0;}bufchain stdout_data, stderr_data;struct output_data odata, edata;void try_output(int is_stderr){ struct output_data *data = (is_stderr ? &edata : &odata); void *senddata; int sendlen; if (!data->busy) { bufchain_prefix(is_stderr ? &stderr_data : &stdout_data, &senddata, &sendlen); data->buffer = senddata; data->len = sendlen; SetEvent(data->eventback); data->busy = 1; }}int from_backend(void *frontend_handle, int is_stderr, const char *data, int len){ int osize, esize; if (is_stderr) { bufchain_add(&stderr_data, data, len); try_output(1); } else { bufchain_add(&stdout_data, data, len); try_output(0); } osize = bufchain_size(&stdout_data); esize = bufchain_size(&stderr_data); return osize + esize;}static DWORD main_thread_id;void agent_schedule_callback(void (*callback)(void *, void *, int), void *callback_ctx, void *data, int len){ struct agent_callback *c = snew(struct agent_callback); c->callback = callback; c->callback_ctx = callback_ctx; c->data = data; c->len = len; PostThreadMessage(main_thread_id, WM_AGENT_CALLBACK, 0, (LPARAM)c);}/* * Short description of parameters. */static void usage(void){ printf("PuTTY Link: command-line connection utility\n"); printf("%s\n", ver); printf("Usage: plink [options] [user@]host [command]\n"); printf(" (\"host\" can also be a PuTTY saved session name)\n"); printf("Options:\n"); printf(" -V print version information\n"); printf(" -v show verbose messages\n"); printf(" -load sessname Load settings from saved session\n"); printf(" -ssh -telnet -rlogin -raw\n"); printf(" force use of a particular protocol\n"); printf(" -P port connect to specified port\n"); printf(" -l user connect with specified username\n"); printf(" -m file read remote command(s) from file\n"); printf(" -batch disable all interactive prompts\n"); printf("The following options only apply to SSH connections:\n"); printf(" -pw passw login with specified password\n"); printf(" -D [listen-IP:]listen-port\n"); printf(" Dynamic SOCKS-based port forwarding\n"); printf(" -L [listen-IP:]listen-port:host:port\n"); printf(" Forward local port to remote address\n"); printf(" -R [listen-IP:]listen-port:host:port\n"); printf(" Forward remote port to local address\n"); printf(" -X -x enable / disable X11 forwarding\n"); printf(" -A -a enable / disable agent forwarding\n"); printf(" -t -T enable / disable pty allocation\n"); printf(" -1 -2 force use of particular protocol version\n"); printf(" -C enable compression\n"); printf(" -i key private key file for authentication\n"); printf(" -s remote command is an SSH subsystem (SSH-2 only)\n"); printf(" -N don't start a shell/command (SSH-2 only)\n"); exit(1);}static void version(void){ printf("plink: %s\n", ver); exit(1);}char *do_select(SOCKET skt, int startup){ int events; if (startup) { events = (FD_CONNECT | FD_READ | FD_WRITE | FD_OOB | FD_CLOSE | FD_ACCEPT); } else { events = 0; } if (p_WSAEventSelect(skt, netevent, events) == SOCKET_ERROR) { switch (p_WSAGetLastError()) { case WSAENETDOWN: return "Network is down"; default: return "WSAEventSelect(): unknown error"; } } return NULL;}int main(int argc, char **argv){ WSAEVENT stdinevent, stdoutevent, stderrevent; HANDLE handles[4]; DWORD in_threadid, out_threadid, err_threadid; struct input_data idata; int reading; int sending; int portnumber = -1; SOCKET *sklist; int skcount, sksize; int connopen; int exitcode; int errors; int use_subsystem = 0; statics()->ssh_get_line = console_get_line; sklist = NULL; skcount = sksize = 0; /* * Initialise port and protocol to sensible defaults. (These * will be overridden by more or less anything.) */ statics()->default_protocol = PROT_SSH; statics()->default_port = 22; statics()->flags = FLAG_STDERR; /* * Process the command line. */ do_defaults(NULL, &cfg); loaded_session = FALSE; statics()->default_protocol = cfg.protocol; statics()->default_port = cfg.port; errors = 0; { /* * Override the default protocol if PLINK_PROTOCOL is set. */ char *p = getenv("PLINK_PROTOCOL"); int i; if (p) { for (i = 0; backends[i].backend != NULL; i++) { if (!strcmp(backends[i].name, p)) { statics()->default_protocol = cfg.protocol = backends[i].protocol; statics()->default_port = cfg.port = backends[i].backend->default_port; break; } } } } while (--argc) { char *p = *++argv; if (*p == '-') { int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), 1, &cfg); if (ret == -2) { fprintf(stderr, "plink: option \"%s\" requires an argument\n", p); errors = 1; } else if (ret == 2) { --argc, ++argv; } else if (ret == 1) { continue; } else if (!strcmp(p, "-batch")) { console_batch_mode = 1; } else if (!strcmp(p, "-s")) { /* Save status to write to cfg later. */ use_subsystem = 1; } else if (!strcmp(p, "-V")) { version(); } else { fprintf(stderr, "plink: unknown option \"%s\"\n", p); errors = 1; } } else if (*p) { if (!*cfg.host) { char *q = p; /* * If the hostname starts with "telnet:", set the * protocol to Telnet and process the string as a * Telnet URL. */ if (!strncmp(q, "telnet:", 7)) { char c; q += 7; if (q[0] == '/' && q[1] == '/') q += 2; cfg.protocol = PROT_TELNET; p = q; while (*p && *p != ':' && *p != '/') p++; c = *p; if (*p) *p++ = '\0'; if (c == ':') cfg.port = atoi(p); else cfg.port = -1; strncpy(cfg.host, q, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; } else { char *r, *user, *host; /* * Before we process the [user@]host string, we * first check for the presence of a protocol * prefix (a protocol name followed by ","). */ r = strchr(p, ','); if (r) { int i, j; for (i = 0; backends[i].backend != NULL; i++) { j = strlen(backends[i].name); if (j == r - p && !memcmp(backends[i].name, p, j)) { statics()->default_protocol = cfg.protocol = backends[i].protocol; portnumber = backends[i].backend->default_port; p = r + 1; break; } } } /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -