7d8fdea5c1f059e28cf8ffd9d779677c8d2c75f4
[silc.git] / apps / silcd / serverid.c
1 /*
2
3   serverid.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "serverincludes.h"
23 #include "server_internal.h"
24
25 /* Creates a Server ID. Newly created Server ID is returned to the
26    new_id argument. */
27
28 void silc_id_create_server_id(const char *ip, SilcUInt16 port, SilcRng rng,
29                               SilcServerID **new_id)
30 {
31   SILC_LOG_DEBUG(("Creating new Server ID"));
32
33   *new_id = silc_calloc(1, sizeof(**new_id));
34
35   /* Create the ID */
36
37   if (!silc_net_addr2bin(ip, (*new_id)->ip.data,
38                          sizeof((*new_id)->ip.data))) {
39     silc_free(*new_id);
40     *new_id = NULL;
41     return;
42   }
43
44   (*new_id)->ip.data_len = silc_net_is_ip4(ip) ? 4 : 16;
45   (*new_id)->port = SILC_SWAB_16(port);
46   (*new_id)->rnd = silc_rng_get_rn16(rng);
47
48   SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(*new_id, SILC_ID_SERVER)));
49 }
50
51 /* Creates Client ID. This assures that there are no collisions in the
52    created Client IDs.  If the collision would occur (meaning that there
53    are 2^8 occurences of the `nickname' this will return FALSE, and the
54    caller must recall the function with different nickname. If this returns
55    TRUE the new ID was created successfully. */
56
57 bool silc_id_create_client_id(SilcServer server,
58                               SilcServerID *server_id, SilcRng rng,
59                               SilcHash md5hash, char *nickname, 
60                               SilcClientID **new_id)
61 {
62   unsigned char hash[16];
63   bool finding = FALSE;
64   char nick[128 + 1];
65
66   SILC_LOG_DEBUG(("Creating new Client ID"));
67
68   *new_id = silc_calloc(1, sizeof(**new_id));
69
70   /* Create hash of the nickanem */
71   memset(nick, 0, sizeof(nick));
72   silc_to_lower(nickname, nick, sizeof(nick) - 1);
73   silc_hash_make(md5hash, nick, strlen(nick), hash);
74
75   /* Create the ID */
76   memcpy((*new_id)->ip.data, server_id->ip.data, server_id->ip.data_len);
77   (*new_id)->ip.data_len = server_id->ip.data_len;
78   (*new_id)->rnd = silc_rng_get_byte(rng);
79   memcpy((*new_id)->hash, hash, CLIENTID_HASH_LEN);
80
81   /* Assure that the ID does not exist already */
82   while (1) {
83     if (!silc_idlist_find_client_by_id(server->local_list, 
84                                        *new_id, FALSE, NULL))
85       if (!silc_idlist_find_client_by_id(server->global_list, 
86                                          *new_id, FALSE, NULL))
87         break;
88
89     /* The ID exists, start increasing the rnd from 0 until we find a
90        ID that does not exist. If we wrap and it still exists then we
91        will return FALSE and the caller must send some other nickname
92        since this cannot be used anymore. */
93     (*new_id)->rnd++;
94
95     if (finding && (*new_id)->rnd == 0)
96       return FALSE;
97
98     if (!finding) {
99       (*new_id)->rnd = 0;
100       finding = TRUE;
101     }
102   }
103
104   SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(*new_id, SILC_ID_CLIENT)));
105
106   return TRUE;
107 }
108
109 /* Creates Channel ID */
110
111 bool silc_id_create_channel_id(SilcServer server,
112                                SilcServerID *router_id, SilcRng rng,
113                                SilcChannelID **new_id)
114 {
115   bool finding = TRUE;
116
117   SILC_LOG_DEBUG(("Creating new Channel ID"));
118
119   *new_id = silc_calloc(1, sizeof(**new_id));
120
121   /* Create the ID */
122   memcpy((*new_id)->ip.data, router_id->ip.data, router_id->ip.data_len);
123   (*new_id)->ip.data_len = router_id->ip.data_len;
124   (*new_id)->port = router_id->port;
125   (*new_id)->rnd = silc_rng_get_rn16(rng);
126
127   /* Assure that the ID does not exist already */
128   while (1) {
129     if (!silc_idlist_find_channel_by_id(server->local_list, 
130                                         *new_id, NULL))
131       break;
132
133     (*new_id)->rnd++;
134     
135     if (finding && (*new_id)->rnd == 0)
136       return FALSE;
137     
138     if (!finding) {
139       (*new_id)->rnd = 0;
140       finding = TRUE;
141     }
142   }
143
144   SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(*new_id, SILC_ID_CHANNEL)));
145
146   return TRUE;
147 }
148
149 /* Checks whether the `server_id' is valid.  It must be based to the
150    IP address provided in the `remote' socket connection. */
151
152 bool silc_id_is_valid_server_id(SilcServer server,
153                                 SilcServerID *server_id,
154                                 SilcSocketConnection remote)
155 {
156   unsigned char ip[16];
157
158   if (!silc_net_addr2bin(remote->ip, ip, sizeof(ip)))
159     return FALSE;
160
161   if (silc_net_is_ip4(remote->ip)) {
162     if (!memcmp(server_id->ip.data, ip, 4))
163       return TRUE;
164   } else {
165     if (!memcmp(server_id->ip.data, ip, 16))
166       return TRUE;
167   }
168
169   return FALSE;
170 }