Mon Jun 18 22:21:37 CEST 2007 Jochen Eisinger <coffee@silcnet.org>
[silc.git] / lib / silcclient / client.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2005 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /* Static task callback prototypes */
26 SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
27 SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
28 SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
29 SILC_TASK_CALLBACK(silc_client_rekey_final);
30
31 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
32                                      void *context);
33 static void silc_client_packet_parse_type(SilcClient client,
34                                           SilcSocketConnection sock,
35                                           SilcPacketContext *packet);
36 void silc_client_resolve_auth_method(bool success,
37                                      SilcProtocolAuthMeth auth_meth,
38                                      const unsigned char *auth_data,
39                                      SilcUInt32 auth_data_len, void *context);
40
41 /* Allocates new client object. This has to be done before client may
42    work. After calling this one must call silc_client_init to initialize
43    the client. The `application' is application specific user data pointer
44    and caller must free it. */
45
46 SilcClient silc_client_alloc(SilcClientOperations *ops,
47                              SilcClientParams *params,
48                              void *application,
49                              const char *version_string)
50 {
51   SilcClient new_client;
52
53   new_client = silc_calloc(1, sizeof(*new_client));
54   new_client->application = application;
55
56   new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
57   new_client->internal->ops = ops;
58   new_client->internal->params =
59     silc_calloc(1, sizeof(*new_client->internal->params));
60   if (!version_string)
61     version_string = silc_version_string;
62   new_client->internal->silc_client_version = strdup(version_string);
63
64   if (params)
65     memcpy(new_client->internal->params, params, sizeof(*params));
66
67   if (!new_client->internal->params->task_max)
68     new_client->internal->params->task_max = 200;
69
70   if (!new_client->internal->params->rekey_secs)
71     new_client->internal->params->rekey_secs = 3600;
72
73   if (!new_client->internal->params->connauth_request_secs)
74     new_client->internal->params->connauth_request_secs = 2;
75
76   new_client->internal->params->
77     nickname_format[sizeof(new_client->internal->
78                            params->nickname_format) - 1] = 0;
79
80   return new_client;
81 }
82
83 /* Frees client object and its internals. */
84
85 void silc_client_free(SilcClient client)
86 {
87   if (client) {
88     if (client->rng)
89       silc_rng_free(client->rng);
90
91     if (!client->internal->params->dont_register_crypto_library) {
92       silc_cipher_unregister_all();
93       silc_pkcs_unregister_all();
94       silc_hash_unregister_all();
95       silc_hmac_unregister_all();
96     }
97
98     silc_hash_free(client->md5hash);
99     silc_hash_free(client->sha1hash);
100     silc_hmac_free(client->internal->md5hmac);
101     silc_hmac_free(client->internal->sha1hmac);
102     silc_cipher_free(client->internal->none_cipher);
103     silc_free(client->internal->params);
104     silc_free(client->internal->silc_client_version);
105     silc_free(client->internal);
106     silc_free(client);
107   }
108 }
109
110 /* Initializes the client. This makes all the necessary steps to make
111    the client ready to be run. One must call silc_client_run to run the
112    client. Returns FALSE if error occured, TRUE otherwise. */
113
114 bool silc_client_init(SilcClient client)
115 {
116   SILC_LOG_DEBUG(("Initializing client"));
117
118   assert(client);
119   assert(client->username);
120   assert(client->hostname);
121   assert(client->realname);
122
123   /* Validate essential strings */
124   if (client->nickname)
125     if (!silc_identifier_verify(client->nickname, strlen(client->nickname),
126                                 SILC_STRING_UTF8, 128)) {
127       SILC_LOG_ERROR(("Malformed nickname '%s'", client->nickname));
128       return FALSE;
129     }
130   if (!silc_identifier_verify(client->username, strlen(client->username),
131                               SILC_STRING_UTF8, 128)) {
132     SILC_LOG_ERROR(("Malformed username '%s'", client->username));
133     return FALSE;
134   }
135   if (!silc_identifier_verify(client->hostname, strlen(client->hostname),
136                               SILC_STRING_UTF8, 256)) {
137     SILC_LOG_ERROR(("Malformed hostname '%s'", client->hostname));
138     return FALSE;
139   }
140   if (!silc_utf8_valid(client->realname, strlen(client->realname))) {
141     SILC_LOG_ERROR(("Malformed realname '%s'", client->realname));
142     return FALSE;
143   }
144
145   if (!client->internal->params->dont_register_crypto_library) {
146     /* Initialize the crypto library.  If application has done this already
147        this has no effect.  Also, we will not be overriding something
148        application might have registered earlier. */
149     silc_cipher_register_default();
150     silc_pkcs_register_default();
151     silc_hash_register_default();
152     silc_hmac_register_default();
153   }
154
155   /* Initialize hash functions for client to use */
156   silc_hash_alloc("md5", &client->md5hash);
157   silc_hash_alloc("sha1", &client->sha1hash);
158
159   /* Initialize none cipher */
160   silc_cipher_alloc("none", &client->internal->none_cipher);
161
162   /* Initialize random number generator */
163   client->rng = silc_rng_alloc();
164   silc_rng_init(client->rng);
165   silc_rng_global_init(client->rng);
166
167   /* Register protocols */
168   silc_client_protocols_register();
169
170   /* Initialize the scheduler */
171   client->schedule =
172     silc_schedule_init(client->internal->params->task_max ?
173                        client->internal->params->task_max : 200, client);
174   if (!client->schedule)
175     return FALSE;
176
177   /* Register commands */
178   silc_client_commands_register(client);
179
180   return TRUE;
181 }
182
183 /* Stops the client. This is called to stop the client and thus to stop
184    the program. */
185
186 void silc_client_stop(SilcClient client)
187 {
188   SILC_LOG_DEBUG(("Stopping client"));
189
190   silc_schedule_stop(client->schedule);
191   silc_schedule_uninit(client->schedule);
192
193   silc_client_protocols_unregister();
194   silc_client_commands_unregister(client);
195
196   SILC_LOG_DEBUG(("Client stopped"));
197 }
198
199 /* Runs the client. This starts the scheduler from the utility library.
200    When this functions returns the execution of the appliation is over. */
201
202 void silc_client_run(SilcClient client)
203 {
204   SILC_LOG_DEBUG(("Running client"));
205
206   assert(client);
207   assert(client->pkcs);
208   assert(client->public_key);
209   assert(client->private_key);
210
211   /* Start the scheduler, the heart of the SILC client. When this returns
212      the program will be terminated. */
213   silc_schedule(client->schedule);
214 }
215
216 /* Runs the client and returns immeadiately. This function is used when
217    the SILC Client object indicated by the `client' is run under some
218    other scheduler, or event loop or main loop.  On GUI applications,
219    for example this may be desired to use to run the client under the
220    GUI application's main loop.  Typically the GUI application would
221    register an idle task that calls this function multiple times in
222    a second to quickly process the SILC specific data. */
223
224 void silc_client_run_one(SilcClient client)
225 {
226   /* Run the scheduler once. */
227   silc_schedule_one(client->schedule, 0);
228 }
229
230 /* Allocates and adds new connection to the client. This adds the allocated
231    connection to the connection table and returns a pointer to it. A client
232    can have multiple connections to multiple servers. Every connection must
233    be added to the client using this function. User data `context' may
234    be sent as argument. This function is normally used only if the
235    application performed the connecting outside the library. The library
236    however may use this internally. */
237
238 SilcClientConnection
239 silc_client_add_connection(SilcClient client,
240                            SilcClientConnectionParams *params,
241                            char *hostname, int port, void *context)
242 {
243   SilcClientConnection conn;
244   int i;
245
246   SILC_LOG_DEBUG(("Adding new connection to %s:%d", hostname, port));
247
248   conn = silc_calloc(1, sizeof(*conn));
249   conn->internal = silc_calloc(1, sizeof(*conn->internal));
250
251   /* Initialize ID caches */
252   conn->client = client;
253   conn->remote_host = strdup(hostname);
254   conn->remote_port = port;
255   conn->context = context;
256   conn->internal->client_cache =
257     silc_idcache_alloc(0, SILC_ID_CLIENT, NULL, NULL, FALSE, TRUE);
258   conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL,
259                                                      NULL, FALSE, TRUE);
260   conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL,
261                                                     NULL, FALSE, TRUE);
262   conn->internal->pending_commands = silc_dlist_init();
263   conn->internal->ftp_sessions = silc_dlist_init();
264
265   if (params) {
266     if (params->detach_data)
267       conn->internal->params.detach_data =
268         silc_memdup(params->detach_data,
269                     params->detach_data_len);
270     conn->internal->params.detach_data_len = params->detach_data_len;
271   }
272
273   /* Add the connection to connections table */
274   for (i = 0; i < client->internal->conns_count; i++)
275     if (client->internal->conns && !client->internal->conns[i]) {
276       client->internal->conns[i] = conn;
277       return conn;
278     }
279
280   client->internal->conns =
281     silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
282                  * (client->internal->conns_count + 1));
283   client->internal->conns[client->internal->conns_count] = conn;
284   client->internal->conns_count++;
285
286   return conn;
287 }
288
289 /* Removes connection from client. Frees all memory. */
290
291 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
292 {
293   int i;
294
295   for (i = 0; i < client->internal->conns_count; i++)
296     if (client->internal->conns[i] == conn) {
297       /* Free all cache entries */
298       SilcIDCacheList list;
299       SilcIDCacheEntry entry;
300       SilcClientCommandPending *r;
301       bool ret;
302
303       if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
304         ret = silc_idcache_list_first(list, &entry);
305         while (ret) {
306           silc_client_del_client(client, conn, entry->context);
307           ret = silc_idcache_list_next(list, &entry);
308         }
309         silc_idcache_list_free(list);
310       }
311
312       if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
313         ret = silc_idcache_list_first(list, &entry);
314         while (ret) {
315           silc_client_del_channel(client, conn, entry->context);
316           ret = silc_idcache_list_next(list, &entry);
317         }
318         silc_idcache_list_free(list);
319       }
320
321       if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
322         ret = silc_idcache_list_first(list, &entry);
323         while (ret) {
324           silc_client_del_server(client, conn, entry->context);
325           ret = silc_idcache_list_next(list, &entry);
326         }
327         silc_idcache_list_free(list);
328       }
329
330       /* Clear ID caches */
331       if (conn->internal->client_cache)
332         silc_idcache_free(conn->internal->client_cache);
333       if (conn->internal->channel_cache)
334         silc_idcache_free(conn->internal->channel_cache);
335       if (conn->internal->server_cache)
336         silc_idcache_free(conn->internal->server_cache);
337
338       /* Free data (my ID is freed in above silc_client_del_client).
339          conn->nickname is freed when freeing the local_entry->nickname. */
340       silc_free(conn->remote_host);
341       silc_free(conn->local_id_data);
342       if (conn->internal->send_key)
343         silc_cipher_free(conn->internal->send_key);
344       if (conn->internal->receive_key)
345         silc_cipher_free(conn->internal->receive_key);
346       if (conn->internal->hmac_send)
347         silc_hmac_free(conn->internal->hmac_send);
348       if (conn->internal->hmac_receive)
349         silc_hmac_free(conn->internal->hmac_receive);
350       silc_free(conn->internal->rekey);
351
352       if (conn->internal->active_session) {
353         if (conn->sock)
354           conn->sock->user_data = NULL;
355         silc_client_ftp_session_free(conn->internal->active_session);
356         conn->internal->active_session = NULL;
357       }
358
359       silc_client_ftp_free_sessions(client, conn);
360
361       if (conn->internal->pending_commands) {
362         silc_dlist_start(conn->internal->pending_commands);
363         while ((r = silc_dlist_get(conn->internal->pending_commands))
364                != SILC_LIST_END)
365           silc_dlist_del(conn->internal->pending_commands, r);
366         silc_dlist_uninit(conn->internal->pending_commands);
367       }
368
369       silc_free(conn->internal);
370       memset(conn, 0, sizeof(*conn));
371       silc_free(conn);
372
373       client->internal->conns[i] = NULL;
374     }
375 }
376
377 /* Adds listener socket to the listener sockets table. This function is
378    used to add socket objects that are listeners to the client.  This should
379    not be used to add other connection objects. */
380
381 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
382 {
383   int i;
384
385   if (!client->internal->sockets) {
386     client->internal->sockets =
387       silc_calloc(1, sizeof(*client->internal->sockets));
388     client->internal->sockets[0] = silc_socket_dup(sock);
389     client->internal->sockets_count = 1;
390     return;
391   }
392
393   for (i = 0; i < client->internal->sockets_count; i++) {
394     if (client->internal->sockets[i] == NULL) {
395       client->internal->sockets[i] = silc_socket_dup(sock);
396       return;
397     }
398   }
399
400   client->internal->sockets =
401     silc_realloc(client->internal->sockets,
402                  sizeof(*client->internal->sockets) *
403                  (client->internal->sockets_count + 1));
404   client->internal->sockets[client->internal->sockets_count] =
405     silc_socket_dup(sock);
406   client->internal->sockets_count++;
407 }
408
409 /* Deletes listener socket from the listener sockets table. */
410
411 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
412 {
413   int i;
414
415   if (!client->internal->sockets)
416     return;
417
418   for (i = 0; i < client->internal->sockets_count; i++) {
419     if (client->internal->sockets[i] == sock) {
420       silc_socket_free(sock);
421       client->internal->sockets[i] = NULL;
422       return;
423     }
424   }
425 }
426
427 static int
428 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
429 {
430   int sock;
431
432   /* XXX In the future we should give up this non-blocking connect all
433      together and use threads instead. */
434   /* Create connection to server asynchronously */
435   sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
436   if (sock < 0)
437     return -1;
438
439   /* Register task that will receive the async connect and will
440      read the result. */
441   ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
442                                      silc_client_connect_to_server_start,
443                                      (void *)ctx, 0, 0,
444                                      SILC_TASK_FD,
445                                      SILC_TASK_PRI_NORMAL);
446   silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
447                               FALSE);
448
449   ctx->sock = sock;
450
451   return sock;
452 }
453
454 /* Connects to remote server. This is the main routine used to connect
455    to SILC server. Returns -1 on error and the created socket otherwise.
456    The `context' is user context that is saved into the SilcClientConnection
457    that is created after the connection is created. Note that application
458    may handle the connecting process outside the library. If this is the
459    case then this function is not used at all. When the connecting is
460    done the `connect' client operation is called. */
461
462 int silc_client_connect_to_server(SilcClient client,
463                                   SilcClientConnectionParams *params,
464                                   int port, char *host, void *context)
465 {
466   SilcClientInternalConnectContext *ctx;
467   SilcClientConnection conn;
468   int sock;
469
470   SILC_LOG_DEBUG(("Connecting to port %d of server %s",
471                   port, host));
472
473   conn = silc_client_add_connection(client, params, host, port, context);
474
475   client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
476                              "Connecting to port %d of server %s", port, host);
477
478   /* Allocate internal context for connection process. This is
479      needed as we are doing async connecting. */
480   ctx = silc_calloc(1, sizeof(*ctx));
481   ctx->client = client;
482   ctx->conn = conn;
483   ctx->host = strdup(host);
484   ctx->port = port ? port : 706;
485   ctx->tries = 0;
486
487   /* Do the actual connecting process */
488   sock = silc_client_connect_to_server_internal(ctx);
489   if (sock == -1)
490     silc_client_del_connection(client, conn);
491   return sock;
492 }
493
494 /* Socket hostname and IP lookup callback that is called before actually
495    starting the key exchange.  The lookup is called from the function
496    silc_client_start_key_exchange. */
497
498 static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
499                                               void *context)
500 {
501   SilcClientConnection conn = (SilcClientConnection)context;
502   SilcClient client = conn->client;
503   SilcProtocol protocol;
504   SilcClientKEInternalContext *proto_ctx;
505
506   SILC_LOG_DEBUG(("Start"));
507
508   if (conn->sock->hostname) {
509     silc_free(conn->remote_host);
510     conn->remote_host = strdup(conn->sock->hostname);
511   } else {
512     conn->sock->hostname = strdup(conn->remote_host);
513   }
514   if (!conn->sock->ip)
515     conn->sock->ip = strdup(conn->sock->hostname);
516   conn->sock->port = conn->remote_port;
517
518   /* Allocate internal Key Exchange context. This is sent to the
519      protocol as context. */
520   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
521   proto_ctx->client = (void *)client;
522   proto_ctx->sock = silc_socket_dup(conn->sock);
523   proto_ctx->rng = client->rng;
524   proto_ctx->responder = FALSE;
525   proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
526   proto_ctx->verify = silc_client_protocol_ke_verify_key;
527
528   /* Perform key exchange protocol. silc_client_connect_to_server_final
529      will be called after the protocol is finished. */
530   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
531                       &protocol, (void *)proto_ctx,
532                       silc_client_connect_to_server_second);
533   if (!protocol) {
534     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
535                                "Error: Could not start key exchange protocol");
536     silc_net_close_connection(conn->sock->sock);
537     client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
538     return;
539   }
540   conn->sock->protocol = protocol;
541
542   /* Register the connection for network input and output. This sets
543      that scheduler will listen for incoming packets for this connection
544      and sets that outgoing packets may be sent to this connection as well.
545      However, this doesn't set the scheduler for outgoing traffic, it will
546      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
547      later when outgoing data is available. */
548   context = (void *)client;
549   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
550
551   /* Execute the protocol */
552   silc_protocol_execute(protocol, client->schedule, 0, 0);
553 }
554
555 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
556    key material between client and server.  This function can be called
557    directly if application is performing its own connecting and does not
558    use the connecting provided by this library. This function is normally
559    used only if the application performed the connecting outside the library.
560    The library however may use this internally. */
561
562 void silc_client_start_key_exchange(SilcClient client,
563                                     SilcClientConnection conn,
564                                     int fd)
565 {
566   assert(client->pkcs);
567   assert(client->public_key);
568   assert(client->private_key);
569
570   /* Allocate new socket connection object */
571   silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
572
573   /* Sometimes when doing quick reconnects the new socket may be same as
574      the old one and there might be pending stuff for the old socket.
575      If new one is same then those pending sutff might cause problems.
576      Make sure they do not do that. */
577   silc_schedule_task_del_by_fd(client->schedule, fd);
578
579   conn->nickname = (client->nickname ? strdup(client->nickname) :
580                     strdup(client->username));
581
582   /* Resolve the remote hostname and IP address for our socket connection */
583   silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
584                           conn, client->schedule);
585 }
586
587 /* Callback called when error has occurred during connecting (KE) to
588    the server.  The `connect' client operation will be called. */
589
590 SILC_TASK_CALLBACK(silc_client_connect_failure)
591 {
592   SilcClientKEInternalContext *ctx =
593     (SilcClientKEInternalContext *)context;
594   SilcClient client = (SilcClient)ctx->client;
595
596   client->internal->ops->connected(client, ctx->sock->user_data,
597                                    SILC_CLIENT_CONN_ERROR_KE);
598   if (ctx->packet)
599     silc_packet_context_free(ctx->packet);
600   silc_free(ctx);
601 }
602
603 /* Callback called when error has occurred during connecting (auth) to
604    the server.  The `connect' client operation will be called. */
605
606 SILC_TASK_CALLBACK(silc_client_connect_failure_auth)
607 {
608   SilcClientConnAuthInternalContext *ctx =
609     (SilcClientConnAuthInternalContext *)context;
610   SilcClient client = (SilcClient)ctx->client;
611
612   client->internal->ops->connected(client, ctx->sock->user_data, ctx->status);
613   silc_free(ctx);
614 }
615
616 /* Start of the connection to the remote server. This is called after
617    succesful TCP/IP connection has been established to the remote host. */
618
619 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
620 {
621   SilcClientInternalConnectContext *ctx =
622     (SilcClientInternalConnectContext *)context;
623   SilcClient client = ctx->client;
624   SilcClientConnection conn = ctx->conn;
625   int opt, opt_len = sizeof(opt);
626
627   SILC_LOG_DEBUG(("Start"));
628
629   /* Check the socket status as it might be in error */
630   silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
631   if (opt != 0) {
632     if (ctx->tries < 2) {
633       /* Connection failed but lets try again */
634       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
635                                  "Could not connect to server %s: %s",
636                                  ctx->host, strerror(opt));
637       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
638                                  "Connecting to port %d of server %s resumed",
639                                  ctx->port, ctx->host);
640
641       /* Unregister old connection try */
642       silc_schedule_unset_listen_fd(client->schedule, fd);
643       silc_net_close_connection(fd);
644       silc_schedule_task_del(client->schedule, ctx->task);
645
646       /* Try again */
647       silc_client_connect_to_server_internal(ctx);
648       ctx->tries++;
649     } else {
650       /* Connection failed and we won't try anymore */
651       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
652                                  "Could not connect to server %s: %s",
653                                  ctx->host, strerror(opt));
654       silc_schedule_unset_listen_fd(client->schedule, fd);
655       silc_net_close_connection(fd);
656       silc_schedule_task_del(client->schedule, ctx->task);
657       silc_free(ctx);
658
659       /* Notify application of failure */
660       client->internal->ops->connected(client, conn,
661                                        SILC_CLIENT_CONN_ERROR_TIMEOUT);
662     }
663     return;
664   }
665
666   silc_schedule_unset_listen_fd(client->schedule, fd);
667   silc_schedule_task_del(client->schedule, ctx->task);
668   silc_free(ctx);
669
670   silc_client_start_key_exchange(client, conn, fd);
671 }
672
673 /* Second part of the connecting to the server. This executed
674    authentication protocol. */
675
676 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
677 {
678   SilcProtocol protocol = (SilcProtocol)context;
679   SilcClientKEInternalContext *ctx =
680     (SilcClientKEInternalContext *)protocol->context;
681   SilcClient client = (SilcClient)ctx->client;
682   SilcSocketConnection sock = NULL;
683   SilcClientConnAuthInternalContext *proto_ctx;
684
685   SILC_LOG_DEBUG(("Start"));
686
687   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
688       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
689     /* Error occured during protocol */
690     SILC_LOG_DEBUG(("Error during KE protocol"));
691     silc_protocol_free(protocol);
692     silc_ske_free_key_material(ctx->keymat);
693     if (ctx->ske)
694       silc_ske_free(ctx->ske);
695     if (ctx->dest_id)
696       silc_free(ctx->dest_id);
697     ctx->sock->protocol = NULL;
698     silc_socket_free(ctx->sock);
699
700     /* Notify application of failure */
701     silc_schedule_task_add(client->schedule, ctx->sock->sock,
702                            silc_client_connect_failure, ctx,
703                            0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
704     return;
705   }
706
707   /* We now have the key material as the result of the key exchange
708      protocol. Take the key material into use. Free the raw key material
709      as soon as we've set them into use. */
710   silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
711                                    ctx->ske->prop->cipher,
712                                    ctx->ske->prop->pkcs,
713                                    ctx->ske->prop->hash,
714                                    ctx->ske->prop->hmac,
715                                    ctx->ske->prop->group,
716                                    ctx->responder);
717   silc_ske_free_key_material(ctx->keymat);
718
719   /* Allocate internal context for the authentication protocol. This
720      is sent as context for the protocol. */
721   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
722   proto_ctx->client = (void *)client;
723   proto_ctx->sock = sock = ctx->sock;
724   proto_ctx->ske = ctx->ske;    /* Save SKE object from previous protocol */
725   proto_ctx->dest_id_type = ctx->dest_id_type;
726   proto_ctx->dest_id = ctx->dest_id;
727
728   /* Free old protocol as it is finished now */
729   silc_protocol_free(protocol);
730   if (ctx->packet)
731     silc_packet_context_free(ctx->packet);
732   ctx->packet = NULL;
733   silc_free(ctx);
734   sock->protocol = NULL;
735
736   /* Resolve the authentication method to be used in this connection. The
737      completion callback is called after the application has resolved
738      the authentication method. */
739   client->internal->ops->get_auth_method(client, sock->user_data,
740                                          sock->hostname,
741                                          sock->port,
742                                          silc_client_resolve_auth_method,
743                                          proto_ctx);
744 }
745
746 /* Authentication method resolving callback. Application calls this function
747    after we've called the client->internal->ops->get_auth_method
748    client operation to resolve the authentication method. We will continue
749    the executiong of the protocol in this function. */
750
751 void silc_client_resolve_auth_method(bool success,
752                                      SilcProtocolAuthMeth auth_meth,
753                                      const unsigned char *auth_data,
754                                      SilcUInt32 auth_data_len, void *context)
755 {
756   SilcClientConnAuthInternalContext *proto_ctx =
757     (SilcClientConnAuthInternalContext *)context;
758   SilcClient client = (SilcClient)proto_ctx->client;
759
760   if (!success)
761     auth_meth = SILC_AUTH_NONE;
762
763   proto_ctx->auth_meth = auth_meth;
764
765   if (success && auth_data && auth_data_len) {
766
767     /* Passphrase must be UTF-8 encoded, if it isn't encode it */
768     if (auth_meth == SILC_AUTH_PASSWORD &&
769         !silc_utf8_valid(auth_data, auth_data_len)) {
770       int payload_len = 0;
771       unsigned char *autf8 = NULL;
772       payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
773                                           SILC_STRING_ASCII);
774       autf8 = silc_calloc(payload_len, sizeof(*autf8));
775       auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
776                                        SILC_STRING_ASCII, autf8, payload_len);
777       auth_data = autf8;
778     }
779
780     proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
781     proto_ctx->auth_data_len = auth_data_len;
782   }
783
784   /* Allocate the authenteication protocol and execute it. */
785   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
786                       &proto_ctx->sock->protocol, (void *)proto_ctx,
787                       silc_client_connect_to_server_final);
788
789   /* Execute the protocol */
790   silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
791 }
792
793 /* Finalizes the connection to the remote SILC server. This is called
794    after authentication protocol has been completed. This send our
795    user information to the server to receive our client ID from
796    server. */
797
798 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
799 {
800   SilcProtocol protocol = (SilcProtocol)context;
801   SilcClientConnAuthInternalContext *ctx =
802     (SilcClientConnAuthInternalContext *)protocol->context;
803   SilcClient client = (SilcClient)ctx->client;
804   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
805   SilcBuffer packet;
806
807   SILC_LOG_DEBUG(("Start"));
808
809   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
810       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
811     /* Error occured during protocol */
812     SILC_LOG_DEBUG(("Error during authentication protocol"));
813     ctx->status = SILC_CLIENT_CONN_ERROR_AUTH;
814     goto err;
815   }
816
817   if (conn->internal->params.detach_data) {
818     /* Send RESUME_CLIENT packet to the server, which is used to resume
819        old detached session back. */
820     SilcBuffer auth;
821     SilcClientID *old_client_id;
822     unsigned char *old_id;
823     SilcUInt16 old_id_len;
824
825     if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len)) {
826       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
827       goto err;
828     }
829
830     old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
831     if (!old_client_id) {
832       silc_free(old_id);
833       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
834       goto err;
835     }
836
837     /* Generate authentication data that server will verify */
838     auth = silc_auth_public_key_auth_generate(client->public_key,
839                                               client->private_key,
840                                               client->rng,
841                                               conn->internal->hash,
842                                               old_client_id, SILC_ID_CLIENT);
843     if (!auth) {
844       silc_free(old_client_id);
845       silc_free(old_id);
846       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
847       goto err;
848     }
849
850     packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
851     silc_buffer_format(packet,
852                        SILC_STR_UI_SHORT(old_id_len),
853                        SILC_STR_UI_XNSTRING(old_id, old_id_len),
854                        SILC_STR_UI_XNSTRING(auth->data, auth->len),
855                        SILC_STR_END);
856
857     /* Send the packet */
858     silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
859                             NULL, 0, NULL, NULL,
860                             packet->data, packet->len, TRUE);
861     silc_buffer_free(packet);
862     silc_buffer_free(auth);
863     silc_free(old_client_id);
864     silc_free(old_id);
865   } else {
866     /* Send NEW_CLIENT packet to the server. We will become registered
867        to the SILC network after sending this packet and we will receive
868        client ID from the server. */
869     packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
870                                strlen(client->realname));
871     silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
872     silc_buffer_format(packet,
873                        SILC_STR_UI_SHORT(strlen(client->username)),
874                        SILC_STR_UI_XNSTRING(client->username,
875                                             strlen(client->username)),
876                        SILC_STR_UI_SHORT(strlen(client->realname)),
877                        SILC_STR_UI_XNSTRING(client->realname,
878                                             strlen(client->realname)),
879                        SILC_STR_END);
880
881     /* Send the packet */
882     silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
883                             NULL, 0, NULL, NULL,
884                             packet->data, packet->len, TRUE);
885     silc_buffer_free(packet);
886   }
887
888   /* Save remote ID. */
889   conn->remote_id = ctx->dest_id;
890   conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
891   conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
892
893   /* Register re-key timeout */
894   conn->internal->rekey->timeout = client->internal->params->rekey_secs;
895   conn->internal->rekey->context = (void *)client;
896   silc_schedule_task_add(client->schedule, conn->sock->sock,
897                          silc_client_rekey_callback,
898                          (void *)conn->sock, conn->internal->rekey->timeout, 0,
899                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
900
901   silc_protocol_free(protocol);
902   silc_free(ctx->auth_data);
903   if (ctx->ske)
904     silc_ske_free(ctx->ske);
905   silc_socket_free(ctx->sock);
906   silc_free(ctx);
907   conn->sock->protocol = NULL;
908   return;
909
910  err:
911   silc_protocol_free(protocol);
912   silc_free(ctx->auth_data);
913   silc_free(ctx->dest_id);
914   if (ctx->ske)
915     silc_ske_free(ctx->ske);
916   conn->sock->protocol = NULL;
917   silc_socket_free(ctx->sock);
918
919   /* Notify application of failure */
920   silc_schedule_task_add(client->schedule, ctx->sock->sock,
921                          silc_client_connect_failure_auth, ctx,
922                          0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
923 }
924
925 /* Internal routine that sends packet or marks packet to be sent. This
926    is used directly only in special cases. Normal cases should use
927    silc_server_packet_send. Returns < 0 on error. */
928
929 int silc_client_packet_send_real(SilcClient client,
930                                  SilcSocketConnection sock,
931                                  bool force_send)
932 {
933   int ret;
934
935   /* If rekey protocol is active we must assure that all packets are
936      sent through packet queue. */
937   if (SILC_CLIENT_IS_REKEY(sock))
938     force_send = FALSE;
939
940   /* If outbound data is already pending do not force send */
941   if (SILC_IS_OUTBUF_PENDING(sock))
942     force_send = FALSE;
943
944   /* Send the packet */
945   ret = silc_packet_send(sock, force_send);
946   if (ret != -2)
947     return ret;
948
949   /* Mark that there is some outgoing data available for this connection.
950      This call sets the connection both for input and output (the input
951      is set always and this call keeps the input setting, actually).
952      Actual data sending is performed by silc_client_packet_process. */
953   SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
954
955   /* Mark to socket that data is pending in outgoing buffer. This flag
956      is needed if new data is added to the buffer before the earlier
957      put data is sent to the network. */
958   SILC_SET_OUTBUF_PENDING(sock);
959
960   return 0;
961 }
962
963 /* Packet processing callback. This is used to send and receive packets
964    from network. This is generic task. */
965
966 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
967 {
968   SilcClient client = (SilcClient)context;
969   SilcSocketConnection sock = NULL;
970   SilcClientConnection conn;
971   int ret;
972
973   SILC_LOG_DEBUG(("Processing packet"));
974
975   SILC_CLIENT_GET_SOCK(client, fd, sock);
976   if (sock == NULL)
977     return;
978
979   conn = (SilcClientConnection)sock->user_data;
980
981   /* Packet sending */
982   if (type == SILC_TASK_WRITE) {
983     /* Do not send data to disconnected connection */
984     if (SILC_IS_DISCONNECTED(sock))
985       return;
986
987     ret = silc_packet_send(sock, TRUE);
988
989     /* If returned -2 could not write to connection now, will do
990        it later. */
991     if (ret == -2)
992       return;
993
994     /* Error */
995     if (ret == -1)
996       return;
997
998     /* The packet has been sent and now it is time to set the connection
999        back to only for input. When there is again some outgoing data
1000        available for this connection it will be set for output as well.
1001        This call clears the output setting and sets it only for input. */
1002     SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
1003     SILC_UNSET_OUTBUF_PENDING(sock);
1004
1005     silc_buffer_clear(sock->outbuf);
1006     return;
1007   }
1008
1009   /* Packet receiving */
1010   if (type == SILC_TASK_READ) {
1011     /* Read data from network */
1012     ret = silc_packet_receive(sock);
1013     if (ret < 0)
1014       return;
1015
1016     /* EOF */
1017     if (ret == 0) {
1018       SILC_LOG_DEBUG(("Read EOF"));
1019
1020       /* If connection is disconnecting already we will finally
1021          close the connection */
1022       if (SILC_IS_DISCONNECTING(sock)) {
1023         if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
1024           client->internal->ops->disconnected(client, conn, 0, NULL);
1025         silc_client_close_connection_real(client, sock, conn);
1026         return;
1027       }
1028
1029       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
1030       if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
1031         client->internal->ops->disconnected(client, conn, 0, NULL);
1032       silc_client_close_connection_real(client, sock, conn);
1033       return;
1034     }
1035
1036     /* Process the packet. This will call the parser that will then
1037        decrypt and parse the packet. */
1038     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
1039       silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
1040                                   conn->internal->hmac_receive,
1041                                   conn->internal->psn_receive,
1042                                   silc_client_packet_parse, client);
1043     else
1044       silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
1045                                   silc_client_packet_parse, client);
1046   }
1047 }
1048
1049 /* Parser callback called by silc_packet_receive_process. Thie merely
1050    registers timeout that will handle the actual parsing when appropriate. */
1051
1052 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
1053                                      void *context)
1054 {
1055   SilcClient client = (SilcClient)context;
1056   SilcSocketConnection sock = parser_context->sock;
1057   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1058   SilcPacketContext *packet = parser_context->packet;
1059   SilcPacketType ret;
1060
1061   if (conn && conn->internal->hmac_receive && conn->sock == sock)
1062     conn->internal->psn_receive = parser_context->packet->sequence + 1;
1063
1064   /* Parse the packet immediately */
1065   if (parser_context->normal)
1066     ret = silc_packet_parse(packet, conn->internal->receive_key);
1067   else
1068     ret = silc_packet_parse_special(packet, conn->internal->receive_key);
1069
1070   if (ret == SILC_PACKET_NONE) {
1071     silc_packet_context_free(packet);
1072     silc_free(parser_context);
1073     return FALSE;
1074   }
1075
1076   /* If protocol for this connection is key exchange or rekey then we'll
1077      process all packets synchronously, since there might be packets in
1078      queue that we are not able to decrypt without first processing the
1079      packets before them. */
1080   if (sock->protocol && sock->protocol->protocol &&
1081       (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1082        sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1083
1084     /* Parse the incoming packet type */
1085     silc_client_packet_parse_type(client, sock, packet);
1086
1087     /* Reprocess the buffer since we'll return FALSE. This is because
1088        the `conn->internal->receive_key' might have become valid by processing
1089        the previous packet */
1090     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
1091       silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
1092                                   conn->internal->hmac_receive,
1093                                   conn->internal->psn_receive,
1094                                   silc_client_packet_parse, client);
1095     else
1096       silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
1097                                   silc_client_packet_parse, client);
1098
1099     silc_packet_context_free(packet);
1100     silc_free(parser_context);
1101
1102     return FALSE;
1103   }
1104
1105   /* Parse the incoming packet type */
1106   silc_client_packet_parse_type(client, sock, packet);
1107   silc_packet_context_free(packet);
1108   silc_free(parser_context);
1109   return TRUE;
1110 }
1111
1112 /* Parses the packet type and calls what ever routines the packet type
1113    requires. This is done for all incoming packets. */
1114
1115 void silc_client_packet_parse_type(SilcClient client,
1116                                    SilcSocketConnection sock,
1117                                    SilcPacketContext *packet)
1118 {
1119   SilcBuffer buffer = packet->buffer;
1120   SilcPacketType type = packet->type;
1121
1122   SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(type)));
1123
1124   /* Parse the packet type */
1125   switch(type) {
1126
1127   case SILC_PACKET_DISCONNECT:
1128     silc_client_disconnected_by_server(client, sock, buffer);
1129     break;
1130
1131   case SILC_PACKET_SUCCESS:
1132     /*
1133      * Success received for something. For now we can have only
1134      * one protocol for connection executing at once hence this
1135      * success message is for whatever protocol is executing currently.
1136      */
1137     if (sock->protocol)
1138       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1139     break;
1140
1141   case SILC_PACKET_FAILURE:
1142     /*
1143      * Failure received for some protocol. Set the protocol state to
1144      * error and call the protocol callback. This fill cause error on
1145      * protocol and it will call the final callback.
1146      */
1147     silc_client_process_failure(client, sock, packet);
1148     break;
1149
1150   case SILC_PACKET_REJECT:
1151     break;
1152
1153   case SILC_PACKET_NOTIFY:
1154     /*
1155      * Received notify message
1156      */
1157     silc_client_notify_by_server(client, sock, packet);
1158     break;
1159
1160   case SILC_PACKET_ERROR:
1161     /*
1162      * Received error message
1163      */
1164     silc_client_error_by_server(client, sock, buffer);
1165     break;
1166
1167   case SILC_PACKET_CHANNEL_MESSAGE:
1168     /*
1169      * Received message to (from, actually) a channel
1170      */
1171     silc_client_channel_message(client, sock, packet);
1172     break;
1173
1174   case SILC_PACKET_CHANNEL_KEY:
1175     /*
1176      * Received key for a channel. By receiving this key the client will be
1177      * able to talk to the channel it has just joined. This can also be
1178      * a new key for existing channel as keys expire peridiocally.
1179      */
1180     silc_client_receive_channel_key(client, sock, buffer);
1181     break;
1182
1183   case SILC_PACKET_PRIVATE_MESSAGE:
1184     /*
1185      * Received private message
1186      */
1187     silc_client_private_message(client, sock, packet);
1188     break;
1189
1190   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
1191     /*
1192      * Received private message key indicator
1193      */
1194     silc_client_private_message_key(client, sock, packet);
1195     break;
1196
1197   case SILC_PACKET_COMMAND:
1198     /*
1199      * Received command packet, a special case since normally client
1200      * does not receive commands.
1201      */
1202     silc_client_command_process(client, sock, packet);
1203     break;
1204
1205   case SILC_PACKET_COMMAND_REPLY:
1206     /*
1207      * Recived reply for a command
1208      */
1209     silc_client_command_reply_process(client, sock, packet);
1210     break;
1211
1212   case SILC_PACKET_KEY_EXCHANGE:
1213     if (sock->protocol && sock->protocol->protocol &&
1214         sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1215       SilcClientKEInternalContext *proto_ctx =
1216         (SilcClientKEInternalContext *)sock->protocol->context;
1217
1218       proto_ctx->packet = silc_packet_context_dup(packet);
1219       proto_ctx->dest_id_type = packet->src_id_type;
1220       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1221                                           packet->src_id_type);
1222       if (!proto_ctx->dest_id)
1223         break;
1224
1225       /* Let the protocol handle the packet */
1226       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1227     } else {
1228       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
1229                       "protocol active, packet dropped."));
1230     }
1231     break;
1232
1233   case SILC_PACKET_KEY_EXCHANGE_1:
1234     if (sock->protocol && sock->protocol->protocol &&
1235         (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1236          sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1237
1238       if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1239         SilcClientRekeyInternalContext *proto_ctx =
1240           (SilcClientRekeyInternalContext *)sock->protocol->context;
1241
1242         if (proto_ctx->packet)
1243           silc_packet_context_free(proto_ctx->packet);
1244
1245         proto_ctx->packet = silc_packet_context_dup(packet);
1246
1247         /* Let the protocol handle the packet */
1248         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1249       } else {
1250         SilcClientKEInternalContext *proto_ctx =
1251           (SilcClientKEInternalContext *)sock->protocol->context;
1252
1253         if (proto_ctx->packet)
1254           silc_packet_context_free(proto_ctx->packet);
1255
1256         proto_ctx->packet = silc_packet_context_dup(packet);
1257         proto_ctx->dest_id_type = packet->src_id_type;
1258         proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1259                                             packet->src_id_type);
1260         if (!proto_ctx->dest_id)
1261           break;
1262
1263         /* Let the protocol handle the packet */
1264         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1265       }
1266     } else {
1267       SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
1268                       "protocol active, packet dropped."));
1269     }
1270     break;
1271
1272   case SILC_PACKET_KEY_EXCHANGE_2:
1273     if (sock->protocol && sock->protocol->protocol &&
1274         (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1275          sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1276
1277       if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1278         SilcClientRekeyInternalContext *proto_ctx =
1279           (SilcClientRekeyInternalContext *)sock->protocol->context;
1280
1281         if (proto_ctx->packet)
1282           silc_packet_context_free(proto_ctx->packet);
1283
1284         proto_ctx->packet = silc_packet_context_dup(packet);
1285
1286         /* Let the protocol handle the packet */
1287         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1288       } else {
1289         SilcClientKEInternalContext *proto_ctx =
1290           (SilcClientKEInternalContext *)sock->protocol->context;
1291
1292         if (proto_ctx->packet)
1293           silc_packet_context_free(proto_ctx->packet);
1294         if (proto_ctx->dest_id)
1295           silc_free(proto_ctx->dest_id);
1296         proto_ctx->packet = silc_packet_context_dup(packet);
1297         proto_ctx->dest_id_type = packet->src_id_type;
1298         proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1299                                             packet->src_id_type);
1300         if (!proto_ctx->dest_id)
1301           break;
1302
1303         /* Let the protocol handle the packet */
1304         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1305       }
1306     } else {
1307       SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
1308                       "protocol active, packet dropped."));
1309     }
1310     break;
1311
1312   case SILC_PACKET_NEW_ID:
1313     {
1314       /*
1315        * Received new ID from server. This packet is received at
1316        * the connection to the server.  New ID is also received when
1317        * user changes nickname but in that case the new ID is received
1318        * as command reply and not as this packet type.
1319        */
1320       SilcIDPayload idp;
1321
1322       idp = silc_id_payload_parse(buffer->data, buffer->len);
1323       if (!idp)
1324         break;
1325       if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
1326         break;
1327
1328       silc_client_receive_new_id(client, sock, idp);
1329       silc_id_payload_free(idp);
1330       break;
1331     }
1332
1333   case SILC_PACKET_HEARTBEAT:
1334     /*
1335      * Received heartbeat packet
1336      */
1337     SILC_LOG_DEBUG(("Heartbeat packet"));
1338     break;
1339
1340   case SILC_PACKET_KEY_AGREEMENT:
1341     /*
1342      * Received key agreement packet
1343      */
1344     SILC_LOG_DEBUG(("Key agreement packet"));
1345     silc_client_key_agreement(client, sock, packet);
1346     break;
1347
1348   case SILC_PACKET_REKEY:
1349     SILC_LOG_DEBUG(("Re-key packet"));
1350     /* We ignore this for now */
1351     break;
1352
1353   case SILC_PACKET_REKEY_DONE:
1354     SILC_LOG_DEBUG(("Re-key done packet"));
1355
1356     if (sock->protocol && sock->protocol->protocol &&
1357         sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1358
1359       SilcClientRekeyInternalContext *proto_ctx =
1360         (SilcClientRekeyInternalContext *)sock->protocol->context;
1361
1362       if (proto_ctx->packet)
1363         silc_packet_context_free(proto_ctx->packet);
1364
1365       proto_ctx->packet = silc_packet_context_dup(packet);
1366
1367       /* Let the protocol handle the packet */
1368       if (proto_ctx->responder == FALSE)
1369         silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1370       else
1371         /* Let the protocol handle the packet */
1372         silc_protocol_execute(sock->protocol, client->schedule,
1373                               0, 100000);
1374     } else {
1375       SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1376                       "protocol active, packet dropped."));
1377     }
1378     break;
1379
1380   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
1381     /*
1382      * Reveived reply to our connection authentication method request
1383      * packet. This is used to resolve the authentication method for the
1384      * current session from the server if the client does not know it.
1385      */
1386     silc_client_connection_auth_request(client, sock, packet);
1387     break;
1388
1389   case SILC_PACKET_FTP:
1390     /* Received file transfer packet. */
1391     silc_client_ftp(client, sock, packet);
1392     break;
1393
1394   default:
1395     SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1396     break;
1397   }
1398 }
1399
1400 /* Sends packet. This doesn't actually send the packet instead it assembles
1401    it and marks it to be sent. However, if force_send is TRUE the packet
1402    is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1403    will be derived from sock argument. Otherwise the valid arguments sent
1404    are used. */
1405
1406 void silc_client_packet_send(SilcClient client,
1407                              SilcSocketConnection sock,
1408                              SilcPacketType type,
1409                              void *dst_id,
1410                              SilcIdType dst_id_type,
1411                              SilcCipher cipher,
1412                              SilcHmac hmac,
1413                              unsigned char *data,
1414                              SilcUInt32 data_len,
1415                              bool force_send)
1416 {
1417   SilcPacketContext packetdata;
1418   const SilcBufferStruct packet;
1419   int block_len;
1420   SilcUInt32 sequence = 0;
1421   int src_id_allocated = FALSE;
1422
1423   if (!sock)
1424     return;
1425
1426   SILC_LOG_DEBUG(("Sending packet, type %d", type));
1427
1428   /* Get data used in the packet sending, keys and stuff */
1429   if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1430     if (!cipher && ((SilcClientConnection)sock->user_data)->internal->send_key)
1431       cipher = ((SilcClientConnection)sock->user_data)->internal->send_key;
1432
1433     if (!hmac && ((SilcClientConnection)sock->user_data)->internal->hmac_send)
1434       hmac = ((SilcClientConnection)sock->user_data)->internal->hmac_send;
1435
1436     if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1437       dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1438       dst_id_type = SILC_ID_SERVER;
1439     }
1440
1441     if (hmac)
1442       sequence = ((SilcClientConnection)sock->user_data)->internal->psn_send++;
1443
1444     /* Check for mandatory rekey */
1445     if (sequence == SILC_CLIENT_REKEY_THRESHOLD)
1446       silc_schedule_task_add(client->schedule, sock->sock,
1447                              silc_client_rekey_callback, sock, 0, 1,
1448                              SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1449   }
1450
1451   block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
1452
1453   /* Set the packet context pointers */
1454   packetdata.flags = 0;
1455   packetdata.type = type;
1456   if (sock->user_data &&
1457       ((SilcClientConnection)sock->user_data)->local_id_data) {
1458     packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1459     packetdata.src_id_len =
1460       silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1461                       SILC_ID_CLIENT);
1462   } else {
1463     packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1464     packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1465     src_id_allocated = TRUE;
1466   }
1467   packetdata.src_id_type = SILC_ID_CLIENT;
1468   if (dst_id) {
1469     packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1470     packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1471     packetdata.dst_id_type = dst_id_type;
1472   } else {
1473     packetdata.dst_id = NULL;
1474     packetdata.dst_id_len = 0;
1475     packetdata.dst_id_type = SILC_ID_NONE;
1476   }
1477   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1478                                             packetdata.src_id_len +
1479                                             packetdata.dst_id_len));
1480   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1481     packetdata.src_id_len + packetdata.dst_id_len;
1482   if (type == SILC_PACKET_CONNECTION_AUTH)
1483     SILC_PACKET_PADLEN_MAX(packetdata.truelen, block_len, packetdata.padlen);
1484   else
1485     SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen);
1486
1487   /* Create the outgoing packet */
1488   if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
1489                             data, data_len, (const SilcBuffer)&packet)) {
1490     SILC_LOG_ERROR(("Error assembling packet"));
1491     goto out;
1492   }
1493
1494   /* Encrypt the packet */
1495   if (cipher)
1496     silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet,
1497                         packet.len);
1498
1499   SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, packet.len),
1500                    packet.data, packet.len);
1501
1502   /* Now actually send the packet */
1503   silc_client_packet_send_real(client, sock, force_send);
1504
1505  out:
1506   if (src_id_allocated && packetdata.src_id)
1507     silc_free(packetdata.src_id);
1508   if (packetdata.dst_id)
1509     silc_free(packetdata.dst_id);
1510 }
1511
1512 /* Packet sending routine for application.  This is the only routine that
1513    is provided for application to send SILC packets. */
1514
1515 bool silc_client_send_packet(SilcClient client,
1516                              SilcClientConnection conn,
1517                              SilcPacketType type,
1518                              const unsigned char *data,
1519                              SilcUInt32 data_len)
1520 {
1521
1522   assert(client);
1523   if (!conn)
1524     return FALSE;
1525
1526   silc_client_packet_send(client, conn->sock, type, NULL, 0, NULL, NULL,
1527                           (unsigned char *)data, data_len, TRUE);
1528   return TRUE;
1529 }
1530
1531 void silc_client_packet_queue_purge(SilcClient client,
1532                                     SilcSocketConnection sock)
1533 {
1534   if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
1535       !(SILC_IS_DISCONNECTED(sock))) {
1536     int ret;
1537
1538     ret = silc_packet_send(sock, TRUE);
1539     if (ret == -2) {
1540       if (sock->outbuf && sock->outbuf->len > 0) {
1541         /* Couldn't send all data, put the queue back up, we'll send
1542            rest later. */
1543         SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
1544         SILC_SET_OUTBUF_PENDING(sock);
1545         return;
1546       }
1547     }
1548
1549     /* Purged all data */
1550     SILC_UNSET_OUTBUF_PENDING(sock);
1551     SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
1552     silc_buffer_clear(sock->outbuf);
1553   }
1554 }
1555
1556 /* Closes connection to remote end. Free's all allocated data except
1557    for some information such as nickname etc. that are valid at all time.
1558    If the `sock' is NULL then the conn->sock will be used.  If `sock' is
1559    provided it will be checked whether the sock and `conn->sock' are the
1560    same (they can be different, ie. a socket can use `conn' as its
1561    connection but `conn->sock' might be actually a different connection
1562    than the `sock'). */
1563
1564 void silc_client_close_connection_real(SilcClient client,
1565                                        SilcSocketConnection sock,
1566                                        SilcClientConnection conn)
1567 {
1568   int del = FALSE;
1569
1570   SILC_LOG_DEBUG(("Start"));
1571
1572   if (!sock && !conn)
1573     return;
1574
1575   if (!sock || (sock && conn->sock == sock))
1576     del = TRUE;
1577   if (!sock)
1578     sock = conn->sock;
1579
1580   if (!sock) {
1581     if (del && conn)
1582       silc_client_del_connection(client, conn);
1583     return;
1584   }
1585
1586   /* We won't listen for this connection anymore */
1587   silc_schedule_unset_listen_fd(client->schedule, sock->sock);
1588
1589   /* Unregister all tasks */
1590   silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1591
1592   /* Close the actual connection */
1593   silc_net_close_connection(sock->sock);
1594
1595   /* Cancel any active protocol */
1596   if (sock->protocol) {
1597     if (sock->protocol->protocol->type ==
1598         SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1599         sock->protocol->protocol->type ==
1600         SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1601       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1602       silc_protocol_execute_final(sock->protocol, client->schedule);
1603       /* The application will recall this function with these protocols
1604          (the ops->connected client operation). */
1605       return;
1606     } else {
1607       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1608       silc_protocol_execute_final(sock->protocol, client->schedule);
1609       sock->protocol = NULL;
1610     }
1611   }
1612
1613   /* Free everything */
1614   if (del && sock->user_data)
1615     silc_client_del_connection(client, conn);
1616
1617   silc_socket_free(sock);
1618 }
1619
1620 /* Closes the connection to the remote end */
1621
1622 void silc_client_close_connection(SilcClient client,
1623                                   SilcClientConnection conn)
1624 {
1625   silc_client_close_connection_real(client, NULL, conn);
1626 }
1627
1628 /* Called when we receive disconnection packet from server. This
1629    closes our end properly and displays the reason of the disconnection
1630    on the screen. */
1631
1632 SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
1633 {
1634   SilcClient client = (SilcClient)context;
1635   SilcSocketConnection sock;
1636
1637   SILC_CLIENT_GET_SOCK(client, fd, sock);
1638   if (sock == NULL)
1639     return;
1640
1641   silc_client_close_connection_real(client, sock, sock->user_data);
1642 }
1643
1644 /* Called when we receive disconnection packet from server. This
1645    closes our end properly and displays the reason of the disconnection
1646    on the screen. */
1647
1648 void silc_client_disconnected_by_server(SilcClient client,
1649                                         SilcSocketConnection sock,
1650                                         SilcBuffer packet)
1651 {
1652   SilcClientConnection conn;
1653   SilcStatus status;
1654   char *message = NULL;
1655
1656   SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1657
1658   if (packet->len < 1)
1659     return;
1660
1661   status = (SilcStatus)packet->data[0];
1662
1663   if (packet->len > 1 &&
1664       silc_utf8_valid(packet->data + 1, packet->len - 1))
1665     message = silc_memdup(packet->data + 1, packet->len - 1);
1666
1667   conn = (SilcClientConnection)sock->user_data;
1668   if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
1669     client->internal->ops->disconnected(client, conn, status, message);
1670
1671   silc_free(message);
1672
1673   SILC_SET_DISCONNECTED(sock);
1674
1675   /* Close connection through scheduler. */
1676   silc_schedule_task_add(client->schedule, sock->sock,
1677                          silc_client_disconnected_by_server_later,
1678                          client, 0, 1, SILC_TASK_TIMEOUT,
1679                          SILC_TASK_PRI_NORMAL);
1680 }
1681
1682 /* Received error message from server. Display it on the screen.
1683    We don't take any action what so ever of the error message. */
1684
1685 void silc_client_error_by_server(SilcClient client,
1686                                  SilcSocketConnection sock,
1687                                  SilcBuffer message)
1688 {
1689   char *msg;
1690
1691   msg = silc_memdup(message->data, message->len);
1692   client->internal->ops->say(client, sock->user_data,
1693                              SILC_CLIENT_MESSAGE_AUDIT, msg);
1694   silc_free(msg);
1695 }
1696
1697 /* Auto-nicking callback to send NICK command to server. */
1698
1699 SILC_TASK_CALLBACK(silc_client_send_auto_nick)
1700 {
1701   SilcClientConnection conn = (SilcClientConnection)context;
1702   SilcClient client = conn->client;
1703   if (client)
1704     silc_client_command_send(client, conn, SILC_COMMAND_NICK,
1705                              ++conn->cmd_ident, 1, 1,
1706                              client->nickname, strlen(client->nickname));
1707 }
1708
1709 /* Client session resuming callback.  If the session was resumed
1710    this callback is called after the resuming is completed.  This
1711    will call the `connect' client operation to the application
1712    since it has not been called yet. */
1713
1714 static void silc_client_resume_session_cb(SilcClient client,
1715                                           SilcClientConnection conn,
1716                                           bool success,
1717                                           void *context)
1718 {
1719   SilcBuffer sidp;
1720
1721   /* Notify application that connection is created to server */
1722   client->internal->ops->connected(client, conn, success ?
1723                                    SILC_CLIENT_CONN_SUCCESS_RESUME :
1724                                    SILC_CLIENT_CONN_ERROR_RESUME);
1725
1726   if (success) {
1727     /* Issue INFO command to fetch the real server name and server
1728        information and other stuff. */
1729     silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1730                                  silc_client_command_reply_info_i, 0,
1731                                  ++conn->cmd_ident);
1732     sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1733     silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1734                              conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1735     silc_buffer_free(sidp);
1736   }
1737 }
1738
1739 /* Processes the received new Client ID from server. Old Client ID is
1740    deleted from cache and new one is added. */
1741
1742 void silc_client_receive_new_id(SilcClient client,
1743                                 SilcSocketConnection sock,
1744                                 SilcIDPayload idp)
1745 {
1746   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1747   int connecting = FALSE;
1748   SilcClientID *client_id = silc_id_payload_get_id(idp);
1749   char *nickname;
1750
1751   if (!conn->local_entry)
1752     connecting = TRUE;
1753
1754   /* Delete old ID from ID cache */
1755   if (conn->local_id) {
1756     /* Check whether they are different */
1757     if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1758       silc_free(client_id);
1759       return;
1760     }
1761
1762     silc_idcache_del_by_context(conn->internal->client_cache,
1763                                 conn->local_entry);
1764     silc_free(conn->local_id);
1765   }
1766
1767   /* Save the new ID */
1768
1769   if (conn->local_id_data)
1770     silc_free(conn->local_id_data);
1771
1772   conn->local_id = client_id;
1773   conn->local_id_data = silc_id_payload_get_data(idp);
1774   conn->local_id_data_len = silc_id_payload_get_len(idp);;
1775
1776   if (!conn->local_entry)
1777     conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1778
1779   conn->local_entry->nickname = conn->nickname;
1780   if (!conn->local_entry->username)
1781     conn->local_entry->username = strdup(client->username);
1782   if (!conn->local_entry->server)
1783     conn->local_entry->server = strdup(conn->remote_host);
1784   conn->local_entry->id = conn->local_id;
1785   conn->local_entry->valid = TRUE;
1786   if (!conn->local_entry->channels)
1787     conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
1788                                                         NULL, NULL,
1789                                                         NULL, NULL, NULL,
1790                                                         TRUE);
1791
1792   /* Normalize nickname */
1793   nickname = silc_identifier_check(conn->nickname, strlen(conn->nickname),
1794                                    SILC_STRING_UTF8, 128, NULL);
1795   if (!nickname)
1796     return;
1797
1798     /* Put it to the ID cache */
1799   silc_idcache_add(conn->internal->client_cache, nickname, conn->local_id,
1800                    (void *)conn->local_entry, 0, NULL);
1801
1802   if (connecting) {
1803     SilcBuffer sidp;
1804
1805     /* Issue IDENTIFY command for itself to get resolved hostname
1806        correctly from server. */
1807     silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
1808                                  silc_client_command_reply_identify_i, 0,
1809                                  ++conn->cmd_ident);
1810     sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
1811     silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1812                              conn->cmd_ident, 1, 5, sidp->data, sidp->len);
1813     silc_buffer_free(sidp);
1814
1815     if (!conn->internal->params.detach_data) {
1816       /* Send NICK command if the nickname was set by the application (and is
1817          not same as the username). Send this with little timeout. */
1818       if (client->nickname &&
1819           !silc_utf8_strcasecmp(client->nickname, client->username))
1820         silc_schedule_task_add(client->schedule, 0,
1821                                silc_client_send_auto_nick, conn,
1822                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1823
1824       /* Notify application of successful connection. We do it here now that
1825          we've received the Client ID and are allowed to send traffic. */
1826       client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_SUCCESS);
1827
1828       /* Issue INFO command to fetch the real server name and server
1829          information and other stuff. */
1830       silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1831                                    silc_client_command_reply_info_i, 0,
1832                                    ++conn->cmd_ident);
1833       sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1834       silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1835                                conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1836       silc_buffer_free(sidp);
1837     } else {
1838       /* We are resuming session.  Start resolving informations from the
1839          server we need to set the client libary in the state before
1840          detaching the session.  The connect client operation is called
1841          after this is successfully completed */
1842       silc_client_resume_session(client, conn, silc_client_resume_session_cb,
1843                                  NULL);
1844     }
1845   }
1846 }
1847
1848 /* Removes a client entry from all channels it has joined. */
1849
1850 void silc_client_remove_from_channels(SilcClient client,
1851                                       SilcClientConnection conn,
1852                                       SilcClientEntry client_entry)
1853 {
1854   SilcHashTableList htl;
1855   SilcChannelUser chu;
1856
1857   silc_hash_table_list(client_entry->channels, &htl);
1858   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1859     silc_hash_table_del(chu->client->channels, chu->channel);
1860     silc_hash_table_del(chu->channel->user_list, chu->client);
1861     silc_free(chu);
1862   }
1863
1864   silc_hash_table_list_reset(&htl);
1865 }
1866
1867 /* Replaces `old' client entries from all channels to `new' client entry.
1868    This can be called for example when nickname changes and old ID entry
1869    is replaced from ID cache with the new one. If the old ID entry is only
1870    updated, then this fucntion needs not to be called. */
1871
1872 void silc_client_replace_from_channels(SilcClient client,
1873                                        SilcClientConnection conn,
1874                                        SilcClientEntry old,
1875                                        SilcClientEntry new)
1876 {
1877   SilcHashTableList htl;
1878   SilcChannelUser chu;
1879
1880   silc_hash_table_list(old->channels, &htl);
1881   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1882     /* Replace client entry */
1883     silc_hash_table_del(chu->client->channels, chu->channel);
1884     silc_hash_table_del(chu->channel->user_list, chu->client);
1885
1886     chu->client = new;
1887     silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1888     silc_hash_table_add(chu->client->channels, chu->channel, chu);
1889   }
1890   silc_hash_table_list_reset(&htl);
1891 }
1892
1893 /* Registers failure timeout to process the received failure packet
1894    with timeout. */
1895
1896 void silc_client_process_failure(SilcClient client,
1897                                  SilcSocketConnection sock,
1898                                  SilcPacketContext *packet)
1899 {
1900   SilcUInt32 failure = 0;
1901
1902   if (sock->protocol) {
1903     if (packet->buffer->len >= 4)
1904       SILC_GET32_MSB(failure, packet->buffer->data);
1905
1906     /* Notify application */
1907     client->internal->ops->failure(client, sock->user_data, sock->protocol,
1908                                    SILC_32_TO_PTR(failure));
1909   }
1910 }
1911
1912 /* A timeout callback for the re-key. We will be the initiator of the
1913    re-key protocol. */
1914
1915 SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback)
1916 {
1917   SilcSocketConnection sock = (SilcSocketConnection)context;
1918   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1919   SilcClient client = (SilcClient)conn->internal->rekey->context;
1920   SilcProtocol protocol;
1921   SilcClientRekeyInternalContext *proto_ctx;
1922
1923   SILC_LOG_DEBUG(("Start"));
1924
1925   /* If rekey protocol is active already wait for it to finish */
1926   if (sock->protocol && sock->protocol->protocol &&
1927       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
1928     return;
1929
1930   /* Allocate internal protocol context. This is sent as context
1931      to the protocol. */
1932   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1933   proto_ctx->client = (void *)client;
1934   proto_ctx->sock = silc_socket_dup(sock);
1935   proto_ctx->responder = FALSE;
1936   proto_ctx->pfs = conn->internal->rekey->pfs;
1937
1938   /* Perform rekey protocol. Will call the final callback after the
1939      protocol is over. */
1940   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1941                       &protocol, proto_ctx, silc_client_rekey_final);
1942   sock->protocol = protocol;
1943
1944   /* Run the protocol */
1945   silc_protocol_execute(protocol, client->schedule, 0, 0);
1946 }
1947
1948 /* The final callback for the REKEY protocol. This will actually take the
1949    new key material into use. */
1950
1951 SILC_TASK_CALLBACK(silc_client_rekey_final)
1952 {
1953   SilcProtocol protocol = (SilcProtocol)context;
1954   SilcClientRekeyInternalContext *ctx =
1955     (SilcClientRekeyInternalContext *)protocol->context;
1956   SilcClient client = (SilcClient)ctx->client;
1957   SilcSocketConnection sock = ctx->sock;
1958   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1959
1960   SILC_LOG_DEBUG(("Start"));
1961
1962   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1963       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1964     /* Error occured during protocol */
1965     silc_protocol_cancel(protocol, client->schedule);
1966     silc_protocol_free(protocol);
1967     sock->protocol = NULL;
1968     if (ctx->packet)
1969       silc_packet_context_free(ctx->packet);
1970     if (ctx->ske)
1971       silc_ske_free(ctx->ske);
1972     silc_socket_free(ctx->sock);
1973     silc_free(ctx);
1974     return;
1975   }
1976
1977   /* Purge the outgoing data queue to assure that all rekey packets really
1978      go to the network before we quit the protocol. */
1979   silc_client_packet_queue_purge(client, sock);
1980
1981   /* Re-register re-key timeout */
1982   if (ctx->responder == FALSE)
1983     silc_schedule_task_add(client->schedule, sock->sock,
1984                            silc_client_rekey_callback,
1985                            sock, conn->internal->rekey->timeout, 0,
1986                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1987
1988   /* Cleanup */
1989   silc_protocol_free(protocol);
1990   sock->protocol = NULL;
1991   if (ctx->packet)
1992     silc_packet_context_free(ctx->packet);
1993   if (ctx->ske)
1994     silc_ske_free(ctx->ske);
1995   silc_socket_free(ctx->sock);
1996   silc_free(ctx);
1997 }
1998
1999 /* Processes incoming connection authentication method request packet.
2000    It is a reply to our previously sent request. The packet can be used
2001    to resolve the authentication method for the current session if the
2002    client does not know it beforehand. */
2003
2004 void silc_client_connection_auth_request(SilcClient client,
2005                                          SilcSocketConnection sock,
2006                                          SilcPacketContext *packet)
2007 {
2008   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
2009   SilcUInt16 conn_type, auth_meth;
2010   int ret;
2011
2012   /* If we haven't send our request then ignore this one. */
2013   if (!conn->internal->connauth)
2014     return;
2015
2016   /* Parse the payload */
2017   ret = silc_buffer_unformat(packet->buffer,
2018                              SILC_STR_UI_SHORT(&conn_type),
2019                              SILC_STR_UI_SHORT(&auth_meth),
2020                              SILC_STR_END);
2021   if (ret == -1)
2022     auth_meth = SILC_AUTH_NONE;
2023
2024   /* Call the request callback to notify application for received
2025      authentication method information. */
2026   if (conn->internal->connauth->callback)
2027     (*conn->internal->connauth->callback)(client, conn, auth_meth,
2028                                           conn->internal->connauth->context);
2029
2030   silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
2031
2032   silc_free(conn->internal->connauth);
2033   conn->internal->connauth = NULL;
2034 }
2035
2036 /* Timeout task callback called if the server does not reply to our
2037    connection authentication method request in the specified time interval. */
2038
2039 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
2040 {
2041   SilcClientConnection conn = (SilcClientConnection)context;
2042   SilcClient client = conn->client;
2043
2044   if (!conn->internal->connauth)
2045     return;
2046
2047   /* Call the request callback to notify application */
2048   if (conn->internal->connauth->callback)
2049     (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
2050                                           conn->internal->connauth->context);
2051
2052   silc_free(conn->internal->connauth);
2053   conn->internal->connauth = NULL;
2054 }
2055
2056 /* This function can be used to request the current authentication method
2057    from the server. This may be called when connecting to the server
2058    and the client library requests the authentication data from the
2059    application. If the application does not know the current authentication
2060    method it can request it from the server using this function.
2061    The `callback' with `context' will be called after the server has
2062    replied back with the current authentication method. */
2063
2064 void
2065 silc_client_request_authentication_method(SilcClient client,
2066                                           SilcClientConnection conn,
2067                                           SilcConnectionAuthRequest callback,
2068                                           void *context)
2069 {
2070   SilcClientConnAuthRequest connauth;
2071   SilcBuffer packet;
2072
2073   assert(client && conn);
2074   connauth = silc_calloc(1, sizeof(*connauth));
2075   connauth->callback = callback;
2076   connauth->context = context;
2077
2078   if (conn->internal->connauth)
2079     silc_free(conn->internal->connauth);
2080
2081   conn->internal->connauth = connauth;
2082
2083   /* Assemble the request packet and send it to the server */
2084   packet = silc_buffer_alloc(4);
2085   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
2086   silc_buffer_format(packet,
2087                      SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
2088                      SILC_STR_UI_SHORT(SILC_AUTH_NONE),
2089                      SILC_STR_END);
2090   silc_client_packet_send(client, conn->sock,
2091                           SILC_PACKET_CONNECTION_AUTH_REQUEST,
2092                           NULL, 0, NULL, NULL,
2093                           packet->data, packet->len, FALSE);
2094   silc_buffer_free(packet);
2095
2096   /* Register a timeout in case server does not reply anything back. */
2097   connauth->timeout =
2098     silc_schedule_task_add(client->schedule, conn->sock->sock,
2099                            silc_client_request_authentication_method_timeout,
2100                            conn,
2101                            client->internal->params->connauth_request_secs, 0,
2102                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
2103 }