SilcBuffer silc_public_key_payload_encode(SilcPublicKey public_key) { SilcBuffer buffer; unsigned char *pk; SilcUInt32 pk_len; SilcPKCSType type; if (!public_key) return NULL; type = silc_pkcs_get_type(public_key); pk = silc_pkcs_public_key_encode(public_key, &pk_len); if (!pk) return NULL; buffer = silc_buffer_alloc_size(4 + pk_len); if (!buffer) { silc_free(pk); return NULL; } if (silc_buffer_format(buffer, SILC_STR_UI_SHORT(pk_len), SILC_STR_UI_SHORT(type), SILC_STR_DATA(pk, pk_len), SILC_STR_END) < 0) { silc_buffer_free(buffer); silc_free(pk); return NULL; } silc_free(pk); return buffer; }
SilcBool silc_public_key_payload_decode(unsigned char *data, SilcUInt32 data_len, SilcPublicKey *public_key) { SilcBufferStruct buf; SilcUInt16 pk_len, pk_type; unsigned char *pk; int ret; if (!public_key) return FALSE; silc_buffer_set(&buf, data, data_len); ret = silc_buffer_unformat(&buf, SILC_STR_ADVANCE, SILC_STR_UI_SHORT(&pk_len), SILC_STR_UI_SHORT(&pk_type), SILC_STR_END); if (ret < 0 || pk_len > data_len - 4) return FALSE; if (pk_type < SILC_PKCS_SILC || pk_type > SILC_PKCS_SPKI) return FALSE; ret = silc_buffer_unformat(&buf, SILC_STR_DATA(&pk, pk_len), SILC_STR_END); if (ret < 0) return FALSE; return silc_pkcs_public_key_alloc((SilcPKCSType)pk_type, pk, pk_len, public_key); }
static void silc_sftp_server_attr(SilcSFTP sftp, SilcSFTPStatus status, const SilcSFTPAttributes attrs, void *context) { SilcSFTPServer server = (SilcSFTPServer)sftp; SilcUInt32 id = SILC_PTR_TO_32(context); SilcBuffer attr_buf; SILC_LOG_DEBUG(("Attr callback")); SILC_LOG_DEBUG(("Request ID: %d", id)); if (status != SILC_SFTP_STATUS_OK) { silc_sftp_send_error(server, status, id); return; } attr_buf = silc_sftp_attr_encode(attrs); if (!attr_buf) { silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id); return; } silc_sftp_send_packet(server, SILC_SFTP_ATTRS, 4 + silc_buffer_len(attr_buf), SILC_STR_UI_INT(id), SILC_STR_DATA(silc_buffer_data(attr_buf), silc_buffer_len(attr_buf)), SILC_STR_END); silc_buffer_free(attr_buf); }
SilcBuffer silc_notify_payload_encode_args(SilcNotifyType type, SilcUInt32 argc, SilcBuffer args) { SilcBuffer buffer; SilcUInt32 len; len = 5 + (args ? silc_buffer_len(args) : 0); buffer = silc_buffer_alloc_size(len); if (!buffer) return NULL; silc_buffer_format(buffer, SILC_STR_UI_SHORT(type), SILC_STR_UI_SHORT(len), SILC_STR_UI_CHAR(argc), SILC_STR_END); if (args) silc_buffer_format(buffer, SILC_STR_OFFSET(5), SILC_STR_DATA(args->data, silc_buffer_len(args)), SILC_STR_END); return buffer; }
static void silc_sftp_server_name(SilcSFTP sftp, SilcSFTPStatus status, const SilcSFTPName name, void *context) { SilcSFTPServer server = (SilcSFTPServer)sftp; SilcUInt32 id = SILC_PTR_TO_32(context); SilcBuffer namebuf; SILC_LOG_DEBUG(("Name callback")); SILC_LOG_DEBUG(("Request ID: %d", id)); if (status != SILC_SFTP_STATUS_OK) { silc_sftp_send_error(server, status, id); return; } namebuf = silc_sftp_name_encode(name); if (!namebuf) { silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id); return; } silc_sftp_send_packet(server, SILC_SFTP_NAME, 4 + silc_buffer_len(namebuf), SILC_STR_UI_INT(id), SILC_STR_DATA(silc_buffer_data(namebuf), silc_buffer_len(namebuf)), SILC_STR_END); }
static SilcBool silc_client_send_private_message_key_request(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { const char *cipher, *hmac; SILC_LOG_DEBUG(("Sending private message key request")); cipher = silc_cipher_get_name(client_entry->internal.send_key); hmac = silc_hmac_get_name(client_entry->internal.hmac_send); /* Send the packet */ return silc_packet_send_va_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE_KEY, 0, 0, NULL, SILC_ID_CLIENT, &client_entry->id, NULL, NULL, SILC_STR_UI_SHORT(strlen(cipher)), SILC_STR_DATA(cipher, strlen(cipher)), SILC_STR_UI_SHORT(strlen(hmac)), SILC_STR_DATA(hmac, strlen(hmac)), SILC_STR_END); }
SilcBuffer silc_sftp_name_encode(SilcSFTPName name) { SilcBuffer buffer; int i, len = 4; SilcBuffer *attr_buf; attr_buf = silc_calloc(name->count, sizeof(*attr_buf)); if (!attr_buf) return NULL; for (i = 0; i < name->count; i++) { len += (8 + strlen(name->filename[i]) + strlen(name->long_filename[i])); attr_buf[i] = silc_sftp_attr_encode(name->attrs[i]); if (!attr_buf[i]) return NULL; len += silc_buffer_len(attr_buf[i]); } buffer = silc_buffer_alloc(len); if (!buffer) return NULL; silc_buffer_end(buffer); silc_buffer_format(buffer, SILC_STR_UI_INT(name->count), SILC_STR_END); silc_buffer_pull(buffer, 4); for (i = 0; i < name->count; i++) { len = silc_buffer_format(buffer, SILC_STR_UI_INT(strlen(name->filename[i])), SILC_STR_UI32_STRING(name->filename[i]), SILC_STR_UI_INT(strlen(name->long_filename[i])), SILC_STR_UI32_STRING(name->long_filename[i]), SILC_STR_DATA(silc_buffer_data(attr_buf[i]), silc_buffer_len(attr_buf[i])), SILC_STR_END); silc_buffer_pull(buffer, len); silc_free(attr_buf[i]); } silc_free(attr_buf); silc_buffer_push(buffer, buffer->data - buffer->head); return buffer; }
int silc_mp_format(SilcStack stack, SilcBuffer buffer, void *value, void *context) { SilcMPInt *mp = value; unsigned char *m; SilcUInt32 m_len; int ret; /* Encode */ m = silc_mp_mp2bin(mp, 0, &m_len); if (!m) return -1; ret = silc_buffer_sformat(stack, buffer, SILC_STR_UINT32(m_len), SILC_STR_DATA(m, m_len), SILC_STR_END); silc_free(m); return ret; }
SilcClientFileError silc_client_file_receive(SilcClient client, SilcClientConnection conn, SilcClientConnectionParams *params, SilcPublicKey public_key, SilcPrivateKey private_key, SilcClientFileMonitor monitor, void *monitor_context, const char *path, SilcUInt32 session_id, SilcClientFileAskName ask_name, void *ask_name_context) { SilcClientFtpSession session; SilcBuffer keyagr; if (!client || !conn) return SILC_CLIENT_FILE_ERROR; SILC_LOG_DEBUG(("Start, Session ID: %d", session_id)); /* Get the session */ silc_dlist_start(client->internal->ftp_sessions); while ((session = silc_dlist_get(client->internal->ftp_sessions)) != SILC_LIST_END) { if (session->session_id == session_id) { break; } } if (session == SILC_LIST_END) { SILC_LOG_DEBUG(("Unknown session ID: %d\n", session_id)); return SILC_CLIENT_FILE_UNKNOWN_SESSION; } /* See if we have this session running already */ if (session->sftp || session->listener) { SILC_LOG_DEBUG(("Session already started")); return SILC_CLIENT_FILE_ALREADY_STARTED; } session->monitor = monitor; session->monitor_context = monitor_context; session->ask_name = ask_name; session->ask_name_context = ask_name_context; session->path = path ? strdup(path) : NULL; /* If the hostname and port already exists then the remote client did provide the connection point to us and we won't create listener, but create the connection ourselves. */ if (session->hostname && session->port) { SILC_LOG_DEBUG(("Connecting to remote client")); /* Connect to the remote client. Performs key exchange automatically. */ session->op = silc_client_connect_to_client(client, params, public_key, private_key, session->hostname, session->port, silc_client_ftp_connect_completion, session); if (!session->op) { silc_free(session); return SILC_CLIENT_FILE_ERROR; } } else { /* Add the listener for the key agreement */ SILC_LOG_DEBUG(("Creating listener for file transfer")); if (!params || (!params->local_ip && !params->bind_ip)) { session->client->internal->ops->say(session->client, session->conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot create listener for file " "transfer; IP address and/or port " "not provided"); silc_free(session); return SILC_CLIENT_FILE_ERROR; } session->listener = silc_client_listener_add(client, conn->internal->schedule, params, public_key, private_key, silc_client_ftp_connect_completion, session); if (!session->listener) { client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot create listener for file transfer: " "%s", strerror(errno)); silc_free(session); return SILC_CLIENT_FILE_NO_MEMORY; } session->hostname = (params->bind_ip ? strdup(params->bind_ip) : strdup(params->local_ip)); session->port = silc_client_listener_get_local_port(session->listener); /* Send the key agreement inside FTP packet */ SILC_LOG_DEBUG(("Sending key agreement for file transfer")); keyagr = silc_key_agreement_payload_encode(session->hostname, 0, session->port); if (!keyagr) { silc_client_listener_free(session->listener); silc_free(session); return SILC_CLIENT_FILE_NO_MEMORY; } silc_packet_send_va_ext(conn->stream, SILC_PACKET_FTP, 0, 0, NULL, SILC_ID_CLIENT, &session->client_entry->id, NULL, NULL, SILC_STR_UI_CHAR(1), SILC_STR_DATA(silc_buffer_data(keyagr), silc_buffer_len(keyagr)), SILC_STR_END); silc_buffer_free(keyagr); /* Add session request timeout */ if (params && params->timeout_secs) silc_schedule_task_add_timeout(client->schedule, silc_client_ftp_timeout, session, params->timeout_secs, 0); } return SILC_CLIENT_FILE_OK; }
SilcClientFileError silc_client_file_send(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, SilcClientConnectionParams *params, SilcPublicKey public_key, SilcPrivateKey private_key, SilcClientFileMonitor monitor, void *monitor_context, const char *filepath, SilcUInt32 *session_id) { SilcClientFtpSession session; SilcBuffer keyagr; char *filename, *path; int fd; SILC_LOG_DEBUG(("File send request (file: %s)", filepath)); if (!client || !client_entry || !filepath || !params || !public_key || !private_key) return SILC_CLIENT_FILE_ERROR; /* Check for existing session for `filepath'. */ silc_dlist_start(client->internal->ftp_sessions); while ((session = silc_dlist_get(client->internal->ftp_sessions))) { if (session->filepath && !strcmp(session->filepath, filepath) && session->client_entry == client_entry) return SILC_CLIENT_FILE_ALREADY_STARTED; } /* See whether the file exists and can be opened */ fd = silc_file_open(filepath, O_RDONLY); if (fd < 0) return SILC_CLIENT_FILE_NO_SUCH_FILE; silc_file_close(fd); /* Add new session */ session = silc_calloc(1, sizeof(*session)); if (!session) return SILC_CLIENT_FILE_ERROR; session->session_id = ++client->internal->next_session_id; session->client = client; session->server_conn = conn; session->initiator = TRUE; session->client_entry = silc_client_ref_client(client, conn, client_entry); session->monitor = monitor; session->monitor_context = monitor_context; session->filepath = strdup(filepath); session->params = *params; session->public_key = public_key; session->private_key = private_key; if (silc_asprintf(&path, "file://%s", filepath) < 0) { silc_free(session); return SILC_CLIENT_FILE_NO_MEMORY; } /* Allocate memory filesystem and put the file to it */ if (strrchr(path, '/')) filename = strrchr(path, '/') + 1; else filename = (char *)path; session->fs = silc_sftp_fs_memory_alloc(SILC_SFTP_FS_PERM_READ | SILC_SFTP_FS_PERM_EXEC); silc_sftp_fs_memory_add_file(session->fs, NULL, SILC_SFTP_FS_PERM_READ, filename, path); session->filesize = silc_file_size(filepath); /* If local IP is provided, create listener for incoming key exchange */ if (params->local_ip || params->bind_ip) { session->listener = silc_client_listener_add(client, conn->internal->schedule, params, public_key, private_key, silc_client_ftp_connect_completion, session); if (!session->listener) { client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot create listener for file transfer: " "%s", strerror(errno)); silc_free(session); return SILC_CLIENT_FILE_NO_MEMORY; } session->hostname = (params->bind_ip ? strdup(params->bind_ip) : strdup(params->local_ip)); session->port = silc_client_listener_get_local_port(session->listener); } SILC_LOG_DEBUG(("Sending key agreement for file transfer")); /* Send the key agreement inside FTP packet */ keyagr = silc_key_agreement_payload_encode(session->hostname, 0, session->port); if (!keyagr) { if (session->listener) silc_client_listener_free(session->listener); silc_free(session); return SILC_CLIENT_FILE_NO_MEMORY; } silc_packet_send_va_ext(conn->stream, SILC_PACKET_FTP, 0, 0, NULL, SILC_ID_CLIENT, &client_entry->id, NULL, NULL, SILC_STR_UI_CHAR(1), SILC_STR_DATA(silc_buffer_data(keyagr), silc_buffer_len(keyagr)), SILC_STR_END); silc_buffer_free(keyagr); silc_free(path); silc_dlist_add(client->internal->ftp_sessions, session); if (session_id) *session_id = session->session_id; /* Add session request timeout */ if (params && params->timeout_secs) silc_schedule_task_add_timeout(client->schedule, silc_client_ftp_timeout, session, params->timeout_secs, 0); return SILC_CLIENT_FILE_OK; }
SilcBuffer silc_notify_payload_encode(SilcNotifyType type, SilcUInt32 argc, va_list ap) { SilcBuffer buffer; SilcBuffer args = NULL; unsigned char **argv; SilcUInt32 *argv_lens = NULL, *argv_types = NULL; unsigned char *x; SilcUInt32 x_len, len = 0; int i, k = 0; if (argc) { argv = silc_calloc(argc, sizeof(unsigned char *)); if (!argv) return NULL; argv_lens = silc_calloc(argc, sizeof(SilcUInt32)); if (!argv_lens) { silc_free(argv); return NULL; } argv_types = silc_calloc(argc, sizeof(SilcUInt32)); if (!argv_types) { silc_free(argv_lens); silc_free(argv); return NULL; } for (i = 0, k = 0; i < argc; i++) { x = va_arg(ap, unsigned char *); x_len = va_arg(ap, SilcUInt32); if (!x || !x_len) continue; argv[k] = silc_memdup(x, x_len); if (!argv[k]) return NULL; argv_lens[k] = x_len; argv_types[k] = i + 1; k++; } args = silc_argument_payload_encode(k, argv, argv_lens, argv_types); len = silc_buffer_len(args); for (i = 0; i < k; i++) silc_free(argv[i]); silc_free(argv); silc_free(argv_lens); silc_free(argv_types); } len += 5; buffer = silc_buffer_alloc_size(len); if (!buffer) return NULL; silc_buffer_format(buffer, SILC_STR_UI_SHORT(type), SILC_STR_UI_SHORT(len), SILC_STR_UI_CHAR(k), SILC_STR_END); if (k) { silc_buffer_format(buffer, SILC_STR_OFFSET(5), SILC_STR_DATA(args->data, silc_buffer_len(args)), SILC_STR_END); silc_buffer_free(args); } return buffer; }
SilcBuffer silc_sftp_attr_encode(SilcSFTPAttributes attr) { SilcBuffer buffer; int i, ret; SilcUInt32 len = 4; if (attr->flags & SILC_SFTP_ATTR_SIZE) len += 8; if (attr->flags & SILC_SFTP_ATTR_UIDGID) len += 8; if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) len += 4; if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) len += 8; if (attr->flags & SILC_SFTP_ATTR_EXTENDED) { len += 4; for (i = 0; i < attr->extended_count; i++) { len += 8; len += silc_buffer_len(attr->extended_type[i]); len += silc_buffer_len(attr->extended_data[i]); } } buffer = silc_buffer_alloc_size(len); if (!buffer) return NULL; silc_buffer_format(buffer, SILC_STR_UI_INT(attr->flags), SILC_STR_END); silc_buffer_pull(buffer, 4); if (attr->flags & SILC_SFTP_ATTR_SIZE) { silc_buffer_format(buffer, SILC_STR_UI_INT64(attr->size), SILC_STR_END); silc_buffer_pull(buffer, 8); } if (attr->flags & SILC_SFTP_ATTR_UIDGID) { silc_buffer_format(buffer, SILC_STR_UI_INT(attr->uid), SILC_STR_UI_INT(attr->gid), SILC_STR_END); silc_buffer_pull(buffer, 8); } if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) { silc_buffer_format(buffer, SILC_STR_UI_INT(attr->permissions), SILC_STR_END); silc_buffer_pull(buffer, 4); } if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) { silc_buffer_format(buffer, SILC_STR_UI_INT(attr->atime), SILC_STR_UI_INT(attr->mtime), SILC_STR_END); silc_buffer_pull(buffer, 8); } if (attr->flags & SILC_SFTP_ATTR_EXTENDED) { silc_buffer_format(buffer, SILC_STR_UI_INT(attr->extended_count), SILC_STR_END); silc_buffer_pull(buffer, 4); for (i = 0; i < attr->extended_count; i++) { ret = silc_buffer_format( buffer, SILC_STR_UI_INT(silc_buffer_len(attr->extended_type[i])), SILC_STR_DATA(silc_buffer_data(attr->extended_type[i]), silc_buffer_len(attr->extended_type[i])), SILC_STR_UI_INT(silc_buffer_len(attr->extended_data[i])), SILC_STR_DATA(silc_buffer_data(attr->extended_data[i]), silc_buffer_len(attr->extended_data[i])), SILC_STR_END); silc_buffer_pull(buffer, ret); } } silc_buffer_push(buffer, buffer->data - buffer->head); return buffer; }
static void silc_pkcs_ssh_sign_cb(SilcBool success, const unsigned char *signature, SilcUInt32 signature_len, void *context) { SilcSshSign sign = context; SilcStack stack = sign->stack; unsigned char rbuf[20], sbuf[20]; SilcBufferStruct sig; SilcAsn1 asn1; SilcMPInt r, s; memset(&sig, 0, sizeof(sig)); /* Format the signature. RSA is easy because PKCS#1 is already in correct format. For DSA the returned signature is in PKIX compliant format and we have to reformat it for SSH2. */ if (!strcmp(sign->privkey->pkcs->name, "dsa")) { asn1 = silc_asn1_alloc(stack); if (!asn1) { sign->sign_cb(FALSE, NULL, 0, sign->context); silc_sfree(stack, sign); silc_stack_free(stack); return; } /* Decode the signature */ silc_buffer_set(&sig, (unsigned char *)signature, signature_len); if (!silc_asn1_decode(asn1, &sig, SILC_ASN1_SEQUENCE, SILC_ASN1_INT(&r), SILC_ASN1_INT(&s), SILC_ASN1_END, SILC_ASN1_END)) { sign->sign_cb(FALSE, NULL, 0, sign->context); silc_asn1_free(asn1); silc_sfree(stack, sign); silc_stack_free(stack); return; } /* Encode the integers */ memset(rbuf, 0, sizeof(rbuf)); memset(sbuf, 0, sizeof(sbuf)); silc_mp_mp2bin_noalloc(&r, rbuf, sizeof(rbuf)); silc_mp_mp2bin_noalloc(&s, sbuf, sizeof(sbuf)); silc_asn1_free(asn1); /* Encode SSH2 DSS signature */ if (silc_buffer_sformat(stack, &sig, SILC_STR_UI_INT(7), SILC_STR_UI32_STRING("ssh-dss"), SILC_STR_UI_INT(sizeof(rbuf) + sizeof(sbuf)), SILC_STR_DATA(rbuf, sizeof(rbuf)), SILC_STR_DATA(sbuf, sizeof(sbuf)), SILC_STR_END) < 0) { sign->sign_cb(FALSE, NULL, 0, sign->context); silc_sfree(stack, sign); silc_stack_free(stack); return; } } else { /* Encode SSH2 RSA signature */ if (silc_buffer_sformat(stack, &sig, SILC_STR_UI_INT(7), SILC_STR_UI32_STRING("ssh-rsa"), SILC_STR_UI_INT(signature_len), SILC_STR_DATA(signature, signature_len), SILC_STR_END) < 0) { sign->sign_cb(FALSE, NULL, 0, sign->context); silc_sfree(stack, sign); silc_stack_free(stack); return; } } /* Deliver result */ sign->sign_cb(TRUE, silc_buffer_data(&sig), silc_buffer_len(&sig), sign->context); silc_buffer_spurge(stack, &sig); silc_sfree(stack, sign); silc_stack_free(stack); }
static void silc_sftp_server_receive_process(SilcSFTP sftp, SilcBuffer buffer) { SilcSFTPServer server = (SilcSFTPServer)sftp; SilcSFTPPacket type; char *filename = NULL, *path = NULL; unsigned char *payload = NULL; SilcUInt32 payload_len; int ret; SilcBufferStruct buf; SilcUInt32 id; SilcSFTPAttributes attrs; SilcSFTPHandle handle; SilcSFTPMonitorDataStruct mdata; SILC_LOG_DEBUG(("Start")); /* Parse the packet */ type = silc_sftp_packet_decode(buffer, &payload, &payload_len); if (type <= 0) return; silc_buffer_set(&buf, payload, payload_len); memset(&mdata, 0, sizeof(mdata)); switch (type) { case SILC_SFTP_READ: { unsigned char *hdata; SilcUInt32 hdata_len; SilcUInt64 offset; SilcUInt32 len; SILC_LOG_DEBUG(("Read request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_UI_INT64(&offset), SILC_STR_UI_INT(&len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Read operation */ server->fs->fs->sftp_read(server->fs->fs_context, sftp, handle, offset, len, silc_sftp_server_data, SILC_32_TO_PTR(id)); /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) { mdata.offset = offset; mdata.data_len = len; (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata, server->monitor_context); } } break; case SILC_SFTP_WRITE: { unsigned char *hdata; SilcUInt32 hdata_len; SilcUInt64 offset; unsigned char *data; SilcUInt32 data_len; SILC_LOG_DEBUG(("Read request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_UI_INT64(&offset), SILC_STR_UI32_NSTRING(&data, &data_len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Write operation */ server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset, (const unsigned char *)data, data_len, silc_sftp_server_status, SILC_32_TO_PTR(id)); /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) { mdata.offset = offset; mdata.data_len = data_len; (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata, server->monitor_context); } } break; case SILC_SFTP_INIT: { SilcSFTPVersion version; SILC_LOG_DEBUG(("Init request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&version), SILC_STR_END); if (ret < 0) break; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_INIT && server->monitor) { mdata.version = version; (*server->monitor)(sftp, SILC_SFTP_MONITOR_INIT, &mdata, server->monitor_context); } silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4, SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION), SILC_STR_END); } break; case SILC_SFTP_OPEN: { SilcSFTPFileOperation pflags; unsigned char *attr_buf; SilcUInt32 attr_len = 0; SilcBufferStruct tmpbuf; SILC_LOG_DEBUG(("Open request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&filename), SILC_STR_UI_INT(&pflags), SILC_STR_UI32_NSTRING(&attr_buf, &attr_len), SILC_STR_END); if (ret < 0) goto failure; if (attr_len) { silc_buffer_set(&tmpbuf, attr_buf, attr_len); attrs = silc_sftp_attr_decode(&tmpbuf); if (!attrs) goto failure; } else { attrs = silc_calloc(1, sizeof(*attrs)); if (!attrs) goto failure; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_OPEN && server->monitor) { mdata.name = filename; mdata.pflags = pflags; (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPEN, &mdata, server->monitor_context); } /* Open operation */ server->fs->fs->sftp_open(server->fs->fs_context, sftp, filename, pflags, attrs, silc_sftp_server_handle, SILC_32_TO_PTR(id)); silc_free(filename); silc_sftp_attr_free(attrs); } break; case SILC_SFTP_CLOSE: { unsigned char *hdata; SilcUInt32 hdata_len; SILC_LOG_DEBUG(("Close request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_CLOSE && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_CLOSE, &mdata, server->monitor_context); } /* Close operation */ server->fs->fs->sftp_close(server->fs->fs_context, sftp, handle, silc_sftp_server_status, SILC_32_TO_PTR(id)); } break; case SILC_SFTP_REMOVE: { SILC_LOG_DEBUG(("Remove request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&filename), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_REMOVE && server->monitor) { mdata.name = filename; (*server->monitor)(sftp, SILC_SFTP_MONITOR_REMOVE, &mdata, server->monitor_context); } /* Remove operation */ server->fs->fs->sftp_remove(server->fs->fs_context, sftp, filename, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_free(filename); } break; case SILC_SFTP_RENAME: { char *newname = NULL; SILC_LOG_DEBUG(("Rename request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&filename), SILC_STR_UI32_STRING_ALLOC(&newname), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_RENAME && server->monitor) { mdata.name = filename; mdata.name2 = newname; (*server->monitor)(sftp, SILC_SFTP_MONITOR_RENAME, &mdata, server->monitor_context); } /* Rename operation */ server->fs->fs->sftp_rename(server->fs->fs_context, sftp, filename, newname, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_free(filename); silc_free(newname); } break; case SILC_SFTP_MKDIR: { unsigned char *attr_buf; SilcUInt32 attr_len = 0; SilcBufferStruct tmpbuf; SILC_LOG_DEBUG(("Mkdir request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_UI32_NSTRING(&attr_buf, &attr_len), SILC_STR_END); if (ret < 0) goto failure; if (attr_len) { silc_buffer_set(&tmpbuf, attr_buf, attr_len); attrs = silc_sftp_attr_decode(&tmpbuf); if (!attrs) goto failure; } else { attrs = silc_calloc(1, sizeof(*attrs)); if (!attrs) goto failure; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_MKDIR && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_MKDIR, &mdata, server->monitor_context); } /* Mkdir operation */ server->fs->fs->sftp_mkdir(server->fs->fs_context, sftp, path, attrs, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_sftp_attr_free(attrs); silc_free(path); } break; case SILC_SFTP_RMDIR: { SILC_LOG_DEBUG(("Rmdir request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_RMDIR && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_RMDIR, &mdata, server->monitor_context); } /* Rmdir operation */ server->fs->fs->sftp_rmdir(server->fs->fs_context, sftp, path, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_OPENDIR: { SILC_LOG_DEBUG(("Opendir request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_OPENDIR && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPENDIR, &mdata, server->monitor_context); } /* Opendir operation */ server->fs->fs->sftp_opendir(server->fs->fs_context, sftp, path, silc_sftp_server_handle, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_READDIR: { unsigned char *hdata; SilcUInt32 hdata_len; SILC_LOG_DEBUG(("Readdir request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_READDIR && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_READDIR, &mdata, server->monitor_context); } /* Readdir operation */ server->fs->fs->sftp_readdir(server->fs->fs_context, sftp, handle, silc_sftp_server_name, SILC_32_TO_PTR(id)); } break; case SILC_SFTP_STAT: { SILC_LOG_DEBUG(("Stat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_STAT && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_STAT, &mdata, server->monitor_context); } /* Stat operation */ server->fs->fs->sftp_stat(server->fs->fs_context, sftp, path, silc_sftp_server_attr, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_LSTAT: { SILC_LOG_DEBUG(("Lstat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_LSTAT && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_LSTAT, &mdata, server->monitor_context); } /* Lstat operation */ server->fs->fs->sftp_lstat(server->fs->fs_context, sftp, path, silc_sftp_server_attr, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_FSTAT: { unsigned char *hdata; SilcUInt32 hdata_len; SILC_LOG_DEBUG(("Fstat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_FSTAT && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSTAT, &mdata, server->monitor_context); } /* Fstat operation */ server->fs->fs->sftp_fstat(server->fs->fs_context, sftp, handle, silc_sftp_server_attr, SILC_32_TO_PTR(id)); } break; case SILC_SFTP_SETSTAT: { unsigned char *attr_buf; SilcUInt32 attr_len = 0; SilcBufferStruct tmpbuf; SILC_LOG_DEBUG(("Setstat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_UI32_NSTRING(&attr_buf, &attr_len), SILC_STR_END); if (ret < 0) goto failure; if (attr_len) { silc_buffer_set(&tmpbuf, attr_buf, attr_len); attrs = silc_sftp_attr_decode(&tmpbuf); if (!attrs) goto failure; } else { attrs = silc_calloc(1, sizeof(*attrs)); if (!attrs) goto failure; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_SETSTAT && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_SETSTAT, &mdata, server->monitor_context); } /* Setstat operation */ server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_sftp_attr_free(attrs); silc_free(path); } break; case SILC_SFTP_FSETSTAT: { unsigned char *hdata, *attr_buf; SilcUInt32 hdata_len, attr_len = 0; SilcBufferStruct tmpbuf; SILC_LOG_DEBUG(("Fsetstat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_UI32_NSTRING(&attr_buf, &attr_len), SILC_STR_END); if (ret < 0) goto failure; if (attr_len) { silc_buffer_set(&tmpbuf, attr_buf, attr_len); attrs = silc_sftp_attr_decode(&tmpbuf); if (!attrs) goto failure; } else { attrs = silc_calloc(1, sizeof(*attrs)); if (!attrs) goto failure; } /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_FSETSTAT && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSETSTAT, &mdata, server->monitor_context); } /* Fsetstat operation */ server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp, handle, attrs, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_sftp_attr_free(attrs); } break; case SILC_SFTP_READLINK: { SILC_LOG_DEBUG(("Readlink request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_READLINK && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_READLINK, &mdata, server->monitor_context); } /* Readlink operation */ server->fs->fs->sftp_readlink(server->fs->fs_context, sftp, path, silc_sftp_server_name, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_SYMLINK: { char *target = NULL; SILC_LOG_DEBUG(("Symlink request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_UI32_STRING_ALLOC(&target), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_SYMLINK && server->monitor) { mdata.name = path; mdata.name2 = target; (*server->monitor)(sftp, SILC_SFTP_MONITOR_SYMLINK, &mdata, server->monitor_context); } /* Symlink operation */ server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_free(path); silc_free(target); } break; case SILC_SFTP_REALPATH: { SILC_LOG_DEBUG(("Realpath request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_REALPATH && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_REALPATH, &mdata, server->monitor_context); } /* Realpath operation */ server->fs->fs->sftp_realpath(server->fs->fs_context, sftp, path, silc_sftp_server_name, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_EXTENDED: { char *request = NULL; unsigned char *data; SilcUInt32 data_len; SILC_LOG_DEBUG(("Extended request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&request), SILC_STR_END); if (ret < 0) goto failure; data_len = 8 + strlen(request); silc_buffer_pull(&buf, data_len); ret = silc_buffer_unformat(&buf, SILC_STR_DATA(&data, silc_buffer_len(&buf)), SILC_STR_END); if (ret < 0) goto failure; data_len = silc_buffer_len(&buf); /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_EXTENDED && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_EXTENDED, &mdata, server->monitor_context); } /* Extended operation */ server->fs->fs->sftp_extended(server->fs->fs_context, sftp, request, data, data_len, silc_sftp_server_extended, SILC_32_TO_PTR(id)); silc_free(request); } break; default: break; } return; failure: silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id); }