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 /* Packet sending routine for application. This is the only routine that
1459 is provided for application to send SILC packets. */
1461 bool silc_client_send_packet(SilcClient client,
1462 SilcClientConnection conn,
1463 SilcPacketType type,
1464 const unsigned char *data,
1465 SilcUInt32 data_len)
1472 silc_client_packet_send(client, conn->sock, type, NULL, 0, NULL, NULL,
1473 (unsigned char *)data, data_len, TRUE);
1477 void silc_client_packet_queue_purge(SilcClient client,
1478 SilcSocketConnection sock)
1480 if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
1481 (SILC_IS_DISCONNECTED(sock) == FALSE)) {
1482 silc_packet_send(sock, TRUE);
1483 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
1484 SILC_UNSET_OUTBUF_PENDING(sock);
1485 silc_buffer_clear(sock->outbuf);
1489 /* Closes connection to remote end. Free's all allocated data except
1490 for some information such as nickname etc. that are valid at all time.
1491 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1492 provided it will be checked whether the sock and `conn->sock' are the
1493 same (they can be different, ie. a socket can use `conn' as its
1494 connection but `conn->sock' might be actually a different connection
1495 than the `sock'). */
1497 void silc_client_close_connection_real(SilcClient client,
1498 SilcSocketConnection sock,
1499 SilcClientConnection conn)
1503 SILC_LOG_DEBUG(("Start"));
1508 if (!sock || (sock && conn->sock == sock))
1513 /* We won't listen for this connection anymore */
1514 silc_schedule_unset_listen_fd(client->schedule, sock->sock);
1516 /* Unregister all tasks */
1517 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1519 /* Close the actual connection */
1520 silc_net_close_connection(sock->sock);
1522 /* Cancel any active protocol */
1523 if (sock->protocol) {
1524 if (sock->protocol->protocol->type ==
1525 SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1526 sock->protocol->protocol->type ==
1527 SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1528 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1529 silc_protocol_execute_final(sock->protocol, client->schedule);
1530 /* The application will recall this function with these protocols
1531 (the ops->connected client operation). */
1534 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1535 silc_protocol_execute_final(sock->protocol, client->schedule);
1536 sock->protocol = NULL;
1540 /* Free everything */
1541 if (del && sock->user_data)
1542 silc_client_del_connection(client, conn);
1544 silc_socket_free(sock);
1547 /* Closes the connection to the remote end */
1549 void silc_client_close_connection(SilcClient client,
1550 SilcClientConnection conn)
1552 silc_client_close_connection_real(client, NULL, conn);
1555 /* Called when we receive disconnection packet from server. This
1556 closes our end properly and displays the reason of the disconnection
1559 SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
1561 SilcClient client = (SilcClient)context;
1562 SilcSocketConnection sock;
1564 SILC_CLIENT_GET_SOCK(client, fd, sock);
1568 silc_client_close_connection_real(client, sock, sock->user_data);
1571 /* Called when we receive disconnection packet from server. This
1572 closes our end properly and displays the reason of the disconnection
1575 void silc_client_disconnected_by_server(SilcClient client,
1576 SilcSocketConnection sock,
1579 SilcClientConnection conn;
1581 char *message = NULL;
1583 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1585 if (packet->len < 1)
1588 status = (SilcStatus)packet->data[0];
1590 if (packet->len > 1 &&
1591 silc_utf8_valid(packet->data + 1, packet->len - 1))
1592 message = silc_memdup(packet->data + 1, packet->len - 1);
1594 conn = (SilcClientConnection)sock->user_data;
1595 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
1596 client->internal->ops->disconnected(client, conn, status, message);
1600 SILC_SET_DISCONNECTED(sock);
1602 /* Close connection through scheduler. */
1603 silc_schedule_task_add(client->schedule, sock->sock,
1604 silc_client_disconnected_by_server_later,
1605 client, 0, 1, SILC_TASK_TIMEOUT,
1606 SILC_TASK_PRI_NORMAL);
1609 /* Received error message from server. Display it on the screen.
1610 We don't take any action what so ever of the error message. */
1612 void silc_client_error_by_server(SilcClient client,
1613 SilcSocketConnection sock,
1618 msg = silc_memdup(message->data, message->len);
1619 client->internal->ops->say(client, sock->user_data,
1620 SILC_CLIENT_MESSAGE_AUDIT, msg);
1624 /* Auto-nicking callback to send NICK command to server. */
1626 SILC_TASK_CALLBACK(silc_client_send_auto_nick)
1628 SilcClientConnection conn = (SilcClientConnection)context;
1629 SilcClient client = conn->client;
1631 silc_client_command_send(client, conn, SILC_COMMAND_NICK,
1632 ++conn->cmd_ident, 1, 1,
1633 client->nickname, strlen(client->nickname));
1636 /* Client session resuming callback. If the session was resumed
1637 this callback is called after the resuming is completed. This
1638 will call the `connect' client operation to the application
1639 since it has not been called yet. */
1641 static void silc_client_resume_session_cb(SilcClient client,
1642 SilcClientConnection conn,
1648 /* Notify application that connection is created to server */
1649 client->internal->ops->connected(client, conn, success ?
1650 SILC_CLIENT_CONN_SUCCESS_RESUME :
1651 SILC_CLIENT_CONN_ERROR);
1654 /* Issue INFO command to fetch the real server name and server
1655 information and other stuff. */
1656 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1657 silc_client_command_reply_info_i, 0,
1659 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1660 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1661 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1662 silc_buffer_free(sidp);
1666 /* Processes the received new Client ID from server. Old Client ID is
1667 deleted from cache and new one is added. */
1669 void silc_client_receive_new_id(SilcClient client,
1670 SilcSocketConnection sock,
1673 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1674 int connecting = FALSE;
1675 SilcClientID *client_id = silc_id_payload_get_id(idp);
1677 if (!conn->local_entry)
1680 /* Delete old ID from ID cache */
1681 if (conn->local_id) {
1682 /* Check whether they are different */
1683 if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1684 silc_free(client_id);
1688 silc_idcache_del_by_context(conn->internal->client_cache,
1690 silc_free(conn->local_id);
1693 /* Save the new ID */
1695 if (conn->local_id_data)
1696 silc_free(conn->local_id_data);
1698 conn->local_id = client_id;
1699 conn->local_id_data = silc_id_payload_get_data(idp);
1700 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1702 if (!conn->local_entry)
1703 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1705 conn->local_entry->nickname = conn->nickname;
1706 if (!conn->local_entry->username)
1707 conn->local_entry->username = strdup(client->username);
1708 if (!conn->local_entry->server)
1709 conn->local_entry->server = strdup(conn->remote_host);
1710 conn->local_entry->id = conn->local_id;
1711 conn->local_entry->valid = TRUE;
1712 if (!conn->local_entry->channels)
1713 conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
1718 /* Put it to the ID cache */
1719 silc_idcache_add(conn->internal->client_cache,
1720 strdup(conn->nickname), conn->local_id,
1721 (void *)conn->local_entry, 0, NULL);
1726 /* Issue IDENTIFY command for itself to get resolved hostname
1727 correctly from server. */
1728 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
1729 silc_client_command_reply_identify_i, 0,
1731 sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
1732 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1733 conn->cmd_ident, 1, 5, sidp->data, sidp->len);
1734 silc_buffer_free(sidp);
1736 if (!conn->internal->params.detach_data) {
1737 /* Send NICK command if the nickname was set by the application (and is
1738 not same as the username). Send this with little timeout. */
1739 if (client->nickname && strcmp(client->nickname, client->username))
1740 silc_schedule_task_add(client->schedule, 0,
1741 silc_client_send_auto_nick, conn,
1742 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1744 /* Notify application of successful connection. We do it here now that
1745 we've received the Client ID and are allowed to send traffic. */
1746 client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_SUCCESS);
1748 /* Issue INFO command to fetch the real server name and server
1749 information and other stuff. */
1750 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1751 silc_client_command_reply_info_i, 0,
1753 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1754 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1755 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1756 silc_buffer_free(sidp);
1758 /* We are resuming session. Start resolving informations from the
1759 server we need to set the client libary in the state before
1760 detaching the session. The connect client operation is called
1761 after this is successfully completed */
1762 silc_client_resume_session(client, conn, silc_client_resume_session_cb,
1768 /* Removes a client entry from all channels it has joined. */
1770 void silc_client_remove_from_channels(SilcClient client,
1771 SilcClientConnection conn,
1772 SilcClientEntry client_entry)
1774 SilcHashTableList htl;
1775 SilcChannelUser chu;
1777 silc_hash_table_list(client_entry->channels, &htl);
1778 while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1779 silc_hash_table_del(chu->client->channels, chu->channel);
1780 silc_hash_table_del(chu->channel->user_list, chu->client);
1784 silc_hash_table_list_reset(&htl);
1787 /* Replaces `old' client entries from all channels to `new' client entry.
1788 This can be called for example when nickname changes and old ID entry
1789 is replaced from ID cache with the new one. If the old ID entry is only
1790 updated, then this fucntion needs not to be called. */
1792 void silc_client_replace_from_channels(SilcClient client,
1793 SilcClientConnection conn,
1794 SilcClientEntry old,
1795 SilcClientEntry new)
1797 SilcHashTableList htl;
1798 SilcChannelUser chu;
1800 silc_hash_table_list(old->channels, &htl);
1801 while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1802 /* Replace client entry */
1803 silc_hash_table_del(chu->client->channels, chu->channel);
1804 silc_hash_table_del(chu->channel->user_list, chu->client);
1807 silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1808 silc_hash_table_add(chu->client->channels, chu->channel, chu);
1810 silc_hash_table_list_reset(&htl);
1813 /* Registers failure timeout to process the received failure packet
1816 void silc_client_process_failure(SilcClient client,
1817 SilcSocketConnection sock,
1818 SilcPacketContext *packet)
1820 SilcUInt32 failure = 0;
1822 if (sock->protocol) {
1823 if (packet->buffer->len >= 4)
1824 SILC_GET32_MSB(failure, packet->buffer->data);
1826 /* Notify application */
1827 client->internal->ops->failure(client, sock->user_data, sock->protocol,
1832 /* A timeout callback for the re-key. We will be the initiator of the
1835 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1837 SilcSocketConnection sock = (SilcSocketConnection)context;
1838 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1839 SilcClient client = (SilcClient)conn->internal->rekey->context;
1840 SilcProtocol protocol;
1841 SilcClientRekeyInternalContext *proto_ctx;
1843 SILC_LOG_DEBUG(("Start"));
1845 /* Allocate internal protocol context. This is sent as context
1847 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1848 proto_ctx->client = (void *)client;
1849 proto_ctx->sock = silc_socket_dup(sock);
1850 proto_ctx->responder = FALSE;
1851 proto_ctx->pfs = conn->internal->rekey->pfs;
1853 /* Perform rekey protocol. Will call the final callback after the
1854 protocol is over. */
1855 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1856 &protocol, proto_ctx, silc_client_rekey_final);
1857 sock->protocol = protocol;
1859 /* Run the protocol */
1860 silc_protocol_execute(protocol, client->schedule, 0, 0);
1862 /* Re-register re-key timeout */
1863 silc_schedule_task_add(client->schedule, sock->sock,
1864 silc_client_rekey_callback,
1865 context, conn->internal->rekey->timeout, 0,
1866 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1869 /* The final callback for the REKEY protocol. This will actually take the
1870 new key material into use. */
1872 SILC_TASK_CALLBACK(silc_client_rekey_final)
1874 SilcProtocol protocol = (SilcProtocol)context;
1875 SilcClientRekeyInternalContext *ctx =
1876 (SilcClientRekeyInternalContext *)protocol->context;
1877 SilcClient client = (SilcClient)ctx->client;
1878 SilcSocketConnection sock = ctx->sock;
1880 SILC_LOG_DEBUG(("Start"));
1882 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1883 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1884 /* Error occured during protocol */
1885 silc_protocol_cancel(protocol, client->schedule);
1886 silc_protocol_free(protocol);
1887 sock->protocol = NULL;
1889 silc_packet_context_free(ctx->packet);
1891 silc_ske_free(ctx->ske);
1892 silc_socket_free(ctx->sock);
1897 /* Purge the outgoing data queue to assure that all rekey packets really
1898 go to the network before we quit the protocol. */
1899 silc_client_packet_queue_purge(client, sock);
1902 silc_protocol_free(protocol);
1903 sock->protocol = NULL;
1905 silc_packet_context_free(ctx->packet);
1907 silc_ske_free(ctx->ske);
1908 silc_socket_free(ctx->sock);
1912 /* Processes incoming connection authentication method request packet.
1913 It is a reply to our previously sent request. The packet can be used
1914 to resolve the authentication method for the current session if the
1915 client does not know it beforehand. */
1917 void silc_client_connection_auth_request(SilcClient client,
1918 SilcSocketConnection sock,
1919 SilcPacketContext *packet)
1921 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1922 SilcUInt16 conn_type, auth_meth;
1925 /* If we haven't send our request then ignore this one. */
1926 if (!conn->internal->connauth)
1929 /* Parse the payload */
1930 ret = silc_buffer_unformat(packet->buffer,
1931 SILC_STR_UI_SHORT(&conn_type),
1932 SILC_STR_UI_SHORT(&auth_meth),
1935 auth_meth = SILC_AUTH_NONE;
1937 /* Call the request callback to notify application for received
1938 authentication method information. */
1939 if (conn->internal->connauth->callback)
1940 (*conn->internal->connauth->callback)(client, conn, auth_meth,
1941 conn->internal->connauth->context);
1943 silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
1945 silc_free(conn->internal->connauth);
1946 conn->internal->connauth = NULL;
1949 /* Timeout task callback called if the server does not reply to our
1950 connection authentication method request in the specified time interval. */
1952 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1954 SilcClientConnection conn = (SilcClientConnection)context;
1955 SilcClient client = conn->client;
1957 if (!conn->internal->connauth)
1960 /* Call the request callback to notify application */
1961 if (conn->internal->connauth->callback)
1962 (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
1963 conn->internal->connauth->context);
1965 silc_free(conn->internal->connauth);
1966 conn->internal->connauth = NULL;
1969 /* This function can be used to request the current authentication method
1970 from the server. This may be called when connecting to the server
1971 and the client library requests the authentication data from the
1972 application. If the application does not know the current authentication
1973 method it can request it from the server using this function.
1974 The `callback' with `context' will be called after the server has
1975 replied back with the current authentication method. */
1978 silc_client_request_authentication_method(SilcClient client,
1979 SilcClientConnection conn,
1980 SilcConnectionAuthRequest callback,
1983 SilcClientConnAuthRequest connauth;
1986 assert(client && conn);
1987 connauth = silc_calloc(1, sizeof(*connauth));
1988 connauth->callback = callback;
1989 connauth->context = context;
1991 if (conn->internal->connauth)
1992 silc_free(conn->internal->connauth);
1994 conn->internal->connauth = connauth;
1996 /* Assemble the request packet and send it to the server */
1997 packet = silc_buffer_alloc(4);
1998 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1999 silc_buffer_format(packet,
2000 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
2001 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
2003 silc_client_packet_send(client, conn->sock,
2004 SILC_PACKET_CONNECTION_AUTH_REQUEST,
2005 NULL, 0, NULL, NULL,
2006 packet->data, packet->len, FALSE);
2007 silc_buffer_free(packet);
2009 /* Register a timeout in case server does not reply anything back. */
2011 silc_schedule_task_add(client->schedule, conn->sock->sock,
2012 silc_client_request_authentication_method_timeout,
2014 client->internal->params->connauth_request_secs, 0,
2015 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);