Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.102
1.102 ! djm 1: /* $OpenBSD: sftp-server.c,v 1.101 2013/10/14 23:28:23 djm Exp $ */
1.1 markus 2: /*
1.45 markus 3: * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
1.1 markus 4: *
1.45 markus 5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 markus 8: *
1.45 markus 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 markus 16: */
1.52 stevesk 17:
18: #include <sys/types.h>
19: #include <sys/stat.h>
1.66 stevesk 20: #include <sys/time.h>
1.67 stevesk 21: #include <sys/param.h>
1.79 djm 22: #include <sys/mount.h>
23: #include <sys/statvfs.h>
1.51 stevesk 24:
25: #include <dirent.h>
1.62 stevesk 26: #include <errno.h>
1.59 stevesk 27: #include <fcntl.h>
1.68 stevesk 28: #include <stdlib.h>
1.69 stevesk 29: #include <stdio.h>
1.65 stevesk 30: #include <string.h>
1.70 deraadt 31: #include <pwd.h>
1.64 stevesk 32: #include <time.h>
1.63 stevesk 33: #include <unistd.h>
1.70 deraadt 34: #include <stdarg.h>
1.1 markus 35:
1.70 deraadt 36: #include "xmalloc.h"
1.1 markus 37: #include "buffer.h"
1.14 markus 38: #include "log.h"
1.49 djm 39: #include "misc.h"
1.98 djm 40: #include "match.h"
1.58 djm 41: #include "uidswap.h"
1.1 markus 42:
1.10 markus 43: #include "sftp.h"
1.15 djm 44: #include "sftp-common.h"
1.1 markus 45:
46: /* helper */
1.10 markus 47: #define get_int64() buffer_get_int64(&iqueue);
1.1 markus 48: #define get_int() buffer_get_int(&iqueue);
49: #define get_string(lenp) buffer_get_string(&iqueue, lenp);
1.58 djm 50:
51: /* Our verbosity */
1.98 djm 52: static LogLevel log_level = SYSLOG_LEVEL_ERROR;
1.58 djm 53:
54: /* Our client */
1.98 djm 55: static struct passwd *pw = NULL;
56: static char *client_addr = NULL;
1.1 markus 57:
58: /* input and output queue */
1.98 djm 59: static Buffer iqueue;
60: static Buffer oqueue;
1.1 markus 61:
1.23 djm 62: /* Version of client */
1.98 djm 63: static u_int version;
64:
65: /* SSH2_FXP_INIT received */
66: static int init_done;
1.23 djm 67:
1.90 djm 68: /* Disable writes */
1.98 djm 69: static int readonly;
70:
71: /* Requests that are allowed/denied */
72: static char *request_whitelist, *request_blacklist;
1.90 djm 73:
1.43 miod 74: /* portable attributes, etc. */
1.1 markus 75: typedef struct Stat Stat;
76:
1.15 djm 77: struct Stat {
1.1 markus 78: char *name;
79: char *long_name;
80: Attrib attrib;
81: };
82:
1.98 djm 83: /* Packet handlers */
84: static void process_open(u_int32_t id);
85: static void process_close(u_int32_t id);
86: static void process_read(u_int32_t id);
87: static void process_write(u_int32_t id);
88: static void process_stat(u_int32_t id);
89: static void process_lstat(u_int32_t id);
90: static void process_fstat(u_int32_t id);
91: static void process_setstat(u_int32_t id);
92: static void process_fsetstat(u_int32_t id);
93: static void process_opendir(u_int32_t id);
94: static void process_readdir(u_int32_t id);
95: static void process_remove(u_int32_t id);
96: static void process_mkdir(u_int32_t id);
97: static void process_rmdir(u_int32_t id);
98: static void process_realpath(u_int32_t id);
99: static void process_rename(u_int32_t id);
100: static void process_readlink(u_int32_t id);
101: static void process_symlink(u_int32_t id);
102: static void process_extended_posix_rename(u_int32_t id);
103: static void process_extended_statvfs(u_int32_t id);
104: static void process_extended_fstatvfs(u_int32_t id);
105: static void process_extended_hardlink(u_int32_t id);
1.102 ! djm 106: static void process_extended_fsync(u_int32_t id);
1.98 djm 107: static void process_extended(u_int32_t id);
108:
109: struct sftp_handler {
110: const char *name; /* user-visible name for fine-grained perms */
111: const char *ext_name; /* extended request name */
112: u_int type; /* packet type, for non extended packets */
113: void (*handler)(u_int32_t);
114: int does_write; /* if nonzero, banned for readonly mode */
115: };
116:
117: struct sftp_handler handlers[] = {
118: /* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */
119: { "open", NULL, SSH2_FXP_OPEN, process_open, 0 },
120: { "close", NULL, SSH2_FXP_CLOSE, process_close, 0 },
121: { "read", NULL, SSH2_FXP_READ, process_read, 0 },
122: { "write", NULL, SSH2_FXP_WRITE, process_write, 1 },
123: { "lstat", NULL, SSH2_FXP_LSTAT, process_lstat, 0 },
124: { "fstat", NULL, SSH2_FXP_FSTAT, process_fstat, 0 },
125: { "setstat", NULL, SSH2_FXP_SETSTAT, process_setstat, 1 },
126: { "fsetstat", NULL, SSH2_FXP_FSETSTAT, process_fsetstat, 1 },
127: { "opendir", NULL, SSH2_FXP_OPENDIR, process_opendir, 0 },
128: { "readdir", NULL, SSH2_FXP_READDIR, process_readdir, 0 },
129: { "remove", NULL, SSH2_FXP_REMOVE, process_remove, 1 },
130: { "mkdir", NULL, SSH2_FXP_MKDIR, process_mkdir, 1 },
131: { "rmdir", NULL, SSH2_FXP_RMDIR, process_rmdir, 1 },
132: { "realpath", NULL, SSH2_FXP_REALPATH, process_realpath, 0 },
133: { "stat", NULL, SSH2_FXP_STAT, process_stat, 0 },
134: { "rename", NULL, SSH2_FXP_RENAME, process_rename, 1 },
135: { "readlink", NULL, SSH2_FXP_READLINK, process_readlink, 0 },
136: { "symlink", NULL, SSH2_FXP_SYMLINK, process_symlink, 1 },
137: { NULL, NULL, 0, NULL, 0 }
138: };
139:
140: /* SSH2_FXP_EXTENDED submessages */
141: struct sftp_handler extended_handlers[] = {
142: { "posix-rename", "posix-rename@openssh.com", 0,
143: process_extended_posix_rename, 1 },
144: { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
145: { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
146: { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
1.102 ! djm 147: { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
1.98 djm 148: { NULL, NULL, 0, NULL, 0 }
149: };
150:
151: static int
152: request_permitted(struct sftp_handler *h)
153: {
154: char *result;
155:
156: if (readonly && h->does_write) {
157: verbose("Refusing %s request in read-only mode", h->name);
158: return 0;
159: }
160: if (request_blacklist != NULL &&
161: ((result = match_list(h->name, request_blacklist, NULL))) != NULL) {
162: free(result);
163: verbose("Refusing blacklisted %s request", h->name);
164: return 0;
165: }
166: if (request_whitelist != NULL &&
167: ((result = match_list(h->name, request_whitelist, NULL))) != NULL) {
168: free(result);
169: debug2("Permitting whitelisted %s request", h->name);
170: return 1;
171: }
172: if (request_whitelist != NULL) {
173: verbose("Refusing non-whitelisted %s request", h->name);
174: return 0;
175: }
176: return 1;
177: }
178:
1.28 itojun 179: static int
1.2 markus 180: errno_to_portable(int unixerrno)
1.1 markus 181: {
182: int ret = 0;
1.22 deraadt 183:
1.2 markus 184: switch (unixerrno) {
1.1 markus 185: case 0:
1.10 markus 186: ret = SSH2_FX_OK;
1.1 markus 187: break;
188: case ENOENT:
189: case ENOTDIR:
190: case EBADF:
191: case ELOOP:
1.10 markus 192: ret = SSH2_FX_NO_SUCH_FILE;
1.1 markus 193: break;
194: case EPERM:
195: case EACCES:
196: case EFAULT:
1.10 markus 197: ret = SSH2_FX_PERMISSION_DENIED;
1.1 markus 198: break;
199: case ENAMETOOLONG:
200: case EINVAL:
1.10 markus 201: ret = SSH2_FX_BAD_MESSAGE;
1.82 dtucker 202: break;
203: case ENOSYS:
204: ret = SSH2_FX_OP_UNSUPPORTED;
1.1 markus 205: break;
206: default:
1.10 markus 207: ret = SSH2_FX_FAILURE;
1.1 markus 208: break;
209: }
210: return ret;
211: }
212:
1.28 itojun 213: static int
1.1 markus 214: flags_from_portable(int pflags)
215: {
216: int flags = 0;
1.22 deraadt 217:
1.20 deraadt 218: if ((pflags & SSH2_FXF_READ) &&
219: (pflags & SSH2_FXF_WRITE)) {
1.1 markus 220: flags = O_RDWR;
1.10 markus 221: } else if (pflags & SSH2_FXF_READ) {
1.1 markus 222: flags = O_RDONLY;
1.10 markus 223: } else if (pflags & SSH2_FXF_WRITE) {
1.1 markus 224: flags = O_WRONLY;
225: }
1.101 djm 226: if (pflags & SSH2_FXF_APPEND)
227: flags |= O_APPEND;
1.10 markus 228: if (pflags & SSH2_FXF_CREAT)
1.1 markus 229: flags |= O_CREAT;
1.10 markus 230: if (pflags & SSH2_FXF_TRUNC)
1.1 markus 231: flags |= O_TRUNC;
1.10 markus 232: if (pflags & SSH2_FXF_EXCL)
1.1 markus 233: flags |= O_EXCL;
234: return flags;
235: }
236:
1.58 djm 237: static const char *
238: string_from_portable(int pflags)
239: {
240: static char ret[128];
241:
242: *ret = '\0';
243:
244: #define PAPPEND(str) { \
245: if (*ret != '\0') \
246: strlcat(ret, ",", sizeof(ret)); \
1.70 deraadt 247: strlcat(ret, str, sizeof(ret)); \
1.58 djm 248: }
249:
250: if (pflags & SSH2_FXF_READ)
251: PAPPEND("READ")
252: if (pflags & SSH2_FXF_WRITE)
253: PAPPEND("WRITE")
1.101 djm 254: if (pflags & SSH2_FXF_APPEND)
255: PAPPEND("APPEND")
1.58 djm 256: if (pflags & SSH2_FXF_CREAT)
257: PAPPEND("CREATE")
258: if (pflags & SSH2_FXF_TRUNC)
259: PAPPEND("TRUNCATE")
260: if (pflags & SSH2_FXF_EXCL)
261: PAPPEND("EXCL")
262:
263: return ret;
264: }
265:
1.28 itojun 266: static Attrib *
1.1 markus 267: get_attrib(void)
268: {
269: return decode_attrib(&iqueue);
270: }
271:
272: /* handle handles */
273:
274: typedef struct Handle Handle;
275: struct Handle {
276: int use;
277: DIR *dirp;
278: int fd;
1.101 djm 279: int flags;
1.1 markus 280: char *name;
1.58 djm 281: u_int64_t bytes_read, bytes_write;
1.75 djm 282: int next_unused;
1.1 markus 283: };
1.22 deraadt 284:
1.1 markus 285: enum {
286: HANDLE_UNUSED,
287: HANDLE_DIR,
288: HANDLE_FILE
289: };
1.22 deraadt 290:
1.75 djm 291: Handle *handles = NULL;
292: u_int num_handles = 0;
293: int first_unused_handle = -1;
294:
295: static void handle_unused(int i)
296: {
297: handles[i].use = HANDLE_UNUSED;
298: handles[i].next_unused = first_unused_handle;
299: first_unused_handle = i;
1.1 markus 300: }
301:
1.28 itojun 302: static int
1.101 djm 303: handle_new(int use, const char *name, int fd, int flags, DIR *dirp)
1.1 markus 304: {
1.75 djm 305: int i;
306:
307: if (first_unused_handle == -1) {
308: if (num_handles + 1 <= num_handles)
309: return -1;
310: num_handles++;
311: handles = xrealloc(handles, num_handles, sizeof(Handle));
312: handle_unused(num_handles - 1);
313: }
314:
315: i = first_unused_handle;
316: first_unused_handle = handles[i].next_unused;
317:
318: handles[i].use = use;
319: handles[i].dirp = dirp;
320: handles[i].fd = fd;
1.101 djm 321: handles[i].flags = flags;
1.75 djm 322: handles[i].name = xstrdup(name);
323: handles[i].bytes_read = handles[i].bytes_write = 0;
1.22 deraadt 324:
1.75 djm 325: return i;
1.1 markus 326: }
327:
1.28 itojun 328: static int
1.1 markus 329: handle_is_ok(int i, int type)
330: {
1.75 djm 331: return i >= 0 && (u_int)i < num_handles && handles[i].use == type;
1.1 markus 332: }
333:
1.28 itojun 334: static int
1.1 markus 335: handle_to_string(int handle, char **stringp, int *hlenp)
336: {
337: if (stringp == NULL || hlenp == NULL)
338: return -1;
1.13 markus 339: *stringp = xmalloc(sizeof(int32_t));
1.57 djm 340: put_u32(*stringp, handle);
1.13 markus 341: *hlenp = sizeof(int32_t);
1.1 markus 342: return 0;
343: }
344:
1.28 itojun 345: static int
1.44 jakob 346: handle_from_string(const char *handle, u_int hlen)
1.1 markus 347: {
1.13 markus 348: int val;
1.22 deraadt 349:
1.13 markus 350: if (hlen != sizeof(int32_t))
1.1 markus 351: return -1;
1.57 djm 352: val = get_u32(handle);
1.1 markus 353: if (handle_is_ok(val, HANDLE_FILE) ||
354: handle_is_ok(val, HANDLE_DIR))
355: return val;
356: return -1;
357: }
358:
1.28 itojun 359: static char *
1.1 markus 360: handle_to_name(int handle)
361: {
362: if (handle_is_ok(handle, HANDLE_DIR)||
363: handle_is_ok(handle, HANDLE_FILE))
364: return handles[handle].name;
365: return NULL;
366: }
367:
1.28 itojun 368: static DIR *
1.1 markus 369: handle_to_dir(int handle)
370: {
371: if (handle_is_ok(handle, HANDLE_DIR))
372: return handles[handle].dirp;
373: return NULL;
374: }
375:
1.28 itojun 376: static int
1.1 markus 377: handle_to_fd(int handle)
378: {
1.17 stevesk 379: if (handle_is_ok(handle, HANDLE_FILE))
1.1 markus 380: return handles[handle].fd;
381: return -1;
382: }
383:
1.101 djm 384: static int
385: handle_to_flags(int handle)
386: {
387: if (handle_is_ok(handle, HANDLE_FILE))
388: return handles[handle].flags;
389: return 0;
390: }
391:
1.58 djm 392: static void
393: handle_update_read(int handle, ssize_t bytes)
394: {
395: if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
396: handles[handle].bytes_read += bytes;
397: }
398:
399: static void
400: handle_update_write(int handle, ssize_t bytes)
401: {
402: if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
403: handles[handle].bytes_write += bytes;
404: }
405:
406: static u_int64_t
407: handle_bytes_read(int handle)
408: {
409: if (handle_is_ok(handle, HANDLE_FILE))
410: return (handles[handle].bytes_read);
411: return 0;
412: }
413:
414: static u_int64_t
415: handle_bytes_write(int handle)
416: {
417: if (handle_is_ok(handle, HANDLE_FILE))
418: return (handles[handle].bytes_write);
419: return 0;
420: }
421:
1.28 itojun 422: static int
1.1 markus 423: handle_close(int handle)
424: {
425: int ret = -1;
1.22 deraadt 426:
1.1 markus 427: if (handle_is_ok(handle, HANDLE_FILE)) {
428: ret = close(handles[handle].fd);
1.97 djm 429: free(handles[handle].name);
1.75 djm 430: handle_unused(handle);
1.1 markus 431: } else if (handle_is_ok(handle, HANDLE_DIR)) {
432: ret = closedir(handles[handle].dirp);
1.97 djm 433: free(handles[handle].name);
1.75 djm 434: handle_unused(handle);
1.1 markus 435: } else {
436: errno = ENOENT;
437: }
438: return ret;
439: }
440:
1.58 djm 441: static void
442: handle_log_close(int handle, char *emsg)
443: {
444: if (handle_is_ok(handle, HANDLE_FILE)) {
445: logit("%s%sclose \"%s\" bytes read %llu written %llu",
446: emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
447: handle_to_name(handle),
1.72 stevesk 448: (unsigned long long)handle_bytes_read(handle),
449: (unsigned long long)handle_bytes_write(handle));
1.58 djm 450: } else {
451: logit("%s%sclosedir \"%s\"",
452: emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
453: handle_to_name(handle));
454: }
455: }
456:
457: static void
458: handle_log_exit(void)
459: {
460: u_int i;
461:
1.75 djm 462: for (i = 0; i < num_handles; i++)
1.58 djm 463: if (handles[i].use != HANDLE_UNUSED)
464: handle_log_close(i, "forced");
465: }
466:
1.28 itojun 467: static int
1.1 markus 468: get_handle(void)
469: {
470: char *handle;
1.10 markus 471: int val = -1;
1.5 markus 472: u_int hlen;
1.22 deraadt 473:
1.1 markus 474: handle = get_string(&hlen);
1.10 markus 475: if (hlen < 256)
476: val = handle_from_string(handle, hlen);
1.97 djm 477: free(handle);
1.1 markus 478: return val;
479: }
480:
481: /* send replies */
482:
1.28 itojun 483: static void
1.1 markus 484: send_msg(Buffer *m)
485: {
486: int mlen = buffer_len(m);
1.22 deraadt 487:
1.1 markus 488: buffer_put_int(&oqueue, mlen);
489: buffer_append(&oqueue, buffer_ptr(m), mlen);
490: buffer_consume(m, mlen);
491: }
492:
1.58 djm 493: static const char *
494: status_to_message(u_int32_t status)
1.1 markus 495: {
1.23 djm 496: const char *status_messages[] = {
497: "Success", /* SSH_FX_OK */
498: "End of file", /* SSH_FX_EOF */
499: "No such file", /* SSH_FX_NO_SUCH_FILE */
500: "Permission denied", /* SSH_FX_PERMISSION_DENIED */
501: "Failure", /* SSH_FX_FAILURE */
502: "Bad message", /* SSH_FX_BAD_MESSAGE */
503: "No connection", /* SSH_FX_NO_CONNECTION */
504: "Connection lost", /* SSH_FX_CONNECTION_LOST */
505: "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
506: "Unknown error" /* Others */
507: };
1.58 djm 508: return (status_messages[MIN(status,SSH2_FX_MAX)]);
509: }
1.22 deraadt 510:
1.58 djm 511: static void
512: send_status(u_int32_t id, u_int32_t status)
513: {
514: Buffer msg;
515:
516: debug3("request %u: sent status %u", id, status);
517: if (log_level > SYSLOG_LEVEL_VERBOSE ||
518: (status != SSH2_FX_OK && status != SSH2_FX_EOF))
519: logit("sent status %s", status_to_message(status));
1.1 markus 520: buffer_init(&msg);
1.10 markus 521: buffer_put_char(&msg, SSH2_FXP_STATUS);
1.1 markus 522: buffer_put_int(&msg, id);
1.46 avsm 523: buffer_put_int(&msg, status);
1.23 djm 524: if (version >= 3) {
1.58 djm 525: buffer_put_cstring(&msg, status_to_message(status));
1.23 djm 526: buffer_put_cstring(&msg, "");
527: }
1.1 markus 528: send_msg(&msg);
529: buffer_free(&msg);
530: }
1.28 itojun 531: static void
1.44 jakob 532: send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
1.1 markus 533: {
534: Buffer msg;
1.22 deraadt 535:
1.1 markus 536: buffer_init(&msg);
537: buffer_put_char(&msg, type);
538: buffer_put_int(&msg, id);
539: buffer_put_string(&msg, data, dlen);
540: send_msg(&msg);
541: buffer_free(&msg);
542: }
543:
1.28 itojun 544: static void
1.44 jakob 545: send_data(u_int32_t id, const char *data, int dlen)
1.1 markus 546: {
1.58 djm 547: debug("request %u: sent data len %d", id, dlen);
1.10 markus 548: send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
1.1 markus 549: }
550:
1.28 itojun 551: static void
1.1 markus 552: send_handle(u_int32_t id, int handle)
553: {
554: char *string;
555: int hlen;
1.22 deraadt 556:
1.1 markus 557: handle_to_string(handle, &string, &hlen);
1.58 djm 558: debug("request %u: sent handle handle %d", id, handle);
1.10 markus 559: send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
1.97 djm 560: free(string);
1.1 markus 561: }
562:
1.28 itojun 563: static void
1.44 jakob 564: send_names(u_int32_t id, int count, const Stat *stats)
1.1 markus 565: {
566: Buffer msg;
567: int i;
1.22 deraadt 568:
1.1 markus 569: buffer_init(&msg);
1.10 markus 570: buffer_put_char(&msg, SSH2_FXP_NAME);
1.1 markus 571: buffer_put_int(&msg, id);
572: buffer_put_int(&msg, count);
1.58 djm 573: debug("request %u: sent names count %d", id, count);
1.1 markus 574: for (i = 0; i < count; i++) {
575: buffer_put_cstring(&msg, stats[i].name);
576: buffer_put_cstring(&msg, stats[i].long_name);
577: encode_attrib(&msg, &stats[i].attrib);
578: }
579: send_msg(&msg);
580: buffer_free(&msg);
581: }
582:
1.28 itojun 583: static void
1.44 jakob 584: send_attrib(u_int32_t id, const Attrib *a)
1.1 markus 585: {
586: Buffer msg;
1.22 deraadt 587:
1.58 djm 588: debug("request %u: sent attrib have 0x%x", id, a->flags);
1.1 markus 589: buffer_init(&msg);
1.10 markus 590: buffer_put_char(&msg, SSH2_FXP_ATTRS);
1.1 markus 591: buffer_put_int(&msg, id);
592: encode_attrib(&msg, a);
593: send_msg(&msg);
594: buffer_free(&msg);
595: }
596:
1.79 djm 597: static void
598: send_statvfs(u_int32_t id, struct statvfs *st)
599: {
600: Buffer msg;
601: u_int64_t flag;
602:
603: flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
604: flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
605:
606: buffer_init(&msg);
607: buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY);
608: buffer_put_int(&msg, id);
1.83 dtucker 609: buffer_put_int64(&msg, st->f_bsize);
610: buffer_put_int64(&msg, st->f_frsize);
1.79 djm 611: buffer_put_int64(&msg, st->f_blocks);
612: buffer_put_int64(&msg, st->f_bfree);
613: buffer_put_int64(&msg, st->f_bavail);
614: buffer_put_int64(&msg, st->f_files);
615: buffer_put_int64(&msg, st->f_ffree);
616: buffer_put_int64(&msg, st->f_favail);
1.81 djm 617: buffer_put_int64(&msg, st->f_fsid);
1.83 dtucker 618: buffer_put_int64(&msg, flag);
619: buffer_put_int64(&msg, st->f_namemax);
1.79 djm 620: send_msg(&msg);
621: buffer_free(&msg);
622: }
623:
1.1 markus 624: /* parse incoming */
625:
1.28 itojun 626: static void
1.1 markus 627: process_init(void)
628: {
629: Buffer msg;
630:
1.35 markus 631: version = get_int();
1.94 djm 632: verbose("received client version %u", version);
1.1 markus 633: buffer_init(&msg);
1.10 markus 634: buffer_put_char(&msg, SSH2_FXP_VERSION);
635: buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
1.78 djm 636: /* POSIX rename extension */
637: buffer_put_cstring(&msg, "posix-rename@openssh.com");
638: buffer_put_cstring(&msg, "1"); /* version */
1.80 djm 639: /* statvfs extension */
1.79 djm 640: buffer_put_cstring(&msg, "statvfs@openssh.com");
1.81 djm 641: buffer_put_cstring(&msg, "2"); /* version */
1.80 djm 642: /* fstatvfs extension */
1.79 djm 643: buffer_put_cstring(&msg, "fstatvfs@openssh.com");
1.81 djm 644: buffer_put_cstring(&msg, "2"); /* version */
1.93 djm 645: /* hardlink extension */
646: buffer_put_cstring(&msg, "hardlink@openssh.com");
647: buffer_put_cstring(&msg, "1"); /* version */
1.102 ! djm 648: /* fsync extension */
! 649: buffer_put_cstring(&msg, "fsync@openssh.com");
! 650: buffer_put_cstring(&msg, "1"); /* version */
1.1 markus 651: send_msg(&msg);
652: buffer_free(&msg);
653: }
654:
1.28 itojun 655: static void
1.98 djm 656: process_open(u_int32_t id)
1.1 markus 657: {
1.98 djm 658: u_int32_t pflags;
1.1 markus 659: Attrib *a;
660: char *name;
1.10 markus 661: int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1 markus 662:
663: name = get_string(NULL);
1.10 markus 664: pflags = get_int(); /* portable flags */
1.61 djm 665: debug3("request %u: open flags %d", id, pflags);
1.1 markus 666: a = get_attrib();
667: flags = flags_from_portable(pflags);
1.10 markus 668: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.58 djm 669: logit("open \"%s\" flags %s mode 0%o",
670: name, string_from_portable(pflags), mode);
1.90 djm 671: if (readonly &&
1.98 djm 672: ((flags & O_ACCMODE) == O_WRONLY ||
673: (flags & O_ACCMODE) == O_RDWR)) {
674: verbose("Refusing open request in read-only mode");
675: status = SSH2_FX_PERMISSION_DENIED;
676: } else {
1.90 djm 677: fd = open(name, flags, mode);
678: if (fd < 0) {
679: status = errno_to_portable(errno);
1.1 markus 680: } else {
1.101 djm 681: handle = handle_new(HANDLE_FILE, name, fd, flags, NULL);
1.90 djm 682: if (handle < 0) {
683: close(fd);
684: } else {
685: send_handle(id, handle);
686: status = SSH2_FX_OK;
687: }
1.1 markus 688: }
689: }
1.10 markus 690: if (status != SSH2_FX_OK)
1.1 markus 691: send_status(id, status);
1.97 djm 692: free(name);
1.1 markus 693: }
694:
1.28 itojun 695: static void
1.98 djm 696: process_close(u_int32_t id)
1.1 markus 697: {
1.10 markus 698: int handle, ret, status = SSH2_FX_FAILURE;
1.1 markus 699:
700: handle = get_handle();
1.58 djm 701: debug3("request %u: close handle %u", id, handle);
702: handle_log_close(handle, NULL);
1.1 markus 703: ret = handle_close(handle);
1.10 markus 704: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 705: send_status(id, status);
706: }
707:
1.28 itojun 708: static void
1.98 djm 709: process_read(u_int32_t id)
1.1 markus 710: {
711: char buf[64*1024];
1.98 djm 712: u_int32_t len;
1.10 markus 713: int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1 markus 714: u_int64_t off;
715:
716: handle = get_handle();
1.10 markus 717: off = get_int64();
1.1 markus 718: len = get_int();
719:
1.58 djm 720: debug("request %u: read \"%s\" (handle %d) off %llu len %d",
721: id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1 markus 722: if (len > sizeof buf) {
723: len = sizeof buf;
1.58 djm 724: debug2("read change len %d", len);
1.1 markus 725: }
726: fd = handle_to_fd(handle);
727: if (fd >= 0) {
728: if (lseek(fd, off, SEEK_SET) < 0) {
729: error("process_read: seek failed");
730: status = errno_to_portable(errno);
731: } else {
732: ret = read(fd, buf, len);
733: if (ret < 0) {
734: status = errno_to_portable(errno);
735: } else if (ret == 0) {
1.10 markus 736: status = SSH2_FX_EOF;
1.1 markus 737: } else {
738: send_data(id, buf, ret);
1.10 markus 739: status = SSH2_FX_OK;
1.58 djm 740: handle_update_read(handle, ret);
1.1 markus 741: }
742: }
743: }
1.10 markus 744: if (status != SSH2_FX_OK)
1.1 markus 745: send_status(id, status);
746: }
747:
1.28 itojun 748: static void
1.98 djm 749: process_write(u_int32_t id)
1.1 markus 750: {
751: u_int64_t off;
1.5 markus 752: u_int len;
1.90 djm 753: int handle, fd, ret, status;
1.1 markus 754: char *data;
755:
756: handle = get_handle();
1.10 markus 757: off = get_int64();
1.1 markus 758: data = get_string(&len);
759:
1.58 djm 760: debug("request %u: write \"%s\" (handle %d) off %llu len %d",
761: id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1 markus 762: fd = handle_to_fd(handle);
1.90 djm 763:
764: if (fd < 0)
765: status = SSH2_FX_FAILURE;
766: else {
1.101 djm 767: if (!(handle_to_flags(handle) & O_APPEND) &&
768: lseek(fd, off, SEEK_SET) < 0) {
1.1 markus 769: status = errno_to_portable(errno);
770: error("process_write: seek failed");
771: } else {
772: /* XXX ATOMICIO ? */
773: ret = write(fd, data, len);
1.48 djm 774: if (ret < 0) {
1.1 markus 775: error("process_write: write failed");
776: status = errno_to_portable(errno);
1.48 djm 777: } else if ((size_t)ret == len) {
1.10 markus 778: status = SSH2_FX_OK;
1.58 djm 779: handle_update_write(handle, ret);
1.1 markus 780: } else {
1.58 djm 781: debug2("nothing at all written");
1.90 djm 782: status = SSH2_FX_FAILURE;
1.1 markus 783: }
784: }
785: }
786: send_status(id, status);
1.97 djm 787: free(data);
1.1 markus 788: }
789:
1.28 itojun 790: static void
1.98 djm 791: process_do_stat(u_int32_t id, int do_lstat)
1.1 markus 792: {
1.13 markus 793: Attrib a;
1.1 markus 794: struct stat st;
795: char *name;
1.10 markus 796: int ret, status = SSH2_FX_FAILURE;
1.1 markus 797:
798: name = get_string(NULL);
1.58 djm 799: debug3("request %u: %sstat", id, do_lstat ? "l" : "");
800: verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
1.1 markus 801: ret = do_lstat ? lstat(name, &st) : stat(name, &st);
802: if (ret < 0) {
803: status = errno_to_portable(errno);
804: } else {
1.13 markus 805: stat_to_attrib(&st, &a);
806: send_attrib(id, &a);
1.10 markus 807: status = SSH2_FX_OK;
1.1 markus 808: }
1.10 markus 809: if (status != SSH2_FX_OK)
1.1 markus 810: send_status(id, status);
1.97 djm 811: free(name);
1.1 markus 812: }
813:
1.28 itojun 814: static void
1.98 djm 815: process_stat(u_int32_t id)
1.1 markus 816: {
1.98 djm 817: process_do_stat(id, 0);
1.1 markus 818: }
819:
1.28 itojun 820: static void
1.98 djm 821: process_lstat(u_int32_t id)
1.1 markus 822: {
1.98 djm 823: process_do_stat(id, 1);
1.1 markus 824: }
825:
1.28 itojun 826: static void
1.98 djm 827: process_fstat(u_int32_t id)
1.1 markus 828: {
1.13 markus 829: Attrib a;
1.1 markus 830: struct stat st;
1.10 markus 831: int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1 markus 832:
833: handle = get_handle();
1.58 djm 834: debug("request %u: fstat \"%s\" (handle %u)",
835: id, handle_to_name(handle), handle);
1.1 markus 836: fd = handle_to_fd(handle);
1.71 stevesk 837: if (fd >= 0) {
1.1 markus 838: ret = fstat(fd, &st);
839: if (ret < 0) {
840: status = errno_to_portable(errno);
841: } else {
1.13 markus 842: stat_to_attrib(&st, &a);
843: send_attrib(id, &a);
1.10 markus 844: status = SSH2_FX_OK;
1.1 markus 845: }
846: }
1.10 markus 847: if (status != SSH2_FX_OK)
1.1 markus 848: send_status(id, status);
849: }
850:
1.28 itojun 851: static struct timeval *
1.44 jakob 852: attrib_to_tv(const Attrib *a)
1.1 markus 853: {
854: static struct timeval tv[2];
1.22 deraadt 855:
1.1 markus 856: tv[0].tv_sec = a->atime;
857: tv[0].tv_usec = 0;
858: tv[1].tv_sec = a->mtime;
859: tv[1].tv_usec = 0;
860: return tv;
861: }
862:
1.28 itojun 863: static void
1.98 djm 864: process_setstat(u_int32_t id)
1.1 markus 865: {
866: Attrib *a;
867: char *name;
1.36 deraadt 868: int status = SSH2_FX_OK, ret;
1.1 markus 869:
870: name = get_string(NULL);
871: a = get_attrib();
1.58 djm 872: debug("request %u: setstat name \"%s\"", id, name);
1.33 markus 873: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.72 stevesk 874: logit("set \"%s\" size %llu",
875: name, (unsigned long long)a->size);
1.33 markus 876: ret = truncate(name, a->size);
877: if (ret == -1)
878: status = errno_to_portable(errno);
879: }
1.10 markus 880: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58 djm 881: logit("set \"%s\" mode %04o", name, a->perm);
1.84 djm 882: ret = chmod(name, a->perm & 07777);
1.1 markus 883: if (ret == -1)
884: status = errno_to_portable(errno);
885: }
1.10 markus 886: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58 djm 887: char buf[64];
888: time_t t = a->mtime;
889:
890: strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
891: localtime(&t));
892: logit("set \"%s\" modtime %s", name, buf);
1.1 markus 893: ret = utimes(name, attrib_to_tv(a));
894: if (ret == -1)
895: status = errno_to_portable(errno);
896: }
1.18 stevesk 897: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58 djm 898: logit("set \"%s\" owner %lu group %lu", name,
899: (u_long)a->uid, (u_long)a->gid);
1.18 stevesk 900: ret = chown(name, a->uid, a->gid);
901: if (ret == -1)
902: status = errno_to_portable(errno);
903: }
1.1 markus 904: send_status(id, status);
1.97 djm 905: free(name);
1.1 markus 906: }
907:
1.28 itojun 908: static void
1.98 djm 909: process_fsetstat(u_int32_t id)
1.1 markus 910: {
911: Attrib *a;
912: int handle, fd, ret;
1.10 markus 913: int status = SSH2_FX_OK;
1.1 markus 914:
915: handle = get_handle();
916: a = get_attrib();
1.58 djm 917: debug("request %u: fsetstat handle %d", id, handle);
1.1 markus 918: fd = handle_to_fd(handle);
1.90 djm 919: if (fd < 0)
1.10 markus 920: status = SSH2_FX_FAILURE;
1.90 djm 921: else {
1.58 djm 922: char *name = handle_to_name(handle);
923:
1.33 markus 924: if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.72 stevesk 925: logit("set \"%s\" size %llu",
926: name, (unsigned long long)a->size);
1.33 markus 927: ret = ftruncate(fd, a->size);
928: if (ret == -1)
929: status = errno_to_portable(errno);
930: }
1.10 markus 931: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58 djm 932: logit("set \"%s\" mode %04o", name, a->perm);
1.84 djm 933: ret = fchmod(fd, a->perm & 07777);
1.1 markus 934: if (ret == -1)
935: status = errno_to_portable(errno);
936: }
1.10 markus 937: if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58 djm 938: char buf[64];
939: time_t t = a->mtime;
940:
941: strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
942: localtime(&t));
943: logit("set \"%s\" modtime %s", name, buf);
1.1 markus 944: ret = futimes(fd, attrib_to_tv(a));
1.18 stevesk 945: if (ret == -1)
946: status = errno_to_portable(errno);
947: }
948: if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58 djm 949: logit("set \"%s\" owner %lu group %lu", name,
950: (u_long)a->uid, (u_long)a->gid);
1.18 stevesk 951: ret = fchown(fd, a->uid, a->gid);
1.1 markus 952: if (ret == -1)
953: status = errno_to_portable(errno);
954: }
955: }
956: send_status(id, status);
957: }
958:
1.28 itojun 959: static void
1.98 djm 960: process_opendir(u_int32_t id)
1.1 markus 961: {
962: DIR *dirp = NULL;
963: char *path;
1.10 markus 964: int handle, status = SSH2_FX_FAILURE;
1.1 markus 965:
966: path = get_string(NULL);
1.58 djm 967: debug3("request %u: opendir", id);
968: logit("opendir \"%s\"", path);
1.17 stevesk 969: dirp = opendir(path);
1.1 markus 970: if (dirp == NULL) {
971: status = errno_to_portable(errno);
972: } else {
1.101 djm 973: handle = handle_new(HANDLE_DIR, path, 0, 0, dirp);
1.1 markus 974: if (handle < 0) {
975: closedir(dirp);
976: } else {
977: send_handle(id, handle);
1.10 markus 978: status = SSH2_FX_OK;
1.1 markus 979: }
1.17 stevesk 980:
1.1 markus 981: }
1.10 markus 982: if (status != SSH2_FX_OK)
1.1 markus 983: send_status(id, status);
1.97 djm 984: free(path);
1.1 markus 985: }
986:
1.28 itojun 987: static void
1.98 djm 988: process_readdir(u_int32_t id)
1.1 markus 989: {
990: DIR *dirp;
991: struct dirent *dp;
992: char *path;
993: int handle;
994:
995: handle = get_handle();
1.58 djm 996: debug("request %u: readdir \"%s\" (handle %d)", id,
997: handle_to_name(handle), handle);
1.1 markus 998: dirp = handle_to_dir(handle);
999: path = handle_to_name(handle);
1000: if (dirp == NULL || path == NULL) {
1.10 markus 1001: send_status(id, SSH2_FX_FAILURE);
1.1 markus 1002: } else {
1003: struct stat st;
1.58 djm 1004: char pathname[MAXPATHLEN];
1.1 markus 1005: Stat *stats;
1006: int nstats = 10, count = 0, i;
1.36 deraadt 1007:
1.54 djm 1008: stats = xcalloc(nstats, sizeof(Stat));
1.1 markus 1009: while ((dp = readdir(dirp)) != NULL) {
1010: if (count >= nstats) {
1011: nstats *= 2;
1.55 djm 1012: stats = xrealloc(stats, nstats, sizeof(Stat));
1.1 markus 1013: }
1014: /* XXX OVERFLOW ? */
1.30 jakob 1015: snprintf(pathname, sizeof pathname, "%s%s%s", path,
1016: strcmp(path, "/") ? "/" : "", dp->d_name);
1.1 markus 1017: if (lstat(pathname, &st) < 0)
1018: continue;
1.13 markus 1019: stat_to_attrib(&st, &(stats[count].attrib));
1.1 markus 1020: stats[count].name = xstrdup(dp->d_name);
1.91 djm 1021: stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
1.1 markus 1022: count++;
1023: /* send up to 100 entries in one message */
1.11 markus 1024: /* XXX check packet size instead */
1.1 markus 1025: if (count == 100)
1026: break;
1027: }
1.10 markus 1028: if (count > 0) {
1029: send_names(id, count, stats);
1.31 deraadt 1030: for (i = 0; i < count; i++) {
1.97 djm 1031: free(stats[i].name);
1032: free(stats[i].long_name);
1.10 markus 1033: }
1034: } else {
1035: send_status(id, SSH2_FX_EOF);
1.1 markus 1036: }
1.97 djm 1037: free(stats);
1.1 markus 1038: }
1039: }
1040:
1.28 itojun 1041: static void
1.98 djm 1042: process_remove(u_int32_t id)
1.1 markus 1043: {
1044: char *name;
1.10 markus 1045: int status = SSH2_FX_FAILURE;
1.1 markus 1046: int ret;
1047:
1048: name = get_string(NULL);
1.58 djm 1049: debug3("request %u: remove", id);
1050: logit("remove name \"%s\"", name);
1.98 djm 1051: ret = unlink(name);
1052: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 1053: send_status(id, status);
1.97 djm 1054: free(name);
1.1 markus 1055: }
1056:
1.28 itojun 1057: static void
1.98 djm 1058: process_mkdir(u_int32_t id)
1.1 markus 1059: {
1060: Attrib *a;
1061: char *name;
1.10 markus 1062: int ret, mode, status = SSH2_FX_FAILURE;
1.1 markus 1063:
1064: name = get_string(NULL);
1065: a = get_attrib();
1.10 markus 1066: mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
1.84 djm 1067: a->perm & 07777 : 0777;
1.58 djm 1068: debug3("request %u: mkdir", id);
1069: logit("mkdir name \"%s\" mode 0%o", name, mode);
1.98 djm 1070: ret = mkdir(name, mode);
1071: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 1072: send_status(id, status);
1.97 djm 1073: free(name);
1.1 markus 1074: }
1075:
1.28 itojun 1076: static void
1.98 djm 1077: process_rmdir(u_int32_t id)
1.1 markus 1078: {
1079: char *name;
1080: int ret, status;
1081:
1082: name = get_string(NULL);
1.58 djm 1083: debug3("request %u: rmdir", id);
1084: logit("rmdir name \"%s\"", name);
1.98 djm 1085: ret = rmdir(name);
1086: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1 markus 1087: send_status(id, status);
1.97 djm 1088: free(name);
1.1 markus 1089: }
1090:
1.28 itojun 1091: static void
1.98 djm 1092: process_realpath(u_int32_t id)
1.1 markus 1093: {
1094: char resolvedname[MAXPATHLEN];
1095: char *path;
1096:
1097: path = get_string(NULL);
1.7 markus 1098: if (path[0] == '\0') {
1.97 djm 1099: free(path);
1.7 markus 1100: path = xstrdup(".");
1101: }
1.58 djm 1102: debug3("request %u: realpath", id);
1103: verbose("realpath \"%s\"", path);
1.1 markus 1104: if (realpath(path, resolvedname) == NULL) {
1105: send_status(id, errno_to_portable(errno));
1106: } else {
1107: Stat s;
1108: attrib_clear(&s.attrib);
1109: s.name = s.long_name = resolvedname;
1110: send_names(id, 1, &s);
1111: }
1.97 djm 1112: free(path);
1.1 markus 1113: }
1114:
1.28 itojun 1115: static void
1.98 djm 1116: process_rename(u_int32_t id)
1.1 markus 1117: {
1118: char *oldpath, *newpath;
1.39 markus 1119: int status;
1.41 deraadt 1120: struct stat sb;
1.1 markus 1121:
1122: oldpath = get_string(NULL);
1123: newpath = get_string(NULL);
1.58 djm 1124: debug3("request %u: rename", id);
1125: logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1.41 deraadt 1126: status = SSH2_FX_FAILURE;
1.98 djm 1127: if (lstat(oldpath, &sb) == -1)
1.39 markus 1128: status = errno_to_portable(errno);
1.41 deraadt 1129: else if (S_ISREG(sb.st_mode)) {
1130: /* Race-free rename of regular files */
1.47 dtucker 1131: if (link(oldpath, newpath) == -1) {
1132: if (errno == EOPNOTSUPP) {
1133: struct stat st;
1134:
1135: /*
1136: * fs doesn't support links, so fall back to
1137: * stat+rename. This is racy.
1138: */
1139: if (stat(newpath, &st) == -1) {
1140: if (rename(oldpath, newpath) == -1)
1141: status =
1142: errno_to_portable(errno);
1143: else
1144: status = SSH2_FX_OK;
1145: }
1146: } else {
1147: status = errno_to_portable(errno);
1148: }
1149: } else if (unlink(oldpath) == -1) {
1.41 deraadt 1150: status = errno_to_portable(errno);
1151: /* clean spare link */
1152: unlink(newpath);
1153: } else
1154: status = SSH2_FX_OK;
1155: } else if (stat(newpath, &sb) == -1) {
1156: if (rename(oldpath, newpath) == -1)
1157: status = errno_to_portable(errno);
1158: else
1159: status = SSH2_FX_OK;
1160: }
1.1 markus 1161: send_status(id, status);
1.97 djm 1162: free(oldpath);
1163: free(newpath);
1.1 markus 1164: }
1165:
1.28 itojun 1166: static void
1.98 djm 1167: process_readlink(u_int32_t id)
1.23 djm 1168: {
1.26 markus 1169: int len;
1.46 avsm 1170: char buf[MAXPATHLEN];
1.23 djm 1171: char *path;
1172:
1173: path = get_string(NULL);
1.58 djm 1174: debug3("request %u: readlink", id);
1175: verbose("readlink \"%s\"", path);
1.46 avsm 1176: if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1.23 djm 1177: send_status(id, errno_to_portable(errno));
1178: else {
1179: Stat s;
1.31 deraadt 1180:
1.46 avsm 1181: buf[len] = '\0';
1.23 djm 1182: attrib_clear(&s.attrib);
1.46 avsm 1183: s.name = s.long_name = buf;
1.23 djm 1184: send_names(id, 1, &s);
1185: }
1.97 djm 1186: free(path);
1.23 djm 1187: }
1188:
1.28 itojun 1189: static void
1.98 djm 1190: process_symlink(u_int32_t id)
1.23 djm 1191: {
1192: char *oldpath, *newpath;
1.39 markus 1193: int ret, status;
1.23 djm 1194:
1195: oldpath = get_string(NULL);
1196: newpath = get_string(NULL);
1.58 djm 1197: debug3("request %u: symlink", id);
1198: logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1.39 markus 1199: /* this will fail if 'newpath' exists */
1.98 djm 1200: ret = symlink(oldpath, newpath);
1201: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.23 djm 1202: send_status(id, status);
1.97 djm 1203: free(oldpath);
1204: free(newpath);
1.23 djm 1205: }
1206:
1.28 itojun 1207: static void
1.78 djm 1208: process_extended_posix_rename(u_int32_t id)
1209: {
1210: char *oldpath, *newpath;
1.90 djm 1211: int ret, status;
1.78 djm 1212:
1213: oldpath = get_string(NULL);
1214: newpath = get_string(NULL);
1215: debug3("request %u: posix-rename", id);
1216: logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1.98 djm 1217: ret = rename(oldpath, newpath);
1218: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.90 djm 1219: send_status(id, status);
1.97 djm 1220: free(oldpath);
1221: free(newpath);
1.78 djm 1222: }
1223:
1224: static void
1.79 djm 1225: process_extended_statvfs(u_int32_t id)
1226: {
1227: char *path;
1228: struct statvfs st;
1229:
1230: path = get_string(NULL);
1231: debug3("request %u: statfs", id);
1232: logit("statfs \"%s\"", path);
1233:
1234: if (statvfs(path, &st) != 0)
1235: send_status(id, errno_to_portable(errno));
1236: else
1237: send_statvfs(id, &st);
1.97 djm 1238: free(path);
1.79 djm 1239: }
1240:
1241: static void
1242: process_extended_fstatvfs(u_int32_t id)
1243: {
1244: int handle, fd;
1245: struct statvfs st;
1246:
1247: handle = get_handle();
1248: debug("request %u: fstatvfs \"%s\" (handle %u)",
1249: id, handle_to_name(handle), handle);
1250: if ((fd = handle_to_fd(handle)) < 0) {
1251: send_status(id, SSH2_FX_FAILURE);
1252: return;
1253: }
1254: if (fstatvfs(fd, &st) != 0)
1255: send_status(id, errno_to_portable(errno));
1256: else
1257: send_statvfs(id, &st);
1258: }
1259:
1260: static void
1.93 djm 1261: process_extended_hardlink(u_int32_t id)
1262: {
1263: char *oldpath, *newpath;
1264: int ret, status;
1265:
1266: oldpath = get_string(NULL);
1267: newpath = get_string(NULL);
1268: debug3("request %u: hardlink", id);
1269: logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
1.98 djm 1270: ret = link(oldpath, newpath);
1271: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.93 djm 1272: send_status(id, status);
1.97 djm 1273: free(oldpath);
1274: free(newpath);
1.102 ! djm 1275: }
! 1276:
! 1277: static void
! 1278: process_extended_fsync(u_int32_t id)
! 1279: {
! 1280: int handle, fd, ret, status = SSH2_FX_OP_UNSUPPORTED;
! 1281:
! 1282: handle = get_handle();
! 1283: debug3("request %u: fsync (handle %u)", id, handle);
! 1284: verbose("fsync \"%s\"", handle_to_name(handle));
! 1285: if ((fd = handle_to_fd(handle)) < 0)
! 1286: status = SSH2_FX_NO_SUCH_FILE;
! 1287: else if (handle_is_ok(handle, HANDLE_FILE)) {
! 1288: ret = fsync(fd);
! 1289: status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
! 1290: }
! 1291: send_status(id, status);
1.93 djm 1292: }
1293:
1294: static void
1.98 djm 1295: process_extended(u_int32_t id)
1.10 markus 1296: {
1297: char *request;
1.98 djm 1298: u_int i;
1.10 markus 1299:
1300: request = get_string(NULL);
1.98 djm 1301: for (i = 0; extended_handlers[i].handler != NULL; i++) {
1302: if (strcmp(request, extended_handlers[i].ext_name) == 0) {
1303: if (!request_permitted(&extended_handlers[i]))
1304: send_status(id, SSH2_FX_PERMISSION_DENIED);
1305: else
1306: extended_handlers[i].handler(id);
1307: break;
1308: }
1309: }
1310: if (extended_handlers[i].handler == NULL) {
1311: error("Unknown extended request \"%.100s\"", request);
1.78 djm 1312: send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
1.98 djm 1313: }
1.97 djm 1314: free(request);
1.10 markus 1315: }
1.1 markus 1316:
1317: /* stolen from ssh-agent */
1318:
1.28 itojun 1319: static void
1.1 markus 1320: process(void)
1321: {
1.98 djm 1322: u_int msg_len, buf_len, consumed, type, i;
1.9 markus 1323: u_char *cp;
1.98 djm 1324: u_int32_t id;
1.1 markus 1325:
1.34 markus 1326: buf_len = buffer_len(&iqueue);
1327: if (buf_len < 5)
1.1 markus 1328: return; /* Incomplete message. */
1.32 stevesk 1329: cp = buffer_ptr(&iqueue);
1.57 djm 1330: msg_len = get_u32(cp);
1.50 djm 1331: if (msg_len > SFTP_MAX_MSG_LENGTH) {
1.58 djm 1332: error("bad message from %s local user %s",
1333: client_addr, pw->pw_name);
1.76 markus 1334: sftp_server_cleanup_exit(11);
1.1 markus 1335: }
1.34 markus 1336: if (buf_len < msg_len + 4)
1.1 markus 1337: return;
1338: buffer_consume(&iqueue, 4);
1.34 markus 1339: buf_len -= 4;
1.1 markus 1340: type = buffer_get_char(&iqueue);
1.98 djm 1341:
1.1 markus 1342: switch (type) {
1.10 markus 1343: case SSH2_FXP_INIT:
1.1 markus 1344: process_init();
1.98 djm 1345: init_done = 1;
1.1 markus 1346: break;
1.10 markus 1347: case SSH2_FXP_EXTENDED:
1.98 djm 1348: if (!init_done)
1349: fatal("Received extended request before init");
1350: id = get_int();
1351: process_extended(id);
1.10 markus 1352: break;
1.1 markus 1353: default:
1.98 djm 1354: if (!init_done)
1355: fatal("Received %u request before init", type);
1356: id = get_int();
1357: for (i = 0; handlers[i].handler != NULL; i++) {
1358: if (type == handlers[i].type) {
1359: if (!request_permitted(&handlers[i])) {
1360: send_status(id,
1361: SSH2_FX_PERMISSION_DENIED);
1362: } else {
1363: handlers[i].handler(id);
1364: }
1365: break;
1366: }
1367: }
1368: if (handlers[i].handler == NULL)
1369: error("Unknown message %u", type);
1.1 markus 1370: }
1.34 markus 1371: /* discard the remaining bytes from the current packet */
1.76 markus 1372: if (buf_len < buffer_len(&iqueue)) {
1373: error("iqueue grew unexpectedly");
1374: sftp_server_cleanup_exit(255);
1375: }
1.34 markus 1376: consumed = buf_len - buffer_len(&iqueue);
1.76 markus 1377: if (msg_len < consumed) {
1.98 djm 1378: error("msg_len %u < consumed %u", msg_len, consumed);
1.76 markus 1379: sftp_server_cleanup_exit(255);
1380: }
1.34 markus 1381: if (msg_len > consumed)
1382: buffer_consume(&iqueue, msg_len - consumed);
1.1 markus 1383: }
1384:
1.58 djm 1385: /* Cleanup handler that logs active handles upon normal exit */
1386: void
1.76 markus 1387: sftp_server_cleanup_exit(int i)
1.58 djm 1388: {
1389: if (pw != NULL && client_addr != NULL) {
1390: handle_log_exit();
1391: logit("session closed for local user %s from [%s]",
1392: pw->pw_name, client_addr);
1393: }
1394: _exit(i);
1395: }
1396:
1397: static void
1.76 markus 1398: sftp_server_usage(void)
1.58 djm 1399: {
1400: extern char *__progname;
1401:
1402: fprintf(stderr,
1.96 jmc 1403: "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
1.100 jmc 1404: "[-l log_level]\n\t[-P blacklisted_requests] "
1405: "[-p whitelisted_requests] [-u umask]\n"
1406: " %s -Q protocol_feature\n",
1407: __progname, __progname);
1.58 djm 1408: exit(1);
1409: }
1410:
1.1 markus 1411: int
1.77 djm 1412: sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1.1 markus 1413: {
1.21 millert 1414: fd_set *rset, *wset;
1.98 djm 1415: int i, in, out, max, ch, skipargs = 0, log_stderr = 0;
1.21 millert 1416: ssize_t len, olen, set_size;
1.58 djm 1417: SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1.95 djm 1418: char *cp, *homedir = NULL, buf[4*4096];
1.92 djm 1419: long mask;
1.58 djm 1420:
1421: extern char *optarg;
1422: extern char *__progname;
1.49 djm 1423:
1.58 djm 1424: log_init(__progname, log_level, log_facility, log_stderr);
1425:
1.95 djm 1426: pw = pwcopy(user_pw);
1427:
1.98 djm 1428: while (!skipargs && (ch = getopt(argc, argv,
1429: "d:f:l:P:p:Q:u:cehR")) != -1) {
1.58 djm 1430: switch (ch) {
1.98 djm 1431: case 'Q':
1432: if (strcasecmp(optarg, "requests") != 0) {
1433: fprintf(stderr, "Invalid query type\n");
1434: exit(1);
1435: }
1436: for (i = 0; handlers[i].handler != NULL; i++)
1437: printf("%s\n", handlers[i].name);
1438: for (i = 0; extended_handlers[i].handler != NULL; i++)
1439: printf("%s\n", extended_handlers[i].name);
1440: exit(0);
1441: break;
1.90 djm 1442: case 'R':
1443: readonly = 1;
1444: break;
1.58 djm 1445: case 'c':
1446: /*
1447: * Ignore all arguments if we are invoked as a
1.70 deraadt 1448: * shell using "sftp-server -c command"
1.58 djm 1449: */
1450: skipargs = 1;
1451: break;
1452: case 'e':
1453: log_stderr = 1;
1454: break;
1455: case 'l':
1456: log_level = log_level_number(optarg);
1457: if (log_level == SYSLOG_LEVEL_NOT_SET)
1458: error("Invalid log level \"%s\"", optarg);
1459: break;
1460: case 'f':
1461: log_facility = log_facility_number(optarg);
1.74 djm 1462: if (log_facility == SYSLOG_FACILITY_NOT_SET)
1.58 djm 1463: error("Invalid log facility \"%s\"", optarg);
1.86 djm 1464: break;
1.95 djm 1465: case 'd':
1466: cp = tilde_expand_filename(optarg, user_pw->pw_uid);
1467: homedir = percent_expand(cp, "d", user_pw->pw_dir,
1468: "u", user_pw->pw_name, (char *)NULL);
1469: free(cp);
1.98 djm 1470: break;
1471: case 'p':
1472: if (request_whitelist != NULL)
1473: fatal("Permitted requests already set");
1474: request_whitelist = xstrdup(optarg);
1475: break;
1476: case 'P':
1477: if (request_blacklist != NULL)
1478: fatal("Refused requests already set");
1479: request_blacklist = xstrdup(optarg);
1.95 djm 1480: break;
1.86 djm 1481: case 'u':
1.92 djm 1482: errno = 0;
1483: mask = strtol(optarg, &cp, 8);
1484: if (mask < 0 || mask > 0777 || *cp != '\0' ||
1485: cp == optarg || (mask == 0 && errno != 0))
1486: fatal("Invalid umask \"%s\"", optarg);
1487: (void)umask((mode_t)mask);
1.58 djm 1488: break;
1489: case 'h':
1490: default:
1.76 markus 1491: sftp_server_usage();
1.58 djm 1492: }
1493: }
1494:
1495: log_init(__progname, log_level, log_facility, log_stderr);
1496:
1497: if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1498: client_addr = xstrdup(cp);
1.76 markus 1499: if ((cp = strchr(client_addr, ' ')) == NULL) {
1500: error("Malformed SSH_CONNECTION variable: \"%s\"",
1.58 djm 1501: getenv("SSH_CONNECTION"));
1.76 markus 1502: sftp_server_cleanup_exit(255);
1503: }
1.58 djm 1504: *cp = '\0';
1505: } else
1506: client_addr = xstrdup("UNKNOWN");
1507:
1508: logit("session opened for local user %s from [%s]",
1509: pw->pw_name, client_addr);
1.10 markus 1510:
1.89 djm 1511: in = STDIN_FILENO;
1512: out = STDOUT_FILENO;
1.1 markus 1513:
1514: max = 0;
1515: if (in > max)
1516: max = in;
1517: if (out > max)
1518: max = out;
1519:
1520: buffer_init(&iqueue);
1521: buffer_init(&oqueue);
1522:
1.21 millert 1523: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1524: rset = (fd_set *)xmalloc(set_size);
1525: wset = (fd_set *)xmalloc(set_size);
1.95 djm 1526:
1527: if (homedir != NULL) {
1528: if (chdir(homedir) != 0) {
1529: error("chdir to \"%s\" failed: %s", homedir,
1530: strerror(errno));
1531: }
1532: }
1.21 millert 1533:
1.1 markus 1534: for (;;) {
1.21 millert 1535: memset(rset, 0, set_size);
1536: memset(wset, 0, set_size);
1.1 markus 1537:
1.73 djm 1538: /*
1539: * Ensure that we can read a full buffer and handle
1540: * the worst-case length packet it can generate,
1541: * otherwise apply backpressure by stopping reads.
1542: */
1543: if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
1544: buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1545: FD_SET(in, rset);
1546:
1.1 markus 1547: olen = buffer_len(&oqueue);
1548: if (olen > 0)
1.21 millert 1549: FD_SET(out, wset);
1.1 markus 1550:
1.21 millert 1551: if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1 markus 1552: if (errno == EINTR)
1553: continue;
1.58 djm 1554: error("select: %s", strerror(errno));
1.76 markus 1555: sftp_server_cleanup_exit(2);
1.1 markus 1556: }
1557:
1558: /* copy stdin to iqueue */
1.21 millert 1559: if (FD_ISSET(in, rset)) {
1.1 markus 1560: len = read(in, buf, sizeof buf);
1561: if (len == 0) {
1562: debug("read eof");
1.76 markus 1563: sftp_server_cleanup_exit(0);
1.1 markus 1564: } else if (len < 0) {
1.58 djm 1565: error("read: %s", strerror(errno));
1.76 markus 1566: sftp_server_cleanup_exit(1);
1.1 markus 1567: } else {
1568: buffer_append(&iqueue, buf, len);
1569: }
1570: }
1571: /* send oqueue to stdout */
1.21 millert 1572: if (FD_ISSET(out, wset)) {
1.1 markus 1573: len = write(out, buffer_ptr(&oqueue), olen);
1574: if (len < 0) {
1.58 djm 1575: error("write: %s", strerror(errno));
1.76 markus 1576: sftp_server_cleanup_exit(1);
1.1 markus 1577: } else {
1578: buffer_consume(&oqueue, len);
1579: }
1580: }
1.73 djm 1581:
1582: /*
1583: * Process requests from client if we can fit the results
1584: * into the output buffer, otherwise stop processing input
1585: * and let the output queue drain.
1586: */
1587: if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1588: process();
1.1 markus 1589: }
1590: }