blob: 3c254e3324b0764eb07ca95917d8c20872316f4f [file] [log] [blame]
Damien Miller5598b4f2006-07-24 14:09:40 +10001/* $OpenBSD: sftp-server.c,v 1.64 2006/07/22 19:08:54 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>
Darren Tucker39972492006-07-12 22:22:46 +100023#include <errno.h>
Damien Miller57cf6382006-07-10 21:13:46 +100024#include <fcntl.h>
Damien Miller9f2abc42006-07-10 20:53:08 +100025#include <pwd.h>
Damien Millere6b3b612006-07-24 14:01:23 +100026#include <unistd.h>
Damien Miller5598b4f2006-07-24 14:09:40 +100027#include <time.h>
Damien Miller7b28dc52000-09-05 13:34:53 +110028
Damien Miller7b28dc52000-09-05 13:34:53 +110029#include "buffer.h"
30#include "bufaux.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000031#include "log.h"
Damien Miller7b28dc52000-09-05 13:34:53 +110032#include "xmalloc.h"
Darren Tuckerce321d82005-10-03 18:11:24 +100033#include "misc.h"
Damien Millerfef95ad2006-07-10 20:46:55 +100034#include "uidswap.h"
Damien Miller7b28dc52000-09-05 13:34:53 +110035
Ben Lindstrom2f959b42001-01-11 06:20:23 +000036#include "sftp.h"
Damien Miller33804262001-02-04 23:20:18 +110037#include "sftp-common.h"
Damien Miller7b28dc52000-09-05 13:34:53 +110038
39/* helper */
Ben Lindstrom2f959b42001-01-11 06:20:23 +000040#define get_int64() buffer_get_int64(&iqueue);
Damien Miller7b28dc52000-09-05 13:34:53 +110041#define get_int() buffer_get_int(&iqueue);
42#define get_string(lenp) buffer_get_string(&iqueue, lenp);
Damien Miller7b28dc52000-09-05 13:34:53 +110043
Damien Millerfef95ad2006-07-10 20:46:55 +100044/* Our verbosity */
45LogLevel log_level = SYSLOG_LEVEL_ERROR;
46
47/* Our client */
48struct passwd *pw = NULL;
49char *client_addr = NULL;
Ben Lindstrom49a79c02000-11-17 03:47:20 +000050
Damien Miller7b28dc52000-09-05 13:34:53 +110051/* input and output queue */
52Buffer iqueue;
53Buffer oqueue;
54
Damien Miller058316f2001-03-08 10:08:49 +110055/* Version of client */
56int version;
57
Darren Tuckera6612d42003-06-28 12:39:03 +100058/* portable attributes, etc. */
Damien Miller7b28dc52000-09-05 13:34:53 +110059
Damien Miller7b28dc52000-09-05 13:34:53 +110060typedef struct Stat Stat;
61
Damien Miller33804262001-02-04 23:20:18 +110062struct Stat {
Damien Miller7b28dc52000-09-05 13:34:53 +110063 char *name;
64 char *long_name;
65 Attrib attrib;
66};
67
Ben Lindstrombba81212001-06-25 05:01:22 +000068static int
Damien Miller7b28dc52000-09-05 13:34:53 +110069errno_to_portable(int unixerrno)
70{
71 int ret = 0;
Ben Lindstrom1addabd2001-03-05 07:09:11 +000072
Damien Miller7b28dc52000-09-05 13:34:53 +110073 switch (unixerrno) {
74 case 0:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000075 ret = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +110076 break;
77 case ENOENT:
78 case ENOTDIR:
79 case EBADF:
80 case ELOOP:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000081 ret = SSH2_FX_NO_SUCH_FILE;
Damien Miller7b28dc52000-09-05 13:34:53 +110082 break;
83 case EPERM:
84 case EACCES:
85 case EFAULT:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000086 ret = SSH2_FX_PERMISSION_DENIED;
Damien Miller7b28dc52000-09-05 13:34:53 +110087 break;
88 case ENAMETOOLONG:
89 case EINVAL:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000090 ret = SSH2_FX_BAD_MESSAGE;
Damien Miller7b28dc52000-09-05 13:34:53 +110091 break;
92 default:
Ben Lindstrom2f959b42001-01-11 06:20:23 +000093 ret = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +110094 break;
95 }
96 return ret;
97}
98
Ben Lindstrombba81212001-06-25 05:01:22 +000099static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100100flags_from_portable(int pflags)
101{
102 int flags = 0;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000103
Ben Lindstrom36592512001-03-05 05:02:08 +0000104 if ((pflags & SSH2_FXF_READ) &&
105 (pflags & SSH2_FXF_WRITE)) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100106 flags = O_RDWR;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000107 } else if (pflags & SSH2_FXF_READ) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100108 flags = O_RDONLY;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000109 } else if (pflags & SSH2_FXF_WRITE) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100110 flags = O_WRONLY;
111 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000112 if (pflags & SSH2_FXF_CREAT)
Damien Miller7b28dc52000-09-05 13:34:53 +1100113 flags |= O_CREAT;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000114 if (pflags & SSH2_FXF_TRUNC)
Damien Miller7b28dc52000-09-05 13:34:53 +1100115 flags |= O_TRUNC;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000116 if (pflags & SSH2_FXF_EXCL)
Damien Miller7b28dc52000-09-05 13:34:53 +1100117 flags |= O_EXCL;
118 return flags;
119}
120
Damien Millerfef95ad2006-07-10 20:46:55 +1000121static const char *
122string_from_portable(int pflags)
123{
124 static char ret[128];
125
126 *ret = '\0';
127
128#define PAPPEND(str) { \
129 if (*ret != '\0') \
130 strlcat(ret, ",", sizeof(ret)); \
131 strlcat(ret, str, sizeof(ret)); \
132 }
133
134 if (pflags & SSH2_FXF_READ)
135 PAPPEND("READ")
136 if (pflags & SSH2_FXF_WRITE)
137 PAPPEND("WRITE")
138 if (pflags & SSH2_FXF_CREAT)
139 PAPPEND("CREATE")
140 if (pflags & SSH2_FXF_TRUNC)
141 PAPPEND("TRUNCATE")
142 if (pflags & SSH2_FXF_EXCL)
143 PAPPEND("EXCL")
144
145 return ret;
146}
147
Ben Lindstrombba81212001-06-25 05:01:22 +0000148static Attrib *
Damien Miller7b28dc52000-09-05 13:34:53 +1100149get_attrib(void)
150{
151 return decode_attrib(&iqueue);
152}
153
154/* handle handles */
155
156typedef struct Handle Handle;
157struct Handle {
158 int use;
159 DIR *dirp;
160 int fd;
161 char *name;
Damien Millerfef95ad2006-07-10 20:46:55 +1000162 u_int64_t bytes_read, bytes_write;
Damien Miller7b28dc52000-09-05 13:34:53 +1100163};
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000164
Damien Miller7b28dc52000-09-05 13:34:53 +1100165enum {
166 HANDLE_UNUSED,
167 HANDLE_DIR,
168 HANDLE_FILE
169};
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000170
Damien Miller7b28dc52000-09-05 13:34:53 +1100171Handle handles[100];
172
Ben Lindstrombba81212001-06-25 05:01:22 +0000173static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100174handle_init(void)
175{
Damien Millereccb9de2005-06-17 12:59:34 +1000176 u_int i;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000177
Damien Miller9f0f5c62001-12-21 14:45:46 +1100178 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
Damien Miller7b28dc52000-09-05 13:34:53 +1100179 handles[i].use = HANDLE_UNUSED;
180}
181
Ben Lindstrombba81212001-06-25 05:01:22 +0000182static int
Damien Millerf58b58c2003-11-17 21:18:23 +1100183handle_new(int use, const char *name, int fd, DIR *dirp)
Damien Miller7b28dc52000-09-05 13:34:53 +1100184{
Damien Millereccb9de2005-06-17 12:59:34 +1000185 u_int i;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000186
Damien Miller9f0f5c62001-12-21 14:45:46 +1100187 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100188 if (handles[i].use == HANDLE_UNUSED) {
189 handles[i].use = use;
190 handles[i].dirp = dirp;
191 handles[i].fd = fd;
Damien Miller00111382003-03-10 11:21:17 +1100192 handles[i].name = xstrdup(name);
Damien Millerfef95ad2006-07-10 20:46:55 +1000193 handles[i].bytes_read = handles[i].bytes_write = 0;
Damien Miller7b28dc52000-09-05 13:34:53 +1100194 return i;
195 }
196 }
197 return -1;
198}
199
Ben Lindstrombba81212001-06-25 05:01:22 +0000200static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100201handle_is_ok(int i, int type)
202{
Damien Millereccb9de2005-06-17 12:59:34 +1000203 return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000204 handles[i].use == type;
Damien Miller7b28dc52000-09-05 13:34:53 +1100205}
206
Ben Lindstrombba81212001-06-25 05:01:22 +0000207static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100208handle_to_string(int handle, char **stringp, int *hlenp)
209{
Damien Miller7b28dc52000-09-05 13:34:53 +1100210 if (stringp == NULL || hlenp == NULL)
211 return -1;
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000212 *stringp = xmalloc(sizeof(int32_t));
Damien Miller3f941882006-03-31 23:13:02 +1100213 put_u32(*stringp, handle);
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000214 *hlenp = sizeof(int32_t);
Damien Miller7b28dc52000-09-05 13:34:53 +1100215 return 0;
216}
217
Ben Lindstrombba81212001-06-25 05:01:22 +0000218static int
Damien Millerf58b58c2003-11-17 21:18:23 +1100219handle_from_string(const char *handle, u_int hlen)
Damien Miller7b28dc52000-09-05 13:34:53 +1100220{
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000221 int val;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000222
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000223 if (hlen != sizeof(int32_t))
Damien Miller7b28dc52000-09-05 13:34:53 +1100224 return -1;
Damien Miller3f941882006-03-31 23:13:02 +1100225 val = get_u32(handle);
Damien Miller7b28dc52000-09-05 13:34:53 +1100226 if (handle_is_ok(val, HANDLE_FILE) ||
227 handle_is_ok(val, HANDLE_DIR))
228 return val;
229 return -1;
230}
231
Ben Lindstrombba81212001-06-25 05:01:22 +0000232static char *
Damien Miller7b28dc52000-09-05 13:34:53 +1100233handle_to_name(int handle)
234{
235 if (handle_is_ok(handle, HANDLE_DIR)||
236 handle_is_ok(handle, HANDLE_FILE))
237 return handles[handle].name;
238 return NULL;
239}
240
Ben Lindstrombba81212001-06-25 05:01:22 +0000241static DIR *
Damien Miller7b28dc52000-09-05 13:34:53 +1100242handle_to_dir(int handle)
243{
244 if (handle_is_ok(handle, HANDLE_DIR))
245 return handles[handle].dirp;
246 return NULL;
247}
248
Ben Lindstrombba81212001-06-25 05:01:22 +0000249static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100250handle_to_fd(int handle)
251{
Kevin Stevesef4eea92001-02-05 12:42:17 +0000252 if (handle_is_ok(handle, HANDLE_FILE))
Damien Miller7b28dc52000-09-05 13:34:53 +1100253 return handles[handle].fd;
254 return -1;
255}
256
Damien Millerfef95ad2006-07-10 20:46:55 +1000257static void
258handle_update_read(int handle, ssize_t bytes)
259{
260 if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
261 handles[handle].bytes_read += bytes;
262}
263
264static void
265handle_update_write(int handle, ssize_t bytes)
266{
267 if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
268 handles[handle].bytes_write += bytes;
269}
270
271static u_int64_t
272handle_bytes_read(int handle)
273{
274 if (handle_is_ok(handle, HANDLE_FILE))
275 return (handles[handle].bytes_read);
276 return 0;
277}
278
279static u_int64_t
280handle_bytes_write(int handle)
281{
282 if (handle_is_ok(handle, HANDLE_FILE))
283 return (handles[handle].bytes_write);
284 return 0;
285}
286
Ben Lindstrombba81212001-06-25 05:01:22 +0000287static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100288handle_close(int handle)
289{
290 int ret = -1;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000291
Damien Miller7b28dc52000-09-05 13:34:53 +1100292 if (handle_is_ok(handle, HANDLE_FILE)) {
293 ret = close(handles[handle].fd);
294 handles[handle].use = HANDLE_UNUSED;
Damien Miller00111382003-03-10 11:21:17 +1100295 xfree(handles[handle].name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100296 } else if (handle_is_ok(handle, HANDLE_DIR)) {
297 ret = closedir(handles[handle].dirp);
298 handles[handle].use = HANDLE_UNUSED;
Damien Miller00111382003-03-10 11:21:17 +1100299 xfree(handles[handle].name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100300 } else {
301 errno = ENOENT;
302 }
303 return ret;
304}
305
Damien Millerfef95ad2006-07-10 20:46:55 +1000306static void
307handle_log_close(int handle, char *emsg)
308{
309 if (handle_is_ok(handle, HANDLE_FILE)) {
310 logit("%s%sclose \"%s\" bytes read %llu written %llu",
311 emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
312 handle_to_name(handle),
313 handle_bytes_read(handle), handle_bytes_write(handle));
314 } else {
315 logit("%s%sclosedir \"%s\"",
316 emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
317 handle_to_name(handle));
318 }
319}
320
321static void
322handle_log_exit(void)
323{
324 u_int i;
325
326 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
327 if (handles[i].use != HANDLE_UNUSED)
328 handle_log_close(i, "forced");
329}
330
Ben Lindstrombba81212001-06-25 05:01:22 +0000331static int
Damien Miller7b28dc52000-09-05 13:34:53 +1100332get_handle(void)
333{
334 char *handle;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000335 int val = -1;
Damien Millere4340be2000-09-16 13:29:08 +1100336 u_int hlen;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000337
Damien Miller7b28dc52000-09-05 13:34:53 +1100338 handle = get_string(&hlen);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000339 if (hlen < 256)
340 val = handle_from_string(handle, hlen);
Damien Miller7b28dc52000-09-05 13:34:53 +1100341 xfree(handle);
342 return val;
343}
344
345/* send replies */
346
Ben Lindstrombba81212001-06-25 05:01:22 +0000347static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100348send_msg(Buffer *m)
349{
350 int mlen = buffer_len(m);
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000351
Damien Miller7b28dc52000-09-05 13:34:53 +1100352 buffer_put_int(&oqueue, mlen);
353 buffer_append(&oqueue, buffer_ptr(m), mlen);
354 buffer_consume(m, mlen);
355}
356
Damien Millerfef95ad2006-07-10 20:46:55 +1000357static const char *
358status_to_message(u_int32_t status)
Damien Miller7b28dc52000-09-05 13:34:53 +1100359{
Damien Miller058316f2001-03-08 10:08:49 +1100360 const char *status_messages[] = {
361 "Success", /* SSH_FX_OK */
362 "End of file", /* SSH_FX_EOF */
363 "No such file", /* SSH_FX_NO_SUCH_FILE */
364 "Permission denied", /* SSH_FX_PERMISSION_DENIED */
365 "Failure", /* SSH_FX_FAILURE */
366 "Bad message", /* SSH_FX_BAD_MESSAGE */
367 "No connection", /* SSH_FX_NO_CONNECTION */
368 "Connection lost", /* SSH_FX_CONNECTION_LOST */
369 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
370 "Unknown error" /* Others */
371 };
Damien Millerfef95ad2006-07-10 20:46:55 +1000372 return (status_messages[MIN(status,SSH2_FX_MAX)]);
373}
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000374
Damien Millerfef95ad2006-07-10 20:46:55 +1000375static void
376send_status(u_int32_t id, u_int32_t status)
377{
378 Buffer msg;
379
380 debug3("request %u: sent status %u", id, status);
381 if (log_level > SYSLOG_LEVEL_VERBOSE ||
382 (status != SSH2_FX_OK && status != SSH2_FX_EOF))
383 logit("sent status %s", status_to_message(status));
Damien Miller7b28dc52000-09-05 13:34:53 +1100384 buffer_init(&msg);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000385 buffer_put_char(&msg, SSH2_FXP_STATUS);
Damien Miller7b28dc52000-09-05 13:34:53 +1100386 buffer_put_int(&msg, id);
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000387 buffer_put_int(&msg, status);
Damien Miller058316f2001-03-08 10:08:49 +1100388 if (version >= 3) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000389 buffer_put_cstring(&msg, status_to_message(status));
Damien Miller058316f2001-03-08 10:08:49 +1100390 buffer_put_cstring(&msg, "");
391 }
Damien Miller7b28dc52000-09-05 13:34:53 +1100392 send_msg(&msg);
393 buffer_free(&msg);
394}
Ben Lindstrombba81212001-06-25 05:01:22 +0000395static void
Damien Millerf58b58c2003-11-17 21:18:23 +1100396send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
Damien Miller7b28dc52000-09-05 13:34:53 +1100397{
398 Buffer msg;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000399
Damien Miller7b28dc52000-09-05 13:34:53 +1100400 buffer_init(&msg);
401 buffer_put_char(&msg, type);
402 buffer_put_int(&msg, id);
403 buffer_put_string(&msg, data, dlen);
404 send_msg(&msg);
405 buffer_free(&msg);
406}
407
Ben Lindstrombba81212001-06-25 05:01:22 +0000408static void
Damien Millerf58b58c2003-11-17 21:18:23 +1100409send_data(u_int32_t id, const char *data, int dlen)
Damien Miller7b28dc52000-09-05 13:34:53 +1100410{
Damien Millerfef95ad2006-07-10 20:46:55 +1000411 debug("request %u: sent data len %d", id, dlen);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000412 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
Damien Miller7b28dc52000-09-05 13:34:53 +1100413}
414
Ben Lindstrombba81212001-06-25 05:01:22 +0000415static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100416send_handle(u_int32_t id, int handle)
417{
418 char *string;
419 int hlen;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000420
Damien Miller7b28dc52000-09-05 13:34:53 +1100421 handle_to_string(handle, &string, &hlen);
Damien Millerfef95ad2006-07-10 20:46:55 +1000422 debug("request %u: sent handle handle %d", id, handle);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000423 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
Damien Miller7b28dc52000-09-05 13:34:53 +1100424 xfree(string);
425}
426
Ben Lindstrombba81212001-06-25 05:01:22 +0000427static void
Damien Millerf58b58c2003-11-17 21:18:23 +1100428send_names(u_int32_t id, int count, const Stat *stats)
Damien Miller7b28dc52000-09-05 13:34:53 +1100429{
430 Buffer msg;
431 int i;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000432
Damien Miller7b28dc52000-09-05 13:34:53 +1100433 buffer_init(&msg);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000434 buffer_put_char(&msg, SSH2_FXP_NAME);
Damien Miller7b28dc52000-09-05 13:34:53 +1100435 buffer_put_int(&msg, id);
436 buffer_put_int(&msg, count);
Damien Millerfef95ad2006-07-10 20:46:55 +1000437 debug("request %u: sent names count %d", id, count);
Damien Miller7b28dc52000-09-05 13:34:53 +1100438 for (i = 0; i < count; i++) {
439 buffer_put_cstring(&msg, stats[i].name);
440 buffer_put_cstring(&msg, stats[i].long_name);
441 encode_attrib(&msg, &stats[i].attrib);
442 }
443 send_msg(&msg);
444 buffer_free(&msg);
445}
446
Ben Lindstrombba81212001-06-25 05:01:22 +0000447static void
Damien Millerf58b58c2003-11-17 21:18:23 +1100448send_attrib(u_int32_t id, const Attrib *a)
Damien Miller7b28dc52000-09-05 13:34:53 +1100449{
450 Buffer msg;
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000451
Damien Millerfef95ad2006-07-10 20:46:55 +1000452 debug("request %u: sent attrib have 0x%x", id, a->flags);
Damien Miller7b28dc52000-09-05 13:34:53 +1100453 buffer_init(&msg);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000454 buffer_put_char(&msg, SSH2_FXP_ATTRS);
Damien Miller7b28dc52000-09-05 13:34:53 +1100455 buffer_put_int(&msg, id);
456 encode_attrib(&msg, a);
457 send_msg(&msg);
458 buffer_free(&msg);
459}
460
461/* parse incoming */
462
Ben Lindstrombba81212001-06-25 05:01:22 +0000463static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100464process_init(void)
465{
466 Buffer msg;
Damien Miller7b28dc52000-09-05 13:34:53 +1100467
Ben Lindstrom937df1d2002-06-06 21:58:35 +0000468 version = get_int();
Damien Millerfef95ad2006-07-10 20:46:55 +1000469 verbose("received client version %d", version);
Damien Miller7b28dc52000-09-05 13:34:53 +1100470 buffer_init(&msg);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000471 buffer_put_char(&msg, SSH2_FXP_VERSION);
472 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
Damien Miller7b28dc52000-09-05 13:34:53 +1100473 send_msg(&msg);
474 buffer_free(&msg);
475}
476
Ben Lindstrombba81212001-06-25 05:01:22 +0000477static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100478process_open(void)
479{
480 u_int32_t id, pflags;
481 Attrib *a;
482 char *name;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000483 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100484
485 id = get_int();
486 name = get_string(NULL);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000487 pflags = get_int(); /* portable flags */
Damien Miller6444fe92006-07-10 21:31:27 +1000488 debug3("request %u: open flags %d", id, pflags);
Damien Miller7b28dc52000-09-05 13:34:53 +1100489 a = get_attrib();
490 flags = flags_from_portable(pflags);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000491 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
Damien Millerfef95ad2006-07-10 20:46:55 +1000492 logit("open \"%s\" flags %s mode 0%o",
493 name, string_from_portable(pflags), mode);
Damien Miller7b28dc52000-09-05 13:34:53 +1100494 fd = open(name, flags, mode);
495 if (fd < 0) {
496 status = errno_to_portable(errno);
497 } else {
Damien Miller00111382003-03-10 11:21:17 +1100498 handle = handle_new(HANDLE_FILE, name, fd, NULL);
Damien Miller7b28dc52000-09-05 13:34:53 +1100499 if (handle < 0) {
500 close(fd);
501 } else {
502 send_handle(id, handle);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000503 status = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100504 }
505 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000506 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100507 send_status(id, status);
508 xfree(name);
509}
510
Ben Lindstrombba81212001-06-25 05:01:22 +0000511static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100512process_close(void)
513{
514 u_int32_t id;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000515 int handle, ret, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100516
517 id = get_int();
518 handle = get_handle();
Damien Millerfef95ad2006-07-10 20:46:55 +1000519 debug3("request %u: close handle %u", id, handle);
520 handle_log_close(handle, NULL);
Damien Miller7b28dc52000-09-05 13:34:53 +1100521 ret = handle_close(handle);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000522 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100523 send_status(id, status);
524}
525
Ben Lindstrombba81212001-06-25 05:01:22 +0000526static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100527process_read(void)
528{
529 char buf[64*1024];
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000530 u_int32_t id, len;
531 int handle, fd, ret, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100532 u_int64_t off;
533
534 id = get_int();
535 handle = get_handle();
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000536 off = get_int64();
Damien Miller7b28dc52000-09-05 13:34:53 +1100537 len = get_int();
538
Damien Millerfef95ad2006-07-10 20:46:55 +1000539 debug("request %u: read \"%s\" (handle %d) off %llu len %d",
540 id, handle_to_name(handle), handle, (unsigned long long)off, len);
Damien Miller7b28dc52000-09-05 13:34:53 +1100541 if (len > sizeof buf) {
542 len = sizeof buf;
Damien Millerfef95ad2006-07-10 20:46:55 +1000543 debug2("read change len %d", len);
Damien Miller7b28dc52000-09-05 13:34:53 +1100544 }
545 fd = handle_to_fd(handle);
546 if (fd >= 0) {
547 if (lseek(fd, off, SEEK_SET) < 0) {
548 error("process_read: seek failed");
549 status = errno_to_portable(errno);
550 } else {
551 ret = read(fd, buf, len);
552 if (ret < 0) {
553 status = errno_to_portable(errno);
554 } else if (ret == 0) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000555 status = SSH2_FX_EOF;
Damien Miller7b28dc52000-09-05 13:34:53 +1100556 } else {
557 send_data(id, buf, ret);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000558 status = SSH2_FX_OK;
Damien Millerfef95ad2006-07-10 20:46:55 +1000559 handle_update_read(handle, ret);
Damien Miller7b28dc52000-09-05 13:34:53 +1100560 }
561 }
562 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000563 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100564 send_status(id, status);
565}
566
Ben Lindstrombba81212001-06-25 05:01:22 +0000567static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100568process_write(void)
569{
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000570 u_int32_t id;
Damien Miller7b28dc52000-09-05 13:34:53 +1100571 u_int64_t off;
Damien Millere4340be2000-09-16 13:29:08 +1100572 u_int len;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000573 int handle, fd, ret, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100574 char *data;
575
576 id = get_int();
577 handle = get_handle();
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000578 off = get_int64();
Damien Miller7b28dc52000-09-05 13:34:53 +1100579 data = get_string(&len);
580
Damien Millerfef95ad2006-07-10 20:46:55 +1000581 debug("request %u: write \"%s\" (handle %d) off %llu len %d",
582 id, handle_to_name(handle), handle, (unsigned long long)off, len);
Damien Miller7b28dc52000-09-05 13:34:53 +1100583 fd = handle_to_fd(handle);
584 if (fd >= 0) {
585 if (lseek(fd, off, SEEK_SET) < 0) {
586 status = errno_to_portable(errno);
587 error("process_write: seek failed");
588 } else {
589/* XXX ATOMICIO ? */
590 ret = write(fd, data, len);
Damien Millereccb9de2005-06-17 12:59:34 +1000591 if (ret < 0) {
Damien Miller7b28dc52000-09-05 13:34:53 +1100592 error("process_write: write failed");
593 status = errno_to_portable(errno);
Damien Millereccb9de2005-06-17 12:59:34 +1000594 } else if ((size_t)ret == len) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000595 status = SSH2_FX_OK;
Damien Millerfef95ad2006-07-10 20:46:55 +1000596 handle_update_write(handle, ret);
Damien Miller7b28dc52000-09-05 13:34:53 +1100597 } else {
Damien Millerfef95ad2006-07-10 20:46:55 +1000598 debug2("nothing at all written");
Damien Miller7b28dc52000-09-05 13:34:53 +1100599 }
600 }
601 }
602 send_status(id, status);
603 xfree(data);
604}
605
Ben Lindstrombba81212001-06-25 05:01:22 +0000606static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100607process_do_stat(int do_lstat)
608{
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000609 Attrib a;
Damien Miller7b28dc52000-09-05 13:34:53 +1100610 struct stat st;
611 u_int32_t id;
612 char *name;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000613 int ret, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100614
615 id = get_int();
616 name = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000617 debug3("request %u: %sstat", id, do_lstat ? "l" : "");
618 verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100619 ret = do_lstat ? lstat(name, &st) : stat(name, &st);
620 if (ret < 0) {
621 status = errno_to_portable(errno);
622 } else {
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000623 stat_to_attrib(&st, &a);
624 send_attrib(id, &a);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000625 status = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100626 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000627 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100628 send_status(id, status);
629 xfree(name);
630}
631
Ben Lindstrombba81212001-06-25 05:01:22 +0000632static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100633process_stat(void)
634{
635 process_do_stat(0);
636}
637
Ben Lindstrombba81212001-06-25 05:01:22 +0000638static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100639process_lstat(void)
640{
641 process_do_stat(1);
642}
643
Ben Lindstrombba81212001-06-25 05:01:22 +0000644static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100645process_fstat(void)
646{
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000647 Attrib a;
Damien Miller7b28dc52000-09-05 13:34:53 +1100648 struct stat st;
649 u_int32_t id;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000650 int fd, ret, handle, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100651
652 id = get_int();
653 handle = get_handle();
Damien Millerfef95ad2006-07-10 20:46:55 +1000654 debug("request %u: fstat \"%s\" (handle %u)",
655 id, handle_to_name(handle), handle);
Damien Miller7b28dc52000-09-05 13:34:53 +1100656 fd = handle_to_fd(handle);
657 if (fd >= 0) {
658 ret = fstat(fd, &st);
659 if (ret < 0) {
660 status = errno_to_portable(errno);
661 } else {
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000662 stat_to_attrib(&st, &a);
663 send_attrib(id, &a);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000664 status = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100665 }
666 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000667 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100668 send_status(id, status);
669}
670
Ben Lindstrombba81212001-06-25 05:01:22 +0000671static struct timeval *
Damien Millerf58b58c2003-11-17 21:18:23 +1100672attrib_to_tv(const Attrib *a)
Damien Miller7b28dc52000-09-05 13:34:53 +1100673{
674 static struct timeval tv[2];
Ben Lindstrom1addabd2001-03-05 07:09:11 +0000675
Damien Miller7b28dc52000-09-05 13:34:53 +1100676 tv[0].tv_sec = a->atime;
677 tv[0].tv_usec = 0;
678 tv[1].tv_sec = a->mtime;
679 tv[1].tv_usec = 0;
680 return tv;
681}
682
Ben Lindstrombba81212001-06-25 05:01:22 +0000683static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100684process_setstat(void)
685{
686 Attrib *a;
687 u_int32_t id;
688 char *name;
Ben Lindstromb1f483f2002-06-23 21:27:18 +0000689 int status = SSH2_FX_OK, ret;
Damien Miller7b28dc52000-09-05 13:34:53 +1100690
691 id = get_int();
692 name = get_string(NULL);
693 a = get_attrib();
Damien Millerfef95ad2006-07-10 20:46:55 +1000694 debug("request %u: setstat name \"%s\"", id, name);
Damien Miller00c92172002-02-13 14:05:00 +1100695 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000696 logit("set \"%s\" size %llu", name, a->size);
Damien Miller00c92172002-02-13 14:05:00 +1100697 ret = truncate(name, a->size);
698 if (ret == -1)
699 status = errno_to_portable(errno);
700 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000701 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000702 logit("set \"%s\" mode %04o", name, a->perm);
Damien Miller7b28dc52000-09-05 13:34:53 +1100703 ret = chmod(name, a->perm & 0777);
704 if (ret == -1)
705 status = errno_to_portable(errno);
706 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000707 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000708 char buf[64];
709 time_t t = a->mtime;
710
711 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
712 localtime(&t));
713 logit("set \"%s\" modtime %s", name, buf);
Damien Miller7b28dc52000-09-05 13:34:53 +1100714 ret = utimes(name, attrib_to_tv(a));
715 if (ret == -1)
716 status = errno_to_portable(errno);
717 }
Kevin Steves8e743932001-02-05 13:24:35 +0000718 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000719 logit("set \"%s\" owner %lu group %lu", name,
720 (u_long)a->uid, (u_long)a->gid);
Kevin Steves8e743932001-02-05 13:24:35 +0000721 ret = chown(name, a->uid, a->gid);
722 if (ret == -1)
723 status = errno_to_portable(errno);
724 }
Damien Miller7b28dc52000-09-05 13:34:53 +1100725 send_status(id, status);
726 xfree(name);
727}
728
Ben Lindstrombba81212001-06-25 05:01:22 +0000729static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100730process_fsetstat(void)
731{
732 Attrib *a;
733 u_int32_t id;
734 int handle, fd, ret;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000735 int status = SSH2_FX_OK;
Kevin Stevesf7ffab32001-01-24 20:11:06 +0000736
Damien Miller7b28dc52000-09-05 13:34:53 +1100737 id = get_int();
738 handle = get_handle();
739 a = get_attrib();
Damien Millerfef95ad2006-07-10 20:46:55 +1000740 debug("request %u: fsetstat handle %d", id, handle);
Damien Miller7b28dc52000-09-05 13:34:53 +1100741 fd = handle_to_fd(handle);
Damien Millerfef95ad2006-07-10 20:46:55 +1000742 if (fd < 0) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000743 status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100744 } else {
Damien Millerfef95ad2006-07-10 20:46:55 +1000745 char *name = handle_to_name(handle);
746
Damien Miller00c92172002-02-13 14:05:00 +1100747 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000748 logit("set \"%s\" size %llu", name, a->size);
Damien Miller00c92172002-02-13 14:05:00 +1100749 ret = ftruncate(fd, a->size);
750 if (ret == -1)
751 status = errno_to_portable(errno);
752 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000753 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000754 logit("set \"%s\" mode %04o", name, a->perm);
Ben Lindstrom200e3c92001-01-15 01:56:46 +0000755#ifdef HAVE_FCHMOD
Damien Miller7b28dc52000-09-05 13:34:53 +1100756 ret = fchmod(fd, a->perm & 0777);
Ben Lindstrom200e3c92001-01-15 01:56:46 +0000757#else
Kevin Stevesb6b37ba2001-01-24 20:01:44 +0000758 ret = chmod(name, a->perm & 0777);
Ben Lindstrom200e3c92001-01-15 01:56:46 +0000759#endif
Damien Miller7b28dc52000-09-05 13:34:53 +1100760 if (ret == -1)
761 status = errno_to_portable(errno);
762 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000763 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000764 char buf[64];
765 time_t t = a->mtime;
766
767 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
768 localtime(&t));
769 logit("set \"%s\" modtime %s", name, buf);
Damien Miller7b28dc52000-09-05 13:34:53 +1100770#ifdef HAVE_FUTIMES
771 ret = futimes(fd, attrib_to_tv(a));
772#else
773 ret = utimes(name, attrib_to_tv(a));
774#endif
775 if (ret == -1)
776 status = errno_to_portable(errno);
777 }
Kevin Steves8e743932001-02-05 13:24:35 +0000778 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
Damien Millerfef95ad2006-07-10 20:46:55 +1000779 logit("set \"%s\" owner %lu group %lu", name,
780 (u_long)a->uid, (u_long)a->gid);
Ben Lindstrom34bb0c72001-02-13 02:40:56 +0000781#ifdef HAVE_FCHOWN
Kevin Steves8e743932001-02-05 13:24:35 +0000782 ret = fchown(fd, a->uid, a->gid);
Ben Lindstrom34bb0c72001-02-13 02:40:56 +0000783#else
784 ret = chown(name, a->uid, a->gid);
785#endif
Kevin Steves8e743932001-02-05 13:24:35 +0000786 if (ret == -1)
787 status = errno_to_portable(errno);
788 }
Damien Miller7b28dc52000-09-05 13:34:53 +1100789 }
790 send_status(id, status);
791}
792
Ben Lindstrombba81212001-06-25 05:01:22 +0000793static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100794process_opendir(void)
795{
796 DIR *dirp = NULL;
797 char *path;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000798 int handle, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100799 u_int32_t id;
800
801 id = get_int();
802 path = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000803 debug3("request %u: opendir", id);
804 logit("opendir \"%s\"", path);
Kevin Stevesef4eea92001-02-05 12:42:17 +0000805 dirp = opendir(path);
Damien Miller7b28dc52000-09-05 13:34:53 +1100806 if (dirp == NULL) {
807 status = errno_to_portable(errno);
808 } else {
Damien Miller00111382003-03-10 11:21:17 +1100809 handle = handle_new(HANDLE_DIR, path, 0, dirp);
Damien Miller7b28dc52000-09-05 13:34:53 +1100810 if (handle < 0) {
811 closedir(dirp);
812 } else {
813 send_handle(id, handle);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000814 status = SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100815 }
Kevin Stevesef4eea92001-02-05 12:42:17 +0000816
Damien Miller7b28dc52000-09-05 13:34:53 +1100817 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000818 if (status != SSH2_FX_OK)
Damien Miller7b28dc52000-09-05 13:34:53 +1100819 send_status(id, status);
820 xfree(path);
821}
822
Ben Lindstrombba81212001-06-25 05:01:22 +0000823static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100824process_readdir(void)
825{
826 DIR *dirp;
827 struct dirent *dp;
828 char *path;
829 int handle;
830 u_int32_t id;
831
832 id = get_int();
833 handle = get_handle();
Damien Millerfef95ad2006-07-10 20:46:55 +1000834 debug("request %u: readdir \"%s\" (handle %d)", id,
835 handle_to_name(handle), handle);
Damien Miller7b28dc52000-09-05 13:34:53 +1100836 dirp = handle_to_dir(handle);
837 path = handle_to_name(handle);
838 if (dirp == NULL || path == NULL) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000839 send_status(id, SSH2_FX_FAILURE);
Damien Miller7b28dc52000-09-05 13:34:53 +1100840 } else {
Damien Miller7b28dc52000-09-05 13:34:53 +1100841 struct stat st;
Damien Millerfef95ad2006-07-10 20:46:55 +1000842 char pathname[MAXPATHLEN];
Damien Miller7b28dc52000-09-05 13:34:53 +1100843 Stat *stats;
844 int nstats = 10, count = 0, i;
Ben Lindstromb1f483f2002-06-23 21:27:18 +0000845
Damien Miller07d86be2006-03-26 14:19:21 +1100846 stats = xcalloc(nstats, sizeof(Stat));
Damien Miller7b28dc52000-09-05 13:34:53 +1100847 while ((dp = readdir(dirp)) != NULL) {
848 if (count >= nstats) {
849 nstats *= 2;
Damien Miller36812092006-03-26 14:22:47 +1100850 stats = xrealloc(stats, nstats, sizeof(Stat));
Damien Miller7b28dc52000-09-05 13:34:53 +1100851 }
852/* XXX OVERFLOW ? */
Ben Lindstrom95148e32001-08-06 21:30:53 +0000853 snprintf(pathname, sizeof pathname, "%s%s%s", path,
854 strcmp(path, "/") ? "/" : "", dp->d_name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100855 if (lstat(pathname, &st) < 0)
856 continue;
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000857 stat_to_attrib(&st, &(stats[count].attrib));
Damien Miller7b28dc52000-09-05 13:34:53 +1100858 stats[count].name = xstrdup(dp->d_name);
Damien Millere1a49812002-09-12 09:54:25 +1000859 stats[count].long_name = ls_file(dp->d_name, &st, 0);
Damien Miller7b28dc52000-09-05 13:34:53 +1100860 count++;
861 /* send up to 100 entries in one message */
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000862 /* XXX check packet size instead */
Damien Miller7b28dc52000-09-05 13:34:53 +1100863 if (count == 100)
864 break;
865 }
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000866 if (count > 0) {
867 send_names(id, count, stats);
Damien Miller9f0f5c62001-12-21 14:45:46 +1100868 for (i = 0; i < count; i++) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000869 xfree(stats[i].name);
870 xfree(stats[i].long_name);
871 }
872 } else {
873 send_status(id, SSH2_FX_EOF);
Damien Miller7b28dc52000-09-05 13:34:53 +1100874 }
875 xfree(stats);
876 }
877}
878
Ben Lindstrombba81212001-06-25 05:01:22 +0000879static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100880process_remove(void)
881{
882 char *name;
883 u_int32_t id;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000884 int status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100885 int ret;
886
887 id = get_int();
888 name = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000889 debug3("request %u: remove", id);
890 logit("remove name \"%s\"", name);
Kevin Stevesa074feb2000-12-21 22:33:45 +0000891 ret = unlink(name);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000892 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100893 send_status(id, status);
894 xfree(name);
895}
896
Ben Lindstrombba81212001-06-25 05:01:22 +0000897static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100898process_mkdir(void)
899{
900 Attrib *a;
901 u_int32_t id;
902 char *name;
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000903 int ret, mode, status = SSH2_FX_FAILURE;
Damien Miller7b28dc52000-09-05 13:34:53 +1100904
905 id = get_int();
906 name = get_string(NULL);
907 a = get_attrib();
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000908 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
909 a->perm & 0777 : 0777;
Damien Millerfef95ad2006-07-10 20:46:55 +1000910 debug3("request %u: mkdir", id);
911 logit("mkdir name \"%s\" mode 0%o", name, mode);
Damien Miller7b28dc52000-09-05 13:34:53 +1100912 ret = mkdir(name, mode);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000913 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100914 send_status(id, status);
915 xfree(name);
916}
917
Ben Lindstrombba81212001-06-25 05:01:22 +0000918static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100919process_rmdir(void)
920{
921 u_int32_t id;
922 char *name;
923 int ret, status;
924
925 id = get_int();
926 name = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000927 debug3("request %u: rmdir", id);
928 logit("rmdir name \"%s\"", name);
Damien Miller7b28dc52000-09-05 13:34:53 +1100929 ret = rmdir(name);
Ben Lindstrom2f959b42001-01-11 06:20:23 +0000930 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller7b28dc52000-09-05 13:34:53 +1100931 send_status(id, status);
932 xfree(name);
933}
934
Ben Lindstrombba81212001-06-25 05:01:22 +0000935static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100936process_realpath(void)
937{
938 char resolvedname[MAXPATHLEN];
939 u_int32_t id;
940 char *path;
941
942 id = get_int();
943 path = get_string(NULL);
Ben Lindstromfa1b3d02000-12-10 01:55:37 +0000944 if (path[0] == '\0') {
945 xfree(path);
946 path = xstrdup(".");
947 }
Damien Millerfef95ad2006-07-10 20:46:55 +1000948 debug3("request %u: realpath", id);
949 verbose("realpath \"%s\"", path);
Damien Miller7b28dc52000-09-05 13:34:53 +1100950 if (realpath(path, resolvedname) == NULL) {
951 send_status(id, errno_to_portable(errno));
952 } else {
953 Stat s;
954 attrib_clear(&s.attrib);
955 s.name = s.long_name = resolvedname;
956 send_names(id, 1, &s);
957 }
958 xfree(path);
959}
960
Ben Lindstrombba81212001-06-25 05:01:22 +0000961static void
Damien Miller7b28dc52000-09-05 13:34:53 +1100962process_rename(void)
963{
964 u_int32_t id;
965 char *oldpath, *newpath;
Damien Miller9e51a732003-02-24 11:58:44 +1100966 int status;
Damien Millerb3207e82003-03-26 16:01:11 +1100967 struct stat sb;
Damien Miller7b28dc52000-09-05 13:34:53 +1100968
969 id = get_int();
970 oldpath = get_string(NULL);
971 newpath = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +1000972 debug3("request %u: rename", id);
973 logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
Damien Millerb3207e82003-03-26 16:01:11 +1100974 status = SSH2_FX_FAILURE;
975 if (lstat(oldpath, &sb) == -1)
Damien Miller9e51a732003-02-24 11:58:44 +1100976 status = errno_to_portable(errno);
Damien Millerb3207e82003-03-26 16:01:11 +1100977 else if (S_ISREG(sb.st_mode)) {
978 /* Race-free rename of regular files */
Darren Tuckeraedc1d62004-06-25 17:06:02 +1000979 if (link(oldpath, newpath) == -1) {
Darren Tuckere59b5082004-06-28 16:01:19 +1000980 if (errno == EOPNOTSUPP
981#ifdef LINK_OPNOTSUPP_ERRNO
982 || errno == LINK_OPNOTSUPP_ERRNO
983#endif
984 ) {
Darren Tuckeraedc1d62004-06-25 17:06:02 +1000985 struct stat st;
986
987 /*
988 * fs doesn't support links, so fall back to
989 * stat+rename. This is racy.
990 */
991 if (stat(newpath, &st) == -1) {
992 if (rename(oldpath, newpath) == -1)
993 status =
994 errno_to_portable(errno);
995 else
996 status = SSH2_FX_OK;
997 }
998 } else {
999 status = errno_to_portable(errno);
1000 }
1001 } else if (unlink(oldpath) == -1) {
Damien Millerb3207e82003-03-26 16:01:11 +11001002 status = errno_to_portable(errno);
1003 /* clean spare link */
1004 unlink(newpath);
1005 } else
1006 status = SSH2_FX_OK;
1007 } else if (stat(newpath, &sb) == -1) {
1008 if (rename(oldpath, newpath) == -1)
1009 status = errno_to_portable(errno);
1010 else
1011 status = SSH2_FX_OK;
1012 }
Damien Miller7b28dc52000-09-05 13:34:53 +11001013 send_status(id, status);
1014 xfree(oldpath);
1015 xfree(newpath);
1016}
1017
Ben Lindstrombba81212001-06-25 05:01:22 +00001018static void
Damien Miller058316f2001-03-08 10:08:49 +11001019process_readlink(void)
1020{
1021 u_int32_t id;
Ben Lindstromabbb73d2001-05-17 03:14:57 +00001022 int len;
Darren Tucker3f9fdc72004-06-22 12:56:01 +10001023 char buf[MAXPATHLEN];
Damien Miller058316f2001-03-08 10:08:49 +11001024 char *path;
1025
1026 id = get_int();
1027 path = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +10001028 debug3("request %u: readlink", id);
1029 verbose("readlink \"%s\"", path);
Darren Tucker3f9fdc72004-06-22 12:56:01 +10001030 if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
Damien Miller058316f2001-03-08 10:08:49 +11001031 send_status(id, errno_to_portable(errno));
1032 else {
1033 Stat s;
Damien Miller9f0f5c62001-12-21 14:45:46 +11001034
Darren Tucker3f9fdc72004-06-22 12:56:01 +10001035 buf[len] = '\0';
Damien Miller058316f2001-03-08 10:08:49 +11001036 attrib_clear(&s.attrib);
Darren Tucker3f9fdc72004-06-22 12:56:01 +10001037 s.name = s.long_name = buf;
Damien Miller058316f2001-03-08 10:08:49 +11001038 send_names(id, 1, &s);
1039 }
1040 xfree(path);
1041}
1042
Ben Lindstrombba81212001-06-25 05:01:22 +00001043static void
Damien Miller058316f2001-03-08 10:08:49 +11001044process_symlink(void)
1045{
1046 u_int32_t id;
Damien Miller058316f2001-03-08 10:08:49 +11001047 char *oldpath, *newpath;
Damien Miller9e51a732003-02-24 11:58:44 +11001048 int ret, status;
Damien Miller058316f2001-03-08 10:08:49 +11001049
1050 id = get_int();
1051 oldpath = get_string(NULL);
1052 newpath = get_string(NULL);
Damien Millerfef95ad2006-07-10 20:46:55 +10001053 debug3("request %u: symlink", id);
1054 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
Damien Miller9e51a732003-02-24 11:58:44 +11001055 /* this will fail if 'newpath' exists */
1056 ret = symlink(oldpath, newpath);
1057 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Damien Miller058316f2001-03-08 10:08:49 +11001058 send_status(id, status);
1059 xfree(oldpath);
1060 xfree(newpath);
1061}
1062
Ben Lindstrombba81212001-06-25 05:01:22 +00001063static void
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001064process_extended(void)
1065{
1066 u_int32_t id;
1067 char *request;
1068
1069 id = get_int();
1070 request = get_string(NULL);
1071 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
1072 xfree(request);
1073}
Damien Miller7b28dc52000-09-05 13:34:53 +11001074
1075/* stolen from ssh-agent */
1076
Ben Lindstrombba81212001-06-25 05:01:22 +00001077static void
Damien Miller7b28dc52000-09-05 13:34:53 +11001078process(void)
1079{
Ben Lindstrom46c16222000-12-22 01:43:59 +00001080 u_int msg_len;
Ben Lindstrom2c140472002-06-06 21:57:54 +00001081 u_int buf_len;
1082 u_int consumed;
Ben Lindstrom46c16222000-12-22 01:43:59 +00001083 u_int type;
1084 u_char *cp;
Damien Miller7b28dc52000-09-05 13:34:53 +11001085
Ben Lindstrom2c140472002-06-06 21:57:54 +00001086 buf_len = buffer_len(&iqueue);
1087 if (buf_len < 5)
Damien Miller7b28dc52000-09-05 13:34:53 +11001088 return; /* Incomplete message. */
Damien Miller708d21c2002-01-22 23:18:15 +11001089 cp = buffer_ptr(&iqueue);
Damien Miller3f941882006-03-31 23:13:02 +11001090 msg_len = get_u32(cp);
Damien Miller54446182006-01-02 23:40:50 +11001091 if (msg_len > SFTP_MAX_MSG_LENGTH) {
Damien Millerfef95ad2006-07-10 20:46:55 +10001092 error("bad message from %s local user %s",
1093 client_addr, pw->pw_name);
1094 cleanup_exit(11);
Damien Miller7b28dc52000-09-05 13:34:53 +11001095 }
Ben Lindstrom2c140472002-06-06 21:57:54 +00001096 if (buf_len < msg_len + 4)
Damien Miller7b28dc52000-09-05 13:34:53 +11001097 return;
1098 buffer_consume(&iqueue, 4);
Ben Lindstrom2c140472002-06-06 21:57:54 +00001099 buf_len -= 4;
Damien Miller7b28dc52000-09-05 13:34:53 +11001100 type = buffer_get_char(&iqueue);
1101 switch (type) {
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001102 case SSH2_FXP_INIT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001103 process_init();
1104 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001105 case SSH2_FXP_OPEN:
Damien Miller7b28dc52000-09-05 13:34:53 +11001106 process_open();
1107 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001108 case SSH2_FXP_CLOSE:
Damien Miller7b28dc52000-09-05 13:34:53 +11001109 process_close();
1110 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001111 case SSH2_FXP_READ:
Damien Miller7b28dc52000-09-05 13:34:53 +11001112 process_read();
1113 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001114 case SSH2_FXP_WRITE:
Damien Miller7b28dc52000-09-05 13:34:53 +11001115 process_write();
1116 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001117 case SSH2_FXP_LSTAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001118 process_lstat();
1119 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001120 case SSH2_FXP_FSTAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001121 process_fstat();
1122 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001123 case SSH2_FXP_SETSTAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001124 process_setstat();
1125 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001126 case SSH2_FXP_FSETSTAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001127 process_fsetstat();
1128 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001129 case SSH2_FXP_OPENDIR:
Damien Miller7b28dc52000-09-05 13:34:53 +11001130 process_opendir();
1131 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001132 case SSH2_FXP_READDIR:
Damien Miller7b28dc52000-09-05 13:34:53 +11001133 process_readdir();
1134 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001135 case SSH2_FXP_REMOVE:
Damien Miller7b28dc52000-09-05 13:34:53 +11001136 process_remove();
1137 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001138 case SSH2_FXP_MKDIR:
Damien Miller7b28dc52000-09-05 13:34:53 +11001139 process_mkdir();
1140 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001141 case SSH2_FXP_RMDIR:
Damien Miller7b28dc52000-09-05 13:34:53 +11001142 process_rmdir();
1143 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001144 case SSH2_FXP_REALPATH:
Damien Miller7b28dc52000-09-05 13:34:53 +11001145 process_realpath();
1146 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001147 case SSH2_FXP_STAT:
Damien Miller7b28dc52000-09-05 13:34:53 +11001148 process_stat();
1149 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001150 case SSH2_FXP_RENAME:
Damien Miller7b28dc52000-09-05 13:34:53 +11001151 process_rename();
1152 break;
Damien Miller058316f2001-03-08 10:08:49 +11001153 case SSH2_FXP_READLINK:
1154 process_readlink();
1155 break;
1156 case SSH2_FXP_SYMLINK:
1157 process_symlink();
1158 break;
Ben Lindstrom2f959b42001-01-11 06:20:23 +00001159 case SSH2_FXP_EXTENDED:
1160 process_extended();
1161 break;
Damien Miller7b28dc52000-09-05 13:34:53 +11001162 default:
1163 error("Unknown message %d", type);
1164 break;
1165 }
Ben Lindstrom2c140472002-06-06 21:57:54 +00001166 /* discard the remaining bytes from the current packet */
1167 if (buf_len < buffer_len(&iqueue))
Damien Millerfef95ad2006-07-10 20:46:55 +10001168 fatal("iqueue grew unexpectedly");
Ben Lindstrom2c140472002-06-06 21:57:54 +00001169 consumed = buf_len - buffer_len(&iqueue);
1170 if (msg_len < consumed)
1171 fatal("msg_len %d < consumed %d", msg_len, consumed);
1172 if (msg_len > consumed)
1173 buffer_consume(&iqueue, msg_len - consumed);
Damien Miller7b28dc52000-09-05 13:34:53 +11001174}
1175
Damien Millerfef95ad2006-07-10 20:46:55 +10001176/* Cleanup handler that logs active handles upon normal exit */
1177void
1178cleanup_exit(int i)
1179{
1180 if (pw != NULL && client_addr != NULL) {
1181 handle_log_exit();
1182 logit("session closed for local user %s from [%s]",
1183 pw->pw_name, client_addr);
1184 }
1185 _exit(i);
1186}
1187
1188static void
1189usage(void)
1190{
1191 extern char *__progname;
1192
1193 fprintf(stderr,
1194 "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
1195 exit(1);
1196}
1197
Damien Miller7b28dc52000-09-05 13:34:53 +11001198int
Damien Millerfef95ad2006-07-10 20:46:55 +10001199main(int argc, char **argv)
Damien Miller7b28dc52000-09-05 13:34:53 +11001200{
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001201 fd_set *rset, *wset;
Damien Millerfef95ad2006-07-10 20:46:55 +10001202 int in, out, max, ch, skipargs = 0, log_stderr = 0;
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001203 ssize_t len, olen, set_size;
Damien Millerfef95ad2006-07-10 20:46:55 +10001204 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1205 char *cp;
1206
Damien Millerfef95ad2006-07-10 20:46:55 +10001207 extern char *optarg;
1208 extern char *__progname;
Damien Miller7b28dc52000-09-05 13:34:53 +11001209
Darren Tuckerce321d82005-10-03 18:11:24 +10001210 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1211 sanitise_stdfd();
1212
Damien Millerfef95ad2006-07-10 20:46:55 +10001213 __progname = ssh_get_progname(argv[0]);
1214 log_init(__progname, log_level, log_facility, log_stderr);
Ben Lindstromc7f4ccd2001-03-15 00:09:15 +00001215
Damien Millerfef95ad2006-07-10 20:46:55 +10001216 while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
1217 switch (ch) {
1218 case 'c':
1219 /*
1220 * Ignore all arguments if we are invoked as a
1221 * shell using "sftp-server -c command"
1222 */
1223 skipargs = 1;
1224 break;
1225 case 'e':
1226 log_stderr = 1;
1227 break;
1228 case 'l':
1229 log_level = log_level_number(optarg);
1230 if (log_level == SYSLOG_LEVEL_NOT_SET)
1231 error("Invalid log level \"%s\"", optarg);
1232 break;
1233 case 'f':
1234 log_facility = log_facility_number(optarg);
1235 if (log_level == SYSLOG_FACILITY_NOT_SET)
1236 error("Invalid log facility \"%s\"", optarg);
1237 break;
1238 case 'h':
1239 default:
1240 usage();
1241 }
1242 }
1243
1244 log_init(__progname, log_level, log_facility, log_stderr);
1245
1246 if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1247 client_addr = xstrdup(cp);
1248 if ((cp = strchr(client_addr, ' ')) == NULL)
1249 fatal("Malformed SSH_CONNECTION variable: \"%s\"",
1250 getenv("SSH_CONNECTION"));
1251 *cp = '\0';
1252 } else
1253 client_addr = xstrdup("UNKNOWN");
1254
1255 if ((pw = getpwuid(getuid())) == NULL)
1256 fatal("No user found for uid %lu", (u_long)getuid());
1257 pw = pwcopy(pw);
1258
1259 logit("session opened for local user %s from [%s]",
1260 pw->pw_name, client_addr);
1261
Damien Miller7b28dc52000-09-05 13:34:53 +11001262 handle_init();
1263
Damien Miller7b28dc52000-09-05 13:34:53 +11001264 in = dup(STDIN_FILENO);
1265 out = dup(STDOUT_FILENO);
1266
Damien Miller402b3312001-04-14 00:28:42 +10001267#ifdef HAVE_CYGWIN
1268 setmode(in, O_BINARY);
1269 setmode(out, O_BINARY);
1270#endif
1271
Damien Miller7b28dc52000-09-05 13:34:53 +11001272 max = 0;
1273 if (in > max)
1274 max = in;
1275 if (out > max)
1276 max = out;
1277
1278 buffer_init(&iqueue);
1279 buffer_init(&oqueue);
1280
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001281 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1282 rset = (fd_set *)xmalloc(set_size);
1283 wset = (fd_set *)xmalloc(set_size);
Damien Miller7b28dc52000-09-05 13:34:53 +11001284
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001285 for (;;) {
1286 memset(rset, 0, set_size);
1287 memset(wset, 0, set_size);
1288
1289 FD_SET(in, rset);
Damien Miller7b28dc52000-09-05 13:34:53 +11001290 olen = buffer_len(&oqueue);
1291 if (olen > 0)
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001292 FD_SET(out, wset);
Damien Miller7b28dc52000-09-05 13:34:53 +11001293
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001294 if (select(max+1, rset, wset, NULL, NULL) < 0) {
Damien Miller7b28dc52000-09-05 13:34:53 +11001295 if (errno == EINTR)
1296 continue;
Damien Millerfef95ad2006-07-10 20:46:55 +10001297 error("select: %s", strerror(errno));
1298 cleanup_exit(2);
Damien Miller7b28dc52000-09-05 13:34:53 +11001299 }
1300
1301 /* copy stdin to iqueue */
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001302 if (FD_ISSET(in, rset)) {
Damien Miller7b28dc52000-09-05 13:34:53 +11001303 char buf[4*4096];
1304 len = read(in, buf, sizeof buf);
1305 if (len == 0) {
1306 debug("read eof");
Damien Millerfef95ad2006-07-10 20:46:55 +10001307 cleanup_exit(0);
Damien Miller7b28dc52000-09-05 13:34:53 +11001308 } else if (len < 0) {
Damien Millerfef95ad2006-07-10 20:46:55 +10001309 error("read: %s", strerror(errno));
1310 cleanup_exit(1);
Damien Miller7b28dc52000-09-05 13:34:53 +11001311 } else {
1312 buffer_append(&iqueue, buf, len);
1313 }
1314 }
1315 /* send oqueue to stdout */
Ben Lindstromcb80bdf2001-03-05 07:06:12 +00001316 if (FD_ISSET(out, wset)) {
Damien Miller7b28dc52000-09-05 13:34:53 +11001317 len = write(out, buffer_ptr(&oqueue), olen);
1318 if (len < 0) {
Damien Millerfef95ad2006-07-10 20:46:55 +10001319 error("write: %s", strerror(errno));
1320 cleanup_exit(1);
Damien Miller7b28dc52000-09-05 13:34:53 +11001321 } else {
1322 buffer_consume(&oqueue, len);
1323 }
1324 }
1325 /* process requests from client */
1326 process();
1327 }
1328}