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