X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fcommand.c;h=25df5eddead10cca6f40826c906f0d7fe4b7efe0;hb=da3a876c26b6d697ee6446ad81a8edfff1828cab;hp=06e5b96d7717fed78c6d947714f6f5bb70300415;hpb=346885ee9466a6f1d5ecc99a5401aa3043acf7c0;p=silc.git diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 06e5b96d..25df5edd 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -67,6 +67,7 @@ SilcServerCommand silc_command_list[] = SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG), SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG), SILC_SERVER_CMD(detach, DETACH, SILC_CF_LAG_STRICT | SILC_CF_REG), + SILC_SERVER_CMD(watch, WATCH, SILC_CF_LAG | SILC_CF_REG), SILC_SERVER_CMD(silcoper, SILCOPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER), SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG), @@ -2046,19 +2047,21 @@ SILC_SERVER_CMD_FUNC(nick) FALSE : TRUE, client->id, new_id, nick); + /* Check if anyone is watching the old nickname */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, client, nick, + SILC_NOTIFY_TYPE_NICK_CHANGE); + oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); /* Remove old cache entry */ silc_idcache_del_by_context(server->local_list->clients, client); - /* Free old ID */ silc_free(client->id); + client->id = new_id; - /* Save the nickname as this client is our local client */ silc_free(client->nickname); - client->nickname = strdup(nick); - client->id = new_id; /* Update client cache */ silc_idcache_add(server->local_list->clients, client->nickname, @@ -2074,6 +2077,11 @@ SILC_SERVER_CMD_FUNC(nick) client->nickname, strlen(client->nickname)); + /* Check if anyone is watching the new nickname */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, client, NULL, + SILC_NOTIFY_TYPE_NICK_CHANGE); + send_reply: /* Send the new Client ID as reply command back to client */ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, @@ -2345,8 +2353,9 @@ SILC_SERVER_CMD_FUNC(topic) goto out; } - if (chl->mode == SILC_CHANNEL_UMODE_NONE && - channel->mode & SILC_CHANNEL_MODE_TOPIC) { + if (channel->mode & SILC_CHANNEL_MODE_TOPIC && + !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) && + !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC, SILC_STATUS_ERR_NO_CHANNEL_PRIV); goto out; @@ -2451,8 +2460,9 @@ SILC_SERVER_CMD_FUNC(invite) /* Check whether the channel is invite-only channel. If yes then the sender of this command must be at least channel operator. */ - if (chl->mode == SILC_CHANNEL_UMODE_NONE && - channel->mode & SILC_CHANNEL_MODE_INVITE) { + if (channel->mode & SILC_CHANNEL_MODE_INVITE && + !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) && + !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE, SILC_STATUS_ERR_NO_CHANNEL_PRIV); goto out; @@ -2750,6 +2760,11 @@ SILC_SERVER_CMD_FUNC(kill) silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, SILC_STATUS_OK); + /* Check if anyone is watching this nickname */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, client, NULL, + SILC_NOTIFY_TYPE_KILLED); + /* Now do the killing */ silc_server_kill_client(server, remote_client, comment, client->id, SILC_ID_CLIENT); @@ -3759,6 +3774,11 @@ SILC_SERVER_CMD_FUNC(umode) if (!server->standalone) silc_server_send_notify_umode(server, server->router->connection, TRUE, client->id, client->mode); + + /* Check if anyone is watching this nickname */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, client, NULL, + SILC_NOTIFY_TYPE_UMODE_CHANGE); } /* Send command reply to sender */ @@ -3838,10 +3858,11 @@ SILC_SERVER_CMD_FUNC(cmode) /* Check that client has rights to change any requested channel modes */ if (set_mask && !silc_server_check_cmode_rights(server, channel, chl, mode_mask)) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, - (chl->mode == 0 ? - SILC_STATUS_ERR_NO_CHANNEL_PRIV : - SILC_STATUS_ERR_NO_CHANNEL_FOPRIV)); + silc_server_command_send_status_reply( + cmd, SILC_COMMAND_CMODE, + (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) ? + SILC_STATUS_ERR_NO_CHANNEL_PRIV : + SILC_STATUS_ERR_NO_CHANNEL_FOPRIV)); goto out; } @@ -4394,6 +4415,53 @@ SILC_SERVER_CMD_FUNC(cumode) } } + if (target_mask & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS) { + if (target_client != client) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_NOT_YOU); + goto out; + } + + if (!(chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)) { + chl->mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS; + notify = TRUE; + } + } else { + if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS) { + if (target_client != client) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_NOT_YOU); + goto out; + } + + chl->mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS; + notify = TRUE; + } + } + + if (target_mask & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS) { + if (target_client != client) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_NOT_YOU); + goto out; + } + + if (!(chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)) { + chl->mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS; + notify = TRUE; + } + } else { + if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS) { + if (target_client != client) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, + SILC_STATUS_ERR_NOT_YOU); + goto out; + } + + chl->mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS; + notify = TRUE; + } + } idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); @@ -4487,7 +4555,8 @@ SILC_SERVER_CMD_FUNC(kick) } /* Check that the kicker is channel operator or channel founder */ - if (chl->mode == SILC_CHANNEL_UMODE_NONE) { + if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) && + !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK, SILC_STATUS_ERR_NO_CHANNEL_PRIV); goto out; @@ -4663,6 +4732,11 @@ SILC_SERVER_CMD_FUNC(oper) silc_server_send_notify_umode(server, server->router->connection, TRUE, client->id, client->mode); + /* Check if anyone is watching this nickname */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, client, NULL, + SILC_NOTIFY_TYPE_UMODE_CHANGE); + /* Send reply to the sender */ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER, SILC_STATUS_OK); @@ -4731,6 +4805,11 @@ SILC_SERVER_CMD_FUNC(detach) server->server_type == SILC_SERVER ? FALSE : TRUE, client->id, client->mode); + /* Check if anyone is watching this nickname */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, client, NULL, + SILC_NOTIFY_TYPE_UMODE_CHANGE); + q = silc_calloc(1, sizeof(*q)); q->server = server; q->sock = cmd->sock; @@ -4755,6 +4834,165 @@ SILC_SERVER_CMD_FUNC(detach) silc_server_command_free(cmd); } +/* Server side of WATCH command. */ + +SILC_SERVER_CMD_FUNC(watch) +{ + SilcServerCommandContext cmd = (SilcServerCommandContext)context; + SilcServer server = cmd->server; + char *add_nick, *del_nick; + SilcUInt32 add_nick_len, del_nick_len, tmp_len; + char nick[128 + 1]; + unsigned char hash[16], *tmp; + SilcClientEntry client; + SilcClientID *client_id = NULL; + + SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WATCH, cmd, 1, 3); + + if (server->server_type == SILC_SERVER && !server->standalone) { + if (!cmd->pending) { + /* Send the command to router */ + SilcBuffer tmpbuf; + SilcUInt16 old_ident; + + old_ident = silc_command_get_ident(cmd->payload); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); + tmpbuf = silc_command_payload_encode_payload(cmd->payload); + + silc_server_packet_send(server, 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_WATCH, + silc_command_get_ident(cmd->payload), + silc_server_command_watch, + silc_server_command_dup(cmd)); + cmd->pending = TRUE; + silc_command_set_ident(cmd->payload, old_ident); + silc_buffer_free(tmpbuf); + } else if (context2) { + /* Received reply from router, just send same data to the client. */ + SilcServerCommandReplyContext reply = context2; + SilcStatus status; + silc_command_get_status(reply->payload, &status, NULL); + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, status); + } + + goto out; + } + + /* We are router and keep the watch list for local cell */ + + /* Get the client ID */ + tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + if (!tmp) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL); + if (!client_id) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); + goto out; + } + + /* Get the client entry which must be in local list */ + client = silc_idlist_find_client_by_id(server->local_list, + client_id, TRUE, NULL); + if (!client) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); + goto out; + } + + /* Take nickname */ + add_nick = silc_argument_get_arg_type(cmd->args, 2, &add_nick_len); + del_nick = silc_argument_get_arg_type(cmd->args, 3, &del_nick_len); + if (!add_nick && !del_nick) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + if (add_nick && add_nick_len > 128) + add_nick[128] = '\0'; + if (del_nick && del_nick_len > 128) + del_nick[128] = '\0'; + + memset(nick, 0, sizeof(nick)); + + /* Add new nickname to be watched in our cell */ + if (add_nick) { + if (silc_server_name_bad_chars(add_nick, strlen(add_nick)) == TRUE) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, + SILC_STATUS_ERR_BAD_NICKNAME); + goto out; + } + + /* Hash the nick, we have the hash saved, not nicks because we can + do one to one mapping to the nick from Client ID hash this way. */ + silc_to_lower(add_nick, nick, sizeof(nick) - 1); + silc_hash_make(server->md5hash, nick, strlen(nick), hash); + + /* Check whether this client is already watching this nickname */ + if (silc_hash_table_find_by_context(server->watcher_list, hash, + client, NULL)) { + /* Nickname is alredy being watched for this client */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, + SILC_STATUS_ERR_NICKNAME_IN_USE); + goto out; + } + + /* Get the nickname from the watcher list and use the same key in + new entries as well. If key doesn't exist then create it. */ + if (!silc_hash_table_find(server->watcher_list, hash, (void **)&tmp, NULL)) + tmp = silc_memdup(hash, CLIENTID_HASH_LEN); + + /* Add the client to the watcher list with the specified nickname hash. */ + silc_hash_table_add(server->watcher_list, tmp, client); + } + + /* Delete nickname from watch list */ + if (del_nick) { + if (silc_server_name_bad_chars(del_nick, strlen(del_nick)) == TRUE) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, + SILC_STATUS_ERR_BAD_NICKNAME); + goto out; + } + + /* Hash the nick, we have the hash saved, not nicks because we can + do one to one mapping to the nick from Client ID hash this way. */ + silc_to_lower(del_nick, nick, sizeof(nick) - 1); + silc_hash_make(server->md5hash, nick, strlen(nick), hash); + + /* Check that this client is watching for this nickname */ + if (!silc_hash_table_find_by_context(server->watcher_list, hash, + client, (void **)&tmp)) { + /* Nickname is alredy being watched for this client */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, + SILC_STATUS_ERR_NO_SUCH_NICK); + goto out; + } + + /* Delete the nickname from the watcher list. */ + silc_hash_table_del_by_context(server->watcher_list, hash, client); + + /* Now check whether there still exists entries with this key, if not + then free the key to not leak memory. */ + if (!silc_hash_table_find(server->watcher_list, hash, NULL, NULL)) + silc_free(tmp); + } + + silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, + SILC_STATUS_OK); + + out: + silc_free(client_id); + silc_server_command_free(cmd); +} + /* Server side of SILCOPER command. Client uses this comand to obtain router operator privileges to this router. */ @@ -4845,6 +5083,11 @@ SILC_SERVER_CMD_FUNC(silcoper) silc_server_send_notify_umode(server, server->router->connection, TRUE, client->id, client->mode); + /* Check if anyone is watching this nickname */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, client, NULL, + SILC_NOTIFY_TYPE_UMODE_CHANGE); + /* Send reply to the sender */ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER, SILC_STATUS_OK); @@ -5404,7 +5647,8 @@ SILC_SERVER_CMD_FUNC(connect) goto out; /* Check whether client has the permissions. */ - if (client->mode == SILC_UMODE_NONE) { + if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) && + !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT, SILC_STATUS_ERR_NO_SERVER_PRIV); goto out; @@ -5461,7 +5705,8 @@ SILC_SERVER_CMD_FUNC(close) goto out; /* Check whether client has the permissions. */ - if (client->mode == SILC_UMODE_NONE) { + if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) && + !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE, SILC_STATUS_ERR_NO_SERVER_PRIV); goto out; @@ -5528,7 +5773,8 @@ SILC_SERVER_CMD_FUNC(shutdown) goto out; /* Check whether client has the permission. */ - if (client->mode == SILC_UMODE_NONE) { + if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) && + !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_SHUTDOWN, SILC_STATUS_ERR_NO_SERVER_PRIV); goto out;