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; }
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; }
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 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; }
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; }
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); } }