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