]> asedeno.scripts.mit.edu Git - PuTTY_svn.git/blob - unix/uxputty.c
Having created and used uxsel, it actually turns out to be
[PuTTY_svn.git] / unix / uxputty.c
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  */
20 void 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 }
30 void 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 }
40 void 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  */
54 void cleanup_exit(int code)
55 {
56     /*
57      * Clean up.
58      */
59     sk_cleanup();
60     random_save_seed();
61     exit(code);
62 }
63
64 void 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  */
145 void 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
180 void 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
204 char *cp_name(int codepage)
205 {
206     return "";
207 }
208 char *cp_enumerate(int index)
209 {
210     return NULL;
211 }
212 int decode_codepage(char *cp_name)
213 {
214     return -2;
215 }
216
217 printer_enum *printer_start_enum(int *nprinters_ptr) {
218     *nprinters_ptr = 0;
219     return NULL;
220 }
221 char *printer_get_name(printer_enum *pe, int i) { return NULL;
222 }
223 void printer_finish_enum(printer_enum *pe) { }
224
225 Backend *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
238 int 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
244 int 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 }