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