Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.47
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.47 ! dtucker 17: RCSID("$OpenBSD: sftp-server.c,v 1.46 2004/06/21 17:36:31 avsm 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 */
1.47 ! dtucker 822: if (link(oldpath, newpath) == -1) {
! 823: if (errno == EOPNOTSUPP) {
! 824: struct stat st;
! 825:
! 826: /*
! 827: * fs doesn't support links, so fall back to
! 828: * stat+rename. This is racy.
! 829: */
! 830: if (stat(newpath, &st) == -1) {
! 831: if (rename(oldpath, newpath) == -1)
! 832: status =
! 833: errno_to_portable(errno);
! 834: else
! 835: status = SSH2_FX_OK;
! 836: }
! 837: } else {
! 838: status = errno_to_portable(errno);
! 839: }
! 840: } else if (unlink(oldpath) == -1) {
1.41 deraadt 841: status = errno_to_portable(errno);
842: /* clean spare link */
843: unlink(newpath);
844: } else
845: status = SSH2_FX_OK;
846: } else if (stat(newpath, &sb) == -1) {
847: if (rename(oldpath, newpath) == -1)
848: status = errno_to_portable(errno);
849: else
850: status = SSH2_FX_OK;
851: }
1.1 markus 852: send_status(id, status);
853: xfree(oldpath);
854: xfree(newpath);
855: }
856:
1.28 itojun 857: static void
1.23 djm 858: process_readlink(void)
859: {
860: u_int32_t id;
1.26 markus 861: int len;
1.46 avsm 862: char buf[MAXPATHLEN];
1.23 djm 863: char *path;
864:
865: id = get_int();
866: path = get_string(NULL);
1.36 deraadt 867: TRACE("readlink id %u path %s", id, path);
1.46 avsm 868: if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1.23 djm 869: send_status(id, errno_to_portable(errno));
870: else {
871: Stat s;
1.31 deraadt 872:
1.46 avsm 873: buf[len] = '\0';
1.23 djm 874: attrib_clear(&s.attrib);
1.46 avsm 875: s.name = s.long_name = buf;
1.23 djm 876: send_names(id, 1, &s);
877: }
878: xfree(path);
879: }
880:
1.28 itojun 881: static void
1.23 djm 882: process_symlink(void)
883: {
884: u_int32_t id;
885: char *oldpath, *newpath;
1.39 markus 886: int ret, status;
1.23 djm 887:
888: id = get_int();
889: oldpath = get_string(NULL);
890: newpath = get_string(NULL);
1.36 deraadt 891: TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
1.39 markus 892: /* this will fail if 'newpath' exists */
893: ret = symlink(oldpath, newpath);
894: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.23 djm 895: send_status(id, status);
896: xfree(oldpath);
897: xfree(newpath);
898: }
899:
1.28 itojun 900: static void
1.10 markus 901: process_extended(void)
902: {
903: u_int32_t id;
904: char *request;
905:
906: id = get_int();
907: request = get_string(NULL);
908: send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
909: xfree(request);
910: }
1.1 markus 911:
912: /* stolen from ssh-agent */
913:
1.28 itojun 914: static void
1.1 markus 915: process(void)
916: {
1.9 markus 917: u_int msg_len;
1.34 markus 918: u_int buf_len;
919: u_int consumed;
1.9 markus 920: u_int type;
921: u_char *cp;
1.1 markus 922:
1.34 markus 923: buf_len = buffer_len(&iqueue);
924: if (buf_len < 5)
1.1 markus 925: return; /* Incomplete message. */
1.32 stevesk 926: cp = buffer_ptr(&iqueue);
1.1 markus 927: msg_len = GET_32BIT(cp);
928: if (msg_len > 256 * 1024) {
929: error("bad message ");
930: exit(11);
931: }
1.34 markus 932: if (buf_len < msg_len + 4)
1.1 markus 933: return;
934: buffer_consume(&iqueue, 4);
1.34 markus 935: buf_len -= 4;
1.1 markus 936: type = buffer_get_char(&iqueue);
937: switch (type) {
1.10 markus 938: case SSH2_FXP_INIT:
1.1 markus 939: process_init();
940: break;
1.10 markus 941: case SSH2_FXP_OPEN:
1.1 markus 942: process_open();
943: break;
1.10 markus 944: case SSH2_FXP_CLOSE:
1.1 markus 945: process_close();
946: break;
1.10 markus 947: case SSH2_FXP_READ:
1.1 markus 948: process_read();
949: break;
1.10 markus 950: case SSH2_FXP_WRITE:
1.1 markus 951: process_write();
952: break;
1.10 markus 953: case SSH2_FXP_LSTAT:
1.1 markus 954: process_lstat();
955: break;
1.10 markus 956: case SSH2_FXP_FSTAT:
1.1 markus 957: process_fstat();
958: break;
1.10 markus 959: case SSH2_FXP_SETSTAT:
1.1 markus 960: process_setstat();
961: break;
1.10 markus 962: case SSH2_FXP_FSETSTAT:
1.1 markus 963: process_fsetstat();
964: break;
1.10 markus 965: case SSH2_FXP_OPENDIR:
1.1 markus 966: process_opendir();
967: break;
1.10 markus 968: case SSH2_FXP_READDIR:
1.1 markus 969: process_readdir();
970: break;
1.10 markus 971: case SSH2_FXP_REMOVE:
1.1 markus 972: process_remove();
973: break;
1.10 markus 974: case SSH2_FXP_MKDIR:
1.1 markus 975: process_mkdir();
976: break;
1.10 markus 977: case SSH2_FXP_RMDIR:
1.1 markus 978: process_rmdir();
979: break;
1.10 markus 980: case SSH2_FXP_REALPATH:
1.1 markus 981: process_realpath();
982: break;
1.10 markus 983: case SSH2_FXP_STAT:
1.1 markus 984: process_stat();
985: break;
1.10 markus 986: case SSH2_FXP_RENAME:
1.1 markus 987: process_rename();
1.23 djm 988: break;
989: case SSH2_FXP_READLINK:
990: process_readlink();
991: break;
992: case SSH2_FXP_SYMLINK:
993: process_symlink();
1.1 markus 994: break;
1.10 markus 995: case SSH2_FXP_EXTENDED:
996: process_extended();
997: break;
1.1 markus 998: default:
999: error("Unknown message %d", type);
1000: break;
1001: }
1.34 markus 1002: /* discard the remaining bytes from the current packet */
1003: if (buf_len < buffer_len(&iqueue))
1004: fatal("iqueue grows");
1005: consumed = buf_len - buffer_len(&iqueue);
1006: if (msg_len < consumed)
1007: fatal("msg_len %d < consumed %d", msg_len, consumed);
1008: if (msg_len > consumed)
1009: buffer_consume(&iqueue, msg_len - consumed);
1.1 markus 1010: }
1011:
1012: int
1013: main(int ac, char **av)
1014: {
1.21 millert 1015: fd_set *rset, *wset;
1.1 markus 1016: int in, out, max;
1.21 millert 1017: ssize_t len, olen, set_size;
1.24 deraadt 1018:
1019: /* XXX should use getopt */
1.1 markus 1020:
1021: handle_init();
1.10 markus 1022:
1.11 markus 1023: #ifdef DEBUG_SFTP_SERVER
1.17 stevesk 1024: log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1.11 markus 1025: #endif
1.1 markus 1026:
1027: in = dup(STDIN_FILENO);
1028: out = dup(STDOUT_FILENO);
1029:
1030: max = 0;
1031: if (in > max)
1032: max = in;
1033: if (out > max)
1034: max = out;
1035:
1036: buffer_init(&iqueue);
1037: buffer_init(&oqueue);
1038:
1.21 millert 1039: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1040: rset = (fd_set *)xmalloc(set_size);
1041: wset = (fd_set *)xmalloc(set_size);
1042:
1.1 markus 1043: for (;;) {
1.21 millert 1044: memset(rset, 0, set_size);
1045: memset(wset, 0, set_size);
1.1 markus 1046:
1.21 millert 1047: FD_SET(in, rset);
1.1 markus 1048: olen = buffer_len(&oqueue);
1049: if (olen > 0)
1.21 millert 1050: FD_SET(out, wset);
1.1 markus 1051:
1.21 millert 1052: if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1 markus 1053: if (errno == EINTR)
1054: continue;
1055: exit(2);
1056: }
1057:
1058: /* copy stdin to iqueue */
1.21 millert 1059: if (FD_ISSET(in, rset)) {
1.1 markus 1060: char buf[4*4096];
1061: len = read(in, buf, sizeof buf);
1062: if (len == 0) {
1063: debug("read eof");
1064: exit(0);
1065: } else if (len < 0) {
1066: error("read error");
1067: exit(1);
1068: } else {
1069: buffer_append(&iqueue, buf, len);
1070: }
1071: }
1072: /* send oqueue to stdout */
1.21 millert 1073: if (FD_ISSET(out, wset)) {
1.1 markus 1074: len = write(out, buffer_ptr(&oqueue), olen);
1075: if (len < 0) {
1076: error("write error");
1077: exit(1);
1078: } else {
1079: buffer_consume(&oqueue, len);
1080: }
1081: }
1082: /* process requests from client */
1083: process();
1084: }
1085: }