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