Added SILC Server library.
[silc.git] / lib / silcsftp / sftp_server.c
1 /*
2
3   sftp_server.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 - 2004 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcsftp.h"
23 #include "silcsftp_fs.h"
24 #include "sftp_util.h"
25
26 /* SFTP Server context */
27 typedef struct {
28   SilcSFTPSendPacketCallback send_packet;
29   void *send_context;
30   SilcSFTPMonitors monitors;
31   SilcSFTPMonitor monitor;
32   void *monitor_context;
33   SilcSFTPFilesystem fs;
34   SilcBuffer packet;
35 } *SilcSFTPServer;
36
37 /* General routine to send SFTP packet to the SFTP client. */
38
39 static void silc_sftp_send_packet(SilcSFTPServer sftp,
40                                   SilcSFTPPacket type,
41                                   SilcUInt32 len, ...)
42 {
43   SilcBuffer tmp;
44   va_list vp;
45
46   va_start(vp, len);
47   tmp = silc_sftp_packet_encode_vp(type, sftp->packet, len, vp);
48   va_end(vp);
49   if (!tmp)
50     return;
51   sftp->packet = tmp;
52
53   SILC_LOG_HEXDUMP(("SFTP packet to client"), sftp->packet->data,
54                    sftp->packet->len);
55
56   /* Send the packet */
57   (*sftp->send_packet)(sftp->packet, sftp->send_context);
58
59   /* Clear packet */
60   sftp->packet->data = sftp->packet->tail = sftp->packet->head;
61   sftp->packet->len = 0;
62 }
63
64 /* Sends error to the client */
65
66 static void silc_sftp_send_error(SilcSFTPServer sftp,
67                                  SilcSFTPStatus status,
68                                  SilcUInt32 id)
69 {
70   SILC_LOG_DEBUG(("Send error %d", status));
71
72   silc_sftp_send_packet(sftp, SILC_SFTP_STATUS, 16,
73                         SILC_STR_UI_INT(id),
74                         SILC_STR_UI_INT(status),
75                         SILC_STR_UI_INT(0),      /* Error */
76                         SILC_STR_UI_INT(0),      /* Language tag */
77                         SILC_STR_END);
78 }
79
80 /* Status callback */
81
82 static void silc_sftp_server_status(SilcSFTP sftp,
83                                     SilcSFTPStatus status,
84                                     const char *message,
85                                     const char *language_tag,
86                                     void *context)
87 {
88   SilcSFTPServer server = (SilcSFTPServer)sftp;
89   SilcUInt32 id = SILC_PTR_TO_32(context);
90   int mlen, llen;
91
92   SILC_LOG_DEBUG(("Status callback"));
93   SILC_LOG_DEBUG(("Request ID: %d", id));
94
95   if (!message)
96     message = "";
97   if (!language_tag)
98     language_tag = "";
99   mlen = strlen(message);
100   llen = strlen(language_tag);
101
102   silc_sftp_send_packet(server, SILC_SFTP_STATUS, 16 + mlen + llen,
103                         SILC_STR_UI_INT(id),
104                         SILC_STR_UI_INT(status),
105                         SILC_STR_UI_INT(mlen),
106                         SILC_STR_UI32_STRING(message),
107                         SILC_STR_UI_INT(llen),
108                         SILC_STR_UI32_STRING(language_tag),
109                         SILC_STR_END);
110 }
111
112 /* Handle callback */
113
114 static void silc_sftp_server_handle(SilcSFTP sftp,
115                                     SilcSFTPStatus status,
116                                     SilcSFTPHandle handle,
117                                     void *context)
118 {
119   SilcSFTPServer server = (SilcSFTPServer)sftp;
120   SilcUInt32 id = SILC_PTR_TO_32(context);
121   unsigned char *hdata;
122   SilcUInt32 hdata_len;
123
124   SILC_LOG_DEBUG(("Handle callback"));
125   SILC_LOG_DEBUG(("Request ID: %d", id));
126
127   if (status != SILC_SFTP_STATUS_OK) {
128     silc_sftp_send_error(server, status, id);
129     return;
130   }
131
132   hdata = server->fs->fs->sftp_encode_handle(server->fs->fs_context, sftp,
133                                              handle, &hdata_len);
134   if (!hdata) {
135     silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
136     return;
137   }
138
139   silc_sftp_send_packet(server, SILC_SFTP_HANDLE, 8 + hdata_len,
140                         SILC_STR_UI_INT(id),
141                         SILC_STR_UI_INT(hdata_len),
142                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
143                         SILC_STR_END);
144 }
145
146 /* Data callback */
147
148 static void silc_sftp_server_data(SilcSFTP sftp,
149                                   SilcSFTPStatus status,
150                                   const unsigned char *data,
151                                   SilcUInt32 data_len,
152                                   void *context)
153 {
154   SilcSFTPServer server = (SilcSFTPServer)sftp;
155   SilcUInt32 id = SILC_PTR_TO_32(context);
156
157   SILC_LOG_DEBUG(("Data callback"));
158   SILC_LOG_DEBUG(("Request ID: %d", id));
159
160   if (status != SILC_SFTP_STATUS_OK) {
161     silc_sftp_send_error(server, status, id);
162     return;
163   }
164
165   silc_sftp_send_packet(server, SILC_SFTP_DATA, 8 + data_len,
166                         SILC_STR_UI_INT(id),
167                         SILC_STR_UI_INT(data_len),
168                         SILC_STR_UI_XNSTRING(data, data_len),
169                         SILC_STR_END);
170 }
171
172 /* Name callback */
173
174 static void silc_sftp_server_name(SilcSFTP sftp,
175                                   SilcSFTPStatus status,
176                                   const SilcSFTPName name,
177                                   void *context)
178 {
179   SilcSFTPServer server = (SilcSFTPServer)sftp;
180   SilcUInt32 id = SILC_PTR_TO_32(context);
181   SilcBuffer namebuf;
182
183   SILC_LOG_DEBUG(("Name callback"));
184   SILC_LOG_DEBUG(("Request ID: %d", id));
185
186   if (status != SILC_SFTP_STATUS_OK) {
187     silc_sftp_send_error(server, status, id);
188     return;
189   }
190
191   namebuf = silc_sftp_name_encode(name);
192   if (!namebuf) {
193     silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
194     return;
195   }
196
197   silc_sftp_send_packet(server, SILC_SFTP_NAME, 4 + namebuf->len,
198                         SILC_STR_UI_INT(id),
199                         SILC_STR_UI_XNSTRING(namebuf->data, namebuf->len),
200                         SILC_STR_END);
201 }
202
203 /* Attributes callback */
204
205 static void silc_sftp_server_attr(SilcSFTP sftp,
206                                   SilcSFTPStatus status,
207                                   const SilcSFTPAttributes attrs,
208                                   void *context)
209 {
210   SilcSFTPServer server = (SilcSFTPServer)sftp;
211   SilcUInt32 id = SILC_PTR_TO_32(context);
212   SilcBuffer attr_buf;
213
214   SILC_LOG_DEBUG(("Attr callback"));
215   SILC_LOG_DEBUG(("Request ID: %d", id));
216
217   if (status != SILC_SFTP_STATUS_OK) {
218     silc_sftp_send_error(server, status, id);
219     return;
220   }
221
222   attr_buf = silc_sftp_attr_encode(attrs);
223   if (!attr_buf) {
224     silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
225     return;
226   }
227
228   silc_sftp_send_packet(server, SILC_SFTP_ATTRS, 4 + attr_buf->len,
229                         SILC_STR_UI_INT(id),
230                         SILC_STR_UI_XNSTRING(attr_buf->data, attr_buf->len),
231                         SILC_STR_END);
232
233   silc_buffer_free(attr_buf);
234 }
235
236 /* Extended callback */
237
238 static void silc_sftp_server_extended(SilcSFTP sftp,
239                                       SilcSFTPStatus status,
240                                       const unsigned char *data,
241                                       SilcUInt32 data_len,
242                                       void *context)
243 {
244   SilcSFTPServer server = (SilcSFTPServer)sftp;
245   SilcUInt32 id = SILC_PTR_TO_32(context);
246
247   SILC_LOG_DEBUG(("Extended callback"));
248   SILC_LOG_DEBUG(("Request ID: %d", id));
249
250   if (status != SILC_SFTP_STATUS_OK) {
251     silc_sftp_send_error(server, status, id);
252     return;
253   }
254
255   silc_sftp_send_packet(server, SILC_SFTP_EXTENDED, 4 + data_len,
256                         SILC_STR_UI_INT(id),
257                         SILC_STR_UI_XNSTRING(data, data_len),
258                         SILC_STR_END);
259 }
260
261 /* Starts SFTP server and returns context to it.  This function returns the
262    allocated SFTP client context or NULL on error. The `send_packet' is called
263    by the library when it needs to send a packet. The `fs' is the
264    structure containing filesystem access callbacks. */
265
266 SilcSFTP silc_sftp_server_start(SilcSFTPSendPacketCallback send_packet,
267                                 void *send_context,
268                                 SilcSFTPFilesystem fs)
269 {
270   SilcSFTPServer server;
271
272   server = silc_calloc(1, sizeof(*server));
273   if (!server)
274     return NULL;
275   server->send_packet = send_packet;
276   server->send_context = send_context;
277   server->fs = fs;
278
279   SILC_LOG_DEBUG(("Starting SFTP server %p", server));
280
281   return (SilcSFTP)server;
282 }
283
284 /* Shutdown's the SFTP server.  The caller is responsible of closing
285    the associated socket connection.  The SFTP context is freed and is
286    invalid after this function returns. */
287
288 void silc_sftp_server_shutdown(SilcSFTP sftp)
289 {
290   SilcSFTPServer server = (SilcSFTPServer)sftp;
291
292   SILC_LOG_DEBUG(("Stopping SFTP server %p", server));
293
294   if (server->packet)
295     silc_buffer_free(server->packet);
296   silc_free(server);
297 }
298
299 /* Sets monitor callback */
300
301 void silc_sftp_server_set_monitor(SilcSFTP sftp,
302                                   SilcSFTPMonitors monitors,
303                                   SilcSFTPMonitor monitor,
304                                   void *context)
305 {
306   SilcSFTPServer server = (SilcSFTPServer)sftp;
307   server->monitors = monitors;
308   server->monitor = monitor;
309   server->monitor_context = context;
310 }
311
312 /* Function that is called to process the incmoing SFTP packet. */
313 /* XXX Some day this will go away and we have automatic receive callbacks
314    for SilcSocketConnection API or SilcPacketContext API. */
315
316 void silc_sftp_server_receive_process(SilcSFTP sftp,
317                                       SilcSocketConnection sock,
318                                       SilcPacketContext *packet)
319 {
320   SilcSFTPServer server = (SilcSFTPServer)sftp;
321   SilcSFTPPacket type;
322   char *filename = NULL, *path = NULL;
323   const unsigned char *payload = NULL;
324   SilcUInt32 payload_len;
325   int ret;
326   SilcBufferStruct buf;
327   SilcUInt32 id;
328   SilcSFTPAttributes attrs;
329   SilcSFTPHandle handle;
330   SilcSFTPMonitorDataStruct mdata;
331
332   SILC_LOG_DEBUG(("Start"));
333
334   /* Parse the packet */
335   type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload,
336                                  &payload_len);
337   if (!type)
338     return;
339
340   silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
341
342   memset(&mdata, 0, sizeof(mdata));
343
344   switch (type) {
345   case SILC_SFTP_INIT:
346     {
347       SilcSFTPVersion version;
348
349       SILC_LOG_DEBUG(("Init request"));
350
351       ret = silc_buffer_unformat(&buf,
352                                  SILC_STR_UI_INT(&version),
353                                  SILC_STR_END);
354       if (ret < 0)
355         break;
356
357       /* Call monitor */
358       if (server->monitors & SILC_SFTP_MONITOR_INIT && server->monitor) {
359         mdata.version = version;
360         (*server->monitor)(sftp, SILC_SFTP_MONITOR_INIT, &mdata,
361                            server->monitor_context);
362       }
363
364       silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4,
365                             SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
366                             SILC_STR_END);
367     }
368     break;
369
370   case SILC_SFTP_OPEN:
371     {
372       SilcSFTPFileOperation pflags;
373       unsigned char *attr_buf;
374       SilcUInt32 attr_len = 0;
375       SilcBufferStruct tmpbuf;
376
377       SILC_LOG_DEBUG(("Open request"));
378
379       ret = silc_buffer_unformat(&buf,
380                                  SILC_STR_UI_INT(&id),
381                                  SILC_STR_UI32_STRING_ALLOC(&filename),
382                                  SILC_STR_UI_INT(&pflags),
383                                  SILC_STR_UI32_NSTRING(&attr_buf,
384                                                        &attr_len),
385                                  SILC_STR_END);
386       if (ret < 0)
387         goto failure;
388
389       if (attr_len) {
390         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
391         attrs = silc_sftp_attr_decode(&tmpbuf);
392         if (!attrs)
393           goto failure;
394       } else {
395         attrs = silc_calloc(1, sizeof(*attrs));
396         if (!attrs)
397           goto failure;
398       }
399
400       /* Call monitor */
401       if (server->monitors & SILC_SFTP_MONITOR_OPEN && server->monitor) {
402         mdata.name = filename;
403         mdata.pflags = pflags;
404         (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPEN, &mdata,
405                            server->monitor_context);
406       }
407
408       /* Open operation */
409       server->fs->fs->sftp_open(server->fs->fs_context, sftp, filename, pflags,
410                                 attrs, silc_sftp_server_handle,
411                                 SILC_32_TO_PTR(id));
412
413       silc_free(filename);
414       silc_sftp_attr_free(attrs);
415     }
416     break;
417
418   case SILC_SFTP_CLOSE:
419     {
420       unsigned char *hdata;
421       SilcUInt32 hdata_len;
422
423       SILC_LOG_DEBUG(("Close request"));
424
425       ret = silc_buffer_unformat(&buf,
426                                  SILC_STR_UI_INT(&id),
427                                  SILC_STR_UI32_NSTRING(&hdata,
428                                                        &hdata_len),
429                                  SILC_STR_END);
430       if (ret < 0)
431         goto failure;
432
433       /* Get the handle */
434       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
435                                                (const unsigned char *)hdata,
436                                                hdata_len);
437       if (!handle) {
438         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
439         break;
440       }
441
442       /* Call monitor */
443       if (server->monitors & SILC_SFTP_MONITOR_CLOSE && server->monitor) {
444         (*server->monitor)(sftp, SILC_SFTP_MONITOR_CLOSE, &mdata,
445                            server->monitor_context);
446       }
447
448       /* Close operation */
449       server->fs->fs->sftp_close(server->fs->fs_context, sftp, handle,
450                                  silc_sftp_server_status, SILC_32_TO_PTR(id));
451
452     }
453     break;
454
455   case SILC_SFTP_READ:
456     {
457       unsigned char *hdata;
458       SilcUInt32 hdata_len;
459       SilcUInt64 offset;
460       SilcUInt32 len;
461
462       SILC_LOG_DEBUG(("Read request"));
463
464       ret = silc_buffer_unformat(&buf,
465                                  SILC_STR_UI_INT(&id),
466                                  SILC_STR_UI32_NSTRING(&hdata,
467                                                        &hdata_len),
468                                  SILC_STR_UI_INT64(&offset),
469                                  SILC_STR_UI_INT(&len),
470                                  SILC_STR_END);
471       if (ret < 0)
472         goto failure;
473
474       /* Get the handle */
475       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
476                                                (const unsigned char *)hdata,
477                                                hdata_len);
478       if (!handle) {
479         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
480         break;
481       }
482
483       /* Read operation */
484       server->fs->fs->sftp_read(server->fs->fs_context, sftp,
485                                 handle, offset, len,
486                                 silc_sftp_server_data, SILC_32_TO_PTR(id));
487
488       /* Call monitor */
489       if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) {
490         mdata.offset = offset;
491         mdata.data_len = len;
492         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata,
493                            server->monitor_context);
494       }
495     }
496     break;
497
498   case SILC_SFTP_WRITE:
499     {
500       unsigned char *hdata;
501       SilcUInt32 hdata_len;
502       SilcUInt64 offset;
503       unsigned char *data;
504       SilcUInt32 data_len;
505
506       SILC_LOG_DEBUG(("Read request"));
507
508       ret = silc_buffer_unformat(&buf,
509                                  SILC_STR_UI_INT(&id),
510                                  SILC_STR_UI32_NSTRING(&hdata,
511                                                        &hdata_len),
512                                  SILC_STR_UI_INT64(&offset),
513                                  SILC_STR_UI32_NSTRING(&data,
514                                                        &data_len),
515                                  SILC_STR_END);
516       if (ret < 0)
517         goto failure;
518
519       /* Get the handle */
520       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
521                                                (const unsigned char *)hdata,
522                                                hdata_len);
523       if (!handle) {
524         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
525         break;
526       }
527
528       /* Write operation */
529       server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset,
530                                  (const unsigned char *)data, data_len,
531                                  silc_sftp_server_status, SILC_32_TO_PTR(id));
532
533       /* Call monitor */
534       if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) {
535         mdata.offset = offset;
536         mdata.data_len = data_len;
537         (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata,
538                            server->monitor_context);
539       }
540     }
541     break;
542
543   case SILC_SFTP_REMOVE:
544     {
545       SILC_LOG_DEBUG(("Remove request"));
546
547       ret = silc_buffer_unformat(&buf,
548                                  SILC_STR_UI_INT(&id),
549                                  SILC_STR_UI32_STRING_ALLOC(&filename),
550                                  SILC_STR_END);
551       if (ret < 0)
552         goto failure;
553
554       /* Call monitor */
555       if (server->monitors & SILC_SFTP_MONITOR_REMOVE && server->monitor) {
556         mdata.name = filename;
557         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REMOVE, &mdata,
558                            server->monitor_context);
559       }
560
561       /* Remove operation */
562       server->fs->fs->sftp_remove(server->fs->fs_context, sftp, filename,
563                                   silc_sftp_server_status, SILC_32_TO_PTR(id));
564
565       silc_free(filename);
566     }
567     break;
568
569   case SILC_SFTP_RENAME:
570     {
571       char *newname = NULL;
572
573       SILC_LOG_DEBUG(("Rename request"));
574
575       ret = silc_buffer_unformat(&buf,
576                                  SILC_STR_UI_INT(&id),
577                                  SILC_STR_UI32_STRING_ALLOC(&filename),
578                                  SILC_STR_UI32_STRING_ALLOC(&newname),
579                                  SILC_STR_END);
580       if (ret < 0)
581         goto failure;
582
583       /* Call monitor */
584       if (server->monitors & SILC_SFTP_MONITOR_RENAME && server->monitor) {
585         mdata.name = filename;
586         mdata.name2 = newname;
587         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RENAME, &mdata,
588                            server->monitor_context);
589       }
590
591       /* Rename operation */
592       server->fs->fs->sftp_rename(server->fs->fs_context, sftp,
593                                   filename, newname,
594                                   silc_sftp_server_status, SILC_32_TO_PTR(id));
595
596       silc_free(filename);
597       silc_free(newname);
598     }
599     break;
600
601   case SILC_SFTP_MKDIR:
602     {
603       unsigned char *attr_buf;
604       SilcUInt32 attr_len = 0;
605       SilcBufferStruct tmpbuf;
606
607       SILC_LOG_DEBUG(("Mkdir request"));
608
609       ret = silc_buffer_unformat(&buf,
610                                  SILC_STR_UI_INT(&id),
611                                  SILC_STR_UI32_STRING_ALLOC(&path),
612                                  SILC_STR_UI32_NSTRING(&attr_buf,
613                                                        &attr_len),
614                                  SILC_STR_END);
615       if (ret < 0)
616         goto failure;
617
618       if (attr_len) {
619         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
620         attrs = silc_sftp_attr_decode(&tmpbuf);
621         if (!attrs)
622           goto failure;
623       } else {
624         attrs = silc_calloc(1, sizeof(*attrs));
625         if (!attrs)
626           goto failure;
627       }
628
629       /* Call monitor */
630       if (server->monitors & SILC_SFTP_MONITOR_MKDIR && server->monitor) {
631         mdata.name = path;
632         (*server->monitor)(sftp, SILC_SFTP_MONITOR_MKDIR, &mdata,
633                            server->monitor_context);
634       }
635
636       /* Mkdir operation */
637       server->fs->fs->sftp_mkdir(server->fs->fs_context, sftp, path, attrs,
638                                  silc_sftp_server_status, SILC_32_TO_PTR(id));
639
640       silc_sftp_attr_free(attrs);
641       silc_free(path);
642     }
643     break;
644
645   case SILC_SFTP_RMDIR:
646     {
647       SILC_LOG_DEBUG(("Rmdir request"));
648
649       ret = silc_buffer_unformat(&buf,
650                                  SILC_STR_UI_INT(&id),
651                                  SILC_STR_UI32_STRING_ALLOC(&path),
652                                  SILC_STR_END);
653       if (ret < 0)
654         goto failure;
655
656       /* Call monitor */
657       if (server->monitors & SILC_SFTP_MONITOR_RMDIR && server->monitor) {
658         mdata.name = path;
659         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RMDIR, &mdata,
660                            server->monitor_context);
661       }
662
663       /* Rmdir operation */
664       server->fs->fs->sftp_rmdir(server->fs->fs_context, sftp, path,
665                                  silc_sftp_server_status, SILC_32_TO_PTR(id));
666
667       silc_free(path);
668     }
669     break;
670
671   case SILC_SFTP_OPENDIR:
672     {
673       SILC_LOG_DEBUG(("Opendir request"));
674
675       ret = silc_buffer_unformat(&buf,
676                                  SILC_STR_UI_INT(&id),
677                                  SILC_STR_UI32_STRING_ALLOC(&path),
678                                  SILC_STR_END);
679       if (ret < 0)
680         goto failure;
681
682       /* Call monitor */
683       if (server->monitors & SILC_SFTP_MONITOR_OPENDIR && server->monitor) {
684         mdata.name = path;
685         (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPENDIR, &mdata,
686                            server->monitor_context);
687       }
688
689       /* Opendir operation */
690       server->fs->fs->sftp_opendir(server->fs->fs_context, sftp, path,
691                                    silc_sftp_server_handle, SILC_32_TO_PTR(id));
692
693       silc_free(path);
694     }
695     break;
696
697   case SILC_SFTP_READDIR:
698     {
699       unsigned char *hdata;
700       SilcUInt32 hdata_len;
701
702       SILC_LOG_DEBUG(("Readdir request"));
703
704       ret = silc_buffer_unformat(&buf,
705                                  SILC_STR_UI_INT(&id),
706                                  SILC_STR_UI32_NSTRING(&hdata,
707                                                        &hdata_len),
708                                  SILC_STR_END);
709       if (ret < 0)
710         goto failure;
711
712       /* Get the handle */
713       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
714                                                (const unsigned char *)hdata,
715                                                hdata_len);
716       if (!handle) {
717         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
718         break;
719       }
720
721       /* Call monitor */
722       if (server->monitors & SILC_SFTP_MONITOR_READDIR && server->monitor) {
723         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READDIR, &mdata,
724                            server->monitor_context);
725       }
726
727       /* Readdir operation */
728       server->fs->fs->sftp_readdir(server->fs->fs_context, sftp, handle,
729                                    silc_sftp_server_name, SILC_32_TO_PTR(id));
730     }
731     break;
732
733   case SILC_SFTP_STAT:
734     {
735       SILC_LOG_DEBUG(("Stat request"));
736
737       ret = silc_buffer_unformat(&buf,
738                                  SILC_STR_UI_INT(&id),
739                                  SILC_STR_UI32_STRING_ALLOC(&path),
740                                  SILC_STR_END);
741       if (ret < 0)
742         goto failure;
743
744       /* Call monitor */
745       if (server->monitors & SILC_SFTP_MONITOR_STAT && server->monitor) {
746         mdata.name = path;
747         (*server->monitor)(sftp, SILC_SFTP_MONITOR_STAT, &mdata,
748                            server->monitor_context);
749       }
750
751       /* Stat operation */
752       server->fs->fs->sftp_stat(server->fs->fs_context, sftp, path,
753                                 silc_sftp_server_attr, SILC_32_TO_PTR(id));
754
755       silc_free(path);
756     }
757     break;
758
759   case SILC_SFTP_LSTAT:
760     {
761       SILC_LOG_DEBUG(("Lstat request"));
762
763       ret = silc_buffer_unformat(&buf,
764                                  SILC_STR_UI_INT(&id),
765                                  SILC_STR_UI32_STRING_ALLOC(&path),
766                                  SILC_STR_END);
767       if (ret < 0)
768         goto failure;
769
770       /* Call monitor */
771       if (server->monitors & SILC_SFTP_MONITOR_LSTAT && server->monitor) {
772         mdata.name = path;
773         (*server->monitor)(sftp, SILC_SFTP_MONITOR_LSTAT, &mdata,
774                            server->monitor_context);
775       }
776
777       /* Lstat operation */
778       server->fs->fs->sftp_lstat(server->fs->fs_context, sftp, path,
779                                  silc_sftp_server_attr, SILC_32_TO_PTR(id));
780
781       silc_free(path);
782     }
783     break;
784
785   case SILC_SFTP_FSTAT:
786     {
787       unsigned char *hdata;
788       SilcUInt32 hdata_len;
789
790       SILC_LOG_DEBUG(("Fstat request"));
791
792       ret = silc_buffer_unformat(&buf,
793                                  SILC_STR_UI_INT(&id),
794                                  SILC_STR_UI32_NSTRING(&hdata,
795                                                        &hdata_len),
796                                  SILC_STR_END);
797       if (ret < 0)
798         goto failure;
799
800       /* Get the handle */
801       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
802                                                (const unsigned char *)hdata,
803                                                hdata_len);
804       if (!handle) {
805         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
806         break;
807       }
808
809       /* Call monitor */
810       if (server->monitors & SILC_SFTP_MONITOR_FSTAT && server->monitor) {
811         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSTAT, &mdata,
812                            server->monitor_context);
813       }
814
815       /* Fstat operation */
816       server->fs->fs->sftp_fstat(server->fs->fs_context, sftp, handle,
817                                  silc_sftp_server_attr, SILC_32_TO_PTR(id));
818     }
819     break;
820
821   case SILC_SFTP_SETSTAT:
822     {
823       unsigned char *attr_buf;
824       SilcUInt32 attr_len = 0;
825       SilcBufferStruct tmpbuf;
826
827       SILC_LOG_DEBUG(("Setstat request"));
828
829       ret = silc_buffer_unformat(&buf,
830                                  SILC_STR_UI_INT(&id),
831                                  SILC_STR_UI32_STRING_ALLOC(&path),
832                                  SILC_STR_UI32_NSTRING(&attr_buf,
833                                                        &attr_len),
834                                  SILC_STR_END);
835       if (ret < 0)
836         goto failure;
837
838       if (attr_len) {
839         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
840         attrs = silc_sftp_attr_decode(&tmpbuf);
841         if (!attrs)
842           goto failure;
843       } else {
844         attrs = silc_calloc(1, sizeof(*attrs));
845         if (!attrs)
846           goto failure;
847       }
848
849       /* Call monitor */
850       if (server->monitors & SILC_SFTP_MONITOR_SETSTAT && server->monitor) {
851         mdata.name = path;
852         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SETSTAT, &mdata,
853                            server->monitor_context);
854       }
855
856       /* Setstat operation */
857       server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs,
858                                    silc_sftp_server_status, SILC_32_TO_PTR(id));
859
860       silc_sftp_attr_free(attrs);
861       silc_free(path);
862     }
863     break;
864
865   case SILC_SFTP_FSETSTAT:
866     {
867       unsigned char *hdata, *attr_buf;
868       SilcUInt32 hdata_len, attr_len = 0;
869       SilcBufferStruct tmpbuf;
870
871       SILC_LOG_DEBUG(("Fsetstat request"));
872
873       ret = silc_buffer_unformat(&buf,
874                                  SILC_STR_UI_INT(&id),
875                                  SILC_STR_UI32_NSTRING(&hdata,
876                                                        &hdata_len),
877                                  SILC_STR_UI32_NSTRING(&attr_buf,
878                                                        &attr_len),
879                                  SILC_STR_END);
880       if (ret < 0)
881         goto failure;
882
883       if (attr_len) {
884         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
885         attrs = silc_sftp_attr_decode(&tmpbuf);
886         if (!attrs)
887           goto failure;
888       } else {
889         attrs = silc_calloc(1, sizeof(*attrs));
890         if (!attrs)
891           goto failure;
892       }
893
894       /* Get the handle */
895       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
896                                                (const unsigned char *)hdata,
897                                                hdata_len);
898       if (!handle) {
899         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
900         break;
901       }
902
903       /* Call monitor */
904       if (server->monitors & SILC_SFTP_MONITOR_FSETSTAT && server->monitor) {
905         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSETSTAT, &mdata,
906                            server->monitor_context);
907       }
908
909       /* Fsetstat operation */
910       server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp,
911                                     handle, attrs,
912                                     silc_sftp_server_status,
913                                     SILC_32_TO_PTR(id));
914
915       silc_sftp_attr_free(attrs);
916     }
917     break;
918
919   case SILC_SFTP_READLINK:
920     {
921       SILC_LOG_DEBUG(("Readlink request"));
922
923       ret = silc_buffer_unformat(&buf,
924                                  SILC_STR_UI_INT(&id),
925                                  SILC_STR_UI32_STRING_ALLOC(&path),
926                                  SILC_STR_END);
927       if (ret < 0)
928         goto failure;
929
930       /* Call monitor */
931       if (server->monitors & SILC_SFTP_MONITOR_READLINK && server->monitor) {
932         mdata.name = path;
933         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READLINK, &mdata,
934                            server->monitor_context);
935       }
936
937       /* Readlink operation */
938       server->fs->fs->sftp_readlink(server->fs->fs_context, sftp, path,
939                                     silc_sftp_server_name, SILC_32_TO_PTR(id));
940
941       silc_free(path);
942     }
943     break;
944
945   case SILC_SFTP_SYMLINK:
946     {
947       char *target = NULL;
948
949       SILC_LOG_DEBUG(("Symlink request"));
950
951       ret = silc_buffer_unformat(&buf,
952                                  SILC_STR_UI_INT(&id),
953                                  SILC_STR_UI32_STRING_ALLOC(&path),
954                                  SILC_STR_UI32_STRING_ALLOC(&target),
955                                  SILC_STR_END);
956       if (ret < 0)
957         goto failure;
958
959       /* Call monitor */
960       if (server->monitors & SILC_SFTP_MONITOR_SYMLINK && server->monitor) {
961         mdata.name = path;
962         mdata.name2 = target;
963         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SYMLINK, &mdata,
964                            server->monitor_context);
965       }
966
967       /* Symlink operation */
968       server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target,
969                                    silc_sftp_server_status, SILC_32_TO_PTR(id));
970
971       silc_free(path);
972       silc_free(target);
973     }
974     break;
975
976   case SILC_SFTP_REALPATH:
977     {
978       SILC_LOG_DEBUG(("Realpath request"));
979
980       ret = silc_buffer_unformat(&buf,
981                                  SILC_STR_UI_INT(&id),
982                                  SILC_STR_UI32_STRING_ALLOC(&path),
983                                  SILC_STR_END);
984       if (ret < 0)
985         goto failure;
986
987       /* Call monitor */
988       if (server->monitors & SILC_SFTP_MONITOR_REALPATH && server->monitor) {
989         mdata.name = path;
990         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REALPATH, &mdata,
991                            server->monitor_context);
992       }
993
994       /* Realpath operation */
995       server->fs->fs->sftp_realpath(server->fs->fs_context, sftp, path,
996                                     silc_sftp_server_name, SILC_32_TO_PTR(id));
997
998       silc_free(path);
999     }
1000     break;
1001
1002   case SILC_SFTP_EXTENDED:
1003     {
1004       char *request = NULL;
1005       unsigned char *data;
1006       SilcUInt32 data_len;
1007
1008       SILC_LOG_DEBUG(("Extended request"));
1009
1010       ret = silc_buffer_unformat(&buf,
1011                                  SILC_STR_UI_INT(&id),
1012                                  SILC_STR_UI32_STRING_ALLOC(&request),
1013                                  SILC_STR_END);
1014       if (ret < 0)
1015         goto failure;
1016
1017       data_len = 8 + strlen(request);
1018       silc_buffer_pull(&buf, data_len);
1019       ret = silc_buffer_unformat(&buf,
1020                                  SILC_STR_UI_XNSTRING(&data, buf.len),
1021                                  SILC_STR_END);
1022       if (ret < 0)
1023         goto failure;
1024       data_len = buf.len;
1025
1026       /* Call monitor */
1027       if (server->monitors & SILC_SFTP_MONITOR_EXTENDED && server->monitor) {
1028         (*server->monitor)(sftp, SILC_SFTP_MONITOR_EXTENDED, &mdata,
1029                            server->monitor_context);
1030       }
1031
1032       /* Extended operation */
1033       server->fs->fs->sftp_extended(server->fs->fs_context, sftp,
1034                                     request, data, data_len,
1035                                     silc_sftp_server_extended,
1036                                     SILC_32_TO_PTR(id));
1037
1038       silc_free(request);
1039     }
1040     break;
1041
1042   default:
1043     break;
1044   }
1045
1046   return;
1047
1048  failure:
1049   silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
1050 }