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