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