Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.42
1.1 markus 1: /*
1.33 markus 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.42 ! itojun 25: RCSID("$OpenBSD: sftp-server.c,v 1.41 2003/03/26 04:02:51 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:
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.31 deraadt 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.31 deraadt 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;
1.40 markus 155: handles[i].name = xstrdup(name);
1.1 markus 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;
1.40 markus 227: xfree(handles[handle].name);
1.1 markus 228: } else if (handle_is_ok(handle, HANDLE_DIR)) {
229: ret = closedir(handles[handle].dirp);
230: handles[handle].use = HANDLE_UNUSED;
1.40 markus 231: xfree(handles[handle].name);
1.1 markus 232: } else {
233: errno = ENOENT;
234: }
235: return ret;
236: }
237:
1.28 itojun 238: static int
1.1 markus 239: get_handle(void)
240: {
241: char *handle;
1.10 markus 242: int val = -1;
1.5 markus 243: u_int hlen;
1.22 deraadt 244:
1.1 markus 245: handle = get_string(&hlen);
1.10 markus 246: if (hlen < 256)
247: val = handle_from_string(handle, hlen);
1.1 markus 248: xfree(handle);
249: return val;
250: }
251:
252: /* send replies */
253:
1.28 itojun 254: static void
1.1 markus 255: send_msg(Buffer *m)
256: {
257: int mlen = buffer_len(m);
1.22 deraadt 258:
1.1 markus 259: buffer_put_int(&oqueue, mlen);
260: buffer_append(&oqueue, buffer_ptr(m), mlen);
261: buffer_consume(m, mlen);
262: }
263:
1.28 itojun 264: static void
1.1 markus 265: send_status(u_int32_t id, u_int32_t error)
266: {
267: Buffer msg;
1.23 djm 268: const char *status_messages[] = {
269: "Success", /* SSH_FX_OK */
270: "End of file", /* SSH_FX_EOF */
271: "No such file", /* SSH_FX_NO_SUCH_FILE */
272: "Permission denied", /* SSH_FX_PERMISSION_DENIED */
273: "Failure", /* SSH_FX_FAILURE */
274: "Bad message", /* SSH_FX_BAD_MESSAGE */
275: "No connection", /* SSH_FX_NO_CONNECTION */
276: "Connection lost", /* SSH_FX_CONNECTION_LOST */
277: "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
278: "Unknown error" /* Others */
279: };
1.22 deraadt 280:
1.36 deraadt 281: TRACE("sent status id %u error %u", id, error);
1.1 markus 282: buffer_init(&msg);
1.10 markus 283: buffer_put_char(&msg, SSH2_FXP_STATUS);
1.1 markus 284: buffer_put_int(&msg, id);
285: buffer_put_int(&msg, error);
1.23 djm 286: if (version >= 3) {
1.25 markus 287: buffer_put_cstring(&msg,
1.23 djm 288: status_messages[MIN(error,SSH2_FX_MAX)]);
289: buffer_put_cstring(&msg, "");
290: }
1.1 markus 291: send_msg(&msg);
292: buffer_free(&msg);
293: }
1.28 itojun 294: static void
1.1 markus 295: send_data_or_handle(char type, u_int32_t id, char *data, int dlen)
296: {
297: Buffer msg;
1.22 deraadt 298:
1.1 markus 299: buffer_init(&msg);
300: buffer_put_char(&msg, type);
301: buffer_put_int(&msg, id);
302: buffer_put_string(&msg, data, dlen);
303: send_msg(&msg);
304: buffer_free(&msg);
305: }
306:
1.28 itojun 307: static void
1.1 markus 308: send_data(u_int32_t id, char *data, int dlen)
309: {
1.36 deraadt 310: TRACE("sent data id %u len %d", id, dlen);
1.10 markus 311: send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
1.1 markus 312: }
313:
1.28 itojun 314: static void
1.1 markus 315: send_handle(u_int32_t id, int handle)
316: {
317: char *string;
318: int hlen;
1.22 deraadt 319:
1.1 markus 320: handle_to_string(handle, &string, &hlen);
1.36 deraadt 321: TRACE("sent handle id %u handle %d", id, handle);
1.10 markus 322: send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
1.1 markus 323: xfree(string);
324: }
325:
1.28 itojun 326: static void
1.1 markus 327: send_names(u_int32_t id, int count, Stat *stats)
328: {
329: Buffer msg;
330: int i;
1.22 deraadt 331:
1.1 markus 332: buffer_init(&msg);
1.10 markus 333: buffer_put_char(&msg, SSH2_FXP_NAME);
1.1 markus 334: buffer_put_int(&msg, id);
335: buffer_put_int(&msg, count);
1.36 deraadt 336: TRACE("sent names id %u count %d", id, count);
1.1 markus 337: for (i = 0; i < count; i++) {
338: buffer_put_cstring(&msg, stats[i].name);
339: buffer_put_cstring(&msg, stats[i].long_name);
340: encode_attrib(&msg, &stats[i].attrib);
341: }
342: send_msg(&msg);
343: buffer_free(&msg);
344: }
345:
1.28 itojun 346: static void
1.1 markus 347: send_attrib(u_int32_t id, Attrib *a)
348: {
349: Buffer msg;
1.22 deraadt 350:
1.36 deraadt 351: TRACE("sent attrib id %u have 0x%x", id, a->flags);
1.1 markus 352: buffer_init(&msg);
1.10 markus 353: buffer_put_char(&msg, SSH2_FXP_ATTRS);
1.1 markus 354: buffer_put_int(&msg, id);
355: encode_attrib(&msg, a);
356: send_msg(&msg);
357: buffer_free(&msg);
358: }
359:
360: /* parse incoming */
361:
1.28 itojun 362: static void
1.1 markus 363: process_init(void)
364: {
365: Buffer msg;
366:
1.35 markus 367: version = get_int();
1.1 markus 368: TRACE("client version %d", version);
369: buffer_init(&msg);
1.10 markus 370: buffer_put_char(&msg, SSH2_FXP_VERSION);
371: buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
1.1 markus 372: send_msg(&msg);
373: buffer_free(&msg);
374: }
375:
1.28 itojun 376: static void
1.1 markus 377: process_open(void)
378: {
379: u_int32_t id, pflags;
380: Attrib *a;
381: char *name;
1.10 markus 382: int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1 markus 383:
384: id = get_int();
385: name = get_string(NULL);
1.10 markus 386: pflags = get_int(); /* portable flags */
1.1 markus 387: a = get_attrib();
388: flags = flags_from_portable(pflags);
1.10 markus 389: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.36 deraadt 390: TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode);
1.1 markus 391: fd = open(name, flags, mode);
392: if (fd < 0) {
393: status = errno_to_portable(errno);
394: } else {
1.40 markus 395: handle = handle_new(HANDLE_FILE, name, fd, NULL);
1.1 markus 396: if (handle < 0) {
397: close(fd);
398: } else {
399: send_handle(id, handle);
1.10 markus 400: status = SSH2_FX_OK;
1.1 markus 401: }
402: }
1.10 markus 403: if (status != SSH2_FX_OK)
1.1 markus 404: send_status(id, status);
405: xfree(name);
406: }
407:
1.28 itojun 408: static void
1.1 markus 409: process_close(void)
410: {
411: u_int32_t id;
1.10 markus 412: int handle, ret, status = SSH2_FX_FAILURE;
1.1 markus 413:
414: id = get_int();
415: handle = get_handle();
1.36 deraadt 416: TRACE("close id %u handle %d", id, handle);
1.1 markus 417: ret = handle_close(handle);
1.10 markus 418: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 419: send_status(id, status);
420: }
421:
1.28 itojun 422: static void
1.1 markus 423: process_read(void)
424: {
425: char buf[64*1024];
1.10 markus 426: u_int32_t id, len;
427: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 428: u_int64_t off;
429:
430: id = get_int();
431: handle = get_handle();
1.10 markus 432: off = get_int64();
1.1 markus 433: len = get_int();
434:
1.36 deraadt 435: TRACE("read id %u handle %d off %llu len %d", id, handle,
1.16 deraadt 436: (unsigned long long)off, len);
1.1 markus 437: if (len > sizeof buf) {
438: len = sizeof buf;
1.42 ! itojun 439: logit("read change len %d", len);
1.1 markus 440: }
441: fd = handle_to_fd(handle);
442: if (fd >= 0) {
443: if (lseek(fd, off, SEEK_SET) < 0) {
444: error("process_read: seek failed");
445: status = errno_to_portable(errno);
446: } else {
447: ret = read(fd, buf, len);
448: if (ret < 0) {
449: status = errno_to_portable(errno);
450: } else if (ret == 0) {
1.10 markus 451: status = SSH2_FX_EOF;
1.1 markus 452: } else {
453: send_data(id, buf, ret);
1.10 markus 454: status = SSH2_FX_OK;
1.1 markus 455: }
456: }
457: }
1.10 markus 458: if (status != SSH2_FX_OK)
1.1 markus 459: send_status(id, status);
460: }
461:
1.28 itojun 462: static void
1.1 markus 463: process_write(void)
464: {
1.10 markus 465: u_int32_t id;
1.1 markus 466: u_int64_t off;
1.5 markus 467: u_int len;
1.10 markus 468: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 469: char *data;
470:
471: id = get_int();
472: handle = get_handle();
1.10 markus 473: off = get_int64();
1.1 markus 474: data = get_string(&len);
475:
1.36 deraadt 476: TRACE("write id %u handle %d off %llu len %d", id, handle,
1.16 deraadt 477: (unsigned long long)off, len);
1.1 markus 478: fd = handle_to_fd(handle);
479: if (fd >= 0) {
480: if (lseek(fd, off, SEEK_SET) < 0) {
481: status = errno_to_portable(errno);
482: error("process_write: seek failed");
483: } else {
484: /* XXX ATOMICIO ? */
485: ret = write(fd, data, len);
486: if (ret == -1) {
487: error("process_write: write failed");
488: status = errno_to_portable(errno);
489: } else if (ret == len) {
1.10 markus 490: status = SSH2_FX_OK;
1.1 markus 491: } else {
1.42 ! itojun 492: logit("nothing at all written");
1.1 markus 493: }
494: }
495: }
496: send_status(id, status);
497: xfree(data);
498: }
499:
1.28 itojun 500: static void
1.1 markus 501: process_do_stat(int do_lstat)
502: {
1.13 markus 503: Attrib a;
1.1 markus 504: struct stat st;
505: u_int32_t id;
506: char *name;
1.10 markus 507: int ret, status = SSH2_FX_FAILURE;
1.1 markus 508:
509: id = get_int();
510: name = get_string(NULL);
1.36 deraadt 511: TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name);
1.1 markus 512: ret = do_lstat ? lstat(name, &st) : stat(name, &st);
513: if (ret < 0) {
514: status = errno_to_portable(errno);
515: } else {
1.13 markus 516: stat_to_attrib(&st, &a);
517: send_attrib(id, &a);
1.10 markus 518: status = SSH2_FX_OK;
1.1 markus 519: }
1.10 markus 520: if (status != SSH2_FX_OK)
1.1 markus 521: send_status(id, status);
522: xfree(name);
523: }
524:
1.28 itojun 525: static void
1.1 markus 526: process_stat(void)
527: {
528: process_do_stat(0);
529: }
530:
1.28 itojun 531: static void
1.1 markus 532: process_lstat(void)
533: {
534: process_do_stat(1);
535: }
536:
1.28 itojun 537: static void
1.1 markus 538: process_fstat(void)
539: {
1.13 markus 540: Attrib a;
1.1 markus 541: struct stat st;
542: u_int32_t id;
1.10 markus 543: int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1 markus 544:
545: id = get_int();
546: handle = get_handle();
1.36 deraadt 547: TRACE("fstat id %u handle %d", id, handle);
1.1 markus 548: fd = handle_to_fd(handle);
549: if (fd >= 0) {
550: ret = fstat(fd, &st);
551: if (ret < 0) {
552: status = errno_to_portable(errno);
553: } else {
1.13 markus 554: stat_to_attrib(&st, &a);
555: send_attrib(id, &a);
1.10 markus 556: status = SSH2_FX_OK;
1.1 markus 557: }
558: }
1.10 markus 559: if (status != SSH2_FX_OK)
1.1 markus 560: send_status(id, status);
561: }
562:
1.28 itojun 563: static struct timeval *
1.1 markus 564: attrib_to_tv(Attrib *a)
565: {
566: static struct timeval tv[2];
1.22 deraadt 567:
1.1 markus 568: tv[0].tv_sec = a->atime;
569: tv[0].tv_usec = 0;
570: tv[1].tv_sec = a->mtime;
571: tv[1].tv_usec = 0;
572: return tv;
573: }
574:
1.28 itojun 575: static void
1.1 markus 576: process_setstat(void)
577: {
578: Attrib *a;
579: u_int32_t id;
580: char *name;
1.36 deraadt 581: int status = SSH2_FX_OK, ret;
1.1 markus 582:
583: id = get_int();
584: name = get_string(NULL);
585: a = get_attrib();
1.36 deraadt 586: TRACE("setstat id %u name %s", id, name);
1.33 markus 587: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
588: ret = truncate(name, a->size);
589: if (ret == -1)
590: status = errno_to_portable(errno);
591: }
1.10 markus 592: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 593: ret = chmod(name, a->perm & 0777);
594: if (ret == -1)
595: status = errno_to_portable(errno);
596: }
1.10 markus 597: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 598: ret = utimes(name, attrib_to_tv(a));
599: if (ret == -1)
600: status = errno_to_portable(errno);
601: }
1.18 stevesk 602: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
603: ret = chown(name, a->uid, a->gid);
604: if (ret == -1)
605: status = errno_to_portable(errno);
606: }
1.1 markus 607: send_status(id, status);
608: xfree(name);
609: }
610:
1.28 itojun 611: static void
1.1 markus 612: process_fsetstat(void)
613: {
614: Attrib *a;
615: u_int32_t id;
616: int handle, fd, ret;
1.10 markus 617: int status = SSH2_FX_OK;
1.1 markus 618:
619: id = get_int();
620: handle = get_handle();
621: a = get_attrib();
1.36 deraadt 622: TRACE("fsetstat id %u handle %d", id, handle);
1.1 markus 623: fd = handle_to_fd(handle);
624: if (fd < 0) {
1.10 markus 625: status = SSH2_FX_FAILURE;
1.1 markus 626: } else {
1.33 markus 627: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
628: ret = ftruncate(fd, a->size);
629: if (ret == -1)
630: status = errno_to_portable(errno);
631: }
1.10 markus 632: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 633: ret = fchmod(fd, a->perm & 0777);
634: if (ret == -1)
635: status = errno_to_portable(errno);
636: }
1.10 markus 637: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 638: ret = futimes(fd, attrib_to_tv(a));
1.18 stevesk 639: if (ret == -1)
640: status = errno_to_portable(errno);
641: }
642: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
643: ret = fchown(fd, a->uid, a->gid);
1.1 markus 644: if (ret == -1)
645: status = errno_to_portable(errno);
646: }
647: }
648: send_status(id, status);
649: }
650:
1.28 itojun 651: static void
1.1 markus 652: process_opendir(void)
653: {
654: DIR *dirp = NULL;
655: char *path;
1.10 markus 656: int handle, status = SSH2_FX_FAILURE;
1.1 markus 657: u_int32_t id;
658:
659: id = get_int();
660: path = get_string(NULL);
1.36 deraadt 661: TRACE("opendir id %u path %s", id, path);
1.17 stevesk 662: dirp = opendir(path);
1.1 markus 663: if (dirp == NULL) {
664: status = errno_to_portable(errno);
665: } else {
1.40 markus 666: handle = handle_new(HANDLE_DIR, path, 0, dirp);
1.1 markus 667: if (handle < 0) {
668: closedir(dirp);
669: } else {
670: send_handle(id, handle);
1.10 markus 671: status = SSH2_FX_OK;
1.1 markus 672: }
1.17 stevesk 673:
1.1 markus 674: }
1.10 markus 675: if (status != SSH2_FX_OK)
1.1 markus 676: send_status(id, status);
677: xfree(path);
678: }
679:
1.28 itojun 680: static void
1.1 markus 681: process_readdir(void)
682: {
683: DIR *dirp;
684: struct dirent *dp;
685: char *path;
686: int handle;
687: u_int32_t id;
688:
689: id = get_int();
690: handle = get_handle();
1.36 deraadt 691: TRACE("readdir id %u handle %d", id, handle);
1.1 markus 692: dirp = handle_to_dir(handle);
693: path = handle_to_name(handle);
694: if (dirp == NULL || path == NULL) {
1.10 markus 695: send_status(id, SSH2_FX_FAILURE);
1.1 markus 696: } else {
697: struct stat st;
698: char pathname[1024];
699: Stat *stats;
700: int nstats = 10, count = 0, i;
1.36 deraadt 701:
1.1 markus 702: stats = xmalloc(nstats * sizeof(Stat));
703: while ((dp = readdir(dirp)) != NULL) {
704: if (count >= nstats) {
705: nstats *= 2;
706: stats = xrealloc(stats, nstats * sizeof(Stat));
707: }
708: /* XXX OVERFLOW ? */
1.30 jakob 709: snprintf(pathname, sizeof pathname, "%s%s%s", path,
710: strcmp(path, "/") ? "/" : "", dp->d_name);
1.1 markus 711: if (lstat(pathname, &st) < 0)
712: continue;
1.13 markus 713: stat_to_attrib(&st, &(stats[count].attrib));
1.1 markus 714: stats[count].name = xstrdup(dp->d_name);
1.38 djm 715: stats[count].long_name = ls_file(dp->d_name, &st, 0);
1.1 markus 716: count++;
717: /* send up to 100 entries in one message */
1.11 markus 718: /* XXX check packet size instead */
1.1 markus 719: if (count == 100)
720: break;
721: }
1.10 markus 722: if (count > 0) {
723: send_names(id, count, stats);
1.31 deraadt 724: for (i = 0; i < count; i++) {
1.10 markus 725: xfree(stats[i].name);
726: xfree(stats[i].long_name);
727: }
728: } else {
729: send_status(id, SSH2_FX_EOF);
1.1 markus 730: }
731: xfree(stats);
732: }
733: }
734:
1.28 itojun 735: static void
1.1 markus 736: process_remove(void)
737: {
738: char *name;
739: u_int32_t id;
1.10 markus 740: int status = SSH2_FX_FAILURE;
1.1 markus 741: int ret;
742:
743: id = get_int();
744: name = get_string(NULL);
1.36 deraadt 745: TRACE("remove id %u name %s", id, name);
1.8 markus 746: ret = unlink(name);
1.10 markus 747: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 748: send_status(id, status);
749: xfree(name);
750: }
751:
1.28 itojun 752: static void
1.1 markus 753: process_mkdir(void)
754: {
755: Attrib *a;
756: u_int32_t id;
757: char *name;
1.10 markus 758: int ret, mode, status = SSH2_FX_FAILURE;
1.1 markus 759:
760: id = get_int();
761: name = get_string(NULL);
762: a = get_attrib();
1.10 markus 763: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
764: a->perm & 0777 : 0777;
1.36 deraadt 765: TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
1.1 markus 766: ret = mkdir(name, mode);
1.10 markus 767: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 768: send_status(id, status);
769: xfree(name);
770: }
771:
1.28 itojun 772: static void
1.1 markus 773: process_rmdir(void)
774: {
775: u_int32_t id;
776: char *name;
777: int ret, status;
778:
779: id = get_int();
780: name = get_string(NULL);
1.36 deraadt 781: TRACE("rmdir id %u name %s", id, name);
1.1 markus 782: ret = rmdir(name);
1.10 markus 783: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 784: send_status(id, status);
785: xfree(name);
786: }
787:
1.28 itojun 788: static void
1.1 markus 789: process_realpath(void)
790: {
791: char resolvedname[MAXPATHLEN];
792: u_int32_t id;
793: char *path;
794:
795: id = get_int();
796: path = get_string(NULL);
1.7 markus 797: if (path[0] == '\0') {
798: xfree(path);
799: path = xstrdup(".");
800: }
1.36 deraadt 801: TRACE("realpath id %u path %s", id, path);
1.1 markus 802: if (realpath(path, resolvedname) == NULL) {
803: send_status(id, errno_to_portable(errno));
804: } else {
805: Stat s;
806: attrib_clear(&s.attrib);
807: s.name = s.long_name = resolvedname;
808: send_names(id, 1, &s);
809: }
810: xfree(path);
811: }
812:
1.28 itojun 813: static void
1.1 markus 814: process_rename(void)
815: {
816: u_int32_t id;
817: char *oldpath, *newpath;
1.39 markus 818: int status;
1.41 deraadt 819: struct stat sb;
1.1 markus 820:
821: id = get_int();
822: oldpath = get_string(NULL);
823: newpath = get_string(NULL);
1.36 deraadt 824: TRACE("rename id %u old %s new %s", id, oldpath, newpath);
1.41 deraadt 825: status = SSH2_FX_FAILURE;
826: if (lstat(oldpath, &sb) == -1)
1.39 markus 827: status = errno_to_portable(errno);
1.41 deraadt 828: else if (S_ISREG(sb.st_mode)) {
829: /* Race-free rename of regular files */
830: if (link(oldpath, newpath) == -1)
831: status = errno_to_portable(errno);
832: else if (unlink(oldpath) == -1) {
833: status = errno_to_portable(errno);
834: /* clean spare link */
835: unlink(newpath);
836: } else
837: status = SSH2_FX_OK;
838: } else if (stat(newpath, &sb) == -1) {
839: if (rename(oldpath, newpath) == -1)
840: status = errno_to_portable(errno);
841: else
842: status = SSH2_FX_OK;
843: }
1.1 markus 844: send_status(id, status);
845: xfree(oldpath);
846: xfree(newpath);
847: }
848:
1.28 itojun 849: static void
1.23 djm 850: process_readlink(void)
851: {
852: u_int32_t id;
1.26 markus 853: int len;
1.23 djm 854: char link[MAXPATHLEN];
855: char *path;
856:
857: id = get_int();
858: path = get_string(NULL);
1.36 deraadt 859: TRACE("readlink id %u path %s", id, path);
1.26 markus 860: if ((len = readlink(path, link, sizeof(link) - 1)) == -1)
1.23 djm 861: send_status(id, errno_to_portable(errno));
862: else {
863: Stat s;
1.31 deraadt 864:
1.26 markus 865: link[len] = '\0';
1.23 djm 866: attrib_clear(&s.attrib);
867: s.name = s.long_name = link;
868: send_names(id, 1, &s);
869: }
870: xfree(path);
871: }
872:
1.28 itojun 873: static void
1.23 djm 874: process_symlink(void)
875: {
876: u_int32_t id;
877: char *oldpath, *newpath;
1.39 markus 878: int ret, status;
1.23 djm 879:
880: id = get_int();
881: oldpath = get_string(NULL);
882: newpath = get_string(NULL);
1.36 deraadt 883: TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
1.39 markus 884: /* this will fail if 'newpath' exists */
885: ret = symlink(oldpath, newpath);
886: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.23 djm 887: send_status(id, status);
888: xfree(oldpath);
889: xfree(newpath);
890: }
891:
1.28 itojun 892: static void
1.10 markus 893: process_extended(void)
894: {
895: u_int32_t id;
896: char *request;
897:
898: id = get_int();
899: request = get_string(NULL);
900: send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
901: xfree(request);
902: }
1.1 markus 903:
904: /* stolen from ssh-agent */
905:
1.28 itojun 906: static void
1.1 markus 907: process(void)
908: {
1.9 markus 909: u_int msg_len;
1.34 markus 910: u_int buf_len;
911: u_int consumed;
1.9 markus 912: u_int type;
913: u_char *cp;
1.1 markus 914:
1.34 markus 915: buf_len = buffer_len(&iqueue);
916: if (buf_len < 5)
1.1 markus 917: return; /* Incomplete message. */
1.32 stevesk 918: cp = buffer_ptr(&iqueue);
1.1 markus 919: msg_len = GET_32BIT(cp);
920: if (msg_len > 256 * 1024) {
921: error("bad message ");
922: exit(11);
923: }
1.34 markus 924: if (buf_len < msg_len + 4)
1.1 markus 925: return;
926: buffer_consume(&iqueue, 4);
1.34 markus 927: buf_len -= 4;
1.1 markus 928: type = buffer_get_char(&iqueue);
929: switch (type) {
1.10 markus 930: case SSH2_FXP_INIT:
1.1 markus 931: process_init();
932: break;
1.10 markus 933: case SSH2_FXP_OPEN:
1.1 markus 934: process_open();
935: break;
1.10 markus 936: case SSH2_FXP_CLOSE:
1.1 markus 937: process_close();
938: break;
1.10 markus 939: case SSH2_FXP_READ:
1.1 markus 940: process_read();
941: break;
1.10 markus 942: case SSH2_FXP_WRITE:
1.1 markus 943: process_write();
944: break;
1.10 markus 945: case SSH2_FXP_LSTAT:
1.1 markus 946: process_lstat();
947: break;
1.10 markus 948: case SSH2_FXP_FSTAT:
1.1 markus 949: process_fstat();
950: break;
1.10 markus 951: case SSH2_FXP_SETSTAT:
1.1 markus 952: process_setstat();
953: break;
1.10 markus 954: case SSH2_FXP_FSETSTAT:
1.1 markus 955: process_fsetstat();
956: break;
1.10 markus 957: case SSH2_FXP_OPENDIR:
1.1 markus 958: process_opendir();
959: break;
1.10 markus 960: case SSH2_FXP_READDIR:
1.1 markus 961: process_readdir();
962: break;
1.10 markus 963: case SSH2_FXP_REMOVE:
1.1 markus 964: process_remove();
965: break;
1.10 markus 966: case SSH2_FXP_MKDIR:
1.1 markus 967: process_mkdir();
968: break;
1.10 markus 969: case SSH2_FXP_RMDIR:
1.1 markus 970: process_rmdir();
971: break;
1.10 markus 972: case SSH2_FXP_REALPATH:
1.1 markus 973: process_realpath();
974: break;
1.10 markus 975: case SSH2_FXP_STAT:
1.1 markus 976: process_stat();
977: break;
1.10 markus 978: case SSH2_FXP_RENAME:
1.1 markus 979: process_rename();
1.23 djm 980: break;
981: case SSH2_FXP_READLINK:
982: process_readlink();
983: break;
984: case SSH2_FXP_SYMLINK:
985: process_symlink();
1.1 markus 986: break;
1.10 markus 987: case SSH2_FXP_EXTENDED:
988: process_extended();
989: break;
1.1 markus 990: default:
991: error("Unknown message %d", type);
992: break;
993: }
1.34 markus 994: /* discard the remaining bytes from the current packet */
995: if (buf_len < buffer_len(&iqueue))
996: fatal("iqueue grows");
997: consumed = buf_len - buffer_len(&iqueue);
998: if (msg_len < consumed)
999: fatal("msg_len %d < consumed %d", msg_len, consumed);
1000: if (msg_len > consumed)
1001: buffer_consume(&iqueue, msg_len - consumed);
1.1 markus 1002: }
1003:
1004: int
1005: main(int ac, char **av)
1006: {
1.21 millert 1007: fd_set *rset, *wset;
1.1 markus 1008: int in, out, max;
1.21 millert 1009: ssize_t len, olen, set_size;
1.24 deraadt 1010:
1011: /* XXX should use getopt */
1.1 markus 1012:
1013: handle_init();
1.10 markus 1014:
1.11 markus 1015: #ifdef DEBUG_SFTP_SERVER
1.17 stevesk 1016: log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1.11 markus 1017: #endif
1.1 markus 1018:
1019: in = dup(STDIN_FILENO);
1020: out = dup(STDOUT_FILENO);
1021:
1022: max = 0;
1023: if (in > max)
1024: max = in;
1025: if (out > max)
1026: max = out;
1027:
1028: buffer_init(&iqueue);
1029: buffer_init(&oqueue);
1030:
1.21 millert 1031: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1032: rset = (fd_set *)xmalloc(set_size);
1033: wset = (fd_set *)xmalloc(set_size);
1034:
1.1 markus 1035: for (;;) {
1.21 millert 1036: memset(rset, 0, set_size);
1037: memset(wset, 0, set_size);
1.1 markus 1038:
1.21 millert 1039: FD_SET(in, rset);
1.1 markus 1040: olen = buffer_len(&oqueue);
1041: if (olen > 0)
1.21 millert 1042: FD_SET(out, wset);
1.1 markus 1043:
1.21 millert 1044: if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1 markus 1045: if (errno == EINTR)
1046: continue;
1047: exit(2);
1048: }
1049:
1050: /* copy stdin to iqueue */
1.21 millert 1051: if (FD_ISSET(in, rset)) {
1.1 markus 1052: char buf[4*4096];
1053: len = read(in, buf, sizeof buf);
1054: if (len == 0) {
1055: debug("read eof");
1056: exit(0);
1057: } else if (len < 0) {
1058: error("read error");
1059: exit(1);
1060: } else {
1061: buffer_append(&iqueue, buf, len);
1062: }
1063: }
1064: /* send oqueue to stdout */
1.21 millert 1065: if (FD_ISSET(out, wset)) {
1.1 markus 1066: len = write(out, buffer_ptr(&oqueue), olen);
1067: if (len < 0) {
1068: error("write error");
1069: exit(1);
1070: } else {
1071: buffer_consume(&oqueue, len);
1072: }
1073: }
1074: /* process requests from client */
1075: process();
1076: }
1077: }