1 /* pfs-sftp.c:
2 *
3 ****************************************************************
4 * Copyright (C) 2002 - 2004 Scott Parish
5 * Copyright (C) 2003 Tom Lord
6 *
7 * See the file "COPYING" for further information about
8 * the copyright and warranty status of this work.
9 */
10
11
12 #include <string.h>
13 #include <stdio.h>
14 #include <errno.h>
15 #include "config-options.h"
16 #include "hackerlab/arrays/ar.h"
17 #include "hackerlab/bugs/panic.h"
18 #include "hackerlab/machine/types.h"
19 #include "hackerlab/mem/alloc-limits.h"
20 #include "hackerlab/mem/mem.h"
21 #include "hackerlab/char/str.h"
22 #include "hackerlab/fmt/cvt.h"
23 #include "hackerlab/fs/file-names.h"
24 #include "hackerlab/os/errno-to-string.h"
25 #include "hackerlab/vu/safe.h"
26 #include "tla/libfsutils/tmp-files.h"
27 #include "tla/libfsutils/file-contents.h"
28 #include "tla/libarch/archives.h"
29 #include "tla/libarch/exec.h"
30 #include "tla/libarch/pfs-sftp.h"
31 #include "tla/libarch/pfs-sftp-version.h"
32 #include "tla/libarch/sftp.h"
33
34
35
36
37 #undef FIXME
38 /* TODO: look through ssh/tcp/ethernet specks to find an optimal size */
39 #define SFTP_RWSIZE 16384
40
41 /* PipeLine-REQuests: num r/w requests open at once for get() and put() */
42 #define MAX_PL_REQS 16
43
44 #undef MIN
45 #define MIN(A,B) ((A) < (B) ? (A) : (B))
46 #define LISTING_FILE ".listing"
47
48
49 #define WRITE_UINT4(str, ui) do { \
50 (str)[0] = (ui) >> 24; \
51 (str)[1] = (ui) >> 16; \
52 (str)[2] = (ui) >> 8; \
53 (str)[3] = (ui); } while (0)
54
55 #define WRITE_UINT8(str, ui) do { \
56 (str)[0] = (ui) >> 56; \
57 (str)[1] = (ui) >> 48; \
58 (str)[2] = (ui) >> 40; \
59 (str)[3] = (ui) >> 32; \
60 (str)[4] = (ui) >> 24; \
61 (str)[5] = (ui) >> 16; \
62 (str)[6] = (ui) >> 8; \
63 (str)[7] = (ui); } while (0)
64
65 #define READ_UINT4(str) ( \
66 ((t_uint32)(unsigned char)((str)[0]) << 24) | \
67 ((t_uint32)(unsigned char)((str)[1]) << 16) | \
68 ((t_uint32)(unsigned char)((str)[2]) << 8) | \
69 ((t_uint32)(unsigned char)((str)[3])) )
70
71 #define READ_UINT8(str) ( \
72 ((unsigned long long int)(unsigned char)((str)[0]) << 56) | \
73 ((unsigned long long int)(unsigned char)((str)[1]) << 48) | \
74 ((unsigned long long int)(unsigned char)((str)[2]) << 40) | \
75 ((unsigned long long int)(unsigned char)((str)[3]) << 32) | \
76 ((unsigned long long int)(unsigned char)((str)[4]) << 24) | \
77 ((unsigned long long int)(unsigned char)((str)[5]) << 16) | \
78 ((unsigned long long int)(unsigned char)((str)[6]) << 8) | \
79 ((unsigned long long int)(unsigned char)((str)[7])) )
80
81
82 struct arch_pfs_sftp_session
83 {
84 struct arch_pfs_session pfs;
85
86 char * cwd;
87 t_uint32 request_id;
88 t_uint32 plreqs;
89
90 int in_fd;
91 int out_fd;
92 };
93
94
95 struct sftp_attrs
96 {
97 t_uint32 flags;
98 unsigned long long int size;
99 t_uint32 uid;
100 t_uint32 gid;
101 t_uint32 perms;
102 t_uint32 atime;
103 t_uint32 mtime;
104 unsigned char *extended;
105 };
106
107
108
109
110
111
112 /* __STDC__ prototypes for static functions */
113 static int sftp_write_pkt (struct arch_pfs_sftp_session * p,
114 int soft_errors,
115 const char *fmt, ...);
116 static int sftp_export_attrs (struct sftp_attrs *a,
117 char ** pkt,
118 int * len);
119 static void sftp_client_do_init (struct arch_pfs_sftp_session * p,
120 int soft_errors);
121 static int sftp_server_response (struct arch_pfs_sftp_session * p,
122 char ** pkt,
123 int * pkt_len,
124 int expected_response,
125 int soft_errors);
126 static int sftp_decode_status (char * pkt,
127 int pkt_len,
128 int i,
129 int soft_errors);
130 static t_uchar * sftp_abs_path (const t_uchar * cwd,
131 const t_uchar *path);
132 static int sftp_get (struct arch_pfs_sftp_session * p,
133 int data_fd,
134 const t_uchar * path,
135 int soft_errors);
136 static int pfs_get_file (struct arch_pfs_session * p,
137 int out_fd,
138 const t_uchar * path,
139 int soft_errors);
140 static t_uchar * pfs_file_contents (struct arch_pfs_session * p,
141 const t_uchar * path,
142 int soft_errors);
143 static rel_table pfs_directory_files (struct arch_pfs_session * p,
144 const t_uchar * path,
145 int soft_errors);
146 static int sftp_import_attrs (struct sftp_attrs *a,
147 char * pkt,
148 unsigned int pkt_len,
149 int soft_errors);
150 static int pfs_put_file (struct arch_pfs_session *p,
151 const t_uchar * path,
152 mode_t perms,
153 int data_fd,
154 int soft_errors);
155 static int pfs_mkdir (struct arch_pfs_session * p,
156 const t_uchar * path,
157 mode_t mode,
158 int soft_errors);
159 static int pfs_file_exists (struct arch_pfs_session * p,
160 const t_uchar * path);
161 static int pfs_is_dir (struct arch_pfs_session * p,
162 const t_uchar * path);
163 static int pfs_rename (struct arch_pfs_session * p,
164 t_uchar ** errstr,
165 const t_uchar * from,
166 const t_uchar * to,
167 int soft_errors);
168 static int pfs_rmdir (struct arch_pfs_session * p,
169 const t_uchar * path,
170 int soft_errors);
171 static int pfs_rm (struct arch_pfs_session * p,
172 const t_uchar * path,
173 int soft_errors);
174 static t_uchar * dirfold (t_uchar *dir);
175
176
177
178 struct arch_pfs_vtable sftp_pfs_fns =
179 {
180 pfs_file_exists,
181 pfs_is_dir,
182
183 pfs_file_contents,
184 pfs_get_file,
185 pfs_directory_files,
186
187 pfs_put_file,
188
189 pfs_mkdir,
190 pfs_rename,
191
192 pfs_rmdir,
193 pfs_rm,
194 };
195
196
197
198
199 int
arch_pfs_sftp_supported_protocol(const t_uchar * uri)200 arch_pfs_sftp_supported_protocol (const t_uchar * uri)
201 {
202 if (!str_cmp_prefix ("sftp:", uri))
203 return 1;
204 else
205 return 0;
206 }
207
208
209 static int
sftp_write_pkt(struct arch_pfs_sftp_session * p,int soft_errors,const char * fmt,...)210 sftp_write_pkt (struct arch_pfs_sftp_session * p,
211 int soft_errors,
212 const char *fmt, ...)
213 {
214 va_list ap;
215 struct sftp_attrs *attrs;
216 char *buf;
217 int i;
218 int errn = 0;
219 unsigned int len, s_len, ret;
220 t_uint32 l;
221 unsigned long long ll;
222 char *s;
223 unsigned char c;
224
225 va_start (ap, fmt);
226
227 len = 4;
228 buf = lim_malloc (0, len);
229 i = 4;
230
231 while (*fmt)
232 switch (*fmt++)
233 {
234 case '8': /* unsigned long long */
235 ll = va_arg (ap, unsigned long long);
236 len += sizeof (ll);
237 buf = lim_realloc (0, buf, len);
238 WRITE_UINT8 (buf + i, ll);
239 i += sizeof (ll);
240 break;
241
242 case '4': /* t_uint32 */
243 l = va_arg (ap, t_uint32);
244 len += sizeof (l);
245 buf = lim_realloc (0, buf, len);
246 WRITE_UINT4 (buf + i, l);
247 i += sizeof (l);
248 break;
249
250 case '1': /* int */
251 c = va_arg (ap, int);
252 len += sizeof (c);
253 buf = lim_realloc (0, buf, len);
254 buf[i] = c;
255 i += sizeof (c);
256 break;
257
258 case 's': /* char*,size_t (IE: <int32:length> <string>) */
259 s = va_arg (ap, char *);
260 l = va_arg (ap, size_t);
261 len += sizeof (l) + l;
262 buf = lim_realloc (0, buf, len);
263 WRITE_UINT4 (buf + i, l);
264 i += sizeof (l);
265 mem_move (buf + i, s, l);
266 i += l;
267 break;
268
269 case 'a': /* struct sftp_attrs* */
270 attrs = va_arg (ap, struct sftp_attrs *);
271 sftp_export_attrs (attrs, &s, &s_len);
272 len += s_len;
273 buf = lim_realloc (0, buf, len);
274 mem_move (buf + i, s, s_len);
275 i += s_len;
276 break;
277
278 default:
279 if (!soft_errors)
280 {
281 safe_printfmt (2, "Invalid fmt to sftp_write_pkt!\n");
282 exit (2);
283 }
284 else
285 return -1;
286 }
287
288 c = va_arg (ap, int);
289
290 WRITE_UINT4 (buf, len - sizeof(len));
291 ret = vu_write_retry (&errn, p->out_fd, buf, len);
292
293 lim_free (0, buf);
294 va_end (ap);
295
296 return ret;
297 }
298
299
300
301 /* take the structure and create an sftp attr string, returns size of string */
302 static int
sftp_export_attrs(struct sftp_attrs * a,char ** pkt,int * len)303 sftp_export_attrs (struct sftp_attrs *a,
304 char ** pkt,
305 int * len)
306 {
307 int i = 0;
308
309 *len = sizeof (a->flags)
310 + (a->flags & SSH_FILEXFER_ATTR_SIZE ? sizeof (a->size) : 0)
311 + (a->flags & SSH_FILEXFER_ATTR_UIDGID ? sizeof (a->uid)*2 : 0)
312 + (a->flags & SSH_FILEXFER_ATTR_PERMISSIONS ? sizeof (a->perms) : 0)
313 + (a->flags & SSH_FILEXFER_ATTR_ACMODTIME ? sizeof (a->atime)*2 : 0);
314
315 *pkt = lim_malloc (0, *len);
316
317 WRITE_UINT4 (*pkt, a->flags);
318 i += 4;
319
320 if (a->flags & SSH_FILEXFER_ATTR_SIZE)
321 {
322 WRITE_UINT8 (*pkt + i, a->size);
323 i += 8;
324 }
325
326 if (a->flags & SSH_FILEXFER_ATTR_UIDGID)
327 {
328 WRITE_UINT4 (*pkt + i, a->uid);
329 i += 4;
330 WRITE_UINT4 (*pkt + i, a->gid);
331 i += 4;
332 }
333
334 if (a->flags & SSH_FILEXFER_ATTR_PERMISSIONS)
335 {
336 WRITE_UINT4 (*pkt + i, a->perms);
337 i += 4;
338 }
339
340 if (a->flags & SSH_FILEXFER_ATTR_ACMODTIME)
341 {
342 WRITE_UINT4 (*pkt + i, a->atime);
343 i += 4;
344 WRITE_UINT4 (*pkt + i, a->mtime);
345 i += 4;
346 }
347
348 return *len;
349 }
350
351
352
353
354
355 struct arch_pfs_session *
arch_pfs_sftp_connect(const t_uchar * uri)356 arch_pfs_sftp_connect (const t_uchar * uri)
357 {
358 struct arch_pfs_sftp_session * answer = 0;
359 t_uchar * hostname = 0;
360 t_uchar * port = 0;
361 t_uchar * user = 0;
362 t_uchar ** ssh_argv;
363 int subproc;
364 int pin[2], pout[2];
365 int c_in_fd, c_out_fd;
366 enum arch_ssh_type ssh_type = arch_pfs_sftp_ssh_type ();
367
368 answer = (struct arch_pfs_sftp_session *)lim_malloc (0, sizeof (*answer));
369 mem_set0 ((t_uchar *)answer, sizeof (*answer));
370 answer->pfs.vtable = &sftp_pfs_fns;
371
372 if (arch_pfs_sftp_parse_uri (&user, &hostname, &port, &answer->cwd, uri)!=0)
373 {
374 safe_printfmt (2, "Invalid sftp URL\n");
375 /*safe_printfmt (2, "Invalid sftp URL: %s\n", uri);
376 * can't use URI (may be mangled by arch_pfs_pfs_make_archive, etc */
377 exit (2);
378 }
379
380 ssh_argv = 0;
381 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = arch_pfs_sftp_ssh_binary (ssh_type);
382
383 if (port)
384 {
385 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-p";
386 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = port;
387 }
388
389 if (user)
390 {
391 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-l";
392 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = user;
393 }
394
395 if (ssh_type == ssh_type_lsh)
396 {
397 /* `--no-x11-forward' is the default with `lshc', so we don't need to
398 make it explicit. Furthermore, it is not supported by `lshg', so
399 we'd better not use it so that both `lshc' and `lshg' can be used
400 interchangeably. */
401
402 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "--subsystem=sftp";
403 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = hostname;
404 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = 0;
405 }
406 else if (ssh_type == ssh_type_openssh)
407 {
408 /* From OpenSSH' ssh(1), when using `-s', "The subsystem is specified
409 as the remote command". IOW, we are to perform an invokation along
410 the lines of:
411
412 $ ssh -l USER -2 -s REMOTE-HOST sftp
413
414 We assume the use of `ssh', not `sftp'. */
415
416 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-oFallBackToRsh=no";
417 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-oForwardX11=no";
418 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-oForwardAgent=no";
419 /* *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-oClearAllForwardings=yes"; */
420 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-2";
421 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-s";
422 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = hostname;
423 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "sftp";
424 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = 0;
425 }
426 else if (ssh_type == ssh_type_fsecure3)
427 {
428 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-x";
429 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-a";
430 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "-s";
431 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = "sftp";
432 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = hostname;
433 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar *)) = 0;
434 }
435 else if (ssh_type == ssh_type_psftp)
436 {
437 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar*)) = "-2";
438 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar*)) = hostname;
439 *(t_uchar **)ar_push ((void **)&ssh_argv, 0, sizeof (t_uchar*)) = 0;
440 }
441 else
442 panic ("undefined SSH implementation type");
443
444
445 if ((pipe (pin) == -1) || (pipe (pout) == -1))
446 panic ("Couldn't create pipe(s)");
447
448 answer->out_fd = pout[1];
449 answer->in_fd = pin[0];
450 c_in_fd = pout[0];
451 c_out_fd = pin[1];
452
453 subproc = fork ();
454
455 if (subproc < 0)
456 panic ("unable to fork");
457
458 if (subproc == 0)
459 {
460 if ((dup2 (c_in_fd, STDIN_FILENO) == -1) ||
461 (dup2 (c_out_fd, STDOUT_FILENO) == -1))
462 {
463 safe_printfmt (2, "dup2: %s\n", errno_to_string (errno));
464 exit (1);
465 }
466
467 close (answer->in_fd);
468 close (answer->out_fd);
469 close (c_in_fd);
470 close (c_out_fd);
471 arch_util_execvp (ssh_argv[0], ssh_argv);
472 safe_printfmt (2, "exec: %s: %s\n", ssh_argv[0], errno_to_string (errno));
473 exit (1);
474 }
475
476 close (c_in_fd);
477 close (c_out_fd);
478
479 sftp_client_do_init (answer, 0);
480 if (!pfs_file_exists((struct arch_pfs_session *)answer, answer->cwd))
481 {
482 safe_printfmt (2, "No such file or directory: %s\n", answer->cwd);
483 exit (2);
484 }
485
486 lim_free (0, hostname);
487 lim_free (0, user);
488 lim_free (0, port);
489
490 return (struct arch_pfs_session *)answer;
491 }
492
493
494
495
496 static void
sftp_client_do_init(struct arch_pfs_sftp_session * p,int soft_errors)497 sftp_client_do_init (struct arch_pfs_sftp_session * p,
498 int soft_errors)
499 {
500 int pkt_len;
501 char *pkt;
502
503 sftp_write_pkt (p, soft_errors, "14", SSH_FXP_INIT,
504 (t_uint32)SFTP_VERSION, soft_errors);
505 sftp_server_response (p, &pkt, &pkt_len, SSH_FXP_VERSION, soft_errors);
506
507 lim_free (0, pkt);
508 }
509
510
511
512
513 static int
sftp_server_response(struct arch_pfs_sftp_session * p,char ** pkt,int * pkt_len,int expected_response,int soft_errors)514 sftp_server_response (struct arch_pfs_sftp_session * p,
515 char ** pkt,
516 int * pkt_len,
517 int expected_response,
518 int soft_errors)
519 {
520 int i, errn;
521 unsigned int len, read_len, total_read, response;
522 unsigned char *pl;
523 unsigned char buf[4];
524
525 errn = 0;
526
527 read_len = vu_read_retry (&errn, p->in_fd, buf, 4);
528
529 if (read_len < 4)
530 {
531 if (!soft_errors)
532 {
533 if (errn)
534 safe_printfmt (2, "Error reading from server: %s\n", errno_to_string (errn));
535 else
536 safe_printfmt (2, "Error reading from server\n");
537 exit (2);
538 }
539 else
540 return -1;
541 }
542
543 *pkt_len = len = READ_UINT4 (buf);
544
545 *pkt = pl = lim_malloc (0, len);
546
547 total_read = 0;
548 while (len)
549 {
550 read_len = vu_read_retry (&errn, p->in_fd, pl + total_read,
551 MIN(len, BUFSIZ));
552 if (read_len <= 0 || read_len > len)
553 {
554 if (!soft_errors)
555 {
556 if (errn)
557 safe_printfmt (2, "Error reading from server: %s\n", errno_to_string (errn));
558 else
559 safe_printfmt (2, "Error reading from server.\n");
560 exit (2);
561 }
562 else
563 return -1;
564 }
565 total_read += read_len;
566 len -= read_len;
567 }
568
569 i = 0;
570 response = pl[i++];
571
572 if (response != SSH_FXP_VERSION)
573 {
574 int rq_id_offset = 0; /* request_id offset caused by pipe-lining */
575 if (p->plreqs)
576 rq_id_offset = p->plreqs - 1;
577
578 if (READ_UINT4 (pl + i) != (p->request_id - rq_id_offset))
579 {
580 if (!soft_errors)
581 {
582 lim_free (0, pl);
583 safe_printfmt (2, "Error: server returned wrong request id\n");
584 exit(2);
585 }
586 else
587 return -1;
588 }
589 i += 4;
590 }
591
592 if (response != expected_response)
593 {
594 if (response == SSH_FXP_STATUS)
595 {
596 return sftp_decode_status (pl, *pkt_len, i, soft_errors);
597 }
598
599
600 if (!soft_errors)
601 {
602 safe_printfmt (2, "Error: server returned wrong response\n");
603 exit (2);
604 }
605 else
606 lim_free (0, pl);
607 }
608
609 return i;
610 }
611
612
613
614
615 static int
sftp_decode_status(char * pkt,int pkt_len,int i,int soft_errors)616 sftp_decode_status (char * pkt,
617 int pkt_len,
618 int i,
619 int soft_errors)
620 {
621 int code, err_len;
622 const char *err_msg;
623
624 code = READ_UINT4 (pkt + i);
625 i += 4;
626
627 if (code == SSH_FX_OK || code == SSH_FX_EOF)
628 return 0;
629
630 if ( i == pkt_len )
631 {
632 switch (code)
633 {
634 case SSH_FX_NO_SUCH_FILE:
635 err_msg = "no such file or directory"; break;
636
637 case SSH_FX_PERMISSION_DENIED:
638 err_msg = "permission denied"; break;
639
640 case SSH_FX_FAILURE:
641 err_msg = "failure"; break;
642
643 case SSH_FX_BAD_MESSAGE:
644 err_msg = "bad message"; break;
645
646 case SSH_FX_NO_CONNECTION:
647 err_msg = "no connection"; break;
648
649 case SSH_FX_CONNECTION_LOST:
650 err_msg = "connection lost"; break;
651
652 case SSH_FX_OP_UNSUPPORTED:
653 err_msg = "operation not supported"; break;
654
655 default:
656 err_msg = "???"; break;
657 }
658 err_len = strlen(err_msg);
659 }
660 else if ( pkt_len - i < 4 ||
661 pkt_len - i < (err_len = READ_UINT4 (pkt + i)) + 4 )
662 {
663 if (!soft_errors)
664 {
665 safe_printfmt (2, "sftp_decode_status: Packet too short(1): possibly garbage from server?\n");
666 exit (2);
667 }
668 else
669 return -1;
670 }
671 else
672 {
673 i += 4;
674 err_msg = pkt + i;
675 }
676
677 if (!soft_errors)
678 {
679 safe_printfmt (2, "sftp status: %.*s\n", err_len, err_msg);
680 exit (2);
681 }
682 else
683 return -1;
684
685 }
686
687
688
689 static t_uchar *
sftp_abs_path(const t_uchar * cwd,const t_uchar * path)690 sftp_abs_path (const t_uchar * cwd,
691 const t_uchar *path)
692 {
693 t_uchar * ap;
694 if (path[0] != '/')
695 ap = str_alloc_cat_many (0, cwd, "/", path, str_end);
696 else
697 ap = str_save (0, path);
698
699 return dirfold (ap);
700 }
701
702
703
704 static int
sftp_get(struct arch_pfs_sftp_session * p,int data_fd,const t_uchar * path,int soft_errors)705 sftp_get (struct arch_pfs_sftp_session * p,
706 int data_fd,
707 const t_uchar * path,
708 int soft_errors)
709 {
710 struct sftp_attrs attrs;
711 unsigned int pkt_len;
712 char *pkt, *file;
713 int ret, handle_len, i;
714 unsigned long long total_read;
715 char *handle;
716 int len, errn, eof, numpkts;
717
718 file = sftp_abs_path (p->cwd, path);
719
720 attrs.flags = 0;
721 ret = sftp_write_pkt (p, soft_errors,
722 "14s4a", SSH_FXP_OPEN, ++p->request_id,
723 file, str_length (file),
724 (t_uint32)SSH_FXF_READ, &attrs);
725 lim_free (0, file);
726
727 if (0 > ret)
728 return -1;
729
730 if (0 > (i = sftp_server_response (p, &pkt, &pkt_len, SSH_FXP_HANDLE,
731 soft_errors)))
732 return -1;
733
734 handle_len = READ_UINT4 (pkt + i);
735 i += 4;
736 if (handle_len > pkt_len - i)
737 {
738 if (!soft_errors)
739 {
740 safe_printfmt(2, "sftp_client_get: Packet too short(2): did we get garbage from server?\n");
741 exit (2);
742 }
743 else
744 lim_free (0, pkt);
745 return -1;
746 }
747 handle = lim_malloc (0, handle_len);
748 mem_move (handle, pkt + i, handle_len);
749
750 lim_free (0, pkt);
751
752 total_read = 0;
753 eof = 0;
754 numpkts = 0;
755 while (1)
756 {
757 for (; ! eof && p->plreqs <= MIN(MAX_PL_REQS, numpkts + 1); p->plreqs++)
758 {
759 ret = sftp_write_pkt (p, soft_errors, "14s84", SSH_FXP_READ,
760 ++p->request_id, handle, (size_t)handle_len,
761 total_read + SFTP_RWSIZE * p->plreqs,
762 (t_uint32)SFTP_RWSIZE);
763 if (0 > ret)
764 {
765 lim_free (0, handle);
766 return -1;
767 }
768 }
769
770 if (0 > (i = sftp_server_response (p, &pkt, &pkt_len, SSH_FXP_DATA,
771 soft_errors)))
772 {
773 lim_free (0, handle);
774 return -1;
775 }
776
777 p->plreqs--;
778 numpkts++;
779
780 if (i == 0)
781 {
782 if (p->plreqs)
783 {
784 eof = 1;
785 continue;
786 }
787
788 lim_free (0, pkt);
789 break;
790 }
791
792 if (eof)
793 {
794 safe_printfmt(2, "EOF already reached, but the server sent data!\n");
795 exit(2);
796 }
797
798 len = READ_UINT4 (pkt + i);
799 i += 4;
800 if (len > pkt_len - i)
801 {
802 if (!soft_errors) {
803 safe_printfmt (2, "sftp_client_get: Packet too short(3): did we get garbage from server?\n");
804 exit (2);
805 }
806 else {
807 lim_free (0, handle);
808 lim_free (0, pkt);
809 return -1;
810 }
811 }
812
813 if (0 > vu_write_retry (&errn, data_fd, pkt + i, len))
814 {
815 if (! soft_errors) {
816 safe_printfmt(2, "Error while writing: %s\n", errno_to_string (errn));
817 exit (2);
818 }
819 else
820 return -1;
821 }
822 i += len;
823 total_read += len;
824
825 lim_free (0, pkt);
826 }
827
828 if (p->plreqs)
829 {
830 safe_printfmt (2, "sftp_client_get: Requests still in pipe-line!\n");
831 exit (2);
832 }
833
834 if (0 > sftp_write_pkt (p, soft_errors,
835 "14s", SSH_FXP_CLOSE, ++p->request_id,
836 handle, (size_t)handle_len))
837 return -1;
838
839 lim_free (0, handle);
840
841 if (0 > (i = sftp_server_response (p, &pkt, &pkt_len, SSH_FXP_STATUS,
842 soft_errors)))
843 return -1;
844
845 if (i >= 0)
846 lim_free (0, pkt);
847
848 return i;
849 }
850
851
852
853
854 static int
pfs_get_file(struct arch_pfs_session * p,int out_fd,const t_uchar * path,int soft_errors)855 pfs_get_file (struct arch_pfs_session * p,
856 int out_fd,
857 const t_uchar * path,
858 int soft_errors)
859 {
860 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
861
862 return sftp_get (pfs, out_fd, path, soft_errors);
863 }
864
865
866 static t_uchar *
pfs_file_contents(struct arch_pfs_session * p,const t_uchar * path,int soft_errors)867 pfs_file_contents (struct arch_pfs_session * p,
868 const t_uchar * path,
869 int soft_errors)
870 {
871 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
872 t_uchar * tmp_path = 0;
873 int fd;
874 t_uchar * answer = 0;
875
876 tmp_path = tmp_file_name ("/tmp", ",,pfs-sftp-file-contents");
877 fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
878 safe_unlink (tmp_path);
879
880 if (0 > sftp_get (pfs, fd, path, soft_errors))
881 {
882 safe_close(fd);
883 return 0;
884 }
885
886 safe_lseek (fd, (off_t)0, SEEK_SET);
887 answer = fd_contents (fd);
888 safe_close (fd);
889
890 return answer;
891 }
892
893
894 static rel_table
pfs_directory_files(struct arch_pfs_session * p,const t_uchar * path,int soft_errors)895 pfs_directory_files (struct arch_pfs_session * p,
896 const t_uchar * path,
897 int soft_errors)
898 {
899 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
900 struct sftp_attrs attrs;
901 rel_table answer = rel_table_nil;
902 unsigned int pkt_len, j, count;
903 char *pkt, *dir, *file;
904 int len, handle_len, dots, i;
905 char *handle;
906
907 dir = sftp_abs_path (pfs->cwd, path);
908
909 chop_slashes:
910 i = str_length (dir);
911 if (i > 1 && dir[i - 1] == '/')
912 {
913 dir[i - 1] = 0;
914 goto chop_slashes;
915 }
916
917 if (0 > sftp_write_pkt (pfs, soft_errors,
918 "14s", SSH_FXP_OPENDIR, ++pfs->request_id,
919 dir, str_length (dir)))
920 return rel_table_nil;
921 lim_free (0, dir);
922
923 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_HANDLE,
924 soft_errors)))
925 return rel_table_nil;
926
927 handle_len = READ_UINT4 (pkt + i);
928 i += 4;
929 if (handle_len > pkt_len - i)
930 {
931 if (! soft_errors) {
932 safe_printfmt(2, "sftp_client_list: Packet too short(4): did we get garbage from server?\n");
933 exit (2);
934 }
935 lim_free (0, pkt);
936 return rel_table_nil;
937 }
938 handle = lim_malloc (0, handle_len);
939 mem_move (handle, pkt + i, handle_len);
940
941 lim_free (0, pkt);
942
943 while (1)
944 {
945 if (0 >sftp_write_pkt (pfs, soft_errors,
946 "14s", SSH_FXP_READDIR, ++pfs->request_id,
947 handle, (size_t)handle_len))
948 return rel_table_nil;
949
950 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_NAME,
951 soft_errors)))
952 return rel_table_nil;
953 if (i == 0)
954 {
955 lim_free (0, pkt);
956 break;
957 }
958
959 count = READ_UINT4 (pkt + i);
960 i += 4;
961
962 for (j = 0; j < count; j++)
963 {
964 len = READ_UINT4 (pkt + i);
965 i += 4;
966 if (len > pkt_len - i)
967 {
968 if (!soft_errors)
969 {
970 safe_printfmt(2, "sftp_client_list: Packet too short(5): did we get garbage from server? (%d > %d - %d)\n", len, pkt_len, i);
971 lim_free (0, handle);
972 lim_free (0, pkt);
973 exit (2);
974 }
975 return rel_table_nil;
976 }
977
978 dots = 0;
979 if ((len == 1 && pkt[i] == '.') ||
980 (len == 2 && pkt[i] == '.' && pkt[i+1] == '.'))
981 dots = 1;
982
983 if (!dots)
984 {
985 file = str_save_n (0, pkt+i, len);
986 rel_add_records (&answer, rel_singleton_record_taking (rel_make_field_str (file)), rel_record_null);
987 }
988
989 i += len;
990
991 len = READ_UINT4 (pkt + i);
992 i += 4;
993 if (len > pkt_len - i)
994 {
995 if (! soft_errors)
996 {
997 safe_printfmt(2, "sftp_client_list: Packet too short(6): did we get garbage from server?\n");
998 lim_free (0, handle);
999 lim_free (0, pkt);
1000 exit (2);
1001 }
1002 return rel_table_nil;
1003 }
1004 i += len;
1005
1006 if (0 > (i += sftp_import_attrs (&attrs, pkt + i, pkt_len - i,
1007 soft_errors)))
1008 return rel_table_nil;
1009 }
1010
1011 lim_free (0, pkt);
1012 }
1013
1014 if (0 > sftp_write_pkt (pfs, soft_errors,
1015 "14s", SSH_FXP_CLOSE, ++pfs->request_id,
1016 handle, (size_t)handle_len))
1017 return rel_table_nil;
1018 lim_free (0, handle);
1019
1020 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_HANDLE,
1021 soft_errors)))
1022 return rel_table_nil;
1023
1024 if (i >= 0)
1025 lim_free (0, pkt);
1026
1027 return answer;
1028 }
1029
1030
1031
1032 /* take an sftp attr string and initialize a structure from it */
1033 static int
sftp_import_attrs(struct sftp_attrs * a,char * pkt,unsigned int pkt_len,int soft_errors)1034 sftp_import_attrs (struct sftp_attrs *a,
1035 char * pkt,
1036 unsigned int pkt_len,
1037 int soft_errors)
1038 {
1039 int count, i, j;
1040 unsigned int len;
1041
1042 i = 0;
1043
1044 a->flags = READ_UINT4 (pkt);
1045 i += 4;
1046
1047 len = (a->flags & SSH_FILEXFER_ATTR_SIZE ? sizeof (a->size) : 0)
1048 + (a->flags & SSH_FILEXFER_ATTR_UIDGID ? sizeof (a->uid)*2 : 0)
1049 + (a->flags & SSH_FILEXFER_ATTR_PERMISSIONS ? sizeof (a->perms) : 0)
1050 + (a->flags & SSH_FILEXFER_ATTR_ACMODTIME ? sizeof (a->atime)*2 : 0);
1051
1052 if (len > pkt_len - i)
1053 {
1054 if (!soft_errors)
1055 {
1056 safe_printfmt (2, "sftp_import_attrs: Packet too short(7): did we get garbage from server?\n");
1057 exit (2);
1058 }
1059 return -1;
1060 }
1061
1062 if (a->flags & SSH_FILEXFER_ATTR_SIZE)
1063 {
1064 a->size = READ_UINT8 (pkt + i);
1065 i += 8;
1066 }
1067
1068 if (a->flags & SSH_FILEXFER_ATTR_UIDGID)
1069 {
1070 a->uid = READ_UINT4 (pkt + i);
1071 i += 4;
1072 a->gid = READ_UINT4 (pkt + i);
1073 i += 4;
1074 }
1075
1076 if (a->flags & SSH_FILEXFER_ATTR_PERMISSIONS)
1077 {
1078 a->perms = READ_UINT4 (pkt + i);
1079 i += 4;
1080 }
1081
1082 if (a->flags & SSH_FILEXFER_ATTR_ACMODTIME)
1083 {
1084 a->atime = READ_UINT4 (pkt + i);
1085 i += 4;
1086 a->mtime = READ_UINT4 (pkt + i);
1087 i += 4;
1088 }
1089
1090 if (a->flags & SSH_FILEXFER_ATTR_EXTENDED)
1091 {
1092 count = READ_UINT4 (pkt + i);
1093 for (j = 0; j < count; j++)
1094 {
1095 i += READ_UINT4 (pkt + i);
1096 i += READ_UINT4 (pkt + i);
1097 }
1098 }
1099
1100 return i;
1101 }
1102
1103 static int
pfs_put_file(struct arch_pfs_session * p,const t_uchar * path,mode_t perms,int data_fd,int soft_errors)1104 pfs_put_file (struct arch_pfs_session *p,
1105 const t_uchar * path,
1106 mode_t perms,
1107 int data_fd,
1108 int soft_errors)
1109 {
1110 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
1111 struct sftp_attrs attrs;
1112 unsigned int pkt_len;
1113 char *pkt, *file;
1114 int ret, handle_len, i, errn;
1115 unsigned long long total_written;
1116 char *handle;
1117 char buf[SFTP_RWSIZE];
1118 int len, eof;
1119
1120 file = sftp_abs_path (pfs->cwd, path);
1121
1122 attrs.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
1123 attrs.perms = perms;
1124
1125 ret = sftp_write_pkt (pfs, soft_errors,
1126 "14s4a", SSH_FXP_OPEN, ++pfs->request_id, file,
1127 str_length (file),
1128 (t_uint32)(SSH_FXF_WRITE | SSH_FXF_CREAT |
1129 SSH_FXF_TRUNC),
1130 &attrs);
1131 lim_free (0, file);
1132
1133 if (0 > ret)
1134 return -1;
1135
1136 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_HANDLE,
1137 soft_errors)))
1138 return i;
1139
1140 handle_len = READ_UINT4 (pkt + i);
1141 i += 4;
1142 if (handle_len > pkt_len - i)
1143 {
1144 if (!soft_errors)
1145 {
1146 safe_printfmt (2, "sftp_client_put: Packet to short(8): did we get garbage from server?\n");
1147 exit (2);
1148 }
1149 lim_free (0, pkt);
1150 return -1;
1151 }
1152 handle = lim_malloc (0, handle_len);
1153 mem_move (handle, pkt + i, handle_len);
1154
1155 lim_free (0, pkt);
1156
1157 total_written = 0;
1158 eof = 0;
1159 while (1)
1160 {
1161 for (; ! eof && pfs->plreqs <= MAX_PL_REQS; pfs->plreqs++)
1162 {
1163 if (0 > (len = vu_read_retry (&errn, data_fd, buf, sizeof (buf))))
1164 {
1165 if (!soft_errors)
1166 {
1167 safe_printfmt (2, "Failed to read file to put()!\n");
1168 exit (2);
1169 }
1170 lim_free (0, handle);
1171 return -1;
1172 }
1173
1174 ret = sftp_write_pkt (pfs, soft_errors, "14s8s", SSH_FXP_WRITE,
1175 ++pfs->request_id, handle, (size_t)handle_len,
1176 total_written + pfs->plreqs * sizeof (buf),
1177 buf, (size_t)len);
1178 if (0 > ret)
1179 {
1180 lim_free (0, handle);
1181 return -1;
1182 }
1183
1184 if (len < sizeof (buf))
1185 eof = 1;
1186 }
1187
1188 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_STATUS,
1189 soft_errors)))
1190 {
1191 lim_free (0, handle);
1192 return i;
1193 }
1194
1195 i = sftp_decode_status (pkt, pkt_len, i, soft_errors);
1196 lim_free (0, pkt);
1197 if (i == -1)
1198 {
1199 lim_free (0, handle);
1200 return -1;
1201 }
1202
1203 total_written += len;
1204
1205 if (! --pfs->plreqs)
1206 break;
1207 }
1208
1209 if (pfs->plreqs)
1210 {
1211 safe_printfmt (2, "pfs_put_file: Requests still in pipe-line!\n");
1212 exit (2);
1213 }
1214
1215 ret = sftp_write_pkt (pfs, soft_errors,
1216 "14s", SSH_FXP_CLOSE, ++pfs->request_id, handle,
1217 (size_t)handle_len);
1218 lim_free (0, handle);
1219
1220 if (0 > ret)
1221 return -1;
1222
1223 i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_STATUS, soft_errors);
1224
1225 if (i >= 0)
1226 {
1227 lim_free (0, pkt);
1228 i = 0;
1229 }
1230 else
1231 i = -1;
1232
1233 return i;
1234 }
1235
1236 static int
pfs_mkdir(struct arch_pfs_session * p,const t_uchar * path,mode_t mode,int soft_errors)1237 pfs_mkdir (struct arch_pfs_session * p,
1238 const t_uchar * path,
1239 mode_t mode,
1240 int soft_errors)
1241 {
1242 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
1243 struct sftp_attrs attrs;
1244 t_uchar * dir = 0;
1245 int answer = 0;
1246 int ret, i;
1247 unsigned int pkt_len;
1248 char *pkt;
1249
1250 attrs.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
1251 attrs.perms = mode;
1252
1253 dir = sftp_abs_path (pfs->cwd, path);
1254
1255 if (pfs_file_exists (p, dir))
1256 {
1257 lim_free (0, dir);
1258
1259 if (soft_errors)
1260 {
1261 return -1;
1262 }
1263 else
1264 {
1265 safe_printfmt(2, "Error creating directory %s in path %s: File exists\n", path, pfs->cwd);
1266 exit(2);
1267 }
1268 }
1269
1270 ret = sftp_write_pkt (pfs, soft_errors,
1271 "14sa", SSH_FXP_MKDIR, ++pfs->request_id,
1272 dir, str_length (dir), &attrs);
1273 if (0 > ret)
1274 {
1275 lim_free (0, dir);
1276 return -1;
1277 }
1278
1279 lim_free (0, dir);
1280
1281 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_STATUS,
1282 soft_errors)))
1283 return -1;
1284
1285 if (0 > sftp_decode_status (pkt, pkt_len, i, 1))
1286 {
1287 if (soft_errors)
1288 {
1289 return -1;
1290 }
1291 else
1292 {
1293 safe_printfmt(2, "Error creating directory %s in path %s\n", path, pfs->cwd);
1294 safe_printfmt(2, "Server: ");
1295 sftp_decode_status(pkt, pkt_len, i, 0);
1296 }
1297 }
1298
1299 lim_free (0, pkt);
1300
1301 return answer;
1302 }
1303
1304
1305 static int
pfs_file_exists(struct arch_pfs_session * p,const t_uchar * path)1306 pfs_file_exists (struct arch_pfs_session * p,
1307 const t_uchar * path)
1308 {
1309 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
1310 struct sftp_attrs attrs;
1311 t_uchar * path_dir = 0;
1312 char *pkt;
1313 unsigned int pkt_len;
1314 int i;
1315
1316 path_dir = sftp_abs_path(pfs->cwd, path);
1317
1318 if (0 > sftp_write_pkt(pfs, 1, "14s",
1319 SSH_FXP_STAT, ++pfs->request_id, path_dir,
1320 str_length (path_dir)))
1321 return 0;
1322
1323 lim_free (0, path_dir);
1324
1325 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_ATTRS,
1326 1)))
1327 return 0;
1328
1329 if (0 > (i = sftp_import_attrs (&attrs, pkt + i, pkt_len - i, 1)))
1330 return 0;
1331
1332 lim_free (0, pkt);
1333
1334 return 1;
1335 }
1336
1337
1338 static int
pfs_is_dir(struct arch_pfs_session * p,const t_uchar * path)1339 pfs_is_dir (struct arch_pfs_session * p,
1340 const t_uchar * path)
1341 {
1342 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
1343 int ret, i;
1344 unsigned int pkt_len;
1345 char *pkt, *dir;
1346 struct sftp_attrs attrs;
1347
1348 dir = sftp_abs_path (pfs->cwd, path);
1349
1350 if (0 > sftp_write_pkt (pfs, 1,
1351 "14s", SSH_FXP_STAT, ++pfs->request_id, dir,
1352 str_length (dir)))
1353 {
1354 lim_free (0, dir);
1355 return -1;
1356 }
1357
1358 lim_free (0, dir);
1359
1360 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_ATTRS, 1)))
1361 return -1;
1362
1363 if (0 > (i = sftp_import_attrs (&attrs, pkt + i, pkt_len - i, 1)))
1364 {
1365 lim_free (0, pkt);
1366 return -1;
1367 }
1368
1369 ret = 0;
1370 if (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS && attrs.perms & S_IFDIR)
1371 ret = 1;
1372
1373 lim_free (0, pkt);
1374
1375 return ret;
1376 }
1377
1378
1379 static int
pfs_rename(struct arch_pfs_session * p,t_uchar ** errstr,const t_uchar * from,const t_uchar * to,int soft_errors)1380 pfs_rename (struct arch_pfs_session * p,
1381 t_uchar ** errstr,
1382 const t_uchar * from,
1383 const t_uchar * to,
1384 int soft_errors)
1385 {
1386 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
1387 int ret, i;
1388 unsigned int pkt_len;
1389 char *pkt, *from2, *to2, *file, *b;
1390
1391 from2 = sftp_abs_path (pfs->cwd, from);
1392 to2 = sftp_abs_path (pfs->cwd, to);
1393
1394 if (0 < pfs_is_dir (p, to2))
1395 {
1396 b = file = str_save (0, from);
1397
1398 filename:
1399 file = str_chr_rindex (file, '/');
1400 if (!file)
1401 file = b;
1402 else if (!file[1])
1403 {
1404 file[0] = 0;
1405 goto filename;
1406 }
1407 else
1408 file++;
1409
1410 to2 = str_realloc_cat_many (0, to2, "/", file, str_end);
1411 lim_free (0, b);
1412 }
1413
1414 ret = sftp_write_pkt (pfs, soft_errors,
1415 "14ss", SSH_FXP_RENAME, ++pfs->request_id, from2,
1416 str_length (from2), to2, str_length (to2));
1417
1418 lim_free (0, from2);
1419 lim_free (0, to2);
1420
1421 if (0 > ret)
1422 return -1;
1423
1424 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_STATUS,
1425 soft_errors)))
1426 return -1;
1427
1428 if (0 > (i = sftp_decode_status (pkt, pkt_len, i, soft_errors)))
1429 {
1430 lim_free (0, pkt);
1431 return -1;
1432 }
1433
1434 lim_free (0, pkt);
1435
1436 return i;
1437 }
1438
1439
1440 static int
pfs_rmdir(struct arch_pfs_session * p,const t_uchar * path,int soft_errors)1441 pfs_rmdir (struct arch_pfs_session * p,
1442 const t_uchar * path,
1443 int soft_errors)
1444 {
1445 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
1446
1447 int ret, i;
1448 unsigned int pkt_len;
1449 char *pkt, *dir;
1450
1451 dir = sftp_abs_path (pfs->cwd, path);
1452
1453 ret = sftp_write_pkt (pfs, soft_errors,
1454 "14s", SSH_FXP_RMDIR, ++pfs->request_id, dir,
1455 str_length (dir));
1456
1457 lim_free (0, dir);
1458
1459 if (0 > ret)
1460 return -1;
1461
1462 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_STATUS,
1463 soft_errors)))
1464 return -1;
1465
1466 if (0 > sftp_decode_status (pkt, pkt_len, i, 1))
1467 {
1468 if (soft_errors)
1469 {
1470 return -1;
1471 }
1472 else
1473 {
1474 safe_printfmt(2, "Error creating directory %s in path %s\n", path, pfs->cwd);
1475 safe_printfmt(2, "Server: ");
1476 sftp_decode_status(pkt, pkt_len, i, 0);
1477 }
1478 }
1479
1480 lim_free (0, pkt);
1481
1482 return i;
1483 }
1484
1485 static int
pfs_rm(struct arch_pfs_session * p,const t_uchar * path,int soft_errors)1486 pfs_rm (struct arch_pfs_session * p,
1487 const t_uchar * path,
1488 int soft_errors)
1489 {
1490 struct arch_pfs_sftp_session * pfs = (struct arch_pfs_sftp_session *)p;
1491 int ret, i;
1492 unsigned int pkt_len;
1493 char *pkt, *file;
1494
1495 file = sftp_abs_path (pfs->cwd, path);
1496
1497 ret = sftp_write_pkt (pfs, soft_errors,
1498 "14s", SSH_FXP_REMOVE, ++pfs->request_id, file,
1499 str_length (file));
1500
1501 lim_free (0, file);
1502
1503 if (0 > ret)
1504 return -1;
1505
1506 if (0 > (i = sftp_server_response (pfs, &pkt, &pkt_len, SSH_FXP_STATUS,
1507 soft_errors)))
1508 return -1;
1509
1510 i = sftp_decode_status (pkt, pkt_len, i, soft_errors);
1511
1512 lim_free (0, pkt);
1513
1514 return i;
1515 }
1516
1517
1518 static t_uchar *
dirfold(t_uchar * dir)1519 dirfold (t_uchar *dir)
1520 {
1521 t_uchar * buf;
1522 t_uchar * this;
1523 t_uchar * next;
1524 int dir_i = 0;
1525
1526 this = next = buf = str_save (0, dir);
1527 while ((this = str_separate (&next, "/")) != NULL)
1528 {
1529 if (str_length (this) == 0 || (str_length (this) == 1 && this[0] == '.'))
1530 continue;
1531 else if (str_length (this) == 2 && *this == '.' && this[1] == '.')
1532 {
1533 if (dir_i > 0)
1534 dir_i = (int)((char *)strrchr (dir, '/') - (char *)dir);
1535 dir[dir_i] = 0;
1536 }
1537 else
1538 {
1539 dir[dir_i++] = '/';
1540 strcpy (dir + dir_i, this);
1541 dir_i += str_length (this);
1542 }
1543 }
1544 lim_free (0, buf);
1545
1546 if (!str_length (dir))
1547 str_cpy (dir, "/");
1548
1549 return dir;
1550 }
1551
1552
1553 int
arch_pfs_sftp_parse_uri(t_uchar ** user,t_uchar ** hostname,t_uchar ** port,char ** path,const t_uchar * uri)1554 arch_pfs_sftp_parse_uri (t_uchar ** user,
1555 t_uchar ** hostname,
1556 t_uchar ** port,
1557 char ** path,
1558 const t_uchar * uri)
1559 {
1560 const t_uchar * start;
1561 const t_uchar * stop;
1562 t_uchar * host_part = 0;
1563 const t_uchar * at;
1564 const t_uchar * h0;
1565 const t_uchar * h1;
1566 const t_uchar * colon;
1567
1568 /* [user@]hostname[:port]/path
1569 * ^ ^ ^ ^ ^
1570 * | | | | |
1571 * | at?| | stop[*]
1572 * | | | 0-byte of host_part
1573 * | h0 |
1574 * | |
1575 * | |
1576 * | |
1577 * start[*] colon?
1578 * host_part h1
1579 *
1580 *
1581 * start and stop point to one copy of the string
1582 * (the original uri which includes the /path).
1583 *
1584 * host_part points to another copy of the string
1585 * (local to this block) which all the other pointers
1586 * point into.
1587 *
1588 * at? and colon? are 0 if @ and : are not present.
1589 *
1590 * The reason to make host_part is so that str_chr_index
1591 * searches are confined to just the host_part.
1592 */
1593
1594
1595 start = uri + sizeof ("sftp://") - 1;
1596 stop = str_chr_index (start, '/');
1597 if (!stop)
1598 return -1;
1599 *path = str_save (0, stop);
1600
1601 host_part = str_save_n (0, start, stop - start);
1602
1603 at = str_chr_index (host_part, '@');
1604 if (at)
1605 h0 = at + 1;
1606 else
1607 h0 = host_part;
1608
1609 colon = str_chr_index (h0, ':');
1610 if (colon)
1611 h1 = colon;
1612 else
1613 h1 = h0 + str_length (h0);
1614
1615 if (at)
1616 *user = str_save_n (0, host_part, at - host_part);
1617
1618 if (colon)
1619 *port = str_save (0, colon + 1);
1620
1621 *hostname = str_save_n (0, h0, h1 - h0);
1622
1623 lim_free (0, host_part);
1624 return 0;
1625 }
1626
1627
1628
1629
1630 /* tag: Tom Lord Thu Jun 5 15:23:06 2003 (pfs-sftp.c)
1631 */
1632