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"));
108 assert(client->username);
109 assert(client->hostname);
110 assert(client->realname);
112 /* Initialize the crypto library. If application has done this already
113 this has no effect. Also, we will not be overriding something
114 application might have registered earlier. */
115 silc_cipher_register_default();
116 silc_pkcs_register_default();
117 silc_hash_register_default();
118 silc_hmac_register_default();
120 /* Initialize hash functions for client to use */
121 silc_hash_alloc("md5", &client->md5hash);
122 silc_hash_alloc("sha1", &client->sha1hash);
124 /* Initialize none cipher */
125 silc_cipher_alloc("none", &client->internal->none_cipher);
127 /* Initialize random number generator */
128 client->rng = silc_rng_alloc();
129 silc_rng_init(client->rng);
130 silc_rng_global_init(client->rng);
132 /* Register protocols */
133 silc_client_protocols_register();
135 /* Initialize the scheduler */
137 silc_schedule_init(client->internal->params->task_max ?
138 client->internal->params->task_max : 200, client);
139 if (!client->schedule)
142 /* Register commands */
143 silc_client_commands_register(client);
148 /* Stops the client. This is called to stop the client and thus to stop
151 void silc_client_stop(SilcClient client)
153 SILC_LOG_DEBUG(("Stopping client"));
155 silc_schedule_stop(client->schedule);
156 silc_schedule_uninit(client->schedule);
158 silc_client_protocols_unregister();
159 silc_client_commands_unregister(client);
161 SILC_LOG_DEBUG(("Client stopped"));
164 /* Runs the client. This starts the scheduler from the utility library.
165 When this functions returns the execution of the appliation is over. */
167 void silc_client_run(SilcClient client)
169 SILC_LOG_DEBUG(("Running client"));
172 assert(client->pkcs);
173 assert(client->public_key);
174 assert(client->private_key);
176 /* Start the scheduler, the heart of the SILC client. When this returns
177 the program will be terminated. */
178 silc_schedule(client->schedule);
181 /* Runs the client and returns immeadiately. This function is used when
182 the SILC Client object indicated by the `client' is run under some
183 other scheduler, or event loop or main loop. On GUI applications,
184 for example this may be desired to use to run the client under the
185 GUI application's main loop. Typically the GUI application would
186 register an idle task that calls this function multiple times in
187 a second to quickly process the SILC specific data. */
189 void silc_client_run_one(SilcClient client)
191 /* Run the scheduler once. */
192 silc_schedule_one(client->schedule, 0);
195 static void silc_client_entry_destructor(SilcIDCache cache,
196 SilcIDCacheEntry entry)
198 silc_free(entry->name);
201 /* Allocates and adds new connection to the client. This adds the allocated
202 connection to the connection table and returns a pointer to it. A client
203 can have multiple connections to multiple servers. Every connection must
204 be added to the client using this function. User data `context' may
205 be sent as argument. This function is normally used only if the
206 application performed the connecting outside the library. The library
207 however may use this internally. */
210 silc_client_add_connection(SilcClient client,
211 SilcClientConnectionParams *params,
212 char *hostname, int port, void *context)
214 SilcClientConnection conn;
217 SILC_LOG_DEBUG(("Adding new connection to %s:%d", hostname, port));
219 conn = silc_calloc(1, sizeof(*conn));
220 conn->internal = silc_calloc(1, sizeof(*conn->internal));
222 /* Initialize ID caches */
223 conn->client = client;
224 conn->remote_host = strdup(hostname);
225 conn->remote_port = port;
226 conn->context = context;
227 conn->internal->client_cache =
228 silc_idcache_alloc(0, SILC_ID_CLIENT, silc_client_entry_destructor);
229 conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
230 conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
231 conn->internal->pending_commands = silc_dlist_init();
232 conn->internal->ftp_sessions = silc_dlist_init();
235 if (params->detach_data)
236 conn->internal->params.detach_data =
237 silc_memdup(params->detach_data,
238 params->detach_data_len);
239 conn->internal->params.detach_data_len = params->detach_data_len;
242 /* Add the connection to connections table */
243 for (i = 0; i < client->internal->conns_count; i++)
244 if (client->internal->conns && !client->internal->conns[i]) {
245 client->internal->conns[i] = conn;
249 client->internal->conns =
250 silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
251 * (client->internal->conns_count + 1));
252 client->internal->conns[client->internal->conns_count] = conn;
253 client->internal->conns_count++;
258 /* Removes connection from client. Frees all memory. */
260 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
264 for (i = 0; i < client->internal->conns_count; i++)
265 if (client->internal->conns[i] == conn) {
266 /* Free all cache entries */
267 SilcIDCacheList list;
268 SilcIDCacheEntry entry;
269 SilcClientCommandPending *r;
272 if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
273 ret = silc_idcache_list_first(list, &entry);
275 silc_client_del_client(client, conn, entry->context);
276 ret = silc_idcache_list_next(list, &entry);
278 silc_idcache_list_free(list);
281 if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
282 ret = silc_idcache_list_first(list, &entry);
284 silc_client_del_channel(client, conn, entry->context);
285 ret = silc_idcache_list_next(list, &entry);
287 silc_idcache_list_free(list);
290 if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
291 ret = silc_idcache_list_first(list, &entry);
293 silc_client_del_server(client, conn, entry->context);
294 ret = silc_idcache_list_next(list, &entry);
296 silc_idcache_list_free(list);
299 /* Clear ID caches */
300 if (conn->internal->client_cache)
301 silc_idcache_free(conn->internal->client_cache);
302 if (conn->internal->channel_cache)
303 silc_idcache_free(conn->internal->channel_cache);
304 if (conn->internal->server_cache)
305 silc_idcache_free(conn->internal->server_cache);
307 /* Free data (my ID is freed in above silc_client_del_client).
308 conn->nickname is freed when freeing the local_entry->nickname. */
309 silc_free(conn->remote_host);
310 silc_free(conn->local_id_data);
311 if (conn->internal->send_key)
312 silc_cipher_free(conn->internal->send_key);
313 if (conn->internal->receive_key)
314 silc_cipher_free(conn->internal->receive_key);
315 if (conn->internal->hmac_send)
316 silc_hmac_free(conn->internal->hmac_send);
317 if (conn->internal->hmac_receive)
318 silc_hmac_free(conn->internal->hmac_receive);
319 silc_free(conn->internal->rekey);
321 if (conn->internal->active_session) {
322 conn->sock->user_data = NULL;
323 silc_client_ftp_session_free(conn->internal->active_session);
324 conn->internal->active_session = NULL;
327 silc_client_ftp_free_sessions(client, conn);
329 if (conn->internal->pending_commands) {
330 silc_dlist_start(conn->internal->pending_commands);
331 while ((r = silc_dlist_get(conn->internal->pending_commands))
333 silc_dlist_del(conn->internal->pending_commands, r);
334 silc_dlist_uninit(conn->internal->pending_commands);
337 silc_free(conn->internal);
338 memset(conn, 0, sizeof(*conn));
341 client->internal->conns[i] = NULL;
345 /* Adds listener socket to the listener sockets table. This function is
346 used to add socket objects that are listeners to the client. This should
347 not be used to add other connection objects. */
349 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
353 if (!client->internal->sockets) {
354 client->internal->sockets =
355 silc_calloc(1, sizeof(*client->internal->sockets));
356 client->internal->sockets[0] = silc_socket_dup(sock);
357 client->internal->sockets_count = 1;
361 for (i = 0; i < client->internal->sockets_count; i++) {
362 if (client->internal->sockets[i] == NULL) {
363 client->internal->sockets[i] = silc_socket_dup(sock);
368 client->internal->sockets =
369 silc_realloc(client->internal->sockets,
370 sizeof(*client->internal->sockets) *
371 (client->internal->sockets_count + 1));
372 client->internal->sockets[client->internal->sockets_count] =
373 silc_socket_dup(sock);
374 client->internal->sockets_count++;
377 /* Deletes listener socket from the listener sockets table. */
379 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
383 if (!client->internal->sockets)
386 for (i = 0; i < client->internal->sockets_count; i++) {
387 if (client->internal->sockets[i] == sock) {
388 silc_socket_free(sock);
389 client->internal->sockets[i] = NULL;
396 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
400 /* XXX In the future we should give up this non-blocking connect all
401 together and use threads instead. */
402 /* Create connection to server asynchronously */
403 sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
407 /* Register task that will receive the async connect and will
409 ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
410 silc_client_connect_to_server_start,
413 SILC_TASK_PRI_NORMAL);
414 silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
422 /* Connects to remote server. This is the main routine used to connect
423 to SILC server. Returns -1 on error and the created socket otherwise.
424 The `context' is user context that is saved into the SilcClientConnection
425 that is created after the connection is created. Note that application
426 may handle the connecting process outside the library. If this is the
427 case then this function is not used at all. When the connecting is
428 done the `connect' client operation is called. */
430 int silc_client_connect_to_server(SilcClient client,
431 SilcClientConnectionParams *params,
432 int port, char *host, void *context)
434 SilcClientInternalConnectContext *ctx;
435 SilcClientConnection conn;
438 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
441 conn = silc_client_add_connection(client, params, host, port, context);
443 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
444 "Connecting to port %d of server %s", port, host);
446 /* Allocate internal context for connection process. This is
447 needed as we are doing async connecting. */
448 ctx = silc_calloc(1, sizeof(*ctx));
449 ctx->client = client;
451 ctx->host = strdup(host);
452 ctx->port = port ? port : 706;
455 /* Do the actual connecting process */
456 sock = silc_client_connect_to_server_internal(ctx);
458 silc_client_del_connection(client, conn);
462 /* Socket hostname and IP lookup callback that is called before actually
463 starting the key exchange. The lookup is called from the function
464 silc_client_start_key_exchange. */
466 static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
469 SilcClientConnection conn = (SilcClientConnection)context;
470 SilcClient client = conn->client;
471 SilcProtocol protocol;
472 SilcClientKEInternalContext *proto_ctx;
474 SILC_LOG_DEBUG(("Start"));
476 if (conn->sock->hostname) {
477 silc_free(conn->remote_host);
478 conn->remote_host = strdup(conn->sock->hostname);
480 conn->sock->hostname = strdup(conn->remote_host);
483 conn->sock->ip = strdup(conn->sock->hostname);
484 conn->sock->port = conn->remote_port;
486 /* Allocate internal Key Exchange context. This is sent to the
487 protocol as context. */
488 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
489 proto_ctx->client = (void *)client;
490 proto_ctx->sock = silc_socket_dup(conn->sock);
491 proto_ctx->rng = client->rng;
492 proto_ctx->responder = FALSE;
493 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
494 proto_ctx->verify = silc_client_protocol_ke_verify_key;
496 /* Perform key exchange protocol. silc_client_connect_to_server_final
497 will be called after the protocol is finished. */
498 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
499 &protocol, (void *)proto_ctx,
500 silc_client_connect_to_server_second);
502 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
503 "Error: Could not start key exchange protocol");
504 silc_net_close_connection(conn->sock->sock);
505 client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
508 conn->sock->protocol = protocol;
510 /* Register the connection for network input and output. This sets
511 that scheduler will listen for incoming packets for this connection
512 and sets that outgoing packets may be sent to this connection as well.
513 However, this doesn't set the scheduler for outgoing traffic, it will
514 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
515 later when outgoing data is available. */
516 context = (void *)client;
517 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
519 /* Execute the protocol */
520 silc_protocol_execute(protocol, client->schedule, 0, 0);
523 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
524 key material between client and server. This function can be called
525 directly if application is performing its own connecting and does not
526 use the connecting provided by this library. This function is normally
527 used only if the application performed the connecting outside the library.
528 The library however may use this internally. */
530 void silc_client_start_key_exchange(SilcClient client,
531 SilcClientConnection conn,
534 assert(client->pkcs);
535 assert(client->public_key);
536 assert(client->private_key);
538 /* Allocate new socket connection object */
539 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
541 /* Sometimes when doing quick reconnects the new socket may be same as
542 the old one and there might be pending stuff for the old socket.
543 If new one is same then those pending sutff might cause problems.
544 Make sure they do not do that. */
545 silc_schedule_task_del_by_fd(client->schedule, fd);
547 conn->nickname = (client->nickname ? strdup(client->nickname) :
548 strdup(client->username));
550 /* Resolve the remote hostname and IP address for our socket connection */
551 silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
552 conn, client->schedule);
555 /* Callback called when error has occurred during connecting (KE) to
556 the server. The `connect' client operation will be called. */
558 SILC_TASK_CALLBACK(silc_client_connect_failure)
560 SilcClientKEInternalContext *ctx =
561 (SilcClientKEInternalContext *)context;
562 SilcClient client = (SilcClient)ctx->client;
564 client->internal->ops->connected(client, ctx->sock->user_data,
565 SILC_CLIENT_CONN_ERROR);
567 silc_packet_context_free(ctx->packet);
571 /* Callback called when error has occurred during connecting (auth) to
572 the server. The `connect' client operation will be called. */
574 SILC_TASK_CALLBACK(silc_client_connect_failure_auth)
576 SilcClientConnAuthInternalContext *ctx =
577 (SilcClientConnAuthInternalContext *)context;
578 SilcClient client = (SilcClient)ctx->client;
580 client->internal->ops->connected(client, ctx->sock->user_data,
581 SILC_CLIENT_CONN_ERROR);
585 /* Start of the connection to the remote server. This is called after
586 succesful TCP/IP connection has been established to the remote host. */
588 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
590 SilcClientInternalConnectContext *ctx =
591 (SilcClientInternalConnectContext *)context;
592 SilcClient client = ctx->client;
593 SilcClientConnection conn = ctx->conn;
594 int opt, opt_len = sizeof(opt);
596 SILC_LOG_DEBUG(("Start"));
598 /* Check the socket status as it might be in error */
599 silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
601 if (ctx->tries < 2) {
602 /* Connection failed but lets try again */
603 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
604 "Could not connect to server %s: %s",
605 ctx->host, strerror(opt));
606 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
607 "Connecting to port %d of server %s resumed",
608 ctx->port, ctx->host);
610 /* Unregister old connection try */
611 silc_schedule_unset_listen_fd(client->schedule, fd);
612 silc_net_close_connection(fd);
613 silc_schedule_task_del(client->schedule, ctx->task);
616 silc_client_connect_to_server_internal(ctx);
619 /* Connection failed and we won't try anymore */
620 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
621 "Could not connect to server %s: %s",
622 ctx->host, strerror(opt));
623 silc_schedule_unset_listen_fd(client->schedule, fd);
624 silc_net_close_connection(fd);
625 silc_schedule_task_del(client->schedule, ctx->task);
628 /* Notify application of failure */
629 client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
630 silc_client_del_connection(client, conn);
635 silc_schedule_unset_listen_fd(client->schedule, fd);
636 silc_schedule_task_del(client->schedule, ctx->task);
639 silc_client_start_key_exchange(client, conn, fd);
642 /* Second part of the connecting to the server. This executed
643 authentication protocol. */
645 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
647 SilcProtocol protocol = (SilcProtocol)context;
648 SilcClientKEInternalContext *ctx =
649 (SilcClientKEInternalContext *)protocol->context;
650 SilcClient client = (SilcClient)ctx->client;
651 SilcSocketConnection sock = NULL;
652 SilcClientConnAuthInternalContext *proto_ctx;
654 SILC_LOG_DEBUG(("Start"));
656 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
657 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
658 /* Error occured during protocol */
659 SILC_LOG_DEBUG(("Error during KE protocol"));
660 silc_protocol_free(protocol);
661 silc_ske_free_key_material(ctx->keymat);
663 silc_ske_free(ctx->ske);
665 silc_free(ctx->dest_id);
666 ctx->sock->protocol = NULL;
667 silc_socket_free(ctx->sock);
669 /* Notify application of failure */
670 silc_schedule_task_add(client->schedule, ctx->sock->sock,
671 silc_client_connect_failure, ctx,
672 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
676 /* We now have the key material as the result of the key exchange
677 protocol. Take the key material into use. Free the raw key material
678 as soon as we've set them into use. */
679 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
680 ctx->ske->prop->cipher,
681 ctx->ske->prop->pkcs,
682 ctx->ske->prop->hash,
683 ctx->ske->prop->hmac,
684 ctx->ske->prop->group,
686 silc_ske_free_key_material(ctx->keymat);
688 /* Allocate internal context for the authentication protocol. This
689 is sent as context for the protocol. */
690 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
691 proto_ctx->client = (void *)client;
692 proto_ctx->sock = sock = ctx->sock;
693 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
694 proto_ctx->dest_id_type = ctx->dest_id_type;
695 proto_ctx->dest_id = ctx->dest_id;
697 /* Free old protocol as it is finished now */
698 silc_protocol_free(protocol);
700 silc_packet_context_free(ctx->packet);
703 sock->protocol = NULL;
705 /* Resolve the authentication method to be used in this connection. The
706 completion callback is called after the application has resolved
707 the authentication method. */
708 client->internal->ops->get_auth_method(client, sock->user_data,
711 silc_client_resolve_auth_method,
715 /* Authentication method resolving callback. Application calls this function
716 after we've called the client->internal->ops->get_auth_method
717 client operation to resolve the authentication method. We will continue
718 the executiong of the protocol in this function. */
720 void silc_client_resolve_auth_method(bool success,
721 SilcProtocolAuthMeth auth_meth,
722 const unsigned char *auth_data,
723 SilcUInt32 auth_data_len, void *context)
725 SilcClientConnAuthInternalContext *proto_ctx =
726 (SilcClientConnAuthInternalContext *)context;
727 SilcClient client = (SilcClient)proto_ctx->client;
730 auth_meth = SILC_AUTH_NONE;
732 proto_ctx->auth_meth = auth_meth;
734 if (success && auth_data && auth_data_len) {
736 /* Passphrase must be UTF-8 encoded, if it isn't encode it */
737 if (auth_meth == SILC_AUTH_PASSWORD &&
738 !silc_utf8_valid(auth_data, auth_data_len)) {
740 unsigned char *autf8 = NULL;
741 payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
743 autf8 = silc_calloc(payload_len, sizeof(*autf8));
744 auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
745 SILC_STRING_ASCII, autf8, payload_len);
749 proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
750 proto_ctx->auth_data_len = auth_data_len;
753 /* Allocate the authenteication protocol and execute it. */
754 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
755 &proto_ctx->sock->protocol, (void *)proto_ctx,
756 silc_client_connect_to_server_final);
758 /* Execute the protocol */
759 silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
762 /* Finalizes the connection to the remote SILC server. This is called
763 after authentication protocol has been completed. This send our
764 user information to the server to receive our client ID from
767 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
769 SilcProtocol protocol = (SilcProtocol)context;
770 SilcClientConnAuthInternalContext *ctx =
771 (SilcClientConnAuthInternalContext *)protocol->context;
772 SilcClient client = (SilcClient)ctx->client;
773 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
776 SILC_LOG_DEBUG(("Start"));
778 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
779 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
780 /* Error occured during protocol */
781 SILC_LOG_DEBUG(("Error during authentication protocol"));
785 if (conn->internal->params.detach_data) {
786 /* Send RESUME_CLIENT packet to the server, which is used to resume
787 old detached session back. */
789 SilcClientID *old_client_id;
790 unsigned char *old_id;
791 SilcUInt16 old_id_len;
793 if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len))
796 old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
797 if (!old_client_id) {
802 /* Generate authentication data that server will verify */
803 auth = silc_auth_public_key_auth_generate(client->public_key,
806 conn->internal->hash,
807 old_client_id, SILC_ID_CLIENT);
809 silc_free(old_client_id);
814 packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
815 silc_buffer_format(packet,
816 SILC_STR_UI_SHORT(old_id_len),
817 SILC_STR_UI_XNSTRING(old_id, old_id_len),
818 SILC_STR_UI_XNSTRING(auth->data, auth->len),
821 /* Send the packet */
822 silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
824 packet->data, packet->len, TRUE);
825 silc_buffer_free(packet);
826 silc_buffer_free(auth);
827 silc_free(old_client_id);
830 /* Send NEW_CLIENT packet to the server. We will become registered
831 to the SILC network after sending this packet and we will receive
832 client ID from the server. */
833 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
834 strlen(client->realname));
835 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
836 silc_buffer_format(packet,
837 SILC_STR_UI_SHORT(strlen(client->username)),
838 SILC_STR_UI_XNSTRING(client->username,
839 strlen(client->username)),
840 SILC_STR_UI_SHORT(strlen(client->realname)),
841 SILC_STR_UI_XNSTRING(client->realname,
842 strlen(client->realname)),
845 /* Send the packet */
846 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
848 packet->data, packet->len, TRUE);
849 silc_buffer_free(packet);
852 /* Save remote ID. */
853 conn->remote_id = ctx->dest_id;
854 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
855 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
857 /* Register re-key timeout */
858 conn->internal->rekey->timeout = client->internal->params->rekey_secs;
859 conn->internal->rekey->context = (void *)client;
860 silc_schedule_task_add(client->schedule, conn->sock->sock,
861 silc_client_rekey_callback,
862 (void *)conn->sock, conn->internal->rekey->timeout, 0,
863 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
865 silc_protocol_free(protocol);
866 silc_free(ctx->auth_data);
868 silc_ske_free(ctx->ske);
869 silc_socket_free(ctx->sock);
871 conn->sock->protocol = NULL;
875 silc_protocol_free(protocol);
876 silc_free(ctx->auth_data);
877 silc_free(ctx->dest_id);
879 silc_ske_free(ctx->ske);
880 conn->sock->protocol = NULL;
881 silc_socket_free(ctx->sock);
883 /* Notify application of failure */
884 silc_schedule_task_add(client->schedule, ctx->sock->sock,
885 silc_client_connect_failure_auth, ctx,
886 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
889 /* Internal routine that sends packet or marks packet to be sent. This
890 is used directly only in special cases. Normal cases should use
891 silc_server_packet_send. Returns < 0 on error. */
893 int silc_client_packet_send_real(SilcClient client,
894 SilcSocketConnection sock,
899 /* If rekey protocol is active we must assure that all packets are
900 sent through packet queue. */
901 if (SILC_CLIENT_IS_REKEY(sock))
904 /* If outbound data is already pending do not force send */
905 if (SILC_IS_OUTBUF_PENDING(sock))
908 /* Send the packet */
909 ret = silc_packet_send(sock, force_send);
913 /* Mark that there is some outgoing data available for this connection.
914 This call sets the connection both for input and output (the input
915 is set always and this call keeps the input setting, actually).
916 Actual data sending is performed by silc_client_packet_process. */
917 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
919 /* Mark to socket that data is pending in outgoing buffer. This flag
920 is needed if new data is added to the buffer before the earlier
921 put data is sent to the network. */
922 SILC_SET_OUTBUF_PENDING(sock);
927 /* Packet processing callback. This is used to send and receive packets
928 from network. This is generic task. */
930 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
932 SilcClient client = (SilcClient)context;
933 SilcSocketConnection sock = NULL;
934 SilcClientConnection conn;
937 SILC_LOG_DEBUG(("Processing packet"));
939 SILC_CLIENT_GET_SOCK(client, fd, sock);
943 conn = (SilcClientConnection)sock->user_data;
946 if (type == SILC_TASK_WRITE) {
947 /* Do not send data to disconnected connection */
948 if (SILC_IS_DISCONNECTED(sock))
951 ret = silc_packet_send(sock, TRUE);
953 /* If returned -2 could not write to connection now, will do
962 /* The packet has been sent and now it is time to set the connection
963 back to only for input. When there is again some outgoing data
964 available for this connection it will be set for output as well.
965 This call clears the output setting and sets it only for input. */
966 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
967 SILC_UNSET_OUTBUF_PENDING(sock);
969 silc_buffer_clear(sock->outbuf);
973 /* Packet receiving */
974 if (type == SILC_TASK_READ) {
975 /* Read data from network */
976 ret = silc_packet_receive(sock);
982 SILC_LOG_DEBUG(("Read EOF"));
984 /* If connection is disconnecting already we will finally
985 close the connection */
986 if (SILC_IS_DISCONNECTING(sock)) {
987 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
988 client->internal->ops->disconnected(client, conn, 0, NULL);
989 silc_client_close_connection_real(client, sock, conn);
993 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
994 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
995 client->internal->ops->disconnected(client, conn, 0, NULL);
996 silc_client_close_connection_real(client, sock, conn);
1000 /* Process the packet. This will call the parser that will then
1001 decrypt and parse the packet. */
1002 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
1003 silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
1004 conn->internal->hmac_receive,
1005 conn->internal->psn_receive,
1006 silc_client_packet_parse, client);
1008 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
1009 silc_client_packet_parse, client);
1013 /* Parser callback called by silc_packet_receive_process. Thie merely
1014 registers timeout that will handle the actual parsing when appropriate. */
1016 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
1019 SilcClient client = (SilcClient)context;
1020 SilcSocketConnection sock = parser_context->sock;
1021 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1022 SilcPacketContext *packet = parser_context->packet;
1025 if (conn && conn->internal->hmac_receive && conn->sock == sock)
1026 conn->internal->psn_receive = parser_context->packet->sequence + 1;
1028 /* Parse the packet immediately */
1029 if (parser_context->normal)
1030 ret = silc_packet_parse(packet, conn->internal->receive_key);
1032 ret = silc_packet_parse_special(packet, conn->internal->receive_key);
1034 if (ret == SILC_PACKET_NONE) {
1035 silc_packet_context_free(packet);
1036 silc_free(parser_context);
1040 /* If protocol for this connection is key exchange or rekey then we'll
1041 process all packets synchronously, since there might be packets in
1042 queue that we are not able to decrypt without first processing the
1043 packets before them. */
1044 if ((ret == SILC_PACKET_REKEY || ret == SILC_PACKET_REKEY_DONE) ||
1045 (sock->protocol && sock->protocol->protocol &&
1046 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1047 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY))) {
1049 /* Parse the incoming packet type */
1050 silc_client_packet_parse_type(client, sock, packet);
1051 silc_packet_context_free(packet);
1052 silc_free(parser_context);
1054 /* Reprocess the buffer since we'll return FALSE. This is because
1055 the `conn->internal->receive_key' might have become valid by processing
1056 the previous packet */
1057 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
1058 silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
1059 conn->internal->hmac_receive,
1060 conn->internal->psn_receive,
1061 silc_client_packet_parse, client);
1063 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
1064 silc_client_packet_parse, client);
1069 /* Parse the incoming packet type */
1070 silc_client_packet_parse_type(client, sock, packet);
1071 silc_packet_context_free(packet);
1072 silc_free(parser_context);
1076 /* Parses the packet type and calls what ever routines the packet type
1077 requires. This is done for all incoming packets. */
1079 void silc_client_packet_parse_type(SilcClient client,
1080 SilcSocketConnection sock,
1081 SilcPacketContext *packet)
1083 SilcBuffer buffer = packet->buffer;
1084 SilcPacketType type = packet->type;
1086 SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(type)));
1088 /* Parse the packet type */
1091 case SILC_PACKET_DISCONNECT:
1092 silc_client_disconnected_by_server(client, sock, buffer);
1095 case SILC_PACKET_SUCCESS:
1097 * Success received for something. For now we can have only
1098 * one protocol for connection executing at once hence this
1099 * success message is for whatever protocol is executing currently.
1102 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1105 case SILC_PACKET_FAILURE:
1107 * Failure received for some protocol. Set the protocol state to
1108 * error and call the protocol callback. This fill cause error on
1109 * protocol and it will call the final callback.
1111 silc_client_process_failure(client, sock, packet);
1114 case SILC_PACKET_REJECT:
1117 case SILC_PACKET_NOTIFY:
1119 * Received notify message
1121 silc_client_notify_by_server(client, sock, packet);
1124 case SILC_PACKET_ERROR:
1126 * Received error message
1128 silc_client_error_by_server(client, sock, buffer);
1131 case SILC_PACKET_CHANNEL_MESSAGE:
1133 * Received message to (from, actually) a channel
1135 silc_client_channel_message(client, sock, packet);
1138 case SILC_PACKET_CHANNEL_KEY:
1140 * Received key for a channel. By receiving this key the client will be
1141 * able to talk to the channel it has just joined. This can also be
1142 * a new key for existing channel as keys expire peridiocally.
1144 silc_client_receive_channel_key(client, sock, buffer);
1147 case SILC_PACKET_PRIVATE_MESSAGE:
1149 * Received private message
1151 silc_client_private_message(client, sock, packet);
1154 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
1156 * Received private message key
1160 case SILC_PACKET_COMMAND:
1162 * Received command packet, a special case since normally client
1163 * does not receive commands.
1165 silc_client_command_process(client, sock, packet);
1168 case SILC_PACKET_COMMAND_REPLY:
1170 * Recived reply for a command
1172 silc_client_command_reply_process(client, sock, packet);
1175 case SILC_PACKET_KEY_EXCHANGE:
1176 if (sock->protocol && sock->protocol->protocol &&
1177 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1178 SilcClientKEInternalContext *proto_ctx =
1179 (SilcClientKEInternalContext *)sock->protocol->context;
1181 proto_ctx->packet = silc_packet_context_dup(packet);
1182 proto_ctx->dest_id_type = packet->src_id_type;
1183 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1184 packet->src_id_type);
1185 if (!proto_ctx->dest_id)
1188 /* Let the protocol handle the packet */
1189 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1191 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
1192 "protocol active, packet dropped."));
1196 case SILC_PACKET_KEY_EXCHANGE_1:
1197 if (sock->protocol && sock->protocol->protocol &&
1198 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1199 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1201 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1202 SilcClientRekeyInternalContext *proto_ctx =
1203 (SilcClientRekeyInternalContext *)sock->protocol->context;
1205 if (proto_ctx->packet)
1206 silc_packet_context_free(proto_ctx->packet);
1208 proto_ctx->packet = silc_packet_context_dup(packet);
1210 /* Let the protocol handle the packet */
1211 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1213 SilcClientKEInternalContext *proto_ctx =
1214 (SilcClientKEInternalContext *)sock->protocol->context;
1216 if (proto_ctx->packet)
1217 silc_packet_context_free(proto_ctx->packet);
1219 proto_ctx->packet = silc_packet_context_dup(packet);
1220 proto_ctx->dest_id_type = packet->src_id_type;
1221 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1222 packet->src_id_type);
1223 if (!proto_ctx->dest_id)
1226 /* Let the protocol handle the packet */
1227 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1230 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
1231 "protocol active, packet dropped."));
1235 case SILC_PACKET_KEY_EXCHANGE_2:
1236 if (sock->protocol && sock->protocol->protocol &&
1237 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1238 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1240 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1241 SilcClientRekeyInternalContext *proto_ctx =
1242 (SilcClientRekeyInternalContext *)sock->protocol->context;
1244 if (proto_ctx->packet)
1245 silc_packet_context_free(proto_ctx->packet);
1247 proto_ctx->packet = silc_packet_context_dup(packet);
1249 /* Let the protocol handle the packet */
1250 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1252 SilcClientKEInternalContext *proto_ctx =
1253 (SilcClientKEInternalContext *)sock->protocol->context;
1255 if (proto_ctx->packet)
1256 silc_packet_context_free(proto_ctx->packet);
1257 if (proto_ctx->dest_id)
1258 silc_free(proto_ctx->dest_id);
1259 proto_ctx->packet = silc_packet_context_dup(packet);
1260 proto_ctx->dest_id_type = packet->src_id_type;
1261 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1262 packet->src_id_type);
1263 if (!proto_ctx->dest_id)
1266 /* Let the protocol handle the packet */
1267 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1270 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
1271 "protocol active, packet dropped."));
1275 case SILC_PACKET_NEW_ID:
1278 * Received new ID from server. This packet is received at
1279 * the connection to the server. New ID is also received when
1280 * user changes nickname but in that case the new ID is received
1281 * as command reply and not as this packet type.
1285 idp = silc_id_payload_parse(buffer->data, buffer->len);
1288 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
1291 silc_client_receive_new_id(client, sock, idp);
1292 silc_id_payload_free(idp);
1296 case SILC_PACKET_HEARTBEAT:
1298 * Received heartbeat packet
1300 SILC_LOG_DEBUG(("Heartbeat packet"));
1303 case SILC_PACKET_KEY_AGREEMENT:
1305 * Received key agreement packet
1307 SILC_LOG_DEBUG(("Key agreement packet"));
1308 silc_client_key_agreement(client, sock, packet);
1311 case SILC_PACKET_REKEY:
1312 SILC_LOG_DEBUG(("Re-key packet"));
1313 /* We ignore this for now */
1316 case SILC_PACKET_REKEY_DONE:
1317 SILC_LOG_DEBUG(("Re-key done packet"));
1319 if (sock->protocol && sock->protocol->protocol &&
1320 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1322 SilcClientRekeyInternalContext *proto_ctx =
1323 (SilcClientRekeyInternalContext *)sock->protocol->context;
1325 if (proto_ctx->packet)
1326 silc_packet_context_free(proto_ctx->packet);
1328 proto_ctx->packet = silc_packet_context_dup(packet);
1330 /* Let the protocol handle the packet */
1331 if (proto_ctx->responder == FALSE)
1332 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1334 /* Let the protocol handle the packet */
1335 silc_protocol_execute(sock->protocol, client->schedule,
1338 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1339 "protocol active, packet dropped."));
1343 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
1345 * Reveived reply to our connection authentication method request
1346 * packet. This is used to resolve the authentication method for the
1347 * current session from the server if the client does not know it.
1349 silc_client_connection_auth_request(client, sock, packet);
1352 case SILC_PACKET_FTP:
1353 /* Received file transfer packet. */
1354 silc_client_ftp(client, sock, packet);
1358 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1363 /* Sends packet. This doesn't actually send the packet instead it assembles
1364 it and marks it to be sent. However, if force_send is TRUE the packet
1365 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1366 will be derived from sock argument. Otherwise the valid arguments sent
1369 void silc_client_packet_send(SilcClient client,
1370 SilcSocketConnection sock,
1371 SilcPacketType type,
1373 SilcIdType dst_id_type,
1376 unsigned char *data,
1377 SilcUInt32 data_len,
1380 SilcPacketContext packetdata;
1381 const SilcBufferStruct packet;
1383 SilcUInt32 sequence = 0;
1388 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1390 /* Get data used in the packet sending, keys and stuff */
1391 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1392 if (!cipher && ((SilcClientConnection)sock->user_data)->internal->send_key)
1393 cipher = ((SilcClientConnection)sock->user_data)->internal->send_key;
1395 if (!hmac && ((SilcClientConnection)sock->user_data)->internal->hmac_send)
1396 hmac = ((SilcClientConnection)sock->user_data)->internal->hmac_send;
1398 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1399 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1400 dst_id_type = SILC_ID_SERVER;
1404 sequence = ((SilcClientConnection)sock->user_data)->internal->psn_send++;
1407 block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
1409 /* Set the packet context pointers */
1410 packetdata.flags = 0;
1411 packetdata.type = type;
1412 if (sock->user_data &&
1413 ((SilcClientConnection)sock->user_data)->local_id_data) {
1414 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1415 packetdata.src_id_len =
1416 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1419 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1420 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1422 packetdata.src_id_type = SILC_ID_CLIENT;
1424 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1425 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1426 packetdata.dst_id_type = dst_id_type;
1428 packetdata.dst_id = NULL;
1429 packetdata.dst_id_len = 0;
1430 packetdata.dst_id_type = SILC_ID_NONE;
1432 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1433 packetdata.src_id_len +
1434 packetdata.dst_id_len));
1435 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1436 packetdata.src_id_len + packetdata.dst_id_len;
1437 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
1439 /* Create the outgoing packet */
1440 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
1441 data, data_len, (const SilcBuffer)&packet)) {
1442 SILC_LOG_ERROR(("Error assembling packet"));
1446 /* Encrypt the packet */
1448 silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet,
1451 SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, packet.len),
1452 packet.data, packet.len);
1454 /* Now actually send the packet */
1455 silc_client_packet_send_real(client, sock, force_send);
1458 void silc_client_packet_queue_purge(SilcClient client,
1459 SilcSocketConnection sock)
1461 if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
1462 (SILC_IS_DISCONNECTED(sock) == FALSE)) {
1463 silc_packet_send(sock, TRUE);
1464 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
1465 SILC_UNSET_OUTBUF_PENDING(sock);
1466 silc_buffer_clear(sock->outbuf);
1470 /* Closes connection to remote end. Free's all allocated data except
1471 for some information such as nickname etc. that are valid at all time.
1472 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1473 provided it will be checked whether the sock and `conn->sock' are the
1474 same (they can be different, ie. a socket can use `conn' as its
1475 connection but `conn->sock' might be actually a different connection
1476 than the `sock'). */
1478 void silc_client_close_connection_real(SilcClient client,
1479 SilcSocketConnection sock,
1480 SilcClientConnection conn)
1484 SILC_LOG_DEBUG(("Start"));
1489 if (!sock || (sock && conn->sock == sock))
1494 /* We won't listen for this connection anymore */
1495 silc_schedule_unset_listen_fd(client->schedule, sock->sock);
1497 /* Unregister all tasks */
1498 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1500 /* Close the actual connection */
1501 silc_net_close_connection(sock->sock);
1503 /* Cancel any active protocol */
1504 if (sock->protocol) {
1505 if (sock->protocol->protocol->type ==
1506 SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1507 sock->protocol->protocol->type ==
1508 SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1509 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1510 silc_protocol_execute_final(sock->protocol, client->schedule);
1511 /* The application will recall this function with these protocols
1512 (the ops->connected client operation). */
1515 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1516 silc_protocol_execute_final(sock->protocol, client->schedule);
1517 sock->protocol = NULL;
1521 /* Free everything */
1522 if (del && sock->user_data)
1523 silc_client_del_connection(client, conn);
1525 silc_socket_free(sock);
1528 /* Closes the connection to the remote end */
1530 void silc_client_close_connection(SilcClient client,
1531 SilcClientConnection conn)
1533 silc_client_close_connection_real(client, NULL, conn);
1536 /* Called when we receive disconnection packet from server. This
1537 closes our end properly and displays the reason of the disconnection
1540 SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
1542 SilcClient client = (SilcClient)context;
1543 SilcSocketConnection sock;
1545 SILC_CLIENT_GET_SOCK(client, fd, sock);
1549 silc_client_close_connection_real(client, sock, sock->user_data);
1552 /* Called when we receive disconnection packet from server. This
1553 closes our end properly and displays the reason of the disconnection
1556 void silc_client_disconnected_by_server(SilcClient client,
1557 SilcSocketConnection sock,
1560 SilcClientConnection conn;
1562 char *message = NULL;
1564 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1566 if (packet->len < 1)
1569 status = (SilcStatus)packet->data[0];
1571 if (packet->len > 1 &&
1572 silc_utf8_valid(packet->data + 1, packet->len - 1))
1573 message = silc_memdup(packet->data + 1, packet->len - 1);
1575 conn = (SilcClientConnection)sock->user_data;
1576 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
1577 client->internal->ops->disconnected(client, conn, status, message);
1581 SILC_SET_DISCONNECTED(sock);
1583 /* Close connection through scheduler. */
1584 silc_schedule_task_add(client->schedule, sock->sock,
1585 silc_client_disconnected_by_server_later,
1586 client, 0, 1, SILC_TASK_TIMEOUT,
1587 SILC_TASK_PRI_NORMAL);
1590 /* Received error message from server. Display it on the screen.
1591 We don't take any action what so ever of the error message. */
1593 void silc_client_error_by_server(SilcClient client,
1594 SilcSocketConnection sock,
1599 msg = silc_memdup(message->data, message->len);
1600 client->internal->ops->say(client, sock->user_data,
1601 SILC_CLIENT_MESSAGE_AUDIT, msg);
1605 /* Auto-nicking callback to send NICK command to server. */
1607 SILC_TASK_CALLBACK(silc_client_send_auto_nick)
1609 SilcClientConnection conn = (SilcClientConnection)context;
1610 SilcClient client = conn->client;
1612 silc_client_command_send(client, conn, SILC_COMMAND_NICK,
1613 ++conn->cmd_ident, 1, 1,
1614 client->nickname, strlen(client->nickname));
1617 /* Client session resuming callback. If the session was resumed
1618 this callback is called after the resuming is completed. This
1619 will call the `connect' client operation to the application
1620 since it has not been called yet. */
1622 static void silc_client_resume_session_cb(SilcClient client,
1623 SilcClientConnection conn,
1629 /* Notify application that connection is created to server */
1630 client->internal->ops->connected(client, conn, success ?
1631 SILC_CLIENT_CONN_SUCCESS_RESUME :
1632 SILC_CLIENT_CONN_ERROR);
1635 /* Issue INFO command to fetch the real server name and server
1636 information and other stuff. */
1637 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1638 silc_client_command_reply_info_i, 0,
1640 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1641 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1642 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1643 silc_buffer_free(sidp);
1647 /* Processes the received new Client ID from server. Old Client ID is
1648 deleted from cache and new one is added. */
1650 void silc_client_receive_new_id(SilcClient client,
1651 SilcSocketConnection sock,
1654 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1655 int connecting = FALSE;
1656 SilcClientID *client_id = silc_id_payload_get_id(idp);
1658 if (!conn->local_entry)
1661 /* Delete old ID from ID cache */
1662 if (conn->local_id) {
1663 /* Check whether they are different */
1664 if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1665 silc_free(client_id);
1669 silc_idcache_del_by_context(conn->internal->client_cache,
1671 silc_free(conn->local_id);
1674 /* Save the new ID */
1676 if (conn->local_id_data)
1677 silc_free(conn->local_id_data);
1679 conn->local_id = client_id;
1680 conn->local_id_data = silc_id_payload_get_data(idp);
1681 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1683 if (!conn->local_entry)
1684 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1686 conn->local_entry->nickname = conn->nickname;
1687 if (!conn->local_entry->username)
1688 conn->local_entry->username = strdup(client->username);
1689 if (!conn->local_entry->server)
1690 conn->local_entry->server = strdup(conn->remote_host);
1691 conn->local_entry->id = conn->local_id;
1692 conn->local_entry->valid = TRUE;
1693 if (!conn->local_entry->channels)
1694 conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
1699 /* Put it to the ID cache */
1700 silc_idcache_add(conn->internal->client_cache,
1701 strdup(conn->nickname), conn->local_id,
1702 (void *)conn->local_entry, 0, NULL);
1707 /* Issue IDENTIFY command for itself to get resolved hostname
1708 correctly from server. */
1709 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
1710 silc_client_command_reply_identify_i, 0,
1712 sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
1713 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1714 conn->cmd_ident, 1, 5, sidp->data, sidp->len);
1715 silc_buffer_free(sidp);
1717 if (!conn->internal->params.detach_data) {
1718 /* Send NICK command if the nickname was set by the application (and is
1719 not same as the username). Send this with little timeout. */
1720 if (client->nickname && strcmp(client->nickname, client->username))
1721 silc_schedule_task_add(client->schedule, 0,
1722 silc_client_send_auto_nick, conn,
1723 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1725 /* Notify application of successful connection. We do it here now that
1726 we've received the Client ID and are allowed to send traffic. */
1727 client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_SUCCESS);
1729 /* Issue INFO command to fetch the real server name and server
1730 information and other stuff. */
1731 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1732 silc_client_command_reply_info_i, 0,
1734 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1735 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1736 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1737 silc_buffer_free(sidp);
1739 /* We are resuming session. Start resolving informations from the
1740 server we need to set the client libary in the state before
1741 detaching the session. The connect client operation is called
1742 after this is successfully completed */
1743 silc_client_resume_session(client, conn, silc_client_resume_session_cb,
1749 /* Removes a client entry from all channels it has joined. */
1751 void silc_client_remove_from_channels(SilcClient client,
1752 SilcClientConnection conn,
1753 SilcClientEntry client_entry)
1755 SilcHashTableList htl;
1756 SilcChannelUser chu;
1758 silc_hash_table_list(client_entry->channels, &htl);
1759 while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1760 silc_hash_table_del(chu->client->channels, chu->channel);
1761 silc_hash_table_del(chu->channel->user_list, chu->client);
1765 silc_hash_table_list_reset(&htl);
1768 /* Replaces `old' client entries from all channels to `new' client entry.
1769 This can be called for example when nickname changes and old ID entry
1770 is replaced from ID cache with the new one. If the old ID entry is only
1771 updated, then this fucntion needs not to be called. */
1773 void silc_client_replace_from_channels(SilcClient client,
1774 SilcClientConnection conn,
1775 SilcClientEntry old,
1776 SilcClientEntry new)
1778 SilcHashTableList htl;
1779 SilcChannelUser chu;
1781 silc_hash_table_list(old->channels, &htl);
1782 while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1783 /* Replace client entry */
1784 silc_hash_table_del(chu->client->channels, chu->channel);
1785 silc_hash_table_del(chu->channel->user_list, chu->client);
1788 silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1789 silc_hash_table_add(chu->client->channels, chu->channel, chu);
1791 silc_hash_table_list_reset(&htl);
1794 /* Registers failure timeout to process the received failure packet
1797 void silc_client_process_failure(SilcClient client,
1798 SilcSocketConnection sock,
1799 SilcPacketContext *packet)
1801 SilcUInt32 failure = 0;
1803 if (sock->protocol) {
1804 if (packet->buffer->len >= 4)
1805 SILC_GET32_MSB(failure, packet->buffer->data);
1807 /* Notify application */
1808 client->internal->ops->failure(client, sock->user_data, sock->protocol,
1813 /* A timeout callback for the re-key. We will be the initiator of the
1816 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1818 SilcSocketConnection sock = (SilcSocketConnection)context;
1819 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1820 SilcClient client = (SilcClient)conn->internal->rekey->context;
1821 SilcProtocol protocol;
1822 SilcClientRekeyInternalContext *proto_ctx;
1824 SILC_LOG_DEBUG(("Start"));
1826 /* Allocate internal protocol context. This is sent as context
1828 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1829 proto_ctx->client = (void *)client;
1830 proto_ctx->sock = silc_socket_dup(sock);
1831 proto_ctx->responder = FALSE;
1832 proto_ctx->pfs = conn->internal->rekey->pfs;
1834 /* Perform rekey protocol. Will call the final callback after the
1835 protocol is over. */
1836 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1837 &protocol, proto_ctx, silc_client_rekey_final);
1838 sock->protocol = protocol;
1840 /* Run the protocol */
1841 silc_protocol_execute(protocol, client->schedule, 0, 0);
1843 /* Re-register re-key timeout */
1844 silc_schedule_task_add(client->schedule, sock->sock,
1845 silc_client_rekey_callback,
1846 context, conn->internal->rekey->timeout, 0,
1847 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1850 /* The final callback for the REKEY protocol. This will actually take the
1851 new key material into use. */
1853 SILC_TASK_CALLBACK(silc_client_rekey_final)
1855 SilcProtocol protocol = (SilcProtocol)context;
1856 SilcClientRekeyInternalContext *ctx =
1857 (SilcClientRekeyInternalContext *)protocol->context;
1858 SilcClient client = (SilcClient)ctx->client;
1859 SilcSocketConnection sock = ctx->sock;
1861 SILC_LOG_DEBUG(("Start"));
1863 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1864 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1865 /* Error occured during protocol */
1866 silc_protocol_cancel(protocol, client->schedule);
1867 silc_protocol_free(protocol);
1868 sock->protocol = NULL;
1870 silc_packet_context_free(ctx->packet);
1872 silc_ske_free(ctx->ske);
1873 silc_socket_free(ctx->sock);
1878 /* Purge the outgoing data queue to assure that all rekey packets really
1879 go to the network before we quit the protocol. */
1880 silc_client_packet_queue_purge(client, sock);
1883 silc_protocol_free(protocol);
1884 sock->protocol = NULL;
1886 silc_packet_context_free(ctx->packet);
1888 silc_ske_free(ctx->ske);
1889 silc_socket_free(ctx->sock);
1893 /* Processes incoming connection authentication method request packet.
1894 It is a reply to our previously sent request. The packet can be used
1895 to resolve the authentication method for the current session if the
1896 client does not know it beforehand. */
1898 void silc_client_connection_auth_request(SilcClient client,
1899 SilcSocketConnection sock,
1900 SilcPacketContext *packet)
1902 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1903 SilcUInt16 conn_type, auth_meth;
1906 /* If we haven't send our request then ignore this one. */
1907 if (!conn->internal->connauth)
1910 /* Parse the payload */
1911 ret = silc_buffer_unformat(packet->buffer,
1912 SILC_STR_UI_SHORT(&conn_type),
1913 SILC_STR_UI_SHORT(&auth_meth),
1916 auth_meth = SILC_AUTH_NONE;
1918 /* Call the request callback to notify application for received
1919 authentication method information. */
1920 if (conn->internal->connauth->callback)
1921 (*conn->internal->connauth->callback)(client, conn, auth_meth,
1922 conn->internal->connauth->context);
1924 silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
1926 silc_free(conn->internal->connauth);
1927 conn->internal->connauth = NULL;
1930 /* Timeout task callback called if the server does not reply to our
1931 connection authentication method request in the specified time interval. */
1933 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1935 SilcClientConnection conn = (SilcClientConnection)context;
1936 SilcClient client = conn->client;
1938 if (!conn->internal->connauth)
1941 /* Call the request callback to notify application */
1942 if (conn->internal->connauth->callback)
1943 (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
1944 conn->internal->connauth->context);
1946 silc_free(conn->internal->connauth);
1947 conn->internal->connauth = NULL;
1950 /* This function can be used to request the current authentication method
1951 from the server. This may be called when connecting to the server
1952 and the client library requests the authentication data from the
1953 application. If the application does not know the current authentication
1954 method it can request it from the server using this function.
1955 The `callback' with `context' will be called after the server has
1956 replied back with the current authentication method. */
1959 silc_client_request_authentication_method(SilcClient client,
1960 SilcClientConnection conn,
1961 SilcConnectionAuthRequest callback,
1964 SilcClientConnAuthRequest connauth;
1967 assert(client && conn);
1968 connauth = silc_calloc(1, sizeof(*connauth));
1969 connauth->callback = callback;
1970 connauth->context = context;
1972 if (conn->internal->connauth)
1973 silc_free(conn->internal->connauth);
1975 conn->internal->connauth = connauth;
1977 /* Assemble the request packet and send it to the server */
1978 packet = silc_buffer_alloc(4);
1979 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1980 silc_buffer_format(packet,
1981 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1982 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1984 silc_client_packet_send(client, conn->sock,
1985 SILC_PACKET_CONNECTION_AUTH_REQUEST,
1986 NULL, 0, NULL, NULL,
1987 packet->data, packet->len, FALSE);
1988 silc_buffer_free(packet);
1990 /* Register a timeout in case server does not reply anything back. */
1992 silc_schedule_task_add(client->schedule, conn->sock->sock,
1993 silc_client_request_authentication_method_timeout,
1995 client->internal->params->connauth_request_secs, 0,
1996 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);