version 1.6.4.2, 2001/03/12 15:44:15 |
version 1.6.4.3, 2001/03/21 18:53:06 |
|
|
Buffer iqueue; |
Buffer iqueue; |
Buffer oqueue; |
Buffer oqueue; |
|
|
|
/* Version of client */ |
|
int version; |
|
|
/* portable attibutes, etc. */ |
/* portable attibutes, etc. */ |
|
|
typedef struct Stat Stat; |
typedef struct Stat Stat; |
|
|
errno_to_portable(int unixerrno) |
errno_to_portable(int unixerrno) |
{ |
{ |
int ret = 0; |
int ret = 0; |
|
|
switch (unixerrno) { |
switch (unixerrno) { |
case 0: |
case 0: |
ret = SSH2_FX_OK; |
ret = SSH2_FX_OK; |
|
|
flags_from_portable(int pflags) |
flags_from_portable(int pflags) |
{ |
{ |
int flags = 0; |
int flags = 0; |
if (pflags & SSH2_FXF_READ && |
|
pflags & SSH2_FXF_WRITE) { |
if ((pflags & SSH2_FXF_READ) && |
|
(pflags & SSH2_FXF_WRITE)) { |
flags = O_RDWR; |
flags = O_RDWR; |
} else if (pflags & SSH2_FXF_READ) { |
} else if (pflags & SSH2_FXF_READ) { |
flags = O_RDONLY; |
flags = O_RDONLY; |
|
|
int fd; |
int fd; |
char *name; |
char *name; |
}; |
}; |
|
|
enum { |
enum { |
HANDLE_UNUSED, |
HANDLE_UNUSED, |
HANDLE_DIR, |
HANDLE_DIR, |
HANDLE_FILE |
HANDLE_FILE |
}; |
}; |
|
|
Handle handles[100]; |
Handle handles[100]; |
|
|
void |
void |
handle_init(void) |
handle_init(void) |
{ |
{ |
int i; |
int i; |
|
|
for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) |
for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) |
handles[i].use = HANDLE_UNUSED; |
handles[i].use = HANDLE_UNUSED; |
} |
} |
|
|
handle_new(int use, char *name, int fd, DIR *dirp) |
handle_new(int use, char *name, int fd, DIR *dirp) |
{ |
{ |
int i; |
int i; |
|
|
for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) { |
for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) { |
if (handles[i].use == HANDLE_UNUSED) { |
if (handles[i].use == HANDLE_UNUSED) { |
handles[i].use = use; |
handles[i].use = use; |
|
|
handle_from_string(char *handle, u_int hlen) |
handle_from_string(char *handle, u_int hlen) |
{ |
{ |
int val; |
int val; |
|
|
if (hlen != sizeof(int32_t)) |
if (hlen != sizeof(int32_t)) |
return -1; |
return -1; |
val = GET_32BIT(handle); |
val = GET_32BIT(handle); |
|
|
handle_close(int handle) |
handle_close(int handle) |
{ |
{ |
int ret = -1; |
int ret = -1; |
|
|
if (handle_is_ok(handle, HANDLE_FILE)) { |
if (handle_is_ok(handle, HANDLE_FILE)) { |
ret = close(handles[handle].fd); |
ret = close(handles[handle].fd); |
handles[handle].use = HANDLE_UNUSED; |
handles[handle].use = HANDLE_UNUSED; |
|
|
char *handle; |
char *handle; |
int val = -1; |
int val = -1; |
u_int hlen; |
u_int hlen; |
|
|
handle = get_string(&hlen); |
handle = get_string(&hlen); |
if (hlen < 256) |
if (hlen < 256) |
val = handle_from_string(handle, hlen); |
val = handle_from_string(handle, hlen); |
|
|
send_msg(Buffer *m) |
send_msg(Buffer *m) |
{ |
{ |
int mlen = buffer_len(m); |
int mlen = buffer_len(m); |
|
|
buffer_put_int(&oqueue, mlen); |
buffer_put_int(&oqueue, mlen); |
buffer_append(&oqueue, buffer_ptr(m), mlen); |
buffer_append(&oqueue, buffer_ptr(m), mlen); |
buffer_consume(m, mlen); |
buffer_consume(m, mlen); |
|
|
send_status(u_int32_t id, u_int32_t error) |
send_status(u_int32_t id, u_int32_t error) |
{ |
{ |
Buffer msg; |
Buffer msg; |
|
const char *status_messages[] = { |
|
"Success", /* SSH_FX_OK */ |
|
"End of file", /* SSH_FX_EOF */ |
|
"No such file", /* SSH_FX_NO_SUCH_FILE */ |
|
"Permission denied", /* SSH_FX_PERMISSION_DENIED */ |
|
"Failure", /* SSH_FX_FAILURE */ |
|
"Bad message", /* SSH_FX_BAD_MESSAGE */ |
|
"No connection", /* SSH_FX_NO_CONNECTION */ |
|
"Connection lost", /* SSH_FX_CONNECTION_LOST */ |
|
"Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ |
|
"Unknown error" /* Others */ |
|
}; |
|
|
TRACE("sent status id %d error %d", id, error); |
TRACE("sent status id %d error %d", id, error); |
buffer_init(&msg); |
buffer_init(&msg); |
buffer_put_char(&msg, SSH2_FXP_STATUS); |
buffer_put_char(&msg, SSH2_FXP_STATUS); |
buffer_put_int(&msg, id); |
buffer_put_int(&msg, id); |
buffer_put_int(&msg, error); |
buffer_put_int(&msg, error); |
|
if (version >= 3) { |
|
buffer_put_cstring(&msg, |
|
status_messages[MIN(error,SSH2_FX_MAX)]); |
|
buffer_put_cstring(&msg, ""); |
|
} |
send_msg(&msg); |
send_msg(&msg); |
buffer_free(&msg); |
buffer_free(&msg); |
} |
} |
|
|
send_data_or_handle(char type, u_int32_t id, char *data, int dlen) |
send_data_or_handle(char type, u_int32_t id, char *data, int dlen) |
{ |
{ |
Buffer msg; |
Buffer msg; |
|
|
buffer_init(&msg); |
buffer_init(&msg); |
buffer_put_char(&msg, type); |
buffer_put_char(&msg, type); |
buffer_put_int(&msg, id); |
buffer_put_int(&msg, id); |
|
|
{ |
{ |
char *string; |
char *string; |
int hlen; |
int hlen; |
|
|
handle_to_string(handle, &string, &hlen); |
handle_to_string(handle, &string, &hlen); |
TRACE("sent handle id %d handle %d", id, handle); |
TRACE("sent handle id %d handle %d", id, handle); |
send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); |
send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); |
|
|
{ |
{ |
Buffer msg; |
Buffer msg; |
int i; |
int i; |
|
|
buffer_init(&msg); |
buffer_init(&msg); |
buffer_put_char(&msg, SSH2_FXP_NAME); |
buffer_put_char(&msg, SSH2_FXP_NAME); |
buffer_put_int(&msg, id); |
buffer_put_int(&msg, id); |
|
|
send_attrib(u_int32_t id, Attrib *a) |
send_attrib(u_int32_t id, Attrib *a) |
{ |
{ |
Buffer msg; |
Buffer msg; |
|
|
TRACE("sent attrib id %d have 0x%x", id, a->flags); |
TRACE("sent attrib id %d have 0x%x", id, a->flags); |
buffer_init(&msg); |
buffer_init(&msg); |
buffer_put_char(&msg, SSH2_FXP_ATTRS); |
buffer_put_char(&msg, SSH2_FXP_ATTRS); |
|
|
process_init(void) |
process_init(void) |
{ |
{ |
Buffer msg; |
Buffer msg; |
int version = buffer_get_int(&iqueue); |
|
|
|
|
version = buffer_get_int(&iqueue); |
TRACE("client version %d", version); |
TRACE("client version %d", version); |
buffer_init(&msg); |
buffer_init(&msg); |
buffer_put_char(&msg, SSH2_FXP_VERSION); |
buffer_put_char(&msg, SSH2_FXP_VERSION); |
|
|
attrib_to_tv(Attrib *a) |
attrib_to_tv(Attrib *a) |
{ |
{ |
static struct timeval tv[2]; |
static struct timeval tv[2]; |
|
|
tv[0].tv_sec = a->atime; |
tv[0].tv_sec = a->atime; |
tv[0].tv_usec = 0; |
tv[0].tv_usec = 0; |
tv[1].tv_sec = a->mtime; |
tv[1].tv_sec = a->mtime; |
|
|
} |
} |
|
|
void |
void |
|
process_readlink(void) |
|
{ |
|
u_int32_t id; |
|
char link[MAXPATHLEN]; |
|
char *path; |
|
|
|
id = get_int(); |
|
path = get_string(NULL); |
|
TRACE("readlink id %d path %s", id, path); |
|
if (readlink(path, link, sizeof(link) - 1) == -1) |
|
send_status(id, errno_to_portable(errno)); |
|
else { |
|
Stat s; |
|
|
|
link[sizeof(link) - 1] = '\0'; |
|
attrib_clear(&s.attrib); |
|
s.name = s.long_name = link; |
|
send_names(id, 1, &s); |
|
} |
|
xfree(path); |
|
} |
|
|
|
void |
|
process_symlink(void) |
|
{ |
|
u_int32_t id; |
|
struct stat st; |
|
char *oldpath, *newpath; |
|
int ret, status = SSH2_FX_FAILURE; |
|
|
|
id = get_int(); |
|
oldpath = get_string(NULL); |
|
newpath = get_string(NULL); |
|
TRACE("symlink id %d old %s new %s", id, oldpath, newpath); |
|
/* fail if 'newpath' exists */ |
|
if (stat(newpath, &st) == -1) { |
|
ret = symlink(oldpath, newpath); |
|
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
|
} |
|
send_status(id, status); |
|
xfree(oldpath); |
|
xfree(newpath); |
|
} |
|
|
|
void |
process_extended(void) |
process_extended(void) |
{ |
{ |
u_int32_t id; |
u_int32_t id; |
|
|
case SSH2_FXP_RENAME: |
case SSH2_FXP_RENAME: |
process_rename(); |
process_rename(); |
break; |
break; |
|
case SSH2_FXP_READLINK: |
|
process_readlink(); |
|
break; |
|
case SSH2_FXP_SYMLINK: |
|
process_symlink(); |
|
break; |
case SSH2_FXP_EXTENDED: |
case SSH2_FXP_EXTENDED: |
process_extended(); |
process_extended(); |
break; |
break; |
|
|
int |
int |
main(int ac, char **av) |
main(int ac, char **av) |
{ |
{ |
fd_set rset, wset; |
fd_set *rset, *wset; |
int in, out, max; |
int in, out, max; |
ssize_t len, olen; |
ssize_t len, olen, set_size; |
|
|
|
/* XXX should use getopt */ |
|
|
handle_init(); |
handle_init(); |
|
|
#ifdef DEBUG_SFTP_SERVER |
#ifdef DEBUG_SFTP_SERVER |
|
|
buffer_init(&iqueue); |
buffer_init(&iqueue); |
buffer_init(&oqueue); |
buffer_init(&oqueue); |
|
|
|
set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); |
|
rset = (fd_set *)xmalloc(set_size); |
|
wset = (fd_set *)xmalloc(set_size); |
|
|
for (;;) { |
for (;;) { |
FD_ZERO(&rset); |
memset(rset, 0, set_size); |
FD_ZERO(&wset); |
memset(wset, 0, set_size); |
|
|
FD_SET(in, &rset); |
FD_SET(in, rset); |
olen = buffer_len(&oqueue); |
olen = buffer_len(&oqueue); |
if (olen > 0) |
if (olen > 0) |
FD_SET(out, &wset); |
FD_SET(out, wset); |
|
|
if (select(max+1, &rset, &wset, NULL, NULL) < 0) { |
if (select(max+1, rset, wset, NULL, NULL) < 0) { |
if (errno == EINTR) |
if (errno == EINTR) |
continue; |
continue; |
exit(2); |
exit(2); |
} |
} |
|
|
/* copy stdin to iqueue */ |
/* copy stdin to iqueue */ |
if (FD_ISSET(in, &rset)) { |
if (FD_ISSET(in, rset)) { |
char buf[4*4096]; |
char buf[4*4096]; |
len = read(in, buf, sizeof buf); |
len = read(in, buf, sizeof buf); |
if (len == 0) { |
if (len == 0) { |
|
|
} |
} |
} |
} |
/* send oqueue to stdout */ |
/* send oqueue to stdout */ |
if (FD_ISSET(out, &wset)) { |
if (FD_ISSET(out, wset)) { |
len = write(out, buffer_ptr(&oqueue), olen); |
len = write(out, buffer_ptr(&oqueue), olen); |
if (len < 0) { |
if (len < 0) { |
error("write error"); |
error("write error"); |