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