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