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