9439f488ceaa2878cb86f9f517ab91c406d7edf3
[silc.git] / apps / silcd / command.c
1 /*
2
3   command.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2009 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 "serverincludes.h"
21 #include "server_internal.h"
22
23 static int silc_server_is_registered(SilcServer server,
24                                      SilcPacketStream sock,
25                                      SilcServerCommandContext cmd,
26                                      SilcCommand command);
27 static void
28 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
29                                       SilcCommand command,
30                                       SilcStatus status,
31                                       SilcStatus error);
32 static void
33 silc_server_command_send_status_data(SilcServerCommandContext cmd,
34                                      SilcCommand command,
35                                      SilcStatus status,
36                                      SilcStatus error,
37                                      SilcUInt32 arg_type,
38                                      const unsigned char *arg,
39                                      SilcUInt32 arg_len);
40 static bool
41 silc_server_command_pending_error_check(SilcServerCommandContext cmd,
42                                         SilcServerCommandReplyContext cmdr,
43                                         SilcCommand command);
44 SILC_TASK_CALLBACK(silc_server_command_process_timeout);
45
46 /* Server command list. */
47 SilcServerCommand silc_command_list[] =
48 {
49   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
50   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
51   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
52   SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
53   SILC_SERVER_CMD(list, LIST, SILC_CF_LAG_STRICT | SILC_CF_REG),
54   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
55   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
56   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
57   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
58   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
59   SILC_SERVER_CMD(stats, STATS, SILC_CF_LAG | SILC_CF_REG),
60   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
61   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
62   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
63   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
64   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
65   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG_STRICT | SILC_CF_REG),
66   SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
67   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
68   SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG),
69   SILC_SERVER_CMD(detach, DETACH, SILC_CF_LAG_STRICT | SILC_CF_REG),
70   SILC_SERVER_CMD(watch, WATCH, SILC_CF_LAG | SILC_CF_REG),
71   SILC_SERVER_CMD(silcoper, SILCOPER,
72                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
73   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
74   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
75   SILC_SERVER_CMD(getkey, GETKEY, SILC_CF_LAG | SILC_CF_REG),
76   SILC_SERVER_CMD(service, SERVICE, SILC_CF_LAG_STRICT | SILC_CF_REG),
77
78   SILC_SERVER_CMD(connect, PRIV_CONNECT,
79                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
80   SILC_SERVER_CMD(close, PRIV_CLOSE,
81                   SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
82   SILC_SERVER_CMD(shutdown, PRIV_SHUTDOWN, SILC_CF_LAG | SILC_CF_REG |
83                   SILC_CF_OPER),
84
85   { NULL, 0 },
86 };
87
88 /* Returns TRUE if the connection is registered. Unregistered connections
89    usually cannot send commands hence the check. */
90
91 static int silc_server_is_registered(SilcServer server,
92                                      SilcPacketStream sock,
93                                      SilcServerCommandContext cmd,
94                                      SilcCommand command)
95 {
96   SilcIDListData idata = silc_packet_get_context(sock);
97
98   if (!idata)
99     return FALSE;
100
101   if (idata->status & SILC_IDLIST_STATUS_REGISTERED)
102     return TRUE;
103
104   silc_server_command_send_status_reply(cmd, command,
105                                         SILC_STATUS_ERR_NOT_REGISTERED, 0);
106   return FALSE;
107 }
108
109 /* Performs several checks to the command. It first checks whether this
110    command was called as pending command callback. If it was then it checks
111    whether error occurred in the command reply where the pending command
112    callback was called.
113
114    It also checks that the requested command includes correct amount
115    of arguments. */
116 #define SILC_SERVER_COMMAND_CHECK(command, context, min, max)                \
117 do {                                                                         \
118   SilcUInt32 _argc;                                                          \
119                                                                              \
120   if (silc_server_command_pending_error_check(cmd, context2, command)) {     \
121     SILC_LOG_DEBUG(("Error occurred in command reply, command not called")); \
122     silc_server_command_free(cmd);                                           \
123     return;                                                                  \
124   }                                                                          \
125                                                                              \
126   if (context2 &&                                                            \
127       !silc_server_is_registered(cmd->server, cmd->sock, cmd, command)) {    \
128     SILC_LOG_DEBUG(("Not registered, command not called"));                  \
129     silc_server_command_free(cmd);                                           \
130     return;                                                                  \
131   }                                                                          \
132                                                                              \
133   _argc = silc_argument_get_arg_num(cmd->args);                              \
134   if (_argc < min) {                                                         \
135     SILC_LOG_DEBUG(("Not enough parameters in command"));                    \
136     silc_server_command_send_status_reply(cmd, command,                      \
137                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, \
138                                           0);                                \
139     silc_server_command_free(cmd);                                           \
140     return;                                                                  \
141   }                                                                          \
142   if (_argc > max) {                                                         \
143     SILC_LOG_DEBUG(("Too many parameters in command"));                      \
144     silc_server_command_send_status_reply(cmd, command,                      \
145                                           SILC_STATUS_ERR_TOO_MANY_PARAMS,   \
146                                           0);                                \
147     silc_server_command_free(cmd);                                           \
148     return;                                                                  \
149   }                                                                          \
150 } while(0)
151
152 /* Internal context to hold data when executed command with timeout. */
153 typedef struct {
154   SilcServerCommandContext ctx;
155   SilcServerCommand *cmd;
156 } *SilcServerCommandTimeout;
157
158 /* Timeout callback to process commands with timeout for client. Client's
159    commands are always executed with timeout. */
160
161 SILC_TASK_CALLBACK(silc_server_command_process_timeout)
162 {
163   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
164   SilcClientEntry client = silc_packet_get_context(timeout->ctx->sock);
165
166   if (!client) {
167     SILC_LOG_DEBUG(("Client entry is invalid"));
168     silc_server_command_free(timeout->ctx);
169     silc_free(timeout);
170     return;
171   }
172
173   /* Update access time */
174   client->last_command = time(NULL);
175
176   if (!(timeout->cmd->flags & SILC_CF_REG)) {
177     SILC_LOG_DEBUG(("Calling %s command",
178                     silc_get_command_name(timeout->cmd->cmd)));
179     timeout->cmd->cb(timeout->ctx, NULL);
180   } else if (silc_server_is_registered(timeout->ctx->server,
181                                        timeout->ctx->sock,
182                                        timeout->ctx,
183                                        timeout->cmd->cmd)) {
184     SILC_LOG_DEBUG(("Calling %s command",
185                     silc_get_command_name(timeout->cmd->cmd)));
186     timeout->cmd->cb(timeout->ctx, NULL);
187   } else {
188     SILC_LOG_DEBUG(("Client is not registered"));
189     silc_server_command_free(timeout->ctx);
190   }
191
192   silc_free(timeout);
193 }
194
195 /* Processes received command packet. */
196
197 void silc_server_command_process(SilcServer server,
198                                  SilcPacketStream sock,
199                                  SilcPacket packet)
200 {
201   SilcIDListData idata = silc_packet_get_context(sock);
202   SilcServerCommandContext ctx;
203   SilcServerCommand *cmd;
204   SilcCommand command;
205
206   if (!idata)
207     return;
208
209   /* Allocate command context. This must be free'd by the
210      command routine receiving it. */
211   ctx = silc_server_command_alloc();
212   ctx->server = server;
213   ctx->sock = sock;
214   ctx->packet = packet; /* Save original packet */
215   silc_packet_stream_ref(sock);
216
217   /* Parse the command payload in the packet */
218   ctx->payload = silc_command_payload_parse(packet->buffer.data,
219                                             silc_buffer_len(&packet->buffer));
220   if (!ctx->payload) {
221     SILC_LOG_ERROR(("Bad command payload"));
222     silc_packet_free(packet);
223     silc_packet_stream_unref(ctx->sock);
224     silc_free(ctx);
225     return;
226   }
227   ctx->args = silc_command_get_args(ctx->payload);
228
229   /* Get the command */
230   command = silc_command_get(ctx->payload);
231   for (cmd = silc_command_list; cmd->cb; cmd++)
232     if (cmd->cmd == command)
233       break;
234
235   if (!cmd || !cmd->cb) {
236     SILC_LOG_DEBUG(("Unknown command %d", command));
237     silc_server_command_send_status_reply(ctx, command,
238                                           SILC_STATUS_ERR_UNKNOWN_COMMAND, 0);
239     silc_packet_free(packet);
240     silc_packet_stream_unref(ctx->sock);
241     silc_free(ctx);
242     return;
243   }
244
245   /* Execute client's commands always with timeout.  Normally they are
246      executed with zero (0) timeout but if client is sending command more
247      frequently than once in 2 seconds, then the timeout may be 0 to 2
248      seconds. */
249   if (idata->conn_type == SILC_CONN_CLIENT) {
250     SilcClientEntry client = silc_packet_get_context(sock);
251     SilcServerCommandTimeout timeout;
252     int fast;
253
254     timeout = silc_calloc(1, sizeof(*timeout));
255     timeout->ctx = ctx;
256     timeout->cmd = cmd;
257
258     if (client->last_command && (time(NULL) - client->last_command) < 2) {
259       client->fast_command++;
260       fast = FALSE;
261     } else {
262       if (client->fast_command - 2 <= 0)
263         client->fast_command = 0;
264       else
265         client->fast_command -= 2;
266       fast = TRUE;
267     }
268
269     if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
270                   (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
271       silc_schedule_task_add_timeout(
272                             server->schedule,
273                             silc_server_command_process_timeout, timeout,
274                             (client->fast_command < 3 ? 0 :
275                              2 - (time(NULL) - client->last_command)),
276                             (client->fast_command < 3 ? 200000 : 0));
277     else
278       silc_schedule_task_add_timeout(server->schedule,
279                                      silc_server_command_process_timeout,
280                                      timeout, 0, 0);
281     return;
282   }
283
284   /* Execute for server */
285
286   if (!(cmd->flags & SILC_CF_REG)) {
287     SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
288     cmd->cb(ctx, NULL);
289   } else if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
290     SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
291     cmd->cb(ctx, NULL);
292   } else {
293     SILC_LOG_DEBUG(("Server is not registered"));
294     silc_server_command_free(ctx);
295   }
296 }
297
298 /* Allocate Command Context */
299
300 SilcServerCommandContext silc_server_command_alloc()
301 {
302   SilcServerCommandContext ctx = silc_calloc(1, sizeof(*ctx));
303   ctx->users++;
304   return ctx;
305 }
306
307 /* Free's the command context allocated before executing the command */
308
309 void silc_server_command_free(SilcServerCommandContext ctx)
310 {
311   ctx->users--;
312   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
313                   ctx->users));
314   if (ctx->users < 1) {
315     if (ctx->payload)
316       silc_command_payload_free(ctx->payload);
317     if (ctx->packet)
318       silc_packet_free(ctx->packet);
319     if (ctx->sock)
320       silc_packet_stream_unref(ctx->sock);
321     silc_free(ctx);
322   }
323 }
324
325 /* Duplicate Command Context by adding reference counter. The context won't
326    be free'd untill it hits zero. */
327
328 SilcServerCommandContext
329 silc_server_command_dup(SilcServerCommandContext ctx)
330 {
331   ctx->users++;
332   SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
333                   ctx->users));
334   return ctx;
335 }
336
337 /* Timeout for pending command.  If reply to pending command never arrives
338    this is called to free resources. */
339
340 SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
341 {
342   SilcServer server = app_context;
343   SilcServerCommandPending *reply = context;
344   SilcServerCommandReplyContext cmdr;
345   SilcBuffer tmpreply;
346   int i;
347
348   SILC_LOG_DEBUG(("Timeout pending command %p", reply));
349
350   /* Allocate temporary and bogus command reply context */
351   cmdr = silc_calloc(1, sizeof(*cmdr));
352   cmdr->server = server;
353   cmdr->ident = reply->ident;
354
355   /* Check for pending commands and mark to be exeucted */
356   cmdr->callbacks =
357     silc_server_command_pending_check(server, reply->reply_cmd,
358                                       reply->ident, &cmdr->callbacks_count);
359
360   /* Create bogus command reply with an error inside */
361   tmpreply =
362     silc_command_reply_payload_encode_va(reply->reply_cmd ? reply->reply_cmd :
363                                          SILC_COMMAND_RESERVED,
364                                          SILC_STATUS_ERR_TIMEDOUT, 0,
365                                          reply->ident, 0);
366   cmdr->payload = silc_command_payload_parse(tmpreply->data,
367                                              silc_buffer_len(tmpreply));
368   silc_buffer_free(tmpreply);
369
370   /* Call all callbacks. Same as SILC_SERVER_PENDING_EXEC macro. */
371   for (i = 0; i < cmdr->callbacks_count; i++)
372     if (cmdr->callbacks[i].callback)
373       (*cmdr->callbacks[i].callback)(cmdr->callbacks[i].context, cmdr);
374
375   silc_server_command_pending_del(server, reply->reply_cmd, reply->ident);
376   silc_server_command_reply_free(cmdr);
377 }
378
379 /* Add new pending command to be executed when reply to a command has been
380    received. The `reply_cmd' is the command that will call the `callback'
381    with `context' when reply has been received.  It can be SILC_COMMAND_NONE
382    to match any command with the `ident'.  If `ident' is non-zero
383    the `callback' will be executed when received reply with command
384    identifier `ident'. If there already exists pending command for the
385    specified command, ident, callback and context this function has no
386    effect. */
387
388 SilcBool silc_server_command_pending(SilcServer server,
389                                  SilcCommand reply_cmd,
390                                  SilcUInt16 ident,
391                                  SilcCommandCb callback,
392                                  void *context)
393 {
394   return silc_server_command_pending_timed(server, reply_cmd, ident, callback,
395                                            context, 0);
396 }
397
398 /* Same as silc_server_command_pending with specific timeout for pending
399    commands.  If the `timeout' is zero default timeout is used. */
400
401 SilcBool silc_server_command_pending_timed(SilcServer server,
402                                        SilcCommand reply_cmd,
403                                        SilcUInt16 ident,
404                                        SilcCommandCb callback,
405                                        void *context,
406                                        SilcUInt16 timeout)
407 {
408   SilcServerCommandPending *reply;
409
410   /* Check whether identical pending already exists for same command,
411      ident, callback and callback context. If it does then it would be
412      error to register it again. */
413   silc_dlist_start(server->pending_commands);
414   while ((reply = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
415     if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
416         reply->callback == callback && reply->context == context)
417       return FALSE;
418   }
419
420   reply = silc_calloc(1, sizeof(*reply));
421   reply->reply_cmd = reply_cmd;
422   reply->ident = ident;
423   reply->context = context;
424   reply->callback = callback;
425   reply->timeout =
426     silc_schedule_task_add_timeout(server->schedule,
427                                    silc_server_command_pending_timeout, reply,
428                                    timeout ? timeout : 12, 0);
429   silc_dlist_add(server->pending_commands, reply);
430
431   return TRUE;
432 }
433
434 /* Deletes pending command by reply command type. */
435
436 void silc_server_command_pending_del(SilcServer server,
437                                      SilcCommand reply_cmd,
438                                      SilcUInt16 ident)
439 {
440   SilcServerCommandPending *r;
441
442   silc_dlist_start(server->pending_commands);
443   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
444     if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
445                                        r->reply_check))
446         && r->ident == ident) {
447       silc_dlist_del(server->pending_commands, r);
448       if (r->timeout)
449         silc_schedule_task_del(server->schedule, r->timeout);
450       silc_free(r);
451     }
452   }
453 }
454
455 /* Checks for pending commands and marks callbacks to be called from
456    the command reply function. Returns TRUE if there were pending command. */
457
458 SilcServerCommandPendingCallbacks
459 silc_server_command_pending_check(SilcServer server,
460                                   SilcCommand command,
461                                   SilcUInt16 ident,
462                                   SilcUInt32 *callbacks_count)
463 {
464   SilcServerCommandPending *r;
465   SilcServerCommandPendingCallbacks callbacks = NULL;
466   int i = 0;
467
468   silc_dlist_start(server->pending_commands);
469   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
470     if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
471         && r->ident == ident) {
472       callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
473       callbacks[i].context = r->context;
474       callbacks[i].callback = r->callback;
475       r->reply_check = TRUE;
476       i++;
477     }
478   }
479
480   *callbacks_count = i;
481   return callbacks;
482 }
483
484 /* Sends simple status message as command reply packet */
485
486 static void
487 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
488                                       SilcCommand command,
489                                       SilcStatus status,
490                                       SilcStatus error)
491 {
492   SilcBuffer buffer;
493
494   /* Statistics */
495   cmd->server->stat.commands_sent++;
496
497   SILC_LOG_DEBUG(("Sending command status %d", status));
498
499   buffer =
500     silc_command_reply_payload_encode_va(command, status, error,
501                                          silc_command_get_ident(cmd->payload),
502                                          0);
503   silc_server_packet_send(cmd->server, cmd->sock,
504                           SILC_PACKET_COMMAND_REPLY, 0,
505                           buffer->data, silc_buffer_len(buffer));
506   silc_buffer_free(buffer);
507 }
508
509 /* Sends command status reply with one extra argument. The argument
510    type must be sent as argument. */
511
512 static void
513 silc_server_command_send_status_data(SilcServerCommandContext cmd,
514                                      SilcCommand command,
515                                      SilcStatus status,
516                                      SilcStatus error,
517                                      SilcUInt32 arg_type,
518                                      const unsigned char *arg,
519                                      SilcUInt32 arg_len)
520 {
521   SilcBuffer buffer;
522
523   /* Statistics */
524   cmd->server->stat.commands_sent++;
525
526   SILC_LOG_DEBUG(("Sending command status %d", status));
527
528   buffer =
529     silc_command_reply_payload_encode_va(command, status, 0,
530                                          silc_command_get_ident(cmd->payload),
531                                          1, arg_type, arg, arg_len);
532   silc_server_packet_send(cmd->server, cmd->sock,
533                           SILC_PACKET_COMMAND_REPLY, 0,
534                           buffer->data, silc_buffer_len(buffer));
535   silc_buffer_free(buffer);
536 }
537
538 static void
539 silc_server_command_send_status_data2(SilcServerCommandContext cmd,
540                                       SilcCommand command,
541                                       SilcStatus status,
542                                       SilcStatus error,
543                                       SilcUInt32 arg_type1,
544                                       const unsigned char *arg1,
545                                       SilcUInt32 arg_len1,
546                                       SilcUInt32 arg_type2,
547                                       const unsigned char *arg2,
548                                       SilcUInt32 arg_len2)
549 {
550   SilcBuffer buffer;
551
552   /* Statistics */
553   cmd->server->stat.commands_sent++;
554
555   SILC_LOG_DEBUG(("Sending command status %d", status));
556
557   buffer =
558     silc_command_reply_payload_encode_va(command, status, 0,
559                                          silc_command_get_ident(cmd->payload),
560                                          2, arg_type1, arg1, arg_len1,
561                                          arg_type2, arg2, arg_len2);
562   silc_server_packet_send(cmd->server, cmd->sock,
563                           SILC_PACKET_COMMAND_REPLY, 0,
564                           buffer->data, silc_buffer_len(buffer));
565   silc_buffer_free(buffer);
566 }
567
568 /* This function can be called to check whether in the command reply
569    an error occurred. This function has no effect if this is called
570    when the command function was not called as pending command callback.
571    This returns TRUE if error had occurred. */
572
573 static bool
574 silc_server_command_pending_error_check(SilcServerCommandContext cmd,
575                                         SilcServerCommandReplyContext cmdr,
576                                         SilcCommand command)
577 {
578   if (!cmd->pending || !cmdr)
579     return FALSE;
580
581   if (!silc_command_get_status(cmdr->payload, NULL, NULL)) {
582     SilcBuffer buffer;
583
584     /* Statistics */
585     cmd->server->stat.commands_sent++;
586
587     /* Send the same command reply payload */
588     silc_command_set_command(cmdr->payload, silc_command_get(cmd->payload));
589     silc_command_set_ident(cmdr->payload,
590                            silc_command_get_ident(cmd->payload));
591     buffer = silc_command_payload_encode_payload(cmdr->payload);
592     silc_server_packet_send(cmd->server, cmd->sock,
593                             SILC_PACKET_COMMAND_REPLY, 0,
594                             buffer->data, silc_buffer_len(buffer));
595     silc_buffer_free(buffer);
596     return TRUE;
597   }
598
599   return FALSE;
600 }
601
602 /* Server side of command WHOIS. */
603
604 SILC_SERVER_CMD_FUNC(whois)
605 {
606   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
607   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 256);
608   silc_server_query_command(cmd->server, SILC_COMMAND_WHOIS, cmd, NULL);
609   silc_server_command_free(cmd);
610 }
611
612 /* Server side of command WHOWAS. */
613
614 SILC_SERVER_CMD_FUNC(whowas)
615 {
616   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
617   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
618   silc_server_query_command(cmd->server, SILC_COMMAND_WHOWAS, cmd, NULL);
619   silc_server_command_free(cmd);
620 }
621
622 /* Server side of command IDENTIFY. */
623
624 SILC_SERVER_CMD_FUNC(identify)
625 {
626   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
627   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 256);
628   silc_server_query_command(cmd->server, SILC_COMMAND_IDENTIFY, cmd, NULL);
629   silc_server_command_free(cmd);
630 }
631
632 /* Server side of command NICK. Sets nickname for user. Setting
633    nickname causes generation of a new client ID for the client. The
634    new client ID is sent to the client after changing the nickname. */
635
636 SILC_SERVER_CMD_FUNC(nick)
637 {
638   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
639   SilcClientEntry client = silc_packet_get_context(cmd->sock);
640   SilcServer server = cmd->server;
641   SilcBuffer nidp, oidp = NULL;
642   SilcClientID *new_id;
643   SilcUInt32 nick_len;
644   unsigned char *nick, *nickc = NULL;
645   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
646
647   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
648     goto out;
649
650   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
651
652   /* Get nickname */
653   nick = silc_argument_get_arg_type(cmd->args, 1, &nick_len);
654   if (!nick) {
655     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
656                                           SILC_STATUS_ERR_BAD_NICKNAME, 0);
657     goto out;
658   }
659
660   /* Truncate over long nicks */
661   if (nick_len > 128) {
662     nick_len = 128;
663     nick[nick_len - 1] = '\0';
664   }
665
666   /* Check for valid nickname string.  This is cached, original is saved
667      in the client context. */
668   nickc = silc_identifier_check(nick, nick_len, SILC_STRING_UTF8, 128, NULL);
669   if (!nickc) {
670     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
671                                           SILC_STATUS_ERR_BAD_NICKNAME, 0);
672     goto out;
673   }
674
675   /* Check for same nickname */
676   if (strlen(client->nickname) == nick_len &&
677       !memcmp(client->nickname, nick, nick_len)) {
678     nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
679     silc_free(nickc);
680     goto send_reply;
681   }
682
683   /* Create new Client ID */
684   if (!silc_id_create_client_id(cmd->server, cmd->server->id,
685                                 cmd->server->rng,
686                                 cmd->server->md5hash,
687                                 nickc, strlen(nickc), &new_id)) {
688     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
689                                           SILC_STATUS_ERR_BAD_NICKNAME, 0);
690     silc_free(nickc);
691     goto out;
692   }
693
694   /* Send notify about nickname change to our router. We send the new
695      ID and ask to replace it with the old one. If we are router the
696      packet is broadcasted. Send NICK_CHANGE notify. */
697   silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server),
698                                       SILC_BROADCAST(server), client->id,
699                                       new_id, nick);
700
701   /* Check if anyone is watching the old nickname */
702   if (server->server_type == SILC_ROUTER)
703     silc_server_check_watcher_list(server, client, nick,
704                                    SILC_NOTIFY_TYPE_NICK_CHANGE);
705
706   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
707
708   /* Update client entry */
709   silc_idcache_update_by_context(server->local_list->clients, client,
710                                  new_id, nickc, TRUE);
711   silc_free(new_id);
712   silc_free(client->nickname);
713   client->nickname = strdup(nick);
714
715   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
716
717   /* Send NICK_CHANGE notify to the client's channels */
718   silc_server_send_notify_on_channels(server, NULL, client,
719                                       SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
720                                       oidp->data, silc_buffer_len(oidp),
721                                       nidp->data, silc_buffer_len(nidp),
722                                       client->nickname,
723                                       strlen(client->nickname));
724
725   /* Check if anyone is watching the new nickname */
726   if (server->server_type == SILC_ROUTER)
727     silc_server_check_watcher_list(server, client, NULL,
728                                    SILC_NOTIFY_TYPE_NICK_CHANGE);
729
730  send_reply:
731   /* Send the new Client ID as reply command back to client */
732   silc_server_send_command_reply(cmd->server, cmd->sock,
733                                  SILC_COMMAND_NICK,
734                                  SILC_STATUS_OK, 0, ident, 2,
735                                  2, nidp->data, silc_buffer_len(nidp),
736                                  3, nick, nick_len);
737   silc_buffer_free(nidp);
738   if (oidp)
739     silc_buffer_free(oidp);
740
741  out:
742   silc_server_command_free(cmd);
743 }
744
745 /* Sends the LIST command reply */
746
747 static void
748 silc_server_command_list_send_reply(SilcServerCommandContext cmd,
749                                     SilcChannelEntry *lch,
750                                     SilcUInt32 lch_count,
751                                     SilcChannelEntry *gch,
752                                     SilcUInt32 gch_count)
753 {
754   int i, k;
755   SilcBuffer idp;
756   SilcChannelEntry entry;
757   SilcStatus status;
758   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
759   char *topic;
760   unsigned char usercount[4];
761   SilcUInt32 users;
762   int valid_lcount = 0, valid_rcount = 0;
763
764   for (i = 0; i < lch_count; i++) {
765     if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
766       lch[i] = NULL;
767     else
768       valid_lcount++;
769   }
770   for (i = 0; i < gch_count; i++) {
771     if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
772       gch[i] = NULL;
773     else
774       valid_rcount++;
775   }
776
777   if (!lch_count && !gch_count) {
778     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
779                                           SILC_STATUS_OK, 0);
780     return;
781   }
782
783   status = SILC_STATUS_OK;
784   if ((lch_count + gch_count) > 1)
785     status = SILC_STATUS_LIST_START;
786
787   /* Local list */
788   for (i = 0, k = 0; i < lch_count; i++) {
789     entry = lch[i];
790     if (!entry)
791       continue;
792
793     if (k >= 1)
794       status = SILC_STATUS_LIST_ITEM;
795     if (valid_lcount > 1 && k == valid_lcount - 1 && !valid_rcount)
796       status = SILC_STATUS_LIST_END;
797
798     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
799
800     if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
801       topic = "*private*";
802       memset(usercount, 0, sizeof(usercount));
803     } else {
804       topic = entry->topic;
805       users = silc_hash_table_count(entry->user_list);
806       SILC_PUT32_MSB(users, usercount);
807     }
808
809     /* Send the reply */
810     silc_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_LIST,
811                                    status, 0, ident, 4,
812                                    2, idp->data, silc_buffer_len(idp),
813                                    3, entry->channel_name,
814                                    strlen(entry->channel_name),
815                                    4, topic, topic ? strlen(topic) : 0,
816                                    5, usercount, 4);
817     silc_buffer_free(idp);
818     k++;
819   }
820
821   /* Global list */
822   for (i = 0, k = 0; i < gch_count; i++) {
823     entry = gch[i];
824     if (!entry)
825       continue;
826
827     if (k >= 1)
828       status = SILC_STATUS_LIST_ITEM;
829     if (valid_rcount > 1 && k == valid_rcount - 1)
830       status = SILC_STATUS_LIST_END;
831
832     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
833
834     if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
835       topic = "*private*";
836       memset(usercount, 0, sizeof(usercount));
837     } else {
838       topic = entry->topic;
839       users = entry->user_count;
840       SILC_PUT32_MSB(users, usercount);
841     }
842
843     /* Send the reply */
844     silc_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_LIST,
845                                    status, 0, ident, 4,
846                                    2, idp->data, silc_buffer_len(idp),
847                                    3, entry->channel_name,
848                                    strlen(entry->channel_name),
849                                    4, topic, topic ? strlen(topic) : 0,
850                                    5, usercount, 4);
851     silc_buffer_free(idp);
852     k++;
853   }
854 }
855
856 /* Server side of LIST command. This lists the channel of the requested
857    server. Secret channels are not listed. */
858
859 SILC_SERVER_CMD_FUNC(list)
860 {
861   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
862   SilcServer server = cmd->server;
863   SilcID id;
864   SilcChannelID *channel_id = NULL;
865   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
866   SilcUInt32 lch_count = 0, gch_count = 0;
867
868   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 1);
869
870   /* If we are normal server, send the command to router, since we
871      want to know all channels in the network. */
872   if (!cmd->pending && server->server_type != SILC_ROUTER &&
873       !server->standalone) {
874     SilcBuffer tmpbuf;
875     SilcUInt16 old_ident;
876
877     /* Statistics */
878     cmd->server->stat.commands_sent++;
879
880     old_ident = silc_command_get_ident(cmd->payload);
881     silc_command_set_ident(cmd->payload, ++server->cmd_ident);
882     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
883     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
884                             SILC_PACKET_COMMAND, cmd->packet->flags,
885                             tmpbuf->data, silc_buffer_len(tmpbuf));
886
887     /* Reprocess this packet after received reply from router */
888     silc_server_command_pending(server, SILC_COMMAND_LIST,
889                                 silc_command_get_ident(cmd->payload),
890                                 silc_server_command_list,
891                                 silc_server_command_dup(cmd));
892     cmd->pending = TRUE;
893     silc_command_set_ident(cmd->payload, old_ident);
894     silc_buffer_free(tmpbuf);
895     goto out;
896   }
897
898   /* Get Channel ID */
899   if (silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL))
900     channel_id = SILC_ID_GET_ID(id);
901
902   /* Get the channels from local list */
903   lchannels = silc_idlist_get_channels(server->local_list, channel_id,
904                                        &lch_count);
905
906   /* Get the channels from global list */
907   gchannels = silc_idlist_get_channels(server->global_list, channel_id,
908                                        &gch_count);
909
910   /* Send the reply */
911   silc_server_command_list_send_reply(cmd, lchannels, lch_count,
912                                       gchannels, gch_count);
913
914   silc_free(lchannels);
915   silc_free(gchannels);
916
917  out:
918   silc_server_command_free(cmd);
919 }
920
921 /* Server side of TOPIC command. Sets topic for channel and/or returns
922    current topic to client. */
923
924 SILC_SERVER_CMD_FUNC(topic)
925 {
926   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
927   SilcServer server = cmd->server;
928   SilcClientEntry client = silc_packet_get_context(cmd->sock);
929   SilcID id;
930   SilcChannelEntry channel;
931   SilcChannelClientEntry chl;
932   SilcBuffer idp;
933   unsigned char *tmp;
934   SilcUInt32 argc, tmp_len;
935   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
936
937   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
938     goto out;
939
940   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
941
942   argc = silc_argument_get_arg_num(cmd->args);
943
944   /* Get Channel ID */
945   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
946     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
947                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
948     goto out;
949   }
950
951   /* Check whether the channel exists */
952   channel = silc_idlist_find_channel_by_id(server->local_list,
953                                            SILC_ID_GET_ID(id), NULL);
954   if (!channel) {
955     channel = silc_idlist_find_channel_by_id(server->global_list,
956                                              SILC_ID_GET_ID(id), NULL);
957     if (!channel) {
958       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
959       silc_server_command_send_status_data(cmd, SILC_COMMAND_TOPIC,
960                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
961                                            0, 2, tmp, tmp_len);
962       goto out;
963     }
964   }
965
966   if (argc > 1) {
967     /* Get the topic */
968     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
969     if (!tmp) {
970       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
971                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
972                                             0);
973       goto out;
974     }
975     if (tmp_len > 256) {
976       tmp_len = 256;
977       tmp[tmp_len - 1] = '\0';
978     }
979
980     if (!silc_utf8_valid(tmp, tmp_len)) {
981       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
982                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
983                                             0);
984       goto out;
985     }
986
987     /* See whether the client is on channel and has rights to change topic */
988     if (!silc_server_client_on_channel(client, channel, &chl)) {
989       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
990       silc_server_command_send_status_data(cmd, SILC_COMMAND_TOPIC,
991                                            SILC_STATUS_ERR_NOT_ON_CHANNEL,
992                                            0, 2, tmp, tmp_len);
993       goto out;
994     }
995
996     if (channel->mode & SILC_CHANNEL_MODE_TOPIC &&
997         !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
998         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
999       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1000       silc_server_command_send_status_data(cmd, SILC_COMMAND_TOPIC,
1001                                            SILC_STATUS_ERR_NO_CHANNEL_PRIV,
1002                                            0, 2, tmp, tmp_len);
1003       goto out;
1004     }
1005
1006     if (!channel->topic || strcmp(channel->topic, tmp)) {
1007       /* Set the topic for channel */
1008       silc_free(channel->topic);
1009       channel->topic = strdup(tmp);
1010
1011       /* Send TOPIC_SET notify type to the network */
1012       silc_server_send_notify_topic_set(server, SILC_PRIMARY_ROUTE(server),
1013                                         SILC_BROADCAST(server), channel,
1014                                         client->id, SILC_ID_CLIENT,
1015                                         channel->topic);
1016
1017       /* Send notify about topic change to all clients on the channel */
1018       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1019       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
1020                                          SILC_NOTIFY_TYPE_TOPIC_SET, 2,
1021                                          idp->data, silc_buffer_len(idp),
1022                                          channel->topic,
1023                                          strlen(channel->topic));
1024       silc_buffer_free(idp);
1025     }
1026   }
1027
1028   /* Send the topic to client as reply packet */
1029   idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
1030   silc_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_TOPIC,
1031                                  SILC_STATUS_OK, 0, ident, 2,
1032                                  2, idp->data, silc_buffer_len(idp),
1033                                  3, channel->topic,
1034                                  channel->topic ?
1035                                  strlen(channel->topic) : 0);
1036   silc_buffer_free(idp);
1037
1038  out:
1039   silc_server_command_free(cmd);
1040 }
1041
1042 /* Server side of INVITE command. Invites some client to join some channel.
1043    This command is also used to manage the invite list of the channel. */
1044
1045 SILC_SERVER_CMD_FUNC(invite)
1046 {
1047   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1048   SilcServer server = cmd->server;
1049   SilcPacketStream sock = cmd->sock, dest_sock;
1050   SilcChannelClientEntry chl;
1051   SilcClientEntry sender, dest;
1052   SilcChannelEntry channel;
1053   SilcID id, id2;
1054   SilcIDListData idata;
1055   SilcArgumentPayload args;
1056   SilcHashTableList htl;
1057   SilcBuffer list, tmp2;
1058   SilcBufferStruct alist;
1059   unsigned char *tmp, *atype = NULL;
1060   SilcUInt32 len, len2, ttype;
1061   void *type;
1062   SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
1063
1064   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
1065
1066   /* Get Channel ID */
1067   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
1068     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1069                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
1070     goto out;
1071   }
1072
1073   /* Get the channel entry */
1074   channel = silc_idlist_find_channel_by_id(server->local_list,
1075                                            SILC_ID_GET_ID(id), NULL);
1076   if (!channel) {
1077     channel = silc_idlist_find_channel_by_id(server->global_list,
1078                                              SILC_ID_GET_ID(id), NULL);
1079     if (!channel) {
1080       tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1081       silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
1082                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
1083                                            0, 2, tmp, len);
1084       goto out;
1085     }
1086   }
1087
1088   /* Check whether the sender of this command is on the channel. */
1089   sender = silc_packet_get_context(sock);
1090   if (!sender || !silc_server_client_on_channel(sender, channel, &chl)) {
1091     tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1092     silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
1093                                          SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
1094                                          2, tmp, len);
1095     goto out;
1096   }
1097
1098   /* Check whether the channel is invite-only channel. If yes then the
1099      sender of this command must be at least channel operator. */
1100   if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
1101       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
1102       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
1103     tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1104     silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
1105                                          SILC_STATUS_ERR_NO_CHANNEL_PRIV,
1106                                          0, 2, tmp, len);
1107     goto out;
1108   }
1109
1110   /* Get destination client ID */
1111   if (silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id2, NULL)) {
1112     SilcBool resolve;
1113
1114     /* Get the client entry */
1115     dest = silc_server_query_client(server, SILC_ID_GET_ID(id2),
1116                                     FALSE, &resolve);
1117     if (!dest) {
1118       if (server->server_type != SILC_SERVER || !resolve || cmd->pending) {
1119         tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1120         silc_server_command_send_status_data(
1121                                         cmd, SILC_COMMAND_INVITE,
1122                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
1123                                         2, tmp, len);
1124         goto out;
1125       }
1126
1127       /* The client info is being resolved. Reprocess this packet after
1128          receiving the reply to the query. */
1129       silc_server_command_pending(server, SILC_COMMAND_WHOIS,
1130                                   server->cmd_ident,
1131                                   silc_server_command_invite,
1132                                   silc_server_command_dup(cmd));
1133       cmd->pending = TRUE;
1134       goto out;
1135     }
1136
1137     /* Check whether the requested client is already on the channel. */
1138     if (silc_server_client_on_channel(dest, channel, NULL)) {
1139       tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1140       atype = silc_argument_get_arg_type(cmd->args, 1, &len2);
1141       silc_server_command_send_status_data2(cmd, SILC_COMMAND_INVITE,
1142                                             SILC_STATUS_ERR_USER_ON_CHANNEL,
1143                                             0, 2, tmp, len,
1144                                             3, atype, len2);
1145       goto out;
1146     }
1147
1148     /* Get route to the client */
1149     dest_sock = silc_server_get_client_route(server, NULL, 0,
1150                                              SILC_ID_GET_ID(id2),
1151                                              &idata, NULL);
1152     if (!dest_sock) {
1153       tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1154       silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
1155                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
1156                                            0, 2, tmp, len);
1157       goto out;
1158     }
1159
1160     /* Add the client to the invite list */
1161
1162     /* Allocate hash table for invite list if it doesn't exist yet */
1163     if (!channel->invite_list)
1164       channel->invite_list =
1165         silc_hash_table_alloc(0, silc_hash_ptr,
1166                               NULL, NULL, NULL,
1167                               silc_server_inviteban_destruct, channel, TRUE);
1168
1169     /* Check if the ID is in the list already */
1170     tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1171     silc_hash_table_list(channel->invite_list, &htl);
1172     while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2)) {
1173       if (SILC_PTR_TO_32(type) == 3 && !memcmp(tmp2->data, tmp, len)) {
1174         tmp = NULL;
1175         break;
1176       }
1177     }
1178     silc_hash_table_list_reset(&htl);
1179
1180     /* Add new Client ID to invite list */
1181     if (tmp) {
1182       list = silc_buffer_alloc_size(len);
1183       silc_buffer_put(list, tmp, len);
1184       silc_hash_table_add(channel->invite_list, (void *)3, list);
1185     }
1186
1187     if (!(dest->mode & SILC_UMODE_BLOCK_INVITE)) {
1188       /* Send notify to the client that is invited to the channel */
1189       SilcBuffer idp, idp2;
1190       idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
1191       idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
1192       silc_server_send_notify_dest(server, dest_sock, FALSE,
1193                                    SILC_ID_GET_ID(id2), SILC_ID_CLIENT,
1194                                    SILC_NOTIFY_TYPE_INVITE, 3,
1195                                    idp->data, silc_buffer_len(idp),
1196                                    channel->channel_name,
1197                                    strlen(channel->channel_name),
1198                                    idp2->data, silc_buffer_len(idp2));
1199       silc_buffer_free(idp);
1200       silc_buffer_free(idp2);
1201     }
1202   }
1203
1204   /* Get the invite information */
1205   tmp = silc_argument_get_arg_type(cmd->args, 4, &len2);
1206   if (tmp && len2 > 2) {
1207     /* Parse the arguments to see they are constructed correctly */
1208     SILC_GET16_MSB(argc, tmp);
1209     args = silc_argument_payload_parse(tmp + 2, len2 - 2, argc);
1210     if (!args) {
1211       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1212                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
1213                                             0);
1214       goto out;
1215     }
1216
1217     /* Get the type of action */
1218     atype = silc_argument_get_arg_type(cmd->args, 3, &len);
1219     if (atype && len == 1) {
1220       if (atype[0] == 0x00) {
1221         /* Allocate hash table for invite list if it doesn't exist yet */
1222         if (!channel->invite_list)
1223           channel->invite_list =
1224             silc_hash_table_alloc(0, silc_hash_ptr,
1225                                   NULL, NULL, NULL,
1226                                   silc_server_inviteban_destruct, channel,
1227                                   TRUE);
1228
1229         /* Check for resource limit */
1230         if (silc_hash_table_count(channel->invite_list) > 64) {
1231           silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1232                                                 SILC_STATUS_ERR_RESOURCE_LIMIT,
1233                                                 0);
1234           goto out;
1235         }
1236       }
1237
1238       /* Now add or delete the information. */
1239       if (!silc_server_inviteban_process(server, channel->invite_list,
1240                                          (SilcUInt8)atype[0], args)) {
1241         silc_server_command_send_status_reply(
1242                                     cmd, SILC_COMMAND_INVITE,
1243                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
1244                                     0);
1245         goto out;
1246       }
1247     }
1248     silc_argument_payload_free(args);
1249   }
1250
1251   /* Encode invite list */
1252   list = NULL;
1253   if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
1254     list = silc_buffer_alloc_size(2);
1255     silc_buffer_format(list,
1256                        SILC_STR_UI_SHORT(silc_hash_table_count(
1257                                           channel->invite_list)),
1258                        SILC_STR_END);
1259     silc_hash_table_list(channel->invite_list, &htl);
1260     while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
1261       list = silc_argument_payload_encode_one(list, tmp2->data,
1262                                               silc_buffer_len(tmp2),
1263                                               SILC_PTR_TO_32(type));
1264     silc_hash_table_list_reset(&htl);
1265   }
1266
1267   /* The notify is sent to local servers (not clients), and to network. */
1268   if (atype && tmp && len2) {
1269     silc_buffer_set(&alist, tmp, len2);
1270
1271     /* Send to local servers if we are router */
1272     if (server->server_type == SILC_ROUTER) {
1273       SilcBuffer idp, idp2;
1274       idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
1275       idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
1276       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, FALSE,
1277                                          SILC_NOTIFY_TYPE_INVITE, 5,
1278                                          idp->data, silc_buffer_len(idp),
1279                                          channel->channel_name,
1280                                          strlen(channel->channel_name),
1281                                          idp2->data, silc_buffer_len(idp2),
1282                                          atype, 1,
1283                                          tmp ? alist.data : NULL,
1284                                          tmp ? silc_buffer_len(&alist) : 0);
1285       silc_buffer_free(idp);
1286       silc_buffer_free(idp2);
1287     }
1288
1289     /* Send to network */
1290     silc_server_send_notify_invite(server, SILC_PRIMARY_ROUTE(server),
1291                                    SILC_BROADCAST(server), channel,
1292                                    sender->id, atype,
1293                                    tmp ? &alist : NULL);
1294   }
1295
1296   /* Send invite list back only if the list was modified, or no arguments
1297      was given. */
1298   ttype = 0;
1299   argc = silc_argument_get_arg_num(cmd->args);
1300   if (argc == 1)
1301     ttype = 1;
1302   if (silc_argument_get_arg_type(cmd->args, 3, &len))
1303     ttype = 1;
1304
1305   /* Send command reply */
1306   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1307   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_INVITE,
1308                                  SILC_STATUS_OK, 0, ident, 2,
1309                                  2, tmp, len,
1310                                  3, ttype && list ?
1311                                  list->data : NULL,
1312                                  ttype && list ? silc_buffer_len(list) : 0);
1313   silc_buffer_free(list);
1314
1315  out:
1316   silc_server_command_free(cmd);
1317 }
1318
1319 typedef struct {
1320   SilcPacketStream sock;
1321   char *signoff;
1322 } *QuitInternal;
1323
1324 /* Quits connection to client. This gets called if client won't
1325    close the connection even when it has issued QUIT command. */
1326
1327 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
1328 {
1329   SilcServer server = app_context;
1330   QuitInternal q = (QuitInternal)context;
1331   SilcClientEntry client = silc_packet_get_context(q->sock);
1332
1333   if (client) {
1334     /* Free all client specific data, such as client entry and entires
1335        on channels this client may be on. */
1336     silc_server_free_sock_user_data(server, q->sock, q->signoff);
1337     silc_server_close_connection(server, q->sock);
1338   }
1339
1340   silc_packet_stream_unref(q->sock);
1341   silc_free(q->signoff);
1342   silc_free(q);
1343 }
1344
1345 /* Quits SILC session. This is the normal way to disconnect client. */
1346
1347 SILC_SERVER_CMD_FUNC(quit)
1348 {
1349   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1350   SilcServer server = cmd->server;
1351   SilcPacketStream sock = cmd->sock;
1352   SilcClientEntry client = silc_packet_get_context(sock);
1353   QuitInternal q;
1354   unsigned char *tmp = NULL;
1355   SilcUInt32 len = 0;
1356
1357   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_QUIT, cmd, 0, 1);
1358
1359   if (client->data.conn_type != SILC_CONN_CLIENT)
1360     goto out;
1361
1362   /* Get message */
1363   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1364   if (len > 128)
1365     tmp = NULL;
1366
1367   q = silc_calloc(1, sizeof(*q));
1368   q->sock = sock;
1369   q->signoff = tmp ? strdup(tmp) : NULL;
1370   silc_packet_stream_ref(q->sock);
1371
1372   /* We quit the connection with little timeout */
1373   silc_schedule_task_add_timeout(server->schedule,
1374                                  silc_server_command_quit_cb, (void *)q,
1375                                  0, 200000);
1376
1377  out:
1378   silc_server_command_free(cmd);
1379 }
1380
1381 /* Server side of command KILL. This command is used by router operator
1382    to remove an client from the SILC Network temporarily. */
1383
1384 SILC_SERVER_CMD_FUNC(kill)
1385 {
1386   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1387   SilcServer server = cmd->server;
1388   SilcClientEntry client = silc_packet_get_context(cmd->sock);
1389   SilcClientEntry remote_client;
1390   SilcID id;
1391   unsigned char *tmp, *comment, *auth;
1392   SilcUInt32 tmp_len, tmp_len2, auth_len;
1393
1394   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 3);
1395
1396   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
1397     goto out;
1398
1399   /* Get authentication payload if present */
1400   auth = silc_argument_get_arg_type(cmd->args, 3, &auth_len);
1401
1402   if (!auth) {
1403     /* Router operator killing */
1404
1405     /* KILL command works only on router */
1406     if (server->server_type != SILC_ROUTER) {
1407       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
1408                                             SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
1409       goto out;
1410     }
1411
1412     /* Check whether client has the permissions. */
1413     if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
1414       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
1415                                             SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
1416       goto out;
1417     }
1418   }
1419
1420   /* Get the client ID */
1421   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
1422     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
1423                                           SILC_STATUS_ERR_NO_CLIENT_ID, 0);
1424     goto out;
1425   }
1426
1427   /* Get the client entry */
1428   remote_client = silc_idlist_find_client_by_id(server->local_list,
1429                                                 SILC_ID_GET_ID(id),
1430                                                 TRUE, NULL);
1431   if (!remote_client) {
1432     remote_client = silc_idlist_find_client_by_id(server->global_list,
1433                                                   SILC_ID_GET_ID(id),
1434                                                   TRUE, NULL);
1435     if (!remote_client) {
1436       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1437       silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
1438                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
1439                                            0, 2, tmp, tmp_len);
1440       goto out;
1441     }
1442   }
1443
1444   /* Get comment */
1445   comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
1446   if (comment && tmp_len2 > 128) {
1447     tmp_len2 = 128;
1448     comment[tmp_len2 - 1] = '\0';
1449   }
1450
1451   /* If authentication data is provided then verify that killing is
1452      actually allowed */
1453   if (auth && auth_len) {
1454     SilcPacketStream sock;
1455
1456     if (!SILC_IS_LOCAL(remote_client) || !remote_client->data.public_key) {
1457       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
1458                                             SILC_STATUS_ERR_OPERATION_ALLOWED,
1459                                             0);
1460       goto out;
1461     }
1462
1463     /* Verify the signature */
1464     if (!silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
1465                                remote_client->data.public_key, 0,
1466                                server->sha1hash, remote_client->id,
1467                                SILC_ID_CLIENT)) {
1468       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
1469                                             SILC_STATUS_ERR_AUTH_FAILED, 0);
1470       goto out;
1471     }
1472
1473     /* Send reply to the sender */
1474     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1475     silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
1476                                          SILC_STATUS_OK, 0,
1477                                          2, tmp, tmp_len);
1478
1479     /* Do normal signoff for the destination client */
1480     sock = remote_client->connection;
1481
1482     if (sock)
1483       silc_packet_stream_ref(sock);
1484
1485     silc_server_remove_from_channels(server, NULL, remote_client,
1486                                      TRUE, (char *)"Killed", TRUE, TRUE);
1487     silc_server_free_sock_user_data(server, sock, comment ? comment :
1488                                     (unsigned char *)"Killed");
1489     if (sock) {
1490       silc_packet_set_context(sock, NULL);
1491       silc_server_close_connection(server, sock);
1492       silc_packet_stream_unref(sock);
1493     }
1494   } else {
1495     /* Router operator killing */
1496
1497     /* Send reply to the sender */
1498     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1499     silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
1500                                          SILC_STATUS_OK, 0,
1501                                          2, tmp, tmp_len);
1502
1503     /* Check if anyone is watching this nickname */
1504     if (server->server_type == SILC_ROUTER)
1505       silc_server_check_watcher_list(server, client, NULL,
1506                                      SILC_NOTIFY_TYPE_KILLED);
1507
1508     /* Now do the killing */
1509     silc_server_kill_client(server, remote_client, comment, client->id,
1510                             SILC_ID_CLIENT);
1511   }
1512
1513  out:
1514   silc_server_command_free(cmd);
1515 }
1516
1517 /* Server side of command INFO. This sends information about us to
1518    the client. If client requested specific server we will send the
1519    command to that server. */
1520
1521 SILC_SERVER_CMD_FUNC(info)
1522 {
1523   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1524   SilcServer server = cmd->server;
1525   SilcBuffer idp;
1526   unsigned char *tmp;
1527   SilcUInt32 tmp_len;
1528   char *dest_server = NULL, *server_info = NULL, *server_name;
1529   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1530   SilcServerEntry entry = NULL;
1531   SilcID id;
1532
1533   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 0, 2);
1534
1535   /* Get server name */
1536   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
1537   if (dest_server) {
1538     /* Check server name. */
1539     dest_server = silc_identifier_check(dest_server, strlen(dest_server),
1540                                         SILC_STRING_UTF8, 256, &tmp_len);
1541     if (!dest_server) {
1542       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1543                                             SILC_STATUS_ERR_BAD_SERVER, 0);
1544       goto out;
1545     }
1546   }
1547
1548   /* Get Server ID */
1549   if (silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
1550     /* Check whether we have this server cached */
1551     entry = silc_idlist_find_server_by_id(server->local_list,
1552                                           SILC_ID_GET_ID(id), TRUE, NULL);
1553     if (!entry) {
1554       entry = silc_idlist_find_server_by_id(server->global_list,
1555                                             SILC_ID_GET_ID(id), TRUE, NULL);
1556       if (!entry && server->server_type != SILC_SERVER) {
1557         tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1558         silc_server_command_send_status_data(cmd, SILC_COMMAND_INFO,
1559                                              SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
1560                                              0, 2, tmp, tmp_len);
1561         goto out;
1562       }
1563     }
1564   }
1565
1566   if ((!dest_server && !entry) || (entry && entry == server->id_entry) ||
1567       (dest_server && !cmd->pending &&
1568        !memcmp(dest_server, server->server_name, strlen(dest_server)))) {
1569     /* Send our reply */
1570     char info_string[256];
1571
1572     memset(info_string, 0, sizeof(info_string));
1573     silc_snprintf(info_string, sizeof(info_string),
1574                   "location: %s server: %s admin: %s <%s> version: %s",
1575                   server->config->server_info->location,
1576                   server->config->server_info->server_type,
1577                   server->config->server_info->admin,
1578                   server->config->server_info->email,
1579                   silc_dist_version);
1580
1581     server_info = info_string;
1582     entry = server->id_entry;
1583   } else {
1584     /* Check whether we have this server cached */
1585     if (!entry && dest_server) {
1586       entry = silc_idlist_find_server_by_name(server->global_list,
1587                                               dest_server, TRUE, NULL);
1588       if (!entry) {
1589         entry = silc_idlist_find_server_by_name(server->local_list,
1590                                                 dest_server, TRUE, NULL);
1591       }
1592     }
1593
1594     if (!cmd->pending &&
1595         server->server_type != SILC_SERVER && entry && !entry->server_info) {
1596       /* Send to the server */
1597       SilcBuffer tmpbuf;
1598       SilcUInt16 old_ident;
1599
1600       /* Statistics */
1601       cmd->server->stat.commands_sent++;
1602
1603       old_ident = silc_command_get_ident(cmd->payload);
1604       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
1605       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
1606
1607       silc_server_packet_send(server, entry->connection,
1608                               SILC_PACKET_COMMAND, cmd->packet->flags,
1609                               tmpbuf->data, silc_buffer_len(tmpbuf));
1610
1611       /* Reprocess this packet after received reply from router */
1612       silc_server_command_pending(server, SILC_COMMAND_INFO,
1613                                   silc_command_get_ident(cmd->payload),
1614                                   silc_server_command_info,
1615                                   silc_server_command_dup(cmd));
1616       cmd->pending = TRUE;
1617       silc_command_set_ident(cmd->payload, old_ident);
1618       silc_buffer_free(tmpbuf);
1619       goto out;
1620     }
1621
1622     if (!entry && !cmd->pending && !server->standalone) {
1623       /* Send to the primary router */
1624       SilcBuffer tmpbuf;
1625       SilcUInt16 old_ident;
1626
1627       /* Statistics */
1628       cmd->server->stat.commands_sent++;
1629
1630       old_ident = silc_command_get_ident(cmd->payload);
1631       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
1632       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
1633
1634       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
1635                               SILC_PACKET_COMMAND, cmd->packet->flags,
1636                               tmpbuf->data, silc_buffer_len(tmpbuf));
1637
1638       /* Reprocess this packet after received reply from router */
1639       silc_server_command_pending(server, SILC_COMMAND_INFO,
1640                                   silc_command_get_ident(cmd->payload),
1641                                   silc_server_command_info,
1642                                   silc_server_command_dup(cmd));
1643       cmd->pending = TRUE;
1644       silc_command_set_ident(cmd->payload, old_ident);
1645       silc_buffer_free(tmpbuf);
1646       goto out;
1647     }
1648   }
1649
1650   if (!entry) {
1651     if (dest_server) {
1652       silc_free(dest_server);
1653       dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
1654       silc_server_command_send_status_data(cmd, SILC_COMMAND_INFO,
1655                                            SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
1656                                            2, dest_server,
1657                                            strlen(dest_server));
1658       dest_server = NULL;
1659     }
1660     goto out;
1661   }
1662
1663   idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1664   if (!server_info)
1665     server_info = entry->server_info;
1666   server_name = entry->server_name;
1667
1668   /* Send the reply */
1669   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_INFO,
1670                                  SILC_STATUS_OK, 0, ident, 3,
1671                                  2, idp->data, silc_buffer_len(idp),
1672                                  3, server_name,
1673                                  strlen(server_name),
1674                                  4, server_info,
1675                                  server_info ?
1676                                  strlen(server_info) : 0);
1677   silc_buffer_free(idp);
1678
1679  out:
1680   silc_free(dest_server);
1681   silc_server_command_free(cmd);
1682 }
1683
1684 /* Server side of command PING. This just replies to the ping. */
1685
1686 SILC_SERVER_CMD_FUNC(ping)
1687 {
1688   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1689   SilcServer server = cmd->server;
1690   SilcUInt32 tmp_len;
1691   unsigned char *tmp;
1692   SilcID id;
1693
1694   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PING, cmd, 1, 1);
1695
1696   /* Get Server ID */
1697   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
1698     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1699                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
1700                                           0);
1701     goto out;
1702   }
1703
1704   if (SILC_ID_SERVER_COMPARE(SILC_ID_GET_ID(id), server->id)) {
1705     /* Send our reply */
1706     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1707                                           SILC_STATUS_OK, 0);
1708   } else {
1709     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1710     silc_server_command_send_status_data(cmd, SILC_COMMAND_PING,
1711                                          SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
1712                                          2, tmp, tmp_len);
1713     goto out;
1714   }
1715
1716  out:
1717   silc_server_command_free(cmd);
1718 }
1719
1720 /* Server side of command STATS. */
1721
1722 SILC_SERVER_CMD_FUNC(stats)
1723 {
1724   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1725   SilcServer server = cmd->server;
1726   SilcID id;
1727   unsigned char *tmp;
1728   SilcUInt32 tmp_len;
1729   SilcBuffer packet, stats;
1730   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1731   SilcUInt32 uptime;
1732
1733   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_STATS, cmd, 1, 1);
1734
1735   /* Get Server ID */
1736   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
1737     silc_server_command_send_status_reply(cmd, SILC_COMMAND_STATS,
1738                                           SILC_STATUS_ERR_NO_SERVER_ID, 0);
1739     goto out;
1740   }
1741
1742   SILC_LOG_DEBUG(("id %s", silc_id_render(SILC_ID_GET_ID(id),
1743                                           id.type)));
1744
1745   /* The ID must be ours */
1746   if (!SILC_ID_SERVER_COMPARE(server->id, SILC_ID_GET_ID(id))) {
1747     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1748     silc_server_command_send_status_data(cmd, SILC_COMMAND_STATS,
1749                                          SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
1750                                          2, tmp, tmp_len);
1751     goto out;
1752   }
1753
1754   /* If we are router then just send everything we got. If we are normal
1755      server then we'll send this to our router to get all the latest
1756      statistical information. */
1757   if (!cmd->pending && server->server_type != SILC_ROUTER &&
1758       !server->standalone) {
1759     SilcBuffer idp;
1760
1761     /* Statistics */
1762     cmd->server->stat.commands_sent++;
1763
1764     /* Send request to our router */
1765     idp = silc_id_payload_encode(server->router->id,
1766                                  SILC_ID_SERVER);
1767     packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
1768                                             ++server->cmd_ident, 1,
1769                                             1, idp->data,
1770                                             silc_buffer_len(idp));
1771     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
1772                             SILC_PACKET_COMMAND, 0, packet->data,
1773                             silc_buffer_len(packet));
1774
1775     /* Reprocess this packet after received reply from router */
1776     silc_server_command_pending(server, SILC_COMMAND_STATS,
1777                                 server->cmd_ident,
1778                                 silc_server_command_stats,
1779                                 silc_server_command_dup(cmd));
1780     cmd->pending = TRUE;
1781     silc_buffer_free(packet);
1782     silc_buffer_free(idp);
1783     goto out;
1784   }
1785
1786   /* Send our reply to sender */
1787   uptime = time(NULL) - server->starttime;
1788
1789   stats = silc_buffer_alloc_size(60);
1790   silc_buffer_format(stats,
1791                      SILC_STR_UI_INT(server->starttime),
1792                      SILC_STR_UI_INT(uptime),
1793                      SILC_STR_UI_INT(server->stat.my_clients),
1794                      SILC_STR_UI_INT(server->stat.my_channels),
1795                      SILC_STR_UI_INT(server->stat.my_server_ops),
1796                      SILC_STR_UI_INT(server->stat.my_router_ops),
1797                      SILC_STR_UI_INT(server->stat.cell_clients),
1798                      SILC_STR_UI_INT(server->stat.cell_channels),
1799                      SILC_STR_UI_INT(server->stat.cell_servers),
1800                      SILC_STR_UI_INT(server->stat.clients),
1801                      SILC_STR_UI_INT(server->stat.channels),
1802                      SILC_STR_UI_INT(server->stat.servers),
1803                      SILC_STR_UI_INT(server->stat.routers),
1804                      SILC_STR_UI_INT(server->stat.server_ops),
1805                      SILC_STR_UI_INT(server->stat.router_ops),
1806                      SILC_STR_END);
1807
1808   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1809   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_STATS,
1810                                  SILC_STATUS_OK, 0, ident, 2,
1811                                  2, tmp, tmp_len,
1812                                  3, stats->data, silc_buffer_len(stats));
1813   silc_buffer_free(stats);
1814
1815  out:
1816   silc_server_command_free(cmd);
1817 }
1818
1819 /* Internal routine to join channel. The channel sent to this function
1820    has been either created or resolved from ID lists. This joins the sent
1821    client to the channel. */
1822
1823 static void silc_server_command_join_channel(SilcServer server,
1824                                              SilcServerCommandContext cmd,
1825                                              SilcChannelEntry channel,
1826                                              SilcClientID *client_id,
1827                                              SilcBool created,
1828                                              SilcBool create_key,
1829                                              SilcUInt32 umode,
1830                                              const unsigned char *auth,
1831                                              SilcUInt32 auth_len,
1832                                              const unsigned char *cauth,
1833                                              SilcUInt32 cauth_len)
1834 {
1835   SilcPacketStream sock = cmd->sock;
1836   SilcIDListData idata = silc_packet_get_context(sock);
1837   unsigned char *tmp;
1838   SilcUInt32 tmp_len, user_count;
1839   unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4], ulimit[4];
1840   SilcClientEntry client;
1841   SilcChannelClientEntry chl;
1842   SilcBuffer reply, chidp, clidp, keyp = NULL;
1843   SilcBuffer user_list, mode_list, invite_list, ban_list;
1844   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1845   char check[512], check2[512];
1846   void *plen;
1847   SilcBool founder = FALSE;
1848   SilcBool resolve;
1849   SilcBuffer fkey = NULL, chpklist = NULL;
1850   const char *cipher, *hostname, *ip;
1851
1852   SILC_LOG_DEBUG(("Joining client to channel"));
1853
1854   if (!channel)
1855     return;
1856
1857   silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
1858                               NULL, &hostname, &ip, NULL);
1859
1860   /* Get the client entry */
1861   if (idata->conn_type == SILC_CONN_CLIENT) {
1862     client = (SilcClientEntry)idata;
1863     if (!client)
1864       return;
1865   } else {
1866     client = silc_server_query_client(server, client_id, FALSE,
1867                                       &resolve);
1868     if (!client) {
1869       if (!resolve || cmd->pending) {
1870         tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1871         silc_server_command_send_status_data(
1872                                          cmd, SILC_COMMAND_JOIN,
1873                                          SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
1874                                          2, tmp, tmp_len);
1875         goto out;
1876       }
1877
1878       /* The client info is being resolved. Reprocess this packet after
1879          receiving the reply to the query. */
1880       silc_server_command_pending(server, SILC_COMMAND_WHOIS,
1881                                   server->cmd_ident,
1882                                   silc_server_command_join,
1883                                   silc_server_command_dup(cmd));
1884       cmd->pending = TRUE;
1885       goto out;
1886     }
1887
1888     if (!client->data.public_key &&
1889         (auth || cauth || channel->ban_list ||
1890          (channel->mode & SILC_CHANNEL_MODE_INVITE))) {
1891       if (cmd->pending == 2)
1892         goto out;
1893
1894       /* We must retrieve the client's public key by sending
1895          GETKEY command. Reprocess this packet after receiving the key */
1896       clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1897       silc_server_send_command(server, cmd->sock,
1898                                SILC_COMMAND_GETKEY, ++server->cmd_ident,
1899                                1, 1, clidp->data, silc_buffer_len(clidp));
1900       silc_buffer_free(clidp);
1901       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
1902                                   server->cmd_ident,
1903                                   silc_server_command_join,
1904                                   silc_server_command_dup(cmd));
1905       cmd->pending = 2;
1906       goto out;
1907     }
1908
1909     cmd->pending = FALSE;
1910   }
1911
1912   /*
1913    * Check founder auth payload if provided.  If client can gain founder
1914    * privileges it can override various conditions on joining the channel,
1915    * and can have directly the founder mode set on the channel.
1916    */
1917   if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
1918     SilcIDListData idata = (SilcIDListData)client;
1919     SilcChannelClientEntry chl2;
1920     SilcHashTableList htl;
1921
1922     if (channel->founder_key && idata->public_key &&
1923         silc_pkcs_public_key_compare(channel->founder_key,
1924                                      idata->public_key)) {
1925       /* Check whether the client is to become founder */
1926       if (silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
1927                                 channel->founder_key, 0, server->sha1hash,
1928                                 client->id, SILC_ID_CLIENT)) {
1929
1930         /* There cannot be anyone else as founder on the channel now.  This
1931            client is definitely the founder due to this authentication */
1932         silc_hash_table_list(channel->user_list, &htl);
1933         while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
1934           if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
1935             chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
1936             silc_server_force_cumode_change(server, NULL, channel, chl2,
1937                                             chl2->mode);
1938             break;
1939           }
1940         silc_hash_table_list_reset(&htl);
1941
1942         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
1943         founder = TRUE;
1944       }
1945     }
1946   }
1947
1948   /*
1949    * Check channel modes
1950    */
1951
1952   if (!umode) {
1953     memset(check, 0, sizeof(check));
1954     memset(check2, 0, sizeof(check2));
1955     silc_strncat(check, sizeof(check),
1956                  client->nickname, strlen(client->nickname));
1957     silc_strncat(check, sizeof(check), "!", 1);
1958     silc_strncat(check, sizeof(check),
1959                  client->username, strlen(client->username));
1960     if (!strchr(client->username, '@')) {
1961       silc_strncat(check, sizeof(check), "@", 1);
1962       silc_strncat(check, sizeof(check),
1963                    hostname, strlen(hostname));
1964     }
1965
1966     silc_strncat(check2, sizeof(check2),
1967                  client->nickname, strlen(client->nickname));
1968     if (!strchr(client->nickname, '@')) {
1969       silc_strncat(check2, sizeof(check2), "@", 1);
1970       silc_strncat(check2, sizeof(check2),
1971                    SILC_IS_LOCAL(client) ? server->server_name :
1972                    client->router->server_name,
1973                    SILC_IS_LOCAL(client) ? strlen(server->server_name) :
1974                    strlen(client->router->server_name));
1975     }
1976     silc_strncat(check2, sizeof(check2), "!", 1);
1977     silc_strncat(check2, sizeof(check2),
1978                  client->username, strlen(client->username));
1979     if (!strchr(client->username, '@')) {
1980       silc_strncat(check2, sizeof(check2), "@", 1);
1981       silc_strncat(check2, sizeof(check2),
1982                    hostname, strlen(hostname));
1983     }
1984
1985     /* Check invite list if channel is invite-only channel */
1986     if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1987       if (!channel->invite_list ||
1988           !silc_hash_table_count(channel->invite_list) ||
1989           (!silc_server_inviteban_match(server, channel->invite_list,
1990                                         3, client->id) &&
1991            !silc_server_inviteban_match(server, channel->invite_list,
1992                                         2, client->data.public_key) &&
1993            !silc_server_inviteban_match(server, channel->invite_list,
1994                                         1, client->nickname) &&
1995            !silc_server_inviteban_match(server, channel->invite_list,
1996                                         1, check) &&
1997            !silc_server_inviteban_match(server, channel->invite_list,
1998                                         1, check2))) {
1999         chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2000         silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
2001                                              SILC_STATUS_ERR_NOT_INVITED, 0,
2002                                              2, chidp->data,
2003                                              silc_buffer_len(chidp));
2004         silc_buffer_free(chidp);
2005         goto out;
2006       }
2007     }
2008
2009     /* Check ban list if it exists. If the client's nickname, server,
2010        username and/or hostname is in the ban list the access to the
2011        channel is denied. */
2012     if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
2013       if (silc_server_inviteban_match(server, channel->ban_list,
2014                                       3, client->id) ||
2015           silc_server_inviteban_match(server, channel->ban_list,
2016                                       2, client->data.public_key) ||
2017           silc_server_inviteban_match(server, channel->ban_list,
2018                                       1, client->nickname) ||
2019           silc_server_inviteban_match(server, channel->ban_list,
2020                                       1, check) ||
2021           silc_server_inviteban_match(server, channel->ban_list,
2022                                       1, check2)) {
2023         chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2024         silc_server_command_send_status_data(
2025                                       cmd, SILC_COMMAND_JOIN,
2026                                       SILC_STATUS_ERR_BANNED_FROM_CHANNEL, 0,
2027                                       2, chidp->data,
2028                                       silc_buffer_len(chidp));
2029         silc_buffer_free(chidp);
2030         goto out;
2031       }
2032     }
2033
2034     /* Check user count limit if set. */
2035     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
2036       if (silc_hash_table_count(channel->user_list) + 1 >
2037           channel->user_limit) {
2038         chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2039         silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
2040                                              SILC_STATUS_ERR_CHANNEL_IS_FULL,
2041                                              0, 2, chidp->data,
2042                                              silc_buffer_len(chidp));
2043         silc_buffer_free(chidp);
2044         goto out;
2045       }
2046     }
2047   }
2048
2049   /* Check the channel passphrase if set. */
2050   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2051     /* Get passphrase */
2052     tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2053     if (tmp)
2054       passphrase = silc_memdup(tmp, tmp_len);
2055
2056     if (!passphrase || !channel->passphrase ||
2057         strlen(channel->passphrase) != strlen(passphrase) ||
2058         memcmp(passphrase, channel->passphrase, strlen(channel->passphrase))) {
2059       chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2060       silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
2061                                            SILC_STATUS_ERR_BAD_PASSWORD, 0,
2062                                            2, chidp->data,
2063                                            silc_buffer_len(chidp));
2064       silc_buffer_free(chidp);
2065       goto out;
2066     }
2067   }
2068
2069   /* Verify channel authentication with channel public keys if set. */
2070   if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
2071     if (!silc_server_verify_channel_auth(server, channel, client->id,
2072                                          cauth, cauth_len)) {
2073       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2074                                             SILC_STATUS_ERR_PERM_DENIED, 0);
2075       goto out;
2076     }
2077   }
2078
2079   /*
2080    * Client is allowed to join to the channel. Make it happen.
2081    */
2082
2083   /* Check whether the client already is on the channel */
2084   if (silc_server_client_on_channel(client, channel, NULL)) {
2085     clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2086     chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2087     silc_server_command_send_status_data2(cmd, SILC_COMMAND_JOIN,
2088                                           SILC_STATUS_ERR_USER_ON_CHANNEL, 0,
2089                                           2, clidp->data,
2090                                           silc_buffer_len(clidp),
2091                                           3, chidp->data,
2092                                           silc_buffer_len(chidp));
2093     silc_buffer_free(clidp);
2094     silc_buffer_free(chidp);
2095     goto out;
2096   }
2097
2098   /* Generate new channel key as protocol dictates */
2099   if (create_key) {
2100     if (!silc_server_create_channel_key(server, channel, 0))
2101       goto out;
2102
2103     /* Send the channel key. This is broadcasted to the channel but is not
2104        sent to the client who is joining to the channel. */
2105     if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
2106       silc_server_send_channel_key(server, NULL, channel,
2107                                    server->server_type == SILC_ROUTER ?
2108                                    FALSE : !server->standalone);
2109   }
2110
2111   /* Join the client to the channel by adding it to channel's user list.
2112      Add also the channel to client entry's channels list for fast cross-
2113      referencing. */
2114   chl = silc_calloc(1, sizeof(*chl));
2115   chl->mode = umode;
2116   chl->client = client;
2117   chl->channel = channel;
2118   silc_hash_table_add(channel->user_list, client, chl);
2119   silc_hash_table_add(client->channels, channel, chl);
2120   channel->user_count++;
2121   channel->disabled = FALSE;
2122
2123   /* Get users on the channel */
2124   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
2125                                    &user_count);
2126
2127   /* Encode Client ID Payload of the original client who wants to join */
2128   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2129
2130   /* Encode command reply packet */
2131   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
2132   SILC_PUT32_MSB(channel->mode, mode);
2133   SILC_PUT32_MSB(created, tmp2);
2134   SILC_PUT32_MSB(user_count, tmp3);
2135   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
2136     SILC_PUT32_MSB(channel->user_limit, ulimit);
2137
2138   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
2139     unsigned char cid[32];
2140     SilcUInt32 cid_len;
2141     silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), &cid_len);
2142     cipher = silc_cipher_get_name(channel->send_key);
2143     keyp = silc_channel_key_payload_encode(cid_len, cid,
2144                                            strlen(cipher), cipher,
2145                                            channel->key_len / 8, channel->key);
2146   }
2147
2148   if (channel->founder_key)
2149     fkey = silc_public_key_payload_encode(channel->founder_key);
2150
2151   /* Encode invite list */
2152   invite_list = NULL;
2153   if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
2154     SilcHashTableList htl;
2155
2156     invite_list = silc_buffer_alloc_size(2);
2157     silc_buffer_format(invite_list,
2158                        SILC_STR_UI_SHORT(silc_hash_table_count(
2159                                           channel->invite_list)),
2160                        SILC_STR_END);
2161
2162     silc_hash_table_list(channel->invite_list, &htl);
2163     while (silc_hash_table_get(&htl, (void *)&plen, (void *)&reply))
2164       invite_list = silc_argument_payload_encode_one(invite_list,
2165                                                      reply->data,
2166                                                      silc_buffer_len(reply),
2167                                                      SILC_PTR_TO_32(plen));
2168     silc_hash_table_list_reset(&htl);
2169   }
2170
2171   /* Encode ban list */
2172   ban_list = NULL;
2173   if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
2174     SilcHashTableList htl;
2175
2176     ban_list = silc_buffer_alloc_size(2);
2177     silc_buffer_format(ban_list,
2178                        SILC_STR_UI_SHORT(silc_hash_table_count(
2179                                           channel->ban_list)),
2180                        SILC_STR_END);
2181
2182     silc_hash_table_list(channel->ban_list, &htl);
2183     while (silc_hash_table_get(&htl, (void *)&plen, (void *)&reply))
2184       ban_list = silc_argument_payload_encode_one(ban_list,
2185                                                   reply->data,
2186                                                   silc_buffer_len(reply),
2187                                                   SILC_PTR_TO_32(plen));
2188     silc_hash_table_list_reset(&htl);
2189   }
2190
2191   if (channel->channel_pubkeys)
2192     chpklist = silc_server_get_channel_pk_list(server, channel, FALSE, FALSE);
2193
2194   reply =
2195     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
2196                                          SILC_STATUS_OK, 0, ident, 16,
2197                                          2, channel->channel_name,
2198                                          strlen(channel->channel_name),
2199                                          3, chidp->data,
2200                                          silc_buffer_len(chidp),
2201                                          4, clidp->data,
2202                                          silc_buffer_len(clidp),
2203                                          5, mode, 4,
2204                                          6, tmp2, 4,
2205                                          7, keyp ? keyp->data : NULL,
2206                                          keyp ? silc_buffer_len(keyp) : 0,
2207                                          8, ban_list ? ban_list->data : NULL,
2208                                          ban_list ?
2209                                          silc_buffer_len(ban_list): 0,
2210                                          9, invite_list ? invite_list->data :
2211                                          NULL,
2212                                          invite_list ?
2213                                          silc_buffer_len(invite_list) : 0,
2214                                          10, channel->topic,
2215                                          channel->topic ?
2216                                          strlen(channel->topic) : 0,
2217                                          11, silc_hmac_get_name(channel->hmac),
2218                                          strlen(silc_hmac_get_name(channel->
2219                                                                    hmac)),
2220                                          12, tmp3, 4,
2221                                          13, user_list->data,
2222                                          silc_buffer_len(user_list),
2223                                          14, mode_list->data,
2224                                          silc_buffer_len(mode_list),
2225                                          15, fkey ? fkey->data : NULL,
2226                                          fkey ? silc_buffer_len(fkey) : 0,
2227                                          16, chpklist ? chpklist->data : NULL,
2228                                          chpklist ? silc_buffer_len(chpklist) : 0,
2229                                          17, (channel->mode &
2230                                               SILC_CHANNEL_MODE_ULIMIT ?
2231                                               ulimit : NULL),
2232                                          (channel->mode &
2233                                           SILC_CHANNEL_MODE_ULIMIT ?
2234                                           sizeof(ulimit) : 0));
2235
2236   /* Send command reply */
2237   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
2238                           reply->data, silc_buffer_len(reply));
2239
2240   /* Statistics */
2241   cmd->server->stat.commands_sent++;
2242
2243   /* Send JOIN notify to locally connected clients on the channel. If
2244      we are normal server then router will send or have sent JOIN notify
2245      already. However since we've added the client already to our channel
2246      we'll ignore it (in packet_receive.c) so we must send it here. If
2247      we are router then this will send it to local clients and local
2248      servers. */
2249   SILC_LOG_DEBUG(("Send JOIN notify to channel"));
2250   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
2251                                      SILC_NOTIFY_TYPE_JOIN, 2,
2252                                      clidp->data, silc_buffer_len(clidp),
2253                                      chidp->data, silc_buffer_len(chidp));
2254
2255   /* Update statistics */
2256   server->stat.my_chanclients++;
2257   if (server->server_type == SILC_ROUTER) {
2258     server->stat.cell_chanclients++;
2259     server->stat.chanclients++;
2260   }
2261
2262   if (!cmd->pending) {
2263     /* Send JOIN notify packet to our primary router */
2264     silc_server_send_notify_join(server, SILC_PRIMARY_ROUTE(server),
2265                                  SILC_BROADCAST(server), channel, client->id);
2266
2267     if (keyp)
2268       /* Distribute the channel key to all backup routers. */
2269       silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
2270                               keyp->data, silc_buffer_len(keyp), FALSE, TRUE);
2271
2272     /* If client became founder by providing correct founder auth data
2273        notify the mode change to the channel. */
2274     if (founder) {
2275       SILC_PUT32_MSB(chl->mode, mode);
2276       SILC_LOG_DEBUG(("Send CUMODE_CHANGE notify to channel"));
2277       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
2278                                          SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
2279                                          clidp->data,
2280                                          silc_buffer_len(clidp),
2281                                          mode, 4, clidp->data,
2282                                          silc_buffer_len(clidp),
2283                                          fkey ? fkey->data : NULL,
2284                                          fkey ? silc_buffer_len(fkey) : 0);
2285     }
2286   }
2287
2288   /* Set CUMODE notify type to network */
2289   if (founder)
2290     silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server),
2291                                    SILC_BROADCAST(server), channel,
2292                                    chl->mode, client->id, SILC_ID_CLIENT,
2293                                    client->id, channel->founder_key);
2294
2295   silc_buffer_free(reply);
2296   silc_buffer_free(clidp);
2297   silc_buffer_free(chidp);
2298   silc_buffer_free(keyp);
2299   silc_buffer_free(user_list);
2300   silc_buffer_free(mode_list);
2301   silc_buffer_free(fkey);
2302   silc_buffer_free(chpklist);
2303   silc_buffer_free(invite_list);
2304   silc_buffer_free(ban_list);
2305
2306  out:
2307   if (passphrase)
2308     memset(passphrase, 0, strlen(passphrase));
2309   silc_free(passphrase);
2310 }
2311
2312 /* Server side of command JOIN. Joins client into requested channel. If
2313    the channel does not exist it will be created. */
2314
2315 void silc_server_command_join_connected(SilcServer server,
2316                                         SilcServerEntry server_entry,
2317                                         void *context)
2318 {
2319   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2320
2321   if (!server_entry) {
2322     SilcUInt32 tmp_len;
2323     unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2324     char serv[256 + 1];
2325
2326     SILC_LOG_DEBUG(("Connecting to router failed"));
2327     silc_parse_userfqdn(tmp, NULL, 0, serv, sizeof(serv));
2328
2329     if (serv[0]) {
2330       silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
2331                                            SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
2332                                            2, serv, strlen(serv));
2333     } else {
2334       silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
2335                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0,
2336                                            2, tmp, tmp_len);
2337     }
2338     silc_server_command_free(cmd);
2339     return;
2340   }
2341
2342   /* Reprocess command */
2343   SILC_LOG_DEBUG(("Reprocess JOIN after connecting to router"));
2344   silc_server_command_join(cmd, NULL);
2345 }
2346
2347 SILC_SERVER_CMD_FUNC(join)
2348 {
2349   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2350   SilcServer server = cmd->server;
2351   SilcIDListData idata = silc_packet_get_context(cmd->sock);
2352   unsigned char *auth, *cauth;
2353   SilcUInt32 tmp_len, auth_len, cauth_len;
2354   char *tmp, *channel_name, *channel_namec = NULL, *cipher, *hmac;
2355   char parsed[256 + 1], serv[256 + 1];
2356   SilcChannelEntry channel;
2357   SilcUInt32 umode = 0;
2358   SilcBool created = FALSE, create_key = TRUE;
2359   SilcID id;
2360
2361   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 7);
2362
2363   /* Get channel name */
2364   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2365   if (!tmp) {
2366     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2367                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
2368                                           0);
2369     goto out;
2370   }
2371
2372   /* Truncate over long channel names */
2373   if (tmp_len > 256) {
2374     tmp_len = 256;
2375     tmp[tmp_len - 1] = '\0';
2376   }
2377
2378   /* Parse server name from the channel name */
2379   silc_parse_userfqdn(tmp, parsed, sizeof(parsed), serv,
2380                       sizeof(serv));
2381   channel_name = parsed;
2382
2383   if (server->config->dynamic_server) {
2384     /* If server name is not specified but local channels is FALSE then the
2385        channel will be global, based on our router name. */
2386     if (!serv[0] && !server->config->local_channels) {
2387       if (!server->standalone) {
2388         silc_snprintf(serv, sizeof(serv), "%s", server->router->server_name);
2389       } else {
2390         SilcServerConfigRouter *router;
2391         router = silc_server_config_get_primary_router(server);
2392         if (router) {
2393           /* Create connection to primary router */
2394           SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
2395                           router->host, router->port));
2396           silc_server_create_connection(server, FALSE, TRUE,
2397                                         router->host, router->port,
2398                                         silc_server_command_join_connected,
2399                                         cmd);
2400           return;
2401         }
2402       }
2403     }
2404
2405     /* If server name is ours, ignore it. */
2406     if (serv[0] && silc_utf8_strcasecmp(serv, server->server_name))
2407       memset(serv, 0, sizeof(serv));
2408
2409     /* Create connection */
2410     if (serv[0] && server->standalone) {
2411       SilcServerConfigRouter *router;
2412       router = silc_server_config_get_primary_router(server);
2413       if (router) {
2414         /* Create connection to primary router */
2415         SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d",
2416                         router->host, router->port));
2417         silc_server_create_connection(server, FALSE, TRUE,
2418                                       router->host, router->port,
2419                                       silc_server_command_join_connected, cmd);
2420         return;
2421       }
2422     }
2423   }
2424
2425   /* Check for valid channel name.  This is cached, the original is saved
2426      in the channel context. */
2427   channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
2428                                           SILC_STRING_UTF8, 256, NULL);
2429   if (!channel_namec) {
2430     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2431                                           SILC_STATUS_ERR_BAD_CHANNEL, 0);
2432     goto out;
2433   }
2434
2435   /* Get Client ID of the client who is joining to the channel */
2436   if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
2437     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2438                                           SILC_STATUS_ERR_NO_CLIENT_ID,
2439                                           0);
2440     goto out;
2441   }
2442   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2443
2444   /* Get cipher, hmac name and auth payload */
2445   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
2446   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
2447   auth = silc_argument_get_arg_type(cmd->args, 6, &auth_len);
2448   cauth = silc_argument_get_arg_type(cmd->args, 7, &cauth_len);
2449
2450   /* See if the channel exists */
2451   channel = silc_idlist_find_channel_by_name(server->local_list,
2452                                              channel_namec, NULL);
2453
2454   if (idata->conn_type == SILC_CONN_CLIENT) {
2455     SilcClientEntry entry = (SilcClientEntry)idata;
2456     if (!entry) {
2457       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2458                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
2459                                             0);
2460       goto out;
2461     }
2462
2463 #ifndef SILC_DIST_INPLACE
2464     /* Limit how many channels client can join */
2465     if (!cmd->pending && entry->channels &&
2466         silc_hash_table_count(entry->channels) >=
2467         server->config->param.chlimit) {
2468       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
2469                                             SILC_STATUS_ERR_RESOURCE_LIMIT,
2470                                             0);
2471       goto out;
2472     }
2473 #endif /* SILC_DIST_INPLACE */
2474
2475     if (!channel ||
2476         (channel->disabled && server->server_type != SILC_ROUTER)) {
2477       /* Channel not found or not valid */
2478
2479       /* If we are standalone server we don't have a router, we just create
2480          the channel by ourselves (unless it existed). */
2481       if (server->standalone) {
2482         if (!channel) {
2483           channel = silc_server_create_new_channel(server, server->id, cipher,
2484                                                    hmac, channel_name, TRUE);
2485           if (!channel) {
2486             if (cipher) {
2487               silc_server_command_send_status_data(
2488                                 cmd, SILC_COMMAND_JOIN,
2489                                 SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
2490                                 0, 2, cipher, strlen(cipher));
2491             } else if (hmac) {
2492               silc_server_command_send_status_data(
2493                                 cmd, SILC_COMMAND_JOIN,
2494                                 SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
2495                                 0, 2, hmac, strlen(hmac));
2496             } else {
2497               silc_server_command_send_status_reply(
2498                                 cmd, SILC_COMMAND_JOIN,
2499                                 SILC_STATUS_ERR_RESOURCE_LIMIT,
2500                                 0);
2501             }
2502             goto out;
2503           }
2504
2505           umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2506           created = TRUE;
2507           create_key = FALSE;
2508         }
2509       } else {
2510
2511         /* The channel does not exist on our server. If we are normal server
2512            we will send JOIN command to our router which will handle the
2513            joining procedure (either creates the channel if it doesn't exist
2514            or joins the client to it). */
2515         if (server->server_type != SILC_ROUTER) {
2516           SilcBuffer tmpbuf;
2517           SilcUInt16 old_ident;
2518
2519           /* If this is pending command callback then we've resolved
2520              it and it didn't work, return since we've notified the
2521              client already in the command reply callback. */
2522           if (cmd->pending)
2523             goto out;
2524
2525           /* Statistics */
2526           cmd->server->stat.commands_sent++;
2527
2528           old_ident = silc_command_get_ident(cmd->payload);
2529           silc_command_set_ident(cmd->payload, ++server->cmd_ident);
2530           tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2531
2532           /* Send JOIN command to our router */
2533           silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
2534                                   SILC_PACKET_COMMAND, cmd->packet->flags,
2535                                   tmpbuf->data, silc_buffer_len(tmpbuf));
2536
2537           /* Reprocess this packet after received reply from router */
2538           silc_server_command_pending(server, SILC_COMMAND_JOIN,
2539                                       silc_command_get_ident(cmd->payload),
2540                                       silc_server_command_join,
2541                                       silc_server_command_dup(cmd));
2542           cmd->pending = TRUE;
2543           silc_command_set_ident(cmd->payload, old_ident);
2544           silc_buffer_free(tmpbuf);
2545           goto out;
2546         }
2547
2548         /* We are router and the channel does not seem exist so we will check
2549            our global list as well for the channel. */
2550         channel = silc_idlist_find_channel_by_name(server->global_list,
2551                                                    channel_namec, NULL);
2552         if (!channel) {
2553           /* Channel really does not exist, create it */
2554           channel = silc_server_create_new_channel(server, server->id, cipher,
2555                                                    hmac, channel_name, TRUE);
2556           if (!channel) {
2557             if (cipher) {
2558               silc_server_command_send_status_data(
2559                                       cmd, SILC_COMMAND_JOIN,
2560                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
2561                                       0, 2, cipher, strlen(cipher));
2562             } else if (hmac) {
2563               silc_server_command_send_status_data(
2564                                       cmd, SILC_COMMAND_JOIN,
2565                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
2566                                       0, 2, hmac, strlen(hmac));
2567             } else {
2568               silc_server_command_send_status_reply(
2569                                       cmd, SILC_COMMAND_JOIN,
2570                                       SILC_STATUS_ERR_RESOURCE_LIMIT,
2571                                       0);
2572             }
2573             goto out;
2574           }
2575
2576           umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2577           created = TRUE;
2578           create_key = FALSE;
2579         }
2580       }
2581     }
2582   } else {
2583     if (!channel) {
2584       /* Channel not found */
2585
2586       /* If the command came from router and we are normal server then
2587          something went wrong with the joining as the channel was not found.
2588          We can't do anything else but ignore this. */
2589       if (idata->conn_type == SILC_CONN_ROUTER ||
2590           server->server_type != SILC_ROUTER)
2591         goto out;
2592
2593       /* We are router and the channel does not seem exist so we will check
2594          our global list as well for the channel. */
2595       channel = silc_idlist_find_channel_by_name(server->global_list,
2596                                                  channel_namec, NULL);
2597       if (!channel) {
2598         /* Channel really does not exist, create it */
2599         channel = silc_server_create_new_channel(server, server->id, cipher,
2600                                                  hmac, channel_name, TRUE);
2601         if (!channel) {
2602           if (cipher) {
2603             silc_server_command_send_status_data(
2604                                       cmd, SILC_COMMAND_JOIN,
2605                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
2606                                       0, 2, cipher, strlen(cipher));
2607           } else if (hmac) {
2608             silc_server_command_send_status_data(
2609                                       cmd, SILC_COMMAND_JOIN,
2610                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
2611                                       0, 2, hmac, strlen(hmac));
2612           } else {
2613             silc_server_command_send_status_reply(
2614                                       cmd, SILC_COMMAND_JOIN,
2615                                       SILC_STATUS_ERR_RESOURCE_LIMIT,
2616                                       0);
2617           }
2618           goto out;
2619         }
2620
2621         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2622         created = TRUE;
2623         create_key = FALSE;
2624       }
2625     }
2626   }
2627
2628   /* Check whether the channel was created by our router */
2629   if (cmd->pending && context2) {
2630     SilcServerCommandReplyContext reply = context2;
2631
2632     if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
2633       tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
2634       SILC_GET32_MSB(created, tmp);
2635       if (silc_argument_get_arg_type(reply->args, 7, NULL))
2636         create_key = FALSE;     /* Router returned the key already */
2637
2638       if (silc_command_get_status(reply->payload, NULL, NULL) &&
2639           channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2640         /* Save channel passphrase, if user provided it successfully */
2641         unsigned char *pa;
2642         SilcUInt32 pa_len;
2643         pa = silc_argument_get_arg_type(cmd->args, 3, &pa_len);
2644         if (pa) {
2645           silc_free(channel->passphrase);
2646           channel->passphrase = silc_memdup(pa, pa_len);
2647         }
2648       }
2649     }
2650
2651     if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
2652         !channel->disabled && !silc_hash_table_count(channel->user_list))
2653       created = TRUE;
2654   }
2655
2656   /* If the channel does not have global users and is also empty the client
2657      will be the channel founder and operator. */
2658   if (!channel->disabled &&
2659       !channel->global_users && !silc_hash_table_count(channel->user_list))
2660     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
2661
2662   /* Join to the channel */
2663   silc_server_command_join_channel(server, cmd, channel, SILC_ID_GET_ID(id),
2664                                    created, create_key, umode,
2665                                    auth, auth_len, cauth, cauth_len);
2666
2667  out:
2668   silc_free(channel_namec);
2669   silc_server_command_free(cmd);
2670 }
2671
2672 /* Server side of command MOTD. Sends server's current "message of the
2673    day" to the client. */
2674
2675 SILC_SERVER_CMD_FUNC(motd)
2676 {
2677   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2678   SilcServer server = cmd->server;
2679   SilcBuffer idp;
2680   char *motd, *dest_server = NULL;
2681   SilcUInt32 motd_len;
2682   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
2683
2684   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_MOTD, cmd, 1, 1);
2685
2686   /* Get server name */
2687   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
2688   if (!dest_server) {
2689     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
2690                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
2691                                           0);
2692     goto out;
2693   }
2694
2695   /* Check server name */
2696   dest_server = silc_identifier_check(dest_server, strlen(dest_server),
2697                                       SILC_STRING_UTF8, 256, NULL);
2698   if (!dest_server) {
2699     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
2700                                           SILC_STATUS_ERR_BAD_SERVER,
2701                                           0);
2702     goto out;
2703   }
2704
2705   if (!memcmp(dest_server, server->server_name, strlen(dest_server))) {
2706     /* Send our MOTD */
2707
2708     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
2709
2710     if (server->config && server->config->server_info &&
2711         server->config->server_info->motd_file) {
2712       /* Send motd */
2713       motd = silc_file_readfile(server->config->server_info->motd_file,
2714                                 &motd_len);
2715       if (!motd) {
2716         /* No motd */
2717         silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
2718                                        SILC_STATUS_OK, 0, ident, 1,
2719                                        2, idp->data, silc_buffer_len(idp));
2720         goto out;
2721       }
2722
2723       motd[motd_len] = 0;
2724       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
2725                                      SILC_STATUS_OK, 0, ident, 2,
2726                                      2, idp->data, silc_buffer_len(idp),
2727                                      3, motd, motd_len);
2728     } else {
2729       /* No motd */
2730       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
2731                                      SILC_STATUS_OK, 0, ident, 1,
2732                                      2, idp->data, silc_buffer_len(idp));
2733     }
2734     silc_buffer_free(idp);
2735   } else {
2736     SilcServerEntry entry;
2737
2738     /* Check whether we have this server cached */
2739     entry = silc_idlist_find_server_by_name(server->global_list,
2740                                             dest_server, TRUE, NULL);
2741     if (!entry) {
2742       entry = silc_idlist_find_server_by_name(server->local_list,
2743                                               dest_server, TRUE, NULL);
2744     }
2745
2746     if (server->server_type != SILC_SERVER && !cmd->pending &&
2747         entry && !entry->motd) {
2748       /* Send to the server */
2749       SilcBuffer tmpbuf;
2750       SilcUInt16 old_ident;
2751
2752       /* Statistics */
2753       cmd->server->stat.commands_sent++;
2754
2755       old_ident = silc_command_get_ident(cmd->payload);
2756       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
2757       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2758
2759       silc_server_packet_send(server, entry->connection,
2760                               SILC_PACKET_COMMAND, cmd->packet->flags,
2761                               tmpbuf->data, silc_buffer_len(tmpbuf));
2762
2763       /* Reprocess this packet after received reply from router */
2764       silc_server_command_pending(server, SILC_COMMAND_MOTD,
2765                                   silc_command_get_ident(cmd->payload),
2766                                   silc_server_command_motd,
2767                                   silc_server_command_dup(cmd));
2768       cmd->pending = TRUE;
2769       silc_command_set_ident(cmd->payload, old_ident);
2770       silc_buffer_free(tmpbuf);
2771       goto out;
2772     }
2773
2774     /* Send to primary router only if we don't know the server
2775      * the client requested or if the server is not locally connected */
2776     if ((!entry || !(entry->data.status & SILC_IDLIST_STATUS_LOCAL))
2777         && !cmd->pending && !server->standalone) {
2778       /* Send to the primary router */
2779       SilcBuffer tmpbuf;
2780       SilcUInt16 old_ident;
2781
2782       /* Statistics */
2783       cmd->server->stat.commands_sent++;
2784
2785       old_ident = silc_command_get_ident(cmd->payload);
2786       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
2787       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
2788
2789       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
2790                               SILC_PACKET_COMMAND, cmd->packet->flags,
2791                               tmpbuf->data, silc_buffer_len(tmpbuf));
2792
2793       /* Reprocess this packet after received reply from router */
2794       silc_server_command_pending(server, SILC_COMMAND_MOTD,
2795                                   silc_command_get_ident(cmd->payload),
2796                                   silc_server_command_motd,
2797                                   silc_server_command_dup(cmd));
2798       cmd->pending = TRUE;
2799       silc_command_set_ident(cmd->payload, old_ident);
2800       silc_buffer_free(tmpbuf);
2801       goto out;
2802     }
2803
2804     if (!entry) {
2805       silc_free(dest_server);
2806       dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
2807       silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
2808                                            SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
2809                                            2, dest_server,
2810                                            strlen(dest_server));
2811       dest_server = NULL;
2812       goto out;
2813     }
2814
2815     idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
2816     silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
2817                                    SILC_STATUS_OK, 0, ident, 2,
2818                                    2, idp->data, silc_buffer_len(idp),
2819                                    3, entry->motd,
2820                                    entry->motd ?
2821                                    strlen(entry->motd) : 0);
2822     silc_buffer_free(idp);
2823   }
2824
2825  out:
2826   silc_free(dest_server);
2827   silc_server_command_free(cmd);
2828 }
2829
2830 /* Server side of command UMODE. Client can use this command to set/unset
2831    user mode. Client actually cannot set itself to be as server/router
2832    operator so this can be used only to unset the modes. */
2833
2834 SILC_SERVER_CMD_FUNC(umode)
2835 {
2836   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2837   SilcServer server = cmd->server;
2838   SilcClientEntry client = silc_packet_get_context(cmd->sock);
2839   unsigned char *tmp_mask, m[4];
2840   SilcUInt32 mask = 0, tmp_len;
2841   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
2842   SilcBool set_mask = FALSE;
2843
2844   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
2845     goto out;
2846
2847   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 1, 2);
2848
2849   /* Get the client's mode mask */
2850   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2851   if (tmp_mask && tmp_len == 4) {
2852     SILC_GET32_MSB(mask, tmp_mask);
2853     set_mask = TRUE;
2854   }
2855
2856   if (set_mask) {
2857     /* Check that mode changing is allowed. */
2858     if (!silc_server_check_umode_rights(server, client, mask)) {
2859       silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
2860                                             SILC_STATUS_ERR_PERM_DENIED, 0);
2861       goto out;
2862     }
2863
2864     /* Anonymous mode cannot be set by client */
2865     if (mask & SILC_UMODE_ANONYMOUS &&
2866         !(client->mode & SILC_UMODE_ANONYMOUS)) {
2867       silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
2868                                             SILC_STATUS_ERR_PERM_DENIED, 0);
2869       goto out;
2870     }
2871
2872     /* Update statistics */
2873     if (mask & SILC_UMODE_GONE) {
2874       if (!(client->mode & SILC_UMODE_GONE))
2875         server->stat.my_aways++;
2876     } else {
2877       if (client->mode & SILC_UMODE_GONE)
2878         server->stat.my_aways--;
2879     }
2880
2881     /* If the client has anonymous mode set, preserve it. */
2882     if (client->mode & SILC_UMODE_ANONYMOUS)
2883       mask |= SILC_UMODE_ANONYMOUS;
2884
2885     /* Change the mode */
2886     client->mode = mask;
2887
2888     /* Send UMODE change to primary router */
2889     silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
2890                                   SILC_BROADCAST(server), client->id,
2891                                   client->mode);
2892
2893     /* Check if anyone is watching this nickname */
2894     if (server->server_type == SILC_ROUTER)
2895       silc_server_check_watcher_list(server, client, NULL,
2896                                      SILC_NOTIFY_TYPE_UMODE_CHANGE);
2897   }
2898
2899   /* Send command reply to sender */
2900   SILC_PUT32_MSB(client->mode, m);
2901   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_UMODE,
2902                                  SILC_STATUS_OK, 0, ident, 1,
2903                                  2, m, sizeof(m));
2904
2905  out:
2906   silc_server_command_free(cmd);
2907 }
2908
2909 /* Server side command of CMODE. Changes channel mode */
2910
2911 SILC_SERVER_CMD_FUNC(cmode)
2912 {
2913   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2914   SilcServer server = cmd->server;
2915   SilcClientEntry client = silc_packet_get_context(cmd->sock);
2916   SilcIDListData idata = (SilcIDListData)client;
2917   SilcID id;
2918   SilcChannelEntry channel;
2919   SilcChannelClientEntry chl;
2920   SilcBuffer cidp;
2921   unsigned char *tmp, *tmp_id, *tmp_mask, *chpkdata = NULL;
2922   char *cipher = NULL, *hmac = NULL, *passphrase = NULL, ulimit[4];
2923   SilcUInt32 mode_mask = 0, old_mask = 0, tmp_len, tmp_len2, chpklen;
2924   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
2925   SilcBool set_mask = FALSE, set_chpk = FALSE;
2926   SilcPublicKey founder_key = NULL;
2927   SilcBuffer fkey = NULL, chpklist = NULL;
2928   SilcBufferStruct chpk;
2929
2930   if (!client) {
2931     silc_server_command_free(cmd);
2932     return;
2933   }
2934
2935   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 9);
2936
2937   /* Get Channel ID */
2938   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
2939     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2940                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
2941     silc_server_command_free(cmd);
2942     return;
2943   }
2944
2945   /* Get channel entry */
2946   channel = silc_idlist_find_channel_by_id(server->local_list,
2947                                            SILC_ID_GET_ID(id), NULL);
2948   if (!channel) {
2949     channel = silc_idlist_find_channel_by_id(server->global_list,
2950                                              SILC_ID_GET_ID(id), NULL);
2951     if (!channel) {
2952       tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
2953       silc_server_command_send_status_data(cmd, SILC_COMMAND_CMODE,
2954                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
2955                                            0, 2, tmp_id, tmp_len2);
2956       silc_server_command_free(cmd);
2957       return;
2958     }
2959   }
2960   old_mask = channel->mode;
2961
2962   /* Get the channel mode mask */
2963   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2964   if (tmp_mask && tmp_len == 4) {
2965     SILC_GET32_MSB(mode_mask, tmp_mask);
2966     set_mask = TRUE;
2967   }
2968
2969   /* Check whether this client is on the channel */
2970   if (!silc_server_client_on_channel(client, channel, &chl)) {
2971     tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
2972     silc_server_command_send_status_data(cmd, SILC_COMMAND_CMODE,
2973                                          SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
2974                                          2, tmp_id, tmp_len2);
2975     goto out;
2976   }
2977
2978   /* Check that client has rights to change any requested channel modes */
2979   if (set_mask && !silc_server_check_cmode_rights(server, channel, chl,
2980                                                   mode_mask)) {
2981     SILC_LOG_DEBUG(("Client does not have rights to change mode"));
2982     tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
2983     silc_server_command_send_status_data(
2984                              cmd, SILC_COMMAND_CMODE,
2985                              (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) ?
2986                               SILC_STATUS_ERR_NO_CHANNEL_PRIV :
2987                               SILC_STATUS_ERR_NO_CHANNEL_FOPRIV), 0,
2988                              2, tmp_id, tmp_len2);
2989     goto out;
2990   }
2991
2992   /* If mode mask was not sent as argument then merely return the current
2993      mode mask, founder key and channel public key list to the sender. */
2994   if (!set_mask) {
2995     unsigned char m[4];
2996     SILC_PUT32_MSB(channel->mode, m);
2997     if (channel->founder_key)
2998       fkey = silc_public_key_payload_encode(channel->founder_key);
2999     if (channel->channel_pubkeys)
3000       chpklist = silc_server_get_channel_pk_list(server, channel,
3001                                                  FALSE, FALSE);
3002     tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
3003     silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_CMODE,
3004                                    SILC_STATUS_OK, 0, ident, 4,
3005                                    2, tmp_id, tmp_len2,
3006                                    3, m, sizeof(m),
3007                                    4, fkey ? fkey->data : NULL,
3008                                    fkey ? silc_buffer_len(fkey) : 0,
3009                                    5, chpklist ? chpklist->data : NULL,
3010                                    chpklist ? silc_buffer_len(chpklist) : 0);
3011     goto out;
3012   }
3013
3014   /*
3015    * Check the modes. Modes that requires nothing special operation are
3016    * not checked here.
3017    */
3018
3019   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
3020     /* Channel uses private keys to protect traffic. Client(s) has set the
3021        key locally they want to use, server does not know that key. */
3022     /* Nothing interesting to do here */
3023   } else {
3024     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
3025       /* The mode is removed and we need to generate and distribute
3026          new channel key. Clients are not using private channel keys
3027          anymore after this. */
3028
3029       /* if we don't remove the flag from the mode
3030        * silc_server_create_channel_key won't create a new key */
3031       channel->mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
3032
3033       /* Re-generate channel key */
3034       if (!silc_server_create_channel_key(server, channel, 0))
3035         goto out;
3036
3037       /* Send the channel key. This sends it to our local clients and if
3038          we are normal server to our router as well. */
3039       silc_server_send_channel_key(server, NULL, channel,
3040                                    server->server_type == SILC_ROUTER ?
3041                                    FALSE : !server->standalone);
3042
3043       cipher = (char *)silc_cipher_get_name(channel->send_key);
3044       hmac = (char *)silc_hmac_get_name(channel->hmac);
3045     }
3046   }
3047
3048   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
3049     /* User limit is set on channel */
3050     SilcUInt32 user_limit;
3051
3052     /* Get user limit */
3053     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
3054     if (!tmp) {
3055       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
3056         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3057                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
3058         goto out;
3059       }
3060     } else {
3061       SILC_GET32_MSB(user_limit, tmp);
3062       channel->user_limit = user_limit;
3063     }
3064   } else {
3065     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
3066       /* User limit mode is unset. Remove user limit */
3067       channel->user_limit = 0;
3068   }
3069
3070   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
3071     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
3072       /* Passphrase has been set to channel */
3073
3074       /* Get the passphrase */
3075       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
3076       if (!tmp) {
3077         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3078                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
3079         goto out;
3080       }
3081
3082       /* Save the passphrase */
3083       passphrase = channel->passphrase = silc_memdup(tmp, strlen(tmp));
3084     }
3085   } else {
3086     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
3087       /* Passphrase mode is unset. remove the passphrase */
3088       silc_free(channel->passphrase);
3089       channel->passphrase = NULL;
3090     }
3091   }
3092
3093   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
3094     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
3095       /* Cipher to use protect the traffic */
3096       SilcCipher send_key, receive_key, olds, oldr;
3097
3098       /* Get cipher */
3099       cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
3100       if (!cipher) {
3101         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3102                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
3103         goto out;
3104       }
3105
3106       /* Delete old cipher and allocate the new one */
3107       if (!silc_cipher_alloc(cipher, &send_key)) {
3108         silc_server_command_send_status_data(
3109                                          cmd, SILC_COMMAND_CMODE,
3110                                          SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
3111                                          2, cipher, strlen(cipher));
3112         goto out;
3113       }
3114       if (!silc_cipher_alloc(cipher, &receive_key)) {
3115         silc_server_command_send_status_data(
3116                                          cmd, SILC_COMMAND_CMODE,
3117                                          SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
3118                                          2, cipher, strlen(cipher));
3119         goto out;
3120       }
3121
3122       olds = channel->send_key;
3123       oldr = channel->receive_key;
3124       channel->send_key = send_key;
3125       channel->receive_key = receive_key;
3126
3127       /* Re-generate channel key */
3128       if (!silc_server_create_channel_key(server, channel, 0)) {
3129         /* We don't have new key, revert to old one */
3130         channel->send_key = olds;
3131         channel->receive_key = oldr;
3132         goto out;
3133       }
3134
3135       /* Remove old channel key for good */
3136       silc_cipher_free(olds);
3137       silc_cipher_free(oldr);
3138
3139       /* Send the channel key. This sends it to our local clients and if
3140          we are normal server to our router as well. */
3141       silc_server_send_channel_key(server, NULL, channel,
3142                                    server->server_type == SILC_ROUTER ?
3143                                    FALSE : !server->standalone);
3144     }
3145   } else {
3146     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
3147       /* Cipher mode is unset. Remove the cipher and revert back to
3148          default cipher */
3149       SilcCipher send_key, receive_key, olds, oldr;
3150       cipher = channel->cipher;
3151
3152       /* Delete old cipher and allocate default one */
3153       if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER,
3154                              &send_key)) {
3155         silc_server_command_send_status_data(
3156                                       cmd, SILC_COMMAND_CMODE,
3157                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
3158                                       2, cipher, strlen(cipher));
3159         goto out;
3160       }
3161       if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER,
3162                              &receive_key)) {
3163         silc_server_command_send_status_data(
3164                                       cmd, SILC_COMMAND_CMODE,
3165                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
3166                                       2, cipher, strlen(cipher));
3167         goto out;
3168       }
3169
3170       olds = channel->send_key;
3171       oldr = channel->receive_key;
3172       channel->send_key = send_key;
3173       channel->receive_key = receive_key;
3174
3175       /* Re-generate channel key */
3176       if (!silc_server_create_channel_key(server, channel, 0)) {
3177         /* We don't have new key, revert to old one */
3178         channel->send_key = olds;
3179         channel->receive_key = oldr;
3180         goto out;
3181       }
3182
3183       /* Remove old channel key for good */
3184       silc_cipher_free(olds);
3185       silc_cipher_free(oldr);
3186
3187       /* Send the channel key. This sends it to our local clients and if
3188          we are normal server to our router as well. */
3189       silc_server_send_channel_key(server, NULL, channel,
3190                                    server->server_type == SILC_ROUTER ?
3191                                    FALSE : !server->standalone);
3192     }
3193   }
3194
3195   if (mode_mask & SILC_CHANNEL_MODE_HMAC) {
3196     if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
3197       /* HMAC to use protect the traffic */
3198       unsigned char hash[SILC_HASH_MAXLEN];
3199       SilcHmac newhmac;
3200
3201       /* Get hmac */
3202       hmac = silc_argument_get_arg_type(cmd->args, 6, NULL);
3203       if (!hmac) {
3204         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3205                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
3206         goto out;
3207       }
3208
3209       /* Delete old hmac and allocate the new one */
3210       if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
3211         silc_server_command_send_status_data(
3212                                         cmd, SILC_COMMAND_CMODE,
3213                                         SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
3214                                         2, hmac, strlen(hmac));
3215         goto out;
3216       }
3217
3218       silc_hmac_free(channel->hmac);
3219       channel->hmac = newhmac;
3220
3221       /* Set the HMAC key out of current channel key. The client must do
3222          this locally. */
3223       silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
3224                      channel->key_len / 8, hash);
3225       silc_hmac_set_key(channel->hmac, hash,
3226                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
3227       memset(hash, 0, sizeof(hash));
3228     }
3229   } else {
3230     if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
3231       /* Hmac mode is unset. Remove the hmac and revert back to
3232          default hmac */
3233       SilcHmac newhmac;
3234       unsigned char hash[SILC_HASH_MAXLEN];
3235       hmac = channel->hmac_name;
3236
3237       /* Delete old hmac and allocate default one */
3238       if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, &newhmac)) {
3239         silc_server_command_send_status_data(
3240                                         cmd, SILC_COMMAND_CMODE,
3241                                         SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
3242                                         2, hmac, strlen(hmac));
3243         goto out;
3244       }
3245
3246       silc_hmac_free(channel->hmac);
3247       channel->hmac = newhmac;
3248
3249       /* Set the HMAC key out of current channel key. The client must do
3250          this locally. */
3251       silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
3252                      channel->key_len / 8,
3253                      hash);
3254       silc_hmac_set_key(channel->hmac, hash,
3255                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
3256       memset(hash, 0, sizeof(hash));
3257     }
3258   }
3259
3260   if (mode_mask & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
3261     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3262       /* Check if the founder public key was received */
3263       founder_key = idata->public_key;
3264       tmp = silc_argument_get_arg_type(cmd->args, 8, &tmp_len);
3265       if (tmp) {
3266         if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
3267           silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3268                                                 SILC_STATUS_ERR_AUTH_FAILED,
3269                                                 0);
3270           goto out;
3271         }
3272       } else {
3273         /* If key was not sent and the channel mode has already founder
3274            then the key was not to be changed. */
3275         if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
3276           goto has_founder;
3277       }
3278
3279       /* Set the founder authentication */
3280       tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
3281       if (!tmp) {
3282         silc_server_command_send_status_reply(
3283                                      cmd, SILC_COMMAND_CMODE,
3284                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
3285         goto out;
3286       }
3287
3288       /* Verify the payload before setting the mode */
3289       if (!silc_auth_verify_data(tmp, tmp_len, SILC_AUTH_PUBLIC_KEY,
3290                                  founder_key, 0, server->sha1hash,
3291                                  client->id, SILC_ID_CLIENT)) {
3292         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3293                                               SILC_STATUS_ERR_AUTH_FAILED,
3294                                               0);
3295         goto out;
3296       }
3297
3298       /* Save the public key */
3299       if (channel->founder_key)
3300         silc_pkcs_public_key_free(channel->founder_key);
3301       if (silc_argument_get_arg_type(cmd->args, 8, NULL))
3302         channel->founder_key = founder_key;
3303       else
3304         channel->founder_key = silc_pkcs_public_key_copy(founder_key);
3305       if (!channel->founder_key) {
3306         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3307                                               SILC_STATUS_ERR_AUTH_FAILED,
3308                                               0);
3309         goto out;
3310       }
3311
3312       fkey = silc_public_key_payload_encode(channel->founder_key);
3313       if (!fkey) {
3314         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
3315                                               SILC_STATUS_ERR_AUTH_FAILED,
3316                                               0);
3317         silc_pkcs_public_key_free(channel->founder_key);
3318         channel->founder_key = NULL;
3319         goto out;
3320       }
3321     }
3322   } else {
3323     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3324       if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
3325         if (channel->founder_key)
3326           silc_pkcs_public_key_free(channel->founder_key);
3327         channel->founder_key = NULL;
3328       }
3329     }
3330   }
3331  has_founder:
3332
3333   if (mode_mask & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
3334     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3335       SilcStatus st;
3336
3337       chpkdata = silc_argument_get_arg_type(cmd->args, 9, &chpklen);
3338
3339       if (!chpkdata && channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
3340         goto has_pk_list;
3341
3342       set_chpk = TRUE;
3343
3344       /* Process the channel public key(s) */
3345       st = silc_server_set_channel_pk_list(server, NULL, channel,
3346                                            chpkdata, chpklen);
3347       if (st != SILC_STATUS_OK) {
3348         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, st, 0);
3349         goto out;
3350       }
3351     }
3352   } else {
3353     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3354       if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
3355         if (channel->channel_pubkeys)
3356           silc_hash_table_free(channel->channel_pubkeys);
3357         channel->channel_pubkeys = NULL;
3358         set_chpk = TRUE;
3359       }
3360     }
3361   }
3362  has_pk_list:
3363
3364   /* Finally, set the mode */
3365   old_mask = channel->mode = mode_mask;
3366
3367   /* Send CMODE_CHANGE notify. */
3368   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
3369   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT)
3370     SILC_PUT32_MSB(channel->user_limit, ulimit);
3371   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
3372                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 8,
3373                                      cidp->data, silc_buffer_len(cidp),
3374                                      tmp_mask, 4,
3375                                      cipher, cipher ? strlen(cipher) : 0,
3376                                      hmac, hmac ? strlen(hmac) : 0,
3377                                      passphrase, passphrase ?
3378                                      strlen(passphrase) : 0,
3379                                      fkey ? fkey->data : NULL,
3380                                      fkey ? silc_buffer_len(fkey) : 0,
3381                                      chpkdata ? chpkdata : NULL,
3382                                      chpkdata ? chpklen : 0,
3383                                      mode_mask & SILC_CHANNEL_MODE_ULIMIT ?
3384                                      ulimit : NULL,
3385                                      mode_mask & SILC_CHANNEL_MODE_ULIMIT ?
3386                                      sizeof(ulimit) : 0);
3387
3388   /* Set CMODE notify type to network */
3389   if (chpkdata && chpklen)
3390     silc_buffer_set(&chpk, chpkdata, chpklen);
3391   silc_server_send_notify_cmode(server, SILC_PRIMARY_ROUTE(server),
3392                                 SILC_BROADCAST(server), channel,
3393                                 mode_mask, client->id, SILC_ID_CLIENT,
3394                                 cipher, hmac, passphrase, founder_key,
3395                                 chpkdata ? &chpk : NULL);
3396
3397   if (set_chpk)
3398     chpklist = silc_server_get_channel_pk_list(server, channel, FALSE, FALSE);
3399
3400   /* Send command reply to sender */
3401   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
3402   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_CMODE,
3403                                  SILC_STATUS_OK, 0, ident, 5,
3404                                  2, tmp_id, tmp_len2,
3405                                  3, tmp_mask, 4,
3406                                  4, fkey ? fkey->data : NULL,
3407                                  fkey ? silc_buffer_len(fkey) : 0,
3408                                  5, chpklist ? chpklist->data :
3409                                  NULL, chpklist ? silc_buffer_len(chpklist)
3410                                  : 0,
3411                                  6, (mode_mask &
3412                                      SILC_CHANNEL_MODE_ULIMIT ?
3413                                      ulimit : NULL),
3414                                  (mode_mask &
3415                                   SILC_CHANNEL_MODE_ULIMIT ?
3416                                   sizeof(ulimit) : 0));
3417   silc_buffer_free(cidp);
3418
3419  out:
3420   channel->mode = old_mask;
3421   silc_buffer_free(chpklist);
3422   silc_buffer_free(fkey);
3423   silc_server_command_free(cmd);
3424 }
3425
3426 /* Server side of CUMODE command. Changes client's mode on a channel. */
3427
3428 SILC_SERVER_CMD_FUNC(cumode)
3429 {
3430   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3431   SilcServer server = cmd->server;
3432   SilcClientEntry client = silc_packet_get_context(cmd->sock);
3433   SilcID id, id2;
3434   SilcChannelEntry channel;
3435   SilcClientEntry target_client;
3436   SilcChannelClientEntry chl;
3437   SilcBuffer idp;
3438   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
3439   SilcUInt32 target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
3440   int notify = FALSE;
3441   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
3442   SilcPublicKey founder_key = NULL;
3443   SilcBuffer fkey = NULL;
3444
3445   if (!client)
3446     goto out;
3447
3448   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
3449
3450   /* Get Channel ID */
3451   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
3452     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3453                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
3454     goto out;
3455   }
3456
3457   /* Get channel entry */
3458   channel = silc_idlist_find_channel_by_id(server->local_list,
3459                                            SILC_ID_GET_ID(id), NULL);
3460   if (!channel) {
3461     channel = silc_idlist_find_channel_by_id(server->global_list,
3462                                              SILC_ID_GET_ID(id), NULL);
3463     if (!channel) {
3464       tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3465       silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
3466                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
3467                                            0, 2, tmp_ch_id, tmp_ch_len);
3468       goto out;
3469     }
3470   }
3471
3472   /* Check whether sender is on the channel */
3473   if (!silc_server_client_on_channel(client, channel, &chl)) {
3474     tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3475     silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
3476                                          SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
3477                                          2, tmp_ch_id, tmp_ch_len);
3478     goto out;
3479   }
3480   sender_mask = chl->mode;
3481
3482   /* Get the target client's channel mode mask */
3483   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
3484   if (!tmp_mask) {
3485     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3486                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
3487                                           0);
3488     goto out;
3489   }
3490   SILC_GET32_MSB(target_mask, tmp_mask);
3491
3492   /* Get target Client ID */
3493   if (!silc_argument_get_decoded(cmd->args, 3, SILC_ARGUMENT_ID, &id2, NULL)) {
3494     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3495                                           SILC_STATUS_ERR_NO_CLIENT_ID, 0);
3496     goto out;
3497   }
3498
3499   /* Get target client's entry */
3500   target_client = silc_idlist_find_client_by_id(server->local_list,
3501                                                 SILC_ID_GET_ID(id2),
3502                                                 TRUE, NULL);
3503   if (!target_client)
3504     target_client = silc_idlist_find_client_by_id(server->global_list,
3505                                                   SILC_ID_GET_ID(id2),
3506                                                   TRUE, NULL);
3507
3508   if (target_client != client &&
3509       !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
3510       !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
3511     tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3512     silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
3513                                          SILC_STATUS_ERR_NOT_YOU, 0,
3514                                          2, tmp_ch_id, tmp_ch_len);
3515     goto out;
3516   }
3517
3518   /* Check whether target client is on the channel */
3519   if (target_client != client) {
3520     if (!silc_server_client_on_channel(target_client, channel, &chl)) {
3521       tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3522       tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
3523       silc_server_command_send_status_data2(
3524                                   cmd, SILC_COMMAND_CUMODE,
3525                                   SILC_STATUS_ERR_USER_NOT_ON_CHANNEL, 0,
3526                                   2, tmp_id, tmp_len,
3527                                   3, tmp_ch_id, tmp_ch_len);
3528       goto out;
3529     }
3530   }
3531
3532   /*
3533    * Change the mode
3534    */
3535
3536   /* If the target client is founder, no one else can change their mode
3537      but themselves. */
3538   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) {
3539     tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3540     silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
3541                                          SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
3542                                          0, 2, tmp_ch_id, tmp_ch_len);
3543     goto out;
3544   }
3545
3546   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
3547     if (target_client != client) {
3548       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3549                                             SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
3550                                             0);
3551       goto out;
3552     }
3553
3554     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
3555       /* The client tries to claim the founder rights. */
3556       unsigned char *tmp_auth;
3557       SilcUInt32 tmp_auth_len;
3558       SilcChannelClientEntry chl2;
3559       SilcHashTableList htl;
3560
3561       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
3562           !channel->founder_key) {
3563         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3564                                               SILC_STATUS_ERR_AUTH_FAILED, 0);
3565         goto out;
3566       }
3567
3568       tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
3569       if (!tmp_auth) {
3570         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3571                                               SILC_STATUS_ERR_AUTH_FAILED, 0);
3572         goto out;
3573       }
3574
3575       /* Verify the authentication payload */
3576       if (!silc_auth_verify_data(tmp_auth, tmp_auth_len, SILC_AUTH_PUBLIC_KEY,
3577                                  channel->founder_key, 0, server->sha1hash,
3578                                  client->id, SILC_ID_CLIENT)) {
3579         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3580                                               SILC_STATUS_ERR_AUTH_FAILED, 0);
3581         goto out;
3582       }
3583
3584       notify = TRUE;
3585       founder_key = channel->founder_key;
3586       fkey = silc_public_key_payload_encode(founder_key);
3587       if (!fkey) {
3588         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3589                                               SILC_STATUS_ERR_AUTH_FAILED, 0);
3590         goto out;
3591       }
3592
3593       /* There cannot be anyone else as founder on the channel now.  This
3594          client is definitely the founder due to this authentication.  This
3595          is done only on router, not on server, since server cannot know
3596          whether router will accept this mode change or not.  XXX This
3597          probably shouldn't be done anymore at all, may cause problems in
3598          router-router connections too (maybe just AUTH_FAILED error should
3599          be returned). -Pekka */
3600       if (server->server_type == SILC_ROUTER) {
3601         silc_hash_table_list(channel->user_list, &htl);
3602         while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
3603           if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
3604             chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
3605             silc_server_force_cumode_change(server, NULL, channel, chl2,
3606                                             chl2->mode);
3607             break;
3608           }
3609         silc_hash_table_list_reset(&htl);
3610       }
3611
3612       sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
3613     }
3614   } else {
3615     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3616       if (target_client == client) {
3617         /* Remove channel founder rights from itself */
3618         chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
3619         notify = TRUE;
3620       } else {
3621         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3622                                               SILC_STATUS_ERR_NOT_YOU, 0);
3623         goto out;
3624       }
3625     }
3626   }
3627
3628   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
3629     /* Promote to operator */
3630     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
3631       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
3632           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
3633         tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3634         silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
3635                                              SILC_STATUS_ERR_NO_CHANNEL_PRIV,
3636                                              0, 2, tmp_ch_id, tmp_ch_len);
3637         goto out;
3638       }
3639
3640       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
3641       notify = TRUE;
3642     }
3643   } else {
3644     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
3645       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
3646           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
3647         tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3648         silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
3649                                              SILC_STATUS_ERR_NO_CHANNEL_PRIV,
3650                                              0, 2, tmp_ch_id, tmp_ch_len);
3651         goto out;
3652       }
3653
3654       /* Demote to normal user */
3655       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
3656       notify = TRUE;
3657     }
3658   }
3659
3660   if (target_mask & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) {
3661     if (target_client != client) {
3662       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3663                                             SILC_STATUS_ERR_NOT_YOU, 0);
3664       goto out;
3665     }
3666
3667     if (!(chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)) {
3668       chl->mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
3669       notify = TRUE;
3670     }
3671   } else {
3672     if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) {
3673       if (target_client != client) {
3674         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3675                                               SILC_STATUS_ERR_NOT_YOU, 0);
3676         goto out;
3677       }
3678
3679       chl->mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
3680       notify = TRUE;
3681     }
3682   }
3683
3684   if (target_mask & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS) {
3685     if (target_client != client) {
3686       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3687                                             SILC_STATUS_ERR_NOT_YOU, 0);
3688       goto out;
3689     }
3690
3691     if (!(chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)) {
3692       chl->mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
3693       notify = TRUE;
3694     }
3695   } else {
3696     if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS) {
3697       if (target_client != client) {
3698         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3699                                               SILC_STATUS_ERR_NOT_YOU, 0);
3700         goto out;
3701       }
3702
3703       chl->mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS;
3704       notify = TRUE;
3705     }
3706   }
3707
3708   if (target_mask & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS) {
3709     if (target_client != client) {
3710       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3711                                             SILC_STATUS_ERR_NOT_YOU, 0);
3712       goto out;
3713     }
3714
3715     if (!(chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)) {
3716       chl->mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
3717       notify = TRUE;
3718     }
3719   } else {
3720     if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS) {
3721       if (target_client != client) {
3722         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3723                                               SILC_STATUS_ERR_NOT_YOU, 0);
3724         goto out;
3725       }
3726
3727       chl->mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS;
3728       notify = TRUE;
3729     }
3730   }
3731
3732   if (target_mask & SILC_CHANNEL_UMODE_QUIET) {
3733     if (!(chl->mode & SILC_CHANNEL_UMODE_QUIET)) {
3734       if (client == target_client) {
3735         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3736                                               SILC_STATUS_ERR_PERM_DENIED, 0);
3737         goto out;
3738       }
3739       chl->mode |= SILC_CHANNEL_UMODE_QUIET;
3740       notify = TRUE;
3741     }
3742   } else {
3743     if (chl->mode & SILC_CHANNEL_UMODE_QUIET) {
3744       if (client == target_client) {
3745         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
3746                                               SILC_STATUS_ERR_PERM_DENIED, 0);
3747         goto out;
3748       }
3749       chl->mode &= ~SILC_CHANNEL_UMODE_QUIET;
3750       notify = TRUE;
3751     }
3752   }
3753
3754   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
3755   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
3756   tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
3757
3758   /* Send notify to channel, notify only if mode was actually changed. */
3759   if (notify) {
3760     silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
3761                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
3762                                        idp->data, silc_buffer_len(idp),
3763                                        tmp_mask, 4,
3764                                        tmp_id, tmp_len,
3765                                        fkey ? fkey->data : NULL,
3766                                        fkey ? silc_buffer_len(fkey) : 0);
3767
3768     /* Set CUMODE notify type to network */
3769     silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server),
3770                                    SILC_BROADCAST(server), channel,
3771                                    target_mask, client->id, SILC_ID_CLIENT,
3772                                    target_client->id, founder_key);
3773   }
3774
3775   /* Send command reply to sender */
3776   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_CUMODE,
3777                                  SILC_STATUS_OK, 0, ident, 3,
3778                                  2, tmp_mask, 4,
3779                                  3, tmp_ch_id, tmp_ch_len,
3780                                  4, tmp_id, tmp_len);
3781   silc_buffer_free(idp);
3782
3783  out:
3784   silc_buffer_free(fkey);
3785   silc_server_command_free(cmd);
3786 }
3787
3788 /* Server side of KICK command. Kicks client out of channel. */
3789
3790 SILC_SERVER_CMD_FUNC(kick)
3791 {
3792   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3793   SilcServer server = cmd->server;
3794   SilcClientEntry client = silc_packet_get_context(cmd->sock);
3795   SilcClientEntry target_client;
3796   SilcID id, id2;
3797   SilcChannelEntry channel;
3798   SilcChannelClientEntry chl;
3799   SilcBuffer idp;
3800   SilcUInt32 tmp_len, target_idp_len, clen;
3801   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
3802   unsigned char *tmp, *comment, *target_idp;
3803
3804   if (!client)
3805     goto out;
3806
3807   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
3808
3809   /* Get Channel ID */
3810   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
3811     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3812                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
3813     goto out;
3814   }
3815
3816   /* Get channel entry */
3817   channel = silc_idlist_find_channel_by_id(server->local_list,
3818                                            SILC_ID_GET_ID(id), NULL);
3819   if (!channel) {
3820     channel = silc_idlist_find_channel_by_id(server->local_list,
3821                                              SILC_ID_GET_ID(id), NULL);
3822     if (!channel) {
3823       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3824       silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
3825                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
3826                                            0, 2, tmp, tmp_len);
3827       goto out;
3828     }
3829   }
3830
3831   /* Check whether sender is on the channel */
3832   if (!silc_server_client_on_channel(client, channel, &chl)) {
3833     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3834     silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
3835                                          SILC_STATUS_ERR_NOT_ON_CHANNEL,
3836                                          0, 2, tmp, tmp_len);
3837     goto out;
3838   }
3839
3840   /* Check that the kicker is channel operator or channel founder */
3841   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
3842       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
3843     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3844     silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
3845                                          SILC_STATUS_ERR_NO_CHANNEL_PRIV,
3846                                          0, 2, tmp, tmp_len);
3847     goto out;
3848   }
3849
3850   /* Get target Client ID */
3851   if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id2, NULL)) {
3852     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
3853                                           SILC_STATUS_ERR_NO_CLIENT_ID, 0);
3854     goto out;
3855   }
3856
3857   /* Get target client's entry */
3858   target_client = silc_idlist_find_client_by_id(server->local_list,
3859                                                 SILC_ID_GET_ID(id2),
3860                                                 TRUE, NULL);
3861   if (!target_client)
3862     target_client = silc_idlist_find_client_by_id(server->global_list,
3863                                                   SILC_ID_GET_ID(id2),
3864                                                   TRUE, NULL);
3865
3866   /* Check whether target client is on the channel */
3867   if (!silc_server_client_on_channel(target_client, channel, &chl)) {
3868     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3869     target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
3870     silc_server_command_send_status_data2(cmd, SILC_COMMAND_KICK,
3871                                           SILC_STATUS_ERR_USER_NOT_ON_CHANNEL,
3872                                           0, 2, target_idp, target_idp_len,
3873                                           3, tmp, tmp_len);
3874     goto out;
3875   }
3876
3877   /* Check that the target client is not channel founder. Channel founder
3878      cannot be kicked from the channel. */
3879   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
3880     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3881     silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
3882                                          SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
3883                                          0, 2, tmp, tmp_len);
3884     goto out;
3885   }
3886
3887   /* Get comment */
3888   comment = silc_argument_get_arg_type(cmd->args, 3, &clen);
3889   if (clen > 128)
3890     comment = NULL;
3891
3892   /* Send the reply back to the client */
3893   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3894   target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
3895   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_KICK,
3896                                  SILC_STATUS_OK, 0, ident, 2,
3897                                  2, tmp, tmp_len,
3898                                  3, target_idp, target_idp_len);
3899
3900   /* Send KICKED notify to local clients on the channel */
3901   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
3902   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
3903                                      SILC_NOTIFY_TYPE_KICKED, 3,
3904                                      target_idp, target_idp_len,
3905                                      comment, comment ? strlen(comment) : 0,
3906                                      idp->data, silc_buffer_len(idp));
3907   silc_buffer_free(idp);
3908
3909   /* Send KICKED notify to primary route */
3910   silc_server_send_notify_kicked(server, SILC_PRIMARY_ROUTE(server),
3911                                  SILC_BROADCAST(server), channel,
3912                                  target_client->id, client->id, comment);
3913
3914   /* Remove the client from channel's invite list */
3915   if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
3916     SilcBuffer ab =
3917       silc_argument_payload_encode_one(NULL, target_idp, target_idp_len, 3);
3918     SilcArgumentPayload args =
3919       silc_argument_payload_parse(ab->data, silc_buffer_len(ab), 1);
3920
3921     silc_server_inviteban_process(server, channel->invite_list, 1, args);
3922     silc_buffer_free(ab);
3923     silc_argument_payload_free(args);
3924   }
3925
3926   /* Remove the client from the channel. If the channel does not exist
3927      after removing the client then the client kicked itself off the channel
3928      and we don't have to send anything after that. */
3929   if (!silc_server_remove_from_one_channel(server, NULL, channel,
3930                                            target_client, FALSE))
3931     goto out;
3932
3933   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
3934     /* Re-generate channel key */
3935     if (!silc_server_create_channel_key(server, channel, 0))
3936       goto out;
3937
3938     /* Send the channel key to the channel. The key of course is not sent
3939        to the client who was kicked off the channel. */
3940     silc_server_send_channel_key(server, target_client->connection, channel,
3941                                  server->server_type == SILC_ROUTER ?
3942                                  FALSE : !server->standalone);
3943   }
3944
3945  out:
3946   silc_server_command_free(cmd);
3947 }
3948
3949 /* Server side of OPER command. Client uses this comand to obtain server
3950    operator privileges to this server/router. */
3951
3952 SILC_SERVER_CMD_FUNC(oper)
3953 {
3954   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
3955   SilcServer server = cmd->server;
3956   SilcClientEntry client = silc_packet_get_context(cmd->sock);
3957   unsigned char *username = NULL, *auth;
3958   SilcUInt32 tmp_len;
3959   SilcServerConfigAdmin *admin;
3960   SilcIDListData idata = (SilcIDListData)client;
3961   SilcBool result = FALSE;
3962   SilcPublicKey cached_key;
3963   const char *hostname, *ip;
3964
3965   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
3966     goto out;
3967
3968   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
3969
3970   silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
3971                               NULL, &hostname, &ip, NULL);
3972
3973   /* Get the username */
3974   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
3975   if (!username) {
3976     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
3977                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
3978                                           0);
3979     goto out;
3980   }
3981
3982   /* Check username */
3983   username = silc_identifier_check(username, strlen(username),
3984                                    SILC_STRING_UTF8, 128, &tmp_len);
3985   if (!username) {
3986     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
3987                                           SILC_STATUS_ERR_BAD_USERNAME,
3988                                           0);
3989     goto out;
3990   }
3991
3992   /* Get the admin configuration */
3993   admin = silc_server_config_find_admin(server, (char *)ip,
3994                                         username, client->nickname);
3995   if (!admin) {
3996     admin = silc_server_config_find_admin(server, (char *)hostname,
3997                                           username, client->nickname);
3998     if (!admin) {
3999       silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4000                                             SILC_STATUS_ERR_AUTH_FAILED,
4001                                             0);
4002       SILC_LOG_INFO(("OPER authentication failed for username '%s' by "
4003                      "nickname '%s' from %s", username,
4004                      client->nickname, hostname));
4005       goto out;
4006     }
4007   }
4008
4009   /* Get the authentication payload */
4010   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4011   if (!auth) {
4012     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4013                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4014                                           0);
4015     goto out;
4016   }
4017
4018   /* Verify the authentication data. If both passphrase and public key
4019      is set then try both of them. */
4020   if (admin->passphrase)
4021     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PASSWORD,
4022                                    admin->passphrase, admin->passphrase_len,
4023                                    idata->hash, client->id, SILC_ID_CLIENT);
4024   if (!result && admin->publickeys) {
4025     cached_key =
4026       silc_server_get_public_key(server,
4027                                  SILC_SKR_USAGE_SERVICE_AUTHORIZATION, admin);
4028     if (!cached_key)
4029       goto out;
4030     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
4031                                    cached_key, 0, idata->hash,
4032                                    client->id, SILC_ID_CLIENT);
4033   }
4034   if (!result) {
4035     /* Authentication failed */
4036     silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4037                                           SILC_STATUS_ERR_AUTH_FAILED,
4038                                           0);
4039     goto out;
4040   }
4041
4042   /* Client is now server operator */
4043   client->mode |= SILC_UMODE_SERVER_OPERATOR;
4044
4045   /* Update statistics */
4046   if (SILC_IS_LOCAL(client))
4047     server->stat.my_server_ops++;
4048   if (server->server_type == SILC_ROUTER)
4049     server->stat.server_ops++;
4050
4051   /* Send UMODE change to primary router */
4052   silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
4053                                 SILC_BROADCAST(server), client->id,
4054                                 client->mode);
4055
4056   /* Check if anyone is watching this nickname */
4057   if (server->server_type == SILC_ROUTER)
4058     silc_server_check_watcher_list(server, client, NULL,
4059                                    SILC_NOTIFY_TYPE_UMODE_CHANGE);
4060
4061   /* Send reply to the sender */
4062   silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
4063                                         SILC_STATUS_OK, 0);
4064
4065  out:
4066   silc_free(username);
4067   silc_server_command_free(cmd);
4068 }
4069
4070 SILC_TASK_CALLBACK(silc_server_command_detach_cb)
4071 {
4072   SilcServer server = app_context;
4073   QuitInternal q = (QuitInternal)context;
4074   SilcPacketStream sock = q->sock;
4075   SilcClientEntry client = silc_packet_get_context(sock);
4076   SilcIDListData idata = (SilcIDListData)client;
4077
4078   if (!client) {
4079     silc_packet_stream_unref(sock);
4080     silc_free(q);
4081     return;
4082   }
4083
4084   SILC_LOG_DEBUG(("Detaching client %s",
4085                   silc_id_render(client->id, SILC_ID_CLIENT)));
4086
4087   /* Stop rekey for the client. */
4088   silc_server_stop_rekey(server, client);
4089
4090   /* Abort any active protocol */
4091   idata = silc_packet_get_context(sock);
4092   if (idata && idata->sconn && idata->sconn->op) {
4093     SILC_LOG_DEBUG(("Abort active protocol"));
4094     silc_async_abort(idata->sconn->op, NULL, NULL);
4095     idata->sconn->op = NULL;
4096   }
4097
4098   silc_schedule_task_del_by_all(server->schedule, 0, silc_server_do_heartbeat,
4099                                 sock);
4100
4101   /* Close the connection on our side */
4102   client->router = NULL;
4103   client->connection = NULL;
4104   silc_server_close_connection(server, sock);
4105
4106   /* Mark the client as locally detached. */
4107   client->local_detached = TRUE;
4108
4109   /* Decrement the user count; we'll increment it if the user resumes on our
4110      server. */
4111   SILC_VERIFY(&server->stat.my_clients > 0);
4112   server->stat.my_clients--;
4113
4114   silc_packet_stream_unref(sock);
4115   silc_free(q);
4116 }
4117
4118 SILC_TASK_CALLBACK(silc_server_command_detach_timeout)
4119 {
4120   SilcServer server = app_context;
4121   QuitInternal q = (QuitInternal)context;
4122   SilcClientID *client_id = (SilcClientID *)q->sock;
4123   SilcClientEntry client;
4124
4125   client = silc_idlist_find_client_by_id(server->local_list, client_id,
4126                                          TRUE, NULL);
4127   if (client && client->mode & SILC_UMODE_DETACHED) {
4128     SILC_LOG_DEBUG(("Detach timeout"));
4129     silc_server_free_client_data(server, NULL, client, TRUE,
4130                                  "Detach timeout");
4131   }
4132
4133   silc_free(client_id);
4134   silc_free(q);
4135 }
4136
4137 /* Server side of DETACH command.  Detached the client from the network
4138    by closing the connection but preserving the session. */
4139
4140 SILC_SERVER_CMD_FUNC(detach)
4141 {
4142   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4143   SilcServer server = cmd->server;
4144   SilcClientEntry client = silc_packet_get_context(cmd->sock);
4145   QuitInternal q;
4146
4147   if (server->config->detach_disabled) {
4148     silc_server_command_send_status_reply(cmd, SILC_COMMAND_DETACH,
4149                                           SILC_STATUS_ERR_OPERATION_ALLOWED,
4150                                           0);
4151     goto out;
4152   }
4153
4154   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
4155     goto out;
4156
4157   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_DETACH, cmd, 0, 0);
4158
4159   /* Remove operator privileges, since the client may resume in some
4160      other server which to it does not have operator privileges. */
4161   SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
4162   SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
4163
4164   /* Send the user mode notify to notify that client is detached */
4165   client->mode |= SILC_UMODE_DETACHED;
4166   client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
4167   client->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
4168   client->last_command = 0;
4169   client->fast_command = 0;
4170   silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
4171                                 SILC_BROADCAST(server), client->id,
4172                                 client->mode);
4173   server->stat.my_detached++;
4174
4175   /* Check if anyone is watching this nickname */
4176   if (server->server_type == SILC_ROUTER)
4177     silc_server_check_watcher_list(server, client, NULL,
4178                                    SILC_NOTIFY_TYPE_UMODE_CHANGE);
4179
4180   q = silc_calloc(1, sizeof(*q));
4181   q->sock = cmd->sock;
4182   silc_packet_stream_ref(q->sock);
4183   silc_schedule_task_add_timeout(server->schedule,
4184                                  silc_server_command_detach_cb,
4185                                  q, 0, 200000);
4186
4187   if (server->config->detach_timeout) {
4188     q = silc_calloc(1, sizeof(*q));
4189     q->sock = (void *)silc_id_dup(client->id, SILC_ID_CLIENT);
4190     silc_schedule_task_add_timeout(server->schedule,
4191                                    silc_server_command_detach_timeout,
4192                                    q, server->config->detach_timeout * 60, 0);
4193   }
4194
4195   /* Send reply to the sender */
4196   silc_server_command_send_status_reply(cmd, SILC_COMMAND_DETACH,
4197                                         SILC_STATUS_OK, 0);
4198
4199  out:
4200   silc_server_command_free(cmd);
4201 }
4202
4203 /* Server side of WATCH command. */
4204
4205 SILC_SERVER_CMD_FUNC(watch)
4206 {
4207   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4208   SilcServer server = cmd->server;
4209   char *add_nick, *del_nick;
4210   SilcUInt32 add_nick_len, del_nick_len, tmp_len, pk_len;
4211   unsigned char hash[SILC_HASH_MAXLEN], *tmp,  *pk, *nick;
4212   SilcClientEntry client;
4213   SilcID id;
4214   SilcUInt16 old_ident;
4215
4216   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WATCH, cmd, 1, 3);
4217
4218   if (server->server_type != SILC_ROUTER && !server->standalone) {
4219     if (!cmd->pending) {
4220       /* Send the command to router */
4221       SilcBuffer tmpbuf;
4222
4223       /* If backup receives this from primary, handle it locally */
4224       if (server->server_type == SILC_BACKUP_ROUTER &&
4225           cmd->sock == SILC_PRIMARY_ROUTE(server))
4226         goto process_watch;
4227
4228       SILC_LOG_DEBUG(("Forwarding WATCH to router"));
4229
4230       /* Statistics */
4231       cmd->server->stat.commands_sent++;
4232
4233       old_ident = silc_command_get_ident(cmd->payload);
4234       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
4235       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
4236
4237       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
4238                               SILC_PACKET_COMMAND, cmd->packet->flags,
4239                               tmpbuf->data, silc_buffer_len(tmpbuf));
4240
4241       /* Reprocess this packet after received reply from router */
4242       silc_server_command_pending(server, SILC_COMMAND_WATCH,
4243                                   silc_command_get_ident(cmd->payload),
4244                                   silc_server_command_watch,
4245                                   silc_server_command_dup(cmd));
4246       cmd->pending = TRUE;
4247       silc_command_set_ident(cmd->payload, old_ident);
4248       silc_buffer_free(tmpbuf);
4249       goto out;
4250     } else {
4251       SilcServerCommandReplyContext reply = context2;
4252       SilcStatus status;
4253
4254       if (!reply)
4255         goto out;
4256
4257       silc_command_get_status(reply->payload, &status, NULL);
4258
4259       /* Backup router handles the WATCH command also. */
4260       if (server->server_type != SILC_BACKUP_ROUTER ||
4261           SILC_STATUS_IS_ERROR(status)) {
4262         /* Received reply from router, just send same data to the client. */
4263         SILC_LOG_DEBUG(("Received reply to WATCH from router"));
4264         silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, status,
4265                                               0);
4266         goto out;
4267       }
4268     }
4269   }
4270
4271   /* We are router and keep the watch list for local cell */
4272  process_watch:
4273
4274   /* Get the client ID */
4275   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
4276     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
4277                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4278                                           0);
4279     goto out;
4280   }
4281
4282   /* Get the client entry which must be in local list */
4283   client = silc_idlist_find_client_by_id(server->local_list,
4284                                          SILC_ID_GET_ID(id), TRUE, NULL);
4285   if (!client) {
4286     /* Backup checks global list also */
4287     if (server->server_type == SILC_BACKUP_ROUTER)
4288       client = silc_idlist_find_client_by_id(server->global_list,
4289                                              SILC_ID_GET_ID(id), TRUE, NULL);
4290     if (!client) {
4291       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4292       silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
4293                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
4294                                            0, 2, tmp, tmp_len);
4295       goto out;
4296     }
4297   }
4298
4299   /* Take public key for watching by public key */
4300   pk = silc_argument_get_arg_type(cmd->args, 4, &pk_len);
4301
4302   /* Take nickname */
4303   add_nick = silc_argument_get_arg_type(cmd->args, 2, &add_nick_len);
4304   del_nick = silc_argument_get_arg_type(cmd->args, 3, &del_nick_len);
4305   if (!add_nick && !del_nick && !pk) {
4306     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
4307                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4308                                           0);
4309     goto out;
4310   }
4311
4312   if (add_nick && add_nick_len > 128) {
4313     add_nick_len = 128;
4314     add_nick[add_nick_len - 1] = '\0';
4315   }
4316   if (del_nick && del_nick_len > 128) {
4317     del_nick_len = 128;
4318     del_nick[del_nick_len - 1] = '\0';
4319   }
4320
4321   /* Add new nickname to be watched in our cell */
4322   if (add_nick) {
4323     nick = silc_identifier_check(add_nick, add_nick_len, SILC_STRING_UTF8, 128,
4324                                  &add_nick_len);
4325     if (!nick) {
4326       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
4327                                             SILC_STATUS_ERR_BAD_NICKNAME, 0);
4328       goto out;
4329     }
4330
4331     /* Hash the nick, we have the hash saved, not nicks because we can
4332        do one to one mapping to the nick from Client ID hash this way. */
4333     silc_hash_make(server->md5hash, nick, add_nick_len, hash);
4334
4335     /* Check whether this client is already watching this nickname */
4336     if (silc_hash_table_find_by_context(server->watcher_list, hash,
4337                                         client, NULL)) {
4338       /* Nickname is alredy being watched for this client */
4339       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
4340                                             SILC_STATUS_ERR_NICKNAME_IN_USE,
4341                                             0);
4342       silc_free(nick);
4343       goto out;
4344     }
4345
4346     /* Get the nickname from the watcher list and use the same key in
4347        new entries as well.  If key doesn't exist then create it. */
4348     if (!silc_hash_table_find(server->watcher_list, hash, (void *)&tmp, NULL))
4349       tmp = silc_memdup(hash, CLIENTID_HASH_LEN);
4350
4351     /* Add the client to the watcher list with the specified nickname hash. */
4352     silc_hash_table_add(server->watcher_list, tmp, client);
4353     silc_free(nick);
4354   }
4355
4356   /* Delete nickname from watch list */
4357   if (del_nick) {
4358     nick = silc_identifier_check(del_nick, del_nick_len, SILC_STRING_UTF8, 128,
4359                                  &del_nick_len);
4360     if (!nick) {
4361       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
4362                                             SILC_STATUS_ERR_BAD_NICKNAME, 0);
4363       goto out;
4364     }
4365
4366     /* Hash the nick, we have the hash saved, not nicks because we can
4367        do one to one mapping to the nick from Client ID hash this way. */
4368     silc_hash_make(server->md5hash, nick, del_nick_len, hash);
4369
4370     /* Check that this client is watching for this nickname */
4371     if (!silc_hash_table_find_by_context(server->watcher_list, hash,
4372                                          client, (void *)&tmp)) {
4373       /* Nickname is alredy being watched for this client */
4374       silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
4375                                            SILC_STATUS_ERR_NO_SUCH_NICK, 0,
4376                                            2, nick, del_nick_len);
4377       silc_free(nick);
4378       goto out;
4379     }
4380
4381     /* Delete the nickname from the watcher list. */
4382     silc_hash_table_del_by_context(server->watcher_list, hash, client);
4383
4384     /* Now check whether there still exists entries with this key, if not
4385        then free the key to not leak memory. */
4386     if (!silc_hash_table_find(server->watcher_list, hash, NULL, NULL))
4387       silc_free(tmp);
4388     silc_free(nick);
4389   }
4390
4391   /* Add/del public key */
4392   if (pk) {
4393     SilcUInt16 pkargc;
4394     SilcArgumentPayload pkargs;
4395     SilcUInt32 type;
4396     SilcPublicKey public_key, pkkey;
4397
4398     if (pk_len < 2) {
4399       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
4400                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4401                                             0);
4402       goto out;
4403     }
4404
4405     /* Get the argument from the Argument List Payload */
4406     SILC_GET16_MSB(pkargc, pk);
4407     pkargs = silc_argument_payload_parse(pk + 2, pk_len - 2, pkargc);
4408     if (!pkargs) {
4409       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
4410                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4411                                             0);
4412       goto out;
4413     }
4414
4415     pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
4416     while (pk) {
4417       if (!silc_public_key_payload_decode(pk, pk_len, &public_key)) {
4418         pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
4419         continue;
4420       }
4421       if (type == 0x03)
4422         type = 0x00;
4423
4424       if (type == 0x00) {
4425         /* Add public key to watch list */
4426
4427         /* Check whether this client is already watching this public key */
4428         if (silc_hash_table_find_by_context(server->watcher_list_pk,
4429                                             public_key, client, NULL)) {
4430           silc_pkcs_public_key_free(public_key);
4431           silc_server_command_send_status_reply(
4432                                 cmd, SILC_COMMAND_WATCH,
4433                                 SILC_STATUS_ERR_NICKNAME_IN_USE, 0);
4434           goto out;
4435         }
4436
4437         /* Get the public key from the watcher list and use the same key in
4438            new entries as well.  If key doesn't exist then create it. */
4439         pkkey = NULL;
4440         if (!silc_hash_table_find(server->watcher_list_pk, public_key,
4441                                   (void *)&pkkey, NULL))
4442           pkkey = public_key;
4443         else
4444           silc_pkcs_public_key_free(public_key);
4445
4446         /* Add the client to the watcher list with the specified public
4447            key. */
4448         silc_hash_table_add(server->watcher_list_pk, pkkey, client);
4449
4450       } else if (type == 0x01) {
4451         /* Delete public key from watch list */
4452
4453         /* Check that this client is watching this public key */
4454         if (silc_hash_table_find_by_context(server->watcher_list_pk,
4455                                             public_key, client,
4456                                             (void *)&pkkey)) {
4457           silc_pkcs_public_key_free(public_key);
4458           silc_server_command_send_status_reply(
4459                                 cmd, SILC_COMMAND_WATCH,
4460                                 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
4461           goto out;
4462         }
4463
4464         /* Delete the public key from the watcher list. */
4465         silc_hash_table_del_by_context(server->watcher_list_pk,
4466                                        public_key, client);
4467
4468         /* Now check whether there still exists entries with this key, if
4469            not then free the key to not leak memory. */
4470         if (!silc_hash_table_find(server->watcher_list_pk, hash, NULL, NULL))
4471           silc_pkcs_public_key_free(pkkey);
4472         silc_pkcs_public_key_free(public_key);
4473       }
4474
4475       pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
4476     }
4477   }
4478
4479   /* Send reply */
4480   silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
4481                                         SILC_STATUS_OK, 0);
4482
4483   /* Distribute the watch list to backup routers too */
4484   if (server->backup) {
4485     SilcBuffer tmpbuf;
4486
4487     /* Statistics */
4488     cmd->server->stat.commands_sent++;
4489
4490     old_ident = silc_command_get_ident(cmd->payload);
4491     silc_command_set_ident(cmd->payload, ++server->cmd_ident);
4492     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
4493     silc_server_backup_send(server, silc_packet_get_context(cmd->sock),
4494                             SILC_PACKET_COMMAND,
4495                             cmd->packet->flags, tmpbuf->data,
4496                             silc_buffer_len(tmpbuf),
4497                             FALSE, TRUE);
4498     silc_command_set_ident(cmd->payload, old_ident);
4499     silc_buffer_free(tmpbuf);
4500   }
4501
4502  out:
4503   silc_server_command_free(cmd);
4504 }
4505
4506 /* Server side of SILCOPER command. Client uses this comand to obtain router
4507    operator privileges to this router. */
4508
4509 SILC_SERVER_CMD_FUNC(silcoper)
4510 {
4511   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4512   SilcServer server = cmd->server;
4513   SilcClientEntry client = silc_packet_get_context(cmd->sock);
4514   unsigned char *username = NULL, *auth;
4515   SilcUInt32 tmp_len;
4516   SilcServerConfigAdmin *admin;
4517   SilcIDListData idata = (SilcIDListData)client;
4518   SilcBool result = FALSE;
4519   SilcPublicKey cached_key;
4520   const char *hostname, *ip;
4521
4522   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
4523     goto out;
4524
4525   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
4526
4527   silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
4528                               NULL, &hostname, &ip, NULL);
4529
4530   if (server->server_type != SILC_ROUTER) {
4531     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4532                                           SILC_STATUS_ERR_AUTH_FAILED, 0);
4533     goto out;
4534   }
4535
4536   /* Get the username */
4537   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
4538   if (!username) {
4539     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4540                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4541                                           0);
4542     goto out;
4543   }
4544
4545   /* Check username */
4546   username = silc_identifier_check(username, tmp_len, SILC_STRING_UTF8, 128,
4547                                    &tmp_len);
4548   if (!username) {
4549     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4550                                           SILC_STATUS_ERR_BAD_USERNAME,
4551                                           0);
4552     goto out;
4553   }
4554
4555   /* Get the admin configuration */
4556   admin = silc_server_config_find_admin(server, (char *)ip,
4557                                         username, client->nickname);
4558   if (!admin) {
4559     admin = silc_server_config_find_admin(server, (char *)hostname,
4560                                           username, client->nickname);
4561     if (!admin) {
4562       silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4563                                             SILC_STATUS_ERR_AUTH_FAILED, 0);
4564       SILC_LOG_INFO(("SILCOPER authentication failed for username '%s' by "
4565                      "nickname '%s' from %s", username,
4566                      client->nickname, hostname));
4567       goto out;
4568     }
4569   }
4570
4571   /* Get the authentication payload */
4572   auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
4573   if (!auth) {
4574     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4575                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4576                                           0);
4577     goto out;
4578   }
4579
4580   /* Verify the authentication data. If both passphrase and public key
4581      is set then try both of them. */
4582   if (admin->passphrase)
4583     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PASSWORD,
4584                                    admin->passphrase, admin->passphrase_len,
4585                                    idata->hash, client->id, SILC_ID_CLIENT);
4586   if (!result && admin->publickeys) {
4587     cached_key =
4588       silc_server_get_public_key(server,
4589                                  SILC_SKR_USAGE_SERVICE_AUTHORIZATION, admin);
4590     if (!cached_key)
4591       goto out;
4592     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
4593                                    cached_key, 0, idata->hash,
4594                                    client->id, SILC_ID_CLIENT);
4595   }
4596   if (!result) {
4597     /* Authentication failed */
4598     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4599                                           SILC_STATUS_ERR_AUTH_FAILED, 0);
4600     goto out;
4601   }
4602
4603   /* Client is now router operator */
4604   client->mode |= SILC_UMODE_ROUTER_OPERATOR;
4605
4606   /* Update statistics */
4607   if (SILC_IS_LOCAL(client))
4608     server->stat.my_router_ops++;
4609   if (server->server_type == SILC_ROUTER)
4610     server->stat.router_ops++;
4611
4612   /* Send UMODE change to primary router */
4613   silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
4614                                 SILC_BROADCAST(server), client->id,
4615                                 client->mode);
4616
4617   /* Check if anyone is watching this nickname */
4618   if (server->server_type == SILC_ROUTER)
4619     silc_server_check_watcher_list(server, client, NULL,
4620                                    SILC_NOTIFY_TYPE_UMODE_CHANGE);
4621
4622   /* Send reply to the sender */
4623   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
4624                                         SILC_STATUS_OK, 0);
4625
4626  out:
4627   silc_free(username);
4628   silc_server_command_free(cmd);
4629 }
4630
4631 /* Server side of command BAN. This is used to manage the ban list of the
4632    channel. To add clients and remove clients from the ban list. */
4633
4634 SILC_SERVER_CMD_FUNC(ban)
4635 {
4636   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4637   SilcServer server = cmd->server;
4638   SilcClientEntry client = silc_packet_get_context(cmd->sock);
4639   SilcBuffer list, tmp2;
4640   SilcChannelEntry channel;
4641   SilcChannelClientEntry chl;
4642   SilcID id;
4643   unsigned char *tmp_id, *tmp, *atype = NULL;
4644   SilcUInt32 id_len, len, len2;
4645   SilcArgumentPayload args;
4646   SilcHashTableList htl;
4647   void *type;
4648   SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
4649   SilcBufferStruct blist;
4650
4651   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
4652     goto out;
4653
4654   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_BAN, cmd, 0, 3);
4655
4656   /* Get Channel ID */
4657   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
4658     silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4659                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
4660     goto out;
4661   }
4662
4663   /* Get channel entry. The server must know about the channel since the
4664      client is expected to be on the channel. */
4665   channel = silc_idlist_find_channel_by_id(server->local_list,
4666                                            SILC_ID_GET_ID(id), NULL);
4667   if (!channel) {
4668     channel = silc_idlist_find_channel_by_id(server->global_list,
4669                                              SILC_ID_GET_ID(id), NULL);
4670     if (!channel) {
4671       tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
4672       silc_server_command_send_status_data(
4673                                            cmd, SILC_COMMAND_BAN,
4674                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
4675                                            0, 2, tmp_id, id_len);
4676       goto out;
4677     }
4678   }
4679
4680   /* Check whether this client is on the channel */
4681   if (!silc_server_client_on_channel(client, channel, &chl)) {
4682     tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
4683     silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
4684                                          SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
4685                                          2, tmp_id, id_len);
4686     goto out;
4687   }
4688
4689   /* The client must be at least channel operator. */
4690   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
4691     tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
4692     silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
4693                                          SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0,
4694                                          2, tmp_id, id_len);
4695     goto out;
4696   }
4697
4698   /* Get the ban information */
4699   tmp = silc_argument_get_arg_type(cmd->args, 3, &len2);
4700   if (tmp && len2 > 2) {
4701     /* Parse the arguments to see they are constructed correctly */
4702     SILC_GET16_MSB(argc, tmp);
4703     args = silc_argument_payload_parse(tmp + 2, len2 - 2, argc);
4704     if (!args) {
4705       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4706                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4707                                             0);
4708       goto out;
4709     }
4710
4711     /* Get the type of action */
4712     atype = silc_argument_get_arg_type(cmd->args, 2, &len);
4713     if (atype && len == 1) {
4714       if (atype[0] == 0x00) {
4715         /* Allocate hash table for ban list if it doesn't exist yet */
4716         if (!channel->ban_list)
4717           channel->ban_list =
4718             silc_hash_table_alloc(0, silc_hash_ptr,
4719                                   NULL, NULL, NULL,
4720                                   silc_server_inviteban_destruct, channel,
4721                                   TRUE);
4722
4723         /* Check for resource limit */
4724         if (silc_hash_table_count(channel->ban_list) > 64) {
4725           silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
4726                                                 SILC_STATUS_ERR_RESOURCE_LIMIT,
4727                                                 0);
4728           goto out;
4729         }
4730       }
4731
4732       /* Now add or delete the information. */
4733       if (!silc_server_inviteban_process(server, channel->ban_list,
4734                                          (SilcUInt8)atype[0], args)) {
4735         silc_server_command_send_status_reply(
4736                                       cmd, SILC_COMMAND_BAN,
4737                                       SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
4738                                       0);
4739         goto out;
4740       }
4741     }
4742     silc_argument_payload_free(args);
4743   }
4744
4745   /* Encode ban list */
4746   list = NULL;
4747   if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
4748     list = silc_buffer_alloc_size(2);
4749     silc_buffer_format(list,
4750                        SILC_STR_UI_SHORT(silc_hash_table_count(
4751                                           channel->ban_list)),
4752                        SILC_STR_END);
4753     silc_hash_table_list(channel->ban_list, &htl);
4754     while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
4755       list = silc_argument_payload_encode_one(list, tmp2->data,
4756                                               silc_buffer_len(tmp2),
4757                                               SILC_PTR_TO_32(type));
4758     silc_hash_table_list_reset(&htl);
4759   }
4760
4761   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
4762
4763   /* Send BAN notify type to local servers (but not clients) and to
4764      network. */
4765   if (atype && tmp && len2) {
4766     silc_buffer_set(&blist, tmp, len2);
4767
4768     /* Send to local servers if we are router */
4769     if (server->server_type == SILC_ROUTER)
4770       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, FALSE,
4771                                          SILC_NOTIFY_TYPE_BAN, 3,
4772                                          tmp_id, id_len,
4773                                          atype, 1,
4774                                          tmp ? blist.data : NULL,
4775                                          tmp ? silc_buffer_len(&blist) : 0);
4776
4777     /* Send to network. */
4778     silc_server_send_notify_ban(server, SILC_PRIMARY_ROUTE(server),
4779                                 SILC_BROADCAST(server), channel, atype,
4780                                 &blist);
4781   }
4782
4783   /* Send the reply back to the client */
4784   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_BAN,
4785                                  SILC_STATUS_OK, 0, ident, 2,
4786                                  2, tmp_id, id_len,
4787                                  3, list ? list->data : NULL,
4788                                  list ? silc_buffer_len(list) : 0);
4789   silc_buffer_free(list);
4790
4791  out:
4792   silc_server_command_free(cmd);
4793 }
4794
4795 /* Server side command of LEAVE. Removes client from a channel. */
4796
4797 SILC_SERVER_CMD_FUNC(leave)
4798 {
4799   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4800   SilcServer server = cmd->server;
4801   SilcPacketStream sock = cmd->sock;
4802   SilcClientEntry id_entry = silc_packet_get_context(cmd->sock);
4803   SilcID id;
4804   SilcChannelEntry channel;
4805   SilcUInt32 len;
4806   unsigned char *tmp;
4807
4808   if (id_entry->data.conn_type != SILC_CONN_CLIENT || !id_entry)
4809     goto out;
4810
4811   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 2);
4812
4813   /* Get Channel ID */
4814   if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
4815     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
4816                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
4817     goto out;
4818   }
4819
4820   /* Get channel entry */
4821   channel = silc_idlist_find_channel_by_id(server->local_list,
4822                                            SILC_ID_GET_ID(id), NULL);
4823   if (!channel) {
4824     channel = silc_idlist_find_channel_by_id(server->global_list,
4825                                              SILC_ID_GET_ID(id), NULL);
4826     if (!channel) {
4827       tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
4828       silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
4829                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
4830                                            0, 2, tmp, len);
4831       goto out;
4832     }
4833   }
4834
4835   /* Check whether this client is on the channel */
4836   if (!silc_server_client_on_channel(id_entry, channel, NULL)) {
4837     tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
4838     silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
4839                                          SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
4840                                          2, tmp, len);
4841     goto out;
4842   }
4843
4844   /* Notify routers that they should remove this client from their list
4845      of clients on the channel. Send LEAVE notify type. */
4846   silc_server_send_notify_leave(server, SILC_PRIMARY_ROUTE(server),
4847                                 SILC_BROADCAST(server), channel, id_entry->id);
4848
4849   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
4850   silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
4851                                        SILC_STATUS_OK, 0, 2, tmp, len);
4852
4853   /* Remove client from channel */
4854   if (!silc_server_remove_from_one_channel(server, sock, channel, id_entry,
4855                                            TRUE))
4856     /* If the channel does not exist anymore we won't send anything */
4857     goto out;
4858
4859   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
4860     /* Re-generate channel key */
4861     if (!silc_server_create_channel_key(server, channel, 0))
4862       goto out;
4863
4864     /* Send the channel key */
4865     silc_server_send_channel_key(server, NULL, channel,
4866                                  server->server_type == SILC_ROUTER ?
4867                                  FALSE : !server->standalone);
4868   }
4869
4870  out:
4871   silc_server_command_free(cmd);
4872 }
4873
4874 /* Server side of command USERS. Resolves clients and their USERS currently
4875    joined on the requested channel. The list of Client ID's and their modes
4876    on the channel is sent back. */
4877
4878 SILC_SERVER_CMD_FUNC(users)
4879 {
4880   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
4881   SilcServer server = cmd->server;
4882   SilcIDListData idata = silc_packet_get_context(cmd->sock);
4883   SilcChannelEntry channel;
4884   SilcID id;
4885   SilcBuffer idp;
4886   unsigned char *channel_id;
4887   SilcUInt32 channel_id_len;
4888   SilcBuffer client_id_list;
4889   SilcBuffer client_mode_list;
4890   unsigned char lc[4];
4891   SilcUInt32 list_count = 0;
4892   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
4893   char *channel_name, *channel_namec = NULL;
4894
4895   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_USERS, cmd, 1, 2);
4896
4897   /* Get Channel ID */
4898   channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
4899
4900   /* Get channel name */
4901   channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
4902
4903   if (!channel_id && !channel_name) {
4904     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4905                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
4906     goto out;
4907   }
4908
4909   /* Check channel name */
4910   if (channel_name) {
4911     channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
4912                                             SILC_STRING_UTF8, 256, NULL);
4913     if (!channel_namec) {
4914       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
4915                                             SILC_STATUS_ERR_BAD_CHANNEL, 0);
4916       goto out;
4917     }
4918   }
4919
4920   /* Check Channel ID */
4921   if (channel_id) {
4922     if (!silc_id_payload_parse_id(channel_id, channel_id_len, &id)) {
4923       silc_server_command_send_status_data(cmd, SILC_COMMAND_USERS,
4924                                            SILC_STATUS_ERR_BAD_CHANNEL_ID, 0,
4925                                            2, channel_id, channel_id_len);
4926       goto out;
4927     }
4928   }
4929
4930   /* If we are server and we don't know about this channel we will send
4931      the command to our router. If we know about the channel then we also
4932      have the list of users already. */
4933   if (channel_id)
4934     channel = silc_idlist_find_channel_by_id(server->local_list,
4935                                              SILC_ID_GET_ID(id), NULL);
4936   else
4937     channel = silc_idlist_find_channel_by_name(server->local_list,
4938                                                channel_namec, NULL);
4939
4940   if (!channel || (!server->standalone && (channel->disabled ||
4941                     !channel->users_resolved))) {
4942     if (server->server_type != SILC_ROUTER && !server->standalone &&
4943         !cmd->pending) {
4944       SilcBuffer tmpbuf;
4945
4946       /* Statistics */
4947       cmd->server->stat.commands_sent++;
4948
4949       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
4950       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
4951
4952       /* Send USERS command */
4953       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
4954                               SILC_PACKET_COMMAND, cmd->packet->flags,
4955                               tmpbuf->data, silc_buffer_len(tmpbuf));
4956
4957       /* Reprocess this packet after received reply */
4958       silc_server_command_pending(server, SILC_COMMAND_USERS,
4959                                   silc_command_get_ident(cmd->payload),
4960                                   silc_server_command_users,
4961                                   silc_server_command_dup(cmd));
4962       cmd->pending = TRUE;
4963       silc_command_set_ident(cmd->payload, ident);
4964       silc_buffer_free(tmpbuf);
4965       goto out;
4966     }
4967
4968     /* Check the global list as well. */
4969     if (channel_id)
4970       channel = silc_idlist_find_channel_by_id(server->global_list,
4971                                                SILC_ID_GET_ID(id), NULL);
4972     else
4973       channel = silc_idlist_find_channel_by_name(server->global_list,
4974                                                  channel_namec, NULL);
4975     if (!channel) {
4976       /* Channel really does not exist */
4977       if (channel_id)
4978         silc_server_command_send_status_data(
4979                                     cmd, SILC_COMMAND_USERS,
4980                                     SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID, 0,
4981                                     2, channel_id, channel_id_len);
4982       else
4983         silc_server_command_send_status_data(
4984                                     cmd, SILC_COMMAND_USERS,
4985                                     SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0,
4986                                     2, channel_name, strlen(channel_name));
4987       goto out;
4988     }
4989   }
4990
4991   /* If the channel is private or secret do not send anything, unless the
4992      user requesting this command is on the channel or is server */
4993   if (idata->conn_type == SILC_CONN_CLIENT) {
4994     if (channel->mode & (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)
4995         && !silc_server_client_on_channel((SilcClientEntry)idata, channel,
4996                                           NULL)) {
4997       silc_server_command_send_status_data(cmd, SILC_COMMAND_USERS,
4998                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0,
4999                                            2, channel->channel_name,
5000                                            strlen(channel->channel_name));
5001       goto out;
5002     }
5003   }
5004
5005   /* Get the users list */
5006   if (!silc_server_get_users_on_channel(server, channel, &client_id_list,
5007                                         &client_mode_list, &list_count)) {
5008     list_count = 0;
5009     client_id_list = NULL;
5010     client_mode_list = NULL;
5011   }
5012
5013   /* List count */
5014   SILC_PUT32_MSB(list_count, lc);
5015
5016   /* Send reply */
5017   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
5018   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_USERS,
5019                                  SILC_STATUS_OK, 0, ident, 4,
5020                                  2, idp->data, silc_buffer_len(idp),
5021                                  3, lc, 4,
5022                                  4, client_id_list ?
5023                                  client_id_list->data : NULL,
5024                                  client_id_list ?
5025                                  silc_buffer_len(client_id_list) : 0,
5026                                  5, client_mode_list ?
5027                                  client_mode_list->data : NULL,
5028                                  client_mode_list ?
5029                                  silc_buffer_len(client_mode_list) : 0);
5030   silc_buffer_free(idp);
5031   if (client_id_list)
5032     silc_buffer_free(client_id_list);
5033   if (client_mode_list)
5034     silc_buffer_free(client_mode_list);
5035
5036  out:
5037   silc_free(channel_namec);
5038   silc_server_command_free(cmd);
5039 }
5040
5041 /* Server side of command GETKEY. This fetches the client's public key
5042    from the server where to the client is connected. */
5043
5044 SILC_SERVER_CMD_FUNC(getkey)
5045 {
5046   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5047   SilcServer server = cmd->server;
5048   SilcClientEntry client;
5049   SilcServerEntry server_entry;
5050   SilcClientID client_id;
5051   SilcServerID server_id;
5052   SilcIDPayload idp = NULL;
5053   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
5054   unsigned char *tmp;
5055   SilcUInt32 tmp_len;
5056   SilcBuffer pk = NULL;
5057   SilcIdType id_type;
5058   SilcPublicKey public_key;
5059
5060   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5061   if (!tmp) {
5062     silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
5063                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5064                                           0);
5065     goto out;
5066   }
5067   idp = silc_id_payload_parse(tmp, tmp_len);
5068   if (!idp) {
5069     silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
5070                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5071                                           0);
5072     goto out;
5073   }
5074
5075   id_type = silc_id_payload_get_type(idp);
5076   if (id_type == SILC_ID_CLIENT) {
5077     silc_id_payload_get_id(idp, &client_id, sizeof(client_id));
5078
5079     /* If the client is not found from local list there is no chance it
5080        would be locally connected client so send the command further. */
5081     client = silc_idlist_find_client_by_id(server->local_list,
5082                                            &client_id, TRUE, NULL);
5083     if (!client)
5084       client = silc_idlist_find_client_by_id(server->global_list,
5085                                              &client_id, TRUE, NULL);
5086
5087     if ((!client && !cmd->pending && !server->standalone) ||
5088         (client && !client->connection && !cmd->pending &&
5089          !(client->mode & SILC_UMODE_DETACHED)) ||
5090         (client && !client->data.public_key && !cmd->pending)) {
5091       SilcBuffer tmpbuf;
5092       SilcUInt16 old_ident;
5093       SilcPacketStream dest_sock;
5094
5095       dest_sock = silc_server_get_client_route(server, NULL, 0,
5096                                                &client_id, NULL, NULL);
5097       if (!dest_sock)
5098         goto out;
5099
5100       /* Statistics */
5101       cmd->server->stat.commands_sent++;
5102
5103       old_ident = silc_command_get_ident(cmd->payload);
5104       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
5105       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
5106
5107       silc_server_packet_send(server, dest_sock,
5108                               SILC_PACKET_COMMAND, cmd->packet->flags,
5109                               tmpbuf->data, silc_buffer_len(tmpbuf));
5110
5111       /* Reprocess this packet after received reply from router */
5112       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
5113                                   silc_command_get_ident(cmd->payload),
5114                                   silc_server_command_getkey,
5115                                   silc_server_command_dup(cmd));
5116       cmd->pending = TRUE;
5117       silc_command_set_ident(cmd->payload, old_ident);
5118       silc_buffer_free(tmpbuf);
5119       goto out;
5120     }
5121
5122     if (!client) {
5123       silc_server_command_send_status_data(cmd, SILC_COMMAND_GETKEY,
5124                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
5125                                            0, 2, tmp, tmp_len);
5126       goto out;
5127     }
5128
5129     /* The client is locally connected, just get the public key and
5130        send it back. If they key does not exist then do not send it,
5131        send just OK reply */
5132     public_key = client->data.public_key;
5133     if (public_key)
5134       pk = silc_public_key_payload_encode(public_key);
5135   } else if (id_type == SILC_ID_SERVER) {
5136     silc_id_payload_get_id(idp, &server_id, sizeof(server_id));
5137
5138     /* If the server is not found from local list there is no chance it
5139        would be locally connected server so send the command further. */
5140     server_entry = silc_idlist_find_server_by_id(server->local_list,
5141                                                  &server_id, TRUE, NULL);
5142     if (!server_entry)
5143       server_entry = silc_idlist_find_server_by_id(server->global_list,
5144                                                    &server_id, TRUE, NULL);
5145
5146     if (server_entry != server->id_entry &&
5147         ((!server_entry && !cmd->pending && !server->standalone) ||
5148          (server_entry && !server_entry->connection && !cmd->pending &&
5149           !server->standalone) ||
5150          (server_entry && !server_entry->data.public_key && !cmd->pending &&
5151           !server->standalone))) {
5152       SilcBuffer tmpbuf;
5153       SilcUInt16 old_ident;
5154
5155       /* Statistics */
5156       cmd->server->stat.commands_sent++;
5157
5158       old_ident = silc_command_get_ident(cmd->payload);
5159       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
5160       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
5161
5162       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
5163                               SILC_PACKET_COMMAND, cmd->packet->flags,
5164                               tmpbuf->data, silc_buffer_len(tmpbuf));
5165
5166       /* Reprocess this packet after received reply from router */
5167       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
5168                                   silc_command_get_ident(cmd->payload),
5169                                   silc_server_command_getkey,
5170                                   silc_server_command_dup(cmd));
5171       cmd->pending = TRUE;
5172       silc_command_set_ident(cmd->payload, old_ident);
5173       silc_buffer_free(tmpbuf);
5174       goto out;
5175     }
5176
5177     if (!server_entry) {
5178       silc_server_command_send_status_data(cmd, SILC_COMMAND_GETKEY,
5179                                            SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
5180                                            0, 2, tmp, tmp_len);
5181       goto out;
5182     }
5183
5184     /* If they key does not exist then do not send it, send just OK reply */
5185     public_key = (!server_entry->data.public_key ?
5186                   (server_entry == server->id_entry ? server->public_key :
5187                    NULL) : server_entry->data.public_key);
5188     if (public_key)
5189       pk = silc_public_key_payload_encode(public_key);
5190   } else {
5191     goto out;
5192   }
5193
5194   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5195   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_GETKEY,
5196                                  SILC_STATUS_OK, 0, ident, 2,
5197                                  2, tmp, tmp_len,
5198                                  3, pk ? pk->data : NULL,
5199                                  pk ? silc_buffer_len(pk) : 0);
5200
5201  out:
5202   if (idp)
5203     silc_id_payload_free(idp);
5204   silc_buffer_free(pk);
5205   silc_server_command_free(cmd);
5206 }
5207
5208 /* Server side of command SERVICE. */
5209 /* XXX currently this just sends empty reply back */
5210
5211 SILC_SERVER_CMD_FUNC(service)
5212 {
5213   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5214   SilcServer server = cmd->server;
5215   SilcUInt32 tmp_len, auth_len;
5216   unsigned char *service_name, *auth;
5217   SilcBool send_list = FALSE;
5218   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
5219
5220   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SERVICE, cmd, 0, 256);
5221
5222   /* Get requested service */
5223   service_name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5224   if (service_name && tmp_len) {
5225     /* Verify service name */
5226     if (!silc_identifier_verify(service_name, tmp_len,
5227                                 SILC_STRING_UTF8, 256)) {
5228       silc_server_command_send_status_reply(cmd, SILC_COMMAND_SERVICE,
5229                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5230                                             0);
5231       goto out;
5232     }
5233   }
5234
5235   /* Get authentication payload if present */
5236   auth = silc_argument_get_arg_type(cmd->args, 2, &auth_len);
5237   if (auth) {
5238     /* XXX */
5239   }
5240
5241
5242   send_list = TRUE;
5243
5244   /* Send our service list back */
5245   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_SERVICE,
5246                                  SILC_STATUS_OK, 0, ident, 0);
5247
5248  out:
5249   silc_server_command_free(cmd);
5250 }
5251
5252
5253 /* Private range commands, specific to this implementation */
5254
5255 /* Server side command of CONNECT. Connects us to the specified remote
5256    server or router. */
5257
5258 SILC_SERVER_CMD_FUNC(connect)
5259 {
5260   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5261   SilcServer server = cmd->server;
5262   SilcClientEntry client = silc_packet_get_context(cmd->sock);
5263   unsigned char *tmp, *host;
5264   SilcUInt32 tmp_len;
5265   SilcUInt32 port = SILC_PORT;
5266
5267   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
5268     goto out;
5269
5270   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CONNECT, cmd, 1, 2);
5271
5272   /* Check whether client has the permissions. */
5273   if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
5274       !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
5275     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
5276                                           SILC_STATUS_ERR_NO_SERVER_PRIV, 0);
5277     goto out;
5278   }
5279
5280   if (server->server_type == SILC_ROUTER && !server->backup_router &&
5281       client->mode & SILC_UMODE_SERVER_OPERATOR) {
5282     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
5283                                           SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
5284     goto out;
5285   }
5286
5287   /* Get the remote server */
5288   host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5289   if (!host) {
5290     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
5291                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5292                                           0);
5293     goto out;
5294   }
5295
5296   /* Get port */
5297   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
5298   if (tmp)
5299     SILC_GET32_MSB(port, tmp);
5300
5301   /* Create the connection. It is done with timeout and is async. */
5302   silc_server_create_connection(server, FALSE, FALSE, host, port, NULL, NULL);
5303
5304   /* Send reply to the sender */
5305   silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
5306                                         SILC_STATUS_OK, 0);
5307
5308  out:
5309   silc_server_command_free(cmd);
5310 }
5311
5312 /* Server side command of CLOSE. Closes connection to a specified server. */
5313
5314 SILC_SERVER_CMD_FUNC(close)
5315 {
5316   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5317   SilcServer server = cmd->server;
5318   SilcClientEntry client = silc_packet_get_context(cmd->sock);
5319   SilcServerEntry server_entry;
5320   SilcPacketStream sock;
5321   unsigned char *tmp;
5322   SilcUInt32 tmp_len;
5323   unsigned char *name;
5324   SilcUInt32 port = SILC_PORT;
5325
5326   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
5327     goto out;
5328
5329   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CLOSE, cmd, 1, 2);
5330
5331   /* Check whether client has the permissions. */
5332   if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
5333       !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
5334     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
5335                                           SILC_STATUS_ERR_NO_SERVER_PRIV,
5336                                           0);
5337     goto out;
5338   }
5339
5340   /* Get the remote server */
5341   name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
5342   if (!name) {
5343     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
5344                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
5345                                           0);
5346     goto out;
5347   }
5348
5349   /* Get port */
5350   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
5351   if (tmp)
5352     SILC_GET32_MSB(port, tmp);
5353
5354   server_entry = silc_idlist_find_server_by_conn(server->local_list,
5355                                                  name, port, TRUE, NULL);
5356   if (!server_entry)
5357     server_entry = silc_idlist_find_server_by_conn(server->global_list,
5358                                                    name, port, TRUE, NULL);
5359   if (!server_entry) {
5360     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
5361                                           SILC_STATUS_ERR_NO_SERVER_ID, 0);
5362     goto out;
5363   }
5364
5365   if (server_entry == server->id_entry) {
5366     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
5367                                           SILC_STATUS_ERR_NO_SERVER_ID, 0);
5368     goto out;
5369   }
5370
5371   /* Send reply to the sender */
5372   silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
5373                                         SILC_STATUS_OK, 0);
5374
5375   /* Close the connection to the server */
5376   sock = server_entry->connection;
5377
5378   if (server_entry->server_type == SILC_BACKUP_ROUTER) {
5379     server->backup_closed = TRUE;
5380     silc_server_backup_del(server, server_entry);
5381   }
5382
5383   server->backup_noswitch = TRUE;
5384   if (server->router == server_entry) {
5385     server->id_entry->router = NULL;
5386     server->router = NULL;
5387     server->standalone = TRUE;
5388   }
5389   silc_server_disconnect_remote(server, sock,
5390                                 SILC_STATUS_ERR_BANNED_FROM_SERVER,
5391                                 "Closed by administrator");
5392   silc_server_free_sock_user_data(server, sock, NULL);
5393   server->backup_noswitch = FALSE;
5394
5395  out:
5396   silc_server_command_free(cmd);
5397 }
5398
5399 /* Server side command of SHUTDOWN. Shutdowns the server and closes all
5400    active connections. */
5401
5402 SILC_SERVER_CMD_FUNC(shutdown)
5403 {
5404   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
5405   SilcServer server = cmd->server;
5406   SilcClientEntry client = silc_packet_get_context(cmd->sock);
5407
5408   if (client->data.conn_type != SILC_CONN_CLIENT || !client)
5409     goto out;
5410
5411   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_SHUTDOWN, cmd, 0, 0);
5412
5413   /* Check whether client has the permission. */
5414   if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
5415       !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
5416     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_SHUTDOWN,
5417                                           SILC_STATUS_ERR_NO_SERVER_PRIV,
5418                                           0);
5419     goto out;
5420   }
5421
5422   /* Send reply to the sender */
5423   silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_SHUTDOWN,
5424                                         SILC_STATUS_OK, 0);
5425
5426   /* Then, gracefully, or not, bring the server down. */
5427   silc_server_stop(server);
5428   exit(0);
5429
5430  out:
5431   silc_server_command_free(cmd);
5432 }