Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.30
1.1 markus 1: /*
1.29 markus 2: * Copyright (c) 2000, 2001 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 ! jakob 25: RCSID("$OpenBSD: sftp-server.c,v 1.29 2001/06/25 08:25:40 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.1 markus 141: for(i = 0; i < sizeof(handles)/sizeof(Handle); i++)
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.1 markus 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:
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.1 markus 279: TRACE("sent status id %d error %d", id, error);
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: {
308: TRACE("sent data id %d 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);
319: TRACE("sent handle id %d 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);
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:
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.1 markus 349: TRACE("sent attrib id %d have 0x%x", id, a->flags);
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.23 djm 365: version = buffer_get_int(&iqueue);
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.1 markus 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);
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();
414: TRACE("close id %d handle %d", id, handle);
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.19 itojun 433: TRACE("read id %d 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.19 itojun 474: TRACE("write id %d 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);
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 {
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();
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 {
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;
579: int ret;
1.10 markus 580: int status = SSH2_FX_OK;
1.1 markus 581:
582: id = get_int();
583: name = get_string(NULL);
584: a = get_attrib();
585: TRACE("setstat id %d name %s", id, name);
1.10 markus 586: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 587: ret = chmod(name, a->perm & 0777);
588: if (ret == -1)
589: status = errno_to_portable(errno);
590: }
1.10 markus 591: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 592: ret = utimes(name, attrib_to_tv(a));
593: if (ret == -1)
594: status = errno_to_portable(errno);
595: }
1.18 stevesk 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: }
1.1 markus 601: send_status(id, status);
602: xfree(name);
603: }
604:
1.28 itojun 605: static void
1.1 markus 606: process_fsetstat(void)
607: {
608: Attrib *a;
609: u_int32_t id;
610: int handle, fd, ret;
1.10 markus 611: int status = SSH2_FX_OK;
1.1 markus 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) {
1.10 markus 619: status = SSH2_FX_FAILURE;
1.1 markus 620: } else {
1.10 markus 621: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 622: ret = fchmod(fd, a->perm & 0777);
623: if (ret == -1)
624: status = errno_to_portable(errno);
625: }
1.10 markus 626: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 627: ret = futimes(fd, attrib_to_tv(a));
1.18 stevesk 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);
1.1 markus 633: if (ret == -1)
634: status = errno_to_portable(errno);
635: }
636: }
637: send_status(id, status);
638: }
639:
1.28 itojun 640: static void
1.1 markus 641: process_opendir(void)
642: {
643: DIR *dirp = NULL;
644: char *path;
1.10 markus 645: int handle, status = SSH2_FX_FAILURE;
1.1 markus 646: u_int32_t id;
647:
648: id = get_int();
649: path = get_string(NULL);
650: TRACE("opendir id %d path %s", id, path);
1.17 stevesk 651: dirp = opendir(path);
1.1 markus 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);
1.10 markus 660: status = SSH2_FX_OK;
1.1 markus 661: }
1.17 stevesk 662:
1.1 markus 663: }
1.10 markus 664: if (status != SSH2_FX_OK)
1.1 markus 665: send_status(id, status);
666: xfree(path);
667: }
668:
1.10 markus 669: /*
1.12 markus 670: * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
1.10 markus 671: */
1.28 itojun 672: static char *
1.1 markus 673: ls_file(char *name, struct stat *st)
674: {
1.27 markus 675: int ulen, glen, sz = 0;
1.12 markus 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';
1.27 markus 703: ulen = MAX(strlen(user), 8);
704: glen = MAX(strlen(group), 8);
705: snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode,
706: st->st_nlink, ulen, user, glen, group,
707: (unsigned long long)st->st_size, tbuf, name);
1.1 markus 708: return xstrdup(buf);
709: }
710:
1.28 itojun 711: static void
1.1 markus 712: process_readdir(void)
713: {
714: DIR *dirp;
715: struct dirent *dp;
716: char *path;
717: int handle;
718: u_int32_t id;
719:
720: id = get_int();
721: handle = get_handle();
722: TRACE("readdir id %d handle %d", id, handle);
723: dirp = handle_to_dir(handle);
724: path = handle_to_name(handle);
725: if (dirp == NULL || path == NULL) {
1.10 markus 726: send_status(id, SSH2_FX_FAILURE);
1.1 markus 727: } else {
728: struct stat st;
729: char pathname[1024];
730: Stat *stats;
731: int nstats = 10, count = 0, i;
732: stats = xmalloc(nstats * sizeof(Stat));
733: while ((dp = readdir(dirp)) != NULL) {
734: if (count >= nstats) {
735: nstats *= 2;
736: stats = xrealloc(stats, nstats * sizeof(Stat));
737: }
738: /* XXX OVERFLOW ? */
1.30 ! jakob 739: snprintf(pathname, sizeof pathname, "%s%s%s", path,
! 740: strcmp(path, "/") ? "/" : "", dp->d_name);
1.1 markus 741: if (lstat(pathname, &st) < 0)
742: continue;
1.13 markus 743: stat_to_attrib(&st, &(stats[count].attrib));
1.1 markus 744: stats[count].name = xstrdup(dp->d_name);
745: stats[count].long_name = ls_file(dp->d_name, &st);
746: count++;
747: /* send up to 100 entries in one message */
1.11 markus 748: /* XXX check packet size instead */
1.1 markus 749: if (count == 100)
750: break;
751: }
1.10 markus 752: if (count > 0) {
753: send_names(id, count, stats);
754: for(i = 0; i < count; i++) {
755: xfree(stats[i].name);
756: xfree(stats[i].long_name);
757: }
758: } else {
759: send_status(id, SSH2_FX_EOF);
1.1 markus 760: }
761: xfree(stats);
762: }
763: }
764:
1.28 itojun 765: static void
1.1 markus 766: process_remove(void)
767: {
768: char *name;
769: u_int32_t id;
1.10 markus 770: int status = SSH2_FX_FAILURE;
1.1 markus 771: int ret;
772:
773: id = get_int();
774: name = get_string(NULL);
775: TRACE("remove id %d name %s", id, name);
1.8 markus 776: ret = unlink(name);
1.10 markus 777: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 778: send_status(id, status);
779: xfree(name);
780: }
781:
1.28 itojun 782: static void
1.1 markus 783: process_mkdir(void)
784: {
785: Attrib *a;
786: u_int32_t id;
787: char *name;
1.10 markus 788: int ret, mode, status = SSH2_FX_FAILURE;
1.1 markus 789:
790: id = get_int();
791: name = get_string(NULL);
792: a = get_attrib();
1.10 markus 793: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
794: a->perm & 0777 : 0777;
1.1 markus 795: TRACE("mkdir id %d name %s mode 0%o", id, name, mode);
796: ret = mkdir(name, mode);
1.10 markus 797: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 798: send_status(id, status);
799: xfree(name);
800: }
801:
1.28 itojun 802: static void
1.1 markus 803: process_rmdir(void)
804: {
805: u_int32_t id;
806: char *name;
807: int ret, status;
808:
809: id = get_int();
810: name = get_string(NULL);
811: TRACE("rmdir id %d name %s", id, name);
812: ret = rmdir(name);
1.10 markus 813: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 814: send_status(id, status);
815: xfree(name);
816: }
817:
1.28 itojun 818: static void
1.1 markus 819: process_realpath(void)
820: {
821: char resolvedname[MAXPATHLEN];
822: u_int32_t id;
823: char *path;
824:
825: id = get_int();
826: path = get_string(NULL);
1.7 markus 827: if (path[0] == '\0') {
828: xfree(path);
829: path = xstrdup(".");
830: }
1.1 markus 831: TRACE("realpath id %d path %s", id, path);
832: if (realpath(path, resolvedname) == NULL) {
833: send_status(id, errno_to_portable(errno));
834: } else {
835: Stat s;
836: attrib_clear(&s.attrib);
837: s.name = s.long_name = resolvedname;
838: send_names(id, 1, &s);
839: }
840: xfree(path);
841: }
842:
1.28 itojun 843: static void
1.1 markus 844: process_rename(void)
845: {
846: u_int32_t id;
1.11 markus 847: struct stat st;
1.1 markus 848: char *oldpath, *newpath;
1.11 markus 849: int ret, status = SSH2_FX_FAILURE;
1.1 markus 850:
851: id = get_int();
852: oldpath = get_string(NULL);
853: newpath = get_string(NULL);
854: TRACE("rename id %d old %s new %s", id, oldpath, newpath);
1.11 markus 855: /* fail if 'newpath' exists */
856: if (stat(newpath, &st) == -1) {
857: ret = rename(oldpath, newpath);
858: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
859: }
1.1 markus 860: send_status(id, status);
861: xfree(oldpath);
862: xfree(newpath);
863: }
864:
1.28 itojun 865: static void
1.23 djm 866: process_readlink(void)
867: {
868: u_int32_t id;
1.26 markus 869: int len;
1.23 djm 870: char link[MAXPATHLEN];
871: char *path;
872:
873: id = get_int();
874: path = get_string(NULL);
875: TRACE("readlink id %d path %s", id, path);
1.26 markus 876: if ((len = readlink(path, link, sizeof(link) - 1)) == -1)
1.23 djm 877: send_status(id, errno_to_portable(errno));
878: else {
879: Stat s;
880:
1.26 markus 881: link[len] = '\0';
1.23 djm 882: attrib_clear(&s.attrib);
883: s.name = s.long_name = link;
884: send_names(id, 1, &s);
885: }
886: xfree(path);
887: }
888:
1.28 itojun 889: static void
1.23 djm 890: process_symlink(void)
891: {
892: u_int32_t id;
893: struct stat st;
894: char *oldpath, *newpath;
895: int ret, status = SSH2_FX_FAILURE;
896:
897: id = get_int();
898: oldpath = get_string(NULL);
899: newpath = get_string(NULL);
900: TRACE("symlink id %d old %s new %s", id, oldpath, newpath);
901: /* fail if 'newpath' exists */
902: if (stat(newpath, &st) == -1) {
903: ret = symlink(oldpath, newpath);
904: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
905: }
906: send_status(id, status);
907: xfree(oldpath);
908: xfree(newpath);
909: }
910:
1.28 itojun 911: static void
1.10 markus 912: process_extended(void)
913: {
914: u_int32_t id;
915: char *request;
916:
917: id = get_int();
918: request = get_string(NULL);
919: send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
920: xfree(request);
921: }
1.1 markus 922:
923: /* stolen from ssh-agent */
924:
1.28 itojun 925: static void
1.1 markus 926: process(void)
927: {
1.9 markus 928: u_int msg_len;
929: u_int type;
930: u_char *cp;
1.1 markus 931:
932: if (buffer_len(&iqueue) < 5)
933: return; /* Incomplete message. */
1.9 markus 934: cp = (u_char *) buffer_ptr(&iqueue);
1.1 markus 935: msg_len = GET_32BIT(cp);
936: if (msg_len > 256 * 1024) {
937: error("bad message ");
938: exit(11);
939: }
940: if (buffer_len(&iqueue) < msg_len + 4)
941: return;
942: buffer_consume(&iqueue, 4);
943: type = buffer_get_char(&iqueue);
944: switch (type) {
1.10 markus 945: case SSH2_FXP_INIT:
1.1 markus 946: process_init();
947: break;
1.10 markus 948: case SSH2_FXP_OPEN:
1.1 markus 949: process_open();
950: break;
1.10 markus 951: case SSH2_FXP_CLOSE:
1.1 markus 952: process_close();
953: break;
1.10 markus 954: case SSH2_FXP_READ:
1.1 markus 955: process_read();
956: break;
1.10 markus 957: case SSH2_FXP_WRITE:
1.1 markus 958: process_write();
959: break;
1.10 markus 960: case SSH2_FXP_LSTAT:
1.1 markus 961: process_lstat();
962: break;
1.10 markus 963: case SSH2_FXP_FSTAT:
1.1 markus 964: process_fstat();
965: break;
1.10 markus 966: case SSH2_FXP_SETSTAT:
1.1 markus 967: process_setstat();
968: break;
1.10 markus 969: case SSH2_FXP_FSETSTAT:
1.1 markus 970: process_fsetstat();
971: break;
1.10 markus 972: case SSH2_FXP_OPENDIR:
1.1 markus 973: process_opendir();
974: break;
1.10 markus 975: case SSH2_FXP_READDIR:
1.1 markus 976: process_readdir();
977: break;
1.10 markus 978: case SSH2_FXP_REMOVE:
1.1 markus 979: process_remove();
980: break;
1.10 markus 981: case SSH2_FXP_MKDIR:
1.1 markus 982: process_mkdir();
983: break;
1.10 markus 984: case SSH2_FXP_RMDIR:
1.1 markus 985: process_rmdir();
986: break;
1.10 markus 987: case SSH2_FXP_REALPATH:
1.1 markus 988: process_realpath();
989: break;
1.10 markus 990: case SSH2_FXP_STAT:
1.1 markus 991: process_stat();
992: break;
1.10 markus 993: case SSH2_FXP_RENAME:
1.1 markus 994: process_rename();
1.23 djm 995: break;
996: case SSH2_FXP_READLINK:
997: process_readlink();
998: break;
999: case SSH2_FXP_SYMLINK:
1000: process_symlink();
1.1 markus 1001: break;
1.10 markus 1002: case SSH2_FXP_EXTENDED:
1003: process_extended();
1004: break;
1.1 markus 1005: default:
1006: error("Unknown message %d", type);
1007: break;
1008: }
1009: }
1010:
1011: int
1012: main(int ac, char **av)
1013: {
1.21 millert 1014: fd_set *rset, *wset;
1.1 markus 1015: int in, out, max;
1.21 millert 1016: ssize_t len, olen, set_size;
1.24 deraadt 1017:
1018: /* XXX should use getopt */
1.1 markus 1019:
1020: handle_init();
1.10 markus 1021:
1.11 markus 1022: #ifdef DEBUG_SFTP_SERVER
1.17 stevesk 1023: log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1.11 markus 1024: #endif
1.1 markus 1025:
1026: in = dup(STDIN_FILENO);
1027: out = dup(STDOUT_FILENO);
1028:
1029: max = 0;
1030: if (in > max)
1031: max = in;
1032: if (out > max)
1033: max = out;
1034:
1035: buffer_init(&iqueue);
1036: buffer_init(&oqueue);
1037:
1.21 millert 1038: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1039: rset = (fd_set *)xmalloc(set_size);
1040: wset = (fd_set *)xmalloc(set_size);
1041:
1.1 markus 1042: for (;;) {
1.21 millert 1043: memset(rset, 0, set_size);
1044: memset(wset, 0, set_size);
1.1 markus 1045:
1.21 millert 1046: FD_SET(in, rset);
1.1 markus 1047: olen = buffer_len(&oqueue);
1048: if (olen > 0)
1.21 millert 1049: FD_SET(out, wset);
1.1 markus 1050:
1.21 millert 1051: if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1 markus 1052: if (errno == EINTR)
1053: continue;
1054: exit(2);
1055: }
1056:
1057: /* copy stdin to iqueue */
1.21 millert 1058: if (FD_ISSET(in, rset)) {
1.1 markus 1059: char buf[4*4096];
1060: len = read(in, buf, sizeof buf);
1061: if (len == 0) {
1062: debug("read eof");
1063: exit(0);
1064: } else if (len < 0) {
1065: error("read error");
1066: exit(1);
1067: } else {
1068: buffer_append(&iqueue, buf, len);
1069: }
1070: }
1071: /* send oqueue to stdout */
1.21 millert 1072: if (FD_ISSET(out, wset)) {
1.1 markus 1073: len = write(out, buffer_ptr(&oqueue), olen);
1074: if (len < 0) {
1075: error("write error");
1076: exit(1);
1077: } else {
1078: buffer_consume(&oqueue, len);
1079: }
1080: }
1081: /* process requests from client */
1082: process();
1083: }
1084: }