- /* We are ready to process the command request. Let's search for the
- requested client and send reply to the requesting client. */
-
- /* Parse the whois request */
- if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
- &nick, &server_name, &count,
- SILC_COMMAND_WHOIS))
- return 0;
-
- /* Get all clients matching that ID or nickname from local list */
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->local_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- }
-
- /* Check global list as well */
- if (!clients) {
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- }
- }
-
- if (!clients) {
- /* Such client(s) really does not exist in the SILC network. */
- if (!client_id_count) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
- } else {
- SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
- goto out;
- }
-
- /* Router always finds the client entry if it exists in the SILC network.
- However, it might be incomplete entry and does not include all the
- mandatory fields that WHOIS command reply requires. Check for these and
- make query from the server who owns the client if some fields are
- missing. */
- if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
-
- /* Send the command reply to the client */
- silc_server_command_whois_send_reply(cmd, clients, clients_count,
- count);
-
- out:
- if (client_id_count) {
- for (i = 0; i < client_id_count; i++)
- silc_free(client_id[i]);
- silc_free(client_id);
- }
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
-
- return ret;
-}
-
-static int
-silc_server_command_whois_from_server(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
- SilcClientEntry *clients = NULL, entry;
- SilcClientID **client_id = NULL;
- unsigned int client_id_count = 0;
- int i, ret = 0;
-
- /* Parse the whois request */
- if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
- &nick, &server_name, &count,
- SILC_COMMAND_WHOIS))
- return 0;
-
- /* Process the command request. Let's search for the requested client and
- send reply to the requesting server. */
-
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->local_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- }
-
- /* If we are router we will check our global list as well. */
- if (!clients && server->server_type == SILC_ROUTER) {
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- }
- }
-
- if (!clients) {
- /* Such a client really does not exist in the SILC network. */
- if (!client_id_count) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
- } else {
- SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
- goto out;
- }
-
- /* Router always finds the client entry if it exists in the SILC network.
- However, it might be incomplete entry and does not include all the
- mandatory fields that WHOIS command reply requires. Check for these and
- make query from the server who owns the client if some fields are
- missing. */
- if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
-
- /* Send the command reply to the client */
- silc_server_command_whois_send_reply(cmd, clients, clients_count,
- count);
-
- out:
- if (client_id_count) {
- for (i = 0; i < client_id_count; i++)
- silc_free(client_id[i]);
- silc_free(client_id);
- }
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
-
- return ret;
-}
-
-/* Server side of command WHOIS. Processes user's query and sends found
- results as command replies back to the client. */
-
-SILC_SERVER_CMD_FUNC(whois)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- int ret = 0;
-
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3328);
-
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_whois_from_client(cmd);
- else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
- (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
- ret = silc_server_command_whois_from_server(cmd);
-
- if (!ret)
- silc_server_command_free(cmd);
-}
-
-/******************************************************************************
-
- WHOWAS Functions
-
-******************************************************************************/
-
-static int
-silc_server_command_whowas_parse(SilcServerCommandContext cmd,
- char **nickname,
- char **server_name,
- int *count)
-{
- unsigned char *tmp;
- unsigned int len;
-
- tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return FALSE;
- }
-
- /* Get the nickname@server string and parse it. */
- if (strchr(tmp, '@')) {
- len = strcspn(tmp, "@");
- *nickname = silc_calloc(len + 1, sizeof(char));
- memcpy(*nickname, tmp, len);
- *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
- memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
- } else {
- *nickname = strdup(tmp);
- }
- /* Get the max count of reply messages allowed */
- tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
- if (tmp)
- *count = atoi(tmp);
- else
- *count = 0;
-
- return TRUE;
-}
-
-static char
-silc_server_command_whowas_check(SilcServerCommandContext cmd,
- SilcClientEntry *clients,
- unsigned int clients_count)
-{
- SilcServer server = cmd->server;
- int i;
- SilcClientEntry entry;
-
- for (i = 0; i < clients_count; i++) {
- entry = clients[i];
-
- if (!entry->nickname || !entry->username) {
- SilcBuffer tmpbuf;
- unsigned short old_ident;
-
- if (!entry->router)
- continue;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send WHOWAS command */
- silc_server_packet_send(server, entry->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply */
- silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
- silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
- silc_server_command_whowas,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
-
- silc_command_set_ident(cmd->payload, old_ident);
-
- silc_buffer_free(tmpbuf);
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static void
-silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
- SilcClientEntry *clients,
- unsigned int clients_count)
-{
- SilcServer server = cmd->server;
- char *tmp;
- int i, count = 0, len;
- SilcBuffer packet, idp;
- SilcClientEntry entry = NULL;
- SilcCommandStatus status;
- unsigned short ident = silc_command_get_ident(cmd->payload);
- char found = FALSE;
- char nh[256], uh[256];
-
- status = SILC_STATUS_OK;
- if (clients_count > 1)
- status = SILC_STATUS_LIST_START;
-
- for (i = 0; i < clients_count; i++) {
- entry = clients[i];
-
- /* We will take only clients that are not valid anymore. They are the
- ones that are not registered anymore but still have a ID. They
- have disconnected us, and thus valid for WHOWAS. */
- if (entry->data.registered == TRUE)
- continue;
- if (entry->id == NULL)
- continue;
-
- if (count && i - 1 == count)
- break;
-
- found = TRUE;
-
- if (clients_count > 2)
- status = SILC_STATUS_LIST_ITEM;
-
- if (clients_count > 1 && i == clients_count - 1)
- status = SILC_STATUS_LIST_END;
-
- /* Sanity check, however these should never fail. However, as
- this sanity check has been added here they have failed. */
- if (!entry->nickname || !entry->username)
- continue;
-
- /* Send WHOWAS reply */
- idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- tmp = silc_argument_get_first_arg(cmd->args, NULL);
-
- memset(uh, 0, sizeof(uh));
- memset(nh, 0, sizeof(nh));
-
- strncat(nh, entry->nickname, strlen(entry->nickname));
- if (!strchr(entry->nickname, '@')) {
- strncat(nh, "@", 1);
- len = entry->router ? strlen(entry->router->server_name) :
- strlen(server->server_name);
- strncat(nh, entry->router ? entry->router->server_name :
- server->server_name, len);
- }
-
- strncat(uh, entry->username, strlen(entry->username));
- if (!strchr(entry->username, '@')) {
- strncat(uh, "@", 1);
- strcat(uh, "*private*");
- }
-
- if (entry->userinfo)
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
- status, ident, 4,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh),
- 5, entry->userinfo,
- strlen(entry->userinfo));
- else
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh));
-
- silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
- 0, packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(idp);
- }
-
- if (found == FALSE && entry)
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
-}
-
-static int
-silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
- SilcClientEntry *clients = NULL;
- int ret = 0;
-
- /* Protocol dictates that we must always send the received WHOWAS request
- to our router if we are normal server, so let's do it now unless we
- are standalone. We will not send any replies to the client until we
- have received reply from the router. */
- if (server->server_type == SILC_SERVER &&
- !cmd->pending && !server->standalone) {
- SilcBuffer tmpbuf;
- unsigned short old_ident;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send WHOWAS command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
- silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
- silc_server_command_whowas,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
-
- silc_command_set_ident(cmd->payload, old_ident);
-
- silc_buffer_free(tmpbuf);
- ret = -1;
- goto out;
- }
-
- /* We are ready to process the command request. Let's search for the
- requested client and send reply to the requesting client. */
-
- /* Parse the whowas request */
- if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
- return 0;
-
- /* Get all clients matching that nickname from local list */
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
-
- /* Check global list as well */
- if (!clients) {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
- }
-
- if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
-
- /* Send the command reply to the client */
- silc_server_command_whowas_send_reply(cmd, clients, clients_count);
-
- out:
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
-
- return ret;
-}
-
-static int
-silc_server_command_whowas_from_server(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
- SilcClientEntry *clients = NULL;
- int ret = 0;
-
- /* Parse the whowas request */
- if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
- return 0;
-
- /* Process the command request. Let's search for the requested client and
- send reply to the requesting server. */
-
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
-
- /* If we are router we will check our global list as well. */
- if (!clients && server->server_type == SILC_ROUTER) {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
- }
-
- if (!clients) {
- /* Such a client really does not exist in the SILC network. */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
- goto out;
- }
-
- /* Send the command reply to the client */
- silc_server_command_whowas_send_reply(cmd, clients, clients_count);
-
- out:
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
-
- return ret;
-}
-
-/* Server side of command WHOWAS. */
-
-SILC_SERVER_CMD_FUNC(whowas)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- int ret = 0;
-
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOWAS, cmd, 1, 2);
-
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_whowas_from_client(cmd);
- else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
- (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
- ret = silc_server_command_whowas_from_server(cmd);
-
- if (!ret)
- silc_server_command_free(cmd);
-}
-
-/******************************************************************************
-
- IDENTIFY Functions
-
-******************************************************************************/
-
-/* Checks that all mandatory fields are present. If not then send WHOIS
- request to the server who owns the client. We use WHOIS because we want
- to get as much information as possible at once. */
-
-static char
-silc_server_command_identify_check(SilcServerCommandContext cmd,
- SilcClientEntry *clients,
- unsigned int clients_count)
-{
- SilcServer server = cmd->server;
- int i;
- SilcClientEntry entry;
-
- for (i = 0; i < clients_count; i++) {
- entry = clients[i];
-
- if (entry->data.registered == FALSE)
- continue;
-
- if (!entry->nickname) {
- SilcBuffer tmpbuf;
- unsigned short old_ident;
-
- if (!entry->router)
- continue;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
- silc_command_set_command(cmd->payload, SILC_COMMAND_WHOIS);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send WHOIS request. We send WHOIS since we're doing the requesting
- now anyway so make it a good one. */
- silc_server_packet_send(server, entry->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply */
- silc_server_command_pending(server, SILC_COMMAND_WHOIS,
- silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
- silc_server_command_identify,
- silc_server_command_dup(cmd));
-
- cmd->pending = TRUE;
-
- /* Put old data back to the Command Payload we just changed */
- silc_command_set_ident(cmd->payload, old_ident);
- silc_command_set_command(cmd->payload, SILC_COMMAND_IDENTIFY);
-
- silc_buffer_free(tmpbuf);
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static void
-silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
- SilcClientEntry *clients,
- unsigned int clients_count,
- int count)
-{
- SilcServer server = cmd->server;
- char *tmp;
- int i, k, len;
- SilcBuffer packet, idp;
- SilcClientEntry entry;
- SilcCommandStatus status;
- unsigned short ident = silc_command_get_ident(cmd->payload);
- char nh[256], uh[256];
- SilcSocketConnection hsock;
-
- len = 0;
- for (i = 0; i < clients_count; i++)
- if (clients[i]->data.registered)
- len++;
-
- status = SILC_STATUS_OK;
- if (len > 1)
- status = SILC_STATUS_LIST_START;
-
- for (i = 0, k = 0; i < clients_count; i++) {
- entry = clients[i];
-
- if (entry->data.registered == FALSE) {
- if (clients_count == 1) {
- SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
- continue;
- }
-
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
-
- if (clients_count > 1 && k == clients_count - 1)
- status = SILC_STATUS_LIST_END;
-
- if (count && k - 1 == count)
- status = SILC_STATUS_LIST_END;
-
- if (count && k - 1 > count)
- break;
-
- /* Send IDENTIFY reply */
- idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- tmp = silc_argument_get_first_arg(cmd->args, NULL);
-
- memset(uh, 0, sizeof(uh));
- memset(nh, 0, sizeof(nh));
-
- strncat(nh, entry->nickname, strlen(entry->nickname));
- if (!strchr(entry->nickname, '@')) {
- strncat(nh, "@", 1);
- len = entry->router ? strlen(entry->router->server_name) :
- strlen(server->server_name);
- strncat(nh, entry->router ? entry->router->server_name :
- server->server_name, len);
- }
-
- if (!entry->username) {
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- status, ident, 2,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh));
- } else {
- strncat(uh, entry->username, strlen(entry->username));
- if (!strchr(entry->username, '@')) {
- strncat(uh, "@", 1);
- hsock = (SilcSocketConnection)entry->connection;
- len = strlen(hsock->hostname);
- strncat(uh, hsock->hostname, len);
- }
-
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh));
- }
-
- silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
- 0, packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(idp);
-
- k++;
- }
-}
-
-static int
-silc_server_command_identify_from_client(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
- SilcClientEntry *clients = NULL, entry;
- SilcClientID **client_id = NULL;
- unsigned int client_id_count = 0;
- int i, ret = 0;
-
- /* Protocol dictates that we must always send the received IDENTIFY request
- to our router if we are normal server, so let's do it now unless we
- are standalone. We will not send any replies to the client until we
- have received reply from the router. */
- if (server->server_type == SILC_SERVER &&
- !cmd->pending && !server->standalone) {
- SilcBuffer tmpbuf;
- unsigned short old_ident;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send IDENTIFY command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
- silc_command_get_ident(cmd->payload),
- silc_server_command_destructor,
- silc_server_command_identify,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
-
- silc_command_set_ident(cmd->payload, old_ident);
-
- silc_buffer_free(tmpbuf);
- ret = -1;
- goto out;
- }
-
- /* We are ready to process the command request. Let's search for the
- requested client and send reply to the requesting client. */
-
- /* Parse the IDENTIFY request */
- if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
- &nick, &server_name, &count,
- SILC_COMMAND_IDENTIFY))
- return 0;
-
- /* Get all clients matching that ID or nickname from local list */
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->local_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
- }
-
- /* Check global list as well */
- if (!clients) {
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
- }
- }
-
- if (!clients) {
- /* Such a client really does not exist in the SILC network. */
- if (!client_id_count) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
- } else {
- SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
- goto out;
- }
-
- /* Check that all mandatory fields are present and request those data
- from the server who owns the client if necessary. */
- if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
-
- /* Send the command reply to the client */
- silc_server_command_identify_send_reply(cmd, clients, clients_count,
- count);
-
- out:
- if (client_id_count) {
- for (i = 0; i < client_id_count; i++)
- silc_free(client_id[i]);
- silc_free(client_id);
- }
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
-
- return ret;
-}
-
-static int
-silc_server_command_identify_from_server(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count = 0;
- SilcClientEntry *clients = NULL, entry;
- SilcClientID **client_id = NULL;
- unsigned int client_id_count = 0;
- int i, ret = 0;
-
- /* Parse the IDENTIFY request */
- if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
- &nick, &server_name, &count,
- SILC_COMMAND_IDENTIFY))
- return 0;
-
- /* Process the command request. Let's search for the requested client and
- send reply to the requesting server. */
-
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->local_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
- }
-
- /* If we are router we will check our global list as well. */
- if (!clients && server->server_type == SILC_ROUTER) {
- if (client_id_count) {
- /* Check all Client ID's received in the command packet */
- for (i = 0; i < client_id_count; i++) {
- entry = silc_idlist_find_client_by_id(server->global_list,
- client_id[i], NULL);
- if (entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
- (clients_count + 1));
- clients[clients_count++] = entry;
- }
- }
- } else {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
- if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
- }
- }
-
- if (!clients) {
- /* Such a client really does not exist in the SILC network. */
- if (!client_id_count) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
- } else {
- SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 2, idp->data, idp->len);
- silc_buffer_free(idp);
- }
- goto out;
- }
-
- /* Check that all mandatory fields are present and request those data
- from the server who owns the client if necessary. */
- if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
-
- /* Send the command reply */
- silc_server_command_identify_send_reply(cmd, clients, clients_count, count);
-
- out:
- if (client_id_count) {
- for (i = 0; i < client_id_count; i++)
- silc_free(client_id[i]);
- silc_free(client_id);
- }
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
-
- return ret;
-}
-
-SILC_SERVER_CMD_FUNC(identify)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- int ret = 0;
-
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
-
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_identify_from_client(cmd);
- else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) |
- (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
- ret = silc_server_command_identify_from_server(cmd);
-
- if (!ret)
- silc_server_command_free(cmd);
-}
-
-/* Checks string for bad characters and returns TRUE if they are found. */
-
-static int silc_server_command_bad_chars(char *nick)
-{
- if (strchr(nick, '\\')) return TRUE;
- if (strchr(nick, '\"')) return TRUE;
- if (strchr(nick, '´')) return TRUE;
- if (strchr(nick, '`')) return TRUE;
- if (strchr(nick, '\'')) return TRUE;
- if (strchr(nick, '*')) return TRUE;
- if (strchr(nick, '/')) return TRUE;
- if (strchr(nick, '@')) return TRUE;
-
- return FALSE;
-}
-
-/* Server side of command NICK. Sets nickname for user. Setting
- nickname causes generation of a new client ID for the client. The
- new client ID is sent to the client after changing the nickname. */
-
-SILC_SERVER_CMD_FUNC(nick)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- SilcServer server = cmd->server;
- SilcBuffer packet, nidp, oidp;
- SilcClientID *new_id;
- char *nick;
- unsigned short ident = silc_command_get_ident(cmd->payload);
-
- if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
- goto out;
-
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1);
-
- /* Check nickname */
- nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
- if (silc_server_command_bad_chars(nick) == TRUE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
- SILC_STATUS_ERR_BAD_NICKNAME);
- goto out;
- }
-
- if (strlen(nick) > 128)
- nick[127] = '\0';
-
- /* Create new Client ID */
- silc_id_create_client_id(cmd->server->id, cmd->server->rng,
- cmd->server->md5hash, nick,
- &new_id);
-
- /* Send notify about nickname change to our router. We send the new
- ID and ask to replace it with the old one. If we are router the
- packet is broadcasted. Send NICK_CHANGE notify. */
- if (!server->standalone)
- silc_server_send_notify_nick_change(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE, client->id,
- new_id, SILC_ID_CLIENT_LEN);
-
- /* Remove old cache entry */
- silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
- client->id);
-
- oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
- /* Free old ID */
- if (client->id) {
- memset(client->id, 0, SILC_ID_CLIENT_LEN);
- silc_free(client->id);
- }
-
- /* Save the nickname as this client is our local client */
- if (client->nickname)
- silc_free(client->nickname);
-
- client->nickname = strdup(nick);
- client->id = new_id;
-
- /* Update client cache */
- silc_idcache_add(server->local_list->clients, client->nickname,
- strlen(client->nickname), SILC_ID_CLIENT, client->id,
- (void *)client, TRUE, FALSE);
-
- nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
- /* Send NICK_CHANGE notify to the client's channels */
- silc_server_send_notify_on_channels(server, NULL, client,
- SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
- oidp->data, oidp->len,
- nidp->data, nidp->len);
-
- /* Send the new Client ID as reply command back to client */
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK,
- SILC_STATUS_OK, ident, 1,
- 2, nidp->data, nidp->len);
- silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
- 0, packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(nidp);
- silc_buffer_free(oidp);
-
- out:
- silc_server_command_free(cmd);
-}
-
-/* Sends the LIST command reply */
-
-static void
-silc_server_command_list_send_reply(SilcServerCommandContext cmd,
- SilcChannelEntry *lch,
- unsigned int lch_count,
- SilcChannelEntry *gch,
- unsigned int gch_count)
-{
- int i;
- SilcBuffer packet, idp;
- SilcChannelEntry entry;
- SilcCommandStatus status;
- unsigned short ident = silc_command_get_ident(cmd->payload);
- char *topic;
- unsigned char usercount[4];
- unsigned int users;
-
- for (i = 0; i < lch_count; i++)
- if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
- lch[i] = NULL;
- for (i = 0; i < gch_count; i++)
- if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
- gch[i] = NULL;
-
- status = SILC_STATUS_OK;
- if ((lch_count + gch_count) > 1)
- status = SILC_STATUS_LIST_START;
-
- /* Local list */
- for (i = 0; i < lch_count; i++) {
- entry = lch[i];
-
- if (!entry)
- continue;
-
- if (i >= 1)
- status = SILC_STATUS_LIST_ITEM;
-
- if (i == lch_count - 1 && gch_count)
- break;
- if (lch_count > 1 && i == lch_count - 1)
- status = SILC_STATUS_LIST_END;
-
- idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
-
- if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
- topic = "*private*";
- memset(usercount, 0, sizeof(usercount));
- } else {
- topic = entry->topic;
- users = silc_list_count(entry->user_list);
- SILC_PUT32_MSB(users, usercount);
- }
-
- /* Send the reply */
- if (topic)
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 4,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 4, topic, strlen(topic),
- 5, usercount, 4);
- else
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 5, usercount, 4);
- silc_server_packet_send(cmd->server, cmd->sock,
- SILC_PACKET_COMMAND_REPLY, 0, packet->data,
- packet->len, FALSE);
- silc_buffer_free(packet);
- silc_buffer_free(idp);
- }
-
- status = i ? SILC_STATUS_LIST_ITEM : SILC_STATUS_OK;
-
- /* Global list */
- for (i = 0; i < gch_count; i++) {
- entry = gch[i];
-
- if (!entry)
- continue;
-
- if (i >= 1)
- status = SILC_STATUS_LIST_ITEM;
-
- if (gch_count > 1 && i == lch_count - 1)
- status = SILC_STATUS_LIST_END;
-
- idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
-
- if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
- topic = "*private*";
- memset(usercount, 0, sizeof(usercount));
- } else {
- topic = entry->topic;
- users = silc_list_count(entry->user_list);
- SILC_PUT32_MSB(users, usercount);
- }
-
- /* Send the reply */
- if (topic)
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 4,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 4, topic, strlen(topic),
- 5, usercount, 4);
- else
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 5, usercount, 4);
- silc_server_packet_send(cmd->server, cmd->sock,
- SILC_PACKET_COMMAND_REPLY, 0, packet->data,
- packet->len, FALSE);
- silc_buffer_free(packet);
- silc_buffer_free(idp);
- }
-}
-
-/* Server side of LIST command. This lists the channel of the requested
- server. Secret channels are not listed. */
-
-SILC_SERVER_CMD_FUNC(list)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcChannelID *channel_id = NULL;
- unsigned char *tmp;
- unsigned int tmp_len;
- SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
- unsigned int lch_count = 0, gch_count = 0;
-
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LIST, cmd, 0, 2);
-