Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.38.2.1
1.1 markus 1: /*
1.33 markus 2: * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved.
1.1 markus 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.
9: * 2. Redistributions in binary form must reproduce the above copyright
10: * notice, this list of conditions and the following disclaimer in the
11: * documentation and/or other materials provided with the distribution.
12: *
13: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
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.38.2.1! margarid 25: RCSID("$OpenBSD: sftp-server.c,v 1.40 2003/03/05 22:33:43 markus Exp $");
1.1 markus 26:
27: #include "buffer.h"
28: #include "bufaux.h"
29: #include "getput.h"
1.14 markus 30: #include "log.h"
1.1 markus 31: #include "xmalloc.h"
32:
1.10 markus 33: #include "sftp.h"
1.15 djm 34: #include "sftp-common.h"
1.1 markus 35:
36: /* helper */
1.10 markus 37: #define get_int64() buffer_get_int64(&iqueue);
1.1 markus 38: #define get_int() buffer_get_int(&iqueue);
39: #define get_string(lenp) buffer_get_string(&iqueue, lenp);
1.10 markus 40: #define TRACE debug
1.1 markus 41:
42: /* input and output queue */
43: Buffer iqueue;
44: Buffer oqueue;
45:
1.23 djm 46: /* Version of client */
47: int version;
48:
1.1 markus 49: /* portable attibutes, etc. */
50:
51: typedef struct Stat Stat;
52:
1.15 djm 53: struct Stat {
1.1 markus 54: char *name;
55: char *long_name;
56: Attrib attrib;
57: };
58:
1.28 itojun 59: static int
1.2 markus 60: errno_to_portable(int unixerrno)
1.1 markus 61: {
62: int ret = 0;
1.22 deraadt 63:
1.2 markus 64: switch (unixerrno) {
1.1 markus 65: case 0:
1.10 markus 66: ret = SSH2_FX_OK;
1.1 markus 67: break;
68: case ENOENT:
69: case ENOTDIR:
70: case EBADF:
71: case ELOOP:
1.10 markus 72: ret = SSH2_FX_NO_SUCH_FILE;
1.1 markus 73: break;
74: case EPERM:
75: case EACCES:
76: case EFAULT:
1.10 markus 77: ret = SSH2_FX_PERMISSION_DENIED;
1.1 markus 78: break;
79: case ENAMETOOLONG:
80: case EINVAL:
1.10 markus 81: ret = SSH2_FX_BAD_MESSAGE;
1.1 markus 82: break;
83: default:
1.10 markus 84: ret = SSH2_FX_FAILURE;
1.1 markus 85: break;
86: }
87: return ret;
88: }
89:
1.28 itojun 90: static int
1.1 markus 91: flags_from_portable(int pflags)
92: {
93: int flags = 0;
1.22 deraadt 94:
1.20 deraadt 95: if ((pflags & SSH2_FXF_READ) &&
96: (pflags & SSH2_FXF_WRITE)) {
1.1 markus 97: flags = O_RDWR;
1.10 markus 98: } else if (pflags & SSH2_FXF_READ) {
1.1 markus 99: flags = O_RDONLY;
1.10 markus 100: } else if (pflags & SSH2_FXF_WRITE) {
1.1 markus 101: flags = O_WRONLY;
102: }
1.10 markus 103: if (pflags & SSH2_FXF_CREAT)
1.1 markus 104: flags |= O_CREAT;
1.10 markus 105: if (pflags & SSH2_FXF_TRUNC)
1.1 markus 106: flags |= O_TRUNC;
1.10 markus 107: if (pflags & SSH2_FXF_EXCL)
1.1 markus 108: flags |= O_EXCL;
109: return flags;
110: }
111:
1.28 itojun 112: static Attrib *
1.1 markus 113: get_attrib(void)
114: {
115: return decode_attrib(&iqueue);
116: }
117:
118: /* handle handles */
119:
120: typedef struct Handle Handle;
121: struct Handle {
122: int use;
123: DIR *dirp;
124: int fd;
125: char *name;
126: };
1.22 deraadt 127:
1.1 markus 128: enum {
129: HANDLE_UNUSED,
130: HANDLE_DIR,
131: HANDLE_FILE
132: };
1.22 deraadt 133:
1.1 markus 134: Handle handles[100];
135:
1.28 itojun 136: static void
1.1 markus 137: handle_init(void)
138: {
139: int i;
1.22 deraadt 140:
1.31 deraadt 141: for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
1.1 markus 142: handles[i].use = HANDLE_UNUSED;
143: }
144:
1.28 itojun 145: static int
1.1 markus 146: handle_new(int use, char *name, int fd, DIR *dirp)
147: {
148: int i;
1.22 deraadt 149:
1.31 deraadt 150: for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
1.1 markus 151: if (handles[i].use == HANDLE_UNUSED) {
152: handles[i].use = use;
153: handles[i].dirp = dirp;
154: handles[i].fd = fd;
1.38.2.1! margarid 155: handles[i].name = xstrdup(name);
1.1 markus 156: return i;
157: }
158: }
159: return -1;
160: }
161:
1.28 itojun 162: static int
1.1 markus 163: handle_is_ok(int i, int type)
164: {
1.10 markus 165: return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&
166: handles[i].use == type;
1.1 markus 167: }
168:
1.28 itojun 169: static int
1.1 markus 170: handle_to_string(int handle, char **stringp, int *hlenp)
171: {
172: if (stringp == NULL || hlenp == NULL)
173: return -1;
1.13 markus 174: *stringp = xmalloc(sizeof(int32_t));
175: PUT_32BIT(*stringp, handle);
176: *hlenp = sizeof(int32_t);
1.1 markus 177: return 0;
178: }
179:
1.28 itojun 180: static int
1.5 markus 181: handle_from_string(char *handle, u_int hlen)
1.1 markus 182: {
1.13 markus 183: int val;
1.22 deraadt 184:
1.13 markus 185: if (hlen != sizeof(int32_t))
1.1 markus 186: return -1;
1.13 markus 187: val = GET_32BIT(handle);
1.1 markus 188: if (handle_is_ok(val, HANDLE_FILE) ||
189: handle_is_ok(val, HANDLE_DIR))
190: return val;
191: return -1;
192: }
193:
1.28 itojun 194: static char *
1.1 markus 195: handle_to_name(int handle)
196: {
197: if (handle_is_ok(handle, HANDLE_DIR)||
198: handle_is_ok(handle, HANDLE_FILE))
199: return handles[handle].name;
200: return NULL;
201: }
202:
1.28 itojun 203: static DIR *
1.1 markus 204: handle_to_dir(int handle)
205: {
206: if (handle_is_ok(handle, HANDLE_DIR))
207: return handles[handle].dirp;
208: return NULL;
209: }
210:
1.28 itojun 211: static int
1.1 markus 212: handle_to_fd(int handle)
213: {
1.17 stevesk 214: if (handle_is_ok(handle, HANDLE_FILE))
1.1 markus 215: return handles[handle].fd;
216: return -1;
217: }
218:
1.28 itojun 219: static int
1.1 markus 220: handle_close(int handle)
221: {
222: int ret = -1;
1.22 deraadt 223:
1.1 markus 224: if (handle_is_ok(handle, HANDLE_FILE)) {
225: ret = close(handles[handle].fd);
226: handles[handle].use = HANDLE_UNUSED;
1.38.2.1! margarid 227: xfree(handles[handle].name);
1.1 markus 228: } else if (handle_is_ok(handle, HANDLE_DIR)) {
229: ret = closedir(handles[handle].dirp);
230: handles[handle].use = HANDLE_UNUSED;
1.38.2.1! margarid 231: xfree(handles[handle].name);
1.1 markus 232: } else {
233: errno = ENOENT;
234: }
235: return ret;
236: }
237:
1.28 itojun 238: static int
1.1 markus 239: get_handle(void)
240: {
241: char *handle;
1.10 markus 242: int val = -1;
1.5 markus 243: u_int hlen;
1.22 deraadt 244:
1.1 markus 245: handle = get_string(&hlen);
1.10 markus 246: if (hlen < 256)
247: val = handle_from_string(handle, hlen);
1.1 markus 248: xfree(handle);
249: return val;
250: }
251:
252: /* send replies */
253:
1.28 itojun 254: static void
1.1 markus 255: send_msg(Buffer *m)
256: {
257: int mlen = buffer_len(m);
1.22 deraadt 258:
1.1 markus 259: buffer_put_int(&oqueue, mlen);
260: buffer_append(&oqueue, buffer_ptr(m), mlen);
261: buffer_consume(m, mlen);
262: }
263:
1.28 itojun 264: static void
1.1 markus 265: send_status(u_int32_t id, u_int32_t error)
266: {
267: Buffer msg;
1.23 djm 268: const char *status_messages[] = {
269: "Success", /* SSH_FX_OK */
270: "End of file", /* SSH_FX_EOF */
271: "No such file", /* SSH_FX_NO_SUCH_FILE */
272: "Permission denied", /* SSH_FX_PERMISSION_DENIED */
273: "Failure", /* SSH_FX_FAILURE */
274: "Bad message", /* SSH_FX_BAD_MESSAGE */
275: "No connection", /* SSH_FX_NO_CONNECTION */
276: "Connection lost", /* SSH_FX_CONNECTION_LOST */
277: "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
278: "Unknown error" /* Others */
279: };
1.22 deraadt 280:
1.36 deraadt 281: TRACE("sent status id %u error %u", id, error);
1.1 markus 282: buffer_init(&msg);
1.10 markus 283: buffer_put_char(&msg, SSH2_FXP_STATUS);
1.1 markus 284: buffer_put_int(&msg, id);
285: buffer_put_int(&msg, error);
1.23 djm 286: if (version >= 3) {
1.25 markus 287: buffer_put_cstring(&msg,
1.23 djm 288: status_messages[MIN(error,SSH2_FX_MAX)]);
289: buffer_put_cstring(&msg, "");
290: }
1.1 markus 291: send_msg(&msg);
292: buffer_free(&msg);
293: }
1.28 itojun 294: static void
1.1 markus 295: send_data_or_handle(char type, u_int32_t id, char *data, int dlen)
296: {
297: Buffer msg;
1.22 deraadt 298:
1.1 markus 299: buffer_init(&msg);
300: buffer_put_char(&msg, type);
301: buffer_put_int(&msg, id);
302: buffer_put_string(&msg, data, dlen);
303: send_msg(&msg);
304: buffer_free(&msg);
305: }
306:
1.28 itojun 307: static void
1.1 markus 308: send_data(u_int32_t id, char *data, int dlen)
309: {
1.36 deraadt 310: TRACE("sent data id %u len %d", id, dlen);
1.10 markus 311: send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
1.1 markus 312: }
313:
1.28 itojun 314: static void
1.1 markus 315: send_handle(u_int32_t id, int handle)
316: {
317: char *string;
318: int hlen;
1.22 deraadt 319:
1.1 markus 320: handle_to_string(handle, &string, &hlen);
1.36 deraadt 321: TRACE("sent handle id %u handle %d", id, handle);
1.10 markus 322: send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
1.1 markus 323: xfree(string);
324: }
325:
1.28 itojun 326: static void
1.1 markus 327: send_names(u_int32_t id, int count, Stat *stats)
328: {
329: Buffer msg;
330: int i;
1.22 deraadt 331:
1.1 markus 332: buffer_init(&msg);
1.10 markus 333: buffer_put_char(&msg, SSH2_FXP_NAME);
1.1 markus 334: buffer_put_int(&msg, id);
335: buffer_put_int(&msg, count);
1.36 deraadt 336: TRACE("sent names id %u count %d", id, count);
1.1 markus 337: for (i = 0; i < count; i++) {
338: buffer_put_cstring(&msg, stats[i].name);
339: buffer_put_cstring(&msg, stats[i].long_name);
340: encode_attrib(&msg, &stats[i].attrib);
341: }
342: send_msg(&msg);
343: buffer_free(&msg);
344: }
345:
1.28 itojun 346: static void
1.1 markus 347: send_attrib(u_int32_t id, Attrib *a)
348: {
349: Buffer msg;
1.22 deraadt 350:
1.36 deraadt 351: TRACE("sent attrib id %u have 0x%x", id, a->flags);
1.1 markus 352: buffer_init(&msg);
1.10 markus 353: buffer_put_char(&msg, SSH2_FXP_ATTRS);
1.1 markus 354: buffer_put_int(&msg, id);
355: encode_attrib(&msg, a);
356: send_msg(&msg);
357: buffer_free(&msg);
358: }
359:
360: /* parse incoming */
361:
1.28 itojun 362: static void
1.1 markus 363: process_init(void)
364: {
365: Buffer msg;
366:
1.35 markus 367: version = get_int();
1.1 markus 368: TRACE("client version %d", version);
369: buffer_init(&msg);
1.10 markus 370: buffer_put_char(&msg, SSH2_FXP_VERSION);
371: buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
1.1 markus 372: send_msg(&msg);
373: buffer_free(&msg);
374: }
375:
1.28 itojun 376: static void
1.1 markus 377: process_open(void)
378: {
379: u_int32_t id, pflags;
380: Attrib *a;
381: char *name;
1.10 markus 382: int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1 markus 383:
384: id = get_int();
385: name = get_string(NULL);
1.10 markus 386: pflags = get_int(); /* portable flags */
1.1 markus 387: a = get_attrib();
388: flags = flags_from_portable(pflags);
1.10 markus 389: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.36 deraadt 390: TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode);
1.1 markus 391: fd = open(name, flags, mode);
392: if (fd < 0) {
393: status = errno_to_portable(errno);
394: } else {
1.38.2.1! margarid 395: handle = handle_new(HANDLE_FILE, name, fd, NULL);
1.1 markus 396: if (handle < 0) {
397: close(fd);
398: } else {
399: send_handle(id, handle);
1.10 markus 400: status = SSH2_FX_OK;
1.1 markus 401: }
402: }
1.10 markus 403: if (status != SSH2_FX_OK)
1.1 markus 404: send_status(id, status);
405: xfree(name);
406: }
407:
1.28 itojun 408: static void
1.1 markus 409: process_close(void)
410: {
411: u_int32_t id;
1.10 markus 412: int handle, ret, status = SSH2_FX_FAILURE;
1.1 markus 413:
414: id = get_int();
415: handle = get_handle();
1.36 deraadt 416: TRACE("close id %u handle %d", id, handle);
1.1 markus 417: ret = handle_close(handle);
1.10 markus 418: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 419: send_status(id, status);
420: }
421:
1.28 itojun 422: static void
1.1 markus 423: process_read(void)
424: {
425: char buf[64*1024];
1.10 markus 426: u_int32_t id, len;
427: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 428: u_int64_t off;
429:
430: id = get_int();
431: handle = get_handle();
1.10 markus 432: off = get_int64();
1.1 markus 433: len = get_int();
434:
1.36 deraadt 435: TRACE("read id %u handle %d off %llu len %d", id, handle,
1.16 deraadt 436: (unsigned long long)off, len);
1.1 markus 437: if (len > sizeof buf) {
438: len = sizeof buf;
439: log("read change len %d", len);
440: }
441: fd = handle_to_fd(handle);
442: if (fd >= 0) {
443: if (lseek(fd, off, SEEK_SET) < 0) {
444: error("process_read: seek failed");
445: status = errno_to_portable(errno);
446: } else {
447: ret = read(fd, buf, len);
448: if (ret < 0) {
449: status = errno_to_portable(errno);
450: } else if (ret == 0) {
1.10 markus 451: status = SSH2_FX_EOF;
1.1 markus 452: } else {
453: send_data(id, buf, ret);
1.10 markus 454: status = SSH2_FX_OK;
1.1 markus 455: }
456: }
457: }
1.10 markus 458: if (status != SSH2_FX_OK)
1.1 markus 459: send_status(id, status);
460: }
461:
1.28 itojun 462: static void
1.1 markus 463: process_write(void)
464: {
1.10 markus 465: u_int32_t id;
1.1 markus 466: u_int64_t off;
1.5 markus 467: u_int len;
1.10 markus 468: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 469: char *data;
470:
471: id = get_int();
472: handle = get_handle();
1.10 markus 473: off = get_int64();
1.1 markus 474: data = get_string(&len);
475:
1.36 deraadt 476: TRACE("write id %u handle %d off %llu len %d", id, handle,
1.16 deraadt 477: (unsigned long long)off, len);
1.1 markus 478: fd = handle_to_fd(handle);
479: if (fd >= 0) {
480: if (lseek(fd, off, SEEK_SET) < 0) {
481: status = errno_to_portable(errno);
482: error("process_write: seek failed");
483: } else {
484: /* XXX ATOMICIO ? */
485: ret = write(fd, data, len);
486: if (ret == -1) {
487: error("process_write: write failed");
488: status = errno_to_portable(errno);
489: } else if (ret == len) {
1.10 markus 490: status = SSH2_FX_OK;
1.1 markus 491: } else {
492: log("nothing at all written");
493: }
494: }
495: }
496: send_status(id, status);
497: xfree(data);
498: }
499:
1.28 itojun 500: static void
1.1 markus 501: process_do_stat(int do_lstat)
502: {
1.13 markus 503: Attrib a;
1.1 markus 504: struct stat st;
505: u_int32_t id;
506: char *name;
1.10 markus 507: int ret, status = SSH2_FX_FAILURE;
1.1 markus 508:
509: id = get_int();
510: name = get_string(NULL);
1.36 deraadt 511: TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name);
1.1 markus 512: ret = do_lstat ? lstat(name, &st) : stat(name, &st);
513: if (ret < 0) {
514: status = errno_to_portable(errno);
515: } else {
1.13 markus 516: stat_to_attrib(&st, &a);
517: send_attrib(id, &a);
1.10 markus 518: status = SSH2_FX_OK;
1.1 markus 519: }
1.10 markus 520: if (status != SSH2_FX_OK)
1.1 markus 521: send_status(id, status);
522: xfree(name);
523: }
524:
1.28 itojun 525: static void
1.1 markus 526: process_stat(void)
527: {
528: process_do_stat(0);
529: }
530:
1.28 itojun 531: static void
1.1 markus 532: process_lstat(void)
533: {
534: process_do_stat(1);
535: }
536:
1.28 itojun 537: static void
1.1 markus 538: process_fstat(void)
539: {
1.13 markus 540: Attrib a;
1.1 markus 541: struct stat st;
542: u_int32_t id;
1.10 markus 543: int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1 markus 544:
545: id = get_int();
546: handle = get_handle();
1.36 deraadt 547: TRACE("fstat id %u handle %d", id, handle);
1.1 markus 548: fd = handle_to_fd(handle);
549: if (fd >= 0) {
550: ret = fstat(fd, &st);
551: if (ret < 0) {
552: status = errno_to_portable(errno);
553: } else {
1.13 markus 554: stat_to_attrib(&st, &a);
555: send_attrib(id, &a);
1.10 markus 556: status = SSH2_FX_OK;
1.1 markus 557: }
558: }
1.10 markus 559: if (status != SSH2_FX_OK)
1.1 markus 560: send_status(id, status);
561: }
562:
1.28 itojun 563: static struct timeval *
1.1 markus 564: attrib_to_tv(Attrib *a)
565: {
566: static struct timeval tv[2];
1.22 deraadt 567:
1.1 markus 568: tv[0].tv_sec = a->atime;
569: tv[0].tv_usec = 0;
570: tv[1].tv_sec = a->mtime;
571: tv[1].tv_usec = 0;
572: return tv;
573: }
574:
1.28 itojun 575: static void
1.1 markus 576: process_setstat(void)
577: {
578: Attrib *a;
579: u_int32_t id;
580: char *name;
1.36 deraadt 581: int status = SSH2_FX_OK, ret;
1.1 markus 582:
583: id = get_int();
584: name = get_string(NULL);
585: a = get_attrib();
1.36 deraadt 586: TRACE("setstat id %u name %s", id, name);
1.33 markus 587: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
588: ret = truncate(name, a->size);
589: if (ret == -1)
590: status = errno_to_portable(errno);
591: }
1.10 markus 592: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 593: ret = chmod(name, a->perm & 0777);
594: if (ret == -1)
595: status = errno_to_portable(errno);
596: }
1.10 markus 597: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 598: ret = utimes(name, attrib_to_tv(a));
599: if (ret == -1)
600: status = errno_to_portable(errno);
601: }
1.18 stevesk 602: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
603: ret = chown(name, a->uid, a->gid);
604: if (ret == -1)
605: status = errno_to_portable(errno);
606: }
1.1 markus 607: send_status(id, status);
608: xfree(name);
609: }
610:
1.28 itojun 611: static void
1.1 markus 612: process_fsetstat(void)
613: {
614: Attrib *a;
615: u_int32_t id;
616: int handle, fd, ret;
1.10 markus 617: int status = SSH2_FX_OK;
1.1 markus 618:
619: id = get_int();
620: handle = get_handle();
621: a = get_attrib();
1.36 deraadt 622: TRACE("fsetstat id %u handle %d", id, handle);
1.1 markus 623: fd = handle_to_fd(handle);
624: if (fd < 0) {
1.10 markus 625: status = SSH2_FX_FAILURE;
1.1 markus 626: } else {
1.33 markus 627: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
628: ret = ftruncate(fd, a->size);
629: if (ret == -1)
630: status = errno_to_portable(errno);
631: }
1.10 markus 632: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 633: ret = fchmod(fd, a->perm & 0777);
634: if (ret == -1)
635: status = errno_to_portable(errno);
636: }
1.10 markus 637: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 638: ret = futimes(fd, attrib_to_tv(a));
1.18 stevesk 639: if (ret == -1)
640: status = errno_to_portable(errno);
641: }
642: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
643: ret = fchown(fd, a->uid, a->gid);
1.1 markus 644: if (ret == -1)
645: status = errno_to_portable(errno);
646: }
647: }
648: send_status(id, status);
649: }
650:
1.28 itojun 651: static void
1.1 markus 652: process_opendir(void)
653: {
654: DIR *dirp = NULL;
655: char *path;
1.10 markus 656: int handle, status = SSH2_FX_FAILURE;
1.1 markus 657: u_int32_t id;
658:
659: id = get_int();
660: path = get_string(NULL);
1.36 deraadt 661: TRACE("opendir id %u path %s", id, path);
1.17 stevesk 662: dirp = opendir(path);
1.1 markus 663: if (dirp == NULL) {
664: status = errno_to_portable(errno);
665: } else {
1.38.2.1! margarid 666: handle = handle_new(HANDLE_DIR, path, 0, dirp);
1.1 markus 667: if (handle < 0) {
668: closedir(dirp);
669: } else {
670: send_handle(id, handle);
1.10 markus 671: status = SSH2_FX_OK;
1.1 markus 672: }
1.17 stevesk 673:
1.1 markus 674: }
1.10 markus 675: if (status != SSH2_FX_OK)
1.1 markus 676: send_status(id, status);
677: xfree(path);
678: }
679:
1.28 itojun 680: static void
1.1 markus 681: process_readdir(void)
682: {
683: DIR *dirp;
684: struct dirent *dp;
685: char *path;
686: int handle;
687: u_int32_t id;
688:
689: id = get_int();
690: handle = get_handle();
1.36 deraadt 691: TRACE("readdir id %u handle %d", id, handle);
1.1 markus 692: dirp = handle_to_dir(handle);
693: path = handle_to_name(handle);
694: if (dirp == NULL || path == NULL) {
1.10 markus 695: send_status(id, SSH2_FX_FAILURE);
1.1 markus 696: } else {
697: struct stat st;
698: char pathname[1024];
699: Stat *stats;
700: int nstats = 10, count = 0, i;
1.36 deraadt 701:
1.1 markus 702: stats = xmalloc(nstats * sizeof(Stat));
703: while ((dp = readdir(dirp)) != NULL) {
704: if (count >= nstats) {
705: nstats *= 2;
706: stats = xrealloc(stats, nstats * sizeof(Stat));
707: }
708: /* XXX OVERFLOW ? */
1.30 jakob 709: snprintf(pathname, sizeof pathname, "%s%s%s", path,
710: strcmp(path, "/") ? "/" : "", dp->d_name);
1.1 markus 711: if (lstat(pathname, &st) < 0)
712: continue;
1.13 markus 713: stat_to_attrib(&st, &(stats[count].attrib));
1.1 markus 714: stats[count].name = xstrdup(dp->d_name);
1.38 djm 715: stats[count].long_name = ls_file(dp->d_name, &st, 0);
1.1 markus 716: count++;
717: /* send up to 100 entries in one message */
1.11 markus 718: /* XXX check packet size instead */
1.1 markus 719: if (count == 100)
720: break;
721: }
1.10 markus 722: if (count > 0) {
723: send_names(id, count, stats);
1.31 deraadt 724: for (i = 0; i < count; i++) {
1.10 markus 725: xfree(stats[i].name);
726: xfree(stats[i].long_name);
727: }
728: } else {
729: send_status(id, SSH2_FX_EOF);
1.1 markus 730: }
731: xfree(stats);
732: }
733: }
734:
1.28 itojun 735: static void
1.1 markus 736: process_remove(void)
737: {
738: char *name;
739: u_int32_t id;
1.10 markus 740: int status = SSH2_FX_FAILURE;
1.1 markus 741: int ret;
742:
743: id = get_int();
744: name = get_string(NULL);
1.36 deraadt 745: TRACE("remove id %u name %s", id, name);
1.8 markus 746: ret = unlink(name);
1.10 markus 747: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 748: send_status(id, status);
749: xfree(name);
750: }
751:
1.28 itojun 752: static void
1.1 markus 753: process_mkdir(void)
754: {
755: Attrib *a;
756: u_int32_t id;
757: char *name;
1.10 markus 758: int ret, mode, status = SSH2_FX_FAILURE;
1.1 markus 759:
760: id = get_int();
761: name = get_string(NULL);
762: a = get_attrib();
1.10 markus 763: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
764: a->perm & 0777 : 0777;
1.36 deraadt 765: TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
1.1 markus 766: ret = mkdir(name, mode);
1.10 markus 767: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 768: send_status(id, status);
769: xfree(name);
770: }
771:
1.28 itojun 772: static void
1.1 markus 773: process_rmdir(void)
774: {
775: u_int32_t id;
776: char *name;
777: int ret, status;
778:
779: id = get_int();
780: name = get_string(NULL);
1.36 deraadt 781: TRACE("rmdir id %u name %s", id, name);
1.1 markus 782: ret = rmdir(name);
1.10 markus 783: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 784: send_status(id, status);
785: xfree(name);
786: }
787:
1.28 itojun 788: static void
1.1 markus 789: process_realpath(void)
790: {
791: char resolvedname[MAXPATHLEN];
792: u_int32_t id;
793: char *path;
794:
795: id = get_int();
796: path = get_string(NULL);
1.7 markus 797: if (path[0] == '\0') {
798: xfree(path);
799: path = xstrdup(".");
800: }
1.36 deraadt 801: TRACE("realpath id %u path %s", id, path);
1.1 markus 802: if (realpath(path, resolvedname) == NULL) {
803: send_status(id, errno_to_portable(errno));
804: } else {
805: Stat s;
806: attrib_clear(&s.attrib);
807: s.name = s.long_name = resolvedname;
808: send_names(id, 1, &s);
809: }
810: xfree(path);
811: }
812:
1.28 itojun 813: static void
1.1 markus 814: process_rename(void)
815: {
816: u_int32_t id;
817: char *oldpath, *newpath;
1.38.2.1! margarid 818: int status;
1.1 markus 819:
820: id = get_int();
821: oldpath = get_string(NULL);
822: newpath = get_string(NULL);
1.36 deraadt 823: TRACE("rename id %u old %s new %s", id, oldpath, newpath);
1.11 markus 824: /* fail if 'newpath' exists */
1.38.2.1! margarid 825: if (link(oldpath, newpath) == -1)
! 826: status = errno_to_portable(errno);
! 827: else if (unlink(oldpath) == -1) {
! 828: status = errno_to_portable(errno);
! 829: /* clean spare link */
! 830: unlink(newpath);
! 831: } else
! 832: status = SSH2_FX_OK;
1.1 markus 833: send_status(id, status);
834: xfree(oldpath);
835: xfree(newpath);
836: }
837:
1.28 itojun 838: static void
1.23 djm 839: process_readlink(void)
840: {
841: u_int32_t id;
1.26 markus 842: int len;
1.23 djm 843: char link[MAXPATHLEN];
844: char *path;
845:
846: id = get_int();
847: path = get_string(NULL);
1.36 deraadt 848: TRACE("readlink id %u path %s", id, path);
1.26 markus 849: if ((len = readlink(path, link, sizeof(link) - 1)) == -1)
1.23 djm 850: send_status(id, errno_to_portable(errno));
851: else {
852: Stat s;
1.31 deraadt 853:
1.26 markus 854: link[len] = '\0';
1.23 djm 855: attrib_clear(&s.attrib);
856: s.name = s.long_name = link;
857: send_names(id, 1, &s);
858: }
859: xfree(path);
860: }
861:
1.28 itojun 862: static void
1.23 djm 863: process_symlink(void)
864: {
865: u_int32_t id;
866: char *oldpath, *newpath;
1.38.2.1! margarid 867: int ret, status;
1.23 djm 868:
869: id = get_int();
870: oldpath = get_string(NULL);
871: newpath = get_string(NULL);
1.36 deraadt 872: TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
1.38.2.1! margarid 873: /* this will fail if 'newpath' exists */
! 874: ret = symlink(oldpath, newpath);
! 875: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.23 djm 876: send_status(id, status);
877: xfree(oldpath);
878: xfree(newpath);
879: }
880:
1.28 itojun 881: static void
1.10 markus 882: process_extended(void)
883: {
884: u_int32_t id;
885: char *request;
886:
887: id = get_int();
888: request = get_string(NULL);
889: send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
890: xfree(request);
891: }
1.1 markus 892:
893: /* stolen from ssh-agent */
894:
1.28 itojun 895: static void
1.1 markus 896: process(void)
897: {
1.9 markus 898: u_int msg_len;
1.34 markus 899: u_int buf_len;
900: u_int consumed;
1.9 markus 901: u_int type;
902: u_char *cp;
1.1 markus 903:
1.34 markus 904: buf_len = buffer_len(&iqueue);
905: if (buf_len < 5)
1.1 markus 906: return; /* Incomplete message. */
1.32 stevesk 907: cp = buffer_ptr(&iqueue);
1.1 markus 908: msg_len = GET_32BIT(cp);
909: if (msg_len > 256 * 1024) {
910: error("bad message ");
911: exit(11);
912: }
1.34 markus 913: if (buf_len < msg_len + 4)
1.1 markus 914: return;
915: buffer_consume(&iqueue, 4);
1.34 markus 916: buf_len -= 4;
1.1 markus 917: type = buffer_get_char(&iqueue);
918: switch (type) {
1.10 markus 919: case SSH2_FXP_INIT:
1.1 markus 920: process_init();
921: break;
1.10 markus 922: case SSH2_FXP_OPEN:
1.1 markus 923: process_open();
924: break;
1.10 markus 925: case SSH2_FXP_CLOSE:
1.1 markus 926: process_close();
927: break;
1.10 markus 928: case SSH2_FXP_READ:
1.1 markus 929: process_read();
930: break;
1.10 markus 931: case SSH2_FXP_WRITE:
1.1 markus 932: process_write();
933: break;
1.10 markus 934: case SSH2_FXP_LSTAT:
1.1 markus 935: process_lstat();
936: break;
1.10 markus 937: case SSH2_FXP_FSTAT:
1.1 markus 938: process_fstat();
939: break;
1.10 markus 940: case SSH2_FXP_SETSTAT:
1.1 markus 941: process_setstat();
942: break;
1.10 markus 943: case SSH2_FXP_FSETSTAT:
1.1 markus 944: process_fsetstat();
945: break;
1.10 markus 946: case SSH2_FXP_OPENDIR:
1.1 markus 947: process_opendir();
948: break;
1.10 markus 949: case SSH2_FXP_READDIR:
1.1 markus 950: process_readdir();
951: break;
1.10 markus 952: case SSH2_FXP_REMOVE:
1.1 markus 953: process_remove();
954: break;
1.10 markus 955: case SSH2_FXP_MKDIR:
1.1 markus 956: process_mkdir();
957: break;
1.10 markus 958: case SSH2_FXP_RMDIR:
1.1 markus 959: process_rmdir();
960: break;
1.10 markus 961: case SSH2_FXP_REALPATH:
1.1 markus 962: process_realpath();
963: break;
1.10 markus 964: case SSH2_FXP_STAT:
1.1 markus 965: process_stat();
966: break;
1.10 markus 967: case SSH2_FXP_RENAME:
1.1 markus 968: process_rename();
1.23 djm 969: break;
970: case SSH2_FXP_READLINK:
971: process_readlink();
972: break;
973: case SSH2_FXP_SYMLINK:
974: process_symlink();
1.1 markus 975: break;
1.10 markus 976: case SSH2_FXP_EXTENDED:
977: process_extended();
978: break;
1.1 markus 979: default:
980: error("Unknown message %d", type);
981: break;
982: }
1.34 markus 983: /* discard the remaining bytes from the current packet */
984: if (buf_len < buffer_len(&iqueue))
985: fatal("iqueue grows");
986: consumed = buf_len - buffer_len(&iqueue);
987: if (msg_len < consumed)
988: fatal("msg_len %d < consumed %d", msg_len, consumed);
989: if (msg_len > consumed)
990: buffer_consume(&iqueue, msg_len - consumed);
1.1 markus 991: }
992:
993: int
994: main(int ac, char **av)
995: {
1.21 millert 996: fd_set *rset, *wset;
1.1 markus 997: int in, out, max;
1.21 millert 998: ssize_t len, olen, set_size;
1.24 deraadt 999:
1000: /* XXX should use getopt */
1.1 markus 1001:
1002: handle_init();
1.10 markus 1003:
1.11 markus 1004: #ifdef DEBUG_SFTP_SERVER
1.17 stevesk 1005: log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1.11 markus 1006: #endif
1.1 markus 1007:
1008: in = dup(STDIN_FILENO);
1009: out = dup(STDOUT_FILENO);
1010:
1011: max = 0;
1012: if (in > max)
1013: max = in;
1014: if (out > max)
1015: max = out;
1016:
1017: buffer_init(&iqueue);
1018: buffer_init(&oqueue);
1019:
1.21 millert 1020: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1021: rset = (fd_set *)xmalloc(set_size);
1022: wset = (fd_set *)xmalloc(set_size);
1023:
1.1 markus 1024: for (;;) {
1.21 millert 1025: memset(rset, 0, set_size);
1026: memset(wset, 0, set_size);
1.1 markus 1027:
1.21 millert 1028: FD_SET(in, rset);
1.1 markus 1029: olen = buffer_len(&oqueue);
1030: if (olen > 0)
1.21 millert 1031: FD_SET(out, wset);
1.1 markus 1032:
1.21 millert 1033: if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1 markus 1034: if (errno == EINTR)
1035: continue;
1036: exit(2);
1037: }
1038:
1039: /* copy stdin to iqueue */
1.21 millert 1040: if (FD_ISSET(in, rset)) {
1.1 markus 1041: char buf[4*4096];
1042: len = read(in, buf, sizeof buf);
1043: if (len == 0) {
1044: debug("read eof");
1045: exit(0);
1046: } else if (len < 0) {
1047: error("read error");
1048: exit(1);
1049: } else {
1050: buffer_append(&iqueue, buf, len);
1051: }
1052: }
1053: /* send oqueue to stdout */
1.21 millert 1054: if (FD_ISSET(out, wset)) {
1.1 markus 1055: len = write(out, buffer_ptr(&oqueue), olen);
1056: if (len < 0) {
1057: error("write error");
1058: exit(1);
1059: } else {
1060: buffer_consume(&oqueue, len);
1061: }
1062: }
1063: /* process requests from client */
1064: process();
1065: }
1066: }