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
187
188
189
190
191
192
193 static void
194 sftpfs_fill_config_entity_from_string (sftpfs_ssh_config_entity_t *config_entity, char *buffer)
195 {
196 int i;
197
198 for (i = 0; config_variables[i].pattern != NULL; i++)
199 {
200 if (mc_search_run (config_variables[i].pattern_regexp, buffer, 0, strlen (buffer), NULL))
201 {
202 int value_offset;
203 char *value;
204
205
206 value_offset = mc_search_getstart_result_by_num (config_variables[i].pattern_regexp, 1);
207 value = &buffer[value_offset];
208
209 switch (config_variables[i].type)
210 {
211 case STRING:
212 G_STRUCT_MEMBER (char *, config_entity, config_variables[i].offset) =
213 g_strdup (value);
214 break;
215 case FILENAME:
216 G_STRUCT_MEMBER (char *, config_entity, config_variables[i].offset) =
217 sftpfs_correct_file_name (value);
218 break;
219 case INTEGER:
220 G_STRUCT_MEMBER (int, config_entity, config_variables[i].offset) = atoi (value);
221 break;
222 case BOOLEAN:
223 G_STRUCT_MEMBER (gboolean, config_entity, config_variables[i].offset) =
224 strcasecmp (value, "True") == 0;
225 break;
226 default:
227 continue;
228 }
229 return;
230 }
231 }
232 }
233
234
235
236
237
238
239
240
241
242
243
244
245 static gboolean
246 sftpfs_fill_config_entity_from_config (FILE *ssh_config_handler,
247 sftpfs_ssh_config_entity_t *config_entity,
248 const vfs_path_element_t *vpath_element, GError **mcerror)
249 {
250 char buffer[BUF_MEDIUM];
251 gboolean host_block_hit = FALSE;
252 gboolean pattern_block_hit = FALSE;
253 mc_search_t *host_regexp;
254 gboolean ok = TRUE;
255
256 mc_return_val_if_error (mcerror, FALSE);
257
258 host_regexp = mc_search_new ("^\\s*host\\s+(.*)$", NULL);
259 host_regexp->search_type = MC_SEARCH_T_REGEX;
260 host_regexp->is_case_sensitive = FALSE;
261
262 while (TRUE)
263 {
264 char *cr;
265
266 if (fgets (buffer, sizeof (buffer), ssh_config_handler) == NULL)
267 {
268 int e;
269
270 e = errno;
271
272 if (!feof (ssh_config_handler))
273 {
274 mc_propagate_error (mcerror, e, _ ("sftp: an error occurred while reading %s: %s"),
275 SFTPFS_SSH_CONFIG, strerror (e));
276 ok = FALSE;
277 goto done;
278 }
279
280 break;
281 }
282
283 cr = strrchr (buffer, '\n');
284 if (cr != NULL)
285 *cr = '\0';
286
287 if (mc_search_run (host_regexp, buffer, 0, strlen (buffer), NULL))
288 {
289 const char *host_pattern;
290 int host_pattern_offset;
291
292
293 if (host_block_hit)
294 goto done;
295
296 host_pattern_offset = mc_search_getstart_result_by_num (host_regexp, 1);
297 host_pattern = &buffer[host_pattern_offset];
298 if (strcmp (host_pattern, vpath_element->host) == 0)
299 {
300
301 host_block_hit = TRUE;
302 }
303 else
304 {
305 mc_search_t *pattern_regexp;
306
307 pattern_regexp = mc_search_new (host_pattern, NULL);
308 pattern_regexp->search_type = MC_SEARCH_T_GLOB;
309 pattern_regexp->is_case_sensitive = FALSE;
310 pattern_regexp->is_entire_line = TRUE;
311 pattern_block_hit = mc_search_run (pattern_regexp, vpath_element->host, 0,
312 strlen (vpath_element->host), NULL);
313 mc_search_free (pattern_regexp);
314 }
315 }
316 else if (pattern_block_hit || host_block_hit)
317 {
318 sftpfs_fill_config_entity_from_string (config_entity, buffer);
319 }
320 }
321
322 done:
323 mc_search_free (host_regexp);
324 return ok;
325 }
326
327
328
329
330
331
332
333
334
335
336 static sftpfs_ssh_config_entity_t *
337 sftpfs_get_config_entity (const vfs_path_element_t *vpath_element, GError **mcerror)
338 {
339 sftpfs_ssh_config_entity_t *config_entity;
340 FILE *ssh_config_handler;
341 char *config_filename;
342
343 mc_return_val_if_error (mcerror, FALSE);
344
345 config_entity = g_new0 (sftpfs_ssh_config_entity_t, 1);
346 config_entity->password_auth = TRUE;
347 config_entity->identities_only = FALSE;
348 config_entity->pubkey_auth = TRUE;
349 config_entity->port = SFTP_DEFAULT_PORT;
350
351 config_filename = sftpfs_correct_file_name (SFTPFS_SSH_CONFIG);
352 ssh_config_handler = fopen (config_filename, "r");
353 g_free (config_filename);
354
355 if (ssh_config_handler != NULL)
356 {
357 gboolean ok;
358
359 ok = sftpfs_fill_config_entity_from_config (ssh_config_handler, config_entity,
360 vpath_element, mcerror);
361 fclose (ssh_config_handler);
362
363 if (!ok)
364 {
365 sftpfs_ssh_config_entity_free (config_entity);
366 return NULL;
367 }
368 }
369
370 if (config_entity->user == NULL)
371 {
372 config_entity->user = vfs_get_local_username ();
373 if (config_entity->user == NULL)
374 {
375 sftpfs_ssh_config_entity_free (config_entity);
376 config_entity = NULL;
377 mc_propagate_error (mcerror, EPERM, "%s", _ ("sftp: Unable to get current user name."));
378 }
379 }
380 return config_entity;
381 }
382
383
384
385
386
387
388
389
390
391
392
393 void
394 sftpfs_fill_connection_data_from_config (struct vfs_s_super *super, GError **mcerror)
395 {
396 sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
397 sftpfs_ssh_config_entity_t *config_entity;
398
399 mc_return_if_error (mcerror);
400
401 config_entity = sftpfs_get_config_entity (super->path_element, mcerror);
402 if (config_entity == NULL)
403 return;
404
405 sftpfs_super->config_auth_type = (config_entity->pubkey_auth) ? PUBKEY : 0;
406 sftpfs_super->config_auth_type |= (config_entity->identities_only) ? 0 : AGENT;
407 sftpfs_super->config_auth_type |= (config_entity->password_auth) ? PASSWORD : 0;
408
409 if (super->path_element->port == 0)
410 super->path_element->port = config_entity->port;
411
412 if (super->path_element->user == NULL)
413 super->path_element->user = g_strdup (config_entity->user);
414
415 if (config_entity->real_host != NULL)
416 {
417 char *tmp_str = super->path_element->host;
418
419 super->path_element->host =
420 sftpsfs_expand_hostname (super->path_element->host, config_entity->real_host);
421
422 g_free (tmp_str);
423 }
424
425 if (config_entity->identity_file != NULL)
426 {
427 sftpfs_super->privkey = g_strdup (config_entity->identity_file);
428 sftpfs_super->pubkey = g_strdup_printf ("%s.pub", config_entity->identity_file);
429 }
430
431 sftpfs_ssh_config_entity_free (config_entity);
432 }
433
434
435
436
437
438
439 void
440 sftpfs_init_config_variables_patterns (void)
441 {
442 int i;
443
444 for (i = 0; config_variables[i].pattern != NULL; i++)
445 {
446 config_variables[i].pattern_regexp = mc_search_new (config_variables[i].pattern, NULL);
447 config_variables[i].pattern_regexp->search_type = MC_SEARCH_T_REGEX;
448 config_variables[i].pattern_regexp->is_case_sensitive = FALSE;
449 }
450 }
451
452
453
454
455
456
457 void
458 sftpfs_deinit_config_variables_patterns (void)
459 {
460 int i;
461
462 for (i = 0; config_variables[i].pattern != NULL; i++)
463 {
464 mc_search_free (config_variables[i].pattern_regexp);
465 config_variables[i].pattern_regexp = NULL;
466 }
467 }
468
469