1709795f |
1 | /* |
2 | * uxstore.c: Unix-specific implementation of the interface defined |
3 | * in storage.h. |
4 | */ |
5 | |
6 | #include <stdio.h> |
7 | #include <stdlib.h> |
0ac15bdc |
8 | #include <ctype.h> |
c5e438ec |
9 | #include <unistd.h> |
10 | #include <fcntl.h> |
11 | #include <sys/stat.h> |
12 | #include <sys/types.h> |
1709795f |
13 | #include "putty.h" |
14 | #include "storage.h" |
0ac15bdc |
15 | #include "tree234.h" |
1709795f |
16 | |
faec60ed |
17 | /* |
18 | * For the moment, the only existing Unix utility is pterm and that |
19 | * has no GUI configuration at all, so our write routines need do |
20 | * nothing. Eventually I suppose these will read and write an rc |
21 | * file somewhere or other. |
22 | */ |
1709795f |
23 | |
24 | void *open_settings_w(char *sessionname) |
25 | { |
26 | return NULL; |
27 | } |
28 | |
29 | void write_setting_s(void *handle, char *key, char *value) |
30 | { |
31 | } |
32 | |
33 | void write_setting_i(void *handle, char *key, int value) |
34 | { |
35 | } |
36 | |
37 | void close_settings_w(void *handle) |
38 | { |
39 | } |
40 | |
faec60ed |
41 | /* |
42 | * Reading settings, for the moment, is done by retrieving X |
43 | * resources from the X display. When we introduce disk files, I |
44 | * think what will happen is that the X resources will override |
45 | * PuTTY's inbuilt defaults, but that the disk files will then |
46 | * override those. This isn't optimal, but it's the best I can |
47 | * immediately work out. |
48 | */ |
49 | |
0ac15bdc |
50 | struct xrm_string { |
51 | char *key; |
52 | char *value; |
53 | }; |
54 | |
55 | static tree234 *xrmtree = NULL; |
56 | |
57 | int xrmcmp(void *av, void *bv) |
58 | { |
59 | struct xrm_string *a = (struct xrm_string *)av; |
60 | struct xrm_string *b = (struct xrm_string *)bv; |
61 | return strcmp(a->key, b->key); |
62 | } |
63 | |
64 | void provide_xrm_string(char *string) |
65 | { |
66 | char *p, *q; |
67 | struct xrm_string *xrms, *ret; |
68 | |
69 | p = q = strchr(string, ':'); |
70 | if (!q) { |
71 | fprintf(stderr, "pterm: expected a colon in resource string" |
72 | " \"%s\"\n", string); |
73 | return; |
74 | } |
75 | q++; |
76 | while (p > string && p[-1] != '.' && p[-1] != '*') |
77 | p--; |
78 | xrms = smalloc(sizeof(struct xrm_string)); |
79 | xrms->key = smalloc(q-p); |
80 | memcpy(xrms->key, p, q-p); |
81 | xrms->key[q-p-1] = '\0'; |
82 | while (*q && isspace(*q)) |
83 | q++; |
84 | xrms->value = dupstr(q); |
85 | |
86 | if (!xrmtree) |
87 | xrmtree = newtree234(xrmcmp); |
88 | |
89 | ret = add234(xrmtree, xrms); |
90 | if (ret) { |
91 | /* Override an existing string. */ |
92 | del234(xrmtree, ret); |
93 | add234(xrmtree, xrms); |
94 | } |
95 | } |
96 | |
97 | char *get_setting(char *key) |
98 | { |
99 | struct xrm_string tmp, *ret; |
100 | tmp.key = key; |
101 | if (xrmtree) { |
102 | ret = find234(xrmtree, &tmp, NULL); |
103 | if (ret) |
104 | return ret->value; |
105 | } |
c5e438ec |
106 | return x_get_default(key); |
0ac15bdc |
107 | } |
108 | |
1709795f |
109 | void *open_settings_r(char *sessionname) |
110 | { |
faec60ed |
111 | static int thing_to_return_an_arbitrary_non_null_pointer_to; |
c5e438ec |
112 | return &thing_to_return_an_arbitrary_non_null_pointer_to; |
1709795f |
113 | } |
114 | |
115 | char *read_setting_s(void *handle, char *key, char *buffer, int buflen) |
116 | { |
0ac15bdc |
117 | char *val = get_setting(key); |
faec60ed |
118 | if (!val) |
119 | return NULL; |
120 | else { |
121 | strncpy(buffer, val, buflen); |
122 | buffer[buflen-1] = '\0'; |
123 | return buffer; |
124 | } |
1709795f |
125 | } |
126 | |
127 | int read_setting_i(void *handle, char *key, int defvalue) |
128 | { |
0ac15bdc |
129 | char *val = get_setting(key); |
faec60ed |
130 | if (!val) |
131 | return defvalue; |
132 | else |
133 | return atoi(val); |
1709795f |
134 | } |
135 | |
136 | void close_settings_r(void *handle) |
137 | { |
138 | } |
139 | |
140 | void del_settings(char *sessionname) |
141 | { |
142 | } |
143 | |
144 | void *enum_settings_start(void) |
145 | { |
146 | return NULL; |
147 | } |
148 | |
149 | char *enum_settings_next(void *handle, char *buffer, int buflen) |
150 | { |
151 | return NULL; |
152 | } |
153 | |
154 | void enum_settings_finish(void *handle) |
155 | { |
156 | } |
157 | |
c5e438ec |
158 | enum { |
d9c40fd6 |
159 | INDEX_DIR, INDEX_HOSTKEYS, INDEX_RANDSEED |
c5e438ec |
160 | }; |
161 | |
162 | static void make_filename(char *filename, int index) |
163 | { |
164 | char *home; |
165 | int len; |
166 | home = getenv("HOME"); |
167 | strncpy(filename, home, FILENAME_MAX); |
168 | len = strlen(filename); |
169 | strncpy(filename + len, |
170 | index == INDEX_DIR ? "/.putty" : |
171 | index == INDEX_HOSTKEYS ? "/.putty/sshhostkeys" : |
d9c40fd6 |
172 | index == INDEX_RANDSEED ? "/.putty/randomseed" : |
c5e438ec |
173 | "/.putty/ERROR", FILENAME_MAX - len); |
174 | filename[FILENAME_MAX-1] = '\0'; |
175 | } |
176 | |
177 | /* |
178 | * Read an entire line of text from a file. Return a buffer |
179 | * malloced to be as big as necessary (caller must free). |
180 | */ |
181 | static char *fgetline(FILE *fp) |
182 | { |
183 | char *ret = smalloc(512); |
184 | int size = 512, len = 0; |
185 | while (fgets(ret + len, size - len, fp)) { |
186 | len += strlen(ret + len); |
187 | if (ret[len-1] == '\n') |
188 | break; /* got a newline, we're done */ |
189 | size = len + 512; |
190 | ret = srealloc(ret, size); |
191 | } |
192 | if (len == 0) { /* first fgets returned NULL */ |
193 | sfree(ret); |
194 | return NULL; |
195 | } |
196 | ret[len] = '\0'; |
197 | return ret; |
198 | } |
199 | |
200 | /* |
201 | * Lines in the host keys file are of the form |
202 | * |
203 | * type@port:hostname keydata |
204 | * |
205 | * e.g. |
206 | * |
207 | * rsa@22:foovax.example.org 0x23,0x293487364395345345....2343 |
208 | */ |
1709795f |
209 | int verify_host_key(char *hostname, int port, char *keytype, char *key) |
210 | { |
c5e438ec |
211 | FILE *fp; |
212 | char filename[FILENAME_MAX]; |
213 | char *line; |
214 | int ret; |
215 | |
216 | make_filename(filename, INDEX_HOSTKEYS); |
217 | fp = fopen(filename, "r"); |
218 | if (!fp) |
219 | return 1; /* key does not exist */ |
220 | |
221 | ret = 1; |
222 | while ( (line = fgetline(fp)) ) { |
223 | int i; |
224 | char *p = line; |
225 | char porttext[20]; |
226 | |
227 | line[strcspn(line, "\n")] = '\0'; /* strip trailing newline */ |
228 | |
229 | i = strlen(keytype); |
230 | if (strncmp(p, keytype, i)) |
231 | goto done; |
232 | p += i; |
233 | |
234 | if (*p != '@') |
235 | goto done; |
236 | p++; |
237 | |
238 | sprintf(porttext, "%d", port); |
239 | i = strlen(porttext); |
240 | if (strncmp(p, porttext, i)) |
241 | goto done; |
242 | p += i; |
243 | |
244 | if (*p != ':') |
245 | goto done; |
246 | p++; |
247 | |
248 | i = strlen(hostname); |
249 | if (strncmp(p, hostname, i)) |
250 | goto done; |
251 | p += i; |
252 | |
253 | if (*p != ' ') |
254 | goto done; |
255 | p++; |
256 | |
257 | /* |
258 | * Found the key. Now just work out whether it's the right |
259 | * one or not. |
260 | */ |
261 | if (!strcmp(p, key)) |
262 | ret = 0; /* key matched OK */ |
263 | else |
264 | ret = 2; /* key mismatch */ |
265 | |
266 | done: |
267 | sfree(line); |
268 | if (ret != 1) |
269 | break; |
270 | } |
271 | |
272 | return ret; |
1709795f |
273 | } |
274 | |
275 | void store_host_key(char *hostname, int port, char *keytype, char *key) |
276 | { |
c5e438ec |
277 | FILE *fp; |
278 | int fd; |
279 | char filename[FILENAME_MAX]; |
280 | |
281 | make_filename(filename, INDEX_HOSTKEYS); |
282 | fd = open(filename, O_CREAT | O_APPEND | O_RDWR, 0600); |
283 | if (fd < 0) { |
284 | char dir[FILENAME_MAX]; |
285 | |
286 | make_filename(dir, INDEX_DIR); |
287 | mkdir(dir, 0700); |
288 | fd = open(filename, O_CREAT | O_APPEND | O_RDWR, 0600); |
289 | } |
290 | if (fd < 0) { |
291 | perror(filename); |
292 | exit(1); |
293 | } |
294 | fp = fdopen(fd, "a"); |
295 | fprintf(fp, "%s@%d:%s %s\n", keytype, port, hostname, key); |
296 | fclose(fp); |
1709795f |
297 | } |
298 | |
299 | void read_random_seed(noise_consumer_t consumer) |
300 | { |
d9c40fd6 |
301 | int fd; |
302 | char fname[FILENAME_MAX]; |
303 | |
304 | make_filename(fname, INDEX_RANDSEED); |
305 | fd = open(fname, O_RDONLY); |
306 | if (fd) { |
307 | char buf[512]; |
308 | int ret; |
309 | while ( (ret = read(fd, buf, sizeof(buf))) > 0) |
310 | consumer(buf, ret); |
311 | close(fd); |
312 | } |
1709795f |
313 | } |
314 | |
315 | void write_random_seed(void *data, int len) |
316 | { |
d9c40fd6 |
317 | int fd; |
318 | char fname[FILENAME_MAX]; |
319 | |
320 | make_filename(fname, INDEX_RANDSEED); |
321 | fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0600); |
322 | if (fd < 0) { |
323 | char dir[FILENAME_MAX]; |
324 | |
325 | make_filename(dir, INDEX_DIR); |
326 | mkdir(dir, 0700); |
327 | fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0600); |
328 | } |
329 | |
330 | while (len > 0) { |
331 | int ret = write(fd, data, len); |
332 | if (ret <= 0) break; |
333 | len -= ret; |
334 | data = (char *)data + len; |
335 | } |
336 | |
337 | close(fd); |
1709795f |
338 | } |
339 | |
340 | void cleanup_all(void) |
341 | { |
342 | } |