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