updates.
[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
224   silc_sftp_send_packet(server, SILC_SFTP_ATTRS, 4 + attr_buf->len,
225                         SILC_STR_UI_INT(id),
226                         SILC_STR_UI_XNSTRING(attr_buf->data, attr_buf->len),
227                         SILC_STR_END);
228
229   silc_buffer_free(attr_buf);
230 }
231
232 /* Extended callback */
233
234 static void silc_sftp_server_extended(SilcSFTP sftp,
235                                       SilcSFTPStatus status,
236                                       const unsigned char *data,
237                                       SilcUInt32 data_len,
238                                       void *context)
239 {
240   SilcSFTPServer server = (SilcSFTPServer)sftp;
241   SilcUInt32 id = (SilcUInt32)context;
242
243   SILC_LOG_DEBUG(("Extended callback"));
244   SILC_LOG_DEBUG(("Request ID: %d", id));
245
246   if (status != SILC_SFTP_STATUS_OK) {
247     silc_sftp_send_error(server, status, id);
248     return;
249   }
250
251   silc_sftp_send_packet(server, SILC_SFTP_EXTENDED, 4 + data_len,
252                         SILC_STR_UI_INT(id),
253                         SILC_STR_UI_XNSTRING(data, data_len),
254                         SILC_STR_END);
255 }
256
257 /* Starts SFTP server and returns context to it.  This function returns the
258    allocated SFTP client context or NULL on error. The `send_packet' is called
259    by the library when it needs to send a packet. The `fs' is the
260    structure containing filesystem access callbacks. */
261
262 SilcSFTP silc_sftp_server_start(SilcSFTPSendPacketCallback send_packet,
263                                 void *send_context,
264                                 SilcSFTPFilesystem fs)
265 {
266   SilcSFTPServer server;
267
268   server = silc_calloc(1, sizeof(*server));
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   if (server->packet)
289     silc_buffer_free(server->packet);
290   silc_free(server);
291 }
292
293 /* Sets monitor callback */
294
295 void silc_sftp_server_set_monitor(SilcSFTP sftp,
296                                   SilcSFTPMonitors monitors,
297                                   SilcSFTPMonitor monitor, 
298                                   void *context)
299 {
300   SilcSFTPServer server = (SilcSFTPServer)sftp;
301   server->monitors = monitors;
302   server->monitor = monitor;
303   server->monitor_context = context;
304 }
305
306 /* Function that is called to process the incmoing SFTP packet. */
307 /* XXX Some day this will go away and we have automatic receive callbacks
308    for SilcSocketConnection API or SilcPacketContext API. */
309
310 void silc_sftp_server_receive_process(SilcSFTP sftp,
311                                       SilcSocketConnection sock,
312                                       SilcPacketContext *packet)
313 {
314   SilcSFTPServer server = (SilcSFTPServer)sftp;
315   SilcSFTPPacket type;
316   char *filename = NULL, *path = NULL;
317   const unsigned char *payload = NULL;
318   SilcUInt32 payload_len;
319   int ret;
320   SilcBufferStruct buf;
321   SilcUInt32 id;
322   SilcSFTPAttributes attrs;
323   SilcSFTPHandle handle;
324   SilcSFTPMonitorDataStruct mdata;
325
326   SILC_LOG_DEBUG(("Start"));
327
328   /* Parse the packet */
329   type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload, 
330                                  &payload_len);
331   if (!type)
332     return;
333
334   silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
335
336   memset(&mdata, 0, sizeof(mdata));
337
338   switch (type) {
339   case SILC_SFTP_INIT:
340     {
341       SilcSFTPVersion version;
342
343       SILC_LOG_DEBUG(("Init request"));
344
345       ret = silc_buffer_unformat(&buf,
346                                  SILC_STR_UI_INT(&version),
347                                  SILC_STR_END);
348       if (ret < 0)
349         break;
350
351       /* Call monitor */
352       if (server->monitors & SILC_SFTP_MONITOR_INIT && server->monitor) {
353         mdata.version = version;
354         (*server->monitor)(sftp, SILC_SFTP_MONITOR_INIT, &mdata,
355                            server->monitor_context);
356       }
357
358       silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4,
359                             SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
360                             SILC_STR_END);
361     }
362     break;
363
364   case SILC_SFTP_OPEN:
365     {
366       SilcSFTPFileOperation pflags;
367       unsigned char *attr_buf;
368       SilcUInt32 attr_len = 0;
369       SilcBufferStruct tmpbuf;
370
371       SILC_LOG_DEBUG(("Open request"));
372
373       ret = silc_buffer_unformat(&buf,
374                                  SILC_STR_UI_INT(&id),
375                                  SILC_STR_UI32_STRING_ALLOC(&filename),
376                                  SILC_STR_UI_INT(&pflags),
377                                  SILC_STR_UI32_NSTRING(&attr_buf, 
378                                                        &attr_len),
379                                  SILC_STR_END);
380       if (ret < 0)
381         goto failure;
382
383       if (attr_len) {
384         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
385         attrs = silc_sftp_attr_decode(&tmpbuf);
386       } else {
387         attrs = silc_calloc(1, sizeof(*attrs));
388       }
389
390       /* Call monitor */
391       if (server->monitors & SILC_SFTP_MONITOR_OPEN && server->monitor) {
392         mdata.name = filename;
393         mdata.pflags = pflags;
394         (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPEN, &mdata,
395                            server->monitor_context);
396       }
397
398       /* Open operation */
399       server->fs->fs->sftp_open(server->fs->fs_context, sftp, filename, pflags,
400                                 attrs, silc_sftp_server_handle, (void *)id);
401
402       silc_free(filename);
403       silc_sftp_attr_free(attrs);
404     }
405     break;
406
407   case SILC_SFTP_CLOSE:
408     {
409       unsigned char *hdata;
410       SilcUInt32 hdata_len;
411
412       SILC_LOG_DEBUG(("Close request"));
413
414       ret = silc_buffer_unformat(&buf,
415                                  SILC_STR_UI_INT(&id),
416                                  SILC_STR_UI32_NSTRING(&hdata, 
417                                                        &hdata_len),
418                                  SILC_STR_END);
419       if (ret < 0)
420         goto failure;
421
422       /* Get the handle */
423       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
424                                                (const unsigned char *)hdata,
425                                                hdata_len);
426       if (!handle) {
427         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
428         break;
429       }
430
431       /* Call monitor */
432       if (server->monitors & SILC_SFTP_MONITOR_CLOSE && server->monitor) {
433         (*server->monitor)(sftp, SILC_SFTP_MONITOR_CLOSE, &mdata,
434                            server->monitor_context);
435       }
436
437       /* Close operation */
438       server->fs->fs->sftp_close(server->fs->fs_context, sftp, handle,
439                                  silc_sftp_server_status, (void *)id);
440     }
441     break;
442
443   case SILC_SFTP_READ:
444     {
445       unsigned char *hdata;
446       SilcUInt32 hdata_len;
447       SilcUInt64 offset;
448       SilcUInt32 len;
449
450       SILC_LOG_DEBUG(("Read request"));
451
452       ret = silc_buffer_unformat(&buf,
453                                  SILC_STR_UI_INT(&id),
454                                  SILC_STR_UI32_NSTRING(&hdata, 
455                                                        &hdata_len),
456                                  SILC_STR_UI_INT64(&offset),
457                                  SILC_STR_UI_INT(&len),
458                                  SILC_STR_END);
459       if (ret < 0)
460         goto failure;
461
462       /* Get the handle */
463       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
464                                                (const unsigned char *)hdata,
465                                                hdata_len);
466       if (!handle) {
467         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
468         break;
469       }
470
471       /* Call monitor */
472       if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) {
473         mdata.offset = offset;
474         mdata.data_len = len;
475         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata,
476                            server->monitor_context);
477       }
478
479       /* Read operation */
480       server->fs->fs->sftp_read(server->fs->fs_context, sftp, 
481                                 handle, offset, len,
482                                 silc_sftp_server_data, (void *)id);
483     }
484     break;
485
486   case SILC_SFTP_WRITE:
487     {
488       unsigned char *hdata;
489       SilcUInt32 hdata_len;
490       SilcUInt64 offset;
491       unsigned char *data;
492       SilcUInt32 data_len;
493
494       SILC_LOG_DEBUG(("Read request"));
495
496       ret = silc_buffer_unformat(&buf,
497                                  SILC_STR_UI_INT(&id),
498                                  SILC_STR_UI32_NSTRING(&hdata, 
499                                                        &hdata_len),
500                                  SILC_STR_UI_INT64(&offset),
501                                  SILC_STR_UI32_NSTRING(&data, 
502                                                        &data_len),
503                                  SILC_STR_END);
504       if (ret < 0)
505         goto failure;
506
507       /* Get the handle */
508       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
509                                                (const unsigned char *)hdata,
510                                                hdata_len);
511       if (!handle) {
512         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
513         break;
514       }
515
516       /* Call monitor */
517       if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) {
518         mdata.offset = offset;
519         mdata.data_len = data_len;
520         (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata,
521                            server->monitor_context);
522       }
523
524       /* Write operation */
525       server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset, 
526                                  (const unsigned char *)data, data_len,
527                                  silc_sftp_server_status, (void *)id);
528     }
529     break;
530
531   case SILC_SFTP_REMOVE:
532     {
533       SILC_LOG_DEBUG(("Remove request"));
534
535       ret = silc_buffer_unformat(&buf,
536                                  SILC_STR_UI_INT(&id),
537                                  SILC_STR_UI32_STRING_ALLOC(&filename),
538                                  SILC_STR_END);
539       if (ret < 0)
540         goto failure;
541
542       /* Call monitor */
543       if (server->monitors & SILC_SFTP_MONITOR_REMOVE && server->monitor) {
544         mdata.name = filename;
545         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REMOVE, &mdata,
546                            server->monitor_context);
547       }
548
549       /* Remove operation */
550       server->fs->fs->sftp_remove(server->fs->fs_context, sftp, filename,
551                                   silc_sftp_server_status, (void *)id);
552
553       silc_free(filename);
554     }
555     break;
556
557   case SILC_SFTP_RENAME:
558     {
559       char *newname = NULL;
560
561       SILC_LOG_DEBUG(("Rename request"));
562
563       ret = silc_buffer_unformat(&buf,
564                                  SILC_STR_UI_INT(&id),
565                                  SILC_STR_UI32_STRING_ALLOC(&filename),
566                                  SILC_STR_UI32_STRING_ALLOC(&newname),
567                                  SILC_STR_END);
568       if (ret < 0)
569         goto failure;
570
571       /* Call monitor */
572       if (server->monitors & SILC_SFTP_MONITOR_RENAME && server->monitor) {
573         mdata.name = filename;
574         mdata.name2 = newname;
575         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RENAME, &mdata,
576                            server->monitor_context);
577       }
578
579       /* Rename operation */
580       server->fs->fs->sftp_rename(server->fs->fs_context, sftp, 
581                                   filename, newname,
582                                   silc_sftp_server_status, (void *)id);
583
584       silc_free(filename);
585       silc_free(newname);
586     }
587     break;
588
589   case SILC_SFTP_MKDIR:
590     {
591       unsigned char *attr_buf;
592       SilcUInt32 attr_len = 0;
593       SilcBufferStruct tmpbuf;
594
595       SILC_LOG_DEBUG(("Mkdir request"));
596
597       ret = silc_buffer_unformat(&buf,
598                                  SILC_STR_UI_INT(&id),
599                                  SILC_STR_UI32_STRING_ALLOC(&path),
600                                  SILC_STR_UI32_NSTRING(&attr_buf,
601                                                        &attr_len),
602                                  SILC_STR_END);
603       if (ret < 0)
604         goto failure;
605
606       if (attr_len) {
607         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
608         attrs = silc_sftp_attr_decode(&tmpbuf);
609       } else {
610         attrs = silc_calloc(1, sizeof(*attrs));
611       }
612
613       /* Call monitor */
614       if (server->monitors & SILC_SFTP_MONITOR_MKDIR && server->monitor) {
615         mdata.name = path;
616         (*server->monitor)(sftp, SILC_SFTP_MONITOR_MKDIR, &mdata,
617                            server->monitor_context);
618       }
619
620       /* Mkdir operation */
621       server->fs->fs->sftp_mkdir(server->fs->fs_context, sftp, path, attrs,
622                                  silc_sftp_server_status, (void *)id);
623
624       silc_sftp_attr_free(attrs);
625       silc_free(path);
626     }
627     break;
628
629   case SILC_SFTP_RMDIR:
630     {
631       SILC_LOG_DEBUG(("Rmdir request"));
632
633       ret = silc_buffer_unformat(&buf,
634                                  SILC_STR_UI_INT(&id),
635                                  SILC_STR_UI32_STRING_ALLOC(&path),
636                                  SILC_STR_END);
637       if (ret < 0)
638         goto failure;
639
640       /* Call monitor */
641       if (server->monitors & SILC_SFTP_MONITOR_RMDIR && server->monitor) {
642         mdata.name = path;
643         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RMDIR, &mdata,
644                            server->monitor_context);
645       }
646
647       /* Rmdir operation */
648       server->fs->fs->sftp_rmdir(server->fs->fs_context, sftp, path,
649                                  silc_sftp_server_status, (void *)id);
650
651       silc_free(path);
652     }
653     break;
654
655   case SILC_SFTP_OPENDIR:
656     {
657       SILC_LOG_DEBUG(("Opendir request"));
658
659       ret = silc_buffer_unformat(&buf,
660                                  SILC_STR_UI_INT(&id),
661                                  SILC_STR_UI32_STRING_ALLOC(&path),
662                                  SILC_STR_END);
663       if (ret < 0)
664         goto failure;
665
666       /* Call monitor */
667       if (server->monitors & SILC_SFTP_MONITOR_OPENDIR && server->monitor) {
668         mdata.name = path;
669         (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPENDIR, &mdata,
670                            server->monitor_context);
671       }
672
673       /* Opendir operation */
674       server->fs->fs->sftp_opendir(server->fs->fs_context, sftp, path,
675                                    silc_sftp_server_handle, (void *)id);
676
677       silc_free(path);
678     }
679     break;
680
681   case SILC_SFTP_READDIR:
682     {
683       unsigned char *hdata;
684       SilcUInt32 hdata_len;
685
686       SILC_LOG_DEBUG(("Readdir request"));
687
688       ret = silc_buffer_unformat(&buf,
689                                  SILC_STR_UI_INT(&id),
690                                  SILC_STR_UI32_NSTRING(&hdata, 
691                                                        &hdata_len),
692                                  SILC_STR_END);
693       if (ret < 0)
694         goto failure;
695
696       /* Get the handle */
697       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
698                                                (const unsigned char *)hdata,
699                                                hdata_len);
700       if (!handle) {
701         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
702         break;
703       }
704
705       /* Call monitor */
706       if (server->monitors & SILC_SFTP_MONITOR_READDIR && server->monitor) {
707         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READDIR, &mdata,
708                            server->monitor_context);
709       }
710
711       /* Readdir operation */
712       server->fs->fs->sftp_readdir(server->fs->fs_context, sftp, handle,
713                                    silc_sftp_server_name, (void *)id);
714     }
715     break;
716
717   case SILC_SFTP_STAT:
718     {
719       SILC_LOG_DEBUG(("Stat request"));
720
721       ret = silc_buffer_unformat(&buf,
722                                  SILC_STR_UI_INT(&id),
723                                  SILC_STR_UI32_STRING_ALLOC(&path),
724                                  SILC_STR_END);
725       if (ret < 0)
726         goto failure;
727
728       /* Call monitor */
729       if (server->monitors & SILC_SFTP_MONITOR_STAT && server->monitor) {
730         mdata.name = path;
731         (*server->monitor)(sftp, SILC_SFTP_MONITOR_STAT, &mdata,
732                            server->monitor_context);
733       }
734
735       /* Stat operation */
736       server->fs->fs->sftp_stat(server->fs->fs_context, sftp, path,
737                                 silc_sftp_server_attr, (void *)id);
738
739       silc_free(path);
740     }
741     break;
742
743   case SILC_SFTP_LSTAT:
744     {
745       SILC_LOG_DEBUG(("Lstat request"));
746
747       ret = silc_buffer_unformat(&buf,
748                                  SILC_STR_UI_INT(&id),
749                                  SILC_STR_UI32_STRING_ALLOC(&path),
750                                  SILC_STR_END);
751       if (ret < 0)
752         goto failure;
753
754       /* Call monitor */
755       if (server->monitors & SILC_SFTP_MONITOR_LSTAT && server->monitor) {
756         mdata.name = path;
757         (*server->monitor)(sftp, SILC_SFTP_MONITOR_LSTAT, &mdata,
758                            server->monitor_context);
759       }
760
761       /* Lstat operation */
762       server->fs->fs->sftp_lstat(server->fs->fs_context, sftp, path,
763                                  silc_sftp_server_attr, (void *)id);
764
765       silc_free(path);
766     }
767     break;
768
769   case SILC_SFTP_FSTAT:
770     {
771       unsigned char *hdata;
772       SilcUInt32 hdata_len;
773
774       SILC_LOG_DEBUG(("Fstat request"));
775
776       ret = silc_buffer_unformat(&buf,
777                                  SILC_STR_UI_INT(&id),
778                                  SILC_STR_UI32_NSTRING(&hdata, 
779                                                        &hdata_len),
780                                  SILC_STR_END);
781       if (ret < 0)
782         goto failure;
783
784       /* Get the handle */
785       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
786                                                (const unsigned char *)hdata,
787                                                hdata_len);
788       if (!handle) {
789         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
790         break;
791       }
792
793       /* Call monitor */
794       if (server->monitors & SILC_SFTP_MONITOR_FSTAT && server->monitor) {
795         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSTAT, &mdata,
796                            server->monitor_context);
797       }
798
799       /* Fstat operation */
800       server->fs->fs->sftp_fstat(server->fs->fs_context, sftp, handle,
801                                  silc_sftp_server_attr, (void *)id);
802     }
803     break;
804
805   case SILC_SFTP_SETSTAT:
806     {
807       unsigned char *attr_buf;
808       SilcUInt32 attr_len = 0;
809       SilcBufferStruct tmpbuf;
810
811       SILC_LOG_DEBUG(("Setstat request"));
812
813       ret = silc_buffer_unformat(&buf,
814                                  SILC_STR_UI_INT(&id),
815                                  SILC_STR_UI32_STRING_ALLOC(&path),
816                                  SILC_STR_UI32_NSTRING(&attr_buf,
817                                                        &attr_len),
818                                  SILC_STR_END);
819       if (ret < 0)
820         goto failure;
821
822       if (attr_len) {
823         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
824         attrs = silc_sftp_attr_decode(&tmpbuf);
825       } else {
826         attrs = silc_calloc(1, sizeof(*attrs));
827       }
828
829       /* Call monitor */
830       if (server->monitors & SILC_SFTP_MONITOR_SETSTAT && server->monitor) {
831         mdata.name = path;
832         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SETSTAT, &mdata,
833                            server->monitor_context);
834       }
835
836       /* Setstat operation */
837       server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs,
838                                    silc_sftp_server_status, (void *)id);
839
840       silc_sftp_attr_free(attrs);
841       silc_free(path);
842     }
843     break;
844
845   case SILC_SFTP_FSETSTAT:
846     {
847       unsigned char *hdata, *attr_buf;
848       SilcUInt32 hdata_len, attr_len = 0;
849       SilcBufferStruct tmpbuf;
850
851       SILC_LOG_DEBUG(("Fsetstat request"));
852
853       ret = silc_buffer_unformat(&buf,
854                                  SILC_STR_UI_INT(&id),
855                                  SILC_STR_UI32_NSTRING(&hdata, 
856                                                        &hdata_len),
857                                  SILC_STR_UI32_NSTRING(&attr_buf,
858                                                        &attr_len),
859                                  SILC_STR_END);
860       if (ret < 0)
861         goto failure;
862
863       if (attr_len) {
864         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
865         attrs = silc_sftp_attr_decode(&tmpbuf);
866       } else {
867         attrs = silc_calloc(1, sizeof(*attrs));
868       }
869
870       /* Get the handle */
871       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
872                                                (const unsigned char *)hdata,
873                                                hdata_len);
874       if (!handle) {
875         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
876         break;
877       }
878
879       /* Call monitor */
880       if (server->monitors & SILC_SFTP_MONITOR_FSETSTAT && server->monitor) {
881         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSETSTAT, &mdata,
882                            server->monitor_context);
883       }
884
885       /* Fsetstat operation */
886       server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp, 
887                                     handle, attrs,
888                                     silc_sftp_server_status, (void *)id);
889
890       silc_sftp_attr_free(attrs);
891     }
892     break;
893
894   case SILC_SFTP_READLINK:
895     {
896       SILC_LOG_DEBUG(("Readlink request"));
897
898       ret = silc_buffer_unformat(&buf,
899                                  SILC_STR_UI_INT(&id),
900                                  SILC_STR_UI32_STRING_ALLOC(&path),
901                                  SILC_STR_END);
902       if (ret < 0)
903         goto failure;
904
905       /* Call monitor */
906       if (server->monitors & SILC_SFTP_MONITOR_READLINK && server->monitor) {
907         mdata.name = path;
908         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READLINK, &mdata,
909                            server->monitor_context);
910       }
911
912       /* Readlink operation */
913       server->fs->fs->sftp_readlink(server->fs->fs_context, sftp, path,
914                                     silc_sftp_server_name, (void *)id);
915
916       silc_free(path);
917     }
918     break;
919
920   case SILC_SFTP_SYMLINK:
921     {
922       char *target = NULL;
923
924       SILC_LOG_DEBUG(("Symlink request"));
925
926       ret = silc_buffer_unformat(&buf,
927                                  SILC_STR_UI_INT(&id),
928                                  SILC_STR_UI32_STRING_ALLOC(&path),
929                                  SILC_STR_UI32_STRING_ALLOC(&target),
930                                  SILC_STR_END);
931       if (ret < 0)
932         goto failure;
933
934       /* Call monitor */
935       if (server->monitors & SILC_SFTP_MONITOR_SYMLINK && server->monitor) {
936         mdata.name = path;
937         mdata.name2 = target;
938         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SYMLINK, &mdata,
939                            server->monitor_context);
940       }
941
942       /* Symlink operation */
943       server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target,
944                                    silc_sftp_server_status, (void *)id);
945
946       silc_free(path);
947       silc_free(target);
948     }
949     break;
950
951   case SILC_SFTP_REALPATH:
952     {
953       SILC_LOG_DEBUG(("Realpath request"));
954
955       ret = silc_buffer_unformat(&buf,
956                                  SILC_STR_UI_INT(&id),
957                                  SILC_STR_UI32_STRING_ALLOC(&path),
958                                  SILC_STR_END);
959       if (ret < 0)
960         goto failure;
961
962       /* Call monitor */
963       if (server->monitors & SILC_SFTP_MONITOR_REALPATH && server->monitor) {
964         mdata.name = path;
965         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REALPATH, &mdata,
966                            server->monitor_context);
967       }
968
969       /* Realpath operation */
970       server->fs->fs->sftp_realpath(server->fs->fs_context, sftp, path,
971                                     silc_sftp_server_name, (void *)id);
972
973       silc_free(path);
974     }
975     break;
976
977   case SILC_SFTP_EXTENDED:
978     {
979       char *request = NULL;
980       unsigned char *data;
981       SilcUInt32 data_len;
982
983       SILC_LOG_DEBUG(("Extended request"));
984
985       ret = silc_buffer_unformat(&buf,
986                                  SILC_STR_UI_INT(&id),
987                                  SILC_STR_UI32_STRING_ALLOC(&request),
988                                  SILC_STR_END);
989       if (ret < 0)
990         goto failure;
991
992       data_len = 8 + strlen(request);
993       silc_buffer_pull(&buf, data_len);
994       ret = silc_buffer_unformat(&buf,
995                                  SILC_STR_UI_XNSTRING(&data, buf.len),
996                                  SILC_STR_END);
997       if (ret < 0)
998         goto failure;
999       data_len = buf.len;
1000
1001       /* Call monitor */
1002       if (server->monitors & SILC_SFTP_MONITOR_EXTENDED && server->monitor) {
1003         (*server->monitor)(sftp, SILC_SFTP_MONITOR_EXTENDED, &mdata,
1004                            server->monitor_context);
1005       }
1006
1007       /* Extended operation */
1008       server->fs->fs->sftp_extended(server->fs->fs_context, sftp, 
1009                                     request, data, data_len,
1010                                     silc_sftp_server_extended, (void *)id);
1011
1012       silc_free(request);
1013     }
1014     break;
1015
1016   default:
1017     break;
1018   }
1019
1020   return;
1021
1022  failure:
1023   silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
1024 }