Merge commit 'origin/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   if (!schedule)
365     schedule = silc_schedule_get_global();
366
367   server = silc_calloc(1, sizeof(*server));
368   if (!server)
369     return NULL;
370   server->stream = stream;
371   server->schedule = schedule;
372   server->error = error_cb;
373   server->context = context;
374   server->fs = fs;
375
376   /* We handle the stream now */
377   silc_stream_set_notifier(stream, schedule, silc_sftp_server_io, server);
378
379   SILC_LOG_DEBUG(("Starting SFTP server %p", server));
380
381   return (SilcSFTP)server;
382 }
383
384 /* Shutdown's the SFTP server.  The caller is responsible of closing
385    the associated socket connection.  The SFTP context is freed and is
386    invalid after this function returns. */
387
388 void silc_sftp_server_shutdown(SilcSFTP sftp)
389 {
390   SilcSFTPServer server = (SilcSFTPServer)sftp;
391
392   SILC_LOG_DEBUG(("Stopping SFTP server %p", server));
393
394   silc_stream_set_notifier(server->stream, server->schedule, NULL, NULL);
395   if (server->packet)
396     silc_buffer_free(server->packet);
397   silc_free(server);
398 }
399
400 /* Sets monitor callback */
401
402 void silc_sftp_server_set_monitor(SilcSFTP sftp,
403                                   SilcSFTPMonitors monitors,
404                                   SilcSFTPMonitor monitor,
405                                   void *context)
406 {
407   SilcSFTPServer server = (SilcSFTPServer)sftp;
408   server->monitors = monitors;
409   server->monitor = monitor;
410   server->monitor_context = context;
411 }
412
413 /* Function that is called to process the incmoing SFTP packet. */
414
415 static void silc_sftp_server_receive_process(SilcSFTP sftp, SilcBuffer buffer)
416 {
417   SilcSFTPServer server = (SilcSFTPServer)sftp;
418   SilcSFTPPacket type;
419   char *filename = NULL, *path = NULL;
420   unsigned char *payload = NULL;
421   SilcUInt32 payload_len;
422   int ret;
423   SilcBufferStruct buf;
424   SilcUInt32 id;
425   SilcSFTPAttributes attrs;
426   SilcSFTPHandle handle;
427   SilcSFTPMonitorDataStruct mdata;
428
429   SILC_LOG_DEBUG(("Start"));
430
431   /* Parse the packet */
432   type = silc_sftp_packet_decode(buffer, &payload, &payload_len);
433   if (type <= 0)
434     return;
435
436   silc_buffer_set(&buf, payload, payload_len);
437
438   memset(&mdata, 0, sizeof(mdata));
439
440   switch (type) {
441   case SILC_SFTP_READ:
442     {
443       unsigned char *hdata;
444       SilcUInt32 hdata_len;
445       SilcUInt64 offset;
446       SilcUInt32 len;
447
448       SILC_LOG_DEBUG(("Read request"));
449
450       ret = silc_buffer_unformat(&buf,
451                                  SILC_STR_UI_INT(&id),
452                                  SILC_STR_UI32_NSTRING(&hdata,
453                                                        &hdata_len),
454                                  SILC_STR_UI_INT64(&offset),
455                                  SILC_STR_UI_INT(&len),
456                                  SILC_STR_END);
457       if (ret < 0)
458         goto failure;
459
460       /* Get the handle */
461       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
462                                                (const unsigned char *)hdata,
463                                                hdata_len);
464       if (!handle) {
465         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
466         break;
467       }
468
469       /* Read operation */
470       server->fs->fs->sftp_read(server->fs->fs_context, sftp,
471                                 handle, offset, len,
472                                 silc_sftp_server_data, SILC_32_TO_PTR(id));
473
474       /* Call monitor */
475       if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) {
476         mdata.offset = offset;
477         mdata.data_len = len;
478         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata,
479                            server->monitor_context);
480       }
481     }
482     break;
483
484   case SILC_SFTP_WRITE:
485     {
486       unsigned char *hdata;
487       SilcUInt32 hdata_len;
488       SilcUInt64 offset;
489       unsigned char *data;
490       SilcUInt32 data_len;
491
492       SILC_LOG_DEBUG(("Read request"));
493
494       ret = silc_buffer_unformat(&buf,
495                                  SILC_STR_UI_INT(&id),
496                                  SILC_STR_UI32_NSTRING(&hdata,
497                                                        &hdata_len),
498                                  SILC_STR_UI_INT64(&offset),
499                                  SILC_STR_UI32_NSTRING(&data,
500                                                        &data_len),
501                                  SILC_STR_END);
502       if (ret < 0)
503         goto failure;
504
505       /* Get the handle */
506       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
507                                                (const unsigned char *)hdata,
508                                                hdata_len);
509       if (!handle) {
510         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
511         break;
512       }
513
514       /* Write operation */
515       server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset,
516                                  (const unsigned char *)data, data_len,
517                                  silc_sftp_server_status, SILC_32_TO_PTR(id));
518
519       /* Call monitor */
520       if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) {
521         mdata.offset = offset;
522         mdata.data_len = data_len;
523         (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata,
524                            server->monitor_context);
525       }
526     }
527     break;
528
529   case SILC_SFTP_INIT:
530     {
531       SilcSFTPVersion version;
532
533       SILC_LOG_DEBUG(("Init request"));
534
535       ret = silc_buffer_unformat(&buf,
536                                  SILC_STR_UI_INT(&version),
537                                  SILC_STR_END);
538       if (ret < 0)
539         break;
540
541       /* Call monitor */
542       if (server->monitors & SILC_SFTP_MONITOR_INIT && server->monitor) {
543         mdata.version = version;
544         (*server->monitor)(sftp, SILC_SFTP_MONITOR_INIT, &mdata,
545                            server->monitor_context);
546       }
547
548       silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4,
549                             SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
550                             SILC_STR_END);
551     }
552     break;
553
554   case SILC_SFTP_OPEN:
555     {
556       SilcSFTPFileOperation pflags;
557       unsigned char *attr_buf;
558       SilcUInt32 attr_len = 0;
559       SilcBufferStruct tmpbuf;
560
561       SILC_LOG_DEBUG(("Open request"));
562
563       ret = silc_buffer_unformat(&buf,
564                                  SILC_STR_UI_INT(&id),
565                                  SILC_STR_UI32_STRING_ALLOC(&filename),
566                                  SILC_STR_UI_INT(&pflags),
567                                  SILC_STR_UI32_NSTRING(&attr_buf,
568                                                        &attr_len),
569                                  SILC_STR_END);
570       if (ret < 0)
571         goto failure;
572
573       if (attr_len) {
574         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
575         attrs = silc_sftp_attr_decode(&tmpbuf);
576         if (!attrs)
577           goto failure;
578       } else {
579         attrs = silc_calloc(1, sizeof(*attrs));
580         if (!attrs)
581           goto failure;
582       }
583
584       /* Call monitor */
585       if (server->monitors & SILC_SFTP_MONITOR_OPEN && server->monitor) {
586         mdata.name = filename;
587         mdata.pflags = pflags;
588         (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPEN, &mdata,
589                            server->monitor_context);
590       }
591
592       /* Open operation */
593       server->fs->fs->sftp_open(server->fs->fs_context, sftp, filename, pflags,
594                                 attrs, silc_sftp_server_handle,
595                                 SILC_32_TO_PTR(id));
596
597       silc_free(filename);
598       silc_sftp_attr_free(attrs);
599     }
600     break;
601
602   case SILC_SFTP_CLOSE:
603     {
604       unsigned char *hdata;
605       SilcUInt32 hdata_len;
606
607       SILC_LOG_DEBUG(("Close request"));
608
609       ret = silc_buffer_unformat(&buf,
610                                  SILC_STR_UI_INT(&id),
611                                  SILC_STR_UI32_NSTRING(&hdata,
612                                                        &hdata_len),
613                                  SILC_STR_END);
614       if (ret < 0)
615         goto failure;
616
617       /* Get the handle */
618       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
619                                                (const unsigned char *)hdata,
620                                                hdata_len);
621       if (!handle) {
622         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
623         break;
624       }
625
626       /* Call monitor */
627       if (server->monitors & SILC_SFTP_MONITOR_CLOSE && server->monitor) {
628         (*server->monitor)(sftp, SILC_SFTP_MONITOR_CLOSE, &mdata,
629                            server->monitor_context);
630       }
631
632       /* Close operation */
633       server->fs->fs->sftp_close(server->fs->fs_context, sftp, handle,
634                                  silc_sftp_server_status, SILC_32_TO_PTR(id));
635
636     }
637     break;
638
639   case SILC_SFTP_REMOVE:
640     {
641       SILC_LOG_DEBUG(("Remove request"));
642
643       ret = silc_buffer_unformat(&buf,
644                                  SILC_STR_UI_INT(&id),
645                                  SILC_STR_UI32_STRING_ALLOC(&filename),
646                                  SILC_STR_END);
647       if (ret < 0)
648         goto failure;
649
650       /* Call monitor */
651       if (server->monitors & SILC_SFTP_MONITOR_REMOVE && server->monitor) {
652         mdata.name = filename;
653         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REMOVE, &mdata,
654                            server->monitor_context);
655       }
656
657       /* Remove operation */
658       server->fs->fs->sftp_remove(server->fs->fs_context, sftp, filename,
659                                   silc_sftp_server_status, SILC_32_TO_PTR(id));
660
661       silc_free(filename);
662     }
663     break;
664
665   case SILC_SFTP_RENAME:
666     {
667       char *newname = NULL;
668
669       SILC_LOG_DEBUG(("Rename request"));
670
671       ret = silc_buffer_unformat(&buf,
672                                  SILC_STR_UI_INT(&id),
673                                  SILC_STR_UI32_STRING_ALLOC(&filename),
674                                  SILC_STR_UI32_STRING_ALLOC(&newname),
675                                  SILC_STR_END);
676       if (ret < 0)
677         goto failure;
678
679       /* Call monitor */
680       if (server->monitors & SILC_SFTP_MONITOR_RENAME && server->monitor) {
681         mdata.name = filename;
682         mdata.name2 = newname;
683         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RENAME, &mdata,
684                            server->monitor_context);
685       }
686
687       /* Rename operation */
688       server->fs->fs->sftp_rename(server->fs->fs_context, sftp,
689                                   filename, newname,
690                                   silc_sftp_server_status, SILC_32_TO_PTR(id));
691
692       silc_free(filename);
693       silc_free(newname);
694     }
695     break;
696
697   case SILC_SFTP_MKDIR:
698     {
699       unsigned char *attr_buf;
700       SilcUInt32 attr_len = 0;
701       SilcBufferStruct tmpbuf;
702
703       SILC_LOG_DEBUG(("Mkdir request"));
704
705       ret = silc_buffer_unformat(&buf,
706                                  SILC_STR_UI_INT(&id),
707                                  SILC_STR_UI32_STRING_ALLOC(&path),
708                                  SILC_STR_UI32_NSTRING(&attr_buf,
709                                                        &attr_len),
710                                  SILC_STR_END);
711       if (ret < 0)
712         goto failure;
713
714       if (attr_len) {
715         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
716         attrs = silc_sftp_attr_decode(&tmpbuf);
717         if (!attrs)
718           goto failure;
719       } else {
720         attrs = silc_calloc(1, sizeof(*attrs));
721         if (!attrs)
722           goto failure;
723       }
724
725       /* Call monitor */
726       if (server->monitors & SILC_SFTP_MONITOR_MKDIR && server->monitor) {
727         mdata.name = path;
728         (*server->monitor)(sftp, SILC_SFTP_MONITOR_MKDIR, &mdata,
729                            server->monitor_context);
730       }
731
732       /* Mkdir operation */
733       server->fs->fs->sftp_mkdir(server->fs->fs_context, sftp, path, attrs,
734                                  silc_sftp_server_status, SILC_32_TO_PTR(id));
735
736       silc_sftp_attr_free(attrs);
737       silc_free(path);
738     }
739     break;
740
741   case SILC_SFTP_RMDIR:
742     {
743       SILC_LOG_DEBUG(("Rmdir request"));
744
745       ret = silc_buffer_unformat(&buf,
746                                  SILC_STR_UI_INT(&id),
747                                  SILC_STR_UI32_STRING_ALLOC(&path),
748                                  SILC_STR_END);
749       if (ret < 0)
750         goto failure;
751
752       /* Call monitor */
753       if (server->monitors & SILC_SFTP_MONITOR_RMDIR && server->monitor) {
754         mdata.name = path;
755         (*server->monitor)(sftp, SILC_SFTP_MONITOR_RMDIR, &mdata,
756                            server->monitor_context);
757       }
758
759       /* Rmdir operation */
760       server->fs->fs->sftp_rmdir(server->fs->fs_context, sftp, path,
761                                  silc_sftp_server_status, SILC_32_TO_PTR(id));
762
763       silc_free(path);
764     }
765     break;
766
767   case SILC_SFTP_OPENDIR:
768     {
769       SILC_LOG_DEBUG(("Opendir request"));
770
771       ret = silc_buffer_unformat(&buf,
772                                  SILC_STR_UI_INT(&id),
773                                  SILC_STR_UI32_STRING_ALLOC(&path),
774                                  SILC_STR_END);
775       if (ret < 0)
776         goto failure;
777
778       /* Call monitor */
779       if (server->monitors & SILC_SFTP_MONITOR_OPENDIR && server->monitor) {
780         mdata.name = path;
781         (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPENDIR, &mdata,
782                            server->monitor_context);
783       }
784
785       /* Opendir operation */
786       server->fs->fs->sftp_opendir(server->fs->fs_context, sftp, path,
787                                    silc_sftp_server_handle, SILC_32_TO_PTR(id));
788
789       silc_free(path);
790     }
791     break;
792
793   case SILC_SFTP_READDIR:
794     {
795       unsigned char *hdata;
796       SilcUInt32 hdata_len;
797
798       SILC_LOG_DEBUG(("Readdir request"));
799
800       ret = silc_buffer_unformat(&buf,
801                                  SILC_STR_UI_INT(&id),
802                                  SILC_STR_UI32_NSTRING(&hdata,
803                                                        &hdata_len),
804                                  SILC_STR_END);
805       if (ret < 0)
806         goto failure;
807
808       /* Get the handle */
809       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
810                                                (const unsigned char *)hdata,
811                                                hdata_len);
812       if (!handle) {
813         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
814         break;
815       }
816
817       /* Call monitor */
818       if (server->monitors & SILC_SFTP_MONITOR_READDIR && server->monitor) {
819         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READDIR, &mdata,
820                            server->monitor_context);
821       }
822
823       /* Readdir operation */
824       server->fs->fs->sftp_readdir(server->fs->fs_context, sftp, handle,
825                                    silc_sftp_server_name, SILC_32_TO_PTR(id));
826     }
827     break;
828
829   case SILC_SFTP_STAT:
830     {
831       SILC_LOG_DEBUG(("Stat request"));
832
833       ret = silc_buffer_unformat(&buf,
834                                  SILC_STR_UI_INT(&id),
835                                  SILC_STR_UI32_STRING_ALLOC(&path),
836                                  SILC_STR_END);
837       if (ret < 0)
838         goto failure;
839
840       /* Call monitor */
841       if (server->monitors & SILC_SFTP_MONITOR_STAT && server->monitor) {
842         mdata.name = path;
843         (*server->monitor)(sftp, SILC_SFTP_MONITOR_STAT, &mdata,
844                            server->monitor_context);
845       }
846
847       /* Stat operation */
848       server->fs->fs->sftp_stat(server->fs->fs_context, sftp, path,
849                                 silc_sftp_server_attr, SILC_32_TO_PTR(id));
850
851       silc_free(path);
852     }
853     break;
854
855   case SILC_SFTP_LSTAT:
856     {
857       SILC_LOG_DEBUG(("Lstat request"));
858
859       ret = silc_buffer_unformat(&buf,
860                                  SILC_STR_UI_INT(&id),
861                                  SILC_STR_UI32_STRING_ALLOC(&path),
862                                  SILC_STR_END);
863       if (ret < 0)
864         goto failure;
865
866       /* Call monitor */
867       if (server->monitors & SILC_SFTP_MONITOR_LSTAT && server->monitor) {
868         mdata.name = path;
869         (*server->monitor)(sftp, SILC_SFTP_MONITOR_LSTAT, &mdata,
870                            server->monitor_context);
871       }
872
873       /* Lstat operation */
874       server->fs->fs->sftp_lstat(server->fs->fs_context, sftp, path,
875                                  silc_sftp_server_attr, SILC_32_TO_PTR(id));
876
877       silc_free(path);
878     }
879     break;
880
881   case SILC_SFTP_FSTAT:
882     {
883       unsigned char *hdata;
884       SilcUInt32 hdata_len;
885
886       SILC_LOG_DEBUG(("Fstat request"));
887
888       ret = silc_buffer_unformat(&buf,
889                                  SILC_STR_UI_INT(&id),
890                                  SILC_STR_UI32_NSTRING(&hdata,
891                                                        &hdata_len),
892                                  SILC_STR_END);
893       if (ret < 0)
894         goto failure;
895
896       /* Get the handle */
897       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
898                                                (const unsigned char *)hdata,
899                                                hdata_len);
900       if (!handle) {
901         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
902         break;
903       }
904
905       /* Call monitor */
906       if (server->monitors & SILC_SFTP_MONITOR_FSTAT && server->monitor) {
907         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSTAT, &mdata,
908                            server->monitor_context);
909       }
910
911       /* Fstat operation */
912       server->fs->fs->sftp_fstat(server->fs->fs_context, sftp, handle,
913                                  silc_sftp_server_attr, SILC_32_TO_PTR(id));
914     }
915     break;
916
917   case SILC_SFTP_SETSTAT:
918     {
919       unsigned char *attr_buf;
920       SilcUInt32 attr_len = 0;
921       SilcBufferStruct tmpbuf;
922
923       SILC_LOG_DEBUG(("Setstat request"));
924
925       ret = silc_buffer_unformat(&buf,
926                                  SILC_STR_UI_INT(&id),
927                                  SILC_STR_UI32_STRING_ALLOC(&path),
928                                  SILC_STR_UI32_NSTRING(&attr_buf,
929                                                        &attr_len),
930                                  SILC_STR_END);
931       if (ret < 0)
932         goto failure;
933
934       if (attr_len) {
935         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
936         attrs = silc_sftp_attr_decode(&tmpbuf);
937         if (!attrs)
938           goto failure;
939       } else {
940         attrs = silc_calloc(1, sizeof(*attrs));
941         if (!attrs)
942           goto failure;
943       }
944
945       /* Call monitor */
946       if (server->monitors & SILC_SFTP_MONITOR_SETSTAT && server->monitor) {
947         mdata.name = path;
948         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SETSTAT, &mdata,
949                            server->monitor_context);
950       }
951
952       /* Setstat operation */
953       server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs,
954                                    silc_sftp_server_status,
955                                    SILC_32_TO_PTR(id));
956
957       silc_sftp_attr_free(attrs);
958       silc_free(path);
959     }
960     break;
961
962   case SILC_SFTP_FSETSTAT:
963     {
964       unsigned char *hdata, *attr_buf;
965       SilcUInt32 hdata_len, attr_len = 0;
966       SilcBufferStruct tmpbuf;
967
968       SILC_LOG_DEBUG(("Fsetstat request"));
969
970       ret = silc_buffer_unformat(&buf,
971                                  SILC_STR_UI_INT(&id),
972                                  SILC_STR_UI32_NSTRING(&hdata,
973                                                        &hdata_len),
974                                  SILC_STR_UI32_NSTRING(&attr_buf,
975                                                        &attr_len),
976                                  SILC_STR_END);
977       if (ret < 0)
978         goto failure;
979
980       if (attr_len) {
981         silc_buffer_set(&tmpbuf, attr_buf, attr_len);
982         attrs = silc_sftp_attr_decode(&tmpbuf);
983         if (!attrs)
984           goto failure;
985       } else {
986         attrs = silc_calloc(1, sizeof(*attrs));
987         if (!attrs)
988           goto failure;
989       }
990
991       /* Get the handle */
992       handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
993                                                (const unsigned char *)hdata,
994                                                hdata_len);
995       if (!handle) {
996         silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
997         break;
998       }
999
1000       /* Call monitor */
1001       if (server->monitors & SILC_SFTP_MONITOR_FSETSTAT && server->monitor) {
1002         (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSETSTAT, &mdata,
1003                            server->monitor_context);
1004       }
1005
1006       /* Fsetstat operation */
1007       server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp,
1008                                     handle, attrs,
1009                                     silc_sftp_server_status,
1010                                     SILC_32_TO_PTR(id));
1011
1012       silc_sftp_attr_free(attrs);
1013     }
1014     break;
1015
1016   case SILC_SFTP_READLINK:
1017     {
1018       SILC_LOG_DEBUG(("Readlink request"));
1019
1020       ret = silc_buffer_unformat(&buf,
1021                                  SILC_STR_UI_INT(&id),
1022                                  SILC_STR_UI32_STRING_ALLOC(&path),
1023                                  SILC_STR_END);
1024       if (ret < 0)
1025         goto failure;
1026
1027       /* Call monitor */
1028       if (server->monitors & SILC_SFTP_MONITOR_READLINK && server->monitor) {
1029         mdata.name = path;
1030         (*server->monitor)(sftp, SILC_SFTP_MONITOR_READLINK, &mdata,
1031                            server->monitor_context);
1032       }
1033
1034       /* Readlink operation */
1035       server->fs->fs->sftp_readlink(server->fs->fs_context, sftp, path,
1036                                     silc_sftp_server_name, SILC_32_TO_PTR(id));
1037
1038       silc_free(path);
1039     }
1040     break;
1041
1042   case SILC_SFTP_SYMLINK:
1043     {
1044       char *target = NULL;
1045
1046       SILC_LOG_DEBUG(("Symlink request"));
1047
1048       ret = silc_buffer_unformat(&buf,
1049                                  SILC_STR_UI_INT(&id),
1050                                  SILC_STR_UI32_STRING_ALLOC(&path),
1051                                  SILC_STR_UI32_STRING_ALLOC(&target),
1052                                  SILC_STR_END);
1053       if (ret < 0)
1054         goto failure;
1055
1056       /* Call monitor */
1057       if (server->monitors & SILC_SFTP_MONITOR_SYMLINK && server->monitor) {
1058         mdata.name = path;
1059         mdata.name2 = target;
1060         (*server->monitor)(sftp, SILC_SFTP_MONITOR_SYMLINK, &mdata,
1061                            server->monitor_context);
1062       }
1063
1064       /* Symlink operation */
1065       server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target,
1066                                    silc_sftp_server_status,
1067                                    SILC_32_TO_PTR(id));
1068
1069       silc_free(path);
1070       silc_free(target);
1071     }
1072     break;
1073
1074   case SILC_SFTP_REALPATH:
1075     {
1076       SILC_LOG_DEBUG(("Realpath request"));
1077
1078       ret = silc_buffer_unformat(&buf,
1079                                  SILC_STR_UI_INT(&id),
1080                                  SILC_STR_UI32_STRING_ALLOC(&path),
1081                                  SILC_STR_END);
1082       if (ret < 0)
1083         goto failure;
1084
1085       /* Call monitor */
1086       if (server->monitors & SILC_SFTP_MONITOR_REALPATH && server->monitor) {
1087         mdata.name = path;
1088         (*server->monitor)(sftp, SILC_SFTP_MONITOR_REALPATH, &mdata,
1089                            server->monitor_context);
1090       }
1091
1092       /* Realpath operation */
1093       server->fs->fs->sftp_realpath(server->fs->fs_context, sftp, path,
1094                                     silc_sftp_server_name, SILC_32_TO_PTR(id));
1095
1096       silc_free(path);
1097     }
1098     break;
1099
1100   case SILC_SFTP_EXTENDED:
1101     {
1102       char *request = NULL;
1103       unsigned char *data;
1104       SilcUInt32 data_len;
1105
1106       SILC_LOG_DEBUG(("Extended request"));
1107
1108       ret = silc_buffer_unformat(&buf,
1109                                  SILC_STR_UI_INT(&id),
1110                                  SILC_STR_UI32_STRING_ALLOC(&request),
1111                                  SILC_STR_END);
1112       if (ret < 0)
1113         goto failure;
1114
1115       data_len = 8 + strlen(request);
1116       silc_buffer_pull(&buf, data_len);
1117       ret = silc_buffer_unformat(&buf,
1118                                  SILC_STR_DATA(&data, silc_buffer_len(&buf)),
1119                                  SILC_STR_END);
1120       if (ret < 0)
1121         goto failure;
1122       data_len = silc_buffer_len(&buf);
1123
1124       /* Call monitor */
1125       if (server->monitors & SILC_SFTP_MONITOR_EXTENDED && server->monitor) {
1126         (*server->monitor)(sftp, SILC_SFTP_MONITOR_EXTENDED, &mdata,
1127                            server->monitor_context);
1128       }
1129
1130       /* Extended operation */
1131       server->fs->fs->sftp_extended(server->fs->fs_context, sftp,
1132                                     request, data, data_len,
1133                                     silc_sftp_server_extended,
1134                                     SILC_32_TO_PTR(id));
1135
1136       silc_free(request);
1137     }
1138     break;
1139
1140   default:
1141     break;
1142   }
1143
1144   return;
1145
1146  failure:
1147   silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id);
1148 }