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