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