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