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