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