More client library rewrites (added rekey)
[silc.git] / lib / silcclient / client_register.c
1 /*
2
3   client_register.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 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
20 #include "silc.h"
21 #include "silcclient.h"
22 #include "client_internal.h"
23
24 /************************** Types and definitions ***************************/
25
26 /* Resume session context */
27 typedef struct {
28   SilcClient client;
29   SilcClientConnection conn;
30   SilcBufferStruct detach;
31   char *nickname;
32   SilcClientID client_id;
33   SilcUInt32 channel_count;
34   SilcUInt32 *cmd_idents;
35   SilcUInt32 cmd_idents_count;
36   SilcBool success;
37 } *SilcClientResumeSession;
38
39 /************************ Static utility functions **************************/
40
41 /* Command callback.  Nothing interesting to do here. */
42
43 static SilcBool
44 silc_client_register_command_called(SilcClient client,
45                                     SilcClientConnection conn,
46                                     SilcCommand command,
47                                     SilcStatus status,
48                                     SilcStatus error,
49                                     void *context,
50                                     va_list ap)
51 {
52   return FALSE;
53 }
54
55 /* Continues resuming after resolving.  Continue after last reply. */
56
57 static SilcBool
58 silc_client_resume_continue(SilcClient client,
59                             SilcClientConnection conn,
60                             SilcCommand command,
61                             SilcStatus status,
62                             SilcStatus error,
63                             void *context,
64                             va_list ap)
65 {
66   if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END ||
67       SILC_STATUS_IS_ERROR(status)) {
68     silc_fsm_continue(&conn->internal->event_thread);
69     return FALSE;
70   }
71
72   return TRUE;
73 }
74
75 /****************************** NEW_ID packet *******************************/
76
77 /* Received new ID packet from server during registering to SILC network */
78
79 SILC_FSM_STATE(silc_client_new_id)
80 {
81   SilcClientConnection conn = fsm_context;
82   SilcClient client = conn->client;
83   SilcPacket packet = state_context;
84   SilcID id;
85
86   if (conn->local_id)
87     goto out;
88
89   SILC_LOG_DEBUG(("New ID received from server"));
90
91   if (!silc_id_payload_parse_id(silc_buffer_data(&packet->buffer),
92                                 silc_buffer_len(&packet->buffer), &id))
93     goto out;
94
95   SILC_LOG_DEBUG(("New ID %s", silc_id_render(&id.u.client_id,
96                                               SILC_ID_CLIENT)));
97
98   /* Create local client entry */
99   conn->local_entry = silc_client_add_client(client, conn,
100                                              client->username,
101                                              client->username,
102                                              client->realname,
103                                              &id.u.client_id, 0);
104   if (!conn->local_entry)
105     goto out;
106
107   /* Save the ID */
108   conn->local_id = &conn->local_entry->id;
109   conn->internal->local_idp = silc_buffer_copy(&packet->buffer);
110
111   /* Save cache entry */
112   silc_mutex_lock(conn->internal->lock);
113   if (!silc_idcache_find_by_id_one(conn->internal->client_cache,
114                                    conn->local_id,
115                                    &conn->internal->local_entry)) {
116     silc_mutex_unlock(conn->internal->lock);
117     goto out;
118   }
119   silc_mutex_unlock(conn->internal->lock);
120
121   /* Save remote ID */
122   if (packet->src_id_len) {
123     conn->internal->remote_idp =
124       silc_id_payload_encode_data(packet->src_id,
125                                   packet->src_id_len,
126                                   packet->src_id_type);
127     if (!conn->internal->remote_idp)
128       goto out;
129     silc_id_payload_parse_id(silc_buffer_data(conn->internal->remote_idp),
130                              silc_buffer_len(conn->internal->remote_idp),
131                              &conn->remote_id);
132   }
133
134   /* Set IDs to the packet stream */
135   silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id,
136                       conn->remote_id.type, SILC_ID_GET_ID(conn->remote_id));
137
138   /* Signal connection that new ID was received so it can continue
139      with the registering. */
140   if (conn->internal->registering)
141     silc_fsm_continue_sync(&conn->internal->event_thread);
142
143  out:
144   /** Packet processed */
145   silc_packet_free(packet);
146   return SILC_FSM_FINISH;
147 }
148
149
150 /************************ Register to SILC network **************************/
151
152 /* Register to network */
153
154 SILC_FSM_STATE(silc_client_st_register)
155 {
156   SilcClientConnection conn = fsm_context;
157   SilcClient client = conn->client;
158
159   SILC_LOG_DEBUG(("Register to network"));
160
161   /* Send NEW_CLIENT packet to register to network */
162   if (!silc_packet_send_va(conn->stream, SILC_PACKET_NEW_CLIENT, 0,
163                            SILC_STR_UI_SHORT(strlen(client->username)),
164                            SILC_STR_DATA(client->username,
165                                          strlen(client->username)),
166                            SILC_STR_UI_SHORT(strlen(client->realname)),
167                            SILC_STR_DATA(client->realname,
168                                          strlen(client->realname)),
169                            SILC_STR_END)) {
170     /** Error sending packet */
171     silc_fsm_next(fsm, silc_client_st_register_error);
172     return SILC_FSM_CONTINUE;
173   }
174
175   /** Wait for new ID */
176   conn->internal->registering = TRUE;
177   silc_fsm_next_later(fsm, silc_client_st_register_complete,
178                       conn->internal->retry_timer, 0);
179   return SILC_FSM_WAIT;
180 }
181
182 /* Wait for NEW_ID packet to arrive */
183
184 SILC_FSM_STATE(silc_client_st_register_complete)
185 {
186   SilcClientConnection conn = fsm_context;
187   SilcClient client = conn->client;
188
189   if (!conn->local_id) {
190     if (conn->internal->retry_count++ >= SILC_CLIENT_RETRY_COUNT) {
191       /** Timeout, ID not received */
192       conn->internal->registering = FALSE;
193       conn->internal->retry_count = 0;
194       conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN;
195       silc_fsm_next(fsm, silc_client_st_register_error);
196       return SILC_FSM_CONTINUE;
197     }
198
199     /** Resend registering packet */
200     silc_fsm_next(fsm, silc_client_st_register);
201     conn->internal->retry_timer = ((conn->internal->retry_timer *
202                                     SILC_CLIENT_RETRY_MUL) +
203                                    (silc_rng_get_rn16(client->rng) %
204                                     SILC_CLIENT_RETRY_RAND));
205     return SILC_FSM_CONTINUE;
206   }
207
208   SILC_LOG_DEBUG(("Registered to network"));
209
210   /* Issue IDENTIFY command for itself to get resolved hostname
211      correctly from server. */
212   silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
213                            silc_client_register_command_called, NULL,
214                            1, 5, silc_buffer_data(conn->internal->local_idp),
215                            silc_buffer_len(conn->internal->local_idp));
216
217   /* Call NICK command if the nickname was set by the application (and is
218      not same as the username). */
219   if (conn->internal->params.nickname &&
220       !silc_utf8_strcasecmp(conn->internal->params.nickname, client->username))
221     silc_client_command_call(client, conn, NULL,
222                              "NICK", conn->internal->params.nickname, NULL);
223
224   /* Issue INFO command to fetch the real server name and server
225      information and other stuff. */
226   silc_client_command_send(client, conn, SILC_COMMAND_INFO,
227                            silc_client_register_command_called, NULL,
228                            1, 2, silc_buffer_data(conn->internal->remote_idp),
229                            silc_buffer_len(conn->internal->remote_idp));
230
231   /* Call connection callback.  We are now inside SILC network. */
232   conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
233                  conn->callback_context);
234
235   conn->internal->registering = FALSE;
236   silc_schedule_task_del_by_all(conn->internal->schedule, 0,
237                                 silc_client_connect_timeout, conn);
238
239   return SILC_FSM_FINISH;
240 }
241
242 /* Error registering to network */
243
244 SILC_FSM_STATE(silc_client_st_register_error)
245 {
246   SilcClientConnection conn = fsm_context;
247   SilcClient client = conn->client;
248
249   SILC_LOG_DEBUG(("Error registering to network"));
250
251   /* Signal to close connection */
252   if (!conn->internal->disconnected) {
253     conn->internal->disconnected = TRUE;
254     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
255   }
256
257   /* Call connect callback */
258   conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
259                  conn->callback_context);
260
261   silc_schedule_task_del_by_all(conn->internal->schedule, 0,
262                                 silc_client_connect_timeout, conn);
263
264   return SILC_FSM_FINISH;
265 }
266
267 /************************* Resume detached session **************************/
268
269 /* Resume detached session */
270
271 SILC_FSM_STATE(silc_client_st_resume)
272 {
273   SilcClientConnection conn = fsm_context;
274   SilcClient client = conn->client;
275   SilcClientResumeSession resume;
276   SilcBuffer auth;
277   unsigned char *id;
278   SilcUInt16 id_len;
279   int ret;
280
281   SILC_LOG_DEBUG(("Resuming detached session"));
282
283   resume = silc_calloc(1, sizeof(*resume));
284   if (!resume) {
285     /** Out of memory */
286     silc_fsm_next(fsm, silc_client_st_resume_error);
287     return SILC_FSM_CONTINUE;
288   }
289   silc_fsm_set_state_context(fsm, resume);
290
291   silc_buffer_set(&resume->detach, conn->internal->params.detach_data,
292                   conn->internal->params.detach_data_len);
293   SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(&resume->detach),
294                    silc_buffer_len(&resume->detach));
295
296   /* Take the old client ID from the detachment data */
297   ret = silc_buffer_unformat(&resume->detach,
298                              SILC_STR_ADVANCE,
299                              SILC_STR_UI16_NSTRING_ALLOC(&resume->nickname,
300                                                          NULL),
301                              SILC_STR_UI16_NSTRING(&id, &id_len),
302                              SILC_STR_UI_INT(NULL),
303                              SILC_STR_UI_INT(&resume->channel_count),
304                              SILC_STR_END);
305   if (ret < 0) {
306     /** Malformed detach data */
307     silc_fsm_next(fsm, silc_client_st_resume_error);
308     return SILC_FSM_CONTINUE;
309   }
310
311   if (!silc_id_str2id(id, id_len, SILC_ID_CLIENT, &resume->client_id,
312                       sizeof(resume->client_id))) {
313     /** Malformed ID */
314     silc_fsm_next(fsm, silc_client_st_resume_error);
315     return SILC_FSM_CONTINUE;
316   }
317
318   /* Generate authentication data that server will verify */
319   auth = silc_auth_public_key_auth_generate(conn->public_key,
320                                             conn->private_key,
321                                             client->rng,
322                                             conn->internal->hash,
323                                             &resume->client_id,
324                                             SILC_ID_CLIENT);
325   if (!auth) {
326     /** Out of memory */
327     silc_fsm_next(fsm, silc_client_st_resume_error);
328     return SILC_FSM_CONTINUE;
329   }
330
331   /* Send RESUME_CLIENT packet to resume to network */
332   if (!silc_packet_send_va(conn->stream, SILC_PACKET_RESUME_CLIENT, 0,
333                            SILC_STR_UI_SHORT(id_len),
334                            SILC_STR_DATA(id, id_len),
335                            SILC_STR_DATA(silc_buffer_data(auth),
336                                          silc_buffer_len(auth)),
337                            SILC_STR_END)) {
338     /** Error sending packet */
339     silc_fsm_next(fsm, silc_client_st_resume_error);
340     return SILC_FSM_CONTINUE;
341   }
342
343   /** Wait for new ID */
344   conn->internal->registering = TRUE;
345   silc_fsm_next_later(fsm, silc_client_st_resume_resolve_channels, 15, 0);
346   return SILC_FSM_WAIT;
347 }
348
349 /* Resolve the old session information, user mode and joined channels. */
350
351 SILC_FSM_STATE(silc_client_st_resume_resolve_channels)
352 {
353   SilcClientConnection conn = fsm_context;
354   SilcClient client = conn->client;
355   SilcClientResumeSession resume = state_context;
356   SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
357   unsigned char **res_argv = NULL;
358   int i;
359
360   if (!conn->local_id) {
361     /** Timeout, ID not received */
362     conn->internal->registering = FALSE;
363     silc_fsm_next(fsm, silc_client_st_resume_error);
364     return SILC_FSM_CONTINUE;
365   }
366
367   /* First, send UMODE command to get our own user mode in the network */
368   SILC_LOG_DEBUG(("Resolving user mode"));
369   silc_client_command_send(client, conn, SILC_COMMAND_UMODE,
370                            silc_client_register_command_called, NULL,
371                            1, 1, silc_buffer_data(conn->internal->local_idp),
372                            silc_buffer_len(conn->internal->local_idp));
373
374   /* Second, send IDENTIFY command for all channels we know about.  These
375      are the channels we've joined to according our detachment data. */
376   for (i = 0; i < resume->channel_count; i++) {
377     SilcChannelID channel_id;
378     unsigned char *chid;
379     SilcUInt16 chid_len;
380     SilcBuffer idp;
381
382     if (silc_buffer_unformat(&resume->detach,
383                              SILC_STR_ADVANCE,
384                              SILC_STR_UI16_NSTRING(NULL, NULL),
385                              SILC_STR_UI16_NSTRING(&chid, &chid_len),
386                              SILC_STR_UI_INT(NULL),
387                              SILC_STR_END) < 0)
388       continue;
389
390     idp = silc_id_payload_encode_data(chid, chid_len, SILC_ID_CHANNEL);
391     if (!idp)
392       continue;
393     res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1));
394     res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
395                                  (res_argc + 1));
396     res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
397                                   (res_argc + 1));
398     res_argv[res_argc] = silc_buffer_steal(idp, &res_argv_lens[res_argc]);
399     res_argv_types[res_argc] = res_argc + 5;
400     res_argc++;
401     silc_buffer_free(idp);
402   }
403
404   /* Send IDENTIFY command */
405   SILC_LOG_DEBUG(("Resolving joined channels"));
406   silc_client_command_send_argv(client, conn, SILC_COMMAND_IDENTIFY,
407                                 silc_client_resume_continue, conn,
408                                 res_argc, res_argv, res_argv_lens,
409                                 res_argv_types);
410
411   for (i = 0; i < resume->channel_count; i++)
412     silc_free(res_argv[i]);
413   silc_free(res_argv);
414   silc_free(res_argv_lens);
415   silc_free(res_argv_types);
416
417   /** Wait for channels */
418   silc_fsm_next(fsm, silc_client_st_resume_resolve_cmodes);
419   return SILC_FSM_WAIT;
420 }
421
422 /* Resolve joined channel modes. */
423
424 SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes)
425 {
426   SilcClientConnection conn = fsm_context;
427   SilcClientResumeSession resume = state_context;
428   SilcHashTableList htl;
429   SilcChannelUser chu;
430
431   SILC_LOG_DEBUG(("Resolving joined channel modes"));
432
433   silc_hash_table_list(conn->local_entry->channels, &htl);
434   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
435
436   }
437   silc_hash_table_list_reset(&htl);
438
439   return SILC_FSM_FINISH;
440 }
441
442 SILC_FSM_STATE(silc_client_st_resume_error)
443 {
444   /* XXX */
445   /* Close connection */
446
447   return SILC_FSM_FINISH;
448 }
449
450 /* Generates the session detachment data. This data can be used later
451    to resume back to the server. */
452
453 SilcBuffer silc_client_get_detach_data(SilcClient client,
454                                        SilcClientConnection conn)
455 {
456   SilcBuffer detach;
457   SilcHashTableList htl;
458   SilcChannelUser chu;
459   int ret, ch_count;
460
461   SILC_LOG_DEBUG(("Creating detachment data"));
462
463   ch_count = silc_hash_table_count(conn->local_entry->channels);
464
465   /* Save the nickname, Client ID and user mode in SILC network */
466   detach = silc_buffer_alloc(0);
467   if (!detach)
468     return NULL;
469   ret =
470     silc_buffer_format(detach,
471                        SILC_STR_ADVANCE,
472                        SILC_STR_UI_SHORT(strlen(conn->local_entry->nickname)),
473                        SILC_STR_DATA(conn->local_entry->nickname,
474                                      strlen(conn->local_entry->nickname)),
475                        SILC_STR_UI_SHORT(silc_buffer_len(conn->internal->
476                                                          local_idp)),
477                        SILC_STR_DATA(silc_buffer_data(conn->internal->
478                                                       local_idp),
479                                      silc_buffer_len(conn->internal->
480                                                      local_idp)),
481                        SILC_STR_UI_INT(conn->local_entry->mode),
482                        SILC_STR_UI_INT(ch_count),
483                        SILC_STR_END);
484   if (ret < 0) {
485     silc_buffer_free(detach);
486     return NULL;
487   }
488
489   /* Save all joined channels */
490   silc_hash_table_list(conn->local_entry->channels, &htl);
491   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
492     unsigned char chid[32];
493     SilcUInt32 chid_len;
494
495     silc_id_id2str(&chu->channel->id, SILC_ID_CHANNEL, chid, sizeof(chid),
496                    &chid_len);
497     silc_buffer_format(detach,
498                        SILC_STR_ADVANCE,
499                        SILC_STR_UI_SHORT(strlen(chu->channel->channel_name)),
500                        SILC_STR_DATA(chu->channel->channel_name,
501                                      strlen(chu->channel->channel_name)),
502                        SILC_STR_UI_SHORT(chid_len),
503                        SILC_STR_DATA(chid, chid_len),
504                        SILC_STR_UI_INT(chu->channel->mode),
505                        SILC_STR_END);
506     silc_free(chid);
507   }
508   silc_hash_table_list_reset(&htl);
509
510   silc_buffer_start(detach);
511   SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(detach),
512                    silc_buffer_len(detach));
513
514   return detach;
515 }