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