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