1 /*
2 
3   sftp_client.c
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 2001 - 2007 Pekka Riikonen
8 
9   The contents of this file are subject to one of the Licenses specified
10   in the COPYING file;  You may not use this file except in compliance
11   with the License.
12 
13   The software distributed under the License is distributed on an "AS IS"
14   basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15   KIND, either expressed or implied.  See the COPYING file for more
16   information.
17 
18 */
19 /* $Id$ */
20 
21 #include "silc.h"
22 #include "silcsftp.h"
23 #include "sftp_util.h"
24 
25 /* Request context. Every request will allocate this context and set
26    the correct callback function according the `type' field. */
27 typedef struct SilcSFTPRequestStruct {
28   struct SilcSFTPRequestStruct *next;
29   SilcSFTPStatusCallback status;
30   SilcSFTPHandleCallback handle;
31   SilcSFTPDataCallback data;
32   SilcSFTPNameCallback name;
33   SilcSFTPAttrCallback attr;
34   SilcSFTPExtendedCallback extended;
35   void *context;
36   SilcUInt32 id;
37   SilcSFTPPacket type;
38 } *SilcSFTPRequest;
39 
40 /* SFTP client context */
41 typedef struct {
42   SilcStream stream;
43   SilcSchedule schedule;
44   SilcSFTPVersionCallback version;
45   SilcSFTPErrorCallback error;
46   void *context;
47   SilcList requests;
48   SilcBuffer packet;
49   SilcUInt32 id;
50 } *SilcSFTPClient;
51 
52 /* File handle */
53 struct SilcSFTPHandleStruct {
54   unsigned char *data;
55   SilcUInt32 data_len;
56 };
57 
58 static void silc_sftp_client_receive_process(SilcSFTP context,
59 					     SilcBuffer buffer);
60 
61 /* Creates SilcSFTPHandle and returns pointer to it. The caller must free
62    the context. */
63 
silc_sftp_handle_create(unsigned char * data,SilcUInt32 data_len)64 static SilcSFTPHandle silc_sftp_handle_create(unsigned char *data,
65 					      SilcUInt32 data_len)
66 {
67   SilcSFTPHandle handle;
68 
69   handle = silc_calloc(1, sizeof(*handle));
70   if (!handle)
71     return NULL;
72   handle->data = silc_calloc(data_len, sizeof(*handle->data));
73   if (!handle->data)
74     return NULL;
75   memcpy(handle->data, data, data_len);
76   handle->data_len = data_len;
77 
78   return handle;
79 }
80 
81 /* Deletes the handle indicated by the `handle'. */
82 
silc_sftp_handle_delete(SilcSFTPHandle handle)83 static void silc_sftp_handle_delete(SilcSFTPHandle handle)
84 {
85   silc_free(handle->data);
86   silc_free(handle);
87 }
88 
89 /* Returns the handle data of the `handle' to the `data' pointer. */
90 
silc_sftp_handle_get(SilcSFTPHandle handle,const unsigned char ** data,SilcUInt32 * data_len)91 static void silc_sftp_handle_get(SilcSFTPHandle handle,
92 				 const unsigned char **data,
93 				 SilcUInt32 *data_len)
94 {
95   *data = (const unsigned char *)handle->data;
96   *data_len = handle->data_len;
97 }
98 
99 /* Generic routine to send SFTP packet to the SFTP server. */
100 
silc_sftp_send_packet(SilcSFTPClient sftp,SilcSFTPPacket type,SilcUInt32 len,...)101 static void silc_sftp_send_packet(SilcSFTPClient sftp,
102 				  SilcSFTPPacket type,
103 				  SilcUInt32 len, ...)
104 {
105   SilcBuffer tmp;
106   va_list vp;
107   int ret;
108 
109   va_start(vp, len);
110   tmp = silc_sftp_packet_encode_vp(type, sftp->packet, len, vp);
111   va_end(vp);
112   if (!tmp)
113     return;
114   sftp->packet = tmp;
115 
116   SILC_LOG_HEXDUMP(("SFTP packet to server"), sftp->packet->data,
117 		   silc_buffer_len(sftp->packet));
118 
119   /* Send the packet */
120   while (silc_buffer_len(sftp->packet) > 0) {
121     ret = silc_stream_write(sftp->stream, silc_buffer_data(sftp->packet),
122 			    silc_buffer_len(sftp->packet));
123     if (ret == -2) {
124       SILC_LOG_ERROR(("Error sending SFTP packet type %d", type));
125       sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_NO_CONNECTION,
126 		  sftp->context);
127       silc_buffer_reset(sftp->packet);
128       return;
129     }
130     if (ret == 0) {
131       sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_EOF, sftp->context);
132       silc_buffer_reset(sftp->packet);
133       return;
134     }
135     if (ret == -1)
136       return;
137 
138     silc_buffer_pull(sftp->packet, ret);
139   }
140 
141   /* Clear packet */
142   silc_buffer_reset(sftp->packet);
143 }
144 
145 /* Finds request by request ID. */
146 
silc_sftp_find_request(SilcSFTPClient sftp,SilcUInt32 id)147 static SilcSFTPRequest silc_sftp_find_request(SilcSFTPClient sftp,
148 					      SilcUInt32 id)
149 {
150   SilcSFTPRequest req;
151 
152   SILC_LOG_DEBUG(("Finding request ID: %d", id));
153 
154   silc_list_start(sftp->requests);
155   while ((req = silc_list_get(sftp->requests)) != SILC_LIST_END) {
156     if (req->id == id)
157       return req;
158   }
159 
160   SILC_LOG_DEBUG(("Unknown request ID %d", id));
161 
162   return NULL;
163 }
164 
165 /* Function used to call the request callback indicated by the `req'. The
166    `status' will be sent to the callback function as the status of the
167    operation. The variable argument list includes the status and req->type
168    specific data. */
169 
silc_sftp_call_request(SilcSFTPClient sftp,SilcSFTPRequest req,SilcSFTPPacket type,SilcSFTPStatus status,...)170 static void silc_sftp_call_request(SilcSFTPClient sftp,
171 				   SilcSFTPRequest req,
172 				   SilcSFTPPacket type,
173 				   SilcSFTPStatus status, ...)
174 {
175   va_list vp;
176 
177   SILC_LOG_DEBUG(("Start"));
178 
179   va_start(vp, status);
180 
181   switch (req->type) {
182   case SILC_SFTP_READ:
183     {
184       /* Data returned */
185       unsigned char *data;
186       SilcUInt32 data_len;
187 
188       if (status != SILC_SFTP_STATUS_OK) {
189 	if (req->data)
190 	  (*req->data)((SilcSFTP)sftp, status, NULL, 0, req->context);
191 	break;
192       }
193 
194       data = (unsigned char *)va_arg(vp, unsigned char *);
195       data_len = (SilcUInt32)va_arg(vp, SilcUInt32);
196 
197       if (req->data)
198 	(*req->data)((SilcSFTP)sftp, status, (const unsigned char *)data,
199 		     data_len, req->context);
200     }
201     break;
202 
203   case SILC_SFTP_OPEN:
204   case SILC_SFTP_OPENDIR:
205     {
206       /* Handle returned */
207       SilcSFTPHandle handle;
208       unsigned char *hdata;
209       SilcUInt32 hdata_len;
210 
211       if (status != SILC_SFTP_STATUS_OK) {
212 	if (req->handle)
213 	  (*req->handle)((SilcSFTP)sftp, status, NULL, req->context);
214 	break;
215       }
216 
217       hdata = (unsigned char *)va_arg(vp, unsigned char *);
218       hdata_len = (SilcUInt32)va_arg(vp, SilcUInt32);
219       handle = silc_sftp_handle_create(hdata, hdata_len);
220       if (!handle) {
221 	if (req->handle)
222 	  (*req->handle)((SilcSFTP)sftp, status, NULL, req->context);
223 	break;
224       }
225 
226       if (req->handle)
227 	(*req->handle)((SilcSFTP)sftp, status, handle, req->context);
228     }
229     break;
230 
231   case SILC_SFTP_CLOSE:
232   case SILC_SFTP_WRITE:
233   case SILC_SFTP_REMOVE:
234   case SILC_SFTP_RENAME:
235   case SILC_SFTP_MKDIR:
236   case SILC_SFTP_RMDIR:
237   case SILC_SFTP_SETSTAT:
238   case SILC_SFTP_FSETSTAT:
239   case SILC_SFTP_SYMLINK:
240     {
241       /* Status returned */
242       char *message, *language_tag;
243 
244       message = (char *)va_arg(vp, char *);
245       language_tag = (char *)va_arg(vp, char *);
246 
247       if (req->status)
248 	(*req->status)((SilcSFTP)sftp, status, (const char *)message,
249 		       (const char *)language_tag, req->context);
250     }
251     break;
252 
253   case SILC_SFTP_STAT:
254   case SILC_SFTP_LSTAT:
255   case SILC_SFTP_FSTAT:
256     {
257       /* Attributes returned */
258       SilcSFTPAttributes attr;
259 
260       if (status != SILC_SFTP_STATUS_OK) {
261 	if (req->attr)
262 	  (*req->attr)((SilcSFTP)sftp, status, NULL, req->context);
263 	break;
264       }
265 
266       attr = (SilcSFTPAttributes)va_arg(vp, SilcSFTPAttributes);
267 
268       if (req->attr)
269 	(*req->attr)((SilcSFTP)sftp, status, (const SilcSFTPAttributes)attr,
270 		     req->context);
271     }
272     break;
273 
274   case SILC_SFTP_READDIR:
275   case SILC_SFTP_REALPATH:
276   case SILC_SFTP_READLINK:
277     {
278       /* Name(s) returned */
279       SilcSFTPName name;
280 
281       if (status != SILC_SFTP_STATUS_OK) {
282 	if (req->name)
283 	  (*req->name)((SilcSFTP)sftp, status, NULL, req->context);
284 	break;
285       }
286 
287       name = (SilcSFTPName)va_arg(vp, SilcSFTPName);
288 
289       if (req->name)
290 	(*req->name)((SilcSFTP)sftp, status, name, req->context);
291     }
292     break;
293 
294   case SILC_SFTP_EXTENDED:
295     {
296       /* Extended reply returned */
297       unsigned char *data;
298       SilcUInt32 data_len;
299 
300       if (status != SILC_SFTP_STATUS_OK) {
301 	if (req->extended)
302 	  (*req->extended)((SilcSFTP)sftp, status, NULL, 0, req->context);
303 	break;
304       }
305 
306       data = (unsigned char *)va_arg(vp, unsigned char *);
307       data_len = (SilcUInt32)va_arg(vp, SilcUInt32);
308 
309       if (req->extended)
310 	(*req->extended)((SilcSFTP)sftp, status, (const unsigned char *)data,
311 			 data_len, req->context);
312     }
313     break;
314 
315   default:
316     SILC_LOG_DEBUG(("Unknown request type %d", req->type));
317     break;
318   }
319 
320   /* Remove this request */
321   silc_list_del(sftp->requests, req);
322   silc_free(req);
323 
324   va_end(vp);
325 }
326 
327 /* Handles stream I/O */
328 
silc_sftp_client_io(SilcStream stream,SilcStreamStatus status,void * context)329 static void silc_sftp_client_io(SilcStream stream, SilcStreamStatus status,
330 				void *context)
331 {
332   SilcSFTPClient sftp = context;
333   unsigned char inbuf[65536];
334   SilcBufferStruct packet;
335   int ret;
336 
337   switch (status) {
338   case SILC_STREAM_CAN_READ:
339     SILC_LOG_DEBUG(("Reading data from stream"));
340 
341     /* Read data from stream */
342     ret = silc_stream_read(stream, inbuf, sizeof(inbuf));
343     if (ret <= 0) {
344       if (ret == 0)
345 	sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
346       if (ret == -2)
347 	sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
348       return;
349     }
350 
351     SILC_LOG_DEBUG(("Read %d bytes", ret));
352 
353     /* Now process the SFTP packet */
354     silc_buffer_set(&packet, inbuf, ret);
355     silc_sftp_client_receive_process(context, &packet);
356     break;
357 
358   case SILC_STREAM_CAN_WRITE:
359     if (!silc_buffer_headlen(sftp->packet))
360       return;
361 
362     SILC_LOG_DEBUG(("Writing pending data to stream"));
363 
364     /* Write pending data to stream */
365     silc_buffer_push(sftp->packet, silc_buffer_headlen(sftp->packet));
366     while (silc_buffer_len(sftp->packet) > 0) {
367       ret = silc_stream_write(stream, sftp->packet->data,
368 			      silc_buffer_len(sftp->packet));
369       if (ret == 0) {
370 	sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
371 	silc_buffer_reset(sftp->packet);
372 	return;
373       }
374 
375       if (ret == -2) {
376 	sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
377 	silc_buffer_reset(sftp->packet);
378 	return;
379       }
380 
381       if (ret == -1)
382 	return;
383 
384       /* Wrote data */
385       silc_buffer_pull(sftp->packet, ret);
386     }
387     break;
388 
389   default:
390     break;
391   }
392 }
393 
394 /* Starts SFTP client and returns context for it. */
395 
silc_sftp_client_start(SilcStream stream,SilcSchedule schedule,SilcSFTPVersionCallback version_cb,SilcSFTPErrorCallback error_cb,void * context)396 SilcSFTP silc_sftp_client_start(SilcStream stream,
397 				SilcSchedule schedule,
398 				SilcSFTPVersionCallback version_cb,
399 				SilcSFTPErrorCallback error_cb,
400 				void *context)
401 {
402   SilcSFTPClient sftp;
403 
404   SILC_LOG_DEBUG(("Starting SFTP client"));
405 
406   if (!stream)
407     return NULL;
408 
409   sftp = silc_calloc(1, sizeof(*sftp));
410   if (!sftp)
411     return NULL;
412   sftp->stream = stream;
413   sftp->version = version_cb;
414   sftp->error = error_cb;
415   sftp->context = context;
416   sftp->schedule = schedule;
417   silc_list_init(sftp->requests, struct SilcSFTPRequestStruct, next);
418 
419   /* We handle the stream now */
420   silc_stream_set_notifier(stream, schedule, silc_sftp_client_io, sftp);
421 
422   /* Send the SFTP session initialization to the server */
423   silc_sftp_send_packet(sftp, SILC_SFTP_INIT, 4,
424 			SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
425 			SILC_STR_END);
426 
427   return (SilcSFTP)sftp;
428 }
429 
430 /* Shutdown's the SFTP client.  The caller is responsible of closing
431    the associated socket connection.  The SFTP context is freed and is
432    invalid after this function returns. */
433 
silc_sftp_client_shutdown(SilcSFTP context)434 void silc_sftp_client_shutdown(SilcSFTP context)
435 {
436   SilcSFTPClient sftp = (SilcSFTPClient)context;
437 
438   silc_stream_set_notifier(sftp->stream, sftp->schedule, NULL, NULL);
439   if (sftp->packet)
440     silc_buffer_free(sftp->packet);
441   silc_free(sftp);
442 }
443 
444 /* Function that is called to process the incmoing SFTP packet. */
445 
silc_sftp_client_receive_process(SilcSFTP context,SilcBuffer buffer)446 void silc_sftp_client_receive_process(SilcSFTP context, SilcBuffer buffer)
447 {
448   SilcSFTPClient sftp = (SilcSFTPClient)context;
449   SilcSFTPRequest req;
450   SilcSFTPPacket type;
451   unsigned char *payload = NULL;
452   SilcUInt32 payload_len;
453   int ret;
454   SilcBufferStruct buf;
455   SilcUInt32 id;
456 
457   SILC_LOG_DEBUG(("Process SFTP packet"));
458 
459   /* Parse the packet */
460   type = silc_sftp_packet_decode(buffer, &payload, &payload_len);
461   if (type <= 0)
462     return;
463 
464   silc_buffer_set(&buf, payload, payload_len);
465 
466   switch (type) {
467   case SILC_SFTP_DATA:
468     {
469       unsigned char *data = NULL;
470       SilcUInt32 data_len = 0;
471 
472       SILC_LOG_DEBUG(("Data packet"));
473 
474       ret = silc_buffer_unformat(&buf,
475 				 SILC_STR_UI_INT(&id),
476 				 SILC_STR_UI32_NSTRING(&data, &data_len),
477 				 SILC_STR_END);
478       if (ret < 0)
479 	break;
480 
481       /* Get request */
482       req = silc_sftp_find_request(sftp, id);
483       if (!req)
484 	break;
485 
486       /* Call the callback */
487       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
488 			     data, data_len);
489     }
490     break;
491 
492   case SILC_SFTP_VERSION:
493     {
494       SilcSFTPVersion version;
495 
496       SILC_LOG_DEBUG(("Version packet"));
497 
498       ret = silc_buffer_unformat(&buf,
499 				 SILC_STR_UI_INT(&version),
500 				 SILC_STR_END);
501       if (ret < 0) {
502 	(*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_FAILURE, 0,
503 			 sftp->context);
504 	break;
505       }
506 
507       /* Call the callback */
508       (*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_OK, version,
509 		       sftp->context);
510     }
511     break;
512 
513   case SILC_SFTP_STATUS:
514     {
515       SilcUInt32 status;
516       char *message = NULL, *language_tag = NULL;
517 
518       SILC_LOG_DEBUG(("Status packet"));
519 
520       ret = silc_buffer_unformat(&buf,
521 				 SILC_STR_UI_INT(&id),
522 				 SILC_STR_UI_INT(&status),
523 				 SILC_STR_END);
524       if (ret < 0)
525 	break;
526 
527       if (status != SILC_SFTP_STATUS_OK) {
528 	silc_buffer_pull(&buf, 8);
529 	ret = silc_buffer_unformat(&buf,
530 				   SILC_STR_UI32_STRING_ALLOC(&message),
531 				   SILC_STR_UI32_STRING_ALLOC(&language_tag),
532 				   SILC_STR_END);
533 	if (ret < 0)
534 	  break;
535 
536 	silc_buffer_push(&buf, 8);
537       }
538 
539       /* Get request */
540       req = silc_sftp_find_request(sftp, id);
541       if (!req) {
542 	silc_free(message);
543 	silc_free(language_tag);
544 	break;
545       }
546 
547       /* Call the callback */
548       silc_sftp_call_request(sftp, req, type, status, message, language_tag);
549 
550       silc_free(message);
551       silc_free(language_tag);
552     }
553     break;
554 
555   case SILC_SFTP_HANDLE:
556     {
557       unsigned char *handle = NULL;
558       SilcUInt32 handle_len;
559 
560       SILC_LOG_DEBUG(("Handle packet"));
561 
562       ret = silc_buffer_unformat(&buf,
563 				 SILC_STR_UI_INT(&id),
564 				 SILC_STR_UI32_NSTRING(&handle,
565 						       &handle_len),
566 				 SILC_STR_END);
567       if (ret < 0)
568 	break;
569 
570       /* Get request */
571       req = silc_sftp_find_request(sftp, id);
572       if (!req)
573 	break;
574 
575       /* Call the callback */
576       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
577 			     handle, handle_len);
578     }
579     break;
580 
581   case SILC_SFTP_NAME:
582     {
583       SilcUInt32 count;
584       SilcSFTPName name = NULL;
585 
586       SILC_LOG_DEBUG(("Name packet"));
587 
588       ret = silc_buffer_unformat(&buf,
589 				 SILC_STR_UI_INT(&id),
590 				 SILC_STR_UI_INT(&count),
591 				 SILC_STR_END);
592       if (ret < 0)
593 	break;
594 
595       /* Get request */
596       req = silc_sftp_find_request(sftp, id);
597       if (!req)
598 	break;
599 
600       silc_buffer_pull(&buf, 8);
601       name = silc_sftp_name_decode(count, &buf);
602       if (!name)
603 	break;
604       silc_buffer_push(&buf, 8);
605 
606       /* Call the callback */
607       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, name);
608       silc_sftp_name_free(name);
609     }
610     break;
611 
612   case SILC_SFTP_ATTRS:
613     {
614       SilcSFTPAttributes attr = NULL;
615       unsigned char *data;
616       SilcBufferStruct tmpbuf;
617 
618       SILC_LOG_DEBUG(("Attributes packet"));
619 
620       ret =
621 	silc_buffer_unformat(&buf,
622 			     SILC_STR_UI_INT(&id),
623 			     SILC_STR_DATA(&data, silc_buffer_len(&buf) - 4),
624 			     SILC_STR_END);
625       if (ret < 0)
626 	break;
627 
628       /* Get request */
629       req = silc_sftp_find_request(sftp, id);
630       if (!req)
631 	break;
632 
633       silc_buffer_set(&tmpbuf, data, silc_buffer_len(&buf) - 4);
634       attr = silc_sftp_attr_decode(&tmpbuf);
635       if (!attr)
636 	break;
637 
638       /* Call the callback */
639       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, attr);
640     }
641     break;
642 
643   case SILC_SFTP_EXTENDED_REPLY:
644     {
645       unsigned char *data = NULL;
646 
647       SILC_LOG_DEBUG(("Extended reply packet"));
648 
649       ret = silc_buffer_unformat(&buf,
650 				 SILC_STR_UI_INT(&id),
651 				 SILC_STR_DATA(&data,
652 					       silc_buffer_len(&buf) - 4),
653 				 SILC_STR_END);
654       if (ret < 0)
655 	break;
656 
657       /* Get request */
658       req = silc_sftp_find_request(sftp, id);
659       if (!req)
660 	break;
661 
662       /* Call the callback */
663       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
664 			     data, silc_buffer_len(&buf) - 4);
665     }
666     break;
667 
668   default:
669     break;
670   }
671 }
672 
silc_sftp_open(SilcSFTP sftp,const char * filename,SilcSFTPFileOperation pflags,SilcSFTPAttributes attrs,SilcSFTPHandleCallback callback,void * context)673 void silc_sftp_open(SilcSFTP sftp,
674 		    const char *filename,
675 		    SilcSFTPFileOperation pflags,
676 		    SilcSFTPAttributes attrs,
677 		    SilcSFTPHandleCallback callback,
678 		    void *context)
679 {
680   SilcSFTPClient client = (SilcSFTPClient)sftp;
681   SilcSFTPRequest req;
682   SilcBuffer attrs_buf;
683   SilcUInt32 len = 0;
684 
685   SILC_LOG_DEBUG(("Open request"));
686 
687   req = silc_calloc(1, sizeof(*req));
688   if (!req)
689     return;
690   req->id = client->id++;
691   req->type = SILC_SFTP_OPEN;
692   req->handle = callback;
693   req->context = context;
694   silc_list_add(client->requests, req);
695 
696   attrs_buf = silc_sftp_attr_encode(attrs);
697   if (!attrs_buf)
698     return;
699   len = 4 + 4 + strlen(filename) + 4 + silc_buffer_len(attrs_buf);
700 
701   silc_sftp_send_packet(client, req->type, len,
702 			SILC_STR_UI_INT(req->id),
703 			SILC_STR_UI_INT(strlen(filename)),
704 			SILC_STR_UI32_STRING(filename),
705 			SILC_STR_UI_INT(pflags),
706 			SILC_STR_UI_XNSTRING(attrs_buf->data,
707 					     silc_buffer_len(attrs_buf)),
708 			SILC_STR_END);
709 
710   silc_buffer_free(attrs_buf);
711 }
712 
silc_sftp_close(SilcSFTP sftp,SilcSFTPHandle handle,SilcSFTPStatusCallback callback,void * context)713 void silc_sftp_close(SilcSFTP sftp,
714 		     SilcSFTPHandle handle,
715 		     SilcSFTPStatusCallback callback,
716 		     void *context)
717 {
718   SilcSFTPClient client = (SilcSFTPClient)sftp;
719   SilcSFTPRequest req;
720   SilcUInt32 len = 0;
721   const unsigned char *hdata;
722   SilcUInt32 hdata_len;
723 
724   SILC_LOG_DEBUG(("Close request"));
725 
726   req = silc_calloc(1, sizeof(*req));
727   if (!req)
728     return;
729   req->id = client->id++;
730   req->type = SILC_SFTP_CLOSE;
731   req->status = callback;
732   req->context = context;
733   silc_list_add(client->requests, req);
734 
735   silc_sftp_handle_get(handle, &hdata, &hdata_len);
736   len = 4 + 4 + hdata_len;
737 
738   silc_sftp_send_packet(client, req->type, len,
739 			SILC_STR_UI_INT(req->id),
740 			SILC_STR_UI_INT(hdata_len),
741 			SILC_STR_UI_XNSTRING(hdata, hdata_len),
742 			SILC_STR_END);
743   silc_sftp_handle_delete(handle);
744 }
745 
silc_sftp_read(SilcSFTP sftp,SilcSFTPHandle handle,SilcUInt64 offset,SilcUInt32 len,SilcSFTPDataCallback callback,void * context)746 void silc_sftp_read(SilcSFTP sftp,
747 		    SilcSFTPHandle handle,
748 		    SilcUInt64 offset,
749 		    SilcUInt32 len,
750 		    SilcSFTPDataCallback callback,
751 		    void *context)
752 {
753   SilcSFTPClient client = (SilcSFTPClient)sftp;
754   SilcSFTPRequest req;
755   SilcUInt32 len2 = 0;
756   const unsigned char *hdata;
757   SilcUInt32 hdata_len;
758 
759   SILC_LOG_DEBUG(("Read request"));
760 
761   req = silc_calloc(1, sizeof(*req));
762   if (!req)
763     return;
764   req->id = client->id++;
765   req->type = SILC_SFTP_READ;
766   req->data = callback;
767   req->context = context;
768   silc_list_add(client->requests, req);
769 
770   silc_sftp_handle_get(handle, &hdata, &hdata_len);
771   len2 = 4 + 4 + hdata_len + 8 + 4;
772 
773   silc_sftp_send_packet(client, req->type, len2,
774 			SILC_STR_UI_INT(req->id),
775 			SILC_STR_UI_INT(hdata_len),
776 			SILC_STR_UI_XNSTRING(hdata, hdata_len),
777 			SILC_STR_UI_INT64(offset),
778 			SILC_STR_UI_INT(len),
779 			SILC_STR_END);
780 }
781 
silc_sftp_write(SilcSFTP sftp,SilcSFTPHandle handle,SilcUInt64 offset,const unsigned char * data,SilcUInt32 data_len,SilcSFTPStatusCallback callback,void * context)782 void silc_sftp_write(SilcSFTP sftp,
783 		     SilcSFTPHandle handle,
784 		     SilcUInt64 offset,
785 		     const unsigned char *data,
786 		     SilcUInt32 data_len,
787 		     SilcSFTPStatusCallback callback,
788 		     void *context)
789 {
790   SilcSFTPClient client = (SilcSFTPClient)sftp;
791   SilcSFTPRequest req;
792   SilcUInt32 len = 0;
793   const unsigned char *hdata;
794   SilcUInt32 hdata_len;
795 
796   SILC_LOG_DEBUG(("Write request"));
797 
798   req = silc_calloc(1, sizeof(*req));
799   if (!req)
800     return;
801   req->id = client->id++;
802   req->type = SILC_SFTP_WRITE;
803   req->status = callback;
804   req->context = context;
805   silc_list_add(client->requests, req);
806 
807   silc_sftp_handle_get(handle, &hdata, &hdata_len);
808   len = 4 + 4 + hdata_len + 8 + 4 + data_len;
809 
810   silc_sftp_send_packet(client, req->type, len,
811 			SILC_STR_UI_INT(req->id),
812 			SILC_STR_UI_INT(hdata_len),
813 			SILC_STR_UI_XNSTRING(hdata, hdata_len),
814 			SILC_STR_UI_INT64(offset),
815 			SILC_STR_UI_INT(data_len),
816 			SILC_STR_UI_XNSTRING(data, data_len),
817 			SILC_STR_END);
818 }
819 
silc_sftp_remove(SilcSFTP sftp,const char * filename,SilcSFTPStatusCallback callback,void * context)820 void silc_sftp_remove(SilcSFTP sftp,
821 		      const char *filename,
822 		      SilcSFTPStatusCallback callback,
823 		      void *context)
824 {
825   SilcSFTPClient client = (SilcSFTPClient)sftp;
826   SilcSFTPRequest req;
827   SilcUInt32 len = 0;
828 
829   SILC_LOG_DEBUG(("Remove request"));
830 
831   req = silc_calloc(1, sizeof(*req));
832   if (!req)
833     return;
834   req->id = client->id++;
835   req->type = SILC_SFTP_REMOVE;
836   req->status = callback;
837   req->context = context;
838   silc_list_add(client->requests, req);
839 
840   len = 4 + 4 + strlen(filename);
841 
842   silc_sftp_send_packet(client, req->type, len,
843 			SILC_STR_UI_INT(req->id),
844 			SILC_STR_UI_INT(strlen(filename)),
845 			SILC_STR_UI32_STRING(filename),
846 			SILC_STR_END);
847 }
848 
silc_sftp_rename(SilcSFTP sftp,const char * oldname,const char * newname,SilcSFTPStatusCallback callback,void * context)849 void silc_sftp_rename(SilcSFTP sftp,
850 		      const char *oldname,
851 		      const char *newname,
852 		      SilcSFTPStatusCallback callback,
853 		      void *context)
854 {
855   SilcSFTPClient client = (SilcSFTPClient)sftp;
856   SilcSFTPRequest req;
857   SilcUInt32 len = 0;
858 
859   SILC_LOG_DEBUG(("Rename request"));
860 
861   req = silc_calloc(1, sizeof(*req));
862   if (!req)
863     return;
864   req->id = client->id++;
865   req->type = SILC_SFTP_RENAME;
866   req->status = callback;
867   req->context = context;
868   silc_list_add(client->requests, req);
869 
870   len = 4 + 4 + strlen(oldname) + 4 + strlen(newname);
871 
872   silc_sftp_send_packet(client, req->type, len,
873 			SILC_STR_UI_INT(req->id),
874 			SILC_STR_UI_INT(strlen(oldname)),
875 			SILC_STR_UI32_STRING(oldname),
876 			SILC_STR_UI_INT(strlen(newname)),
877 			SILC_STR_UI32_STRING(newname),
878 			SILC_STR_END);
879 }
880 
silc_sftp_mkdir(SilcSFTP sftp,const char * path,SilcSFTPAttributes attrs,SilcSFTPStatusCallback callback,void * context)881 void silc_sftp_mkdir(SilcSFTP sftp,
882 		     const char *path,
883 		     SilcSFTPAttributes attrs,
884 		     SilcSFTPStatusCallback callback,
885 		     void *context)
886 {
887   SilcSFTPClient client = (SilcSFTPClient)sftp;
888   SilcSFTPRequest req;
889   SilcUInt32 len = 0;
890   SilcBuffer attrs_buf;
891 
892   SILC_LOG_DEBUG(("Mkdir request"));
893 
894   req = silc_calloc(1, sizeof(*req));
895   if (!req)
896     return;
897   req->id = client->id++;
898   req->type = SILC_SFTP_MKDIR;
899   req->status = callback;
900   req->context = context;
901   silc_list_add(client->requests, req);
902 
903   attrs_buf = silc_sftp_attr_encode(attrs);
904   if (!attrs_buf)
905     return;
906   len = 4 + 4 + strlen(path) + silc_buffer_len(attrs_buf);
907 
908   silc_sftp_send_packet(client, req->type, len,
909 			SILC_STR_UI_INT(req->id),
910 			SILC_STR_UI_INT(strlen(path)),
911 			SILC_STR_UI32_STRING(path),
912 			SILC_STR_UI_XNSTRING(attrs_buf->data,
913 					     silc_buffer_len(attrs_buf)),
914 			SILC_STR_END);
915 
916   silc_buffer_free(attrs_buf);
917 }
918 
silc_sftp_rmdir(SilcSFTP sftp,const char * path,SilcSFTPStatusCallback callback,void * context)919 void silc_sftp_rmdir(SilcSFTP sftp,
920 		     const char *path,
921 		     SilcSFTPStatusCallback callback,
922 		     void *context)
923 {
924   SilcSFTPClient client = (SilcSFTPClient)sftp;
925   SilcSFTPRequest req;
926   SilcUInt32 len = 0;
927 
928   SILC_LOG_DEBUG(("Rmdir request"));
929 
930   req = silc_calloc(1, sizeof(*req));
931   if (!req)
932     return;
933   req->id = client->id++;
934   req->type = SILC_SFTP_RMDIR;
935   req->status = callback;
936   req->context = context;
937   silc_list_add(client->requests, req);
938 
939   len = 4 + 4 + strlen(path);
940 
941   silc_sftp_send_packet(client, req->type, len,
942 			SILC_STR_UI_INT(req->id),
943 			SILC_STR_UI_INT(strlen(path)),
944 			SILC_STR_UI32_STRING(path),
945 			SILC_STR_END);
946 }
947 
silc_sftp_opendir(SilcSFTP sftp,const char * path,SilcSFTPHandleCallback callback,void * context)948 void silc_sftp_opendir(SilcSFTP sftp,
949 		       const char *path,
950 		       SilcSFTPHandleCallback callback,
951 		       void *context)
952 {
953   SilcSFTPClient client = (SilcSFTPClient)sftp;
954   SilcSFTPRequest req;
955   SilcUInt32 len = 0;
956 
957   SILC_LOG_DEBUG(("Opendir request"));
958 
959   req = silc_calloc(1, sizeof(*req));
960   if (!req)
961     return;
962   req->id = client->id++;
963   req->type = SILC_SFTP_OPENDIR;
964   req->handle = callback;
965   req->context = context;
966   silc_list_add(client->requests, req);
967 
968   len = 4 + 4 + strlen(path);
969 
970   silc_sftp_send_packet(client, req->type, len,
971 			SILC_STR_UI_INT(req->id),
972 			SILC_STR_UI_INT(strlen(path)),
973 			SILC_STR_UI32_STRING(path),
974 			SILC_STR_END);
975 }
976 
silc_sftp_readdir(SilcSFTP sftp,SilcSFTPHandle handle,SilcSFTPNameCallback callback,void * context)977 void silc_sftp_readdir(SilcSFTP sftp,
978 		       SilcSFTPHandle handle,
979 		       SilcSFTPNameCallback callback,
980 		       void *context)
981 {
982   SilcSFTPClient client = (SilcSFTPClient)sftp;
983   SilcSFTPRequest req;
984   SilcUInt32 len = 0;
985   const unsigned char *hdata;
986   SilcUInt32 hdata_len;
987 
988   SILC_LOG_DEBUG(("Readdir request"));
989 
990   req = silc_calloc(1, sizeof(*req));
991   if (!req)
992     return;
993   req->id = client->id++;
994   req->type = SILC_SFTP_READDIR;
995   req->name = callback;
996   req->context = context;
997   silc_list_add(client->requests, req);
998 
999   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1000   len = 4 + 4 + hdata_len;
1001 
1002   silc_sftp_send_packet(client, req->type, len,
1003 			SILC_STR_UI_INT(req->id),
1004 			SILC_STR_UI_INT(hdata_len),
1005 			SILC_STR_UI_XNSTRING(hdata, hdata_len),
1006 			SILC_STR_END);
1007 }
1008 
silc_sftp_stat(SilcSFTP sftp,const char * path,SilcSFTPAttrCallback callback,void * context)1009 void silc_sftp_stat(SilcSFTP sftp,
1010 		    const char *path,
1011 		    SilcSFTPAttrCallback callback,
1012 		    void *context)
1013 {
1014   SilcSFTPClient client = (SilcSFTPClient)sftp;
1015   SilcSFTPRequest req;
1016   SilcUInt32 len = 0;
1017 
1018   SILC_LOG_DEBUG(("Stat request"));
1019 
1020   req = silc_calloc(1, sizeof(*req));
1021   if (!req)
1022     return;
1023   req->id = client->id++;
1024   req->type = SILC_SFTP_STAT;
1025   req->attr = callback;
1026   req->context = context;
1027   silc_list_add(client->requests, req);
1028 
1029   len = 4 + 4 + strlen(path);
1030 
1031   silc_sftp_send_packet(client, req->type, len,
1032 			SILC_STR_UI_INT(req->id),
1033 			SILC_STR_UI_INT(strlen(path)),
1034 			SILC_STR_UI32_STRING(path),
1035 			SILC_STR_END);
1036 }
1037 
silc_sftp_lstat(SilcSFTP sftp,const char * path,SilcSFTPAttrCallback callback,void * context)1038 void silc_sftp_lstat(SilcSFTP sftp,
1039 		     const char *path,
1040 		     SilcSFTPAttrCallback callback,
1041 		     void *context)
1042 {
1043   SilcSFTPClient client = (SilcSFTPClient)sftp;
1044   SilcSFTPRequest req;
1045   SilcUInt32 len = 0;
1046 
1047   SILC_LOG_DEBUG(("Lstat request"));
1048 
1049   req = silc_calloc(1, sizeof(*req));
1050   if (!req)
1051     return;
1052   req->id = client->id++;
1053   req->type = SILC_SFTP_LSTAT;
1054   req->attr = callback;
1055   req->context = context;
1056   silc_list_add(client->requests, req);
1057 
1058   len = 4 + 4 + strlen(path);
1059 
1060   silc_sftp_send_packet(client, req->type, len,
1061 			SILC_STR_UI_INT(req->id),
1062 			SILC_STR_UI_INT(strlen(path)),
1063 			SILC_STR_UI32_STRING(path),
1064 			SILC_STR_END);
1065 }
1066 
silc_sftp_fstat(SilcSFTP sftp,SilcSFTPHandle handle,SilcSFTPAttrCallback callback,void * context)1067 void silc_sftp_fstat(SilcSFTP sftp,
1068 		     SilcSFTPHandle handle,
1069 		     SilcSFTPAttrCallback callback,
1070 		     void *context)
1071 {
1072   SilcSFTPClient client = (SilcSFTPClient)sftp;
1073   SilcSFTPRequest req;
1074   SilcUInt32 len = 0;
1075   const unsigned char *hdata;
1076   SilcUInt32 hdata_len;
1077 
1078   SILC_LOG_DEBUG(("Fstat request"));
1079 
1080   req = silc_calloc(1, sizeof(*req));
1081   if (!req)
1082     return;
1083   req->id = client->id++;
1084   req->type = SILC_SFTP_FSTAT;
1085   req->attr = callback;
1086   req->context = context;
1087   silc_list_add(client->requests, req);
1088 
1089   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1090   len = 4 + 4 + hdata_len;
1091 
1092   silc_sftp_send_packet(client, req->type, len,
1093 			SILC_STR_UI_INT(req->id),
1094 			SILC_STR_UI_INT(hdata_len),
1095 			SILC_STR_UI_XNSTRING(hdata, hdata_len),
1096 			SILC_STR_END);
1097 }
1098 
silc_sftp_setstat(SilcSFTP sftp,const char * path,SilcSFTPAttributes attrs,SilcSFTPStatusCallback callback,void * context)1099 void silc_sftp_setstat(SilcSFTP sftp,
1100 		       const char *path,
1101 		       SilcSFTPAttributes attrs,
1102 		       SilcSFTPStatusCallback callback,
1103 		       void *context)
1104 {
1105   SilcSFTPClient client = (SilcSFTPClient)sftp;
1106   SilcSFTPRequest req;
1107   SilcUInt32 len = 0;
1108   SilcBuffer attrs_buf;
1109 
1110   SILC_LOG_DEBUG(("Setstat request"));
1111 
1112   req = silc_calloc(1, sizeof(*req));
1113   if (!req)
1114     return;
1115   req->id = client->id++;
1116   req->type = SILC_SFTP_SETSTAT;
1117   req->status = callback;
1118   req->context = context;
1119   silc_list_add(client->requests, req);
1120 
1121   attrs_buf = silc_sftp_attr_encode(attrs);
1122   if (!attrs_buf)
1123     return;
1124   len = 4 + 4 + strlen(path) + silc_buffer_len(attrs_buf);
1125 
1126   silc_sftp_send_packet(client, req->type, len,
1127 			SILC_STR_UI_INT(req->id),
1128 			SILC_STR_UI_INT(strlen(path)),
1129 			SILC_STR_UI32_STRING(path),
1130 			SILC_STR_UI_XNSTRING(attrs_buf->data,
1131 					     silc_buffer_len(attrs_buf)),
1132 			SILC_STR_END);
1133 
1134   silc_buffer_free(attrs_buf);
1135 }
1136 
silc_sftp_fsetstat(SilcSFTP sftp,SilcSFTPHandle handle,SilcSFTPAttributes attrs,SilcSFTPStatusCallback callback,void * context)1137 void silc_sftp_fsetstat(SilcSFTP sftp,
1138 			SilcSFTPHandle handle,
1139 			SilcSFTPAttributes attrs,
1140 			SilcSFTPStatusCallback callback,
1141 			void *context)
1142 {
1143   SilcSFTPClient client = (SilcSFTPClient)sftp;
1144   SilcSFTPRequest req;
1145   SilcUInt32 len = 0;
1146   SilcBuffer attrs_buf;
1147   const unsigned char *hdata;
1148   SilcUInt32 hdata_len;
1149 
1150   SILC_LOG_DEBUG(("Fsetstat request"));
1151 
1152   req = silc_calloc(1, sizeof(*req));
1153   if (!req)
1154     return;
1155   req->id = client->id++;
1156   req->type = SILC_SFTP_FSETSTAT;
1157   req->status = callback;
1158   req->context = context;
1159   silc_list_add(client->requests, req);
1160 
1161   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1162   attrs_buf = silc_sftp_attr_encode(attrs);
1163   if (!attrs_buf)
1164     return;
1165   len = 4 + 4 + hdata_len + silc_buffer_len(attrs_buf);
1166 
1167   silc_sftp_send_packet(client, req->type, len,
1168 			SILC_STR_UI_INT(req->id),
1169 			SILC_STR_UI_INT(hdata_len),
1170 			SILC_STR_UI_XNSTRING(hdata, hdata_len),
1171 			SILC_STR_UI_XNSTRING(attrs_buf->data,
1172 					     silc_buffer_len(attrs_buf)),
1173 			SILC_STR_END);
1174 
1175   silc_buffer_free(attrs_buf);
1176 }
1177 
silc_sftp_readlink(SilcSFTP sftp,const char * path,SilcSFTPNameCallback callback,void * context)1178 void silc_sftp_readlink(SilcSFTP sftp,
1179 			const char *path,
1180 			SilcSFTPNameCallback callback,
1181 			void *context)
1182 {
1183   SilcSFTPClient client = (SilcSFTPClient)sftp;
1184   SilcSFTPRequest req;
1185   SilcUInt32 len = 0;
1186 
1187   SILC_LOG_DEBUG(("Readlink request"));
1188 
1189   req = silc_calloc(1, sizeof(*req));
1190   if (!req)
1191     return;
1192   req->id = client->id++;
1193   req->type = SILC_SFTP_READLINK;
1194   req->name = callback;
1195   req->context = context;
1196   silc_list_add(client->requests, req);
1197 
1198   len = 4 + 4 + strlen(path);
1199 
1200   silc_sftp_send_packet(client, req->type, len,
1201 			SILC_STR_UI_INT(req->id),
1202 			SILC_STR_UI_INT(strlen(path)),
1203 			SILC_STR_UI32_STRING(path),
1204 			SILC_STR_END);
1205 }
1206 
silc_sftp_symlink(SilcSFTP sftp,const char * linkpath,const char * targetpath,SilcSFTPStatusCallback callback,void * context)1207 void silc_sftp_symlink(SilcSFTP sftp,
1208 		       const char *linkpath,
1209 		       const char *targetpath,
1210 		       SilcSFTPStatusCallback callback,
1211 		       void *context)
1212 {
1213   SilcSFTPClient client = (SilcSFTPClient)sftp;
1214   SilcSFTPRequest req;
1215   SilcUInt32 len = 0;
1216 
1217   SILC_LOG_DEBUG(("Symlink request"));
1218 
1219   req = silc_calloc(1, sizeof(*req));
1220   if (!req)
1221     return;
1222   req->id = client->id++;
1223   req->type = SILC_SFTP_SYMLINK;
1224   req->status = callback;
1225   req->context = context;
1226   silc_list_add(client->requests, req);
1227 
1228   len = 4 + 4 + strlen(linkpath) + 4 + strlen(targetpath);
1229 
1230   silc_sftp_send_packet(client, req->type, len,
1231 			SILC_STR_UI_INT(req->id),
1232 			SILC_STR_UI_INT(strlen(linkpath)),
1233 			SILC_STR_UI32_STRING(linkpath),
1234 			SILC_STR_UI_INT(strlen(targetpath)),
1235 			SILC_STR_UI32_STRING(targetpath),
1236 			SILC_STR_END);
1237 }
1238 
silc_sftp_realpath(SilcSFTP sftp,const char * path,SilcSFTPNameCallback callback,void * context)1239 void silc_sftp_realpath(SilcSFTP sftp,
1240 			const char *path,
1241 			SilcSFTPNameCallback callback,
1242 			void *context)
1243 {
1244   SilcSFTPClient client = (SilcSFTPClient)sftp;
1245   SilcSFTPRequest req;
1246   SilcUInt32 len = 0;
1247 
1248   SILC_LOG_DEBUG(("Realpath request"));
1249 
1250   req = silc_calloc(1, sizeof(*req));
1251   if (!req)
1252     return;
1253   req->id = client->id++;
1254   req->type = SILC_SFTP_REALPATH;
1255   req->name = callback;
1256   req->context = context;
1257   silc_list_add(client->requests, req);
1258 
1259   len = 4 + 4 + strlen(path);
1260 
1261   silc_sftp_send_packet(client, req->type, len,
1262 			SILC_STR_UI_INT(req->id),
1263 			SILC_STR_UI_INT(strlen(path)),
1264 			SILC_STR_UI32_STRING(path),
1265 			SILC_STR_END);
1266 }
1267 
silc_sftp_extended(SilcSFTP sftp,const char * request,const unsigned char * data,SilcUInt32 data_len,SilcSFTPExtendedCallback callback,void * context)1268 void silc_sftp_extended(SilcSFTP sftp,
1269 			const char *request,
1270 			const unsigned char *data,
1271 			SilcUInt32 data_len,
1272 			SilcSFTPExtendedCallback callback,
1273 			void *context)
1274 {
1275   SilcSFTPClient client = (SilcSFTPClient)sftp;
1276   SilcSFTPRequest req;
1277   SilcUInt32 len = 0;
1278 
1279   SILC_LOG_DEBUG(("Extended request"));
1280 
1281   req = silc_calloc(1, sizeof(*req));
1282   if (!req)
1283     return;
1284   req->id = client->id++;
1285   req->type = SILC_SFTP_WRITE;
1286   req->extended = callback;
1287   req->context = context;
1288   silc_list_add(client->requests, req);
1289 
1290   len = 4 + 4 + strlen(request) + data_len;
1291 
1292   silc_sftp_send_packet(client, req->type, len,
1293 			SILC_STR_UI_INT(req->id),
1294 			SILC_STR_UI_INT(strlen(request)),
1295 			SILC_STR_UI32_STRING(request),
1296 			SILC_STR_UI_XNSTRING(data, data_len),
1297 			SILC_STR_END);
1298 }
1299