updates.
[silc.git] / apps / silcd / packet_receive.c
index fe420c61f635e38d5e9fb6557c004556fd55ce0b..f207289903b432154ca047fc228dcecbcec00437 100644 (file)
@@ -278,6 +278,9 @@ void silc_server_notify(SilcServer server,
 
     client->data.registered = FALSE;
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+    server->stat.clients--;
+    if (server->server_type == SILC_ROUTER)
+      server->stat.cell_clients--;
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -313,7 +316,7 @@ void silc_server_notify(SilcServer server,
 
     if (channel->topic)
       silc_free(channel->topic);
-    channel->topic = silc_calloc(tmp_len, sizeof(*channel->topic));
+    channel->topic = silc_calloc(tmp_len + 1, sizeof(*channel->topic));
     memcpy(channel->topic, tmp, tmp_len);
 
     /* Send the same notify to the channel */
@@ -698,9 +701,11 @@ void silc_server_notify(SilcServer server,
       }
       if (users_modes) {
        silc_buffer_push(users_modes, users_modes->data - users_modes->head);
-       silc_server_packet_send(server, sock,
-                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                               users_modes->data, users_modes->len, FALSE);
+       silc_server_packet_send_dest(server, sock,
+                                    SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                                    channel->id, SILC_ID_CHANNEL,
+                                    users_modes->data, 
+                                    users_modes->len, FALSE);
        silc_buffer_free(users_modes);
       }
     }
@@ -1277,6 +1282,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   char *username = NULL, *realname = NULL, *id_string;
   uint32 id_len;
   int ret;
+  char *hostname, *nickname;
 
   SILC_LOG_DEBUG(("Creating new client"));
 
@@ -1319,16 +1325,102 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     return NULL;
   }
 
+  if (strlen(username) > 128)
+    username[127] = '\0';
+
+  nickname = strdup(username);
+
+  /* Make sanity checks for the hostname of the client. If the hostname
+     is provided in the `username' check that it is the same than the
+     resolved hostname, or if not resolved the hostname that appears in
+     the client's public key. If the hostname is not present then put
+     it from the resolved name or from the public key. */
+  if (strchr(username, '@')) {
+    SilcPublicKeyIdentifier pident;
+    int tlen = strcspn(username, "@");
+    char *phostname = NULL;
+
+    hostname = silc_calloc((strlen(username) - tlen) + 1, sizeof(char));
+    memcpy(hostname, username + tlen + 1, strlen(username) - tlen - 1);
+
+    if (strcmp(sock->hostname, sock->ip) && 
+       strcmp(sock->hostname, hostname)) {
+      silc_free(username);
+      silc_free(hostname);
+      if (realname)
+       silc_free(realname);
+      silc_server_disconnect_remote(server, sock, 
+                                   "Server closed connection: "
+                                   "Incomplete client information");
+      return NULL;
+    }
+    
+    pident = silc_pkcs_decode_identifier(client->data.public_key->identifier);
+    if (pident) {
+      phostname = strdup(pident->host);
+      silc_pkcs_free_identifier(pident);
+    }
+
+    if (!strcmp(sock->hostname, sock->ip) && 
+       phostname && strcmp(phostname, hostname)) {
+      silc_free(username);
+      silc_free(hostname);
+      if (phostname)
+       silc_free(phostname);
+      if (realname)
+       silc_free(realname);
+      silc_server_disconnect_remote(server, sock, 
+                                   "Server closed connection: "
+                                   "Incomplete client information");
+      return NULL;
+    }
+    
+    if (phostname)
+      silc_free(phostname);
+  } else {
+    /* The hostname is not present, add it. */
+    char *newusername;
+    /* XXX For now we cannot take the host name from the public key since
+       they are not trusted or we cannot verify them as trusted. Just take
+       what the resolved name or address is. */
+#if 0
+    if (strcmp(sock->hostname, sock->ip)) {
+#endif
+      newusername = silc_calloc(strlen(username) + 
+                               strlen(sock->hostname) + 2,
+                               sizeof(*newusername));
+      strncat(newusername, username, strlen(username));
+      strncat(newusername, "@", 1);
+      strncat(newusername, sock->hostname, strlen(sock->hostname));
+      silc_free(username);
+      username = newusername;
+#if 0
+    } else {
+      SilcPublicKeyIdentifier pident = 
+       silc_pkcs_decode_identifier(client->data.public_key->identifier);
+      
+      if (pident) {
+       newusername = silc_calloc(strlen(username) + 
+                                 strlen(pident->host) + 2,
+                                 sizeof(*newusername));
+       strncat(newusername, username, strlen(username));
+       strncat(newusername, "@", 1);
+       strncat(newusername, pident->host, strlen(pident->host));
+       silc_free(username);
+       username = newusername;
+       silc_pkcs_free_identifier(pident);
+      }
+    }
+#endif
+  }
+
   /* Create Client ID */
   silc_id_create_client_id(server->id, server->rng, server->md5hash,
                           username, &client_id);
 
-  if (strlen(username) > 128)
-    username[127] = '\0';
-
   /* Update client entry */
   idata->registered = TRUE;
-  client->nickname = strdup(username);
+  client->nickname = nickname;
   client->username = username;
   client->userinfo = realname ? realname : strdup(" ");
   client->id = client_id;
@@ -1361,8 +1453,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   /* Send some nice info to the client */
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                         ("Welcome to the SILC Network %s@%s",
-                          username, sock->hostname));
+                         ("Welcome to the SILC Network %s",
+                          username));
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Your host is %s, running version %s",
                           server->config->server_info->server_name,
@@ -1791,6 +1883,9 @@ void silc_server_new_channel(SilcServer server,
        return;
       }
 
+      /* Get the mode and set it to the channel */
+      channel->mode = silc_channel_get_mode(payload);
+
       /* Send the new channel key to the server */
       chk = silc_channel_key_payload_encode(id_len, id,
                                            strlen(channel->channel_key->
@@ -1871,9 +1966,11 @@ void silc_server_new_channel(SilcServer server,
       }
       if (users_modes) {
        silc_buffer_push(users_modes, users_modes->data - users_modes->head);
-       silc_server_packet_send(server, sock,
-                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                               users_modes->data, users_modes->len, FALSE);
+       silc_server_packet_send_dest(server, sock,
+                                    SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                                    channel->id, SILC_ID_CHANNEL,
+                                    users_modes->data, 
+                                    users_modes->len, FALSE);
        silc_buffer_free(users_modes);
       }
     }