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