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