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