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