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