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