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