5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
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.
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.
21 #include "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
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);
32 static bool silc_client_packet_parse(SilcPacketParserContext *parser_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);
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. */
47 SilcClient silc_client_alloc(SilcClientOperations *ops,
48 SilcClientParams *params,
50 const char *version_string)
52 SilcClient new_client;
54 new_client = silc_calloc(1, sizeof(*new_client));
55 new_client->application = application;
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));
62 version_string = silc_version_string;
63 new_client->internal->silc_client_version = strdup(version_string);
66 memcpy(new_client->internal->params, params, sizeof(*params));
68 if (!new_client->internal->params->task_max)
69 new_client->internal->params->task_max = 200;
71 if (!new_client->internal->params->rekey_secs)
72 new_client->internal->params->rekey_secs = 3600;
74 if (!new_client->internal->params->connauth_request_secs)
75 new_client->internal->params->connauth_request_secs = 2;
77 new_client->internal->params->
78 nickname_format[sizeof(new_client->internal->
79 params->nickname_format) - 1] = 0;
84 /* Frees client object and its internals. */
86 void silc_client_free(SilcClient client)
90 silc_rng_free(client->rng);
92 silc_free(client->internal->params);
93 silc_free(client->internal->silc_client_version);
94 silc_free(client->internal);
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. */
103 int silc_client_init(SilcClient client)
105 SILC_LOG_DEBUG(("Initializing client"));
107 assert(client->username);
108 assert(client->hostname);
109 assert(client->realname);
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();
119 /* Initialize hash functions for client to use */
120 silc_hash_alloc("md5", &client->md5hash);
121 silc_hash_alloc("sha1", &client->sha1hash);
123 /* Initialize none cipher */
124 silc_cipher_alloc("none", &client->internal->none_cipher);
126 /* Initialize random number generator */
127 client->rng = silc_rng_alloc();
128 silc_rng_init(client->rng);
129 silc_rng_global_init(client->rng);
131 /* Register protocols */
132 silc_client_protocols_register();
134 /* Initialize the scheduler */
136 silc_schedule_init(client->internal->params->task_max ?
137 client->internal->params->task_max : 200, client);
138 if (!client->schedule)
141 /* Register commands */
142 silc_client_commands_register(client);
147 /* Stops the client. This is called to stop the client and thus to stop
150 void silc_client_stop(SilcClient client)
152 SILC_LOG_DEBUG(("Stopping client"));
154 silc_schedule_stop(client->schedule);
155 silc_schedule_uninit(client->schedule);
157 silc_client_protocols_unregister();
158 silc_client_commands_unregister(client);
160 SILC_LOG_DEBUG(("Client stopped"));
163 /* Runs the client. This starts the scheduler from the utility library.
164 When this functions returns the execution of the appliation is over. */
166 void silc_client_run(SilcClient client)
168 SILC_LOG_DEBUG(("Running client"));
170 assert(client->pkcs);
171 assert(client->public_key);
172 assert(client->private_key);
174 /* Start the scheduler, the heart of the SILC client. When this returns
175 the program will be terminated. */
176 silc_schedule(client->schedule);
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. */
187 void silc_client_run_one(SilcClient client)
189 /* Run the scheduler once. */
190 silc_schedule_one(client->schedule, 0);
193 static void silc_client_entry_destructor(SilcIDCache cache,
194 SilcIDCacheEntry entry)
196 silc_free(entry->name);
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. */
208 silc_client_add_connection(SilcClient client,
209 SilcClientConnectionParams *params,
210 char *hostname, int port, void *context)
212 SilcClientConnection conn;
215 SILC_LOG_DEBUG(("Adding new connection to %s:%d", hostname, port));
217 conn = silc_calloc(1, sizeof(*conn));
218 conn->internal = silc_calloc(1, sizeof(*conn->internal));
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();
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;
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;
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++;
256 /* Removes connection from client. Frees all memory. */
258 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
262 for (i = 0; i < client->internal->conns_count; i++)
263 if (client->internal->conns[i] == conn) {
264 /* Free all cache entries */
265 SilcIDCacheList list;
266 SilcIDCacheEntry entry;
267 SilcClientCommandPending *r;
270 if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
271 ret = silc_idcache_list_first(list, &entry);
273 silc_client_del_client(client, conn, entry->context);
274 ret = silc_idcache_list_next(list, &entry);
276 silc_idcache_list_free(list);
279 if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
280 ret = silc_idcache_list_first(list, &entry);
282 silc_client_del_channel(client, conn, entry->context);
283 ret = silc_idcache_list_next(list, &entry);
285 silc_idcache_list_free(list);
288 if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
289 ret = silc_idcache_list_first(list, &entry);
291 silc_client_del_server(client, conn, entry->context);
292 ret = silc_idcache_list_next(list, &entry);
294 silc_idcache_list_free(list);
297 /* Clear ID caches */
298 if (conn->internal->client_cache)
299 silc_idcache_free(conn->internal->client_cache);
300 if (conn->internal->channel_cache)
301 silc_idcache_free(conn->internal->channel_cache);
302 if (conn->internal->server_cache)
303 silc_idcache_free(conn->internal->server_cache);
305 /* Free data (my ID is freed in above silc_client_del_client).
306 conn->nickname is freed when freeing the local_entry->nickname. */
307 silc_free(conn->remote_host);
308 silc_free(conn->local_id_data);
309 if (conn->internal->send_key)
310 silc_cipher_free(conn->internal->send_key);
311 if (conn->internal->receive_key)
312 silc_cipher_free(conn->internal->receive_key);
313 if (conn->internal->hmac_send)
314 silc_hmac_free(conn->internal->hmac_send);
315 if (conn->internal->hmac_receive)
316 silc_hmac_free(conn->internal->hmac_receive);
317 silc_free(conn->internal->rekey);
319 if (conn->internal->active_session) {
320 conn->sock->user_data = NULL;
321 silc_client_ftp_session_free(conn->internal->active_session);
322 conn->internal->active_session = NULL;
325 silc_client_ftp_free_sessions(client, conn);
327 if (conn->internal->pending_commands) {
328 silc_dlist_start(conn->internal->pending_commands);
329 while ((r = silc_dlist_get(conn->internal->pending_commands))
331 silc_dlist_del(conn->internal->pending_commands, r);
332 silc_dlist_uninit(conn->internal->pending_commands);
335 silc_free(conn->internal);
336 memset(conn, 0, sizeof(*conn));
339 client->internal->conns[i] = NULL;
343 /* Adds listener socket to the listener sockets table. This function is
344 used to add socket objects that are listeners to the client. This should
345 not be used to add other connection objects. */
347 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
351 if (!client->internal->sockets) {
352 client->internal->sockets =
353 silc_calloc(1, sizeof(*client->internal->sockets));
354 client->internal->sockets[0] = silc_socket_dup(sock);
355 client->internal->sockets_count = 1;
359 for (i = 0; i < client->internal->sockets_count; i++) {
360 if (client->internal->sockets[i] == NULL) {
361 client->internal->sockets[i] = silc_socket_dup(sock);
366 client->internal->sockets =
367 silc_realloc(client->internal->sockets,
368 sizeof(*client->internal->sockets) *
369 (client->internal->sockets_count + 1));
370 client->internal->sockets[client->internal->sockets_count] =
371 silc_socket_dup(sock);
372 client->internal->sockets_count++;
375 /* Deletes listener socket from the listener sockets table. */
377 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
381 if (!client->internal->sockets)
384 for (i = 0; i < client->internal->sockets_count; i++) {
385 if (client->internal->sockets[i] == sock) {
386 silc_socket_free(sock);
387 client->internal->sockets[i] = NULL;
394 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
398 /* XXX In the future we should give up this non-blocking connect all
399 together and use threads instead. */
400 /* Create connection to server asynchronously */
401 sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
405 /* Register task that will receive the async connect and will
407 ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
408 silc_client_connect_to_server_start,
411 SILC_TASK_PRI_NORMAL);
412 silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
420 /* Connects to remote server. This is the main routine used to connect
421 to SILC server. Returns -1 on error and the created socket otherwise.
422 The `context' is user context that is saved into the SilcClientConnection
423 that is created after the connection is created. Note that application
424 may handle the connecting process outside the library. If this is the
425 case then this function is not used at all. When the connecting is
426 done the `connect' client operation is called. */
428 int silc_client_connect_to_server(SilcClient client,
429 SilcClientConnectionParams *params,
430 int port, char *host, void *context)
432 SilcClientInternalConnectContext *ctx;
433 SilcClientConnection conn;
436 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
439 conn = silc_client_add_connection(client, params, host, port, context);
441 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
442 "Connecting to port %d of server %s", port, host);
444 /* Allocate internal context for connection process. This is
445 needed as we are doing async connecting. */
446 ctx = silc_calloc(1, sizeof(*ctx));
447 ctx->client = client;
449 ctx->host = strdup(host);
450 ctx->port = port ? port : 706;
453 /* Do the actual connecting process */
454 sock = silc_client_connect_to_server_internal(ctx);
456 silc_client_del_connection(client, conn);
460 /* Socket hostname and IP lookup callback that is called before actually
461 starting the key exchange. The lookup is called from the function
462 silc_client_start_key_exchange. */
464 static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
467 SilcClientConnection conn = (SilcClientConnection)context;
468 SilcClient client = conn->client;
469 SilcProtocol protocol;
470 SilcClientKEInternalContext *proto_ctx;
472 SILC_LOG_DEBUG(("Start"));
474 if (conn->sock->hostname) {
475 silc_free(conn->remote_host);
476 conn->remote_host = strdup(conn->sock->hostname);
478 conn->sock->hostname = strdup(conn->remote_host);
481 conn->sock->ip = strdup(conn->sock->hostname);
482 conn->sock->port = conn->remote_port;
484 /* Allocate internal Key Exchange context. This is sent to the
485 protocol as context. */
486 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
487 proto_ctx->client = (void *)client;
488 proto_ctx->sock = silc_socket_dup(conn->sock);
489 proto_ctx->rng = client->rng;
490 proto_ctx->responder = FALSE;
491 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
492 proto_ctx->verify = silc_client_protocol_ke_verify_key;
494 /* Perform key exchange protocol. silc_client_connect_to_server_final
495 will be called after the protocol is finished. */
496 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
497 &protocol, (void *)proto_ctx,
498 silc_client_connect_to_server_second);
500 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
501 "Error: Could not start key exchange protocol");
502 silc_net_close_connection(conn->sock->sock);
503 client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
506 conn->sock->protocol = protocol;
508 /* Register the connection for network input and output. This sets
509 that scheduler will listen for incoming packets for this connection
510 and sets that outgoing packets may be sent to this connection as well.
511 However, this doesn't set the scheduler for outgoing traffic, it will
512 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
513 later when outgoing data is available. */
514 context = (void *)client;
515 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
517 /* Execute the protocol */
518 silc_protocol_execute(protocol, client->schedule, 0, 0);
521 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
522 key material between client and server. This function can be called
523 directly if application is performing its own connecting and does not
524 use the connecting provided by this library. This function is normally
525 used only if the application performed the connecting outside the library.
526 The library however may use this internally. */
528 void silc_client_start_key_exchange(SilcClient client,
529 SilcClientConnection conn,
532 assert(client->pkcs);
533 assert(client->public_key);
534 assert(client->private_key);
536 /* Allocate new socket connection object */
537 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
539 /* Sometimes when doing quick reconnects the new socket may be same as
540 the old one and there might be pending stuff for the old socket.
541 If new one is same then those pending sutff might cause problems.
542 Make sure they do not do that. */
543 silc_schedule_task_del_by_fd(client->schedule, fd);
545 conn->nickname = (client->nickname ? strdup(client->nickname) :
546 strdup(client->username));
548 /* Resolve the remote hostname and IP address for our socket connection */
549 silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
550 conn, client->schedule);
553 /* Callback called when error has occurred during connecting (KE) to
554 the server. The `connect' client operation will be called. */
556 SILC_TASK_CALLBACK(silc_client_connect_failure)
558 SilcClientKEInternalContext *ctx =
559 (SilcClientKEInternalContext *)context;
560 SilcClient client = (SilcClient)ctx->client;
562 client->internal->ops->connected(client, ctx->sock->user_data,
563 SILC_CLIENT_CONN_ERROR);
565 silc_packet_context_free(ctx->packet);
569 /* Callback called when error has occurred during connecting (auth) to
570 the server. The `connect' client operation will be called. */
572 SILC_TASK_CALLBACK(silc_client_connect_failure_auth)
574 SilcClientConnAuthInternalContext *ctx =
575 (SilcClientConnAuthInternalContext *)context;
576 SilcClient client = (SilcClient)ctx->client;
578 client->internal->ops->connected(client, ctx->sock->user_data,
579 SILC_CLIENT_CONN_ERROR);
583 /* Start of the connection to the remote server. This is called after
584 succesful TCP/IP connection has been established to the remote host. */
586 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
588 SilcClientInternalConnectContext *ctx =
589 (SilcClientInternalConnectContext *)context;
590 SilcClient client = ctx->client;
591 SilcClientConnection conn = ctx->conn;
592 int opt, opt_len = sizeof(opt);
594 SILC_LOG_DEBUG(("Start"));
596 /* Check the socket status as it might be in error */
597 silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
599 if (ctx->tries < 2) {
600 /* Connection failed but lets try again */
601 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
602 "Could not connect to server %s: %s",
603 ctx->host, strerror(opt));
604 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
605 "Connecting to port %d of server %s resumed",
606 ctx->port, ctx->host);
608 /* Unregister old connection try */
609 silc_schedule_unset_listen_fd(client->schedule, fd);
610 silc_net_close_connection(fd);
611 silc_schedule_task_del(client->schedule, ctx->task);
614 silc_client_connect_to_server_internal(ctx);
617 /* Connection failed and we won't try anymore */
618 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
619 "Could not connect to server %s: %s",
620 ctx->host, strerror(opt));
621 silc_schedule_unset_listen_fd(client->schedule, fd);
622 silc_net_close_connection(fd);
623 silc_schedule_task_del(client->schedule, ctx->task);
626 /* Notify application of failure */
627 client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
628 silc_client_del_connection(client, conn);
633 silc_schedule_unset_listen_fd(client->schedule, fd);
634 silc_schedule_task_del(client->schedule, ctx->task);
637 silc_client_start_key_exchange(client, conn, fd);
640 /* Second part of the connecting to the server. This executed
641 authentication protocol. */
643 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
645 SilcProtocol protocol = (SilcProtocol)context;
646 SilcClientKEInternalContext *ctx =
647 (SilcClientKEInternalContext *)protocol->context;
648 SilcClient client = (SilcClient)ctx->client;
649 SilcSocketConnection sock = NULL;
650 SilcClientConnAuthInternalContext *proto_ctx;
652 SILC_LOG_DEBUG(("Start"));
654 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
655 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
656 /* Error occured during protocol */
657 SILC_LOG_DEBUG(("Error during KE protocol"));
658 silc_protocol_free(protocol);
659 silc_ske_free_key_material(ctx->keymat);
661 silc_ske_free(ctx->ske);
663 silc_free(ctx->dest_id);
664 ctx->sock->protocol = NULL;
665 silc_socket_free(ctx->sock);
667 /* Notify application of failure */
668 silc_schedule_task_add(client->schedule, ctx->sock->sock,
669 silc_client_connect_failure, ctx,
670 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
674 /* We now have the key material as the result of the key exchange
675 protocol. Take the key material into use. Free the raw key material
676 as soon as we've set them into use. */
677 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
678 ctx->ske->prop->cipher,
679 ctx->ske->prop->pkcs,
680 ctx->ske->prop->hash,
681 ctx->ske->prop->hmac,
682 ctx->ske->prop->group,
684 silc_ske_free_key_material(ctx->keymat);
686 /* Allocate internal context for the authentication protocol. This
687 is sent as context for the protocol. */
688 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
689 proto_ctx->client = (void *)client;
690 proto_ctx->sock = sock = ctx->sock;
691 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
692 proto_ctx->dest_id_type = ctx->dest_id_type;
693 proto_ctx->dest_id = ctx->dest_id;
695 /* Free old protocol as it is finished now */
696 silc_protocol_free(protocol);
698 silc_packet_context_free(ctx->packet);
701 sock->protocol = NULL;
703 /* Resolve the authentication method to be used in this connection. The
704 completion callback is called after the application has resolved
705 the authentication method. */
706 client->internal->ops->get_auth_method(client, sock->user_data,
709 silc_client_resolve_auth_method,
713 /* Authentication method resolving callback. Application calls this function
714 after we've called the client->internal->ops->get_auth_method
715 client operation to resolve the authentication method. We will continue
716 the executiong of the protocol in this function. */
718 void silc_client_resolve_auth_method(bool success,
719 SilcProtocolAuthMeth auth_meth,
720 const unsigned char *auth_data,
721 SilcUInt32 auth_data_len, void *context)
723 SilcClientConnAuthInternalContext *proto_ctx =
724 (SilcClientConnAuthInternalContext *)context;
725 SilcClient client = (SilcClient)proto_ctx->client;
728 auth_meth = SILC_AUTH_NONE;
730 proto_ctx->auth_meth = auth_meth;
732 if (success && auth_data && auth_data_len) {
734 /* Passphrase must be UTF-8 encoded, if it isn't encode it */
735 if (auth_meth == SILC_AUTH_PASSWORD &&
736 !silc_utf8_valid(auth_data, auth_data_len)) {
738 unsigned char *autf8 = NULL;
739 payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
741 autf8 = silc_calloc(payload_len, sizeof(*autf8));
742 auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
743 SILC_STRING_ASCII, autf8, payload_len);
747 proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
748 proto_ctx->auth_data_len = auth_data_len;
751 /* Allocate the authenteication protocol and execute it. */
752 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
753 &proto_ctx->sock->protocol, (void *)proto_ctx,
754 silc_client_connect_to_server_final);
756 /* Execute the protocol */
757 silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
760 /* Finalizes the connection to the remote SILC server. This is called
761 after authentication protocol has been completed. This send our
762 user information to the server to receive our client ID from
765 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
767 SilcProtocol protocol = (SilcProtocol)context;
768 SilcClientConnAuthInternalContext *ctx =
769 (SilcClientConnAuthInternalContext *)protocol->context;
770 SilcClient client = (SilcClient)ctx->client;
771 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
774 SILC_LOG_DEBUG(("Start"));
776 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
777 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
778 /* Error occured during protocol */
779 SILC_LOG_DEBUG(("Error during authentication protocol"));
783 if (conn->internal->params.detach_data) {
784 /* Send RESUME_CLIENT packet to the server, which is used to resume
785 old detached session back. */
787 SilcClientID *old_client_id;
788 unsigned char *old_id;
789 SilcUInt16 old_id_len;
791 if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len))
794 old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
795 if (!old_client_id) {
800 /* Generate authentication data that server will verify */
801 auth = silc_auth_public_key_auth_generate(client->public_key,
804 conn->internal->hash,
805 old_client_id, SILC_ID_CLIENT);
807 silc_free(old_client_id);
812 packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
813 silc_buffer_format(packet,
814 SILC_STR_UI_SHORT(old_id_len),
815 SILC_STR_UI_XNSTRING(old_id, old_id_len),
816 SILC_STR_UI_XNSTRING(auth->data, auth->len),
819 /* Send the packet */
820 silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
822 packet->data, packet->len, TRUE);
823 silc_buffer_free(packet);
824 silc_buffer_free(auth);
825 silc_free(old_client_id);
828 /* Send NEW_CLIENT packet to the server. We will become registered
829 to the SILC network after sending this packet and we will receive
830 client ID from the server. */
831 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
832 strlen(client->realname));
833 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
834 silc_buffer_format(packet,
835 SILC_STR_UI_SHORT(strlen(client->username)),
836 SILC_STR_UI_XNSTRING(client->username,
837 strlen(client->username)),
838 SILC_STR_UI_SHORT(strlen(client->realname)),
839 SILC_STR_UI_XNSTRING(client->realname,
840 strlen(client->realname)),
843 /* Send the packet */
844 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
846 packet->data, packet->len, TRUE);
847 silc_buffer_free(packet);
850 /* Save remote ID. */
851 conn->remote_id = ctx->dest_id;
852 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
853 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
855 /* Register re-key timeout */
856 conn->internal->rekey->timeout = client->internal->params->rekey_secs;
857 conn->internal->rekey->context = (void *)client;
858 silc_schedule_task_add(client->schedule, conn->sock->sock,
859 silc_client_rekey_callback,
860 (void *)conn->sock, conn->internal->rekey->timeout, 0,
861 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
863 silc_protocol_free(protocol);
864 silc_free(ctx->auth_data);
866 silc_ske_free(ctx->ske);
867 silc_socket_free(ctx->sock);
869 conn->sock->protocol = NULL;
873 silc_protocol_free(protocol);
874 silc_free(ctx->auth_data);
875 silc_free(ctx->dest_id);
877 silc_ske_free(ctx->ske);
878 conn->sock->protocol = NULL;
879 silc_socket_free(ctx->sock);
881 /* Notify application of failure */
882 silc_schedule_task_add(client->schedule, ctx->sock->sock,
883 silc_client_connect_failure_auth, ctx,
884 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
887 /* Internal routine that sends packet or marks packet to be sent. This
888 is used directly only in special cases. Normal cases should use
889 silc_server_packet_send. Returns < 0 on error. */
891 int silc_client_packet_send_real(SilcClient client,
892 SilcSocketConnection sock,
897 /* If rekey protocol is active we must assure that all packets are
898 sent through packet queue. */
899 if (SILC_CLIENT_IS_REKEY(sock))
902 /* If outbound data is already pending do not force send */
903 if (SILC_IS_OUTBUF_PENDING(sock))
906 /* Send the packet */
907 ret = silc_packet_send(sock, force_send);
911 /* Mark that there is some outgoing data available for this connection.
912 This call sets the connection both for input and output (the input
913 is set always and this call keeps the input setting, actually).
914 Actual data sending is performed by silc_client_packet_process. */
915 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
917 /* Mark to socket that data is pending in outgoing buffer. This flag
918 is needed if new data is added to the buffer before the earlier
919 put data is sent to the network. */
920 SILC_SET_OUTBUF_PENDING(sock);
925 /* Packet processing callback. This is used to send and receive packets
926 from network. This is generic task. */
928 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
930 SilcClient client = (SilcClient)context;
931 SilcSocketConnection sock = NULL;
932 SilcClientConnection conn;
935 SILC_LOG_DEBUG(("Processing packet"));
937 SILC_CLIENT_GET_SOCK(client, fd, sock);
941 conn = (SilcClientConnection)sock->user_data;
944 if (type == SILC_TASK_WRITE) {
945 /* Do not send data to disconnected connection */
946 if (SILC_IS_DISCONNECTED(sock))
949 ret = silc_packet_send(sock, TRUE);
951 /* If returned -2 could not write to connection now, will do
960 /* The packet has been sent and now it is time to set the connection
961 back to only for input. When there is again some outgoing data
962 available for this connection it will be set for output as well.
963 This call clears the output setting and sets it only for input. */
964 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
965 SILC_UNSET_OUTBUF_PENDING(sock);
967 silc_buffer_clear(sock->outbuf);
971 /* Packet receiving */
972 if (type == SILC_TASK_READ) {
973 /* Read data from network */
974 ret = silc_packet_receive(sock);
980 SILC_LOG_DEBUG(("Read EOF"));
982 /* If connection is disconnecting already we will finally
983 close the connection */
984 if (SILC_IS_DISCONNECTING(sock)) {
985 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
986 client->internal->ops->disconnected(client, conn, 0, NULL);
987 silc_client_close_connection_real(client, sock, conn);
991 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
992 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
993 client->internal->ops->disconnected(client, conn, 0, NULL);
994 silc_client_close_connection_real(client, sock, conn);
998 /* Process the packet. This will call the parser that will then
999 decrypt and parse the packet. */
1000 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
1001 silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
1002 conn->internal->hmac_receive,
1003 conn->internal->psn_receive,
1004 silc_client_packet_parse, client);
1006 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
1007 silc_client_packet_parse, client);
1011 /* Parser callback called by silc_packet_receive_process. Thie merely
1012 registers timeout that will handle the actual parsing when appropriate. */
1014 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
1017 SilcClient client = (SilcClient)context;
1018 SilcSocketConnection sock = parser_context->sock;
1019 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1020 SilcPacketContext *packet = parser_context->packet;
1023 if (conn && conn->internal->hmac_receive && conn->sock == sock)
1024 conn->internal->psn_receive = parser_context->packet->sequence + 1;
1026 /* Parse the packet immediately */
1027 if (parser_context->normal)
1028 ret = silc_packet_parse(packet, conn->internal->receive_key);
1030 ret = silc_packet_parse_special(packet, conn->internal->receive_key);
1032 if (ret == SILC_PACKET_NONE) {
1033 silc_packet_context_free(packet);
1034 silc_free(parser_context);
1038 /* If protocol for this connection is key exchange or rekey then we'll
1039 process all packets synchronously, since there might be packets in
1040 queue that we are not able to decrypt without first processing the
1041 packets before them. */
1042 if ((ret == SILC_PACKET_REKEY || ret == SILC_PACKET_REKEY_DONE) ||
1043 (sock->protocol && sock->protocol->protocol &&
1044 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1045 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY))) {
1047 /* Parse the incoming packet type */
1048 silc_client_packet_parse_type(client, sock, packet);
1049 silc_packet_context_free(packet);
1050 silc_free(parser_context);
1052 /* Reprocess the buffer since we'll return FALSE. This is because
1053 the `conn->internal->receive_key' might have become valid by processing
1054 the previous packet */
1055 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
1056 silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
1057 conn->internal->hmac_receive,
1058 conn->internal->psn_receive,
1059 silc_client_packet_parse, client);
1061 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
1062 silc_client_packet_parse, client);
1067 /* Parse the incoming packet type */
1068 silc_client_packet_parse_type(client, sock, packet);
1069 silc_packet_context_free(packet);
1070 silc_free(parser_context);
1074 /* Parses the packet type and calls what ever routines the packet type
1075 requires. This is done for all incoming packets. */
1077 void silc_client_packet_parse_type(SilcClient client,
1078 SilcSocketConnection sock,
1079 SilcPacketContext *packet)
1081 SilcBuffer buffer = packet->buffer;
1082 SilcPacketType type = packet->type;
1084 SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(type)));
1086 /* Parse the packet type */
1089 case SILC_PACKET_DISCONNECT:
1090 silc_client_disconnected_by_server(client, sock, buffer);
1093 case SILC_PACKET_SUCCESS:
1095 * Success received for something. For now we can have only
1096 * one protocol for connection executing at once hence this
1097 * success message is for whatever protocol is executing currently.
1100 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1103 case SILC_PACKET_FAILURE:
1105 * Failure received for some protocol. Set the protocol state to
1106 * error and call the protocol callback. This fill cause error on
1107 * protocol and it will call the final callback.
1109 silc_client_process_failure(client, sock, packet);
1112 case SILC_PACKET_REJECT:
1115 case SILC_PACKET_NOTIFY:
1117 * Received notify message
1119 silc_client_notify_by_server(client, sock, packet);
1122 case SILC_PACKET_ERROR:
1124 * Received error message
1126 silc_client_error_by_server(client, sock, buffer);
1129 case SILC_PACKET_CHANNEL_MESSAGE:
1131 * Received message to (from, actually) a channel
1133 silc_client_channel_message(client, sock, packet);
1136 case SILC_PACKET_CHANNEL_KEY:
1138 * Received key for a channel. By receiving this key the client will be
1139 * able to talk to the channel it has just joined. This can also be
1140 * a new key for existing channel as keys expire peridiocally.
1142 silc_client_receive_channel_key(client, sock, buffer);
1145 case SILC_PACKET_PRIVATE_MESSAGE:
1147 * Received private message
1149 silc_client_private_message(client, sock, packet);
1152 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
1154 * Received private message key
1158 case SILC_PACKET_COMMAND:
1160 * Received command packet, a special case since normally client
1161 * does not receive commands.
1163 silc_client_command_process(client, sock, packet);
1166 case SILC_PACKET_COMMAND_REPLY:
1168 * Recived reply for a command
1170 silc_client_command_reply_process(client, sock, packet);
1173 case SILC_PACKET_KEY_EXCHANGE:
1174 if (sock->protocol && sock->protocol->protocol &&
1175 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1176 SilcClientKEInternalContext *proto_ctx =
1177 (SilcClientKEInternalContext *)sock->protocol->context;
1179 proto_ctx->packet = silc_packet_context_dup(packet);
1180 proto_ctx->dest_id_type = packet->src_id_type;
1181 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1182 packet->src_id_type);
1183 if (!proto_ctx->dest_id)
1186 /* Let the protocol handle the packet */
1187 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1189 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
1190 "protocol active, packet dropped."));
1194 case SILC_PACKET_KEY_EXCHANGE_1:
1195 if (sock->protocol && sock->protocol->protocol &&
1196 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1197 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1199 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1200 SilcClientRekeyInternalContext *proto_ctx =
1201 (SilcClientRekeyInternalContext *)sock->protocol->context;
1203 if (proto_ctx->packet)
1204 silc_packet_context_free(proto_ctx->packet);
1206 proto_ctx->packet = silc_packet_context_dup(packet);
1208 /* Let the protocol handle the packet */
1209 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1211 SilcClientKEInternalContext *proto_ctx =
1212 (SilcClientKEInternalContext *)sock->protocol->context;
1214 if (proto_ctx->packet)
1215 silc_packet_context_free(proto_ctx->packet);
1217 proto_ctx->packet = silc_packet_context_dup(packet);
1218 proto_ctx->dest_id_type = packet->src_id_type;
1219 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1220 packet->src_id_type);
1221 if (!proto_ctx->dest_id)
1224 /* Let the protocol handle the packet */
1225 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1228 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
1229 "protocol active, packet dropped."));
1233 case SILC_PACKET_KEY_EXCHANGE_2:
1234 if (sock->protocol && sock->protocol->protocol &&
1235 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1236 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1238 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1239 SilcClientRekeyInternalContext *proto_ctx =
1240 (SilcClientRekeyInternalContext *)sock->protocol->context;
1242 if (proto_ctx->packet)
1243 silc_packet_context_free(proto_ctx->packet);
1245 proto_ctx->packet = silc_packet_context_dup(packet);
1247 /* Let the protocol handle the packet */
1248 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1250 SilcClientKEInternalContext *proto_ctx =
1251 (SilcClientKEInternalContext *)sock->protocol->context;
1253 if (proto_ctx->packet)
1254 silc_packet_context_free(proto_ctx->packet);
1255 if (proto_ctx->dest_id)
1256 silc_free(proto_ctx->dest_id);
1257 proto_ctx->packet = silc_packet_context_dup(packet);
1258 proto_ctx->dest_id_type = packet->src_id_type;
1259 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1260 packet->src_id_type);
1261 if (!proto_ctx->dest_id)
1264 /* Let the protocol handle the packet */
1265 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1268 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
1269 "protocol active, packet dropped."));
1273 case SILC_PACKET_NEW_ID:
1276 * Received new ID from server. This packet is received at
1277 * the connection to the server. New ID is also received when
1278 * user changes nickname but in that case the new ID is received
1279 * as command reply and not as this packet type.
1283 idp = silc_id_payload_parse(buffer->data, buffer->len);
1286 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
1289 silc_client_receive_new_id(client, sock, idp);
1290 silc_id_payload_free(idp);
1294 case SILC_PACKET_HEARTBEAT:
1296 * Received heartbeat packet
1298 SILC_LOG_DEBUG(("Heartbeat packet"));
1301 case SILC_PACKET_KEY_AGREEMENT:
1303 * Received key agreement packet
1305 SILC_LOG_DEBUG(("Key agreement packet"));
1306 silc_client_key_agreement(client, sock, packet);
1309 case SILC_PACKET_REKEY:
1310 SILC_LOG_DEBUG(("Re-key packet"));
1311 /* We ignore this for now */
1314 case SILC_PACKET_REKEY_DONE:
1315 SILC_LOG_DEBUG(("Re-key done packet"));
1317 if (sock->protocol && sock->protocol->protocol &&
1318 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1320 SilcClientRekeyInternalContext *proto_ctx =
1321 (SilcClientRekeyInternalContext *)sock->protocol->context;
1323 if (proto_ctx->packet)
1324 silc_packet_context_free(proto_ctx->packet);
1326 proto_ctx->packet = silc_packet_context_dup(packet);
1328 /* Let the protocol handle the packet */
1329 if (proto_ctx->responder == FALSE)
1330 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1332 /* Let the protocol handle the packet */
1333 silc_protocol_execute(sock->protocol, client->schedule,
1336 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1337 "protocol active, packet dropped."));
1341 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
1343 * Reveived reply to our connection authentication method request
1344 * packet. This is used to resolve the authentication method for the
1345 * current session from the server if the client does not know it.
1347 silc_client_connection_auth_request(client, sock, packet);
1350 case SILC_PACKET_FTP:
1351 /* Received file transfer packet. */
1352 silc_client_ftp(client, sock, packet);
1356 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1361 /* Sends packet. This doesn't actually send the packet instead it assembles
1362 it and marks it to be sent. However, if force_send is TRUE the packet
1363 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1364 will be derived from sock argument. Otherwise the valid arguments sent
1367 void silc_client_packet_send(SilcClient client,
1368 SilcSocketConnection sock,
1369 SilcPacketType type,
1371 SilcIdType dst_id_type,
1374 unsigned char *data,
1375 SilcUInt32 data_len,
1378 SilcPacketContext packetdata;
1379 const SilcBufferStruct packet;
1381 SilcUInt32 sequence = 0;
1386 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1388 /* Get data used in the packet sending, keys and stuff */
1389 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1390 if (!cipher && ((SilcClientConnection)sock->user_data)->internal->send_key)
1391 cipher = ((SilcClientConnection)sock->user_data)->internal->send_key;
1393 if (!hmac && ((SilcClientConnection)sock->user_data)->internal->hmac_send)
1394 hmac = ((SilcClientConnection)sock->user_data)->internal->hmac_send;
1396 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1397 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1398 dst_id_type = SILC_ID_SERVER;
1402 sequence = ((SilcClientConnection)sock->user_data)->internal->psn_send++;
1405 block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
1407 /* Set the packet context pointers */
1408 packetdata.flags = 0;
1409 packetdata.type = type;
1410 if (sock->user_data &&
1411 ((SilcClientConnection)sock->user_data)->local_id_data) {
1412 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1413 packetdata.src_id_len =
1414 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1417 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1418 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1420 packetdata.src_id_type = SILC_ID_CLIENT;
1422 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1423 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1424 packetdata.dst_id_type = dst_id_type;
1426 packetdata.dst_id = NULL;
1427 packetdata.dst_id_len = 0;
1428 packetdata.dst_id_type = SILC_ID_NONE;
1430 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1431 packetdata.src_id_len +
1432 packetdata.dst_id_len));
1433 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1434 packetdata.src_id_len + packetdata.dst_id_len;
1435 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
1437 /* Create the outgoing packet */
1438 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
1439 data, data_len, (const SilcBuffer)&packet)) {
1440 SILC_LOG_ERROR(("Error assembling packet"));
1444 /* Encrypt the packet */
1446 silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet,
1449 SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, packet.len),
1450 packet.data, packet.len);
1452 /* Now actually send the packet */
1453 silc_client_packet_send_real(client, sock, force_send);
1456 void silc_client_packet_queue_purge(SilcClient client,
1457 SilcSocketConnection sock)
1459 if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
1460 (SILC_IS_DISCONNECTED(sock) == FALSE)) {
1461 silc_packet_send(sock, TRUE);
1462 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
1463 SILC_UNSET_OUTBUF_PENDING(sock);
1464 silc_buffer_clear(sock->outbuf);
1468 /* Closes connection to remote end. Free's all allocated data except
1469 for some information such as nickname etc. that are valid at all time.
1470 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1471 provided it will be checked whether the sock and `conn->sock' are the
1472 same (they can be different, ie. a socket can use `conn' as its
1473 connection but `conn->sock' might be actually a different connection
1474 than the `sock'). */
1476 void silc_client_close_connection_real(SilcClient client,
1477 SilcSocketConnection sock,
1478 SilcClientConnection conn)
1482 SILC_LOG_DEBUG(("Start"));
1487 if (!sock || (sock && conn->sock == sock))
1492 /* We won't listen for this connection anymore */
1493 silc_schedule_unset_listen_fd(client->schedule, sock->sock);
1495 /* Unregister all tasks */
1496 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1498 /* Close the actual connection */
1499 silc_net_close_connection(sock->sock);
1501 /* Cancel any active protocol */
1502 if (sock->protocol) {
1503 if (sock->protocol->protocol->type ==
1504 SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1505 sock->protocol->protocol->type ==
1506 SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1507 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1508 silc_protocol_execute_final(sock->protocol, client->schedule);
1509 /* The application will recall this function with these protocols
1510 (the ops->connected client operation). */
1513 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1514 silc_protocol_execute_final(sock->protocol, client->schedule);
1515 sock->protocol = NULL;
1519 /* Free everything */
1520 if (del && sock->user_data)
1521 silc_client_del_connection(client, conn);
1523 silc_socket_free(sock);
1526 /* Closes the connection to the remote end */
1528 void silc_client_close_connection(SilcClient client,
1529 SilcClientConnection conn)
1531 silc_client_close_connection_real(client, NULL, conn);
1534 /* Called when we receive disconnection packet from server. This
1535 closes our end properly and displays the reason of the disconnection
1538 SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
1540 SilcClient client = (SilcClient)context;
1541 SilcSocketConnection sock;
1543 SILC_CLIENT_GET_SOCK(client, fd, sock);
1547 silc_client_close_connection_real(client, sock, sock->user_data);
1550 /* Called when we receive disconnection packet from server. This
1551 closes our end properly and displays the reason of the disconnection
1554 void silc_client_disconnected_by_server(SilcClient client,
1555 SilcSocketConnection sock,
1558 SilcClientConnection conn;
1560 char *message = NULL;
1562 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1564 if (packet->len < 1)
1567 status = (SilcStatus)packet->data[0];
1569 if (packet->len > 1 &&
1570 silc_utf8_valid(packet->data + 1, packet->len - 1))
1571 message = silc_memdup(packet->data + 1, packet->len - 1);
1573 conn = (SilcClientConnection)sock->user_data;
1574 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
1575 client->internal->ops->disconnected(client, conn, status, message);
1579 SILC_SET_DISCONNECTED(sock);
1581 /* Close connection through scheduler. */
1582 silc_schedule_task_add(client->schedule, sock->sock,
1583 silc_client_disconnected_by_server_later,
1584 client, 0, 1, SILC_TASK_TIMEOUT,
1585 SILC_TASK_PRI_NORMAL);
1588 /* Received error message from server. Display it on the screen.
1589 We don't take any action what so ever of the error message. */
1591 void silc_client_error_by_server(SilcClient client,
1592 SilcSocketConnection sock,
1597 msg = silc_memdup(message->data, message->len);
1598 client->internal->ops->say(client, sock->user_data,
1599 SILC_CLIENT_MESSAGE_AUDIT, msg);
1603 /* Auto-nicking callback to send NICK command to server. */
1605 SILC_TASK_CALLBACK(silc_client_send_auto_nick)
1607 SilcClientConnection conn = (SilcClientConnection)context;
1608 SilcClient client = conn->client;
1610 silc_client_command_send(client, conn, SILC_COMMAND_NICK,
1611 ++conn->cmd_ident, 1, 1,
1612 client->nickname, strlen(client->nickname));
1615 /* Client session resuming callback. If the session was resumed
1616 this callback is called after the resuming is completed. This
1617 will call the `connect' client operation to the application
1618 since it has not been called yet. */
1620 static void silc_client_resume_session_cb(SilcClient client,
1621 SilcClientConnection conn,
1627 /* Notify application that connection is created to server */
1628 client->internal->ops->connected(client, conn, success ?
1629 SILC_CLIENT_CONN_SUCCESS_RESUME :
1630 SILC_CLIENT_CONN_ERROR);
1633 /* Issue INFO command to fetch the real server name and server
1634 information and other stuff. */
1635 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1636 silc_client_command_reply_info_i, 0,
1638 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1639 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1640 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1641 silc_buffer_free(sidp);
1645 /* Processes the received new Client ID from server. Old Client ID is
1646 deleted from cache and new one is added. */
1648 void silc_client_receive_new_id(SilcClient client,
1649 SilcSocketConnection sock,
1652 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1653 int connecting = FALSE;
1654 SilcClientID *client_id = silc_id_payload_get_id(idp);
1656 if (!conn->local_entry)
1659 /* Delete old ID from ID cache */
1660 if (conn->local_id) {
1661 /* Check whether they are different */
1662 if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1663 silc_free(client_id);
1667 silc_idcache_del_by_context(conn->internal->client_cache,
1669 silc_free(conn->local_id);
1672 /* Save the new ID */
1674 if (conn->local_id_data)
1675 silc_free(conn->local_id_data);
1677 conn->local_id = client_id;
1678 conn->local_id_data = silc_id_payload_get_data(idp);
1679 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1681 if (!conn->local_entry)
1682 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1684 conn->local_entry->nickname = conn->nickname;
1685 if (!conn->local_entry->username)
1686 conn->local_entry->username = strdup(client->username);
1687 if (!conn->local_entry->server)
1688 conn->local_entry->server = strdup(conn->remote_host);
1689 conn->local_entry->id = conn->local_id;
1690 conn->local_entry->valid = TRUE;
1691 if (!conn->local_entry->channels)
1692 conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
1697 /* Put it to the ID cache */
1698 silc_idcache_add(conn->internal->client_cache,
1699 strdup(conn->nickname), conn->local_id,
1700 (void *)conn->local_entry, 0, NULL);
1705 /* Issue IDENTIFY command for itself to get resolved hostname
1706 correctly from server. */
1707 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
1708 silc_client_command_reply_identify_i, 0,
1710 sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
1711 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1712 conn->cmd_ident, 1, 5, sidp->data, sidp->len);
1713 silc_buffer_free(sidp);
1715 if (!conn->internal->params.detach_data) {
1716 /* Send NICK command if the nickname was set by the application (and is
1717 not same as the username). Send this with little timeout. */
1718 if (client->nickname && strcmp(client->nickname, client->username))
1719 silc_schedule_task_add(client->schedule, 0,
1720 silc_client_send_auto_nick, conn,
1721 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1723 /* Notify application of successful connection. We do it here now that
1724 we've received the Client ID and are allowed to send traffic. */
1725 client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_SUCCESS);
1727 /* Issue INFO command to fetch the real server name and server
1728 information and other stuff. */
1729 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1730 silc_client_command_reply_info_i, 0,
1732 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1733 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1734 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1735 silc_buffer_free(sidp);
1737 /* We are resuming session. Start resolving informations from the
1738 server we need to set the client libary in the state before
1739 detaching the session. The connect client operation is called
1740 after this is successfully completed */
1741 silc_client_resume_session(client, conn, silc_client_resume_session_cb,
1747 /* Removes a client entry from all channels it has joined. */
1749 void silc_client_remove_from_channels(SilcClient client,
1750 SilcClientConnection conn,
1751 SilcClientEntry client_entry)
1753 SilcHashTableList htl;
1754 SilcChannelUser chu;
1756 silc_hash_table_list(client_entry->channels, &htl);
1757 while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1758 silc_hash_table_del(chu->client->channels, chu->channel);
1759 silc_hash_table_del(chu->channel->user_list, chu->client);
1763 silc_hash_table_list_reset(&htl);
1766 /* Replaces `old' client entries from all channels to `new' client entry.
1767 This can be called for example when nickname changes and old ID entry
1768 is replaced from ID cache with the new one. If the old ID entry is only
1769 updated, then this fucntion needs not to be called. */
1771 void silc_client_replace_from_channels(SilcClient client,
1772 SilcClientConnection conn,
1773 SilcClientEntry old,
1774 SilcClientEntry new)
1776 SilcHashTableList htl;
1777 SilcChannelUser chu;
1779 silc_hash_table_list(old->channels, &htl);
1780 while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1781 /* Replace client entry */
1782 silc_hash_table_del(chu->client->channels, chu->channel);
1783 silc_hash_table_del(chu->channel->user_list, chu->client);
1786 silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1787 silc_hash_table_add(chu->client->channels, chu->channel, chu);
1789 silc_hash_table_list_reset(&htl);
1792 /* Registers failure timeout to process the received failure packet
1795 void silc_client_process_failure(SilcClient client,
1796 SilcSocketConnection sock,
1797 SilcPacketContext *packet)
1799 SilcUInt32 failure = 0;
1801 if (sock->protocol) {
1802 if (packet->buffer->len >= 4)
1803 SILC_GET32_MSB(failure, packet->buffer->data);
1805 /* Notify application */
1806 client->internal->ops->failure(client, sock->user_data, sock->protocol,
1811 /* A timeout callback for the re-key. We will be the initiator of the
1814 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1816 SilcSocketConnection sock = (SilcSocketConnection)context;
1817 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1818 SilcClient client = (SilcClient)conn->internal->rekey->context;
1819 SilcProtocol protocol;
1820 SilcClientRekeyInternalContext *proto_ctx;
1822 SILC_LOG_DEBUG(("Start"));
1824 /* Allocate internal protocol context. This is sent as context
1826 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1827 proto_ctx->client = (void *)client;
1828 proto_ctx->sock = silc_socket_dup(sock);
1829 proto_ctx->responder = FALSE;
1830 proto_ctx->pfs = conn->internal->rekey->pfs;
1832 /* Perform rekey protocol. Will call the final callback after the
1833 protocol is over. */
1834 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1835 &protocol, proto_ctx, silc_client_rekey_final);
1836 sock->protocol = protocol;
1838 /* Run the protocol */
1839 silc_protocol_execute(protocol, client->schedule, 0, 0);
1841 /* Re-register re-key timeout */
1842 silc_schedule_task_add(client->schedule, sock->sock,
1843 silc_client_rekey_callback,
1844 context, conn->internal->rekey->timeout, 0,
1845 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1848 /* The final callback for the REKEY protocol. This will actually take the
1849 new key material into use. */
1851 SILC_TASK_CALLBACK(silc_client_rekey_final)
1853 SilcProtocol protocol = (SilcProtocol)context;
1854 SilcClientRekeyInternalContext *ctx =
1855 (SilcClientRekeyInternalContext *)protocol->context;
1856 SilcClient client = (SilcClient)ctx->client;
1857 SilcSocketConnection sock = ctx->sock;
1859 SILC_LOG_DEBUG(("Start"));
1861 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1862 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1863 /* Error occured during protocol */
1864 silc_protocol_cancel(protocol, client->schedule);
1865 silc_protocol_free(protocol);
1866 sock->protocol = NULL;
1868 silc_packet_context_free(ctx->packet);
1870 silc_ske_free(ctx->ske);
1871 silc_socket_free(ctx->sock);
1876 /* Purge the outgoing data queue to assure that all rekey packets really
1877 go to the network before we quit the protocol. */
1878 silc_client_packet_queue_purge(client, sock);
1881 silc_protocol_free(protocol);
1882 sock->protocol = NULL;
1884 silc_packet_context_free(ctx->packet);
1886 silc_ske_free(ctx->ske);
1887 silc_socket_free(ctx->sock);
1891 /* Processes incoming connection authentication method request packet.
1892 It is a reply to our previously sent request. The packet can be used
1893 to resolve the authentication method for the current session if the
1894 client does not know it beforehand. */
1896 void silc_client_connection_auth_request(SilcClient client,
1897 SilcSocketConnection sock,
1898 SilcPacketContext *packet)
1900 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1901 SilcUInt16 conn_type, auth_meth;
1904 /* If we haven't send our request then ignore this one. */
1905 if (!conn->internal->connauth)
1908 /* Parse the payload */
1909 ret = silc_buffer_unformat(packet->buffer,
1910 SILC_STR_UI_SHORT(&conn_type),
1911 SILC_STR_UI_SHORT(&auth_meth),
1914 auth_meth = SILC_AUTH_NONE;
1916 /* Call the request callback to notify application for received
1917 authentication method information. */
1918 if (conn->internal->connauth->callback)
1919 (*conn->internal->connauth->callback)(client, conn, auth_meth,
1920 conn->internal->connauth->context);
1922 silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
1924 silc_free(conn->internal->connauth);
1925 conn->internal->connauth = NULL;
1928 /* Timeout task callback called if the server does not reply to our
1929 connection authentication method request in the specified time interval. */
1931 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1933 SilcClientConnection conn = (SilcClientConnection)context;
1934 SilcClient client = conn->client;
1936 if (!conn->internal->connauth)
1939 /* Call the request callback to notify application */
1940 if (conn->internal->connauth->callback)
1941 (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
1942 conn->internal->connauth->context);
1944 silc_free(conn->internal->connauth);
1945 conn->internal->connauth = NULL;
1948 /* This function can be used to request the current authentication method
1949 from the server. This may be called when connecting to the server
1950 and the client library requests the authentication data from the
1951 application. If the application does not know the current authentication
1952 method it can request it from the server using this function.
1953 The `callback' with `context' will be called after the server has
1954 replied back with the current authentication method. */
1957 silc_client_request_authentication_method(SilcClient client,
1958 SilcClientConnection conn,
1959 SilcConnectionAuthRequest callback,
1962 SilcClientConnAuthRequest connauth;
1965 connauth = silc_calloc(1, sizeof(*connauth));
1966 connauth->callback = callback;
1967 connauth->context = context;
1969 if (conn->internal->connauth)
1970 silc_free(conn->internal->connauth);
1972 conn->internal->connauth = connauth;
1974 /* Assemble the request packet and send it to the server */
1975 packet = silc_buffer_alloc(4);
1976 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1977 silc_buffer_format(packet,
1978 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1979 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1981 silc_client_packet_send(client, conn->sock,
1982 SILC_PACKET_CONNECTION_AUTH_REQUEST,
1983 NULL, 0, NULL, NULL,
1984 packet->data, packet->len, FALSE);
1985 silc_buffer_free(packet);
1987 /* Register a timeout in case server does not reply anything back. */
1989 silc_schedule_task_add(client->schedule, conn->sock->sock,
1990 silc_client_request_authentication_method_timeout,
1992 client->internal->params->connauth_request_secs, 0,
1993 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);