This source file includes following definitions.
- sftpfs_ssh_config_entity_free
- sftpfs_correct_file_name
- sftpsfs_expand_hostname
- sftpfs_fill_config_entity_from_string
- sftpfs_fill_config_entity_from_config
- sftpfs_get_config_entity
- sftpfs_fill_connection_data_from_config
- sftpfs_init_config_variables_patterns
- sftpfs_deinit_config_variables_patterns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 #include <config.h>
28 #include <errno.h>
29 #include <stddef.h>
30 #include <stdlib.h>
31
32 #include "lib/global.h"
33
34 #include "lib/search.h"
35 #include "lib/util.h"
36 #include "lib/vfs/utilvfs.h"
37
38 #include "internal.h"
39
40
41
42
43
44 #define SFTP_DEFAULT_PORT 22
45
46 #ifndef SFTPFS_SSH_CONFIG
47 #define SFTPFS_SSH_CONFIG "~/.ssh/config"
48 #endif
49
50
51
52 typedef struct
53 {
54 char *real_host;
55 int port;
56 char *user;
57 gboolean password_auth;
58 gboolean identities_only;
59 gboolean pubkey_auth;
60 char *identity_file;
61
62 } sftpfs_ssh_config_entity_t;
63
64 enum config_var_type
65 {
66 STRING,
67 INTEGER,
68 BOOLEAN,
69 FILENAME
70 };
71
72
73
74
75
76 static struct
77 {
78 const char *pattern;
79 mc_search_t *pattern_regexp;
80 enum config_var_type type;
81 size_t offset;
82 } config_variables[] = {
83 {
84 "^\\s*User\\s+(.*)$",
85 NULL,
86 STRING,
87 offsetof (sftpfs_ssh_config_entity_t, user),
88 },
89 {
90 "^\\s*HostName\\s+(.*)$",
91 NULL,
92 STRING,
93 offsetof (sftpfs_ssh_config_entity_t, real_host),
94 },
95 {
96 "^\\s*IdentitiesOnly\\s+(.*)$",
97 NULL,
98 BOOLEAN,
99 offsetof (sftpfs_ssh_config_entity_t, identities_only),
100 },
101 {
102 "^\\s*IdentityFile\\s+(.*)$",
103 NULL,
104 FILENAME,
105 offsetof (sftpfs_ssh_config_entity_t, identity_file),
106 },
107 {
108 "^\\s*Port\\s+(.*)$",
109 NULL,
110 INTEGER,
111 offsetof (sftpfs_ssh_config_entity_t, port),
112 },
113 {
114 "^\\s*PasswordAuthentication\\s+(.*)$",
115 NULL,
116 BOOLEAN,
117 offsetof (sftpfs_ssh_config_entity_t, password_auth),
118 },
119 {
120 "^\\s*PubkeyAuthentication\\s+(.*)$",
121 NULL,
122 STRING,
123 offsetof (sftpfs_ssh_config_entity_t, pubkey_auth),
124 },
125 { NULL, NULL, 0, 0 },
126 };
127
128
129
130
131
132
133
134
135
136
137 static void
138 sftpfs_ssh_config_entity_free (sftpfs_ssh_config_entity_t *config_entity)
139 {
140 g_free (config_entity->real_host);
141 g_free (config_entity->user);
142 g_free (config_entity->identity_file);
143 g_free (config_entity);
144 }
145
146
147
148
149
150
151
152
153
154 static char *
155 sftpfs_correct_file_name (const char *filename)
156 {
157 vfs_path_t *vpath;
158 char *fn;
159
160 fn = tilde_expand (filename);
161 vpath = vfs_path_from_str (fn);
162 g_free (fn);
163 return vfs_path_free (vpath, FALSE);
164 }
165
166
167
168
169
170
171
172
173
174
175 static char *
176 sftpsfs_expand_hostname (const char *host, const char *real_host)
177 {
178 if (g_str_has_prefix (real_host, "%h"))
179 return g_strconcat (host, real_host + 2, (char *) NULL);
180
181 return g_strdup (real_host);
182 }
183
184
185
186 #define POINTER_TO_STRUCTURE_MEMBER(type) \
187 ((type) ((char *) config_entity + (size_t) config_variables[i].offset))
188
189
190
191
192
193
194
195
196 static void
197 sftpfs_fill_config_entity_from_string (sftpfs_ssh_config_entity_t *config_entity, char *buffer)
198 {
199 int i;
200
201 for (i = 0; config_variables[i].pattern != NULL; i++)
202 {
203 if (mc_search_run (config_variables[i].pattern_regexp, buffer, 0, strlen (buffer), NULL))
204 {
205 int value_offset;
206 char *value;
207
208 int *pointer_int;
209 char **pointer_str;
210 gboolean *pointer_bool;
211
212
213 value_offset = mc_search_getstart_result_by_num (config_variables[i].pattern_regexp, 1);
214 value = &buffer[value_offset];
215
216 switch (config_variables[i].type)
217 {
218 case STRING:
219 pointer_str = POINTER_TO_STRUCTURE_MEMBER (char **);
220 *pointer_str = g_strdup (value);
221 break;
222 case FILENAME:
223 pointer_str = POINTER_TO_STRUCTURE_MEMBER (char **);
224 *pointer_str = sftpfs_correct_file_name (value);
225 break;
226 case INTEGER:
227 pointer_int = POINTER_TO_STRUCTURE_MEMBER (int *);
228 *pointer_int = atoi (value);
229 break;
230 case BOOLEAN:
231 pointer_bool = POINTER_TO_STRUCTURE_MEMBER (gboolean *);
232 *pointer_bool = strcasecmp (value, "True") == 0;
233 break;
234 default:
235 continue;
236 }
237 return;
238 }
239 }
240 }
241
242 #undef POINTER_TO_STRUCTURE_MEMBER
243
244
245
246
247
248
249
250
251
252
253
254
255 static gboolean
256 sftpfs_fill_config_entity_from_config (FILE *ssh_config_handler,
257 sftpfs_ssh_config_entity_t *config_entity,
258 const vfs_path_element_t *vpath_element, GError **mcerror)
259 {
260 char buffer[BUF_MEDIUM];
261 gboolean host_block_hit = FALSE;
262 gboolean pattern_block_hit = FALSE;
263 mc_search_t *host_regexp;
264 gboolean ok = TRUE;
265
266 mc_return_val_if_error (mcerror, FALSE);
267
268 host_regexp = mc_search_new ("^\\s*host\\s+(.*)$", DEFAULT_CHARSET);
269 host_regexp->search_type = MC_SEARCH_T_REGEX;
270 host_regexp->is_case_sensitive = FALSE;
271
272 while (TRUE)
273 {
274 char *cr;
275
276 if (fgets (buffer, sizeof (buffer), ssh_config_handler) == NULL)
277 {
278 int e;
279
280 e = errno;
281
282 if (!feof (ssh_config_handler))
283 {
284 mc_propagate_error (mcerror, e, _ ("sftp: an error occurred while reading %s: %s"),
285 SFTPFS_SSH_CONFIG, strerror (e));
286 ok = FALSE;
287 goto done;
288 }
289
290 break;
291 }
292
293 cr = strrchr (buffer, '\n');
294 if (cr != NULL)
295 *cr = '\0';
296
297 if (mc_search_run (host_regexp, buffer, 0, strlen (buffer), NULL))
298 {
299 const char *host_pattern;
300 int host_pattern_offset;
301
302
303 if (host_block_hit)
304 goto done;
305
306 host_pattern_offset = mc_search_getstart_result_by_num (host_regexp, 1);
307 host_pattern = &buffer[host_pattern_offset];
308 if (strcmp (host_pattern, vpath_element->host) == 0)
309 {
310
311 host_block_hit = TRUE;
312 }
313 else
314 {
315 mc_search_t *pattern_regexp;
316
317 pattern_regexp = mc_search_new (host_pattern, DEFAULT_CHARSET);
318 pattern_regexp->search_type = MC_SEARCH_T_GLOB;
319 pattern_regexp->is_case_sensitive = FALSE;
320 pattern_regexp->is_entire_line = TRUE;
321 pattern_block_hit = mc_search_run (pattern_regexp, vpath_element->host, 0,
322 strlen (vpath_element->host), NULL);
323 mc_search_free (pattern_regexp);
324 }
325 }
326 else if (pattern_block_hit || host_block_hit)
327 {
328 sftpfs_fill_config_entity_from_string (config_entity, buffer);
329 }
330 }
331
332 done:
333 mc_search_free (host_regexp);
334 return ok;
335 }
336
337
338
339
340
341
342
343
344
345
346 static sftpfs_ssh_config_entity_t *
347 sftpfs_get_config_entity (const vfs_path_element_t *vpath_element, GError **mcerror)
348 {
349 sftpfs_ssh_config_entity_t *config_entity;
350 FILE *ssh_config_handler;
351 char *config_filename;
352
353 mc_return_val_if_error (mcerror, FALSE);
354
355 config_entity = g_new0 (sftpfs_ssh_config_entity_t, 1);
356 config_entity->password_auth = TRUE;
357 config_entity->identities_only = FALSE;
358 config_entity->pubkey_auth = TRUE;
359 config_entity->port = SFTP_DEFAULT_PORT;
360
361 config_filename = sftpfs_correct_file_name (SFTPFS_SSH_CONFIG);
362 ssh_config_handler = fopen (config_filename, "r");
363 g_free (config_filename);
364
365 if (ssh_config_handler != NULL)
366 {
367 gboolean ok;
368
369 ok = sftpfs_fill_config_entity_from_config (ssh_config_handler, config_entity,
370 vpath_element, mcerror);
371 fclose (ssh_config_handler);
372
373 if (!ok)
374 {
375 sftpfs_ssh_config_entity_free (config_entity);
376 return NULL;
377 }
378 }
379
380 if (config_entity->user == NULL)
381 {
382 config_entity->user = vfs_get_local_username ();
383 if (config_entity->user == NULL)
384 {
385 sftpfs_ssh_config_entity_free (config_entity);
386 config_entity = NULL;
387 mc_propagate_error (mcerror, EPERM, "%s", _ ("sftp: Unable to get current user name."));
388 }
389 }
390 return config_entity;
391 }
392
393
394
395
396
397
398
399
400
401
402
403 void
404 sftpfs_fill_connection_data_from_config (struct vfs_s_super *super, GError **mcerror)
405 {
406 sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
407 sftpfs_ssh_config_entity_t *config_entity;
408
409 mc_return_if_error (mcerror);
410
411 config_entity = sftpfs_get_config_entity (super->path_element, mcerror);
412 if (config_entity == NULL)
413 return;
414
415 sftpfs_super->config_auth_type = (config_entity->pubkey_auth) ? PUBKEY : 0;
416 sftpfs_super->config_auth_type |= (config_entity->identities_only) ? 0 : AGENT;
417 sftpfs_super->config_auth_type |= (config_entity->password_auth) ? PASSWORD : 0;
418
419 if (super->path_element->port == 0)
420 super->path_element->port = config_entity->port;
421
422 if (super->path_element->user == NULL)
423 super->path_element->user = g_strdup (config_entity->user);
424
425 if (config_entity->real_host != NULL)
426 {
427 char *tmp_str = super->path_element->host;
428
429 super->path_element->host =
430 sftpsfs_expand_hostname (super->path_element->host, config_entity->real_host);
431
432 g_free (tmp_str);
433 }
434
435 if (config_entity->identity_file != NULL)
436 {
437 sftpfs_super->privkey = g_strdup (config_entity->identity_file);
438 sftpfs_super->pubkey = g_strdup_printf ("%s.pub", config_entity->identity_file);
439 }
440
441 sftpfs_ssh_config_entity_free (config_entity);
442 }
443
444
445
446
447
448
449 void
450 sftpfs_init_config_variables_patterns (void)
451 {
452 int i;
453
454 for (i = 0; config_variables[i].pattern != NULL; i++)
455 {
456 config_variables[i].pattern_regexp =
457 mc_search_new (config_variables[i].pattern, DEFAULT_CHARSET);
458 config_variables[i].pattern_regexp->search_type = MC_SEARCH_T_REGEX;
459 config_variables[i].pattern_regexp->is_case_sensitive = FALSE;
460 }
461 }
462
463
464
465
466
467
468 void
469 sftpfs_deinit_config_variables_patterns (void)
470 {
471 int i;
472
473 for (i = 0; config_variables[i].pattern != NULL; i++)
474 {
475 mc_search_free (config_variables[i].pattern_regexp);
476 config_variables[i].pattern_regexp = NULL;
477 }
478 }
479
480