Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.73
1.73 ! djm 1: /* $OpenBSD: sftp-server.c,v 1.72 2007/04/18 01:12:43 stevesk Exp $ */
1.1 markus 2: /*
1.45 markus 3: * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
1.1 markus 4: *
1.45 markus 5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 markus 8: *
1.45 markus 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 markus 16: */
1.52 stevesk 17:
18: #include <sys/types.h>
19: #include <sys/stat.h>
1.66 stevesk 20: #include <sys/time.h>
1.67 stevesk 21: #include <sys/param.h>
1.51 stevesk 22:
23: #include <dirent.h>
1.62 stevesk 24: #include <errno.h>
1.59 stevesk 25: #include <fcntl.h>
1.68 stevesk 26: #include <stdlib.h>
1.69 stevesk 27: #include <stdio.h>
1.65 stevesk 28: #include <string.h>
1.70 deraadt 29: #include <pwd.h>
1.64 stevesk 30: #include <time.h>
1.63 stevesk 31: #include <unistd.h>
1.70 deraadt 32: #include <stdarg.h>
1.1 markus 33:
1.70 deraadt 34: #include "xmalloc.h"
1.1 markus 35: #include "buffer.h"
1.14 markus 36: #include "log.h"
1.49 djm 37: #include "misc.h"
1.58 djm 38: #include "uidswap.h"
1.1 markus 39:
1.10 markus 40: #include "sftp.h"
1.15 djm 41: #include "sftp-common.h"
1.1 markus 42:
43: /* helper */
1.10 markus 44: #define get_int64() buffer_get_int64(&iqueue);
1.1 markus 45: #define get_int() buffer_get_int(&iqueue);
46: #define get_string(lenp) buffer_get_string(&iqueue, lenp);
1.58 djm 47:
48: /* Our verbosity */
49: LogLevel log_level = SYSLOG_LEVEL_ERROR;
50:
51: /* Our client */
52: struct passwd *pw = NULL;
53: char *client_addr = NULL;
1.1 markus 54:
55: /* input and output queue */
56: Buffer iqueue;
57: Buffer oqueue;
58:
1.23 djm 59: /* Version of client */
60: int version;
61:
1.43 miod 62: /* portable attributes, etc. */
1.1 markus 63:
64: typedef struct Stat Stat;
65:
1.15 djm 66: struct Stat {
1.1 markus 67: char *name;
68: char *long_name;
69: Attrib attrib;
70: };
71:
1.28 itojun 72: static int
1.2 markus 73: errno_to_portable(int unixerrno)
1.1 markus 74: {
75: int ret = 0;
1.22 deraadt 76:
1.2 markus 77: switch (unixerrno) {
1.1 markus 78: case 0:
1.10 markus 79: ret = SSH2_FX_OK;
1.1 markus 80: break;
81: case ENOENT:
82: case ENOTDIR:
83: case EBADF:
84: case ELOOP:
1.10 markus 85: ret = SSH2_FX_NO_SUCH_FILE;
1.1 markus 86: break;
87: case EPERM:
88: case EACCES:
89: case EFAULT:
1.10 markus 90: ret = SSH2_FX_PERMISSION_DENIED;
1.1 markus 91: break;
92: case ENAMETOOLONG:
93: case EINVAL:
1.10 markus 94: ret = SSH2_FX_BAD_MESSAGE;
1.1 markus 95: break;
96: default:
1.10 markus 97: ret = SSH2_FX_FAILURE;
1.1 markus 98: break;
99: }
100: return ret;
101: }
102:
1.28 itojun 103: static int
1.1 markus 104: flags_from_portable(int pflags)
105: {
106: int flags = 0;
1.22 deraadt 107:
1.20 deraadt 108: if ((pflags & SSH2_FXF_READ) &&
109: (pflags & SSH2_FXF_WRITE)) {
1.1 markus 110: flags = O_RDWR;
1.10 markus 111: } else if (pflags & SSH2_FXF_READ) {
1.1 markus 112: flags = O_RDONLY;
1.10 markus 113: } else if (pflags & SSH2_FXF_WRITE) {
1.1 markus 114: flags = O_WRONLY;
115: }
1.10 markus 116: if (pflags & SSH2_FXF_CREAT)
1.1 markus 117: flags |= O_CREAT;
1.10 markus 118: if (pflags & SSH2_FXF_TRUNC)
1.1 markus 119: flags |= O_TRUNC;
1.10 markus 120: if (pflags & SSH2_FXF_EXCL)
1.1 markus 121: flags |= O_EXCL;
122: return flags;
123: }
124:
1.58 djm 125: static const char *
126: string_from_portable(int pflags)
127: {
128: static char ret[128];
129:
130: *ret = '\0';
131:
132: #define PAPPEND(str) { \
133: if (*ret != '\0') \
134: strlcat(ret, ",", sizeof(ret)); \
1.70 deraadt 135: strlcat(ret, str, sizeof(ret)); \
1.58 djm 136: }
137:
138: if (pflags & SSH2_FXF_READ)
139: PAPPEND("READ")
140: if (pflags & SSH2_FXF_WRITE)
141: PAPPEND("WRITE")
142: if (pflags & SSH2_FXF_CREAT)
143: PAPPEND("CREATE")
144: if (pflags & SSH2_FXF_TRUNC)
145: PAPPEND("TRUNCATE")
146: if (pflags & SSH2_FXF_EXCL)
147: PAPPEND("EXCL")
148:
149: return ret;
150: }
151:
1.28 itojun 152: static Attrib *
1.1 markus 153: get_attrib(void)
154: {
155: return decode_attrib(&iqueue);
156: }
157:
158: /* handle handles */
159:
160: typedef struct Handle Handle;
161: struct Handle {
162: int use;
163: DIR *dirp;
164: int fd;
165: char *name;
1.58 djm 166: u_int64_t bytes_read, bytes_write;
1.1 markus 167: };
1.22 deraadt 168:
1.1 markus 169: enum {
170: HANDLE_UNUSED,
171: HANDLE_DIR,
172: HANDLE_FILE
173: };
1.22 deraadt 174:
1.1 markus 175: Handle handles[100];
176:
1.28 itojun 177: static void
1.1 markus 178: handle_init(void)
179: {
1.48 djm 180: u_int i;
1.22 deraadt 181:
1.31 deraadt 182: for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
1.1 markus 183: handles[i].use = HANDLE_UNUSED;
184: }
185:
1.28 itojun 186: static int
1.44 jakob 187: handle_new(int use, const char *name, int fd, DIR *dirp)
1.1 markus 188: {
1.48 djm 189: u_int i;
1.22 deraadt 190:
1.31 deraadt 191: for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
1.1 markus 192: if (handles[i].use == HANDLE_UNUSED) {
193: handles[i].use = use;
194: handles[i].dirp = dirp;
195: handles[i].fd = fd;
1.40 markus 196: handles[i].name = xstrdup(name);
1.58 djm 197: handles[i].bytes_read = handles[i].bytes_write = 0;
1.1 markus 198: return i;
199: }
200: }
201: return -1;
202: }
203:
1.28 itojun 204: static int
1.1 markus 205: handle_is_ok(int i, int type)
206: {
1.48 djm 207: return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
1.10 markus 208: handles[i].use == type;
1.1 markus 209: }
210:
1.28 itojun 211: static int
1.1 markus 212: handle_to_string(int handle, char **stringp, int *hlenp)
213: {
214: if (stringp == NULL || hlenp == NULL)
215: return -1;
1.13 markus 216: *stringp = xmalloc(sizeof(int32_t));
1.57 djm 217: put_u32(*stringp, handle);
1.13 markus 218: *hlenp = sizeof(int32_t);
1.1 markus 219: return 0;
220: }
221:
1.28 itojun 222: static int
1.44 jakob 223: handle_from_string(const char *handle, u_int hlen)
1.1 markus 224: {
1.13 markus 225: int val;
1.22 deraadt 226:
1.13 markus 227: if (hlen != sizeof(int32_t))
1.1 markus 228: return -1;
1.57 djm 229: val = get_u32(handle);
1.1 markus 230: if (handle_is_ok(val, HANDLE_FILE) ||
231: handle_is_ok(val, HANDLE_DIR))
232: return val;
233: return -1;
234: }
235:
1.28 itojun 236: static char *
1.1 markus 237: handle_to_name(int handle)
238: {
239: if (handle_is_ok(handle, HANDLE_DIR)||
240: handle_is_ok(handle, HANDLE_FILE))
241: return handles[handle].name;
242: return NULL;
243: }
244:
1.28 itojun 245: static DIR *
1.1 markus 246: handle_to_dir(int handle)
247: {
248: if (handle_is_ok(handle, HANDLE_DIR))
249: return handles[handle].dirp;
250: return NULL;
251: }
252:
1.28 itojun 253: static int
1.1 markus 254: handle_to_fd(int handle)
255: {
1.17 stevesk 256: if (handle_is_ok(handle, HANDLE_FILE))
1.1 markus 257: return handles[handle].fd;
258: return -1;
259: }
260:
1.58 djm 261: static void
262: handle_update_read(int handle, ssize_t bytes)
263: {
264: if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
265: handles[handle].bytes_read += bytes;
266: }
267:
268: static void
269: handle_update_write(int handle, ssize_t bytes)
270: {
271: if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
272: handles[handle].bytes_write += bytes;
273: }
274:
275: static u_int64_t
276: handle_bytes_read(int handle)
277: {
278: if (handle_is_ok(handle, HANDLE_FILE))
279: return (handles[handle].bytes_read);
280: return 0;
281: }
282:
283: static u_int64_t
284: handle_bytes_write(int handle)
285: {
286: if (handle_is_ok(handle, HANDLE_FILE))
287: return (handles[handle].bytes_write);
288: return 0;
289: }
290:
1.28 itojun 291: static int
1.1 markus 292: handle_close(int handle)
293: {
294: int ret = -1;
1.22 deraadt 295:
1.1 markus 296: if (handle_is_ok(handle, HANDLE_FILE)) {
297: ret = close(handles[handle].fd);
298: handles[handle].use = HANDLE_UNUSED;
1.40 markus 299: xfree(handles[handle].name);
1.1 markus 300: } else if (handle_is_ok(handle, HANDLE_DIR)) {
301: ret = closedir(handles[handle].dirp);
302: handles[handle].use = HANDLE_UNUSED;
1.40 markus 303: xfree(handles[handle].name);
1.1 markus 304: } else {
305: errno = ENOENT;
306: }
307: return ret;
308: }
309:
1.58 djm 310: static void
311: handle_log_close(int handle, char *emsg)
312: {
313: if (handle_is_ok(handle, HANDLE_FILE)) {
314: logit("%s%sclose \"%s\" bytes read %llu written %llu",
315: emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
316: handle_to_name(handle),
1.72 stevesk 317: (unsigned long long)handle_bytes_read(handle),
318: (unsigned long long)handle_bytes_write(handle));
1.58 djm 319: } else {
320: logit("%s%sclosedir \"%s\"",
321: emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
322: handle_to_name(handle));
323: }
324: }
325:
326: static void
327: handle_log_exit(void)
328: {
329: u_int i;
330:
331: for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
332: if (handles[i].use != HANDLE_UNUSED)
333: handle_log_close(i, "forced");
334: }
335:
1.28 itojun 336: static int
1.1 markus 337: get_handle(void)
338: {
339: char *handle;
1.10 markus 340: int val = -1;
1.5 markus 341: u_int hlen;
1.22 deraadt 342:
1.1 markus 343: handle = get_string(&hlen);
1.10 markus 344: if (hlen < 256)
345: val = handle_from_string(handle, hlen);
1.1 markus 346: xfree(handle);
347: return val;
348: }
349:
350: /* send replies */
351:
1.28 itojun 352: static void
1.1 markus 353: send_msg(Buffer *m)
354: {
355: int mlen = buffer_len(m);
1.22 deraadt 356:
1.1 markus 357: buffer_put_int(&oqueue, mlen);
358: buffer_append(&oqueue, buffer_ptr(m), mlen);
359: buffer_consume(m, mlen);
360: }
361:
1.58 djm 362: static const char *
363: status_to_message(u_int32_t status)
1.1 markus 364: {
1.23 djm 365: const char *status_messages[] = {
366: "Success", /* SSH_FX_OK */
367: "End of file", /* SSH_FX_EOF */
368: "No such file", /* SSH_FX_NO_SUCH_FILE */
369: "Permission denied", /* SSH_FX_PERMISSION_DENIED */
370: "Failure", /* SSH_FX_FAILURE */
371: "Bad message", /* SSH_FX_BAD_MESSAGE */
372: "No connection", /* SSH_FX_NO_CONNECTION */
373: "Connection lost", /* SSH_FX_CONNECTION_LOST */
374: "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
375: "Unknown error" /* Others */
376: };
1.58 djm 377: return (status_messages[MIN(status,SSH2_FX_MAX)]);
378: }
1.22 deraadt 379:
1.58 djm 380: static void
381: send_status(u_int32_t id, u_int32_t status)
382: {
383: Buffer msg;
384:
385: debug3("request %u: sent status %u", id, status);
386: if (log_level > SYSLOG_LEVEL_VERBOSE ||
387: (status != SSH2_FX_OK && status != SSH2_FX_EOF))
388: logit("sent status %s", status_to_message(status));
1.1 markus 389: buffer_init(&msg);
1.10 markus 390: buffer_put_char(&msg, SSH2_FXP_STATUS);
1.1 markus 391: buffer_put_int(&msg, id);
1.46 avsm 392: buffer_put_int(&msg, status);
1.23 djm 393: if (version >= 3) {
1.58 djm 394: buffer_put_cstring(&msg, status_to_message(status));
1.23 djm 395: buffer_put_cstring(&msg, "");
396: }
1.1 markus 397: send_msg(&msg);
398: buffer_free(&msg);
399: }
1.28 itojun 400: static void
1.44 jakob 401: send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
1.1 markus 402: {
403: Buffer msg;
1.22 deraadt 404:
1.1 markus 405: buffer_init(&msg);
406: buffer_put_char(&msg, type);
407: buffer_put_int(&msg, id);
408: buffer_put_string(&msg, data, dlen);
409: send_msg(&msg);
410: buffer_free(&msg);
411: }
412:
1.28 itojun 413: static void
1.44 jakob 414: send_data(u_int32_t id, const char *data, int dlen)
1.1 markus 415: {
1.58 djm 416: debug("request %u: sent data len %d", id, dlen);
1.10 markus 417: send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
1.1 markus 418: }
419:
1.28 itojun 420: static void
1.1 markus 421: send_handle(u_int32_t id, int handle)
422: {
423: char *string;
424: int hlen;
1.22 deraadt 425:
1.1 markus 426: handle_to_string(handle, &string, &hlen);
1.58 djm 427: debug("request %u: sent handle handle %d", id, handle);
1.10 markus 428: send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
1.1 markus 429: xfree(string);
430: }
431:
1.28 itojun 432: static void
1.44 jakob 433: send_names(u_int32_t id, int count, const Stat *stats)
1.1 markus 434: {
435: Buffer msg;
436: int i;
1.22 deraadt 437:
1.1 markus 438: buffer_init(&msg);
1.10 markus 439: buffer_put_char(&msg, SSH2_FXP_NAME);
1.1 markus 440: buffer_put_int(&msg, id);
441: buffer_put_int(&msg, count);
1.58 djm 442: debug("request %u: sent names count %d", id, count);
1.1 markus 443: for (i = 0; i < count; i++) {
444: buffer_put_cstring(&msg, stats[i].name);
445: buffer_put_cstring(&msg, stats[i].long_name);
446: encode_attrib(&msg, &stats[i].attrib);
447: }
448: send_msg(&msg);
449: buffer_free(&msg);
450: }
451:
1.28 itojun 452: static void
1.44 jakob 453: send_attrib(u_int32_t id, const Attrib *a)
1.1 markus 454: {
455: Buffer msg;
1.22 deraadt 456:
1.58 djm 457: debug("request %u: sent attrib have 0x%x", id, a->flags);
1.1 markus 458: buffer_init(&msg);
1.10 markus 459: buffer_put_char(&msg, SSH2_FXP_ATTRS);
1.1 markus 460: buffer_put_int(&msg, id);
461: encode_attrib(&msg, a);
462: send_msg(&msg);
463: buffer_free(&msg);
464: }
465:
466: /* parse incoming */
467:
1.28 itojun 468: static void
1.1 markus 469: process_init(void)
470: {
471: Buffer msg;
472:
1.35 markus 473: version = get_int();
1.58 djm 474: verbose("received client version %d", version);
1.1 markus 475: buffer_init(&msg);
1.10 markus 476: buffer_put_char(&msg, SSH2_FXP_VERSION);
477: buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
1.1 markus 478: send_msg(&msg);
479: buffer_free(&msg);
480: }
481:
1.28 itojun 482: static void
1.1 markus 483: process_open(void)
484: {
485: u_int32_t id, pflags;
486: Attrib *a;
487: char *name;
1.10 markus 488: int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1 markus 489:
490: id = get_int();
491: name = get_string(NULL);
1.10 markus 492: pflags = get_int(); /* portable flags */
1.61 djm 493: debug3("request %u: open flags %d", id, pflags);
1.1 markus 494: a = get_attrib();
495: flags = flags_from_portable(pflags);
1.10 markus 496: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.58 djm 497: logit("open \"%s\" flags %s mode 0%o",
498: name, string_from_portable(pflags), mode);
1.1 markus 499: fd = open(name, flags, mode);
500: if (fd < 0) {
501: status = errno_to_portable(errno);
502: } else {
1.40 markus 503: handle = handle_new(HANDLE_FILE, name, fd, NULL);
1.1 markus 504: if (handle < 0) {
505: close(fd);
506: } else {
507: send_handle(id, handle);
1.10 markus 508: status = SSH2_FX_OK;
1.1 markus 509: }
510: }
1.10 markus 511: if (status != SSH2_FX_OK)
1.1 markus 512: send_status(id, status);
513: xfree(name);
514: }
515:
1.28 itojun 516: static void
1.1 markus 517: process_close(void)
518: {
519: u_int32_t id;
1.10 markus 520: int handle, ret, status = SSH2_FX_FAILURE;
1.1 markus 521:
522: id = get_int();
523: handle = get_handle();
1.58 djm 524: debug3("request %u: close handle %u", id, handle);
525: handle_log_close(handle, NULL);
1.1 markus 526: ret = handle_close(handle);
1.10 markus 527: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 528: send_status(id, status);
529: }
530:
1.28 itojun 531: static void
1.1 markus 532: process_read(void)
533: {
534: char buf[64*1024];
1.10 markus 535: u_int32_t id, len;
536: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 537: u_int64_t off;
538:
539: id = get_int();
540: handle = get_handle();
1.10 markus 541: off = get_int64();
1.1 markus 542: len = get_int();
543:
1.58 djm 544: debug("request %u: read \"%s\" (handle %d) off %llu len %d",
545: id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1 markus 546: if (len > sizeof buf) {
547: len = sizeof buf;
1.58 djm 548: debug2("read change len %d", len);
1.1 markus 549: }
550: fd = handle_to_fd(handle);
551: if (fd >= 0) {
552: if (lseek(fd, off, SEEK_SET) < 0) {
553: error("process_read: seek failed");
554: status = errno_to_portable(errno);
555: } else {
556: ret = read(fd, buf, len);
557: if (ret < 0) {
558: status = errno_to_portable(errno);
559: } else if (ret == 0) {
1.10 markus 560: status = SSH2_FX_EOF;
1.1 markus 561: } else {
562: send_data(id, buf, ret);
1.10 markus 563: status = SSH2_FX_OK;
1.58 djm 564: handle_update_read(handle, ret);
1.1 markus 565: }
566: }
567: }
1.10 markus 568: if (status != SSH2_FX_OK)
1.1 markus 569: send_status(id, status);
570: }
571:
1.28 itojun 572: static void
1.1 markus 573: process_write(void)
574: {
1.10 markus 575: u_int32_t id;
1.1 markus 576: u_int64_t off;
1.5 markus 577: u_int len;
1.10 markus 578: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 579: char *data;
580:
581: id = get_int();
582: handle = get_handle();
1.10 markus 583: off = get_int64();
1.1 markus 584: data = get_string(&len);
585:
1.58 djm 586: debug("request %u: write \"%s\" (handle %d) off %llu len %d",
587: id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1 markus 588: fd = handle_to_fd(handle);
589: if (fd >= 0) {
590: if (lseek(fd, off, SEEK_SET) < 0) {
591: status = errno_to_portable(errno);
592: error("process_write: seek failed");
593: } else {
594: /* XXX ATOMICIO ? */
595: ret = write(fd, data, len);
1.48 djm 596: if (ret < 0) {
1.1 markus 597: error("process_write: write failed");
598: status = errno_to_portable(errno);
1.48 djm 599: } else if ((size_t)ret == len) {
1.10 markus 600: status = SSH2_FX_OK;
1.58 djm 601: handle_update_write(handle, ret);
1.1 markus 602: } else {
1.58 djm 603: debug2("nothing at all written");
1.1 markus 604: }
605: }
606: }
607: send_status(id, status);
608: xfree(data);
609: }
610:
1.28 itojun 611: static void
1.1 markus 612: process_do_stat(int do_lstat)
613: {
1.13 markus 614: Attrib a;
1.1 markus 615: struct stat st;
616: u_int32_t id;
617: char *name;
1.10 markus 618: int ret, status = SSH2_FX_FAILURE;
1.1 markus 619:
620: id = get_int();
621: name = get_string(NULL);
1.58 djm 622: debug3("request %u: %sstat", id, do_lstat ? "l" : "");
623: verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
1.1 markus 624: ret = do_lstat ? lstat(name, &st) : stat(name, &st);
625: if (ret < 0) {
626: status = errno_to_portable(errno);
627: } else {
1.13 markus 628: stat_to_attrib(&st, &a);
629: send_attrib(id, &a);
1.10 markus 630: status = SSH2_FX_OK;
1.1 markus 631: }
1.10 markus 632: if (status != SSH2_FX_OK)
1.1 markus 633: send_status(id, status);
634: xfree(name);
635: }
636:
1.28 itojun 637: static void
1.1 markus 638: process_stat(void)
639: {
640: process_do_stat(0);
641: }
642:
1.28 itojun 643: static void
1.1 markus 644: process_lstat(void)
645: {
646: process_do_stat(1);
647: }
648:
1.28 itojun 649: static void
1.1 markus 650: process_fstat(void)
651: {
1.13 markus 652: Attrib a;
1.1 markus 653: struct stat st;
654: u_int32_t id;
1.10 markus 655: int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1 markus 656:
657: id = get_int();
658: handle = get_handle();
1.58 djm 659: debug("request %u: fstat \"%s\" (handle %u)",
660: id, handle_to_name(handle), handle);
1.1 markus 661: fd = handle_to_fd(handle);
1.71 stevesk 662: if (fd >= 0) {
1.1 markus 663: ret = fstat(fd, &st);
664: if (ret < 0) {
665: status = errno_to_portable(errno);
666: } else {
1.13 markus 667: stat_to_attrib(&st, &a);
668: send_attrib(id, &a);
1.10 markus 669: status = SSH2_FX_OK;
1.1 markus 670: }
671: }
1.10 markus 672: if (status != SSH2_FX_OK)
1.1 markus 673: send_status(id, status);
674: }
675:
1.28 itojun 676: static struct timeval *
1.44 jakob 677: attrib_to_tv(const Attrib *a)
1.1 markus 678: {
679: static struct timeval tv[2];
1.22 deraadt 680:
1.1 markus 681: tv[0].tv_sec = a->atime;
682: tv[0].tv_usec = 0;
683: tv[1].tv_sec = a->mtime;
684: tv[1].tv_usec = 0;
685: return tv;
686: }
687:
1.28 itojun 688: static void
1.1 markus 689: process_setstat(void)
690: {
691: Attrib *a;
692: u_int32_t id;
693: char *name;
1.36 deraadt 694: int status = SSH2_FX_OK, ret;
1.1 markus 695:
696: id = get_int();
697: name = get_string(NULL);
698: a = get_attrib();
1.58 djm 699: debug("request %u: setstat name \"%s\"", id, name);
1.33 markus 700: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.72 stevesk 701: logit("set \"%s\" size %llu",
702: name, (unsigned long long)a->size);
1.33 markus 703: ret = truncate(name, a->size);
704: if (ret == -1)
705: status = errno_to_portable(errno);
706: }
1.10 markus 707: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58 djm 708: logit("set \"%s\" mode %04o", name, a->perm);
1.1 markus 709: ret = chmod(name, a->perm & 0777);
710: if (ret == -1)
711: status = errno_to_portable(errno);
712: }
1.10 markus 713: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58 djm 714: char buf[64];
715: time_t t = a->mtime;
716:
717: strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
718: localtime(&t));
719: logit("set \"%s\" modtime %s", name, buf);
1.1 markus 720: ret = utimes(name, attrib_to_tv(a));
721: if (ret == -1)
722: status = errno_to_portable(errno);
723: }
1.18 stevesk 724: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58 djm 725: logit("set \"%s\" owner %lu group %lu", name,
726: (u_long)a->uid, (u_long)a->gid);
1.18 stevesk 727: ret = chown(name, a->uid, a->gid);
728: if (ret == -1)
729: status = errno_to_portable(errno);
730: }
1.1 markus 731: send_status(id, status);
732: xfree(name);
733: }
734:
1.28 itojun 735: static void
1.1 markus 736: process_fsetstat(void)
737: {
738: Attrib *a;
739: u_int32_t id;
740: int handle, fd, ret;
1.10 markus 741: int status = SSH2_FX_OK;
1.1 markus 742:
743: id = get_int();
744: handle = get_handle();
745: a = get_attrib();
1.58 djm 746: debug("request %u: fsetstat handle %d", id, handle);
1.1 markus 747: fd = handle_to_fd(handle);
748: if (fd < 0) {
1.10 markus 749: status = SSH2_FX_FAILURE;
1.1 markus 750: } else {
1.58 djm 751: char *name = handle_to_name(handle);
752:
1.33 markus 753: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.72 stevesk 754: logit("set \"%s\" size %llu",
755: name, (unsigned long long)a->size);
1.33 markus 756: ret = ftruncate(fd, a->size);
757: if (ret == -1)
758: status = errno_to_portable(errno);
759: }
1.10 markus 760: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58 djm 761: logit("set \"%s\" mode %04o", name, a->perm);
1.1 markus 762: ret = fchmod(fd, a->perm & 0777);
763: if (ret == -1)
764: status = errno_to_portable(errno);
765: }
1.10 markus 766: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58 djm 767: char buf[64];
768: time_t t = a->mtime;
769:
770: strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
771: localtime(&t));
772: logit("set \"%s\" modtime %s", name, buf);
1.1 markus 773: ret = futimes(fd, attrib_to_tv(a));
1.18 stevesk 774: if (ret == -1)
775: status = errno_to_portable(errno);
776: }
777: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58 djm 778: logit("set \"%s\" owner %lu group %lu", name,
779: (u_long)a->uid, (u_long)a->gid);
1.18 stevesk 780: ret = fchown(fd, a->uid, a->gid);
1.1 markus 781: if (ret == -1)
782: status = errno_to_portable(errno);
783: }
784: }
785: send_status(id, status);
786: }
787:
1.28 itojun 788: static void
1.1 markus 789: process_opendir(void)
790: {
791: DIR *dirp = NULL;
792: char *path;
1.10 markus 793: int handle, status = SSH2_FX_FAILURE;
1.1 markus 794: u_int32_t id;
795:
796: id = get_int();
797: path = get_string(NULL);
1.58 djm 798: debug3("request %u: opendir", id);
799: logit("opendir \"%s\"", path);
1.17 stevesk 800: dirp = opendir(path);
1.1 markus 801: if (dirp == NULL) {
802: status = errno_to_portable(errno);
803: } else {
1.40 markus 804: handle = handle_new(HANDLE_DIR, path, 0, dirp);
1.1 markus 805: if (handle < 0) {
806: closedir(dirp);
807: } else {
808: send_handle(id, handle);
1.10 markus 809: status = SSH2_FX_OK;
1.1 markus 810: }
1.17 stevesk 811:
1.1 markus 812: }
1.10 markus 813: if (status != SSH2_FX_OK)
1.1 markus 814: send_status(id, status);
815: xfree(path);
816: }
817:
1.28 itojun 818: static void
1.1 markus 819: process_readdir(void)
820: {
821: DIR *dirp;
822: struct dirent *dp;
823: char *path;
824: int handle;
825: u_int32_t id;
826:
827: id = get_int();
828: handle = get_handle();
1.58 djm 829: debug("request %u: readdir \"%s\" (handle %d)", id,
830: handle_to_name(handle), handle);
1.1 markus 831: dirp = handle_to_dir(handle);
832: path = handle_to_name(handle);
833: if (dirp == NULL || path == NULL) {
1.10 markus 834: send_status(id, SSH2_FX_FAILURE);
1.1 markus 835: } else {
836: struct stat st;
1.58 djm 837: char pathname[MAXPATHLEN];
1.1 markus 838: Stat *stats;
839: int nstats = 10, count = 0, i;
1.36 deraadt 840:
1.54 djm 841: stats = xcalloc(nstats, sizeof(Stat));
1.1 markus 842: while ((dp = readdir(dirp)) != NULL) {
843: if (count >= nstats) {
844: nstats *= 2;
1.55 djm 845: stats = xrealloc(stats, nstats, sizeof(Stat));
1.1 markus 846: }
847: /* XXX OVERFLOW ? */
1.30 jakob 848: snprintf(pathname, sizeof pathname, "%s%s%s", path,
849: strcmp(path, "/") ? "/" : "", dp->d_name);
1.1 markus 850: if (lstat(pathname, &st) < 0)
851: continue;
1.13 markus 852: stat_to_attrib(&st, &(stats[count].attrib));
1.1 markus 853: stats[count].name = xstrdup(dp->d_name);
1.38 djm 854: stats[count].long_name = ls_file(dp->d_name, &st, 0);
1.1 markus 855: count++;
856: /* send up to 100 entries in one message */
1.11 markus 857: /* XXX check packet size instead */
1.1 markus 858: if (count == 100)
859: break;
860: }
1.10 markus 861: if (count > 0) {
862: send_names(id, count, stats);
1.31 deraadt 863: for (i = 0; i < count; i++) {
1.10 markus 864: xfree(stats[i].name);
865: xfree(stats[i].long_name);
866: }
867: } else {
868: send_status(id, SSH2_FX_EOF);
1.1 markus 869: }
870: xfree(stats);
871: }
872: }
873:
1.28 itojun 874: static void
1.1 markus 875: process_remove(void)
876: {
877: char *name;
878: u_int32_t id;
1.10 markus 879: int status = SSH2_FX_FAILURE;
1.1 markus 880: int ret;
881:
882: id = get_int();
883: name = get_string(NULL);
1.58 djm 884: debug3("request %u: remove", id);
885: logit("remove name \"%s\"", name);
1.8 markus 886: ret = unlink(name);
1.10 markus 887: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 888: send_status(id, status);
889: xfree(name);
890: }
891:
1.28 itojun 892: static void
1.1 markus 893: process_mkdir(void)
894: {
895: Attrib *a;
896: u_int32_t id;
897: char *name;
1.10 markus 898: int ret, mode, status = SSH2_FX_FAILURE;
1.1 markus 899:
900: id = get_int();
901: name = get_string(NULL);
902: a = get_attrib();
1.10 markus 903: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
904: a->perm & 0777 : 0777;
1.58 djm 905: debug3("request %u: mkdir", id);
906: logit("mkdir name \"%s\" mode 0%o", name, mode);
1.1 markus 907: ret = mkdir(name, mode);
1.10 markus 908: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 909: send_status(id, status);
910: xfree(name);
911: }
912:
1.28 itojun 913: static void
1.1 markus 914: process_rmdir(void)
915: {
916: u_int32_t id;
917: char *name;
918: int ret, status;
919:
920: id = get_int();
921: name = get_string(NULL);
1.58 djm 922: debug3("request %u: rmdir", id);
923: logit("rmdir name \"%s\"", name);
1.1 markus 924: ret = rmdir(name);
1.10 markus 925: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 926: send_status(id, status);
927: xfree(name);
928: }
929:
1.28 itojun 930: static void
1.1 markus 931: process_realpath(void)
932: {
933: char resolvedname[MAXPATHLEN];
934: u_int32_t id;
935: char *path;
936:
937: id = get_int();
938: path = get_string(NULL);
1.7 markus 939: if (path[0] == '\0') {
940: xfree(path);
941: path = xstrdup(".");
942: }
1.58 djm 943: debug3("request %u: realpath", id);
944: verbose("realpath \"%s\"", path);
1.1 markus 945: if (realpath(path, resolvedname) == NULL) {
946: send_status(id, errno_to_portable(errno));
947: } else {
948: Stat s;
949: attrib_clear(&s.attrib);
950: s.name = s.long_name = resolvedname;
951: send_names(id, 1, &s);
952: }
953: xfree(path);
954: }
955:
1.28 itojun 956: static void
1.1 markus 957: process_rename(void)
958: {
959: u_int32_t id;
960: char *oldpath, *newpath;
1.39 markus 961: int status;
1.41 deraadt 962: struct stat sb;
1.1 markus 963:
964: id = get_int();
965: oldpath = get_string(NULL);
966: newpath = get_string(NULL);
1.58 djm 967: debug3("request %u: rename", id);
968: logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1.41 deraadt 969: status = SSH2_FX_FAILURE;
970: if (lstat(oldpath, &sb) == -1)
1.39 markus 971: status = errno_to_portable(errno);
1.41 deraadt 972: else if (S_ISREG(sb.st_mode)) {
973: /* Race-free rename of regular files */
1.47 dtucker 974: if (link(oldpath, newpath) == -1) {
975: if (errno == EOPNOTSUPP) {
976: struct stat st;
977:
978: /*
979: * fs doesn't support links, so fall back to
980: * stat+rename. This is racy.
981: */
982: if (stat(newpath, &st) == -1) {
983: if (rename(oldpath, newpath) == -1)
984: status =
985: errno_to_portable(errno);
986: else
987: status = SSH2_FX_OK;
988: }
989: } else {
990: status = errno_to_portable(errno);
991: }
992: } else if (unlink(oldpath) == -1) {
1.41 deraadt 993: status = errno_to_portable(errno);
994: /* clean spare link */
995: unlink(newpath);
996: } else
997: status = SSH2_FX_OK;
998: } else if (stat(newpath, &sb) == -1) {
999: if (rename(oldpath, newpath) == -1)
1000: status = errno_to_portable(errno);
1001: else
1002: status = SSH2_FX_OK;
1003: }
1.1 markus 1004: send_status(id, status);
1005: xfree(oldpath);
1006: xfree(newpath);
1007: }
1008:
1.28 itojun 1009: static void
1.23 djm 1010: process_readlink(void)
1011: {
1012: u_int32_t id;
1.26 markus 1013: int len;
1.46 avsm 1014: char buf[MAXPATHLEN];
1.23 djm 1015: char *path;
1016:
1017: id = get_int();
1018: path = get_string(NULL);
1.58 djm 1019: debug3("request %u: readlink", id);
1020: verbose("readlink \"%s\"", path);
1.46 avsm 1021: if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1.23 djm 1022: send_status(id, errno_to_portable(errno));
1023: else {
1024: Stat s;
1.31 deraadt 1025:
1.46 avsm 1026: buf[len] = '\0';
1.23 djm 1027: attrib_clear(&s.attrib);
1.46 avsm 1028: s.name = s.long_name = buf;
1.23 djm 1029: send_names(id, 1, &s);
1030: }
1031: xfree(path);
1032: }
1033:
1.28 itojun 1034: static void
1.23 djm 1035: process_symlink(void)
1036: {
1037: u_int32_t id;
1038: char *oldpath, *newpath;
1.39 markus 1039: int ret, status;
1.23 djm 1040:
1041: id = get_int();
1042: oldpath = get_string(NULL);
1043: newpath = get_string(NULL);
1.58 djm 1044: debug3("request %u: symlink", id);
1045: logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1.39 markus 1046: /* this will fail if 'newpath' exists */
1047: ret = symlink(oldpath, newpath);
1048: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.23 djm 1049: send_status(id, status);
1050: xfree(oldpath);
1051: xfree(newpath);
1052: }
1053:
1.28 itojun 1054: static void
1.10 markus 1055: process_extended(void)
1056: {
1057: u_int32_t id;
1058: char *request;
1059:
1060: id = get_int();
1061: request = get_string(NULL);
1062: send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
1063: xfree(request);
1064: }
1.1 markus 1065:
1066: /* stolen from ssh-agent */
1067:
1.28 itojun 1068: static void
1.1 markus 1069: process(void)
1070: {
1.9 markus 1071: u_int msg_len;
1.34 markus 1072: u_int buf_len;
1073: u_int consumed;
1.9 markus 1074: u_int type;
1075: u_char *cp;
1.1 markus 1076:
1.34 markus 1077: buf_len = buffer_len(&iqueue);
1078: if (buf_len < 5)
1.1 markus 1079: return; /* Incomplete message. */
1.32 stevesk 1080: cp = buffer_ptr(&iqueue);
1.57 djm 1081: msg_len = get_u32(cp);
1.50 djm 1082: if (msg_len > SFTP_MAX_MSG_LENGTH) {
1.58 djm 1083: error("bad message from %s local user %s",
1084: client_addr, pw->pw_name);
1085: cleanup_exit(11);
1.1 markus 1086: }
1.34 markus 1087: if (buf_len < msg_len + 4)
1.1 markus 1088: return;
1089: buffer_consume(&iqueue, 4);
1.34 markus 1090: buf_len -= 4;
1.1 markus 1091: type = buffer_get_char(&iqueue);
1092: switch (type) {
1.10 markus 1093: case SSH2_FXP_INIT:
1.1 markus 1094: process_init();
1095: break;
1.10 markus 1096: case SSH2_FXP_OPEN:
1.1 markus 1097: process_open();
1098: break;
1.10 markus 1099: case SSH2_FXP_CLOSE:
1.1 markus 1100: process_close();
1101: break;
1.10 markus 1102: case SSH2_FXP_READ:
1.1 markus 1103: process_read();
1104: break;
1.10 markus 1105: case SSH2_FXP_WRITE:
1.1 markus 1106: process_write();
1107: break;
1.10 markus 1108: case SSH2_FXP_LSTAT:
1.1 markus 1109: process_lstat();
1110: break;
1.10 markus 1111: case SSH2_FXP_FSTAT:
1.1 markus 1112: process_fstat();
1113: break;
1.10 markus 1114: case SSH2_FXP_SETSTAT:
1.1 markus 1115: process_setstat();
1116: break;
1.10 markus 1117: case SSH2_FXP_FSETSTAT:
1.1 markus 1118: process_fsetstat();
1119: break;
1.10 markus 1120: case SSH2_FXP_OPENDIR:
1.1 markus 1121: process_opendir();
1122: break;
1.10 markus 1123: case SSH2_FXP_READDIR:
1.1 markus 1124: process_readdir();
1125: break;
1.10 markus 1126: case SSH2_FXP_REMOVE:
1.1 markus 1127: process_remove();
1128: break;
1.10 markus 1129: case SSH2_FXP_MKDIR:
1.1 markus 1130: process_mkdir();
1131: break;
1.10 markus 1132: case SSH2_FXP_RMDIR:
1.1 markus 1133: process_rmdir();
1134: break;
1.10 markus 1135: case SSH2_FXP_REALPATH:
1.1 markus 1136: process_realpath();
1137: break;
1.10 markus 1138: case SSH2_FXP_STAT:
1.1 markus 1139: process_stat();
1140: break;
1.10 markus 1141: case SSH2_FXP_RENAME:
1.1 markus 1142: process_rename();
1.23 djm 1143: break;
1144: case SSH2_FXP_READLINK:
1145: process_readlink();
1146: break;
1147: case SSH2_FXP_SYMLINK:
1148: process_symlink();
1.1 markus 1149: break;
1.10 markus 1150: case SSH2_FXP_EXTENDED:
1151: process_extended();
1152: break;
1.1 markus 1153: default:
1154: error("Unknown message %d", type);
1155: break;
1156: }
1.34 markus 1157: /* discard the remaining bytes from the current packet */
1158: if (buf_len < buffer_len(&iqueue))
1.58 djm 1159: fatal("iqueue grew unexpectedly");
1.34 markus 1160: consumed = buf_len - buffer_len(&iqueue);
1161: if (msg_len < consumed)
1162: fatal("msg_len %d < consumed %d", msg_len, consumed);
1163: if (msg_len > consumed)
1164: buffer_consume(&iqueue, msg_len - consumed);
1.1 markus 1165: }
1166:
1.58 djm 1167: /* Cleanup handler that logs active handles upon normal exit */
1168: void
1169: cleanup_exit(int i)
1170: {
1171: if (pw != NULL && client_addr != NULL) {
1172: handle_log_exit();
1173: logit("session closed for local user %s from [%s]",
1174: pw->pw_name, client_addr);
1175: }
1176: _exit(i);
1177: }
1178:
1179: static void
1180: usage(void)
1181: {
1182: extern char *__progname;
1183:
1184: fprintf(stderr,
1185: "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
1186: exit(1);
1187: }
1188:
1.1 markus 1189: int
1.58 djm 1190: main(int argc, char **argv)
1.1 markus 1191: {
1.21 millert 1192: fd_set *rset, *wset;
1.58 djm 1193: int in, out, max, ch, skipargs = 0, log_stderr = 0;
1.21 millert 1194: ssize_t len, olen, set_size;
1.58 djm 1195: SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1.73 ! djm 1196: char *cp, buf[4*4096];
1.58 djm 1197:
1198: extern char *optarg;
1199: extern char *__progname;
1.49 djm 1200:
1201: /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1202: sanitise_stdfd();
1.24 deraadt 1203:
1.58 djm 1204: log_init(__progname, log_level, log_facility, log_stderr);
1205:
1206: while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
1207: switch (ch) {
1208: case 'c':
1209: /*
1210: * Ignore all arguments if we are invoked as a
1.70 deraadt 1211: * shell using "sftp-server -c command"
1.58 djm 1212: */
1213: skipargs = 1;
1214: break;
1215: case 'e':
1216: log_stderr = 1;
1217: break;
1218: case 'l':
1219: log_level = log_level_number(optarg);
1220: if (log_level == SYSLOG_LEVEL_NOT_SET)
1221: error("Invalid log level \"%s\"", optarg);
1222: break;
1223: case 'f':
1224: log_facility = log_facility_number(optarg);
1225: if (log_level == SYSLOG_FACILITY_NOT_SET)
1226: error("Invalid log facility \"%s\"", optarg);
1227: break;
1228: case 'h':
1229: default:
1230: usage();
1231: }
1232: }
1233:
1234: log_init(__progname, log_level, log_facility, log_stderr);
1235:
1236: if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1237: client_addr = xstrdup(cp);
1238: if ((cp = strchr(client_addr, ' ')) == NULL)
1239: fatal("Malformed SSH_CONNECTION variable: \"%s\"",
1240: getenv("SSH_CONNECTION"));
1241: *cp = '\0';
1242: } else
1243: client_addr = xstrdup("UNKNOWN");
1244:
1245: if ((pw = getpwuid(getuid())) == NULL)
1246: fatal("No user found for uid %lu", (u_long)getuid());
1247: pw = pwcopy(pw);
1248:
1249: logit("session opened for local user %s from [%s]",
1250: pw->pw_name, client_addr);
1.1 markus 1251:
1252: handle_init();
1.10 markus 1253:
1.1 markus 1254: in = dup(STDIN_FILENO);
1255: out = dup(STDOUT_FILENO);
1256:
1257: max = 0;
1258: if (in > max)
1259: max = in;
1260: if (out > max)
1261: max = out;
1262:
1263: buffer_init(&iqueue);
1264: buffer_init(&oqueue);
1265:
1.21 millert 1266: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1267: rset = (fd_set *)xmalloc(set_size);
1268: wset = (fd_set *)xmalloc(set_size);
1269:
1.1 markus 1270: for (;;) {
1.21 millert 1271: memset(rset, 0, set_size);
1272: memset(wset, 0, set_size);
1.1 markus 1273:
1.73 ! djm 1274: /*
! 1275: * Ensure that we can read a full buffer and handle
! 1276: * the worst-case length packet it can generate,
! 1277: * otherwise apply backpressure by stopping reads.
! 1278: */
! 1279: if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
! 1280: buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
! 1281: FD_SET(in, rset);
! 1282:
1.1 markus 1283: olen = buffer_len(&oqueue);
1284: if (olen > 0)
1.21 millert 1285: FD_SET(out, wset);
1.1 markus 1286:
1.21 millert 1287: if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1 markus 1288: if (errno == EINTR)
1289: continue;
1.58 djm 1290: error("select: %s", strerror(errno));
1291: cleanup_exit(2);
1.1 markus 1292: }
1293:
1294: /* copy stdin to iqueue */
1.21 millert 1295: if (FD_ISSET(in, rset)) {
1.1 markus 1296: len = read(in, buf, sizeof buf);
1297: if (len == 0) {
1298: debug("read eof");
1.58 djm 1299: cleanup_exit(0);
1.1 markus 1300: } else if (len < 0) {
1.58 djm 1301: error("read: %s", strerror(errno));
1302: cleanup_exit(1);
1.1 markus 1303: } else {
1304: buffer_append(&iqueue, buf, len);
1305: }
1306: }
1307: /* send oqueue to stdout */
1.21 millert 1308: if (FD_ISSET(out, wset)) {
1.1 markus 1309: len = write(out, buffer_ptr(&oqueue), olen);
1310: if (len < 0) {
1.58 djm 1311: error("write: %s", strerror(errno));
1312: cleanup_exit(1);
1.1 markus 1313: } else {
1314: buffer_consume(&oqueue, len);
1315: }
1316: }
1.73 ! djm 1317:
! 1318: /*
! 1319: * Process requests from client if we can fit the results
! 1320: * into the output buffer, otherwise stop processing input
! 1321: * and let the output queue drain.
! 1322: */
! 1323: if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
! 1324: process();
1.1 markus 1325: }
1326: }