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); }
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); }
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; }
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_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; }
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; }
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; }
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; }
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 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_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; }
SilcSFTPName silc_sftp_name_decode(SilcUInt32 count, SilcBuffer buffer) { SilcSFTPName name; int i; int ret; name = silc_calloc(1, sizeof(*name)); if (!name) return NULL; name->filename = silc_calloc(count, sizeof(*name->filename)); name->long_filename = silc_calloc(count, sizeof(*name->filename)); name->attrs = silc_calloc(count, sizeof(*name->attrs)); if (!name->filename || !name->long_filename || !name->attrs) { silc_sftp_name_free(name); return NULL; } name->count = count; for (i = 0; i < count; i++) { ret = silc_buffer_unformat(buffer, SILC_STR_UI32_STRING_ALLOC(&name->filename[i]), SILC_STR_UI32_STRING_ALLOC(&name->long_filename[i]), SILC_STR_END); if (ret < 0) { silc_sftp_name_free(name); return NULL; } silc_buffer_pull(buffer, ret); /* Decode attributes, this will pull the `buffer' to correct place for next round automatically. */ name->attrs[i] = silc_sftp_attr_decode(buffer); if (!name->attrs[i]) { silc_sftp_name_free(name); return NULL; } } return name; }
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_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; }
SilcSFTPAttributes silc_sftp_attr_decode(SilcBuffer buffer) { SilcSFTPAttributes attr; attr = silc_calloc(1, sizeof(*attr)); if (!attr) return NULL; if (silc_buffer_unformat(buffer, SILC_STR_UI_INT(&attr->flags), SILC_STR_END) < 0) goto out; silc_buffer_pull(buffer, 4); if (attr->flags & SILC_SFTP_ATTR_SIZE) { if (silc_buffer_unformat(buffer, SILC_STR_UI_INT64(&attr->size), SILC_STR_END) < 0) goto out; silc_buffer_pull(buffer, 8); } if (attr->flags & SILC_SFTP_ATTR_UIDGID) { if (silc_buffer_unformat(buffer, SILC_STR_UI_INT(&attr->uid), SILC_STR_UI_INT(&attr->gid), SILC_STR_END) < 0) goto out; silc_buffer_pull(buffer, 8); } if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) { if (silc_buffer_unformat(buffer, SILC_STR_UI_INT(&attr->permissions), SILC_STR_END) < 0) goto out; silc_buffer_pull(buffer, 4); } if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) { if (silc_buffer_unformat(buffer, SILC_STR_UI_INT(&attr->atime), SILC_STR_UI_INT(&attr->mtime), SILC_STR_END) < 0) goto out; silc_buffer_pull(buffer, 8); } if (attr->flags & SILC_SFTP_ATTR_EXTENDED) { int i; if (silc_buffer_unformat(buffer, SILC_STR_UI_INT(&attr->extended_count), SILC_STR_END) < 0) goto out; silc_buffer_pull(buffer, 4); attr->extended_type = silc_calloc(attr->extended_count, sizeof(*attr->extended_type)); attr->extended_data = silc_calloc(attr->extended_count, sizeof(*attr->extended_data)); if (!attr->extended_type || !attr->extended_data) return NULL; for (i = 0; i < attr->extended_count; i++) { unsigned char *tmp, *tmp2; SilcUInt32 tmp_len, tmp2_len; if (silc_buffer_unformat(buffer, SILC_STR_UI32_NSTRING(&tmp, &tmp_len), SILC_STR_UI32_NSTRING(&tmp2, &tmp2_len), SILC_STR_END) < 0) goto out; attr->extended_type[i] = silc_buffer_alloc(tmp_len); attr->extended_data[i] = silc_buffer_alloc(tmp2_len); if (!attr->extended_type[i] || !attr->extended_data[i]) return NULL; silc_buffer_put(attr->extended_type[i], tmp, tmp_len); silc_buffer_put(attr->extended_data[i], tmp2, tmp2_len); silc_buffer_pull(buffer, tmp_len + 4 + tmp2_len + 4); } } return attr; out: silc_sftp_attr_free(attr); return NULL; }
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; }
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 asn1_dump(SilcAsn1 asn1, SilcBuffer src, int depth) { SilcBool ret = FALSE; SilcBerEncoding renc; SilcUInt32 rtag; const unsigned char *rdata; SilcBufferStruct buf; SilcBerClass rclass; SilcUInt32 rdata_len, len = 0; SilcBool rindef; char indent[256]; memset(indent, 0, sizeof(indent)); while (silc_buffer_len(src)) { /* Decode the BER block */ ret = silc_ber_decode(src, &rclass, &renc, &rtag, &rdata, &rdata_len, &rindef, &len); if (!ret) { fprintf(stderr, "Error: Cannot parse BER block, malformed ASN.1 data\n"); return -1; } /* If class is 0, encoding 0, tag 0 and data length 0 ignore them as they are zero bytes, unless user wants to see them */ if (rclass == 0 && renc == 0 && rtag == 0 && rdata_len == 0 && !parse_all) { if (len && silc_buffer_len(src) >= len) silc_buffer_pull(src, len); continue; } if (depth) memset(indent, 32, depth); fprintf(stdout, "%04d: %s%s [%d] %s %s %s", depth, indent, asn1_tag_name(rtag), (int)rtag, rclass == SILC_BER_CLASS_UNIVERSAL ? "univ" : rclass == SILC_BER_CLASS_APPLICATION ? "appl" : rclass == SILC_BER_CLASS_CONTEXT ? "cont" : "priv", renc == SILC_BER_ENC_PRIMITIVE ? "primit" : "constr", rindef ? "indef" : "defin"); if (rtag != SILC_ASN1_TAG_SEQUENCE && rtag != SILC_ASN1_TAG_SET && rtag != SILC_ASN1_TAG_SEQUENCE_OF) { if (hexdump) { fprintf(stdout, " [len %lu]\n", rdata_len); silc_hexdump(rdata, rdata_len, stdout); } else { fprintf(stdout, "\n"); } } else { fprintf(stdout, "\n"); } if (renc == SILC_BER_ENC_PRIMITIVE) len = len + rdata_len; else len = len; if (len && silc_buffer_len(src) >= len) silc_buffer_pull(src, len); /* Decode sequences and sets recursively */ if ((rtag == SILC_ASN1_TAG_SEQUENCE || rtag == SILC_ASN1_TAG_SET || rtag == SILC_ASN1_TAG_SEQUENCE_OF) && depth + 1 < sizeof(indent) - 1) { silc_buffer_set(&buf, (unsigned char *)rdata, rdata_len); if (silc_buffer_len(src) >= rdata_len) silc_buffer_pull(src, rdata_len); if (asn1_dump(asn1, &buf, depth + 1) < 0) return -1; if (silc_buffer_len(src) == 0) return 0; } } return 0; }
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); } }
static void silc_sftp_server_receive_process(SilcSFTP sftp, SilcBuffer buffer) { SilcSFTPServer server = (SilcSFTPServer)sftp; SilcSFTPPacket type; char *filename = NULL, *path = NULL; unsigned char *payload = NULL; SilcUInt32 payload_len; int ret; SilcBufferStruct buf; SilcUInt32 id; SilcSFTPAttributes attrs; SilcSFTPHandle handle; SilcSFTPMonitorDataStruct mdata; SILC_LOG_DEBUG(("Start")); /* Parse the packet */ type = silc_sftp_packet_decode(buffer, &payload, &payload_len); if (type <= 0) return; silc_buffer_set(&buf, payload, payload_len); memset(&mdata, 0, sizeof(mdata)); switch (type) { case SILC_SFTP_READ: { unsigned char *hdata; SilcUInt32 hdata_len; SilcUInt64 offset; SilcUInt32 len; SILC_LOG_DEBUG(("Read request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_UI_INT64(&offset), SILC_STR_UI_INT(&len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Read operation */ server->fs->fs->sftp_read(server->fs->fs_context, sftp, handle, offset, len, silc_sftp_server_data, SILC_32_TO_PTR(id)); /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) { mdata.offset = offset; mdata.data_len = len; (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata, server->monitor_context); } } break; case SILC_SFTP_WRITE: { unsigned char *hdata; SilcUInt32 hdata_len; SilcUInt64 offset; unsigned char *data; SilcUInt32 data_len; SILC_LOG_DEBUG(("Read request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_UI_INT64(&offset), SILC_STR_UI32_NSTRING(&data, &data_len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Write operation */ server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset, (const unsigned char *)data, data_len, silc_sftp_server_status, SILC_32_TO_PTR(id)); /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) { mdata.offset = offset; mdata.data_len = data_len; (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata, server->monitor_context); } } break; case SILC_SFTP_INIT: { SilcSFTPVersion version; SILC_LOG_DEBUG(("Init request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&version), SILC_STR_END); if (ret < 0) break; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_INIT && server->monitor) { mdata.version = version; (*server->monitor)(sftp, SILC_SFTP_MONITOR_INIT, &mdata, server->monitor_context); } silc_sftp_send_packet(server, SILC_SFTP_VERSION, 4, SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION), SILC_STR_END); } break; case SILC_SFTP_OPEN: { SilcSFTPFileOperation pflags; unsigned char *attr_buf; SilcUInt32 attr_len = 0; SilcBufferStruct tmpbuf; SILC_LOG_DEBUG(("Open request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&filename), SILC_STR_UI_INT(&pflags), SILC_STR_UI32_NSTRING(&attr_buf, &attr_len), SILC_STR_END); if (ret < 0) goto failure; if (attr_len) { silc_buffer_set(&tmpbuf, attr_buf, attr_len); attrs = silc_sftp_attr_decode(&tmpbuf); if (!attrs) goto failure; } else { attrs = silc_calloc(1, sizeof(*attrs)); if (!attrs) goto failure; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_OPEN && server->monitor) { mdata.name = filename; mdata.pflags = pflags; (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPEN, &mdata, server->monitor_context); } /* Open operation */ server->fs->fs->sftp_open(server->fs->fs_context, sftp, filename, pflags, attrs, silc_sftp_server_handle, SILC_32_TO_PTR(id)); silc_free(filename); silc_sftp_attr_free(attrs); } break; case SILC_SFTP_CLOSE: { unsigned char *hdata; SilcUInt32 hdata_len; SILC_LOG_DEBUG(("Close request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_CLOSE && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_CLOSE, &mdata, server->monitor_context); } /* Close operation */ server->fs->fs->sftp_close(server->fs->fs_context, sftp, handle, silc_sftp_server_status, SILC_32_TO_PTR(id)); } break; case SILC_SFTP_REMOVE: { SILC_LOG_DEBUG(("Remove request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&filename), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_REMOVE && server->monitor) { mdata.name = filename; (*server->monitor)(sftp, SILC_SFTP_MONITOR_REMOVE, &mdata, server->monitor_context); } /* Remove operation */ server->fs->fs->sftp_remove(server->fs->fs_context, sftp, filename, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_free(filename); } break; case SILC_SFTP_RENAME: { char *newname = NULL; SILC_LOG_DEBUG(("Rename request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&filename), SILC_STR_UI32_STRING_ALLOC(&newname), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_RENAME && server->monitor) { mdata.name = filename; mdata.name2 = newname; (*server->monitor)(sftp, SILC_SFTP_MONITOR_RENAME, &mdata, server->monitor_context); } /* Rename operation */ server->fs->fs->sftp_rename(server->fs->fs_context, sftp, filename, newname, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_free(filename); silc_free(newname); } break; case SILC_SFTP_MKDIR: { unsigned char *attr_buf; SilcUInt32 attr_len = 0; SilcBufferStruct tmpbuf; SILC_LOG_DEBUG(("Mkdir request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_UI32_NSTRING(&attr_buf, &attr_len), SILC_STR_END); if (ret < 0) goto failure; if (attr_len) { silc_buffer_set(&tmpbuf, attr_buf, attr_len); attrs = silc_sftp_attr_decode(&tmpbuf); if (!attrs) goto failure; } else { attrs = silc_calloc(1, sizeof(*attrs)); if (!attrs) goto failure; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_MKDIR && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_MKDIR, &mdata, server->monitor_context); } /* Mkdir operation */ server->fs->fs->sftp_mkdir(server->fs->fs_context, sftp, path, attrs, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_sftp_attr_free(attrs); silc_free(path); } break; case SILC_SFTP_RMDIR: { SILC_LOG_DEBUG(("Rmdir request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_RMDIR && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_RMDIR, &mdata, server->monitor_context); } /* Rmdir operation */ server->fs->fs->sftp_rmdir(server->fs->fs_context, sftp, path, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_OPENDIR: { SILC_LOG_DEBUG(("Opendir request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_OPENDIR && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_OPENDIR, &mdata, server->monitor_context); } /* Opendir operation */ server->fs->fs->sftp_opendir(server->fs->fs_context, sftp, path, silc_sftp_server_handle, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_READDIR: { unsigned char *hdata; SilcUInt32 hdata_len; SILC_LOG_DEBUG(("Readdir request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_READDIR && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_READDIR, &mdata, server->monitor_context); } /* Readdir operation */ server->fs->fs->sftp_readdir(server->fs->fs_context, sftp, handle, silc_sftp_server_name, SILC_32_TO_PTR(id)); } break; case SILC_SFTP_STAT: { SILC_LOG_DEBUG(("Stat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_STAT && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_STAT, &mdata, server->monitor_context); } /* Stat operation */ server->fs->fs->sftp_stat(server->fs->fs_context, sftp, path, silc_sftp_server_attr, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_LSTAT: { SILC_LOG_DEBUG(("Lstat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_LSTAT && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_LSTAT, &mdata, server->monitor_context); } /* Lstat operation */ server->fs->fs->sftp_lstat(server->fs->fs_context, sftp, path, silc_sftp_server_attr, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_FSTAT: { unsigned char *hdata; SilcUInt32 hdata_len; SILC_LOG_DEBUG(("Fstat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_END); if (ret < 0) goto failure; /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_FSTAT && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSTAT, &mdata, server->monitor_context); } /* Fstat operation */ server->fs->fs->sftp_fstat(server->fs->fs_context, sftp, handle, silc_sftp_server_attr, SILC_32_TO_PTR(id)); } break; case SILC_SFTP_SETSTAT: { unsigned char *attr_buf; SilcUInt32 attr_len = 0; SilcBufferStruct tmpbuf; SILC_LOG_DEBUG(("Setstat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_UI32_NSTRING(&attr_buf, &attr_len), SILC_STR_END); if (ret < 0) goto failure; if (attr_len) { silc_buffer_set(&tmpbuf, attr_buf, attr_len); attrs = silc_sftp_attr_decode(&tmpbuf); if (!attrs) goto failure; } else { attrs = silc_calloc(1, sizeof(*attrs)); if (!attrs) goto failure; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_SETSTAT && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_SETSTAT, &mdata, server->monitor_context); } /* Setstat operation */ server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_sftp_attr_free(attrs); silc_free(path); } break; case SILC_SFTP_FSETSTAT: { unsigned char *hdata, *attr_buf; SilcUInt32 hdata_len, attr_len = 0; SilcBufferStruct tmpbuf; SILC_LOG_DEBUG(("Fsetstat request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_NSTRING(&hdata, &hdata_len), SILC_STR_UI32_NSTRING(&attr_buf, &attr_len), SILC_STR_END); if (ret < 0) goto failure; if (attr_len) { silc_buffer_set(&tmpbuf, attr_buf, attr_len); attrs = silc_sftp_attr_decode(&tmpbuf); if (!attrs) goto failure; } else { attrs = silc_calloc(1, sizeof(*attrs)); if (!attrs) goto failure; } /* Get the handle */ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp, (const unsigned char *)hdata, hdata_len); if (!handle) { silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id); break; } /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_FSETSTAT && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_FSETSTAT, &mdata, server->monitor_context); } /* Fsetstat operation */ server->fs->fs->sftp_fsetstat(server->fs->fs_context, sftp, handle, attrs, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_sftp_attr_free(attrs); } break; case SILC_SFTP_READLINK: { SILC_LOG_DEBUG(("Readlink request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_READLINK && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_READLINK, &mdata, server->monitor_context); } /* Readlink operation */ server->fs->fs->sftp_readlink(server->fs->fs_context, sftp, path, silc_sftp_server_name, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_SYMLINK: { char *target = NULL; SILC_LOG_DEBUG(("Symlink request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_UI32_STRING_ALLOC(&target), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_SYMLINK && server->monitor) { mdata.name = path; mdata.name2 = target; (*server->monitor)(sftp, SILC_SFTP_MONITOR_SYMLINK, &mdata, server->monitor_context); } /* Symlink operation */ server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target, silc_sftp_server_status, SILC_32_TO_PTR(id)); silc_free(path); silc_free(target); } break; case SILC_SFTP_REALPATH: { SILC_LOG_DEBUG(("Realpath request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&path), SILC_STR_END); if (ret < 0) goto failure; /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_REALPATH && server->monitor) { mdata.name = path; (*server->monitor)(sftp, SILC_SFTP_MONITOR_REALPATH, &mdata, server->monitor_context); } /* Realpath operation */ server->fs->fs->sftp_realpath(server->fs->fs_context, sftp, path, silc_sftp_server_name, SILC_32_TO_PTR(id)); silc_free(path); } break; case SILC_SFTP_EXTENDED: { char *request = NULL; unsigned char *data; SilcUInt32 data_len; SILC_LOG_DEBUG(("Extended request")); ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&id), SILC_STR_UI32_STRING_ALLOC(&request), SILC_STR_END); if (ret < 0) goto failure; data_len = 8 + strlen(request); silc_buffer_pull(&buf, data_len); ret = silc_buffer_unformat(&buf, SILC_STR_DATA(&data, silc_buffer_len(&buf)), SILC_STR_END); if (ret < 0) goto failure; data_len = silc_buffer_len(&buf); /* Call monitor */ if (server->monitors & SILC_SFTP_MONITOR_EXTENDED && server->monitor) { (*server->monitor)(sftp, SILC_SFTP_MONITOR_EXTENDED, &mdata, server->monitor_context); } /* Extended operation */ server->fs->fs->sftp_extended(server->fs->fs_context, sftp, request, data, data_len, silc_sftp_server_extended, SILC_32_TO_PTR(id)); silc_free(request); } break; default: break; } return; failure: silc_sftp_send_error(server, SILC_SFTP_STATUS_FAILURE, id); }
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; }
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; }
static void silc_sftp_server_io(SilcStream stream, SilcStreamStatus status, void *context) { SilcSFTPServer sftp = context; unsigned char inbuf[33792]; SilcBufferStruct packet; int ret; switch (status) { case SILC_STREAM_CAN_READ: SILC_LOG_DEBUG(("Reading data from stream")); /* Read data from stream */ ret = silc_stream_read(stream, inbuf, sizeof(inbuf)); if (ret <= 0) { if (ret == 0) sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context); if (ret == -2) sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context); return; } /* Now process the SFTP packet */ silc_buffer_set(&packet, inbuf, ret); silc_sftp_server_receive_process(context, &packet); break; case SILC_STREAM_CAN_WRITE: if (!silc_buffer_headlen(sftp->packet)) return; SILC_LOG_DEBUG(("Writing pending data to stream")); /* Write pending data to stream */ silc_buffer_push(sftp->packet, silc_buffer_headlen(sftp->packet)); while (silc_buffer_len(sftp->packet) > 0) { ret = silc_stream_write(stream, sftp->packet->data, silc_buffer_len(sftp->packet)); if (ret == 0) { sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context); silc_buffer_reset(sftp->packet); return; } if (ret == -2) { sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context); silc_buffer_reset(sftp->packet); return; } if (ret == -1) return; /* Wrote data */ silc_buffer_pull(sftp->packet, ret); } break; default: break; } }