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); }
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 void silc_sftp_send_packet(SilcSFTPServer sftp, SilcSFTPPacket type, SilcUInt32 len, ...) { SilcBuffer tmp; va_list vp; int ret; va_start(vp, len); tmp = silc_sftp_packet_encode_vp(type, sftp->packet, len, vp); va_end(vp); if (!tmp) return; sftp->packet = tmp; SILC_LOG_HEXDUMP(("SFTP packet to client"), silc_buffer_data(sftp->packet), silc_buffer_len(sftp->packet)); /* Send the packet */ while (silc_buffer_len(sftp->packet) > 0) { ret = silc_stream_write(sftp->stream, silc_buffer_data(sftp->packet), silc_buffer_len(sftp->packet)); if (ret == -2) { SILC_LOG_ERROR(("Error sending SFTP packet type %d", type)); sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context); silc_buffer_reset(sftp->packet); return; } if (ret == 0) { sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_EOF, sftp->context); silc_buffer_reset(sftp->packet); return; } if (ret == -1) return; silc_buffer_pull(sftp->packet, ret); } /* Clear packet */ silc_buffer_reset(sftp->packet); }
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; }
SilcBool silc_client_private_message_wait(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, SilcMessagePayload *payload) { SilcPacket packet; if (!client_entry->internal.prv_waiter) return FALSE; /* Block until private message arrives */ do { if ((silc_packet_wait(client_entry->internal.prv_waiter, 0, &packet)) < 0) return FALSE; /* Parse the payload and decrypt it also if private message key is set */ *payload = silc_message_payload_parse(silc_buffer_data(&packet->buffer), silc_buffer_len(&packet->buffer), TRUE, !client_entry->internal.generated, client_entry->internal.receive_key, client_entry->internal.hmac_receive, packet->src_id, packet->src_id_len, packet->dst_id, packet->dst_id_len, NULL, FALSE, NULL); if (!(*payload)) { silc_packet_free(packet); continue; } break; } while (1); silc_packet_free(packet); return TRUE; }
int main(int argc, char **argv) { int opt, ret, i; SilcAsn1 asn1; SilcBufferStruct buf; unsigned char *data, *tmp; SilcUInt32 data_len; if (argc < 2) { usage(); return 1; } while ((opt = getopt(argc, argv, "hxbai")) != EOF) { switch (opt) { case 'h': usage(); return 1; break; case 'x': hexdump = TRUE; break; case 'b': dec_base64 = TRUE; break; case 'i': ignore_header = TRUE; break; case 'a': parse_all = TRUE; break; default: usage(); return 1; } } data = tmp = silc_file_readfile(argv[argc - 1], &data_len, NULL); if (!data) { fprintf(stderr, "Error: Cannot read file '%s': %s\n", argv[argc - 1], silc_errno_string(silc_errno)); return 1; } silc_buffer_set(&buf, data, data_len); if (ignore_header) { SilcBool header = FALSE; for (i = 0; i < data_len; i++) { if (data_len > i + 4 && data[i ] == '-' && data[i + 1] == '-' && data[i + 2] == '-' && data[i + 3] == '-') { if (data_len > i + 5 && (data[i + 4] == '\r' || tmp[i + 4] == '\n')) { /* End of line, header */ if (data_len > i + 6 && data[i + 4] == '\r' && data[i + 5] == '\n') i++; i += 5; silc_buffer_pull(&buf, i); header = TRUE; } else if (i > 0 && data_len > i + 5 && data[i + 4] != '-' && header) { /* Start of line, footer */ silc_buffer_push_tail(&buf, silc_buffer_truelen(&buf) - i); break; } } } } if (dec_base64) { data = silc_base64_decode(NULL, silc_buffer_data(&buf), silc_buffer_len(&buf), &data_len); if (!data) { fprintf(stderr, "Error: Cannot decode Base64 encoding\n"); return 1; } silc_buffer_set(&buf, data, data_len); silc_free(tmp); } asn1 = silc_asn1_alloc(NULL); ret = asn1_dump(asn1, &buf, 0); silc_asn1_free(asn1); silc_free(data); return ret; }
int main(int argc, char **argv) { SilcBool success = FALSE; SilcMessagePayload message; SilcBuffer buf; const char *msg = "FOOBAR MESSAGE"; unsigned char *data, tmp[1023], *tmp2; SilcUInt32 data_len; SilcUInt16 flags; int i, n; if (argc > 1 && !strcmp(argv[1], "-d")) { silc_log_debug(TRUE); silc_log_debug_hexdump(TRUE); silc_log_set_debug_string("*message*"); } silc_cipher_register_default(); silc_hash_register_default(); silc_hmac_register_default(); silc_pkcs_register_default(); SILC_LOG_DEBUG(("Load keypair")); if (!silc_load_key_pair("pubkey.pub", "privkey.prv", "", &public_key, &private_key)) { SILC_LOG_DEBUG(("Create keypair")); if (!silc_create_key_pair("rsa", 2048, "pubkey.pub", "privkey.prv", NULL, "", &public_key, &private_key, FALSE)) goto err; } SILC_LOG_DEBUG(("Alloc RNG")); rng = silc_rng_alloc(); silc_rng_init(rng); SILC_LOG_DEBUG(("Alloc AES")); if (!silc_cipher_alloc("aes-128-cbc", &key)) goto err; SILC_LOG_DEBUG(("Alloc SHA-256")); if (!silc_hash_alloc("sha256", &hash)) goto err; SILC_LOG_DEBUG(("Alloc HMAC")); if (!silc_hmac_alloc("hmac-sha256-96", hash, &hmac)) goto err; SILC_LOG_DEBUG(("Set static key: '1234567890123456'")); if (!silc_cipher_set_key(key, "1234567890123456", 16 * 8)) goto err; SILC_LOG_DEBUG(("Set HMAC key: '1234567890123456'")); silc_hmac_set_key(hmac, "1234567890123456", 16); /* Simple private message */ SILC_LOG_DEBUG(("Encoding private message len %d (static key)", strlen(msg))); buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 | SILC_MESSAGE_FLAG_ACK, msg, strlen(msg), TRUE, TRUE, key, hmac, rng, NULL, NULL, NULL, NULL); if (!buf) goto err; SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf)); SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); SILC_LOG_DEBUG(("Flags: %x", flags)); if (!(flags & SILC_MESSAGE_FLAG_ACTION)) goto err; if (!(flags & SILC_MESSAGE_FLAG_UTF8)) goto err; if (!(flags & SILC_MESSAGE_FLAG_ACK)) goto err; data = silc_message_get_data(message, &data_len); SILC_LOG_HEXDUMP(("Data"), data, data_len); if (data_len != strlen(msg) || memcmp(data, msg, strlen(msg))) goto err; SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), silc_hmac_len(hmac)); silc_message_payload_free(message); /* Simple private message */ n = 10; SILC_LOG_DEBUG(("Encoding private message len %d (static key)", n)); buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 | SILC_MESSAGE_FLAG_ACK, msg, n, TRUE, TRUE, key, hmac, rng, NULL, NULL, NULL, buf); if (!buf) goto err; SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf)); SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); SILC_LOG_DEBUG(("Flags: %x", flags)); if (!(flags & SILC_MESSAGE_FLAG_ACTION)) goto err; if (!(flags & SILC_MESSAGE_FLAG_UTF8)) goto err; if (!(flags & SILC_MESSAGE_FLAG_ACK)) goto err; data = silc_message_get_data(message, &data_len); SILC_LOG_HEXDUMP(("Data"), data, data_len); if (data_len != n || memcmp(data, msg, n)) goto err; SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), silc_hmac_len(hmac)); silc_message_payload_free(message); /* Simple private message */ n = 1; SILC_LOG_DEBUG(("Encoding private message len %d (static key)", n)); buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 | SILC_MESSAGE_FLAG_ACK, msg, n, TRUE, TRUE, key, hmac, rng, NULL, NULL, NULL, buf); if (!buf) goto err; SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf)); SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); SILC_LOG_DEBUG(("Flags: %x", flags)); if (!(flags & SILC_MESSAGE_FLAG_ACTION)) goto err; if (!(flags & SILC_MESSAGE_FLAG_UTF8)) goto err; if (!(flags & SILC_MESSAGE_FLAG_ACK)) goto err; data = silc_message_get_data(message, &data_len); SILC_LOG_HEXDUMP(("Data"), data, data_len); if (data_len != n || memcmp(data, msg, n)) goto err; SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), silc_hmac_len(hmac)); silc_message_payload_free(message); /* Simple private message */ for (i = 0; i < sizeof(tmp); i++) tmp[i] = (32 + i) & 127; SILC_LOG_DEBUG(("Encoding private message len %d (static key)", sizeof(tmp))); buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 | SILC_MESSAGE_FLAG_ACK, tmp, sizeof(tmp), TRUE, TRUE, key, hmac, rng, NULL, NULL, NULL, buf); if (!buf) goto err; SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf)); SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); SILC_LOG_DEBUG(("Flags: %x", flags)); if (!(flags & SILC_MESSAGE_FLAG_ACTION)) goto err; if (!(flags & SILC_MESSAGE_FLAG_UTF8)) goto err; if (!(flags & SILC_MESSAGE_FLAG_ACK)) goto err; data = silc_message_get_data(message, &data_len); SILC_LOG_HEXDUMP(("Data"), data, data_len); if (data_len != sizeof(tmp) || memcmp(data, tmp, sizeof(tmp))) goto err; SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), silc_hmac_len(hmac)); silc_message_payload_free(message); /* Digitally signed private message */ for (i = 0; i < sizeof(tmp); i++) tmp[i] = (32 + i) & 127; SILC_LOG_DEBUG(("Encoding private message len %d (static key) SIGNED", sizeof(tmp))); buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 | SILC_MESSAGE_FLAG_ACK | SILC_MESSAGE_FLAG_SIGNED, tmp, sizeof(tmp), TRUE, TRUE, key, hmac, rng, public_key, private_key, hash, buf); if (!buf) goto err; SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf)); SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); SILC_LOG_DEBUG(("Flags: %x", flags)); if (!(flags & SILC_MESSAGE_FLAG_ACTION)) goto err; if (!(flags & SILC_MESSAGE_FLAG_UTF8)) goto err; if (!(flags & SILC_MESSAGE_FLAG_ACK)) goto err; if (!(flags & SILC_MESSAGE_FLAG_SIGNED)) goto err; data = silc_message_get_data(message, &data_len); SILC_LOG_HEXDUMP(("Data"), data, data_len); if (data_len != sizeof(tmp) || memcmp(data, tmp, sizeof(tmp))) goto err; SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), silc_hmac_len(hmac)); SILC_LOG_DEBUG(("Verifying signature")); if (silc_message_signed_verify(message, public_key, hash) != SILC_AUTH_OK) goto err; SILC_LOG_DEBUG(("Signature Ok")); SILC_LOG_DEBUG(("Get public key")); pk2 = silc_message_signed_get_public_key(message, NULL, NULL); if (!pk2) goto err; SILC_LOG_DEBUG(("Verify public key")); if (!silc_pkcs_public_key_compare(public_key, pk2)) goto err; SILC_LOG_DEBUG(("Public key Ok")); silc_pkcs_public_key_free(pk2); silc_message_payload_free(message); /* Digitally signed channel message */ for (i = 0; i < sizeof(tmp) / 2; i++) tmp[i] = (32 + i) & 127; SILC_LOG_DEBUG(("Encoding channel message len %d (static key) SIGNED", sizeof(tmp) / 2)); buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 | SILC_MESSAGE_FLAG_ACK | SILC_MESSAGE_FLAG_SIGNED, tmp, sizeof(tmp) / 2, TRUE, FALSE, key, hmac, rng, public_key, private_key, hash, buf); if (!buf) goto err; SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf)); SILC_LOG_DEBUG(("Parsing channel messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), FALSE, TRUE, key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); SILC_LOG_DEBUG(("Flags: %x", flags)); if (!(flags & SILC_MESSAGE_FLAG_ACTION)) goto err; if (!(flags & SILC_MESSAGE_FLAG_UTF8)) goto err; if (!(flags & SILC_MESSAGE_FLAG_ACK)) goto err; if (!(flags & SILC_MESSAGE_FLAG_SIGNED)) goto err; data = silc_message_get_data(message, &data_len); SILC_LOG_HEXDUMP(("Data"), data, data_len); if (data_len != sizeof(tmp) / 2 || memcmp(data, tmp, sizeof(tmp) / 2)) goto err; SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), silc_hmac_len(hmac)); SILC_LOG_DEBUG(("Verifying signature")); if (silc_message_signed_verify(message, public_key, hash) != SILC_AUTH_OK) goto err; SILC_LOG_DEBUG(("Signature Ok")); SILC_LOG_DEBUG(("Get public key")); pk2 = silc_message_signed_get_public_key(message, NULL, NULL); if (!pk2) goto err; SILC_LOG_DEBUG(("Verify public key")); if (!silc_pkcs_public_key_compare(public_key, pk2)) goto err; SILC_LOG_DEBUG(("Public key Ok")); silc_pkcs_public_key_free(pk2); silc_message_payload_free(message); /* Digitally signed private message (no encryption) */ for (i = 0; i < sizeof(tmp) / 2; i++) tmp[i] = (32 + i) & 127; SILC_LOG_DEBUG(("Encoding private message len %d SIGNED", sizeof(tmp) / 2)); buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 | SILC_MESSAGE_FLAG_ACK | SILC_MESSAGE_FLAG_SIGNED, tmp, sizeof(tmp) / 2, FALSE, TRUE, NULL, NULL, rng, public_key, private_key, hash, buf); if (!buf) goto err; SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf)); SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, FALSE, NULL, NULL, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); SILC_LOG_DEBUG(("Flags: %x", flags)); if (!(flags & SILC_MESSAGE_FLAG_ACTION)) goto err; if (!(flags & SILC_MESSAGE_FLAG_UTF8)) goto err; if (!(flags & SILC_MESSAGE_FLAG_ACK)) goto err; if (!(flags & SILC_MESSAGE_FLAG_SIGNED)) goto err; data = silc_message_get_data(message, &data_len); SILC_LOG_HEXDUMP(("Data"), data, data_len); if (data_len != sizeof(tmp) / 2 || memcmp(data, tmp, sizeof(tmp) / 2)) goto err; SILC_LOG_DEBUG(("Verifying signature")); if (silc_message_signed_verify(message, public_key, hash) != SILC_AUTH_OK) goto err; SILC_LOG_DEBUG(("Signature Ok")); SILC_LOG_DEBUG(("Get public key")); pk2 = silc_message_signed_get_public_key(message, NULL, NULL); if (!pk2) goto err; SILC_LOG_DEBUG(("Verify public key")); if (!silc_pkcs_public_key_compare(public_key, pk2)) goto err; SILC_LOG_DEBUG(("Public key Ok")); silc_pkcs_public_key_free(pk2); silc_message_payload_free(message); /* Digitally signed channel message (LARGE) */ n = 65550; tmp2 = silc_malloc(n); if (!tmp2) goto err; SILC_LOG_DEBUG(("Encoding channel message len %d (static key) SIGNED LARGE", n)); buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 | SILC_MESSAGE_FLAG_ACK | SILC_MESSAGE_FLAG_SIGNED, tmp2, n, TRUE, FALSE, key, hmac, rng, public_key, private_key, hash, buf); if (!buf) goto err; SILC_LOG_DEBUG(("Message length: %d", silc_buffer_len(buf))); if (silc_buffer_len(buf) > SILC_PACKET_MAX_LEN) goto err; SILC_LOG_DEBUG(("Parsing channel messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), FALSE, TRUE, key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); SILC_LOG_DEBUG(("Flags: %x", flags)); if (!(flags & SILC_MESSAGE_FLAG_ACTION)) goto err; if (!(flags & SILC_MESSAGE_FLAG_UTF8)) goto err; if (!(flags & SILC_MESSAGE_FLAG_ACK)) goto err; if (!(flags & SILC_MESSAGE_FLAG_SIGNED)) goto err; data = silc_message_get_data(message, &data_len); SILC_LOG_DEBUG(("Data len: %d", data_len)); if (silc_buffer_len(buf) > SILC_PACKET_MAX_LEN) goto err; SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), silc_hmac_len(hmac)); SILC_LOG_DEBUG(("Verifying signature")); if (silc_message_signed_verify(message, public_key, hash) != SILC_AUTH_OK) goto err; SILC_LOG_DEBUG(("Signature Ok")); SILC_LOG_DEBUG(("Get public key")); pk2 = silc_message_signed_get_public_key(message, NULL, NULL); if (!pk2) goto err; SILC_LOG_DEBUG(("Verify public key")); if (!silc_pkcs_public_key_compare(public_key, pk2)) goto err; SILC_LOG_DEBUG(("Public key Ok")); silc_pkcs_public_key_free(pk2); silc_message_payload_free(message); silc_free(tmp2); success = TRUE; SILC_LOG_DEBUG(("Cleanup")); silc_pkcs_public_key_free(public_key); silc_pkcs_private_key_free(private_key); silc_cipher_free(key); silc_hash_free(hash); silc_rng_free(rng); err: silc_cipher_unregister_all(); silc_hash_unregister_all(); silc_hmac_unregister_all(); silc_pkcs_unregister_all(); SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE")); fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE"); return success; }
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_buffer_stream_io(SilcStream stream, SilcStreamStatus status, void *context) { SilcBufferStream bs = context; SilcBuffer buffer = NULL; SilcUInt32 buf_len; int ret, len; if (bs->closed) return; if (status == SILC_STREAM_CAN_READ) { /* Read data */ SILC_LOG_DEBUG(("Read data from buffer stream %p", bs)); while ((ret = silc_stream_read(bs->stream, bs->inbuf->tail, silc_buffer_taillen(bs->inbuf))) > 0) { if (!buffer) { buffer = silc_buffer_alloc(0); if (!buffer) return; } silc_buffer_pull_tail(bs->inbuf, ret); /* Parse the buffer */ while ((len = silc_buffer_unformat(bs->inbuf, SILC_STR_BUFFER_ALLOC(buffer), SILC_STR_END)) > 0) { /* Deliver the buffer */ SILC_LOG_HEXDUMP(("Received buffer, size %d", silc_buffer_len(buffer)), silc_buffer_data(buffer), silc_buffer_len(buffer)); bs->receiver(SILC_OK, (SilcStream)bs, buffer, bs->context); silc_buffer_pull(bs->inbuf, len); buffer = silc_buffer_alloc(0); if (!buffer) return; } if (silc_buffer_len(bs->inbuf) > 0) { /* Not complete buffer, read more data */ buf_len = 4; if (silc_buffer_len(bs->inbuf) >= 4) { SILC_GET32_MSB(buf_len, bs->inbuf->data); SILC_LOG_DEBUG(("Incomplete buffer, wait for rest, buffer size %d", buf_len)); } /* Enlarge inbuf if needed */ if (silc_buffer_taillen(bs->inbuf) < buf_len) silc_buffer_realloc(bs->inbuf, silc_buffer_truelen(bs->inbuf) + buf_len); continue; } /* All data read, read more */ silc_buffer_reset(bs->inbuf); } silc_buffer_free(buffer); if (ret == 0 || ret == -2) { bs->receiver(silc_errno, (SilcStream)bs, NULL, bs->context); return; } } else { /* Write any pending data */ SILC_LOG_DEBUG(("Write pending data to buffer stream %p", bs)); while (silc_buffer_len(&bs->queue) > 0) { ret = silc_stream_write(bs->stream, silc_buffer_data(&bs->queue), silc_buffer_len(&bs->queue)); if (silc_unlikely(ret == 0)) return; if (silc_unlikely(ret == -2)) return; if (silc_unlikely(ret == -1)) { SILC_LOG_DEBUG(("Buffer stream %p would block, send later", bs)); return; } /* Wrote data */ silc_buffer_pull(&bs->queue, ret); } memset(&bs->queue, 0, sizeof(bs->queue)); silc_buffer_reset(bs->outbuf); } }
SilcBuffer silc_client_attributes_process(SilcClient client, SilcClientConnection conn, SilcDList attrs) { SilcBuffer buffer = NULL; SilcAttrForeach f; SilcAttribute attribute; SilcAttributePayload attr; SilcAttributeObjPk pk; unsigned char sign[2048 + 1]; SilcUInt32 sign_len; SILC_LOG_DEBUG(("Process Requested Attributes")); /* If nothing is set by application assume that we don't want to use attributes, ignore the request. */ if (!conn->internal->attrs) { SILC_LOG_DEBUG(("User has not set any attributes")); return NULL; } /* Always put our public key. */ pk.type = "silc-rsa"; pk.data = silc_pkcs_public_key_encode(conn->public_key, &pk.data_len); buffer = silc_attribute_payload_encode(buffer, SILC_ATTRIBUTE_USER_PUBLIC_KEY, pk.data ? SILC_ATTRIBUTE_FLAG_VALID : SILC_ATTRIBUTE_FLAG_INVALID, &pk, sizeof(pk)); silc_free(pk.data); /* Go through all requested attributes */ f.buffer = buffer; silc_dlist_start(attrs); while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) { /* Put all attributes of this type */ attribute = silc_attribute_get_attribute(attr); /* Ignore signature since we will compute it later */ if (attribute == SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE) continue; silc_hash_table_find_foreach(conn->internal->attrs, SILC_32_TO_PTR(attribute), silc_client_attributes_process_foreach, &f); } buffer = f.buffer; /* Finally compute the digital signature of all the data we provided. */ if (silc_pkcs_sign(conn->private_key, silc_buffer_data(buffer), silc_buffer_len(buffer), sign, sizeof(sign), &sign_len, TRUE, conn->internal->sha1hash)) { pk.type = NULL; pk.data = sign; pk.data_len = sign_len; buffer = silc_attribute_payload_encode(buffer, SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE, SILC_ATTRIBUTE_FLAG_VALID, &pk, sizeof(pk)); } return buffer; }
SilcBool silc_client_save_channel_key(SilcClient client, SilcClientConnection conn, SilcBuffer key_payload, SilcChannelEntry channel) { unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN]; SilcUInt32 tmp_len; SilcChannelID id; SilcChannelKeyPayload payload; SILC_LOG_DEBUG(("New channel key")); payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload), silc_buffer_len(key_payload)); if (!payload) return FALSE; id_string = silc_channel_key_get_id(payload, &tmp_len); if (!id_string) { silc_channel_key_payload_free(payload); return FALSE; } if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) { silc_channel_key_payload_free(payload); return FALSE; } /* Find channel. */ if (!channel) { channel = silc_client_get_channel_by_id(client, conn, &id); if (!channel) { SILC_LOG_DEBUG(("Key for unknown channel")); silc_channel_key_payload_free(payload); return FALSE; } } else { silc_client_ref_channel(client, conn, channel); } /* Save the old key for a short period of time so that we can decrypt channel message even after the rekey if some client would be sending messages with the old key after the rekey. */ if (!channel->internal.old_channel_keys) channel->internal.old_channel_keys = silc_dlist_init(); if (!channel->internal.old_hmacs) channel->internal.old_hmacs = silc_dlist_init(); if (channel->internal.old_channel_keys && channel->internal.old_hmacs) { silc_dlist_add(channel->internal.old_channel_keys, channel->internal.receive_key); silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac); silc_schedule_task_add_timeout(client->schedule, silc_client_save_channel_key_rekey, channel, 15, 0); } /* Get channel cipher */ cipher = silc_channel_key_get_cipher(payload, NULL); if (!silc_cipher_alloc(cipher, &channel->internal.send_key)) { client->internal->ops->say( conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Cannot talk to channel: unsupported cipher %s", cipher); silc_client_unref_channel(client, conn, channel); silc_channel_key_payload_free(payload); return FALSE; } if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) { client->internal->ops->say( conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Cannot talk to channel: unsupported cipher %s", cipher); silc_client_unref_channel(client, conn, channel); silc_channel_key_payload_free(payload); return FALSE; } /* Set the cipher key. Both sending and receiving keys are same */ key = silc_channel_key_get_key(payload, &tmp_len); silc_cipher_set_key(channel->internal.send_key, key, tmp_len * 8, TRUE); silc_cipher_set_key(channel->internal.receive_key, key, tmp_len * 8, FALSE); /* Get channel HMAC */ hmac = (channel->internal.hmac ? (char *)silc_hmac_get_name(channel->internal.hmac) : SILC_DEFAULT_HMAC); if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) { client->internal->ops->say( conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Cannot talk to channel: unsupported HMAC %s", hmac); silc_client_unref_channel(client, conn, channel); silc_channel_key_payload_free(payload); return FALSE; } channel->cipher = silc_cipher_get_name(channel->internal.send_key); channel->hmac = silc_hmac_get_name(channel->internal.hmac); /* Set HMAC key */ silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key, tmp_len, hash); silc_hmac_set_key(channel->internal.hmac, hash, silc_hash_len(silc_hmac_get_hash(channel->internal.hmac))); memset(hash, 0, sizeof(hash)); silc_channel_key_payload_free(payload); silc_client_unref_channel(client, conn, channel); return TRUE; }
SilcBool silc_pkcs1_verify(void *public_key, unsigned char *signature, SilcUInt32 signature_len, unsigned char *data, SilcUInt32 data_len, SilcHash hash) { RsaPublicKey *key = public_key; SilcBool ret = FALSE; SilcMPInt mp_tmp2; SilcMPInt mp_dst; unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN]; SilcUInt32 verify_len, len = (key->bits + 7) / 8; SilcBufferStruct di, ldi; SilcHash ihash = NULL; SilcAsn1 asn1 = NULL; char *oid; SILC_LOG_DEBUG(("Verify signature")); asn1 = silc_asn1_alloc(); if (!asn1) return FALSE; silc_mp_init(&mp_tmp2); silc_mp_init(&mp_dst); /* Format the signature into MP int */ silc_mp_bin2mp(signature, signature_len, &mp_tmp2); /* Verify */ silc_rsa_public_operation(key, &mp_tmp2, &mp_dst); /* MP to data */ verify = silc_mp_mp2bin(&mp_dst, len, &verify_len); /* Unpad data */ if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len, unpadded, sizeof(unpadded), &len)) goto err; silc_buffer_set(&di, unpadded, len); /* If hash isn't given, allocate the one given in digest info */ if (!hash) { /* Decode digest info */ if (!silc_asn1_decode(asn1, &di, SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL), SILC_ASN1_SEQUENCE, SILC_ASN1_SEQUENCE, SILC_ASN1_OID(&oid), SILC_ASN1_END, SILC_ASN1_END, SILC_ASN1_END)) goto err; if (!silc_hash_alloc_by_oid(oid, &ihash)) { SILC_LOG_DEBUG(("Unknown OID %s", oid)); goto err; } hash = ihash; } /* Hash the data */ silc_hash_make(hash, data, data_len, hashr); data = hashr; data_len = silc_hash_len(hash); oid = (char *)silc_hash_get_oid(hash); /* Encode digest info for comparison */ memset(&ldi, 0, sizeof(ldi)); if (!silc_asn1_encode(asn1, &ldi, SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL), SILC_ASN1_SEQUENCE, SILC_ASN1_SEQUENCE, SILC_ASN1_OID(oid), SILC_ASN1_NULL, SILC_ASN1_END, SILC_ASN1_OCTET_STRING(data, data_len), SILC_ASN1_END, SILC_ASN1_END)) goto err; SILC_LOG_HEXDUMP(("DigestInfo remote"), silc_buffer_data(&di), silc_buffer_len(&di)); SILC_LOG_HEXDUMP(("DigestInfo local"), silc_buffer_data(&ldi), silc_buffer_len(&ldi)); /* Compare */ if (silc_buffer_len(&di) == silc_buffer_len(&ldi) && !memcmp(silc_buffer_data(&di), silc_buffer_data(&ldi), silc_buffer_len(&ldi))) ret = TRUE; memset(verify, 0, verify_len); memset(unpadded, 0, sizeof(unpadded)); silc_free(verify); silc_mp_uninit(&mp_tmp2); silc_mp_uninit(&mp_dst); if (hash) memset(hashr, 0, sizeof(hashr)); if (ihash) silc_hash_free(ihash); silc_asn1_free(asn1); return ret; err: memset(verify, 0, verify_len); silc_free(verify); silc_mp_uninit(&mp_tmp2); silc_mp_uninit(&mp_dst); if (ihash) silc_hash_free(ihash); silc_asn1_free(asn1); return FALSE; }
SilcBool silc_pkcs1_sign(void *private_key, unsigned char *src, SilcUInt32 src_len, unsigned char *signature, SilcUInt32 signature_size, SilcUInt32 *ret_signature_len, SilcBool compute_hash, SilcHash hash) { RsaPrivateKey *key = private_key; unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN]; SilcMPInt mp_tmp; SilcMPInt mp_dst; SilcBufferStruct di; SilcUInt32 len = (key->bits + 7) / 8; const char *oid; SilcAsn1 asn1; SILC_LOG_DEBUG(("Sign")); if (sizeof(padded) < len) return FALSE; if (signature_size < len) return FALSE; oid = silc_hash_get_oid(hash); if (!oid) return FALSE; asn1 = silc_asn1_alloc(); if (!asn1) return FALSE; /* Compute hash */ if (compute_hash) { silc_hash_make(hash, src, src_len, hashr); src = hashr; src_len = silc_hash_len(hash); } /* Encode digest info */ memset(&di, 0, sizeof(di)); if (!silc_asn1_encode(asn1, &di, SILC_ASN1_SEQUENCE, SILC_ASN1_SEQUENCE, SILC_ASN1_OID(oid), SILC_ASN1_NULL, SILC_ASN1_END, SILC_ASN1_OCTET_STRING(src, src_len), SILC_ASN1_END, SILC_ASN1_END)) { silc_asn1_free(asn1); return FALSE; } SILC_LOG_HEXDUMP(("DigestInfo"), silc_buffer_data(&di), silc_buffer_len(&di)); /* Pad data */ if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, silc_buffer_data(&di), silc_buffer_len(&di), padded, len, NULL)) { silc_asn1_free(asn1); return FALSE; } silc_mp_init(&mp_tmp); silc_mp_init(&mp_dst); /* Data to MP */ silc_mp_bin2mp(padded, len, &mp_tmp); /* Sign */ silc_rsa_private_operation(key, &mp_tmp, &mp_dst); /* MP to data */ silc_mp_mp2bin_noalloc(&mp_dst, signature, len); *ret_signature_len = len; memset(padded, 0, sizeof(padded)); silc_mp_uninit(&mp_tmp); silc_mp_uninit(&mp_dst); if (compute_hash) memset(hashr, 0, sizeof(hashr)); silc_asn1_free(asn1); return TRUE; }
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; }
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; }
SilcBool silc_buffer_stream_send(SilcStream stream, SilcBuffer buffer) { SilcBufferStream bs = stream; int ret; SILC_LOG_HEXDUMP(("Send to buffer stream %p %d bytes", bs, silc_buffer_len(buffer)), silc_buffer_data(buffer), silc_buffer_len(buffer)); if (silc_unlikely(!SILC_IS_BUFFER_STREAM(bs))) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return FALSE; } if (silc_unlikely(!buffer)) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return FALSE; } if (silc_unlikely(bs->closed)) { SILC_LOG_DEBUG(("Buffer stream %p is closed", bs)); silc_set_errno(SILC_ERR_NOT_VALID); return FALSE; } /* Put to queue */ if (silc_buffer_format(bs->outbuf, SILC_STR_ADVANCE, SILC_STR_BUFFER(buffer), SILC_STR_END) < 0) return FALSE; ret = silc_buffer_headlen(&bs->queue); bs->queue.head = bs->outbuf->head; bs->queue.data = bs->queue.head + ret; bs->queue.tail = bs->outbuf->data; bs->queue.end = bs->outbuf->end; /* Write the queue buffer */ while (silc_buffer_len(&bs->queue) > 0) { ret = silc_stream_write(bs->stream, silc_buffer_data(&bs->queue), silc_buffer_len(&bs->queue)); if (silc_unlikely(ret == 0)) return FALSE; if (silc_unlikely(ret == -2)) return FALSE; if (silc_unlikely(ret == -1)) { SILC_LOG_DEBUG(("Buffer stream %p would block, send later", bs)); return TRUE; } /* Wrote data */ silc_buffer_pull(&bs->queue, ret); } memset(&bs->queue, 0, sizeof(bs->queue)); silc_buffer_reset(bs->outbuf); SILC_LOG_DEBUG(("Buffer sent to buffer stream %p", bs)); return TRUE; }