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