updates.
[silc.git] / apps / silcd / command.c
index 0d222bd360af1463a468fb2f1ef2cafe70341521..be933055b0333eed2c5de5c38d95efa221231de1 100644 (file)
@@ -187,6 +187,8 @@ void silc_server_command_process(SilcServer server,
   SilcServerCommand *cmd;
   SilcCommand command;
 
+  SILC_LOG_DEBUG(("Start"));
+
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
   ctx = silc_server_command_alloc();
@@ -3174,6 +3176,8 @@ static void silc_server_command_join_channel(SilcServer server,
   char check[512], check2[512];
   bool founder = FALSE;
   bool resolve;
+  unsigned char *fkey = NULL;
+  SilcUInt32 fkey_len = 0;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -3221,17 +3225,10 @@ static void silc_server_command_join_channel(SilcServer server,
     if (channel->founder_key && idata->public_key &&
        silc_pkcs_public_key_compare(channel->founder_key, 
                                     idata->public_key)) {
-      void *auth_data = (channel->founder_method == SILC_AUTH_PASSWORD ?
-                        (void *)channel->founder_passwd : 
-                        (void *)channel->founder_key);
-      SilcUInt32 auth_data_len = 
-       (channel->founder_method == SILC_AUTH_PASSWORD ?
-        channel->founder_passwd_len : 0);
-
       /* Check whether the client is to become founder */
-      if (silc_auth_verify_data(auth, auth_len, channel->founder_method, 
-                               auth_data, auth_data_len,
-                               idata->hash, client->id, SILC_ID_CLIENT)) {
+      if (silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
+                               channel->founder_key, 0, server->sha1hash,
+                               client->id, SILC_ID_CLIENT)) {
        umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
        founder = TRUE;
       }
@@ -3350,6 +3347,7 @@ static void silc_server_command_join_channel(SilcServer server,
   silc_hash_table_add(channel->user_list, client, chl);
   silc_hash_table_add(client->channels, channel, chl);
   channel->user_count++;
+  channel->disabled = FALSE;
 
   /* Get users on the channel */
   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
@@ -3376,9 +3374,12 @@ static void silc_server_command_join_channel(SilcServer server,
     silc_free(tmp);
   }
 
+  if (channel->founder_key)
+    fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
+
   reply = 
     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
-                                        SILC_STATUS_OK, 0, ident, 13,
+                                        SILC_STATUS_OK, 0, ident, 14,
                                         2, channel->channel_name,
                                         strlen(channel->channel_name),
                                         3, chidp->data, chidp->len,
@@ -3402,7 +3403,8 @@ static void silc_server_command_join_channel(SilcServer server,
                                         12, tmp3, 4,
                                         13, user_list->data, user_list->len,
                                         14, mode_list->data, 
-                                        mode_list->len);
+                                        mode_list->len,
+                                        15, fkey, fkey_len);
 
   /* Send command reply */
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
@@ -3430,24 +3432,25 @@ 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, 4,
+                                        clidp->data, clidp->len,
+                                        mode, 4, clidp->data, clidp->len,
+                                        fkey, fkey_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, channel->founder_key);
+    }
   }
 
   silc_buffer_free(reply);
@@ -3456,6 +3459,7 @@ static void silc_server_command_join_channel(SilcServer server,
   silc_buffer_free(keyp);
   silc_buffer_free(user_list);
   silc_buffer_free(mode_list);
+  silc_free(fkey);
 
  out:
   silc_free(passphrase);
@@ -3526,7 +3530,8 @@ SILC_SERVER_CMD_FUNC(join)
     SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
     client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
 
-    if (!channel || channel->disabled) {
+    if (!channel || 
+       (channel->disabled && server->server_type != SILC_ROUTER)) {
       /* Channel not found */
 
       /* If we are standalone server we don't have a router, we just create 
@@ -3649,13 +3654,14 @@ SILC_SERVER_CMD_FUNC(join)
     }
 
     if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
-       !silc_hash_table_count(channel->user_list))
+       !channel->disabled && !silc_hash_table_count(channel->user_list))
       created = TRUE;
   }
 
   /* If the channel does not have global users and is also empty the client
      will be the channel founder and operator. */
-  if (!channel->global_users && !silc_hash_table_count(channel->user_list))
+  if (!channel->disabled &&
+      !channel->global_users && !silc_hash_table_count(channel->user_list))
     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
 
   /* Join to the channel */
@@ -3898,6 +3904,9 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcUInt32 mode_mask = 0, tmp_len, tmp_len2;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   bool set_mask = FALSE;
+  SilcPublicKey founder_key = NULL;
+  unsigned char *fkey = NULL;
+  SilcUInt32 fkey_len = 0;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 7);
 
@@ -4184,46 +4193,41 @@ SILC_SERVER_CMD_FUNC(cmode)
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
        /* Set the founder authentication */
-       SilcAuthPayload auth;
-       
        tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
        if (!tmp) {
-         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+         silc_server_command_send_status_reply(
+                                    cmd, SILC_COMMAND_CMODE,
                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
          goto out;
        }
 
-       auth = silc_auth_payload_parse(tmp, tmp_len);
-       if (!auth) {
+       /* Verify the payload before setting the mode */
+       if (!silc_auth_verify_data(tmp, tmp_len, SILC_AUTH_PUBLIC_KEY, 
+                                  idata->public_key, 0, server->sha1hash,
+                                  client->id, SILC_ID_CLIENT)) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+                                               SILC_STATUS_ERR_AUTH_FAILED,
+                                               0);
          goto out;
        }
 
        /* Save the public key */
-       tmp = silc_pkcs_public_key_encode(idata->public_key, &tmp_len);
-       silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
-       silc_free(tmp);
-       
-       channel->founder_method = silc_auth_get_method(auth);
-
-       if (channel->founder_method == SILC_AUTH_PASSWORD) {
-         tmp = silc_auth_get_data(auth, &tmp_len);
-         channel->founder_passwd = silc_memdup(tmp, tmp_len);
-         channel->founder_passwd_len = tmp_len;
-       } else {
-         /* Verify the payload before setting the mode */
-         if (!silc_auth_verify(auth, channel->founder_method, 
-                               channel->founder_key, 0, idata->hash,
-                               client->id, SILC_ID_CLIENT)) {
-           silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                                 SILC_STATUS_ERR_AUTH_FAILED,
-                                                 0);
-           goto out;
-         }
-       }
+       channel->founder_key = silc_pkcs_public_key_copy(idata->public_key);
+        if (!channel->founder_key) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                               SILC_STATUS_ERR_AUTH_FAILED,
+                                               0);
+         goto out;
+        }
 
-       silc_auth_payload_free(auth);
+       founder_key = channel->founder_key;
+       fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
+        if (!fkey) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                               SILC_STATUS_ERR_AUTH_FAILED,
+                                               0);
+         goto out;
+        }
       }
     }
   } else {
@@ -4231,10 +4235,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
        if (channel->founder_key)
          silc_pkcs_public_key_free(channel->founder_key);
-       if (channel->founder_passwd) {
-         silc_free(channel->founder_passwd);
-         channel->founder_passwd = NULL;
-       }
+       channel->founder_key = NULL;
       }
     }
   }
@@ -4245,13 +4246,14 @@ SILC_SERVER_CMD_FUNC(cmode)
   /* Send CMODE_CHANGE notify. */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 5,
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 6,
                                     cidp->data, cidp->len, 
                                     tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
                                     hmac, hmac ? strlen(hmac) : 0,
                                     passphrase, passphrase ? 
-                                    strlen(passphrase) : 0);
+                                    strlen(passphrase) : 0,
+                                    fkey, fkey_len);
 
   /* Set CMODE notify type to network */
   if (!server->standalone)
@@ -4259,7 +4261,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                  server->server_type == SILC_ROUTER ? 
                                  TRUE : FALSE, channel,
                                  mode_mask, client->id, SILC_ID_CLIENT,
-                                 cipher, hmac, passphrase);
+                                 cipher, hmac, passphrase, founder_key);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
@@ -4273,6 +4275,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   silc_buffer_free(cidp);
 
  out:
+  silc_free(fkey);
   silc_free(channel_id);
   silc_server_command_free(cmd);
 }
@@ -4295,6 +4298,9 @@ SILC_SERVER_CMD_FUNC(cumode)
   SilcUInt32 target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
   int notify = FALSE;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+  SilcPublicKey founder_key = NULL;
+  unsigned char *fkey = NULL;
+  SilcUInt32 fkey_len = 0;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
 
@@ -4406,40 +4412,42 @@ SILC_SERVER_CMD_FUNC(cumode)
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       /* The client tries to claim the founder rights. */
       unsigned char *tmp_auth;
-      SilcUInt32 tmp_auth_len, auth_len;
-      void *auth;
-      
+      SilcUInt32 tmp_auth_len;
+
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
          !channel->founder_key || !idata->public_key ||
          !silc_pkcs_public_key_compare(channel->founder_key, 
                                        idata->public_key)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                             SILC_STATUS_ERR_NOT_YOU, 0);
+                                             SILC_STATUS_ERR_AUTH_FAILED, 0);
        goto out;
       }
 
       tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
       if (!tmp_auth) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+                                             SILC_STATUS_ERR_AUTH_FAILED, 0);
        goto out;
       }
 
-      auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
-             (void *)channel->founder_passwd : (void *)channel->founder_key);
-      auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
-                 channel->founder_passwd_len : 0);
-      
-      if (!silc_auth_verify_data(tmp_auth, tmp_auth_len,
-                                channel->founder_method, auth, auth_len,
-                                idata->hash, client->id, SILC_ID_CLIENT)) {
+      /* Verify the authentication payload */
+      if (!silc_auth_verify_data(tmp_auth, tmp_auth_len, SILC_AUTH_PUBLIC_KEY,
+                                channel->founder_key, 0, server->sha1hash,
+                                client->id, SILC_ID_CLIENT)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                              SILC_STATUS_ERR_AUTH_FAILED, 0);
        goto out;
       }
-      
+
       sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
       notify = TRUE;
+      founder_key = channel->founder_key;
+      fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
+      if (!fkey) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_AUTH_FAILED, 0);
+       goto out;
+      }
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
@@ -4563,10 +4571,11 @@ SILC_SERVER_CMD_FUNC(cumode)
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
     silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
-                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
                                       idp->data, idp->len,
                                       tmp_mask, 4, 
-                                      tmp_id, tmp_len);
+                                      tmp_id, tmp_len,
+                                      fkey, fkey_len);
 
     /* Set CUMODE notify type to network */
     if (!server->standalone)
@@ -4575,7 +4584,7 @@ SILC_SERVER_CMD_FUNC(cumode)
                                     TRUE : FALSE, channel,
                                     target_mask, client->id, 
                                     SILC_ID_CLIENT,
-                                    target_client->id);
+                                    target_client->id, founder_key);
   }
 
   /* Send command reply to sender */
@@ -4593,6 +4602,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   silc_buffer_free(idp);
 
  out:
+  silc_free(fkey);
   silc_server_command_free(cmd);
 }
 
@@ -4902,6 +4912,8 @@ SILC_SERVER_CMD_FUNC(detach)
   /* Send the user mode notify to notify that client is detached */
   client->mode |= SILC_UMODE_DETACHED;
   client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
+  client->last_command = 0;
+  client->fast_command = 0;
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection,
                                  server->server_type == SILC_SERVER ?
@@ -5462,7 +5474,8 @@ SILC_SERVER_CMD_FUNC(users)
     channel = silc_idlist_find_channel_by_name(server->local_list, 
                                               channel_name, NULL);
 
-  if (!channel || channel->disabled || !channel->users_resolved) {
+  if (!channel || (!server->standalone && (channel->disabled || 
+                   !channel->users_resolved))) {
     if (server->server_type != SILC_ROUTER && !server->standalone &&
        !cmd->pending) {
       SilcBuffer tmpbuf;
@@ -5515,8 +5528,12 @@ SILC_SERVER_CMD_FUNC(users)
   }
 
   /* Get the users list */
-  silc_server_get_users_on_channel(server, channel, &client_id_list,
-                                  &client_mode_list, &list_count);
+  if (!silc_server_get_users_on_channel(server, channel, &client_id_list,
+                                       &client_mode_list, &list_count)) {
+    list_count = 0;
+    client_id_list = NULL;
+    client_mode_list = NULL;
+  }
 
   /* List count */
   SILC_PUT32_MSB(list_count, lc);
@@ -5527,17 +5544,23 @@ SILC_SERVER_CMD_FUNC(users)
                                                SILC_STATUS_OK, 0, ident, 4,
                                                2, idp->data, idp->len,
                                                3, lc, 4,
-                                               4, client_id_list->data,
-                                               client_id_list->len,
-                                               5, client_mode_list->data,
-                                               client_mode_list->len);
+                                               4, client_id_list ? 
+                                               client_id_list->data : NULL,
+                                               client_id_list ?
+                                               client_id_list->len : 0,
+                                               5, client_mode_list ?
+                                               client_mode_list->data : NULL,
+                                               client_mode_list ?
+                                               client_mode_list->len : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
   silc_buffer_free(idp);
   silc_buffer_free(packet);
-  silc_buffer_free(client_id_list);
-  silc_buffer_free(client_mode_list);
+  if (client_id_list)
+    silc_buffer_free(client_id_list);
+  if (client_mode_list)
+    silc_buffer_free(client_mode_list);
   silc_free(id);
 
  out: