1 /* Copyright (c) 2009-2010 by Daniel Stenberg
2  * Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms,
6  * with or without modification, are permitted provided
7  * that the following conditions are met:
8  *
9  *   Redistributions of source code must retain the above
10  *   copyright notice, this list of conditions and the
11  *   following disclaimer.
12  *
13  *   Redistributions in binary form must reproduce the above
14  *   copyright notice, this list of conditions and the following
15  *   disclaimer in the documentation and/or other materials
16  *   provided with the distribution.
17  *
18  *   Neither the name of the copyright holder nor the names
19  *   of any other contributors may be used to endorse or
20  *   promote products derived from this software without
21  *   specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36  * OF SUCH DAMAGE.
37  */
38 
39 #include "libssh2_priv.h"
40 #include <errno.h>
41 #include <stdlib.h>
42 
43 #include "channel.h"
44 #include "session.h"
45 
46 
47 /* Max. length of a quoted string after libssh2_shell_quotearg() processing */
48 #define _libssh2_shell_quotedsize(s)     (3 * strlen(s) + 2)
49 
50 /*
51   This function quotes a string in a way suitable to be used with a
52   shell, e.g. the file name
53   one two
54   becomes
55   'one two'
56 
57   The resulting output string is crafted in a way that makes it usable
58   with the two most common shell types: Bourne Shell derived shells
59   (sh, ksh, ksh93, bash, zsh) and C-Shell derivates (csh, tcsh).
60 
61   The following special cases are handled:
62   o  If the string contains an apostrophy itself, the apostrophy
63   character is written in quotation marks, e.g. "'".
64   The shell cannot handle the syntax 'doesn\'t', so we close the
65   current argument word, add the apostrophe in quotation marks "",
66   and open a new argument word instead (_ indicate the input
67   string characters):
68   _____   _   _
69   'doesn' "'" 't'
70 
71   Sequences of apostrophes are combined in one pair of quotation marks:
72   a'''b
73   becomes
74   _  ___  _
75   'a'"'''"'b'
76 
77   o  If the string contains an exclamation mark (!), the C-Shell
78   interprets it as an event number. Using \! (not within quotation
79   marks or single quotation marks) is a mechanism understood by
80   both Bourne Shell and C-Shell.
81 
82   If a quotation was already started, the argument word is closed
83   first:
84   a!b
85 
86   become
87   _  _ _
88   'a'\!'b'
89 
90   The result buffer must be large enough for the expanded result. A
91   bad case regarding expansion is alternating characters and
92   apostrophes:
93 
94   a'b'c'd'                   (length 8) gets converted to
95   'a'"'"'b'"'"'c'"'"'d'"'"   (length 24)
96 
97   This is the worst case.
98 
99   Maximum length of the result:
100   1 + 6 * (length(input) + 1) / 2) + 1
101 
102   => 3 * length(input) + 2
103 
104   Explanation:
105   o  leading apostrophe
106   o  one character / apostrophe pair (two characters) can get
107   represented as 6 characters: a' -> a'"'"'
108   o  String terminator (+1)
109 
110   A result buffer three times the size of the input buffer + 2
111   characters should be safe.
112 
113   References:
114   o  csh-compatible quotation (special handling for '!' etc.), see
115   http://www.grymoire.com/Unix/Csh.html#toc-uh-10
116 
117   Return value:
118   Length of the resulting string (not counting the terminating '\0'),
119   or 0 in case of errors, e.g. result buffer too small
120 
121   Note: this function could possible be used elsewhere within libssh2, but
122   until then it is kept static and in this source file.
123 */
124 
125 static unsigned
shell_quotearg(const char * path,unsigned char * buf,unsigned bufsize)126 shell_quotearg(const char *path, unsigned char *buf,
127                unsigned bufsize)
128 {
129     const char *src;
130     unsigned char *dst, *endp;
131 
132     /*
133      * Processing States:
134      *  UQSTRING:       unquoted string: ... -- used for quoting exclamation
135      *                  marks. This is the initial state
136      *  SQSTRING:       single-quoted-string: '... -- any character may follow
137      *  QSTRING:        quoted string: "... -- only apostrophes may follow
138      */
139     enum { UQSTRING, SQSTRING, QSTRING } state = UQSTRING;
140 
141     endp = &buf[bufsize];
142     src = path;
143     dst = buf;
144     while (*src && dst < endp - 1) {
145 
146         switch (*src) {
147             /*
148              * Special handling for apostrophe.
149              * An apostrophe is always written in quotation marks, e.g.
150              * ' -> "'".
151              */
152 
153         case '\'':
154             switch (state) {
155             case UQSTRING:      /* Unquoted string */
156                 if (dst+1 >= endp)
157                     return 0;
158                 *dst++ = '"';
159                 break;
160             case QSTRING:       /* Continue quoted string */
161                 break;
162             case SQSTRING:      /* Close single quoted string */
163                 if (dst+2 >= endp)
164                     return 0;
165                 *dst++ = '\'';
166                 *dst++ = '"';
167                 break;
168             default:
169                 break;
170             }
171             state = QSTRING;
172             break;
173 
174             /*
175              * Special handling for exclamation marks. CSH interprets
176              * exclamation marks even when quoted with apostrophes. We convert
177              * it to the plain string \!, because both Bourne Shell and CSH
178              * interpret that as a verbatim exclamation mark.
179              */
180 
181         case '!':
182             switch (state) {
183             case UQSTRING:
184                 if (dst+1 >= endp)
185                     return 0;
186                 *dst++ = '\\';
187                 break;
188             case QSTRING:
189                 if (dst+2 >= endp)
190                     return 0;
191                 *dst++ = '"';           /* Closing quotation mark */
192                 *dst++ = '\\';
193                 break;
194             case SQSTRING:              /* Close single quoted string */
195                 if (dst+2 >= endp)
196                     return 0;
197                 *dst++ = '\'';
198                 *dst++ = '\\';
199                 break;
200             default:
201                 break;
202             }
203             state = UQSTRING;
204             break;
205 
206             /*
207              * Ordinary character: prefer single-quoted string
208              */
209 
210         default:
211             switch (state) {
212             case UQSTRING:
213                 if (dst+1 >= endp)
214                     return 0;
215                 *dst++ = '\'';
216                 break;
217             case QSTRING:
218                 if (dst+2 >= endp)
219                     return 0;
220                 *dst++ = '"';           /* Closing quotation mark */
221                 *dst++ = '\'';
222                 break;
223             case SQSTRING:      /* Continue single quoted string */
224                 break;
225             default:
226                 break;
227             }
228             state = SQSTRING;   /* Start single-quoted string */
229             break;
230         }
231 
232         if (dst+1 >= endp)
233             return 0;
234         *dst++ = *src++;
235     }
236 
237     switch (state) {
238     case UQSTRING:
239         break;
240     case QSTRING:           /* Close quoted string */
241         if (dst+1 >= endp)
242             return 0;
243         *dst++ = '"';
244         break;
245     case SQSTRING:          /* Close single quoted string */
246         if (dst+1 >= endp)
247             return 0;
248         *dst++ = '\'';
249         break;
250     default:
251         break;
252     }
253 
254     if (dst+1 >= endp)
255         return 0;
256     *dst = '\0';
257 
258     /* The result cannot be larger than 3 * strlen(path) + 2 */
259     /* assert((dst - buf) <= (3 * (src - path) + 2)); */
260 
261     return dst - buf;
262 }
263 
264 /*
265  * scp_recv
266  *
267  * Open a channel and request a remote file via SCP
268  *
269  */
270 static LIBSSH2_CHANNEL *
scp_recv(LIBSSH2_SESSION * session,const char * path,libssh2_struct_stat * sb)271 scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb)
272 {
273     int cmd_len;
274     int rc;
275     int tmp_err_code;
276     const char *tmp_err_msg;
277 
278     if (session->scpRecv_state == libssh2_NB_state_idle) {
279         session->scpRecv_mode = 0;
280         session->scpRecv_size = 0;
281         session->scpRecv_mtime = 0;
282         session->scpRecv_atime = 0;
283 
284         session->scpRecv_command_len =
285             _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb?1:0);
286 
287         session->scpRecv_command =
288             LIBSSH2_ALLOC(session, session->scpRecv_command_len);
289 
290         if (!session->scpRecv_command) {
291             _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
292                            "Unable to allocate a command buffer for "
293                            "SCP session");
294             return NULL;
295         }
296 
297         snprintf((char *)session->scpRecv_command,
298                  session->scpRecv_command_len,
299                  "scp -%sf ", sb?"p":"");
300 
301         cmd_len = strlen((char *)session->scpRecv_command);
302         cmd_len += shell_quotearg(path,
303                                   &session->scpRecv_command[cmd_len],
304                                   session->scpRecv_command_len - cmd_len);
305 
306         session->scpRecv_command[cmd_len] = '\0';
307         session->scpRecv_command_len = cmd_len + 1;
308 
309         _libssh2_debug(session, LIBSSH2_TRACE_SCP,
310                        "Opening channel for SCP receive");
311 
312         session->scpRecv_state = libssh2_NB_state_created;
313     }
314 
315     if (session->scpRecv_state == libssh2_NB_state_created) {
316         /* Allocate a channel */
317         session->scpRecv_channel =
318             _libssh2_channel_open(session, "session",
319                                   sizeof("session") - 1,
320                                   LIBSSH2_CHANNEL_WINDOW_DEFAULT,
321                                   LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
322                                   0);
323         if (!session->scpRecv_channel) {
324             if (libssh2_session_last_errno(session) !=
325                 LIBSSH2_ERROR_EAGAIN) {
326                 LIBSSH2_FREE(session, session->scpRecv_command);
327                 session->scpRecv_command = NULL;
328                 session->scpRecv_state = libssh2_NB_state_idle;
329             }
330             else {
331                 _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
332                                "Would block starting up channel");
333             }
334             return NULL;
335         }
336 
337         session->scpRecv_state = libssh2_NB_state_sent;
338     }
339 
340     if (session->scpRecv_state == libssh2_NB_state_sent) {
341         /* Request SCP for the desired file */
342         rc = _libssh2_channel_process_startup(session->scpRecv_channel, "exec",
343                                               sizeof("exec") - 1,
344                                               (char *) session->scpRecv_command,
345                                               session->scpRecv_command_len);
346         if (rc == LIBSSH2_ERROR_EAGAIN) {
347             _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
348                            "Would block requesting SCP startup");
349             return NULL;
350         } else if (rc) {
351             LIBSSH2_FREE(session, session->scpRecv_command);
352             session->scpRecv_command = NULL;
353             goto scp_recv_error;
354         }
355         LIBSSH2_FREE(session, session->scpRecv_command);
356         session->scpRecv_command = NULL;
357 
358         _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup");
359         /* SCP ACK */
360         session->scpRecv_response[0] = '\0';
361 
362         session->scpRecv_state = libssh2_NB_state_sent1;
363     }
364 
365     if (session->scpRecv_state == libssh2_NB_state_sent1) {
366         rc = _libssh2_channel_write(session->scpRecv_channel, 0,
367                                     session->scpRecv_response, 1);
368         if (rc == LIBSSH2_ERROR_EAGAIN) {
369             _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
370                            "Would block sending initial wakeup");
371             return NULL;
372         } else if (rc != 1) {
373             goto scp_recv_error;
374         }
375 
376         /* Parse SCP response */
377         session->scpRecv_response_len = 0;
378 
379         session->scpRecv_state = libssh2_NB_state_sent2;
380     }
381 
382     if ((session->scpRecv_state == libssh2_NB_state_sent2)
383         || (session->scpRecv_state == libssh2_NB_state_sent3)) {
384         while (sb && (session->scpRecv_response_len <
385                       LIBSSH2_SCP_RESPONSE_BUFLEN)) {
386             unsigned char *s, *p;
387 
388             if (session->scpRecv_state == libssh2_NB_state_sent2) {
389                 rc = _libssh2_channel_read(session->scpRecv_channel, 0,
390                                            (char *) session->
391                                            scpRecv_response +
392                                            session->scpRecv_response_len, 1);
393                 if (rc == LIBSSH2_ERROR_EAGAIN) {
394                     _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
395                                    "Would block waiting for SCP response");
396                     return NULL;
397                 }
398                 else if (rc < 0) {
399                     /* error, give up */
400                     _libssh2_error(session, rc, "Failed reading SCP response");
401                     goto scp_recv_error;
402                 }
403                 else if(rc == 0)
404                     goto scp_recv_empty_channel;
405 
406                 session->scpRecv_response_len++;
407 
408                 if (session->scpRecv_response[0] != 'T') {
409                     size_t err_len;
410                     char *err_msg;
411 
412                     /* there can be
413                        01 for warnings
414                        02 for errors
415 
416                        The following string MUST be newline terminated
417                     */
418                     err_len =
419                         _libssh2_channel_packet_data_len(session->
420                                                          scpRecv_channel, 0);
421                     err_msg = LIBSSH2_ALLOC(session, err_len + 1);
422                     if (!err_msg) {
423                         _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
424                                        "Failed to get memory ");
425                         goto scp_recv_error;
426                     }
427 
428                     /* Read the remote error message */
429                     (void)_libssh2_channel_read(session->scpRecv_channel, 0,
430                                                 err_msg, err_len);
431                     /* If it failed for any reason, we ignore it anyway. */
432 
433                     /* zero terminate the error */
434                     err_msg[err_len]=0;
435 
436                     _libssh2_debug(session, LIBSSH2_TRACE_SCP,
437                                    "got %02x %s", session->scpRecv_response[0],
438                                    err_msg);
439 
440                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
441                                    "Failed to recv file");
442 
443                     LIBSSH2_FREE(session, err_msg);
444                     goto scp_recv_error;
445                 }
446 
447                 if ((session->scpRecv_response_len > 1) &&
448                     ((session->
449                       scpRecv_response[session->scpRecv_response_len - 1] <
450                       '0')
451                      || (session->
452                          scpRecv_response[session->scpRecv_response_len - 1] >
453                          '9'))
454                     && (session->
455                         scpRecv_response[session->scpRecv_response_len - 1] !=
456                         ' ')
457                     && (session->
458                         scpRecv_response[session->scpRecv_response_len - 1] !=
459                         '\r')
460                     && (session->
461                         scpRecv_response[session->scpRecv_response_len - 1] !=
462                         '\n')) {
463                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
464                                    "Invalid data in SCP response");
465                     goto scp_recv_error;
466                 }
467 
468                 if ((session->scpRecv_response_len < 9)
469                     || (session->
470                         scpRecv_response[session->scpRecv_response_len - 1] !=
471                         '\n')) {
472                     if (session->scpRecv_response_len ==
473                         LIBSSH2_SCP_RESPONSE_BUFLEN) {
474                         /* You had your chance */
475                         _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
476                                        "Unterminated response from SCP server");
477                         goto scp_recv_error;
478                     }
479                     /* Way too short to be an SCP response, or not done yet,
480                        short circuit */
481                     continue;
482                 }
483 
484                 /* We're guaranteed not to go under response_len == 0 by the
485                    logic above */
486                 while ((session->
487                         scpRecv_response[session->scpRecv_response_len - 1] ==
488                         '\r')
489                        || (session->
490                            scpRecv_response[session->scpRecv_response_len -
491                                             1] == '\n'))
492                     session->scpRecv_response_len--;
493                 session->scpRecv_response[session->scpRecv_response_len] =
494                     '\0';
495 
496                 if (session->scpRecv_response_len < 8) {
497                     /* EOL came too soon */
498                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
499                                    "Invalid response from SCP server, "
500                                    "too short" );
501                     goto scp_recv_error;
502                 }
503 
504                 s = session->scpRecv_response + 1;
505 
506                 p = (unsigned char *) strchr((char *) s, ' ');
507                 if (!p || ((p - s) <= 0)) {
508                     /* No spaces or space in the wrong spot */
509                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
510                                    "Invalid response from SCP server, "
511                                    "malformed mtime");
512                     goto scp_recv_error;
513                 }
514 
515                 *(p++) = '\0';
516                 /* Make sure we don't get fooled by leftover values */
517                 session->scpRecv_mtime = strtol((char *) s, NULL, 10);
518 
519                 s = (unsigned char *) strchr((char *) p, ' ');
520                 if (!s || ((s - p) <= 0)) {
521                     /* No spaces or space in the wrong spot */
522                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
523                                    "Invalid response from SCP server, malformed mtime.usec");
524                     goto scp_recv_error;
525                 }
526 
527                 /* Ignore mtime.usec */
528                 s++;
529                 p = (unsigned char *) strchr((char *) s, ' ');
530                 if (!p || ((p - s) <= 0)) {
531                     /* No spaces or space in the wrong spot */
532                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
533                                    "Invalid response from SCP server, too short or malformed");
534                     goto scp_recv_error;
535                 }
536 
537                 *p = '\0';
538                 /* Make sure we don't get fooled by leftover values */
539                 session->scpRecv_atime = strtol((char *) s, NULL, 10);
540 
541                 /* SCP ACK */
542                 session->scpRecv_response[0] = '\0';
543 
544                 session->scpRecv_state = libssh2_NB_state_sent3;
545             }
546 
547             if (session->scpRecv_state == libssh2_NB_state_sent3) {
548                 rc = _libssh2_channel_write(session->scpRecv_channel, 0,
549                                             session->scpRecv_response, 1);
550                 if (rc == LIBSSH2_ERROR_EAGAIN) {
551                     _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
552                                    "Would block waiting to send SCP ACK");
553                     return NULL;
554                 } else if (rc != 1) {
555                     goto scp_recv_error;
556                 }
557 
558                 _libssh2_debug(session, LIBSSH2_TRACE_SCP,
559                                "mtime = %ld, atime = %ld",
560                                session->scpRecv_mtime, session->scpRecv_atime);
561 
562                 /* We *should* check that atime.usec is valid, but why let
563                    that stop use? */
564                 break;
565             }
566         }
567 
568         session->scpRecv_state = libssh2_NB_state_sent4;
569     }
570 
571     if (session->scpRecv_state == libssh2_NB_state_sent4) {
572         session->scpRecv_response_len = 0;
573 
574         session->scpRecv_state = libssh2_NB_state_sent5;
575     }
576 
577     if ((session->scpRecv_state == libssh2_NB_state_sent5)
578         || (session->scpRecv_state == libssh2_NB_state_sent6)) {
579         while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
580             char *s, *p, *e = NULL;
581 
582             if (session->scpRecv_state == libssh2_NB_state_sent5) {
583                 rc = _libssh2_channel_read(session->scpRecv_channel, 0,
584                                            (char *) session->
585                                            scpRecv_response +
586                                            session->scpRecv_response_len, 1);
587                 if (rc == LIBSSH2_ERROR_EAGAIN) {
588                     _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
589                                    "Would block waiting for SCP response");
590                     return NULL;
591                 }
592                 else if (rc < 0) {
593                     /* error, bail out*/
594                     _libssh2_error(session, rc, "Failed reading SCP response");
595                     goto scp_recv_error;
596                 }
597                 else if(rc == 0)
598                     goto scp_recv_empty_channel;
599 
600                 session->scpRecv_response_len++;
601 
602                 if (session->scpRecv_response[0] != 'C') {
603                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
604                                    "Invalid response from SCP server");
605                     goto scp_recv_error;
606                 }
607 
608                 if ((session->scpRecv_response_len > 1) &&
609                     (session->
610                      scpRecv_response[session->scpRecv_response_len - 1] !=
611                      '\r')
612                     && (session->
613                         scpRecv_response[session->scpRecv_response_len - 1] !=
614                         '\n')
615                     &&
616                     (session->
617                      scpRecv_response[session->scpRecv_response_len - 1]
618                      < 32)) {
619                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
620                                    "Invalid data in SCP response");
621                     goto scp_recv_error;
622                 }
623 
624                 if ((session->scpRecv_response_len < 7)
625                     || (session->
626                         scpRecv_response[session->scpRecv_response_len - 1] !=
627                         '\n')) {
628                     if (session->scpRecv_response_len ==
629                         LIBSSH2_SCP_RESPONSE_BUFLEN) {
630                         /* You had your chance */
631                         _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
632                                        "Unterminated response from SCP server");
633                         goto scp_recv_error;
634                     }
635                     /* Way too short to be an SCP response, or not done yet,
636                        short circuit */
637                     continue;
638                 }
639 
640                 /* We're guaranteed not to go under response_len == 0 by the
641                    logic above */
642                 while ((session->
643                         scpRecv_response[session->scpRecv_response_len - 1] ==
644                         '\r')
645                        || (session->
646                            scpRecv_response[session->scpRecv_response_len -
647                                             1] == '\n')) {
648                     session->scpRecv_response_len--;
649                 }
650                 session->scpRecv_response[session->scpRecv_response_len] =
651                     '\0';
652 
653                 if (session->scpRecv_response_len < 6) {
654                     /* EOL came too soon */
655                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
656                                    "Invalid response from SCP server, too short");
657                     goto scp_recv_error;
658                 }
659 
660                 s = (char *) session->scpRecv_response + 1;
661 
662                 p = strchr(s, ' ');
663                 if (!p || ((p - s) <= 0)) {
664                     /* No spaces or space in the wrong spot */
665                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
666                                    "Invalid response from SCP server, malformed mode");
667                     goto scp_recv_error;
668                 }
669 
670                 *(p++) = '\0';
671                 /* Make sure we don't get fooled by leftover values */
672 
673                 session->scpRecv_mode = strtol(s, &e, 8);
674                 if (e && *e) {
675                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
676                                    "Invalid response from SCP server, invalid mode");
677                     goto scp_recv_error;
678                 }
679 
680                 s = strchr(p, ' ');
681                 if (!s || ((s - p) <= 0)) {
682                     /* No spaces or space in the wrong spot */
683                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
684                                    "Invalid response from SCP server, too short or malformed");
685                     goto scp_recv_error;
686                 }
687 
688                 *s = '\0';
689                 /* Make sure we don't get fooled by leftover values */
690                 session->scpRecv_size = scpsize_strtol(p, &e, 10);
691                 if (e && *e) {
692                     _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
693                                    "Invalid response from SCP server, invalid size");
694                     goto scp_recv_error;
695                 }
696 
697                 /* SCP ACK */
698                 session->scpRecv_response[0] = '\0';
699 
700                 session->scpRecv_state = libssh2_NB_state_sent6;
701             }
702 
703             if (session->scpRecv_state == libssh2_NB_state_sent6) {
704                 rc = _libssh2_channel_write(session->scpRecv_channel, 0,
705                                             session->scpRecv_response, 1);
706                 if (rc == LIBSSH2_ERROR_EAGAIN) {
707                     _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
708                                    "Would block sending SCP ACK");
709                     return NULL;
710                 } else if (rc != 1) {
711                     goto scp_recv_error;
712                 }
713                 _libssh2_debug(session, LIBSSH2_TRACE_SCP,
714                                "mode = 0%lo size = %ld", session->scpRecv_mode,
715                                session->scpRecv_size);
716 
717                 /* We *should* check that basename is valid, but why let that
718                    stop us? */
719                 break;
720             }
721         }
722 
723         session->scpRecv_state = libssh2_NB_state_sent7;
724     }
725 
726     if (sb) {
727         memset(sb, 0, sizeof(libssh2_struct_stat));
728 
729         sb->st_mtime = session->scpRecv_mtime;
730         sb->st_atime = session->scpRecv_atime;
731         sb->st_size = session->scpRecv_size;
732         sb->st_mode = (unsigned short)session->scpRecv_mode;
733     }
734 
735     session->scpRecv_state = libssh2_NB_state_idle;
736     return session->scpRecv_channel;
737 
738   scp_recv_empty_channel:
739     /* the code only jumps here as a result of a zero read from channel_read()
740        so we check EOF status to avoid getting stuck in a loop */
741     if(libssh2_channel_eof(session->scpRecv_channel))
742         _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
743                        "Unexpected channel close");
744     else
745         return session->scpRecv_channel;
746     /* fall-through */
747   scp_recv_error:
748     tmp_err_code = session->err_code;
749     tmp_err_msg = session->err_msg;
750     while (libssh2_channel_free(session->scpRecv_channel) ==
751            LIBSSH2_ERROR_EAGAIN);
752     session->err_code = tmp_err_code;
753     session->err_msg = tmp_err_msg;
754     session->scpRecv_channel = NULL;
755     session->scpRecv_state = libssh2_NB_state_idle;
756     return NULL;
757 }
758 
759 /*
760  * libssh2_scp_recv
761  *
762  * DEPRECATED
763  *
764  * Open a channel and request a remote file via SCP.  This receives files larger
765  * than 2 GB, but is unable to report the proper size on platforms where the
766  * st_size member of struct stat is limited to 2 GB (e.g. windows).
767  *
768  */
769 LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_recv(LIBSSH2_SESSION * session,const char * path,struct stat * sb)770 libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb)
771 {
772     LIBSSH2_CHANNEL *ptr;
773 
774     /* scp_recv uses libssh2_struct_stat, so pass one if the caller gave us a struct to populate... */
775     libssh2_struct_stat sb_intl;
776     libssh2_struct_stat *sb_ptr;
777     sb_ptr = sb ? &sb_intl : NULL;
778 
779     BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb_ptr));
780 
781     /* ...and populate the caller's with as much info as fits. */
782     if (sb) {
783         memset(sb, 0, sizeof(struct stat));
784 
785         sb->st_mtime = sb_intl.st_mtime;
786         sb->st_atime = sb_intl.st_atime;
787         sb->st_size = (off_t)sb_intl.st_size;
788         sb->st_mode = sb_intl.st_mode;
789     }
790 
791     return ptr;
792 }
793 
794 /*
795  * libssh2_scp_recv2
796  *
797  * Open a channel and request a remote file via SCP.  This supports files > 2GB
798  * on platforms that support it.
799  *
800  */
801 LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_recv2(LIBSSH2_SESSION * session,const char * path,libssh2_struct_stat * sb)802 libssh2_scp_recv2(LIBSSH2_SESSION *session, const char *path, libssh2_struct_stat * sb)
803 {
804     LIBSSH2_CHANNEL *ptr;
805     BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb));
806     return ptr;
807 }
808 
809 /*
810  * scp_send()
811  *
812  * Send a file using SCP
813  *
814  */
815 static LIBSSH2_CHANNEL *
scp_send(LIBSSH2_SESSION * session,const char * path,int mode,libssh2_int64_t size,time_t mtime,time_t atime)816 scp_send(LIBSSH2_SESSION * session, const char *path, int mode,
817          libssh2_int64_t size, time_t mtime, time_t atime)
818 {
819     int cmd_len;
820     int rc;
821     int tmp_err_code;
822     const char *tmp_err_msg;
823 
824     if (session->scpSend_state == libssh2_NB_state_idle) {
825         session->scpSend_command_len =
826             _libssh2_shell_quotedsize(path) + sizeof("scp -t ") +
827             ((mtime || atime)?1:0);
828 
829         session->scpSend_command =
830             LIBSSH2_ALLOC(session, session->scpSend_command_len);
831 
832         if (!session->scpSend_command) {
833             _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
834                            "Unable to allocate a command buffer for "
835                            "SCP session");
836             return NULL;
837         }
838 
839         snprintf((char *)session->scpSend_command,
840                  session->scpSend_command_len,
841                  "scp -%st ", (mtime || atime)?"p":"");
842 
843         cmd_len = strlen((char *)session->scpSend_command);
844         cmd_len += shell_quotearg(path,
845                                   &session->scpSend_command[cmd_len],
846                                   session->scpSend_command_len - cmd_len);
847 
848         session->scpSend_command[cmd_len] = '\0';
849         session->scpSend_command_len = cmd_len + 1;
850 
851         _libssh2_debug(session, LIBSSH2_TRACE_SCP,
852                        "Opening channel for SCP send");
853         /* Allocate a channel */
854 
855         session->scpSend_state = libssh2_NB_state_created;
856     }
857 
858     if (session->scpSend_state == libssh2_NB_state_created) {
859         session->scpSend_channel =
860             _libssh2_channel_open(session, "session", sizeof("session") - 1,
861                                   LIBSSH2_CHANNEL_WINDOW_DEFAULT,
862                                   LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
863         if (!session->scpSend_channel) {
864             if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
865                 /* previous call set libssh2_session_last_error(), pass it
866                    through */
867                 LIBSSH2_FREE(session, session->scpSend_command);
868                 session->scpSend_command = NULL;
869                 session->scpSend_state = libssh2_NB_state_idle;
870             }
871             else {
872                 _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
873                                "Would block starting up channel");
874             }
875             return NULL;
876         }
877 
878         session->scpSend_state = libssh2_NB_state_sent;
879     }
880 
881     if (session->scpSend_state == libssh2_NB_state_sent) {
882         /* Request SCP for the desired file */
883         rc = _libssh2_channel_process_startup(session->scpSend_channel, "exec",
884                                               sizeof("exec") - 1,
885                                               (char *) session->scpSend_command,
886                                               session->scpSend_command_len);
887         if (rc == LIBSSH2_ERROR_EAGAIN) {
888             _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
889                            "Would block requesting SCP startup");
890             return NULL;
891         }
892         else if (rc) {
893             /* previous call set libssh2_session_last_error(), pass it
894                through */
895             LIBSSH2_FREE(session, session->scpSend_command);
896             session->scpSend_command = NULL;
897             _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
898                            "Unknown error while getting error string");
899             goto scp_send_error;
900         }
901         LIBSSH2_FREE(session, session->scpSend_command);
902         session->scpSend_command = NULL;
903 
904         session->scpSend_state = libssh2_NB_state_sent1;
905     }
906 
907     if (session->scpSend_state == libssh2_NB_state_sent1) {
908         /* Wait for ACK */
909         rc = _libssh2_channel_read(session->scpSend_channel, 0,
910                                    (char *) session->scpSend_response, 1);
911         if (rc == LIBSSH2_ERROR_EAGAIN) {
912             _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
913                            "Would block waiting for response from remote");
914             return NULL;
915         }
916         else if (rc < 0) {
917             _libssh2_error(session, rc, "SCP failure");
918             goto scp_send_error;
919         }
920         else if(!rc)
921             /* remain in the same state */
922             goto scp_send_empty_channel;
923         else if (session->scpSend_response[0] != 0) {
924             _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
925                            "Invalid ACK response from remote");
926             goto scp_send_error;
927         }
928         if (mtime || atime) {
929             /* Send mtime and atime to be used for file */
930             session->scpSend_response_len =
931                 snprintf((char *) session->scpSend_response,
932                          LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n",
933                          (long)mtime, (long)atime);
934             _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s",
935                            session->scpSend_response);
936         }
937 
938         session->scpSend_state = libssh2_NB_state_sent2;
939     }
940 
941     /* Send mtime and atime to be used for file */
942     if (mtime || atime) {
943         if (session->scpSend_state == libssh2_NB_state_sent2) {
944             rc = _libssh2_channel_write(session->scpSend_channel, 0,
945                                         session->scpSend_response,
946                                         session->scpSend_response_len);
947             if (rc == LIBSSH2_ERROR_EAGAIN) {
948                 _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
949                                "Would block sending time data for SCP file");
950                 return NULL;
951             } else if (rc != (int)session->scpSend_response_len) {
952                 _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
953                                "Unable to send time data for SCP file");
954                 goto scp_send_error;
955             }
956 
957             session->scpSend_state = libssh2_NB_state_sent3;
958         }
959 
960         if (session->scpSend_state == libssh2_NB_state_sent3) {
961             /* Wait for ACK */
962             rc = _libssh2_channel_read(session->scpSend_channel, 0,
963                                        (char *) session->scpSend_response, 1);
964             if (rc == LIBSSH2_ERROR_EAGAIN) {
965                 _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
966                                "Would block waiting for response");
967                 return NULL;
968             }
969             else if (rc < 0) {
970                 _libssh2_error(session, rc, "SCP failure");
971                 goto scp_send_error;
972             }
973             else if(!rc)
974                 /* remain in the same state */
975                 goto scp_send_empty_channel;
976             else if (session->scpSend_response[0] != 0) {
977                 _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
978                                "Invalid SCP ACK response");
979                 goto scp_send_error;
980             }
981 
982             session->scpSend_state = libssh2_NB_state_sent4;
983         }
984     } else {
985         if (session->scpSend_state == libssh2_NB_state_sent2) {
986             session->scpSend_state = libssh2_NB_state_sent4;
987         }
988     }
989 
990     if (session->scpSend_state == libssh2_NB_state_sent4) {
991         /* Send mode, size, and basename */
992         const char *base = strrchr(path, '/');
993         if (base)
994             base++;
995         else
996             base = path;
997 
998         session->scpSend_response_len =
999             snprintf((char *) session->scpSend_response,
1000                      LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %"
1001                      LIBSSH2_INT64_T_FORMAT " %s\n", mode,
1002                      size, base);
1003         _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s",
1004                        session->scpSend_response);
1005 
1006         session->scpSend_state = libssh2_NB_state_sent5;
1007     }
1008 
1009     if (session->scpSend_state == libssh2_NB_state_sent5) {
1010         rc = _libssh2_channel_write(session->scpSend_channel, 0,
1011                                     session->scpSend_response,
1012                                     session->scpSend_response_len);
1013         if (rc == LIBSSH2_ERROR_EAGAIN) {
1014             _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1015                            "Would block send core file data for SCP file");
1016             return NULL;
1017         } else if (rc != (int)session->scpSend_response_len) {
1018             _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1019                            "Unable to send core file data for SCP file");
1020             goto scp_send_error;
1021         }
1022 
1023         session->scpSend_state = libssh2_NB_state_sent6;
1024     }
1025 
1026     if (session->scpSend_state == libssh2_NB_state_sent6) {
1027         /* Wait for ACK */
1028         rc = _libssh2_channel_read(session->scpSend_channel, 0,
1029                                    (char *) session->scpSend_response, 1);
1030         if (rc == LIBSSH2_ERROR_EAGAIN) {
1031             _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1032                            "Would block waiting for response");
1033             return NULL;
1034         }
1035         else if (rc < 0) {
1036             _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
1037                            "Invalid ACK response from remote");
1038             goto scp_send_error;
1039         }
1040         else if (rc == 0)
1041             goto scp_send_empty_channel;
1042 
1043         else if (session->scpSend_response[0] != 0) {
1044             size_t err_len;
1045             char *err_msg;
1046 
1047             err_len =
1048                 _libssh2_channel_packet_data_len(session->scpSend_channel, 0);
1049             err_msg = LIBSSH2_ALLOC(session, err_len + 1);
1050             if (!err_msg) {
1051                 _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1052                                "failed to get memory");
1053                 goto scp_send_error;
1054             }
1055 
1056             /* Read the remote error message */
1057             rc = _libssh2_channel_read(session->scpSend_channel, 0,
1058                                        err_msg, err_len);
1059             if (rc > 0) {
1060                 err_msg[err_len]=0;
1061                 _libssh2_debug(session, LIBSSH2_TRACE_SCP,
1062                                "got %02x %s", session->scpSend_response[0],
1063                                err_msg);
1064             }
1065             LIBSSH2_FREE(session, err_msg);
1066             _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
1067                            "failed to send file");
1068             goto scp_send_error;
1069         }
1070     }
1071 
1072     session->scpSend_state = libssh2_NB_state_idle;
1073     return session->scpSend_channel;
1074 
1075   scp_send_empty_channel:
1076     /* the code only jumps here as a result of a zero read from channel_read()
1077        so we check EOF status to avoid getting stuck in a loop */
1078     if(libssh2_channel_eof(session->scpSend_channel)) {
1079         _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
1080                        "Unexpected channel close");
1081     }
1082     else
1083         return session->scpSend_channel;
1084     /* fall-through */
1085   scp_send_error:
1086     tmp_err_code = session->err_code;
1087     tmp_err_msg = session->err_msg;
1088     while (libssh2_channel_free(session->scpSend_channel) ==
1089            LIBSSH2_ERROR_EAGAIN);
1090     session->err_code = tmp_err_code;
1091     session->err_msg = tmp_err_msg;
1092     session->scpSend_channel = NULL;
1093     session->scpSend_state = libssh2_NB_state_idle;
1094     return NULL;
1095 }
1096 
1097 /*
1098  * libssh2_scp_send_ex
1099  *
1100  * Send a file using SCP. Old API.
1101  */
1102 LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_send_ex(LIBSSH2_SESSION * session,const char * path,int mode,size_t size,long mtime,long atime)1103 libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode,
1104                     size_t size, long mtime, long atime)
1105 {
1106     LIBSSH2_CHANNEL *ptr;
1107     BLOCK_ADJUST_ERRNO(ptr, session,
1108                        scp_send(session, path, mode, size,
1109                                 (time_t)mtime, (time_t)atime));
1110     return ptr;
1111 }
1112 
1113 /*
1114  * libssh2_scp_send64
1115  *
1116  * Send a file using SCP
1117  */
1118 LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_send64(LIBSSH2_SESSION * session,const char * path,int mode,libssh2_int64_t size,time_t mtime,time_t atime)1119 libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode,
1120                    libssh2_int64_t size, time_t mtime, time_t atime)
1121 {
1122     LIBSSH2_CHANNEL *ptr;
1123     BLOCK_ADJUST_ERRNO(ptr, session,
1124                        scp_send(session, path, mode, size, mtime, atime));
1125     return ptr;
1126 }
1127