X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fcommand.c;h=807faee2cf8743ed787d06a14f15ee52bc19eb36;hb=386c883d8774999c6e74d7c6c37e52e4163a4cb1;hp=46dc9c5576b929571ba3acb333c4aea54720ab21;hpb=51effd0a20d89135fd729aa59d98cb3e47b7b23a;p=silc.git diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 46dc9c55..807faee2 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -131,7 +131,6 @@ static int silc_server_is_registered(SilcServer server, silc_server_command_send_status_reply(cmd, command, SILC_STATUS_ERR_NOT_REGISTERED); - silc_server_command_free(cmd); return FALSE; } @@ -149,6 +148,11 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout) SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context; SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data; + if (!client) { + silc_server_command_free(timeout->ctx); + silc_free(timeout); + } + /* Update access time */ client->last_command = time(NULL); @@ -159,6 +163,8 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout) timeout->ctx, timeout->cmd->cmd)) timeout->cmd->cb(timeout->ctx, NULL); + else + silc_server_command_free(timeout->ctx); silc_free(timeout); } @@ -233,15 +239,12 @@ void silc_server_command_process(SilcServer server, silc_server_command_process_timeout, (void *)timeout, 2 - (time(NULL) - client->last_command), 0, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_NORMAL); + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); else silc_schedule_task_add(server->schedule, sock->sock, silc_server_command_process_timeout, - (void *)timeout, - 0, 1, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_NORMAL); + (void *)timeout, 0, 1, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); return; } @@ -251,6 +254,8 @@ void silc_server_command_process(SilcServer server, cmd->cb(ctx, NULL); else if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) cmd->cb(ctx, NULL); + else + silc_server_command_free(ctx); } /* Allocate Command Context */ @@ -304,7 +309,6 @@ silc_server_command_dup(SilcServerCommandContext ctx) bool silc_server_command_pending(SilcServer server, SilcCommand reply_cmd, uint16 ident, - SilcServerPendingDestructor destructor, SilcCommandCb callback, void *context) { @@ -325,7 +329,6 @@ bool silc_server_command_pending(SilcServer server, reply->ident = ident; reply->context = context; reply->callback = callback; - reply->destructor = destructor; silc_dlist_add(server->pending_commands, reply); return TRUE; @@ -369,7 +372,6 @@ silc_server_command_pending_check(SilcServer server, callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1)); callbacks[i].context = r->context; callbacks[i].callback = r->callback; - callbacks[i].destructor = r->destructor; ctx->ident = ident; i++; } @@ -379,14 +381,6 @@ silc_server_command_pending_check(SilcServer server, return callbacks; } -/* Destructor function for pending callbacks. This is called when using - pending commands to free the context given for the pending command. */ - -static void silc_server_command_destructor(void *context) -{ - silc_server_command_free((SilcServerCommandContext)context); -} - /* Sends simple status message as command reply packet */ static void @@ -509,6 +503,8 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd, (*client_id)[0] = silc_id_payload_parse_id(tmp, len); if ((*client_id)[0] == NULL) { silc_free(*client_id); + silc_server_command_send_status_reply(cmd, command, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); return FALSE; } *client_id_count = 1; @@ -526,6 +522,9 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd, for (i = 0; i < *client_id_count; i++) silc_free((*client_id)[i]); silc_free(*client_id); + silc_server_command_send_status_reply( + cmd, command, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); return FALSE; } (*client_id_count)++; @@ -567,6 +566,8 @@ silc_server_command_whois_check(SilcServerCommandContext cmd, int i, k; bool no_res = TRUE; + SILC_LOG_DEBUG(("Start")); + for (i = 0; i < clients_count; i++) { entry = clients[i]; if (!entry) @@ -593,7 +594,6 @@ silc_server_command_whois_check(SilcServerCommandContext cmd, to the command reply and we're done with this one. */ silc_server_command_pending(server, SILC_COMMAND_NONE, entry->resolve_cmd_ident, - silc_server_command_destructor, silc_server_command_whois, silc_server_command_dup(cmd)); no_res = FALSE; @@ -676,7 +676,6 @@ silc_server_command_whois_check(SilcServerCommandContext cmd, /* Reprocess this packet after received reply */ silc_server_command_pending(server, SILC_COMMAND_WHOIS, r->ident, - silc_server_command_destructor, silc_server_command_whois, silc_server_command_dup(cmd)); cmd->pending = TRUE; @@ -846,7 +845,6 @@ silc_server_command_whois_send_router(SilcServerCommandContext cmd) /* Reprocess this packet after received reply from router */ silc_server_command_pending(server, SILC_COMMAND_WHOIS, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_whois, silc_server_command_dup(cmd)); cmd->pending = TRUE; @@ -996,9 +994,7 @@ SILC_SERVER_CMD_FUNC(whois) SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328); ret = silc_server_command_whois_process(cmd); - - if (!ret) - silc_server_command_free(cmd); + silc_server_command_free(cmd); } /****************************************************************************** @@ -1067,11 +1063,9 @@ silc_server_command_whowas_check(SilcServerCommandContext cmd, /* 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); @@ -1089,36 +1083,53 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd, { SilcServer server = cmd->server; char *tmp; - int i, count = 0, len; + int i, k, count = 0, len; SilcBuffer packet, idp; SilcClientEntry entry = NULL; SilcCommandStatus status; uint16 ident = silc_command_get_ident(cmd->payload); - char found = FALSE; char nh[256], uh[256]; + int valid_count; status = SILC_STATUS_OK; - if (clients_count > 1) - status = SILC_STATUS_LIST_START; + /* Process only entries that are not registered anymore. */ + valid_count = 0; for (i = 0; i < clients_count; i++) { - entry = clients[i]; + if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED) + clients[i] = NULL; + else + valid_count++; + } - /* 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.status & SILC_IDLIST_STATUS_REGISTERED || !entry->id) - continue; + if (!valid_count) { + /* No valid entries found at all, just send error */ + unsigned char *tmp; + + tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); + if (tmp) + silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS, + SILC_STATUS_ERR_NO_SUCH_NICK, + 3, tmp, strlen(tmp)); + return; + } - if (count && i - 1 == count) - break; + if (valid_count > 1) + status = SILC_STATUS_LIST_START; - found = TRUE; + for (i = 0, k = 0; i < clients_count; i++) { + entry = clients[i]; + if (!entry) + continue; - if (clients_count > 2) + if (k >= 1) status = SILC_STATUS_LIST_ITEM; - if (clients_count > 1 && i == clients_count - 1) + if (valid_count > 1 && k == valid_count - 1) + status = SILC_STATUS_LIST_END; + if (count && k - 1 == count) status = SILC_STATUS_LIST_END; + if (count && k - 1 > count) + break; /* Send WHOWAS reply */ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT); @@ -1159,13 +1170,9 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd, 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)); + k++; + } } static int @@ -1202,11 +1209,9 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd) /* 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); @@ -1264,7 +1269,6 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd) silc_free(clients); silc_free(nick); silc_free(server_name); - return ret; } @@ -1278,9 +1282,7 @@ SILC_SERVER_CMD_FUNC(whowas) SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2); ret = silc_server_command_whowas_process(cmd); - - if (!ret) - silc_server_command_free(cmd); + silc_server_command_free(cmd); } /****************************************************************************** @@ -1309,7 +1311,6 @@ silc_server_command_identify_send_router(SilcServerCommandContext cmd) /* 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; @@ -1627,7 +1628,6 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd, to the command reply and we're done with this one. */ silc_server_command_pending(server, SILC_COMMAND_NONE, entry->resolve_cmd_ident, - silc_server_command_destructor, silc_server_command_identify, silc_server_command_dup(cmd)); no_res = FALSE; @@ -1710,7 +1710,6 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd, /* Reprocess this packet after received reply */ silc_server_command_pending(server, SILC_COMMAND_WHOIS, r->ident, - silc_server_command_destructor, silc_server_command_identify, silc_server_command_dup(cmd)); cmd->pending = TRUE; @@ -1972,28 +1971,7 @@ SILC_SERVER_CMD_FUNC(identify) SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328); ret = silc_server_command_identify_process(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) -{ - int i; - - for (i = 0; i < strlen(nick); i++) { - if (!isascii(nick[i])) - return TRUE; - if (nick[i] <= 32) return TRUE; - if (nick[i] == ' ') return TRUE; - if (nick[i] == '*') return TRUE; - if (nick[i] == '?') return TRUE; - if (nick[i] == ',') return TRUE; - } - - return FALSE; + silc_server_command_free(cmd); } /* Server side of command NICK. Sets nickname for user. Setting @@ -2007,6 +1985,7 @@ SILC_SERVER_CMD_FUNC(nick) SilcServer server = cmd->server; SilcBuffer packet, nidp, oidp = NULL; SilcClientID *new_id; + uint32 nick_len; char *nick; uint16 ident = silc_command_get_ident(cmd->payload); int nickfail = 0; @@ -2017,16 +1996,15 @@ SILC_SERVER_CMD_FUNC(nick) SILC_SERVER_COMMAND_CHECK(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) { + nick = silc_argument_get_arg_type(cmd->args, 1, &nick_len); + if (nick_len > 128) + nick[128] = '\0'; + if (silc_server_name_bad_chars(nick, nick_len) == TRUE) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK, SILC_STATUS_ERR_BAD_NICKNAME); goto out; } - if (strlen(nick) > 128) - nick[128] = '\0'; - /* Check for same nickname */ if (!strcmp(client->nickname, nick)) { nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); @@ -2103,7 +2081,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd, SilcChannelEntry *gch, uint32 gch_count) { - int i; + int i, k; SilcBuffer packet, idp; SilcChannelEntry entry; SilcCommandStatus status; @@ -2111,27 +2089,34 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd, char *topic; unsigned char usercount[4]; uint32 users; + int valid_lcount = 0, valid_rcount = 0; - for (i = 0; i < lch_count; i++) + 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++) + else + valid_lcount++; + } + for (i = 0; i < gch_count; i++) { if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET) gch[i] = NULL; + else + valid_rcount++; + } status = SILC_STATUS_OK; if ((lch_count + gch_count) > 1) status = SILC_STATUS_LIST_START; /* Local list */ - for (i = 0; i < lch_count; i++) { + for (i = 0, k = 0; i < lch_count; i++) { entry = lch[i]; if (!entry) continue; - if (i >= 1) + if (k >= 1) status = SILC_STATUS_LIST_ITEM; - if (i >= 1 && i == lch_count - 1 && !gch_count) + if (valid_lcount > 1 && k == valid_lcount - 1 && !valid_rcount) status = SILC_STATUS_LIST_END; idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL); @@ -2159,17 +2144,18 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd, packet->len, FALSE); silc_buffer_free(packet); silc_buffer_free(idp); + k++; } /* Global list */ - for (i = 0; i < gch_count; i++) { + for (i = 0, k = 0; i < gch_count; i++) { entry = gch[i]; if (!entry) continue; - if (i >= 1) + if (k >= 1) status = SILC_STATUS_LIST_ITEM; - if (i >= 1 && i == gch_count - 1) + if (valid_rcount > 1 && k == valid_rcount - 1) status = SILC_STATUS_LIST_END; idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL); @@ -2179,7 +2165,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd, memset(usercount, 0, sizeof(usercount)); } else { topic = entry->topic; - users = silc_hash_table_count(entry->user_list); + users = entry->user_count; SILC_PUT32_MSB(users, usercount); } @@ -2197,6 +2183,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd, packet->len, FALSE); silc_buffer_free(packet); silc_buffer_free(idp); + k++; } } @@ -2232,13 +2219,12 @@ SILC_SERVER_CMD_FUNC(list) /* Reprocess this packet after received reply from router */ silc_server_command_pending(server, SILC_COMMAND_LIST, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_list, silc_server_command_dup(cmd)); cmd->pending = TRUE; silc_command_set_ident(cmd->payload, old_ident); silc_buffer_free(tmpbuf); - return; + goto out; } /* Get Channel ID */ @@ -2364,7 +2350,7 @@ SILC_SERVER_CMD_FUNC(topic) idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); /* Send notify about topic change to all clients on the channel */ - silc_server_send_notify_to_channel(server, NULL, channel, TRUE, + silc_server_send_notify_to_channel(server, NULL, channel, FALSE, SILC_NOTIFY_TYPE_TOPIC_SET, 2, idp->data, idp->len, channel->topic, strlen(channel->topic)); @@ -2461,6 +2447,7 @@ SILC_SERVER_CMD_FUNC(invite) tmp = silc_argument_get_arg_type(cmd->args, 2, &len); if (tmp) { char invite[512]; + bool resolve; dest_id = silc_id_payload_parse_id(tmp, len); if (!dest_id) { @@ -2470,11 +2457,12 @@ SILC_SERVER_CMD_FUNC(invite) } /* Get the client entry */ - dest = silc_server_get_client_resolve(server, dest_id); + dest = silc_server_get_client_resolve(server, dest_id, &resolve); if (!dest) { - if (server->server_type != SILC_SERVER) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE, - SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); + if (server->server_type != SILC_SERVER || !resolve) { + silc_server_command_send_status_reply( + cmd, SILC_COMMAND_INVITE, + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); goto out; } @@ -2482,13 +2470,12 @@ SILC_SERVER_CMD_FUNC(invite) receiving the reply to the query. */ silc_server_command_pending(server, SILC_COMMAND_WHOIS, server->cmd_ident, - silc_server_command_destructor, silc_server_command_invite, silc_server_command_dup(cmd)); cmd->pending = TRUE; silc_free(channel_id); silc_free(dest_id); - return; + goto out; } /* Check whether the requested client is already on the channel. */ @@ -2688,6 +2675,7 @@ SILC_SERVER_CMD_FUNC(kill) SilcClientID *client_id; unsigned char *tmp, *comment; uint32 tmp_len, tmp_len2; + bool local; SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2); @@ -2725,9 +2713,11 @@ SILC_SERVER_CMD_FUNC(kill) /* Get the client entry */ remote_client = silc_idlist_find_client_by_id(server->local_list, client_id, TRUE, NULL); + local = TRUE; if (!remote_client) { remote_client = silc_idlist_find_client_by_id(server->global_list, client_id, TRUE, NULL); + local = FALSE; if (!remote_client) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); @@ -2781,9 +2771,17 @@ SILC_SERVER_CMD_FUNC(kill) silc_server_free_client_data(server, sock, remote_client, FALSE, NULL); silc_server_close_connection(server, sock); } else { + /* Update statistics */ + if (remote_client->connection) + server->stat.my_clients--; + if (server->server_type == SILC_ROUTER) + server->stat.cell_clients--; + SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR); + SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR); + /* Remove remote client */ - if (!silc_idlist_del_client(server->global_list, remote_client)) - silc_idlist_del_client(server->local_list, remote_client); + silc_idlist_del_client(local ? server->local_list : + server->global_list, remote_client); } out: @@ -2851,10 +2849,10 @@ SILC_SERVER_CMD_FUNC(info) memset(info_string, 0, sizeof(info_string)); snprintf(info_string, sizeof(info_string), "location: %s server: %s admin: %s <%s>", - server->config->admin_info->location, - server->config->admin_info->server_type, - server->config->admin_info->admin_name, - server->config->admin_info->admin_email); + server->config->server_info->location, + server->config->server_info->server_type, + server->config->server_info->admin, + server->config->server_info->email); server_info = info_string; entry = server->id_entry; @@ -2886,13 +2884,12 @@ SILC_SERVER_CMD_FUNC(info) /* Reprocess this packet after received reply from router */ silc_server_command_pending(server, SILC_COMMAND_INFO, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_info, silc_server_command_dup(cmd)); cmd->pending = TRUE; silc_command_set_ident(cmd->payload, old_ident); silc_buffer_free(tmpbuf); - return; + goto out; } if (!entry && !cmd->pending && !server->standalone) { @@ -2911,13 +2908,12 @@ SILC_SERVER_CMD_FUNC(info) /* Reprocess this packet after received reply from router */ silc_server_command_pending(server, SILC_COMMAND_INFO, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_info, silc_server_command_dup(cmd)); cmd->pending = TRUE; silc_command_set_ident(cmd->payload, old_ident); silc_buffer_free(tmpbuf); - return; + goto out; } } @@ -3016,6 +3012,7 @@ static void silc_server_command_join_channel(SilcServer server, uint16 ident = silc_command_get_ident(cmd->payload); char check[512], check2[512]; bool founder = FALSE; + bool resolve; SILC_LOG_DEBUG(("Start")); @@ -3026,19 +3023,26 @@ static void silc_server_command_join_channel(SilcServer server, if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) { client = (SilcClientEntry)sock->user_data; } else { - client = silc_server_get_client_resolve(server, client_id); + client = silc_server_get_client_resolve(server, client_id, &resolve); if (!client) { if (cmd->pending) goto out; + if (!resolve) { + silc_server_command_send_status_reply( + cmd, SILC_COMMAND_JOIN, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + /* The client info is being resolved. Reprocess this packet after receiving the reply to the query. */ silc_server_command_pending(server, SILC_COMMAND_WHOIS, - server->cmd_ident, NULL, + server->cmd_ident, silc_server_command_join, silc_server_command_dup(cmd)); cmd->pending = TRUE; - return; + goto out; } cmd->pending = FALSE; @@ -3113,8 +3117,7 @@ static void silc_server_command_join_channel(SilcServer server, username and/or hostname is in the ban list the access to the channel is denied. */ if (channel->ban_list) { - if (!channel->ban_list || - silc_string_match(channel->ban_list, check) || + if (silc_string_match(channel->ban_list, check) || silc_string_match(channel->ban_list, check2)) { silc_server_command_send_status_reply( cmd, SILC_COMMAND_JOIN, @@ -3138,10 +3141,8 @@ static void silc_server_command_join_channel(SilcServer server, if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) { /* Get passphrase */ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); - if (tmp) { - passphrase = silc_calloc(tmp_len, sizeof(*passphrase)); - memcpy(passphrase, tmp, tmp_len); - } + if (tmp) + passphrase = silc_memdup(tmp, tmp_len); if (!passphrase || !channel->passphrase || memcmp(passphrase, channel->passphrase, strlen(channel->passphrase))) { @@ -3184,6 +3185,7 @@ static void silc_server_command_join_channel(SilcServer server, chl->channel = channel; silc_hash_table_add(channel->user_list, client, chl); silc_hash_table_add(client->channels, channel, chl); + channel->user_count++; /* Get users on the channel */ silc_server_get_users_on_channel(server, channel, &user_list, &mode_list, @@ -3262,24 +3264,24 @@ static void silc_server_command_join_channel(SilcServer server, /* Distribute the channel key to all backup routers. */ silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0, keyp->data, keyp->len, FALSE, TRUE); + } - /* If client became founder by providing correct founder auth data - notify the mode change to the channel. */ - if (founder) { - SILC_PUT32_MSB(chl->mode, mode); - silc_server_send_notify_to_channel(server, NULL, channel, FALSE, - SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3, - clidp->data, clidp->len, - mode, 4, clidp->data, clidp->len); + /* If client became founder by providing correct founder auth data + notify the mode change to the channel. */ + if (founder) { + SILC_PUT32_MSB(chl->mode, mode); + silc_server_send_notify_to_channel(server, NULL, channel, FALSE, + SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3, + clidp->data, clidp->len, + mode, 4, clidp->data, clidp->len); - /* Set CUMODE notify type to network */ - if (!server->standalone) - silc_server_send_notify_cumode(server, server->router->connection, - server->server_type == SILC_ROUTER ? - TRUE : FALSE, channel, - chl->mode, client->id, SILC_ID_CLIENT, - client->id); - } + /* Set CUMODE notify type to network */ + if (!server->standalone) + silc_server_send_notify_cumode(server, server->router->connection, + server->server_type == SILC_ROUTER ? + TRUE : FALSE, channel, + chl->mode, client->id, SILC_ID_CLIENT, + client->id); } silc_buffer_free(reply); @@ -3319,10 +3321,10 @@ SILC_SERVER_CMD_FUNC(join) } channel_name = tmp; - if (strlen(channel_name) > 256) + if (tmp_len > 256) channel_name[255] = '\0'; - if (silc_server_command_bad_chars(channel_name) == TRUE) { + if (silc_server_name_bad_chars(channel_name, tmp_len) == TRUE) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN, SILC_STATUS_ERR_BAD_CHANNEL); goto out; @@ -3352,16 +3354,8 @@ SILC_SERVER_CMD_FUNC(join) channel_name, NULL); if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) { - /* If this is coming from client the Client ID in the command packet must - be same as the client's ID. */ - if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) { - SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data; - if (!SILC_ID_CLIENT_COMPARE(entry->id, client_id)) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN, - SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); - goto out; - } - } + SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data; + client_id = silc_id_dup(entry->id, SILC_ID_CLIENT); if (!channel || channel->disabled) { /* Channel not found */ @@ -3372,8 +3366,9 @@ SILC_SERVER_CMD_FUNC(join) channel = silc_server_create_new_channel(server, server->id, cipher, hmac, channel_name, TRUE); if (!channel) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN, - SILC_STATUS_ERR_UNKNOWN_ALGORITHM); + silc_server_command_send_status_reply( + cmd, SILC_COMMAND_JOIN, + SILC_STATUS_ERR_UNKNOWN_ALGORITHM); goto out; } @@ -3410,11 +3405,12 @@ SILC_SERVER_CMD_FUNC(join) /* Reprocess this packet after received reply from router */ silc_server_command_pending(server, SILC_COMMAND_JOIN, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_join, silc_server_command_dup(cmd)); cmd->pending = TRUE; - return; + silc_command_set_ident(cmd->payload, old_ident); + silc_buffer_free(tmpbuf); + goto out; } /* We are router and the channel does not seem exist so we will check @@ -3473,11 +3469,17 @@ SILC_SERVER_CMD_FUNC(join) if (cmd->pending && context2) { SilcServerCommandReplyContext reply = (SilcServerCommandReplyContext)context2; + if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) { tmp = silc_argument_get_arg_type(reply->args, 6, NULL); SILC_GET32_MSB(created, tmp); - create_key = FALSE; /* Router returned the key already */ + if (silc_argument_get_arg_type(reply->args, 7, NULL)) + create_key = FALSE; /* Router returned the key already */ } + + if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS && + !silc_hash_table_count(channel->user_list)) + created = TRUE; } /* If the channel does not have global users and is also empty the client @@ -3523,10 +3525,10 @@ SILC_SERVER_CMD_FUNC(motd) idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER); - if (server->config && server->config->motd && - server->config->motd->motd_file) { + if (server->config && server->config->server_info && + server->config->server_info->motd_file) { /* Send motd */ - motd = silc_file_readfile(server->config->motd->motd_file, &motd_len); + motd = silc_file_readfile(server->config->server_info->motd_file, &motd_len); if (!motd) goto out; @@ -3574,13 +3576,12 @@ SILC_SERVER_CMD_FUNC(motd) /* Reprocess this packet after received reply from router */ silc_server_command_pending(server, SILC_COMMAND_MOTD, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_motd, silc_server_command_dup(cmd)); cmd->pending = TRUE; silc_command_set_ident(cmd->payload, old_ident); silc_buffer_free(tmpbuf); - return; + goto out; } if (!entry && !cmd->pending && !server->standalone) { @@ -3599,13 +3600,12 @@ SILC_SERVER_CMD_FUNC(motd) /* Reprocess this packet after received reply from router */ silc_server_command_pending(server, SILC_COMMAND_MOTD, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_motd, silc_server_command_dup(cmd)); cmd->pending = TRUE; silc_command_set_ident(cmd->payload, old_ident); silc_buffer_free(tmpbuf); - return; + goto out; } if (!entry) { @@ -3671,9 +3671,14 @@ SILC_SERVER_CMD_FUNC(umode) goto out; } } else { - if (client->mode & SILC_UMODE_SERVER_OPERATOR) - /* Remove the server operator rights */ + /* Remove the server operator rights */ + if (client->mode & SILC_UMODE_SERVER_OPERATOR) { client->mode &= ~SILC_UMODE_SERVER_OPERATOR; + if (client->connection) + server->stat.my_server_ops--; + if (server->server_type == SILC_ROUTER) + server->stat.server_ops--; + } } if (mask & SILC_UMODE_ROUTER_OPERATOR) { @@ -3684,9 +3689,14 @@ SILC_SERVER_CMD_FUNC(umode) goto out; } } else { - if (client->mode & SILC_UMODE_ROUTER_OPERATOR) - /* Remove the router operator rights */ + /* Remove the router operator rights */ + if (client->mode & SILC_UMODE_ROUTER_OPERATOR) { client->mode &= ~SILC_UMODE_ROUTER_OPERATOR; + if (client->connection) + server->stat.my_router_ops--; + if (server->server_type == SILC_ROUTER) + server->stat.router_ops--; + } } if (mask & SILC_UMODE_GONE) { @@ -3869,22 +3879,22 @@ SILC_SERVER_CMD_FUNC(cmode) /* The mode is removed and we need to generate and distribute new channel key. Clients are not using private channel keys anymore after this. */ - + /* Re-generate channel key */ if (!silc_server_create_channel_key(server, channel, 0)) goto out; - + /* Send the channel key. This sends it to our local clients and if we are normal server to our router as well. */ silc_server_send_channel_key(server, NULL, channel, server->server_type == SILC_ROUTER ? FALSE : !server->standalone); - + cipher = channel->channel_key->cipher->name; hmac = (char *)silc_hmac_get_name(channel->hmac); } } - + if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) { /* User limit is set on channel */ uint32 user_limit; @@ -4097,9 +4107,7 @@ SILC_SERVER_CMD_FUNC(cmode) if (channel->founder_method == SILC_AUTH_PASSWORD) { tmp = silc_auth_get_data(auth, &tmp_len); - channel->founder_passwd = - silc_calloc(tmp_len + 1, sizeof(*channel->founder_passwd)); - memcpy(channel->founder_passwd, tmp, tmp_len); + channel->founder_passwd = silc_memdup(tmp, tmp_len); channel->founder_passwd_len = tmp_len; } else { /* Verify the payload before setting the mode */ @@ -4283,9 +4291,9 @@ SILC_SERVER_CMD_FUNC(cumode) /* If the target client is founder, no one else can change their mode but themselves. */ - if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) { + if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE, - SILC_STATUS_ERR_NOT_YOU); + SILC_STATUS_ERR_NO_CHANNEL_PRIV); goto out; } @@ -4544,7 +4552,7 @@ SILC_SERVER_CMD_FUNC(kick) silc_server_send_notify_kicked(server, server->router->connection, server->server_type == SILC_ROUTER ? TRUE : FALSE, channel, - target_client->id, comment); + target_client->id, client->id, comment); if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) { /* Re-generate channel key */ @@ -4572,8 +4580,9 @@ SILC_SERVER_CMD_FUNC(oper) SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; unsigned char *username, *auth; uint32 tmp_len; - SilcServerConfigSectionAdminConnection *admin; + SilcServerConfigAdmin *admin; SilcIDListData idata = (SilcIDListData)client; + bool result = FALSE; SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2); @@ -4589,10 +4598,10 @@ SILC_SERVER_CMD_FUNC(oper) } /* Get the admin configuration */ - admin = silc_server_config_find_admin(server->config, cmd->sock->ip, + admin = silc_server_config_find_admin(server, cmd->sock->ip, username, client->nickname); if (!admin) { - admin = silc_server_config_find_admin(server->config, cmd->sock->hostname, + admin = silc_server_config_find_admin(server, cmd->sock->hostname, username, client->nickname); if (!admin) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER, @@ -4609,10 +4618,18 @@ SILC_SERVER_CMD_FUNC(oper) goto out; } - /* Verify the authentication data */ - if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, - admin->auth_data, admin->auth_data_len, - idata->hash, client->id, SILC_ID_CLIENT)) { + /* Verify the authentication data. If both passphrase and public key + is set then try both of them. */ + if (admin->passphrase) + result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PASSWORD, + admin->passphrase, admin->passphrase_len, + idata->hash, client->id, SILC_ID_CLIENT); + if (!result && admin->publickey) + result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY, + admin->publickey, 0, + idata->hash, client->id, SILC_ID_CLIENT); + if (!result) { + /* Authentication failed */ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER, SILC_STATUS_ERR_AUTH_FAILED); goto out; @@ -4621,6 +4638,12 @@ SILC_SERVER_CMD_FUNC(oper) /* Client is now server operator */ client->mode |= SILC_UMODE_SERVER_OPERATOR; + /* Update statistics */ + if (client->connection) + server->stat.my_server_ops++; + if (server->server_type == SILC_ROUTER) + server->stat.server_ops++; + /* Send UMODE change to primary router */ if (!server->standalone) silc_server_send_notify_umode(server, server->router->connection, TRUE, @@ -4644,8 +4667,9 @@ SILC_SERVER_CMD_FUNC(silcoper) SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; unsigned char *username, *auth; uint32 tmp_len; - SilcServerConfigSectionAdminConnection *admin; + SilcServerConfigAdmin *admin; SilcIDListData idata = (SilcIDListData)client; + bool result = FALSE; SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2); @@ -4667,10 +4691,10 @@ SILC_SERVER_CMD_FUNC(silcoper) } /* Get the admin configuration */ - admin = silc_server_config_find_admin(server->config, cmd->sock->ip, + admin = silc_server_config_find_admin(server, cmd->sock->ip, username, client->nickname); if (!admin) { - admin = silc_server_config_find_admin(server->config, cmd->sock->hostname, + admin = silc_server_config_find_admin(server, cmd->sock->hostname, username, client->nickname); if (!admin) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER, @@ -4687,11 +4711,19 @@ SILC_SERVER_CMD_FUNC(silcoper) goto out; } - /* Verify the authentication data */ - if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, - admin->auth_data, admin->auth_data_len, - idata->hash, client->id, SILC_ID_CLIENT)) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER, + /* Verify the authentication data. If both passphrase and public key + is set then try both of them. */ + if (admin->passphrase) + result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PASSWORD, + admin->passphrase, admin->passphrase_len, + idata->hash, client->id, SILC_ID_CLIENT); + if (!result && admin->publickey) + result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY, + admin->publickey, 0, + idata->hash, client->id, SILC_ID_CLIENT); + if (!result) { + /* Authentication failed */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER, SILC_STATUS_ERR_AUTH_FAILED); goto out; } @@ -4699,6 +4731,12 @@ SILC_SERVER_CMD_FUNC(silcoper) /* Client is now router operator */ client->mode |= SILC_UMODE_ROUTER_OPERATOR; + /* Update statistics */ + if (client->connection) + server->stat.my_router_ops++; + if (server->server_type == SILC_ROUTER) + server->stat.router_ops++; + /* Send UMODE change to primary router */ if (!server->standalone) silc_server_send_notify_umode(server, server->router->connection, TRUE, @@ -4821,7 +4859,11 @@ SILC_SERVER_CMD_FUNC(ban) } /* Get entry to the channel user list */ - silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl); + if (!silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, + SILC_STATUS_ERR_NOT_ON_CHANNEL); + goto out; + } /* The client must be at least channel operator. */ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) { @@ -4882,7 +4924,7 @@ SILC_SERVER_CMD_FUNC(ban) 2, id, id_len, 3, channel->ban_list, channel->ban_list ? - strlen(channel->ban_list) - 1 : 0); + strlen(channel->ban_list) -1 : 0); silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, packet->data, packet->len, FALSE); @@ -4958,7 +5000,7 @@ SILC_SERVER_CMD_FUNC(close) server->router = NULL; server->standalone = TRUE; } - silc_server_free_sock_user_data(server, sock); + silc_server_free_sock_user_data(server, sock, NULL); silc_server_close_connection(server, sock); out: @@ -5145,15 +5187,13 @@ SILC_SERVER_CMD_FUNC(users) /* Reprocess this packet after received reply */ silc_server_command_pending(server, SILC_COMMAND_USERS, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_users, silc_server_command_dup(cmd)); cmd->pending = TRUE; silc_command_set_ident(cmd->payload, ident); - silc_buffer_free(tmpbuf); silc_free(id); - return; + goto out; } /* Check the global list as well. */ @@ -5236,6 +5276,7 @@ SILC_SERVER_CMD_FUNC(getkey) uint32 tmp_len, pklen; SilcBuffer pk = NULL; SilcIdType id_type; + SilcPublicKey public_key; SILC_LOG_DEBUG(("Start")); @@ -5287,14 +5328,12 @@ SILC_SERVER_CMD_FUNC(getkey) /* Reprocess this packet after received reply from router */ silc_server_command_pending(server, SILC_COMMAND_GETKEY, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_getkey, silc_server_command_dup(cmd)); cmd->pending = TRUE; - silc_command_set_ident(cmd->payload, old_ident); silc_buffer_free(tmpbuf); - return; + goto out; } if (!client) { @@ -5306,11 +5345,12 @@ SILC_SERVER_CMD_FUNC(getkey) /* The client is locally connected, just get the public key and send it back. If they key does not exist then do not send it, send just OK reply */ - if (!client->data.public_key) { + public_key = client->data.public_key; + if (!public_key) { pkdata = NULL; pklen = 0; } else { - tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len); + tmp = silc_pkcs_public_key_encode(public_key, &tmp_len); pk = silc_buffer_alloc(4 + tmp_len); silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk)); silc_buffer_format(pk, @@ -5353,14 +5393,12 @@ SILC_SERVER_CMD_FUNC(getkey) /* Reprocess this packet after received reply from router */ silc_server_command_pending(server, SILC_COMMAND_GETKEY, silc_command_get_ident(cmd->payload), - silc_server_command_destructor, silc_server_command_getkey, silc_server_command_dup(cmd)); cmd->pending = TRUE; - silc_command_set_ident(cmd->payload, old_ident); silc_buffer_free(tmpbuf); - return; + goto out; } if (!server_entry) { @@ -5370,12 +5408,14 @@ SILC_SERVER_CMD_FUNC(getkey) } /* If they key does not exist then do not send it, send just OK reply */ - if (!server_entry->data.public_key) { + public_key = (!server_entry->data.public_key ? + (server_entry == server->id_entry ? server->public_key : + NULL) : server_entry->data.public_key); + if (!public_key) { pkdata = NULL; pklen = 0; } else { - tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, - &tmp_len); + tmp = silc_pkcs_public_key_encode(public_key, &tmp_len); pk = silc_buffer_alloc(4 + tmp_len); silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk)); silc_buffer_format(pk,