SilcBool silc_server_send_notify_channel_change(SilcServer server, SilcPacketStream stream, SilcBool broadcast, SilcChannelID *old_id, SilcChannelID *new_id) { SilcBuffer idp1, idp2; SilcBool ret = FALSE; if (!server || !stream) return ret; idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CHANNEL); idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CHANNEL); if (!idp1 || !idp2) return ret; ret = silc_server_send_notify(server, stream, broadcast, SILC_NOTIFY_TYPE_CHANNEL_CHANGE, 2, idp1->data, silc_buffer_len(idp1), idp2->data, silc_buffer_len(idp2)); silc_buffer_free(idp1); silc_buffer_free(idp2); return ret; }
void silc_buffer_stream_destroy(SilcStream stream) { SilcBufferStream bs = stream; SILC_LOG_DEBUG(("Destroying buffer stream %p", bs)); silc_buffer_stream_close(stream); silc_buffer_free(bs->outbuf); silc_buffer_free(bs->inbuf); silc_free(bs); }
void silc_sftp_attr_free(SilcSFTPAttributes attr) { int i; for (i = 0; i < attr->extended_count; i++) { silc_buffer_free(attr->extended_type[i]); silc_buffer_free(attr->extended_data[i]); } silc_free(attr->extended_type); silc_free(attr->extended_data); silc_free(attr); }
SilcBool silc_server_send_command(SilcServer server, SilcPacketStream stream, SilcCommand command, SilcUInt16 ident, SilcUInt32 argc, ...) { SilcBuffer packet; va_list ap; SilcBool ret = FALSE; /* Statistics */ server->stat.commands_sent++; va_start(ap, argc); packet = silc_command_payload_encode_vap(command, ident, argc, ap); if (!packet) { va_end(ap); return ret; } ret = silc_packet_send(stream, SILC_PACKET_COMMAND, 0, packet->data, silc_buffer_len(packet)); silc_buffer_free(packet); va_end(ap); return ret; }
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_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; }
static void silc_server_command_status_data2(SilcServerCommand cmd, SilcCommand command, SilcStatus status, SilcStatus error, SilcUInt32 arg_type1, const unsigned char *arg1, SilcUInt32 arg_len1, SilcUInt32 arg_type2, const unsigned char *arg2, SilcUInt32 arg_len2) { SilcBuffer buffer; /* Statistics */ cmd->thread->server->stat.commands_sent++; SILC_LOG_DEBUG(("Sending command status %d", status)); buffer = silc_command_reply_payload_encode_va(command, status, 0, silc_command_get_ident(cmd->payload), 2, arg_type1, arg1, arg_len1, arg_type2, arg2, arg_len2); silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0, buffer->data, silc_buffer_len(buffer)); silc_buffer_free(buffer); }
static SilcBool silc_connauth_get_signature(SilcConnAuth connauth, unsigned char **auth_data, SilcUInt32 *auth_data_len) { int len; SilcSKE ske; SilcPrivateKey private_key; SilcBuffer auth; SILC_LOG_DEBUG(("Compute signature")); ske = connauth->ske; private_key = connauth->auth_data; /* Make the authentication data. Protocol says it is HASH plus KE Start Payload. */ len = ske->hash_len + silc_buffer_len(ske->start_payload_copy); auth = silc_buffer_alloc_size(len); if (!auth) return FALSE; silc_buffer_format(auth, SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len), SILC_STR_UI_XNSTRING( ske->start_payload_copy->data, silc_buffer_len(ske->start_payload_copy)), SILC_STR_END); len = ((silc_pkcs_private_key_get_len(private_key) + 7) / 8) + 1; *auth_data = silc_calloc(len, sizeof(**auth_data)); if (*auth_data == NULL) { silc_buffer_free(auth); return FALSE; } /* Compute signature */ if (!silc_pkcs_sign(private_key, auth->data, silc_buffer_len(auth), *auth_data, len, auth_data_len, TRUE, ske->prop->hash)) { silc_free(*auth_data); silc_buffer_free(auth); return FALSE; } silc_buffer_free(auth); return TRUE; }
SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload) { SilcBuffer buffer; SilcBuffer args = NULL; SilcUInt32 len = 0; SilcUInt32 argc = 0; SILC_LOG_DEBUG(("Encoding command payload")); if (payload->args) { args = silc_argument_payload_encode_payload(payload->args); if (args) len = silc_buffer_len(args); argc = silc_argument_get_arg_num(payload->args); } len += SILC_COMMAND_PAYLOAD_LEN; buffer = silc_buffer_alloc_size(len); if (!buffer) { if (args) silc_buffer_free(args); return NULL; } /* Create Command payload */ silc_buffer_format(buffer, SILC_STR_UI_SHORT(len), SILC_STR_UI_CHAR(payload->cmd), SILC_STR_UI_CHAR(argc), SILC_STR_UI_SHORT(payload->ident), SILC_STR_END); /* Add arguments */ if (args) { silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); silc_buffer_format(buffer, SILC_STR_UI_XNSTRING(args->data, silc_buffer_len(args)), SILC_STR_END); silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); silc_buffer_free(args); } return buffer; }
void silcpurple_wb_send(PurpleWhiteboard *wb, GList *draw_list) { SilcPurpleWb wbs = wb->proto_data; SilcBuffer packet; GList *list; int len; PurpleConnection *gc; SilcPurple sg; g_return_if_fail(draw_list); gc = purple_account_get_connection(wb->account); g_return_if_fail(gc); sg = gc->proto_data; g_return_if_fail(sg); len = SILCPURPLE_WB_HEADER; for (list = draw_list; list; list = list->next) len += 4; packet = silc_buffer_alloc_size(len); if (!packet) return; /* Assmeble packet */ silc_buffer_format(packet, SILC_STR_UI32_STRING(SILCPURPLE_WB_MIME), SILC_STR_UI_CHAR(SILCPURPLE_WB_DRAW), SILC_STR_UI_SHORT(wbs->width), SILC_STR_UI_SHORT(wbs->height), SILC_STR_UI_INT(wbs->brush_color), SILC_STR_UI_SHORT(wbs->brush_size), SILC_STR_END); silc_buffer_pull(packet, SILCPURPLE_WB_HEADER); for (list = draw_list; list; list = list->next) { silc_buffer_format(packet, SILC_STR_UI_INT(GPOINTER_TO_INT(list->data)), SILC_STR_END); silc_buffer_pull(packet, 4); } /* Send the message */ if (wbs->type == 0) { /* Private message */ silc_client_send_private_message(sg->client, sg->conn, wbs->u.client, SILC_MESSAGE_FLAG_DATA, NULL, packet->head, len); } else if (wbs->type == 1) { /* Channel message. Channel private keys are not supported. */ silc_client_send_channel_message(sg->client, sg->conn, wbs->u.channel, NULL, SILC_MESSAGE_FLAG_DATA, NULL, packet->head, len); } silc_buffer_free(packet); }
void silc_sftp_server_shutdown(SilcSFTP sftp) { SilcSFTPServer server = (SilcSFTPServer)sftp; SILC_LOG_DEBUG(("Stopping SFTP server %p", server)); silc_stream_set_notifier(server->stream, server->schedule, NULL, NULL); if (server->packet) silc_buffer_free(server->packet); silc_free(server); }
void silc_mime_partial_free(SilcDList partials) { SilcBuffer buf; if (!partials) return; silc_dlist_start(partials); while ((buf = silc_dlist_get(partials)) != SILC_LIST_END) silc_buffer_free(buf); silc_dlist_uninit(partials); }
SilcBool silc_client_send_private_message(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, SilcMessageFlags flags, SilcHash hash, unsigned char *data, SilcUInt32 data_len) { SilcBuffer buffer; SilcBool ret; SilcID sid, rid; if (silc_unlikely(!client || !conn || !client_entry)) return FALSE; if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) return FALSE; if (silc_unlikely(conn->internal->disconnected)) return FALSE; SILC_LOG_DEBUG(("Sending private message")); sid.type = SILC_ID_CLIENT; sid.u.client_id = conn->local_entry->id; rid.type = SILC_ID_CLIENT; rid.u.client_id = client_entry->id; /* Encode private message payload */ buffer = silc_message_payload_encode(flags, data, data_len, (!client_entry->internal.send_key ? FALSE : !client_entry->internal.generated), TRUE, client_entry->internal.send_key, client_entry->internal.hmac_send, client->rng, NULL, conn->private_key, hash, &sid, &rid, NULL); if (silc_unlikely(!buffer)) { SILC_LOG_ERROR(("Error encoding private message")); return FALSE; } /* Send the private message packet */ ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE, client_entry->internal.send_key ? SILC_PACKET_FLAG_PRIVMSG_KEY : 0, 0, NULL, SILC_ID_CLIENT, &client_entry->id, silc_buffer_datalen(buffer), NULL, NULL); silc_buffer_free(buffer); return ret; }
SilcStream silc_buffer_stream_create(SilcStream stream, SilcBufferReceiveCallback receiver, void *context) { SilcBufferStream bs; if (!stream || !receiver) { silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return NULL; } bs = silc_calloc(1, sizeof(*bs)); if (!bs) return NULL; SILC_LOG_DEBUG(("Created new buffer stream %p", bs)); bs->ops = &silc_buffer_stream_ops; bs->stream = stream; bs->receiver = receiver; bs->context = context; bs->inbuf = silc_buffer_alloc(32); bs->outbuf = silc_buffer_alloc(0); if (!bs->inbuf || !bs->outbuf) { silc_buffer_free(bs->inbuf); silc_buffer_free(bs->outbuf); silc_free(bs); return NULL; } /* Set IO callback to the underlaying stream */ silc_stream_set_notifier(bs->stream, silc_stream_get_schedule(bs->stream), silc_buffer_stream_io, bs); return (SilcStream)bs; }
static SilcBool silc_connauth_verify_signature(SilcConnAuth connauth, SilcPublicKey pub_key, unsigned char *sign, SilcUInt32 sign_len) { int len; SilcBuffer auth; SilcSKE ske = connauth->ske; if (!pub_key || !sign) return FALSE; /* Make the authentication data. Protocol says it is HASH plus KE Start Payload. */ len = ske->hash_len + silc_buffer_len(ske->start_payload_copy); auth = silc_buffer_alloc_size(len); if (!auth) return FALSE; silc_buffer_format(auth, SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len), SILC_STR_UI_XNSTRING( ske->start_payload_copy->data, silc_buffer_len(ske->start_payload_copy)), SILC_STR_END); /* Verify signature */ if (!silc_pkcs_verify(pub_key, sign, sign_len, auth->data, silc_buffer_len(auth), ske->prop->hash)) { silc_buffer_free(auth); return FALSE; } silc_buffer_free(auth); return TRUE; }
SilcBuffer silc_command_payload_encode(SilcCommand cmd, SilcUInt32 argc, unsigned char **argv, SilcUInt32 *argv_lens, SilcUInt32 *argv_types, SilcUInt16 ident) { SilcBuffer buffer; SilcBuffer args = NULL; SilcUInt32 len = 0; SILC_LOG_DEBUG(("Encoding command payload")); if (argc) { args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types); if (!args) return NULL; len = silc_buffer_len(args); } len += SILC_COMMAND_PAYLOAD_LEN; buffer = silc_buffer_alloc_size(len); if (!buffer) return NULL; /* Create Command payload */ silc_buffer_format(buffer, SILC_STR_UI_SHORT(len), SILC_STR_UI_CHAR(cmd), SILC_STR_UI_CHAR(argc), SILC_STR_UI_SHORT(ident), SILC_STR_END); /* Add arguments */ if (argc) { silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); silc_buffer_format(buffer, SILC_STR_UI_XNSTRING(args->data, silc_buffer_len(args)), SILC_STR_END); silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); silc_buffer_free(args); } return buffer; }
void silcpurple_wb_clear(PurpleWhiteboard *wb) { SilcPurpleWb wbs = wb->proto_data; SilcBuffer packet; int len; PurpleConnection *gc; SilcPurple sg; gc = purple_account_get_connection(wb->account); g_return_if_fail(gc); sg = gc->proto_data; g_return_if_fail(sg); len = SILCPURPLE_WB_HEADER; packet = silc_buffer_alloc_size(len); if (!packet) return; /* Assmeble packet */ silc_buffer_format(packet, SILC_STR_UI32_STRING(SILCPURPLE_WB_MIME), SILC_STR_UI_CHAR(SILCPURPLE_WB_CLEAR), SILC_STR_UI_SHORT(wbs->width), SILC_STR_UI_SHORT(wbs->height), SILC_STR_UI_INT(wbs->brush_color), SILC_STR_UI_SHORT(wbs->brush_size), SILC_STR_END); /* Send the message */ if (wbs->type == 0) { /* Private message */ silc_client_send_private_message(sg->client, sg->conn, wbs->u.client, SILC_MESSAGE_FLAG_DATA, NULL, packet->head, len); } else if (wbs->type == 1) { /* Channel message */ silc_client_send_channel_message(sg->client, sg->conn, wbs->u.channel, NULL, SILC_MESSAGE_FLAG_DATA, NULL, packet->head, len); } silc_buffer_free(packet); }
SilcBuffer silc_sftp_packet_encode_vp(SilcSFTPPacket packet, SilcBuffer packet_buf, SilcUInt32 len, va_list vp) { SilcBuffer buffer; bool dyn; int ret; if (packet_buf) { if (silc_buffer_truelen(packet_buf) < 4 + 1 + len) { packet_buf = silc_buffer_realloc(packet_buf, 4 + 1 + len); if (!packet_buf) return NULL; } buffer = packet_buf; dyn = FALSE; } else { buffer = silc_buffer_alloc(4 + 1 + len); if (!buffer) return NULL; dyn = TRUE; } silc_buffer_pull_tail(buffer, 4 + 1 + len); silc_buffer_format(buffer, SILC_STR_UI_INT(len), SILC_STR_UI_CHAR(packet), SILC_STR_END); silc_buffer_pull(buffer, 5); ret = silc_buffer_format_vp(buffer, vp); if (ret < 0) { if (dyn) silc_buffer_free(buffer); return NULL; } silc_buffer_push(buffer, 5); return buffer; }
static void silc_server_command_status_reply(SilcServerCommand cmd, SilcCommand command, SilcStatus status, SilcStatus error) { SilcBuffer buffer; /* Statistics */ cmd->thread->server->stat.commands_sent++; SILC_LOG_DEBUG(("Sending command status %d", status)); buffer = silc_command_reply_payload_encode_va(command, status, error, silc_command_get_ident(cmd->payload), 0); silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0, buffer->data, silc_buffer_len(buffer)); silc_buffer_free(buffer); }
SilcBool silc_server_send_notify(SilcServer server, SilcPacketStream stream, SilcBool broadcast, SilcNotifyType type, SilcUInt32 argc, ...) { va_list ap; SilcBuffer packet; SilcBool ret = FALSE; if (!stream) return FALSE; va_start(ap, argc); packet = silc_notify_payload_encode(type, argc, ap); if (!packet) { va_end(ap); return ret; } ret = silc_packet_send(stream, SILC_PACKET_NOTIFY, broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, packet->data, silc_buffer_len(packet)); #if 0 /* Send to backup routers if this is being broadcasted to primary router. The silc_server_backup_send checks further whether to actually send it or not. */ if ((broadcast && stream == SILC_PRIMARY_ROUTE(server)) || (broadcast && !SILC_PRIMARY_ROUTE(server))) silc_server_backup_send(server, NULL, SILC_PACKET_NOTIFY, 0, packet->data, packet->len, FALSE, TRUE); #endif /* 0 */ silc_buffer_free(packet); va_end(ap); return ret; }
SilcBool silc_server_send_notify_args(SilcPacketStream stream, SilcBool broadcast, SilcNotifyType type, SilcUInt32 argc, SilcBuffer args) { SilcBuffer packet; SilcBool ret = FALSE; if (!stream) return FALSE; packet = silc_notify_payload_encode_args(type, argc, args); if (!packet) return ret; ret = silc_packet_send(stream, SILC_PACKET_NOTIFY, broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, packet->data, silc_buffer_len(packet)); silc_buffer_free(packet); return ret; }
SilcBool silc_server_send_new_id(SilcPacketStream stream, SilcBool broadcast, void *id, SilcIdType id_type) { SilcBuffer idp; SilcBool ret = FALSE; if (!stream || !id) return ret; SILC_LOG_DEBUG(("Sending new ID (%s)", silc_id_render(id, id_type))); idp = silc_id_payload_encode(id, id_type); if (!idp) return ret; ret = silc_packet_send(stream, SILC_PACKET_NEW_ID, broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, idp->data, silc_buffer_len(idp)); silc_buffer_free(idp); return ret; }
SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial) { char *type, *id = NULL, *tmp; SilcHashTable f; SilcMime p, complete; int i, number, total = -1; const unsigned char *data; SilcUInt32 data_len; SilcBuffer compbuf = NULL; SILC_LOG_DEBUG(("Assembling MIME fragments")); if (!assembler || !partial) goto err; type = (char *)silc_mime_get_field(partial, "Content-Type"); if (!type) goto err; /* Get ID */ tmp = strstr(type, "id="); if (!tmp) goto err; if (strlen(tmp) <= 4) goto err; tmp += 3; if (*tmp == '"') tmp++; id = strdup(tmp); if (strchr(id, ';')) *strchr(id, ';') = '\0'; if (strrchr(id, '"')) *strrchr(id, '"') = '\0'; SILC_LOG_DEBUG(("Fragment ID %s", id)); /* Get fragment number */ tmp = strstr(type, "number="); if (!tmp) goto err; tmp = strchr(tmp, '='); if (strlen(tmp) < 2) goto err; tmp++; if (strchr(tmp, ';')) { tmp = strdup(tmp); *strchr(tmp, ';') = '\0'; number = atoi(tmp); silc_free(tmp); } else { number = atoi(tmp); } SILC_LOG_DEBUG(("Fragment number %d", number)); /* Find fragments with this ID. */ if (!silc_hash_table_find(assembler->fragments, (void *)id, NULL, (void *)&f)) { /* This is new fragment to new message. Add to hash table and return. */ f = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL, silc_mime_assemble_dest, NULL, TRUE); if (!f) goto err; silc_hash_table_add(f, SILC_32_TO_PTR(number), partial); silc_hash_table_add(assembler->fragments, id, f); return NULL; } /* Try to get total number */ tmp = strstr(type, "total="); if (tmp) { tmp = strchr(tmp, '='); if (strlen(tmp) < 2) goto err; tmp++; if (strchr(tmp, ';')) { tmp = strdup(tmp); *strchr(tmp, ';') = '\0'; total = atoi(tmp); silc_free(tmp); } else { total = atoi(tmp); } SILC_LOG_DEBUG(("Fragment total %d", total)); } /* If more fragments to come, add to hash table */ if (number != total) { silc_hash_table_add(f, SILC_32_TO_PTR(number), partial); return NULL; } silc_hash_table_add(f, SILC_32_TO_PTR(number), partial); /* Verify that we really have all the fragments */ if (silc_hash_table_count(f) < total) return NULL; /* Assemble the complete MIME message now. We get them in order from the hash table. */ for (i = 1; i <= total; i++) { if (!silc_hash_table_find(f, SILC_32_TO_PTR(i), NULL, (void *)&p)) goto err; /* The fragment is in the data portion of the partial message */ data = silc_mime_get_data(p, &data_len); if (!data) goto err; /* Assemble */ if (!compbuf) { compbuf = silc_buffer_alloc_size(data_len); if (!compbuf) goto err; silc_buffer_put(compbuf, data, data_len); } else { compbuf = silc_buffer_realloc(compbuf, silc_buffer_truelen(compbuf) + data_len); if (!compbuf) goto err; silc_buffer_put_tail(compbuf, data, data_len); silc_buffer_pull_tail(compbuf, data_len); } } /* Now parse the complete MIME message and deliver it */ complete = silc_mime_decode(NULL, (const unsigned char *)compbuf->head, silc_buffer_truelen(compbuf)); if (!complete) goto err; /* Delete the hash table entry. Destructors will free memory */ silc_hash_table_del(assembler->fragments, (void *)id); silc_free(id); silc_buffer_free(compbuf); return complete; err: silc_free(id); if (compbuf) silc_buffer_free(compbuf); silc_mime_free(partial); return NULL; }
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; }
static unsigned char * silc_attribute_payload_encode_int(SilcAttribute attribute, SilcAttributeFlags flags, void *object, SilcUInt32 object_size, SilcUInt32 *ret_len) { SilcBuffer tmpbuf = NULL; unsigned char tmp[4], *str = NULL, *ret; SilcUInt32 len; /* Encode according to attribute type */ if (flags & SILC_ATTRIBUTE_FLAG_VALID) { if (!object && !object_size) return NULL; switch (attribute) { case SILC_ATTRIBUTE_USER_INFO: { SilcVCard vcard = object; if (object_size != sizeof(*vcard)) return NULL; str = silc_vcard_encode(vcard, &object_size); if (!str) return NULL; object = str; } break; case SILC_ATTRIBUTE_SERVICE: { SilcAttributeObjService *service = object; SilcUInt32 len2; if (object_size != sizeof(*service)) return NULL; len = strlen(service->address); len2 = strlen(service->signon); tmpbuf = silc_buffer_alloc_size(13 + len + len2); if (!tmpbuf) return NULL; silc_buffer_format(tmpbuf, SILC_STR_UI_INT(service->port), SILC_STR_UI_SHORT(len), SILC_STR_UI_XNSTRING(service->address, len), SILC_STR_UI_CHAR(service->status), SILC_STR_UI_SHORT(len2), SILC_STR_UI_XNSTRING(service->signon, len2), SILC_STR_UI_INT(service->idle), SILC_STR_END); object = tmpbuf->data; object_size = silc_buffer_len(tmpbuf); } break; case SILC_ATTRIBUTE_STATUS_MOOD: case SILC_ATTRIBUTE_PREFERRED_CONTACT: { SilcUInt32 mask = SILC_PTR_TO_32(object); if (object_size != sizeof(SilcUInt32)) return NULL; SILC_PUT32_MSB(mask, tmp); object = tmp; object_size = sizeof(SilcUInt32); } break; case SILC_ATTRIBUTE_STATUS_FREETEXT: case SILC_ATTRIBUTE_PREFERRED_LANGUAGE: case SILC_ATTRIBUTE_TIMEZONE: { unsigned char *string = object; str = silc_malloc(2 + object_size); if (!str) return NULL; SILC_PUT16_MSB(object_size, str); memcpy(str + 2, string, object_size); object = str; object_size += 2; } break; case SILC_ATTRIBUTE_STATUS_MESSAGE: case SILC_ATTRIBUTE_EXTENSION: case SILC_ATTRIBUTE_USER_ICON: { SilcMime mime = object; if (object_size != sizeof(*mime)) return NULL; str = silc_mime_encode(mime, &object_size); if (!str) return NULL; object = str; } break; case SILC_ATTRIBUTE_GEOLOCATION: { SilcAttributeObjGeo *geo = object; SilcUInt32 len1, len2, len3, len4; if (object_size != sizeof(*geo)) return NULL; len1 = (geo->longitude ? strlen(geo->longitude) : 0); len2 = (geo->latitude ? strlen(geo->latitude) : 0); len3 = (geo->altitude ? strlen(geo->altitude) : 0); len4 = (geo->accuracy ? strlen(geo->accuracy) : 0); if (len1 + len2 + len3 + len4 == 0) return NULL; len = len1 + len2 + len3 + len4; tmpbuf = silc_buffer_alloc_size(8 + len); if (!tmpbuf) return NULL; silc_buffer_format(tmpbuf, SILC_STR_UI_SHORT(len1), SILC_STR_UI16_STRING(len1 ? geo->longitude : ""), SILC_STR_UI_SHORT(len2), SILC_STR_UI16_STRING(len2 ? geo->latitude : ""), SILC_STR_UI_SHORT(len3), SILC_STR_UI16_STRING(len3 ? geo->altitude : ""), SILC_STR_UI_SHORT(len4), SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""), SILC_STR_END); object = tmpbuf->data; object_size = silc_buffer_len(tmpbuf); } break; case SILC_ATTRIBUTE_DEVICE_INFO: { SilcAttributeObjDevice *dev = object; SilcUInt32 len1, len2, len3, len4; if (object_size != sizeof(*dev)) return NULL; len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0); len2 = (dev->version ? strlen(dev->version) : 0); len3 = (dev->model ? strlen(dev->model) : 0); len4 = (dev->language ? strlen(dev->language) : 0); if (len1 + len2 + len3 + len4 == 0) return NULL; len = len1 + len2 + len3 + len4; tmpbuf = silc_buffer_alloc_size(4 + 8 + len); if (!tmpbuf) return NULL; silc_buffer_format(tmpbuf, SILC_STR_UI_INT(dev->type), SILC_STR_UI_SHORT(len1), SILC_STR_UI16_STRING(len1 ? dev->manufacturer : ""), SILC_STR_UI_SHORT(len2), SILC_STR_UI16_STRING(len2 ? dev->version : ""), SILC_STR_UI_SHORT(len3), SILC_STR_UI16_STRING(len3 ? dev->model : ""), SILC_STR_UI_SHORT(len4), SILC_STR_UI16_STRING(len4 ? dev->language : ""), SILC_STR_END); object = tmpbuf->data; object_size = silc_buffer_len(tmpbuf); } break; case SILC_ATTRIBUTE_PHONE_NUMBER: { SilcAttributeObjPN *pn = object; if (object_size != sizeof(*pn)) return NULL; if (!pn->number || strlen(pn->number) < 5) return NULL; tmpbuf = silc_buffer_alloc(0); if (!tmpbuf) return NULL; if (silc_buffer_format(tmpbuf, SILC_STR_UI_INT(pn->format), SILC_STR_UI_SHORT(strlen(pn->number)), SILC_STR_UI16_STRING(pn->number), SILC_STR_END) < 0) return NULL; object = tmpbuf->data; object_size = silc_buffer_len(tmpbuf); } break; case SILC_ATTRIBUTE_USER_PUBLIC_KEY: case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: { SilcAttributeObjPk *pk = object; if (object_size != sizeof(*pk)) return NULL; len = (pk->type ? strlen(pk->type) : 0); tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len); if (!tmpbuf) return NULL; silc_buffer_format(tmpbuf, SILC_STR_UI_SHORT(len), SILC_STR_UI16_STRING(pk->type), SILC_STR_UI_XNSTRING(pk->data, pk->data_len), SILC_STR_END); object = tmpbuf->data; object_size = silc_buffer_len(tmpbuf); } break; case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE: case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE: { SilcAttributeObjPk *pk = object; if (object_size != sizeof(*pk)) return NULL; object = pk->data; object_size = pk->data_len; } break; default: return NULL; break; } ret = silc_memdup(object, object_size); if (tmpbuf) silc_buffer_free(tmpbuf); silc_free(str); if (ret_len) *ret_len = object_size; return ret; } return NULL; }
static void silcpurple_add_buddy_i(PurpleConnection *gc, PurpleBuddy *b, gboolean init) { SilcPurple sg = gc->proto_data; SilcClient client = sg->client; SilcClientConnection conn = sg->conn; SilcPurpleBuddyRes r; SilcBuffer attrs; const char *filename, *name = b->name; r = silc_calloc(1, sizeof(*r)); if (!r) return; r->client = client; r->conn = conn; r->b = b; r->init = init; /* See if we have this buddy's public key. If we do use that to search the details. */ filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key"); if (filename) { SilcPublicKey public_key; SilcAttributeObjPk userpk; if (!silc_pkcs_load_public_key(filename, &public_key, SILC_PKCS_FILE_PEM) && !silc_pkcs_load_public_key(filename, &public_key, SILC_PKCS_FILE_BIN)) return; /* Get all attributes, and use the public key to search user */ name = NULL; attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO, SILC_ATTRIBUTE_SERVICE, SILC_ATTRIBUTE_STATUS_MOOD, SILC_ATTRIBUTE_STATUS_FREETEXT, SILC_ATTRIBUTE_STATUS_MESSAGE, SILC_ATTRIBUTE_PREFERRED_LANGUAGE, SILC_ATTRIBUTE_PREFERRED_CONTACT, SILC_ATTRIBUTE_TIMEZONE, SILC_ATTRIBUTE_GEOLOCATION, #ifdef SILC_ATTRIBUTE_USER_ICON SILC_ATTRIBUTE_USER_ICON, #endif SILC_ATTRIBUTE_DEVICE_INFO, 0); userpk.type = "silc-rsa"; userpk.data = silc_pkcs_public_key_encode(public_key, &userpk.data_len); attrs = silc_attribute_payload_encode(attrs, SILC_ATTRIBUTE_USER_PUBLIC_KEY, SILC_ATTRIBUTE_FLAG_VALID, &userpk, sizeof(userpk)); silc_free(userpk.data); silc_pkcs_public_key_free(public_key); r->pubkey_search = TRUE; } else { /* Get all attributes */ attrs = silc_client_attributes_request(0); } /* Resolve */ silc_client_get_clients_whois(client, conn, name, NULL, attrs, silcpurple_add_buddy_resolved, r); silc_buffer_free(attrs); }
void silc_client_del_connection(SilcClient client, SilcClientConnection conn) { SilcList list; SilcIDCacheEntry entry; SilcFSMThread thread; SILC_LOG_DEBUG(("Freeing connection %p", conn)); silc_schedule_task_del_by_context(conn->internal->schedule, conn); /* Free all cache entries */ if (conn->internal->server_cache) { if (silc_idcache_get_all(conn->internal->server_cache, &list)) { silc_list_start(list); while ((entry = silc_list_get(list))) silc_client_del_server(client, conn, entry->context); } } if (conn->internal->channel_cache) { if (silc_idcache_get_all(conn->internal->channel_cache, &list)) { silc_list_start(list); while ((entry = silc_list_get(list))) { silc_client_empty_channel(client, conn, entry->context); silc_client_del_channel(client, conn, entry->context); } } } if (conn->internal->client_cache) { if (silc_idcache_get_all(conn->internal->client_cache, &list)) { silc_list_start(list); while ((entry = silc_list_get(list))) silc_client_del_client(client, conn, entry->context); } } /* Free ID caches */ if (conn->internal->client_cache) silc_idcache_free(conn->internal->client_cache); if (conn->internal->channel_cache) silc_idcache_free(conn->internal->channel_cache); if (conn->internal->server_cache) silc_idcache_free(conn->internal->server_cache); /* Free thread pool */ silc_list_start(conn->internal->thread_pool); while ((thread = silc_list_get(conn->internal->thread_pool))) silc_fsm_free(thread); silc_free(conn->remote_host); silc_buffer_free(conn->internal->local_idp); silc_buffer_free(conn->internal->remote_idp); silc_mutex_free(conn->internal->lock); if (conn->internal->hash) silc_hash_free(conn->internal->hash); if (conn->internal->sha1hash) silc_hash_free(conn->internal->sha1hash); silc_atomic_uninit16(&conn->internal->cmd_ident); silc_free(conn->internal->away_message); if (conn->internal->rekey) silc_ske_free_rekey_material(conn->internal->rekey); if (conn->internal->cop) silc_async_free(conn->internal->cop); silc_free(conn->internal); memset(conn, 'F', sizeof(*conn)); silc_free(conn); }
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; }
unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len) { SilcMime part; SilcHashTableList htl; SilcBufferStruct buf; SilcBuffer buffer; char *field, *value, tmp[1024], tmp2[4]; unsigned char *ret; int i; SILC_LOG_DEBUG(("Encoding MIME message")); if (!mime) return NULL; memset(&buf, 0, sizeof(buf)); /* Encode the headers. Order doesn't matter */ i = 0; silc_hash_table_list(mime->fields, &htl); while (silc_hash_table_get(&htl, (void *)&field, (void *)&value)) { memset(tmp, 0, sizeof(tmp)); SILC_LOG_DEBUG(("Header %s: %s", field, value)); silc_snprintf(tmp, sizeof(tmp) - 1, "%s: %s\r\n", field, value); silc_buffer_strformat(&buf, tmp, SILC_STRFMT_END); i++; } silc_hash_table_list_reset(&htl); if (i) silc_buffer_strformat(&buf, "\r\n", SILC_STRFMT_END); /* Assemble the whole buffer */ buffer = silc_buffer_alloc_size(mime->data_len + silc_buffer_len(&buf)); if (!buffer) return NULL; /* Add headers */ if (silc_buffer_len(&buf)) { silc_buffer_put(buffer, buf.head, silc_buffer_len(&buf)); silc_buffer_pull(buffer, silc_buffer_len(&buf)); silc_buffer_purge(&buf); } /* Add data */ if (mime->data) { SILC_LOG_DEBUG(("Data len %d", mime->data_len)); silc_buffer_put(buffer, mime->data, mime->data_len); } /* Add multiparts */ if (mime->multiparts) { SILC_LOG_DEBUG(("Encoding multiparts")); silc_dlist_start(mime->multiparts); i = 0; while ((part = silc_dlist_get(mime->multiparts)) != SILC_LIST_END) { unsigned char *pd; SilcUInt32 pd_len; /* Recursive encoding */ pd = silc_mime_encode(part, &pd_len); if (!pd) return NULL; memset(tmp, 0, sizeof(tmp)); memset(tmp2, 0, sizeof(tmp2)); /* If fields are not present, add extra CRLF */ if (!silc_hash_table_count(part->fields)) silc_snprintf(tmp2, sizeof(tmp2) - 1, "\r\n"); silc_snprintf(tmp, sizeof(tmp) - 1, "%s--%s\r\n%s", i != 0 ? "\r\n" : "", mime->boundary, tmp2); i = 1; buffer = silc_buffer_realloc(buffer, silc_buffer_truelen(buffer) + pd_len + strlen(tmp)); if (!buffer) return NULL; silc_buffer_put_tail(buffer, tmp, strlen(tmp)); silc_buffer_pull_tail(buffer, strlen(tmp)); silc_buffer_put_tail(buffer, pd, pd_len); silc_buffer_pull_tail(buffer, pd_len); silc_free(pd); } memset(tmp, 0, sizeof(tmp)); silc_snprintf(tmp, sizeof(tmp) - 1, "\r\n--%s--\r\n", mime->boundary); buffer = silc_buffer_realloc(buffer, silc_buffer_truelen(buffer) + strlen(tmp)); if (!buffer) return NULL; silc_buffer_put_tail(buffer, tmp, strlen(tmp)); silc_buffer_pull_tail(buffer, strlen(tmp)); } ret = silc_buffer_steal(buffer, encoded_len); silc_buffer_free(buffer); return ret; }