Added SILC Server library.
[silc.git] / lib / silcserver / server_st_command_reply.c
1 /*
2
3   server_st_command_reply.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
20 #include "silc.h"
21 #include "silcserver.h"
22 #include "server_internal.h"
23
24 /************************** Types and definitions ***************************/
25
26 /* All functions that call the COMMAND_CHECK_STATUS macros must have
27    out: and err: goto labels. */
28
29 #define COMMAND_CHECK_STATUS                                            \
30 do {                                                                    \
31   SILC_LOG_DEBUG(("Start"));                                            \
32   if (!silc_command_get_status(cmd->payload, &status, &error)) {        \
33     if (SILC_STATUS_IS_ERROR(status))                                   \
34       goto out;                                                         \
35     if (status == SILC_STATUS_LIST_END)                                 \
36       goto out;                                                         \
37     goto err;                                                           \
38   }                                                                     \
39 } while(0)
40
41
42 /************************ Static utility functions **************************/
43
44 /* Free's command reply context */
45
46 static void silc_server_command_reply_free(SilcServerCommand cmd)
47 {
48   /* If pending commmands existed, they will eventually free this context */
49   if (!cmd->pending)
50     silc_server_command_free(cmd);
51 }
52
53
54 /************************* Command reply received ***************************/
55
56 /* Received a COMMAND_REPLY packet.  We parse the packet and process the
57    command reply. */
58
59 SILC_FSM_STATE(silc_server_st_packet_command_reply)
60 {
61   SilcServerThread thread = fsm_context;
62   SilcPacket packet = state_context;
63   SilcEntryData data = silc_packet_get_context(packet->stream);
64   SilcServerCommand cmd;
65   SilcCommandPayload payload;
66   SilcCommand command;
67
68   SILC_LOG_DEBUG(("Process command reply"));
69
70   /* Allocate command context. */
71   cmd = silc_server_command_alloc(thread);
72   if (!cmd) {
73     silc_packet_free(packet);
74     return SILC_FSM_FINISH;
75   }
76
77   cmd->packet = packet;
78
79   /* Get command reply payload from packet */
80   cmd->payload = silc_command_payload_parse(packet->buffer.data,
81                                             silc_buffer_len(&packet->buffer));
82   if (!cmd->payload) {
83     SILC_LOG_DEBUG(("Bad command reply payload"));
84     silc_server_command_reply_free(cmd);
85     return SILC_FSM_FINISH;
86   }
87
88   /* Client is allowed to send reply only to WHOIS command. */
89   if (data->type == SILC_CONN_CLIENT &&
90       silc_command_get(cmd->payload) != SILC_COMMAND_WHOIS) {
91     silc_server_command_reply_free(cmd);
92     return SILC_FSM_FINISH;
93   }
94
95   /* Get all command pending for this reply */
96   cmd->pending =
97     silc_server_command_pending_get(thread,
98                                     silc_command_get_ident(cmd->payload));
99
100   silc_fsm_set_state_context(fsm, cmd);
101
102   /* Process command reply */
103   switch (silc_command_get(cmd->payload)) {
104
105   case SILC_COMMAND_WHOIS:
106     /** Command reply WHOIS */
107     silc_fsm_next(fsm, silc_server_st_command_reply_whois);
108     break;
109
110   case SILC_COMMAND_WHOWAS:
111     /** Command reply WHOWAS */
112     silc_fsm_next(fsm, silc_server_st_command_reply_whowas);
113     break;
114
115   case SILC_COMMAND_IDENTIFY:
116     /** Command reply IDENTIFY */
117     silc_fsm_next(fsm, silc_server_st_command_reply_identify);
118     break;
119
120   case SILC_COMMAND_LIST:
121     /** Command reply LIST */
122     silc_fsm_next(fsm, silc_server_st_command_reply_list);
123     break;
124
125   case SILC_COMMAND_INFO:
126     /** Command reply INFO */
127     silc_fsm_next(fsm, silc_server_st_command_reply_info);
128     break;
129
130   case SILC_COMMAND_STATS:
131     /** Command reply STATS */
132     silc_fsm_next(fsm, silc_server_st_command_reply_stats);
133     break;
134
135   case SILC_COMMAND_PING:
136     /** Command reply PING */
137     silc_fsm_next(fsm, silc_server_st_command_reply_ping);
138     break;
139
140   case SILC_COMMAND_JOIN:
141     /** Command reply JOIN */
142     silc_fsm_next(fsm, silc_server_st_command_reply_join);
143     break;
144
145   case SILC_COMMAND_MOTD:
146     /** Command reply MOTD */
147     silc_fsm_next(fsm, silc_server_st_command_reply_motd);
148     break;
149
150   case SILC_COMMAND_WATCH:
151     /** Command reply WATCH */
152     silc_fsm_next(fsm, silc_server_st_command_reply_watch);
153     break;
154
155   case SILC_COMMAND_USERS:
156     /** Command reply USERS */
157     silc_fsm_next(fsm, silc_server_st_command_reply_users);
158     break;
159
160   case SILC_COMMAND_GETKEY:
161     /** Command reply SERVICE */
162     silc_fsm_next(fsm, silc_server_st_command_reply_getkey);
163     break;
164
165   case SILC_COMMAND_SERVICE:
166     /** Command reply SERVICE */
167     silc_fsm_next(fsm, silc_server_st_command_reply_service);
168     break;
169
170   default:
171     SILC_LOG_DEBUG(("Unknown command %d", silc_command_get(cmd->payload)));
172     cmd->pending = NULL;
173     silc_server_command_reply_free(cmd);
174     return SILC_FSM_FINISH;
175     break;
176   }
177
178   /* Statistics */
179
180   return SILC_FSM_CONTINUE;
181 }
182
183
184 /********************************* WHOIS ************************************/
185
186 SILC_FSM_STATE(silc_server_st_command_reply_whois)
187 {
188   SilcServerThread thread = fsm_context;
189   SilcServerCommand cmd = state_context;
190   SilcStatus status, error;
191
192   COMMAND_CHECK_STATUS;
193
194  out:
195   silc_server_command_pending_signal(cmd);
196  err:
197   silc_server_command_reply_free(cmd);
198
199   return SILC_FSM_FINISH;
200 }
201
202
203 /********************************* WHOWAS ***********************************/
204
205 SILC_FSM_STATE(silc_server_st_command_reply_whowas)
206 {
207   SilcServerThread thread = fsm_context;
208   SilcServerCommand cmd = state_context;
209   SilcStatus status, error;
210
211   COMMAND_CHECK_STATUS;
212
213  out:
214   silc_server_command_pending_signal(cmd);
215  err:
216   silc_server_command_reply_free(cmd);
217
218   return SILC_FSM_FINISH;
219 }
220
221
222 /******************************** IDENTIFY **********************************/
223
224 SILC_FSM_STATE(silc_server_st_command_reply_identify)
225 {
226   SilcServerThread thread = fsm_context;
227   SilcServerCommand cmd = state_context;
228   SilcStatus status, error;
229
230   COMMAND_CHECK_STATUS;
231
232  out:
233   silc_server_command_pending_signal(cmd);
234  err:
235   silc_server_command_reply_free(cmd);
236
237   return SILC_FSM_FINISH;
238 }
239
240
241 /********************************** LIST ************************************/
242
243 SILC_FSM_STATE(silc_server_st_command_reply_list)
244 {
245   SilcServerThread thread = fsm_context;
246   SilcServerCommand cmd = state_context;
247   SilcStatus status, error;
248
249   COMMAND_CHECK_STATUS;
250
251  out:
252   silc_server_command_pending_signal(cmd);
253  err:
254   silc_server_command_reply_free(cmd);
255
256   return SILC_FSM_FINISH;
257 }
258
259
260 /********************************** INFO ************************************/
261
262 SILC_FSM_STATE(silc_server_st_command_reply_info)
263 {
264   SilcServerThread thread = fsm_context;
265   SilcServerCommand cmd = state_context;
266   SilcStatus status, error;
267
268   COMMAND_CHECK_STATUS;
269
270  out:
271   silc_server_command_pending_signal(cmd);
272  err:
273   silc_server_command_reply_free(cmd);
274
275   return SILC_FSM_FINISH;
276 }
277
278
279 /********************************** STATS ***********************************/
280
281 SILC_FSM_STATE(silc_server_st_command_reply_stats)
282 {
283   SilcServerThread thread = fsm_context;
284   SilcServer server = thread->server;
285   SilcServerCommand cmd = state_context;
286   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
287   SilcStatus status, error;
288   unsigned char *tmp;
289   SilcUInt32 tmp_len;
290   SilcBufferStruct buf;
291
292   COMMAND_CHECK_STATUS;
293
294   /* Get statistics structure */
295   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
296   if (server->server_type != SILC_ROUTER && tmp) {
297     silc_buffer_set(&buf, tmp, tmp_len);
298     silc_buffer_unformat(&buf,
299                          SILC_STR_UI_INT(NULL),
300                          SILC_STR_UI_INT(NULL),
301                          SILC_STR_UI_INT(NULL),
302                          SILC_STR_UI_INT(NULL),
303                          SILC_STR_UI_INT(NULL),
304                          SILC_STR_UI_INT(NULL),
305                          SILC_STR_UI_INT(&server->stat.cell_clients),
306                          SILC_STR_UI_INT(&server->stat.cell_channels),
307                          SILC_STR_UI_INT(&server->stat.cell_servers),
308                          SILC_STR_UI_INT(&server->stat.clients),
309                          SILC_STR_UI_INT(&server->stat.channels),
310                          SILC_STR_UI_INT(&server->stat.servers),
311                          SILC_STR_UI_INT(&server->stat.routers),
312                          SILC_STR_UI_INT(&server->stat.server_ops),
313                          SILC_STR_UI_INT(&server->stat.router_ops),
314                          SILC_STR_END);
315   }
316
317  out:
318   silc_server_command_pending_signal(cmd);
319  err:
320   silc_server_command_reply_free(cmd);
321
322   return SILC_FSM_FINISH;
323 }
324
325
326 /********************************** PING ************************************/
327
328 SILC_FSM_STATE(silc_server_st_command_reply_ping)
329 {
330   SilcServerThread thread = fsm_context;
331   SilcServerCommand cmd = state_context;
332   SilcStatus status, error;
333
334   COMMAND_CHECK_STATUS;
335
336  out:
337   silc_server_command_pending_signal(cmd);
338  err:
339   silc_server_command_reply_free(cmd);
340
341   return SILC_FSM_FINISH;
342 }
343
344
345 /********************************** JOIN ************************************/
346
347 SILC_FSM_STATE(silc_server_st_command_reply_join)
348 {
349   SilcServerThread thread = fsm_context;
350   SilcServerCommand cmd = state_context;
351   SilcStatus status, error;
352
353   COMMAND_CHECK_STATUS;
354
355  out:
356   silc_server_command_pending_signal(cmd);
357  err:
358   silc_server_command_reply_free(cmd);
359
360   return SILC_FSM_FINISH;
361 }
362
363
364 /********************************** MOTD ************************************/
365
366 SILC_FSM_STATE(silc_server_st_command_reply_motd)
367 {
368   SilcServerThread thread = fsm_context;
369   SilcServerCommand cmd = state_context;
370   SilcStatus status, error;
371
372   COMMAND_CHECK_STATUS;
373
374  out:
375   silc_server_command_pending_signal(cmd);
376  err:
377   silc_server_command_reply_free(cmd);
378
379   return SILC_FSM_FINISH;
380 }
381
382
383 /********************************** WATCH ***********************************/
384
385 SILC_FSM_STATE(silc_server_st_command_reply_watch)
386 {
387   SilcServerThread thread = fsm_context;
388   SilcServerCommand cmd = state_context;
389   SilcStatus status, error;
390
391   COMMAND_CHECK_STATUS;
392
393  out:
394   silc_server_command_pending_signal(cmd);
395  err:
396   silc_server_command_reply_free(cmd);
397
398   return SILC_FSM_FINISH;
399 }
400
401
402 /********************************** USERS ***********************************/
403
404 SILC_FSM_STATE(silc_server_st_command_reply_users)
405 {
406   SilcServerThread thread = fsm_context;
407   SilcServerCommand cmd = state_context;
408   SilcStatus status, error;
409
410   COMMAND_CHECK_STATUS;
411
412  out:
413   silc_server_command_pending_signal(cmd);
414  err:
415   silc_server_command_reply_free(cmd);
416
417   return SILC_FSM_FINISH;
418 }
419
420
421 /********************************** GETKEY **********************************/
422
423 SILC_FSM_STATE(silc_server_st_command_reply_getkey)
424 {
425   SilcServerThread thread = fsm_context;
426   SilcServer server = thread->server;
427   SilcServerCommand cmd = state_context;
428   SilcArgumentPayload args = silc_command_get_args(cmd->payload);
429   SilcStatus status, error;
430   unsigned char *tmp;
431   SilcUInt32 len;
432   SilcClientEntry client = NULL;
433   SilcServerEntry server_entry = NULL;
434   SilcIDPayload idp = NULL;
435   SilcClientID client_id;
436   SilcServerID server_id;
437   SilcIdType id_type;
438   SilcPublicKey public_key = NULL;
439
440   COMMAND_CHECK_STATUS;
441
442   /* Get ID */
443   tmp = silc_argument_get_arg_type(args, 2, &len);
444   if (!tmp)
445     goto out;
446   idp = silc_id_payload_parse(tmp, len);
447   if (!idp)
448     goto out;
449
450   /* Get the public key payload */
451   tmp = silc_argument_get_arg_type(args, 3, &len);
452   if (!tmp)
453     goto out;
454   if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
455     goto out;
456
457   /* Store the public key */
458   id_type = silc_id_payload_get_type(idp);
459   if (id_type == SILC_ID_CLIENT) {
460     if (!silc_id_payload_get_id(idp, &client_id, sizeof(client_id)))
461       goto out;
462
463     client = silc_server_find_client_by_id(server, &client_id, TRUE, NULL);
464     if (!client)
465       goto out;
466
467     if (!client->data.public_key) {
468       silc_skr_add_public_key_simple(server->repository, public_key,
469                                      SILC_SKR_USAGE_IDENTIFICATION, client);
470       client->data.public_key = public_key;
471       public_key = NULL;
472     }
473
474   } else if (id_type == SILC_ID_SERVER) {
475     if (!silc_id_payload_get_id(idp, &server_id, sizeof(server_id)))
476       goto out;
477
478     server_entry = silc_server_find_server_by_id(server, &server_id,
479                                                  TRUE, NULL);
480     if (!server_entry)
481       goto out;
482
483     server_entry->data.public_key = public_key;
484     public_key = NULL;
485   }
486
487  out:
488   silc_server_command_pending_signal(cmd);
489   if (idp)
490     silc_id_payload_free(idp);
491   if (public_key)
492     silc_pkcs_public_key_free(public_key);
493  err:
494   silc_server_command_reply_free(cmd);
495
496   return SILC_FSM_FINISH;
497 }
498
499
500 /******************************** SERVICE ***********************************/
501
502 SILC_FSM_STATE(silc_server_st_command_reply_service)
503 {
504   SilcServerThread thread = fsm_context;
505   SilcServerCommand cmd = state_context;
506   SilcStatus status, error;
507
508   COMMAND_CHECK_STATUS;
509
510  out:
511   silc_server_command_pending_signal(cmd);
512  err:
513   silc_server_command_reply_free(cmd);
514
515   return SILC_FSM_FINISH;
516 }