sftp_server_packet.c
Go to the documentation of this file.
1 /**
2  * @file sftp_server_packet.c
3  * @brief SFTP packet parsing and formatting
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSH Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SFTP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ssh/ssh_misc.h"
36 #include "sftp/sftp_server.h"
37 #include "sftp/sftp_server_file.h"
40 #include "sftp/sftp_server_misc.h"
41 #include "path.h"
42 #include "debug.h"
43 
44 //Check SSH stack configuration
45 #if (SFTP_SERVER_SUPPORT == ENABLED)
46 
47 
48 /**
49  * @brief Parse SSH_FXP_INIT packet
50  * @param[in] session Handle referencing an SFTP session
51  * @param[in] packet Pointer to packet
52  * @param[in] length Length of the packet, in bytes
53  * @return Error code
54  **/
55 
57  const uint8_t *packet, size_t length)
58 {
59  error_t error;
60  uint32_t version;
61 
62  //Debug message
63  TRACE_INFO("SSH_FXP_INIT packet received (%" PRIuSIZE " bytes)...\r\n", length);
64  TRACE_VERBOSE_ARRAY(" ", packet, length);
65 
66  //Malformed packet?
67  if(length != sizeof(uint32_t))
68  return ERROR_INVALID_PACKET;
69 
70  //The SSH_FXP_INIT packet contains the client version
71  version = LOAD32BE(packet);
72 
73  //Sanity check
75  return ERROR_INVALID_VERSION;
76 
77  //The server responds with an SSH_FXP_VERSION packet, supplying the lowest
78  //of its own and the client's version number. Both parties should from then
79  //on adhere to particular version of the protocol
80  session->version = (SftpVersion) MIN(version, SFTP_SERVER_MAX_VERSION);
81 
82  //Send an SSH_FXP_VERSION packet to the client
83  error = sftpFormatFxpVersion(session, session->version);
84 
85  //Return status code
86  return error;
87 }
88 
89 
90 /**
91  * @brief Parse SSH_FXP_OPEN packet
92  * @param[in] session Handle referencing an SFTP session
93  * @param[in] packet Pointer to packet
94  * @param[in] length Length of the packet, in bytes
95  * @return Error code
96  **/
97 
99  const uint8_t *packet, size_t length)
100 {
101  error_t error;
102  size_t n;
103  uint32_t id;
104  uint32_t pflags;
105  uint32_t handle;
106  const uint8_t *p;
109 
110  //Debug message
111  TRACE_INFO("SSH_FXP_OPEN packet received (%" PRIuSIZE " bytes)...\r\n", length);
112  TRACE_VERBOSE_ARRAY(" ", packet, length);
113 
114  //Point to the first field of the packet
115  p = packet;
116 
117  //Malformed packet?
118  if(length < sizeof(uint32_t))
119  return ERROR_INVALID_PACKET;
120 
121  //Get request identifier
122  id = LOAD32BE(p);
123 
124  //Point to the next field
125  p += sizeof(uint32_t);
126  length -= sizeof(uint32_t);
127 
128  //Get filename
129  error = sshParseString(p, length, &filename);
130  //Any error to report?
131  if(error)
132  return error;
133 
134  //Point to the next field
135  p += sizeof(uint32_t) + filename.length;
136  length -= sizeof(uint32_t) + filename.length;
137 
138  //Malformed packet?
139  if(length < sizeof(uint32_t))
140  return ERROR_INVALID_PACKET;
141 
142  //Get pflags
143  pflags = LOAD32BE(p);
144 
145  //Point to the next field
146  p += sizeof(uint32_t);
147  length -= sizeof(uint32_t);
148 
149  //Parse ATTRS compound data
150  error = sftpParseAttributes(session->version, &attributes, p, length, &n);
151  //Any error to report?
152  if(error)
153  return error;
154 
155  //Malformed packet?
156  if(length != n)
157  return ERROR_INVALID_PACKET;
158 
159  //Open the specified file
160  error = sftpServerOpenFile(session, &filename, pflags, &attributes,
161  &handle);
162 
163  //Check status code
164  if(error == NO_ERROR)
165  {
166  //The server will respond to this request with an SSH_FXP_HANDLE packet
167  error = sftpFormatFxpHandle(session, id, handle);
168  }
169  else if(error == ERROR_OUT_OF_RESOURCES)
170  {
171  //Too many files have been open
172  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
173  "Too many open files");
174  }
175  else
176  {
177  //The specified path name does not exist
178  error = sftpFormatFxpStatus(session, id, SSH_FX_NO_SUCH_FILE,
179  "No such file");
180  }
181 
182  //Return status code
183  return error;
184 }
185 
186 
187 /**
188  * @brief Parse SSH_FXP_CLOSE packet
189  * @param[in] session Handle referencing an SFTP session
190  * @param[in] packet Pointer to packet
191  * @param[in] length Length of the packet, in bytes
192  * @return Error code
193  **/
194 
196  const uint8_t *packet, size_t length)
197 {
198  error_t error;
199  uint32_t id;
200  const uint8_t *p;
201  SshBinaryString handle;
202 
203  //Debug message
204  TRACE_INFO("SSH_FXP_CLOSE packet received (%" PRIuSIZE " bytes)...\r\n", length);
205  TRACE_VERBOSE_ARRAY(" ", packet, length);
206 
207  //Point to the first field of the packet
208  p = packet;
209 
210  //Malformed packet?
211  if(length < sizeof(uint32_t))
212  return ERROR_INVALID_PACKET;
213 
214  //Get request identifier
215  id = LOAD32BE(p);
216 
217  //Point to the next field
218  p += sizeof(uint32_t);
219  length -= sizeof(uint32_t);
220 
221  //Get handle
222  error = sshParseBinaryString(p, length, &handle);
223  //Any error to report?
224  if(error)
225  return error;
226 
227  //Malformed message?
228  if(length != (sizeof(uint32_t) + handle.length))
229  return ERROR_INVALID_PACKET;
230 
231  //An SSH_FXP_CLOSE request can be used to close a file
232  error = sftpServerCloseFile(session, &handle);
233 
234  //Check status code
235  if(error)
236  {
237  //This request can also be used to close a directory
238  error = sftpServerCloseDir(session, &handle);
239  }
240 
241  //Check status code
242  if(!error)
243  {
244  //When the operation is successful, the server responds with an
245  //SSH_FXP_STATUS message with SSH_FX_OK status
246  error = sftpFormatFxpStatus(session, id, SSH_FX_OK, "Success");
247  }
248  else
249  {
250  //If an error occurs, the server responds with an SSH_FXP_STATUS
251  //message message indicating an failure
252  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
253  "Invalid handle");
254  }
255 
256  //Return status code
257  return error;
258 }
259 
260 
261 /**
262  * @brief Parse SSH_FXP_READ packet
263  * @param[in] session Handle referencing an SFTP session
264  * @param[in] packet Pointer to packet
265  * @param[in] length Length of the packet, in bytes
266  * @return Error code
267  **/
268 
270  const uint8_t *packet, size_t length)
271 {
272  error_t error;
273  uint32_t id;
274  uint32_t dataLen;
275  uint64_t offset;
276  const uint8_t *p;
277  SshBinaryString handle;
278 
279  //Debug message
280  TRACE_DEBUG("SSH_FXP_READ packet received (%" PRIuSIZE " bytes)...\r\n", length);
281  TRACE_VERBOSE_ARRAY(" ", packet, length);
282 
283  //Point to the first field of the packet
284  p = packet;
285 
286  //Malformed packet?
287  if(length < sizeof(uint32_t))
288  return ERROR_INVALID_PACKET;
289 
290  //Get request identifier
291  id = LOAD32BE(p);
292 
293  //Point to the next field
294  p += sizeof(uint32_t);
295  length -= sizeof(uint32_t);
296 
297  //Get handle
298  error = sshParseBinaryString(p, length, &handle);
299  //Any error to report?
300  if(error)
301  return error;
302 
303  //Point to the next field
304  p += sizeof(uint32_t) + handle.length;
305  length -= sizeof(uint32_t) + handle.length;
306 
307  //Malformed packet?
308  if(length < sizeof(uint64_t))
309  return ERROR_INVALID_PACKET;
310 
311  //The 'offset' field is the offset is relative to the beginning of the
312  //file from where to start reading
313  offset = LOAD64BE(p);
314 
315  //Point to the next field
316  p += sizeof(uint64_t);
317  length -= sizeof(uint64_t);
318 
319  //Malformed packet?
320  if(length != sizeof(uint32_t))
321  return ERROR_INVALID_PACKET;
322 
323  //The 'len' field is the maximum number of bytes to read
324  dataLen = LOAD32BE(p);
325 
326  //Read data from the specified file
327  error = sftpServerReadFile(session, &handle, offset, &dataLen);
328 
329  //Check status code
330  if(!error)
331  {
332  //In response to this request, the server will read as many bytes as it
333  //can from the file (up to 'len'), and return them in an SSH_FXP_DATA
334  //message
335  error = sftpFormatFxpData(session, id, dataLen);
336  }
337 
338  //Check status code
339  if(error == NO_ERROR)
340  {
341  //Successful read operation
342  }
343  else if(error == ERROR_END_OF_STREAM)
344  {
345  //End-of-file condition
346  error = sftpFormatFxpStatus(session, id, SSH_FX_EOF, "No more data");
347  }
348  else if(error == ERROR_INVALID_HANDLE)
349  {
350  //The supplied handle is not valid
351  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
352  "Invalid handle");
353  }
354  else
355  {
356  //Generic error
357  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
358  "Failed to read data");
359  }
360 
361  //Return status code
362  return error;
363 }
364 
365 
366 /**
367  * @brief Parse SSH_FXP_WRITE packet
368  * @param[in] session Handle referencing an SFTP session
369  * @param[in] packet Pointer to packet
370  * @param[in] fragLen Number of bytes available on hand
371  * @param[in] totalLen Total length of the packet, in bytes
372  * @return Error code
373  **/
374 
376  const uint8_t *packet, size_t fragLen, size_t totalLen)
377 {
378  error_t error;
379  uint64_t offset;
380  const uint8_t *p;
381  SshBinaryString handle;
383 
384  //Debug message
385  TRACE_DEBUG("SSH_FXP_WRITE packet received (%" PRIuSIZE " bytes)...\r\n", totalLen);
386  TRACE_VERBOSE_ARRAY(" ", packet, fragLen);
387 
388  //Point to the first field of the packet
389  p = packet;
390 
391  //Malformed packet?
392  if(fragLen < sizeof(uint32_t) || fragLen > totalLen)
393  return ERROR_INVALID_PACKET;
394 
395  //Get request identifier
396  session->requestId = LOAD32BE(p);
397 
398  //Point to the next field
399  p += sizeof(uint32_t);
400  fragLen -= sizeof(uint32_t);
401  totalLen -= sizeof(uint32_t);
402 
403  //Get handle
404  error = sshParseBinaryString(p, fragLen, &handle);
405  //Any error to report?
406  if(error)
407  return error;
408 
409  //Point to the next field
410  p += sizeof(uint32_t) + handle.length;
411  fragLen -= sizeof(uint32_t) + handle.length;
412  totalLen -= sizeof(uint32_t) + handle.length;
413 
414  //Malformed packet?
415  if(fragLen < sizeof(uint64_t))
416  return ERROR_INVALID_PACKET;
417 
418  //The 'offset' field is the offset from the beginning of the file where
419  //to start writing
420  offset = LOAD64BE(p);
421 
422  //Point to the next field
423  p += sizeof(uint64_t);
424  fragLen -= sizeof(uint64_t);
425  totalLen -= sizeof(uint64_t);
426 
427  //Malformed packet?
428  if(fragLen < sizeof(uint32_t))
429  return ERROR_INVALID_PACKET;
430 
431  //The 'data' field is a byte string containing the data to be written
432  error = sshParseBinaryString(p, totalLen, &data);
433  //Any error to report?
434  if(error)
435  return error;
436 
437  //Malformed packet?
438  if(totalLen != (sizeof(uint32_t) + data.length))
439  return ERROR_INVALID_PACKET;
440 
441  //Point to the data payload
442  p += sizeof(uint32_t);
443  fragLen -= sizeof(uint32_t);
444  totalLen -= sizeof(uint32_t);
445 
446  //Write data to the specified file
447  error = sftpServerWriteFile(session, &handle, offset, p, fragLen, totalLen);
448 
449  //Return status code
450  return error;
451 }
452 
453 
454 /**
455  * @brief Parse SSH_FXP_OPENDIR packet
456  * @param[in] session Handle referencing an SFTP session
457  * @param[in] packet Pointer to packet
458  * @param[in] length Length of the packet, in bytes
459  * @return Error code
460  **/
461 
463  const uint8_t *packet, size_t length)
464 {
465  error_t error;
466  uint32_t id;
467  uint32_t handle;
468  const uint8_t *p;
469  SshString path;
470 
471  //Debug message
472  TRACE_INFO("SSH_FXP_OPENDIR packet received (%" PRIuSIZE " bytes)...\r\n", length);
473  TRACE_VERBOSE_ARRAY(" ", packet, length);
474 
475  //Point to the first field of the packet
476  p = packet;
477 
478  //Malformed packet?
479  if(length < sizeof(uint32_t))
480  return ERROR_INVALID_PACKET;
481 
482  //Get request identifier
483  id = LOAD32BE(p);
484 
485  //Point to the next field
486  p += sizeof(uint32_t);
487  length -= sizeof(uint32_t);
488 
489  //The path field specifies the path name of the directory to be listed
490  error = sshParseString(p, length, &path);
491  //Any error to report?
492  if(error)
493  return error;
494 
495  //Malformed message?
496  if(length != (sizeof(uint32_t) + path.length))
497  return ERROR_INVALID_PACKET;
498 
499  //Open the specified directory
500  error = sftpServerOpenDir(session, &path, &handle);
501 
502  //Check status code
503  if(error == NO_ERROR)
504  {
505  //The server will respond to this request with an SSH_FXP_HANDLE packet
506  error = sftpFormatFxpHandle(session, id, handle);
507  }
508  else if(error == ERROR_OUT_OF_RESOURCES)
509  {
510  //Too many files have been open
511  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
512  "Too many open files");
513  }
514  else
515  {
516  //The specified path name does not exist
517  error = sftpFormatFxpStatus(session, id, SSH_FX_NO_SUCH_FILE,
518  "No such directory");
519  }
520 
521  //Return status code
522  return error;
523 }
524 
525 
526 /**
527  * @brief Parse SSH_FXP_READDIR packet
528  * @param[in] session Handle referencing an SFTP session
529  * @param[in] packet Pointer to packet
530  * @param[in] length Length of the packet, in bytes
531  * @return Error code
532  **/
533 
535  const uint8_t *packet, size_t length)
536 {
537  error_t error;
538  uint32_t id;
539  const uint8_t *p;
540  SshBinaryString handle;
541  SftpName name;
542 
543  //Debug message
544  TRACE_DEBUG("SSH_FXP_READDIR packet received (%" PRIuSIZE " bytes)...\r\n", length);
545  TRACE_VERBOSE_ARRAY(" ", packet, length);
546 
547  //Point to the first field of the packet
548  p = packet;
549 
550  //Malformed packet?
551  if(length < sizeof(uint32_t))
552  return ERROR_INVALID_PACKET;
553 
554  //Get request identifier
555  id = LOAD32BE(p);
556 
557  //Point to the next field
558  p += sizeof(uint32_t);
559  length -= sizeof(uint32_t);
560 
561  //Get handle
562  error = sshParseBinaryString(p, length, &handle);
563  //Any error to report?
564  if(error)
565  return error;
566 
567  //Malformed message?
568  if(length != (sizeof(uint32_t) + handle.length))
569  return ERROR_INVALID_PACKET;
570 
571  //Read a new entry from the directory
572  error = sftpServerReadDir(session, &handle, &name);
573 
574  //Check status code
575  if(error == NO_ERROR)
576  {
577  //Each SSH_FXP_READDIR request returns one or more file names with full
578  //file attributes for each file
579  error = sftpFormatFxpName(session, id, &name);
580  }
581  else if(error == ERROR_END_OF_STREAM)
582  {
583  //Return an SSH_FX_EOF if there are no more files in the directory
584  error = sftpFormatFxpStatus(session, id, SSH_FX_EOF, "No more files");
585  }
586  else if(error == ERROR_INVALID_HANDLE)
587  {
588  //The supplied handle is not valid
589  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
590  "Invalid handle");
591  }
592  else
593  {
594  //Generic error
595  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
596  "Failed to read directory");
597  }
598 
599  //Return status code
600  return error;
601 }
602 
603 
604 /**
605  * @brief Parse SSH_FXP_REMOVE packet
606  * @param[in] session Handle referencing an SFTP session
607  * @param[in] packet Pointer to packet
608  * @param[in] length Length of the packet, in bytes
609  * @return Error code
610  **/
611 
613  const uint8_t *packet, size_t length)
614 {
615  error_t error;
616  uint32_t id;
617  const uint8_t *p;
619 
620  //Debug message
621  TRACE_INFO("SSH_FXP_REMOVE packet received (%" PRIuSIZE " bytes)...\r\n", length);
622  TRACE_VERBOSE_ARRAY(" ", packet, length);
623 
624  //Point to the first field of the packet
625  p = packet;
626 
627  //Malformed packet?
628  if(length < sizeof(uint32_t))
629  return ERROR_INVALID_PACKET;
630 
631  //Get request identifier
632  id = LOAD32BE(p);
633 
634  //Point to the next field
635  p += sizeof(uint32_t);
636  length -= sizeof(uint32_t);
637 
638  //The filename field specifies the file to be removed
639  error = sshParseString(p, length, &filename);
640  //Any error to report?
641  if(error)
642  return error;
643 
644  //Malformed message?
645  if(length != (sizeof(uint32_t) + filename.length))
646  return ERROR_INVALID_PACKET;
647 
648  //Remove the specified file
649  error = sftpServerRemoveFile(session, &filename);
650 
651  //Check status code
652  if(!error)
653  {
654  //When the operation is successful, the server responds with an
655  //SSH_FXP_STATUS message with SSH_FX_OK status
656  error = sftpFormatFxpStatus(session, id, SSH_FX_OK, "Success");
657  }
658  else
659  {
660  //If an error occurs, the server responds with an SSH_FXP_STATUS
661  //message message indicating an failure
662  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
663  "Cannot remove file");
664  }
665 
666  //Return status code
667  return error;
668 }
669 
670 
671 /**
672  * @brief Parse SSH_FXP_MKDIR packet
673  * @param[in] session Handle referencing an SFTP session
674  * @param[in] packet Pointer to packet
675  * @param[in] length Length of the packet, in bytes
676  * @return Error code
677  **/
678 
680  const uint8_t *packet, size_t length)
681 {
682  error_t error;
683  size_t n;
684  uint32_t id;
685  const uint8_t *p;
686  SshString path;
688 
689  //Debug message
690  TRACE_INFO("SSH_FXP_MKDIR packet received (%" PRIuSIZE " bytes)...\r\n", length);
691  TRACE_VERBOSE_ARRAY(" ", packet, length);
692 
693  //Point to the first field of the packet
694  p = packet;
695 
696  //Malformed packet?
697  if(length < sizeof(uint32_t))
698  return ERROR_INVALID_PACKET;
699 
700  //Get request identifier
701  id = LOAD32BE(p);
702 
703  //Point to the next field
704  p += sizeof(uint32_t);
705  length -= sizeof(uint32_t);
706 
707  //The path field specifies the directory to be created
708  error = sshParseString(p, length, &path);
709  //Any error to report?
710  if(error)
711  return error;
712 
713  //Point to the next field
714  p += sizeof(uint32_t) + path.length;
715  length -= sizeof(uint32_t) + path.length;
716 
717  //Parse ATTRS compound data
718  error = sftpParseAttributes(session->version, &attributes, p, length, &n);
719  //Any error to report?
720  if(error)
721  return error;
722 
723  //Malformed packet?
724  if(length != n)
725  return ERROR_INVALID_PACKET;
726 
727  //Create the specified directory
728  error = sftpServerCreateDir(session, &path, &attributes);
729 
730  //Check status code
731  if(!error)
732  {
733  //When the operation is successful, the server responds with an
734  //SSH_FXP_STATUS message with SSH_FX_OK status
735  error = sftpFormatFxpStatus(session, id, SSH_FX_OK, "Success");
736  }
737  else
738  {
739  //If an error occurs, the server responds with an SSH_FXP_STATUS
740  //message message indicating an failure
741  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
742  "Cannot create directory");
743  }
744 
745  //Return status code
746  return error;
747 }
748 
749 
750 /**
751  * @brief Parse SSH_FXP_RMDIR packet
752  * @param[in] session Handle referencing an SFTP session
753  * @param[in] packet Pointer to packet
754  * @param[in] length Length of the packet, in bytes
755  * @return Error code
756  **/
757 
759  const uint8_t *packet, size_t length)
760 {
761  error_t error;
762  uint32_t id;
763  const uint8_t *p;
764  SshString path;
765 
766  //Debug message
767  TRACE_INFO("SSH_FXP_RMDIR packet received (%" PRIuSIZE " bytes)...\r\n", length);
768  TRACE_VERBOSE_ARRAY(" ", packet, length);
769 
770  //Point to the first field of the packet
771  p = packet;
772 
773  //Malformed packet?
774  if(length < sizeof(uint32_t))
775  return ERROR_INVALID_PACKET;
776 
777  //Get request identifier
778  id = LOAD32BE(p);
779 
780  //Point to the next field
781  p += sizeof(uint32_t);
782  length -= sizeof(uint32_t);
783 
784  //The path field specifies the directory to be removed
785  error = sshParseString(p, length, &path);
786  //Any error to report?
787  if(error)
788  return error;
789 
790  //Malformed message?
791  if(length != (sizeof(uint32_t) + path.length))
792  return ERROR_INVALID_PACKET;
793 
794  //Remove the specified directory
795  error = sftpServerRemoveDir(session, &path);
796 
797  //Check status code
798  if(!error)
799  {
800  //When the operation is successful, the server responds with an
801  //SSH_FXP_STATUS message with SSH_FX_OK status
802  error = sftpFormatFxpStatus(session, id, SSH_FX_OK, "Success");
803  }
804  else
805  {
806  //If an error occurs, the server responds with an SSH_FXP_STATUS
807  //message message indicating an failure
808  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
809  "Cannot remove directory");
810  }
811 
812  //Return status code
813  return error;
814 }
815 
816 
817 /**
818  * @brief Parse SSH_FXP_REALPATH packet
819  * @param[in] session Handle referencing an SFTP session
820  * @param[in] packet Pointer to packet
821  * @param[in] length Length of the packet, in bytes
822  * @return Error code
823  **/
824 
826  const uint8_t *packet, size_t length)
827 {
828  error_t error;
829  uint32_t id;
830  const uint8_t *p;
831  SshString path;
832  SftpName name;
833 
834  //Debug message
835  TRACE_INFO("SSH_FXP_REALPATH packet received (%" PRIuSIZE " bytes)...\r\n", length);
836  TRACE_VERBOSE_ARRAY(" ", packet, length);
837 
838  //Point to the first field of the packet
839  p = packet;
840 
841  //Malformed packet?
842  if(length < sizeof(uint32_t))
843  return ERROR_INVALID_PACKET;
844 
845  //Get request identifier
846  id = LOAD32BE(p);
847 
848  //Point to the next field
849  p += sizeof(uint32_t);
850  length -= sizeof(uint32_t);
851 
852  //The path field specifies the path name to be canonicalized
853  error = sshParseString(p, length, &path);
854  //Any error to report?
855  if(error)
856  return error;
857 
858  //Malformed message?
859  if(length != (sizeof(uint32_t) + path.length))
860  return ERROR_INVALID_PACKET;
861 
862  //Canonicalize the specified path name to an absolute path
863  error = sftpServerGetRealPath(session, &path, &name);
864 
865  //Check status code
866  if(!error)
867  {
868  //The server will respond with an SSH_FXP_NAME packet containing the
869  //name in canonical form and a dummy attributes value
870  error = sftpFormatFxpName(session, id, &name);
871  }
872  else
873  {
874  //If an error occurs, the server may also respond with SSH_FXP_STATUS
875  error = sftpFormatFxpStatus(session, id, SSH_FX_NO_SUCH_FILE,
876  "Invalid path");
877  }
878 
879  //Return status code
880  return error;
881 }
882 
883 
884 /**
885  * @brief Parse SSH_FXP_STAT packet
886  * @param[in] session Handle referencing an SFTP session
887  * @param[in] packet Pointer to packet
888  * @param[in] length Length of the packet, in bytes
889  * @return Error code
890  **/
891 
893  const uint8_t *packet, size_t length)
894 {
895  error_t error;
896  uint32_t id;
897  const uint8_t *p;
898  SshString path;
900 
901  //Debug message
902  TRACE_INFO("SSH_FXP_STAT packet received (%" PRIuSIZE " bytes)...\r\n", length);
903  TRACE_VERBOSE_ARRAY(" ", packet, length);
904 
905  //Point to the first field of the packet
906  p = packet;
907 
908  //Malformed packet?
909  if(length < sizeof(uint32_t))
910  return ERROR_INVALID_PACKET;
911 
912  //Get request identifier
913  id = LOAD32BE(p);
914 
915  //Point to the next field
916  p += sizeof(uint32_t);
917  length -= sizeof(uint32_t);
918 
919  //The path field specifies the file system object for which status is
920  //to be returned
921  error = sshParseString(p, length, &path);
922  //Any error to report?
923  if(error)
924  return error;
925 
926  //Malformed message?
927  if(length != (sizeof(uint32_t) + path.length))
928  return ERROR_INVALID_PACKET;
929 
930  //Retrieve the attributes of the specified file
931  error = sftpServerGetFileStat(session, &path, &attributes);
932 
933  //Check status code
934  if(!error)
935  {
936  //The server responds to this request with SSH_FXP_ATTRS
937  error = sftpFormatFxpAttrs(session, id, &attributes);
938  }
939  else
940  {
941  //If an error occurs, the server may also respond with SSH_FXP_STATUS
942  error = sftpFormatFxpStatus(session, id, SSH_FX_NO_SUCH_FILE,
943  "No such file");
944  }
945 
946  //Return status code
947  return error;
948 }
949 
950 
951 /**
952  * @brief Parse SSH_FXP_FSTAT packet
953  * @param[in] session Handle referencing an SFTP session
954  * @param[in] packet Pointer to packet
955  * @param[in] length Length of the packet, in bytes
956  * @return Error code
957  **/
958 
960  const uint8_t *packet, size_t length)
961 {
962  error_t error;
963  uint32_t id;
964  const uint8_t *p;
965  SshBinaryString handle;
967 
968  //Debug message
969  TRACE_INFO("SSH_FXP_FSTAT packet received (%" PRIuSIZE " bytes)...\r\n", length);
970  TRACE_VERBOSE_ARRAY(" ", packet, length);
971 
972  //Point to the first field of the packet
973  p = packet;
974 
975  //Malformed packet?
976  if(length < sizeof(uint32_t))
977  return ERROR_INVALID_PACKET;
978 
979  //Get request identifier
980  id = LOAD32BE(p);
981 
982  //Point to the next field
983  p += sizeof(uint32_t);
984  length -= sizeof(uint32_t);
985 
986  //Get handle
987  error = sshParseBinaryString(p, length, &handle);
988  //Any error to report?
989  if(error)
990  return error;
991 
992  //Malformed message?
993  if(length != (sizeof(uint32_t) + handle.length))
994  return ERROR_INVALID_PACKET;
995 
996  //Retrieve the attributes of the specified file
997  error = sftpServerGetFileStatEx(session, &handle, &attributes);
998 
999  //Check status code
1000  if(!error)
1001  {
1002  //The server responds to this request with SSH_FXP_ATTRS
1003  error = sftpFormatFxpAttrs(session, id, &attributes);
1004  }
1005  else
1006  {
1007  //If an error occurs, the server may also respond with SSH_FXP_STATUS
1008  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
1009  "Invalid handle");
1010  }
1011 
1012  //Return status code
1013  return error;
1014 }
1015 
1016 
1017 /**
1018  * @brief Parse SSH_FXP_SETSTAT packet
1019  * @param[in] session Handle referencing an SFTP session
1020  * @param[in] packet Pointer to packet
1021  * @param[in] length Length of the packet, in bytes
1022  * @return Error code
1023  **/
1024 
1026  const uint8_t *packet, size_t length)
1027 {
1028  error_t error;
1029  size_t n;
1030  uint32_t id;
1031  const uint8_t *p;
1032  SshString path;
1034 
1035  //Debug message
1036  TRACE_INFO("SSH_FXP_SETSTAT packet received (%" PRIuSIZE " bytes)...\r\n", length);
1037  TRACE_VERBOSE_ARRAY(" ", packet, length);
1038 
1039  //Point to the first field of the packet
1040  p = packet;
1041 
1042  //Malformed packet?
1043  if(length < sizeof(uint32_t))
1044  return ERROR_INVALID_PACKET;
1045 
1046  //Get request identifier
1047  id = LOAD32BE(p);
1048 
1049  //Point to the next field
1050  p += sizeof(uint32_t);
1051  length -= sizeof(uint32_t);
1052 
1053  //The path field specifies the file system object for which status is
1054  //to be returned
1055  error = sshParseString(p, length, &path);
1056  //Any error to report?
1057  if(error)
1058  return error;
1059 
1060  //Point to the next field
1061  p += sizeof(uint32_t) + path.length;
1062  length -= sizeof(uint32_t) + path.length;
1063 
1064  //Parse ATTRS compound data
1065  error = sftpParseAttributes(session->version, &attributes, p, length, &n);
1066  //Any error to report?
1067  if(error)
1068  return error;
1069 
1070  //Malformed packet?
1071  if(length != n)
1072  return ERROR_INVALID_PACKET;
1073 
1074  //Modify the attributes of the specified file
1075  error = sftpServerSetFileStat(session, &path, &attributes);
1076 
1077  //Check status code
1078  if(!error)
1079  {
1080  //When the operation is successful, the server responds with an
1081  //SSH_FXP_STATUS message with SSH_FX_OK status
1082  error = sftpFormatFxpStatus(session, id, SSH_FX_OK, "Success");
1083  }
1084  else
1085  {
1086  //If an error occurs, the server responds with an SSH_FXP_STATUS
1087  //message message indicating an failure
1088  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
1089  "Invalid handle");
1090  }
1091 
1092  //Return status code
1093  return error;
1094 }
1095 
1096 
1097 /**
1098  * @brief Parse SSH_FXP_FSETSTAT packet
1099  * @param[in] session Handle referencing an SFTP session
1100  * @param[in] packet Pointer to packet
1101  * @param[in] length Length of the packet, in bytes
1102  * @return Error code
1103  **/
1104 
1106  const uint8_t *packet, size_t length)
1107 {
1108  error_t error;
1109  size_t n;
1110  uint32_t id;
1111  const uint8_t *p;
1112  SshBinaryString handle;
1114 
1115  //Debug message
1116  TRACE_INFO("SSH_FXP_FSETSTAT packet received (%" PRIuSIZE " bytes)...\r\n", length);
1117  TRACE_VERBOSE_ARRAY(" ", packet, length);
1118 
1119  //Point to the first field of the packet
1120  p = packet;
1121 
1122  //Malformed packet?
1123  if(length < sizeof(uint32_t))
1124  return ERROR_INVALID_PACKET;
1125 
1126  //Get request identifier
1127  id = LOAD32BE(p);
1128 
1129  //Point to the next field
1130  p += sizeof(uint32_t);
1131  length -= sizeof(uint32_t);
1132 
1133  //Get handle
1134  error = sshParseBinaryString(p, length, &handle);
1135  //Any error to report?
1136  if(error)
1137  return error;
1138 
1139  //Point to the next field
1140  p += sizeof(uint32_t) + handle.length;
1141  length -= sizeof(uint32_t) + handle.length;
1142 
1143  //Parse ATTRS compound data
1144  error = sftpParseAttributes(session->version, &attributes, p, length, &n);
1145  //Any error to report?
1146  if(error)
1147  return error;
1148 
1149  //Malformed packet?
1150  if(length != n)
1151  return ERROR_INVALID_PACKET;
1152 
1153  //Modify the attributes of the specified file
1154  error = sftpServerSetFileStatEx(session, &handle, &attributes);
1155 
1156  //Check status code
1157  if(!error)
1158  {
1159  //When the operation is successful, the server responds with an
1160  //SSH_FXP_STATUS message with SSH_FX_OK status
1161  error = sftpFormatFxpStatus(session, id, SSH_FX_OK, "Success");
1162  }
1163  else
1164  {
1165  //If an error occurs, the server responds with an SSH_FXP_STATUS
1166  //message message indicating an failure
1167  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
1168  "Invalid handle");
1169  }
1170 
1171  //Return status code
1172  return error;
1173 }
1174 
1175 
1176 /**
1177  * @brief Parse SSH_FXP_RENAME packet
1178  * @param[in] session Handle referencing an SFTP session
1179  * @param[in] packet Pointer to packet
1180  * @param[in] length Length of the packet, in bytes
1181  * @return Error code
1182  **/
1183 
1185  const uint8_t *packet, size_t length)
1186 {
1187  error_t error;
1188  uint32_t id;
1189  const uint8_t *p;
1190  SshString oldPath;
1191  SshString newPath;
1192 
1193  //Debug message
1194  TRACE_INFO("SSH_FXP_RENAME packet received (%" PRIuSIZE " bytes)...\r\n", length);
1195  TRACE_VERBOSE_ARRAY(" ", packet, length);
1196 
1197  //Point to the first field of the packet
1198  p = packet;
1199 
1200  //Malformed packet?
1201  if(length < sizeof(uint32_t))
1202  return ERROR_INVALID_PACKET;
1203 
1204  //Get request identifier
1205  id = LOAD32BE(p);
1206 
1207  //Point to the next field
1208  p += sizeof(uint32_t);
1209  length -= sizeof(uint32_t);
1210 
1211  //The oldpath field is the name of an existing file or directory
1212  error = sshParseString(p, length, &oldPath);
1213  //Any error to report?
1214  if(error)
1215  return error;
1216 
1217  //Point to the next field
1218  p += sizeof(uint32_t) + oldPath.length;
1219  length -= sizeof(uint32_t) + oldPath.length;
1220 
1221  //The newpath field is the new name for the file or directory
1222  error = sshParseString(p, length, &newPath);
1223  //Any error to report?
1224  if(error)
1225  return error;
1226 
1227  //Malformed message?
1228  if(length != (sizeof(uint32_t) + newPath.length))
1229  return ERROR_INVALID_PACKET;
1230 
1231  //Rename the specified file
1232  error = sftpServerRenameFile(session, &oldPath, &newPath);
1233 
1234  //Check status code
1235  if(!error)
1236  {
1237  //When the operation is successful, the server responds with an
1238  //SSH_FXP_STATUS message with SSH_FX_OK status
1239  error = sftpFormatFxpStatus(session, id, SSH_FX_OK, "Success");
1240  }
1241  else
1242  {
1243  //If an error occurs, the server responds with an SSH_FXP_STATUS
1244  //message message indicating an failure
1245  error = sftpFormatFxpStatus(session, id, SSH_FX_FAILURE,
1246  "Cannot rename file");
1247  }
1248 
1249  //Return status code
1250  return error;
1251 }
1252 
1253 
1254 /**
1255  * @brief Parse SSH_FXP_EXTENDED packet
1256  * @param[in] session Handle referencing an SFTP session
1257  * @param[in] packet Pointer to packet
1258  * @param[in] length Length of the packet, in bytes
1259  * @return Error code
1260  **/
1261 
1263  const uint8_t *packet, size_t length)
1264 {
1265  error_t error;
1266  uint32_t id;
1267  const uint8_t *p;
1268  SshString extendedRequest;
1269 
1270  //Debug message
1271  TRACE_INFO("SSH_FXP_EXTENDED packet received (%" PRIuSIZE " bytes)...\r\n", length);
1272  TRACE_VERBOSE_ARRAY(" ", packet, length);
1273 
1274  //Point to the first field of the packet
1275  p = packet;
1276 
1277  //Malformed packet?
1278  if(length < sizeof(uint32_t))
1279  return ERROR_INVALID_PACKET;
1280 
1281  //Get request identifier
1282  id = LOAD32BE(p);
1283 
1284  //Point to the next field
1285  p += sizeof(uint32_t);
1286  length -= sizeof(uint32_t);
1287 
1288  //The 'extended-request' field is a string of the format "name@domain", where
1289  //domain is an Internet domain name of the vendor defining the request
1290  error = sshParseString(p, length, &extendedRequest);
1291  //Any error to report?
1292  if(error)
1293  return error;
1294 
1295  //If the server does not recognize the 'extended-request' name, then
1296  //the server must respond with SSH_FXP_STATUS with error/status set to
1297  //SSH_FX_OP_UNSUPPORTED
1298  error = sftpFormatFxpStatus(session, id, SSH_FX_OP_UNSUPPORTED,
1299  "Extended request not supported");
1300 
1301  //Return status code
1302  return error;
1303 }
1304 
1305 
1306 /**
1307  * @brief Format SSH_FXP_VERSION packet
1308  * @param[in] session Handle referencing an SFTP session
1309  * @param[in] version Protocol version number
1310  * @return Error code
1311  **/
1312 
1314 {
1315  size_t length;
1316  uint8_t *p;
1317  SftpPacketHeader *header;
1318 
1319  //Point to the buffer where to format the packet
1320  header = (SftpPacketHeader *) session->buffer;
1321 
1322  //Set packet type
1323  header->type = SSH_FXP_VERSION;
1324  //Total length of the packet
1325  length = sizeof(uint8_t);
1326 
1327  //Point the data payload
1328  p = header->payload;
1329 
1330  //The SSH_FXP_VERSION packet contains the lowest of its own and the
1331  //client's version number
1332  STORE32BE(version, p);
1333 
1334  //Total length of the packet
1335  length += sizeof(uint32_t);
1336 
1337  //Convert the length field to network byte order
1338  header->length = htonl(length);
1339 
1340  //The packet length does not include the length field itself
1341  session->bufferLen = length + sizeof(uint32_t);
1342  session->bufferPos = 0;
1343 
1344  //Debug message
1345  TRACE_INFO("Sending SSH_FXP_VERSION packet (%" PRIuSIZE " bytes)...\r\n", session->bufferLen);
1346  TRACE_VERBOSE_ARRAY(" ", session->buffer, session->bufferLen);
1347 
1348  //Send the packet to the SFTP client
1349  session->state = SFTP_SERVER_SESSION_STATE_SENDING;
1350 
1351  //Successful processing
1352  return NO_ERROR;
1353 }
1354 
1355 
1356 /**
1357  * @brief Format SSH_FXP_STATUS message
1358  * @param[in] session Handle referencing an SFTP session
1359  * @param[in] id Request identifier
1360  * @param[in] statusCode Result of the requested operation
1361  * @param[in] message NULL-terminating description string
1362  * @return Error code
1363  **/
1364 
1366  uint32_t statusCode, const char_t *message)
1367 {
1368  error_t error;
1369  size_t n;
1370  size_t length;
1371  uint8_t *p;
1372  SftpPacketHeader *header;
1373 
1374  //Point to the buffer where to format the packet
1375  header = (SftpPacketHeader *) session->buffer;
1376 
1377  //Set packet type
1378  header->type = SSH_FXP_STATUS;
1379  //Total length of the packet
1380  length = sizeof(uint8_t);
1381 
1382  //Point the data payload
1383  p = header->payload;
1384 
1385  //Format request identifier
1386  STORE32BE(id, p);
1387 
1388  //Point to the next field
1389  p += sizeof(uint32_t);
1390  length += sizeof(uint32_t);
1391 
1392  //Format status code
1393  STORE32BE(statusCode, p);
1394 
1395  //Point to the next field
1396  p += sizeof(uint32_t);
1397  length += sizeof(uint32_t);
1398 
1399  //Copy the description string
1400  error = sshFormatString(message, p, &n);
1401  //Any error to report?
1402  if(error)
1403  return error;
1404 
1405  //Point to the next field
1406  p += n;
1407  length += n;
1408 
1409  //Set language tag
1410  error = sshFormatString("en", p, &n);
1411  //Any error to report?
1412  if(error)
1413  return error;
1414 
1415  //Total length of the message
1416  length += n;
1417 
1418  //Convert the length field to network byte order
1419  header->length = htonl(length);
1420 
1421  //The packet length does not include the length field itself
1422  session->bufferLen = length + sizeof(uint32_t);
1423  session->bufferPos = 0;
1424 
1425  //Debug message
1426  TRACE_DEBUG("Sending SSH_FXP_STATUS packet (%" PRIuSIZE " bytes)...\r\n", session->bufferLen);
1427  TRACE_VERBOSE_ARRAY(" ", session->buffer, session->bufferLen);
1428 
1429  //Send the packet to the SFTP client
1430  session->state = SFTP_SERVER_SESSION_STATE_SENDING;
1431 
1432  //Successful processing
1433  return NO_ERROR;
1434 }
1435 
1436 
1437 /**
1438  * @brief Format SSH_FXP_HANDLE message
1439  * @param[in] session Handle referencing an SFTP session
1440  * @param[in] id Request identifier
1441  * @param[in] handle Opaque value that identifies a file or directory
1442  * @return Error code
1443  **/
1444 
1446  uint32_t handle)
1447 {
1448  size_t length;
1449  uint8_t *p;
1450  SftpPacketHeader *header;
1451 
1452  //Point to the buffer where to format the packet
1453  header = (SftpPacketHeader *) session->buffer;
1454 
1455  //Set packet type
1456  header->type = SSH_FXP_HANDLE;
1457  //Total length of the packet
1458  length = sizeof(uint8_t);
1459 
1460  //Point the data payload
1461  p = header->payload;
1462 
1463  //Format request identifier
1464  STORE32BE(id, p);
1465 
1466  //Point to the next field
1467  p += sizeof(uint32_t);
1468  length += sizeof(uint32_t);
1469 
1470  //The handle field is an arbitrary string that identifies a file or
1471  //directory on the server
1472  STORE32BE(handle, p + sizeof(uint32_t));
1473 
1474  //The string is preceded by a uint32 containing its length
1475  STORE32BE(sizeof(uint32_t), p);
1476 
1477  //Total length of the message
1478  length += 2 * sizeof(uint32_t);
1479 
1480  //Convert the length field to network byte order
1481  header->length = htonl(length);
1482 
1483  //The packet length does not include the length field itself
1484  session->bufferLen = length + sizeof(uint32_t);
1485  session->bufferPos = 0;
1486 
1487  //Debug message
1488  TRACE_INFO("Sending SSH_FXP_HANDLE packet (%" PRIuSIZE " bytes)...\r\n", session->bufferLen);
1489  TRACE_VERBOSE_ARRAY(" ", session->buffer, session->bufferLen);
1490 
1491  //Send the packet to the SFTP client
1492  session->state = SFTP_SERVER_SESSION_STATE_SENDING;
1493 
1494  //Successful processing
1495  return NO_ERROR;
1496 }
1497 
1498 
1499 /**
1500  * @brief Format SSH_FXP_DATA message
1501  * @param[in] session Handle referencing an SFTP session
1502  * @param[in] id Request identifier
1503  * @param[in] dataLen Length of the data string, in bytes
1504  * @return Error code
1505  **/
1506 
1508  size_t dataLen)
1509 {
1510  size_t length;
1511  uint8_t *p;
1512  SftpPacketHeader *header;
1513 
1514  //Point to the buffer where to format the packet
1515  header = (SftpPacketHeader *) session->buffer;
1516 
1517  //Set packet type
1518  header->type = SSH_FXP_DATA;
1519  //Total length of the packet
1520  length = sizeof(uint8_t);
1521 
1522  //Point the data payload
1523  p = header->payload;
1524 
1525  //Format request identifier
1526  STORE32BE(id, p);
1527 
1528  //Point to the next field
1529  p += sizeof(uint32_t);
1530  length += sizeof(uint32_t);
1531 
1532  //The data string is preceded by a uint32 containing its length
1533  STORE32BE(dataLen, p);
1534 
1535  //Point to the data payload
1536  p += sizeof(uint32_t);
1537  length += sizeof(uint32_t);
1538 
1539  //Convert the length field to network byte order
1540  header->length = htonl(length + dataLen);
1541 
1542  //The packet length does not include the length field itself
1543  session->bufferLen = length + sizeof(uint32_t);
1544  session->bufferPos = 0;
1545 
1546  //Debug message
1547  TRACE_DEBUG("Sending SSH_FXP_DATA packet (%" PRIuSIZE " bytes)...\r\n",
1548  session->bufferLen + session->dataLen);
1549  TRACE_VERBOSE_ARRAY(" ", session->buffer, session->bufferLen);
1550 
1551  //Send the packet to the SFTP client
1552  session->state = SFTP_SERVER_SESSION_STATE_SENDING_DATA;
1553 
1554  //Successful processing
1555  return NO_ERROR;
1556 }
1557 
1558 
1559 /**
1560  * @brief Format SSH_FXP_NAME packet
1561  * @param[in] session Handle referencing an SFTP session
1562  * @param[in] id Request identifier
1563  * @param[in] name Pointer to the name structure
1564  * @return Error code
1565  **/
1566 
1568  const SftpName *name)
1569 {
1570  error_t error;
1571  size_t n;
1572  size_t length;
1573  uint8_t *p;
1574  SftpPacketHeader *header;
1575 
1576  //Point to the buffer where to format the packet
1577  header = (SftpPacketHeader *) session->buffer;
1578 
1579  //Set packet type
1580  header->type = SSH_FXP_NAME;
1581  //Total length of the packet
1582  length = sizeof(uint8_t);
1583 
1584  //Point the data payload
1585  p = header->payload;
1586 
1587  //Format request identifier
1588  STORE32BE(id, p);
1589 
1590  //Point to the next field
1591  p += sizeof(uint32_t);
1592  length += sizeof(uint32_t);
1593 
1594  //Number of names returned in this response
1595  STORE32BE(1, p);
1596 
1597  //Point to the next field
1598  p += sizeof(uint32_t);
1599  length += sizeof(uint32_t);
1600 
1601  //Format name structure
1602  error = sftpFormatName(session->version, name, p, &n);
1603  //Any error to report?
1604  if(error)
1605  return error;
1606 
1607  //Total length of the message
1608  length += n;
1609 
1610  //Convert the length field to network byte order
1611  header->length = htonl(length);
1612 
1613  //The packet length does not include the length field itself
1614  session->bufferLen = length + sizeof(uint32_t);
1615  session->bufferPos = 0;
1616 
1617  //Debug message
1618  TRACE_DEBUG("Sending SSH_FXP_NAME packet (%" PRIuSIZE " bytes)...\r\n", session->bufferLen);
1619  TRACE_VERBOSE_ARRAY(" ", session->buffer, session->bufferLen);
1620 
1621  //Send the packet to the SFTP client
1622  session->state = SFTP_SERVER_SESSION_STATE_SENDING;
1623 
1624  //Successful processing
1625  return NO_ERROR;
1626 }
1627 
1628 
1629 /**
1630  * @brief Format SSH_FXP_ATTRS packet
1631  * @param[in] session Handle referencing an SFTP session
1632  * @param[in] id Request identifier
1633  * @param[in] attributes File attributes
1634  * @return Error code
1635  **/
1636 
1638  const SftpFileAttrs *attributes)
1639 {
1640  error_t error;
1641  size_t n;
1642  size_t length;
1643  uint8_t *p;
1644  SftpPacketHeader *header;
1645 
1646  //Point to the buffer where to format the packet
1647  header = (SftpPacketHeader *) session->buffer;
1648 
1649  //Set packet type
1650  header->type = SSH_FXP_ATTRS;
1651  //Total length of the packet
1652  length = sizeof(uint8_t);
1653 
1654  //Point the data payload
1655  p = header->payload;
1656 
1657  //Format request identifier
1658  STORE32BE(id, p);
1659 
1660  //Point to the next field
1661  p += sizeof(uint32_t);
1662  length += sizeof(uint32_t);
1663 
1664  //Format ATTRS compound data
1665  error = sftpFormatAttributes(session->version, attributes, p, &n);
1666  //Any error to report?
1667  if(error)
1668  return error;
1669 
1670  //Total length of the message
1671  length += n;
1672 
1673  //Convert the length field to network byte order
1674  header->length = htonl(length);
1675 
1676  //The packet length does not include the length field itself
1677  session->bufferLen = length + sizeof(uint32_t);
1678  session->bufferPos = 0;
1679 
1680  //Debug message
1681  TRACE_INFO("Sending SSH_FXP_ATTRS packet (%" PRIuSIZE " bytes)...\r\n", session->bufferLen);
1682  TRACE_VERBOSE_ARRAY(" ", session->buffer, session->bufferLen);
1683 
1684  //Send the packet to the SFTP client
1685  session->state = SFTP_SERVER_SESSION_STATE_SENDING;
1686 
1687  //Successful processing
1688  return NO_ERROR;
1689 }
1690 
1691 #endif
error_t sftpServerOpenDir(SftpServerSession *session, const SshString *path, uint32_t *handle)
Open a directory.
error_t sftpServerParseFxpMkDir(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_MKDIR packet.
error_t sftpServerWriteFile(SftpServerSession *session, const SshBinaryString *handle, uint64_t offset, const uint8_t *data, uint32_t fragLen, uint32_t totalLen)
Write the specified file.
Path manipulation helper functions.
@ SSH_FXP_ATTRS
Definition: sftp_common.h:159
error_t sftpServerCloseDir(SftpServerSession *session, const SshBinaryString *handle)
Close a directory.
error_t sftpServerParseFxpSetStat(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_SETSTAT packet.
error_t sftpServerParseFxpFstat(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_FSTAT packet.
#define LOAD32BE(p)
Definition: cpu_endian.h:210
Binary string.
Definition: ssh_types.h:67
error_t sftpServerParseFxpRename(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_RENAME packet.
uint8_t p
Definition: ndp.h:300
uint8_t message[]
Definition: chap.h:154
error_t sftpServerReadDir(SftpServerSession *session, const SshBinaryString *handle, SftpName *name)
Read an entry from the specified directory.
uint8_t data[]
Definition: ethernet.h:222
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
error_t sftpFormatName(SftpVersion version, const SftpName *name, uint8_t *p, size_t *written)
Format name structure.
Definition: sftp_common.c:50
error_t sftpServerRemoveDir(SftpServerSession *session, const SshString *path)
Remove a directory.
error_t sshParseString(const uint8_t *p, size_t length, SshString *string)
Parse a string.
Definition: ssh_misc.c:1152
uint8_t attributes[]
Definition: radius.h:88
@ SSH_FXP_STATUS
Definition: sftp_common.h:155
char_t name[]
size_t length
Definition: ssh_types.h:58
error_t sftpServerReadFile(SftpServerSession *session, const SshBinaryString *handle, uint64_t offset, uint32_t *length)
Read the specified file.
#define SFTP_SERVER_MAX_VERSION
Definition: sftp_server.h:81
uint8_t version
Definition: coap_common.h:177
@ ERROR_INVALID_HANDLE
Definition: error.h:281
@ ERROR_END_OF_STREAM
Definition: error.h:210
error_t sftpServerParseFxpSetFstat(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_FSETSTAT packet.
@ ERROR_INVALID_VERSION
Definition: error.h:118
@ SSH_FXP_HANDLE
Definition: sftp_common.h:156
SFTP server.
error_t sftpServerParseFxpRead(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_READ packet.
#define LOAD64BE(p)
Definition: cpu_endian.h:246
@ SSH_FXP_VERSION
Definition: sftp_common.h:136
error_t sftpServerParseFxpInit(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_INIT packet.
error_t sftpFormatFxpName(SftpServerSession *session, uint32_t id, const SftpName *name)
Format SSH_FXP_NAME packet.
size_t length
Definition: ssh_types.h:69
Directory operations.
#define htonl(value)
Definition: cpu_endian.h:414
#define SFTP_SERVER_MIN_VERSION
Definition: sftp_server.h:74
error_t sftpServerParseFxpOpen(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_OPEN packet.
error_t
Error codes.
Definition: error.h:43
error_t sftpServerParseFxpExtended(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_EXTENDED packet.
File operations.
error_t sftpParseAttributes(SftpVersion version, SftpFileAttrs *attributes, const uint8_t *data, size_t length, size_t *consumed)
Parse file attributes.
Definition: sftp_common.c:454
error_t sftpServerGetRealPath(SftpServerSession *session, const SshString *path, SftpName *name)
Canonicalize a given path name to an absolute path.
error_t sftpFormatAttributes(SftpVersion version, const SftpFileAttrs *attributes, uint8_t *p, size_t *written)
Format file attributes.
Definition: sftp_common.c:255
SftpPacketHeader
Definition: sftp_common.h:219
error_t sftpServerRemoveFile(SftpServerSession *session, const SshString *path)
Remove a file.
error_t sftpServerParseFxpOpenDir(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_OPENDIR packet.
error_t sftpServerParseFxpWrite(SftpServerSession *session, const uint8_t *packet, size_t fragLen, size_t totalLen)
Parse SSH_FXP_WRITE packet.
@ SSH_FXP_DATA
Definition: sftp_common.h:157
error_t sftpFormatFxpStatus(SftpServerSession *session, uint32_t id, uint32_t statusCode, const char_t *message)
Format SSH_FXP_STATUS message.
error_t sftpFormatFxpData(SftpServerSession *session, uint32_t id, size_t dataLen)
Format SSH_FXP_DATA message.
@ ERROR_INVALID_PACKET
Definition: error.h:140
error_t sftpServerRenameFile(SftpServerSession *session, const SshString *oldPath, const SshString *newPath)
Rename the specified file.
@ SSH_FX_FAILURE
Definition: sftp_common.h:175
char_t filename[]
Definition: tftp_common.h:93
error_t sftpServerCloseFile(SftpServerSession *session, const SshBinaryString *handle)
Close a file.
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
@ SSH_FX_OK
Definition: sftp_common.h:171
@ SSH_FX_OP_UNSUPPORTED
Definition: sftp_common.h:179
#define MIN(a, b)
Definition: os_port.h:63
error_t sftpFormatFxpAttrs(SftpServerSession *session, uint32_t id, const SftpFileAttrs *attributes)
Format SSH_FXP_ATTRS packet.
@ SSH_FXP_NAME
Definition: sftp_common.h:158
SFTP packet parsing and formatting.
@ SFTP_SERVER_SESSION_STATE_SENDING_DATA
Definition: sftp_server.h:161
String.
Definition: ssh_types.h:56
uint32_t dataLen
Definition: sftp_common.h:229
error_t sftpServerParseFxpClose(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_CLOSE packet.
error_t sftpServerOpenFile(SftpServerSession *session, const SshString *path, uint32_t pflags, const SftpFileAttrs *attributes, uint32_t *handle)
Open a file.
#define TRACE_DEBUG(...)
Definition: debug.h:107
char char_t
Definition: compiler_port.h:48
Name structure.
Definition: sftp_common.h:265
error_t sftpServerSetFileStat(SftpServerSession *session, const SshString *path, const SftpFileAttrs *attributes)
Modify file attributes.
error_t sftpFormatFxpHandle(SftpServerSession *session, uint32_t id, uint32_t handle)
Format SSH_FXP_HANDLE message.
uint8_t n
error_t sftpServerParseFxpRealPath(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_REALPATH packet.
error_t sftpServerParseFxpStat(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_STAT packet.
error_t sftpServerParseFxpReadDir(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_READDIR packet.
Helper functions for SFTP server.
SSH helper functions.
error_t sftpFormatFxpVersion(SftpServerSession *session, uint32_t version)
Format SSH_FXP_VERSION packet.
error_t sftpServerSetFileStatEx(SftpServerSession *session, const SshBinaryString *handle, const SftpFileAttrs *attributes)
Modify file attributes.
SftpVersion
SFTP protocol version.
Definition: sftp_common.h:118
error_t sshParseBinaryString(const uint8_t *p, size_t length, SshBinaryString *string)
Parse a binary string.
Definition: ssh_misc.c:1189
error_t sshFormatString(const char_t *value, uint8_t *p, size_t *written)
Format a string.
Definition: ssh_misc.c:1384
#define SftpServerSession
Definition: sftp_server.h:120
#define PRIuSIZE
File attributes.
Definition: sftp_common.h:247
error_t sftpServerGetFileStat(SftpServerSession *session, const SshString *path, SftpFileAttrs *attributes)
Retrieve file attributes.
error_t sftpServerCreateDir(SftpServerSession *session, const SshString *path, const SftpFileAttrs *attributes)
Create a directory.
error_t sftpServerParseFxpRemove(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_REMOVE packet.
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
@ SSH_FX_EOF
Definition: sftp_common.h:172
error_t sftpServerGetFileStatEx(SftpServerSession *session, const SshBinaryString *handle, SftpFileAttrs *attributes)
Retrieve file attributes.
@ SFTP_SERVER_SESSION_STATE_SENDING
Definition: sftp_server.h:159
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
error_t sftpServerParseFxpRmDir(SftpServerSession *session, const uint8_t *packet, size_t length)
Parse SSH_FXP_RMDIR packet.
@ SSH_FX_NO_SUCH_FILE
Definition: sftp_common.h:173
#define TRACE_VERBOSE_ARRAY(p, a, n)
Definition: debug.h:125