X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fpacket_receive.c;h=03fcde91e8430f7cb9e16d2072bb163e618e7920;hb=f82024f04b73e3b80ddd6c590699206d3dc5c1eb;hp=20dd6210af285df4be1fdf46d33a2bbc79ad3c34;hpb=a32eecc529a135726587f17d667badb70605c405;p=silc.git diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 20dd6210..03fcde91 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -575,9 +575,6 @@ void silc_server_notify(SilcServer server, FALSE : !server->standalone); } - /* Change mode */ - channel->mode = mode; - /* Get the hmac */ tmp = silc_argument_get_arg_type(args, 4, &tmp_len); if (tmp) { @@ -604,6 +601,48 @@ void silc_server_notify(SilcServer server, channel->passphrase = silc_memdup(tmp, tmp_len); } + /* Get founder public key */ + tmp = silc_argument_get_arg_type(args, 6, &tmp_len); + if (tmp && mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { + if (channel->founder_key) + silc_pkcs_public_key_free(channel->founder_key); + channel->founder_key = NULL; + silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key); + + if (!channel->founder_key || + (client && client->data.public_key && + server->server_type == SILC_ROUTER && + !silc_pkcs_public_key_compare(channel->founder_key, + client->data.public_key))) { + /* A really buggy server isn't checking public keys correctly. + It's not possible that the mode setter and founder wouldn't + have same public key. */ + SILC_LOG_DEBUG(("Enforcing sender to change channel mode")); + + mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH; + silc_server_send_notify_cmode(server, sock, FALSE, channel, + mode, server->id, SILC_ID_SERVER, + channel->cipher, + channel->hmac_name, + channel->passphrase, NULL); + if (channel->founder_key) + silc_pkcs_public_key_free(channel->founder_key); + channel->founder_key = NULL; + } else if (!client->data.public_key) { + client->data.public_key = + silc_pkcs_public_key_copy(channel->founder_key); + } + } + + /* Change mode */ + channel->mode = mode; + + if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && + channel->founder_key) { + silc_pkcs_public_key_free(channel->founder_key); + channel->founder_key = NULL; + } + break; case SILC_NOTIFY_TYPE_CUMODE_CHANGE: @@ -713,66 +752,53 @@ void silc_server_notify(SilcServer server, } } - /* Get entry to the channel user list */ - silc_hash_table_list(channel->user_list, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chl)) { - /* If the mode is channel founder and we already find a client - to have that mode on the channel we will enforce the sender - to change the channel founder mode away. There can be only one - channel founder on the channel. */ - if (server->server_type == SILC_ROUTER && - mode & SILC_CHANNEL_UMODE_CHANFO && - chl->mode & SILC_CHANNEL_UMODE_CHANFO) { - SilcBuffer idp; - unsigned char cumode[4]; - - if (chl->client == client && chl->mode == mode) { - notify_sent = TRUE; - break; - } - + if (mode & SILC_CHANNEL_UMODE_CHANFO && + !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) && + server->server_type == SILC_ROUTER) { + /* Check whether this client is allowed to be channel founder on + this channel. */ + + /* If channel doesn't have founder auth mode then it's impossible + that someone would be getting founder rights with CUMODE command. + In that case there already either is founder or there isn't + founder at all on the channel. */ + if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) { + /* Force the mode to not have founder mode */ mode &= ~SILC_CHANNEL_UMODE_CHANFO; - silc_server_send_notify_cumode(server, sock, FALSE, channel, mode, - client2->id, SILC_ID_CLIENT, - client2->id); - - idp = silc_id_payload_encode(client2->id, SILC_ID_CLIENT); - SILC_PUT32_MSB(mode, cumode); - silc_server_send_notify_to_channel(server, sock, channel, FALSE, - SILC_NOTIFY_TYPE_CUMODE_CHANGE, - 3, idp->data, idp->len, - cumode, 4, - idp->data, idp->len); - silc_buffer_free(idp); + silc_server_force_cumode_change(server, sock, channel, chl, mode); notify_sent = TRUE; - - /* Force the mode change if we alredy set the mode */ - if (chl2) { - chl2->mode = mode; - silc_free(channel_id); - silc_hash_table_list_reset(&htl); - goto out; - } + break; } - - if (chl->client == client2) { - if (chl->mode == mode) { + + /* Get the founder of the channel and if found then this client + cannot be the founder since there already is one. */ + silc_hash_table_list(channel->user_list, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chl2)) + if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) { + mode &= ~SILC_CHANNEL_UMODE_CHANFO; + silc_server_force_cumode_change(server, sock, channel, chl, mode); notify_sent = TRUE; break; } + silc_hash_table_list_reset(&htl); + if (!(mode & SILC_CHANNEL_UMODE_CHANFO)) + break; + + /* XXX Founder not found of the channel. Since the founder auth mode + is set on the channel now check whether this is the client that + originally set the mode. If we don't have the public key it + is resolved first. + if (!silc_pkcs_public_key_compare(channel->founder_key, + client->data.public_key)) + */ + + } - SILC_LOG_DEBUG(("Changing the channel user mode")); + SILC_LOG_DEBUG(("Changing the channel user mode")); + + /* Change the mode */ + chl->mode = mode; - /* Change the mode */ - chl->mode = mode; - if (!(mode & SILC_CHANNEL_UMODE_CHANFO)) - break; - - chl2 = chl; - } - } - silc_hash_table_list_reset(&htl); - /* Send the same notify to the channel */ if (!notify_sent) silc_server_packet_send_to_channel(server, sock, channel, @@ -2627,14 +2653,14 @@ void silc_server_new_channel(SilcServer server, SILC_LOG_DEBUG(("Forcing the server to change channel mode")); silc_server_send_notify_cmode(server, sock, FALSE, channel, channel->mode, server->id, - SILC_ID_SERVER, - channel->cipher, channel->hmac_name, - channel->passphrase); + SILC_ID_SERVER, channel->cipher, + channel->hmac_name, + channel->passphrase, + channel->founder_key); } /* Create new key for the channel and send it to the server and everybody else possibly on the channel. */ - if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) { if (!silc_server_create_channel_key(server, channel, 0)) return;