f9e6ff85d4d061dacf707b017a6593613629f86b
[silc.git] / lib / silccore / silcchannel.c
1 /*
2
3   silcchannel.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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 /* Channel Payload, Channel Message Payload and Channel Key Payload 
21    implementations. */
22 /* $Id$ */
23
24 #include "silcincludes.h"
25 #include "silcchannel.h"
26 #include "silcchannel_i.h"
27
28 /* Parses channel payload returning new channel payload structure. */
29
30 SilcChannelPayload silc_channel_payload_parse(const unsigned char *payload,
31                                               SilcUInt32 payload_len)
32 {
33   SilcBufferStruct buffer;
34   SilcChannelPayload newp;
35   int ret;
36
37   SILC_LOG_DEBUG(("Parsing channel payload"));
38
39   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
40   newp = silc_calloc(1, sizeof(*newp));
41   if (!newp)
42     return NULL;
43
44   /* Parse the Channel Payload. Ignore the padding. */
45   ret = silc_buffer_unformat(&buffer,
46                              SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name, 
47                                                          &newp->name_len),
48                              SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id, 
49                                                          &newp->id_len),
50                              SILC_STR_UI_INT(&newp->mode),
51                              SILC_STR_END);
52   if (ret == -1)
53     goto err;
54
55   if ((newp->name_len < 1 || newp->name_len > buffer.len - 8) ||
56       (newp->id_len < 1 || newp->id_len > buffer.len - 8) ||
57       (newp->id_len + newp->name_len > buffer.len - 8)) {
58     SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
59     goto err;
60   }
61
62   return newp;
63
64  err:
65   silc_channel_payload_free(newp);
66   return NULL;
67 }
68
69 /* Parses list of channel payloads returning list of payloads. */
70
71 SilcDList silc_channel_payload_parse_list(const unsigned char *payload,
72                                           SilcUInt32 payload_len)
73 {
74   SilcBufferStruct buffer;
75   SilcDList list;
76   SilcChannelPayload newp;
77   int len, ret;
78
79   SILC_LOG_DEBUG(("Parsing channel payload list"));
80
81   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
82   list = silc_dlist_init();
83
84   while (buffer.len) {
85     newp = silc_calloc(1, sizeof(*newp));
86     if (!newp)
87       goto err;
88     ret = silc_buffer_unformat(&buffer,
89                                SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name, 
90                                                            &newp->name_len),
91                                SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id, 
92                                                            &newp->id_len),
93                                SILC_STR_UI_INT(&newp->mode),
94                                SILC_STR_END);
95     if (ret == -1)
96       goto err;
97
98     if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
99         (newp->id_len < 1 || newp->id_len > buffer.len)) {
100       SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
101       goto err;
102     }
103
104     len = 2 + newp->name_len + 2 + newp->id_len + 4;
105     if (buffer.len < len)
106       break;
107     silc_buffer_pull(&buffer, len);
108
109     silc_dlist_add(list, newp);
110   }
111   
112   return list;
113
114  err:
115   silc_channel_payload_list_free(list);
116   return NULL;
117 }
118
119 /* Encode new channel payload and returns it as buffer. */
120
121 SilcBuffer silc_channel_payload_encode(const unsigned char *channel_name,
122                                        SilcUInt16 channel_name_len,
123                                        const unsigned char *channel_id,
124                                        SilcUInt32 channel_id_len,
125                                        SilcUInt32 mode)
126 {
127   SilcBuffer buffer;
128
129   SILC_LOG_DEBUG(("Encoding message payload"));
130
131   buffer = silc_buffer_alloc_size(2 + channel_name_len + 2 + 
132                                   channel_id_len + 4);
133   if (!buffer)
134     return NULL;
135
136   /* Encode the Channel Payload */
137   silc_buffer_format(buffer, 
138                      SILC_STR_UI_SHORT(channel_name_len),
139                      SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
140                      SILC_STR_UI_SHORT(channel_id_len),
141                      SILC_STR_UI_XNSTRING(channel_id, channel_id_len),
142                      SILC_STR_UI_INT(mode),
143                      SILC_STR_END);
144
145   return buffer;
146 }
147
148 /* Frees Channel Payload */
149
150 void silc_channel_payload_free(SilcChannelPayload payload)
151 {
152   silc_free(payload->channel_name);
153   silc_free(payload->channel_id);
154   silc_free(payload);
155 }
156
157 /* Free's list of Channel Payloads */
158
159 void silc_channel_payload_list_free(SilcDList list)
160 {
161   SilcChannelPayload entry;
162
163   silc_dlist_start(list);
164   while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
165     silc_free(entry->channel_name);
166     silc_free(entry->channel_id);
167     silc_dlist_del(list, entry);
168     silc_free(entry);
169   }
170
171   silc_dlist_uninit(list);
172 }
173
174 /* Return the channel name */
175
176 unsigned char *silc_channel_get_name(SilcChannelPayload payload,
177                                      SilcUInt32 *channel_name_len)
178 {
179   if (channel_name_len)
180     *channel_name_len = payload->name_len;
181
182   return payload->channel_name;
183 }
184
185 /* Return the channel ID */
186
187 unsigned char *silc_channel_get_id(SilcChannelPayload payload,
188                                    SilcUInt32 *channel_id_len)
189 {
190   if (channel_id_len)
191     *channel_id_len = payload->id_len;
192
193   return payload->channel_id;
194 }
195
196 /* Return the channel ID as parsed ID. */
197
198 SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
199 {
200   return silc_id_str2id(payload->channel_id, payload->id_len,
201                         SILC_ID_CHANNEL);
202 }
203
204 /* Return the mode. The mode is arbitrary. It can be the mode of the
205    channel or perhaps the mode of the client on the channel.  The protocol
206    dictates what the usage of the mode is in different circumstances. */
207
208 SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload)
209 {
210   return payload->mode;
211 }
212
213
214 /******************************************************************************
215
216                              Channel Key Payload
217
218 ******************************************************************************/
219
220 /* Parses channel key payload returning new channel key payload structure */
221
222 SilcChannelKeyPayload 
223 silc_channel_key_payload_parse(const unsigned char *payload,
224                                SilcUInt32 payload_len)
225 {
226   SilcBufferStruct buffer;
227   SilcChannelKeyPayload newp;
228   int ret;
229
230   SILC_LOG_DEBUG(("Parsing channel key payload"));
231
232   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
233   newp = silc_calloc(1, sizeof(*newp));
234   if (!newp)
235     return NULL;
236
237   /* Parse the Channel Key Payload */
238   ret =
239     silc_buffer_unformat(&buffer,
240                          SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
241                          SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher, 
242                                                      &newp->cipher_len),
243                          SILC_STR_UI16_NSTRING_ALLOC(&newp->key, 
244                                                      &newp->key_len),
245                          SILC_STR_END);
246   if (ret == -1)
247     goto err;
248
249   if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1 ||
250       newp->id_len + newp->cipher_len + newp->key_len > buffer.len - 6) {
251     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
252     goto err;
253   }
254
255   return newp;
256
257  err:
258   if (newp->id)
259     silc_free(newp->id);
260   if (newp->cipher)
261     silc_free(newp->cipher);
262   if (newp->key)
263     silc_free(newp->key);
264   silc_free(newp);
265   return NULL;
266 }
267
268 /* Encodes channel key payload into a buffer and returns it. This is used 
269    to add channel key payload into a packet. */
270
271 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
272                                            const unsigned char *id,
273                                            SilcUInt16 cipher_len,
274                                            const unsigned char *cipher,
275                                            SilcUInt16 key_len,
276                                            const unsigned char *key)
277 {
278   SilcBuffer buffer;
279   SilcUInt32 len;
280
281   SILC_LOG_DEBUG(("Encoding channel key payload"));
282
283   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
284      2 + cipher */
285   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
286   buffer = silc_buffer_alloc_size(len);
287   if (!buffer)
288     return NULL;
289
290   /* Encode the Channel Payload */
291   silc_buffer_format(buffer, 
292                      SILC_STR_UI_SHORT(id_len),
293                      SILC_STR_UI_XNSTRING(id, id_len),
294                      SILC_STR_UI_SHORT(cipher_len),
295                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
296                      SILC_STR_UI_SHORT(key_len),
297                      SILC_STR_UI_XNSTRING(key, key_len),
298                      SILC_STR_END);
299
300   return buffer;
301 }
302
303 /* Frees Channel Key Payload */
304
305 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
306 {
307   if (payload) {
308     silc_free(payload->id);
309     silc_free(payload->cipher);
310     if (payload->key) {
311       memset(payload->key, 0, payload->key_len);
312       silc_free(payload->key);
313     }
314     silc_free(payload);
315   }
316 }
317
318 /* Return ID */
319
320 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
321                                        SilcUInt32 *id_len)
322 {
323   if (id_len)
324     *id_len = payload->id_len;
325
326   return payload->id;
327 }
328
329 /* Return cipher name */
330
331 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
332                                            SilcUInt32 *cipher_len)
333 {
334   if (cipher_len)
335     *cipher_len = payload->cipher_len;
336
337   return payload->cipher;
338 }
339
340 /* Return key */
341
342 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
343                                         SilcUInt32 *key_len)
344 {
345   if (key_len)
346     *key_len = payload->key_len;
347
348   return payload->key;
349 }