1b66f2d16SKris Kennaway /* 2b66f2d16SKris Kennaway * Copyright (c) 2000 Markus Friedl. All rights reserved. 3b66f2d16SKris Kennaway * 4b66f2d16SKris Kennaway * Redistribution and use in source and binary forms, with or without 5b66f2d16SKris Kennaway * modification, are permitted provided that the following conditions 6b66f2d16SKris Kennaway * are met: 7b66f2d16SKris Kennaway * 1. Redistributions of source code must retain the above copyright 8b66f2d16SKris Kennaway * notice, this list of conditions and the following disclaimer. 9b66f2d16SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 10b66f2d16SKris Kennaway * notice, this list of conditions and the following disclaimer in the 11b66f2d16SKris Kennaway * documentation and/or other materials provided with the distribution. 12b66f2d16SKris Kennaway * 13b66f2d16SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14b66f2d16SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15b66f2d16SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16b66f2d16SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17b66f2d16SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18b66f2d16SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19b66f2d16SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20b66f2d16SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21b66f2d16SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22b66f2d16SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23b66f2d16SKris Kennaway */ 24b66f2d16SKris Kennaway #include "includes.h" 25b66f2d16SKris Kennaway RCSID("$OpenBSD: sftp-server.c,v 1.6 2000/09/07 20:27:53 deraadt Exp $"); 26b66f2d16SKris Kennaway 27b66f2d16SKris Kennaway #include "ssh.h" 28b66f2d16SKris Kennaway #include "buffer.h" 29b66f2d16SKris Kennaway #include "bufaux.h" 30b66f2d16SKris Kennaway #include "getput.h" 31b66f2d16SKris Kennaway #include "xmalloc.h" 32b66f2d16SKris Kennaway 33b66f2d16SKris Kennaway /* version */ 34b66f2d16SKris Kennaway #define SSH_FILEXFER_VERSION 2 35b66f2d16SKris Kennaway 36b66f2d16SKris Kennaway /* client to server */ 37b66f2d16SKris Kennaway #define SSH_FXP_INIT 1 38b66f2d16SKris Kennaway #define SSH_FXP_OPEN 3 39b66f2d16SKris Kennaway #define SSH_FXP_CLOSE 4 40b66f2d16SKris Kennaway #define SSH_FXP_READ 5 41b66f2d16SKris Kennaway #define SSH_FXP_WRITE 6 42b66f2d16SKris Kennaway #define SSH_FXP_LSTAT 7 43b66f2d16SKris Kennaway #define SSH_FXP_FSTAT 8 44b66f2d16SKris Kennaway #define SSH_FXP_SETSTAT 9 45b66f2d16SKris Kennaway #define SSH_FXP_FSETSTAT 10 46b66f2d16SKris Kennaway #define SSH_FXP_OPENDIR 11 47b66f2d16SKris Kennaway #define SSH_FXP_READDIR 12 48b66f2d16SKris Kennaway #define SSH_FXP_REMOVE 13 49b66f2d16SKris Kennaway #define SSH_FXP_MKDIR 14 50b66f2d16SKris Kennaway #define SSH_FXP_RMDIR 15 51b66f2d16SKris Kennaway #define SSH_FXP_REALPATH 16 52b66f2d16SKris Kennaway #define SSH_FXP_STAT 17 53b66f2d16SKris Kennaway #define SSH_FXP_RENAME 18 54b66f2d16SKris Kennaway 55b66f2d16SKris Kennaway /* server to client */ 56b66f2d16SKris Kennaway #define SSH_FXP_VERSION 2 57b66f2d16SKris Kennaway #define SSH_FXP_STATUS 101 58b66f2d16SKris Kennaway #define SSH_FXP_HANDLE 102 59b66f2d16SKris Kennaway #define SSH_FXP_DATA 103 60b66f2d16SKris Kennaway #define SSH_FXP_NAME 104 61b66f2d16SKris Kennaway #define SSH_FXP_ATTRS 105 62b66f2d16SKris Kennaway 63b66f2d16SKris Kennaway /* portable open modes */ 64b66f2d16SKris Kennaway #define SSH_FXF_READ 0x01 65b66f2d16SKris Kennaway #define SSH_FXF_WRITE 0x02 66b66f2d16SKris Kennaway #define SSH_FXF_APPEND 0x04 67b66f2d16SKris Kennaway #define SSH_FXF_CREAT 0x08 68b66f2d16SKris Kennaway #define SSH_FXF_TRUNC 0x10 69b66f2d16SKris Kennaway #define SSH_FXF_EXCL 0x20 70b66f2d16SKris Kennaway 71b66f2d16SKris Kennaway /* attributes */ 72b66f2d16SKris Kennaway #define SSH_FXA_HAVE_SIZE 0x01 73b66f2d16SKris Kennaway #define SSH_FXA_HAVE_UGID 0x02 74b66f2d16SKris Kennaway #define SSH_FXA_HAVE_PERM 0x04 75b66f2d16SKris Kennaway #define SSH_FXA_HAVE_TIME 0x08 76b66f2d16SKris Kennaway 77b66f2d16SKris Kennaway /* status messages */ 78b66f2d16SKris Kennaway #define SSH_FX_OK 0x00 79b66f2d16SKris Kennaway #define SSH_FX_EOF 0x01 80b66f2d16SKris Kennaway #define SSH_FX_NO_SUCH_FILE 0x02 81b66f2d16SKris Kennaway #define SSH_FX_PERMISSION_DENIED 0x03 82b66f2d16SKris Kennaway #define SSH_FX_FAILURE 0x04 83b66f2d16SKris Kennaway #define SSH_FX_BAD_MESSAGE 0x05 84b66f2d16SKris Kennaway #define SSH_FX_NO_CONNECTION 0x06 85b66f2d16SKris Kennaway #define SSH_FX_CONNECTION_LOST 0x07 86b66f2d16SKris Kennaway 87b66f2d16SKris Kennaway 88b66f2d16SKris Kennaway /* helper */ 89b66f2d16SKris Kennaway #define get_int() buffer_get_int(&iqueue); 90b66f2d16SKris Kennaway #define get_string(lenp) buffer_get_string(&iqueue, lenp); 91b66f2d16SKris Kennaway #define TRACE log 92b66f2d16SKris Kennaway 93b66f2d16SKris Kennaway /* input and output queue */ 94b66f2d16SKris Kennaway Buffer iqueue; 95b66f2d16SKris Kennaway Buffer oqueue; 96b66f2d16SKris Kennaway 97b66f2d16SKris Kennaway /* portable attibutes, etc. */ 98b66f2d16SKris Kennaway 99b66f2d16SKris Kennaway typedef struct Attrib Attrib; 100b66f2d16SKris Kennaway typedef struct Stat Stat; 101b66f2d16SKris Kennaway 102b66f2d16SKris Kennaway struct Attrib 103b66f2d16SKris Kennaway { 104b66f2d16SKris Kennaway u_int32_t flags; 105b66f2d16SKris Kennaway u_int32_t size_high; 106b66f2d16SKris Kennaway u_int32_t size_low; 107b66f2d16SKris Kennaway u_int64_t size; 108b66f2d16SKris Kennaway u_int32_t uid; 109b66f2d16SKris Kennaway u_int32_t gid; 110b66f2d16SKris Kennaway u_int32_t perm; 111b66f2d16SKris Kennaway u_int32_t atime; 112b66f2d16SKris Kennaway u_int32_t mtime; 113b66f2d16SKris Kennaway }; 114b66f2d16SKris Kennaway 115b66f2d16SKris Kennaway struct Stat 116b66f2d16SKris Kennaway { 117b66f2d16SKris Kennaway char *name; 118b66f2d16SKris Kennaway char *long_name; 119b66f2d16SKris Kennaway Attrib attrib; 120b66f2d16SKris Kennaway }; 121b66f2d16SKris Kennaway 122b66f2d16SKris Kennaway int 123b66f2d16SKris Kennaway errno_to_portable(int unixerrno) 124b66f2d16SKris Kennaway { 125b66f2d16SKris Kennaway int ret = 0; 126b66f2d16SKris Kennaway switch (unixerrno) { 127b66f2d16SKris Kennaway case 0: 128b66f2d16SKris Kennaway ret = SSH_FX_OK; 129b66f2d16SKris Kennaway break; 130b66f2d16SKris Kennaway case ENOENT: 131b66f2d16SKris Kennaway case ENOTDIR: 132b66f2d16SKris Kennaway case EBADF: 133b66f2d16SKris Kennaway case ELOOP: 134b66f2d16SKris Kennaway ret = SSH_FX_NO_SUCH_FILE; 135b66f2d16SKris Kennaway break; 136b66f2d16SKris Kennaway case EPERM: 137b66f2d16SKris Kennaway case EACCES: 138b66f2d16SKris Kennaway case EFAULT: 139b66f2d16SKris Kennaway ret = SSH_FX_PERMISSION_DENIED; 140b66f2d16SKris Kennaway break; 141b66f2d16SKris Kennaway case ENAMETOOLONG: 142b66f2d16SKris Kennaway case EINVAL: 143b66f2d16SKris Kennaway ret = SSH_FX_BAD_MESSAGE; 144b66f2d16SKris Kennaway break; 145b66f2d16SKris Kennaway default: 146b66f2d16SKris Kennaway ret = SSH_FX_FAILURE; 147b66f2d16SKris Kennaway break; 148b66f2d16SKris Kennaway } 149b66f2d16SKris Kennaway return ret; 150b66f2d16SKris Kennaway } 151b66f2d16SKris Kennaway 152b66f2d16SKris Kennaway int 153b66f2d16SKris Kennaway flags_from_portable(int pflags) 154b66f2d16SKris Kennaway { 155b66f2d16SKris Kennaway int flags = 0; 156b66f2d16SKris Kennaway if (pflags & SSH_FXF_READ && 157b66f2d16SKris Kennaway pflags & SSH_FXF_WRITE) { 158b66f2d16SKris Kennaway flags = O_RDWR; 159b66f2d16SKris Kennaway } else if (pflags & SSH_FXF_READ) { 160b66f2d16SKris Kennaway flags = O_RDONLY; 161b66f2d16SKris Kennaway } else if (pflags & SSH_FXF_WRITE) { 162b66f2d16SKris Kennaway flags = O_WRONLY; 163b66f2d16SKris Kennaway } 164b66f2d16SKris Kennaway if (pflags & SSH_FXF_CREAT) 165b66f2d16SKris Kennaway flags |= O_CREAT; 166b66f2d16SKris Kennaway if (pflags & SSH_FXF_TRUNC) 167b66f2d16SKris Kennaway flags |= O_TRUNC; 168b66f2d16SKris Kennaway if (pflags & SSH_FXF_EXCL) 169b66f2d16SKris Kennaway flags |= O_EXCL; 170b66f2d16SKris Kennaway return flags; 171b66f2d16SKris Kennaway } 172b66f2d16SKris Kennaway 173b66f2d16SKris Kennaway void 174b66f2d16SKris Kennaway attrib_clear(Attrib *a) 175b66f2d16SKris Kennaway { 176b66f2d16SKris Kennaway a->flags = 0; 177b66f2d16SKris Kennaway a->size_low = 0; 178b66f2d16SKris Kennaway a->size_high = 0; 179b66f2d16SKris Kennaway a->size = 0; 180b66f2d16SKris Kennaway a->uid = 0; 181b66f2d16SKris Kennaway a->gid = 0; 182b66f2d16SKris Kennaway a->perm = 0; 183b66f2d16SKris Kennaway a->atime = 0; 184b66f2d16SKris Kennaway a->mtime = 0; 185b66f2d16SKris Kennaway } 186b66f2d16SKris Kennaway 187b66f2d16SKris Kennaway Attrib * 188b66f2d16SKris Kennaway decode_attrib(Buffer *b) 189b66f2d16SKris Kennaway { 190b66f2d16SKris Kennaway static Attrib a; 191b66f2d16SKris Kennaway attrib_clear(&a); 192b66f2d16SKris Kennaway a.flags = buffer_get_int(b); 193b66f2d16SKris Kennaway if (a.flags & SSH_FXA_HAVE_SIZE) { 194b66f2d16SKris Kennaway a.size_high = buffer_get_int(b); 195b66f2d16SKris Kennaway a.size_low = buffer_get_int(b); 196b66f2d16SKris Kennaway a.size = (((u_int64_t) a.size_high) << 32) + a.size_low; 197b66f2d16SKris Kennaway } 198b66f2d16SKris Kennaway if (a.flags & SSH_FXA_HAVE_UGID) { 199b66f2d16SKris Kennaway a.uid = buffer_get_int(b); 200b66f2d16SKris Kennaway a.gid = buffer_get_int(b); 201b66f2d16SKris Kennaway } 202b66f2d16SKris Kennaway if (a.flags & SSH_FXA_HAVE_PERM) { 203b66f2d16SKris Kennaway a.perm = buffer_get_int(b); 204b66f2d16SKris Kennaway } 205b66f2d16SKris Kennaway if (a.flags & SSH_FXA_HAVE_TIME) { 206b66f2d16SKris Kennaway a.atime = buffer_get_int(b); 207b66f2d16SKris Kennaway a.mtime = buffer_get_int(b); 208b66f2d16SKris Kennaway } 209b66f2d16SKris Kennaway return &a; 210b66f2d16SKris Kennaway } 211b66f2d16SKris Kennaway 212b66f2d16SKris Kennaway void 213b66f2d16SKris Kennaway encode_attrib(Buffer *b, Attrib *a) 214b66f2d16SKris Kennaway { 215b66f2d16SKris Kennaway buffer_put_int(b, a->flags); 216b66f2d16SKris Kennaway if (a->flags & SSH_FXA_HAVE_SIZE) { 217b66f2d16SKris Kennaway buffer_put_int(b, a->size_high); 218b66f2d16SKris Kennaway buffer_put_int(b, a->size_low); 219b66f2d16SKris Kennaway } 220b66f2d16SKris Kennaway if (a->flags & SSH_FXA_HAVE_UGID) { 221b66f2d16SKris Kennaway buffer_put_int(b, a->uid); 222b66f2d16SKris Kennaway buffer_put_int(b, a->gid); 223b66f2d16SKris Kennaway } 224b66f2d16SKris Kennaway if (a->flags & SSH_FXA_HAVE_PERM) { 225b66f2d16SKris Kennaway buffer_put_int(b, a->perm); 226b66f2d16SKris Kennaway } 227b66f2d16SKris Kennaway if (a->flags & SSH_FXA_HAVE_TIME) { 228b66f2d16SKris Kennaway buffer_put_int(b, a->atime); 229b66f2d16SKris Kennaway buffer_put_int(b, a->mtime); 230b66f2d16SKris Kennaway } 231b66f2d16SKris Kennaway } 232b66f2d16SKris Kennaway 233b66f2d16SKris Kennaway Attrib * 234b66f2d16SKris Kennaway stat_to_attrib(struct stat *st) 235b66f2d16SKris Kennaway { 236b66f2d16SKris Kennaway static Attrib a; 237b66f2d16SKris Kennaway attrib_clear(&a); 238b66f2d16SKris Kennaway a.flags = 0; 239b66f2d16SKris Kennaway a.flags |= SSH_FXA_HAVE_SIZE; 240b66f2d16SKris Kennaway a.size = st->st_size; 241b66f2d16SKris Kennaway a.size_low = a.size; 242b66f2d16SKris Kennaway a.size_high = (u_int32_t) (a.size >> 32); 243b66f2d16SKris Kennaway a.flags |= SSH_FXA_HAVE_UGID; 244b66f2d16SKris Kennaway a.uid = st->st_uid; 245b66f2d16SKris Kennaway a.gid = st->st_gid; 246b66f2d16SKris Kennaway a.flags |= SSH_FXA_HAVE_PERM; 247b66f2d16SKris Kennaway a.perm = st->st_mode; 248b66f2d16SKris Kennaway a.flags |= SSH_FXA_HAVE_TIME; 249b66f2d16SKris Kennaway a.atime = st->st_atime; 250b66f2d16SKris Kennaway a.mtime = st->st_mtime; 251b66f2d16SKris Kennaway return &a; 252b66f2d16SKris Kennaway } 253b66f2d16SKris Kennaway 254b66f2d16SKris Kennaway Attrib * 255b66f2d16SKris Kennaway get_attrib(void) 256b66f2d16SKris Kennaway { 257b66f2d16SKris Kennaway return decode_attrib(&iqueue); 258b66f2d16SKris Kennaway } 259b66f2d16SKris Kennaway 260b66f2d16SKris Kennaway /* handle handles */ 261b66f2d16SKris Kennaway 262b66f2d16SKris Kennaway typedef struct Handle Handle; 263b66f2d16SKris Kennaway struct Handle { 264b66f2d16SKris Kennaway int use; 265b66f2d16SKris Kennaway DIR *dirp; 266b66f2d16SKris Kennaway int fd; 267b66f2d16SKris Kennaway char *name; 268b66f2d16SKris Kennaway }; 269b66f2d16SKris Kennaway enum { 270b66f2d16SKris Kennaway HANDLE_UNUSED, 271b66f2d16SKris Kennaway HANDLE_DIR, 272b66f2d16SKris Kennaway HANDLE_FILE 273b66f2d16SKris Kennaway }; 274b66f2d16SKris Kennaway Handle handles[100]; 275b66f2d16SKris Kennaway 276b66f2d16SKris Kennaway void 277b66f2d16SKris Kennaway handle_init(void) 278b66f2d16SKris Kennaway { 279b66f2d16SKris Kennaway int i; 280b66f2d16SKris Kennaway for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) 281b66f2d16SKris Kennaway handles[i].use = HANDLE_UNUSED; 282b66f2d16SKris Kennaway } 283b66f2d16SKris Kennaway 284b66f2d16SKris Kennaway int 285b66f2d16SKris Kennaway handle_new(int use, char *name, int fd, DIR *dirp) 286b66f2d16SKris Kennaway { 287b66f2d16SKris Kennaway int i; 288b66f2d16SKris Kennaway for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) { 289b66f2d16SKris Kennaway if (handles[i].use == HANDLE_UNUSED) { 290b66f2d16SKris Kennaway handles[i].use = use; 291b66f2d16SKris Kennaway handles[i].dirp = dirp; 292b66f2d16SKris Kennaway handles[i].fd = fd; 293b66f2d16SKris Kennaway handles[i].name = name; 294b66f2d16SKris Kennaway return i; 295b66f2d16SKris Kennaway } 296b66f2d16SKris Kennaway } 297b66f2d16SKris Kennaway return -1; 298b66f2d16SKris Kennaway } 299b66f2d16SKris Kennaway 300b66f2d16SKris Kennaway int 301b66f2d16SKris Kennaway handle_is_ok(int i, int type) 302b66f2d16SKris Kennaway { 303b66f2d16SKris Kennaway return i >= 0 && i < sizeof(handles)/sizeof(Handle) && handles[i].use == type; 304b66f2d16SKris Kennaway } 305b66f2d16SKris Kennaway 306b66f2d16SKris Kennaway int 307b66f2d16SKris Kennaway handle_to_string(int handle, char **stringp, int *hlenp) 308b66f2d16SKris Kennaway { 309b66f2d16SKris Kennaway char buf[1024]; 310b66f2d16SKris Kennaway if (stringp == NULL || hlenp == NULL) 311b66f2d16SKris Kennaway return -1; 312b66f2d16SKris Kennaway snprintf(buf, sizeof buf, "%d", handle); 313b66f2d16SKris Kennaway *stringp = xstrdup(buf); 314b66f2d16SKris Kennaway *hlenp = strlen(*stringp); 315b66f2d16SKris Kennaway return 0; 316b66f2d16SKris Kennaway } 317b66f2d16SKris Kennaway 318b66f2d16SKris Kennaway int 319b66f2d16SKris Kennaway handle_from_string(char *handle, u_int hlen) 320b66f2d16SKris Kennaway { 321b66f2d16SKris Kennaway /* XXX OVERFLOW ? */ 322b66f2d16SKris Kennaway char *ep; 323b66f2d16SKris Kennaway long lval = strtol(handle, &ep, 10); 324b66f2d16SKris Kennaway int val = lval; 325b66f2d16SKris Kennaway if (*ep != '\0') 326b66f2d16SKris Kennaway return -1; 327b66f2d16SKris Kennaway if (handle_is_ok(val, HANDLE_FILE) || 328b66f2d16SKris Kennaway handle_is_ok(val, HANDLE_DIR)) 329b66f2d16SKris Kennaway return val; 330b66f2d16SKris Kennaway return -1; 331b66f2d16SKris Kennaway } 332b66f2d16SKris Kennaway 333b66f2d16SKris Kennaway char * 334b66f2d16SKris Kennaway handle_to_name(int handle) 335b66f2d16SKris Kennaway { 336b66f2d16SKris Kennaway if (handle_is_ok(handle, HANDLE_DIR)|| 337b66f2d16SKris Kennaway handle_is_ok(handle, HANDLE_FILE)) 338b66f2d16SKris Kennaway return handles[handle].name; 339b66f2d16SKris Kennaway return NULL; 340b66f2d16SKris Kennaway } 341b66f2d16SKris Kennaway 342b66f2d16SKris Kennaway DIR * 343b66f2d16SKris Kennaway handle_to_dir(int handle) 344b66f2d16SKris Kennaway { 345b66f2d16SKris Kennaway if (handle_is_ok(handle, HANDLE_DIR)) 346b66f2d16SKris Kennaway return handles[handle].dirp; 347b66f2d16SKris Kennaway return NULL; 348b66f2d16SKris Kennaway } 349b66f2d16SKris Kennaway 350b66f2d16SKris Kennaway int 351b66f2d16SKris Kennaway handle_to_fd(int handle) 352b66f2d16SKris Kennaway { 353b66f2d16SKris Kennaway if (handle_is_ok(handle, HANDLE_FILE)) 354b66f2d16SKris Kennaway return handles[handle].fd; 355b66f2d16SKris Kennaway return -1; 356b66f2d16SKris Kennaway } 357b66f2d16SKris Kennaway 358b66f2d16SKris Kennaway int 359b66f2d16SKris Kennaway handle_close(int handle) 360b66f2d16SKris Kennaway { 361b66f2d16SKris Kennaway int ret = -1; 362b66f2d16SKris Kennaway if (handle_is_ok(handle, HANDLE_FILE)) { 363b66f2d16SKris Kennaway ret = close(handles[handle].fd); 364b66f2d16SKris Kennaway handles[handle].use = HANDLE_UNUSED; 365b66f2d16SKris Kennaway } else if (handle_is_ok(handle, HANDLE_DIR)) { 366b66f2d16SKris Kennaway ret = closedir(handles[handle].dirp); 367b66f2d16SKris Kennaway handles[handle].use = HANDLE_UNUSED; 368b66f2d16SKris Kennaway } else { 369b66f2d16SKris Kennaway errno = ENOENT; 370b66f2d16SKris Kennaway } 371b66f2d16SKris Kennaway return ret; 372b66f2d16SKris Kennaway } 373b66f2d16SKris Kennaway 374b66f2d16SKris Kennaway int 375b66f2d16SKris Kennaway get_handle(void) 376b66f2d16SKris Kennaway { 377b66f2d16SKris Kennaway char *handle; 378b66f2d16SKris Kennaway int val; 379b66f2d16SKris Kennaway u_int hlen; 380b66f2d16SKris Kennaway handle = get_string(&hlen); 381b66f2d16SKris Kennaway val = handle_from_string(handle, hlen); 382b66f2d16SKris Kennaway xfree(handle); 383b66f2d16SKris Kennaway return val; 384b66f2d16SKris Kennaway } 385b66f2d16SKris Kennaway 386b66f2d16SKris Kennaway /* send replies */ 387b66f2d16SKris Kennaway 388b66f2d16SKris Kennaway void 389b66f2d16SKris Kennaway send_msg(Buffer *m) 390b66f2d16SKris Kennaway { 391b66f2d16SKris Kennaway int mlen = buffer_len(m); 392b66f2d16SKris Kennaway buffer_put_int(&oqueue, mlen); 393b66f2d16SKris Kennaway buffer_append(&oqueue, buffer_ptr(m), mlen); 394b66f2d16SKris Kennaway buffer_consume(m, mlen); 395b66f2d16SKris Kennaway } 396b66f2d16SKris Kennaway 397b66f2d16SKris Kennaway void 398b66f2d16SKris Kennaway send_status(u_int32_t id, u_int32_t error) 399b66f2d16SKris Kennaway { 400b66f2d16SKris Kennaway Buffer msg; 401b66f2d16SKris Kennaway TRACE("sent status id %d error %d", id, error); 402b66f2d16SKris Kennaway buffer_init(&msg); 403b66f2d16SKris Kennaway buffer_put_char(&msg, SSH_FXP_STATUS); 404b66f2d16SKris Kennaway buffer_put_int(&msg, id); 405b66f2d16SKris Kennaway buffer_put_int(&msg, error); 406b66f2d16SKris Kennaway send_msg(&msg); 407b66f2d16SKris Kennaway buffer_free(&msg); 408b66f2d16SKris Kennaway } 409b66f2d16SKris Kennaway void 410b66f2d16SKris Kennaway send_data_or_handle(char type, u_int32_t id, char *data, int dlen) 411b66f2d16SKris Kennaway { 412b66f2d16SKris Kennaway Buffer msg; 413b66f2d16SKris Kennaway buffer_init(&msg); 414b66f2d16SKris Kennaway buffer_put_char(&msg, type); 415b66f2d16SKris Kennaway buffer_put_int(&msg, id); 416b66f2d16SKris Kennaway buffer_put_string(&msg, data, dlen); 417b66f2d16SKris Kennaway send_msg(&msg); 418b66f2d16SKris Kennaway buffer_free(&msg); 419b66f2d16SKris Kennaway } 420b66f2d16SKris Kennaway 421b66f2d16SKris Kennaway void 422b66f2d16SKris Kennaway send_data(u_int32_t id, char *data, int dlen) 423b66f2d16SKris Kennaway { 424b66f2d16SKris Kennaway TRACE("sent data id %d len %d", id, dlen); 425b66f2d16SKris Kennaway send_data_or_handle(SSH_FXP_DATA, id, data, dlen); 426b66f2d16SKris Kennaway } 427b66f2d16SKris Kennaway 428b66f2d16SKris Kennaway void 429b66f2d16SKris Kennaway send_handle(u_int32_t id, int handle) 430b66f2d16SKris Kennaway { 431b66f2d16SKris Kennaway char *string; 432b66f2d16SKris Kennaway int hlen; 433b66f2d16SKris Kennaway handle_to_string(handle, &string, &hlen); 434b66f2d16SKris Kennaway TRACE("sent handle id %d handle %d", id, handle); 435b66f2d16SKris Kennaway send_data_or_handle(SSH_FXP_HANDLE, id, string, hlen); 436b66f2d16SKris Kennaway xfree(string); 437b66f2d16SKris Kennaway } 438b66f2d16SKris Kennaway 439b66f2d16SKris Kennaway void 440b66f2d16SKris Kennaway send_names(u_int32_t id, int count, Stat *stats) 441b66f2d16SKris Kennaway { 442b66f2d16SKris Kennaway Buffer msg; 443b66f2d16SKris Kennaway int i; 444b66f2d16SKris Kennaway buffer_init(&msg); 445b66f2d16SKris Kennaway buffer_put_char(&msg, SSH_FXP_NAME); 446b66f2d16SKris Kennaway buffer_put_int(&msg, id); 447b66f2d16SKris Kennaway buffer_put_int(&msg, count); 448b66f2d16SKris Kennaway TRACE("sent names id %d count %d", id, count); 449b66f2d16SKris Kennaway for (i = 0; i < count; i++) { 450b66f2d16SKris Kennaway buffer_put_cstring(&msg, stats[i].name); 451b66f2d16SKris Kennaway buffer_put_cstring(&msg, stats[i].long_name); 452b66f2d16SKris Kennaway encode_attrib(&msg, &stats[i].attrib); 453b66f2d16SKris Kennaway } 454b66f2d16SKris Kennaway send_msg(&msg); 455b66f2d16SKris Kennaway buffer_free(&msg); 456b66f2d16SKris Kennaway } 457b66f2d16SKris Kennaway 458b66f2d16SKris Kennaway void 459b66f2d16SKris Kennaway send_attrib(u_int32_t id, Attrib *a) 460b66f2d16SKris Kennaway { 461b66f2d16SKris Kennaway Buffer msg; 462b66f2d16SKris Kennaway TRACE("sent attrib id %d have 0x%x", id, a->flags); 463b66f2d16SKris Kennaway buffer_init(&msg); 464b66f2d16SKris Kennaway buffer_put_char(&msg, SSH_FXP_ATTRS); 465b66f2d16SKris Kennaway buffer_put_int(&msg, id); 466b66f2d16SKris Kennaway encode_attrib(&msg, a); 467b66f2d16SKris Kennaway send_msg(&msg); 468b66f2d16SKris Kennaway buffer_free(&msg); 469b66f2d16SKris Kennaway } 470b66f2d16SKris Kennaway 471b66f2d16SKris Kennaway /* parse incoming */ 472b66f2d16SKris Kennaway 473b66f2d16SKris Kennaway void 474b66f2d16SKris Kennaway process_init(void) 475b66f2d16SKris Kennaway { 476b66f2d16SKris Kennaway Buffer msg; 477b66f2d16SKris Kennaway int version = buffer_get_int(&iqueue); 478b66f2d16SKris Kennaway 479b66f2d16SKris Kennaway TRACE("client version %d", version); 480b66f2d16SKris Kennaway buffer_init(&msg); 481b66f2d16SKris Kennaway buffer_put_char(&msg, SSH_FXP_VERSION); 482b66f2d16SKris Kennaway buffer_put_int(&msg, SSH_FILEXFER_VERSION); 483b66f2d16SKris Kennaway send_msg(&msg); 484b66f2d16SKris Kennaway buffer_free(&msg); 485b66f2d16SKris Kennaway } 486b66f2d16SKris Kennaway 487b66f2d16SKris Kennaway void 488b66f2d16SKris Kennaway process_open(void) 489b66f2d16SKris Kennaway { 490b66f2d16SKris Kennaway u_int32_t id, pflags; 491b66f2d16SKris Kennaway Attrib *a; 492b66f2d16SKris Kennaway char *name; 493b66f2d16SKris Kennaway int handle, fd, flags, mode, status = SSH_FX_FAILURE; 494b66f2d16SKris Kennaway 495b66f2d16SKris Kennaway id = get_int(); 496b66f2d16SKris Kennaway name = get_string(NULL); 497b66f2d16SKris Kennaway pflags = get_int(); 498b66f2d16SKris Kennaway a = get_attrib(); 499b66f2d16SKris Kennaway flags = flags_from_portable(pflags); 500b66f2d16SKris Kennaway mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm : 0666; 501b66f2d16SKris Kennaway TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode); 502b66f2d16SKris Kennaway fd = open(name, flags, mode); 503b66f2d16SKris Kennaway if (fd < 0) { 504b66f2d16SKris Kennaway status = errno_to_portable(errno); 505b66f2d16SKris Kennaway } else { 506b66f2d16SKris Kennaway handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL); 507b66f2d16SKris Kennaway if (handle < 0) { 508b66f2d16SKris Kennaway close(fd); 509b66f2d16SKris Kennaway } else { 510b66f2d16SKris Kennaway send_handle(id, handle); 511b66f2d16SKris Kennaway status = SSH_FX_OK; 512b66f2d16SKris Kennaway } 513b66f2d16SKris Kennaway } 514b66f2d16SKris Kennaway if (status != SSH_FX_OK) 515b66f2d16SKris Kennaway send_status(id, status); 516b66f2d16SKris Kennaway xfree(name); 517b66f2d16SKris Kennaway } 518b66f2d16SKris Kennaway 519b66f2d16SKris Kennaway void 520b66f2d16SKris Kennaway process_close(void) 521b66f2d16SKris Kennaway { 522b66f2d16SKris Kennaway u_int32_t id; 523b66f2d16SKris Kennaway int handle, ret, status = SSH_FX_FAILURE; 524b66f2d16SKris Kennaway 525b66f2d16SKris Kennaway id = get_int(); 526b66f2d16SKris Kennaway handle = get_handle(); 527b66f2d16SKris Kennaway TRACE("close id %d handle %d", id, handle); 528b66f2d16SKris Kennaway ret = handle_close(handle); 529b66f2d16SKris Kennaway status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; 530b66f2d16SKris Kennaway send_status(id, status); 531b66f2d16SKris Kennaway } 532b66f2d16SKris Kennaway 533b66f2d16SKris Kennaway void 534b66f2d16SKris Kennaway process_read(void) 535b66f2d16SKris Kennaway { 536b66f2d16SKris Kennaway char buf[64*1024]; 537b66f2d16SKris Kennaway u_int32_t id, off_high, off_low, len; 538b66f2d16SKris Kennaway int handle, fd, ret, status = SSH_FX_FAILURE; 539b66f2d16SKris Kennaway u_int64_t off; 540b66f2d16SKris Kennaway 541b66f2d16SKris Kennaway id = get_int(); 542b66f2d16SKris Kennaway handle = get_handle(); 543b66f2d16SKris Kennaway off_high = get_int(); 544b66f2d16SKris Kennaway off_low = get_int(); 545b66f2d16SKris Kennaway len = get_int(); 546b66f2d16SKris Kennaway 547b66f2d16SKris Kennaway off = (((u_int64_t) off_high) << 32) + off_low; 548b66f2d16SKris Kennaway TRACE("read id %d handle %d off %qd len %d", id, handle, off, len); 549b66f2d16SKris Kennaway if (len > sizeof buf) { 550b66f2d16SKris Kennaway len = sizeof buf; 551b66f2d16SKris Kennaway log("read change len %d", len); 552b66f2d16SKris Kennaway } 553b66f2d16SKris Kennaway fd = handle_to_fd(handle); 554b66f2d16SKris Kennaway if (fd >= 0) { 555b66f2d16SKris Kennaway if (lseek(fd, off, SEEK_SET) < 0) { 556b66f2d16SKris Kennaway error("process_read: seek failed"); 557b66f2d16SKris Kennaway status = errno_to_portable(errno); 558b66f2d16SKris Kennaway } else { 559b66f2d16SKris Kennaway ret = read(fd, buf, len); 560b66f2d16SKris Kennaway if (ret < 0) { 561b66f2d16SKris Kennaway status = errno_to_portable(errno); 562b66f2d16SKris Kennaway } else if (ret == 0) { 563b66f2d16SKris Kennaway status = SSH_FX_EOF; 564b66f2d16SKris Kennaway } else { 565b66f2d16SKris Kennaway send_data(id, buf, ret); 566b66f2d16SKris Kennaway status = SSH_FX_OK; 567b66f2d16SKris Kennaway } 568b66f2d16SKris Kennaway } 569b66f2d16SKris Kennaway } 570b66f2d16SKris Kennaway if (status != SSH_FX_OK) 571b66f2d16SKris Kennaway send_status(id, status); 572b66f2d16SKris Kennaway } 573b66f2d16SKris Kennaway 574b66f2d16SKris Kennaway void 575b66f2d16SKris Kennaway process_write(void) 576b66f2d16SKris Kennaway { 577b66f2d16SKris Kennaway u_int32_t id, off_high, off_low; 578b66f2d16SKris Kennaway u_int64_t off; 579b66f2d16SKris Kennaway u_int len; 580b66f2d16SKris Kennaway int handle, fd, ret, status = SSH_FX_FAILURE; 581b66f2d16SKris Kennaway char *data; 582b66f2d16SKris Kennaway 583b66f2d16SKris Kennaway id = get_int(); 584b66f2d16SKris Kennaway handle = get_handle(); 585b66f2d16SKris Kennaway off_high = get_int(); 586b66f2d16SKris Kennaway off_low = get_int(); 587b66f2d16SKris Kennaway data = get_string(&len); 588b66f2d16SKris Kennaway 589b66f2d16SKris Kennaway off = (((u_int64_t) off_high) << 32) + off_low; 590b66f2d16SKris Kennaway TRACE("write id %d handle %d off %qd len %d", id, handle, off, len); 591b66f2d16SKris Kennaway fd = handle_to_fd(handle); 592b66f2d16SKris Kennaway if (fd >= 0) { 593b66f2d16SKris Kennaway if (lseek(fd, off, SEEK_SET) < 0) { 594b66f2d16SKris Kennaway status = errno_to_portable(errno); 595b66f2d16SKris Kennaway error("process_write: seek failed"); 596b66f2d16SKris Kennaway } else { 597b66f2d16SKris Kennaway /* XXX ATOMICIO ? */ 598b66f2d16SKris Kennaway ret = write(fd, data, len); 599b66f2d16SKris Kennaway if (ret == -1) { 600b66f2d16SKris Kennaway error("process_write: write failed"); 601b66f2d16SKris Kennaway status = errno_to_portable(errno); 602b66f2d16SKris Kennaway } else if (ret == len) { 603b66f2d16SKris Kennaway status = SSH_FX_OK; 604b66f2d16SKris Kennaway } else { 605b66f2d16SKris Kennaway log("nothing at all written"); 606b66f2d16SKris Kennaway } 607b66f2d16SKris Kennaway } 608b66f2d16SKris Kennaway } 609b66f2d16SKris Kennaway send_status(id, status); 610b66f2d16SKris Kennaway xfree(data); 611b66f2d16SKris Kennaway } 612b66f2d16SKris Kennaway 613b66f2d16SKris Kennaway void 614b66f2d16SKris Kennaway process_do_stat(int do_lstat) 615b66f2d16SKris Kennaway { 616b66f2d16SKris Kennaway Attrib *a; 617b66f2d16SKris Kennaway struct stat st; 618b66f2d16SKris Kennaway u_int32_t id; 619b66f2d16SKris Kennaway char *name; 620b66f2d16SKris Kennaway int ret, status = SSH_FX_FAILURE; 621b66f2d16SKris Kennaway 622b66f2d16SKris Kennaway id = get_int(); 623b66f2d16SKris Kennaway name = get_string(NULL); 624b66f2d16SKris Kennaway TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name); 625b66f2d16SKris Kennaway ret = do_lstat ? lstat(name, &st) : stat(name, &st); 626b66f2d16SKris Kennaway if (ret < 0) { 627b66f2d16SKris Kennaway status = errno_to_portable(errno); 628b66f2d16SKris Kennaway } else { 629b66f2d16SKris Kennaway a = stat_to_attrib(&st); 630b66f2d16SKris Kennaway send_attrib(id, a); 631b66f2d16SKris Kennaway status = SSH_FX_OK; 632b66f2d16SKris Kennaway } 633b66f2d16SKris Kennaway if (status != SSH_FX_OK) 634b66f2d16SKris Kennaway send_status(id, status); 635b66f2d16SKris Kennaway xfree(name); 636b66f2d16SKris Kennaway } 637b66f2d16SKris Kennaway 638b66f2d16SKris Kennaway void 639b66f2d16SKris Kennaway process_stat(void) 640b66f2d16SKris Kennaway { 641b66f2d16SKris Kennaway process_do_stat(0); 642b66f2d16SKris Kennaway } 643b66f2d16SKris Kennaway 644b66f2d16SKris Kennaway void 645b66f2d16SKris Kennaway process_lstat(void) 646b66f2d16SKris Kennaway { 647b66f2d16SKris Kennaway process_do_stat(1); 648b66f2d16SKris Kennaway } 649b66f2d16SKris Kennaway 650b66f2d16SKris Kennaway void 651b66f2d16SKris Kennaway process_fstat(void) 652b66f2d16SKris Kennaway { 653b66f2d16SKris Kennaway Attrib *a; 654b66f2d16SKris Kennaway struct stat st; 655b66f2d16SKris Kennaway u_int32_t id; 656b66f2d16SKris Kennaway int fd, ret, handle, status = SSH_FX_FAILURE; 657b66f2d16SKris Kennaway 658b66f2d16SKris Kennaway id = get_int(); 659b66f2d16SKris Kennaway handle = get_handle(); 660b66f2d16SKris Kennaway TRACE("fstat id %d handle %d", id, handle); 661b66f2d16SKris Kennaway fd = handle_to_fd(handle); 662b66f2d16SKris Kennaway if (fd >= 0) { 663b66f2d16SKris Kennaway ret = fstat(fd, &st); 664b66f2d16SKris Kennaway if (ret < 0) { 665b66f2d16SKris Kennaway status = errno_to_portable(errno); 666b66f2d16SKris Kennaway } else { 667b66f2d16SKris Kennaway a = stat_to_attrib(&st); 668b66f2d16SKris Kennaway send_attrib(id, a); 669b66f2d16SKris Kennaway status = SSH_FX_OK; 670b66f2d16SKris Kennaway } 671b66f2d16SKris Kennaway } 672b66f2d16SKris Kennaway if (status != SSH_FX_OK) 673b66f2d16SKris Kennaway send_status(id, status); 674b66f2d16SKris Kennaway } 675b66f2d16SKris Kennaway 676b66f2d16SKris Kennaway struct timeval * 677b66f2d16SKris Kennaway attrib_to_tv(Attrib *a) 678b66f2d16SKris Kennaway { 679b66f2d16SKris Kennaway static struct timeval tv[2]; 680b66f2d16SKris Kennaway tv[0].tv_sec = a->atime; 681b66f2d16SKris Kennaway tv[0].tv_usec = 0; 682b66f2d16SKris Kennaway tv[1].tv_sec = a->mtime; 683b66f2d16SKris Kennaway tv[1].tv_usec = 0; 684b66f2d16SKris Kennaway return tv; 685b66f2d16SKris Kennaway } 686b66f2d16SKris Kennaway 687b66f2d16SKris Kennaway void 688b66f2d16SKris Kennaway process_setstat(void) 689b66f2d16SKris Kennaway { 690b66f2d16SKris Kennaway Attrib *a; 691b66f2d16SKris Kennaway u_int32_t id; 692b66f2d16SKris Kennaway char *name; 693b66f2d16SKris Kennaway int ret; 694b66f2d16SKris Kennaway int status = SSH_FX_OK; 695b66f2d16SKris Kennaway 696b66f2d16SKris Kennaway id = get_int(); 697b66f2d16SKris Kennaway name = get_string(NULL); 698b66f2d16SKris Kennaway a = get_attrib(); 699b66f2d16SKris Kennaway TRACE("setstat id %d name %s", id, name); 700b66f2d16SKris Kennaway if (a->flags & SSH_FXA_HAVE_PERM) { 701b66f2d16SKris Kennaway ret = chmod(name, a->perm & 0777); 702b66f2d16SKris Kennaway if (ret == -1) 703b66f2d16SKris Kennaway status = errno_to_portable(errno); 704b66f2d16SKris Kennaway } 705b66f2d16SKris Kennaway if (a->flags & SSH_FXA_HAVE_TIME) { 706b66f2d16SKris Kennaway ret = utimes(name, attrib_to_tv(a)); 707b66f2d16SKris Kennaway if (ret == -1) 708b66f2d16SKris Kennaway status = errno_to_portable(errno); 709b66f2d16SKris Kennaway } 710b66f2d16SKris Kennaway send_status(id, status); 711b66f2d16SKris Kennaway xfree(name); 712b66f2d16SKris Kennaway } 713b66f2d16SKris Kennaway 714b66f2d16SKris Kennaway void 715b66f2d16SKris Kennaway process_fsetstat(void) 716b66f2d16SKris Kennaway { 717b66f2d16SKris Kennaway Attrib *a; 718b66f2d16SKris Kennaway u_int32_t id; 719b66f2d16SKris Kennaway int handle, fd, ret; 720b66f2d16SKris Kennaway int status = SSH_FX_OK; 721b66f2d16SKris Kennaway 722b66f2d16SKris Kennaway id = get_int(); 723b66f2d16SKris Kennaway handle = get_handle(); 724b66f2d16SKris Kennaway a = get_attrib(); 725b66f2d16SKris Kennaway TRACE("fsetstat id %d handle %d", id, handle); 726b66f2d16SKris Kennaway fd = handle_to_fd(handle); 727b66f2d16SKris Kennaway if (fd < 0) { 728b66f2d16SKris Kennaway status = SSH_FX_FAILURE; 729b66f2d16SKris Kennaway } else { 730b66f2d16SKris Kennaway if (a->flags & SSH_FXA_HAVE_PERM) { 731b66f2d16SKris Kennaway ret = fchmod(fd, a->perm & 0777); 732b66f2d16SKris Kennaway if (ret == -1) 733b66f2d16SKris Kennaway status = errno_to_portable(errno); 734b66f2d16SKris Kennaway } 735b66f2d16SKris Kennaway if (a->flags & SSH_FXA_HAVE_TIME) { 736b66f2d16SKris Kennaway ret = futimes(fd, attrib_to_tv(a)); 737b66f2d16SKris Kennaway if (ret == -1) 738b66f2d16SKris Kennaway status = errno_to_portable(errno); 739b66f2d16SKris Kennaway } 740b66f2d16SKris Kennaway } 741b66f2d16SKris Kennaway send_status(id, status); 742b66f2d16SKris Kennaway } 743b66f2d16SKris Kennaway 744b66f2d16SKris Kennaway void 745b66f2d16SKris Kennaway process_opendir(void) 746b66f2d16SKris Kennaway { 747b66f2d16SKris Kennaway DIR *dirp = NULL; 748b66f2d16SKris Kennaway char *path; 749b66f2d16SKris Kennaway int handle, status = SSH_FX_FAILURE; 750b66f2d16SKris Kennaway u_int32_t id; 751b66f2d16SKris Kennaway 752b66f2d16SKris Kennaway id = get_int(); 753b66f2d16SKris Kennaway path = get_string(NULL); 754b66f2d16SKris Kennaway TRACE("opendir id %d path %s", id, path); 755b66f2d16SKris Kennaway dirp = opendir(path); 756b66f2d16SKris Kennaway if (dirp == NULL) { 757b66f2d16SKris Kennaway status = errno_to_portable(errno); 758b66f2d16SKris Kennaway } else { 759b66f2d16SKris Kennaway handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp); 760b66f2d16SKris Kennaway if (handle < 0) { 761b66f2d16SKris Kennaway closedir(dirp); 762b66f2d16SKris Kennaway } else { 763b66f2d16SKris Kennaway send_handle(id, handle); 764b66f2d16SKris Kennaway status = SSH_FX_OK; 765b66f2d16SKris Kennaway } 766b66f2d16SKris Kennaway 767b66f2d16SKris Kennaway } 768b66f2d16SKris Kennaway if (status != SSH_FX_OK) 769b66f2d16SKris Kennaway send_status(id, status); 770b66f2d16SKris Kennaway xfree(path); 771b66f2d16SKris Kennaway } 772b66f2d16SKris Kennaway 773b66f2d16SKris Kennaway char * 774b66f2d16SKris Kennaway ls_file(char *name, struct stat *st) 775b66f2d16SKris Kennaway { 776b66f2d16SKris Kennaway char buf[1024]; 777b66f2d16SKris Kennaway snprintf(buf, sizeof buf, "0%o %d %d %qd %d %s", 778b66f2d16SKris Kennaway st->st_mode, st->st_uid, st->st_gid, (long long)st->st_size,(int) st->st_mtime, 779b66f2d16SKris Kennaway name); 780b66f2d16SKris Kennaway return xstrdup(buf); 781b66f2d16SKris Kennaway } 782b66f2d16SKris Kennaway 783b66f2d16SKris Kennaway void 784b66f2d16SKris Kennaway process_readdir(void) 785b66f2d16SKris Kennaway { 786b66f2d16SKris Kennaway DIR *dirp; 787b66f2d16SKris Kennaway struct dirent *dp; 788b66f2d16SKris Kennaway char *path; 789b66f2d16SKris Kennaway int handle; 790b66f2d16SKris Kennaway u_int32_t id; 791b66f2d16SKris Kennaway 792b66f2d16SKris Kennaway id = get_int(); 793b66f2d16SKris Kennaway handle = get_handle(); 794b66f2d16SKris Kennaway TRACE("readdir id %d handle %d", id, handle); 795b66f2d16SKris Kennaway dirp = handle_to_dir(handle); 796b66f2d16SKris Kennaway path = handle_to_name(handle); 797b66f2d16SKris Kennaway if (dirp == NULL || path == NULL) { 798b66f2d16SKris Kennaway send_status(id, SSH_FX_FAILURE); 799b66f2d16SKris Kennaway } else { 800b66f2d16SKris Kennaway Attrib *a; 801b66f2d16SKris Kennaway struct stat st; 802b66f2d16SKris Kennaway char pathname[1024]; 803b66f2d16SKris Kennaway Stat *stats; 804b66f2d16SKris Kennaway int nstats = 10, count = 0, i; 805b66f2d16SKris Kennaway stats = xmalloc(nstats * sizeof(Stat)); 806b66f2d16SKris Kennaway while ((dp = readdir(dirp)) != NULL) { 807b66f2d16SKris Kennaway if (count >= nstats) { 808b66f2d16SKris Kennaway nstats *= 2; 809b66f2d16SKris Kennaway stats = xrealloc(stats, nstats * sizeof(Stat)); 810b66f2d16SKris Kennaway } 811b66f2d16SKris Kennaway /* XXX OVERFLOW ? */ 812b66f2d16SKris Kennaway snprintf(pathname, sizeof pathname, 813b66f2d16SKris Kennaway "%s/%s", path, dp->d_name); 814b66f2d16SKris Kennaway if (lstat(pathname, &st) < 0) 815b66f2d16SKris Kennaway continue; 816b66f2d16SKris Kennaway a = stat_to_attrib(&st); 817b66f2d16SKris Kennaway stats[count].attrib = *a; 818b66f2d16SKris Kennaway stats[count].name = xstrdup(dp->d_name); 819b66f2d16SKris Kennaway stats[count].long_name = ls_file(dp->d_name, &st); 820b66f2d16SKris Kennaway count++; 821b66f2d16SKris Kennaway /* send up to 100 entries in one message */ 822b66f2d16SKris Kennaway if (count == 100) 823b66f2d16SKris Kennaway break; 824b66f2d16SKris Kennaway } 825b66f2d16SKris Kennaway send_names(id, count, stats); 826b66f2d16SKris Kennaway for(i = 0; i < count; i++) { 827b66f2d16SKris Kennaway xfree(stats[i].name); 828b66f2d16SKris Kennaway xfree(stats[i].long_name); 829b66f2d16SKris Kennaway } 830b66f2d16SKris Kennaway xfree(stats); 831b66f2d16SKris Kennaway } 832b66f2d16SKris Kennaway } 833b66f2d16SKris Kennaway 834b66f2d16SKris Kennaway void 835b66f2d16SKris Kennaway process_remove(void) 836b66f2d16SKris Kennaway { 837b66f2d16SKris Kennaway char *name; 838b66f2d16SKris Kennaway u_int32_t id; 839b66f2d16SKris Kennaway int status = SSH_FX_FAILURE; 840b66f2d16SKris Kennaway int ret; 841b66f2d16SKris Kennaway 842b66f2d16SKris Kennaway id = get_int(); 843b66f2d16SKris Kennaway name = get_string(NULL); 844b66f2d16SKris Kennaway TRACE("remove id %d name %s", id, name); 845b66f2d16SKris Kennaway ret = remove(name); 846b66f2d16SKris Kennaway status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; 847b66f2d16SKris Kennaway send_status(id, status); 848b66f2d16SKris Kennaway xfree(name); 849b66f2d16SKris Kennaway } 850b66f2d16SKris Kennaway 851b66f2d16SKris Kennaway void 852b66f2d16SKris Kennaway process_mkdir(void) 853b66f2d16SKris Kennaway { 854b66f2d16SKris Kennaway Attrib *a; 855b66f2d16SKris Kennaway u_int32_t id; 856b66f2d16SKris Kennaway char *name; 857b66f2d16SKris Kennaway int ret, mode, status = SSH_FX_FAILURE; 858b66f2d16SKris Kennaway 859b66f2d16SKris Kennaway id = get_int(); 860b66f2d16SKris Kennaway name = get_string(NULL); 861b66f2d16SKris Kennaway a = get_attrib(); 862b66f2d16SKris Kennaway mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm & 0777 : 0777; 863b66f2d16SKris Kennaway TRACE("mkdir id %d name %s mode 0%o", id, name, mode); 864b66f2d16SKris Kennaway ret = mkdir(name, mode); 865b66f2d16SKris Kennaway status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; 866b66f2d16SKris Kennaway send_status(id, status); 867b66f2d16SKris Kennaway xfree(name); 868b66f2d16SKris Kennaway } 869b66f2d16SKris Kennaway 870b66f2d16SKris Kennaway void 871b66f2d16SKris Kennaway process_rmdir(void) 872b66f2d16SKris Kennaway { 873b66f2d16SKris Kennaway u_int32_t id; 874b66f2d16SKris Kennaway char *name; 875b66f2d16SKris Kennaway int ret, status; 876b66f2d16SKris Kennaway 877b66f2d16SKris Kennaway id = get_int(); 878b66f2d16SKris Kennaway name = get_string(NULL); 879b66f2d16SKris Kennaway TRACE("rmdir id %d name %s", id, name); 880b66f2d16SKris Kennaway ret = rmdir(name); 881b66f2d16SKris Kennaway status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; 882b66f2d16SKris Kennaway send_status(id, status); 883b66f2d16SKris Kennaway xfree(name); 884b66f2d16SKris Kennaway } 885b66f2d16SKris Kennaway 886b66f2d16SKris Kennaway void 887b66f2d16SKris Kennaway process_realpath(void) 888b66f2d16SKris Kennaway { 889b66f2d16SKris Kennaway char resolvedname[MAXPATHLEN]; 890b66f2d16SKris Kennaway u_int32_t id; 891b66f2d16SKris Kennaway char *path; 892b66f2d16SKris Kennaway 893b66f2d16SKris Kennaway id = get_int(); 894b66f2d16SKris Kennaway path = get_string(NULL); 895b66f2d16SKris Kennaway TRACE("realpath id %d path %s", id, path); 896b66f2d16SKris Kennaway if (realpath(path, resolvedname) == NULL) { 897b66f2d16SKris Kennaway send_status(id, errno_to_portable(errno)); 898b66f2d16SKris Kennaway } else { 899b66f2d16SKris Kennaway Stat s; 900b66f2d16SKris Kennaway attrib_clear(&s.attrib); 901b66f2d16SKris Kennaway s.name = s.long_name = resolvedname; 902b66f2d16SKris Kennaway send_names(id, 1, &s); 903b66f2d16SKris Kennaway } 904b66f2d16SKris Kennaway xfree(path); 905b66f2d16SKris Kennaway } 906b66f2d16SKris Kennaway 907b66f2d16SKris Kennaway void 908b66f2d16SKris Kennaway process_rename(void) 909b66f2d16SKris Kennaway { 910b66f2d16SKris Kennaway u_int32_t id; 911b66f2d16SKris Kennaway char *oldpath, *newpath; 912b66f2d16SKris Kennaway int ret, status; 913b66f2d16SKris Kennaway 914b66f2d16SKris Kennaway id = get_int(); 915b66f2d16SKris Kennaway oldpath = get_string(NULL); 916b66f2d16SKris Kennaway newpath = get_string(NULL); 917b66f2d16SKris Kennaway TRACE("rename id %d old %s new %s", id, oldpath, newpath); 918b66f2d16SKris Kennaway ret = rename(oldpath, newpath); 919b66f2d16SKris Kennaway status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK; 920b66f2d16SKris Kennaway send_status(id, status); 921b66f2d16SKris Kennaway xfree(oldpath); 922b66f2d16SKris Kennaway xfree(newpath); 923b66f2d16SKris Kennaway } 924b66f2d16SKris Kennaway 925b66f2d16SKris Kennaway 926b66f2d16SKris Kennaway /* stolen from ssh-agent */ 927b66f2d16SKris Kennaway 928b66f2d16SKris Kennaway void 929b66f2d16SKris Kennaway process(void) 930b66f2d16SKris Kennaway { 931b66f2d16SKris Kennaway unsigned int msg_len; 932b66f2d16SKris Kennaway unsigned int type; 933b66f2d16SKris Kennaway unsigned char *cp; 934b66f2d16SKris Kennaway 935b66f2d16SKris Kennaway if (buffer_len(&iqueue) < 5) 936b66f2d16SKris Kennaway return; /* Incomplete message. */ 937b66f2d16SKris Kennaway cp = (unsigned char *) buffer_ptr(&iqueue); 938b66f2d16SKris Kennaway msg_len = GET_32BIT(cp); 939b66f2d16SKris Kennaway if (msg_len > 256 * 1024) { 940b66f2d16SKris Kennaway error("bad message "); 941b66f2d16SKris Kennaway exit(11); 942b66f2d16SKris Kennaway } 943b66f2d16SKris Kennaway if (buffer_len(&iqueue) < msg_len + 4) 944b66f2d16SKris Kennaway return; 945b66f2d16SKris Kennaway buffer_consume(&iqueue, 4); 946b66f2d16SKris Kennaway type = buffer_get_char(&iqueue); 947b66f2d16SKris Kennaway switch (type) { 948b66f2d16SKris Kennaway case SSH_FXP_INIT: 949b66f2d16SKris Kennaway process_init(); 950b66f2d16SKris Kennaway break; 951b66f2d16SKris Kennaway case SSH_FXP_OPEN: 952b66f2d16SKris Kennaway process_open(); 953b66f2d16SKris Kennaway break; 954b66f2d16SKris Kennaway case SSH_FXP_CLOSE: 955b66f2d16SKris Kennaway process_close(); 956b66f2d16SKris Kennaway break; 957b66f2d16SKris Kennaway case SSH_FXP_READ: 958b66f2d16SKris Kennaway process_read(); 959b66f2d16SKris Kennaway break; 960b66f2d16SKris Kennaway case SSH_FXP_WRITE: 961b66f2d16SKris Kennaway process_write(); 962b66f2d16SKris Kennaway break; 963b66f2d16SKris Kennaway case SSH_FXP_LSTAT: 964b66f2d16SKris Kennaway process_lstat(); 965b66f2d16SKris Kennaway break; 966b66f2d16SKris Kennaway case SSH_FXP_FSTAT: 967b66f2d16SKris Kennaway process_fstat(); 968b66f2d16SKris Kennaway break; 969b66f2d16SKris Kennaway case SSH_FXP_SETSTAT: 970b66f2d16SKris Kennaway process_setstat(); 971b66f2d16SKris Kennaway break; 972b66f2d16SKris Kennaway case SSH_FXP_FSETSTAT: 973b66f2d16SKris Kennaway process_fsetstat(); 974b66f2d16SKris Kennaway break; 975b66f2d16SKris Kennaway case SSH_FXP_OPENDIR: 976b66f2d16SKris Kennaway process_opendir(); 977b66f2d16SKris Kennaway break; 978b66f2d16SKris Kennaway case SSH_FXP_READDIR: 979b66f2d16SKris Kennaway process_readdir(); 980b66f2d16SKris Kennaway break; 981b66f2d16SKris Kennaway case SSH_FXP_REMOVE: 982b66f2d16SKris Kennaway process_remove(); 983b66f2d16SKris Kennaway break; 984b66f2d16SKris Kennaway case SSH_FXP_MKDIR: 985b66f2d16SKris Kennaway process_mkdir(); 986b66f2d16SKris Kennaway break; 987b66f2d16SKris Kennaway case SSH_FXP_RMDIR: 988b66f2d16SKris Kennaway process_rmdir(); 989b66f2d16SKris Kennaway break; 990b66f2d16SKris Kennaway case SSH_FXP_REALPATH: 991b66f2d16SKris Kennaway process_realpath(); 992b66f2d16SKris Kennaway break; 993b66f2d16SKris Kennaway case SSH_FXP_STAT: 994b66f2d16SKris Kennaway process_stat(); 995b66f2d16SKris Kennaway break; 996b66f2d16SKris Kennaway case SSH_FXP_RENAME: 997b66f2d16SKris Kennaway process_rename(); 998b66f2d16SKris Kennaway break; 999b66f2d16SKris Kennaway default: 1000b66f2d16SKris Kennaway error("Unknown message %d", type); 1001b66f2d16SKris Kennaway break; 1002b66f2d16SKris Kennaway } 1003b66f2d16SKris Kennaway } 1004b66f2d16SKris Kennaway 1005b66f2d16SKris Kennaway int 1006b66f2d16SKris Kennaway main(int ac, char **av) 1007b66f2d16SKris Kennaway { 1008b66f2d16SKris Kennaway fd_set rset, wset; 1009b66f2d16SKris Kennaway int in, out, max; 1010b66f2d16SKris Kennaway ssize_t len, olen; 1011b66f2d16SKris Kennaway 1012b66f2d16SKris Kennaway handle_init(); 1013b66f2d16SKris Kennaway 1014b66f2d16SKris Kennaway in = dup(STDIN_FILENO); 1015b66f2d16SKris Kennaway out = dup(STDOUT_FILENO); 1016b66f2d16SKris Kennaway 1017b66f2d16SKris Kennaway max = 0; 1018b66f2d16SKris Kennaway if (in > max) 1019b66f2d16SKris Kennaway max = in; 1020b66f2d16SKris Kennaway if (out > max) 1021b66f2d16SKris Kennaway max = out; 1022b66f2d16SKris Kennaway 1023b66f2d16SKris Kennaway buffer_init(&iqueue); 1024b66f2d16SKris Kennaway buffer_init(&oqueue); 1025b66f2d16SKris Kennaway 1026b66f2d16SKris Kennaway for (;;) { 1027b66f2d16SKris Kennaway FD_ZERO(&rset); 1028b66f2d16SKris Kennaway FD_ZERO(&wset); 1029b66f2d16SKris Kennaway 1030b66f2d16SKris Kennaway FD_SET(in, &rset); 1031b66f2d16SKris Kennaway olen = buffer_len(&oqueue); 1032b66f2d16SKris Kennaway if (olen > 0) 1033b66f2d16SKris Kennaway FD_SET(out, &wset); 1034b66f2d16SKris Kennaway 1035b66f2d16SKris Kennaway if (select(max+1, &rset, &wset, NULL, NULL) < 0) { 1036b66f2d16SKris Kennaway if (errno == EINTR) 1037b66f2d16SKris Kennaway continue; 1038b66f2d16SKris Kennaway exit(2); 1039b66f2d16SKris Kennaway } 1040b66f2d16SKris Kennaway 1041b66f2d16SKris Kennaway /* copy stdin to iqueue */ 1042b66f2d16SKris Kennaway if (FD_ISSET(in, &rset)) { 1043b66f2d16SKris Kennaway char buf[4*4096]; 1044b66f2d16SKris Kennaway len = read(in, buf, sizeof buf); 1045b66f2d16SKris Kennaway if (len == 0) { 1046b66f2d16SKris Kennaway debug("read eof"); 1047b66f2d16SKris Kennaway exit(0); 1048b66f2d16SKris Kennaway } else if (len < 0) { 1049b66f2d16SKris Kennaway error("read error"); 1050b66f2d16SKris Kennaway exit(1); 1051b66f2d16SKris Kennaway } else { 1052b66f2d16SKris Kennaway buffer_append(&iqueue, buf, len); 1053b66f2d16SKris Kennaway } 1054b66f2d16SKris Kennaway } 1055b66f2d16SKris Kennaway /* send oqueue to stdout */ 1056b66f2d16SKris Kennaway if (FD_ISSET(out, &wset)) { 1057b66f2d16SKris Kennaway len = write(out, buffer_ptr(&oqueue), olen); 1058b66f2d16SKris Kennaway if (len < 0) { 1059b66f2d16SKris Kennaway error("write error"); 1060b66f2d16SKris Kennaway exit(1); 1061b66f2d16SKris Kennaway } else { 1062b66f2d16SKris Kennaway buffer_consume(&oqueue, len); 1063b66f2d16SKris Kennaway } 1064b66f2d16SKris Kennaway } 1065b66f2d16SKris Kennaway /* process requests from client */ 1066b66f2d16SKris Kennaway process(); 1067b66f2d16SKris Kennaway } 1068b66f2d16SKris Kennaway } 1069