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