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