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); }
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; }
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); }
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; }
SilcCommandPayload silc_command_payload_parse(const unsigned char *payload, SilcUInt32 payload_len) { SilcBufferStruct buffer; SilcCommandPayload newp; unsigned char args_num; SilcUInt16 p_len; int ret; SILC_LOG_DEBUG(("Parsing command payload")); silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); newp = silc_calloc(1, sizeof(*newp)); if (!newp) return NULL; /* Parse the Command Payload */ ret = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&p_len), SILC_STR_UI_CHAR(&newp->cmd), SILC_STR_UI_CHAR(&args_num), SILC_STR_UI_SHORT(&newp->ident), SILC_STR_END); if (ret == -1) { SILC_LOG_ERROR(("Incorrect command payload in packet")); silc_free(newp); return NULL; } if (p_len != silc_buffer_len(&buffer)) { SILC_LOG_ERROR(("Incorrect command payload in packet")); silc_free(newp); return NULL; } if (newp->cmd == 0) { SILC_LOG_ERROR(("Incorrect command type in command payload")); silc_free(newp); return NULL; } silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN); if (args_num) { newp->args = silc_argument_payload_parse(buffer.data, silc_buffer_len(&buffer), args_num); if (!newp->args) { silc_free(newp); return NULL; } } silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN); return newp; }
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; }
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); }
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; }
SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs, SilcAttribute attribute, SilcAttributeFlags flags, const unsigned char *data, SilcUInt32 data_len) { SilcBuffer buffer = attrs; SilcUInt32 len; len = 4 + (SilcUInt16)data_len; buffer = silc_buffer_realloc(buffer, (buffer ? silc_buffer_truelen(buffer) + len : len)); if (!buffer) return NULL; silc_buffer_pull(buffer, silc_buffer_len(buffer)); silc_buffer_pull_tail(buffer, len); silc_buffer_format(buffer, SILC_STR_UI_CHAR(attribute), SILC_STR_UI_CHAR(flags), SILC_STR_UI_SHORT((SilcUInt16)data_len), SILC_STR_UI_XNSTRING(data, (SilcUInt16)data_len), SILC_STR_END); silc_buffer_push(buffer, buffer->data - buffer->head); return buffer; }
SilcSFTPPacket silc_sftp_packet_decode(SilcBuffer packet, unsigned char **payload, SilcUInt32 *payload_len) { SilcUInt32 len; SilcUInt8 type; int ret; ret = silc_buffer_unformat(packet, SILC_STR_UI_INT(&len), SILC_STR_UI_CHAR(&type), SILC_STR_END); if (ret < 0) return 0; if (type < SILC_SFTP_INIT || type > SILC_SFTP_EXTENDED_REPLY) return 0; if (len > (silc_buffer_len(packet) - 5)) return -1; silc_buffer_pull(packet, 5); ret = silc_buffer_unformat(packet, SILC_STR_UI_XNSTRING(payload, len), SILC_STR_END); if (ret < 0) return 0; silc_buffer_push(packet, 5); *payload_len = len; return (SilcSFTPPacket)type; }
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; }
SilcDList silc_attribute_payload_parse(const unsigned char *payload, SilcUInt32 payload_len) { SilcBufferStruct buffer; SilcDList list; SilcAttributePayload newp; SilcUInt32 len; int ret; SILC_LOG_DEBUG(("Parsing Attribute Payload list")); silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); list = silc_dlist_init(); while (silc_buffer_len(&buffer)) { newp = silc_calloc(1, sizeof(*newp)); if (!newp) goto err; ret = silc_buffer_unformat(&buffer, SILC_STR_UI_CHAR(&newp->attribute), SILC_STR_UI_CHAR(&newp->flags), SILC_STR_UI16_NSTRING_ALLOC(&newp->data, &newp->data_len), SILC_STR_END); if (ret == -1) goto err; if (newp->data_len > silc_buffer_len(&buffer) - 4) { SILC_LOG_ERROR(("Incorrect attribute payload in list")); goto err; } len = 4 + newp->data_len; if (silc_buffer_len(&buffer) < len) break; silc_buffer_pull(&buffer, len); silc_dlist_add(list, newp); } return list; err: silc_attribute_payload_list_free(list); return NULL; }
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; }
static void silcpurple_wb_parse(SilcPurpleWb wbs, PurpleWhiteboard *wb, unsigned char *message, SilcUInt32 message_len) { SilcUInt8 command; SilcUInt16 width, height, brush_size; SilcUInt32 brush_color, x, y, dx, dy; SilcBufferStruct buf; int ret; /* Parse the packet */ silc_buffer_set(&buf, message, message_len); ret = silc_buffer_unformat(&buf, SILC_STR_UI_CHAR(&command), SILC_STR_UI_SHORT(&width), SILC_STR_UI_SHORT(&height), SILC_STR_UI_INT(&brush_color), SILC_STR_UI_SHORT(&brush_size), SILC_STR_END); if (ret < 0) return; silc_buffer_pull(&buf, ret); /* Update whiteboard if its dimensions changed */ if (width != wbs->width || height != wbs->height) silcpurple_wb_set_dimensions(wb, height, width); if (command == SILCPURPLE_WB_DRAW) { /* Parse data and draw it */ ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&dx), SILC_STR_UI_INT(&dy), SILC_STR_END); if (ret < 0) return; silc_buffer_pull(&buf, 8); x = dx; y = dy; while (silc_buffer_len(&buf) > 0) { ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&dx), SILC_STR_UI_INT(&dy), SILC_STR_END); if (ret < 0) return; silc_buffer_pull(&buf, 8); purple_whiteboard_draw_line(wb, x, y, x + dx, y + dy, brush_color, brush_size); x += dx; y += dy; } } if (command == SILCPURPLE_WB_CLEAR) purple_whiteboard_clear(wb); }
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); }
void silc_server_command_reply_process(SilcServer server, SilcPacketStream sock, SilcBuffer buffer) { SilcIDListData idata = silc_packet_get_context(sock); SilcServerCommandReply *cmd; SilcServerCommandReplyContext ctx; SilcCommandPayload payload; SilcCommand command; SILC_LOG_DEBUG(("Start")); /* Get command reply payload from packet */ payload = silc_command_payload_parse(buffer->data, silc_buffer_len(buffer)); if (!payload) { /* Silently ignore bad reply packet */ SILC_LOG_DEBUG(("Bad command reply packet")); return; } /* Allocate command reply context. This must be free'd by the command reply routine receiving it. */ ctx = silc_calloc(1, sizeof(*ctx)); ctx->server = server; ctx->sock = sock; ctx->payload = payload; ctx->args = silc_command_get_args(ctx->payload); ctx->ident = silc_command_get_ident(ctx->payload); command = silc_command_get(ctx->payload); silc_packet_stream_ref(sock); /* Client is not allowed to send reply to all commands */ if (idata->conn_type == SILC_CONN_CLIENT && command != SILC_COMMAND_WHOIS) { silc_server_command_reply_free(ctx); return; } /* Check for pending commands and mark to be exeucted */ ctx->callbacks = silc_server_command_pending_check(server, command, ctx->ident, &ctx->callbacks_count); /* Execute command reply */ for (cmd = silc_command_reply_list; cmd->cb; cmd++) if (cmd->cmd == command) break; if (cmd == NULL || !cmd->cb) { silc_server_command_reply_free(ctx); return; } cmd->cb(ctx, NULL); }
static void sftp_attr(SilcSFTP sftp, SilcSFTPStatus status, const SilcSFTPAttributes attrs, void *context) { SilcSFTPHandle handle = (SilcSFTPHandle)context; int i; fprintf(stderr, "Status %d\n", status); if (status != SILC_SFTP_STATUS_OK) { SILC_LOG_DEBUG(("Error status")); success = FALSE; end_test(); return; } SILC_LOG_DEBUG(("Attr.flags: %d", attrs->flags)); SILC_LOG_DEBUG(("Attr.size: %lu", attrs->size)); SILC_LOG_DEBUG(("Attr.uid: %d", attrs->uid)); SILC_LOG_DEBUG(("Attr.gid: %d", attrs->gid)); SILC_LOG_DEBUG(("Attr.permissions: %d", attrs->permissions)); SILC_LOG_DEBUG(("Attr.atime: %d", attrs->atime)); SILC_LOG_DEBUG(("Attr.mtime: %d", attrs->mtime)); SILC_LOG_DEBUG(("Attr.extended count: %d", attrs->extended_count)); for (i = 0; i < attrs->extended_count; i++) { SILC_LOG_HEXDUMP(("Attr.extended_type[i]:", i), attrs->extended_type[i]->data, silc_buffer_len(attrs->extended_type[i])); SILC_LOG_HEXDUMP(("Attr.extended_data[i]:", i), attrs->extended_data[i]->data, silc_buffer_len(attrs->extended_data[i])); } if (!file) { fprintf(stderr, "Closing file\n"); silc_sftp_close(sftp, handle, sftp_status, context); return; } fprintf(stderr, "LStatting file %s\n", file); silc_sftp_lstat(sftp, file, sftp_attr, context); file = NULL; }
SilcNotifyPayload silc_notify_payload_parse(const unsigned char *payload, SilcUInt32 payload_len) { SilcBufferStruct buffer; SilcNotifyPayload newp; SilcUInt16 len; int ret; SILC_LOG_DEBUG(("Parsing Notify payload")); silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); newp = silc_calloc(1, sizeof(*newp)); if (!newp) return NULL; ret = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&newp->type), SILC_STR_UI_SHORT(&len), SILC_STR_UI_CHAR(&newp->argc), SILC_STR_END); if (ret == -1) goto err; if (len > silc_buffer_len(&buffer)) goto err; if (newp->argc) { silc_buffer_pull(&buffer, 5); newp->args = silc_argument_payload_parse(buffer.data, silc_buffer_len(&buffer), newp->argc); if (!newp->args) goto err; silc_buffer_push(&buffer, 5); } return newp; err: silc_free(newp); return NULL; }
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; }
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; }
static SilcBool silc_client_ftp_coder(SilcStream stream, SilcStreamStatus status, SilcBuffer buffer, void *context) { /* Pull FTP type in the payload, revealing SFTP payload */ if (status == SILC_STREAM_CAN_READ) { if (silc_buffer_len(buffer) >= 1) silc_buffer_pull(buffer, 1); return TRUE; } /* Add FTP type before SFTP data */ if (status == SILC_STREAM_CAN_WRITE) { if (silc_buffer_format(buffer, SILC_STR_UI_CHAR(1), SILC_STR_END) < 0) return FALSE; return TRUE; } return FALSE; }
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; }
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; }
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; }
SilcBool silc_attribute_get_object(SilcAttributePayload payload, void *object, SilcUInt32 object_size) { SilcUInt16 len; SilcBool ret = FALSE; if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID) return FALSE; switch (payload->attribute) { case SILC_ATTRIBUTE_USER_INFO: { SilcVCard vcard = object; if (object_size != sizeof(*vcard)) break; if (!silc_vcard_decode(payload->data, payload->data_len, vcard)) break; ret = TRUE; } break; case SILC_ATTRIBUTE_SERVICE: { SilcAttributeObjService *service = object; SilcBufferStruct buf; SilcUInt16 addr_len, signon_len; char *addr, *signon; int res; if (object_size != sizeof(*service)) break; if (payload->data_len < 13) break; silc_buffer_set(&buf, payload->data, payload->data_len); res = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&service->port), SILC_STR_UI16_NSTRING(&addr, &addr_len), SILC_STR_UI_CHAR(&service->status), SILC_STR_UI16_NSTRING(&signon, &signon_len), SILC_STR_UI_INT(&service->idle), SILC_STR_END); if (res == -1) break; memset(service->address, 0, sizeof(service->address)); memset(service->signon, 0, sizeof(service->signon)); memcpy(service->address, addr, (addr_len < sizeof(service->address) - 1 ? addr_len : sizeof(service->address) - 1)); memcpy(service->signon, signon, (signon_len < sizeof(service->signon) - 1 ? signon_len : sizeof(service->signon) - 1)); ret = TRUE; } break; case SILC_ATTRIBUTE_STATUS_MOOD: case SILC_ATTRIBUTE_PREFERRED_CONTACT: { SilcUInt32 *mask = (SilcUInt32 *)object; if (object_size != sizeof(SilcUInt32)) break; if (payload->data_len < 4) break; SILC_GET32_MSB(*mask, payload->data); ret = TRUE; } break; case SILC_ATTRIBUTE_STATUS_FREETEXT: case SILC_ATTRIBUTE_PREFERRED_LANGUAGE: case SILC_ATTRIBUTE_TIMEZONE: { char *string = object; if (payload->data_len < 2) break; SILC_GET16_MSB(len, payload->data); if (payload->data_len < 2 + len) break; if (object_size < len) break; memcpy(string, payload->data + 2, len); ret = TRUE; } break; case SILC_ATTRIBUTE_STATUS_MESSAGE: case SILC_ATTRIBUTE_EXTENSION: case SILC_ATTRIBUTE_USER_ICON: { SilcMime mime = object; if (object_size != sizeof(*mime)) break; if (!silc_mime_decode(mime, payload->data, payload->data_len)) break; ret = TRUE; } break; case SILC_ATTRIBUTE_GEOLOCATION: { SilcAttributeObjGeo *geo = object; SilcBufferStruct buffer; int res; if (object_size != sizeof(*geo)) break; silc_buffer_set(&buffer, (unsigned char *)payload->data, payload->data_len); res = silc_buffer_unformat(&buffer, SILC_STR_UI16_STRING_ALLOC(&geo->longitude), SILC_STR_UI16_STRING_ALLOC(&geo->latitude), SILC_STR_UI16_STRING_ALLOC(&geo->altitude), SILC_STR_UI16_STRING_ALLOC(&geo->accuracy), SILC_STR_END); if (res == -1) break; ret = TRUE; } break; case SILC_ATTRIBUTE_DEVICE_INFO: { SilcAttributeObjDevice *dev = object; SilcBufferStruct buffer; SilcUInt32 type; int res; if (object_size != sizeof(*dev)) break; silc_buffer_set(&buffer, (unsigned char *)payload->data, payload->data_len); res = silc_buffer_unformat(&buffer, SILC_STR_UI_INT(&type), SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer), SILC_STR_UI16_STRING_ALLOC(&dev->version), SILC_STR_UI16_STRING_ALLOC(&dev->model), SILC_STR_UI16_STRING_ALLOC(&dev->language), SILC_STR_END); if (res == -1) break; dev->type = type; ret = TRUE; } break; case SILC_ATTRIBUTE_PHONE_NUMBER: { SilcAttributeObjPN *pn = object; SilcBufferStruct buffer; SilcUInt32 pn_format; int res; if (object_size != sizeof(*pn)) break; silc_buffer_set(&buffer, (unsigned char *)payload->data, payload->data_len); res = silc_buffer_unformat(&buffer, SILC_STR_UI_INT(&pn_format), SILC_STR_UI16_STRING_ALLOC(&pn->number), SILC_STR_END); if (res == -1) break; pn->format = pn_format; ret = TRUE; } break; case SILC_ATTRIBUTE_USER_PUBLIC_KEY: case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: { SilcAttributeObjPk *pk = object; SilcBufferStruct buffer; int res; if (object_size != sizeof(*pk)) break; silc_buffer_set(&buffer, (unsigned char *)payload->data, payload->data_len); res = silc_buffer_unformat(&buffer, SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len), SILC_STR_END); if (res == -1 || len > silc_buffer_len(&buffer) - 2) break; pk->data = silc_memdup(payload->data + 2 + len, payload->data_len - 2 - len); pk->data_len = payload->data_len - 2 - len; ret = TRUE; } break; case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE: case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE: { SilcAttributeObjPk *pk = object; if (object_size != sizeof(*pk)) break; pk->type = NULL; pk->data = silc_memdup(payload->data, payload->data_len); pk->data_len = payload->data_len; ret = TRUE; } break; default: break; } return ret; }
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; }