5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
23 #include "sftp_util.h"
25 /* SFTP Server context */
27 SilcSocketConnection sock;
28 SilcSFTPSendPacketCallback send_packet;
30 SilcSFTPFilesystem fs;
34 /* General routine to send SFTP packet to the SFTP client. */
36 static void silc_sftp_send_packet(SilcSFTPServer sftp,
44 packet = silc_sftp_packet_encode_vp(type, len, vp);
50 SILC_LOG_HEXDUMP(("SFTP packet to client"), packet->data, packet->len);
53 (*sftp->send_packet)(sftp->sock, packet, sftp->send_context);
55 silc_buffer_free(packet);
58 /* Sends error to the client */
60 static void silc_sftp_send_error(SilcSFTPServer sftp,
61 SilcSFTPStatus status,
64 SILC_LOG_DEBUG(("Send error %d", status));
66 silc_sftp_send_packet(sftp, SILC_SFTP_STATUS, 16,
68 SILC_STR_UI_INT(status),
69 SILC_STR_UI_INT(0), /* Error */
70 SILC_STR_UI_INT(0), /* Language tag */
76 static void silc_sftp_server_status(SilcSFTP sftp,
77 SilcSFTPStatus status,
79 const char *language_tag,
82 SilcSFTPServer server = (SilcSFTPServer)sftp;
83 uint32 id = (uint32)context;
86 SILC_LOG_DEBUG(("Status callback"));
87 SILC_LOG_DEBUG(("Request ID: %d", id));
93 mlen = strlen(message);
94 llen = strlen(language_tag);
96 silc_sftp_send_packet(server, SILC_SFTP_STATUS, 16 + mlen + llen,
98 SILC_STR_UI_INT(status),
99 SILC_STR_UI_INT(mlen),
100 SILC_STR_UI32_STRING(message),
101 SILC_STR_UI_INT(llen),
102 SILC_STR_UI32_STRING(language_tag),
106 /* Handle callback */
108 static void silc_sftp_server_handle(SilcSFTP sftp,
109 SilcSFTPStatus status,
110 SilcSFTPHandle handle,
113 SilcSFTPServer server = (SilcSFTPServer)sftp;
114 uint32 id = (uint32)context;
115 unsigned char *hdata;
118 SILC_LOG_DEBUG(("Handle callback"));
119 SILC_LOG_DEBUG(("Request ID: %d", id));
121 if (status != SILC_SFTP_STATUS_OK) {
122 silc_sftp_send_error(server, status, id);
126 hdata = server->fs->sftp_encode_handle(server->fs_context, sftp,
129 silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
133 silc_sftp_send_packet(server, SILC_SFTP_HANDLE, 8 + hdata_len,
135 SILC_STR_UI_INT(hdata_len),
136 SILC_STR_UI_XNSTRING(hdata, hdata_len),
142 static void silc_sftp_server_data(SilcSFTP sftp,
143 SilcSFTPStatus status,
144 const unsigned char *data,
148 SilcSFTPServer server = (SilcSFTPServer)sftp;
149 uint32 id = (uint32)context;
151 SILC_LOG_DEBUG(("Data callback"));
152 SILC_LOG_DEBUG(("Request ID: %d", id));
154 if (status != SILC_SFTP_STATUS_OK) {
155 silc_sftp_send_error(server, status, id);
159 silc_sftp_send_packet(server, SILC_SFTP_DATA, 8 + data_len,
161 SILC_STR_UI_INT(data_len),
162 SILC_STR_UI_XNSTRING(data, data_len),
168 static void silc_sftp_server_name(SilcSFTP sftp,
169 SilcSFTPStatus status,
170 const SilcSFTPName name,
173 SilcSFTPServer server = (SilcSFTPServer)sftp;
174 uint32 id = (uint32)context;
177 SILC_LOG_DEBUG(("Name callback"));
178 SILC_LOG_DEBUG(("Request ID: %d", id));
180 if (status != SILC_SFTP_STATUS_OK) {
181 silc_sftp_send_error(server, status, id);
185 namebuf = silc_sftp_name_encode(name);
187 silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
191 silc_sftp_send_packet(server, SILC_SFTP_NAME, 4 + namebuf->len,
193 SILC_STR_UI_XNSTRING(namebuf->data, namebuf->len),
197 /* Attributes callback */
199 static void silc_sftp_server_attr(SilcSFTP sftp,
200 SilcSFTPStatus status,
201 const SilcSFTPAttributes attrs,
204 SilcSFTPServer server = (SilcSFTPServer)sftp;
205 uint32 id = (uint32)context;
208 SILC_LOG_DEBUG(("Attr callback"));
209 SILC_LOG_DEBUG(("Request ID: %d", id));
211 if (status != SILC_SFTP_STATUS_OK) {
212 silc_sftp_send_error(server, status, id);
216 attr_buf = silc_sftp_attr_encode(attrs);
218 silc_sftp_send_packet(server, SILC_SFTP_ATTRS, 4 + attr_buf->len,
220 SILC_STR_UI_XNSTRING(attr_buf->data, attr_buf->len),
223 silc_buffer_free(attr_buf);
226 /* Extended callback */
228 static void silc_sftp_server_extended(SilcSFTP sftp,
229 SilcSFTPStatus status,
230 const unsigned char *data,
234 SilcSFTPServer server = (SilcSFTPServer)sftp;
235 uint32 id = (uint32)context;
237 SILC_LOG_DEBUG(("Extended callback"));
238 SILC_LOG_DEBUG(("Request ID: %d", id));
240 if (status != SILC_SFTP_STATUS_OK) {
241 silc_sftp_send_error(server, status, id);
245 silc_sftp_send_packet(server, SILC_SFTP_EXTENDED, 4 + data_len,
247 SILC_STR_UI_XNSTRING(data, data_len),
251 /* Starts SFTP server by associating the socket connection `sock' to the
252 created SFTP server context. This function returns the allocated
253 SFTP client context or NULL on error. The `send_packet' is called
254 by the library when it needs to send a packet. The `fs' is the
255 structure containing filesystem access callbacks. */
257 SilcSFTP silc_sftp_server_start(SilcSocketConnection sock,
258 SilcSFTPSendPacketCallback send_packet,
260 SilcSFTPFilesystem fs,
263 SilcSFTPServer server;
265 server = silc_calloc(1, sizeof(*server));
267 server->send_packet = send_packet;
268 server->send_context = send_context;
270 server->fs_context = fs_context;
272 SILC_LOG_DEBUG(("Starting SFTP server %p", server));
274 return (SilcSFTP)server;
277 /* Shutdown's the SFTP server. The caller is responsible of closing
278 the associated socket connection. The SFTP context is freed and is
279 invalid after this function returns. */
281 void silc_sftp_server_shutdown(SilcSFTP sftp)
283 SilcSFTPServer server = (SilcSFTPServer)sftp;
285 SILC_LOG_DEBUG(("Stopping SFTP server %p", server));
290 /* Function that is called to process the incmoing SFTP packet. */
291 /* XXX Some day this will go away and we have automatic receive callbacks
292 for SilcSocketConnection API or SilcPacketContext API. */
294 void silc_sftp_server_receive_process(SilcSFTP sftp,
295 SilcSocketConnection sock,
296 SilcPacketContext *packet)
298 SilcSFTPServer server = (SilcSFTPServer)sftp;
300 char *filename = NULL, *path = NULL;
301 const unsigned char *payload = NULL;
304 SilcBufferStruct buf;
306 SilcSFTPAttributes attrs;
307 SilcSFTPHandle handle;
309 SILC_LOG_DEBUG(("Start"));
311 /* Parse the packet */
312 type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload,
317 silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
322 SilcSFTPVersion version;
324 SILC_LOG_DEBUG(("Init request"));
326 ret = silc_buffer_unformat(&buf,
327 SILC_STR_UI_INT(&version),
332 silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4,
333 SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
340 SilcSFTPFileOperation pflags;
341 unsigned char *attr_buf;
343 SilcBufferStruct tmpbuf;
345 SILC_LOG_DEBUG(("Open request"));
347 ret = silc_buffer_unformat(&buf,
348 SILC_STR_UI_INT(&id),
349 SILC_STR_UI32_STRING_ALLOC(&filename),
350 SILC_STR_UI_INT(&pflags),
351 SILC_STR_UI32_NSTRING(&attr_buf,
358 silc_buffer_set(&tmpbuf, attr_buf, attr_len);
359 attrs = silc_sftp_attr_decode(&tmpbuf);
361 attrs = silc_calloc(1, sizeof(*attrs));
365 server->fs->sftp_open(server->fs_context, sftp, filename, pflags,
366 attrs, silc_sftp_server_handle, (void *)id);
369 silc_sftp_attr_free(attrs);
373 case SILC_SFTP_CLOSE:
375 unsigned char *hdata;
378 SILC_LOG_DEBUG(("Close request"));
380 ret = silc_buffer_unformat(&buf,
381 SILC_STR_UI_INT(&id),
382 SILC_STR_UI32_NSTRING(&hdata,
389 handle = server->fs->sftp_get_handle(server->fs_context, sftp,
390 (const unsigned char *)hdata,
393 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
397 /* Close operation */
398 server->fs->sftp_close(server->fs_context, sftp, handle,
399 silc_sftp_server_status, (void *)id);
405 unsigned char *hdata;
410 SILC_LOG_DEBUG(("Read request"));
412 ret = silc_buffer_unformat(&buf,
413 SILC_STR_UI_INT(&id),
414 SILC_STR_UI32_NSTRING(&hdata,
416 SILC_STR_UI_INT64(&offset),
417 SILC_STR_UI_INT(&len),
423 handle = server->fs->sftp_get_handle(server->fs_context, sftp,
424 (const unsigned char *)hdata,
427 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
432 server->fs->sftp_read(server->fs_context, sftp, handle, offset, len,
433 silc_sftp_server_data, (void *)id);
437 case SILC_SFTP_WRITE:
439 unsigned char *hdata;
445 SILC_LOG_DEBUG(("Read request"));
447 ret = silc_buffer_unformat(&buf,
448 SILC_STR_UI_INT(&id),
449 SILC_STR_UI32_NSTRING(&hdata,
451 SILC_STR_UI_INT64(&offset),
452 SILC_STR_UI32_NSTRING(&data,
459 handle = server->fs->sftp_get_handle(server->fs_context, sftp,
460 (const unsigned char *)hdata,
463 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
467 /* Write operation */
468 server->fs->sftp_write(server->fs_context, sftp, handle, offset,
469 (const unsigned char *)data, data_len,
470 silc_sftp_server_status, (void *)id);
474 case SILC_SFTP_REMOVE:
476 SILC_LOG_DEBUG(("Remove request"));
478 ret = silc_buffer_unformat(&buf,
479 SILC_STR_UI_INT(&id),
480 SILC_STR_UI32_STRING_ALLOC(&filename),
485 /* Remove operation */
486 server->fs->sftp_remove(server->fs_context, sftp, filename,
487 silc_sftp_server_status, (void *)id);
493 case SILC_SFTP_RENAME:
495 char *newname = NULL;
497 SILC_LOG_DEBUG(("Rename request"));
499 ret = silc_buffer_unformat(&buf,
500 SILC_STR_UI_INT(&id),
501 SILC_STR_UI32_STRING_ALLOC(&filename),
502 SILC_STR_UI32_STRING_ALLOC(&newname),
507 /* Rename operation */
508 server->fs->sftp_rename(server->fs_context, sftp, filename, newname,
509 silc_sftp_server_status, (void *)id);
516 case SILC_SFTP_MKDIR:
518 unsigned char *attr_buf;
520 SilcBufferStruct tmpbuf;
522 SILC_LOG_DEBUG(("Mkdir request"));
524 ret = silc_buffer_unformat(&buf,
525 SILC_STR_UI_INT(&id),
526 SILC_STR_UI32_STRING_ALLOC(&path),
527 SILC_STR_UI32_NSTRING(&attr_buf,
534 silc_buffer_set(&tmpbuf, attr_buf, attr_len);
535 attrs = silc_sftp_attr_decode(&tmpbuf);
537 attrs = silc_calloc(1, sizeof(*attrs));
540 /* Mkdir operation */
541 server->fs->sftp_mkdir(server->fs_context, sftp, path, attrs,
542 silc_sftp_server_status, (void *)id);
544 silc_sftp_attr_free(attrs);
549 case SILC_SFTP_RMDIR:
551 SILC_LOG_DEBUG(("Rmdir request"));
553 ret = silc_buffer_unformat(&buf,
554 SILC_STR_UI_INT(&id),
555 SILC_STR_UI32_STRING_ALLOC(&path),
560 /* Rmdir operation */
561 server->fs->sftp_rmdir(server->fs_context, sftp, path,
562 silc_sftp_server_status, (void *)id);
568 case SILC_SFTP_OPENDIR:
570 SILC_LOG_DEBUG(("Opendir request"));
572 ret = silc_buffer_unformat(&buf,
573 SILC_STR_UI_INT(&id),
574 SILC_STR_UI32_STRING_ALLOC(&path),
579 /* Opendir operation */
580 server->fs->sftp_opendir(server->fs_context, sftp, path,
581 silc_sftp_server_handle, (void *)id);
587 case SILC_SFTP_READDIR:
589 unsigned char *hdata;
592 SILC_LOG_DEBUG(("Readdir request"));
594 ret = silc_buffer_unformat(&buf,
595 SILC_STR_UI_INT(&id),
596 SILC_STR_UI32_NSTRING(&hdata,
603 handle = server->fs->sftp_get_handle(server->fs_context, sftp,
604 (const unsigned char *)hdata,
607 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
611 /* Readdir operation */
612 server->fs->sftp_readdir(server->fs_context, sftp, handle,
613 silc_sftp_server_name, (void *)id);
619 SILC_LOG_DEBUG(("Stat request"));
621 ret = silc_buffer_unformat(&buf,
622 SILC_STR_UI_INT(&id),
623 SILC_STR_UI32_STRING_ALLOC(&path),
629 server->fs->sftp_stat(server->fs_context, sftp, path,
630 silc_sftp_server_attr, (void *)id);
636 case SILC_SFTP_LSTAT:
638 SILC_LOG_DEBUG(("Lstat request"));
640 ret = silc_buffer_unformat(&buf,
641 SILC_STR_UI_INT(&id),
642 SILC_STR_UI32_STRING_ALLOC(&path),
647 /* Lstat operation */
648 server->fs->sftp_lstat(server->fs_context, sftp, path,
649 silc_sftp_server_attr, (void *)id);
655 case SILC_SFTP_FSTAT:
657 unsigned char *hdata;
660 SILC_LOG_DEBUG(("Fstat request"));
662 ret = silc_buffer_unformat(&buf,
663 SILC_STR_UI_INT(&id),
664 SILC_STR_UI32_NSTRING(&hdata,
671 handle = server->fs->sftp_get_handle(server->fs_context, sftp,
672 (const unsigned char *)hdata,
675 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
679 /* Fstat operation */
680 server->fs->sftp_fstat(server->fs_context, sftp, handle,
681 silc_sftp_server_attr, (void *)id);
685 case SILC_SFTP_SETSTAT:
687 unsigned char *attr_buf;
689 SilcBufferStruct tmpbuf;
691 SILC_LOG_DEBUG(("Setstat request"));
693 ret = silc_buffer_unformat(&buf,
694 SILC_STR_UI_INT(&id),
695 SILC_STR_UI32_STRING_ALLOC(&path),
696 SILC_STR_UI32_NSTRING(&attr_buf,
703 silc_buffer_set(&tmpbuf, attr_buf, attr_len);
704 attrs = silc_sftp_attr_decode(&tmpbuf);
706 attrs = silc_calloc(1, sizeof(*attrs));
709 /* Setstat operation */
710 server->fs->sftp_setstat(server->fs_context, sftp, path, attrs,
711 silc_sftp_server_status, (void *)id);
713 silc_sftp_attr_free(attrs);
718 case SILC_SFTP_FSETSTAT:
720 unsigned char *hdata, *attr_buf;
721 uint32 hdata_len, attr_len = 0;
722 SilcBufferStruct tmpbuf;
724 SILC_LOG_DEBUG(("Fsetstat request"));
726 ret = silc_buffer_unformat(&buf,
727 SILC_STR_UI_INT(&id),
728 SILC_STR_UI32_NSTRING(&hdata,
730 SILC_STR_UI32_NSTRING(&attr_buf,
737 silc_buffer_set(&tmpbuf, attr_buf, attr_len);
738 attrs = silc_sftp_attr_decode(&tmpbuf);
740 attrs = silc_calloc(1, sizeof(*attrs));
744 handle = server->fs->sftp_get_handle(server->fs_context, sftp,
745 (const unsigned char *)hdata,
748 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
752 /* Fsetstat operation */
753 server->fs->sftp_fsetstat(server->fs_context, sftp, handle, attrs,
754 silc_sftp_server_status, (void *)id);
756 silc_sftp_attr_free(attrs);
760 case SILC_SFTP_READLINK:
762 SILC_LOG_DEBUG(("Readlink request"));
764 ret = silc_buffer_unformat(&buf,
765 SILC_STR_UI_INT(&id),
766 SILC_STR_UI32_STRING_ALLOC(&path),
771 /* Readlink operation */
772 server->fs->sftp_readlink(server->fs_context, sftp, path,
773 silc_sftp_server_name, (void *)id);
779 case SILC_SFTP_SYMLINK:
783 SILC_LOG_DEBUG(("Symlink request"));
785 ret = silc_buffer_unformat(&buf,
786 SILC_STR_UI_INT(&id),
787 SILC_STR_UI32_STRING_ALLOC(&path),
788 SILC_STR_UI32_STRING_ALLOC(&target),
793 /* Symlink operation */
794 server->fs->sftp_symlink(server->fs_context, sftp, path, target,
795 silc_sftp_server_status, (void *)id);
802 case SILC_SFTP_REALPATH:
804 SILC_LOG_DEBUG(("Realpath request"));
806 ret = silc_buffer_unformat(&buf,
807 SILC_STR_UI_INT(&id),
808 SILC_STR_UI32_STRING_ALLOC(&path),
813 /* Realpath operation */
814 server->fs->sftp_realpath(server->fs_context, sftp, path,
815 silc_sftp_server_name, (void *)id);
821 case SILC_SFTP_EXTENDED:
823 char *request = NULL;
827 SILC_LOG_DEBUG(("Extended request"));
829 ret = silc_buffer_unformat(&buf,
830 SILC_STR_UI_INT(&id),
831 SILC_STR_UI32_STRING_ALLOC(&request),
836 data_len = 8 + strlen(request);
837 silc_buffer_pull(&buf, data_len);
838 ret = silc_buffer_unformat(&buf,
839 SILC_STR_UI_XNSTRING(&data, buf.len),
845 /* Extended operation */
846 server->fs->sftp_extended(server->fs_context, sftp,
847 request, data, data_len,
848 silc_sftp_server_extended, (void *)id);
861 silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);