Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.51
1.1 markus 1: /*
1.45 markus 2: * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
1.1 markus 3: *
1.45 markus 4: * Permission to use, copy, modify, and distribute this software for any
5: * purpose with or without fee is hereby granted, provided that the above
6: * copyright notice and this permission notice appear in all copies.
1.1 markus 7: *
1.45 markus 8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 markus 15: */
16: #include "includes.h"
1.51 ! stevesk 17: RCSID("$OpenBSD: sftp-server.c,v 1.50 2006/01/02 01:20:31 djm Exp $");
! 18:
! 19: #include <dirent.h>
1.1 markus 20:
21: #include "buffer.h"
22: #include "bufaux.h"
23: #include "getput.h"
1.14 markus 24: #include "log.h"
1.1 markus 25: #include "xmalloc.h"
1.49 djm 26: #include "misc.h"
1.1 markus 27:
1.10 markus 28: #include "sftp.h"
1.15 djm 29: #include "sftp-common.h"
1.1 markus 30:
31: /* helper */
1.10 markus 32: #define get_int64() buffer_get_int64(&iqueue);
1.1 markus 33: #define get_int() buffer_get_int(&iqueue);
34: #define get_string(lenp) buffer_get_string(&iqueue, lenp);
1.10 markus 35: #define TRACE debug
1.1 markus 36:
37: /* input and output queue */
38: Buffer iqueue;
39: Buffer oqueue;
40:
1.23 djm 41: /* Version of client */
42: int version;
43:
1.43 miod 44: /* portable attributes, etc. */
1.1 markus 45:
46: typedef struct Stat Stat;
47:
1.15 djm 48: struct Stat {
1.1 markus 49: char *name;
50: char *long_name;
51: Attrib attrib;
52: };
53:
1.28 itojun 54: static int
1.2 markus 55: errno_to_portable(int unixerrno)
1.1 markus 56: {
57: int ret = 0;
1.22 deraadt 58:
1.2 markus 59: switch (unixerrno) {
1.1 markus 60: case 0:
1.10 markus 61: ret = SSH2_FX_OK;
1.1 markus 62: break;
63: case ENOENT:
64: case ENOTDIR:
65: case EBADF:
66: case ELOOP:
1.10 markus 67: ret = SSH2_FX_NO_SUCH_FILE;
1.1 markus 68: break;
69: case EPERM:
70: case EACCES:
71: case EFAULT:
1.10 markus 72: ret = SSH2_FX_PERMISSION_DENIED;
1.1 markus 73: break;
74: case ENAMETOOLONG:
75: case EINVAL:
1.10 markus 76: ret = SSH2_FX_BAD_MESSAGE;
1.1 markus 77: break;
78: default:
1.10 markus 79: ret = SSH2_FX_FAILURE;
1.1 markus 80: break;
81: }
82: return ret;
83: }
84:
1.28 itojun 85: static int
1.1 markus 86: flags_from_portable(int pflags)
87: {
88: int flags = 0;
1.22 deraadt 89:
1.20 deraadt 90: if ((pflags & SSH2_FXF_READ) &&
91: (pflags & SSH2_FXF_WRITE)) {
1.1 markus 92: flags = O_RDWR;
1.10 markus 93: } else if (pflags & SSH2_FXF_READ) {
1.1 markus 94: flags = O_RDONLY;
1.10 markus 95: } else if (pflags & SSH2_FXF_WRITE) {
1.1 markus 96: flags = O_WRONLY;
97: }
1.10 markus 98: if (pflags & SSH2_FXF_CREAT)
1.1 markus 99: flags |= O_CREAT;
1.10 markus 100: if (pflags & SSH2_FXF_TRUNC)
1.1 markus 101: flags |= O_TRUNC;
1.10 markus 102: if (pflags & SSH2_FXF_EXCL)
1.1 markus 103: flags |= O_EXCL;
104: return flags;
105: }
106:
1.28 itojun 107: static Attrib *
1.1 markus 108: get_attrib(void)
109: {
110: return decode_attrib(&iqueue);
111: }
112:
113: /* handle handles */
114:
115: typedef struct Handle Handle;
116: struct Handle {
117: int use;
118: DIR *dirp;
119: int fd;
120: char *name;
121: };
1.22 deraadt 122:
1.1 markus 123: enum {
124: HANDLE_UNUSED,
125: HANDLE_DIR,
126: HANDLE_FILE
127: };
1.22 deraadt 128:
1.1 markus 129: Handle handles[100];
130:
1.28 itojun 131: static void
1.1 markus 132: handle_init(void)
133: {
1.48 djm 134: u_int i;
1.22 deraadt 135:
1.31 deraadt 136: for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
1.1 markus 137: handles[i].use = HANDLE_UNUSED;
138: }
139:
1.28 itojun 140: static int
1.44 jakob 141: handle_new(int use, const char *name, int fd, DIR *dirp)
1.1 markus 142: {
1.48 djm 143: u_int i;
1.22 deraadt 144:
1.31 deraadt 145: for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
1.1 markus 146: if (handles[i].use == HANDLE_UNUSED) {
147: handles[i].use = use;
148: handles[i].dirp = dirp;
149: handles[i].fd = fd;
1.40 markus 150: handles[i].name = xstrdup(name);
1.1 markus 151: return i;
152: }
153: }
154: return -1;
155: }
156:
1.28 itojun 157: static int
1.1 markus 158: handle_is_ok(int i, int type)
159: {
1.48 djm 160: return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
1.10 markus 161: handles[i].use == type;
1.1 markus 162: }
163:
1.28 itojun 164: static int
1.1 markus 165: handle_to_string(int handle, char **stringp, int *hlenp)
166: {
167: if (stringp == NULL || hlenp == NULL)
168: return -1;
1.13 markus 169: *stringp = xmalloc(sizeof(int32_t));
170: PUT_32BIT(*stringp, handle);
171: *hlenp = sizeof(int32_t);
1.1 markus 172: return 0;
173: }
174:
1.28 itojun 175: static int
1.44 jakob 176: handle_from_string(const char *handle, u_int hlen)
1.1 markus 177: {
1.13 markus 178: int val;
1.22 deraadt 179:
1.13 markus 180: if (hlen != sizeof(int32_t))
1.1 markus 181: return -1;
1.13 markus 182: val = GET_32BIT(handle);
1.1 markus 183: if (handle_is_ok(val, HANDLE_FILE) ||
184: handle_is_ok(val, HANDLE_DIR))
185: return val;
186: return -1;
187: }
188:
1.28 itojun 189: static char *
1.1 markus 190: handle_to_name(int handle)
191: {
192: if (handle_is_ok(handle, HANDLE_DIR)||
193: handle_is_ok(handle, HANDLE_FILE))
194: return handles[handle].name;
195: return NULL;
196: }
197:
1.28 itojun 198: static DIR *
1.1 markus 199: handle_to_dir(int handle)
200: {
201: if (handle_is_ok(handle, HANDLE_DIR))
202: return handles[handle].dirp;
203: return NULL;
204: }
205:
1.28 itojun 206: static int
1.1 markus 207: handle_to_fd(int handle)
208: {
1.17 stevesk 209: if (handle_is_ok(handle, HANDLE_FILE))
1.1 markus 210: return handles[handle].fd;
211: return -1;
212: }
213:
1.28 itojun 214: static int
1.1 markus 215: handle_close(int handle)
216: {
217: int ret = -1;
1.22 deraadt 218:
1.1 markus 219: if (handle_is_ok(handle, HANDLE_FILE)) {
220: ret = close(handles[handle].fd);
221: handles[handle].use = HANDLE_UNUSED;
1.40 markus 222: xfree(handles[handle].name);
1.1 markus 223: } else if (handle_is_ok(handle, HANDLE_DIR)) {
224: ret = closedir(handles[handle].dirp);
225: handles[handle].use = HANDLE_UNUSED;
1.40 markus 226: xfree(handles[handle].name);
1.1 markus 227: } else {
228: errno = ENOENT;
229: }
230: return ret;
231: }
232:
1.28 itojun 233: static int
1.1 markus 234: get_handle(void)
235: {
236: char *handle;
1.10 markus 237: int val = -1;
1.5 markus 238: u_int hlen;
1.22 deraadt 239:
1.1 markus 240: handle = get_string(&hlen);
1.10 markus 241: if (hlen < 256)
242: val = handle_from_string(handle, hlen);
1.1 markus 243: xfree(handle);
244: return val;
245: }
246:
247: /* send replies */
248:
1.28 itojun 249: static void
1.1 markus 250: send_msg(Buffer *m)
251: {
252: int mlen = buffer_len(m);
1.22 deraadt 253:
1.1 markus 254: buffer_put_int(&oqueue, mlen);
255: buffer_append(&oqueue, buffer_ptr(m), mlen);
256: buffer_consume(m, mlen);
257: }
258:
1.28 itojun 259: static void
1.46 avsm 260: send_status(u_int32_t id, u_int32_t status)
1.1 markus 261: {
262: Buffer msg;
1.23 djm 263: const char *status_messages[] = {
264: "Success", /* SSH_FX_OK */
265: "End of file", /* SSH_FX_EOF */
266: "No such file", /* SSH_FX_NO_SUCH_FILE */
267: "Permission denied", /* SSH_FX_PERMISSION_DENIED */
268: "Failure", /* SSH_FX_FAILURE */
269: "Bad message", /* SSH_FX_BAD_MESSAGE */
270: "No connection", /* SSH_FX_NO_CONNECTION */
271: "Connection lost", /* SSH_FX_CONNECTION_LOST */
272: "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
273: "Unknown error" /* Others */
274: };
1.22 deraadt 275:
1.46 avsm 276: TRACE("sent status id %u error %u", id, status);
1.1 markus 277: buffer_init(&msg);
1.10 markus 278: buffer_put_char(&msg, SSH2_FXP_STATUS);
1.1 markus 279: buffer_put_int(&msg, id);
1.46 avsm 280: buffer_put_int(&msg, status);
1.23 djm 281: if (version >= 3) {
1.25 markus 282: buffer_put_cstring(&msg,
1.46 avsm 283: status_messages[MIN(status,SSH2_FX_MAX)]);
1.23 djm 284: buffer_put_cstring(&msg, "");
285: }
1.1 markus 286: send_msg(&msg);
287: buffer_free(&msg);
288: }
1.28 itojun 289: static void
1.44 jakob 290: send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
1.1 markus 291: {
292: Buffer msg;
1.22 deraadt 293:
1.1 markus 294: buffer_init(&msg);
295: buffer_put_char(&msg, type);
296: buffer_put_int(&msg, id);
297: buffer_put_string(&msg, data, dlen);
298: send_msg(&msg);
299: buffer_free(&msg);
300: }
301:
1.28 itojun 302: static void
1.44 jakob 303: send_data(u_int32_t id, const char *data, int dlen)
1.1 markus 304: {
1.36 deraadt 305: TRACE("sent data id %u len %d", id, dlen);
1.10 markus 306: send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
1.1 markus 307: }
308:
1.28 itojun 309: static void
1.1 markus 310: send_handle(u_int32_t id, int handle)
311: {
312: char *string;
313: int hlen;
1.22 deraadt 314:
1.1 markus 315: handle_to_string(handle, &string, &hlen);
1.36 deraadt 316: TRACE("sent handle id %u handle %d", id, handle);
1.10 markus 317: send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
1.1 markus 318: xfree(string);
319: }
320:
1.28 itojun 321: static void
1.44 jakob 322: send_names(u_int32_t id, int count, const Stat *stats)
1.1 markus 323: {
324: Buffer msg;
325: int i;
1.22 deraadt 326:
1.1 markus 327: buffer_init(&msg);
1.10 markus 328: buffer_put_char(&msg, SSH2_FXP_NAME);
1.1 markus 329: buffer_put_int(&msg, id);
330: buffer_put_int(&msg, count);
1.36 deraadt 331: TRACE("sent names id %u count %d", id, count);
1.1 markus 332: for (i = 0; i < count; i++) {
333: buffer_put_cstring(&msg, stats[i].name);
334: buffer_put_cstring(&msg, stats[i].long_name);
335: encode_attrib(&msg, &stats[i].attrib);
336: }
337: send_msg(&msg);
338: buffer_free(&msg);
339: }
340:
1.28 itojun 341: static void
1.44 jakob 342: send_attrib(u_int32_t id, const Attrib *a)
1.1 markus 343: {
344: Buffer msg;
1.22 deraadt 345:
1.36 deraadt 346: TRACE("sent attrib id %u have 0x%x", id, a->flags);
1.1 markus 347: buffer_init(&msg);
1.10 markus 348: buffer_put_char(&msg, SSH2_FXP_ATTRS);
1.1 markus 349: buffer_put_int(&msg, id);
350: encode_attrib(&msg, a);
351: send_msg(&msg);
352: buffer_free(&msg);
353: }
354:
355: /* parse incoming */
356:
1.28 itojun 357: static void
1.1 markus 358: process_init(void)
359: {
360: Buffer msg;
361:
1.35 markus 362: version = get_int();
1.1 markus 363: TRACE("client version %d", version);
364: buffer_init(&msg);
1.10 markus 365: buffer_put_char(&msg, SSH2_FXP_VERSION);
366: buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
1.1 markus 367: send_msg(&msg);
368: buffer_free(&msg);
369: }
370:
1.28 itojun 371: static void
1.1 markus 372: process_open(void)
373: {
374: u_int32_t id, pflags;
375: Attrib *a;
376: char *name;
1.10 markus 377: int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1 markus 378:
379: id = get_int();
380: name = get_string(NULL);
1.10 markus 381: pflags = get_int(); /* portable flags */
1.1 markus 382: a = get_attrib();
383: flags = flags_from_portable(pflags);
1.10 markus 384: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.36 deraadt 385: TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode);
1.1 markus 386: fd = open(name, flags, mode);
387: if (fd < 0) {
388: status = errno_to_portable(errno);
389: } else {
1.40 markus 390: handle = handle_new(HANDLE_FILE, name, fd, NULL);
1.1 markus 391: if (handle < 0) {
392: close(fd);
393: } else {
394: send_handle(id, handle);
1.10 markus 395: status = SSH2_FX_OK;
1.1 markus 396: }
397: }
1.10 markus 398: if (status != SSH2_FX_OK)
1.1 markus 399: send_status(id, status);
400: xfree(name);
401: }
402:
1.28 itojun 403: static void
1.1 markus 404: process_close(void)
405: {
406: u_int32_t id;
1.10 markus 407: int handle, ret, status = SSH2_FX_FAILURE;
1.1 markus 408:
409: id = get_int();
410: handle = get_handle();
1.36 deraadt 411: TRACE("close id %u handle %d", id, handle);
1.1 markus 412: ret = handle_close(handle);
1.10 markus 413: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 414: send_status(id, status);
415: }
416:
1.28 itojun 417: static void
1.1 markus 418: process_read(void)
419: {
420: char buf[64*1024];
1.10 markus 421: u_int32_t id, len;
422: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 423: u_int64_t off;
424:
425: id = get_int();
426: handle = get_handle();
1.10 markus 427: off = get_int64();
1.1 markus 428: len = get_int();
429:
1.36 deraadt 430: TRACE("read id %u handle %d off %llu len %d", id, handle,
1.16 deraadt 431: (unsigned long long)off, len);
1.1 markus 432: if (len > sizeof buf) {
433: len = sizeof buf;
1.42 itojun 434: logit("read change len %d", len);
1.1 markus 435: }
436: fd = handle_to_fd(handle);
437: if (fd >= 0) {
438: if (lseek(fd, off, SEEK_SET) < 0) {
439: error("process_read: seek failed");
440: status = errno_to_portable(errno);
441: } else {
442: ret = read(fd, buf, len);
443: if (ret < 0) {
444: status = errno_to_portable(errno);
445: } else if (ret == 0) {
1.10 markus 446: status = SSH2_FX_EOF;
1.1 markus 447: } else {
448: send_data(id, buf, ret);
1.10 markus 449: status = SSH2_FX_OK;
1.1 markus 450: }
451: }
452: }
1.10 markus 453: if (status != SSH2_FX_OK)
1.1 markus 454: send_status(id, status);
455: }
456:
1.28 itojun 457: static void
1.1 markus 458: process_write(void)
459: {
1.10 markus 460: u_int32_t id;
1.1 markus 461: u_int64_t off;
1.5 markus 462: u_int len;
1.10 markus 463: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 464: char *data;
465:
466: id = get_int();
467: handle = get_handle();
1.10 markus 468: off = get_int64();
1.1 markus 469: data = get_string(&len);
470:
1.36 deraadt 471: TRACE("write id %u handle %d off %llu len %d", id, handle,
1.16 deraadt 472: (unsigned long long)off, len);
1.1 markus 473: fd = handle_to_fd(handle);
474: if (fd >= 0) {
475: if (lseek(fd, off, SEEK_SET) < 0) {
476: status = errno_to_portable(errno);
477: error("process_write: seek failed");
478: } else {
479: /* XXX ATOMICIO ? */
480: ret = write(fd, data, len);
1.48 djm 481: if (ret < 0) {
1.1 markus 482: error("process_write: write failed");
483: status = errno_to_portable(errno);
1.48 djm 484: } else if ((size_t)ret == len) {
1.10 markus 485: status = SSH2_FX_OK;
1.1 markus 486: } else {
1.42 itojun 487: logit("nothing at all written");
1.1 markus 488: }
489: }
490: }
491: send_status(id, status);
492: xfree(data);
493: }
494:
1.28 itojun 495: static void
1.1 markus 496: process_do_stat(int do_lstat)
497: {
1.13 markus 498: Attrib a;
1.1 markus 499: struct stat st;
500: u_int32_t id;
501: char *name;
1.10 markus 502: int ret, status = SSH2_FX_FAILURE;
1.1 markus 503:
504: id = get_int();
505: name = get_string(NULL);
1.36 deraadt 506: TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name);
1.1 markus 507: ret = do_lstat ? lstat(name, &st) : stat(name, &st);
508: if (ret < 0) {
509: status = errno_to_portable(errno);
510: } else {
1.13 markus 511: stat_to_attrib(&st, &a);
512: send_attrib(id, &a);
1.10 markus 513: status = SSH2_FX_OK;
1.1 markus 514: }
1.10 markus 515: if (status != SSH2_FX_OK)
1.1 markus 516: send_status(id, status);
517: xfree(name);
518: }
519:
1.28 itojun 520: static void
1.1 markus 521: process_stat(void)
522: {
523: process_do_stat(0);
524: }
525:
1.28 itojun 526: static void
1.1 markus 527: process_lstat(void)
528: {
529: process_do_stat(1);
530: }
531:
1.28 itojun 532: static void
1.1 markus 533: process_fstat(void)
534: {
1.13 markus 535: Attrib a;
1.1 markus 536: struct stat st;
537: u_int32_t id;
1.10 markus 538: int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1 markus 539:
540: id = get_int();
541: handle = get_handle();
1.36 deraadt 542: TRACE("fstat id %u handle %d", id, handle);
1.1 markus 543: fd = handle_to_fd(handle);
544: if (fd >= 0) {
545: ret = fstat(fd, &st);
546: if (ret < 0) {
547: status = errno_to_portable(errno);
548: } else {
1.13 markus 549: stat_to_attrib(&st, &a);
550: send_attrib(id, &a);
1.10 markus 551: status = SSH2_FX_OK;
1.1 markus 552: }
553: }
1.10 markus 554: if (status != SSH2_FX_OK)
1.1 markus 555: send_status(id, status);
556: }
557:
1.28 itojun 558: static struct timeval *
1.44 jakob 559: attrib_to_tv(const Attrib *a)
1.1 markus 560: {
561: static struct timeval tv[2];
1.22 deraadt 562:
1.1 markus 563: tv[0].tv_sec = a->atime;
564: tv[0].tv_usec = 0;
565: tv[1].tv_sec = a->mtime;
566: tv[1].tv_usec = 0;
567: return tv;
568: }
569:
1.28 itojun 570: static void
1.1 markus 571: process_setstat(void)
572: {
573: Attrib *a;
574: u_int32_t id;
575: char *name;
1.36 deraadt 576: int status = SSH2_FX_OK, ret;
1.1 markus 577:
578: id = get_int();
579: name = get_string(NULL);
580: a = get_attrib();
1.36 deraadt 581: TRACE("setstat id %u name %s", id, name);
1.33 markus 582: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
583: ret = truncate(name, a->size);
584: if (ret == -1)
585: status = errno_to_portable(errno);
586: }
1.10 markus 587: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 588: ret = chmod(name, a->perm & 0777);
589: if (ret == -1)
590: status = errno_to_portable(errno);
591: }
1.10 markus 592: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 593: ret = utimes(name, attrib_to_tv(a));
594: if (ret == -1)
595: status = errno_to_portable(errno);
596: }
1.18 stevesk 597: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
598: ret = chown(name, a->uid, a->gid);
599: if (ret == -1)
600: status = errno_to_portable(errno);
601: }
1.1 markus 602: send_status(id, status);
603: xfree(name);
604: }
605:
1.28 itojun 606: static void
1.1 markus 607: process_fsetstat(void)
608: {
609: Attrib *a;
610: u_int32_t id;
611: int handle, fd, ret;
1.10 markus 612: int status = SSH2_FX_OK;
1.1 markus 613:
614: id = get_int();
615: handle = get_handle();
616: a = get_attrib();
1.36 deraadt 617: TRACE("fsetstat id %u handle %d", id, handle);
1.1 markus 618: fd = handle_to_fd(handle);
619: if (fd < 0) {
1.10 markus 620: status = SSH2_FX_FAILURE;
1.1 markus 621: } else {
1.33 markus 622: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
623: ret = ftruncate(fd, a->size);
624: if (ret == -1)
625: status = errno_to_portable(errno);
626: }
1.10 markus 627: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1 markus 628: ret = fchmod(fd, a->perm & 0777);
629: if (ret == -1)
630: status = errno_to_portable(errno);
631: }
1.10 markus 632: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1 markus 633: ret = futimes(fd, attrib_to_tv(a));
1.18 stevesk 634: if (ret == -1)
635: status = errno_to_portable(errno);
636: }
637: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
638: ret = fchown(fd, a->uid, a->gid);
1.1 markus 639: if (ret == -1)
640: status = errno_to_portable(errno);
641: }
642: }
643: send_status(id, status);
644: }
645:
1.28 itojun 646: static void
1.1 markus 647: process_opendir(void)
648: {
649: DIR *dirp = NULL;
650: char *path;
1.10 markus 651: int handle, status = SSH2_FX_FAILURE;
1.1 markus 652: u_int32_t id;
653:
654: id = get_int();
655: path = get_string(NULL);
1.36 deraadt 656: TRACE("opendir id %u path %s", id, path);
1.17 stevesk 657: dirp = opendir(path);
1.1 markus 658: if (dirp == NULL) {
659: status = errno_to_portable(errno);
660: } else {
1.40 markus 661: handle = handle_new(HANDLE_DIR, path, 0, dirp);
1.1 markus 662: if (handle < 0) {
663: closedir(dirp);
664: } else {
665: send_handle(id, handle);
1.10 markus 666: status = SSH2_FX_OK;
1.1 markus 667: }
1.17 stevesk 668:
1.1 markus 669: }
1.10 markus 670: if (status != SSH2_FX_OK)
1.1 markus 671: send_status(id, status);
672: xfree(path);
673: }
674:
1.28 itojun 675: static void
1.1 markus 676: process_readdir(void)
677: {
678: DIR *dirp;
679: struct dirent *dp;
680: char *path;
681: int handle;
682: u_int32_t id;
683:
684: id = get_int();
685: handle = get_handle();
1.36 deraadt 686: TRACE("readdir id %u handle %d", id, handle);
1.1 markus 687: dirp = handle_to_dir(handle);
688: path = handle_to_name(handle);
689: if (dirp == NULL || path == NULL) {
1.10 markus 690: send_status(id, SSH2_FX_FAILURE);
1.1 markus 691: } else {
692: struct stat st;
693: char pathname[1024];
694: Stat *stats;
695: int nstats = 10, count = 0, i;
1.36 deraadt 696:
1.1 markus 697: stats = xmalloc(nstats * sizeof(Stat));
698: while ((dp = readdir(dirp)) != NULL) {
699: if (count >= nstats) {
700: nstats *= 2;
701: stats = xrealloc(stats, nstats * sizeof(Stat));
702: }
703: /* XXX OVERFLOW ? */
1.30 jakob 704: snprintf(pathname, sizeof pathname, "%s%s%s", path,
705: strcmp(path, "/") ? "/" : "", dp->d_name);
1.1 markus 706: if (lstat(pathname, &st) < 0)
707: continue;
1.13 markus 708: stat_to_attrib(&st, &(stats[count].attrib));
1.1 markus 709: stats[count].name = xstrdup(dp->d_name);
1.38 djm 710: stats[count].long_name = ls_file(dp->d_name, &st, 0);
1.1 markus 711: count++;
712: /* send up to 100 entries in one message */
1.11 markus 713: /* XXX check packet size instead */
1.1 markus 714: if (count == 100)
715: break;
716: }
1.10 markus 717: if (count > 0) {
718: send_names(id, count, stats);
1.31 deraadt 719: for (i = 0; i < count; i++) {
1.10 markus 720: xfree(stats[i].name);
721: xfree(stats[i].long_name);
722: }
723: } else {
724: send_status(id, SSH2_FX_EOF);
1.1 markus 725: }
726: xfree(stats);
727: }
728: }
729:
1.28 itojun 730: static void
1.1 markus 731: process_remove(void)
732: {
733: char *name;
734: u_int32_t id;
1.10 markus 735: int status = SSH2_FX_FAILURE;
1.1 markus 736: int ret;
737:
738: id = get_int();
739: name = get_string(NULL);
1.36 deraadt 740: TRACE("remove id %u name %s", id, name);
1.8 markus 741: ret = unlink(name);
1.10 markus 742: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 743: send_status(id, status);
744: xfree(name);
745: }
746:
1.28 itojun 747: static void
1.1 markus 748: process_mkdir(void)
749: {
750: Attrib *a;
751: u_int32_t id;
752: char *name;
1.10 markus 753: int ret, mode, status = SSH2_FX_FAILURE;
1.1 markus 754:
755: id = get_int();
756: name = get_string(NULL);
757: a = get_attrib();
1.10 markus 758: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
759: a->perm & 0777 : 0777;
1.36 deraadt 760: TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
1.1 markus 761: ret = mkdir(name, mode);
1.10 markus 762: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 763: send_status(id, status);
764: xfree(name);
765: }
766:
1.28 itojun 767: static void
1.1 markus 768: process_rmdir(void)
769: {
770: u_int32_t id;
771: char *name;
772: int ret, status;
773:
774: id = get_int();
775: name = get_string(NULL);
1.36 deraadt 776: TRACE("rmdir id %u name %s", id, name);
1.1 markus 777: ret = rmdir(name);
1.10 markus 778: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 779: send_status(id, status);
780: xfree(name);
781: }
782:
1.28 itojun 783: static void
1.1 markus 784: process_realpath(void)
785: {
786: char resolvedname[MAXPATHLEN];
787: u_int32_t id;
788: char *path;
789:
790: id = get_int();
791: path = get_string(NULL);
1.7 markus 792: if (path[0] == '\0') {
793: xfree(path);
794: path = xstrdup(".");
795: }
1.36 deraadt 796: TRACE("realpath id %u path %s", id, path);
1.1 markus 797: if (realpath(path, resolvedname) == NULL) {
798: send_status(id, errno_to_portable(errno));
799: } else {
800: Stat s;
801: attrib_clear(&s.attrib);
802: s.name = s.long_name = resolvedname;
803: send_names(id, 1, &s);
804: }
805: xfree(path);
806: }
807:
1.28 itojun 808: static void
1.1 markus 809: process_rename(void)
810: {
811: u_int32_t id;
812: char *oldpath, *newpath;
1.39 markus 813: int status;
1.41 deraadt 814: struct stat sb;
1.1 markus 815:
816: id = get_int();
817: oldpath = get_string(NULL);
818: newpath = get_string(NULL);
1.36 deraadt 819: TRACE("rename id %u old %s new %s", id, oldpath, newpath);
1.41 deraadt 820: status = SSH2_FX_FAILURE;
821: if (lstat(oldpath, &sb) == -1)
1.39 markus 822: status = errno_to_portable(errno);
1.41 deraadt 823: else if (S_ISREG(sb.st_mode)) {
824: /* Race-free rename of regular files */
1.47 dtucker 825: if (link(oldpath, newpath) == -1) {
826: if (errno == EOPNOTSUPP) {
827: struct stat st;
828:
829: /*
830: * fs doesn't support links, so fall back to
831: * stat+rename. This is racy.
832: */
833: if (stat(newpath, &st) == -1) {
834: if (rename(oldpath, newpath) == -1)
835: status =
836: errno_to_portable(errno);
837: else
838: status = SSH2_FX_OK;
839: }
840: } else {
841: status = errno_to_portable(errno);
842: }
843: } else if (unlink(oldpath) == -1) {
1.41 deraadt 844: status = errno_to_portable(errno);
845: /* clean spare link */
846: unlink(newpath);
847: } else
848: status = SSH2_FX_OK;
849: } else if (stat(newpath, &sb) == -1) {
850: if (rename(oldpath, newpath) == -1)
851: status = errno_to_portable(errno);
852: else
853: status = SSH2_FX_OK;
854: }
1.1 markus 855: send_status(id, status);
856: xfree(oldpath);
857: xfree(newpath);
858: }
859:
1.28 itojun 860: static void
1.23 djm 861: process_readlink(void)
862: {
863: u_int32_t id;
1.26 markus 864: int len;
1.46 avsm 865: char buf[MAXPATHLEN];
1.23 djm 866: char *path;
867:
868: id = get_int();
869: path = get_string(NULL);
1.36 deraadt 870: TRACE("readlink id %u path %s", id, path);
1.46 avsm 871: if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1.23 djm 872: send_status(id, errno_to_portable(errno));
873: else {
874: Stat s;
1.31 deraadt 875:
1.46 avsm 876: buf[len] = '\0';
1.23 djm 877: attrib_clear(&s.attrib);
1.46 avsm 878: s.name = s.long_name = buf;
1.23 djm 879: send_names(id, 1, &s);
880: }
881: xfree(path);
882: }
883:
1.28 itojun 884: static void
1.23 djm 885: process_symlink(void)
886: {
887: u_int32_t id;
888: char *oldpath, *newpath;
1.39 markus 889: int ret, status;
1.23 djm 890:
891: id = get_int();
892: oldpath = get_string(NULL);
893: newpath = get_string(NULL);
1.36 deraadt 894: TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
1.39 markus 895: /* this will fail if 'newpath' exists */
896: ret = symlink(oldpath, newpath);
897: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.23 djm 898: send_status(id, status);
899: xfree(oldpath);
900: xfree(newpath);
901: }
902:
1.28 itojun 903: static void
1.10 markus 904: process_extended(void)
905: {
906: u_int32_t id;
907: char *request;
908:
909: id = get_int();
910: request = get_string(NULL);
911: send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
912: xfree(request);
913: }
1.1 markus 914:
915: /* stolen from ssh-agent */
916:
1.28 itojun 917: static void
1.1 markus 918: process(void)
919: {
1.9 markus 920: u_int msg_len;
1.34 markus 921: u_int buf_len;
922: u_int consumed;
1.9 markus 923: u_int type;
924: u_char *cp;
1.1 markus 925:
1.34 markus 926: buf_len = buffer_len(&iqueue);
927: if (buf_len < 5)
1.1 markus 928: return; /* Incomplete message. */
1.32 stevesk 929: cp = buffer_ptr(&iqueue);
1.1 markus 930: msg_len = GET_32BIT(cp);
1.50 djm 931: if (msg_len > SFTP_MAX_MSG_LENGTH) {
1.1 markus 932: error("bad message ");
933: exit(11);
934: }
1.34 markus 935: if (buf_len < msg_len + 4)
1.1 markus 936: return;
937: buffer_consume(&iqueue, 4);
1.34 markus 938: buf_len -= 4;
1.1 markus 939: type = buffer_get_char(&iqueue);
940: switch (type) {
1.10 markus 941: case SSH2_FXP_INIT:
1.1 markus 942: process_init();
943: break;
1.10 markus 944: case SSH2_FXP_OPEN:
1.1 markus 945: process_open();
946: break;
1.10 markus 947: case SSH2_FXP_CLOSE:
1.1 markus 948: process_close();
949: break;
1.10 markus 950: case SSH2_FXP_READ:
1.1 markus 951: process_read();
952: break;
1.10 markus 953: case SSH2_FXP_WRITE:
1.1 markus 954: process_write();
955: break;
1.10 markus 956: case SSH2_FXP_LSTAT:
1.1 markus 957: process_lstat();
958: break;
1.10 markus 959: case SSH2_FXP_FSTAT:
1.1 markus 960: process_fstat();
961: break;
1.10 markus 962: case SSH2_FXP_SETSTAT:
1.1 markus 963: process_setstat();
964: break;
1.10 markus 965: case SSH2_FXP_FSETSTAT:
1.1 markus 966: process_fsetstat();
967: break;
1.10 markus 968: case SSH2_FXP_OPENDIR:
1.1 markus 969: process_opendir();
970: break;
1.10 markus 971: case SSH2_FXP_READDIR:
1.1 markus 972: process_readdir();
973: break;
1.10 markus 974: case SSH2_FXP_REMOVE:
1.1 markus 975: process_remove();
976: break;
1.10 markus 977: case SSH2_FXP_MKDIR:
1.1 markus 978: process_mkdir();
979: break;
1.10 markus 980: case SSH2_FXP_RMDIR:
1.1 markus 981: process_rmdir();
982: break;
1.10 markus 983: case SSH2_FXP_REALPATH:
1.1 markus 984: process_realpath();
985: break;
1.10 markus 986: case SSH2_FXP_STAT:
1.1 markus 987: process_stat();
988: break;
1.10 markus 989: case SSH2_FXP_RENAME:
1.1 markus 990: process_rename();
1.23 djm 991: break;
992: case SSH2_FXP_READLINK:
993: process_readlink();
994: break;
995: case SSH2_FXP_SYMLINK:
996: process_symlink();
1.1 markus 997: break;
1.10 markus 998: case SSH2_FXP_EXTENDED:
999: process_extended();
1000: break;
1.1 markus 1001: default:
1002: error("Unknown message %d", type);
1003: break;
1004: }
1.34 markus 1005: /* discard the remaining bytes from the current packet */
1006: if (buf_len < buffer_len(&iqueue))
1007: fatal("iqueue grows");
1008: consumed = buf_len - buffer_len(&iqueue);
1009: if (msg_len < consumed)
1010: fatal("msg_len %d < consumed %d", msg_len, consumed);
1011: if (msg_len > consumed)
1012: buffer_consume(&iqueue, msg_len - consumed);
1.1 markus 1013: }
1014:
1015: int
1016: main(int ac, char **av)
1017: {
1.21 millert 1018: fd_set *rset, *wset;
1.1 markus 1019: int in, out, max;
1.21 millert 1020: ssize_t len, olen, set_size;
1.49 djm 1021:
1022: /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1023: sanitise_stdfd();
1.24 deraadt 1024:
1025: /* XXX should use getopt */
1.1 markus 1026:
1027: handle_init();
1.10 markus 1028:
1.11 markus 1029: #ifdef DEBUG_SFTP_SERVER
1.17 stevesk 1030: log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1.11 markus 1031: #endif
1.1 markus 1032:
1033: in = dup(STDIN_FILENO);
1034: out = dup(STDOUT_FILENO);
1035:
1036: max = 0;
1037: if (in > max)
1038: max = in;
1039: if (out > max)
1040: max = out;
1041:
1042: buffer_init(&iqueue);
1043: buffer_init(&oqueue);
1044:
1.21 millert 1045: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1046: rset = (fd_set *)xmalloc(set_size);
1047: wset = (fd_set *)xmalloc(set_size);
1048:
1.1 markus 1049: for (;;) {
1.21 millert 1050: memset(rset, 0, set_size);
1051: memset(wset, 0, set_size);
1.1 markus 1052:
1.21 millert 1053: FD_SET(in, rset);
1.1 markus 1054: olen = buffer_len(&oqueue);
1055: if (olen > 0)
1.21 millert 1056: FD_SET(out, wset);
1.1 markus 1057:
1.21 millert 1058: if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1 markus 1059: if (errno == EINTR)
1060: continue;
1061: exit(2);
1062: }
1063:
1064: /* copy stdin to iqueue */
1.21 millert 1065: if (FD_ISSET(in, rset)) {
1.1 markus 1066: char buf[4*4096];
1067: len = read(in, buf, sizeof buf);
1068: if (len == 0) {
1069: debug("read eof");
1070: exit(0);
1071: } else if (len < 0) {
1072: error("read error");
1073: exit(1);
1074: } else {
1075: buffer_append(&iqueue, buf, len);
1076: }
1077: }
1078: /* send oqueue to stdout */
1.21 millert 1079: if (FD_ISSET(out, wset)) {
1.1 markus 1080: len = write(out, buffer_ptr(&oqueue), olen);
1081: if (len < 0) {
1082: error("write error");
1083: exit(1);
1084: } else {
1085: buffer_consume(&oqueue, len);
1086: }
1087: }
1088: /* process requests from client */
1089: process();
1090: }
1091: }