More client library rewrites (key agreement, plus other).
[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 TRUE;
53 }
54
55 /****************************** NEW_ID packet *******************************/
56
57 /* Received new ID packet from server during registering to SILC network */
58
59 SILC_FSM_STATE(silc_client_new_id)
60 {
61   SilcClientConnection conn = fsm_context;
62   SilcClient client = conn->client;
63   SilcPacket packet = state_context;
64   SilcID id;
65
66   if (conn->local_id)
67     goto out;
68
69   SILC_LOG_DEBUG(("New ID received from server"));
70
71   if (!silc_id_payload_parse_id(silc_buffer_data(&packet->buffer),
72                                 silc_buffer_len(&packet->buffer), &id))
73     goto out;
74
75   SILC_LOG_DEBUG(("New ID %s", silc_id_render(&id.u.client_id,
76                                               SILC_ID_CLIENT)));
77
78   /* Create local client entry */
79   conn->local_entry = silc_client_add_client(client, conn,
80                                              client->username,
81                                              client->username,
82                                              client->realname,
83                                              &id.u.client_id, 0);
84   if (!conn->local_entry)
85     goto out;
86
87   /* Save the ID */
88   conn->local_id = &conn->local_entry->id;
89   conn->internal->local_idp = silc_buffer_copy(&packet->buffer);
90
91   /* Save cache entry */
92   silc_mutex_lock(conn->internal->lock);
93   if (!silc_idcache_find_by_id_one(conn->internal->client_cache,
94                                    conn->local_id,
95                                    &conn->internal->local_entry)) {
96     silc_mutex_unlock(conn->internal->lock);
97     goto out;
98   }
99   silc_mutex_unlock(conn->internal->lock);
100
101   /* Save remote ID */
102   if (packet->src_id_len) {
103     conn->internal->remote_idp =
104       silc_id_payload_encode_data(packet->src_id,
105                                   packet->src_id_len,
106                                   packet->src_id_type);
107     if (!conn->internal->remote_idp)
108       goto out;
109     silc_id_payload_parse_id(silc_buffer_data(conn->internal->remote_idp),
110                              silc_buffer_len(conn->internal->remote_idp),
111                              &conn->remote_id);
112   }
113
114   /* Set IDs to the packet stream */
115   silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id,
116                       conn->remote_id.type, SILC_ID_GET_ID(conn->remote_id));
117
118   /* Signal connection that new ID was received so it can continue
119      with the registering. */
120   if (conn->internal->registering)
121     silc_fsm_continue_sync(&conn->internal->event_thread);
122
123  out:
124   /** Packet processed */
125   silc_packet_free(packet);
126   return SILC_FSM_FINISH;
127 }
128
129
130 /************************ Register to SILC network **************************/
131
132 /* Register to network */
133
134 SILC_FSM_STATE(silc_client_st_register)
135 {
136   SilcClientConnection conn = fsm_context;
137   SilcClient client = conn->client;
138
139   SILC_LOG_DEBUG(("Register to network"));
140
141   /* Send NEW_CLIENT packet to register to network */
142   if (!silc_packet_send_va(conn->stream, SILC_PACKET_NEW_CLIENT, 0,
143                            SILC_STR_UI_SHORT(strlen(client->username)),
144                            SILC_STR_DATA(client->username,
145                                          strlen(client->username)),
146                            SILC_STR_UI_SHORT(strlen(client->realname)),
147                            SILC_STR_DATA(client->realname,
148                                          strlen(client->realname)),
149                            SILC_STR_END)) {
150     /** Error sending packet */
151     silc_fsm_next(fsm, silc_client_st_register_error);
152     return SILC_FSM_CONTINUE;
153   }
154
155   /** Wait for new ID */
156   conn->internal->registering = TRUE;
157   silc_fsm_next_later(fsm, silc_client_st_register_complete,
158                       conn->internal->retry_timer, 0);
159   return SILC_FSM_WAIT;
160 }
161
162 /* Wait for NEW_ID packet to arrive */
163
164 SILC_FSM_STATE(silc_client_st_register_complete)
165 {
166   SilcClientConnection conn = fsm_context;
167   SilcClient client = conn->client;
168
169   if (!conn->local_id) {
170     if (conn->internal->retry_count++ >= SILC_CLIENT_RETRY_COUNT) {
171       /** Timeout, ID not received */
172       conn->internal->registering = FALSE;
173       conn->internal->retry_count = 0;
174       conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN;
175       silc_fsm_next(fsm, silc_client_st_register_error);
176       return SILC_FSM_CONTINUE;
177     }
178
179     /** Resend registering packet */
180     silc_fsm_next(fsm, silc_client_st_register);
181     conn->internal->retry_timer = ((conn->internal->retry_timer *
182                                    SILC_CLIENT_RETRY_MUL) +
183                                    (silc_rng_get_rn16(client->rng) %
184                                     SILC_CLIENT_RETRY_RAND));
185     return SILC_FSM_CONTINUE;
186   }
187
188   SILC_LOG_DEBUG(("Registered to network"));
189
190   /* Issue IDENTIFY command for itself to get resolved hostname
191      correctly from server. */
192   silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
193                            silc_client_register_command_called, NULL,
194                            1, 5, silc_buffer_data(conn->internal->local_idp),
195                            silc_buffer_len(conn->internal->local_idp));
196
197   /* Call NICK command if the nickname was set by the application (and is
198      not same as the username). */
199   if (conn->internal->params.nickname &&
200       !silc_utf8_strcasecmp(conn->internal->params.nickname, client->username))
201     silc_client_command_call(client, conn, NULL,
202                              "NICK", conn->internal->params.nickname, NULL);
203
204   /* Issue INFO command to fetch the real server name and server
205      information and other stuff. */
206   silc_client_command_send(client, conn, SILC_COMMAND_INFO,
207                            silc_client_register_command_called, NULL,
208                            1, 2, silc_buffer_data(conn->internal->remote_idp),
209                            silc_buffer_len(conn->internal->remote_idp));
210
211   /* Call connection callback.  We are now inside SILC network. */
212   conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
213                  conn->callback_context);
214
215   conn->internal->registering = FALSE;
216   silc_schedule_task_del_by_context(conn->internal->schedule, conn);
217
218   return SILC_FSM_FINISH;
219 }
220
221 /* Error registering to network */
222
223 SILC_FSM_STATE(silc_client_st_register_error)
224 {
225   SilcClientConnection conn = fsm_context;
226   SilcClient client = conn->client;
227
228   SILC_LOG_DEBUG(("Error registering to network"));
229
230   /* Signal to close connection */
231   if (!conn->internal->disconnected) {
232     conn->internal->disconnected = TRUE;
233     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
234   }
235
236   /* Call connect callback */
237   conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
238                  conn->callback_context);
239
240   silc_schedule_task_del_by_context(conn->internal->schedule, conn);
241
242   return SILC_FSM_FINISH;
243 }
244
245
246 /************************* Resume detached session **************************/
247
248 /* Resume detached session */
249
250 SILC_FSM_STATE(silc_client_st_resume)
251 {
252   SilcClientConnection conn = fsm_context;
253   SilcClient client = conn->client;
254   SilcClientResumeSession resume;
255   SilcBuffer auth;
256   unsigned char *id;
257   SilcUInt16 id_len;
258   int ret;
259
260   SILC_LOG_DEBUG(("Resuming detached session"));
261
262   resume = silc_calloc(1, sizeof(*resume));
263   if (!resume) {
264     /** Out of memory */
265     silc_fsm_next(fsm, silc_client_st_resume_error);
266     return SILC_FSM_CONTINUE;
267   }
268   silc_fsm_set_state_context(fsm, resume);
269
270   silc_buffer_set(&resume->detach, conn->internal->params.detach_data,
271                   conn->internal->params.detach_data_len);
272   SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(&resume->detach),
273                    silc_buffer_len(&resume->detach));
274
275   /* Take the old client ID from the detachment data */
276   ret = silc_buffer_unformat(&resume->detach,
277                              SILC_STR_ADVANCE,
278                              SILC_STR_UI16_NSTRING_ALLOC(&resume->nickname,
279                                                          NULL),
280                              SILC_STR_UI16_NSTRING(&id, &id_len),
281                              SILC_STR_UI_INT(NULL),
282                              SILC_STR_UI_INT(&resume->channel_count),
283                              SILC_STR_END);
284   if (ret < 0) {
285     /** Malformed detach data */
286     silc_fsm_next(fsm, silc_client_st_resume_error);
287     return SILC_FSM_CONTINUE;
288   }
289
290   if (!silc_id_str2id(id, id_len, SILC_ID_CLIENT, &resume->client_id,
291                       sizeof(resume->client_id))) {
292     /** Malformed ID */
293     silc_fsm_next(fsm, silc_client_st_resume_error);
294     return SILC_FSM_CONTINUE;
295   }
296
297   /* Generate authentication data that server will verify */
298   auth = silc_auth_public_key_auth_generate(conn->public_key,
299                                             conn->private_key,
300                                             client->rng,
301                                             conn->internal->hash,
302                                             &resume->client_id,
303                                             SILC_ID_CLIENT);
304   if (!auth) {
305     /** Out of memory */
306     silc_fsm_next(fsm, silc_client_st_resume_error);
307     return SILC_FSM_CONTINUE;
308   }
309
310   /* Send RESUME_CLIENT packet to resume to network */
311   if (!silc_packet_send_va(conn->stream, SILC_PACKET_RESUME_CLIENT, 0,
312                            SILC_STR_UI_SHORT(id_len),
313                            SILC_STR_UI_XNSTRING(id, id_len),
314                            SILC_STR_UI_XNSTRING(silc_buffer_data(auth),
315                                                 silc_buffer_len(auth)),
316                            SILC_STR_END)) {
317     /** Error sending packet */
318     silc_fsm_next(fsm, silc_client_st_resume_error);
319     return SILC_FSM_CONTINUE;
320   }
321
322   /** Wait for new ID */
323   conn->internal->registering = TRUE;
324   silc_fsm_next_later(fsm, silc_client_st_resume_resolve, 15, 0);
325   return SILC_FSM_WAIT;
326 }
327
328 /* Resolve the old session information */
329
330 SILC_FSM_STATE(silc_client_st_resume_resolve)
331 {
332 #if 0
333   SilcClientConnection conn = fsm_context;
334   SilcClientResumeSession resume = state_context;
335
336   if (!conn->local_id) {
337     /** Timeout, ID not received */
338     conn->internal->registering = FALSE;
339     silc_fsm_next(fsm, silc_client_st_resume_error);
340     return SILC_FSM_CONTINUE;
341   }
342
343
344   for (i = 0; i < ch_count; i++) {
345     char *channel;
346     unsigned char *chid;
347     SilcUInt16 chid_len;
348     SilcUInt32 ch_mode;
349     SilcChannelID *channel_id;
350     SilcChannelEntry channel_entry;
351
352     len = silc_buffer_unformat(&detach,
353                                SILC_STR_UI16_NSTRING_ALLOC(&channel, NULL),
354                                SILC_STR_UI16_NSTRING(&chid, &chid_len),
355                                SILC_STR_UI_INT(&ch_mode),
356                                SILC_STR_END);
357     if (len == -1)
358       return FALSE;
359
360     /* Add new channel */
361     channel_id = silc_id_str2id(chid, chid_len, SILC_ID_CHANNEL);
362     channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
363     if (!channel_entry) {
364       channel_entry = silc_client_add_channel(client, conn, channel, ch_mode,
365                                               channel_id);
366     } else {
367       silc_free(channel);
368       silc_free(channel_id);
369     }
370
371     silc_buffer_pull(&detach, len);
372   }
373 #endif /* 0 */
374
375   return SILC_FSM_FINISH;
376 }
377
378 SILC_FSM_STATE(silc_client_st_resume_error)
379 {
380   /* XXX */
381   /* Close connection */
382
383   return SILC_FSM_FINISH;
384 }
385
386 /* Generates the session detachment data. This data can be used later
387    to resume back to the server. */
388
389 SilcBuffer silc_client_get_detach_data(SilcClient client,
390                                        SilcClientConnection conn)
391 {
392   SilcBuffer detach;
393   SilcHashTableList htl;
394   SilcChannelUser chu;
395   int ret, ch_count;
396
397   SILC_LOG_DEBUG(("Creating detachment data"));
398
399   ch_count = silc_hash_table_count(conn->local_entry->channels);
400
401   /* Save the nickname, Client ID and user mode in SILC network */
402   detach = silc_buffer_alloc(0);
403   if (!detach)
404     return NULL;
405   ret =
406     silc_buffer_format(detach,
407                        SILC_STR_ADVANCE,
408                        SILC_STR_UI_SHORT(strlen(conn->local_entry->nickname)),
409                        SILC_STR_DATA(conn->local_entry->nickname,
410                                      strlen(conn->local_entry->nickname)),
411                        SILC_STR_UI_SHORT(silc_buffer_len(conn->internal->
412                                                          local_idp)),
413                        SILC_STR_DATA(silc_buffer_data(conn->internal->
414                                                       local_idp),
415                                      silc_buffer_len(conn->internal->
416                                                      local_idp)),
417                        SILC_STR_UI_INT(conn->local_entry->mode),
418                        SILC_STR_UI_INT(ch_count),
419                        SILC_STR_END);
420   if (ret < 0) {
421     silc_buffer_free(detach);
422     return NULL;
423   }
424
425   /* Save all joined channels */
426   silc_hash_table_list(conn->local_entry->channels, &htl);
427   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
428     unsigned char chid[32];
429     SilcUInt32 chid_len;
430
431     silc_id_id2str(&chu->channel->id, SILC_ID_CHANNEL, chid, sizeof(chid),
432                    &chid_len);
433     silc_buffer_format(detach,
434                        SILC_STR_ADVANCE,
435                        SILC_STR_UI_SHORT(strlen(chu->channel->channel_name)),
436                        SILC_STR_DATA(chu->channel->channel_name,
437                                      strlen(chu->channel->channel_name)),
438                        SILC_STR_UI_SHORT(chid_len),
439                        SILC_STR_DATA(chid, chid_len),
440                        SILC_STR_UI_INT(chu->channel->mode),
441                        SILC_STR_END);
442     silc_free(chid);
443   }
444   silc_hash_table_list_reset(&htl);
445
446   silc_buffer_start(detach);
447   SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(detach),
448                    silc_buffer_len(detach));
449
450   return detach;
451 }