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