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