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.
20 #include "silcincludes.h"
22 #include "sftp_util.h"
24 /* SFTP Server context */
26 SilcSocketConnection sock;
27 SilcSFTPSendPacketCallback send_packet;
29 SilcSFTPFilesystem fs;
33 /* General routine to send SFTP packet to the SFTP client. */
35 static void silc_sftp_send_packet(SilcSFTPServer sftp,
43 packet = silc_sftp_packet_encode_vp(type, len, vp);
49 SILC_LOG_HEXDUMP(("SFTP packet to client"), packet->data, packet->len);
52 (*sftp->send_packet)(sftp->sock, packet, sftp->send_context);
54 silc_buffer_free(packet);
57 /* Sends error to the client */
59 static void silc_sftp_send_error(SilcSFTPServer sftp,
60 SilcSFTPStatus status,
63 SILC_LOG_DEBUG(("Send error %d", status));
65 silc_sftp_send_packet(sftp, SILC_SFTP_STATUS, 16,
67 SILC_STR_UI_INT(status),
68 SILC_STR_UI_INT(0), /* Error */
69 SILC_STR_UI_INT(0), /* Language tag */
75 static void silc_sftp_server_status(SilcSFTP sftp,
76 SilcSFTPStatus status,
78 const char *language_tag,
81 SilcSFTPServer server = (SilcSFTPServer)sftp;
82 uint32 id = (uint32)context;
85 SILC_LOG_DEBUG(("Status callback"));
86 SILC_LOG_DEBUG(("Request ID: %d", id));
92 mlen = strlen(message);
93 llen = strlen(language_tag);
95 silc_sftp_send_packet(server, SILC_SFTP_STATUS, 16 + mlen + llen,
97 SILC_STR_UI_INT(status),
98 SILC_STR_UI_INT(mlen),
99 SILC_STR_UI32_STRING(message),
100 SILC_STR_UI_INT(llen),
101 SILC_STR_UI32_STRING(language_tag),
105 /* Handle callback */
107 static void silc_sftp_server_handle(SilcSFTP sftp,
108 SilcSFTPStatus status,
109 SilcSFTPHandle handle,
112 SilcSFTPServer server = (SilcSFTPServer)sftp;
113 uint32 id = (uint32)context;
114 unsigned char *hdata;
117 SILC_LOG_DEBUG(("Handle callback"));
118 SILC_LOG_DEBUG(("Request ID: %d", id));
120 if (status != SILC_SFTP_STATUS_OK) {
121 silc_sftp_send_error(server, status, id);
125 hdata = server->fs->sftp_encode_handle(server->fs_context, sftp,
128 silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
132 silc_sftp_send_packet(server, SILC_SFTP_HANDLE, 8 + hdata_len,
134 SILC_STR_UI_INT(hdata_len),
135 SILC_STR_UI_XNSTRING(hdata, hdata_len),
141 static void silc_sftp_server_data(SilcSFTP sftp,
142 SilcSFTPStatus status,
143 const unsigned char *data,
147 SilcSFTPServer server = (SilcSFTPServer)sftp;
148 uint32 id = (uint32)context;
150 SILC_LOG_DEBUG(("Data callback"));
151 SILC_LOG_DEBUG(("Request ID: %d", id));
153 if (status != SILC_SFTP_STATUS_OK) {
154 silc_sftp_send_error(server, status, id);
158 silc_sftp_send_packet(server, SILC_SFTP_DATA, 8 + data_len,
160 SILC_STR_UI_INT(data_len),
161 SILC_STR_UI_XNSTRING(data, data_len),
167 static void silc_sftp_server_name(SilcSFTP sftp,
168 SilcSFTPStatus status,
169 const SilcSFTPName name,
172 SilcSFTPServer server = (SilcSFTPServer)sftp;
173 uint32 id = (uint32)context;
176 SILC_LOG_DEBUG(("Name callback"));
177 SILC_LOG_DEBUG(("Request ID: %d", id));
179 if (status != SILC_SFTP_STATUS_OK) {
180 silc_sftp_send_error(server, status, id);
184 namebuf = silc_sftp_name_encode(name);
186 silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
190 silc_sftp_send_packet(server, SILC_SFTP_NAME, 4 + namebuf->len,
192 SILC_STR_UI_XNSTRING(namebuf->data, namebuf->len),
196 /* Attributes callback */
198 static void silc_sftp_server_attr(SilcSFTP sftp,
199 SilcSFTPStatus status,
200 const SilcSFTPAttributes attrs,
203 SilcSFTPServer server = (SilcSFTPServer)sftp;
204 uint32 id = (uint32)context;
207 SILC_LOG_DEBUG(("Attr callback"));
208 SILC_LOG_DEBUG(("Request ID: %d", id));
210 if (status != SILC_SFTP_STATUS_OK) {
211 silc_sftp_send_error(server, status, id);
215 attr_buf = silc_sftp_attr_encode(attrs);
217 silc_sftp_send_packet(server, SILC_SFTP_ATTRS, 4 + attr_buf->len,
219 SILC_STR_UI_XNSTRING(attr_buf->data, attr_buf->len),
222 silc_buffer_free(attr_buf);
225 /* Extended callback */
227 static void silc_sftp_server_extended(SilcSFTP sftp,
228 SilcSFTPStatus status,
229 const unsigned char *data,
233 SilcSFTPServer server = (SilcSFTPServer)sftp;
234 uint32 id = (uint32)context;
236 SILC_LOG_DEBUG(("Extended callback"));
237 SILC_LOG_DEBUG(("Request ID: %d", id));
239 if (status != SILC_SFTP_STATUS_OK) {
240 silc_sftp_send_error(server, status, id);
244 silc_sftp_send_packet(server, SILC_SFTP_EXTENDED, 4 + data_len,
246 SILC_STR_UI_XNSTRING(data, data_len),
250 /* Starts SFTP server by associating the socket connection `sock' to the
251 created SFTP server context. This function returns the allocated
252 SFTP client context or NULL on error. The `send_packet' is called
253 by the library when it needs to send a packet. The `fs' is the
254 structure containing filesystem access callbacks. */
256 SilcSFTP silc_sftp_server_start(SilcSocketConnection sock,
257 SilcSFTPSendPacketCallback send_packet,
259 SilcSFTPFilesystem fs,
262 SilcSFTPServer server;
264 server = silc_calloc(1, sizeof(*server));
266 server->send_packet = send_packet;
267 server->send_context = send_context;
269 server->fs_context = fs_context;
271 SILC_LOG_DEBUG(("Starting SFTP server %p", server));
273 return (SilcSFTP)server;
276 /* Shutdown's the SFTP server. The caller is responsible of closing
277 the associated socket connection. The SFTP context is freed and is
278 invalid after this function returns. */
280 void silc_sftp_server_shutdown(SilcSFTP sftp)
282 SilcSFTPServer server = (SilcSFTPServer)sftp;
284 SILC_LOG_DEBUG(("Stopping SFTP server %p", server));
289 /* Function that is called to process the incmoing SFTP packet. */
290 /* XXX Some day this will go away and we have automatic receive callbacks
291 for SilcSocketConnection API or SilcPacketContext API. */
293 void silc_sftp_server_receive_process(SilcSFTP sftp,
294 SilcSocketConnection sock,
295 SilcPacketContext *packet)
297 SilcSFTPServer server = (SilcSFTPServer)sftp;
299 char *filename = NULL, *path = NULL;
300 const unsigned char *payload = NULL;
303 SilcBufferStruct buf;
305 SilcSFTPAttributes attrs;
306 SilcSFTPHandle handle;
308 SILC_LOG_DEBUG(("Start"));
310 /* Parse the packet */
311 type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload,
316 silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
321 SilcSFTPVersion version;
323 SILC_LOG_DEBUG(("Init request"));
325 ret = silc_buffer_unformat(&buf,
326 SILC_STR_UI_INT(&version),
331 silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4,
332 SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
339 SilcSFTPFileOperation pflags;
340 unsigned char *attr_buf;
342 SilcBufferStruct tmpbuf;
344 SILC_LOG_DEBUG(("Open request"));
346 ret = silc_buffer_unformat(&buf,
347 SILC_STR_UI_INT(&id),
348 SILC_STR_UI32_STRING_ALLOC(&filename),
349 SILC_STR_UI_INT(&pflags),
350 SILC_STR_UI32_NSTRING(&attr_buf,
357 silc_buffer_set(&tmpbuf, attr_buf, attr_len);
358 attrs = silc_sftp_attr_decode(&tmpbuf);
360 attrs = silc_calloc(1, sizeof(*attrs));
364 server->fs->sftp_open(server->fs_context, sftp, filename, pflags,
365 attrs, silc_sftp_server_handle, (void *)id);
368 silc_sftp_attr_free(attrs);
372 case SILC_SFTP_CLOSE:
374 unsigned char *hdata;
377 SILC_LOG_DEBUG(("Close request"));
379 ret = silc_buffer_unformat(&buf,
380 SILC_STR_UI_INT(&id),
381 SILC_STR_UI32_NSTRING(&hdata,
388 handle = server->fs->sftp_get_handle(server->fs_context, sftp,
389 (const unsigned char *)hdata,
392 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
396 /* Close operation */
397 server->fs->sftp_close(server->fs_context, sftp, handle,
398 silc_sftp_server_status, (void *)id);
404 unsigned char *hdata;
409 SILC_LOG_DEBUG(("Read request"));
411 ret = silc_buffer_unformat(&buf,
412 SILC_STR_UI_INT(&id),
413 SILC_STR_UI32_NSTRING(&hdata,
415 SILC_STR_UI_INT64(&offset),
416 SILC_STR_UI_INT(&len),
422 handle = server->fs->sftp_get_handle(server->fs_context, sftp,
423 (const unsigned char *)hdata,
426 silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
431 server->fs->sftp_read(server->fs_context, sftp, handle, offset, len,
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->sftp_get_handle(server->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->sftp_write(server->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->sftp_remove(server->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->sftp_rename(server->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->sftp_mkdir(server->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->sftp_rmdir(server->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->sftp_opendir(server->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->sftp_get_handle(server->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->sftp_readdir(server->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->sftp_stat(server->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->sftp_lstat(server->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->sftp_get_handle(server->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->sftp_fstat(server->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->sftp_setstat(server->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->sftp_get_handle(server->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->sftp_fsetstat(server->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->sftp_readlink(server->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->sftp_symlink(server->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->sftp_realpath(server->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->sftp_extended(server->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);