Merge commit 'origin/silc.1.1.branch'
[silc.git] / apps / silcd / serverid.c
1 /*
2
3   serverid.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 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 = 0xff;
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 SilcBool silc_id_create_client_id(SilcServer server,
58                                   SilcServerID *server_id, SilcRng rng,
59                                   SilcHash md5hash,
60                                   unsigned char *nickname, SilcUInt32 nick_len,
61                                   SilcClientID **new_id)
62 {
63   unsigned char hash[16];
64   SilcBool finding = FALSE;
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 nickname (it's already checked as valid identifier
71      string). */
72   silc_hash_make(md5hash, nickname, nick_len, hash);
73
74   /* Create the ID */
75   memcpy((*new_id)->ip.data, server_id->ip.data, server_id->ip.data_len);
76   (*new_id)->ip.data_len = server_id->ip.data_len;
77   (*new_id)->rnd = silc_rng_get_byte(rng);
78   memcpy((*new_id)->hash, hash, CLIENTID_HASH_LEN);
79
80   /* Assure that the ID does not exist already */
81   while (1) {
82     if (!silc_idlist_find_client_by_id(server->local_list,
83                                        *new_id, FALSE, NULL))
84       if (!silc_idlist_find_client_by_id(server->global_list,
85                                          *new_id, FALSE, NULL))
86         break;
87
88     /* The ID exists, start increasing the rnd from 0 until we find a
89        ID that does not exist. If we wrap and it still exists then we
90        will return FALSE and the caller must send some other nickname
91        since this cannot be used anymore. */
92     (*new_id)->rnd++;
93
94     if (finding && (*new_id)->rnd == 0)
95       return FALSE;
96
97     if (!finding) {
98       (*new_id)->rnd = 0;
99       finding = TRUE;
100     }
101   }
102
103   SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(*new_id, SILC_ID_CLIENT)));
104
105   return TRUE;
106 }
107
108 /* Creates Channel ID */
109
110 SilcBool silc_id_create_channel_id(SilcServer server,
111                                    SilcServerID *router_id, SilcRng rng,
112                                    SilcChannelID **new_id)
113 {
114   SilcBool finding = TRUE;
115
116   SILC_LOG_DEBUG(("Creating new Channel ID"));
117
118   *new_id = silc_calloc(1, sizeof(**new_id));
119
120   /* Create the ID */
121   memcpy((*new_id)->ip.data, router_id->ip.data, router_id->ip.data_len);
122   (*new_id)->ip.data_len = router_id->ip.data_len;
123   (*new_id)->port = router_id->port;
124   (*new_id)->rnd = silc_rng_get_rn16(rng);
125
126   /* Assure that the ID does not exist already */
127   while (1) {
128     if (!silc_idlist_find_channel_by_id(server->local_list,
129                                         *new_id, NULL))
130       break;
131
132     (*new_id)->rnd++;
133
134     if (finding && (*new_id)->rnd == 0)
135       return FALSE;
136
137     if (!finding) {
138       (*new_id)->rnd = 0;
139       finding = TRUE;
140     }
141   }
142
143   SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(*new_id, SILC_ID_CHANNEL)));
144
145   return TRUE;
146 }
147
148 /* Checks whether the `server_id' is valid.  It must be based to the
149    IP address provided in the `remote' socket connection. */
150
151 SilcBool silc_id_is_valid_server_id(SilcServer server,
152                                     SilcServerID *server_id,
153                                     SilcPacketStream remote)
154 {
155   unsigned char ip[16];
156   const char *remote_ip;
157   SilcStream stream = silc_packet_stream_get_stream(remote);
158
159   silc_socket_stream_get_info(stream, NULL, NULL, &remote_ip, NULL);
160   if (!silc_net_addr2bin(remote_ip, ip, sizeof(ip)))
161     return FALSE;
162
163   if (silc_net_is_ip4(remote_ip)) {
164     if (!memcmp(server_id->ip.data, ip, 4))
165       return TRUE;
166   } else {
167     if (!memcmp(server_id->ip.data, ip, 16))
168       return TRUE;
169   }
170
171   return FALSE;
172 }