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