sshv2.c
上传用户:tjfeida
上传日期:2013-03-10
资源大小:1917k
文件大小:54k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. /*****************************************************************************/
  2. /*  sshv2.c - functions that will use the sshv2 protocol                     */
  3. /*  Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org>                  */
  4. /*                                                                           */
  5. /*  This program is free software; you can redistribute it and/or modify     */
  6. /*  it under the terms of the GNU General Public License as published by     */
  7. /*  the Free Software Foundation; either version 2 of the License, or        */
  8. /*  (at your option) any later version.                                      */
  9. /*                                                                           */
  10. /*  This program is distributed in the hope that it will be useful,          */
  11. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  12. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  13. /*  GNU General Public License for more details.                             */
  14. /*                                                                           */
  15. /*  You should have received a copy of the GNU General Public License        */
  16. /*  along with this program; if not, write to the Free Software              */
  17. /*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA      */
  18. /*****************************************************************************/
  19. #include "gftp.h"
  20. static const char cvsid[] = "$Id: sshv2.c,v 1.11 2002/11/23 14:34:25 masneyb Exp $";
  21. #define SSH_MAX_HANDLE_SIZE 256
  22. #define SSH_MAX_STRING_SIZE 34000
  23. typedef struct sshv2_attribs_tag
  24. {
  25.   gint32 flags;
  26.   gint64 size;
  27.   gint32 uid;
  28.   gint32 gid;
  29.   gint32 perm;
  30.   gint32 atime;
  31.   gint32 mtime;
  32. } sshv2_attribs;
  33. typedef struct sshv2_message_tag
  34. {
  35.   gint32 length;
  36.   char command;
  37.   char *buffer,
  38.        *pos,
  39.        *end;
  40. } sshv2_message;
  41. typedef struct sshv2_params_tag
  42. {
  43.   char handle[SSH_MAX_HANDLE_SIZE + 4]; /* We'll encode the ID in here too */
  44.   int handle_len,
  45.       dont_log_status : 1;              /* For uploading files */
  46.   sshv2_message message;
  47.   gint32 id,
  48.          count;
  49. #ifdef G_HAVE_GINT64
  50.   gint64 offset;
  51. #else
  52.   gint32 offset;
  53. #endif
  54.   char *read_buffer;
  55. } sshv2_params;
  56. #define SSH_MY_VERSION              3
  57. #define SSH_FXP_INIT                1
  58. #define SSH_FXP_VERSION             2
  59. #define SSH_FXP_OPEN                3
  60. #define SSH_FXP_CLOSE               4
  61. #define SSH_FXP_READ                5
  62. #define SSH_FXP_WRITE               6
  63. #define SSH_FXP_LSTAT               7
  64. #define SSH_FXP_FSTAT               8
  65. #define SSH_FXP_SETSTAT             9
  66. #define SSH_FXP_FSETSTAT           10
  67. #define SSH_FXP_OPENDIR            11
  68. #define SSH_FXP_READDIR            12
  69. #define SSH_FXP_REMOVE             13
  70. #define SSH_FXP_MKDIR              14
  71. #define SSH_FXP_RMDIR              15
  72. #define SSH_FXP_REALPATH           16
  73. #define SSH_FXP_STAT               17
  74. #define SSH_FXP_RENAME             18
  75. #define SSH_FXP_STATUS            101
  76. #define SSH_FXP_HANDLE            102
  77. #define SSH_FXP_DATA              103
  78. #define SSH_FXP_NAME              104
  79. #define SSH_FXP_ATTRS             105
  80. #define SSH_FXP_EXTENDED          200
  81. #define SSH_FXP_EXTENDED_REPLY    201
  82. #define SSH_FILEXFER_ATTR_SIZE          0x00000001
  83. #define SSH_FILEXFER_ATTR_UIDGID        0x00000002
  84. #define SSH_FILEXFER_ATTR_PERMISSIONS   0x00000004
  85. #define SSH_FILEXFER_ATTR_ACMODTIME     0x00000008
  86. #define SSH_FILEXFER_ATTR_EXTENDED      0x80000000
  87. #define SSH_FXF_READ            0x00000001
  88. #define SSH_FXF_WRITE           0x00000002
  89. #define SSH_FXF_APPEND          0x00000004
  90. #define SSH_FXF_CREAT           0x00000008
  91. #define SSH_FXF_TRUNC           0x00000010
  92. #define SSH_FXF_EXCL            0x00000020
  93. #define SSH_FX_OK                            0
  94. #define SSH_FX_EOF                           1
  95. #define SSH_FX_NO_SUCH_FILE                  2
  96. #define SSH_FX_PERMISSION_DENIED             3
  97. #define SSH_FX_FAILURE                       4
  98. #define SSH_FX_BAD_MESSAGE                   5
  99. #define SSH_FX_NO_CONNECTION                 6
  100. #define SSH_FX_CONNECTION_LOST               7
  101. #define SSH_FX_OP_UNSUPPORTED                8
  102. static void
  103. sshv2_log_command (gftp_request * request, gftp_logging_level level,
  104.                    char type, char *message, size_t length)
  105. {
  106.   gint32 id, num, attr, stattype;
  107.   char *descr, *pos, oldchar;
  108.   sshv2_params * params;
  109.   params = request->protocol_data;
  110.   memcpy (&id, message, 4);
  111.   id = ntohl (id);
  112.   switch (type)
  113.     {
  114.       case SSH_FXP_INIT:
  115.         request->logging_function (level, request->user_data, 
  116.                                    _("%d: Protocol Initializationn"), id);
  117.         break;
  118.       case SSH_FXP_VERSION:
  119.         memcpy (&num, message, 4);
  120.         num = ntohl (num);
  121.         request->logging_function (level, request->user_data, 
  122.                                    _("%d: Protocol version %dn"), id, num);
  123.         break;
  124.       case SSH_FXP_OPEN:
  125.         memcpy (&num, message + 4, 4);
  126.         num = ntohl (num);
  127.         pos = message + 12 + num - 1;
  128.         oldchar = *pos;
  129.         *pos = '';
  130.         request->logging_function (level, request->user_data,
  131.                                    _("%d: Open %sn"), id, message + 8);
  132.         *pos = oldchar;
  133.         break;
  134.       case SSH_FXP_CLOSE:
  135.         request->logging_function (level, request->user_data, 
  136.                                    _("%d: Closen"), id);
  137.       case SSH_FXP_READ:
  138.       case SSH_FXP_WRITE:
  139.         break;  
  140.       case SSH_FXP_OPENDIR:
  141.         request->logging_function (level, request->user_data, 
  142.                                    _("%d: Open Directory %sn"), id,
  143.                                    message + 8);
  144.         break;
  145.       case SSH_FXP_READDIR:
  146.         request->logging_function (level, request->user_data, 
  147.                                    _("%d: Read Directoryn"), id);
  148.         break;
  149.       case SSH_FXP_REMOVE:
  150.         request->logging_function (level, request->user_data, 
  151.                                    _("%d: Remove file %sn"), id,
  152.                                    message + 8);
  153.         break;
  154.       case SSH_FXP_MKDIR:
  155.         request->logging_function (level, request->user_data, 
  156.                                    _("%d: Make directory %sn"), id,
  157.                                    message + 8);
  158.         break;
  159.       case SSH_FXP_RMDIR:
  160.         request->logging_function (level, request->user_data, 
  161.                                    _("%d: Remove directory %sn"), id,
  162.                                    message + 8);
  163.         break;
  164.       case SSH_FXP_REALPATH:
  165.         request->logging_function (level, request->user_data, 
  166.                                    _("%d: Realpath %sn"), id,
  167.                                    message + 8);
  168.         break;
  169.       case SSH_FXP_ATTRS:
  170.         request->logging_function (level, request->user_data,
  171.                                    _("%d: File attributesn"), id);
  172.         break;
  173.       case SSH_FXP_STAT:
  174.         request->logging_function (level, request->user_data, 
  175.                                    _("%d: Stat %sn"), id,
  176.                                    message + 8);
  177.         break;
  178.       case SSH_FXP_SETSTAT:
  179.         memcpy (&num, message + 4, 4);
  180.         num = ntohl (num);
  181.         pos = message + 12 + num - 1;
  182.         oldchar = *pos;
  183.         *pos = '';
  184.         memcpy (&stattype, message + 8 + num, 4);
  185.         stattype = ntohl (stattype);
  186.         memcpy (&attr, message + 12 + num, 4);
  187.         attr = ntohl (attr);
  188.         switch (stattype)
  189.           {
  190.             case SSH_FILEXFER_ATTR_PERMISSIONS:
  191.               request->logging_function (level, request->user_data,
  192.                                          _("%d: Chmod %s %on"), id,
  193.                                          message + 8, attr);
  194.               break;
  195.             case SSH_FILEXFER_ATTR_ACMODTIME:
  196.               request->logging_function (level, request->user_data,
  197.                                          _("%d: Utime %s %dn"), id,
  198.                                          message + 8, attr);
  199.           }
  200.         *pos = oldchar;
  201.         break;
  202.       case SSH_FXP_STATUS:
  203.         if (params->dont_log_status)
  204.           break;
  205.         memcpy (&num, message + 4, 4);
  206.         num = ntohl (num);
  207.         switch (num)
  208.           {
  209.             case SSH_FX_OK:
  210.               descr = _("OK");
  211.               break;
  212.             case SSH_FX_EOF:
  213.               descr = _("EOF");
  214.               break;
  215.             case SSH_FX_NO_SUCH_FILE:
  216.               descr = _("No such file or directory");
  217.               break;
  218.             case SSH_FX_PERMISSION_DENIED:
  219.               descr = _("Permission denied");
  220.               break;
  221.             case SSH_FX_FAILURE:
  222.               descr = _("Failure");
  223.               break;
  224.             case SSH_FX_BAD_MESSAGE:
  225.               descr = _("Bad message");
  226.               break;
  227.             case SSH_FX_NO_CONNECTION:
  228.               descr = _("No connection");
  229.               break;
  230.             case SSH_FX_CONNECTION_LOST:
  231.               descr = _("Connection lost");
  232.               break;
  233.             case SSH_FX_OP_UNSUPPORTED:
  234.               descr = _("Operation unsupported");
  235.               break;
  236.             default:
  237.               descr = _("Unknown message returned from server");
  238.               break;
  239.           }
  240.         request->logging_function (level, request->user_data,
  241.                                    "%d: %sn", id, descr);
  242.         break;
  243.       case SSH_FXP_HANDLE:
  244.         request->logging_function (level, request->user_data, 
  245.                                    "%d: File handlen", id);
  246.         break;
  247.       case SSH_FXP_DATA:
  248.         break;
  249.       case SSH_FXP_NAME:
  250.         memcpy (&num, message + 4, 4);
  251.         num = ntohl (num);
  252.         request->logging_function (level, request->user_data, 
  253.                                    "%d: Filenames (%d entries)n", id,
  254.                                    num);
  255.         break;
  256.       default:
  257.         request->logging_function (level, request->user_data, 
  258.                                    "Command: %xn", type);
  259.     }
  260. }
  261. static int
  262. sshv2_send_command (gftp_request * request, char type, char *command, 
  263.                     gint32 len)
  264. {
  265.   char buf[34000];
  266.   gint32 clen;
  267.   if (len > 33995)
  268.     {
  269.       request->logging_function (gftp_logging_error, request->user_data,
  270.                              _("Error: Message size %d too bign"), len);
  271.       gftp_disconnect (request);
  272.       return (-1);
  273.     }
  274.   clen = htonl (len + 1);
  275.   memcpy (buf, &clen, 4);
  276.   buf[4] = type;
  277.   memcpy (&buf[5], command, len);
  278.   buf[len + 5] = '';
  279. #ifdef DEBUG
  280.   printf ("rSending: ");
  281.   for (clen=0; clen<len + 5; clen++)
  282.     printf ("%x ", buf[clen] & 0xff);
  283.   printf ("n");
  284. #endif
  285.   sshv2_log_command (request, gftp_logging_send, type, buf + 5, len);
  286.   if (gftp_write (request, buf, len + 5, request->sockfd) < 0)
  287.     return (-2);
  288.   return 0;
  289. }
  290. static int
  291. sshv2_read_response (gftp_request * request, sshv2_message * message,
  292.                      int fd)
  293. {
  294.   ssize_t numread, rem;
  295.   char buf[5], *pos;
  296.   if (fd <= 0)
  297.     fd = request->sockfd;
  298.   pos = buf;
  299.   rem = 5;
  300.   while (rem > 0)
  301.     {
  302.       if ((numread = gftp_read (request, pos, rem, fd)) < 0)
  303.         return (-2);
  304.       rem -= numread;
  305.       pos += numread;
  306.     }
  307.   memcpy (&message->length, buf, 4);
  308.   message->length = ntohl (message->length);
  309.   if (message->length > 34000)
  310.     {
  311.       request->logging_function (gftp_logging_error, request->user_data,
  312.                              _("Error: Message size %d too big from servern"),
  313.                              message->length);
  314.       memset (message, 0, sizeof (*message));
  315.       gftp_disconnect (request);
  316.       return (-1);
  317.     }
  318.   message->command = buf[4];
  319.   message->buffer = g_malloc (message->length + 1);
  320.   message->pos = message->buffer;
  321.   message->end = message->buffer + message->length - 1;
  322.   pos = message->buffer;
  323.   rem = message->length - 1;
  324.   while (rem > 0)
  325.     {
  326.       if ((numread = gftp_read (request, pos, rem, fd)) < 0)
  327.         return (-2);
  328.       rem -= numread;
  329.       pos += numread;
  330.     }
  331.   message->buffer[message->length] = '';
  332.   sshv2_log_command (request, gftp_logging_recv, message->command, 
  333.                      message->buffer, message->length);
  334.   
  335.   return (message->command);
  336. }
  337. static void
  338. sshv2_destroy (gftp_request * request)
  339. {
  340.   g_return_if_fail (request != NULL);
  341.   g_return_if_fail (request->protonum == GFTP_SSHV2_NUM);
  342.   g_free (request->protocol_data);
  343.   request->protocol_data = NULL;
  344. }
  345. static void
  346. sshv2_message_free (sshv2_message * message)
  347. {
  348.   if (message->buffer)
  349.     g_free (message->buffer);
  350.   memset (message, 0, sizeof (*message));
  351. }
  352. static gint32
  353. sshv2_buffer_get_int32 (gftp_request * request, sshv2_message * message,
  354.                         int expected_response)
  355. {
  356.   gint32 ret;
  357.   if (message->end - message->pos < 4)
  358.     {
  359.       request->logging_function (gftp_logging_error, request->user_data,
  360.                      _("Received wrong response from server, disconnectingn"));
  361.       sshv2_message_free (message);
  362.       gftp_disconnect (request);
  363.       return (-2);
  364.     }
  365.   memcpy (&ret, message->pos, 4);
  366.   ret = ntohl (ret);
  367.   message->pos += 4;
  368.   if (expected_response > 0 && ret != expected_response)
  369.     {
  370.       request->logging_function (gftp_logging_error, request->user_data,
  371.                      _("Received wrong response from server, disconnectingn"));
  372.       sshv2_message_free (message);
  373.       gftp_disconnect (request);
  374.       return (-2);
  375.     }
  376.   return (ret);
  377. }
  378. static char *
  379. sshv2_buffer_get_string (gftp_request * request, sshv2_message * message)
  380. {
  381.   char *string;
  382.   gint32 len;
  383.   if ((len = sshv2_buffer_get_int32 (request, message, -1)) < 0)
  384.     return (NULL);
  385.   if (len > SSH_MAX_STRING_SIZE || (message->end - message->pos < len))
  386.     {
  387.       request->logging_function (gftp_logging_error, request->user_data,
  388.                      _("Received wrong response from server, disconnectingn"));
  389.       sshv2_message_free (message);
  390.       gftp_disconnect (request);
  391.       return (NULL);
  392.     }
  393.   string = g_malloc (len + 1);
  394.   memcpy (string, message->pos, len);
  395.   string[len] = '';
  396.   message->pos += len;
  397.   return (string);
  398. }
  399. static int
  400. sshv2_getcwd (gftp_request * request)
  401. {
  402.   sshv2_message message;
  403.   sshv2_params * params;
  404.   char *tempstr, *dir;
  405.   gint32 num;
  406.   size_t len;
  407.   int ret;
  408.   g_return_val_if_fail (request != NULL, -2);
  409.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  410.   if (request->directory == NULL || *request->directory == '')
  411.     dir = ".";
  412.   else
  413.     dir = request->directory;
  414.   params = request->protocol_data;
  415.   len = strlen (dir);
  416.   tempstr = g_malloc (len + 9);
  417.   strcpy (tempstr + 8, dir);
  418.   num = htonl (params->id++);
  419.   memcpy (tempstr, &num, 4);
  420.   num = htonl (len);
  421.   memcpy (tempstr + 4, &num, 4);
  422.   if (sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len + 8) < 0)
  423.     {
  424.       g_free (tempstr);
  425.       return (-2);
  426.     }
  427.   g_free (tempstr);
  428.   if (request->directory)
  429.     {
  430.       g_free (request->directory);
  431.       request->directory = NULL;
  432.     }
  433.   memset (&message, 0, sizeof (message));
  434.   ret = sshv2_read_response (request, &message, -1);
  435.   if (ret == SSH_FXP_STATUS)
  436.     {
  437.       sshv2_message_free (&message);
  438.       return (-2);
  439.     }
  440.   else if (ret != SSH_FXP_NAME)
  441.     {
  442.       request->logging_function (gftp_logging_error, request->user_data,
  443.                      _("Received wrong response from server, disconnectingn"));
  444.       sshv2_message_free (&message);
  445.       gftp_disconnect (request);
  446.       return (-2);
  447.     }
  448.   message.pos += 4;
  449.   if (sshv2_buffer_get_int32 (request, &message, 1) < 0)
  450.     return (-2);
  451.   if ((request->directory = sshv2_buffer_get_string (request, &message)) == NULL)
  452.     return (-2);
  453.   sshv2_message_free (&message);
  454.   return (0);
  455. }
  456. static int
  457. sshv2_connect (gftp_request * request)
  458. {
  459.   char **args, *tempstr, pts_name[20], *p1, p2, *exepath, port[6];
  460.   int version, fdm, fds, s[2];
  461.   sshv2_message message;
  462.   pid_t child;
  463.   g_return_val_if_fail (request != NULL, -2);
  464.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  465.   g_return_val_if_fail (request->hostname != NULL, -2);
  466.   
  467.   if (request->sockfd > 0)
  468.     return (0);
  469.   request->logging_function (gftp_logging_misc, request->user_data,
  470.      _("Opening SSH connection to %sn"),
  471.                              request->hostname);
  472.   /* Ugh!! We don't get a login banner from sftp-server, and if we are
  473.      using ssh-agent to cache a users password, then we won't receive
  474.      any initial text from the server, and we'll block. So I just send a 
  475.      xsftp server banner over. I hope this works on most Unices */
  476.   if (request->sftpserv_path == NULL ||
  477.       *request->sftpserv_path == '')
  478.     {
  479.       p1 = "";
  480.       p2 = ' ';
  481.     }
  482.   else
  483.     {
  484.       p1 = request->sftpserv_path;
  485.       p2 = '/';
  486.     }
  487.   *port = '';
  488.   exepath = g_strdup_printf ("echo -n xsftp ; %s%csftp-server", p1, p2);
  489.   args = make_ssh_exec_args (request, exepath, sshv2_use_sftp_subsys, port);
  490.   if (ssh_use_askpass || sshv2_use_sftp_subsys)
  491.     {
  492.       fdm = fds = 0;
  493.       if (socketpair (AF_LOCAL, SOCK_STREAM, 0, s) < 0)
  494.         {
  495.           request->logging_function (gftp_logging_error, request->user_data,
  496.                                      _("Cannot create a socket pair: %sn"),
  497.                                      g_strerror (errno));
  498.           return (-2);
  499.         }
  500.     }
  501.   else
  502.     {
  503.       s[0] = s[1] = 0;
  504.       if ((fdm = ptym_open (pts_name)) < 0)
  505.         {
  506.           request->logging_function (gftp_logging_error, request->user_data,
  507.                                 _("Cannot open master pty %s: %sn"), pts_name,
  508.                                 g_strerror (errno));
  509.           return (-2);
  510.         }
  511.     }
  512.  
  513.   if ((child = fork ()) == 0)
  514.     {
  515.       setsid ();
  516.       if (ssh_use_askpass || sshv2_use_sftp_subsys)
  517.         {
  518.           close (s[0]);
  519.           fds = s[1];
  520.         }
  521.       else
  522.         {
  523.           if ((fds = ptys_open (fdm, pts_name)) < 0)
  524.             {
  525.               printf ("Cannot open slave pts %s: %sn", pts_name, 
  526.                       g_strerror (errno));
  527.               return (-1);
  528.             }
  529.           close (fdm);
  530.         }
  531.       tty_raw (fds);
  532.       dup2 (fds, 0);
  533.       dup2 (fds, 1);
  534.       dup2 (fds, 2);
  535.       if (!ssh_use_askpass && fds > 2)
  536.         close (fds);
  537.       execvp (ssh_prog_name != NULL && *ssh_prog_name != '' ?
  538.               ssh_prog_name : "ssh", args);
  539.       printf (_("Error: Cannot execute ssh: %sn"), g_strerror (errno));
  540.       return (-1);
  541.     }
  542.   else if (child > 0)
  543.     {
  544.       if (ssh_use_askpass || sshv2_use_sftp_subsys)
  545.         {
  546.           close (s[1]);
  547.           fdm = s[0];
  548.         }
  549.       tty_raw (fdm);
  550.       if (!sshv2_use_sftp_subsys)
  551.         {
  552.           tempstr = ssh_start_login_sequence (request, fdm);
  553.           if (!tempstr ||
  554.               !(strlen (tempstr) > 4 && strcmp (tempstr + strlen (tempstr) - 5,
  555.                                                 "xsftp") == 0))
  556.             {
  557.               g_free (args);
  558.               g_free (exepath);
  559.               return (-2);
  560.             }
  561.           g_free (tempstr);
  562.         }
  563.       g_free (args);
  564.       g_free (exepath);
  565.       request->sockfd = fdm;
  566.       version = htonl (SSH_MY_VERSION);
  567.       if (sshv2_send_command (request, SSH_FXP_INIT, (char *) &version, 4) < 0)
  568.         return (-2);
  569.       memset (&message, 0, sizeof (message));
  570.       if (sshv2_read_response (request, &message, -1) != SSH_FXP_VERSION)
  571.         {
  572.           request->logging_function (gftp_logging_error, request->user_data,
  573.                    _("Received wrong response from server, disconnectingn"));
  574.           sshv2_message_free (&message);
  575.           gftp_disconnect (request);
  576.           return (-2);
  577.         }
  578.       sshv2_message_free (&message);
  579.       request->logging_function (gftp_logging_misc, request->user_data,
  580.          _("Successfully logged into SSH server %sn"),
  581.                                  request->hostname);
  582.     }
  583.   else
  584.     {
  585.       request->logging_function (gftp_logging_error, request->user_data,
  586.                                  _("Cannot fork another process: %sn"),
  587.                                  g_strerror (errno));
  588.       g_free (args);
  589.       return (-1);
  590.     }
  591.   if (sshv2_getcwd (request) < 0)
  592.     {
  593.       if (request->directory)
  594.         g_free (request->directory);
  595.       request->directory = g_strdup (".");
  596.       if (sshv2_getcwd (request) < 0)
  597.         {
  598.           gftp_disconnect (request);
  599.           return (-2);
  600.         }
  601.     }
  602.   return (0);
  603. }
  604. static void
  605. sshv2_disconnect (gftp_request * request)
  606. {
  607.   sshv2_params * params;
  608.   g_return_if_fail (request != NULL);
  609.   g_return_if_fail (request->protonum == GFTP_SSHV2_NUM);
  610.   params = request->protocol_data;
  611.   if (request->sockfd > 0)
  612.     {
  613.       request->logging_function (gftp_logging_misc, request->user_data,
  614.          _("Disconnecting from site %sn"),
  615.                                  request->hostname);
  616.       if (close (request->sockfd) < 0)
  617.         request->logging_function (gftp_logging_error, request->user_data,
  618.                                    _("Error closing file descriptor: %sn"),
  619.                                    g_strerror (errno));
  620.       request->sockfd = -1;
  621.     }
  622.   if (params->message.buffer != NULL)
  623.     sshv2_message_free (&params->message);
  624. }
  625. static int
  626. sshv2_end_transfer (gftp_request * request)
  627. {
  628.   sshv2_params * params;
  629.   sshv2_message message;
  630.   gint32 len;
  631.   g_return_val_if_fail (request != NULL, -2);
  632.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  633.   params = request->protocol_data;
  634.   if (params->message.buffer != NULL)
  635.     {
  636.       sshv2_message_free (&params->message);
  637.       params->count = 0;
  638.     }
  639.   if (params->handle_len > 0)
  640.     {
  641.       len = htonl (params->id++);
  642.       memcpy (params->handle, &len, 4);
  643.       if (sshv2_send_command (request, SSH_FXP_CLOSE, params->handle, 
  644.                               params->handle_len) < 0)
  645.         return (-2);
  646.       memset (&message, 0, sizeof (message));
  647.       if (sshv2_read_response (request, &message, -1) != SSH_FXP_STATUS)
  648.         {
  649.           request->logging_function (gftp_logging_error, request->user_data,
  650.                      _("Received wrong response from server, disconnectingn"));
  651.           sshv2_message_free (&message);
  652.           gftp_disconnect (request);
  653.           return (-2);
  654.         }
  655.       sshv2_message_free (&message);
  656.       params->handle_len = 0;
  657.     }  
  658.   if (params->read_buffer != NULL)
  659.     {
  660.       g_free (params->read_buffer);
  661.       params->read_buffer = NULL;
  662.     }
  663.   return (0);
  664. }
  665. static int
  666. sshv2_list_files (gftp_request * request)
  667. {
  668.   sshv2_params * params;
  669.   sshv2_message message;
  670.   char *tempstr;
  671.   gint32 len;
  672.   int ret;
  673.   g_return_val_if_fail (request != NULL, -2);
  674.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  675.   g_return_val_if_fail (request->sockfd > 0, -2);
  676.   params = request->protocol_data;
  677.   request->logging_function (gftp_logging_misc, request->user_data,
  678.      _("Retrieving directory listing...n"));
  679.   tempstr = g_malloc (strlen (request->directory) + 9);
  680.   len = htonl (params->id++);
  681.   memcpy (tempstr, &len, 4);
  682.   len = htonl (strlen (request->directory));
  683.   memcpy (tempstr + 4, &len, 4);
  684.   strcpy (tempstr + 8, request->directory);
  685.   if (sshv2_send_command (request, SSH_FXP_OPENDIR, tempstr, 
  686.                           strlen (request->directory) + 8) < 0)
  687.     {
  688.       g_free (tempstr);
  689.       return (-2);
  690.     }
  691.   g_free (tempstr);
  692.   memset (&message, 0, sizeof (message));
  693.   ret = sshv2_read_response (request, &message, -1);
  694.   if (ret == SSH_FXP_STATUS)
  695.     {
  696.       sshv2_message_free (&message);
  697.       return (-2);
  698.     }
  699.   else if (ret != SSH_FXP_HANDLE)
  700.     {
  701.       request->logging_function (gftp_logging_error, request->user_data,
  702.                      _("Received wrong response from server, disconnectingn"));
  703.       sshv2_message_free (&message);
  704.       gftp_disconnect (request);
  705.       return (-2);
  706.     }
  707.   if (message.length - 4 > SSH_MAX_HANDLE_SIZE)
  708.     {
  709.       request->logging_function (gftp_logging_error, request->user_data,
  710.                              _("Error: Message size %d too big from servern"),
  711.                              message.length - 4);
  712.       sshv2_message_free (&message);
  713.       gftp_disconnect (request);
  714.       return (-1);
  715.         
  716.     }
  717.   memset (params->handle, 0, 4);
  718.   memcpy (params->handle + 4, message.buffer + 4, message.length - 5);
  719.   params->handle_len = message.length - 1;
  720.   sshv2_message_free (&message);
  721.   params->count = 0;
  722.   return (0);
  723. }
  724. static int
  725. sshv2_get_next_file (gftp_request * request, gftp_file * fle, int fd)
  726. {
  727.   gint32 len, attrs, longnamelen;
  728.   int ret, i, count, retsize;
  729.   sshv2_params *params;
  730.   char *longname;
  731.   g_return_val_if_fail (request != NULL, -2);
  732.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  733.   g_return_val_if_fail (fle != NULL, -2);
  734.   params = request->protocol_data;
  735.   if (request->last_dir_entry)
  736.     {
  737.       g_free (request->last_dir_entry);
  738.       request->last_dir_entry = NULL;
  739.       request->last_dir_entry_len = 0;
  740.     }
  741.   retsize = 0;
  742.   if (params->count > 0)
  743.     ret = SSH_FXP_NAME;
  744.   else
  745.     {
  746.       if (!request->cached)
  747.         {
  748.           if (params->message.buffer != NULL)
  749.             sshv2_message_free (&params->message);
  750.           len = htonl (params->id++);
  751.           memcpy (params->handle, &len, 4);
  752.           if (sshv2_send_command (request, SSH_FXP_READDIR, params->handle,
  753.                                   params->handle_len) < 0)
  754.             return (-2);
  755.         }
  756.       if ((ret = sshv2_read_response (request, &params->message, fd)) < 0)
  757.         return (-2);
  758.       if (!request->cached)
  759.         {
  760.           request->last_dir_entry = g_malloc (params->message.length + 4);
  761.           len = htonl (params->message.length);
  762.           memcpy (request->last_dir_entry, &len, 4);
  763.           request->last_dir_entry[4] = params->message.command;
  764.           memcpy (request->last_dir_entry + 5, params->message.buffer, 
  765.                   params->message.length - 1);
  766.           request->last_dir_entry_len = params->message.length + 4;
  767.         }
  768.       if (ret == SSH_FXP_NAME)
  769.         {
  770.           params->message.pos = params->message.buffer + 4;
  771.           if ((params->count = sshv2_buffer_get_int32 (request, 
  772.                        &params->message, -1)) < 0)
  773.             return (-2);
  774.         }
  775.     }
  776.   if (ret == SSH_FXP_NAME)
  777.     {
  778.       if ((len = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0 ||
  779.           params->message.pos + len > params->message.end)
  780.         return (-2);
  781.       params->message.pos += len;
  782.       if ((longnamelen = sshv2_buffer_get_int32 (request, 
  783.                                                  &params->message, -1)) < 0 || 
  784.            params->message.pos + longnamelen > params->message.end)
  785.         return (-2);
  786.       longname = params->message.pos;
  787.       params->message.pos += longnamelen;
  788.       if ((attrs = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0)
  789.         return (-2);
  790.       if (attrs & SSH_FILEXFER_ATTR_SIZE)
  791.         {
  792.           params->message.pos += 8;
  793.           if (params->message.pos > params->message.end)
  794.             {
  795.               request->logging_function (gftp_logging_error, request->user_data,
  796.                      _("Received wrong response from server, disconnectingn"));
  797.               sshv2_message_free (&params->message);
  798.               gftp_disconnect (request);
  799.               return (-2);
  800.             }
  801.         }
  802.       if (attrs & SSH_FILEXFER_ATTR_UIDGID)
  803.         {
  804.           params->message.pos += 8;
  805.           if (params->message.pos > params->message.end)
  806.             {
  807.               request->logging_function (gftp_logging_error, request->user_data,
  808.                      _("Received wrong response from server, disconnectingn"));
  809.               sshv2_message_free (&params->message);
  810.               gftp_disconnect (request);
  811.               return (-2);
  812.             }
  813.         }
  814.       if (attrs & SSH_FILEXFER_ATTR_PERMISSIONS)
  815.         {
  816.           params->message.pos += 4;
  817.           if (params->message.pos > params->message.end)
  818.             {
  819.               request->logging_function (gftp_logging_error, request->user_data,
  820.                      _("Received wrong response from server, disconnectingn"));
  821.               sshv2_message_free (&params->message);
  822.               gftp_disconnect (request);
  823.               return (-2);
  824.             }
  825.         }
  826.       if (attrs & SSH_FILEXFER_ATTR_ACMODTIME)
  827.         {
  828.           params->message.pos += 8;
  829.           if (params->message.pos > params->message.end)
  830.             {
  831.               request->logging_function (gftp_logging_error, request->user_data,
  832.                      _("Received wrong response from server, disconnectingn"));
  833.               sshv2_message_free (&params->message);
  834.               gftp_disconnect (request);
  835.               return (-2);
  836.             }
  837.         }
  838.       if (attrs & SSH_FILEXFER_ATTR_EXTENDED)
  839.         {
  840.           if ((count = sshv2_buffer_get_int32 (request,
  841.                                                &params->message, -1)) < 0)
  842.             return (-2);
  843.           for (i=0; i<count; i++)
  844.             {
  845.               if ((len = sshv2_buffer_get_int32 (request, 
  846.                                                  &params->message, -1)) < 0 ||
  847.                   params->message.pos + len + 4 > params->message.end)
  848.                 return (-2);
  849.               params->message.pos += len + 4;
  850.               if ((len = sshv2_buffer_get_int32 (request, 
  851.                                                  &params->message, -1)) < 0 ||
  852.                   params->message.pos + len + 4 > params->message.end)
  853.                 return (-2);
  854.            
  855.               params->message.pos += len + 4;
  856.             }
  857.         }
  858.       longname[longnamelen] = '';
  859.       /* The commercial SSH2 puts a / and * after some entries */
  860.       if (longname[longnamelen - 1] == '*')
  861.         longname[--longnamelen] = '';
  862.       if (longname[longnamelen - 1] == '/')
  863.         longname[--longnamelen] = '';
  864.       if (gftp_parse_ls (longname, fle) != 0)
  865.         {
  866.           gftp_file_destroy (fle);
  867.           return (-2);
  868.         }
  869.       retsize = strlen (longname);
  870.       params->count--;
  871.     }
  872.   else if (ret == SSH_FXP_STATUS)
  873.     {
  874.       sshv2_message_free (&params->message);
  875.       return (0);
  876.     }
  877.   else
  878.     {
  879.       request->logging_function (gftp_logging_error, request->user_data,
  880.                      _("Received wrong response from server, disconnectingn"));
  881.       sshv2_message_free (&params->message);
  882.       gftp_disconnect (request);
  883.       return (-2);
  884.     }
  885.   return (retsize);
  886. }
  887. static int
  888. sshv2_chdir (gftp_request * request, const char *directory)
  889. {
  890.   sshv2_message message;
  891.   sshv2_params * params;
  892.   char *tempstr, *dir;
  893.   gint32 num;
  894.   size_t len;
  895.   int ret;
  896.   g_return_val_if_fail (request != NULL, -2);
  897.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  898.   params = request->protocol_data;
  899.   if (request->directory != directory)
  900.     {
  901.       if (*directory == '/')
  902.         {
  903.           len = strlen (directory) + 8;
  904.           tempstr = g_malloc (len + 1);
  905.           strcpy (tempstr + 8, directory);
  906.         }
  907.       else
  908.         {
  909.           len = strlen (directory) + strlen (request->directory) + 9;
  910.           tempstr = g_malloc (len + 1);
  911.           strcpy (tempstr + 8, request->directory);
  912.           strcat (tempstr + 8, "/");
  913.           strcat (tempstr + 8, directory);
  914.         }
  915.       num = htonl (params->id++);
  916.       memcpy (tempstr, &num, 4);
  917.       num = htonl (len - 8);
  918.       memcpy (tempstr + 4, &num, 4);
  919.       if (sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len) < 0)
  920.         {
  921.           g_free (tempstr);
  922.           return (-2);
  923.         }
  924.       g_free (tempstr);
  925.       memset (&message, 0, sizeof (message));
  926.       ret = sshv2_read_response (request, &message, -1);
  927.       if (ret == SSH_FXP_STATUS)
  928.         {
  929.           sshv2_message_free (&message);
  930.           return (-2);
  931.         }
  932.       else if (ret != SSH_FXP_NAME)
  933.         {
  934.           request->logging_function (gftp_logging_error, request->user_data,
  935.                      _("Received wrong response from server, disconnectingn"));
  936.           sshv2_message_free (&message);
  937.           gftp_disconnect (request);
  938.           return (-2);
  939.         }
  940.       message.pos += 4;
  941.       if (sshv2_buffer_get_int32 (request, &message, 1) != 1)
  942.         return (-2);
  943.       if ((dir = sshv2_buffer_get_string (request, &message)) == NULL)
  944.         return (-2);
  945.       if (request->directory)
  946.         g_free (request->directory);
  947.       request->directory = dir;
  948.       sshv2_message_free (&message);
  949.       return (0);
  950.     }
  951.   else
  952.     return (sshv2_getcwd (request));
  953. }
  954. static int 
  955. sshv2_rmdir (gftp_request * request, const char *directory)
  956. {
  957.   sshv2_params * params;
  958.   sshv2_message message;
  959.   char *tempstr;
  960.   gint32 num;
  961.   size_t len;
  962.   g_return_val_if_fail (request != NULL, -2);
  963.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  964.   g_return_val_if_fail (directory != NULL, -2);
  965.   params = request->protocol_data;
  966.   if (*directory == '/')
  967.     {
  968.       len = strlen (directory) + 8;
  969.       tempstr = g_malloc (len + 1);
  970.       strcpy (tempstr + 8, directory);
  971.     }
  972.   else
  973.     {
  974.       len = strlen (directory) + strlen (request->directory) + 9;
  975.       tempstr = g_malloc (len + 1);
  976.       strcpy (tempstr + 8, request->directory);
  977.       strcat (tempstr + 8, "/");
  978.       strcat (tempstr + 8, directory);
  979.     }
  980.   num = htonl (params->id++);
  981.   memcpy (tempstr, &num, 4);
  982.   num = htonl (len - 8);
  983.   memcpy (tempstr + 4, &num, 4);
  984.   if (sshv2_send_command (request, SSH_FXP_RMDIR, tempstr, len) < 0)
  985.     {
  986.       g_free (tempstr);
  987.       return (-2);
  988.     }
  989.   g_free (tempstr);
  990.   memset (&message, 0, sizeof (message));
  991.   if (sshv2_read_response (request, &message, -1) < 0)
  992.     return (-2);
  993.   message.pos += 4;
  994.   if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
  995.     return (-2);
  996.   sshv2_message_free (&message);
  997.   return (0);
  998. }
  999. static int 
  1000. sshv2_rmfile (gftp_request * request, const char *file)
  1001. {
  1002.   sshv2_params * params;
  1003.   sshv2_message message;
  1004.   char *tempstr;
  1005.   gint32 num;
  1006.   size_t len;
  1007.   g_return_val_if_fail (request != NULL, -2);
  1008.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1009.   g_return_val_if_fail (file != NULL, -2);
  1010.   params = request->protocol_data;
  1011.   if (*file == '/')
  1012.     {
  1013.       len = strlen (file) + 8;
  1014.       tempstr = g_malloc (len + 1);
  1015.       strcpy (tempstr + 8, file);
  1016.     }
  1017.   else
  1018.     {
  1019.       len = strlen (file) + strlen (request->directory) + 9;
  1020.       tempstr = g_malloc (len + 1);
  1021.       strcpy (tempstr + 8, request->directory);
  1022.       strcat (tempstr + 8, "/");
  1023.       strcat (tempstr + 8, file);
  1024.     }
  1025.   num = htonl (params->id++);
  1026.   memcpy (tempstr, &num, 4);
  1027.   num = htonl (len - 8);
  1028.   memcpy (tempstr + 4, &num, 4);
  1029.   if (sshv2_send_command (request, SSH_FXP_REMOVE, tempstr, len) < 0)
  1030.     {
  1031.       g_free (tempstr);
  1032.       return (-2);
  1033.     }
  1034.   g_free (tempstr);
  1035.   memset (&message, 0, sizeof (message));
  1036.   if (sshv2_read_response (request, &message, -1) < 0)
  1037.     return (-2);
  1038.   message.pos += 4;
  1039.   if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
  1040.     return (-2);
  1041.   sshv2_message_free (&message);
  1042.   return (0);
  1043. }
  1044. static int 
  1045. sshv2_chmod (gftp_request * request, const char *file, int mode)
  1046. {
  1047.   char *tempstr, buf[10];
  1048.   sshv2_params * params;
  1049.   sshv2_message message;
  1050.   gint32 num;
  1051.   size_t len;
  1052.   g_return_val_if_fail (request != NULL, -2);
  1053.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1054.   g_return_val_if_fail (file != NULL, -2);
  1055.   params = request->protocol_data;
  1056.   if (*file == '/')
  1057.     {
  1058.       len = strlen (file) + 16;
  1059.       tempstr = g_malloc (len + 1);
  1060.       strcpy (tempstr + 8, file);
  1061.     }
  1062.   else
  1063.     {
  1064.       len = strlen (file) + strlen (request->directory) + 17;
  1065.       tempstr = g_malloc (len + 1);
  1066.       strcpy (tempstr + 8, request->directory);
  1067.       strcat (tempstr + 8, "/");
  1068.       strcat (tempstr + 8, file);
  1069.     }
  1070.   num = htonl (params->id++);
  1071.   memcpy (tempstr, &num, 4);
  1072.   num = htonl (len - 16);
  1073.   memcpy (tempstr + 4, &num, 4);
  1074.   num = htonl (SSH_FILEXFER_ATTR_PERMISSIONS);
  1075.   memcpy (tempstr + len - 8, &num, 4);
  1076.   g_snprintf (buf, sizeof (buf), "%d", mode);
  1077.   num = htonl (strtol (buf, NULL, 8));
  1078.   memcpy (tempstr + len - 4, &num, 4);
  1079.   if (sshv2_send_command (request, SSH_FXP_SETSTAT, tempstr, len) < 0)
  1080.     {
  1081.       g_free (tempstr);
  1082.       return (-2);
  1083.     }
  1084.   g_free (tempstr);
  1085.   memset (&message, 0, sizeof (message));
  1086.   if (sshv2_read_response (request, &message, -1) < 0)
  1087.     return (-2);
  1088.   message.pos += 4;
  1089.   if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
  1090.     return (-2);
  1091.   sshv2_message_free (&message);
  1092.   return (0);
  1093. }
  1094. static int 
  1095. sshv2_mkdir (gftp_request * request, const char *newdir)
  1096. {
  1097.   sshv2_params * params;
  1098.   sshv2_message message;
  1099.   char *tempstr;
  1100.   gint32 num;
  1101.   size_t len;
  1102.   g_return_val_if_fail (request != NULL, -2);
  1103.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1104.   g_return_val_if_fail (newdir != NULL, -2);
  1105.   params = request->protocol_data;
  1106.   if (*newdir == '/')
  1107.     {
  1108.       len = strlen (newdir) + 12;
  1109.       tempstr = g_malloc (len + 1);
  1110.       strcpy (tempstr + 8, newdir);
  1111.     }
  1112.   else
  1113.     {
  1114.       len = strlen (newdir) + strlen (request->directory) + 13;
  1115.       tempstr = g_malloc (len + 1);
  1116.       strcpy (tempstr + 8, request->directory);
  1117.       strcat (tempstr + 8, "/");
  1118.       strcat (tempstr + 8, newdir);
  1119.     }
  1120.   num = htonl (params->id++);
  1121.   memcpy (tempstr, &num, 4);
  1122.   num = htonl (len - 12);
  1123.   memcpy (tempstr + 4, &num, 4);
  1124.   memset (tempstr + len - 4, 0, 4);  /* attributes */
  1125.   if (sshv2_send_command (request, SSH_FXP_MKDIR, tempstr, len) < 0)
  1126.     {
  1127.       g_free (tempstr);
  1128.       return (-2);
  1129.     }
  1130.   g_free (tempstr);
  1131.   memset (&message, 0, sizeof (message));
  1132.   if (sshv2_read_response (request, &message, -1) < 0)
  1133.     return (-2);
  1134.   message.pos += 4;
  1135.   if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
  1136.     return (-2);
  1137.   sshv2_message_free (&message);
  1138.   return (0);
  1139. }
  1140. static int 
  1141. sshv2_rename (gftp_request * request, const char *oldname, const char *newname)
  1142. {
  1143.   char *tempstr, *oldstr, *newstr;
  1144.   sshv2_params * params;
  1145.   sshv2_message message;
  1146.   gint32 num;
  1147.   size_t oldlen, newlen;
  1148.   g_return_val_if_fail (request != NULL, -2);
  1149.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1150.   g_return_val_if_fail (oldname != NULL, -2);
  1151.   g_return_val_if_fail (newname != NULL, -2);
  1152.   params = request->protocol_data;
  1153.   if (*oldname == '/')
  1154.     {
  1155.       oldlen = strlen (oldname); 
  1156.       oldstr = g_strdup (oldname);
  1157.     }
  1158.   else
  1159.     {
  1160.       oldlen = strlen (request->directory) + strlen (oldname) + 1;
  1161.       oldstr = g_strconcat (request->directory, "/", oldname, NULL);
  1162.     }
  1163.   if (*newname == '/')
  1164.     {
  1165.       newlen = strlen (newname); 
  1166.       newstr = g_strdup (newname);
  1167.     }
  1168.   else
  1169.     {
  1170.       newlen = strlen (request->directory) + strlen (newname) + 1;
  1171.       newstr = g_strconcat (request->directory, "/", newname, NULL);
  1172.     }
  1173.   tempstr = g_malloc (oldlen + newlen + 13);
  1174.   num = htonl (params->id++);
  1175.   memcpy (tempstr, &num, 4);
  1176.   num = htonl (oldlen);
  1177.   memcpy (tempstr + 4, &num, 4);
  1178.   strcpy (tempstr + 8, oldstr);
  1179.   
  1180.   num = htonl (newlen);
  1181.   memcpy (tempstr + 8 + oldlen, &num, 4);
  1182.   strcpy (tempstr + 12 + oldlen, newstr);
  1183.   if (sshv2_send_command (request, SSH_FXP_RENAME, tempstr, oldlen + newlen + 12) < 0)
  1184.     {
  1185.       g_free (tempstr);
  1186.       return (-2);
  1187.     }
  1188.   g_free (tempstr);
  1189.   memset (&message, 0, sizeof (message));
  1190.   if (sshv2_read_response (request, &message, -1) < 0)
  1191.     return (-2);
  1192.   message.pos += 4;
  1193.   if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
  1194.     return (-2);
  1195.   sshv2_message_free (&message);
  1196.   return (0);
  1197. }
  1198. static int 
  1199. sshv2_set_file_time (gftp_request * request, const char *file, time_t datetime)
  1200. {
  1201.   sshv2_params * params;
  1202.   sshv2_message message;
  1203.   char *tempstr;
  1204.   gint32 num;
  1205.   size_t len;
  1206.   g_return_val_if_fail (request != NULL, -2);
  1207.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1208.   g_return_val_if_fail (file != NULL, -2);
  1209.   params = request->protocol_data;
  1210.   if (*file == '/')
  1211.     {
  1212.       len = strlen (file) + 20;
  1213.       tempstr = g_malloc (len + 1);
  1214.       strcpy (tempstr + 8, file);
  1215.     }
  1216.   else
  1217.     {
  1218.       len = strlen (file) + strlen (request->directory) + 21;
  1219.       tempstr = g_malloc (len + 1);
  1220.       strcpy (tempstr + 8, request->directory);
  1221.       strcat (tempstr + 8, "/");
  1222.       strcat (tempstr + 8, file);
  1223.     }
  1224.   num = htonl (params->id++);
  1225.   memcpy (tempstr, &num, 4);
  1226.   num = htonl (len - 20);
  1227.   memcpy (tempstr + 4, &num, 4);
  1228.   num = htonl (SSH_FILEXFER_ATTR_ACMODTIME);
  1229.   memcpy (tempstr + len - 12, &num, 4);
  1230.   num = htonl (datetime);
  1231.   memcpy (tempstr + len - 8, &num, 4);
  1232.   num = htonl (datetime);
  1233.   memcpy (tempstr + len - 4, &num, 4);
  1234.   if (sshv2_send_command (request, SSH_FXP_SETSTAT, tempstr, len) < 0)
  1235.     {
  1236.       g_free (tempstr);
  1237.       return (-2);
  1238.     }
  1239.   g_free (tempstr);
  1240.   memset (&message, 0, sizeof (message));
  1241.   if (sshv2_read_response (request, &message, -1) < 0)
  1242.     return (-2);
  1243.   message.pos += 4;
  1244.   if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
  1245.     return (-2);
  1246.   sshv2_message_free (&message);
  1247.   return (0);
  1248. }
  1249. static off_t
  1250. sshv2_get_file_size (gftp_request * request, const char *file)
  1251. {
  1252.   gint32 len, highnum, lownum, attrs, num;
  1253.   sshv2_params * params;
  1254.   char *tempstr;
  1255.   int serv_ret;
  1256. #ifdef G_HAVE_GINT64
  1257.   gint64 ret;
  1258. #endif
  1259.   g_return_val_if_fail (request != NULL, -2);
  1260.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1261.   g_return_val_if_fail (file != NULL, -2);
  1262.   params = request->protocol_data;
  1263.   if (*file == '/')
  1264.     {
  1265.       len = strlen (file);
  1266.       tempstr = g_malloc (len + 9);
  1267.       strcpy (tempstr + 8, file);
  1268.     }
  1269.   else
  1270.     {
  1271.       len = strlen (file) + strlen (request->directory) + 1;
  1272.       tempstr = g_malloc (len + 9);
  1273.       strcpy (tempstr + 8, request->directory);
  1274.       strcat (tempstr + 8, "/");
  1275.       strcat (tempstr + 8, file);
  1276.     }
  1277.   num = htonl (params->id++);
  1278.   memcpy (tempstr, &num, 4);
  1279.   num = htonl (len);
  1280.   memcpy (tempstr + 4, &num, 4);
  1281.   if (sshv2_send_command (request, SSH_FXP_STAT, tempstr, len + 8) < 0)
  1282.     {
  1283.       g_free (tempstr);
  1284.       return (-2);
  1285.     }
  1286.   g_free (tempstr);
  1287.   memset (&params->message, 0, sizeof (params->message));
  1288.   serv_ret = sshv2_read_response (request, &params->message, -1);
  1289.   if (serv_ret == SSH_FXP_STATUS)
  1290.     {
  1291.       sshv2_message_free (&params->message);
  1292.       return (-2);
  1293.     }
  1294.   else if (serv_ret != SSH_FXP_ATTRS)
  1295.     {
  1296.       request->logging_function (gftp_logging_error, request->user_data,
  1297.                      _("Received wrong response from server, disconnectingn"));
  1298.       sshv2_message_free (&params->message);
  1299.       gftp_disconnect (request);
  1300.       return (-2);
  1301.     }
  1302.   if (params->message.length < 5)
  1303.     return (-2);
  1304.   params->message.pos += 4;
  1305.   if ((attrs = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0)
  1306.     return (-2);
  1307.   if (attrs & SSH_FILEXFER_ATTR_SIZE)
  1308.     {
  1309.       if ((highnum = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0)
  1310.         return (-2);
  1311.       if ((lownum = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0)
  1312.         return (-2);
  1313.       sshv2_message_free (&params->message);
  1314. #if G_HAVE_GINT64
  1315.       ret = (gint64) lownum | ((gint64) highnum >> 32);
  1316.       return (ret);
  1317. #else
  1318.       return (lownum);
  1319. #endif
  1320.     }
  1321.   sshv2_message_free (&params->message);
  1322.   return (0);
  1323. }
  1324. static off_t
  1325. sshv2_get_file (gftp_request * request, const char *file, int fd,
  1326.                 off_t startsize)
  1327. {
  1328.   sshv2_params * params;
  1329.   sshv2_message message;
  1330.   char *tempstr;
  1331.   size_t stlen;
  1332.   gint32 num;
  1333.   int ret;
  1334.   g_return_val_if_fail (request != NULL, -2);
  1335.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1336.   g_return_val_if_fail (request->sockfd > 0, -2);
  1337.   /* fd ignored for this protocol */
  1338.   params = request->protocol_data;
  1339.   params->offset = startsize;
  1340.   if (*file == '/')
  1341.     {
  1342.       stlen = strlen (file);
  1343.       tempstr = g_malloc (stlen + 16);
  1344.       strcpy (tempstr + 8, file);
  1345.     }
  1346.   else
  1347.     {
  1348.       stlen = strlen (file) + strlen (request->directory) + 1;
  1349.       tempstr = g_malloc (stlen + 16);
  1350.       strcpy (tempstr + 8, request->directory);
  1351.       strcat (tempstr + 8, "/");
  1352.       strcat (tempstr + 8, file);
  1353.     }
  1354.   num = htonl (params->id++);
  1355.   memcpy (tempstr, &num, 4);
  1356.   num = htonl (stlen);
  1357.   memcpy (tempstr + 4, &num, 4);
  1358.   num = htonl (SSH_FXF_READ);
  1359.   memcpy (tempstr + 8 + stlen, &num, 4);
  1360.   memset (tempstr + 12 + stlen, 0, 4);
  1361.   
  1362.   if (sshv2_send_command (request, SSH_FXP_OPEN, tempstr, stlen + 16) < 0)
  1363.     {
  1364.       g_free (tempstr);
  1365.       return (-2);
  1366.     }
  1367.   g_free (tempstr);
  1368.   memset (&message, 0, sizeof (message));
  1369.   ret = sshv2_read_response (request, &message, -1);
  1370.   if (ret == SSH_FXP_STATUS)
  1371.     {
  1372.       sshv2_message_free (&message);
  1373.       return (-2);
  1374.     }
  1375.   else if (ret != SSH_FXP_HANDLE)
  1376.     {
  1377.       request->logging_function (gftp_logging_error, request->user_data,
  1378.                      _("Received wrong response from server, disconnectingn"));
  1379.       sshv2_message_free (&message);
  1380.       gftp_disconnect (request);
  1381.       return (-2);
  1382.     }
  1383.   if (message.length - 4 > SSH_MAX_HANDLE_SIZE)
  1384.     {
  1385.       request->logging_function (gftp_logging_error, request->user_data,
  1386.                              _("Error: Message size %d too big from servern"),
  1387.                              message.length - 4);
  1388.       sshv2_message_free (&message);
  1389.       gftp_disconnect (request);
  1390.       return (-1);
  1391.         
  1392.     }
  1393.   memset (params->handle, 0, 4);
  1394.   memcpy (params->handle + 4, message.buffer+ 4, message.length - 5);
  1395.   params->handle_len = message.length - 1;
  1396.   sshv2_message_free (&message);
  1397.   return (sshv2_get_file_size (request, file));
  1398. }
  1399. static int
  1400. sshv2_put_file (gftp_request * request, const char *file, int fd,
  1401.                 off_t startsize, off_t totalsize)
  1402. {
  1403.   sshv2_params * params;
  1404.   sshv2_message message;
  1405.   char *tempstr;
  1406.   size_t stlen;
  1407.   gint32 num;
  1408.   int ret;
  1409.   g_return_val_if_fail (request != NULL, -2);
  1410.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1411.   g_return_val_if_fail (request->sockfd > 0, -2);
  1412.   /* fd ignored for this protocol */
  1413.   params = request->protocol_data;
  1414.   params->offset = 0;
  1415.   if (*file == '/')
  1416.     {
  1417.       stlen = strlen (file);
  1418.       tempstr = g_malloc (stlen + 16);
  1419.       strcpy (tempstr + 8, file);
  1420.     }
  1421.   else
  1422.     {
  1423.       stlen = strlen (file) + strlen (request->directory) + 1;
  1424.       tempstr = g_malloc (stlen + 16);
  1425.       strcpy (tempstr + 8, request->directory);
  1426.       strcat (tempstr + 8, "/");
  1427.       strcat (tempstr + 8, file);
  1428.     }
  1429.   num = htonl (params->id++);
  1430.   memcpy (tempstr, &num, 4);
  1431.   num = htonl (stlen);
  1432.   memcpy (tempstr + 4, &num, 4);
  1433.   if (startsize > 0)
  1434.     num = htonl (SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_APPEND);
  1435.   else
  1436.     num = htonl (SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC);
  1437.   memcpy (tempstr + 8 + stlen, &num, 4);
  1438.   memset (tempstr + 12 + stlen, 0, 4);
  1439.   
  1440.   if (sshv2_send_command (request, SSH_FXP_OPEN, tempstr, stlen + 16) < 0)
  1441.     {
  1442.       g_free (tempstr);
  1443.       return (-2);
  1444.     }
  1445.   g_free (tempstr);
  1446.   memset (&message, 0, sizeof (message));
  1447.   ret = sshv2_read_response (request, &message, -1);
  1448.   if (ret == SSH_FXP_STATUS)
  1449.     {
  1450.       sshv2_message_free (&message);
  1451.       return (-2);
  1452.     }
  1453.   else if (ret != SSH_FXP_HANDLE)
  1454.     {
  1455.       request->logging_function (gftp_logging_error, request->user_data,
  1456.                      _("Received wrong response from server, disconnectingn"));
  1457.       sshv2_message_free (&message);
  1458.       gftp_disconnect (request);
  1459.       return (-2);
  1460.     }
  1461.   if (message.length - 4 > SSH_MAX_HANDLE_SIZE)
  1462.     {
  1463.       request->logging_function (gftp_logging_error, request->user_data,
  1464.                              _("Error: Message size %d too big from servern"),
  1465.                              message.length - 4);
  1466.       sshv2_message_free (&message);
  1467.       gftp_disconnect (request);
  1468.       return (-1);
  1469.         
  1470.     }
  1471.   memset (params->handle, 0, 4);
  1472.   memcpy (params->handle + 4, message.buffer+ 4, message.length - 5);
  1473.   params->handle_len = message.length - 1;
  1474.   sshv2_message_free (&message);
  1475.   return (0);
  1476. }
  1477. static ssize_t 
  1478. sshv2_get_next_file_chunk (gftp_request * request, char *buf, size_t size)
  1479. {
  1480.   sshv2_params * params;
  1481.   sshv2_message message;
  1482.   gint32 num;
  1483. #ifdef G_HAVE_GINT64
  1484.   gint64 offset;
  1485. #else
  1486.   gint32 offset;
  1487. #endif
  1488.   g_return_val_if_fail (request != NULL, -2);
  1489.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1490.   g_return_val_if_fail (request->sockfd > 0, -2);
  1491.   g_return_val_if_fail (buf != NULL, -2);
  1492.   params = request->protocol_data;
  1493.   if (params->read_buffer == NULL)
  1494.     {
  1495.       params->read_buffer = g_malloc (params->handle_len + 12);
  1496.       num = htonl (params->handle_len);
  1497.       memcpy (params->read_buffer, params->handle, params->handle_len);
  1498.     }
  1499.   num = htonl (params->id++);
  1500.   memcpy (params->read_buffer, &num, 4);
  1501. #ifdef G_HAVE_GINT64
  1502.   offset = hton64 (params->offset);
  1503.   memcpy (params->read_buffer + params->handle_len, &offset, 8);
  1504. #else
  1505.   memset (params->read_buffer + params->handle_len, 0, 4);
  1506.   offset = htonl (params->offset);
  1507.   memcpy (params->read_buffer + params->handle_len + 4, &offset, 4);
  1508. #endif
  1509.   
  1510.   num = htonl (size);
  1511.   memcpy (params->read_buffer + params->handle_len + 8, &num, 4);
  1512.   
  1513.   if (sshv2_send_command (request, SSH_FXP_READ, params->read_buffer, params->handle_len + 12) < 0)
  1514.     return (-2);
  1515.   memset (&message, 0, sizeof (message));
  1516.   if (sshv2_read_response (request, &message, -1) != SSH_FXP_DATA)
  1517.     {
  1518.       message.pos += 4;
  1519.       if ((num = sshv2_buffer_get_int32 (request, &message, SSH_FX_OK)) < 0)
  1520.         return (-2);
  1521.       sshv2_message_free (&message);
  1522.       if (num != SSH_FX_EOF)
  1523.         {
  1524.           request->logging_function (gftp_logging_error, request->user_data,
  1525.                      _("Received wrong response from server, disconnectingn"));
  1526.           gftp_disconnect (request);
  1527.           return (-2);
  1528.         }
  1529.       return (0);
  1530.     }
  1531.   memcpy (&num, message.buffer + 4, 4);
  1532.   num = ntohl (num);
  1533.   if (num > size)
  1534.     {
  1535.       request->logging_function (gftp_logging_error, request->user_data,
  1536.                              _("Error: Message size %d too big from servern"),
  1537.                              num);
  1538.       sshv2_message_free (&message);
  1539.       gftp_disconnect (request);
  1540.       return (-1);
  1541.         
  1542.     }
  1543.   memcpy (buf, message.buffer + 8, num);
  1544.   sshv2_message_free (&message);
  1545.   params->offset += num;
  1546.   return (num);
  1547. }
  1548. static ssize_t 
  1549. sshv2_put_next_file_chunk (gftp_request * request, char *buf, size_t size)
  1550. {
  1551.   sshv2_params * params;
  1552.   sshv2_message message;
  1553.   char tempstr[32768];
  1554.   gint32 num;
  1555.   int ret;
  1556. #ifdef G_HAVE_GINT64
  1557.   gint64 offset;
  1558. #else
  1559.   gint32 offset;
  1560. #endif
  1561.   g_return_val_if_fail (request != NULL, -2);
  1562.   g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
  1563.   g_return_val_if_fail (request->sockfd > 0, -2);
  1564.   g_return_val_if_fail (buf != NULL, -2);
  1565.   g_return_val_if_fail (size <= 32500, -2);
  1566.   params = request->protocol_data;
  1567.   num = htonl (params->handle_len);
  1568.   memcpy (tempstr, params->handle, params->handle_len);
  1569.   num = htonl (params->id++);
  1570.   memcpy (tempstr, &num, 4);
  1571. #ifdef G_HAVE_GINT64
  1572.   offset = hton64 (params->offset);
  1573.   memcpy (tempstr + params->handle_len, &offset, 8);
  1574. #else
  1575.   memset (tempstr + params->handle_len, 0, 4);
  1576.   offset = htonl (params->offset);
  1577.   memcpy (tempstr + params->handle_len + 4, &offset, 4);
  1578. #endif
  1579.  
  1580.   num = htonl (size);
  1581.   memcpy (tempstr + params->handle_len + 8, &num, 4);
  1582.   memcpy (tempstr + params->handle_len + 12, buf, size);
  1583.   
  1584.   if (sshv2_send_command (request, SSH_FXP_WRITE, tempstr, params->handle_len + size + 12) < 0)
  1585.     {
  1586.       g_free (tempstr);
  1587.       return (-2);
  1588.     }
  1589.   memset (&message, 0, sizeof (message));
  1590.   params->dont_log_status = 1;
  1591.   ret = sshv2_read_response (request, &message, -1);
  1592.   params->dont_log_status = 0;
  1593.   if (ret != SSH_FXP_STATUS)
  1594.    {
  1595.      request->logging_function (gftp_logging_error, request->user_data,
  1596.                      _("Received wrong response from server, disconnectingn"));
  1597.      sshv2_message_free (&message);
  1598.      gftp_disconnect (request);
  1599.      return (-2);
  1600.    }
  1601.   message.pos += 4;
  1602.   if ((num = sshv2_buffer_get_int32 (request, &message, SSH_FX_OK)) < 0)
  1603.     return (-2);
  1604.   sshv2_message_free (&message);
  1605.   if (num == SSH_FX_EOF)
  1606.     return (0);
  1607.   else if (num != SSH_FX_OK)
  1608.     return (-1);
  1609.   params->offset += size;
  1610.   return (size);
  1611. }
  1612. static void
  1613. sshv2_set_config_options (gftp_request * request)
  1614. {
  1615.   if (request->sftpserv_path != NULL)
  1616.     {
  1617.       if (ssh2_sftp_path != NULL && 
  1618.           strcmp (ssh2_sftp_path, request->sftpserv_path) == 0)
  1619.         return;
  1620.       g_free (request->sftpserv_path);
  1621.       request->sftpserv_path = NULL;
  1622.     }
  1623.   if (ssh2_sftp_path != NULL)
  1624.     request->sftpserv_path = g_strdup (ssh2_sftp_path);
  1625.   request->need_userpass = ssh_need_userpass;
  1626. }
  1627. static void
  1628. sshv2_swap_socks (gftp_request * dest, gftp_request * source)
  1629. {
  1630.   sshv2_params * sparams, * dparams;
  1631.   sparams = source->protocol_data;
  1632.   dparams = dest->protocol_data;
  1633.   dparams->id = sparams->id;
  1634. }
  1635. void
  1636. sshv2_init (gftp_request * request)
  1637. {
  1638.   sshv2_params * params;
  1639.   g_return_if_fail (request != NULL);
  1640.   request->protonum = GFTP_SSHV2_NUM;
  1641.   request->init = sshv2_init;
  1642.   request->destroy = sshv2_destroy;
  1643.   request->connect = sshv2_connect;
  1644.   request->disconnect = sshv2_disconnect;
  1645.   request->get_file = sshv2_get_file;
  1646.   request->put_file = sshv2_put_file;
  1647.   request->transfer_file = NULL;
  1648.   request->get_next_file_chunk = sshv2_get_next_file_chunk;
  1649.   request->put_next_file_chunk = sshv2_put_next_file_chunk;
  1650.   request->end_transfer = sshv2_end_transfer;
  1651.   request->abort_transfer = sshv2_end_transfer; /* NOTE: uses sshv2_end_transfer */
  1652.   request->list_files = sshv2_list_files;
  1653.   request->get_next_file = sshv2_get_next_file;
  1654.   request->set_data_type = NULL;
  1655.   request->get_file_size = sshv2_get_file_size;
  1656.   request->chdir = sshv2_chdir;
  1657.   request->rmdir = sshv2_rmdir;
  1658.   request->rmfile = sshv2_rmfile;
  1659.   request->mkdir = sshv2_mkdir;
  1660.   request->rename = sshv2_rename;
  1661.   request->chmod = sshv2_chmod;
  1662.   request->set_file_time = sshv2_set_file_time;
  1663.   request->site = NULL;
  1664.   request->parse_url = NULL;
  1665.   request->set_config_options = sshv2_set_config_options;
  1666.   request->swap_socks = sshv2_swap_socks;
  1667.   request->url_prefix = "ssh2";
  1668.   request->protocol_name = "SSH2";
  1669.   request->need_hostport = 1;
  1670.   request->need_userpass = ssh_need_userpass;
  1671.   request->use_cache = 1;
  1672.   request->use_threads = 1;
  1673.   request->always_connected = 0;
  1674.   request->protocol_data = g_malloc0 (sizeof (sshv2_params));
  1675.   gftp_set_config_options (request);
  1676.   params = request->protocol_data;
  1677.   params->id = 1;
  1678. }