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