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