5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
23 * Revision 1.11 2000/07/19 07:08:09 priikone
24 * Added version detection support to SKE.
26 * Revision 1.10 2000/07/17 11:47:30 priikone
27 * Added command lagging support. Added idle counting support.
29 * Revision 1.9 2000/07/12 05:59:41 priikone
30 * Major rewrite of ID Cache system. Support added for the new
31 * ID cache system. Major rewrite of ID List stuff on server. All
32 * SilcXXXList's are now called SilcXXXEntry's and they are pointers
33 * by default. A lot rewritten ID list functions.
35 * Revision 1.8 2000/07/10 05:42:59 priikone
36 * Removed command packet processing from server.c and added it to
38 * Implemented INFO command. Added support for testing that
39 * connections are registered before executing commands.
41 * Revision 1.7 2000/07/07 06:55:24 priikone
42 * Do not allow client to join twice on same channel.
44 * Revision 1.6 2000/07/06 10:20:59 priikone
45 * Cipher name in joining is not mandatory, removed check.
47 * Revision 1.5 2000/07/06 07:16:43 priikone
48 * Fixed a wrong way of sending command replies. The fixed way
49 * does comply with the protocol.
51 * Revision 1.4 2000/07/05 06:13:38 priikone
52 * Added PING, INVITE and NAMES command.
54 * Revision 1.3 2000/07/03 05:52:22 priikone
55 * Implemented LEAVE command.
57 * Revision 1.2 2000/06/28 05:06:38 priikone
58 * Shorter timeout for channel joining notify.
60 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
61 * Imported from internal CVS/Added Log headers.
66 #include "serverincludes.h"
67 #include "server_internal.h"
69 static int silc_server_is_registered(SilcServer server,
70 SilcSocketConnection sock,
71 SilcServerCommandContext cmd,
74 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
76 SilcCommandStatus status);
78 silc_server_command_send_status_data(SilcServerCommandContext cmd,
80 SilcCommandStatus status,
81 unsigned int arg_type,
83 unsigned int arg_len);
84 static void silc_server_command_free(SilcServerCommandContext cmd);
86 /* Server command list. */
87 SilcServerCommand silc_command_list[] =
89 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
90 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
91 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
92 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
93 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
94 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
95 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
96 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
97 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
98 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
99 SILC_SERVER_CMD(connect, CONNECT,
100 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
101 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
102 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
103 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
104 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
105 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
106 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
107 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
108 SILC_SERVER_CMD(restart, RESTART,
109 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
110 SILC_SERVER_CMD(close, CLOSE,
111 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
112 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
113 SILC_SERVER_CMD(silcoper, SILCOPER,
114 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
115 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
116 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
121 /* List of pending commands. */
122 SilcServerCommandPending *silc_command_pending = NULL;
124 /* Returns TRUE if the connection is registered. Unregistered connections
125 usually cannot send commands hence the check. */
127 static int silc_server_is_registered(SilcServer server,
128 SilcSocketConnection sock,
129 SilcServerCommandContext cmd,
133 case SILC_SOCKET_TYPE_CLIENT:
135 SilcClientEntry client = (SilcClientEntry)sock->user_data;
136 if (client->registered)
140 case SILC_SOCKET_TYPE_SERVER:
141 case SILC_SOCKET_TYPE_ROUTER:
143 SilcServerEntry serv = (SilcServerEntry)sock->user_data;
144 if (serv->registered)
152 silc_server_command_send_status_reply(cmd, command,
153 SILC_STATUS_ERR_NOT_REGISTERED);
154 silc_server_command_free(cmd);
158 /* Processes received command packet. */
160 void silc_server_command_process(SilcServer server,
161 SilcSocketConnection sock,
162 SilcPacketContext *packet)
164 SilcServerCommandContext ctx;
165 SilcServerCommand *cmd;
167 /* Check whether it is allowed for this connection to execute any
169 if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
171 SilcClientEntry client = (SilcClientEntry)sock->user_data;
176 /* Allow only one command executed in 2 seconds. */
177 curtime = time(NULL);
178 if (client->last_command && (curtime - client->last_command) < 2)
181 /* Update access time */
182 client->last_command = curtime;
185 /* Allocate command context. This must be free'd by the
186 command routine receiving it. */
187 ctx = silc_calloc(1, sizeof(*ctx));
188 ctx->server = server;
190 ctx->packet = packet; /* Save original packet */
192 /* Parse the command payload in the packet */
193 ctx->payload = silc_command_parse_payload(packet->buffer);
195 SILC_LOG_ERROR(("Bad command payload, packet dropped"));
196 silc_buffer_free(packet->buffer);
201 /* Execute command. If this fails the packet is dropped. */
202 for (cmd = silc_command_list; cmd->cb; cmd++)
203 if (cmd->cmd == silc_command_get(ctx->payload)) {
205 if (!(cmd->flags & SILC_CF_REG)) {
210 if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
217 SILC_LOG_ERROR(("Unknown command, packet dropped"));
223 silc_buffer_free(packet->buffer);
226 /* Add new pending command to the list of pending commands. Currently
227 pending commands are executed from command replies, thus we can
228 execute any command after receiving some specific command reply.
230 The argument `reply_cmd' is the command reply from where the callback
231 function is to be called, thus, it IS NOT the command to be executed. */
233 void silc_server_command_pending(SilcCommand reply_cmd,
234 SilcCommandCb callback,
237 SilcServerCommandPending *reply, *r;
239 reply = silc_calloc(1, sizeof(*reply));
240 reply->reply_cmd = reply_cmd;
241 reply->context = context;
242 reply->callback = callback;
244 if (silc_command_pending == NULL) {
245 silc_command_pending = reply;
249 for (r = silc_command_pending; r; r = r->next) {
250 if (r->next == NULL) {
257 /* Deletes pending command by reply command type. */
259 void silc_server_command_pending_del(SilcCommand reply_cmd)
261 SilcServerCommandPending *r, *tmp;
263 if (silc_command_pending) {
264 if (silc_command_pending->reply_cmd == reply_cmd) {
265 silc_free(silc_command_pending);
266 silc_command_pending = NULL;
270 for (r = silc_command_pending; r; r = r->next) {
271 if (r->next && r->next->reply_cmd == reply_cmd) {
273 r->next = r->next->next;
281 /* Free's the command context allocated before executing the command */
283 static void silc_server_command_free(SilcServerCommandContext cmd)
286 silc_command_free_payload(cmd->payload);
291 #define SILC_COMMAND_STATUS_DATA(x) \
294 /* Sends simple status message as command reply packet */
297 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
299 SilcCommandStatus status)
303 SILC_LOG_DEBUG(("Sending command status %d", status));
305 buffer = silc_command_encode_reply_payload_va(command, status, 0);
306 silc_server_packet_send(cmd->server, cmd->sock,
307 SILC_PACKET_COMMAND_REPLY, 0,
308 buffer->data, buffer->len, FALSE);
309 silc_buffer_free(buffer);
312 /* Sends command status reply with one extra argument. The argument
313 type must be sent as argument. */
316 silc_server_command_send_status_data(SilcServerCommandContext cmd,
318 SilcCommandStatus status,
319 unsigned int arg_type,
321 unsigned int arg_len)
325 SILC_LOG_DEBUG(("Sending command status %d", status));
327 buffer = silc_command_encode_reply_payload_va(command, status, 1,
328 arg_type, arg, arg_len);
329 silc_server_packet_send(cmd->server, cmd->sock,
330 SILC_PACKET_COMMAND_REPLY, 0,
331 buffer->data, buffer->len, FALSE);
332 silc_buffer_free(buffer);
335 /* Server side of command WHOIS. Processes user's query and sends found
336 results as command replies back to the client. */
338 SILC_SERVER_CMD_FUNC(whois)
340 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
341 SilcServer server = cmd->server;
342 char *tmp, *nick = NULL, *server_name = NULL;
343 unsigned int argc, count = 0, len;
344 SilcClientEntry entry;
346 unsigned char *id_string;
348 SILC_LOG_DEBUG(("Start"));
350 argc = silc_command_get_arg_num(cmd->payload);
352 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
353 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
357 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
358 SILC_STATUS_ERR_TOO_MANY_PARAMS);
362 /* Get the nickname@server string and parse it. */
363 tmp = silc_command_get_first_arg(cmd->payload, NULL);
365 if (strchr(tmp, '@')) {
366 len = strcspn(tmp, "@");
367 nick = silc_calloc(len + 1, sizeof(char));
368 memcpy(nick, tmp, len);
369 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
370 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
375 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
376 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
380 /* Get the max count of reply messages allowed */
382 tmp = silc_command_get_next_arg(cmd->payload, NULL);
384 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
385 SILC_STATUS_ERR_TOO_MANY_PARAMS);
389 silc_free(server_name);
395 /* Then, make the query from our local client list */
396 entry = silc_idlist_find_client_by_nickname(server->local_list,
400 /* If we are normal server and are connected to a router we will
401 make global query from the router. */
402 if (server->server_type == SILC_SERVER && !server->standalone) {
407 /* If we are router then we will check our global list as well. */
408 if (server->server_type == SILC_ROUTER) {
410 silc_idlist_find_client_by_nickname(server->global_list,
413 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
414 SILC_STATUS_ERR_NO_SUCH_NICK,
415 3, tmp, strlen(tmp));
421 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
422 SILC_STATUS_ERR_NO_SUCH_NICK,
423 3, tmp, strlen(tmp));
428 /* XXX, works only for local server info */
430 /* Send WHOIS reply */
431 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
432 tmp = silc_command_get_first_arg(cmd->payload, NULL);
435 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
436 char nh[256], uh[256];
437 unsigned char idle[4];
438 SilcSocketConnection hsock;
440 memset(uh, 0, sizeof(uh));
441 memset(nh, 0, sizeof(nh));
443 strncat(nh, entry->nickname, strlen(entry->nickname));
445 len = entry->router ? strlen(entry->router->server_name) :
446 strlen(server->server_name);
447 strncat(nh, entry->router ? entry->router->server_name :
448 server->server_name, len);
450 strncat(uh, entry->username, strlen(entry->username));
452 hsock = (SilcSocketConnection)entry->connection;
453 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
454 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
456 SILC_PUT32_MSB((time(NULL) - entry->last_receive), idle);
461 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
463 2, id_string, SILC_ID_CLIENT_LEN,
467 strlen(entry->userinfo),
471 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
473 2, id_string, SILC_ID_CLIENT_LEN,
481 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
483 2, id_string, SILC_ID_CLIENT_LEN,
485 strlen(entry->nickname),
486 4, tmp, strlen(tmp)); /* XXX */
488 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
489 0, packet->data, packet->len, FALSE);
491 silc_free(id_string);
492 silc_buffer_free(packet);
495 silc_server_command_free(cmd);
498 SILC_SERVER_CMD_FUNC(whowas)
502 SILC_SERVER_CMD_FUNC(identify)
504 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
505 SilcServer server = cmd->server;
506 char *tmp, *nick = NULL, *server_name = NULL;
507 unsigned int argc, count = 0, len;
508 SilcClientEntry entry;
510 unsigned char *id_string;
512 SILC_LOG_DEBUG(("Start"));
514 argc = silc_command_get_arg_num(cmd->payload);
516 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
517 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
521 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
522 SILC_STATUS_ERR_TOO_MANY_PARAMS);
526 /* Get the nickname@server string and parse it. */
527 tmp = silc_command_get_first_arg(cmd->payload, NULL);
529 if (strchr(tmp, '@')) {
530 len = strcspn(tmp, "@");
531 nick = silc_calloc(len + 1, sizeof(char));
532 memcpy(nick, tmp, len);
533 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
534 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
539 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
540 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
544 /* Get the max count of reply messages allowed */
546 tmp = silc_command_get_next_arg(cmd->payload, NULL);
548 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
549 SILC_STATUS_ERR_TOO_MANY_PARAMS);
555 /* Then, make the query from our local client list */
556 entry = silc_idlist_find_client_by_nickname(server->local_list,
560 /* If we are normal server and are connected to a router we will
561 make global query from the router. */
562 if (server->server_type == SILC_SERVER && !server->standalone) {
563 SilcBuffer buffer = cmd->packet->buffer;
565 SILC_LOG_DEBUG(("Requesting identify from router"));
567 /* Send IDENTIFY command to our router */
568 silc_buffer_push(buffer, buffer->data - buffer->head);
569 silc_server_packet_forward(server, (SilcSocketConnection)
570 server->id_entry->router->connection,
571 buffer->data, buffer->len, TRUE);
575 /* If we are router then we will check our global list as well. */
576 if (server->server_type == SILC_ROUTER) {
578 silc_idlist_find_client_by_nickname(server->global_list,
581 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
582 SILC_STATUS_ERR_NO_SUCH_NICK,
583 3, tmp, strlen(tmp));
589 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
590 SILC_STATUS_ERR_NO_SUCH_NICK,
591 3, tmp, strlen(tmp));
596 /* Send IDENTIFY reply */
597 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
598 tmp = silc_command_get_first_arg(cmd->payload, NULL);
599 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
603 3, nick, strlen(nick));
605 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
606 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
607 silc_server_packet_send_dest(server, cmd->sock,
608 SILC_PACKET_COMMAND_REPLY, 0,
609 id, cmd->packet->src_id_type,
610 packet->data, packet->len, FALSE);
614 silc_server_packet_send(server, cmd->sock,
615 SILC_PACKET_COMMAND_REPLY, 0,
616 packet->data, packet->len, FALSE);
618 silc_free(id_string);
619 silc_buffer_free(packet);
625 silc_free(server_name);
626 silc_server_command_free(cmd);
629 /* Checks string for bad characters and returns TRUE if they are found. */
631 static int silc_server_command_bad_chars(char *nick)
633 if (strchr(nick, '\\')) return TRUE;
634 if (strchr(nick, '\"')) return TRUE;
635 if (strchr(nick, '´')) return TRUE;
636 if (strchr(nick, '`')) return TRUE;
637 if (strchr(nick, '\'')) return TRUE;
638 if (strchr(nick, '*')) return TRUE;
639 if (strchr(nick, '/')) return TRUE;
640 if (strchr(nick, '@')) return TRUE;
645 /* Server side of command NICK. Sets nickname for user. Setting
646 nickname causes generation of a new client ID for the client. The
647 new client ID is sent to the client after changing the nickname. */
649 SILC_SERVER_CMD_FUNC(nick)
651 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
652 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
653 SilcServer server = cmd->server;
655 SilcClientID *new_id;
659 SILC_LOG_DEBUG(("Start"));
661 /* Check number of arguments */
662 if (silc_command_get_arg_num(cmd->payload) < 1) {
663 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
664 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
669 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
670 if (silc_server_command_bad_chars(nick) == TRUE) {
671 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
672 SILC_STATUS_ERR_BAD_NICKNAME);
676 /* Create new Client ID */
677 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
678 cmd->server->md5hash, nick,
681 /* Send notify about nickname change to our router. We send the new
682 ID and ask to replace it with the old one. */
683 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
684 silc_server_send_replace_id(server, server->id_entry->router->connection,
686 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
687 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
689 /* If we are router we have to distribute the new Client ID to all
691 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
692 silc_server_send_replace_id(server, server->id_entry->router->connection,
694 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
695 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
697 /* Remove old cache entry */
698 silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
703 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
704 silc_free(id_entry->id);
707 /* Save the nickname as this client is our local client */
708 if (id_entry->nickname)
709 silc_free(id_entry->nickname);
711 id_entry->nickname = strdup(nick);
712 id_entry->id = new_id;
714 /* Update client cache */
715 silc_idcache_add(server->local_list->clients, id_entry->nickname,
716 SILC_ID_CLIENT, id_entry->id, (void *)id_entry, TRUE);
718 /* Send the new Client ID as reply command back to client */
719 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
720 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NICK,
724 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
725 0, packet->data, packet->len, FALSE);
727 silc_free(id_string);
728 silc_buffer_free(packet);
731 silc_server_command_free(cmd);
734 SILC_SERVER_CMD_FUNC(list)
738 SILC_SERVER_CMD_FUNC(topic)
742 /* Server side of INVITE command. Invites some client to join some channel. */
744 SILC_SERVER_CMD_FUNC(invite)
746 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
747 SilcServer server = cmd->server;
748 SilcSocketConnection sock = cmd->sock, dest_sock;
749 SilcClientEntry sender, dest;
750 SilcClientID *dest_id;
751 SilcChannelEntry channel;
752 SilcChannelID *channel_id;
753 unsigned int argc, len;
754 unsigned char *id_string;
756 /* Check number of arguments */
757 argc = silc_command_get_arg_num(cmd->payload);
759 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
760 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
764 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
765 SILC_STATUS_ERR_TOO_MANY_PARAMS);
769 /* Get destination ID */
770 id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
772 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
773 SILC_STATUS_ERR_NO_CLIENT_ID);
776 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
779 id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
781 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
782 SILC_STATUS_ERR_NO_CHANNEL_ID);
785 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
787 /* Check whether the channel exists */
788 channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
790 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
791 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
795 /* Check whether the sender of this command is on the channel. */
796 sender = (SilcClientEntry )sock->user_data;
797 if (!silc_server_client_on_channel(sender, channel)) {
798 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
799 SILC_STATUS_ERR_NOT_ON_CHANNEL);
803 /* Check whether the channel is invite-only channel. If yes then the
804 sender of this command must be at least channel operator. */
807 /* Find the connection data for the destination. If it is local we will
808 send it directly otherwise we will send it to router for routing. */
809 dest = silc_idlist_find_client_by_id(server->local_list, dest_id);
811 dest_sock = (SilcSocketConnection)dest->connection;
813 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
815 /* Check whether the requested client is already on the channel. */
816 /* XXX if we are normal server we don't know about global clients on
817 the channel thus we must request it (NAMES command), check from
818 local cache as well. */
819 if (silc_server_client_on_channel(dest, channel)) {
820 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
821 SILC_STATUS_ERR_USER_ON_CHANNEL);
825 /* Send notify to the client that is invited to the channel */
826 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
827 "%s invites you to channel %s",
828 sender->nickname, channel->channel_name);
830 /* Send command reply */
831 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
835 silc_server_command_free(cmd);
838 /* Quits connection to client. This gets called if client won't
839 close the connection even when it has issued QUIT command. */
841 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
843 SilcServer server = (SilcServer)context;
844 SilcSocketConnection sock = server->sockets[fd];
846 /* Free all client specific data, such as client entry and entires
847 on channels this client may be on. */
848 silc_server_free_sock_user_data(server, sock);
850 /* Close the connection on our side */
851 silc_server_close_connection(server, sock);
854 /* Quits SILC session. This is the normal way to disconnect client. */
856 SILC_SERVER_CMD_FUNC(quit)
858 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
859 SilcServer server = cmd->server;
860 SilcSocketConnection sock = cmd->sock;
862 SILC_LOG_DEBUG(("Start"));
864 /* We quit the connection with little timeout */
865 silc_task_register(server->timeout_queue, sock->sock,
866 silc_server_command_quit_cb, server,
867 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
869 silc_server_command_free(cmd);
872 SILC_SERVER_CMD_FUNC(kill)
876 /* Server side of command INFO. This sends information about us to
877 the client. If client requested specific server we will send the
878 command to that server. */
880 SILC_SERVER_CMD_FUNC(info)
882 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
883 SilcServer server = cmd->server;
886 unsigned char *id_string;
887 char info_string[256], *dest_server;
889 argc = silc_command_get_arg_num(cmd->payload);
891 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
892 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
896 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
897 SILC_STATUS_ERR_TOO_MANY_PARAMS);
901 /* Get server name */
902 dest_server = silc_command_get_arg_type(cmd->payload, 1, NULL);
904 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
905 SILC_STATUS_ERR_NO_SUCH_SERVER);
909 if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
911 memset(info_string, 0, sizeof(info_string));
912 snprintf(info_string, sizeof(info_string),
913 "location: %s server: %s admin: %s <%s>",
914 server->config->admin_info->location,
915 server->config->admin_info->server_type,
916 server->config->admin_info->admin_name,
917 server->config->admin_info->admin_email);
919 id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
922 silc_command_encode_reply_payload_va(SILC_COMMAND_INFO,
924 2, id_string, SILC_ID_SERVER_LEN,
926 strlen(info_string));
927 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
928 packet->data, packet->len, FALSE);
930 silc_free(id_string);
931 silc_buffer_free(packet);
933 /* Send this command to the requested server */
935 if (server->server_type == SILC_SERVER && !server->standalone) {
939 if (server->server_type == SILC_ROUTER) {
945 silc_server_command_free(cmd);
948 SILC_SERVER_CMD_FUNC(connect)
952 /* Server side of command PING. This just replies to the ping. */
954 SILC_SERVER_CMD_FUNC(ping)
956 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
957 SilcServer server = cmd->server;
960 unsigned char *id_string;
962 argc = silc_command_get_arg_num(cmd->payload);
964 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
965 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
969 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
970 SILC_STATUS_ERR_TOO_MANY_PARAMS);
975 id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
977 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
978 SILC_STATUS_ERR_NO_SERVER_ID);
981 id = silc_id_str2id(id_string, SILC_ID_SERVER);
983 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
985 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
988 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
989 SILC_STATUS_ERR_NO_SUCH_SERVER);
996 silc_server_command_free(cmd);
999 SILC_SERVER_CMD_FUNC(oper)
1008 SilcChannelEntry channel;
1010 } JoinInternalContext;
1012 SILC_TASK_CALLBACK(silc_server_command_join_notify)
1014 JoinInternalContext *ctx = (JoinInternalContext *)context;
1016 if (ctx->channel->key && ctx->channel->key_len) {
1017 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
1018 "%s (%s@%s) has joined channel %s",
1019 ctx->nickname, ctx->username,
1020 ctx->hostname, ctx->channel_name);
1023 silc_task_register(ctx->server->timeout_queue, fd,
1024 silc_server_command_join_notify, context,
1025 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1029 /* Assembles NAMES command and executes it. This is called when client
1030 joins to a channel and we wan't to send NAMES command reply to the
1033 void silc_server_command_send_names(SilcServer server,
1034 SilcSocketConnection sock,
1035 SilcChannelEntry channel)
1037 SilcServerCommandContext cmd;
1039 unsigned char *id_string;
1041 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1042 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
1043 1, id_string, SILC_ID_CHANNEL_LEN);
1045 cmd = silc_calloc(1, sizeof(*cmd));
1046 cmd->payload = silc_command_parse_payload(buffer);
1047 cmd->server = server;
1049 cmd->pending = FALSE;
1051 silc_server_command_names((void *)cmd);
1052 silc_free(id_string);
1056 /* Server side of command JOIN. Joins client into requested channel. If
1057 the channel does not exist it will be created. */
1059 SILC_SERVER_CMD_FUNC(join)
1061 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1062 SilcServer server = cmd->server;
1063 SilcSocketConnection sock = cmd->sock;
1064 SilcBuffer buffer = cmd->packet->buffer;
1065 int argc, i, tmp_len;
1066 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
1067 unsigned char *passphrase, mode[4];
1068 SilcChannelEntry channel;
1069 SilcServerID *router_id;
1071 SilcClientEntry client;
1073 SILC_LOG_DEBUG(("Start"));
1075 /* Check number of parameters */
1076 argc = silc_command_get_arg_num(cmd->payload);
1078 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1079 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1083 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1084 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1088 /* Get channel name */
1089 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
1090 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
1091 memcpy(channel_name, tmp, tmp_len);
1092 if (silc_server_command_bad_chars(tmp) == TRUE) {
1093 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1094 SILC_STATUS_ERR_BAD_CHANNEL);
1095 silc_free(channel_name);
1099 /* Get passphrase */
1100 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
1102 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1103 memcpy(passphrase, tmp, tmp_len);
1106 /* Get cipher name */
1107 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
1109 /* See if the channel exists */
1111 silc_idlist_find_channel_by_name(server->local_list, channel_name);
1113 /* Channel not found */
1115 /* If we are standalone server we don't have a router, we just create
1116 the channel by ourselves. */
1117 if (server->standalone) {
1118 router_id = server->id;
1119 channel = silc_server_new_channel(server, router_id,
1120 cipher, channel_name);
1127 /* No channel ID found, the channel does not exist on our server.
1128 We send JOIN command to our router which will handle the joining
1129 procedure (either creates the channel if it doesn't exist or
1130 joins the client to it) - if we are normal server. */
1131 if (server->server_type == SILC_SERVER) {
1133 /* Forward the original JOIN command to the router */
1134 silc_buffer_push(buffer, buffer->data - buffer->head);
1135 silc_server_packet_forward(server, (SilcSocketConnection)
1136 server->id_entry->router->connection,
1137 buffer->data, buffer->len, TRUE);
1139 /* Add the command to be pending. It will be re-executed after
1140 router has replied back to us. */
1141 cmd->pending = TRUE;
1142 silc_server_command_pending(SILC_COMMAND_JOIN,
1143 silc_server_command_join, context);
1148 /* If we are router and the channel does not exist we will check our
1149 global list for the channel. */
1150 if (!channel && server->server_type == SILC_ROUTER) {
1152 /* Notify all routers about the new channel in SILC network. */
1153 if (!server->standalone) {
1155 silc_server_send_new_id(server, server->id_entry->router->connection,
1157 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
1165 /* If the JOIN request was forwarded to us we will make a bit slower
1166 query to get the client pointer. Otherwise, we get the client pointer
1168 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1169 client = (SilcClientEntry)sock->user_data;
1171 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1172 client = silc_idlist_find_client_by_id(server->local_list, id);
1180 /* Check whether the client already is on the channel */
1181 if (silc_server_client_on_channel(client, channel)) {
1182 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1183 SILC_STATUS_ERR_USER_ON_CHANNEL);
1184 silc_free(channel_name);
1188 /* Join the client to the channel */
1189 i = channel->user_list_count;
1190 channel->user_list = silc_realloc(channel->user_list,
1191 sizeof(*channel->user_list) * (i + 1));
1192 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
1193 channel->user_list[i].client = client;
1194 channel->user_list_count++;
1196 /* Add the channel to client's channel list */
1197 i = client->channel_count;
1198 client->channel = silc_realloc(client->channel,
1199 sizeof(*client->channel) * (i + 1));
1200 client->channel[i] = channel;
1201 client->channel_count++;
1203 /* Notify router about new user on channel. If we are normal server
1204 we send it to our router, if we are router we send it to our
1206 if (!server->standalone) {
1210 /* Send command reply to the client. Client receives the Channe ID,
1211 channel mode and possibly other information in this reply packet. */
1212 if (!cmd->pending) {
1213 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1214 SILC_PUT32_MSB(channel->mode, mode);
1216 if (!channel->topic)
1218 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1221 strlen(channel_name),
1222 3, id_string, SILC_ID_CHANNEL_LEN,
1226 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1229 strlen(channel_name),
1230 3, id_string, SILC_ID_CHANNEL_LEN,
1233 strlen(channel->topic));
1235 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1236 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1237 silc_server_packet_send_dest(cmd->server, cmd->sock,
1238 SILC_PACKET_COMMAND_REPLY, 0,
1239 id, cmd->packet->src_id_type,
1240 packet->data, packet->len, FALSE);
1243 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1244 packet->data, packet->len, FALSE);
1246 silc_buffer_free(packet);
1249 /* Send channel key to the client. Client cannot start transmitting
1250 to the channel until we have sent the key. */
1251 if (!cmd->pending) {
1252 tmp_len = strlen(channel->channel_key->cipher->name);
1254 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
1256 channel->channel_key->cipher->name,
1257 channel->key_len / 8, channel->key);
1259 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1260 packet->data, packet->len, FALSE);
1261 silc_buffer_free(packet);
1265 silc_free(id_string);
1267 /* Finally, send notify message to all clients on the channel about
1268 new user on the channel. */
1269 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1270 if (!cmd->pending) {
1271 silc_server_send_notify_to_channel(server, channel,
1272 "%s (%s@%s) has joined channel %s",
1273 client->nickname, client->username,
1274 sock->hostname ? sock->hostname :
1275 sock->ip, channel_name);
1277 /* This is pending command request. Send the notify after we have
1278 received the key for the channel from the router. */
1279 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1280 ctx->channel_name = channel_name;
1281 ctx->nickname = client->nickname;
1282 ctx->username = client->username;
1283 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1284 ctx->channel = channel;
1285 ctx->server = server;
1286 silc_task_register(server->timeout_queue, sock->sock,
1287 silc_server_command_join_notify, ctx,
1288 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1292 /* Send NAMES command reply to the joined channel so the user sees who
1293 is currently on the channel. */
1294 silc_server_command_send_names(server, sock, channel);
1297 silc_server_command_free(cmd);
1300 /* Server side of command MOTD. Sends servers current "message of the
1301 day" to the client. */
1303 SILC_SERVER_CMD_FUNC(motd)
1306 SILC_LOG_DEBUG(("Start"));
1310 SILC_SERVER_CMD_FUNC(umode)
1314 SILC_SERVER_CMD_FUNC(cmode)
1318 SILC_SERVER_CMD_FUNC(kick)
1322 SILC_SERVER_CMD_FUNC(restart)
1326 SILC_SERVER_CMD_FUNC(close)
1330 SILC_SERVER_CMD_FUNC(die)
1334 SILC_SERVER_CMD_FUNC(silcoper)
1338 /* Server side command of LEAVE. Removes client from a channel. */
1340 SILC_SERVER_CMD_FUNC(leave)
1342 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1343 SilcServer server = cmd->server;
1344 SilcSocketConnection sock = cmd->sock;
1345 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
1347 SilcChannelEntry channel;
1349 unsigned int i, argc, key_len;
1350 unsigned char *tmp, channel_key[32];
1352 SILC_LOG_DEBUG(("Start"));
1354 argc = silc_command_get_arg_num(cmd->payload);
1356 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1357 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1361 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1362 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1366 /* Get Channel ID */
1367 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1369 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1370 SILC_STATUS_ERR_NO_CHANNEL_ID);
1373 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1375 /* Get channel entry */
1376 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1378 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1379 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1383 /* Check whether this client is on the channel */
1384 if (!silc_server_client_on_channel(id_entry, channel)) {
1385 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1386 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1390 /* Remove client from channel */
1391 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1392 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1395 /* If the channel does not exist anymore we won't send anything */
1399 /* Re-generate channel key */
1400 key_len = channel->key_len / 8;
1401 for (i = 0; i < key_len; i++)
1402 channel_key[i] = silc_rng_get_byte(server->rng);
1403 channel->channel_key->cipher->set_key(channel->channel_key->context,
1404 channel_key, key_len);
1405 memset(channel->key, 0, key_len);
1406 silc_free(channel->key);
1407 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1408 memcpy(channel->key, channel_key, key_len);
1409 memset(channel_key, 0, sizeof(channel_key));
1411 /* Encode channel key payload to be distributed on the channel */
1413 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1414 strlen(channel->channel_key->cipher->name),
1415 channel->channel_key->cipher->name,
1416 key_len, channel->key);
1418 /* If we are normal server then we will send it to our router. If we
1419 are router we will send it to all local servers that has clients on
1421 if (server->server_type == SILC_SERVER) {
1422 if (!server->standalone)
1423 silc_server_packet_send(server,
1424 cmd->server->id_entry->router->connection,
1425 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1431 /* Send to locally connected clients on the channel */
1432 silc_server_packet_send_local_channel(server, channel,
1433 SILC_PACKET_CHANNEL_KEY, 0,
1434 packet->data, packet->len, FALSE);
1436 silc_buffer_free(packet);
1440 silc_server_command_free(cmd);
1443 /* Server side of command NAMES. Resolves clients and their names currently
1444 joined on the requested channel. The name list is sent back to the
1447 SILC_SERVER_CMD_FUNC(names)
1449 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1450 SilcServer server = cmd->server;
1451 SilcChannelEntry channel;
1454 unsigned int i, len, len2, argc;
1456 char *name_list = NULL, *n;
1457 SilcBuffer client_id_list;
1459 SILC_LOG_DEBUG(("Start"));
1461 argc = silc_command_get_arg_num(cmd->payload);
1463 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1464 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1468 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1469 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1473 /* Get Channel ID */
1474 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1476 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1477 SILC_STATUS_ERR_NO_CHANNEL_ID);
1480 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1482 /* Check whether the channel exists. If we are normal server and the
1483 channel does not exist we will send this same command to our router
1484 which will know if the channel exists. */
1485 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1487 if (server->server_type == SILC_SERVER && !server->standalone) {
1488 /* XXX Send names command */
1490 cmd->pending = TRUE;
1491 silc_server_command_pending(SILC_COMMAND_NAMES,
1492 silc_server_command_names, context);
1496 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1497 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1501 /* Assemble the name list now */
1504 for (i = 0; i < channel->user_list_count; i++) {
1505 if (!channel->user_list[i].client)
1508 n = channel->user_list[i].client->nickname;
1512 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1513 memcpy(name_list + (len - len2), n, len2);
1516 if (i == channel->user_list_count - 1)
1518 memcpy(name_list + len, ",", 1);
1523 /* Assemble the Client ID list now */
1524 client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
1525 channel->user_list_count);
1526 silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1527 channel->user_list_count));
1528 for (i = 0; i < channel->user_list_count; i++) {
1529 unsigned char *id_string;
1531 if (!channel->user_list[i].client)
1534 id_string = silc_id_id2str(channel->user_list[i].client->id,
1536 silc_buffer_format(client_id_list,
1537 SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1539 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1540 silc_free(id_string);
1542 silc_buffer_push(client_id_list,
1543 client_id_list->data - client_id_list->head);
1546 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
1548 2, tmp, SILC_ID_CHANNEL_LEN,
1551 4, client_id_list->data,
1552 client_id_list->len);
1553 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1554 packet->data, packet->len, FALSE);
1556 silc_buffer_free(packet);
1557 silc_free(name_list);
1558 silc_buffer_free(client_id_list);
1562 silc_server_command_free(cmd);