blob: 0c6f4c24e967a265cffa6264e0af93e8ea5d43e7 [file] [log] [blame]
Damien Miller57cf6382006-07-10 21:13:46 +10001/* $OpenBSD: sftp-server.c,v 1.59 2006/07/09 15:15:11 stevesk Exp $ */
Damien Miller7b28dc52000-09-05 13:34:53 +11002/*
Darren Tucker37bd3662004-02-24 09:19:15 +11003 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
Damien Miller7b28dc52000-09-05 13:34:53 +11004 *
Darren Tucker37bd3662004-02-24 09:19:15 +11005 * 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.
Damien Miller7b28dc52000-09-05 13:34:53 +11008 *
Darren Tucker37bd3662004-02-24 09:19:15 +11009 * 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.
Damien Miller7b28dc52000-09-05 13:34:53 +110016 */
17#include "includes.h"
Damien Millerf17883e2006-03-15 11:45:54 +110018
19#include <sys/types.h>
20#include <sys/stat.h>
Damien Miller88f254b2006-03-15 11:25:13 +110021
22#include <dirent.h>
Damien Miller57cf6382006-07-10 21:13:46 +100023#include <fcntl.h>
Damien Miller9f2abc42006-07-10 20:53:08 +100024#include <pwd.h>
Damien Miller7b28dc52000-09-05 13:34:53 +110025
Damien Miller7b28dc52000-09-05 13:34:53 +110026#include "buffer.h"
27#include "bufaux.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000028#include "log.h"
Damien Miller7b28dc52000-09-05 13:34:53 +110029#include "xmalloc.h"
Darren Tuckerce321d82005-10-03 18:11:24 +100030#include "misc.h"
Damien Millerfef95ad2006-07-10 20:46:55 +100031#include "uidswap.h"
Damien Miller7b28dc52000-09-05 13:34:53 +110032
Ben Lindstrom2f959b42001-01-11 06:20:23 +000033#include "sftp.h"
Damien Miller33804262001-02-04 23:20:18 +110034#include "sftp-common.h"
Damien Miller7b28dc52000-09-05 13:34:53 +110035
36/* helper */
Ben Lindstrom2f959b42001-01-11 06:20:23 +000037#define get_int64() buffer_get_int64(&iqueue);
Damien Miller7b28dc52000-09-05 13:34:53 +110038#define get_int() buffer_get_int(&iqueue);
39#define get_string(lenp) buffer_get_string(&iqueue, lenp);
Damien Miller7b28dc52000-09-05 13:34:53 +110040
Damien Millerfef95ad2006-07-10 20:46:55 +100041/* Our verbosity */
42LogLevel log_level = SYSLOG_LEVEL_ERROR;
43
44/* Our client */
45struct passwd *pw = NULL;
46char *client_addr = NULL;
Ben Lindstrom49a79c02000-11-17 03:47:20 +000047
Damien Miller7b28dc52000-09-05 13:34:53 +110048/* input and output queue */
49Buffer iqueue;
50Buffer oqueue;
51
Damien Miller058316f2001-03-08 10:08:49 +110052/* Version of client */
53int version;
54
Darren Tuckera6612d42003-06-28 12:39:03 +100055/* portable attributes, etc. */
Damien Miller7b28dc52000-09-05 13:34:53 +110056
Damien Miller7b28dc52000-09-05 13:34:53 +110057typedef struct Stat Stat;
58
Damien Miller33804262001-02-04 23:20:18 +110059struct Stat {
Damien Miller7b28dc52000-09-05 13:34:53 +110060 char *name;
61 char *long_name;
62 Attrib attrib;
63};
64
Ben Lindstrombba81212001-06-25 05:01:22 +000065static int
Damien Miller7b28dc52000-09-05 13:34:53 +110066errno_to_portable(int unixerrno)
67{
68 int ret = 0;
Ben Lindstrom1addabd2001-03-05 07:09:11 +000069
Damien Miller7b28dc52000-09-05 13:34:53 +110070 switch (unixerrno) {
71 case 0:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000072 ret = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +110073 break;
74 case ENOENT:
75 case ENOTDIR:
76 case EBADF:
77 case ELOOP:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000078 ret = SSH2_FX_NO_SUCH_FILE;
Damien Miller7b28dc52000-09-05 13:34:53 +110079 break;
80 case EPERM:
81 case EACCES:
82 case EFAULT:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000083 ret = SSH2_FX_PERMISSION_DENIED;
Damien Miller7b28dc52000-09-05 13:34:53 +110084 break;
85 case ENAMETOOLONG:
86 case EINVAL:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000087 ret = SSH2_FX_BAD_MESSAGE;
Damien Miller7b28dc52000-09-05 13:34:53 +110088 break;
89 default:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000090 ret = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +110091 break;
92 }
93 return ret;
94}
95
Ben Lindstrombba81212001-06-25 05:01:22 +000096static int
Damien Miller7b28dc52000-09-05 13:34:53 +110097flags_from_portable(int pflags)
98{
99 int flags = 0;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000100
Ben Lindstrom36592512001-03-05 05:02:08 +0000101 if ((pflags & SSH2_FXF_READ) &&
102 (pflags & SSH2_FXF_WRITE)) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100103 flags = O_RDWR;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000104 } else if (pflags & SSH2_FXF_READ) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100105 flags = O_RDONLY;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000106 } else if (pflags & SSH2_FXF_WRITE) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100107 flags = O_WRONLY;
108 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000109 if (pflags & SSH2_FXF_CREAT)
Damien Miller7b28dc52000-09-05 13:34:53 +1100110 flags |= O_CREAT;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000111 if (pflags & SSH2_FXF_TRUNC)
Damien Miller7b28dc52000-09-05 13:34:53 +1100112 flags |= O_TRUNC;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000113 if (pflags & SSH2_FXF_EXCL)
Damien Miller7b28dc52000-09-05 13:34:53 +1100114 flags |= O_EXCL;
115 return flags;
116}
117
Damien Millerfef95ad2006-07-10 20:46:55 +1000118static const char *
119string_from_portable(int pflags)
120{
121 static char ret[128];
122
123 *ret = '\0';
124
125#define PAPPEND(str) { \
126 if (*ret != '\0') \
127 strlcat(ret, ",", sizeof(ret)); \
128 strlcat(ret, str, sizeof(ret)); \
129 }
130
131 if (pflags & SSH2_FXF_READ)
132 PAPPEND("READ")
133 if (pflags & SSH2_FXF_WRITE)
134 PAPPEND("WRITE")
135 if (pflags & SSH2_FXF_CREAT)
136 PAPPEND("CREATE")
137 if (pflags & SSH2_FXF_TRUNC)
138 PAPPEND("TRUNCATE")
139 if (pflags & SSH2_FXF_EXCL)
140 PAPPEND("EXCL")
141
142 return ret;
143}
144
Ben Lindstrombba81212001-06-25 05:01:22 +0000145static Attrib *
Damien Miller7b28dc52000-09-05 13:34:53 +1100146get_attrib(void)
147{
148 return decode_attrib(&iqueue);
149}
150
151/* handle handles */
152
153typedef struct Handle Handle;
154struct Handle {
155 int use;
156 DIR *dirp;
157 int fd;
158 char *name;
Damien Millerfef95ad2006-07-10 20:46:55 +1000159 u_int64_t bytes_read, bytes_write;
Damien Miller7b28dc52000-09-05 13:34:53 +1100160};
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000161
Damien Miller7b28dc52000-09-05 13:34:53 +1100162enum {
163 HANDLE_UNUSED,
164 HANDLE_DIR,
165 HANDLE_FILE
166};
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000167
Damien Miller7b28dc52000-09-05 13:34:53 +1100168Handle handles[100];
169
Ben Lindstrombba81212001-06-25 05:01:22 +0000170static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100171handle_init(void)
172{
Damien Millereccb9de2005-06-17 12:59:34 +1000173 u_int i;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000174
Damien Miller9f0f5c62001-12-21 14:45:46 +1100175 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
Damien Miller7b28dc52000-09-05 13:34:53 +1100176 handles[i].use = HANDLE_UNUSED;
177}
178
Ben Lindstrombba81212001-06-25 05:01:22 +0000179static int
Damien Millerf58b58c2003-11-17 21:18:23 +1100180handle_new(int use, const char *name, int fd, DIR *dirp)
Damien Miller7b28dc52000-09-05 13:34:53 +1100181{
Damien Millereccb9de2005-06-17 12:59:34 +1000182 u_int i;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000183
Damien Miller9f0f5c62001-12-21 14:45:46 +1100184 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100185 if (handles[i].use == HANDLE_UNUSED) {
186 handles[i].use = use;
187 handles[i].dirp = dirp;
188 handles[i].fd = fd;
Damien Miller00111382003-03-10 11:21:17 +1100189 handles[i].name = xstrdup(name);
Damien Millerfef95ad2006-07-10 20:46:55 +1000190 handles[i].bytes_read = handles[i].bytes_write = 0;
Damien Miller7b28dc52000-09-05 13:34:53 +1100191 return i;
192 }
193 }
194 return -1;
195}
196
Ben Lindstrombba81212001-06-25 05:01:22 +0000197static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100198handle_is_ok(int i, int type)
199{
Damien Millereccb9de2005-06-17 12:59:34 +1000200 return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000201 handles[i].use == type;
Damien Miller7b28dc52000-09-05 13:34:53 +1100202}
203
Ben Lindstrombba81212001-06-25 05:01:22 +0000204static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100205handle_to_string(int handle, char **stringp, int *hlenp)
206{
Damien Miller7b28dc52000-09-05 13:34:53 +1100207 if (stringp == NULL || hlenp == NULL)
208 return -1;
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000209 *stringp = xmalloc(sizeof(int32_t));
Damien Miller3f941882006-03-31 23:13:02 +1100210 put_u32(*stringp, handle);
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000211 *hlenp = sizeof(int32_t);
Damien Miller7b28dc52000-09-05 13:34:53 +1100212 return 0;
213}
214
Ben Lindstrombba81212001-06-25 05:01:22 +0000215static int
Damien Millerf58b58c2003-11-17 21:18:23 +1100216handle_from_string(const char *handle, u_int hlen)
Damien Miller7b28dc52000-09-05 13:34:53 +1100217{
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000218 int val;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000219
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000220 if (hlen != sizeof(int32_t))
Damien Miller7b28dc52000-09-05 13:34:53 +1100221 return -1;
Damien Miller3f941882006-03-31 23:13:02 +1100222 val = get_u32(handle);
Damien Miller7b28dc52000-09-05 13:34:53 +1100223 if (handle_is_ok(val, HANDLE_FILE) ||
224 handle_is_ok(val, HANDLE_DIR))
225 return val;
226 return -1;
227}
228
Ben Lindstrombba81212001-06-25 05:01:22 +0000229static char *
Damien Miller7b28dc52000-09-05 13:34:53 +1100230handle_to_name(int handle)
231{
232 if (handle_is_ok(handle, HANDLE_DIR)||
233 handle_is_ok(handle, HANDLE_FILE))
234 return handles[handle].name;
235 return NULL;
236}
237
Ben Lindstrombba81212001-06-25 05:01:22 +0000238static DIR *
Damien Miller7b28dc52000-09-05 13:34:53 +1100239handle_to_dir(int handle)
240{
241 if (handle_is_ok(handle, HANDLE_DIR))
242 return handles[handle].dirp;
243 return NULL;
244}
245
Ben Lindstrombba81212001-06-25 05:01:22 +0000246static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100247handle_to_fd(int handle)
248{
Kevin Stevesef4eea92001-02-05 12:42:17 +0000249 if (handle_is_ok(handle, HANDLE_FILE))
Damien Miller7b28dc52000-09-05 13:34:53 +1100250 return handles[handle].fd;
251 return -1;
252}
253
Damien Millerfef95ad2006-07-10 20:46:55 +1000254static void
255handle_update_read(int handle, ssize_t bytes)
256{
257 if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
258 handles[handle].bytes_read += bytes;
259}
260
261static void
262handle_update_write(int handle, ssize_t bytes)
263{
264 if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
265 handles[handle].bytes_write += bytes;
266}
267
268static u_int64_t
269handle_bytes_read(int handle)
270{
271 if (handle_is_ok(handle, HANDLE_FILE))
272 return (handles[handle].bytes_read);
273 return 0;
274}
275
276static u_int64_t
277handle_bytes_write(int handle)
278{
279 if (handle_is_ok(handle, HANDLE_FILE))
280 return (handles[handle].bytes_write);
281 return 0;
282}
283
Ben Lindstrombba81212001-06-25 05:01:22 +0000284static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100285handle_close(int handle)
286{
287 int ret = -1;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000288
Damien Miller7b28dc52000-09-05 13:34:53 +1100289 if (handle_is_ok(handle, HANDLE_FILE)) {
290 ret = close(handles[handle].fd);
291 handles[handle].use = HANDLE_UNUSED;
Damien Miller00111382003-03-10 11:21:17 +1100292 xfree(handles[handle].name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100293 } else if (handle_is_ok(handle, HANDLE_DIR)) {
294 ret = closedir(handles[handle].dirp);
295 handles[handle].use = HANDLE_UNUSED;
Damien Miller00111382003-03-10 11:21:17 +1100296 xfree(handles[handle].name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100297 } else {
298 errno = ENOENT;
299 }
300 return ret;
301}
302
Damien Millerfef95ad2006-07-10 20:46:55 +1000303static void
304handle_log_close(int handle, char *emsg)
305{
306 if (handle_is_ok(handle, HANDLE_FILE)) {
307 logit("%s%sclose \"%s\" bytes read %llu written %llu",
308 emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
309 handle_to_name(handle),
310 handle_bytes_read(handle), handle_bytes_write(handle));
311 } else {
312 logit("%s%sclosedir \"%s\"",
313 emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
314 handle_to_name(handle));
315 }
316}
317
318static void
319handle_log_exit(void)
320{
321 u_int i;
322
323 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
324 if (handles[i].use != HANDLE_UNUSED)
325 handle_log_close(i, "forced");
326}
327
Ben Lindstrombba81212001-06-25 05:01:22 +0000328static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100329get_handle(void)
330{
331 char *handle;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000332 int val = -1;
Damien Millere4340be2000-09-16 13:29:08 +1100333 u_int hlen;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000334
Damien Miller7b28dc52000-09-05 13:34:53 +1100335 handle = get_string(&hlen);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000336 if (hlen < 256)
337 val = handle_from_string(handle, hlen);
Damien Miller7b28dc52000-09-05 13:34:53 +1100338 xfree(handle);
339 return val;
340}
341
342/* send replies */
343
Ben Lindstrombba81212001-06-25 05:01:22 +0000344static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100345send_msg(Buffer *m)
346{
347 int mlen = buffer_len(m);
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000348
Damien Miller7b28dc52000-09-05 13:34:53 +1100349 buffer_put_int(&oqueue, mlen);
350 buffer_append(&oqueue, buffer_ptr(m), mlen);
351 buffer_consume(m, mlen);
352}
353
Damien Millerfef95ad2006-07-10 20:46:55 +1000354static const char *
355status_to_message(u_int32_t status)
Damien Miller7b28dc52000-09-05 13:34:53 +1100356{
Damien Miller058316f2001-03-08 10:08:49 +1100357 const char *status_messages[] = {
358 "Success", /* SSH_FX_OK */
359 "End of file", /* SSH_FX_EOF */
360 "No such file", /* SSH_FX_NO_SUCH_FILE */
361 "Permission denied", /* SSH_FX_PERMISSION_DENIED */
362 "Failure", /* SSH_FX_FAILURE */
363 "Bad message", /* SSH_FX_BAD_MESSAGE */
364 "No connection", /* SSH_FX_NO_CONNECTION */
365 "Connection lost", /* SSH_FX_CONNECTION_LOST */
366 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
367 "Unknown error" /* Others */
368 };
Damien Millerfef95ad2006-07-10 20:46:55 +1000369 return (status_messages[MIN(status,SSH2_FX_MAX)]);
370}
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000371
Damien Millerfef95ad2006-07-10 20:46:55 +1000372static void
373send_status(u_int32_t id, u_int32_t status)
374{
375 Buffer msg;
376
377 debug3("request %u: sent status %u", id, status);
378 if (log_level > SYSLOG_LEVEL_VERBOSE ||
379 (status != SSH2_FX_OK && status != SSH2_FX_EOF))
380 logit("sent status %s", status_to_message(status));
Damien Miller7b28dc52000-09-05 13:34:53 +1100381 buffer_init(&msg);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000382 buffer_put_char(&msg, SSH2_FXP_STATUS);
Damien Miller7b28dc52000-09-05 13:34:53 +1100383 buffer_put_int(&msg, id);
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000384 buffer_put_int(&msg, status);
Damien Miller058316f2001-03-08 10:08:49 +1100385 if (version >= 3) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000386 buffer_put_cstring(&msg, status_to_message(status));
Damien Miller058316f2001-03-08 10:08:49 +1100387 buffer_put_cstring(&msg, "");
388 }
Damien Miller7b28dc52000-09-05 13:34:53 +1100389 send_msg(&msg);
390 buffer_free(&msg);
391}
Ben Lindstrombba81212001-06-25 05:01:22 +0000392static void
Damien Millerf58b58c2003-11-17 21:18:23 +1100393send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
Damien Miller7b28dc52000-09-05 13:34:53 +1100394{
395 Buffer msg;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000396
Damien Miller7b28dc52000-09-05 13:34:53 +1100397 buffer_init(&msg);
398 buffer_put_char(&msg, type);
399 buffer_put_int(&msg, id);
400 buffer_put_string(&msg, data, dlen);
401 send_msg(&msg);
402 buffer_free(&msg);
403}
404
Ben Lindstrombba81212001-06-25 05:01:22 +0000405static void
Damien Millerf58b58c2003-11-17 21:18:23 +1100406send_data(u_int32_t id, const char *data, int dlen)
Damien Miller7b28dc52000-09-05 13:34:53 +1100407{
Damien Millerfef95ad2006-07-10 20:46:55 +1000408 debug("request %u: sent data len %d", id, dlen);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000409 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
Damien Miller7b28dc52000-09-05 13:34:53 +1100410}
411
Ben Lindstrombba81212001-06-25 05:01:22 +0000412static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100413send_handle(u_int32_t id, int handle)
414{
415 char *string;
416 int hlen;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000417
Damien Miller7b28dc52000-09-05 13:34:53 +1100418 handle_to_string(handle, &string, &hlen);
Damien Millerfef95ad2006-07-10 20:46:55 +1000419 debug("request %u: sent handle handle %d", id, handle);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000420 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
Damien Miller7b28dc52000-09-05 13:34:53 +1100421 xfree(string);
422}
423
Ben Lindstrombba81212001-06-25 05:01:22 +0000424static void
Damien Millerf58b58c2003-11-17 21:18:23 +1100425send_names(u_int32_t id, int count, const Stat *stats)
Damien Miller7b28dc52000-09-05 13:34:53 +1100426{
427 Buffer msg;
428 int i;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000429
Damien Miller7b28dc52000-09-05 13:34:53 +1100430 buffer_init(&msg);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000431 buffer_put_char(&msg, SSH2_FXP_NAME);
Damien Miller7b28dc52000-09-05 13:34:53 +1100432 buffer_put_int(&msg, id);
433 buffer_put_int(&msg, count);
Damien Millerfef95ad2006-07-10 20:46:55 +1000434 debug("request %u: sent names count %d", id, count);
Damien Miller7b28dc52000-09-05 13:34:53 +1100435 for (i = 0; i < count; i++) {
436 buffer_put_cstring(&msg, stats[i].name);
437 buffer_put_cstring(&msg, stats[i].long_name);
438 encode_attrib(&msg, &stats[i].attrib);
439 }
440 send_msg(&msg);
441 buffer_free(&msg);
442}
443
Ben Lindstrombba81212001-06-25 05:01:22 +0000444static void
Damien Millerf58b58c2003-11-17 21:18:23 +1100445send_attrib(u_int32_t id, const Attrib *a)
Damien Miller7b28dc52000-09-05 13:34:53 +1100446{
447 Buffer msg;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000448
Damien Millerfef95ad2006-07-10 20:46:55 +1000449 debug("request %u: sent attrib have 0x%x", id, a->flags);
Damien Miller7b28dc52000-09-05 13:34:53 +1100450 buffer_init(&msg);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000451 buffer_put_char(&msg, SSH2_FXP_ATTRS);
Damien Miller7b28dc52000-09-05 13:34:53 +1100452 buffer_put_int(&msg, id);
453 encode_attrib(&msg, a);
454 send_msg(&msg);
455 buffer_free(&msg);
456}
457
458/* parse incoming */
459
Ben Lindstrombba81212001-06-25 05:01:22 +0000460static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100461process_init(void)
462{
463 Buffer msg;
Damien Miller7b28dc52000-09-05 13:34:53 +1100464
Ben Lindstrom937df1d2002-06-06 21:58:35 +0000465 version = get_int();
Damien Millerfef95ad2006-07-10 20:46:55 +1000466 verbose("received client version %d", version);
Damien Miller7b28dc52000-09-05 13:34:53 +1100467 buffer_init(&msg);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000468 buffer_put_char(&msg, SSH2_FXP_VERSION);
469 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
Damien Miller7b28dc52000-09-05 13:34:53 +1100470 send_msg(&msg);
471 buffer_free(&msg);
472}
473
Ben Lindstrombba81212001-06-25 05:01:22 +0000474static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100475process_open(void)
476{
477 u_int32_t id, pflags;
478 Attrib *a;
479 char *name;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000480 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100481
482 id = get_int();
Damien Millerfef95ad2006-07-10 20:46:55 +1000483 debug3("request %u: open flags %d", id, pflags);
Damien Miller7b28dc52000-09-05 13:34:53 +1100484 name = get_string(NULL);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000485 pflags = get_int(); /* portable flags */
Damien Miller7b28dc52000-09-05 13:34:53 +1100486 a = get_attrib();
487 flags = flags_from_portable(pflags);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000488 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
Damien Millerfef95ad2006-07-10 20:46:55 +1000489 logit("open \"%s\" flags %s mode 0%o",
490 name, string_from_portable(pflags), mode);
Damien Miller7b28dc52000-09-05 13:34:53 +1100491 fd = open(name, flags, mode);
492 if (fd < 0) {
493 status = errno_to_portable(errno);
494 } else {
Damien Miller00111382003-03-10 11:21:17 +1100495 handle = handle_new(HANDLE_FILE, name, fd, NULL);
Damien Miller7b28dc52000-09-05 13:34:53 +1100496 if (handle < 0) {
497 close(fd);
498 } else {
499 send_handle(id, handle);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000500 status = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100501 }
502 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000503 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100504 send_status(id, status);
505 xfree(name);
506}
507
Ben Lindstrombba81212001-06-25 05:01:22 +0000508static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100509process_close(void)
510{
511 u_int32_t id;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000512 int handle, ret, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100513
514 id = get_int();
515 handle = get_handle();
Damien Millerfef95ad2006-07-10 20:46:55 +1000516 debug3("request %u: close handle %u", id, handle);
517 handle_log_close(handle, NULL);
Damien Miller7b28dc52000-09-05 13:34:53 +1100518 ret = handle_close(handle);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000519 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100520 send_status(id, status);
521}
522
Ben Lindstrombba81212001-06-25 05:01:22 +0000523static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100524process_read(void)
525{
526 char buf[64*1024];
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000527 u_int32_t id, len;
528 int handle, fd, ret, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100529 u_int64_t off;
530
531 id = get_int();
532 handle = get_handle();
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000533 off = get_int64();
Damien Miller7b28dc52000-09-05 13:34:53 +1100534 len = get_int();
535
Damien Millerfef95ad2006-07-10 20:46:55 +1000536 debug("request %u: read \"%s\" (handle %d) off %llu len %d",
537 id, handle_to_name(handle), handle, (unsigned long long)off, len);
Damien Miller7b28dc52000-09-05 13:34:53 +1100538 if (len > sizeof buf) {
539 len = sizeof buf;
Damien Millerfef95ad2006-07-10 20:46:55 +1000540 debug2("read change len %d", len);
Damien Miller7b28dc52000-09-05 13:34:53 +1100541 }
542 fd = handle_to_fd(handle);
543 if (fd >= 0) {
544 if (lseek(fd, off, SEEK_SET) < 0) {
545 error("process_read: seek failed");
546 status = errno_to_portable(errno);
547 } else {
548 ret = read(fd, buf, len);
549 if (ret < 0) {
550 status = errno_to_portable(errno);
551 } else if (ret == 0) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000552 status = SSH2_FX_EOF;
Damien Miller7b28dc52000-09-05 13:34:53 +1100553 } else {
554 send_data(id, buf, ret);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000555 status = SSH2_FX_OK;
Damien Millerfef95ad2006-07-10 20:46:55 +1000556 handle_update_read(handle, ret);
Damien Miller7b28dc52000-09-05 13:34:53 +1100557 }
558 }
559 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000560 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100561 send_status(id, status);
562}
563
Ben Lindstrombba81212001-06-25 05:01:22 +0000564static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100565process_write(void)
566{
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000567 u_int32_t id;
Damien Miller7b28dc52000-09-05 13:34:53 +1100568 u_int64_t off;
Damien Millere4340be2000-09-16 13:29:08 +1100569 u_int len;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000570 int handle, fd, ret, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100571 char *data;
572
573 id = get_int();
574 handle = get_handle();
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000575 off = get_int64();
Damien Miller7b28dc52000-09-05 13:34:53 +1100576 data = get_string(&len);
577
Damien Millerfef95ad2006-07-10 20:46:55 +1000578 debug("request %u: write \"%s\" (handle %d) off %llu len %d",
579 id, handle_to_name(handle), handle, (unsigned long long)off, len);
Damien Miller7b28dc52000-09-05 13:34:53 +1100580 fd = handle_to_fd(handle);
581 if (fd >= 0) {
582 if (lseek(fd, off, SEEK_SET) < 0) {
583 status = errno_to_portable(errno);
584 error("process_write: seek failed");
585 } else {
586/* XXX ATOMICIO ? */
587 ret = write(fd, data, len);
Damien Millereccb9de2005-06-17 12:59:34 +1000588 if (ret < 0) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100589 error("process_write: write failed");
590 status = errno_to_portable(errno);
Damien Millereccb9de2005-06-17 12:59:34 +1000591 } else if ((size_t)ret == len) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000592 status = SSH2_FX_OK;
Damien Millerfef95ad2006-07-10 20:46:55 +1000593 handle_update_write(handle, ret);
Damien Miller7b28dc52000-09-05 13:34:53 +1100594 } else {
Damien Millerfef95ad2006-07-10 20:46:55 +1000595 debug2("nothing at all written");
Damien Miller7b28dc52000-09-05 13:34:53 +1100596 }
597 }
598 }
599 send_status(id, status);
600 xfree(data);
601}
602
Ben Lindstrombba81212001-06-25 05:01:22 +0000603static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100604process_do_stat(int do_lstat)
605{
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000606 Attrib a;
Damien Miller7b28dc52000-09-05 13:34:53 +1100607 struct stat st;
608 u_int32_t id;
609 char *name;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000610 int ret, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100611
612 id = get_int();
613 name = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000614 debug3("request %u: %sstat", id, do_lstat ? "l" : "");
615 verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100616 ret = do_lstat ? lstat(name, &st) : stat(name, &st);
617 if (ret < 0) {
618 status = errno_to_portable(errno);
619 } else {
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000620 stat_to_attrib(&st, &a);
621 send_attrib(id, &a);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000622 status = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100623 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000624 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100625 send_status(id, status);
626 xfree(name);
627}
628
Ben Lindstrombba81212001-06-25 05:01:22 +0000629static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100630process_stat(void)
631{
632 process_do_stat(0);
633}
634
Ben Lindstrombba81212001-06-25 05:01:22 +0000635static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100636process_lstat(void)
637{
638 process_do_stat(1);
639}
640
Ben Lindstrombba81212001-06-25 05:01:22 +0000641static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100642process_fstat(void)
643{
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000644 Attrib a;
Damien Miller7b28dc52000-09-05 13:34:53 +1100645 struct stat st;
646 u_int32_t id;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000647 int fd, ret, handle, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100648
649 id = get_int();
650 handle = get_handle();
Damien Millerfef95ad2006-07-10 20:46:55 +1000651 debug("request %u: fstat \"%s\" (handle %u)",
652 id, handle_to_name(handle), handle);
Damien Miller7b28dc52000-09-05 13:34:53 +1100653 fd = handle_to_fd(handle);
654 if (fd >= 0) {
655 ret = fstat(fd, &st);
656 if (ret < 0) {
657 status = errno_to_portable(errno);
658 } else {
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000659 stat_to_attrib(&st, &a);
660 send_attrib(id, &a);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000661 status = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100662 }
663 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000664 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100665 send_status(id, status);
666}
667
Ben Lindstrombba81212001-06-25 05:01:22 +0000668static struct timeval *
Damien Millerf58b58c2003-11-17 21:18:23 +1100669attrib_to_tv(const Attrib *a)
Damien Miller7b28dc52000-09-05 13:34:53 +1100670{
671 static struct timeval tv[2];
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000672
Damien Miller7b28dc52000-09-05 13:34:53 +1100673 tv[0].tv_sec = a->atime;
674 tv[0].tv_usec = 0;
675 tv[1].tv_sec = a->mtime;
676 tv[1].tv_usec = 0;
677 return tv;
678}
679
Ben Lindstrombba81212001-06-25 05:01:22 +0000680static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100681process_setstat(void)
682{
683 Attrib *a;
684 u_int32_t id;
685 char *name;
Ben Lindstromb1f483f2002-06-23 21:27:18 +0000686 int status = SSH2_FX_OK, ret;
Damien Miller7b28dc52000-09-05 13:34:53 +1100687
688 id = get_int();
689 name = get_string(NULL);
690 a = get_attrib();
Damien Millerfef95ad2006-07-10 20:46:55 +1000691 debug("request %u: setstat name \"%s\"", id, name);
Damien Miller00c92172002-02-13 14:05:00 +1100692 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000693 logit("set \"%s\" size %llu", name, a->size);
Damien Miller00c92172002-02-13 14:05:00 +1100694 ret = truncate(name, a->size);
695 if (ret == -1)
696 status = errno_to_portable(errno);
697 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000698 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000699 logit("set \"%s\" mode %04o", name, a->perm);
Damien Miller7b28dc52000-09-05 13:34:53 +1100700 ret = chmod(name, a->perm & 0777);
701 if (ret == -1)
702 status = errno_to_portable(errno);
703 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000704 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000705 char buf[64];
706 time_t t = a->mtime;
707
708 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
709 localtime(&t));
710 logit("set \"%s\" modtime %s", name, buf);
Damien Miller7b28dc52000-09-05 13:34:53 +1100711 ret = utimes(name, attrib_to_tv(a));
712 if (ret == -1)
713 status = errno_to_portable(errno);
714 }
Kevin Steves8e743932001-02-05 13:24:35 +0000715 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000716 logit("set \"%s\" owner %lu group %lu", name,
717 (u_long)a->uid, (u_long)a->gid);
Kevin Steves8e743932001-02-05 13:24:35 +0000718 ret = chown(name, a->uid, a->gid);
719 if (ret == -1)
720 status = errno_to_portable(errno);
721 }
Damien Miller7b28dc52000-09-05 13:34:53 +1100722 send_status(id, status);
723 xfree(name);
724}
725
Ben Lindstrombba81212001-06-25 05:01:22 +0000726static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100727process_fsetstat(void)
728{
729 Attrib *a;
730 u_int32_t id;
731 int handle, fd, ret;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000732 int status = SSH2_FX_OK;
Kevin Stevesf7ffab32001-01-24 20:11:06 +0000733
Damien Miller7b28dc52000-09-05 13:34:53 +1100734 id = get_int();
735 handle = get_handle();
736 a = get_attrib();
Damien Millerfef95ad2006-07-10 20:46:55 +1000737 debug("request %u: fsetstat handle %d", id, handle);
Damien Miller7b28dc52000-09-05 13:34:53 +1100738 fd = handle_to_fd(handle);
Damien Millerfef95ad2006-07-10 20:46:55 +1000739 if (fd < 0) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000740 status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100741 } else {
Damien Millerfef95ad2006-07-10 20:46:55 +1000742 char *name = handle_to_name(handle);
743
Damien Miller00c92172002-02-13 14:05:00 +1100744 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000745 logit("set \"%s\" size %llu", name, a->size);
Damien Miller00c92172002-02-13 14:05:00 +1100746 ret = ftruncate(fd, a->size);
747 if (ret == -1)
748 status = errno_to_portable(errno);
749 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000750 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000751 logit("set \"%s\" mode %04o", name, a->perm);
Ben Lindstrom200e3c92001-01-15 01:56:46 +0000752#ifdef HAVE_FCHMOD
Damien Miller7b28dc52000-09-05 13:34:53 +1100753 ret = fchmod(fd, a->perm & 0777);
Ben Lindstrom200e3c92001-01-15 01:56:46 +0000754#else
Kevin Stevesb6b37ba2001-01-24 20:01:44 +0000755 ret = chmod(name, a->perm & 0777);
Ben Lindstrom200e3c92001-01-15 01:56:46 +0000756#endif
Damien Miller7b28dc52000-09-05 13:34:53 +1100757 if (ret == -1)
758 status = errno_to_portable(errno);
759 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000760 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000761 char buf[64];
762 time_t t = a->mtime;
763
764 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
765 localtime(&t));
766 logit("set \"%s\" modtime %s", name, buf);
Damien Miller7b28dc52000-09-05 13:34:53 +1100767#ifdef HAVE_FUTIMES
768 ret = futimes(fd, attrib_to_tv(a));
769#else
770 ret = utimes(name, attrib_to_tv(a));
771#endif
772 if (ret == -1)
773 status = errno_to_portable(errno);
774 }
Kevin Steves8e743932001-02-05 13:24:35 +0000775 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000776 logit("set \"%s\" owner %lu group %lu", name,
777 (u_long)a->uid, (u_long)a->gid);
Ben Lindstrom34bb0c72001-02-13 02:40:56 +0000778#ifdef HAVE_FCHOWN
Kevin Steves8e743932001-02-05 13:24:35 +0000779 ret = fchown(fd, a->uid, a->gid);
Ben Lindstrom34bb0c72001-02-13 02:40:56 +0000780#else
781 ret = chown(name, a->uid, a->gid);
782#endif
Kevin Steves8e743932001-02-05 13:24:35 +0000783 if (ret == -1)
784 status = errno_to_portable(errno);
785 }
Damien Miller7b28dc52000-09-05 13:34:53 +1100786 }
787 send_status(id, status);
788}
789
Ben Lindstrombba81212001-06-25 05:01:22 +0000790static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100791process_opendir(void)
792{
793 DIR *dirp = NULL;
794 char *path;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000795 int handle, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100796 u_int32_t id;
797
798 id = get_int();
799 path = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000800 debug3("request %u: opendir", id);
801 logit("opendir \"%s\"", path);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000802 dirp = opendir(path);
Damien Miller7b28dc52000-09-05 13:34:53 +1100803 if (dirp == NULL) {
804 status = errno_to_portable(errno);
805 } else {
Damien Miller00111382003-03-10 11:21:17 +1100806 handle = handle_new(HANDLE_DIR, path, 0, dirp);
Damien Miller7b28dc52000-09-05 13:34:53 +1100807 if (handle < 0) {
808 closedir(dirp);
809 } else {
810 send_handle(id, handle);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000811 status = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100812 }
Kevin Stevesef4eea92001-02-05 12:42:17 +0000813
Damien Miller7b28dc52000-09-05 13:34:53 +1100814 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000815 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100816 send_status(id, status);
817 xfree(path);
818}
819
Ben Lindstrombba81212001-06-25 05:01:22 +0000820static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100821process_readdir(void)
822{
823 DIR *dirp;
824 struct dirent *dp;
825 char *path;
826 int handle;
827 u_int32_t id;
828
829 id = get_int();
830 handle = get_handle();
Damien Millerfef95ad2006-07-10 20:46:55 +1000831 debug("request %u: readdir \"%s\" (handle %d)", id,
832 handle_to_name(handle), handle);
Damien Miller7b28dc52000-09-05 13:34:53 +1100833 dirp = handle_to_dir(handle);
834 path = handle_to_name(handle);
835 if (dirp == NULL || path == NULL) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000836 send_status(id, SSH2_FX_FAILURE);
Damien Miller7b28dc52000-09-05 13:34:53 +1100837 } else {
Damien Miller7b28dc52000-09-05 13:34:53 +1100838 struct stat st;
Damien Millerfef95ad2006-07-10 20:46:55 +1000839 char pathname[MAXPATHLEN];
Damien Miller7b28dc52000-09-05 13:34:53 +1100840 Stat *stats;
841 int nstats = 10, count = 0, i;
Ben Lindstromb1f483f2002-06-23 21:27:18 +0000842
Damien Miller07d86be2006-03-26 14:19:21 +1100843 stats = xcalloc(nstats, sizeof(Stat));
Damien Miller7b28dc52000-09-05 13:34:53 +1100844 while ((dp = readdir(dirp)) != NULL) {
845 if (count >= nstats) {
846 nstats *= 2;
Damien Miller36812092006-03-26 14:22:47 +1100847 stats = xrealloc(stats, nstats, sizeof(Stat));
Damien Miller7b28dc52000-09-05 13:34:53 +1100848 }
849/* XXX OVERFLOW ? */
Ben Lindstrom95148e32001-08-06 21:30:53 +0000850 snprintf(pathname, sizeof pathname, "%s%s%s", path,
851 strcmp(path, "/") ? "/" : "", dp->d_name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100852 if (lstat(pathname, &st) < 0)
853 continue;
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000854 stat_to_attrib(&st, &(stats[count].attrib));
Damien Miller7b28dc52000-09-05 13:34:53 +1100855 stats[count].name = xstrdup(dp->d_name);
Damien Millere1a49812002-09-12 09:54:25 +1000856 stats[count].long_name = ls_file(dp->d_name, &st, 0);
Damien Miller7b28dc52000-09-05 13:34:53 +1100857 count++;
858 /* send up to 100 entries in one message */
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000859 /* XXX check packet size instead */
Damien Miller7b28dc52000-09-05 13:34:53 +1100860 if (count == 100)
861 break;
862 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000863 if (count > 0) {
864 send_names(id, count, stats);
Damien Miller9f0f5c62001-12-21 14:45:46 +1100865 for (i = 0; i < count; i++) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000866 xfree(stats[i].name);
867 xfree(stats[i].long_name);
868 }
869 } else {
870 send_status(id, SSH2_FX_EOF);
Damien Miller7b28dc52000-09-05 13:34:53 +1100871 }
872 xfree(stats);
873 }
874}
875
Ben Lindstrombba81212001-06-25 05:01:22 +0000876static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100877process_remove(void)
878{
879 char *name;
880 u_int32_t id;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000881 int status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100882 int ret;
883
884 id = get_int();
885 name = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000886 debug3("request %u: remove", id);
887 logit("remove name \"%s\"", name);
Kevin Stevesa074feb2000-12-21 22:33:45 +0000888 ret = unlink(name);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000889 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100890 send_status(id, status);
891 xfree(name);
892}
893
Ben Lindstrombba81212001-06-25 05:01:22 +0000894static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100895process_mkdir(void)
896{
897 Attrib *a;
898 u_int32_t id;
899 char *name;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000900 int ret, mode, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100901
902 id = get_int();
903 name = get_string(NULL);
904 a = get_attrib();
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000905 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
906 a->perm & 0777 : 0777;
Damien Millerfef95ad2006-07-10 20:46:55 +1000907 debug3("request %u: mkdir", id);
908 logit("mkdir name \"%s\" mode 0%o", name, mode);
Damien Miller7b28dc52000-09-05 13:34:53 +1100909 ret = mkdir(name, mode);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000910 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100911 send_status(id, status);
912 xfree(name);
913}
914
Ben Lindstrombba81212001-06-25 05:01:22 +0000915static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100916process_rmdir(void)
917{
918 u_int32_t id;
919 char *name;
920 int ret, status;
921
922 id = get_int();
923 name = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000924 debug3("request %u: rmdir", id);
925 logit("rmdir name \"%s\"", name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100926 ret = rmdir(name);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000927 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100928 send_status(id, status);
929 xfree(name);
930}
931
Ben Lindstrombba81212001-06-25 05:01:22 +0000932static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100933process_realpath(void)
934{
935 char resolvedname[MAXPATHLEN];
936 u_int32_t id;
937 char *path;
938
939 id = get_int();
940 path = get_string(NULL);
Ben Lindstromfa1b3d02000-12-10 01:55:37 +0000941 if (path[0] == '\0') {
942 xfree(path);
943 path = xstrdup(".");
944 }
Damien Millerfef95ad2006-07-10 20:46:55 +1000945 debug3("request %u: realpath", id);
946 verbose("realpath \"%s\"", path);
Damien Miller7b28dc52000-09-05 13:34:53 +1100947 if (realpath(path, resolvedname) == NULL) {
948 send_status(id, errno_to_portable(errno));
949 } else {
950 Stat s;
951 attrib_clear(&s.attrib);
952 s.name = s.long_name = resolvedname;
953 send_names(id, 1, &s);
954 }
955 xfree(path);
956}
957
Ben Lindstrombba81212001-06-25 05:01:22 +0000958static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100959process_rename(void)
960{
961 u_int32_t id;
962 char *oldpath, *newpath;
Damien Miller9e51a732003-02-24 11:58:44 +1100963 int status;
Damien Millerb3207e82003-03-26 16:01:11 +1100964 struct stat sb;
Damien Miller7b28dc52000-09-05 13:34:53 +1100965
966 id = get_int();
967 oldpath = get_string(NULL);
968 newpath = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000969 debug3("request %u: rename", id);
970 logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
Damien Millerb3207e82003-03-26 16:01:11 +1100971 status = SSH2_FX_FAILURE;
972 if (lstat(oldpath, &sb) == -1)
Damien Miller9e51a732003-02-24 11:58:44 +1100973 status = errno_to_portable(errno);
Damien Millerb3207e82003-03-26 16:01:11 +1100974 else if (S_ISREG(sb.st_mode)) {
975 /* Race-free rename of regular files */
Darren Tuckeraedc1d62004-06-25 17:06:02 +1000976 if (link(oldpath, newpath) == -1) {
Darren Tuckere59b5082004-06-28 16:01:19 +1000977 if (errno == EOPNOTSUPP
978#ifdef LINK_OPNOTSUPP_ERRNO
979 || errno == LINK_OPNOTSUPP_ERRNO
980#endif
981 ) {
Darren Tuckeraedc1d62004-06-25 17:06:02 +1000982 struct stat st;
983
984 /*
985 * fs doesn't support links, so fall back to
986 * stat+rename. This is racy.
987 */
988 if (stat(newpath, &st) == -1) {
989 if (rename(oldpath, newpath) == -1)
990 status =
991 errno_to_portable(errno);
992 else
993 status = SSH2_FX_OK;
994 }
995 } else {
996 status = errno_to_portable(errno);
997 }
998 } else if (unlink(oldpath) == -1) {
Damien Millerb3207e82003-03-26 16:01:11 +1100999 status = errno_to_portable(errno);
1000 /* clean spare link */
1001 unlink(newpath);
1002 } else
1003 status = SSH2_FX_OK;
1004 } else if (stat(newpath, &sb) == -1) {
1005 if (rename(oldpath, newpath) == -1)
1006 status = errno_to_portable(errno);
1007 else
1008 status = SSH2_FX_OK;
1009 }
Damien Miller7b28dc52000-09-05 13:34:53 +11001010 send_status(id, status);
1011 xfree(oldpath);
1012 xfree(newpath);
1013}
1014
Ben Lindstrombba81212001-06-25 05:01:22 +00001015static void
Damien Miller058316f2001-03-08 10:08:49 +11001016process_readlink(void)
1017{
1018 u_int32_t id;
Ben Lindstromabbb73d2001-05-17 03:14:57 +00001019 int len;
Darren Tucker3f9fdc72004-06-22 12:56:01 +10001020 char buf[MAXPATHLEN];
Damien Miller058316f2001-03-08 10:08:49 +11001021 char *path;
1022
1023 id = get_int();
1024 path = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +10001025 debug3("request %u: readlink", id);
1026 verbose("readlink \"%s\"", path);
Darren Tucker3f9fdc72004-06-22 12:56:01 +10001027 if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
Damien Miller058316f2001-03-08 10:08:49 +11001028 send_status(id, errno_to_portable(errno));
1029 else {
1030 Stat s;
Damien Miller9f0f5c62001-12-21 14:45:46 +11001031
Darren Tucker3f9fdc72004-06-22 12:56:01 +10001032 buf[len] = '\0';
Damien Miller058316f2001-03-08 10:08:49 +11001033 attrib_clear(&s.attrib);
Darren Tucker3f9fdc72004-06-22 12:56:01 +10001034 s.name = s.long_name = buf;
Damien Miller058316f2001-03-08 10:08:49 +11001035 send_names(id, 1, &s);
1036 }
1037 xfree(path);
1038}
1039
Ben Lindstrombba81212001-06-25 05:01:22 +00001040static void
Damien Miller058316f2001-03-08 10:08:49 +11001041process_symlink(void)
1042{
1043 u_int32_t id;
Damien Miller058316f2001-03-08 10:08:49 +11001044 char *oldpath, *newpath;
Damien Miller9e51a732003-02-24 11:58:44 +11001045 int ret, status;
Damien Miller058316f2001-03-08 10:08:49 +11001046
1047 id = get_int();
1048 oldpath = get_string(NULL);
1049 newpath = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +10001050 debug3("request %u: symlink", id);
1051 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
Damien Miller9e51a732003-02-24 11:58:44 +11001052 /* this will fail if 'newpath' exists */
1053 ret = symlink(oldpath, newpath);
1054 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller058316f2001-03-08 10:08:49 +11001055 send_status(id, status);
1056 xfree(oldpath);
1057 xfree(newpath);
1058}
1059
Ben Lindstrombba81212001-06-25 05:01:22 +00001060static void
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001061process_extended(void)
1062{
1063 u_int32_t id;
1064 char *request;
1065
1066 id = get_int();
1067 request = get_string(NULL);
1068 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
1069 xfree(request);
1070}
Damien Miller7b28dc52000-09-05 13:34:53 +11001071
1072/* stolen from ssh-agent */
1073
Ben Lindstrombba81212001-06-25 05:01:22 +00001074static void
Damien Miller7b28dc52000-09-05 13:34:53 +11001075process(void)
1076{
Ben Lindstrom46c16222000-12-22 01:43:59 +00001077 u_int msg_len;
Ben Lindstrom2c140472002-06-06 21:57:54 +00001078 u_int buf_len;
1079 u_int consumed;
Ben Lindstrom46c16222000-12-22 01:43:59 +00001080 u_int type;
1081 u_char *cp;
Damien Miller7b28dc52000-09-05 13:34:53 +11001082
Ben Lindstrom2c140472002-06-06 21:57:54 +00001083 buf_len = buffer_len(&iqueue);
1084 if (buf_len < 5)
Damien Miller7b28dc52000-09-05 13:34:53 +11001085 return; /* Incomplete message. */
Damien Miller708d21c2002-01-22 23:18:15 +11001086 cp = buffer_ptr(&iqueue);
Damien Miller3f941882006-03-31 23:13:02 +11001087 msg_len = get_u32(cp);
Damien Miller54446182006-01-02 23:40:50 +11001088 if (msg_len > SFTP_MAX_MSG_LENGTH) {
Damien Millerfef95ad2006-07-10 20:46:55 +10001089 error("bad message from %s local user %s",
1090 client_addr, pw->pw_name);
1091 cleanup_exit(11);
Damien Miller7b28dc52000-09-05 13:34:53 +11001092 }
Ben Lindstrom2c140472002-06-06 21:57:54 +00001093 if (buf_len < msg_len + 4)
Damien Miller7b28dc52000-09-05 13:34:53 +11001094 return;
1095 buffer_consume(&iqueue, 4);
Ben Lindstrom2c140472002-06-06 21:57:54 +00001096 buf_len -= 4;
Damien Miller7b28dc52000-09-05 13:34:53 +11001097 type = buffer_get_char(&iqueue);
1098 switch (type) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001099 case SSH2_FXP_INIT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001100 process_init();
1101 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001102 case SSH2_FXP_OPEN:
Damien Miller7b28dc52000-09-05 13:34:53 +11001103 process_open();
1104 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001105 case SSH2_FXP_CLOSE:
Damien Miller7b28dc52000-09-05 13:34:53 +11001106 process_close();
1107 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001108 case SSH2_FXP_READ:
Damien Miller7b28dc52000-09-05 13:34:53 +11001109 process_read();
1110 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001111 case SSH2_FXP_WRITE:
Damien Miller7b28dc52000-09-05 13:34:53 +11001112 process_write();
1113 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001114 case SSH2_FXP_LSTAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001115 process_lstat();
1116 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001117 case SSH2_FXP_FSTAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001118 process_fstat();
1119 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001120 case SSH2_FXP_SETSTAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001121 process_setstat();
1122 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001123 case SSH2_FXP_FSETSTAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001124 process_fsetstat();
1125 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001126 case SSH2_FXP_OPENDIR:
Damien Miller7b28dc52000-09-05 13:34:53 +11001127 process_opendir();
1128 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001129 case SSH2_FXP_READDIR:
Damien Miller7b28dc52000-09-05 13:34:53 +11001130 process_readdir();
1131 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001132 case SSH2_FXP_REMOVE:
Damien Miller7b28dc52000-09-05 13:34:53 +11001133 process_remove();
1134 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001135 case SSH2_FXP_MKDIR:
Damien Miller7b28dc52000-09-05 13:34:53 +11001136 process_mkdir();
1137 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001138 case SSH2_FXP_RMDIR:
Damien Miller7b28dc52000-09-05 13:34:53 +11001139 process_rmdir();
1140 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001141 case SSH2_FXP_REALPATH:
Damien Miller7b28dc52000-09-05 13:34:53 +11001142 process_realpath();
1143 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001144 case SSH2_FXP_STAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001145 process_stat();
1146 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001147 case SSH2_FXP_RENAME:
Damien Miller7b28dc52000-09-05 13:34:53 +11001148 process_rename();
1149 break;
Damien Miller058316f2001-03-08 10:08:49 +11001150 case SSH2_FXP_READLINK:
1151 process_readlink();
1152 break;
1153 case SSH2_FXP_SYMLINK:
1154 process_symlink();
1155 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001156 case SSH2_FXP_EXTENDED:
1157 process_extended();
1158 break;
Damien Miller7b28dc52000-09-05 13:34:53 +11001159 default:
1160 error("Unknown message %d", type);
1161 break;
1162 }
Ben Lindstrom2c140472002-06-06 21:57:54 +00001163 /* discard the remaining bytes from the current packet */
1164 if (buf_len < buffer_len(&iqueue))
Damien Millerfef95ad2006-07-10 20:46:55 +10001165 fatal("iqueue grew unexpectedly");
Ben Lindstrom2c140472002-06-06 21:57:54 +00001166 consumed = buf_len - buffer_len(&iqueue);
1167 if (msg_len < consumed)
1168 fatal("msg_len %d < consumed %d", msg_len, consumed);
1169 if (msg_len > consumed)
1170 buffer_consume(&iqueue, msg_len - consumed);
Damien Miller7b28dc52000-09-05 13:34:53 +11001171}
1172
Damien Millerfef95ad2006-07-10 20:46:55 +10001173/* Cleanup handler that logs active handles upon normal exit */
1174void
1175cleanup_exit(int i)
1176{
1177 if (pw != NULL && client_addr != NULL) {
1178 handle_log_exit();
1179 logit("session closed for local user %s from [%s]",
1180 pw->pw_name, client_addr);
1181 }
1182 _exit(i);
1183}
1184
1185static void
1186usage(void)
1187{
1188 extern char *__progname;
1189
1190 fprintf(stderr,
1191 "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
1192 exit(1);
1193}
1194
Damien Miller7b28dc52000-09-05 13:34:53 +11001195int
Damien Millerfef95ad2006-07-10 20:46:55 +10001196main(int argc, char **argv)
Damien Miller7b28dc52000-09-05 13:34:53 +11001197{
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001198 fd_set *rset, *wset;
Damien Millerfef95ad2006-07-10 20:46:55 +10001199 int in, out, max, ch, skipargs = 0, log_stderr = 0;
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001200 ssize_t len, olen, set_size;
Damien Millerfef95ad2006-07-10 20:46:55 +10001201 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1202 char *cp;
1203
1204 extern int optind;
1205 extern char *optarg;
1206 extern char *__progname;
Damien Miller7b28dc52000-09-05 13:34:53 +11001207
Darren Tuckerce321d82005-10-03 18:11:24 +10001208 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1209 sanitise_stdfd();
1210
Damien Millerfef95ad2006-07-10 20:46:55 +10001211 __progname = ssh_get_progname(argv[0]);
1212 log_init(__progname, log_level, log_facility, log_stderr);
Ben Lindstromc7f4ccd2001-03-15 00:09:15 +00001213
Damien Millerfef95ad2006-07-10 20:46:55 +10001214 while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
1215 switch (ch) {
1216 case 'c':
1217 /*
1218 * Ignore all arguments if we are invoked as a
1219 * shell using "sftp-server -c command"
1220 */
1221 skipargs = 1;
1222 break;
1223 case 'e':
1224 log_stderr = 1;
1225 break;
1226 case 'l':
1227 log_level = log_level_number(optarg);
1228 if (log_level == SYSLOG_LEVEL_NOT_SET)
1229 error("Invalid log level \"%s\"", optarg);
1230 break;
1231 case 'f':
1232 log_facility = log_facility_number(optarg);
1233 if (log_level == SYSLOG_FACILITY_NOT_SET)
1234 error("Invalid log facility \"%s\"", optarg);
1235 break;
1236 case 'h':
1237 default:
1238 usage();
1239 }
1240 }
1241
1242 log_init(__progname, log_level, log_facility, log_stderr);
1243
1244 if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1245 client_addr = xstrdup(cp);
1246 if ((cp = strchr(client_addr, ' ')) == NULL)
1247 fatal("Malformed SSH_CONNECTION variable: \"%s\"",
1248 getenv("SSH_CONNECTION"));
1249 *cp = '\0';
1250 } else
1251 client_addr = xstrdup("UNKNOWN");
1252
1253 if ((pw = getpwuid(getuid())) == NULL)
1254 fatal("No user found for uid %lu", (u_long)getuid());
1255 pw = pwcopy(pw);
1256
1257 logit("session opened for local user %s from [%s]",
1258 pw->pw_name, client_addr);
1259
Damien Miller7b28dc52000-09-05 13:34:53 +11001260 handle_init();
1261
Damien Miller7b28dc52000-09-05 13:34:53 +11001262 in = dup(STDIN_FILENO);
1263 out = dup(STDOUT_FILENO);
1264
Damien Miller402b3312001-04-14 00:28:42 +10001265#ifdef HAVE_CYGWIN
1266 setmode(in, O_BINARY);
1267 setmode(out, O_BINARY);
1268#endif
1269
Damien Miller7b28dc52000-09-05 13:34:53 +11001270 max = 0;
1271 if (in > max)
1272 max = in;
1273 if (out > max)
1274 max = out;
1275
1276 buffer_init(&iqueue);
1277 buffer_init(&oqueue);
1278
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001279 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1280 rset = (fd_set *)xmalloc(set_size);
1281 wset = (fd_set *)xmalloc(set_size);
Damien Miller7b28dc52000-09-05 13:34:53 +11001282
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001283 for (;;) {
1284 memset(rset, 0, set_size);
1285 memset(wset, 0, set_size);
1286
1287 FD_SET(in, rset);
Damien Miller7b28dc52000-09-05 13:34:53 +11001288 olen = buffer_len(&oqueue);
1289 if (olen > 0)
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001290 FD_SET(out, wset);
Damien Miller7b28dc52000-09-05 13:34:53 +11001291
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001292 if (select(max+1, rset, wset, NULL, NULL) < 0) {
Damien Miller7b28dc52000-09-05 13:34:53 +11001293 if (errno == EINTR)
1294 continue;
Damien Millerfef95ad2006-07-10 20:46:55 +10001295 error("select: %s", strerror(errno));
1296 cleanup_exit(2);
Damien Miller7b28dc52000-09-05 13:34:53 +11001297 }
1298
1299 /* copy stdin to iqueue */
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001300 if (FD_ISSET(in, rset)) {
Damien Miller7b28dc52000-09-05 13:34:53 +11001301 char buf[4*4096];
1302 len = read(in, buf, sizeof buf);
1303 if (len == 0) {
1304 debug("read eof");
Damien Millerfef95ad2006-07-10 20:46:55 +10001305 cleanup_exit(0);
Damien Miller7b28dc52000-09-05 13:34:53 +11001306 } else if (len < 0) {
Damien Millerfef95ad2006-07-10 20:46:55 +10001307 error("read: %s", strerror(errno));
1308 cleanup_exit(1);
Damien Miller7b28dc52000-09-05 13:34:53 +11001309 } else {
1310 buffer_append(&iqueue, buf, len);
1311 }
1312 }
1313 /* send oqueue to stdout */
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001314 if (FD_ISSET(out, wset)) {
Damien Miller7b28dc52000-09-05 13:34:53 +11001315 len = write(out, buffer_ptr(&oqueue), olen);
1316 if (len < 0) {
Damien Millerfef95ad2006-07-10 20:46:55 +10001317 error("write: %s", strerror(errno));
1318 cleanup_exit(1);
Damien Miller7b28dc52000-09-05 13:34:53 +11001319 } else {
1320 buffer_consume(&oqueue, len);
1321 }
1322 }
1323 /* process requests from client */
1324 process();
1325 }
1326}