8c96355aac2a08a9eda17852fd05264d13a6314b
[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 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 "silcincludes.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 = (SilcUInt32)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 = (SilcUInt32)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 = (SilcUInt32)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 = (SilcUInt32)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 = (SilcUInt32)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 = (SilcUInt32)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, (void *)id);
411
412       silc_free(filename);
413       silc_sftp_attr_free(attrs);
414     }
415     break;
416
417   case SILC_SFTP_CLOSE:
418     {
419       unsigned char *hdata;
420       SilcUInt32 hdata_len;
421
422       SILC_LOG_DEBUG(("Close request"));
423
424       ret = silc_buffer_unformat(&buf,
425                                  SILC_STR_UI_INT(&id),
426                                  SILC_STR_UI32_NSTRING(&hdata, 
427                                                        &hdata_len),
428                                  SILC_STR_END);
429       if (ret < 0)
430         goto failure;
431
432       /* Get the handle */
433       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
434                                                (const unsigned char *)hdata,
435                                                hdata_len);
436       if (!handle) {
437         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
438         break;
439       }
440
441       /* Call monitor */
442       if (server->monitors & SILC_SFTP_MONITOR_CLOSE && server->monitor) {
443         (*server->monitor)(sftp, SILC_SFTP_MONITOR_CLOSE, &mdata,
444                            server->monitor_context);
445       }
446
447       /* Close operation */
448       server->fs->fs->sftp_close(server->fs->fs_context, sftp, handle,
449                                  silc_sftp_server_status, (void *)id);
450     }
451     break;
452
453   case SILC_SFTP_READ:
454     {
455       unsigned char *hdata;
456       SilcUInt32 hdata_len;
457       SilcUInt64 offset;
458       SilcUInt32 len;
459
460       SILC_LOG_DEBUG(("Read request"));
461
462       ret = silc_buffer_unformat(&buf,
463                                  SILC_STR_UI_INT(&id),
464                                  SILC_STR_UI32_NSTRING(&hdata, 
465                                                        &hdata_len),
466                                  SILC_STR_UI_INT64(&offset),
467                                  SILC_STR_UI_INT(&len),
468                                  SILC_STR_END);
469       if (ret < 0)
470         goto failure;
471
472       /* Get the handle */
473       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
474                                                (const unsigned char *)hdata,
475                                                hdata_len);
476       if (!handle) {
477         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
478         break;
479       }
480
481       /* Call monitor */
482       if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) {
483         mdata.offset = offset;
484         mdata.data_len = len;
485         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata,
486                            server->monitor_context);
487       }
488
489       /* Read operation */
490       server->fs->fs->sftp_read(server->fs->fs_context, sftp, 
491                                 handle, offset, len,
492                                 silc_sftp_server_data, (void *)id);
493     }
494     break;
495
496   case SILC_SFTP_WRITE:
497     {
498       unsigned char *hdata;
499       SilcUInt32 hdata_len;
500       SilcUInt64 offset;
501       unsigned char *data;
502       SilcUInt32 data_len;
503
504       SILC_LOG_DEBUG(("Read request"));
505
506       ret = silc_buffer_unformat(&buf,
507                                  SILC_STR_UI_INT(&id),
508                                  SILC_STR_UI32_NSTRING(&hdata, 
509                                                        &hdata_len),
510                                  SILC_STR_UI_INT64(&offset),
511                                  SILC_STR_UI32_NSTRING(&data, 
512                                                        &data_len),
513                                  SILC_STR_END);
514       if (ret < 0)
515         goto failure;
516
517       /* Get the handle */
518       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
519                                                (const unsigned char *)hdata,
520                                                hdata_len);
521       if (!handle) {
522         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
523         break;
524       }
525
526       /* Call monitor */
527       if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) {
528         mdata.offset = offset;
529         mdata.data_len = data_len;
530         (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata,
531                            server->monitor_context);
532       }
533
534       /* Write operation */
535       server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset, 
536                                  (const unsigned char *)data, data_len,
537                                  silc_sftp_server_status, (void *)id);
538     }
539     break;
540
541   case SILC_SFTP_REMOVE:
542     {
543       SILC_LOG_DEBUG(("Remove request"));
544
545       ret = silc_buffer_unformat(&buf,
546                                  SILC_STR_UI_INT(&id),
547                                  SILC_STR_UI32_STRING_ALLOC(&filename),
548                                  SILC_STR_END);
549       if (ret < 0)
550         goto failure;
551
552       /* Call monitor */
553       if (server->monitors & SILC_SFTP_MONITOR_REMOVE && server->monitor) {
554         mdata.name = filename;
555         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REMOVE, &mdata,
556                            server->monitor_context);
557       }
558
559       /* Remove operation */
560       server->fs->fs->sftp_remove(server->fs->fs_context, sftp, filename,
561                                   silc_sftp_server_status, (void *)id);
562
563       silc_free(filename);
564     }
565     break;
566
567   case SILC_SFTP_RENAME:
568     {
569       char *newname = NULL;
570
571       SILC_LOG_DEBUG(("Rename request"));
572
573       ret = silc_buffer_unformat(&buf,
574                                  SILC_STR_UI_INT(&id),
575                                  SILC_STR_UI32_STRING_ALLOC(&filename),
576                                  SILC_STR_UI32_STRING_ALLOC(&newname),
577                                  SILC_STR_END);
578       if (ret < 0)
579         goto failure;
580
581       /* Call monitor */
582       if (server->monitors & SILC_SFTP_MONITOR_RENAME && server->monitor) {
583         mdata.name = filename;
584         mdata.name2 = newname;
585         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RENAME, &mdata,
586                            server->monitor_context);
587       }
588
589       /* Rename operation */
590       server->fs->fs->sftp_rename(server->fs->fs_context, sftp, 
591                                   filename, newname,
592                                   silc_sftp_server_status, (void *)id);
593
594       silc_free(filename);
595       silc_free(newname);
596     }
597     break;
598
599   case SILC_SFTP_MKDIR:
600     {
601       unsigned char *attr_buf;
602       SilcUInt32 attr_len = 0;
603       SilcBufferStruct tmpbuf;
604
605       SILC_LOG_DEBUG(("Mkdir request"));
606
607       ret = silc_buffer_unformat(&buf,
608                                  SILC_STR_UI_INT(&id),
609                                  SILC_STR_UI32_STRING_ALLOC(&path),
610                                  SILC_STR_UI32_NSTRING(&attr_buf,
611                                                        &attr_len),
612                                  SILC_STR_END);
613       if (ret < 0)
614         goto failure;
615
616       if (attr_len) {
617         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
618         attrs = silc_sftp_attr_decode(&tmpbuf);
619         if (!attrs)
620           goto failure;
621       } else {
622         attrs = silc_calloc(1, sizeof(*attrs));
623         if (!attrs)
624           goto failure;
625       }
626
627       /* Call monitor */
628       if (server->monitors & SILC_SFTP_MONITOR_MKDIR && server->monitor) {
629         mdata.name = path;
630         (*server->monitor)(sftp, SILC_SFTP_MONITOR_MKDIR, &mdata,
631                            server->monitor_context);
632       }
633
634       /* Mkdir operation */
635       server->fs->fs->sftp_mkdir(server->fs->fs_context, sftp, path, attrs,
636                                  silc_sftp_server_status, (void *)id);
637
638       silc_sftp_attr_free(attrs);
639       silc_free(path);
640     }
641     break;
642
643   case SILC_SFTP_RMDIR:
644     {
645       SILC_LOG_DEBUG(("Rmdir request"));
646
647       ret = silc_buffer_unformat(&buf,
648                                  SILC_STR_UI_INT(&id),
649                                  SILC_STR_UI32_STRING_ALLOC(&path),
650                                  SILC_STR_END);
651       if (ret < 0)
652         goto failure;
653
654       /* Call monitor */
655       if (server->monitors & SILC_SFTP_MONITOR_RMDIR && server->monitor) {
656         mdata.name = path;
657         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RMDIR, &mdata,
658                            server->monitor_context);
659       }
660
661       /* Rmdir operation */
662       server->fs->fs->sftp_rmdir(server->fs->fs_context, sftp, path,
663                                  silc_sftp_server_status, (void *)id);
664
665       silc_free(path);
666     }
667     break;
668
669   case SILC_SFTP_OPENDIR:
670     {
671       SILC_LOG_DEBUG(("Opendir request"));
672
673       ret = silc_buffer_unformat(&buf,
674                                  SILC_STR_UI_INT(&id),
675                                  SILC_STR_UI32_STRING_ALLOC(&path),
676                                  SILC_STR_END);
677       if (ret < 0)
678         goto failure;
679
680       /* Call monitor */
681       if (server->monitors & SILC_SFTP_MONITOR_OPENDIR && server->monitor) {
682         mdata.name = path;
683         (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPENDIR, &mdata,
684                            server->monitor_context);
685       }
686
687       /* Opendir operation */
688       server->fs->fs->sftp_opendir(server->fs->fs_context, sftp, path,
689                                    silc_sftp_server_handle, (void *)id);
690
691       silc_free(path);
692     }
693     break;
694
695   case SILC_SFTP_READDIR:
696     {
697       unsigned char *hdata;
698       SilcUInt32 hdata_len;
699
700       SILC_LOG_DEBUG(("Readdir request"));
701
702       ret = silc_buffer_unformat(&buf,
703                                  SILC_STR_UI_INT(&id),
704                                  SILC_STR_UI32_NSTRING(&hdata, 
705                                                        &hdata_len),
706                                  SILC_STR_END);
707       if (ret < 0)
708         goto failure;
709
710       /* Get the handle */
711       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
712                                                (const unsigned char *)hdata,
713                                                hdata_len);
714       if (!handle) {
715         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
716         break;
717       }
718
719       /* Call monitor */
720       if (server->monitors & SILC_SFTP_MONITOR_READDIR && server->monitor) {
721         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READDIR, &mdata,
722                            server->monitor_context);
723       }
724
725       /* Readdir operation */
726       server->fs->fs->sftp_readdir(server->fs->fs_context, sftp, handle,
727                                    silc_sftp_server_name, (void *)id);
728     }
729     break;
730
731   case SILC_SFTP_STAT:
732     {
733       SILC_LOG_DEBUG(("Stat request"));
734
735       ret = silc_buffer_unformat(&buf,
736                                  SILC_STR_UI_INT(&id),
737                                  SILC_STR_UI32_STRING_ALLOC(&path),
738                                  SILC_STR_END);
739       if (ret < 0)
740         goto failure;
741
742       /* Call monitor */
743       if (server->monitors & SILC_SFTP_MONITOR_STAT && server->monitor) {
744         mdata.name = path;
745         (*server->monitor)(sftp, SILC_SFTP_MONITOR_STAT, &mdata,
746                            server->monitor_context);
747       }
748
749       /* Stat operation */
750       server->fs->fs->sftp_stat(server->fs->fs_context, sftp, path,
751                                 silc_sftp_server_attr, (void *)id);
752
753       silc_free(path);
754     }
755     break;
756
757   case SILC_SFTP_LSTAT:
758     {
759       SILC_LOG_DEBUG(("Lstat request"));
760
761       ret = silc_buffer_unformat(&buf,
762                                  SILC_STR_UI_INT(&id),
763                                  SILC_STR_UI32_STRING_ALLOC(&path),
764                                  SILC_STR_END);
765       if (ret < 0)
766         goto failure;
767
768       /* Call monitor */
769       if (server->monitors & SILC_SFTP_MONITOR_LSTAT && server->monitor) {
770         mdata.name = path;
771         (*server->monitor)(sftp, SILC_SFTP_MONITOR_LSTAT, &mdata,
772                            server->monitor_context);
773       }
774
775       /* Lstat operation */
776       server->fs->fs->sftp_lstat(server->fs->fs_context, sftp, path,
777                                  silc_sftp_server_attr, (void *)id);
778
779       silc_free(path);
780     }
781     break;
782
783   case SILC_SFTP_FSTAT:
784     {
785       unsigned char *hdata;
786       SilcUInt32 hdata_len;
787
788       SILC_LOG_DEBUG(("Fstat request"));
789
790       ret = silc_buffer_unformat(&buf,
791                                  SILC_STR_UI_INT(&id),
792                                  SILC_STR_UI32_NSTRING(&hdata, 
793                                                        &hdata_len),
794                                  SILC_STR_END);
795       if (ret < 0)
796         goto failure;
797
798       /* Get the handle */
799       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
800                                                (const unsigned char *)hdata,
801                                                hdata_len);
802       if (!handle) {
803         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
804         break;
805       }
806
807       /* Call monitor */
808       if (server->monitors & SILC_SFTP_MONITOR_FSTAT && server->monitor) {
809         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSTAT, &mdata,
810                            server->monitor_context);
811       }
812
813       /* Fstat operation */
814       server->fs->fs->sftp_fstat(server->fs->fs_context, sftp, handle,
815                                  silc_sftp_server_attr, (void *)id);
816     }
817     break;
818
819   case SILC_SFTP_SETSTAT:
820     {
821       unsigned char *attr_buf;
822       SilcUInt32 attr_len = 0;
823       SilcBufferStruct tmpbuf;
824
825       SILC_LOG_DEBUG(("Setstat request"));
826
827       ret = silc_buffer_unformat(&buf,
828                                  SILC_STR_UI_INT(&id),
829                                  SILC_STR_UI32_STRING_ALLOC(&path),
830                                  SILC_STR_UI32_NSTRING(&attr_buf,
831                                                        &attr_len),
832                                  SILC_STR_END);
833       if (ret < 0)
834         goto failure;
835
836       if (attr_len) {
837         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
838         attrs = silc_sftp_attr_decode(&tmpbuf);
839         if (!attrs)
840           goto failure;
841       } else {
842         attrs = silc_calloc(1, sizeof(*attrs));
843         if (!attrs)
844           goto failure;
845       }
846
847       /* Call monitor */
848       if (server->monitors & SILC_SFTP_MONITOR_SETSTAT && server->monitor) {
849         mdata.name = path;
850         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SETSTAT, &mdata,
851                            server->monitor_context);
852       }
853
854       /* Setstat operation */
855       server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs,
856                                    silc_sftp_server_status, (void *)id);
857
858       silc_sftp_attr_free(attrs);
859       silc_free(path);
860     }
861     break;
862
863   case SILC_SFTP_FSETSTAT:
864     {
865       unsigned char *hdata, *attr_buf;
866       SilcUInt32 hdata_len, attr_len = 0;
867       SilcBufferStruct tmpbuf;
868
869       SILC_LOG_DEBUG(("Fsetstat request"));
870
871       ret = silc_buffer_unformat(&buf,
872                                  SILC_STR_UI_INT(&id),
873                                  SILC_STR_UI32_NSTRING(&hdata, 
874                                                        &hdata_len),
875                                  SILC_STR_UI32_NSTRING(&attr_buf,
876                                                        &attr_len),
877                                  SILC_STR_END);
878       if (ret < 0)
879         goto failure;
880
881       if (attr_len) {
882         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
883         attrs = silc_sftp_attr_decode(&tmpbuf);
884         if (!attrs)
885           goto failure;
886       } else {
887         attrs = silc_calloc(1, sizeof(*attrs));
888         if (!attrs)
889           goto failure;
890       }
891
892       /* Get the handle */
893       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
894                                                (const unsigned char *)hdata,
895                                                hdata_len);
896       if (!handle) {
897         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
898         break;
899       }
900
901       /* Call monitor */
902       if (server->monitors & SILC_SFTP_MONITOR_FSETSTAT && server->monitor) {
903         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSETSTAT, &mdata,
904                            server->monitor_context);
905       }
906
907       /* Fsetstat operation */
908       server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp, 
909                                     handle, attrs,
910                                     silc_sftp_server_status, (void *)id);
911
912       silc_sftp_attr_free(attrs);
913     }
914     break;
915
916   case SILC_SFTP_READLINK:
917     {
918       SILC_LOG_DEBUG(("Readlink request"));
919
920       ret = silc_buffer_unformat(&buf,
921                                  SILC_STR_UI_INT(&id),
922                                  SILC_STR_UI32_STRING_ALLOC(&path),
923                                  SILC_STR_END);
924       if (ret < 0)
925         goto failure;
926
927       /* Call monitor */
928       if (server->monitors & SILC_SFTP_MONITOR_READLINK && server->monitor) {
929         mdata.name = path;
930         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READLINK, &mdata,
931                            server->monitor_context);
932       }
933
934       /* Readlink operation */
935       server->fs->fs->sftp_readlink(server->fs->fs_context, sftp, path,
936                                     silc_sftp_server_name, (void *)id);
937
938       silc_free(path);
939     }
940     break;
941
942   case SILC_SFTP_SYMLINK:
943     {
944       char *target = NULL;
945
946       SILC_LOG_DEBUG(("Symlink request"));
947
948       ret = silc_buffer_unformat(&buf,
949                                  SILC_STR_UI_INT(&id),
950                                  SILC_STR_UI32_STRING_ALLOC(&path),
951                                  SILC_STR_UI32_STRING_ALLOC(&target),
952                                  SILC_STR_END);
953       if (ret < 0)
954         goto failure;
955
956       /* Call monitor */
957       if (server->monitors & SILC_SFTP_MONITOR_SYMLINK && server->monitor) {
958         mdata.name = path;
959         mdata.name2 = target;
960         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SYMLINK, &mdata,
961                            server->monitor_context);
962       }
963
964       /* Symlink operation */
965       server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target,
966                                    silc_sftp_server_status, (void *)id);
967
968       silc_free(path);
969       silc_free(target);
970     }
971     break;
972
973   case SILC_SFTP_REALPATH:
974     {
975       SILC_LOG_DEBUG(("Realpath request"));
976
977       ret = silc_buffer_unformat(&buf,
978                                  SILC_STR_UI_INT(&id),
979                                  SILC_STR_UI32_STRING_ALLOC(&path),
980                                  SILC_STR_END);
981       if (ret < 0)
982         goto failure;
983
984       /* Call monitor */
985       if (server->monitors & SILC_SFTP_MONITOR_REALPATH && server->monitor) {
986         mdata.name = path;
987         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REALPATH, &mdata,
988                            server->monitor_context);
989       }
990
991       /* Realpath operation */
992       server->fs->fs->sftp_realpath(server->fs->fs_context, sftp, path,
993                                     silc_sftp_server_name, (void *)id);
994
995       silc_free(path);
996     }
997     break;
998
999   case SILC_SFTP_EXTENDED:
1000     {
1001       char *request = NULL;
1002       unsigned char *data;
1003       SilcUInt32 data_len;
1004
1005       SILC_LOG_DEBUG(("Extended request"));
1006
1007       ret = silc_buffer_unformat(&buf,
1008                                  SILC_STR_UI_INT(&id),
1009                                  SILC_STR_UI32_STRING_ALLOC(&request),
1010                                  SILC_STR_END);
1011       if (ret < 0)
1012         goto failure;
1013
1014       data_len = 8 + strlen(request);
1015       silc_buffer_pull(&buf, data_len);
1016       ret = silc_buffer_unformat(&buf,
1017                                  SILC_STR_UI_XNSTRING(&data, buf.len),
1018                                  SILC_STR_END);
1019       if (ret < 0)
1020         goto failure;
1021       data_len = buf.len;
1022
1023       /* Call monitor */
1024       if (server->monitors & SILC_SFTP_MONITOR_EXTENDED && server->monitor) {
1025         (*server->monitor)(sftp, SILC_SFTP_MONITOR_EXTENDED, &mdata,
1026                            server->monitor_context);
1027       }
1028
1029       /* Extended operation */
1030       server->fs->fs->sftp_extended(server->fs->fs_context, sftp, 
1031                                     request, data, data_len,
1032                                     silc_sftp_server_extended, (void *)id);
1033
1034       silc_free(request);
1035     }
1036     break;
1037
1038   default:
1039     break;
1040   }
1041
1042   return;
1043
1044  failure:
1045   silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
1046 }