5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "clientlibincludes.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_packet_parse_real);
30 SILC_TASK_CALLBACK(silc_client_rekey_callback);
31 SILC_TASK_CALLBACK(silc_client_rekey_final);
33 static void 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 uint32 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 *silc_version)
52 SilcClient new_client;
54 new_client = silc_calloc(1, sizeof(*new_client));
55 new_client->application = application;
56 new_client->ops = ops;
57 new_client->silc_client_version = strdup(silc_version);
58 new_client->params = silc_calloc(1, sizeof(*new_client->params));
61 memcpy(new_client->params, params, sizeof(*params));
63 if (!new_client->params->task_max)
64 new_client->params->task_max = 200;
66 if (!new_client->params->rekey_secs)
67 new_client->params->rekey_secs = 3600;
69 if (!new_client->params->connauth_request_secs)
70 new_client->params->connauth_request_secs = 2;
73 nickname_format[sizeof(new_client->params->nickname_format) - 1] = 0;
78 /* Frees client object and its internals. */
80 void silc_client_free(SilcClient client)
84 silc_rng_free(client->rng);
86 silc_free(client->silc_client_version);
87 silc_free(client->params);
92 /* Initializes the client. This makes all the necessary steps to make
93 the client ready to be run. One must call silc_client_run to run the
94 client. Returns FALSE if error occured, TRUE otherwise. */
96 int silc_client_init(SilcClient client)
98 SILC_LOG_DEBUG(("Initializing client"));
100 /* Initialize hash functions for client to use */
101 silc_hash_alloc("md5", &client->md5hash);
102 silc_hash_alloc("sha1", &client->sha1hash);
104 /* Initialize none cipher */
105 silc_cipher_alloc("none", &client->none_cipher);
107 /* Initialize random number generator */
108 client->rng = silc_rng_alloc();
109 silc_rng_init(client->rng);
110 silc_rng_global_init(client->rng);
112 /* Register protocols */
113 silc_client_protocols_register();
115 /* Initialize the scheduler */
116 client->schedule = silc_schedule_init(client->params->task_max ?
117 client->params->task_max : 200);
118 if (!client->schedule)
124 /* Stops the client. This is called to stop the client and thus to stop
127 void silc_client_stop(SilcClient client)
129 SILC_LOG_DEBUG(("Stopping client"));
131 silc_schedule_stop(client->schedule);
132 silc_schedule_uninit(client->schedule);
134 silc_client_protocols_unregister();
136 SILC_LOG_DEBUG(("Client stopped"));
139 /* Runs the client. This starts the scheduler from the utility library.
140 When this functions returns the execution of the appliation is over. */
142 void silc_client_run(SilcClient client)
144 SILC_LOG_DEBUG(("Running client"));
146 /* Start the scheduler, the heart of the SILC client. When this returns
147 the program will be terminated. */
148 silc_schedule(client->schedule);
151 static void silc_client_entry_destructor(SilcIDCache cache,
152 SilcIDCacheEntry entry)
154 silc_free(entry->name);
157 /* Allocates and adds new connection to the client. This adds the allocated
158 connection to the connection table and returns a pointer to it. A client
159 can have multiple connections to multiple servers. Every connection must
160 be added to the client using this function. User data `context' may
161 be sent as argument. This function is normally used only if the
162 application performed the connecting outside the library. The library
163 however may use this internally. */
165 SilcClientConnection silc_client_add_connection(SilcClient client,
170 SilcClientConnection conn;
173 conn = silc_calloc(1, sizeof(*conn));
175 /* Initialize ID caches */
176 conn->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT,
177 silc_client_entry_destructor);
178 conn->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
179 conn->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
180 conn->client = client;
181 conn->remote_host = strdup(hostname);
182 conn->remote_port = port;
183 conn->context = context;
184 conn->pending_commands = silc_dlist_init();
186 /* Add the connection to connections table */
187 for (i = 0; i < client->conns_count; i++)
188 if (client->conns && !client->conns[i]) {
189 client->conns[i] = conn;
193 client->conns = silc_realloc(client->conns, sizeof(*client->conns)
194 * (client->conns_count + 1));
195 client->conns[client->conns_count] = conn;
196 client->conns_count++;
201 /* Removes connection from client. Frees all memory. */
203 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
207 for (i = 0; i < client->conns_count; i++)
208 if (client->conns[i] == conn) {
209 if (conn->pending_commands)
210 silc_dlist_uninit(conn->pending_commands);
212 client->conns[i] = NULL;
216 /* Adds listener socket to the listener sockets table. This function is
217 used to add socket objects that are listeners to the client. This should
218 not be used to add other connection objects. */
220 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
224 if (!client->sockets) {
225 client->sockets = silc_calloc(1, sizeof(*client->sockets));
226 client->sockets[0] = silc_socket_dup(sock);
227 client->sockets_count = 1;
231 for (i = 0; i < client->sockets_count; i++) {
232 if (client->sockets[i] == NULL) {
233 client->sockets[i] = silc_socket_dup(sock);
238 client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
239 (client->sockets_count + 1));
240 client->sockets[client->sockets_count] = silc_socket_dup(sock);
241 client->sockets_count++;
244 /* Deletes listener socket from the listener sockets table. */
246 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
250 if (!client->sockets)
253 for (i = 0; i < client->sockets_count; i++) {
254 if (client->sockets[i] == sock) {
255 silc_socket_free(sock);
256 client->sockets[i] = NULL;
263 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
267 /* XXX In the future we should give up this non-blocking connect all
268 together and use threads instead. */
269 /* Create connection to server asynchronously */
270 sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
274 /* Register task that will receive the async connect and will
276 ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
277 silc_client_connect_to_server_start,
280 SILC_TASK_PRI_NORMAL);
281 silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE);
288 /* Connects to remote server. This is the main routine used to connect
289 to SILC server. Returns -1 on error and the created socket otherwise.
290 The `context' is user context that is saved into the SilcClientConnection
291 that is created after the connection is created. Note that application
292 may handle the connecting process outside the library. If this is the
293 case then this function is not used at all. When the connecting is
294 done the `connect' client operation is called. */
296 int silc_client_connect_to_server(SilcClient client, int port,
297 char *host, void *context)
299 SilcClientInternalConnectContext *ctx;
300 SilcClientConnection conn;
303 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
306 conn = silc_client_add_connection(client, host, port, context);
308 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
309 "Connecting to port %d of server %s", port, host);
311 /* Allocate internal context for connection process. This is
312 needed as we are doing async connecting. */
313 ctx = silc_calloc(1, sizeof(*ctx));
314 ctx->client = client;
316 ctx->host = strdup(host);
320 /* Do the actual connecting process */
321 sock = silc_client_connect_to_server_internal(ctx);
323 silc_client_del_connection(client, conn);
327 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
328 key material between client and server. This function can be called
329 directly if application is performing its own connecting and does not
330 use the connecting provided by this library. This function is normally
331 used only if the application performed the connecting outside the library.
332 The library however may use this internally. */
334 bool silc_client_start_key_exchange(SilcClient client,
335 SilcClientConnection conn,
338 SilcProtocol protocol;
339 SilcClientKEInternalContext *proto_ctx;
342 /* Allocate new socket connection object */
343 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
345 /* Sometimes when doing quick reconnects the new socket may be same as
346 the old one and there might be pending stuff for the old socket.
347 If new one is same then those pending sutff might cause problems.
348 Make sure they do not do that. */
349 silc_schedule_task_del_by_fd(client->schedule, fd);
351 conn->nickname = strdup(client->username);
352 conn->sock->hostname = conn->remote_host;
353 conn->sock->ip = strdup(conn->remote_host);
354 conn->sock->port = conn->remote_port;
356 /* Allocate internal Key Exchange context. This is sent to the
357 protocol as context. */
358 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
359 proto_ctx->client = (void *)client;
360 proto_ctx->sock = silc_socket_dup(conn->sock);
361 proto_ctx->rng = client->rng;
362 proto_ctx->responder = FALSE;
363 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
364 proto_ctx->verify = silc_client_protocol_ke_verify_key;
366 /* Perform key exchange protocol. silc_client_connect_to_server_final
367 will be called after the protocol is finished. */
368 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
369 &protocol, (void *)proto_ctx,
370 silc_client_connect_to_server_second);
372 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
373 "Error: Could not start key exchange protocol");
376 conn->sock->protocol = protocol;
378 /* Register the connection for network input and output. This sets
379 that scheduler will listen for incoming packets for this connection
380 and sets that outgoing packets may be sent to this connection as well.
381 However, this doesn't set the scheduler for outgoing traffic, it will
382 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
383 later when outgoing data is available. */
384 context = (void *)client;
385 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
387 /* Execute the protocol */
388 silc_protocol_execute(protocol, client->schedule, 0, 0);
392 /* Start of the connection to the remote server. This is called after
393 succesful TCP/IP connection has been established to the remote host. */
395 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
397 SilcClientInternalConnectContext *ctx =
398 (SilcClientInternalConnectContext *)context;
399 SilcClient client = ctx->client;
400 SilcClientConnection conn = ctx->conn;
401 int opt, opt_len = sizeof(opt);
403 SILC_LOG_DEBUG(("Start"));
405 /* Check the socket status as it might be in error */
406 silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
408 if (ctx->tries < 2) {
409 /* Connection failed but lets try again */
410 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
411 "Could not connect to server %s: %s",
412 ctx->host, strerror(opt));
413 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
414 "Connecting to port %d of server %s resumed",
415 ctx->port, ctx->host);
417 /* Unregister old connection try */
418 silc_schedule_unset_listen_fd(client->schedule, fd);
419 silc_net_close_connection(fd);
420 silc_schedule_task_del(client->schedule, ctx->task);
423 silc_client_connect_to_server_internal(ctx);
426 /* Connection failed and we won't try anymore */
427 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
428 "Could not connect to server %s: %s",
429 ctx->host, strerror(opt));
430 silc_schedule_unset_listen_fd(client->schedule, fd);
431 silc_net_close_connection(fd);
432 silc_schedule_task_del(client->schedule, ctx->task);
435 /* Notify application of failure */
436 client->ops->connect(client, conn, FALSE);
437 silc_client_del_connection(client, conn);
442 silc_schedule_unset_listen_fd(client->schedule, fd);
443 silc_schedule_task_del(client->schedule, ctx->task);
446 if (!silc_client_start_key_exchange(client, conn, fd)) {
447 silc_net_close_connection(fd);
448 client->ops->connect(client, conn, FALSE);
452 /* Second part of the connecting to the server. This executed
453 authentication protocol. */
455 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
457 SilcProtocol protocol = (SilcProtocol)context;
458 SilcClientKEInternalContext *ctx =
459 (SilcClientKEInternalContext *)protocol->context;
460 SilcClient client = (SilcClient)ctx->client;
461 SilcSocketConnection sock = NULL;
462 SilcClientConnAuthInternalContext *proto_ctx;
464 SILC_LOG_DEBUG(("Start"));
466 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
467 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
468 /* Error occured during protocol */
469 SILC_LOG_DEBUG(("Error during KE protocol"));
470 silc_protocol_free(protocol);
471 silc_ske_free_key_material(ctx->keymat);
473 silc_ske_free(ctx->ske);
475 silc_free(ctx->dest_id);
476 ctx->sock->protocol = NULL;
477 silc_socket_free(ctx->sock);
479 /* Notify application of failure */
480 client->ops->connect(client, ctx->sock->user_data, FALSE);
485 /* We now have the key material as the result of the key exchange
486 protocol. Take the key material into use. Free the raw key material
487 as soon as we've set them into use. */
488 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
489 ctx->ske->prop->cipher,
490 ctx->ske->prop->pkcs,
491 ctx->ske->prop->hash,
492 ctx->ske->prop->hmac,
493 ctx->ske->prop->group);
494 silc_ske_free_key_material(ctx->keymat);
496 /* Allocate internal context for the authentication protocol. This
497 is sent as context for the protocol. */
498 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
499 proto_ctx->client = (void *)client;
500 proto_ctx->sock = sock = ctx->sock;
501 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
502 proto_ctx->dest_id_type = ctx->dest_id_type;
503 proto_ctx->dest_id = ctx->dest_id;
505 /* Free old protocol as it is finished now */
506 silc_protocol_free(protocol);
508 silc_packet_context_free(ctx->packet);
510 sock->protocol = NULL;
512 /* Resolve the authentication method to be used in this connection. The
513 completion callback is called after the application has resolved
514 the authentication method. */
515 client->ops->get_auth_method(client, sock->user_data, sock->hostname,
516 sock->port, silc_client_resolve_auth_method,
520 /* Authentication method resolving callback. Application calls this function
521 after we've called the client->ops->get_auth_method client operation
522 to resolve the authentication method. We will continue the executiong
523 of the protocol in this function. */
525 void silc_client_resolve_auth_method(bool success,
526 SilcProtocolAuthMeth auth_meth,
527 const unsigned char *auth_data,
528 uint32 auth_data_len, void *context)
530 SilcClientConnAuthInternalContext *proto_ctx =
531 (SilcClientConnAuthInternalContext *)context;
532 SilcClient client = (SilcClient)proto_ctx->client;
535 auth_meth = SILC_AUTH_NONE;
537 proto_ctx->auth_meth = auth_meth;
539 if (auth_data && auth_data_len) {
540 proto_ctx->auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
541 memcpy(proto_ctx->auth_data, auth_data, auth_data_len);
542 proto_ctx->auth_data_len = auth_data_len;
545 /* Allocate the authenteication protocol and execute it. */
546 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
547 &proto_ctx->sock->protocol, (void *)proto_ctx,
548 silc_client_connect_to_server_final);
550 /* Execute the protocol */
551 silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
554 /* Finalizes the connection to the remote SILC server. This is called
555 after authentication protocol has been completed. This send our
556 user information to the server to receive our client ID from
559 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
561 SilcProtocol protocol = (SilcProtocol)context;
562 SilcClientConnAuthInternalContext *ctx =
563 (SilcClientConnAuthInternalContext *)protocol->context;
564 SilcClient client = (SilcClient)ctx->client;
565 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
568 SILC_LOG_DEBUG(("Start"));
570 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
571 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
572 /* Error occured during protocol */
573 SILC_LOG_DEBUG(("Error during authentication protocol"));
574 silc_protocol_free(protocol);
576 silc_free(ctx->auth_data);
578 silc_ske_free(ctx->ske);
580 silc_free(ctx->dest_id);
581 conn->sock->protocol = NULL;
582 silc_socket_free(ctx->sock);
584 /* Notify application of failure */
585 client->ops->connect(client, ctx->sock->user_data, FALSE);
590 /* Send NEW_CLIENT packet to the server. We will become registered
591 to the SILC network after sending this packet and we will receive
592 client ID from the server. */
593 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
594 strlen(client->realname));
595 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
596 silc_buffer_format(packet,
597 SILC_STR_UI_SHORT(strlen(client->username)),
598 SILC_STR_UI_XNSTRING(client->username,
599 strlen(client->username)),
600 SILC_STR_UI_SHORT(strlen(client->realname)),
601 SILC_STR_UI_XNSTRING(client->realname,
602 strlen(client->realname)),
605 /* Send the packet */
606 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
608 packet->data, packet->len, TRUE);
609 silc_buffer_free(packet);
611 /* Save remote ID. */
612 conn->remote_id = ctx->dest_id;
613 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
614 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
616 /* Register re-key timeout */
617 conn->rekey->timeout = client->params->rekey_secs;
618 conn->rekey->context = (void *)client;
619 silc_schedule_task_add(client->schedule, conn->sock->sock,
620 silc_client_rekey_callback,
621 (void *)conn->sock, conn->rekey->timeout, 0,
622 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
624 silc_protocol_free(protocol);
626 silc_free(ctx->auth_data);
628 silc_ske_free(ctx->ske);
629 silc_socket_free(ctx->sock);
631 conn->sock->protocol = NULL;
634 /* Internal routine that sends packet or marks packet to be sent. This
635 is used directly only in special cases. Normal cases should use
636 silc_server_packet_send. Returns < 0 on error. */
638 int silc_client_packet_send_real(SilcClient client,
639 SilcSocketConnection sock,
645 /* If rekey protocol is active we must assure that all packets are
646 sent through packet queue. */
647 if (flush == FALSE && SILC_CLIENT_IS_REKEY(sock))
650 /* Send the packet */
651 ret = silc_packet_send(sock, force_send);
655 /* Mark that there is some outgoing data available for this connection.
656 This call sets the connection both for input and output (the input
657 is set always and this call keeps the input setting, actually).
658 Actual data sending is performed by silc_client_packet_process. */
659 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
661 /* Mark to socket that data is pending in outgoing buffer. This flag
662 is needed if new data is added to the buffer before the earlier
663 put data is sent to the network. */
664 SILC_SET_OUTBUF_PENDING(sock);
669 /* Packet processing callback. This is used to send and receive packets
670 from network. This is generic task. */
672 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
674 SilcClient client = (SilcClient)context;
675 SilcSocketConnection sock = NULL;
676 SilcClientConnection conn;
679 SILC_LOG_DEBUG(("Processing packet"));
681 SILC_CLIENT_GET_SOCK(client, fd, sock);
685 conn = (SilcClientConnection)sock->user_data;
688 if (type == SILC_TASK_WRITE) {
689 SILC_LOG_DEBUG(("Writing data to connection"));
691 if (sock->outbuf->data - sock->outbuf->head)
692 silc_buffer_push(sock->outbuf,
693 sock->outbuf->data - sock->outbuf->head);
695 ret = silc_client_packet_send_real(client, sock, TRUE, TRUE);
697 /* If returned -2 could not write to connection now, will do
702 /* The packet has been sent and now it is time to set the connection
703 back to only for input. When there is again some outgoing data
704 available for this connection it will be set for output as well.
705 This call clears the output setting and sets it only for input. */
706 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
707 SILC_UNSET_OUTBUF_PENDING(sock);
709 silc_buffer_clear(sock->outbuf);
713 /* Packet receiving */
714 if (type == SILC_TASK_READ) {
715 SILC_LOG_DEBUG(("Reading data from connection"));
717 /* Read data from network */
718 ret = silc_packet_receive(sock);
724 SILC_LOG_DEBUG(("Read EOF"));
726 /* If connection is disconnecting already we will finally
727 close the connection */
728 if (SILC_IS_DISCONNECTING(sock)) {
729 if (sock == conn->sock)
730 client->ops->disconnect(client, conn);
731 silc_client_close_connection(client, sock, conn);
735 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
736 if (sock == conn->sock)
737 client->ops->disconnect(client, conn);
738 silc_client_close_connection(client, sock, conn);
742 /* Process the packet. This will call the parser that will then
743 decrypt and parse the packet. */
744 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
745 silc_packet_receive_process(sock, conn->receive_key, conn->hmac_receive,
746 silc_client_packet_parse, client);
748 silc_packet_receive_process(sock, NULL, NULL,
749 silc_client_packet_parse, client);
753 /* Callback function that the silc_packet_decrypt will call to make the
754 decision whether the packet is normal or special packet. We will
755 return TRUE if it is normal and FALSE if it is special */
757 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
759 SilcPacketContext *packet,
763 /* Packet is normal packet, if:
765 1) packet is private message packet and does not have private key set
766 2) is other packet than channel message packet
768 all other packets are special packets
771 if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
772 (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
775 if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
781 /* Parses whole packet, received earlier. */
783 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
785 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
786 SilcClient client = (SilcClient)parse_ctx->context;
787 SilcPacketContext *packet = parse_ctx->packet;
788 SilcBuffer buffer = packet->buffer;
789 SilcSocketConnection sock = parse_ctx->sock;
790 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
793 SILC_LOG_DEBUG(("Start"));
795 /* Decrypt the received packet */
796 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
797 ret = silc_packet_decrypt(conn->receive_key, conn->hmac_receive,
799 silc_client_packet_decrypt_check, parse_ctx);
801 ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
802 silc_client_packet_decrypt_check, parse_ctx);
808 /* Parse the packet. Packet type is returned. */
809 ret = silc_packet_parse(packet);
811 /* Parse the packet header in special way as this is "special"
813 ret = silc_packet_parse_special(packet);
816 if (ret == SILC_PACKET_NONE)
819 /* Parse the incoming packet type */
820 silc_client_packet_parse_type(client, sock, packet);
823 /* silc_buffer_clear(sock->inbuf); */
824 silc_packet_context_free(packet);
825 silc_free(parse_ctx);
828 /* Parser callback called by silc_packet_receive_process. Thie merely
829 registers timeout that will handle the actual parsing when appropriate. */
831 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
833 SilcClient client = (SilcClient)parser_context->context;
835 /* Parse the packet */
836 silc_schedule_task_add(client->schedule, parser_context->sock->sock,
837 silc_client_packet_parse_real,
838 (void *)parser_context, 0, 1,
840 SILC_TASK_PRI_NORMAL);
843 /* Parses the packet type and calls what ever routines the packet type
844 requires. This is done for all incoming packets. */
846 void silc_client_packet_parse_type(SilcClient client,
847 SilcSocketConnection sock,
848 SilcPacketContext *packet)
850 SilcBuffer buffer = packet->buffer;
851 SilcPacketType type = packet->type;
853 SILC_LOG_DEBUG(("Parsing packet type %d", type));
855 /* Parse the packet type */
857 case SILC_PACKET_DISCONNECT:
858 silc_client_disconnected_by_server(client, sock, buffer);
860 case SILC_PACKET_SUCCESS:
862 * Success received for something. For now we can have only
863 * one protocol for connection executing at once hence this
864 * success message is for whatever protocol is executing currently.
867 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
869 case SILC_PACKET_FAILURE:
871 * Failure received for some protocol. Set the protocol state to
872 * error and call the protocol callback. This fill cause error on
873 * protocol and it will call the final callback.
875 silc_client_process_failure(client, sock, packet);
877 case SILC_PACKET_REJECT:
880 case SILC_PACKET_NOTIFY:
882 * Received notify message
884 silc_client_notify_by_server(client, sock, packet);
887 case SILC_PACKET_ERROR:
889 * Received error message
891 silc_client_error_by_server(client, sock, buffer);
894 case SILC_PACKET_CHANNEL_MESSAGE:
896 * Received message to (from, actually) a channel
898 silc_client_channel_message(client, sock, packet);
900 case SILC_PACKET_CHANNEL_KEY:
902 * Received key for a channel. By receiving this key the client will be
903 * able to talk to the channel it has just joined. This can also be
904 * a new key for existing channel as keys expire peridiocally.
906 silc_client_receive_channel_key(client, sock, buffer);
909 case SILC_PACKET_PRIVATE_MESSAGE:
911 * Received private message
913 silc_client_private_message(client, sock, packet);
915 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
917 * Received private message key
921 case SILC_PACKET_COMMAND_REPLY:
923 * Recived reply for a command
925 silc_client_command_reply_process(client, sock, packet);
928 case SILC_PACKET_KEY_EXCHANGE:
929 if (sock->protocol && sock->protocol->protocol &&
930 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
931 SilcClientKEInternalContext *proto_ctx =
932 (SilcClientKEInternalContext *)sock->protocol->context;
934 proto_ctx->packet = silc_packet_context_dup(packet);
935 proto_ctx->dest_id_type = packet->src_id_type;
936 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
937 packet->src_id_type);
938 if (!proto_ctx->dest_id)
941 /* Let the protocol handle the packet */
942 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
944 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
945 "protocol active, packet dropped."));
949 case SILC_PACKET_KEY_EXCHANGE_1:
950 if (sock->protocol && sock->protocol->protocol &&
951 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
952 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
954 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
955 SilcClientRekeyInternalContext *proto_ctx =
956 (SilcClientRekeyInternalContext *)sock->protocol->context;
958 if (proto_ctx->packet)
959 silc_packet_context_free(proto_ctx->packet);
961 proto_ctx->packet = silc_packet_context_dup(packet);
963 /* Let the protocol handle the packet */
964 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
966 SilcClientKEInternalContext *proto_ctx =
967 (SilcClientKEInternalContext *)sock->protocol->context;
969 if (proto_ctx->packet)
970 silc_packet_context_free(proto_ctx->packet);
972 proto_ctx->packet = silc_packet_context_dup(packet);
973 proto_ctx->dest_id_type = packet->src_id_type;
974 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
975 packet->src_id_type);
976 if (!proto_ctx->dest_id)
979 /* Let the protocol handle the packet */
980 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
983 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
984 "protocol active, packet dropped."));
987 case SILC_PACKET_KEY_EXCHANGE_2:
988 if (sock->protocol && sock->protocol->protocol &&
989 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
990 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
992 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
993 SilcClientRekeyInternalContext *proto_ctx =
994 (SilcClientRekeyInternalContext *)sock->protocol->context;
996 if (proto_ctx->packet)
997 silc_packet_context_free(proto_ctx->packet);
999 proto_ctx->packet = silc_packet_context_dup(packet);
1001 /* Let the protocol handle the packet */
1002 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1004 SilcClientKEInternalContext *proto_ctx =
1005 (SilcClientKEInternalContext *)sock->protocol->context;
1007 if (proto_ctx->packet)
1008 silc_packet_context_free(proto_ctx->packet);
1010 proto_ctx->packet = silc_packet_context_dup(packet);
1011 proto_ctx->dest_id_type = packet->src_id_type;
1012 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1013 packet->src_id_type);
1014 if (!proto_ctx->dest_id)
1017 /* Let the protocol handle the packet */
1018 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1021 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
1022 "protocol active, packet dropped."));
1026 case SILC_PACKET_NEW_ID:
1029 * Received new ID from server. This packet is received at
1030 * the connection to the server. New ID is also received when
1031 * user changes nickname but in that case the new ID is received
1032 * as command reply and not as this packet type.
1036 idp = silc_id_payload_parse(buffer);
1039 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
1042 silc_client_receive_new_id(client, sock, idp);
1043 silc_id_payload_free(idp);
1047 case SILC_PACKET_HEARTBEAT:
1049 * Received heartbeat packet
1051 SILC_LOG_DEBUG(("Heartbeat packet"));
1054 case SILC_PACKET_KEY_AGREEMENT:
1056 * Received key agreement packet
1058 SILC_LOG_DEBUG(("Key agreement packet"));
1059 silc_client_key_agreement(client, sock, packet);
1062 case SILC_PACKET_REKEY:
1063 SILC_LOG_DEBUG(("Re-key packet"));
1064 /* We ignore this for now */
1067 case SILC_PACKET_REKEY_DONE:
1068 SILC_LOG_DEBUG(("Re-key done packet"));
1070 if (sock->protocol && sock->protocol->protocol &&
1071 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1073 SilcClientRekeyInternalContext *proto_ctx =
1074 (SilcClientRekeyInternalContext *)sock->protocol->context;
1076 if (proto_ctx->packet)
1077 silc_packet_context_free(proto_ctx->packet);
1079 proto_ctx->packet = silc_packet_context_dup(packet);
1081 /* Let the protocol handle the packet */
1082 if (proto_ctx->responder == FALSE)
1083 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1085 /* Let the protocol handle the packet */
1086 silc_protocol_execute(sock->protocol, client->schedule,
1089 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1090 "protocol active, packet dropped."));
1094 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
1096 * Reveived reply to our connection authentication method request
1097 * packet. This is used to resolve the authentication method for the
1098 * current session from the server if the client does not know it.
1100 silc_client_connection_auth_request(client, sock, packet);
1104 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1109 /* Sends packet. This doesn't actually send the packet instead it assembles
1110 it and marks it to be sent. However, if force_send is TRUE the packet
1111 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1112 will be derived from sock argument. Otherwise the valid arguments sent
1115 void silc_client_packet_send(SilcClient client,
1116 SilcSocketConnection sock,
1117 SilcPacketType type,
1119 SilcIdType dst_id_type,
1122 unsigned char *data,
1126 SilcPacketContext packetdata;
1131 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1133 /* Get data used in the packet sending, keys and stuff */
1134 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1135 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1136 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1138 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1139 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1141 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1142 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1143 dst_id_type = SILC_ID_SERVER;
1147 /* Set the packet context pointers */
1148 packetdata.flags = 0;
1149 packetdata.type = type;
1150 if (sock->user_data &&
1151 ((SilcClientConnection)sock->user_data)->local_id_data) {
1152 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1153 packetdata.src_id_len =
1154 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1157 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1158 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1160 packetdata.src_id_type = SILC_ID_CLIENT;
1162 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1163 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1164 packetdata.dst_id_type = dst_id_type;
1166 packetdata.dst_id = NULL;
1167 packetdata.dst_id_len = 0;
1168 packetdata.dst_id_type = SILC_ID_NONE;
1170 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1171 packetdata.src_id_len + packetdata.dst_id_len;
1172 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1174 /* Prepare outgoing data buffer for packet sending */
1175 silc_packet_send_prepare(sock,
1176 SILC_PACKET_HEADER_LEN +
1177 packetdata.src_id_len +
1178 packetdata.dst_id_len,
1182 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1184 packetdata.buffer = sock->outbuf;
1186 /* Put the data to the buffer */
1187 if (data && data_len)
1188 silc_buffer_put(sock->outbuf, data, data_len);
1190 /* Create the outgoing packet */
1191 silc_packet_assemble(&packetdata);
1193 /* Encrypt the packet */
1195 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1197 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1198 sock->outbuf->data, sock->outbuf->len);
1200 /* Now actually send the packet */
1201 silc_client_packet_send_real(client, sock, force_send, FALSE);
1204 /* Closes connection to remote end. Free's all allocated data except
1205 for some information such as nickname etc. that are valid at all time.
1206 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1207 provided it will be checked whether the sock and `conn->sock' are the
1208 same (they can be different, ie. a socket can use `conn' as its
1209 connection but `conn->sock' might be actually a different connection
1210 than the `sock'). */
1212 void silc_client_close_connection(SilcClient client,
1213 SilcSocketConnection sock,
1214 SilcClientConnection conn)
1218 if (!sock || (sock && conn->sock == sock))
1223 /* We won't listen for this connection anymore */
1224 silc_schedule_unset_listen_fd(client->schedule, sock->sock);
1226 /* Unregister all tasks */
1227 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1228 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1230 /* Close the actual connection */
1231 silc_net_close_connection(sock->sock);
1233 /* Cancel any active protocol */
1234 if (sock->protocol) {
1235 if (sock->protocol->protocol->type ==
1236 SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1237 sock->protocol->protocol->type ==
1238 SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1239 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1240 silc_protocol_execute_final(sock->protocol, client->schedule);
1241 /* The application will recall this function with these protocols
1242 (the ops->connect client operation). */
1245 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1246 silc_protocol_execute_final(sock->protocol, client->schedule);
1247 sock->protocol = NULL;
1251 /* Free everything */
1252 if (del && sock->user_data) {
1253 /* Free all cache entries */
1254 SilcIDCacheList list;
1255 SilcIDCacheEntry entry;
1258 if (silc_idcache_get_all(conn->client_cache, &list)) {
1259 ret = silc_idcache_list_first(list, &entry);
1261 silc_client_del_client(client, conn, entry->context);
1262 ret = silc_idcache_list_next(list, &entry);
1264 silc_idcache_list_free(list);
1267 if (silc_idcache_get_all(conn->channel_cache, &list)) {
1268 ret = silc_idcache_list_first(list, &entry);
1270 silc_client_del_channel(client, conn, entry->context);
1271 ret = silc_idcache_list_next(list, &entry);
1273 silc_idcache_list_free(list);
1276 if (silc_idcache_get_all(conn->server_cache, &list)) {
1277 ret = silc_idcache_list_first(list, &entry);
1279 silc_client_del_server(client, conn, entry->context);
1280 ret = silc_idcache_list_next(list, &entry);
1282 silc_idcache_list_free(list);
1285 /* Clear ID caches */
1286 if (conn->client_cache)
1287 silc_idcache_del_all(conn->client_cache);
1288 if (conn->channel_cache)
1289 silc_idcache_del_all(conn->channel_cache);
1290 if (conn->server_cache)
1291 silc_idcache_del_all(conn->server_cache);
1293 /* Free data (my ID is freed in above silc_client_del_client) */
1294 if (conn->remote_host)
1295 silc_free(conn->remote_host);
1296 if (conn->local_id_data)
1297 silc_free(conn->local_id_data);
1299 silc_cipher_free(conn->send_key);
1300 if (conn->receive_key)
1301 silc_cipher_free(conn->receive_key);
1302 if (conn->hmac_send) /* conn->hmac_receive is same */
1303 silc_hmac_free(conn->hmac_send);
1304 if (conn->pending_commands)
1305 silc_dlist_uninit(conn->pending_commands);
1307 silc_free(conn->rekey);
1309 memset(conn, 0, sizeof(*conn));
1310 silc_client_del_connection(client, conn);
1313 silc_socket_free(sock);
1316 /* Called when we receive disconnection packet from server. This
1317 closes our end properly and displays the reason of the disconnection
1320 void silc_client_disconnected_by_server(SilcClient client,
1321 SilcSocketConnection sock,
1326 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1328 msg = silc_calloc(message->len + 1, sizeof(char));
1329 memcpy(msg, message->data, message->len);
1330 client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
1333 SILC_SET_DISCONNECTED(sock);
1334 silc_client_close_connection(client, sock, sock->user_data);
1337 /* Received error message from server. Display it on the screen.
1338 We don't take any action what so ever of the error message. */
1340 void silc_client_error_by_server(SilcClient client,
1341 SilcSocketConnection sock,
1346 msg = silc_calloc(message->len + 1, sizeof(char));
1347 memcpy(msg, message->data, message->len);
1348 client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
1352 /* Processes the received new Client ID from server. Old Client ID is
1353 deleted from cache and new one is added. */
1355 void silc_client_receive_new_id(SilcClient client,
1356 SilcSocketConnection sock,
1359 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1360 int connecting = FALSE;
1363 if (!conn->local_entry)
1366 /* Delete old ID from ID cache */
1367 if (conn->local_id) {
1368 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
1369 silc_free(conn->local_id);
1372 /* Save the new ID */
1374 if (conn->local_id_data)
1375 silc_free(conn->local_id_data);
1377 conn->local_id = silc_id_payload_get_id(idp);
1378 conn->local_id_data = silc_id_payload_get_data(idp);
1379 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1381 if (!conn->local_entry)
1382 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1384 conn->local_entry->nickname = conn->nickname;
1385 if (!conn->local_entry->username)
1386 conn->local_entry->username = strdup(client->username);
1387 if (!conn->local_entry->hostname)
1388 conn->local_entry->hostname = strdup(client->hostname);
1389 conn->local_entry->server = strdup(conn->remote_host);
1390 conn->local_entry->id = conn->local_id;
1391 conn->local_entry->valid = TRUE;
1393 /* Put it to the ID cache */
1394 silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id,
1395 (void *)conn->local_entry, FALSE);
1397 /* Issue INFO command to fetch the real server name and server information
1399 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1400 silc_client_send_command(client, conn, SILC_COMMAND_INFO,
1401 ++conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1402 silc_buffer_free(sidp);
1404 /* Notify application of successful connection. We do it here now that
1405 we've received the Client ID and are allowed to send traffic. */
1407 client->ops->connect(client, conn, TRUE);
1410 /* Processed received Channel ID for a channel. This is called when client
1411 joins to channel and server replies with channel ID. The ID is cached.
1412 Returns the created channel entry. This is also called when received
1413 channel ID in for example USERS command reply that we do not have. */
1415 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1416 SilcSocketConnection sock,
1421 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1422 SilcChannelEntry channel;
1424 SILC_LOG_DEBUG(("New channel ID"));
1426 channel = silc_calloc(1, sizeof(*channel));
1427 channel->channel_name = channel_name;
1428 channel->id = silc_id_payload_get_id(idp);
1429 channel->mode = mode;
1430 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1432 /* Put it to the ID cache */
1433 silc_idcache_add(conn->channel_cache, channel->channel_name,
1434 (void *)channel->id, (void *)channel, FALSE);
1439 /* Removes a client entry from all channel it has joined. This really is
1440 a performance killer (client_entry should have pointers to channel
1443 void silc_client_remove_from_channels(SilcClient client,
1444 SilcClientConnection conn,
1445 SilcClientEntry client_entry)
1447 SilcIDCacheEntry id_cache;
1448 SilcIDCacheList list;
1449 SilcChannelEntry channel;
1450 SilcChannelUser chu;
1452 if (!silc_idcache_get_all(conn->channel_cache, &list))
1455 silc_idcache_list_first(list, &id_cache);
1456 channel = (SilcChannelEntry)id_cache->context;
1460 /* Remove client from channel */
1461 silc_list_start(channel->clients);
1462 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1463 if (chu->client == client_entry) {
1464 silc_list_del(channel->clients, chu);
1470 if (!silc_idcache_list_next(list, &id_cache))
1473 channel = (SilcChannelEntry)id_cache->context;
1476 silc_idcache_list_free(list);
1479 /* Replaces `old' client entries from all channels to `new' client entry.
1480 This can be called for example when nickname changes and old ID entry
1481 is replaced from ID cache with the new one. If the old ID entry is only
1482 updated, then this fucntion needs not to be called. */
1484 void silc_client_replace_from_channels(SilcClient client,
1485 SilcClientConnection conn,
1486 SilcClientEntry old,
1487 SilcClientEntry new)
1489 SilcIDCacheEntry id_cache;
1490 SilcIDCacheList list;
1491 SilcChannelEntry channel;
1492 SilcChannelUser chu;
1494 if (!silc_idcache_get_all(conn->channel_cache, &list))
1497 silc_idcache_list_first(list, &id_cache);
1498 channel = (SilcChannelEntry)id_cache->context;
1502 /* Replace client entry */
1503 silc_list_start(channel->clients);
1504 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1505 if (chu->client == old) {
1511 if (!silc_idcache_list_next(list, &id_cache))
1514 channel = (SilcChannelEntry)id_cache->context;
1517 silc_idcache_list_free(list);
1520 /* Registers failure timeout to process the received failure packet
1523 void silc_client_process_failure(SilcClient client,
1524 SilcSocketConnection sock,
1525 SilcPacketContext *packet)
1529 if (sock->protocol) {
1530 if (packet->buffer->len >= 4)
1531 SILC_GET32_MSB(failure, packet->buffer->data);
1533 /* Notify application */
1534 client->ops->failure(client, sock->user_data, sock->protocol,
1539 /* A timeout callback for the re-key. We will be the initiator of the
1542 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1544 SilcSocketConnection sock = (SilcSocketConnection)context;
1545 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1546 SilcClient client = (SilcClient)conn->rekey->context;
1547 SilcProtocol protocol;
1548 SilcClientRekeyInternalContext *proto_ctx;
1550 SILC_LOG_DEBUG(("Start"));
1552 /* Allocate internal protocol context. This is sent as context
1554 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1555 proto_ctx->client = (void *)client;
1556 proto_ctx->sock = silc_socket_dup(sock);
1557 proto_ctx->responder = FALSE;
1558 proto_ctx->pfs = conn->rekey->pfs;
1560 /* Perform rekey protocol. Will call the final callback after the
1561 protocol is over. */
1562 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1563 &protocol, proto_ctx, silc_client_rekey_final);
1564 sock->protocol = protocol;
1566 /* Run the protocol */
1567 silc_protocol_execute(protocol, client->schedule, 0, 0);
1569 /* Re-register re-key timeout */
1570 silc_schedule_task_add(client->schedule, sock->sock,
1571 silc_client_rekey_callback,
1572 context, conn->rekey->timeout, 0,
1573 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1576 /* The final callback for the REKEY protocol. This will actually take the
1577 new key material into use. */
1579 SILC_TASK_CALLBACK(silc_client_rekey_final)
1581 SilcProtocol protocol = (SilcProtocol)context;
1582 SilcClientRekeyInternalContext *ctx =
1583 (SilcClientRekeyInternalContext *)protocol->context;
1584 SilcClient client = (SilcClient)ctx->client;
1585 SilcSocketConnection sock = ctx->sock;
1587 SILC_LOG_DEBUG(("Start"));
1589 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1590 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1591 /* Error occured during protocol */
1592 silc_protocol_cancel(protocol, client->schedule);
1593 silc_protocol_free(protocol);
1594 sock->protocol = NULL;
1596 silc_packet_context_free(ctx->packet);
1598 silc_ske_free(ctx->ske);
1599 silc_socket_free(ctx->sock);
1605 silc_protocol_free(protocol);
1606 sock->protocol = NULL;
1608 silc_packet_context_free(ctx->packet);
1610 silc_ske_free(ctx->ske);
1611 silc_socket_free(ctx->sock);
1615 /* Processes incoming connection authentication method request packet.
1616 It is a reply to our previously sent request. The packet can be used
1617 to resolve the authentication method for the current session if the
1618 client does not know it beforehand. */
1620 void silc_client_connection_auth_request(SilcClient client,
1621 SilcSocketConnection sock,
1622 SilcPacketContext *packet)
1624 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1625 uint16 conn_type, auth_meth;
1628 /* If we haven't send our request then ignore this one. */
1629 if (!conn->connauth)
1632 /* Parse the payload */
1633 ret = silc_buffer_unformat(packet->buffer,
1634 SILC_STR_UI_SHORT(&conn_type),
1635 SILC_STR_UI_SHORT(&auth_meth),
1638 auth_meth = SILC_AUTH_NONE;
1640 /* Call the request callback to notify application for received
1641 authentication method information. */
1642 if (conn->connauth->callback)
1643 (*conn->connauth->callback)(client, conn, auth_meth,
1644 conn->connauth->context);
1646 silc_schedule_task_del(client->schedule, conn->connauth->timeout);
1648 silc_free(conn->connauth);
1649 conn->connauth = NULL;
1652 /* Timeout task callback called if the server does not reply to our
1653 connection authentication method request in the specified time interval. */
1655 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1657 SilcClientConnection conn = (SilcClientConnection)context;
1658 SilcClient client = conn->client;
1660 if (!conn->connauth)
1663 /* Call the request callback to notify application */
1664 if (conn->connauth->callback)
1665 (*conn->connauth->callback)(client, conn, SILC_AUTH_NONE,
1666 conn->connauth->context);
1668 silc_free(conn->connauth);
1669 conn->connauth = NULL;
1672 /* This function can be used to request the current authentication method
1673 from the server. This may be called when connecting to the server
1674 and the client library requests the authentication data from the
1675 application. If the application does not know the current authentication
1676 method it can request it from the server using this function.
1677 The `callback' with `context' will be called after the server has
1678 replied back with the current authentication method. */
1681 silc_client_request_authentication_method(SilcClient client,
1682 SilcClientConnection conn,
1683 SilcConnectionAuthRequest callback,
1686 SilcClientConnAuthRequest connauth;
1689 connauth = silc_calloc(1, sizeof(*connauth));
1690 connauth->callback = callback;
1691 connauth->context = context;
1694 silc_free(conn->connauth);
1696 conn->connauth = connauth;
1698 /* Assemble the request packet and send it to the server */
1699 packet = silc_buffer_alloc(4);
1700 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1701 silc_buffer_format(packet,
1702 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1703 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1705 silc_client_packet_send(client, conn->sock,
1706 SILC_PACKET_CONNECTION_AUTH_REQUEST,
1707 NULL, 0, NULL, NULL,
1708 packet->data, packet->len, FALSE);
1709 silc_buffer_free(packet);
1711 /* Register a timeout in case server does not reply anything back. */
1713 silc_schedule_task_add(client->schedule, conn->sock->sock,
1714 silc_client_request_authentication_method_timeout,
1715 conn, client->params->connauth_request_secs, 0,
1716 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);