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