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 "silcsftp_fs.h"
24 #include "sftp_util.h"
26 /* SFTP Server context */
28 SilcSocketConnection sock;
29 SilcSFTPSendPacketCallback send_packet;
31 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->fs->sftp_encode_handle(server->fs->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)
262 SilcSFTPServer server;
264 server = silc_calloc(1, sizeof(*server));
266 server->send_packet = send_packet;
267 server->send_context = send_context;
270 SILC_LOG_DEBUG(("Starting SFTP server %p", server));
272 return (SilcSFTP)server;
275 /* Shutdown's the SFTP server. The caller is responsible of closing
276 the associated socket connection. The SFTP context is freed and is
277 invalid after this function returns. */
279 void silc_sftp_server_shutdown(SilcSFTP sftp)
281 SilcSFTPServer server = (SilcSFTPServer)sftp;
283 SILC_LOG_DEBUG(("Stopping SFTP server %p", server));
288 /* Function that is called to process the incmoing SFTP packet. */
289 /* XXX Some day this will go away and we have automatic receive callbacks
290 for SilcSocketConnection API or SilcPacketContext API. */
292 void silc_sftp_server_receive_process(SilcSFTP sftp,
293 SilcSocketConnection sock,
294 SilcPacketContext *packet)
296 SilcSFTPServer server = (SilcSFTPServer)sftp;
298 char *filename = NULL, *path = NULL;
299 const unsigned char *payload = NULL;
302 SilcBufferStruct buf;
304 SilcSFTPAttributes attrs;
305 SilcSFTPHandle handle;
307 SILC_LOG_DEBUG(("Start"));
309 /* Parse the packet */
310 type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload,
315 silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
320 SilcSFTPVersion version;
322 SILC_LOG_DEBUG(("Init request"));
324 ret = silc_buffer_unformat(&buf,
325 SILC_STR_UI_INT(&version),
330 silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4,
331 SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
338 SilcSFTPFileOperation pflags;
339 unsigned char *attr_buf;
341 SilcBufferStruct tmpbuf;
343 SILC_LOG_DEBUG(("Open request"));
345 ret = silc_buffer_unformat(&buf,
346 SILC_STR_UI_INT(&id),
347 SILC_STR_UI32_STRING_ALLOC(&filename),
348 SILC_STR_UI_INT(&pflags),
349 SILC_STR_UI32_NSTRING(&attr_buf,
356 silc_buffer_set(&tmpbuf, attr_buf, attr_len);
357 attrs = silc_sftp_attr_decode(&tmpbuf);
359 attrs = silc_calloc(1, sizeof(*attrs));
363 server->fs->fs->sftp_open(server->fs->fs_context, sftp, filename, pflags,
364 attrs, silc_sftp_server_handle, (void *)id);
367 silc_sftp_attr_free(attrs);
371 case SILC_SFTP_CLOSE:
373 unsigned char *hdata;
376 SILC_LOG_DEBUG(("Close request"));
378 ret = silc_buffer_unformat(&buf,
379 SILC_STR_UI_INT(&id),
380 SILC_STR_UI32_NSTRING(&hdata,
387 handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
388 (const unsigned char *)hdata,
391 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
395 /* Close operation */
396 server->fs->fs->sftp_close(server->fs->fs_context, sftp, handle,
397 silc_sftp_server_status, (void *)id);
403 unsigned char *hdata;
408 SILC_LOG_DEBUG(("Read request"));
410 ret = silc_buffer_unformat(&buf,
411 SILC_STR_UI_INT(&id),
412 SILC_STR_UI32_NSTRING(&hdata,
414 SILC_STR_UI_INT64(&offset),
415 SILC_STR_UI_INT(&len),
421 handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
422 (const unsigned char *)hdata,
425 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
430 server->fs->fs->sftp_read(server->fs->fs_context, sftp,
432 silc_sftp_server_data, (void *)id);
436 case SILC_SFTP_WRITE:
438 unsigned char *hdata;
444 SILC_LOG_DEBUG(("Read request"));
446 ret = silc_buffer_unformat(&buf,
447 SILC_STR_UI_INT(&id),
448 SILC_STR_UI32_NSTRING(&hdata,
450 SILC_STR_UI_INT64(&offset),
451 SILC_STR_UI32_NSTRING(&data,
458 handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
459 (const unsigned char *)hdata,
462 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
466 /* Write operation */
467 server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset,
468 (const unsigned char *)data, data_len,
469 silc_sftp_server_status, (void *)id);
473 case SILC_SFTP_REMOVE:
475 SILC_LOG_DEBUG(("Remove request"));
477 ret = silc_buffer_unformat(&buf,
478 SILC_STR_UI_INT(&id),
479 SILC_STR_UI32_STRING_ALLOC(&filename),
484 /* Remove operation */
485 server->fs->fs->sftp_remove(server->fs->fs_context, sftp, filename,
486 silc_sftp_server_status, (void *)id);
492 case SILC_SFTP_RENAME:
494 char *newname = NULL;
496 SILC_LOG_DEBUG(("Rename request"));
498 ret = silc_buffer_unformat(&buf,
499 SILC_STR_UI_INT(&id),
500 SILC_STR_UI32_STRING_ALLOC(&filename),
501 SILC_STR_UI32_STRING_ALLOC(&newname),
506 /* Rename operation */
507 server->fs->fs->sftp_rename(server->fs->fs_context, sftp, filename, newname,
508 silc_sftp_server_status, (void *)id);
515 case SILC_SFTP_MKDIR:
517 unsigned char *attr_buf;
519 SilcBufferStruct tmpbuf;
521 SILC_LOG_DEBUG(("Mkdir request"));
523 ret = silc_buffer_unformat(&buf,
524 SILC_STR_UI_INT(&id),
525 SILC_STR_UI32_STRING_ALLOC(&path),
526 SILC_STR_UI32_NSTRING(&attr_buf,
533 silc_buffer_set(&tmpbuf, attr_buf, attr_len);
534 attrs = silc_sftp_attr_decode(&tmpbuf);
536 attrs = silc_calloc(1, sizeof(*attrs));
539 /* Mkdir operation */
540 server->fs->fs->sftp_mkdir(server->fs->fs_context, sftp, path, attrs,
541 silc_sftp_server_status, (void *)id);
543 silc_sftp_attr_free(attrs);
548 case SILC_SFTP_RMDIR:
550 SILC_LOG_DEBUG(("Rmdir request"));
552 ret = silc_buffer_unformat(&buf,
553 SILC_STR_UI_INT(&id),
554 SILC_STR_UI32_STRING_ALLOC(&path),
559 /* Rmdir operation */
560 server->fs->fs->sftp_rmdir(server->fs->fs_context, sftp, path,
561 silc_sftp_server_status, (void *)id);
567 case SILC_SFTP_OPENDIR:
569 SILC_LOG_DEBUG(("Opendir request"));
571 ret = silc_buffer_unformat(&buf,
572 SILC_STR_UI_INT(&id),
573 SILC_STR_UI32_STRING_ALLOC(&path),
578 /* Opendir operation */
579 server->fs->fs->sftp_opendir(server->fs->fs_context, sftp, path,
580 silc_sftp_server_handle, (void *)id);
586 case SILC_SFTP_READDIR:
588 unsigned char *hdata;
591 SILC_LOG_DEBUG(("Readdir request"));
593 ret = silc_buffer_unformat(&buf,
594 SILC_STR_UI_INT(&id),
595 SILC_STR_UI32_NSTRING(&hdata,
602 handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
603 (const unsigned char *)hdata,
606 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
610 /* Readdir operation */
611 server->fs->fs->sftp_readdir(server->fs->fs_context, sftp, handle,
612 silc_sftp_server_name, (void *)id);
618 SILC_LOG_DEBUG(("Stat request"));
620 ret = silc_buffer_unformat(&buf,
621 SILC_STR_UI_INT(&id),
622 SILC_STR_UI32_STRING_ALLOC(&path),
628 server->fs->fs->sftp_stat(server->fs->fs_context, sftp, path,
629 silc_sftp_server_attr, (void *)id);
635 case SILC_SFTP_LSTAT:
637 SILC_LOG_DEBUG(("Lstat request"));
639 ret = silc_buffer_unformat(&buf,
640 SILC_STR_UI_INT(&id),
641 SILC_STR_UI32_STRING_ALLOC(&path),
646 /* Lstat operation */
647 server->fs->fs->sftp_lstat(server->fs->fs_context, sftp, path,
648 silc_sftp_server_attr, (void *)id);
654 case SILC_SFTP_FSTAT:
656 unsigned char *hdata;
659 SILC_LOG_DEBUG(("Fstat request"));
661 ret = silc_buffer_unformat(&buf,
662 SILC_STR_UI_INT(&id),
663 SILC_STR_UI32_NSTRING(&hdata,
670 handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
671 (const unsigned char *)hdata,
674 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
678 /* Fstat operation */
679 server->fs->fs->sftp_fstat(server->fs->fs_context, sftp, handle,
680 silc_sftp_server_attr, (void *)id);
684 case SILC_SFTP_SETSTAT:
686 unsigned char *attr_buf;
688 SilcBufferStruct tmpbuf;
690 SILC_LOG_DEBUG(("Setstat request"));
692 ret = silc_buffer_unformat(&buf,
693 SILC_STR_UI_INT(&id),
694 SILC_STR_UI32_STRING_ALLOC(&path),
695 SILC_STR_UI32_NSTRING(&attr_buf,
702 silc_buffer_set(&tmpbuf, attr_buf, attr_len);
703 attrs = silc_sftp_attr_decode(&tmpbuf);
705 attrs = silc_calloc(1, sizeof(*attrs));
708 /* Setstat operation */
709 server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs,
710 silc_sftp_server_status, (void *)id);
712 silc_sftp_attr_free(attrs);
717 case SILC_SFTP_FSETSTAT:
719 unsigned char *hdata, *attr_buf;
720 uint32 hdata_len, attr_len = 0;
721 SilcBufferStruct tmpbuf;
723 SILC_LOG_DEBUG(("Fsetstat request"));
725 ret = silc_buffer_unformat(&buf,
726 SILC_STR_UI_INT(&id),
727 SILC_STR_UI32_NSTRING(&hdata,
729 SILC_STR_UI32_NSTRING(&attr_buf,
736 silc_buffer_set(&tmpbuf, attr_buf, attr_len);
737 attrs = silc_sftp_attr_decode(&tmpbuf);
739 attrs = silc_calloc(1, sizeof(*attrs));
743 handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
744 (const unsigned char *)hdata,
747 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
751 /* Fsetstat operation */
752 server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp, handle, attrs,
753 silc_sftp_server_status, (void *)id);
755 silc_sftp_attr_free(attrs);
759 case SILC_SFTP_READLINK:
761 SILC_LOG_DEBUG(("Readlink request"));
763 ret = silc_buffer_unformat(&buf,
764 SILC_STR_UI_INT(&id),
765 SILC_STR_UI32_STRING_ALLOC(&path),
770 /* Readlink operation */
771 server->fs->fs->sftp_readlink(server->fs->fs_context, sftp, path,
772 silc_sftp_server_name, (void *)id);
778 case SILC_SFTP_SYMLINK:
782 SILC_LOG_DEBUG(("Symlink request"));
784 ret = silc_buffer_unformat(&buf,
785 SILC_STR_UI_INT(&id),
786 SILC_STR_UI32_STRING_ALLOC(&path),
787 SILC_STR_UI32_STRING_ALLOC(&target),
792 /* Symlink operation */
793 server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target,
794 silc_sftp_server_status, (void *)id);
801 case SILC_SFTP_REALPATH:
803 SILC_LOG_DEBUG(("Realpath request"));
805 ret = silc_buffer_unformat(&buf,
806 SILC_STR_UI_INT(&id),
807 SILC_STR_UI32_STRING_ALLOC(&path),
812 /* Realpath operation */
813 server->fs->fs->sftp_realpath(server->fs->fs_context, sftp, path,
814 silc_sftp_server_name, (void *)id);
820 case SILC_SFTP_EXTENDED:
822 char *request = NULL;
826 SILC_LOG_DEBUG(("Extended request"));
828 ret = silc_buffer_unformat(&buf,
829 SILC_STR_UI_INT(&id),
830 SILC_STR_UI32_STRING_ALLOC(&request),
835 data_len = 8 + strlen(request);
836 silc_buffer_pull(&buf, data_len);
837 ret = silc_buffer_unformat(&buf,
838 SILC_STR_UI_XNSTRING(&data, buf.len),
844 /* Extended operation */
845 server->fs->fs->sftp_extended(server->fs->fs_context, sftp,
846 request, data, data_len,
847 silc_sftp_server_extended, (void *)id);
860 silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);