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