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