Deleted Added
full compact
sftp-server.c (65668) sftp-server.c (76259)
1/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.

--- 8 unchanged lines hidden (view full) ---

17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24#include "includes.h"
1/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.

--- 8 unchanged lines hidden (view full) ---

17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24#include "includes.h"
25RCSID("$OpenBSD: sftp-server.c,v 1.6 2000/09/07 20:27:53 deraadt Exp $");
25RCSID("$OpenBSD: sftp-server.c,v 1.25 2001/04/05 10:42:53 markus Exp $");
26
26
27#include "ssh.h"
28#include "buffer.h"
29#include "bufaux.h"
30#include "getput.h"
27#include "buffer.h"
28#include "bufaux.h"
29#include "getput.h"
30#include "log.h"
31#include "xmalloc.h"
32
31#include "xmalloc.h"
32
33/* version */
34#define SSH_FILEXFER_VERSION 2
33#include "sftp.h"
34#include "sftp-common.h"
35
35
36/* client to server */
37#define SSH_FXP_INIT 1
38#define SSH_FXP_OPEN 3
39#define SSH_FXP_CLOSE 4
40#define SSH_FXP_READ 5
41#define SSH_FXP_WRITE 6
42#define SSH_FXP_LSTAT 7
43#define SSH_FXP_FSTAT 8
44#define SSH_FXP_SETSTAT 9
45#define SSH_FXP_FSETSTAT 10
46#define SSH_FXP_OPENDIR 11
47#define SSH_FXP_READDIR 12
48#define SSH_FXP_REMOVE 13
49#define SSH_FXP_MKDIR 14
50#define SSH_FXP_RMDIR 15
51#define SSH_FXP_REALPATH 16
52#define SSH_FXP_STAT 17
53#define SSH_FXP_RENAME 18
54
55/* server to client */
56#define SSH_FXP_VERSION 2
57#define SSH_FXP_STATUS 101
58#define SSH_FXP_HANDLE 102
59#define SSH_FXP_DATA 103
60#define SSH_FXP_NAME 104
61#define SSH_FXP_ATTRS 105
62
63/* portable open modes */
64#define SSH_FXF_READ 0x01
65#define SSH_FXF_WRITE 0x02
66#define SSH_FXF_APPEND 0x04
67#define SSH_FXF_CREAT 0x08
68#define SSH_FXF_TRUNC 0x10
69#define SSH_FXF_EXCL 0x20
70
71/* attributes */
72#define SSH_FXA_HAVE_SIZE 0x01
73#define SSH_FXA_HAVE_UGID 0x02
74#define SSH_FXA_HAVE_PERM 0x04
75#define SSH_FXA_HAVE_TIME 0x08
76
77/* status messages */
78#define SSH_FX_OK 0x00
79#define SSH_FX_EOF 0x01
80#define SSH_FX_NO_SUCH_FILE 0x02
81#define SSH_FX_PERMISSION_DENIED 0x03
82#define SSH_FX_FAILURE 0x04
83#define SSH_FX_BAD_MESSAGE 0x05
84#define SSH_FX_NO_CONNECTION 0x06
85#define SSH_FX_CONNECTION_LOST 0x07
86
87
88/* helper */
36/* helper */
37#define get_int64() buffer_get_int64(&iqueue);
89#define get_int() buffer_get_int(&iqueue);
90#define get_string(lenp) buffer_get_string(&iqueue, lenp);
38#define get_int() buffer_get_int(&iqueue);
39#define get_string(lenp) buffer_get_string(&iqueue, lenp);
91#define TRACE log
40#define TRACE debug
92
93/* input and output queue */
94Buffer iqueue;
95Buffer oqueue;
96
41
42/* input and output queue */
43Buffer iqueue;
44Buffer oqueue;
45
46/* Version of client */
47int version;
48
97/* portable attibutes, etc. */
98
49/* portable attibutes, etc. */
50
99typedef struct Attrib Attrib;
100typedef struct Stat Stat;
101
51typedef struct Stat Stat;
52
102struct Attrib
103{
104 u_int32_t flags;
105 u_int32_t size_high;
106 u_int32_t size_low;
107 u_int64_t size;
108 u_int32_t uid;
109 u_int32_t gid;
110 u_int32_t perm;
111 u_int32_t atime;
112 u_int32_t mtime;
113};
114
115struct Stat
116{
53struct Stat {
117 char *name;
118 char *long_name;
119 Attrib attrib;
120};
121
122int
123errno_to_portable(int unixerrno)
124{
125 int ret = 0;
54 char *name;
55 char *long_name;
56 Attrib attrib;
57};
58
59int
60errno_to_portable(int unixerrno)
61{
62 int ret = 0;
63
126 switch (unixerrno) {
127 case 0:
64 switch (unixerrno) {
65 case 0:
128 ret = SSH_FX_OK;
66 ret = SSH2_FX_OK;
129 break;
130 case ENOENT:
131 case ENOTDIR:
132 case EBADF:
133 case ELOOP:
67 break;
68 case ENOENT:
69 case ENOTDIR:
70 case EBADF:
71 case ELOOP:
134 ret = SSH_FX_NO_SUCH_FILE;
72 ret = SSH2_FX_NO_SUCH_FILE;
135 break;
136 case EPERM:
137 case EACCES:
138 case EFAULT:
73 break;
74 case EPERM:
75 case EACCES:
76 case EFAULT:
139 ret = SSH_FX_PERMISSION_DENIED;
77 ret = SSH2_FX_PERMISSION_DENIED;
140 break;
141 case ENAMETOOLONG:
142 case EINVAL:
78 break;
79 case ENAMETOOLONG:
80 case EINVAL:
143 ret = SSH_FX_BAD_MESSAGE;
81 ret = SSH2_FX_BAD_MESSAGE;
144 break;
145 default:
82 break;
83 default:
146 ret = SSH_FX_FAILURE;
84 ret = SSH2_FX_FAILURE;
147 break;
148 }
149 return ret;
150}
151
152int
153flags_from_portable(int pflags)
154{
155 int flags = 0;
85 break;
86 }
87 return ret;
88}
89
90int
91flags_from_portable(int pflags)
92{
93 int flags = 0;
156 if (pflags & SSH_FXF_READ &&
157 pflags & SSH_FXF_WRITE) {
94
95 if ((pflags & SSH2_FXF_READ) &&
96 (pflags & SSH2_FXF_WRITE)) {
158 flags = O_RDWR;
97 flags = O_RDWR;
159 } else if (pflags & SSH_FXF_READ) {
98 } else if (pflags & SSH2_FXF_READ) {
160 flags = O_RDONLY;
99 flags = O_RDONLY;
161 } else if (pflags & SSH_FXF_WRITE) {
100 } else if (pflags & SSH2_FXF_WRITE) {
162 flags = O_WRONLY;
163 }
101 flags = O_WRONLY;
102 }
164 if (pflags & SSH_FXF_CREAT)
103 if (pflags & SSH2_FXF_CREAT)
165 flags |= O_CREAT;
104 flags |= O_CREAT;
166 if (pflags & SSH_FXF_TRUNC)
105 if (pflags & SSH2_FXF_TRUNC)
167 flags |= O_TRUNC;
106 flags |= O_TRUNC;
168 if (pflags & SSH_FXF_EXCL)
107 if (pflags & SSH2_FXF_EXCL)
169 flags |= O_EXCL;
170 return flags;
171}
172
108 flags |= O_EXCL;
109 return flags;
110}
111
173void
174attrib_clear(Attrib *a)
175{
176 a->flags = 0;
177 a->size_low = 0;
178 a->size_high = 0;
179 a->size = 0;
180 a->uid = 0;
181 a->gid = 0;
182 a->perm = 0;
183 a->atime = 0;
184 a->mtime = 0;
185}
186
187Attrib *
112Attrib *
188decode_attrib(Buffer *b)
189{
190 static Attrib a;
191 attrib_clear(&a);
192 a.flags = buffer_get_int(b);
193 if (a.flags & SSH_FXA_HAVE_SIZE) {
194 a.size_high = buffer_get_int(b);
195 a.size_low = buffer_get_int(b);
196 a.size = (((u_int64_t) a.size_high) << 32) + a.size_low;
197 }
198 if (a.flags & SSH_FXA_HAVE_UGID) {
199 a.uid = buffer_get_int(b);
200 a.gid = buffer_get_int(b);
201 }
202 if (a.flags & SSH_FXA_HAVE_PERM) {
203 a.perm = buffer_get_int(b);
204 }
205 if (a.flags & SSH_FXA_HAVE_TIME) {
206 a.atime = buffer_get_int(b);
207 a.mtime = buffer_get_int(b);
208 }
209 return &a;
210}
211
212void
213encode_attrib(Buffer *b, Attrib *a)
214{
215 buffer_put_int(b, a->flags);
216 if (a->flags & SSH_FXA_HAVE_SIZE) {
217 buffer_put_int(b, a->size_high);
218 buffer_put_int(b, a->size_low);
219 }
220 if (a->flags & SSH_FXA_HAVE_UGID) {
221 buffer_put_int(b, a->uid);
222 buffer_put_int(b, a->gid);
223 }
224 if (a->flags & SSH_FXA_HAVE_PERM) {
225 buffer_put_int(b, a->perm);
226 }
227 if (a->flags & SSH_FXA_HAVE_TIME) {
228 buffer_put_int(b, a->atime);
229 buffer_put_int(b, a->mtime);
230 }
231}
232
233Attrib *
234stat_to_attrib(struct stat *st)
235{
236 static Attrib a;
237 attrib_clear(&a);
238 a.flags = 0;
239 a.flags |= SSH_FXA_HAVE_SIZE;
240 a.size = st->st_size;
241 a.size_low = a.size;
242 a.size_high = (u_int32_t) (a.size >> 32);
243 a.flags |= SSH_FXA_HAVE_UGID;
244 a.uid = st->st_uid;
245 a.gid = st->st_gid;
246 a.flags |= SSH_FXA_HAVE_PERM;
247 a.perm = st->st_mode;
248 a.flags |= SSH_FXA_HAVE_TIME;
249 a.atime = st->st_atime;
250 a.mtime = st->st_mtime;
251 return &a;
252}
253
254Attrib *
255get_attrib(void)
256{
257 return decode_attrib(&iqueue);
258}
259
260/* handle handles */
261
262typedef struct Handle Handle;
263struct Handle {
264 int use;
265 DIR *dirp;
266 int fd;
267 char *name;
268};
113get_attrib(void)
114{
115 return decode_attrib(&iqueue);
116}
117
118/* handle handles */
119
120typedef struct Handle Handle;
121struct Handle {
122 int use;
123 DIR *dirp;
124 int fd;
125 char *name;
126};
127
269enum {
270 HANDLE_UNUSED,
271 HANDLE_DIR,
272 HANDLE_FILE
273};
128enum {
129 HANDLE_UNUSED,
130 HANDLE_DIR,
131 HANDLE_FILE
132};
133
274Handle handles[100];
275
276void
277handle_init(void)
278{
279 int i;
134Handle handles[100];
135
136void
137handle_init(void)
138{
139 int i;
140
280 for(i = 0; i < sizeof(handles)/sizeof(Handle); i++)
281 handles[i].use = HANDLE_UNUSED;
282}
283
284int
285handle_new(int use, char *name, int fd, DIR *dirp)
286{
287 int i;
141 for(i = 0; i < sizeof(handles)/sizeof(Handle); i++)
142 handles[i].use = HANDLE_UNUSED;
143}
144
145int
146handle_new(int use, char *name, int fd, DIR *dirp)
147{
148 int i;
149
288 for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
289 if (handles[i].use == HANDLE_UNUSED) {
290 handles[i].use = use;
291 handles[i].dirp = dirp;
292 handles[i].fd = fd;
293 handles[i].name = name;
294 return i;
295 }
296 }
297 return -1;
298}
299
300int
301handle_is_ok(int i, int type)
302{
150 for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
151 if (handles[i].use == HANDLE_UNUSED) {
152 handles[i].use = use;
153 handles[i].dirp = dirp;
154 handles[i].fd = fd;
155 handles[i].name = name;
156 return i;
157 }
158 }
159 return -1;
160}
161
162int
163handle_is_ok(int i, int type)
164{
303 return i >= 0 && i < sizeof(handles)/sizeof(Handle) && handles[i].use == type;
165 return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&
166 handles[i].use == type;
304}
305
306int
307handle_to_string(int handle, char **stringp, int *hlenp)
308{
167}
168
169int
170handle_to_string(int handle, char **stringp, int *hlenp)
171{
309 char buf[1024];
310 if (stringp == NULL || hlenp == NULL)
311 return -1;
172 if (stringp == NULL || hlenp == NULL)
173 return -1;
312 snprintf(buf, sizeof buf, "%d", handle);
313 *stringp = xstrdup(buf);
314 *hlenp = strlen(*stringp);
174 *stringp = xmalloc(sizeof(int32_t));
175 PUT_32BIT(*stringp, handle);
176 *hlenp = sizeof(int32_t);
315 return 0;
316}
317
318int
319handle_from_string(char *handle, u_int hlen)
320{
177 return 0;
178}
179
180int
181handle_from_string(char *handle, u_int hlen)
182{
321/* XXX OVERFLOW ? */
322 char *ep;
323 long lval = strtol(handle, &ep, 10);
324 int val = lval;
325 if (*ep != '\0')
183 int val;
184
185 if (hlen != sizeof(int32_t))
326 return -1;
186 return -1;
187 val = GET_32BIT(handle);
327 if (handle_is_ok(val, HANDLE_FILE) ||
328 handle_is_ok(val, HANDLE_DIR))
329 return val;
330 return -1;
331}
332
333char *
334handle_to_name(int handle)

--- 10 unchanged lines hidden (view full) ---

345 if (handle_is_ok(handle, HANDLE_DIR))
346 return handles[handle].dirp;
347 return NULL;
348}
349
350int
351handle_to_fd(int handle)
352{
188 if (handle_is_ok(val, HANDLE_FILE) ||
189 handle_is_ok(val, HANDLE_DIR))
190 return val;
191 return -1;
192}
193
194char *
195handle_to_name(int handle)

--- 10 unchanged lines hidden (view full) ---

206 if (handle_is_ok(handle, HANDLE_DIR))
207 return handles[handle].dirp;
208 return NULL;
209}
210
211int
212handle_to_fd(int handle)
213{
353 if (handle_is_ok(handle, HANDLE_FILE))
214 if (handle_is_ok(handle, HANDLE_FILE))
354 return handles[handle].fd;
355 return -1;
356}
357
358int
359handle_close(int handle)
360{
361 int ret = -1;
215 return handles[handle].fd;
216 return -1;
217}
218
219int
220handle_close(int handle)
221{
222 int ret = -1;
223
362 if (handle_is_ok(handle, HANDLE_FILE)) {
363 ret = close(handles[handle].fd);
364 handles[handle].use = HANDLE_UNUSED;
365 } else if (handle_is_ok(handle, HANDLE_DIR)) {
366 ret = closedir(handles[handle].dirp);
367 handles[handle].use = HANDLE_UNUSED;
368 } else {
369 errno = ENOENT;
370 }
371 return ret;
372}
373
374int
375get_handle(void)
376{
377 char *handle;
224 if (handle_is_ok(handle, HANDLE_FILE)) {
225 ret = close(handles[handle].fd);
226 handles[handle].use = HANDLE_UNUSED;
227 } else if (handle_is_ok(handle, HANDLE_DIR)) {
228 ret = closedir(handles[handle].dirp);
229 handles[handle].use = HANDLE_UNUSED;
230 } else {
231 errno = ENOENT;
232 }
233 return ret;
234}
235
236int
237get_handle(void)
238{
239 char *handle;
378 int val;
240 int val = -1;
379 u_int hlen;
241 u_int hlen;
242
380 handle = get_string(&hlen);
243 handle = get_string(&hlen);
381 val = handle_from_string(handle, hlen);
244 if (hlen < 256)
245 val = handle_from_string(handle, hlen);
382 xfree(handle);
383 return val;
384}
385
386/* send replies */
387
388void
389send_msg(Buffer *m)
390{
391 int mlen = buffer_len(m);
246 xfree(handle);
247 return val;
248}
249
250/* send replies */
251
252void
253send_msg(Buffer *m)
254{
255 int mlen = buffer_len(m);
256
392 buffer_put_int(&oqueue, mlen);
393 buffer_append(&oqueue, buffer_ptr(m), mlen);
394 buffer_consume(m, mlen);
395}
396
397void
398send_status(u_int32_t id, u_int32_t error)
399{
400 Buffer msg;
257 buffer_put_int(&oqueue, mlen);
258 buffer_append(&oqueue, buffer_ptr(m), mlen);
259 buffer_consume(m, mlen);
260}
261
262void
263send_status(u_int32_t id, u_int32_t error)
264{
265 Buffer msg;
266 const char *status_messages[] = {
267 "Success", /* SSH_FX_OK */
268 "End of file", /* SSH_FX_EOF */
269 "No such file", /* SSH_FX_NO_SUCH_FILE */
270 "Permission denied", /* SSH_FX_PERMISSION_DENIED */
271 "Failure", /* SSH_FX_FAILURE */
272 "Bad message", /* SSH_FX_BAD_MESSAGE */
273 "No connection", /* SSH_FX_NO_CONNECTION */
274 "Connection lost", /* SSH_FX_CONNECTION_LOST */
275 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
276 "Unknown error" /* Others */
277 };
278
401 TRACE("sent status id %d error %d", id, error);
402 buffer_init(&msg);
279 TRACE("sent status id %d error %d", id, error);
280 buffer_init(&msg);
403 buffer_put_char(&msg, SSH_FXP_STATUS);
281 buffer_put_char(&msg, SSH2_FXP_STATUS);
404 buffer_put_int(&msg, id);
405 buffer_put_int(&msg, error);
282 buffer_put_int(&msg, id);
283 buffer_put_int(&msg, error);
284 if (version >= 3) {
285 buffer_put_cstring(&msg,
286 status_messages[MIN(error,SSH2_FX_MAX)]);
287 buffer_put_cstring(&msg, "");
288 }
406 send_msg(&msg);
407 buffer_free(&msg);
408}
409void
410send_data_or_handle(char type, u_int32_t id, char *data, int dlen)
411{
412 Buffer msg;
289 send_msg(&msg);
290 buffer_free(&msg);
291}
292void
293send_data_or_handle(char type, u_int32_t id, char *data, int dlen)
294{
295 Buffer msg;
296
413 buffer_init(&msg);
414 buffer_put_char(&msg, type);
415 buffer_put_int(&msg, id);
416 buffer_put_string(&msg, data, dlen);
417 send_msg(&msg);
418 buffer_free(&msg);
419}
420
421void
422send_data(u_int32_t id, char *data, int dlen)
423{
424 TRACE("sent data id %d len %d", id, dlen);
297 buffer_init(&msg);
298 buffer_put_char(&msg, type);
299 buffer_put_int(&msg, id);
300 buffer_put_string(&msg, data, dlen);
301 send_msg(&msg);
302 buffer_free(&msg);
303}
304
305void
306send_data(u_int32_t id, char *data, int dlen)
307{
308 TRACE("sent data id %d len %d", id, dlen);
425 send_data_or_handle(SSH_FXP_DATA, id, data, dlen);
309 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
426}
427
428void
429send_handle(u_int32_t id, int handle)
430{
431 char *string;
432 int hlen;
310}
311
312void
313send_handle(u_int32_t id, int handle)
314{
315 char *string;
316 int hlen;
317
433 handle_to_string(handle, &string, &hlen);
434 TRACE("sent handle id %d handle %d", id, handle);
318 handle_to_string(handle, &string, &hlen);
319 TRACE("sent handle id %d handle %d", id, handle);
435 send_data_or_handle(SSH_FXP_HANDLE, id, string, hlen);
320 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
436 xfree(string);
437}
438
439void
440send_names(u_int32_t id, int count, Stat *stats)
441{
442 Buffer msg;
443 int i;
321 xfree(string);
322}
323
324void
325send_names(u_int32_t id, int count, Stat *stats)
326{
327 Buffer msg;
328 int i;
329
444 buffer_init(&msg);
330 buffer_init(&msg);
445 buffer_put_char(&msg, SSH_FXP_NAME);
331 buffer_put_char(&msg, SSH2_FXP_NAME);
446 buffer_put_int(&msg, id);
447 buffer_put_int(&msg, count);
448 TRACE("sent names id %d count %d", id, count);
449 for (i = 0; i < count; i++) {
450 buffer_put_cstring(&msg, stats[i].name);
451 buffer_put_cstring(&msg, stats[i].long_name);
452 encode_attrib(&msg, &stats[i].attrib);
453 }
454 send_msg(&msg);
455 buffer_free(&msg);
456}
457
458void
459send_attrib(u_int32_t id, Attrib *a)
460{
461 Buffer msg;
332 buffer_put_int(&msg, id);
333 buffer_put_int(&msg, count);
334 TRACE("sent names id %d count %d", id, count);
335 for (i = 0; i < count; i++) {
336 buffer_put_cstring(&msg, stats[i].name);
337 buffer_put_cstring(&msg, stats[i].long_name);
338 encode_attrib(&msg, &stats[i].attrib);
339 }
340 send_msg(&msg);
341 buffer_free(&msg);
342}
343
344void
345send_attrib(u_int32_t id, Attrib *a)
346{
347 Buffer msg;
348
462 TRACE("sent attrib id %d have 0x%x", id, a->flags);
463 buffer_init(&msg);
349 TRACE("sent attrib id %d have 0x%x", id, a->flags);
350 buffer_init(&msg);
464 buffer_put_char(&msg, SSH_FXP_ATTRS);
351 buffer_put_char(&msg, SSH2_FXP_ATTRS);
465 buffer_put_int(&msg, id);
466 encode_attrib(&msg, a);
467 send_msg(&msg);
468 buffer_free(&msg);
469}
470
471/* parse incoming */
472
473void
474process_init(void)
475{
476 Buffer msg;
352 buffer_put_int(&msg, id);
353 encode_attrib(&msg, a);
354 send_msg(&msg);
355 buffer_free(&msg);
356}
357
358/* parse incoming */
359
360void
361process_init(void)
362{
363 Buffer msg;
477 int version = buffer_get_int(&iqueue);
478
364
365 version = buffer_get_int(&iqueue);
479 TRACE("client version %d", version);
480 buffer_init(&msg);
366 TRACE("client version %d", version);
367 buffer_init(&msg);
481 buffer_put_char(&msg, SSH_FXP_VERSION);
482 buffer_put_int(&msg, SSH_FILEXFER_VERSION);
368 buffer_put_char(&msg, SSH2_FXP_VERSION);
369 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
483 send_msg(&msg);
484 buffer_free(&msg);
485}
486
487void
488process_open(void)
489{
490 u_int32_t id, pflags;
491 Attrib *a;
492 char *name;
370 send_msg(&msg);
371 buffer_free(&msg);
372}
373
374void
375process_open(void)
376{
377 u_int32_t id, pflags;
378 Attrib *a;
379 char *name;
493 int handle, fd, flags, mode, status = SSH_FX_FAILURE;
380 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
494
495 id = get_int();
496 name = get_string(NULL);
381
382 id = get_int();
383 name = get_string(NULL);
497 pflags = get_int();
384 pflags = get_int(); /* portable flags */
498 a = get_attrib();
499 flags = flags_from_portable(pflags);
385 a = get_attrib();
386 flags = flags_from_portable(pflags);
500 mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm : 0666;
387 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
501 TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode);
502 fd = open(name, flags, mode);
503 if (fd < 0) {
504 status = errno_to_portable(errno);
505 } else {
506 handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL);
507 if (handle < 0) {
508 close(fd);
509 } else {
510 send_handle(id, handle);
388 TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode);
389 fd = open(name, flags, mode);
390 if (fd < 0) {
391 status = errno_to_portable(errno);
392 } else {
393 handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL);
394 if (handle < 0) {
395 close(fd);
396 } else {
397 send_handle(id, handle);
511 status = SSH_FX_OK;
398 status = SSH2_FX_OK;
512 }
513 }
399 }
400 }
514 if (status != SSH_FX_OK)
401 if (status != SSH2_FX_OK)
515 send_status(id, status);
516 xfree(name);
517}
518
519void
520process_close(void)
521{
522 u_int32_t id;
402 send_status(id, status);
403 xfree(name);
404}
405
406void
407process_close(void)
408{
409 u_int32_t id;
523 int handle, ret, status = SSH_FX_FAILURE;
410 int handle, ret, status = SSH2_FX_FAILURE;
524
525 id = get_int();
526 handle = get_handle();
527 TRACE("close id %d handle %d", id, handle);
528 ret = handle_close(handle);
411
412 id = get_int();
413 handle = get_handle();
414 TRACE("close id %d handle %d", id, handle);
415 ret = handle_close(handle);
529 status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
416 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
530 send_status(id, status);
531}
532
533void
534process_read(void)
535{
536 char buf[64*1024];
417 send_status(id, status);
418}
419
420void
421process_read(void)
422{
423 char buf[64*1024];
537 u_int32_t id, off_high, off_low, len;
538 int handle, fd, ret, status = SSH_FX_FAILURE;
424 u_int32_t id, len;
425 int handle, fd, ret, status = SSH2_FX_FAILURE;
539 u_int64_t off;
540
541 id = get_int();
542 handle = get_handle();
426 u_int64_t off;
427
428 id = get_int();
429 handle = get_handle();
543 off_high = get_int();
544 off_low = get_int();
430 off = get_int64();
545 len = get_int();
546
431 len = get_int();
432
547 off = (((u_int64_t) off_high) << 32) + off_low;
548 TRACE("read id %d handle %d off %qd len %d", id, handle, off, len);
433 TRACE("read id %d handle %d off %llu len %d", id, handle,
434 (unsigned long long)off, len);
549 if (len > sizeof buf) {
550 len = sizeof buf;
551 log("read change len %d", len);
552 }
553 fd = handle_to_fd(handle);
554 if (fd >= 0) {
555 if (lseek(fd, off, SEEK_SET) < 0) {
556 error("process_read: seek failed");
557 status = errno_to_portable(errno);
558 } else {
559 ret = read(fd, buf, len);
560 if (ret < 0) {
561 status = errno_to_portable(errno);
562 } else if (ret == 0) {
435 if (len > sizeof buf) {
436 len = sizeof buf;
437 log("read change len %d", len);
438 }
439 fd = handle_to_fd(handle);
440 if (fd >= 0) {
441 if (lseek(fd, off, SEEK_SET) < 0) {
442 error("process_read: seek failed");
443 status = errno_to_portable(errno);
444 } else {
445 ret = read(fd, buf, len);
446 if (ret < 0) {
447 status = errno_to_portable(errno);
448 } else if (ret == 0) {
563 status = SSH_FX_EOF;
449 status = SSH2_FX_EOF;
564 } else {
565 send_data(id, buf, ret);
450 } else {
451 send_data(id, buf, ret);
566 status = SSH_FX_OK;
452 status = SSH2_FX_OK;
567 }
568 }
569 }
453 }
454 }
455 }
570 if (status != SSH_FX_OK)
456 if (status != SSH2_FX_OK)
571 send_status(id, status);
572}
573
574void
575process_write(void)
576{
457 send_status(id, status);
458}
459
460void
461process_write(void)
462{
577 u_int32_t id, off_high, off_low;
463 u_int32_t id;
578 u_int64_t off;
579 u_int len;
464 u_int64_t off;
465 u_int len;
580 int handle, fd, ret, status = SSH_FX_FAILURE;
466 int handle, fd, ret, status = SSH2_FX_FAILURE;
581 char *data;
582
583 id = get_int();
584 handle = get_handle();
467 char *data;
468
469 id = get_int();
470 handle = get_handle();
585 off_high = get_int();
586 off_low = get_int();
471 off = get_int64();
587 data = get_string(&len);
588
472 data = get_string(&len);
473
589 off = (((u_int64_t) off_high) << 32) + off_low;
590 TRACE("write id %d handle %d off %qd len %d", id, handle, off, len);
474 TRACE("write id %d handle %d off %llu len %d", id, handle,
475 (unsigned long long)off, len);
591 fd = handle_to_fd(handle);
592 if (fd >= 0) {
593 if (lseek(fd, off, SEEK_SET) < 0) {
594 status = errno_to_portable(errno);
595 error("process_write: seek failed");
596 } else {
597/* XXX ATOMICIO ? */
598 ret = write(fd, data, len);
599 if (ret == -1) {
600 error("process_write: write failed");
601 status = errno_to_portable(errno);
602 } else if (ret == len) {
476 fd = handle_to_fd(handle);
477 if (fd >= 0) {
478 if (lseek(fd, off, SEEK_SET) < 0) {
479 status = errno_to_portable(errno);
480 error("process_write: seek failed");
481 } else {
482/* XXX ATOMICIO ? */
483 ret = write(fd, data, len);
484 if (ret == -1) {
485 error("process_write: write failed");
486 status = errno_to_portable(errno);
487 } else if (ret == len) {
603 status = SSH_FX_OK;
488 status = SSH2_FX_OK;
604 } else {
605 log("nothing at all written");
606 }
607 }
608 }
609 send_status(id, status);
610 xfree(data);
611}
612
613void
614process_do_stat(int do_lstat)
615{
489 } else {
490 log("nothing at all written");
491 }
492 }
493 }
494 send_status(id, status);
495 xfree(data);
496}
497
498void
499process_do_stat(int do_lstat)
500{
616 Attrib *a;
501 Attrib a;
617 struct stat st;
618 u_int32_t id;
619 char *name;
502 struct stat st;
503 u_int32_t id;
504 char *name;
620 int ret, status = SSH_FX_FAILURE;
505 int ret, status = SSH2_FX_FAILURE;
621
622 id = get_int();
623 name = get_string(NULL);
624 TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name);
625 ret = do_lstat ? lstat(name, &st) : stat(name, &st);
626 if (ret < 0) {
627 status = errno_to_portable(errno);
628 } else {
506
507 id = get_int();
508 name = get_string(NULL);
509 TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name);
510 ret = do_lstat ? lstat(name, &st) : stat(name, &st);
511 if (ret < 0) {
512 status = errno_to_portable(errno);
513 } else {
629 a = stat_to_attrib(&st);
630 send_attrib(id, a);
631 status = SSH_FX_OK;
514 stat_to_attrib(&st, &a);
515 send_attrib(id, &a);
516 status = SSH2_FX_OK;
632 }
517 }
633 if (status != SSH_FX_OK)
518 if (status != SSH2_FX_OK)
634 send_status(id, status);
635 xfree(name);
636}
637
638void
639process_stat(void)
640{
641 process_do_stat(0);
642}
643
644void
645process_lstat(void)
646{
647 process_do_stat(1);
648}
649
650void
651process_fstat(void)
652{
519 send_status(id, status);
520 xfree(name);
521}
522
523void
524process_stat(void)
525{
526 process_do_stat(0);
527}
528
529void
530process_lstat(void)
531{
532 process_do_stat(1);
533}
534
535void
536process_fstat(void)
537{
653 Attrib *a;
538 Attrib a;
654 struct stat st;
655 u_int32_t id;
539 struct stat st;
540 u_int32_t id;
656 int fd, ret, handle, status = SSH_FX_FAILURE;
541 int fd, ret, handle, status = SSH2_FX_FAILURE;
657
658 id = get_int();
659 handle = get_handle();
660 TRACE("fstat id %d handle %d", id, handle);
661 fd = handle_to_fd(handle);
662 if (fd >= 0) {
663 ret = fstat(fd, &st);
664 if (ret < 0) {
665 status = errno_to_portable(errno);
666 } else {
542
543 id = get_int();
544 handle = get_handle();
545 TRACE("fstat id %d handle %d", id, handle);
546 fd = handle_to_fd(handle);
547 if (fd >= 0) {
548 ret = fstat(fd, &st);
549 if (ret < 0) {
550 status = errno_to_portable(errno);
551 } else {
667 a = stat_to_attrib(&st);
668 send_attrib(id, a);
669 status = SSH_FX_OK;
552 stat_to_attrib(&st, &a);
553 send_attrib(id, &a);
554 status = SSH2_FX_OK;
670 }
671 }
555 }
556 }
672 if (status != SSH_FX_OK)
557 if (status != SSH2_FX_OK)
673 send_status(id, status);
674}
675
676struct timeval *
677attrib_to_tv(Attrib *a)
678{
679 static struct timeval tv[2];
558 send_status(id, status);
559}
560
561struct timeval *
562attrib_to_tv(Attrib *a)
563{
564 static struct timeval tv[2];
565
680 tv[0].tv_sec = a->atime;
681 tv[0].tv_usec = 0;
682 tv[1].tv_sec = a->mtime;
683 tv[1].tv_usec = 0;
684 return tv;
685}
686
687void
688process_setstat(void)
689{
690 Attrib *a;
691 u_int32_t id;
692 char *name;
693 int ret;
566 tv[0].tv_sec = a->atime;
567 tv[0].tv_usec = 0;
568 tv[1].tv_sec = a->mtime;
569 tv[1].tv_usec = 0;
570 return tv;
571}
572
573void
574process_setstat(void)
575{
576 Attrib *a;
577 u_int32_t id;
578 char *name;
579 int ret;
694 int status = SSH_FX_OK;
580 int status = SSH2_FX_OK;
695
696 id = get_int();
697 name = get_string(NULL);
698 a = get_attrib();
699 TRACE("setstat id %d name %s", id, name);
581
582 id = get_int();
583 name = get_string(NULL);
584 a = get_attrib();
585 TRACE("setstat id %d name %s", id, name);
700 if (a->flags & SSH_FXA_HAVE_PERM) {
586 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
701 ret = chmod(name, a->perm & 0777);
702 if (ret == -1)
703 status = errno_to_portable(errno);
704 }
587 ret = chmod(name, a->perm & 0777);
588 if (ret == -1)
589 status = errno_to_portable(errno);
590 }
705 if (a->flags & SSH_FXA_HAVE_TIME) {
591 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
706 ret = utimes(name, attrib_to_tv(a));
707 if (ret == -1)
708 status = errno_to_portable(errno);
709 }
592 ret = utimes(name, attrib_to_tv(a));
593 if (ret == -1)
594 status = errno_to_portable(errno);
595 }
596 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
597 ret = chown(name, a->uid, a->gid);
598 if (ret == -1)
599 status = errno_to_portable(errno);
600 }
710 send_status(id, status);
711 xfree(name);
712}
713
714void
715process_fsetstat(void)
716{
717 Attrib *a;
718 u_int32_t id;
719 int handle, fd, ret;
601 send_status(id, status);
602 xfree(name);
603}
604
605void
606process_fsetstat(void)
607{
608 Attrib *a;
609 u_int32_t id;
610 int handle, fd, ret;
720 int status = SSH_FX_OK;
611 int status = SSH2_FX_OK;
721
722 id = get_int();
723 handle = get_handle();
724 a = get_attrib();
725 TRACE("fsetstat id %d handle %d", id, handle);
726 fd = handle_to_fd(handle);
727 if (fd < 0) {
612
613 id = get_int();
614 handle = get_handle();
615 a = get_attrib();
616 TRACE("fsetstat id %d handle %d", id, handle);
617 fd = handle_to_fd(handle);
618 if (fd < 0) {
728 status = SSH_FX_FAILURE;
619 status = SSH2_FX_FAILURE;
729 } else {
620 } else {
730 if (a->flags & SSH_FXA_HAVE_PERM) {
621 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
731 ret = fchmod(fd, a->perm & 0777);
732 if (ret == -1)
733 status = errno_to_portable(errno);
734 }
622 ret = fchmod(fd, a->perm & 0777);
623 if (ret == -1)
624 status = errno_to_portable(errno);
625 }
735 if (a->flags & SSH_FXA_HAVE_TIME) {
626 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
736 ret = futimes(fd, attrib_to_tv(a));
737 if (ret == -1)
738 status = errno_to_portable(errno);
739 }
627 ret = futimes(fd, attrib_to_tv(a));
628 if (ret == -1)
629 status = errno_to_portable(errno);
630 }
631 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
632 ret = fchown(fd, a->uid, a->gid);
633 if (ret == -1)
634 status = errno_to_portable(errno);
635 }
740 }
741 send_status(id, status);
742}
743
744void
745process_opendir(void)
746{
747 DIR *dirp = NULL;
748 char *path;
636 }
637 send_status(id, status);
638}
639
640void
641process_opendir(void)
642{
643 DIR *dirp = NULL;
644 char *path;
749 int handle, status = SSH_FX_FAILURE;
645 int handle, status = SSH2_FX_FAILURE;
750 u_int32_t id;
751
752 id = get_int();
753 path = get_string(NULL);
754 TRACE("opendir id %d path %s", id, path);
646 u_int32_t id;
647
648 id = get_int();
649 path = get_string(NULL);
650 TRACE("opendir id %d path %s", id, path);
755 dirp = opendir(path);
651 dirp = opendir(path);
756 if (dirp == NULL) {
757 status = errno_to_portable(errno);
758 } else {
759 handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp);
760 if (handle < 0) {
761 closedir(dirp);
762 } else {
763 send_handle(id, handle);
652 if (dirp == NULL) {
653 status = errno_to_portable(errno);
654 } else {
655 handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp);
656 if (handle < 0) {
657 closedir(dirp);
658 } else {
659 send_handle(id, handle);
764 status = SSH_FX_OK;
660 status = SSH2_FX_OK;
765 }
661 }
766
662
767 }
663 }
768 if (status != SSH_FX_OK)
664 if (status != SSH2_FX_OK)
769 send_status(id, status);
770 xfree(path);
771}
772
665 send_status(id, status);
666 xfree(path);
667}
668
669/*
670 * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
671 */
773char *
774ls_file(char *name, struct stat *st)
775{
672char *
673ls_file(char *name, struct stat *st)
674{
776 char buf[1024];
777 snprintf(buf, sizeof buf, "0%o %d %d %qd %d %s",
778 st->st_mode, st->st_uid, st->st_gid, (long long)st->st_size,(int) st->st_mtime,
779 name);
675 int sz = 0;
676 struct passwd *pw;
677 struct group *gr;
678 struct tm *ltime = localtime(&st->st_mtime);
679 char *user, *group;
680 char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
681
682 strmode(st->st_mode, mode);
683 if ((pw = getpwuid(st->st_uid)) != NULL) {
684 user = pw->pw_name;
685 } else {
686 snprintf(ubuf, sizeof ubuf, "%d", st->st_uid);
687 user = ubuf;
688 }
689 if ((gr = getgrgid(st->st_gid)) != NULL) {
690 group = gr->gr_name;
691 } else {
692 snprintf(gbuf, sizeof gbuf, "%d", st->st_gid);
693 group = gbuf;
694 }
695 if (ltime != NULL) {
696 if (time(NULL) - st->st_mtime < (365*24*60*60)/2)
697 sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);
698 else
699 sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime);
700 }
701 if (sz == 0)
702 tbuf[0] = '\0';
703 snprintf(buf, sizeof buf, "%s %3d %-8.8s %-8.8s %8llu %s %s", mode,
704 st->st_nlink, user, group, (unsigned long long)st->st_size, tbuf, name);
780 return xstrdup(buf);
781}
782
783void
784process_readdir(void)
785{
786 DIR *dirp;
787 struct dirent *dp;
788 char *path;
789 int handle;
790 u_int32_t id;
791
792 id = get_int();
793 handle = get_handle();
794 TRACE("readdir id %d handle %d", id, handle);
795 dirp = handle_to_dir(handle);
796 path = handle_to_name(handle);
797 if (dirp == NULL || path == NULL) {
705 return xstrdup(buf);
706}
707
708void
709process_readdir(void)
710{
711 DIR *dirp;
712 struct dirent *dp;
713 char *path;
714 int handle;
715 u_int32_t id;
716
717 id = get_int();
718 handle = get_handle();
719 TRACE("readdir id %d handle %d", id, handle);
720 dirp = handle_to_dir(handle);
721 path = handle_to_name(handle);
722 if (dirp == NULL || path == NULL) {
798 send_status(id, SSH_FX_FAILURE);
723 send_status(id, SSH2_FX_FAILURE);
799 } else {
724 } else {
800 Attrib *a;
801 struct stat st;
802 char pathname[1024];
803 Stat *stats;
804 int nstats = 10, count = 0, i;
805 stats = xmalloc(nstats * sizeof(Stat));
806 while ((dp = readdir(dirp)) != NULL) {
807 if (count >= nstats) {
808 nstats *= 2;
809 stats = xrealloc(stats, nstats * sizeof(Stat));
810 }
811/* XXX OVERFLOW ? */
812 snprintf(pathname, sizeof pathname,
813 "%s/%s", path, dp->d_name);
814 if (lstat(pathname, &st) < 0)
815 continue;
725 struct stat st;
726 char pathname[1024];
727 Stat *stats;
728 int nstats = 10, count = 0, i;
729 stats = xmalloc(nstats * sizeof(Stat));
730 while ((dp = readdir(dirp)) != NULL) {
731 if (count >= nstats) {
732 nstats *= 2;
733 stats = xrealloc(stats, nstats * sizeof(Stat));
734 }
735/* XXX OVERFLOW ? */
736 snprintf(pathname, sizeof pathname,
737 "%s/%s", path, dp->d_name);
738 if (lstat(pathname, &st) < 0)
739 continue;
816 a = stat_to_attrib(&st);
817 stats[count].attrib = *a;
740 stat_to_attrib(&st, &(stats[count].attrib));
818 stats[count].name = xstrdup(dp->d_name);
819 stats[count].long_name = ls_file(dp->d_name, &st);
820 count++;
821 /* send up to 100 entries in one message */
741 stats[count].name = xstrdup(dp->d_name);
742 stats[count].long_name = ls_file(dp->d_name, &st);
743 count++;
744 /* send up to 100 entries in one message */
745 /* XXX check packet size instead */
822 if (count == 100)
823 break;
824 }
746 if (count == 100)
747 break;
748 }
825 send_names(id, count, stats);
826 for(i = 0; i < count; i++) {
827 xfree(stats[i].name);
828 xfree(stats[i].long_name);
749 if (count > 0) {
750 send_names(id, count, stats);
751 for(i = 0; i < count; i++) {
752 xfree(stats[i].name);
753 xfree(stats[i].long_name);
754 }
755 } else {
756 send_status(id, SSH2_FX_EOF);
829 }
830 xfree(stats);
831 }
832}
833
834void
835process_remove(void)
836{
837 char *name;
838 u_int32_t id;
757 }
758 xfree(stats);
759 }
760}
761
762void
763process_remove(void)
764{
765 char *name;
766 u_int32_t id;
839 int status = SSH_FX_FAILURE;
767 int status = SSH2_FX_FAILURE;
840 int ret;
841
842 id = get_int();
843 name = get_string(NULL);
844 TRACE("remove id %d name %s", id, name);
768 int ret;
769
770 id = get_int();
771 name = get_string(NULL);
772 TRACE("remove id %d name %s", id, name);
845 ret = remove(name);
846 status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
773 ret = unlink(name);
774 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
847 send_status(id, status);
848 xfree(name);
849}
850
851void
852process_mkdir(void)
853{
854 Attrib *a;
855 u_int32_t id;
856 char *name;
775 send_status(id, status);
776 xfree(name);
777}
778
779void
780process_mkdir(void)
781{
782 Attrib *a;
783 u_int32_t id;
784 char *name;
857 int ret, mode, status = SSH_FX_FAILURE;
785 int ret, mode, status = SSH2_FX_FAILURE;
858
859 id = get_int();
860 name = get_string(NULL);
861 a = get_attrib();
786
787 id = get_int();
788 name = get_string(NULL);
789 a = get_attrib();
862 mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm & 0777 : 0777;
790 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
791 a->perm & 0777 : 0777;
863 TRACE("mkdir id %d name %s mode 0%o", id, name, mode);
864 ret = mkdir(name, mode);
792 TRACE("mkdir id %d name %s mode 0%o", id, name, mode);
793 ret = mkdir(name, mode);
865 status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
794 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
866 send_status(id, status);
867 xfree(name);
868}
869
870void
871process_rmdir(void)
872{
873 u_int32_t id;
874 char *name;
875 int ret, status;
876
877 id = get_int();
878 name = get_string(NULL);
879 TRACE("rmdir id %d name %s", id, name);
880 ret = rmdir(name);
795 send_status(id, status);
796 xfree(name);
797}
798
799void
800process_rmdir(void)
801{
802 u_int32_t id;
803 char *name;
804 int ret, status;
805
806 id = get_int();
807 name = get_string(NULL);
808 TRACE("rmdir id %d name %s", id, name);
809 ret = rmdir(name);
881 status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
810 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
882 send_status(id, status);
883 xfree(name);
884}
885
886void
887process_realpath(void)
888{
889 char resolvedname[MAXPATHLEN];
890 u_int32_t id;
891 char *path;
892
893 id = get_int();
894 path = get_string(NULL);
811 send_status(id, status);
812 xfree(name);
813}
814
815void
816process_realpath(void)
817{
818 char resolvedname[MAXPATHLEN];
819 u_int32_t id;
820 char *path;
821
822 id = get_int();
823 path = get_string(NULL);
824 if (path[0] == '\0') {
825 xfree(path);
826 path = xstrdup(".");
827 }
895 TRACE("realpath id %d path %s", id, path);
896 if (realpath(path, resolvedname) == NULL) {
897 send_status(id, errno_to_portable(errno));
898 } else {
899 Stat s;
900 attrib_clear(&s.attrib);
901 s.name = s.long_name = resolvedname;
902 send_names(id, 1, &s);
903 }
904 xfree(path);
905}
906
907void
908process_rename(void)
909{
910 u_int32_t id;
828 TRACE("realpath id %d path %s", id, path);
829 if (realpath(path, resolvedname) == NULL) {
830 send_status(id, errno_to_portable(errno));
831 } else {
832 Stat s;
833 attrib_clear(&s.attrib);
834 s.name = s.long_name = resolvedname;
835 send_names(id, 1, &s);
836 }
837 xfree(path);
838}
839
840void
841process_rename(void)
842{
843 u_int32_t id;
844 struct stat st;
911 char *oldpath, *newpath;
845 char *oldpath, *newpath;
912 int ret, status;
846 int ret, status = SSH2_FX_FAILURE;
913
914 id = get_int();
915 oldpath = get_string(NULL);
916 newpath = get_string(NULL);
917 TRACE("rename id %d old %s new %s", id, oldpath, newpath);
847
848 id = get_int();
849 oldpath = get_string(NULL);
850 newpath = get_string(NULL);
851 TRACE("rename id %d old %s new %s", id, oldpath, newpath);
918 ret = rename(oldpath, newpath);
919 status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
852 /* fail if 'newpath' exists */
853 if (stat(newpath, &st) == -1) {
854 ret = rename(oldpath, newpath);
855 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
856 }
920 send_status(id, status);
921 xfree(oldpath);
922 xfree(newpath);
923}
924
857 send_status(id, status);
858 xfree(oldpath);
859 xfree(newpath);
860}
861
862void
863process_readlink(void)
864{
865 u_int32_t id;
866 char link[MAXPATHLEN];
867 char *path;
925
868
869 id = get_int();
870 path = get_string(NULL);
871 TRACE("readlink id %d path %s", id, path);
872 if (readlink(path, link, sizeof(link) - 1) == -1)
873 send_status(id, errno_to_portable(errno));
874 else {
875 Stat s;
876
877 link[sizeof(link) - 1] = '\0';
878 attrib_clear(&s.attrib);
879 s.name = s.long_name = link;
880 send_names(id, 1, &s);
881 }
882 xfree(path);
883}
884
885void
886process_symlink(void)
887{
888 u_int32_t id;
889 struct stat st;
890 char *oldpath, *newpath;
891 int ret, status = SSH2_FX_FAILURE;
892
893 id = get_int();
894 oldpath = get_string(NULL);
895 newpath = get_string(NULL);
896 TRACE("symlink id %d old %s new %s", id, oldpath, newpath);
897 /* fail if 'newpath' exists */
898 if (stat(newpath, &st) == -1) {
899 ret = symlink(oldpath, newpath);
900 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
901 }
902 send_status(id, status);
903 xfree(oldpath);
904 xfree(newpath);
905}
906
907void
908process_extended(void)
909{
910 u_int32_t id;
911 char *request;
912
913 id = get_int();
914 request = get_string(NULL);
915 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
916 xfree(request);
917}
918
926/* stolen from ssh-agent */
927
928void
929process(void)
930{
919/* stolen from ssh-agent */
920
921void
922process(void)
923{
931 unsigned int msg_len;
932 unsigned int type;
933 unsigned char *cp;
924 u_int msg_len;
925 u_int type;
926 u_char *cp;
934
935 if (buffer_len(&iqueue) < 5)
936 return; /* Incomplete message. */
927
928 if (buffer_len(&iqueue) < 5)
929 return; /* Incomplete message. */
937 cp = (unsigned char *) buffer_ptr(&iqueue);
930 cp = (u_char *) buffer_ptr(&iqueue);
938 msg_len = GET_32BIT(cp);
939 if (msg_len > 256 * 1024) {
940 error("bad message ");
941 exit(11);
942 }
943 if (buffer_len(&iqueue) < msg_len + 4)
944 return;
945 buffer_consume(&iqueue, 4);
946 type = buffer_get_char(&iqueue);
947 switch (type) {
931 msg_len = GET_32BIT(cp);
932 if (msg_len > 256 * 1024) {
933 error("bad message ");
934 exit(11);
935 }
936 if (buffer_len(&iqueue) < msg_len + 4)
937 return;
938 buffer_consume(&iqueue, 4);
939 type = buffer_get_char(&iqueue);
940 switch (type) {
948 case SSH_FXP_INIT:
941 case SSH2_FXP_INIT:
949 process_init();
950 break;
942 process_init();
943 break;
951 case SSH_FXP_OPEN:
944 case SSH2_FXP_OPEN:
952 process_open();
953 break;
945 process_open();
946 break;
954 case SSH_FXP_CLOSE:
947 case SSH2_FXP_CLOSE:
955 process_close();
956 break;
948 process_close();
949 break;
957 case SSH_FXP_READ:
950 case SSH2_FXP_READ:
958 process_read();
959 break;
951 process_read();
952 break;
960 case SSH_FXP_WRITE:
953 case SSH2_FXP_WRITE:
961 process_write();
962 break;
954 process_write();
955 break;
963 case SSH_FXP_LSTAT:
956 case SSH2_FXP_LSTAT:
964 process_lstat();
965 break;
957 process_lstat();
958 break;
966 case SSH_FXP_FSTAT:
959 case SSH2_FXP_FSTAT:
967 process_fstat();
968 break;
960 process_fstat();
961 break;
969 case SSH_FXP_SETSTAT:
962 case SSH2_FXP_SETSTAT:
970 process_setstat();
971 break;
963 process_setstat();
964 break;
972 case SSH_FXP_FSETSTAT:
965 case SSH2_FXP_FSETSTAT:
973 process_fsetstat();
974 break;
966 process_fsetstat();
967 break;
975 case SSH_FXP_OPENDIR:
968 case SSH2_FXP_OPENDIR:
976 process_opendir();
977 break;
969 process_opendir();
970 break;
978 case SSH_FXP_READDIR:
971 case SSH2_FXP_READDIR:
979 process_readdir();
980 break;
972 process_readdir();
973 break;
981 case SSH_FXP_REMOVE:
974 case SSH2_FXP_REMOVE:
982 process_remove();
983 break;
975 process_remove();
976 break;
984 case SSH_FXP_MKDIR:
977 case SSH2_FXP_MKDIR:
985 process_mkdir();
986 break;
978 process_mkdir();
979 break;
987 case SSH_FXP_RMDIR:
980 case SSH2_FXP_RMDIR:
988 process_rmdir();
989 break;
981 process_rmdir();
982 break;
990 case SSH_FXP_REALPATH:
983 case SSH2_FXP_REALPATH:
991 process_realpath();
992 break;
984 process_realpath();
985 break;
993 case SSH_FXP_STAT:
986 case SSH2_FXP_STAT:
994 process_stat();
995 break;
987 process_stat();
988 break;
996 case SSH_FXP_RENAME:
989 case SSH2_FXP_RENAME:
997 process_rename();
998 break;
990 process_rename();
991 break;
992 case SSH2_FXP_READLINK:
993 process_readlink();
994 break;
995 case SSH2_FXP_SYMLINK:
996 process_symlink();
997 break;
998 case SSH2_FXP_EXTENDED:
999 process_extended();
1000 break;
999 default:
1000 error("Unknown message %d", type);
1001 break;
1002 }
1003}
1004
1005int
1006main(int ac, char **av)
1007{
1001 default:
1002 error("Unknown message %d", type);
1003 break;
1004 }
1005}
1006
1007int
1008main(int ac, char **av)
1009{
1008 fd_set rset, wset;
1010 fd_set *rset, *wset;
1009 int in, out, max;
1011 int in, out, max;
1010 ssize_t len, olen;
1012 ssize_t len, olen, set_size;
1011
1013
1014 /* XXX should use getopt */
1015
1012 handle_init();
1013
1016 handle_init();
1017
1018#ifdef DEBUG_SFTP_SERVER
1019 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1020#endif
1021
1014 in = dup(STDIN_FILENO);
1015 out = dup(STDOUT_FILENO);
1016
1017 max = 0;
1018 if (in > max)
1019 max = in;
1020 if (out > max)
1021 max = out;
1022
1023 buffer_init(&iqueue);
1024 buffer_init(&oqueue);
1025
1022 in = dup(STDIN_FILENO);
1023 out = dup(STDOUT_FILENO);
1024
1025 max = 0;
1026 if (in > max)
1027 max = in;
1028 if (out > max)
1029 max = out;
1030
1031 buffer_init(&iqueue);
1032 buffer_init(&oqueue);
1033
1034 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1035 rset = (fd_set *)xmalloc(set_size);
1036 wset = (fd_set *)xmalloc(set_size);
1037
1026 for (;;) {
1038 for (;;) {
1027 FD_ZERO(&rset);
1028 FD_ZERO(&wset);
1039 memset(rset, 0, set_size);
1040 memset(wset, 0, set_size);
1029
1041
1030 FD_SET(in, &rset);
1042 FD_SET(in, rset);
1031 olen = buffer_len(&oqueue);
1032 if (olen > 0)
1043 olen = buffer_len(&oqueue);
1044 if (olen > 0)
1033 FD_SET(out, &wset);
1045 FD_SET(out, wset);
1034
1046
1035 if (select(max+1, &rset, &wset, NULL, NULL) < 0) {
1047 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1036 if (errno == EINTR)
1037 continue;
1038 exit(2);
1039 }
1040
1041 /* copy stdin to iqueue */
1048 if (errno == EINTR)
1049 continue;
1050 exit(2);
1051 }
1052
1053 /* copy stdin to iqueue */
1042 if (FD_ISSET(in, &rset)) {
1054 if (FD_ISSET(in, rset)) {
1043 char buf[4*4096];
1044 len = read(in, buf, sizeof buf);
1045 if (len == 0) {
1046 debug("read eof");
1047 exit(0);
1048 } else if (len < 0) {
1049 error("read error");
1050 exit(1);
1051 } else {
1052 buffer_append(&iqueue, buf, len);
1053 }
1054 }
1055 /* send oqueue to stdout */
1055 char buf[4*4096];
1056 len = read(in, buf, sizeof buf);
1057 if (len == 0) {
1058 debug("read eof");
1059 exit(0);
1060 } else if (len < 0) {
1061 error("read error");
1062 exit(1);
1063 } else {
1064 buffer_append(&iqueue, buf, len);
1065 }
1066 }
1067 /* send oqueue to stdout */
1056 if (FD_ISSET(out, &wset)) {
1068 if (FD_ISSET(out, wset)) {
1057 len = write(out, buffer_ptr(&oqueue), olen);
1058 if (len < 0) {
1059 error("write error");
1060 exit(1);
1061 } else {
1062 buffer_consume(&oqueue, len);
1063 }
1064 }
1065 /* process requests from client */
1066 process();
1067 }
1068}
1069 len = write(out, buffer_ptr(&oqueue), olen);
1070 if (len < 0) {
1071 error("write error");
1072 exit(1);
1073 } else {
1074 buffer_consume(&oqueue, len);
1075 }
1076 }
1077 /* process requests from client */
1078 process();
1079 }
1080}