Example #1
0
static char
silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
{
  SilcServer server = cmd->server;
  SilcUInt32 len, id_len;
  unsigned char *id_data;
  char *nickname, *username, *realname;
  SilcID id;
  SilcClientEntry client;
  SilcIDCacheEntry cache = NULL;
  char nick[128 + 1], servername[256 + 1], uname[128 + 1];
  int global = FALSE;
  const char *hostname, *ip;

  silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
			      NULL, &hostname, &ip, NULL);

  id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
  nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
  username = silc_argument_get_arg_type(cmd->args, 4, &len);
  if (!id_data || !nickname || !username)
    return FALSE;

  realname = silc_argument_get_arg_type(cmd->args, 5, &len);

  if (!silc_id_payload_parse_id(id_data, id_len, &id))
    return FALSE;

  /* Check if we have this client cached already. */

  client = silc_idlist_find_client_by_id(server->local_list,
					 SILC_ID_GET_ID(id),
					 FALSE, &cache);
  if (!client) {
    client = silc_idlist_find_client_by_id(server->global_list,
					   SILC_ID_GET_ID(id),
					   FALSE, &cache);
    global = TRUE;
  }

  if (!client) {
    /* If router did not find such Client ID in its lists then this must
       be bogus client or some router in the net is buggy. */
    if (server->server_type != SILC_SERVER)
      return FALSE;

    /* Take hostname out of nick string if it includes it. */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));

    /* We don't have that client anywhere, add it. The client is added
       to global list since server didn't have it in the lists so it must be
       global. */
    client = silc_idlist_add_client(server->global_list,
				    strdup(nick), username,
				    strdup(realname),
				    silc_id_dup(SILC_ID_GET_ID(id),
						SILC_ID_CLIENT),
				    silc_packet_get_context(cmd->sock), NULL);
    if (!client) {
      SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
      return FALSE;
    }

    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
    client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
    client->servername = servername[0] ? strdup(servername) : NULL;
  } else {
    /* We have the client already, update the data */

    /* Check nickname */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));
    nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
				     128, NULL);
    if (!nickname) {
      SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOWAS reply "
		      "from %s",
		      nick, hostname ? hostname : ""));
      return FALSE;
    }

    /* Check username */
    silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0);
    if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128))
      return FALSE;

    silc_free(client->nickname);
    silc_free(client->username);
    silc_free(client->servername);

    client->nickname = strdup(nick);
    client->username = strdup(username);
    client->servername = servername[0] ? strdup(servername) : NULL;
    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
    client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;

    /* Update cache entry */
    silc_idcache_update_by_context(global ? server->global_list->clients :
				   server->local_list->clients, client, NULL,
				   nickname, TRUE);
  }

  /* If client is global and is not on any channel then add that we'll
     expire the entry after a while. */
  if (global) {
    client = silc_idlist_find_client_by_id(server->global_list, client->id,
					   FALSE, &cache);
    if (client && !silc_hash_table_count(client->channels)) {
      client->data.created = silc_time();
      silc_dlist_del(server->expired_clients, client);
      silc_dlist_add(server->expired_clients, client);
    }
  }

  return TRUE;
}
Example #2
0
SilcUInt32 silc_status_get_args(SilcStatus status,
                                SilcArgumentPayload args,
                                void **ret_arg1, void **ret_arg2)
{
    SilcUInt32 num, len;
    unsigned char *tmp;

    assert(ret_arg1 && ret_arg2);

    num = silc_argument_get_arg_num(args);
    if (num > 3)
        return 0;
    if (num == 0)
        return 0;

    switch (status) {

    case SILC_STATUS_ERR_NO_SUCH_NICK:
    case SILC_STATUS_ERR_NO_SUCH_CHANNEL:
    case SILC_STATUS_ERR_NO_SUCH_SERVER:
    case SILC_STATUS_ERR_NO_SUCH_SERVICE:
    case SILC_STATUS_ERR_UNKNOWN_ALGORITHM:
        tmp = silc_argument_get_arg_type(args, 2, &len);
        if (!tmp)
            return 0;
        *ret_arg1 = silc_memdup(tmp, len);
        if (!(*ret_arg1))
            return 0;
        num = 1;
        break;

    case SILC_STATUS_ERR_NO_SUCH_CLIENT_ID:
    case SILC_STATUS_ERR_BAD_CLIENT_ID:
    {
        SilcID id;
        tmp = silc_argument_get_arg_type(args, 2, &len);
        if (!tmp)
            return 0;
        if (silc_id_payload_parse_id(tmp, len, &id))
            return 0;
        *ret_arg1 = silc_id_dup(&id.u.client_id, SILC_ID_CLIENT);
        if (!(*ret_arg1))
            return 0;
        num = 1;
    }
    break;

    case SILC_STATUS_ERR_NO_SUCH_SERVER_ID:
    case SILC_STATUS_ERR_BAD_SERVER_ID:
    {
        SilcID id;
        tmp = silc_argument_get_arg_type(args, 2, &len);
        if (!tmp)
            return 0;
        if (silc_id_payload_parse_id(tmp, len, &id))
            return 0;
        *ret_arg1 = silc_id_dup(&id.u.server_id, SILC_ID_SERVER);
        if (!(*ret_arg1))
            return 0;
        num = 1;
    }
    break;

    case SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID:
    case SILC_STATUS_ERR_BAD_CHANNEL_ID:
    case SILC_STATUS_ERR_NOT_ON_CHANNEL:
    case SILC_STATUS_ERR_CHANNEL_IS_FULL:
    case SILC_STATUS_ERR_NOT_INVITED:
    case SILC_STATUS_ERR_BANNED_FROM_CHANNEL:
    case SILC_STATUS_ERR_NO_CHANNEL_PRIV:
    case SILC_STATUS_ERR_NO_CHANNEL_FOPRIV:
    {
        SilcID id;
        tmp = silc_argument_get_arg_type(args, 2, &len);
        if (!tmp)
            return 0;
        if (silc_id_payload_parse_id(tmp, len, &id))
            return 0;
        *ret_arg1 = silc_id_dup(&id.u.channel_id, SILC_ID_CHANNEL);
        if (!(*ret_arg1))
            return 0;
        num = 1;
    }
    break;

    case SILC_STATUS_ERR_USER_NOT_ON_CHANNEL:
    case SILC_STATUS_ERR_USER_ON_CHANNEL:
    {
        SilcID id;
        tmp = silc_argument_get_arg_type(args, 2, &len);
        if (!tmp)
            return 0;
        if (silc_id_payload_parse_id(tmp, len, &id))
            return 0;
        *ret_arg1 = silc_id_dup(&id.u.client_id, id.type);
        if (!(*ret_arg1))
            return 0;
        num = 1;
        tmp = silc_argument_get_arg_type(args, 3, &len);
        if (!tmp)
            return num;
        if (silc_id_payload_parse_id(tmp, len, &id))
            return 0;
        *ret_arg2 = silc_id_dup(&id.u.channel_id, id.type);
        if (!(*ret_arg2))
            return num;
        num = 2;
    }
    break;

    default:
        return 0;
        break;
    }

    return num;
}
Example #3
0
static char
silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
{
  SilcServer server = cmd->server;
  unsigned char *id_data, *umodes;
  char *nickname, *username, *realname, *tmp;
  unsigned char *fingerprint;
  SilcID id;
  SilcClientEntry client;
  char global = FALSE;
  char nick[128 + 1], servername[256 + 1], uname[128 + 1];
  SilcUInt32 mode = 0, len, len2, id_len, flen;
  const char *hostname, *ip;

  silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
			      NULL, &hostname, &ip, NULL);

  id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
  nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
  username = silc_argument_get_arg_type(cmd->args, 4, &len);
  realname = silc_argument_get_arg_type(cmd->args, 5, &len);
  if (!id_data || !nickname || !username || !realname)
    return FALSE;

  tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
  if (tmp)
    SILC_GET32_MSB(mode, tmp);

  if (!silc_id_payload_parse_id(id_data, id_len, &id))
    return FALSE;

  fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);

  /* Check if we have this client cached already. */

  client = silc_idlist_find_client_by_id(server->local_list,
					 SILC_ID_GET_ID(id),
					 FALSE, NULL);
  if (!client) {
    client = silc_idlist_find_client_by_id(server->global_list,
					   SILC_ID_GET_ID(id),
					   FALSE, NULL);
    global = TRUE;
  }

  if (!client) {
    /* If router did not find such Client ID in its lists then this must
       be bogus client or some router in the net is buggy. */
    if (server->server_type != SILC_SERVER)
      return FALSE;

    /* Take hostname out of nick string if it includes it. */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));

    /* We don't have that client anywhere, add it. The client is added
       to global list since server didn't have it in the lists so it must be
       global. This will check for valid nickname and username strings. */
    client = silc_idlist_add_client(server->global_list,
				    strdup(nick), username,
				    strdup(realname),
				    silc_id_dup(SILC_ID_GET_ID(id),
						SILC_ID_CLIENT),
				    silc_packet_get_context(cmd->sock),
				    NULL);
    if (!client) {
      SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
      return FALSE;
    }

    client->data.status |=
      (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
    client->mode = mode;
    client->servername = servername[0] ? strdup(servername) : NULL;

    SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
		    server->stat.clients + 1));
    server->stat.clients++;
  } else {
    /* We have the client already, update the data */

    SILC_LOG_DEBUG(("Updating client data"));

    /* Check nickname */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));
    nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
				     128, NULL);
    if (!nickname) {
      SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply "
		      "from %s",
		      hostname ? hostname : "", nick));
      return FALSE;
    }

    /* Check username */
    silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0);
    if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128)) {
      SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply "
		      "from %s",
		      hostname ? hostname : "", tmp));
      return FALSE;
    }

    /* Update entry */
    silc_idcache_update_by_context(global ? server->global_list->clients :
				   server->local_list->clients, client, NULL,
				   nickname, TRUE);

    silc_free(client->nickname);
    silc_free(client->username);
    silc_free(client->userinfo);
    silc_free(client->servername);

    client->nickname = strdup(nick);
    client->username = strdup(username);
    client->userinfo = strdup(realname);
    client->servername = servername[0] ? strdup(servername) : NULL;
    client->mode = mode;
    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
  }

  /* Save channel list if it was sent to us */
  if (server->server_type == SILC_SERVER) {
    tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
    umodes = silc_argument_get_arg_type(cmd->args, 10, &len2);
    if (tmp && umodes) {
      SilcBufferStruct channels_buf, umodes_buf;
      silc_buffer_set(&channels_buf, tmp, len);
      silc_buffer_set(&umodes_buf, umodes, len2);
      silc_server_save_user_channels(server, cmd->sock, client, &channels_buf,
				     &umodes_buf);
    } else {
      silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
    }
  }

  if (fingerprint && flen == sizeof(client->data.fingerprint))
    memcpy(client->data.fingerprint, fingerprint, flen);

  /* Take Requested Attributes if set. */
  tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
  if (tmp) {
    silc_free(client->attrs);
    client->attrs = silc_memdup(tmp, len);
    client->attrs_len = len;

    /* Try to take public key from attributes if present and we don't have
       the key already.  Do this only on normal server.  Routers do GETKEY
       for all clients anyway. */
    if (server->server_type != SILC_ROUTER && !client->data.public_key) {
      SilcAttributePayload attr;
      SilcAttributeObjPk pk;
      unsigned char f[SILC_HASH_MAXLEN];
      SilcDList attrs = silc_attribute_payload_parse(tmp, len);

      SILC_LOG_DEBUG(("Take client public key from attributes"));

      if (attrs) {
	silc_dlist_start(attrs);
	while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
	  if (silc_attribute_get_attribute(attr) ==
	      SILC_ATTRIBUTE_USER_PUBLIC_KEY) {

	    if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
	      continue;

	    /* Take only SILC public keys */
	    if (strcmp(pk.type, "silc-rsa")) {
	      silc_free(pk.type);
	      silc_free(pk.data);
	      continue;
	    }

	    /* Verify that the server provided fingerprint matches the key */
	    silc_hash_make(server->sha1hash, pk.data, pk.data_len, f);
	    if (memcmp(f, client->data.fingerprint, sizeof(f))) {
	      silc_free(pk.type);
	      silc_free(pk.data);
	      continue;
	    }

	    /* Save the public key. */
	    if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC,
					    pk.data, pk.data_len,
					    &client->data.public_key)) {
	      silc_free(pk.type);
	      silc_free(pk.data);
	      continue;
	    }

	    SILC_LOG_DEBUG(("Saved client public key from attributes"));

	    /* Add client's public key to repository */
	    if (!silc_server_get_public_key_by_client(server, client, NULL))
	      silc_skr_add_public_key_simple(server->repository,
					     client->data.public_key,
					     SILC_SKR_USAGE_IDENTIFICATION,
					     client, NULL);

	    silc_free(pk.type);
	    silc_free(pk.data);
	    break;
	  }
	}

	silc_attribute_payload_list_free(attrs);
      }
    }
  }

  return TRUE;
}