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