Having created and used uxsel, it actually turns out to be
[sgt/putty] / unix / uxputty.c
CommitLineData
1d009ae7 1/*
2 * Unix PuTTY main program.
3 */
4
5#include <stdio.h>
6#include <assert.h>
7#include <termios.h>
8#include <unistd.h>
9
10#include "putty.h"
11#include "storage.h"
12
13/*
14 * FIXME: At least some of these functions should be replaced with
15 * GTK GUI error-box-type things.
16 *
17 * In particular, all the termios-type things must go, and
18 * termios.h should disappear from the above #include list.
19 */
20void fatalbox(char *p, ...)
21{
22 va_list ap;
23 fprintf(stderr, "FATAL ERROR: ");
24 va_start(ap, p);
25 vfprintf(stderr, p, ap);
26 va_end(ap);
27 fputc('\n', stderr);
28 cleanup_exit(1);
29}
30void connection_fatal(void *frontend, char *p, ...)
31{
32 va_list ap;
33 fprintf(stderr, "FATAL ERROR: ");
34 va_start(ap, p);
35 vfprintf(stderr, p, ap);
36 va_end(ap);
37 fputc('\n', stderr);
38 cleanup_exit(1);
39}
40void cmdline_error(char *p, ...)
41{
42 va_list ap;
43 fprintf(stderr, "plink: ");
44 va_start(ap, p);
45 vfprintf(stderr, p, ap);
46 va_end(ap);
47 fputc('\n', stderr);
48 exit(1);
49}
50
51/*
52 * Clean up and exit.
53 */
54void cleanup_exit(int code)
55{
56 /*
57 * Clean up.
58 */
59 sk_cleanup();
60 random_save_seed();
61 exit(code);
62}
63
64void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
65 char *keystr, char *fingerprint)
66{
67 int ret;
68
69 static const char absentmsg[] =
70 "The server's host key is not cached. You have no guarantee\n"
71 "that the server is the computer you think it is.\n"
72 "The server's key fingerprint is:\n"
73 "%s\n"
74 "If you trust this host, enter \"y\" to add the key to\n"
75 "PuTTY's cache and carry on connecting.\n"
76 "If you want to carry on connecting just once, without\n"
77 "adding the key to the cache, enter \"n\".\n"
78 "If you do not trust this host, press Return to abandon the\n"
79 "connection.\n"
80 "Store key in cache? (y/n) ";
81
82 static const char wrongmsg[] =
83 "WARNING - POTENTIAL SECURITY BREACH!\n"
84 "The server's host key does not match the one PuTTY has\n"
85 "cached. This means that either the server administrator\n"
86 "has changed the host key, or you have actually connected\n"
87 "to another computer pretending to be the server.\n"
88 "The new key fingerprint is:\n"
89 "%s\n"
90 "If you were expecting this change and trust the new key,\n"
91 "enter \"y\" to update PuTTY's cache and continue connecting.\n"
92 "If you want to carry on connecting but without updating\n"
93 "the cache, enter \"n\".\n"
94 "If you want to abandon the connection completely, press\n"
95 "Return to cancel. Pressing Return is the ONLY guaranteed\n"
96 "safe choice.\n"
97 "Update cached key? (y/n, Return cancels connection) ";
98
99 static const char abandoned[] = "Connection abandoned.\n";
100
101 char line[32];
102
103 /*
104 * Verify the key.
105 */
106 ret = verify_host_key(host, port, keytype, keystr);
107
108 if (ret == 0) /* success - key matched OK */
109 return;
110
111 if (ret == 2) { /* key was different */
112 fprintf(stderr, wrongmsg, fingerprint);
113 fflush(stderr);
114 }
115 if (ret == 1) { /* key was absent */
116 fprintf(stderr, absentmsg, fingerprint);
117 fflush(stderr);
118 }
119
120 {
121 struct termios oldmode, newmode;
122 tcgetattr(0, &oldmode);
123 newmode = oldmode;
124 newmode.c_lflag |= ECHO | ISIG | ICANON;
125 tcsetattr(0, TCSANOW, &newmode);
126 line[0] = '\0';
127 read(0, line, sizeof(line) - 1);
128 tcsetattr(0, TCSANOW, &oldmode);
129 }
130
131 if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
132 if (line[0] == 'y' || line[0] == 'Y')
133 store_host_key(host, port, keytype, keystr);
134 } else {
135 fprintf(stderr, abandoned);
136 cleanup_exit(0);
137 }
138}
139
140/*
141 * Ask whether the selected cipher is acceptable (since it was
142 * below the configured 'warn' threshold).
143 * cs: 0 = both ways, 1 = client->server, 2 = server->client
144 */
145void askcipher(void *frontend, char *ciphername, int cs)
146{
147 static const char msg[] =
148 "The first %scipher supported by the server is\n"
149 "%s, which is below the configured warning threshold.\n"
150 "Continue with connection? (y/n) ";
151 static const char abandoned[] = "Connection abandoned.\n";
152
153 char line[32];
154
155 fprintf(stderr, msg,
156 (cs == 0) ? "" :
157 (cs == 1) ? "client-to-server " : "server-to-client ",
158 ciphername);
159 fflush(stderr);
160
161 {
162 struct termios oldmode, newmode;
163 tcgetattr(0, &oldmode);
164 newmode = oldmode;
165 newmode.c_lflag |= ECHO | ISIG | ICANON;
166 tcsetattr(0, TCSANOW, &newmode);
167 line[0] = '\0';
168 read(0, line, sizeof(line) - 1);
169 tcsetattr(0, TCSANOW, &oldmode);
170 }
171
172 if (line[0] == 'y' || line[0] == 'Y') {
173 return;
174 } else {
175 fprintf(stderr, abandoned);
176 cleanup_exit(0);
177 }
178}
179
180void old_keyfile_warning(void)
181{
182 static const char message[] =
183 "You are loading an SSH 2 private key which has an\n"
184 "old version of the file format. This means your key\n"
185 "file is not fully tamperproof. Future versions of\n"
186 "PuTTY may stop supporting this private key format,\n"
187 "so we recommend you convert your key to the new\n"
188 "format.\n"
189 "\n"
190 "Once the key is loaded into PuTTYgen, you can perform\n"
191 "this conversion simply by saving it again.\n";
192
193 fputs(message, stderr);
194}
195
196/*
197 * Another bunch of temporary stub functions. These ones will want
198 * removing by means of implementing them properly: libcharset
199 * should invent its own sensible format for codepage names and a
200 * means of enumerating them, and printer_enum needs to be dealt
201 * with somehow or other too.
202 */
203
204char *cp_name(int codepage)
205{
206 return "";
207}
208char *cp_enumerate(int index)
209{
210 return NULL;
211}
212int decode_codepage(char *cp_name)
213{
214 return -2;
215}
216
217printer_enum *printer_start_enum(int *nprinters_ptr) {
218 *nprinters_ptr = 0;
219 return NULL;
220}
221char *printer_get_name(printer_enum *pe, int i) { return NULL;
222}
223void printer_finish_enum(printer_enum *pe) { }
224
225Backend *select_backend(Config *cfg)
226{
227 int i;
228 Backend *back = NULL;
229 for (i = 0; backends[i].backend != NULL; i++)
230 if (backends[i].protocol == cfg->protocol) {
231 back = backends[i].backend;
232 break;
233 }
234 assert(back != NULL);
235 return back;
236}
237
238int cfgbox(Config *cfg)
239{
240 extern int do_config_box(const char *title, Config *cfg);
241 return do_config_box("PuTTY Configuration", cfg);
242}
243
244int main(int argc, char **argv)
245{
246 extern int pt_main(int argc, char **argv);
247 sk_init();
248 flags = FLAG_VERBOSE | FLAG_INTERACTIVE;
249 default_protocol = be_default_protocol;
250 /* Find the appropriate default port. */
251 {
252 int i;
253 default_port = 0; /* illegal */
254 for (i = 0; backends[i].backend != NULL; i++)
255 if (backends[i].protocol == default_protocol) {
256 default_port = backends[i].backend->default_port;
257 break;
258 }
259 }
260 return pt_main(argc, argv);
261}