From 1d009ae71b849a95c86c3117d1b8f063fda8aae5 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 29 Mar 2003 19:52:50 +0000 Subject: [PATCH] Having created and used uxsel, it actually turns out to be practically trivial to put all the pieces together and create a working prototype of Unix PuTTY! It's missing a lot of things - notably GUI request boxes for host keys and logfiles and so forth, the Event Log, mid-session reconfiguration, session loading and saving, sensible population of the character sets drop-down list and probably other fiddly little things too - but it will put up a config box and then create a GUI window containing an SSH connection to the host you specified, so it's _basically_ there. Woo! git-svn-id: svn://svn.tartarus.org/sgt/putty@3020 cda61777-01e9-0310-a592-d414129be87e --- Recipe | 7 ++ unix/gtkdlg.c | 24 +++--- unix/pterm.c | 23 +++-- unix/ptermm.c | 27 ++++++ unix/pty.c | 1 + unix/uxputty.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 322 insertions(+), 21 deletions(-) create mode 100644 unix/ptermm.c create mode 100644 unix/uxputty.c diff --git a/Recipe b/Recipe index ad04c4f8..41710dca 100644 --- a/Recipe +++ b/Recipe @@ -97,6 +97,9 @@ GUITERM = window windlg winctrls terminal sizetip wcwidth unicode ldiscucs + logging printing winutils dialog config wincfg tree234 +# Config box on Unix. +UXCFG = config uxcfg dialog gtkdlg gtkcols gtkpanel + # Non-SSH back ends (putty, puttytel, plink). NONSSH = telnet raw rlogin ldisc @@ -151,6 +154,10 @@ puttygen : [G] puttygen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version pterm : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs + logging uxprint settings pty uxsel be_none uxstore signal CHARSET + + ptermm +putty : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs + + logging uxprint settings pty uxsel be_all uxstore signal CHARSET + + uxputty NONSSH UXSSH UXMISC logging ux_x11 UXCFG plink : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC signal ux_x11 diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 4afabde1..328e1d35 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -716,7 +716,7 @@ void dlg_end(void *dlg, int value) { struct dlgparam *dp = (struct dlgparam *)dlg; dp->retval = value; - gtk_main_quit(); + gtk_widget_destroy(dp->window); } void dlg_refresh(union control *ctrl, void *dlg) @@ -910,7 +910,6 @@ static int listitem_key(GtkWidget *item, GdkEventKey *event, gpointer data, event->keyval==GDK_Page_Up || event->keyval==GDK_KP_Page_Up) ? 2 : 1; int i, n; - GtkWidget *thisitem; GList *children, *chead; chead = children = gtk_container_children(GTK_CONTAINER(list)); @@ -964,13 +963,13 @@ static int listitem_key(GtkWidget *item, GdkEventKey *event, gpointer data, static int listitem_single_key(GtkWidget *item, GdkEventKey *event, gpointer data) { - listitem_key(item, event, data, FALSE); + return listitem_key(item, event, data, FALSE); } static int listitem_multi_key(GtkWidget *item, GdkEventKey *event, gpointer data) { - listitem_key(item, event, data, TRUE); + return listitem_key(item, event, data, TRUE); } static int listitem_button(GtkWidget *item, GdkEventButton *event, @@ -1043,7 +1042,7 @@ static void draglist_down(GtkButton *button, gpointer data) static void filesel_ok(GtkButton *button, gpointer data) { - struct dlgparam *dp = (struct dlgparam *)data; + /* struct dlgparam *dp = (struct dlgparam *)data; */ gpointer filesel = gtk_object_get_data(GTK_OBJECT(button), "user-data"); struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(filesel), "user-data"); char *name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel)); @@ -1052,7 +1051,7 @@ static void filesel_ok(GtkButton *button, gpointer data) static void fontsel_ok(GtkButton *button, gpointer data) { - struct dlgparam *dp = (struct dlgparam *)data; + /* struct dlgparam *dp = (struct dlgparam *)data; */ gpointer fontsel = gtk_object_get_data(GTK_OBJECT(button), "user-data"); struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(fontsel), "user-data"); char *name = gtk_font_selection_dialog_get_font_name @@ -1808,7 +1807,7 @@ int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { GtkWidget *w = dp->treeitems[i]; int vis = TRUE; - while (w && GTK_IS_TREE_ITEM(w) || GTK_IS_TREE(w)) { + while (w && (GTK_IS_TREE_ITEM(w) || GTK_IS_TREE(w))) { if (!GTK_WIDGET_VISIBLE(w)) { vis = FALSE; break; @@ -1825,7 +1824,6 @@ int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event"); if (j >= 0) { - gint return_val; gtk_signal_emit_by_name(GTK_OBJECT(dp->treeitems[j]), "toggle"); gtk_widget_grab_focus(dp->treeitems[j]); } @@ -1892,7 +1890,7 @@ void shortcut_add(struct Shortcuts *scs, GtkWidget *labelw, } } -int do_config_box(const char *title) +int do_config_box(const char *title, Config *cfg) { GtkWidget *window, *hbox, *vbox, *cols, *label, *tree, *treescroll, *panels, *panelvbox; @@ -1901,7 +1899,6 @@ int do_config_box(const char *title) char *path; GtkTreeItem *treeitemlevels[8]; GtkTree *treelevels[8]; - Config cfg; struct dlgparam dp; struct sesslist sl; struct Shortcuts scs; @@ -1909,7 +1906,7 @@ int do_config_box(const char *title) struct selparam *selparams = NULL; int nselparams = 0, selparamsize = 0; - do_defaults(NULL, &cfg); + do_defaults(NULL, cfg); dlg_init(&dp); @@ -2072,7 +2069,7 @@ int do_config_box(const char *title) dp.treeitems[index] = selparams[index].treeitem; } - dp.data = &cfg; + dp.data = cfg; dlg_refresh(NULL, &dp); dp.shortcuts = &selparams[0].shortcuts; @@ -2218,8 +2215,9 @@ char *x_get_default(const char *key) int main(int argc, char **argv) { + Config cfg; gtk_init(&argc, &argv); - printf("returned %d\n", do_config_box("PuTTY Configuration")); + printf("returned %d\n", do_config_box("PuTTY Configuration", &cfg)); return 0; } diff --git a/unix/pterm.c b/unix/pterm.c index d04b9e3d..3eafe14a 100644 --- a/unix/pterm.c +++ b/unix/pterm.c @@ -1948,6 +1948,7 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg) { int err = 0; extern char **pty_argv; /* declared in pty.c */ + extern int use_pty_argv; /* * Macros to make argument handling easier. Note that because @@ -2054,7 +2055,7 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg) cfg->colours[index][2] = col.blue / 256; } - } else if (!strcmp(p, "-e")) { + } else if (use_pty_argv && !strcmp(p, "-e")) { /* This option swallows all further arguments. */ if (!do_everything) break; @@ -2219,9 +2220,10 @@ void uxsel_input_remove(int id) { gdk_input_remove(id); } -int main(int argc, char **argv) +int pt_main(int argc, char **argv) { - extern void pty_pre_init(void); /* declared in pty.c */ + extern Backend *select_backend(Config *cfg); + extern int cfgbox(Config *cfg); struct gui_data *inst; int font_charset; @@ -2229,8 +2231,6 @@ int main(int argc, char **argv) * it */ block_signal(SIGCHLD, 1); - pty_pre_init(); - gtk_init(&argc, &argv); /* @@ -2246,6 +2246,9 @@ int main(int argc, char **argv) if (do_cmdline(argc, argv, 1, &inst->cfg)) exit(1); /* post-defaults, do everything */ + if (!cfgbox(&inst->cfg)) + exit(0); /* config box hit Cancel */ + inst->fonts[0] = gdk_font_load(inst->cfg.font.name); if (!inst->fonts[0]) { fprintf(stderr, "pterm: unable to load font \"%s\"\n", @@ -2397,9 +2400,13 @@ int main(int argc, char **argv) uxsel_init(); - inst->back = &pty_backend; - inst->back->init((void *)inst->term, &inst->backhandle, &inst->cfg, - NULL, 0, NULL, 0); + inst->back = select_backend(&inst->cfg); + { + char *realhost; /* FIXME: don't ignore this! */ + inst->back->init((void *)inst->term, &inst->backhandle, &inst->cfg, + inst->cfg.host, inst->cfg.port, &realhost, + inst->cfg.tcp_nodelay); + } inst->back->provide_logctx(inst->backhandle, inst->logctx); term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle); diff --git a/unix/ptermm.c b/unix/ptermm.c new file mode 100644 index 00000000..4765c546 --- /dev/null +++ b/unix/ptermm.c @@ -0,0 +1,27 @@ +/* + * pterm main program. + */ + +#include + +#include "putty.h" + +Backend *select_backend(Config *cfg) +{ + return &pty_backend; +} + +int cfgbox(Config *cfg) +{ + return 1; /* no-op in pterm */ +} + +int main(int argc, char **argv) +{ + extern int pt_main(int argc, char **argv); + extern void pty_pre_init(void); /* declared in pty.c */ + + pty_pre_init(); + + return pt_main(argc, argv); +} diff --git a/unix/pty.c b/unix/pty.c index eed8ecf7..1c9763a0 100644 --- a/unix/pty.c +++ b/unix/pty.c @@ -84,6 +84,7 @@ static int pty_exit_code; static struct utmp utmp_entry; #endif char **pty_argv; +int use_pty_argv = TRUE; static void pty_close(void); diff --git a/unix/uxputty.c b/unix/uxputty.c new file mode 100644 index 00000000..e6856086 --- /dev/null +++ b/unix/uxputty.c @@ -0,0 +1,261 @@ +/* + * Unix PuTTY main program. + */ + +#include +#include +#include +#include + +#include "putty.h" +#include "storage.h" + +/* + * FIXME: At least some of these functions should be replaced with + * GTK GUI error-box-type things. + * + * In particular, all the termios-type things must go, and + * termios.h should disappear from the above #include list. + */ +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 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); +} + +/* + * Clean up and exit. + */ +void cleanup_exit(int code) +{ + /* + * Clean up. + */ + sk_cleanup(); + random_save_seed(); + exit(code); +} + +void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, + char *keystr, char *fingerprint) +{ + int ret; + + static const char absentmsg[] = + "The server's host key is not cached. You have no guarantee\n" + "that the server is the computer you think it is.\n" + "The server's key fingerprint is:\n" + "%s\n" + "If you trust this host, enter \"y\" to add the key to\n" + "PuTTY's cache and carry on connecting.\n" + "If you want to carry on connecting just once, without\n" + "adding the key to the cache, enter \"n\".\n" + "If you do not trust this host, press Return to abandon the\n" + "connection.\n" + "Store key in cache? (y/n) "; + + static const char wrongmsg[] = + "WARNING - POTENTIAL SECURITY BREACH!\n" + "The server's host key does not match the one PuTTY has\n" + "cached. This means that either the server administrator\n" + "has changed the host key, or you have actually connected\n" + "to another computer pretending to be the server.\n" + "The new key fingerprint is:\n" + "%s\n" + "If you were expecting this change and trust the new key,\n" + "enter \"y\" to update PuTTY's cache and continue connecting.\n" + "If you want to carry on connecting but without updating\n" + "the cache, enter \"n\".\n" + "If you want to abandon the connection completely, press\n" + "Return to cancel. Pressing Return is the ONLY guaranteed\n" + "safe choice.\n" + "Update cached key? (y/n, Return cancels connection) "; + + static const char abandoned[] = "Connection abandoned.\n"; + + char line[32]; + + /* + * Verify the key. + */ + ret = verify_host_key(host, port, keytype, keystr); + + if (ret == 0) /* success - key matched OK */ + return; + + if (ret == 2) { /* key was different */ + fprintf(stderr, wrongmsg, fingerprint); + fflush(stderr); + } + if (ret == 1) { /* key was absent */ + fprintf(stderr, absentmsg, fingerprint); + fflush(stderr); + } + + { + struct termios oldmode, newmode; + tcgetattr(0, &oldmode); + newmode = oldmode; + newmode.c_lflag |= ECHO | ISIG | ICANON; + tcsetattr(0, TCSANOW, &newmode); + line[0] = '\0'; + read(0, line, sizeof(line) - 1); + tcsetattr(0, TCSANOW, &oldmode); + } + + if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') { + if (line[0] == 'y' || line[0] == 'Y') + store_host_key(host, port, keytype, keystr); + } else { + fprintf(stderr, abandoned); + cleanup_exit(0); + } +} + +/* + * Ask whether the selected cipher is acceptable (since it was + * below the configured 'warn' threshold). + * cs: 0 = both ways, 1 = client->server, 2 = server->client + */ +void askcipher(void *frontend, char *ciphername, int cs) +{ + static const char msg[] = + "The first %scipher supported by the server is\n" + "%s, which is below the configured warning threshold.\n" + "Continue with connection? (y/n) "; + static const char abandoned[] = "Connection abandoned.\n"; + + char line[32]; + + fprintf(stderr, msg, + (cs == 0) ? "" : + (cs == 1) ? "client-to-server " : "server-to-client ", + ciphername); + fflush(stderr); + + { + struct termios oldmode, newmode; + tcgetattr(0, &oldmode); + newmode = oldmode; + newmode.c_lflag |= ECHO | ISIG | ICANON; + tcsetattr(0, TCSANOW, &newmode); + line[0] = '\0'; + read(0, line, sizeof(line) - 1); + tcsetattr(0, TCSANOW, &oldmode); + } + + if (line[0] == 'y' || line[0] == 'Y') { + return; + } else { + fprintf(stderr, abandoned); + cleanup_exit(0); + } +} + +void old_keyfile_warning(void) +{ + static const char message[] = + "You are loading an SSH 2 private key which has an\n" + "old version of the file format. This means your key\n" + "file is not fully tamperproof. Future versions of\n" + "PuTTY may stop supporting this private key format,\n" + "so we recommend you convert your key to the new\n" + "format.\n" + "\n" + "Once the key is loaded into PuTTYgen, you can perform\n" + "this conversion simply by saving it again.\n"; + + fputs(message, stderr); +} + +/* + * Another bunch of temporary stub functions. These ones will want + * removing by means of implementing them properly: libcharset + * should invent its own sensible format for codepage names and a + * means of enumerating them, and printer_enum needs to be dealt + * with somehow or other too. + */ + +char *cp_name(int codepage) +{ + return ""; +} +char *cp_enumerate(int index) +{ + return NULL; +} +int decode_codepage(char *cp_name) +{ + return -2; +} + +printer_enum *printer_start_enum(int *nprinters_ptr) { + *nprinters_ptr = 0; + return NULL; +} +char *printer_get_name(printer_enum *pe, int i) { return NULL; +} +void printer_finish_enum(printer_enum *pe) { } + +Backend *select_backend(Config *cfg) +{ + int i; + Backend *back = NULL; + for (i = 0; backends[i].backend != NULL; i++) + if (backends[i].protocol == cfg->protocol) { + back = backends[i].backend; + break; + } + assert(back != NULL); + return back; +} + +int cfgbox(Config *cfg) +{ + extern int do_config_box(const char *title, Config *cfg); + return do_config_box("PuTTY Configuration", cfg); +} + +int main(int argc, char **argv) +{ + extern int pt_main(int argc, char **argv); + sk_init(); + flags = FLAG_VERBOSE | FLAG_INTERACTIVE; + default_protocol = be_default_protocol; + /* Find the appropriate default port. */ + { + int i; + default_port = 0; /* illegal */ + for (i = 0; backends[i].backend != NULL; i++) + if (backends[i].protocol == default_protocol) { + default_port = backends[i].backend->default_port; + break; + } + } + return pt_main(argc, argv); +} -- 2.11.0