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