Пример #1
0
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);
}
Пример #2
0
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;
}
Пример #3
0
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);
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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);
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
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;
}
Пример #13
0
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;
}
Пример #14
0
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;
}
Пример #15
0
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);
}
Пример #16
0
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);
}
Пример #17
0
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);
}
Пример #18
0
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;
}
Пример #19
0
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;
}
Пример #20
0
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;
}
Пример #21
0
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);
}
Пример #22
0
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;
}
Пример #23
0
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;
}
Пример #24
0
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;
}
Пример #25
0
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;
}
Пример #26
0
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;
}
Пример #27
0
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;
}
Пример #28
0
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;
}
Пример #29
0
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;
}
Пример #30
0
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;
}