Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.97
1.97 ! djm 1: /* $OpenBSD: sftp-server.c,v 1.96 2013/01/04 19:26:38 jmc 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 */
1.94 djm 62: u_int version;
1.23 djm 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.97 ! djm 313: free(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.97 ! djm 317: free(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.97 ! djm 361: free(handle);
1.1 markus 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.97 ! djm 444: free(string);
1.1 markus 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.94 djm 516: verbose("received client version %u", 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.93 djm 529: /* hardlink extension */
530: buffer_put_cstring(&msg, "hardlink@openssh.com");
531: buffer_put_cstring(&msg, "1"); /* version */
1.1 markus 532: send_msg(&msg);
533: buffer_free(&msg);
534: }
535:
1.28 itojun 536: static void
1.1 markus 537: process_open(void)
538: {
539: u_int32_t id, pflags;
540: Attrib *a;
541: char *name;
1.10 markus 542: int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1 markus 543:
544: id = get_int();
545: name = get_string(NULL);
1.10 markus 546: pflags = get_int(); /* portable flags */
1.61 djm 547: debug3("request %u: open flags %d", id, pflags);
1.1 markus 548: a = get_attrib();
549: flags = flags_from_portable(pflags);
1.10 markus 550: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.58 djm 551: logit("open \"%s\" flags %s mode 0%o",
552: name, string_from_portable(pflags), mode);
1.90 djm 553: if (readonly &&
554: ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR))
555: status = SSH2_FX_PERMISSION_DENIED;
556: else {
557: fd = open(name, flags, mode);
558: if (fd < 0) {
559: status = errno_to_portable(errno);
1.1 markus 560: } else {
1.90 djm 561: handle = handle_new(HANDLE_FILE, name, fd, NULL);
562: if (handle < 0) {
563: close(fd);
564: } else {
565: send_handle(id, handle);
566: status = SSH2_FX_OK;
567: }
1.1 markus 568: }
569: }
1.10 markus 570: if (status != SSH2_FX_OK)
1.1 markus 571: send_status(id, status);
1.97 ! djm 572: free(name);
1.1 markus 573: }
574:
1.28 itojun 575: static void
1.1 markus 576: process_close(void)
577: {
578: u_int32_t id;
1.10 markus 579: int handle, ret, status = SSH2_FX_FAILURE;
1.1 markus 580:
581: id = get_int();
582: handle = get_handle();
1.58 djm 583: debug3("request %u: close handle %u", id, handle);
584: handle_log_close(handle, NULL);
1.1 markus 585: ret = handle_close(handle);
1.10 markus 586: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 587: send_status(id, status);
588: }
589:
1.28 itojun 590: static void
1.1 markus 591: process_read(void)
592: {
593: char buf[64*1024];
1.10 markus 594: u_int32_t id, len;
595: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 596: u_int64_t off;
597:
598: id = get_int();
599: handle = get_handle();
1.10 markus 600: off = get_int64();
1.1 markus 601: len = get_int();
602:
1.58 djm 603: debug("request %u: read \"%s\" (handle %d) off %llu len %d",
604: id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1 markus 605: if (len > sizeof buf) {
606: len = sizeof buf;
1.58 djm 607: debug2("read change len %d", len);
1.1 markus 608: }
609: fd = handle_to_fd(handle);
610: if (fd >= 0) {
611: if (lseek(fd, off, SEEK_SET) < 0) {
612: error("process_read: seek failed");
613: status = errno_to_portable(errno);
614: } else {
615: ret = read(fd, buf, len);
616: if (ret < 0) {
617: status = errno_to_portable(errno);
618: } else if (ret == 0) {
1.10 markus 619: status = SSH2_FX_EOF;
1.1 markus 620: } else {
621: send_data(id, buf, ret);
1.10 markus 622: status = SSH2_FX_OK;
1.58 djm 623: handle_update_read(handle, ret);
1.1 markus 624: }
625: }
626: }
1.10 markus 627: if (status != SSH2_FX_OK)
1.1 markus 628: send_status(id, status);
629: }
630:
1.28 itojun 631: static void
1.1 markus 632: process_write(void)
633: {
1.10 markus 634: u_int32_t id;
1.1 markus 635: u_int64_t off;
1.5 markus 636: u_int len;
1.90 djm 637: int handle, fd, ret, status;
1.1 markus 638: char *data;
639:
640: id = get_int();
641: handle = get_handle();
1.10 markus 642: off = get_int64();
1.1 markus 643: data = get_string(&len);
644:
1.58 djm 645: debug("request %u: write \"%s\" (handle %d) off %llu len %d",
646: id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1 markus 647: fd = handle_to_fd(handle);
1.90 djm 648:
649: if (fd < 0)
650: status = SSH2_FX_FAILURE;
651: else if (readonly)
652: status = SSH2_FX_PERMISSION_DENIED;
653: else {
1.1 markus 654: if (lseek(fd, off, SEEK_SET) < 0) {
655: status = errno_to_portable(errno);
656: error("process_write: seek failed");
657: } else {
658: /* XXX ATOMICIO ? */
659: ret = write(fd, data, len);
1.48 djm 660: if (ret < 0) {
1.1 markus 661: error("process_write: write failed");
662: status = errno_to_portable(errno);
1.48 djm 663: } else if ((size_t)ret == len) {
1.10 markus 664: status = SSH2_FX_OK;
1.58 djm 665: handle_update_write(handle, ret);
1.1 markus 666: } else {
1.58 djm 667: debug2("nothing at all written");
1.90 djm 668: status = SSH2_FX_FAILURE;
1.1 markus 669: }
670: }
671: }
672: send_status(id, status);
1.97 ! djm 673: free(data);
1.1 markus 674: }
675:
1.28 itojun 676: static void
1.1 markus 677: process_do_stat(int do_lstat)
678: {
1.13 markus 679: Attrib a;
1.1 markus 680: struct stat st;
681: u_int32_t id;
682: char *name;
1.10 markus 683: int ret, status = SSH2_FX_FAILURE;
1.1 markus 684:
685: id = get_int();
686: name = get_string(NULL);
1.58 djm 687: debug3("request %u: %sstat", id, do_lstat ? "l" : "");
688: verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
1.1 markus 689: ret = do_lstat ? lstat(name, &st) : stat(name, &st);
690: if (ret < 0) {
691: status = errno_to_portable(errno);
692: } else {
1.13 markus 693: stat_to_attrib(&st, &a);
694: send_attrib(id, &a);
1.10 markus 695: status = SSH2_FX_OK;
1.1 markus 696: }
1.10 markus 697: if (status != SSH2_FX_OK)
1.1 markus 698: send_status(id, status);
1.97 ! djm 699: free(name);
1.1 markus 700: }
701:
1.28 itojun 702: static void
1.1 markus 703: process_stat(void)
704: {
705: process_do_stat(0);
706: }
707:
1.28 itojun 708: static void
1.1 markus 709: process_lstat(void)
710: {
711: process_do_stat(1);
712: }
713:
1.28 itojun 714: static void
1.1 markus 715: process_fstat(void)
716: {
1.13 markus 717: Attrib a;
1.1 markus 718: struct stat st;
719: u_int32_t id;
1.10 markus 720: int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1 markus 721:
722: id = get_int();
723: handle = get_handle();
1.58 djm 724: debug("request %u: fstat \"%s\" (handle %u)",
725: id, handle_to_name(handle), handle);
1.1 markus 726: fd = handle_to_fd(handle);
1.71 stevesk 727: if (fd >= 0) {
1.1 markus 728: ret = fstat(fd, &st);
729: if (ret < 0) {
730: status = errno_to_portable(errno);
731: } else {
1.13 markus 732: stat_to_attrib(&st, &a);
733: send_attrib(id, &a);
1.10 markus 734: status = SSH2_FX_OK;
1.1 markus 735: }
736: }
1.10 markus 737: if (status != SSH2_FX_OK)
1.1 markus 738: send_status(id, status);
739: }
740:
1.28 itojun 741: static struct timeval *
1.44 jakob 742: attrib_to_tv(const Attrib *a)
1.1 markus 743: {
744: static struct timeval tv[2];
1.22 deraadt 745:
1.1 markus 746: tv[0].tv_sec = a->atime;
747: tv[0].tv_usec = 0;
748: tv[1].tv_sec = a->mtime;
749: tv[1].tv_usec = 0;
750: return tv;
751: }
752:
1.28 itojun 753: static void
1.1 markus 754: process_setstat(void)
755: {
756: Attrib *a;
757: u_int32_t id;
758: char *name;
1.36 deraadt 759: int status = SSH2_FX_OK, ret;
1.1 markus 760:
761: id = get_int();
762: name = get_string(NULL);
763: a = get_attrib();
1.58 djm 764: debug("request %u: setstat name \"%s\"", id, name);
1.90 djm 765: if (readonly) {
766: status = SSH2_FX_PERMISSION_DENIED;
767: a->flags = 0;
768: }
1.33 markus 769: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.72 stevesk 770: logit("set \"%s\" size %llu",
771: name, (unsigned long long)a->size);
1.33 markus 772: ret = truncate(name, a->size);
773: if (ret == -1)
774: status = errno_to_portable(errno);
775: }
1.10 markus 776: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58 djm 777: logit("set \"%s\" mode %04o", name, a->perm);
1.84 djm 778: ret = chmod(name, a->perm & 07777);
1.1 markus 779: if (ret == -1)
780: status = errno_to_portable(errno);
781: }
1.10 markus 782: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58 djm 783: char buf[64];
784: time_t t = a->mtime;
785:
786: strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
787: localtime(&t));
788: logit("set \"%s\" modtime %s", name, buf);
1.1 markus 789: ret = utimes(name, attrib_to_tv(a));
790: if (ret == -1)
791: status = errno_to_portable(errno);
792: }
1.18 stevesk 793: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58 djm 794: logit("set \"%s\" owner %lu group %lu", name,
795: (u_long)a->uid, (u_long)a->gid);
1.18 stevesk 796: ret = chown(name, a->uid, a->gid);
797: if (ret == -1)
798: status = errno_to_portable(errno);
799: }
1.1 markus 800: send_status(id, status);
1.97 ! djm 801: free(name);
1.1 markus 802: }
803:
1.28 itojun 804: static void
1.1 markus 805: process_fsetstat(void)
806: {
807: Attrib *a;
808: u_int32_t id;
809: int handle, fd, ret;
1.10 markus 810: int status = SSH2_FX_OK;
1.1 markus 811:
812: id = get_int();
813: handle = get_handle();
814: a = get_attrib();
1.58 djm 815: debug("request %u: fsetstat handle %d", id, handle);
1.1 markus 816: fd = handle_to_fd(handle);
1.90 djm 817: if (fd < 0)
1.10 markus 818: status = SSH2_FX_FAILURE;
1.90 djm 819: else if (readonly)
820: status = SSH2_FX_PERMISSION_DENIED;
821: else {
1.58 djm 822: char *name = handle_to_name(handle);
823:
1.33 markus 824: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.72 stevesk 825: logit("set \"%s\" size %llu",
826: name, (unsigned long long)a->size);
1.33 markus 827: ret = ftruncate(fd, a->size);
828: if (ret == -1)
829: status = errno_to_portable(errno);
830: }
1.10 markus 831: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58 djm 832: logit("set \"%s\" mode %04o", name, a->perm);
1.84 djm 833: ret = fchmod(fd, a->perm & 07777);
1.1 markus 834: if (ret == -1)
835: status = errno_to_portable(errno);
836: }
1.10 markus 837: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58 djm 838: char buf[64];
839: time_t t = a->mtime;
840:
841: strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
842: localtime(&t));
843: logit("set \"%s\" modtime %s", name, buf);
1.1 markus 844: ret = futimes(fd, attrib_to_tv(a));
1.18 stevesk 845: if (ret == -1)
846: status = errno_to_portable(errno);
847: }
848: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58 djm 849: logit("set \"%s\" owner %lu group %lu", name,
850: (u_long)a->uid, (u_long)a->gid);
1.18 stevesk 851: ret = fchown(fd, a->uid, a->gid);
1.1 markus 852: if (ret == -1)
853: status = errno_to_portable(errno);
854: }
855: }
856: send_status(id, status);
857: }
858:
1.28 itojun 859: static void
1.1 markus 860: process_opendir(void)
861: {
862: DIR *dirp = NULL;
863: char *path;
1.10 markus 864: int handle, status = SSH2_FX_FAILURE;
1.1 markus 865: u_int32_t id;
866:
867: id = get_int();
868: path = get_string(NULL);
1.58 djm 869: debug3("request %u: opendir", id);
870: logit("opendir \"%s\"", path);
1.17 stevesk 871: dirp = opendir(path);
1.1 markus 872: if (dirp == NULL) {
873: status = errno_to_portable(errno);
874: } else {
1.40 markus 875: handle = handle_new(HANDLE_DIR, path, 0, dirp);
1.1 markus 876: if (handle < 0) {
877: closedir(dirp);
878: } else {
879: send_handle(id, handle);
1.10 markus 880: status = SSH2_FX_OK;
1.1 markus 881: }
1.17 stevesk 882:
1.1 markus 883: }
1.10 markus 884: if (status != SSH2_FX_OK)
1.1 markus 885: send_status(id, status);
1.97 ! djm 886: free(path);
1.1 markus 887: }
888:
1.28 itojun 889: static void
1.1 markus 890: process_readdir(void)
891: {
892: DIR *dirp;
893: struct dirent *dp;
894: char *path;
895: int handle;
896: u_int32_t id;
897:
898: id = get_int();
899: handle = get_handle();
1.58 djm 900: debug("request %u: readdir \"%s\" (handle %d)", id,
901: handle_to_name(handle), handle);
1.1 markus 902: dirp = handle_to_dir(handle);
903: path = handle_to_name(handle);
904: if (dirp == NULL || path == NULL) {
1.10 markus 905: send_status(id, SSH2_FX_FAILURE);
1.1 markus 906: } else {
907: struct stat st;
1.58 djm 908: char pathname[MAXPATHLEN];
1.1 markus 909: Stat *stats;
910: int nstats = 10, count = 0, i;
1.36 deraadt 911:
1.54 djm 912: stats = xcalloc(nstats, sizeof(Stat));
1.1 markus 913: while ((dp = readdir(dirp)) != NULL) {
914: if (count >= nstats) {
915: nstats *= 2;
1.55 djm 916: stats = xrealloc(stats, nstats, sizeof(Stat));
1.1 markus 917: }
918: /* XXX OVERFLOW ? */
1.30 jakob 919: snprintf(pathname, sizeof pathname, "%s%s%s", path,
920: strcmp(path, "/") ? "/" : "", dp->d_name);
1.1 markus 921: if (lstat(pathname, &st) < 0)
922: continue;
1.13 markus 923: stat_to_attrib(&st, &(stats[count].attrib));
1.1 markus 924: stats[count].name = xstrdup(dp->d_name);
1.91 djm 925: stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
1.1 markus 926: count++;
927: /* send up to 100 entries in one message */
1.11 markus 928: /* XXX check packet size instead */
1.1 markus 929: if (count == 100)
930: break;
931: }
1.10 markus 932: if (count > 0) {
933: send_names(id, count, stats);
1.31 deraadt 934: for (i = 0; i < count; i++) {
1.97 ! djm 935: free(stats[i].name);
! 936: free(stats[i].long_name);
1.10 markus 937: }
938: } else {
939: send_status(id, SSH2_FX_EOF);
1.1 markus 940: }
1.97 ! djm 941: free(stats);
1.1 markus 942: }
943: }
944:
1.28 itojun 945: static void
1.1 markus 946: process_remove(void)
947: {
948: char *name;
949: u_int32_t id;
1.10 markus 950: int status = SSH2_FX_FAILURE;
1.1 markus 951: int ret;
952:
953: id = get_int();
954: name = get_string(NULL);
1.58 djm 955: debug3("request %u: remove", id);
956: logit("remove name \"%s\"", name);
1.90 djm 957: if (readonly)
958: status = SSH2_FX_PERMISSION_DENIED;
959: else {
960: ret = unlink(name);
961: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
962: }
1.1 markus 963: send_status(id, status);
1.97 ! djm 964: free(name);
1.1 markus 965: }
966:
1.28 itojun 967: static void
1.1 markus 968: process_mkdir(void)
969: {
970: Attrib *a;
971: u_int32_t id;
972: char *name;
1.10 markus 973: int ret, mode, status = SSH2_FX_FAILURE;
1.1 markus 974:
975: id = get_int();
976: name = get_string(NULL);
977: a = get_attrib();
1.10 markus 978: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
1.84 djm 979: a->perm & 07777 : 0777;
1.58 djm 980: debug3("request %u: mkdir", id);
981: logit("mkdir name \"%s\" mode 0%o", name, mode);
1.90 djm 982: if (readonly)
983: status = SSH2_FX_PERMISSION_DENIED;
984: else {
985: ret = mkdir(name, mode);
986: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
987: }
1.1 markus 988: send_status(id, status);
1.97 ! djm 989: free(name);
1.1 markus 990: }
991:
1.28 itojun 992: static void
1.1 markus 993: process_rmdir(void)
994: {
995: u_int32_t id;
996: char *name;
997: int ret, status;
998:
999: id = get_int();
1000: name = get_string(NULL);
1.58 djm 1001: debug3("request %u: rmdir", id);
1002: logit("rmdir name \"%s\"", name);
1.90 djm 1003: if (readonly)
1004: status = SSH2_FX_PERMISSION_DENIED;
1005: else {
1006: ret = rmdir(name);
1007: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1008: }
1.1 markus 1009: send_status(id, status);
1.97 ! djm 1010: free(name);
1.1 markus 1011: }
1012:
1.28 itojun 1013: static void
1.1 markus 1014: process_realpath(void)
1015: {
1016: char resolvedname[MAXPATHLEN];
1017: u_int32_t id;
1018: char *path;
1019:
1020: id = get_int();
1021: path = get_string(NULL);
1.7 markus 1022: if (path[0] == '\0') {
1.97 ! djm 1023: free(path);
1.7 markus 1024: path = xstrdup(".");
1025: }
1.58 djm 1026: debug3("request %u: realpath", id);
1027: verbose("realpath \"%s\"", path);
1.1 markus 1028: if (realpath(path, resolvedname) == NULL) {
1029: send_status(id, errno_to_portable(errno));
1030: } else {
1031: Stat s;
1032: attrib_clear(&s.attrib);
1033: s.name = s.long_name = resolvedname;
1034: send_names(id, 1, &s);
1035: }
1.97 ! djm 1036: free(path);
1.1 markus 1037: }
1038:
1.28 itojun 1039: static void
1.1 markus 1040: process_rename(void)
1041: {
1042: u_int32_t id;
1043: char *oldpath, *newpath;
1.39 markus 1044: int status;
1.41 deraadt 1045: struct stat sb;
1.1 markus 1046:
1047: id = get_int();
1048: oldpath = get_string(NULL);
1049: newpath = get_string(NULL);
1.58 djm 1050: debug3("request %u: rename", id);
1051: logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1.41 deraadt 1052: status = SSH2_FX_FAILURE;
1.90 djm 1053: if (readonly)
1054: status = SSH2_FX_PERMISSION_DENIED;
1055: else if (lstat(oldpath, &sb) == -1)
1.39 markus 1056: status = errno_to_portable(errno);
1.41 deraadt 1057: else if (S_ISREG(sb.st_mode)) {
1058: /* Race-free rename of regular files */
1.47 dtucker 1059: if (link(oldpath, newpath) == -1) {
1060: if (errno == EOPNOTSUPP) {
1061: struct stat st;
1062:
1063: /*
1064: * fs doesn't support links, so fall back to
1065: * stat+rename. This is racy.
1066: */
1067: if (stat(newpath, &st) == -1) {
1068: if (rename(oldpath, newpath) == -1)
1069: status =
1070: errno_to_portable(errno);
1071: else
1072: status = SSH2_FX_OK;
1073: }
1074: } else {
1075: status = errno_to_portable(errno);
1076: }
1077: } else if (unlink(oldpath) == -1) {
1.41 deraadt 1078: status = errno_to_portable(errno);
1079: /* clean spare link */
1080: unlink(newpath);
1081: } else
1082: status = SSH2_FX_OK;
1083: } else if (stat(newpath, &sb) == -1) {
1084: if (rename(oldpath, newpath) == -1)
1085: status = errno_to_portable(errno);
1086: else
1087: status = SSH2_FX_OK;
1088: }
1.1 markus 1089: send_status(id, status);
1.97 ! djm 1090: free(oldpath);
! 1091: free(newpath);
1.1 markus 1092: }
1093:
1.28 itojun 1094: static void
1.23 djm 1095: process_readlink(void)
1096: {
1097: u_int32_t id;
1.26 markus 1098: int len;
1.46 avsm 1099: char buf[MAXPATHLEN];
1.23 djm 1100: char *path;
1101:
1102: id = get_int();
1103: path = get_string(NULL);
1.58 djm 1104: debug3("request %u: readlink", id);
1105: verbose("readlink \"%s\"", path);
1.46 avsm 1106: if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1.23 djm 1107: send_status(id, errno_to_portable(errno));
1108: else {
1109: Stat s;
1.31 deraadt 1110:
1.46 avsm 1111: buf[len] = '\0';
1.23 djm 1112: attrib_clear(&s.attrib);
1.46 avsm 1113: s.name = s.long_name = buf;
1.23 djm 1114: send_names(id, 1, &s);
1115: }
1.97 ! djm 1116: free(path);
1.23 djm 1117: }
1118:
1.28 itojun 1119: static void
1.23 djm 1120: process_symlink(void)
1121: {
1122: u_int32_t id;
1123: char *oldpath, *newpath;
1.39 markus 1124: int ret, status;
1.23 djm 1125:
1126: id = get_int();
1127: oldpath = get_string(NULL);
1128: newpath = get_string(NULL);
1.58 djm 1129: debug3("request %u: symlink", id);
1130: logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1.39 markus 1131: /* this will fail if 'newpath' exists */
1.90 djm 1132: if (readonly)
1133: status = SSH2_FX_PERMISSION_DENIED;
1134: else {
1135: ret = symlink(oldpath, newpath);
1136: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1137: }
1.23 djm 1138: send_status(id, status);
1.97 ! djm 1139: free(oldpath);
! 1140: free(newpath);
1.23 djm 1141: }
1142:
1.28 itojun 1143: static void
1.78 djm 1144: process_extended_posix_rename(u_int32_t id)
1145: {
1146: char *oldpath, *newpath;
1.90 djm 1147: int ret, status;
1.78 djm 1148:
1149: oldpath = get_string(NULL);
1150: newpath = get_string(NULL);
1151: debug3("request %u: posix-rename", id);
1152: logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1.90 djm 1153: if (readonly)
1154: status = SSH2_FX_PERMISSION_DENIED;
1155: else {
1156: ret = rename(oldpath, newpath);
1157: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1158: }
1159: send_status(id, status);
1.97 ! djm 1160: free(oldpath);
! 1161: free(newpath);
1.78 djm 1162: }
1163:
1164: static void
1.79 djm 1165: process_extended_statvfs(u_int32_t id)
1166: {
1167: char *path;
1168: struct statvfs st;
1169:
1170: path = get_string(NULL);
1171: debug3("request %u: statfs", id);
1172: logit("statfs \"%s\"", path);
1173:
1174: if (statvfs(path, &st) != 0)
1175: send_status(id, errno_to_portable(errno));
1176: else
1177: send_statvfs(id, &st);
1.97 ! djm 1178: free(path);
1.79 djm 1179: }
1180:
1181: static void
1182: process_extended_fstatvfs(u_int32_t id)
1183: {
1184: int handle, fd;
1185: struct statvfs st;
1186:
1187: handle = get_handle();
1188: debug("request %u: fstatvfs \"%s\" (handle %u)",
1189: id, handle_to_name(handle), handle);
1190: if ((fd = handle_to_fd(handle)) < 0) {
1191: send_status(id, SSH2_FX_FAILURE);
1192: return;
1193: }
1194: if (fstatvfs(fd, &st) != 0)
1195: send_status(id, errno_to_portable(errno));
1196: else
1197: send_statvfs(id, &st);
1198: }
1199:
1200: static void
1.93 djm 1201: process_extended_hardlink(u_int32_t id)
1202: {
1203: char *oldpath, *newpath;
1204: int ret, status;
1205:
1206: oldpath = get_string(NULL);
1207: newpath = get_string(NULL);
1208: debug3("request %u: hardlink", id);
1209: logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
1210: if (readonly)
1211: status = SSH2_FX_PERMISSION_DENIED;
1212: else {
1213: ret = link(oldpath, newpath);
1214: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1215: }
1216: send_status(id, status);
1.97 ! djm 1217: free(oldpath);
! 1218: free(newpath);
1.93 djm 1219: }
1220:
1221: static void
1.10 markus 1222: process_extended(void)
1223: {
1224: u_int32_t id;
1225: char *request;
1226:
1227: id = get_int();
1228: request = get_string(NULL);
1.78 djm 1229: if (strcmp(request, "posix-rename@openssh.com") == 0)
1230: process_extended_posix_rename(id);
1.79 djm 1231: else if (strcmp(request, "statvfs@openssh.com") == 0)
1232: process_extended_statvfs(id);
1233: else if (strcmp(request, "fstatvfs@openssh.com") == 0)
1234: process_extended_fstatvfs(id);
1.93 djm 1235: else if (strcmp(request, "hardlink@openssh.com") == 0)
1236: process_extended_hardlink(id);
1.78 djm 1237: else
1238: send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
1.97 ! djm 1239: free(request);
1.10 markus 1240: }
1.1 markus 1241:
1242: /* stolen from ssh-agent */
1243:
1.28 itojun 1244: static void
1.1 markus 1245: process(void)
1246: {
1.9 markus 1247: u_int msg_len;
1.34 markus 1248: u_int buf_len;
1249: u_int consumed;
1.9 markus 1250: u_int type;
1251: u_char *cp;
1.1 markus 1252:
1.34 markus 1253: buf_len = buffer_len(&iqueue);
1254: if (buf_len < 5)
1.1 markus 1255: return; /* Incomplete message. */
1.32 stevesk 1256: cp = buffer_ptr(&iqueue);
1.57 djm 1257: msg_len = get_u32(cp);
1.50 djm 1258: if (msg_len > SFTP_MAX_MSG_LENGTH) {
1.58 djm 1259: error("bad message from %s local user %s",
1260: client_addr, pw->pw_name);
1.76 markus 1261: sftp_server_cleanup_exit(11);
1.1 markus 1262: }
1.34 markus 1263: if (buf_len < msg_len + 4)
1.1 markus 1264: return;
1265: buffer_consume(&iqueue, 4);
1.34 markus 1266: buf_len -= 4;
1.1 markus 1267: type = buffer_get_char(&iqueue);
1268: switch (type) {
1.10 markus 1269: case SSH2_FXP_INIT:
1.1 markus 1270: process_init();
1271: break;
1.10 markus 1272: case SSH2_FXP_OPEN:
1.1 markus 1273: process_open();
1274: break;
1.10 markus 1275: case SSH2_FXP_CLOSE:
1.1 markus 1276: process_close();
1277: break;
1.10 markus 1278: case SSH2_FXP_READ:
1.1 markus 1279: process_read();
1280: break;
1.10 markus 1281: case SSH2_FXP_WRITE:
1.1 markus 1282: process_write();
1283: break;
1.10 markus 1284: case SSH2_FXP_LSTAT:
1.1 markus 1285: process_lstat();
1286: break;
1.10 markus 1287: case SSH2_FXP_FSTAT:
1.1 markus 1288: process_fstat();
1289: break;
1.10 markus 1290: case SSH2_FXP_SETSTAT:
1.1 markus 1291: process_setstat();
1292: break;
1.10 markus 1293: case SSH2_FXP_FSETSTAT:
1.1 markus 1294: process_fsetstat();
1295: break;
1.10 markus 1296: case SSH2_FXP_OPENDIR:
1.1 markus 1297: process_opendir();
1298: break;
1.10 markus 1299: case SSH2_FXP_READDIR:
1.1 markus 1300: process_readdir();
1301: break;
1.10 markus 1302: case SSH2_FXP_REMOVE:
1.1 markus 1303: process_remove();
1304: break;
1.10 markus 1305: case SSH2_FXP_MKDIR:
1.1 markus 1306: process_mkdir();
1307: break;
1.10 markus 1308: case SSH2_FXP_RMDIR:
1.1 markus 1309: process_rmdir();
1310: break;
1.10 markus 1311: case SSH2_FXP_REALPATH:
1.1 markus 1312: process_realpath();
1313: break;
1.10 markus 1314: case SSH2_FXP_STAT:
1.1 markus 1315: process_stat();
1316: break;
1.10 markus 1317: case SSH2_FXP_RENAME:
1.1 markus 1318: process_rename();
1.23 djm 1319: break;
1320: case SSH2_FXP_READLINK:
1321: process_readlink();
1322: break;
1323: case SSH2_FXP_SYMLINK:
1324: process_symlink();
1.1 markus 1325: break;
1.10 markus 1326: case SSH2_FXP_EXTENDED:
1327: process_extended();
1328: break;
1.1 markus 1329: default:
1330: error("Unknown message %d", type);
1331: break;
1332: }
1.34 markus 1333: /* discard the remaining bytes from the current packet */
1.76 markus 1334: if (buf_len < buffer_len(&iqueue)) {
1335: error("iqueue grew unexpectedly");
1336: sftp_server_cleanup_exit(255);
1337: }
1.34 markus 1338: consumed = buf_len - buffer_len(&iqueue);
1.76 markus 1339: if (msg_len < consumed) {
1340: error("msg_len %d < consumed %d", msg_len, consumed);
1341: sftp_server_cleanup_exit(255);
1342: }
1.34 markus 1343: if (msg_len > consumed)
1344: buffer_consume(&iqueue, msg_len - consumed);
1.1 markus 1345: }
1346:
1.58 djm 1347: /* Cleanup handler that logs active handles upon normal exit */
1348: void
1.76 markus 1349: sftp_server_cleanup_exit(int i)
1.58 djm 1350: {
1351: if (pw != NULL && client_addr != NULL) {
1352: handle_log_exit();
1353: logit("session closed for local user %s from [%s]",
1354: pw->pw_name, client_addr);
1355: }
1356: _exit(i);
1357: }
1358:
1359: static void
1.76 markus 1360: sftp_server_usage(void)
1.58 djm 1361: {
1362: extern char *__progname;
1363:
1364: fprintf(stderr,
1.96 jmc 1365: "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
1366: "[-l log_level]\n\t[-u umask]\n",
1.86 djm 1367: __progname);
1.58 djm 1368: exit(1);
1369: }
1370:
1.1 markus 1371: int
1.77 djm 1372: sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1.1 markus 1373: {
1.21 millert 1374: fd_set *rset, *wset;
1.58 djm 1375: int in, out, max, ch, skipargs = 0, log_stderr = 0;
1.21 millert 1376: ssize_t len, olen, set_size;
1.58 djm 1377: SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1.95 djm 1378: char *cp, *homedir = NULL, buf[4*4096];
1.92 djm 1379: long mask;
1.58 djm 1380:
1381: extern char *optarg;
1382: extern char *__progname;
1.49 djm 1383:
1.58 djm 1384: log_init(__progname, log_level, log_facility, log_stderr);
1385:
1.95 djm 1386: pw = pwcopy(user_pw);
1387:
1388: while (!skipargs && (ch = getopt(argc, argv, "d:f:l:u:cehR")) != -1) {
1.58 djm 1389: switch (ch) {
1.90 djm 1390: case 'R':
1391: readonly = 1;
1392: break;
1.58 djm 1393: case 'c':
1394: /*
1395: * Ignore all arguments if we are invoked as a
1.70 deraadt 1396: * shell using "sftp-server -c command"
1.58 djm 1397: */
1398: skipargs = 1;
1399: break;
1400: case 'e':
1401: log_stderr = 1;
1402: break;
1403: case 'l':
1404: log_level = log_level_number(optarg);
1405: if (log_level == SYSLOG_LEVEL_NOT_SET)
1406: error("Invalid log level \"%s\"", optarg);
1407: break;
1408: case 'f':
1409: log_facility = log_facility_number(optarg);
1.74 djm 1410: if (log_facility == SYSLOG_FACILITY_NOT_SET)
1.58 djm 1411: error("Invalid log facility \"%s\"", optarg);
1.86 djm 1412: break;
1.95 djm 1413: case 'd':
1414: cp = tilde_expand_filename(optarg, user_pw->pw_uid);
1415: homedir = percent_expand(cp, "d", user_pw->pw_dir,
1416: "u", user_pw->pw_name, (char *)NULL);
1417: free(cp);
1418: break;
1.86 djm 1419: case 'u':
1.92 djm 1420: errno = 0;
1421: mask = strtol(optarg, &cp, 8);
1422: if (mask < 0 || mask > 0777 || *cp != '\0' ||
1423: cp == optarg || (mask == 0 && errno != 0))
1424: fatal("Invalid umask \"%s\"", optarg);
1425: (void)umask((mode_t)mask);
1.58 djm 1426: break;
1427: case 'h':
1428: default:
1.76 markus 1429: sftp_server_usage();
1.58 djm 1430: }
1431: }
1432:
1433: log_init(__progname, log_level, log_facility, log_stderr);
1434:
1435: if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1436: client_addr = xstrdup(cp);
1.76 markus 1437: if ((cp = strchr(client_addr, ' ')) == NULL) {
1438: error("Malformed SSH_CONNECTION variable: \"%s\"",
1.58 djm 1439: getenv("SSH_CONNECTION"));
1.76 markus 1440: sftp_server_cleanup_exit(255);
1441: }
1.58 djm 1442: *cp = '\0';
1443: } else
1444: client_addr = xstrdup("UNKNOWN");
1445:
1446: logit("session opened for local user %s from [%s]",
1447: pw->pw_name, client_addr);
1.10 markus 1448:
1.89 djm 1449: in = STDIN_FILENO;
1450: out = STDOUT_FILENO;
1.1 markus 1451:
1452: max = 0;
1453: if (in > max)
1454: max = in;
1455: if (out > max)
1456: max = out;
1457:
1458: buffer_init(&iqueue);
1459: buffer_init(&oqueue);
1460:
1.21 millert 1461: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1462: rset = (fd_set *)xmalloc(set_size);
1463: wset = (fd_set *)xmalloc(set_size);
1.95 djm 1464:
1465: if (homedir != NULL) {
1466: if (chdir(homedir) != 0) {
1467: error("chdir to \"%s\" failed: %s", homedir,
1468: strerror(errno));
1469: }
1470: }
1.21 millert 1471:
1.1 markus 1472: for (;;) {
1.21 millert 1473: memset(rset, 0, set_size);
1474: memset(wset, 0, set_size);
1.1 markus 1475:
1.73 djm 1476: /*
1477: * Ensure that we can read a full buffer and handle
1478: * the worst-case length packet it can generate,
1479: * otherwise apply backpressure by stopping reads.
1480: */
1481: if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
1482: buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1483: FD_SET(in, rset);
1484:
1.1 markus 1485: olen = buffer_len(&oqueue);
1486: if (olen > 0)
1.21 millert 1487: FD_SET(out, wset);
1.1 markus 1488:
1.21 millert 1489: if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1 markus 1490: if (errno == EINTR)
1491: continue;
1.58 djm 1492: error("select: %s", strerror(errno));
1.76 markus 1493: sftp_server_cleanup_exit(2);
1.1 markus 1494: }
1495:
1496: /* copy stdin to iqueue */
1.21 millert 1497: if (FD_ISSET(in, rset)) {
1.1 markus 1498: len = read(in, buf, sizeof buf);
1499: if (len == 0) {
1500: debug("read eof");
1.76 markus 1501: sftp_server_cleanup_exit(0);
1.1 markus 1502: } else if (len < 0) {
1.58 djm 1503: error("read: %s", strerror(errno));
1.76 markus 1504: sftp_server_cleanup_exit(1);
1.1 markus 1505: } else {
1506: buffer_append(&iqueue, buf, len);
1507: }
1508: }
1509: /* send oqueue to stdout */
1.21 millert 1510: if (FD_ISSET(out, wset)) {
1.1 markus 1511: len = write(out, buffer_ptr(&oqueue), olen);
1512: if (len < 0) {
1.58 djm 1513: error("write: %s", strerror(errno));
1.76 markus 1514: sftp_server_cleanup_exit(1);
1.1 markus 1515: } else {
1516: buffer_consume(&oqueue, len);
1517: }
1518: }
1.73 djm 1519:
1520: /*
1521: * Process requests from client if we can fit the results
1522: * into the output buffer, otherwise stop processing input
1523: * and let the output queue drain.
1524: */
1525: if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1526: process();
1.1 markus 1527: }
1528: }