More client library rewrites (key agreement, plus other).
[silc.git] / lib / silcclient / client.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2006 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /************************** Types and definitions ***************************/
26
27
28 /************************ Static utility functions **************************/
29
30 /* Connection machine FSM destructor.  This will finish the thread where
31    the machine was running and deletes the connection context. */
32
33 static void silc_client_connection_destructor(SilcFSM fsm,
34                                               void *fsm_context,
35                                               void *destructor_context)
36 {
37   SilcClientConnection conn = fsm_context;
38   SilcFSMThread thread = destructor_context;
39
40   /* Delete connection */
41   silc_client_del_connection(conn->client, conn);
42
43   /* Finish the thread were this machine was running */
44   silc_fsm_finish(thread);
45 }
46
47 /* Packet FSM thread destructor */
48
49 static void silc_client_packet_destructor(SilcFSMThread thread,
50                                           void *thread_context,
51                                           void *destructor_context)
52 {
53   SilcClientConnection conn = thread_context;
54
55   /* Add thread back to thread pool */
56   silc_list_add(conn->internal->thread_pool, thread);
57   if (silc_list_count(conn->internal->thread_pool) == 1)
58     silc_list_start(conn->internal->thread_pool);
59 }
60
61 /* Packet engine callback to receive a packet */
62
63 static SilcBool silc_client_packet_receive(SilcPacketEngine engine,
64                                            SilcPacketStream stream,
65                                            SilcPacket packet,
66                                            void *callback_context,
67                                            void *stream_context)
68 {
69   SilcClientConnection conn = stream_context;
70   SilcFSMThread thread;
71
72   /* Packets we do not handle */
73   switch (packet->type) {
74   case SILC_PACKET_HEARTBEAT:
75   case SILC_PACKET_SUCCESS:
76   case SILC_PACKET_FAILURE:
77   case SILC_PACKET_REJECT:
78   case SILC_PACKET_KEY_EXCHANGE:
79   case SILC_PACKET_KEY_EXCHANGE_1:
80   case SILC_PACKET_KEY_EXCHANGE_2:
81   case SILC_PACKET_REKEY:
82   case SILC_PACKET_REKEY_DONE:
83   case SILC_PACKET_CONNECTION_AUTH:
84   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
85     return FALSE;
86     break;
87   }
88
89   /* Get packet processing thread */
90   thread = silc_list_get(conn->internal->thread_pool);
91   if (!thread) {
92     thread = silc_fsm_thread_alloc(&conn->internal->fsm, conn,
93                                    silc_client_packet_destructor, NULL, FALSE);
94     if (!thread)
95       return FALSE;
96   } else {
97     silc_list_del(conn->internal->thread_pool, thread);
98     silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
99                          silc_client_packet_destructor, NULL, FALSE);
100   }
101
102   /* Process packet in thread */
103   silc_fsm_set_state_context(thread, packet);
104   silc_fsm_start_sync(thread, silc_client_connection_st_packet);
105
106   return TRUE;
107 }
108
109 /* Packet engine callback to indicate end of stream */
110
111 static void silc_client_packet_eos(SilcPacketEngine engine,
112                                    SilcPacketStream stream,
113                                    void *callback_context,
114                                    void *stream_context)
115 {
116   SILC_LOG_DEBUG(("End of stream received"));
117 }
118
119 /* Packet engine callback to indicate error */
120
121 static void silc_client_packet_error(SilcPacketEngine engine,
122                                      SilcPacketStream stream,
123                                      SilcPacketError error,
124                                      void *callback_context,
125                                      void *stream_context)
126 {
127
128 }
129
130 /* Packet stream callbacks */
131 static SilcPacketCallbacks silc_client_stream_cbs =
132 {
133   silc_client_packet_receive,
134   silc_client_packet_eos,
135   silc_client_packet_error
136 };
137
138 /* FSM destructor */
139
140 void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
141                                 void *destructor_context)
142 {
143   silc_fsm_free(fsm);
144 }
145
146
147 /************************** Connection's machine ****************************/
148
149 /* Start the connection's state machine.  If threads are in use the machine
150    is always executed in a real thread. */
151
152 SILC_FSM_STATE(silc_client_connection_st_start)
153 {
154   SilcClientConnection conn = fsm_context;
155   SilcFSM connfsm;
156
157   /* Take scheduler for connection */
158   conn->internal->schedule = silc_fsm_get_schedule(fsm);
159
160   /*** Run connection machine */
161   connfsm = &conn->internal->fsm;
162   silc_fsm_init(connfsm, conn, silc_client_connection_destructor,
163                 fsm, conn->internal->schedule);
164   silc_fsm_sema_init(&conn->internal->wait_event, connfsm, 0);
165   silc_fsm_start_sync(connfsm, silc_client_connection_st_run);
166
167   /* Schedule any events set in initialization */
168   if (conn->internal->connect)
169     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
170   if (conn->internal->key_exchange)
171     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
172
173   /* Wait until this thread is terminated from the machine destructor */
174   return SILC_FSM_WAIT;
175 }
176
177 /* Connection machine main state.  This handles various connection related
178    events, but not packet processing.  It's done in dedicated packet
179    processing FSM thread. */
180
181 SILC_FSM_STATE(silc_client_connection_st_run)
182 {
183   SilcClientConnection conn = fsm_context;
184   SilcFSMThread thread;
185
186   /* Wait for events */
187   SILC_FSM_SEMA_WAIT(&conn->internal->wait_event);
188
189   /* Process events */
190   thread = &conn->internal->event_thread;
191
192   if (conn->internal->connect) {
193     SILC_LOG_DEBUG(("Event: connect"));
194     conn->internal->connect = FALSE;
195
196     /*** Event: connect */
197     silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
198                          NULL, NULL, FALSE);
199     silc_fsm_start_sync(thread, silc_client_st_connect);
200     return SILC_FSM_CONTINUE;
201   }
202
203   if (conn->internal->key_exchange) {
204     SILC_LOG_DEBUG(("Event: key exchange"));
205     conn->internal->key_exchange = FALSE;
206
207     /*** Event: key exchange */
208     silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
209                          NULL, NULL, FALSE);
210     silc_fsm_start_sync(thread, silc_client_st_connect_set_stream);
211     return SILC_FSM_CONTINUE;
212   }
213
214   if (conn->internal->disconnected) {
215     /** Event: disconnected */
216     SILC_LOG_DEBUG(("Event: disconnected"));
217     conn->internal->disconnected = FALSE;
218     silc_fsm_next(fsm, silc_client_connection_st_close);
219     return SILC_FSM_CONTINUE;
220   }
221
222   /* NOT REACHED */
223   SILC_ASSERT(FALSE);
224   return SILC_FSM_CONTINUE;
225 }
226
227 /* Packet processor thread.  Each incoming packet is processed in FSM
228    thread in this state.  The thread is run in the connection machine. */
229
230 SILC_FSM_STATE(silc_client_connection_st_packet)
231 {
232   SilcPacket packet = state_context;
233
234   SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(packet->type)));
235
236   switch (packet->type) {
237
238   case SILC_PACKET_PRIVATE_MESSAGE:
239     /** Private message */
240     silc_fsm_next(fsm, silc_client_private_message);
241     break;
242
243   case SILC_PACKET_CHANNEL_MESSAGE:
244     /** Channel message */
245     silc_fsm_next(fsm, silc_client_channel_message);
246     break;
247
248   case SILC_PACKET_FTP:
249     /* File transfer packet */
250     //    silc_client_ftp(client, conn, packet);
251     break;
252
253   case SILC_PACKET_CHANNEL_KEY:
254     /** Channel key */
255     silc_fsm_next(fsm, silc_client_channel_key);
256     break;
257
258   case SILC_PACKET_COMMAND_REPLY:
259     /** Command reply */
260     silc_fsm_next(fsm, silc_client_command_reply);
261     break;
262
263   case SILC_PACKET_NOTIFY:
264     /** Notify */
265     silc_fsm_next(fsm, silc_client_notify);
266     break;
267
268   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
269     /* Private message key indicator */
270     silc_fsm_next(fsm, silc_client_private_message_key);
271     break;
272
273   case SILC_PACKET_DISCONNECT:
274     /** Disconnect */
275     silc_fsm_next(fsm, silc_client_disconnect);
276     break;
277
278   case SILC_PACKET_ERROR:
279     /* Error by server */
280     silc_fsm_next(fsm, silc_client_error);
281     break;
282
283   case SILC_PACKET_KEY_AGREEMENT:
284     /** Key agreement */
285     silc_fsm_next(fsm, silc_client_key_agreement);
286     break;
287
288   case SILC_PACKET_COMMAND:
289     /** Command packet */
290     silc_fsm_next(fsm, silc_client_command);
291     break;
292
293   case SILC_PACKET_NEW_ID:
294     /** New ID */
295     silc_fsm_next(fsm, silc_client_new_id);
296     break;
297
298   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
299     /* Reply to connection authentication request to resolve authentication
300        method from server. */
301     //    silc_client_connection_auth_request(client, conn, packet);
302     break;
303
304   default:
305     silc_packet_free(packet);
306     return SILC_FSM_FINISH;
307     break;
308   }
309
310   return SILC_FSM_CONTINUE;
311 }
312
313 /* Disconnection even to close remote connection.  We close the connection
314    and finish the connection machine in this state.  The connection context
315    is deleted in the machine destructor.  The connection callback must be
316    already called back to application before getting here. */
317
318 SILC_FSM_STATE(silc_client_connection_st_close)
319 {
320   SilcClientConnection conn = fsm_context;
321
322   SILC_LOG_DEBUG(("Closing remote connection"));
323
324   /* Abort ongoing events */
325   if (conn->internal->op)
326     silc_async_abort(conn->internal->op, NULL, NULL);
327
328   /* Close connection */
329   silc_packet_stream_destroy(conn->stream);
330
331   SILC_LOG_DEBUG(("Finishing connection machine"));
332
333   return SILC_FSM_FINISH;
334 }
335
336 /* Received error packet from server.  Send it to application. */
337
338 SILC_FSM_STATE(silc_client_error)
339 {
340   SilcClientConnection conn = fsm_context;
341   SilcClient client = conn->client;
342   SilcPacket packet = state_context;
343   char *msg;
344
345   msg = silc_memdup(silc_buffer_data(&packet->buffer),
346                     silc_buffer_len(&packet->buffer));
347   if (msg)
348     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, msg);
349
350   silc_free(msg);
351   silc_packet_free(packet);
352
353   return SILC_FSM_FINISH;
354 }
355
356 /* Received disconnect packet from server.  We close the connection and
357    send the disconnect message to application. */
358
359 SILC_FSM_STATE(silc_client_disconnect)
360 {
361   SilcClientConnection conn = fsm_context;
362   SilcClient client = conn->client;
363   SilcPacket packet = state_context;
364   SilcStatus status;
365   char *message = NULL;
366
367   SILC_LOG_DEBUG(("Server disconnected"));
368
369   if (silc_buffer_len(&packet->buffer) < 1) {
370     silc_packet_free(packet);
371     return SILC_FSM_FINISH;
372   }
373
374   status = (SilcStatus)packet->buffer.data[0];
375
376   silc_buffer_pull(&packet->buffer, 1);
377   if (silc_buffer_len(&packet->buffer) > 1 &&
378       silc_utf8_valid(silc_buffer_data(&packet->buffer),
379                       silc_buffer_len(&packet->buffer)))
380     message = silc_memdup(silc_buffer_data(&packet->buffer),
381                           silc_buffer_len(&packet->buffer));
382
383   /* Call connection callback */
384   conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, status,
385                  message, conn->callback_context);
386
387   silc_free(message);
388   silc_packet_free(packet);
389
390   /* Signal to close connection */
391   if (!conn->internal->disconnected) {
392     conn->internal->disconnected = TRUE;
393     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
394   }
395
396   return SILC_FSM_FINISH;
397 }
398
399 /*************************** Main client machine ****************************/
400
401 /* The client's main state where we wait for various events */
402
403 SILC_FSM_STATE(silc_client_st_run)
404 {
405   SilcClient client = fsm_context;
406
407   /* Wait for events */
408   SILC_FSM_SEMA_WAIT(&client->internal->wait_event);
409
410   /* Process events */
411
412   if (client->internal->run_callback && client->internal->ops->running) {
413     /* Call running callbcak back to application */
414     SILC_LOG_DEBUG(("We are running, call running callback"));
415     client->internal->run_callback = FALSE;
416     client->internal->ops->running(client, client->application);
417     return SILC_FSM_CONTINUE;
418   }
419
420   /* NOT REACHED */
421   SILC_ASSERT(FALSE);
422   return SILC_FSM_CONTINUE;
423 }
424
425 /******************************* Private API ********************************/
426
427 /* Adds new connection.  Creates the connection context and returns it. */
428
429 static SilcClientConnection
430 silc_client_add_connection(SilcClient client,
431                            SilcConnectionType conn_type,
432                            SilcClientConnectionParams *params,
433                            SilcPublicKey public_key,
434                            SilcPrivateKey private_key,
435                            char *remote_host, int port,
436                            SilcClientConnectCallback callback,
437                            void *context)
438 {
439   SilcClientConnection conn;
440   SilcFSMThread thread;
441
442   if (!callback)
443     return NULL;
444
445   SILC_LOG_DEBUG(("Adding new connection to %s:%d", remote_host, port));
446
447   conn = silc_calloc(1, sizeof(*conn));
448   if (!conn)
449     return NULL;
450
451   conn->client = client;
452   conn->public_key = public_key;
453   conn->private_key = private_key;
454   conn->remote_host = strdup(remote_host);
455   conn->remote_port = port ? port : 706;
456   conn->type = conn_type;
457   conn->callback = callback;
458   conn->callback_context = context;
459
460   conn->internal = silc_calloc(1, sizeof(*conn->internal));
461   if (!conn->internal) {
462     silc_free(conn);
463     return NULL;
464   }
465   conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN;
466   silc_mutex_alloc(&conn->internal->lock);
467   silc_atomic_init16(&conn->internal->cmd_ident, 0);
468
469   if (!silc_hash_alloc("sha1", &conn->internal->sha1hash)) {
470     silc_free(conn);
471     silc_free(conn->internal);
472     return NULL;
473   }
474   if (params)
475     conn->internal->params = *params;
476   conn->internal->verbose = TRUE;
477   silc_list_init(conn->internal->pending_commands,
478                  struct SilcClientCommandContextStruct, next);
479   silc_list_init(conn->internal->thread_pool, SilcFSMThreadStruct, next);
480
481   conn->internal->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT,
482                                                     NULL, NULL);
483   conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL,
484                                                      NULL, NULL);
485   conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER,
486                                                     NULL, NULL);
487   if (!conn->internal->client_cache || !conn->internal->channel_cache ||
488       !conn->internal->server_cache) {
489     silc_client_del_connection(client, conn);
490     return NULL;
491   }
492
493   conn->internal->ftp_sessions = silc_dlist_init();
494
495   /* Run the connection state machine.  If threads are in use the machine
496      is always run in a real thread. */
497   thread = silc_fsm_thread_alloc(&client->internal->fsm, conn,
498                                  silc_client_fsm_destructor, NULL,
499                                  client->internal->params->threads);
500   if (!thread) {
501     silc_client_del_connection(client, conn);
502     return NULL;
503   }
504   silc_fsm_start(thread, silc_client_connection_st_start);
505
506   return conn;
507 }
508
509 /* Deletes connection.  This is always called from the connection machine
510    destructor.  Do not call this directly other places. */
511
512 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
513 {
514   SilcList list;
515   SilcIDCacheEntry entry;
516   SilcFSMThread thread;
517   SilcClientCommandContext cmd;
518
519   SILC_LOG_DEBUG(("Freeing connection %p", conn));
520
521   /* Free all cache entries */
522   if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
523     silc_list_start(list);
524     while ((entry = silc_list_get(list)))
525       silc_client_del_client(client, conn, entry->context);
526   }
527   if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
528     silc_list_start(list);
529     while ((entry = silc_list_get(list)))
530       silc_client_del_channel(client, conn, entry->context);
531   }
532   if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
533     silc_list_start(list);
534     while ((entry = silc_list_get(list)))
535       silc_client_del_server(client, conn, entry->context);
536   }
537
538   /* Free ID caches */
539   if (conn->internal->client_cache)
540     silc_idcache_free(conn->internal->client_cache);
541   if (conn->internal->channel_cache)
542     silc_idcache_free(conn->internal->channel_cache);
543   if (conn->internal->server_cache)
544     silc_idcache_free(conn->internal->server_cache);
545
546   /* Free thread pool */
547   silc_list_start(conn->internal->thread_pool);
548   while ((thread = silc_list_get(conn->internal->thread_pool)))
549     silc_fsm_free(thread);
550
551   /* Free pending commands */
552   silc_list_start(conn->internal->pending_commands);
553   while ((cmd = silc_list_get(conn->internal->pending_commands)))
554     silc_client_command_free(cmd);
555
556   silc_free(conn->remote_host);
557   silc_buffer_free(conn->internal->local_idp);
558   silc_buffer_free(conn->internal->remote_idp);
559   silc_mutex_free(conn->internal->lock);
560   if (conn->internal->hash)
561     silc_hash_free(conn->internal->hash);
562   if (conn->internal->sha1hash)
563     silc_hash_free(conn->internal->sha1hash);
564   silc_atomic_uninit16(&conn->internal->cmd_ident);
565
566   silc_free(conn->internal);
567   memset(conn, 'F', sizeof(*conn));
568   silc_free(conn);
569 }
570
571
572 /******************************* Client API *********************************/
573
574 /* Connects to remote server.  This is the main routine used to connect
575    to remote SILC server.  Performs key exchange also.  Returns the
576    connection context to the connection callback. */
577
578 SilcBool silc_client_connect_to_server(SilcClient client,
579                                        SilcClientConnectionParams *params,
580                                        SilcPublicKey public_key,
581                                        SilcPrivateKey private_key,
582                                        char *remote_host, int port,
583                                        SilcClientConnectCallback callback,
584                                        void *context)
585 {
586   SilcClientConnection conn;
587
588   if (!client || !remote_host)
589     return FALSE;
590
591   /* Add new connection */
592   conn = silc_client_add_connection(client, SILC_CONN_SERVER, params,
593                                     public_key, private_key, remote_host,
594                                     port, callback, context);
595   if (!conn) {
596     callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
597     return FALSE;
598   }
599
600   client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
601                              "Connecting to port %d of server %s",
602                              port, remote_host);
603
604   /* Signal connection machine to start connecting */
605   conn->internal->connect = TRUE;
606   return TRUE;
607 }
608
609 /* Connects to remote client.  Performs key exchange also.  Returns the
610    connection context to the connection callback. */
611
612 SilcBool silc_client_connect_to_client(SilcClient client,
613                                        SilcClientConnectionParams *params,
614                                        SilcPublicKey public_key,
615                                        SilcPrivateKey private_key,
616                                        char *remote_host, int port,
617                                        SilcClientConnectCallback callback,
618                                        void *context)
619 {
620   SilcClientConnection conn;
621
622   if (!client || !remote_host)
623     return FALSE;
624
625   /* Add new connection */
626   conn = silc_client_add_connection(client, SILC_CONN_CLIENT, params,
627                                     public_key, private_key, remote_host,
628                                     port, callback, context);
629   if (!conn) {
630     callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
631     return FALSE;
632   }
633
634   /* Signal connection machine to start connecting */
635   conn->internal->connect = TRUE;
636   return TRUE;
637 }
638
639 /* Starts key exchange in the remote stream indicated by `stream'.  This
640    creates the connection context and returns it in the connection callback. */
641
642 SilcBool silc_client_key_exchange(SilcClient client,
643                                   SilcClientConnectionParams *params,
644                                   SilcPublicKey public_key,
645                                   SilcPrivateKey private_key,
646                                   SilcStream stream,
647                                   SilcConnectionType conn_type,
648                                   SilcClientConnectCallback callback,
649                                   void *context)
650 {
651   SilcClientConnection conn;
652   const char *host;
653   SilcUInt16 port;
654
655   if (!client || !stream)
656     return FALSE;
657
658   if (!silc_socket_stream_get_info(stream, NULL, &host, NULL, &port)) {
659     SILC_LOG_ERROR(("Socket stream does not have remote host name set"));
660     callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
661     return FALSE;
662   }
663
664   /* Add new connection */
665   conn = silc_client_add_connection(client, conn_type, params,
666                                     public_key, private_key,
667                                     (char *)host, port, callback, context);
668   if (!conn) {
669     callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
670     return FALSE;
671   }
672   conn->stream = (void *)stream;
673
674   /* Signal connection to start key exchange */
675   conn->internal->key_exchange = TRUE;
676   return TRUE;
677 }
678
679 /* Closes remote connection */
680
681 void silc_client_close_connection(SilcClient client,
682                                   SilcClientConnection conn)
683 {
684   SILC_LOG_DEBUG(("Closing connection %p", conn));
685
686   /* Signal to close connection */
687   if (!conn->internal->disconnected) {
688     conn->internal->disconnected = TRUE;
689     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
690   }
691 }
692
693 #if 0
694 /* Finalizes the connection to the remote SILC server. This is called
695    after authentication protocol has been completed. This send our
696    user information to the server to receive our client ID from
697    server. */
698
699 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
700 {
701   SilcProtocol protocol = (SilcProtocol)context;
702   SilcClientConnAuthInternalContext *ctx =
703     (SilcClientConnAuthInternalContext *)protocol->context;
704   SilcClient client = (SilcClient)ctx->client;
705   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
706   SilcBuffer packet;
707
708   SILC_LOG_DEBUG(("Start"));
709
710   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
711       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
712     /* Error occured during protocol */
713     SILC_LOG_DEBUG(("Error during authentication protocol"));
714     ctx->status = SILC_CLIENT_CONN_ERROR_AUTH;
715     goto err;
716   }
717
718   if (conn->internal->params.detach_data) {
719     /* Send RESUME_CLIENT packet to the server, which is used to resume
720        old detached session back. */
721     SilcBuffer auth;
722     SilcClientID *old_client_id;
723     unsigned char *old_id;
724     SilcUInt16 old_id_len;
725
726     if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len)) {
727       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
728       goto err;
729     }
730
731     old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
732     if (!old_client_id) {
733       silc_free(old_id);
734       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
735       goto err;
736     }
737
738     /* Generate authentication data that server will verify */
739     auth = silc_auth_public_key_auth_generate(client->public_key,
740                                               client->private_key,
741                                               client->rng,
742                                               conn->internal->hash,
743                                               old_client_id, SILC_ID_CLIENT);
744     if (!auth) {
745       silc_free(old_client_id);
746       silc_free(old_id);
747       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
748       goto err;
749     }
750
751     packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
752     silc_buffer_format(packet,
753                        SILC_STR_UI_SHORT(old_id_len),
754                        SILC_STR_UI_XNSTRING(old_id, old_id_len),
755                        SILC_STR_UI_XNSTRING(auth->data, auth->len),
756                        SILC_STR_END);
757
758     /* Send the packet */
759     silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
760                             NULL, 0, NULL, NULL,
761                             packet->data, packet->len, TRUE);
762     silc_buffer_free(packet);
763     silc_buffer_free(auth);
764     silc_free(old_client_id);
765     silc_free(old_id);
766   } else {
767     /* Send NEW_CLIENT packet to the server. We will become registered
768        to the SILC network after sending this packet and we will receive
769        client ID from the server. */
770     packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
771                                strlen(client->realname));
772     silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
773     silc_buffer_format(packet,
774                        SILC_STR_UI_SHORT(strlen(client->username)),
775                        SILC_STR_UI_XNSTRING(client->username,
776                                             strlen(client->username)),
777                        SILC_STR_UI_SHORT(strlen(client->realname)),
778                        SILC_STR_UI_XNSTRING(client->realname,
779                                             strlen(client->realname)),
780                        SILC_STR_END);
781
782     /* Send the packet */
783     silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
784                             NULL, 0, NULL, NULL,
785                             packet->data, packet->len, TRUE);
786     silc_buffer_free(packet);
787   }
788
789   /* Save remote ID. */
790   conn->remote_id = ctx->dest_id;
791   conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
792   conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
793
794   /* Register re-key timeout */
795   conn->internal->rekey->timeout = client->internal->params->rekey_secs;
796   conn->internal->rekey->context = (void *)client;
797   silc_schedule_task_add(client->schedule, conn->sock->sock,
798                          silc_client_rekey_callback,
799                          (void *)conn->sock, conn->internal->rekey->timeout, 0,
800                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
801
802   silc_protocol_free(protocol);
803   silc_free(ctx->auth_data);
804   if (ctx->ske)
805     silc_ske_free(ctx->ske);
806   silc_socket_free(ctx->sock);
807   silc_free(ctx);
808   conn->sock->protocol = NULL;
809   return;
810
811  err:
812   silc_protocol_free(protocol);
813   silc_free(ctx->auth_data);
814   silc_free(ctx->dest_id);
815   if (ctx->ske)
816     silc_ske_free(ctx->ske);
817   conn->sock->protocol = NULL;
818   silc_socket_free(ctx->sock);
819
820   /* Notify application of failure */
821   silc_schedule_task_add(client->schedule, ctx->sock->sock,
822                          silc_client_connect_failure_auth, ctx,
823                          0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
824 }
825
826 /* Client session resuming callback.  If the session was resumed
827    this callback is called after the resuming is completed.  This
828    will call the `connect' client operation to the application
829    since it has not been called yet. */
830
831 static void silc_client_resume_session_cb(SilcClient client,
832                                           SilcClientConnection conn,
833                                           SilcBool success,
834                                           void *context)
835 {
836   SilcBuffer sidp;
837
838   /* Notify application that connection is created to server */
839   client->internal->ops->connected(client, conn, success ?
840                                    SILC_CLIENT_CONN_SUCCESS_RESUME :
841                                    SILC_CLIENT_CONN_ERROR_RESUME);
842
843   if (success) {
844     /* Issue INFO command to fetch the real server name and server
845        information and other stuff. */
846     silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
847                                  silc_client_command_reply_info_i, 0,
848                                  ++conn->cmd_ident);
849     sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
850     silc_client_command_send(client, conn, SILC_COMMAND_INFO,
851                              conn->cmd_ident, 1, 2, sidp->data, sidp->len);
852     silc_buffer_free(sidp);
853   }
854 }
855
856 /* Processes incoming connection authentication method request packet.
857    It is a reply to our previously sent request. The packet can be used
858    to resolve the authentication method for the current session if the
859    client does not know it beforehand. */
860
861 void silc_client_connection_auth_request(SilcClient client,
862                                          SilcClientConnection conn,
863                                          SilcPacketContext *packet)
864 {
865   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
866   SilcUInt16 conn_type, auth_meth;
867   int ret;
868
869   /* If we haven't send our request then ignore this one. */
870   if (!conn->internal->connauth)
871     return;
872
873   /* Parse the payload */
874   ret = silc_buffer_unformat(packet->buffer,
875                              SILC_STR_UI_SHORT(&conn_type),
876                              SILC_STR_UI_SHORT(&auth_meth),
877                              SILC_STR_END);
878   if (ret == -1)
879     auth_meth = SILC_AUTH_NONE;
880
881   /* Call the request callback to notify application for received
882      authentication method information. */
883   if (conn->internal->connauth->callback)
884     (*conn->internal->connauth->callback)(client, conn, auth_meth,
885                                           conn->internal->connauth->context);
886
887   silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
888
889   silc_free(conn->internal->connauth);
890   conn->internal->connauth = NULL;
891 }
892
893 /* Timeout task callback called if the server does not reply to our
894    connection authentication method request in the specified time interval. */
895
896 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
897 {
898   SilcClientConnection conn = (SilcClientConnection)context;
899   SilcClient client = conn->client;
900
901   if (!conn->internal->connauth)
902     return;
903
904   /* Call the request callback to notify application */
905   if (conn->internal->connauth->callback)
906     (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
907                                           conn->internal->connauth->context);
908
909   silc_free(conn->internal->connauth);
910   conn->internal->connauth = NULL;
911 }
912
913 /* This function can be used to request the current authentication method
914    from the server. This may be called when connecting to the server
915    and the client library requests the authentication data from the
916    application. If the application does not know the current authentication
917    method it can request it from the server using this function.
918    The `callback' with `context' will be called after the server has
919    replied back with the current authentication method. */
920
921 void
922 silc_client_request_authentication_method(SilcClient client,
923                                           SilcClientConnection conn,
924                                           SilcConnectionAuthRequest callback,
925                                           void *context)
926 {
927   SilcClientConnAuthRequest connauth;
928   SilcBuffer packet;
929
930   assert(client && conn);
931   connauth = silc_calloc(1, sizeof(*connauth));
932   connauth->callback = callback;
933   connauth->context = context;
934
935   if (conn->internal->connauth)
936     silc_free(conn->internal->connauth);
937
938   conn->internal->connauth = connauth;
939
940   /* Assemble the request packet and send it to the server */
941   packet = silc_buffer_alloc(4);
942   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
943   silc_buffer_format(packet,
944                      SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
945                      SILC_STR_UI_SHORT(SILC_AUTH_NONE),
946                      SILC_STR_END);
947   silc_client_packet_send(client, conn->sock,
948                           SILC_PACKET_CONNECTION_AUTH_REQUEST,
949                           NULL, 0, NULL, NULL,
950                           packet->data, packet->len, FALSE);
951   silc_buffer_free(packet);
952
953   /* Register a timeout in case server does not reply anything back. */
954   connauth->timeout =
955     silc_schedule_task_add(client->schedule, conn->sock->sock,
956                            silc_client_request_authentication_method_timeout,
957                            conn,
958                            client->internal->params->connauth_request_secs, 0,
959                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
960 }
961 #endif /* 0 */
962
963
964 /* Allocates new client object. This has to be done before client may
965    work. After calling this one must call silc_client_init to initialize
966    the client. The `application' is application specific user data pointer
967    and caller must free it. */
968
969 SilcClient silc_client_alloc(SilcClientOperations *ops,
970                              SilcClientParams *params,
971                              void *application,
972                              const char *version_string)
973 {
974   SilcClient new_client;
975
976   new_client = silc_calloc(1, sizeof(*new_client));
977   if (!new_client)
978     return NULL;
979   new_client->application = application;
980
981   new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
982   if (!new_client->internal) {
983     silc_free(new_client);
984     return NULL;
985   }
986   new_client->internal->ops = ops;
987   new_client->internal->params =
988     silc_calloc(1, sizeof(*new_client->internal->params));
989   if (!version_string)
990     version_string = silc_version_string;
991   new_client->internal->silc_client_version = strdup(version_string);
992
993   if (params)
994     memcpy(new_client->internal->params, params, sizeof(*params));
995
996   if (!new_client->internal->params->rekey_secs)
997     new_client->internal->params->rekey_secs = 3600;
998
999   if (!new_client->internal->params->connauth_request_secs)
1000     new_client->internal->params->connauth_request_secs = 2;
1001
1002   new_client->internal->params->
1003     nickname_format[sizeof(new_client->internal->
1004                            params->nickname_format) - 1] = 0;
1005
1006   return new_client;
1007 }
1008
1009 /* Frees client object and its internals. */
1010
1011 void silc_client_free(SilcClient client)
1012 {
1013   if (client->rng)
1014     silc_rng_free(client->rng);
1015
1016   if (!client->internal->params->dont_register_crypto_library) {
1017     silc_cipher_unregister_all();
1018     silc_pkcs_unregister_all();
1019     silc_hash_unregister_all();
1020     silc_hmac_unregister_all();
1021   }
1022
1023   silc_free(client->username);
1024   silc_free(client->hostname);
1025   silc_free(client->realname);
1026   silc_free(client->internal->params);
1027   silc_free(client->internal->silc_client_version);
1028   silc_free(client->internal);
1029   silc_free(client);
1030 }
1031
1032 /* Initializes the client. This makes all the necessary steps to make
1033    the client ready to be run. One must call silc_client_run to run the
1034    client. Returns FALSE if error occured, TRUE otherwise. */
1035
1036 SilcBool silc_client_init(SilcClient client, const char *username,
1037                           const char *hostname, const char *realname)
1038 {
1039   SILC_LOG_DEBUG(("Initializing client"));
1040
1041   if (!client)
1042     return FALSE;
1043
1044   if (!username || !hostname) {
1045     SILC_LOG_ERROR(("Username, hostname and realname must be given to "
1046                     "silc_client_init"));
1047     return FALSE;
1048   }
1049   if (!realname)
1050     realname = username;
1051
1052   /* Validate essential strings */
1053   if (!silc_identifier_verify(username, strlen(username),
1054                               SILC_STRING_UTF8, 128)) {
1055     SILC_LOG_ERROR(("Malformed username '%s'. Username must be UTF-8 string",
1056                     client->username));
1057     return FALSE;
1058   }
1059   if (!silc_identifier_verify(hostname, strlen(hostname),
1060                               SILC_STRING_UTF8, 256)) {
1061     SILC_LOG_ERROR(("Malformed hostname '%s'. Hostname must be UTF-8 string",
1062                     client->hostname));
1063     return FALSE;
1064   }
1065   if (!silc_utf8_valid(realname, strlen(realname))) {
1066     SILC_LOG_ERROR(("Malformed realname '%s'. Realname must be UTF-8 string",
1067                     client->realname));
1068     return FALSE;
1069   }
1070
1071   /* Take the name strings */
1072   client->username = strdup(username);
1073   client->hostname = strdup(hostname);
1074   client->realname = strdup(realname);
1075   if (!username || !hostname || !realname)
1076     return FALSE;
1077
1078   if (!client->internal->params->dont_register_crypto_library) {
1079     /* Initialize the crypto library.  If application has done this already
1080        this has no effect.  Also, we will not be overriding something
1081        application might have registered earlier. */
1082     silc_cipher_register_default();
1083     silc_pkcs_register_default();
1084     silc_hash_register_default();
1085     silc_hmac_register_default();
1086   }
1087
1088   /* Initialize random number generator */
1089   client->rng = silc_rng_alloc();
1090   if (!client->rng)
1091     return FALSE;
1092   silc_rng_init(client->rng);
1093   silc_rng_global_init(client->rng);
1094
1095   /* Initialize the scheduler */
1096   client->schedule = silc_schedule_init(0, client);
1097   if (!client->schedule)
1098     return FALSE;
1099
1100   /* Start packet engine */
1101   client->internal->packet_engine =
1102     silc_packet_engine_start(client->rng, FALSE, &silc_client_stream_cbs,
1103                              client);
1104   if (!client->internal->packet_engine)
1105     return FALSE;
1106
1107   /* Allocate client lock */
1108   silc_mutex_alloc(&client->internal->lock);
1109
1110   /* Register commands */
1111   silc_client_commands_register(client);
1112
1113   /* Initialize and start the client FSM */
1114   silc_fsm_init(&client->internal->fsm, client, NULL, NULL, client->schedule);
1115   silc_fsm_sema_init(&client->internal->wait_event, &client->internal->fsm, 0);
1116   silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run);
1117
1118   /* Signal the application when we are running */
1119   client->internal->run_callback = TRUE;
1120   SILC_FSM_SEMA_POST(&client->internal->wait_event);
1121
1122   return TRUE;
1123 }
1124
1125 /* Stops the client. This is called to stop the client and thus to stop
1126    the program. */
1127
1128 void silc_client_stop(SilcClient client)
1129 {
1130   SILC_LOG_DEBUG(("Stopping client"));
1131
1132   silc_schedule_stop(client->schedule);
1133   silc_schedule_uninit(client->schedule);
1134   silc_client_commands_unregister(client);
1135
1136   SILC_LOG_DEBUG(("Client stopped"));
1137 }
1138
1139 /* Starts the SILC client FSM machine and blocks here.  When this returns
1140    the client has ended. */
1141
1142 void silc_client_run(SilcClient client)
1143 {
1144   SILC_LOG_DEBUG(("Starting SILC client"));
1145
1146   /* Run the scheduler */
1147   silc_schedule(client->schedule);
1148 }
1149
1150 /* Call scheduler one iteration and return.  This cannot be called if threads
1151    are in use. */
1152
1153 void silc_client_run_one(SilcClient client)
1154 {
1155   silc_schedule_one(client->schedule, 0);
1156 }