Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.30.2.4
1.1 markus 1: /*
1.30.2.1 jason 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.30.2.4! miod 25: RCSID("$OpenBSD: sftp-server.c,v 1.38 2002/09/11 22:41:50 djm 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.30.2.1 jason 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.30.2.1 jason 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;
155: handles[i].name = name;
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;
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:
1.28 itojun 236: static int
1.1 markus 237: get_handle(void)
238: {
239: char *handle;
1.10 markus 240: int val = -1;
1.5 markus 241: u_int hlen;
1.22 deraadt 242:
1.1 markus 243: handle = get_string(&hlen);
1.10 markus 244: if (hlen < 256)
245: val = handle_from_string(handle, hlen);
1.1 markus 246: xfree(handle);
247: return val;
248: }
249:
250: /* send replies */
251:
1.28 itojun 252: static void
1.1 markus 253: send_msg(Buffer *m)
254: {
255: int mlen = buffer_len(m);
1.22 deraadt 256:
1.1 markus 257: buffer_put_int(&oqueue, mlen);
258: buffer_append(&oqueue, buffer_ptr(m), mlen);
259: buffer_consume(m, mlen);
260: }
261:
1.28 itojun 262: static void
1.1 markus 263: send_status(u_int32_t id, u_int32_t error)
264: {
265: Buffer msg;
1.23 djm 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: };
1.22 deraadt 278:
1.30.2.3 miod 279: TRACE("sent status id %u error %u", id, error);
1.1 markus 280: buffer_init(&msg);
1.10 markus 281: buffer_put_char(&msg, SSH2_FXP_STATUS);
1.1 markus 282: buffer_put_int(&msg, id);
283: buffer_put_int(&msg, error);
1.23 djm 284: if (version >= 3) {
1.25 markus 285: buffer_put_cstring(&msg,
1.23 djm 286: status_messages[MIN(error,SSH2_FX_MAX)]);
287: buffer_put_cstring(&msg, "");
288: }
1.1 markus 289: send_msg(&msg);
290: buffer_free(&msg);
291: }
1.28 itojun 292: static void
1.1 markus 293: send_data_or_handle(char type, u_int32_t id, char *data, int dlen)
294: {
295: Buffer msg;
1.22 deraadt 296:
1.1 markus 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:
1.28 itojun 305: static void
1.1 markus 306: send_data(u_int32_t id, char *data, int dlen)
307: {
1.30.2.3 miod 308: TRACE("sent data id %u len %d", id, dlen);
1.10 markus 309: send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
1.1 markus 310: }
311:
1.28 itojun 312: static void
1.1 markus 313: send_handle(u_int32_t id, int handle)
314: {
315: char *string;
316: int hlen;
1.22 deraadt 317:
1.1 markus 318: handle_to_string(handle, &string, &hlen);
1.30.2.3 miod 319: TRACE("sent handle id %u handle %d", id, handle);
1.10 markus 320: send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
1.1 markus 321: xfree(string);
322: }
323:
1.28 itojun 324: static void
1.1 markus 325: send_names(u_int32_t id, int count, Stat *stats)
326: {
327: Buffer msg;
328: int i;
1.22 deraadt 329:
1.1 markus 330: buffer_init(&msg);
1.10 markus 331: buffer_put_char(&msg, SSH2_FXP_NAME);
1.1 markus 332: buffer_put_int(&msg, id);
333: buffer_put_int(&msg, count);
1.30.2.3 miod 334: TRACE("sent names id %u count %d", id, count);
1.1 markus 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:
1.28 itojun 344: static void
1.1 markus 345: send_attrib(u_int32_t id, Attrib *a)
346: {
347: Buffer msg;
1.22 deraadt 348:
1.30.2.3 miod 349: TRACE("sent attrib id %u have 0x%x", id, a->flags);
1.1 markus 350: buffer_init(&msg);
1.10 markus 351: buffer_put_char(&msg, SSH2_FXP_ATTRS);
1.1 markus 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:
1.28 itojun 360: static void
1.1 markus 361: process_init(void)
362: {
363: Buffer msg;
364:
1.30.2.2 miod 365: version = get_int();
1.1 markus 366: TRACE("client version %d", version);
367: buffer_init(&msg);
1.10 markus 368: buffer_put_char(&msg, SSH2_FXP_VERSION);
369: buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
1.1 markus 370: send_msg(&msg);
371: buffer_free(&msg);
372: }
373:
1.28 itojun 374: static void
1.1 markus 375: process_open(void)
376: {
377: u_int32_t id, pflags;
378: Attrib *a;
379: char *name;
1.10 markus 380: int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1 markus 381:
382: id = get_int();
383: name = get_string(NULL);
1.10 markus 384: pflags = get_int(); /* portable flags */
1.1 markus 385: a = get_attrib();
386: flags = flags_from_portable(pflags);
1.10 markus 387: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.30.2.3 miod 388: TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode);
1.1 markus 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);
1.10 markus 398: status = SSH2_FX_OK;
1.1 markus 399: }
400: }
1.10 markus 401: if (status != SSH2_FX_OK)
1.1 markus 402: send_status(id, status);
403: xfree(name);
404: }
405:
1.28 itojun 406: static void
1.1 markus 407: process_close(void)
408: {
409: u_int32_t id;
1.10 markus 410: int handle, ret, status = SSH2_FX_FAILURE;
1.1 markus 411:
412: id = get_int();
413: handle = get_handle();
1.30.2.3 miod 414: TRACE("close id %u handle %d", id, handle);
1.1 markus 415: ret = handle_close(handle);
1.10 markus 416: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 417: send_status(id, status);
418: }
419:
1.28 itojun 420: static void
1.1 markus 421: process_read(void)
422: {
423: char buf[64*1024];
1.10 markus 424: u_int32_t id, len;
425: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 426: u_int64_t off;
427:
428: id = get_int();
429: handle = get_handle();
1.10 markus 430: off = get_int64();
1.1 markus 431: len = get_int();
432:
1.30.2.3 miod 433: TRACE("read id %u handle %d off %llu len %d", id, handle,
1.16 deraadt 434: (unsigned long long)off, len);
1.1 markus 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) {
1.10 markus 449: status = SSH2_FX_EOF;
1.1 markus 450: } else {
451: send_data(id, buf, ret);
1.10 markus 452: status = SSH2_FX_OK;
1.1 markus 453: }
454: }
455: }
1.10 markus 456: if (status != SSH2_FX_OK)
1.1 markus 457: send_status(id, status);
458: }
459:
1.28 itojun 460: static void
1.1 markus 461: process_write(void)
462: {
1.10 markus 463: u_int32_t id;
1.1 markus 464: u_int64_t off;
1.5 markus 465: u_int len;
1.10 markus 466: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 467: char *data;
468:
469: id = get_int();
470: handle = get_handle();
1.10 markus 471: off = get_int64();
1.1 markus 472: data = get_string(&len);
473:
1.30.2.3 miod 474: TRACE("write id %u handle %d off %llu len %d", id, handle,
1.16 deraadt 475: (unsigned long long)off, len);
1.1 markus 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) {
1.10 markus 488: status = SSH2_FX_OK;
1.1 markus 489: } else {
490: log("nothing at all written");
491: }
492: }
493: }
494: send_status(id, status);
495: xfree(data);
496: }
497:
1.28 itojun 498: static void
1.1 markus 499: process_do_stat(int do_lstat)
500: {
1.13 markus 501: Attrib a;
1.1 markus 502: struct stat st;
503: u_int32_t id;
504: char *name;
1.10 markus 505: int ret, status = SSH2_FX_FAILURE;
1.1 markus 506:
507: id = get_int();
508: name = get_string(NULL);
1.30.2.3 miod 509: TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name);
1.1 markus 510: ret = do_lstat ? lstat(name, &st) : stat(name, &st);
511: if (ret < 0) {
512: status = errno_to_portable(errno);
513: } else {
1.13 markus 514: stat_to_attrib(&st, &a);
515: send_attrib(id, &a);
1.10 markus 516: status = SSH2_FX_OK;
1.1 markus 517: }
1.10 markus 518: if (status != SSH2_FX_OK)
1.1 markus 519: send_status(id, status);
520: xfree(name);
521: }
522:
1.28 itojun 523: static void
1.1 markus 524: process_stat(void)
525: {
526: process_do_stat(0);
527: }
528:
1.28 itojun 529: static void
1.1 markus 530: process_lstat(void)
531: {
532: process_do_stat(1);
533: }
534:
1.28 itojun 535: static void
1.1 markus 536: process_fstat(void)
537: {
1.13 markus 538: Attrib a;
1.1 markus 539: struct stat st;
540: u_int32_t id;
1.10 markus 541: int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1 markus 542:
543: id = get_int();
544: handle = get_handle();
1.30.2.3 miod 545: TRACE("fstat id %u handle %d", id, handle);
1.1 markus 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 {
1.13 markus 552: stat_to_attrib(&st, &a);
553: send_attrib(id, &a);
1.10 markus 554: status = SSH2_FX_OK;
1.1 markus 555: }
556: }
1.10 markus 557: if (status != SSH2_FX_OK)
1.1 markus 558: send_status(id, status);
559: }
560:
1.28 itojun 561: static struct timeval *
1.1 markus 562: attrib_to_tv(Attrib *a)
563: {
564: static struct timeval tv[2];
1.22 deraadt 565:
1.1 markus 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:
1.28 itojun 573: static void
1.1 markus 574: process_setstat(void)
575: {
576: Attrib *a;
577: u_int32_t id;
578: char *name;
1.30.2.3 miod 579: int status = SSH2_FX_OK, ret;
1.1 markus 580:
581: id = get_int();
582: name = get_string(NULL);
583: a = get_attrib();
1.30.2.3 miod 584: TRACE("setstat id %u name %s", id, name);
1.30.2.1 jason 585: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
586: ret = truncate(name, a->size);
587: if (ret == -1)
588: status = errno_to_portable(errno);
589: }
1.10 markus 590: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 591: ret = chmod(name, a->perm & 0777);
592: if (ret == -1)
593: status = errno_to_portable(errno);
594: }
1.10 markus 595: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 596: ret = utimes(name, attrib_to_tv(a));
597: if (ret == -1)
598: status = errno_to_portable(errno);
599: }
1.18 stevesk 600: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
601: ret = chown(name, a->uid, a->gid);
602: if (ret == -1)
603: status = errno_to_portable(errno);
604: }
1.1 markus 605: send_status(id, status);
606: xfree(name);
607: }
608:
1.28 itojun 609: static void
1.1 markus 610: process_fsetstat(void)
611: {
612: Attrib *a;
613: u_int32_t id;
614: int handle, fd, ret;
1.10 markus 615: int status = SSH2_FX_OK;
1.1 markus 616:
617: id = get_int();
618: handle = get_handle();
619: a = get_attrib();
1.30.2.3 miod 620: TRACE("fsetstat id %u handle %d", id, handle);
1.1 markus 621: fd = handle_to_fd(handle);
622: if (fd < 0) {
1.10 markus 623: status = SSH2_FX_FAILURE;
1.1 markus 624: } else {
1.30.2.1 jason 625: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
626: ret = ftruncate(fd, a->size);
627: if (ret == -1)
628: status = errno_to_portable(errno);
629: }
1.10 markus 630: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 631: ret = fchmod(fd, a->perm & 0777);
632: if (ret == -1)
633: status = errno_to_portable(errno);
634: }
1.10 markus 635: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 636: ret = futimes(fd, attrib_to_tv(a));
1.18 stevesk 637: if (ret == -1)
638: status = errno_to_portable(errno);
639: }
640: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
641: ret = fchown(fd, a->uid, a->gid);
1.1 markus 642: if (ret == -1)
643: status = errno_to_portable(errno);
644: }
645: }
646: send_status(id, status);
647: }
648:
1.28 itojun 649: static void
1.1 markus 650: process_opendir(void)
651: {
652: DIR *dirp = NULL;
653: char *path;
1.10 markus 654: int handle, status = SSH2_FX_FAILURE;
1.1 markus 655: u_int32_t id;
656:
657: id = get_int();
658: path = get_string(NULL);
1.30.2.3 miod 659: TRACE("opendir id %u path %s", id, path);
1.17 stevesk 660: dirp = opendir(path);
1.1 markus 661: if (dirp == NULL) {
662: status = errno_to_portable(errno);
663: } else {
664: handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp);
665: if (handle < 0) {
666: closedir(dirp);
667: } else {
668: send_handle(id, handle);
1.10 markus 669: status = SSH2_FX_OK;
1.1 markus 670: }
1.17 stevesk 671:
1.1 markus 672: }
1.10 markus 673: if (status != SSH2_FX_OK)
1.1 markus 674: send_status(id, status);
675: xfree(path);
676: }
677:
1.28 itojun 678: static void
1.1 markus 679: process_readdir(void)
680: {
681: DIR *dirp;
682: struct dirent *dp;
683: char *path;
684: int handle;
685: u_int32_t id;
686:
687: id = get_int();
688: handle = get_handle();
1.30.2.3 miod 689: TRACE("readdir id %u handle %d", id, handle);
1.1 markus 690: dirp = handle_to_dir(handle);
691: path = handle_to_name(handle);
692: if (dirp == NULL || path == NULL) {
1.10 markus 693: send_status(id, SSH2_FX_FAILURE);
1.1 markus 694: } else {
695: struct stat st;
696: char pathname[1024];
697: Stat *stats;
698: int nstats = 10, count = 0, i;
1.30.2.3 miod 699:
1.1 markus 700: stats = xmalloc(nstats * sizeof(Stat));
701: while ((dp = readdir(dirp)) != NULL) {
702: if (count >= nstats) {
703: nstats *= 2;
704: stats = xrealloc(stats, nstats * sizeof(Stat));
705: }
706: /* XXX OVERFLOW ? */
1.30 jakob 707: snprintf(pathname, sizeof pathname, "%s%s%s", path,
708: strcmp(path, "/") ? "/" : "", dp->d_name);
1.1 markus 709: if (lstat(pathname, &st) < 0)
710: continue;
1.13 markus 711: stat_to_attrib(&st, &(stats[count].attrib));
1.1 markus 712: stats[count].name = xstrdup(dp->d_name);
1.30.2.4! miod 713: stats[count].long_name = ls_file(dp->d_name, &st, 0);
1.1 markus 714: count++;
715: /* send up to 100 entries in one message */
1.11 markus 716: /* XXX check packet size instead */
1.1 markus 717: if (count == 100)
718: break;
719: }
1.10 markus 720: if (count > 0) {
721: send_names(id, count, stats);
1.30.2.1 jason 722: for (i = 0; i < count; i++) {
1.10 markus 723: xfree(stats[i].name);
724: xfree(stats[i].long_name);
725: }
726: } else {
727: send_status(id, SSH2_FX_EOF);
1.1 markus 728: }
729: xfree(stats);
730: }
731: }
732:
1.28 itojun 733: static void
1.1 markus 734: process_remove(void)
735: {
736: char *name;
737: u_int32_t id;
1.10 markus 738: int status = SSH2_FX_FAILURE;
1.1 markus 739: int ret;
740:
741: id = get_int();
742: name = get_string(NULL);
1.30.2.3 miod 743: TRACE("remove id %u name %s", id, name);
1.8 markus 744: ret = unlink(name);
1.10 markus 745: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 746: send_status(id, status);
747: xfree(name);
748: }
749:
1.28 itojun 750: static void
1.1 markus 751: process_mkdir(void)
752: {
753: Attrib *a;
754: u_int32_t id;
755: char *name;
1.10 markus 756: int ret, mode, status = SSH2_FX_FAILURE;
1.1 markus 757:
758: id = get_int();
759: name = get_string(NULL);
760: a = get_attrib();
1.10 markus 761: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
762: a->perm & 0777 : 0777;
1.30.2.3 miod 763: TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
1.1 markus 764: ret = mkdir(name, mode);
1.10 markus 765: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 766: send_status(id, status);
767: xfree(name);
768: }
769:
1.28 itojun 770: static void
1.1 markus 771: process_rmdir(void)
772: {
773: u_int32_t id;
774: char *name;
775: int ret, status;
776:
777: id = get_int();
778: name = get_string(NULL);
1.30.2.3 miod 779: TRACE("rmdir id %u name %s", id, name);
1.1 markus 780: ret = rmdir(name);
1.10 markus 781: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 782: send_status(id, status);
783: xfree(name);
784: }
785:
1.28 itojun 786: static void
1.1 markus 787: process_realpath(void)
788: {
789: char resolvedname[MAXPATHLEN];
790: u_int32_t id;
791: char *path;
792:
793: id = get_int();
794: path = get_string(NULL);
1.7 markus 795: if (path[0] == '\0') {
796: xfree(path);
797: path = xstrdup(".");
798: }
1.30.2.3 miod 799: TRACE("realpath id %u path %s", id, path);
1.1 markus 800: if (realpath(path, resolvedname) == NULL) {
801: send_status(id, errno_to_portable(errno));
802: } else {
803: Stat s;
804: attrib_clear(&s.attrib);
805: s.name = s.long_name = resolvedname;
806: send_names(id, 1, &s);
807: }
808: xfree(path);
809: }
810:
1.28 itojun 811: static void
1.1 markus 812: process_rename(void)
813: {
814: u_int32_t id;
1.11 markus 815: struct stat st;
1.1 markus 816: char *oldpath, *newpath;
1.11 markus 817: int ret, status = SSH2_FX_FAILURE;
1.1 markus 818:
819: id = get_int();
820: oldpath = get_string(NULL);
821: newpath = get_string(NULL);
1.30.2.3 miod 822: TRACE("rename id %u old %s new %s", id, oldpath, newpath);
1.11 markus 823: /* fail if 'newpath' exists */
824: if (stat(newpath, &st) == -1) {
825: ret = rename(oldpath, newpath);
826: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
827: }
1.1 markus 828: send_status(id, status);
829: xfree(oldpath);
830: xfree(newpath);
831: }
832:
1.28 itojun 833: static void
1.23 djm 834: process_readlink(void)
835: {
836: u_int32_t id;
1.26 markus 837: int len;
1.23 djm 838: char link[MAXPATHLEN];
839: char *path;
840:
841: id = get_int();
842: path = get_string(NULL);
1.30.2.3 miod 843: TRACE("readlink id %u path %s", id, path);
1.26 markus 844: if ((len = readlink(path, link, sizeof(link) - 1)) == -1)
1.23 djm 845: send_status(id, errno_to_portable(errno));
846: else {
847: Stat s;
1.30.2.1 jason 848:
1.26 markus 849: link[len] = '\0';
1.23 djm 850: attrib_clear(&s.attrib);
851: s.name = s.long_name = link;
852: send_names(id, 1, &s);
853: }
854: xfree(path);
855: }
856:
1.28 itojun 857: static void
1.23 djm 858: process_symlink(void)
859: {
860: u_int32_t id;
861: struct stat st;
862: char *oldpath, *newpath;
863: int ret, status = SSH2_FX_FAILURE;
864:
865: id = get_int();
866: oldpath = get_string(NULL);
867: newpath = get_string(NULL);
1.30.2.3 miod 868: TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
1.23 djm 869: /* fail if 'newpath' exists */
870: if (stat(newpath, &st) == -1) {
871: ret = symlink(oldpath, newpath);
872: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
873: }
874: send_status(id, status);
875: xfree(oldpath);
876: xfree(newpath);
877: }
878:
1.28 itojun 879: static void
1.10 markus 880: process_extended(void)
881: {
882: u_int32_t id;
883: char *request;
884:
885: id = get_int();
886: request = get_string(NULL);
887: send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
888: xfree(request);
889: }
1.1 markus 890:
891: /* stolen from ssh-agent */
892:
1.28 itojun 893: static void
1.1 markus 894: process(void)
895: {
1.9 markus 896: u_int msg_len;
1.30.2.2 miod 897: u_int buf_len;
898: u_int consumed;
1.9 markus 899: u_int type;
900: u_char *cp;
1.1 markus 901:
1.30.2.2 miod 902: buf_len = buffer_len(&iqueue);
903: if (buf_len < 5)
1.1 markus 904: return; /* Incomplete message. */
1.30.2.1 jason 905: cp = buffer_ptr(&iqueue);
1.1 markus 906: msg_len = GET_32BIT(cp);
907: if (msg_len > 256 * 1024) {
908: error("bad message ");
909: exit(11);
910: }
1.30.2.2 miod 911: if (buf_len < msg_len + 4)
1.1 markus 912: return;
913: buffer_consume(&iqueue, 4);
1.30.2.2 miod 914: buf_len -= 4;
1.1 markus 915: type = buffer_get_char(&iqueue);
916: switch (type) {
1.10 markus 917: case SSH2_FXP_INIT:
1.1 markus 918: process_init();
919: break;
1.10 markus 920: case SSH2_FXP_OPEN:
1.1 markus 921: process_open();
922: break;
1.10 markus 923: case SSH2_FXP_CLOSE:
1.1 markus 924: process_close();
925: break;
1.10 markus 926: case SSH2_FXP_READ:
1.1 markus 927: process_read();
928: break;
1.10 markus 929: case SSH2_FXP_WRITE:
1.1 markus 930: process_write();
931: break;
1.10 markus 932: case SSH2_FXP_LSTAT:
1.1 markus 933: process_lstat();
934: break;
1.10 markus 935: case SSH2_FXP_FSTAT:
1.1 markus 936: process_fstat();
937: break;
1.10 markus 938: case SSH2_FXP_SETSTAT:
1.1 markus 939: process_setstat();
940: break;
1.10 markus 941: case SSH2_FXP_FSETSTAT:
1.1 markus 942: process_fsetstat();
943: break;
1.10 markus 944: case SSH2_FXP_OPENDIR:
1.1 markus 945: process_opendir();
946: break;
1.10 markus 947: case SSH2_FXP_READDIR:
1.1 markus 948: process_readdir();
949: break;
1.10 markus 950: case SSH2_FXP_REMOVE:
1.1 markus 951: process_remove();
952: break;
1.10 markus 953: case SSH2_FXP_MKDIR:
1.1 markus 954: process_mkdir();
955: break;
1.10 markus 956: case SSH2_FXP_RMDIR:
1.1 markus 957: process_rmdir();
958: break;
1.10 markus 959: case SSH2_FXP_REALPATH:
1.1 markus 960: process_realpath();
961: break;
1.10 markus 962: case SSH2_FXP_STAT:
1.1 markus 963: process_stat();
964: break;
1.10 markus 965: case SSH2_FXP_RENAME:
1.1 markus 966: process_rename();
1.23 djm 967: break;
968: case SSH2_FXP_READLINK:
969: process_readlink();
970: break;
971: case SSH2_FXP_SYMLINK:
972: process_symlink();
1.1 markus 973: break;
1.10 markus 974: case SSH2_FXP_EXTENDED:
975: process_extended();
976: break;
1.1 markus 977: default:
978: error("Unknown message %d", type);
979: break;
980: }
1.30.2.2 miod 981: /* discard the remaining bytes from the current packet */
982: if (buf_len < buffer_len(&iqueue))
983: fatal("iqueue grows");
984: consumed = buf_len - buffer_len(&iqueue);
985: if (msg_len < consumed)
986: fatal("msg_len %d < consumed %d", msg_len, consumed);
987: if (msg_len > consumed)
988: buffer_consume(&iqueue, msg_len - consumed);
1.1 markus 989: }
990:
991: int
992: main(int ac, char **av)
993: {
1.21 millert 994: fd_set *rset, *wset;
1.1 markus 995: int in, out, max;
1.21 millert 996: ssize_t len, olen, set_size;
1.24 deraadt 997:
998: /* XXX should use getopt */
1.1 markus 999:
1000: handle_init();
1.10 markus 1001:
1.11 markus 1002: #ifdef DEBUG_SFTP_SERVER
1.17 stevesk 1003: log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1.11 markus 1004: #endif
1.1 markus 1005:
1006: in = dup(STDIN_FILENO);
1007: out = dup(STDOUT_FILENO);
1008:
1009: max = 0;
1010: if (in > max)
1011: max = in;
1012: if (out > max)
1013: max = out;
1014:
1015: buffer_init(&iqueue);
1016: buffer_init(&oqueue);
1017:
1.21 millert 1018: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1019: rset = (fd_set *)xmalloc(set_size);
1020: wset = (fd_set *)xmalloc(set_size);
1021:
1.1 markus 1022: for (;;) {
1.21 millert 1023: memset(rset, 0, set_size);
1024: memset(wset, 0, set_size);
1.1 markus 1025:
1.21 millert 1026: FD_SET(in, rset);
1.1 markus 1027: olen = buffer_len(&oqueue);
1028: if (olen > 0)
1.21 millert 1029: FD_SET(out, wset);
1.1 markus 1030:
1.21 millert 1031: if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1 markus 1032: if (errno == EINTR)
1033: continue;
1034: exit(2);
1035: }
1036:
1037: /* copy stdin to iqueue */
1.21 millert 1038: if (FD_ISSET(in, rset)) {
1.1 markus 1039: char buf[4*4096];
1040: len = read(in, buf, sizeof buf);
1041: if (len == 0) {
1042: debug("read eof");
1043: exit(0);
1044: } else if (len < 0) {
1045: error("read error");
1046: exit(1);
1047: } else {
1048: buffer_append(&iqueue, buf, len);
1049: }
1050: }
1051: /* send oqueue to stdout */
1.21 millert 1052: if (FD_ISSET(out, wset)) {
1.1 markus 1053: len = write(out, buffer_ptr(&oqueue), olen);
1054: if (len < 0) {
1055: error("write error");
1056: exit(1);
1057: } else {
1058: buffer_consume(&oqueue, len);
1059: }
1060: }
1061: /* process requests from client */
1062: process();
1063: }
1064: }