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