Merged silc_1_1_branch to trunk.
[silc.git] / lib / silcapputil / silcapputil.c
1 /*
2
3   silcapputil.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2007 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
23 static char *silc_create_pk_identifier(void)
24 {
25   char *username = NULL, *realname = NULL;
26   char *hostname, email[256];
27   char *ident;
28
29   /* Get realname */
30   realname = silc_get_real_name();
31
32   /* Get hostname */
33   hostname = silc_net_localhost();
34   if (!hostname)
35     return NULL;
36
37   /* Get username (mandatory) */
38   username = silc_get_username();
39   if (!username)
40     return NULL;
41
42   /* Create default email address, whether it is right or not */
43   silc_snprintf(email, sizeof(email), "%s@%s", username, hostname);
44
45   ident = silc_pkcs_silc_encode_identifier(username, hostname, realname,
46                                            email, NULL, NULL, NULL);
47   if (realname)
48     silc_free(realname);
49   silc_free(hostname);
50   silc_free(username);
51
52   return ident;
53 }
54
55 /* Generate key pair */
56
57 SilcBool silc_create_key_pair(const char *pkcs_name,
58                               SilcUInt32 key_len_bits,
59                               const char *pub_filename,
60                               const char *prv_filename,
61                               const char *pub_identifier,
62                               const char *passphrase,
63                               SilcPublicKey *return_public_key,
64                               SilcPrivateKey *return_private_key,
65                               SilcBool interactive)
66 {
67   SilcRng rng;
68   char line[256];
69   char *pkfile = pub_filename ? strdup(pub_filename) : NULL;
70   char *prvfile = prv_filename ? strdup(prv_filename) : NULL;
71   char *alg = pkcs_name ? strdup(pkcs_name) : NULL;
72   char *identifier = pub_identifier ? strdup(pub_identifier) : NULL;
73   char *pass = passphrase ? strdup(passphrase) : NULL;
74   SilcPublicKey public_key;
75   SilcPrivateKey private_key;
76
77   if (interactive && (!alg || !pub_filename || !prv_filename))
78     printf("\
79 New pair of keys will be created.  Please, answer to following questions.\n\
80 ");
81
82   if (!alg) {
83     if (interactive) {
84       while (!alg) {
85         alg = silc_get_input("PKCS name (l to list names) [rsa]: ", FALSE);
86         if (!alg)
87           alg = strdup("rsa");
88
89         if (*alg == 'l' || *alg == 'L') {
90           char *list = silc_pkcs_get_supported();
91           printf("%s\n", list);
92           silc_free(list);
93           silc_free(alg);
94           alg = NULL;
95         }
96       }
97     } else {
98       alg = strdup("rsa");
99     }
100   }
101
102   if (!silc_pkcs_find_algorithm(alg, NULL)) {
103     fprintf(stderr, "Unknown PKCS algorithm `%s' or crypto library"
104             "is not initialized", alg);
105     return FALSE;
106   }
107
108   if (!key_len_bits) {
109     if (interactive) {
110       char *length = NULL;
111       length = silc_get_input("Key length in key_len_bits [2048]: ", FALSE);
112       if (length)
113         key_len_bits = atoi(length);
114       silc_free(length);
115     }
116     if (!key_len_bits)
117       key_len_bits = 2048;
118   }
119
120   if (!identifier) {
121     char *def = silc_create_pk_identifier();
122
123     if (interactive) {
124       memset(line, 0, sizeof(line));
125       if (def)
126         silc_snprintf(line, sizeof(line), "Identifier [%s]: ", def);
127       else
128         silc_snprintf(line, sizeof(line),
129                "Identifier (eg. UN=jon, HN=jon.dummy.com, "
130                "RN=Jon Johnson, E=jon@dummy.com): ");
131
132       while (!identifier) {
133         identifier = silc_get_input(line, FALSE);
134         if (!identifier && def)
135           identifier = strdup(def);
136       }
137     } else {
138       if (!def) {
139         fprintf(stderr, "Could not create public key identifier: %s\n",
140                 strerror(errno));
141         return FALSE;
142       }
143       identifier = strdup(def);
144     }
145
146     silc_free(def);
147   }
148
149   if (!strstr(identifier, "UN=") || !strstr(identifier, "HN=")) {
150     fprintf(stderr, "Invalid public key identifier.  You must specify both "
151             "UN and HN\n");
152     return FALSE;
153   }
154
155   rng = silc_rng_alloc();
156   silc_rng_init(rng);
157   silc_rng_global_init(rng);
158
159   if (!pkfile) {
160     if (interactive) {
161       memset(line, 0, sizeof(line));
162       silc_snprintf(line, sizeof(line), "Public key filename [public_key.pub]: ");
163       pkfile = silc_get_input(line, FALSE);
164     }
165     if (!pkfile)
166       pkfile = strdup("public_key.pub");
167   }
168
169   if (!prvfile) {
170     if (interactive) {
171       memset(line, 0, sizeof(line));
172       silc_snprintf(line, sizeof(line), "Private key filename [private_key.prv]: ");
173       prvfile = silc_get_input(line, FALSE);
174     }
175     if (!prvfile)
176       prvfile = strdup("private_key.prv");
177   }
178
179   if (!pass) {
180     while (TRUE) {
181       char *pass2 = NULL;
182       pass = silc_get_input("Private key passphrase: ", TRUE);
183       if (!pass) {
184         pass = strdup("");
185         break;
186       } else {
187         SilcBool match;
188         printf("\n");
189         pass2 = silc_get_input("Retype private key passphrase: ", TRUE);
190         if (!pass2)
191           pass2 = strdup("");
192         match = !strcmp(pass, pass2);
193         silc_free(pass2);
194         if (match)
195           break;
196         fprintf(stderr, "\nPassphrases do not match\n\n");
197       }
198     }
199   }
200
201   if (interactive)
202     printf("\nGenerating the key pair...\n");
203
204   /* Generate keys */
205   if (!silc_pkcs_silc_generate_key(alg, key_len_bits,
206                                    identifier, rng, &public_key,
207                                    &private_key))
208     return FALSE;
209
210   /* Save public key into file */
211   if (!silc_pkcs_save_public_key(pkfile, public_key, SILC_PKCS_FILE_BASE64))
212     return FALSE;
213
214   /* Save private key into file */
215   if (!silc_pkcs_save_private_key(prvfile, private_key,
216                                   (const unsigned char *)pass, strlen(pass),
217                                   SILC_PKCS_FILE_BIN, rng))
218     return FALSE;
219
220   if (return_public_key)
221     *return_public_key = public_key;
222   else
223     silc_pkcs_public_key_free(public_key);
224
225   if (return_private_key)
226     *return_private_key = private_key;
227   else
228     silc_pkcs_private_key_free(private_key);
229
230   printf("Public key has been saved into `%s'.\n", pkfile);
231   printf("Private key has been saved into `%s'.\n", prvfile);
232   if (interactive) {
233     printf("Press <Enter> to continue...\n");
234     getchar();
235   }
236
237   silc_rng_free(rng);
238   silc_free(alg);
239   silc_free(pkfile);
240   silc_free(prvfile);
241   silc_free(identifier);
242   memset(pass, 0, strlen(pass));
243   silc_free(pass);
244
245   return TRUE;
246 }
247
248 /* Load key pair */
249
250 SilcBool silc_load_key_pair(const char *pub_filename,
251                             const char *prv_filename,
252                             const char *passphrase,
253                             SilcPublicKey *return_public_key,
254                             SilcPrivateKey *return_private_key)
255 {
256   char *pass = passphrase ? strdup(passphrase) : NULL;
257
258   SILC_LOG_DEBUG(("Loading public and private keys"));
259
260   if (!silc_pkcs_load_public_key(pub_filename, return_public_key)) {
261     if (pass)
262       memset(pass, 0, strlen(pass));
263     silc_free(pass);
264     return FALSE;
265   }
266
267   if (!pass) {
268     pass = silc_get_input("Private key passphrase: ", TRUE);
269     if (!pass)
270       pass = strdup("");
271   }
272
273   if (!silc_pkcs_load_private_key(prv_filename,
274                                   (const unsigned char *)pass, strlen(pass),
275                                   return_private_key)) {
276     silc_pkcs_public_key_free(*return_public_key);
277     *return_public_key = NULL;
278     memset(pass, 0, strlen(pass));
279     silc_free(pass);
280     return FALSE;
281   }
282
283   memset(pass, 0, strlen(pass));
284   silc_free(pass);
285   return TRUE;
286 }
287
288 /* Dump public key into stdout */
289
290 SilcBool silc_show_public_key(SilcPublicKey public_key)
291 {
292   SilcSILCPublicKey silc_pubkey;
293   SilcPublicKeyIdentifier ident;
294   char *fingerprint, *babbleprint;
295   unsigned char *pk;
296   SilcUInt32 pk_len;
297   SilcUInt32 key_len = 0;
298
299   silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
300   if (!silc_pubkey)
301     return FALSE;
302
303   ident = &silc_pubkey->identifier;
304   key_len = silc_pkcs_public_key_get_len(public_key);
305   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
306   if (!pk)
307     return FALSE;
308   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
309   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
310
311   printf("Algorithm          : %s\n", silc_pkcs_get_name(public_key));
312   if (key_len)
313     printf("Key length (bits)  : %d\n", (unsigned int)key_len);
314   if (ident->version)
315     printf("Version            : %s\n", ident->version);
316   if (ident->realname)
317     printf("Real name          : %s\n", ident->realname);
318   if (ident->username)
319     printf("Username           : %s\n", ident->username);
320   if (ident->host)
321     printf("Hostname           : %s\n", ident->host);
322   if (ident->email)
323     printf("Email              : %s\n", ident->email);
324   if (ident->org)
325     printf("Organization       : %s\n", ident->org);
326   if (ident->country)
327     printf("Country            : %s\n", ident->country);
328   printf("Fingerprint (SHA1) : %s\n", fingerprint);
329   printf("Babbleprint (SHA1) : %s\n", babbleprint);
330
331   fflush(stdout);
332
333   silc_free(fingerprint);
334   silc_free(babbleprint);
335   silc_free(pk);
336
337   return TRUE;
338 }
339
340 /* Dump public key into stdout */
341
342 SilcBool silc_show_public_key_file(const char *pub_filename)
343 {
344   SilcPublicKey public_key;
345   SilcBool ret;
346
347   if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
348     fprintf(stderr, "Could not load public key file `%s'\n", pub_filename);
349     return FALSE;
350   }
351
352   printf("Public key file    : %s\n", pub_filename);
353   ret = silc_show_public_key(public_key);
354   silc_pkcs_public_key_free(public_key);
355
356   return ret;
357 }
358
359 /* Change private key passphrase */
360
361 SilcBool silc_change_private_key_passphrase(const char *prv_filename,
362                                             const char *old_passphrase,
363                                             const char *new_passphrase)
364 {
365   SilcPrivateKey private_key;
366   char *pass;
367   SilcRng rng;
368
369   pass = old_passphrase ? strdup(old_passphrase) : NULL;
370   if (!pass) {
371     pass = silc_get_input("Old passphrase: ", TRUE);
372     if (!pass)
373       pass = strdup("");
374   }
375
376   if (!silc_pkcs_load_private_key(prv_filename,
377                                   (const unsigned char *)pass, strlen(pass),
378                                   &private_key)) {
379     memset(pass, 0, strlen(pass));
380     silc_free(pass);
381     fprintf(stderr, "Could not load private key `%s' file\n", prv_filename);
382     return FALSE;
383   }
384
385   memset(pass, 0, strlen(pass));
386   silc_free(pass);
387
388   pass = new_passphrase ? strdup(new_passphrase) : NULL;
389   if (!pass) {
390     char *pass2 = NULL;
391     fprintf(stdout, "\n");
392     pass = silc_get_input("New passphrase: ", TRUE);
393     if (!pass) {
394       pass = strdup("");
395     } else {
396       while (TRUE) {
397         printf("\n");
398         pass2 = silc_get_input("Retype new passphrase: ", TRUE);
399         if (!pass2)
400           pass2 = strdup("");
401         if (!strcmp(pass, pass2))
402           break;
403         fprintf(stderr, "\nPassphrases do not match");
404       }
405       silc_free(pass2);
406     }
407   }
408
409   rng = silc_rng_alloc();
410   silc_rng_init(rng);
411
412   silc_pkcs_save_private_key((char *)prv_filename, private_key,
413                              (unsigned char *)pass, strlen(pass),
414                              SILC_PKCS_FILE_BIN, rng);
415
416   fprintf(stdout, "\nPassphrase changed\n");
417
418   memset(pass, 0, strlen(pass));
419   silc_free(pass);
420
421   silc_pkcs_private_key_free(private_key);
422   silc_rng_free(rng);
423
424   return TRUE;
425 }
426
427 /* Checks that the 'identifier' string is valid identifier string
428    and does not contain any unassigned or prohibited character.  This
429    function is used to check for valid nicknames, channel names,
430    server names, usernames, hostnames, service names, algorithm names,
431    other security property names, and SILC Public Key name. */
432
433 unsigned char *silc_identifier_check(const unsigned char *identifier,
434                                      SilcUInt32 identifier_len,
435                                      SilcStringEncoding identifier_encoding,
436                                      SilcUInt32 max_allowed_length,
437                                      SilcUInt32 *out_len)
438 {
439   unsigned char *utf8s;
440   SilcUInt32 utf8s_len;
441   SilcStringprepStatus status;
442
443   if (!identifier || !identifier_len)
444     return NULL;
445
446   if (max_allowed_length && identifier_len > max_allowed_length)
447     return NULL;
448
449   status = silc_stringprep(identifier, identifier_len,
450                            identifier_encoding, SILC_IDENTIFIER_PREP, 0,
451                            &utf8s, &utf8s_len, SILC_STRING_UTF8);
452   if (status != SILC_STRINGPREP_OK) {
453     SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
454     return NULL;
455   }
456
457   if (out_len)
458     *out_len = utf8s_len;
459
460   return utf8s;
461 }
462
463 /* Same as above but does not allocate memory, just checks the
464    validity of the string. */
465
466 SilcBool silc_identifier_verify(const unsigned char *identifier,
467                                 SilcUInt32 identifier_len,
468                                 SilcStringEncoding identifier_encoding,
469                                 SilcUInt32 max_allowed_length)
470 {
471   SilcStringprepStatus status;
472
473   if (!identifier || !identifier_len)
474     return FALSE;
475
476   if (max_allowed_length && identifier_len > max_allowed_length)
477     return FALSE;
478
479   status = silc_stringprep(identifier, identifier_len,
480                            identifier_encoding, SILC_IDENTIFIER_PREP, 0,
481                            NULL, NULL, SILC_STRING_UTF8);
482   if (status != SILC_STRINGPREP_OK) {
483     SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
484     return FALSE;
485   }
486
487   return TRUE;
488 }
489
490 unsigned char *silc_channel_name_check(const unsigned char *identifier,
491                                        SilcUInt32 identifier_len,
492                                        SilcStringEncoding identifier_encoding,
493                                        SilcUInt32 max_allowed_length,
494                                        SilcUInt32 *out_len)
495 {
496   unsigned char *utf8s;
497   SilcUInt32 utf8s_len;
498   SilcStringprepStatus status;
499
500   if (!identifier || !identifier_len)
501     return NULL;
502
503   if (max_allowed_length && identifier_len > max_allowed_length)
504     return NULL;
505
506   status = silc_stringprep(identifier, identifier_len,
507                            identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
508                            &utf8s, &utf8s_len, SILC_STRING_UTF8);
509   if (status != SILC_STRINGPREP_OK) {
510     SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
511     return NULL;
512   }
513
514   if (out_len)
515     *out_len = utf8s_len;
516
517   return utf8s;
518 }
519
520 /* Same as above but does not allocate memory, just checks the
521    validity of the string. */
522
523 SilcBool silc_channel_name_verify(const unsigned char *identifier,
524                                   SilcUInt32 identifier_len,
525                                   SilcStringEncoding identifier_encoding,
526                                   SilcUInt32 max_allowed_length)
527 {
528   SilcStringprepStatus status;
529
530   if (!identifier || !identifier_len)
531     return FALSE;
532
533   if (max_allowed_length && identifier_len > max_allowed_length)
534     return FALSE;
535
536   status = silc_stringprep(identifier, identifier_len,
537                            identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
538                            NULL, NULL, SILC_STRING_UTF8);
539   if (status != SILC_STRINGPREP_OK) {
540     SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
541     return FALSE;
542   }
543
544   return TRUE;
545 }
546
547 /* Return mode list */
548
549 SilcBool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
550                             SilcUInt32 **list)
551 {
552   int i;
553
554   if (silc_buffer_len(mode_list) / 4 != mode_list_count)
555     return FALSE;
556
557   *list = silc_calloc(mode_list_count, sizeof(**list));
558
559   for (i = 0; i < mode_list_count; i++) {
560     SILC_GET32_MSB((*list)[i], mode_list->data);
561     silc_buffer_pull(mode_list, 4);
562   }
563
564   silc_buffer_push(mode_list, mode_list->data - mode_list->head);
565
566   return TRUE;
567 }
568
569 /* Status message structure. Messages are defined below. */
570 typedef struct {
571   SilcStatus status;
572   const char *message;
573 } SilcStatusMessage;
574
575 #define STAT(x) SILC_STATUS_ERR_##x
576 static const SilcStatusMessage silc_status_messages[] = {
577
578   { STAT(NO_SUCH_NICK),      "There was no such nickname" },
579   { STAT(NO_SUCH_CHANNEL),   "There was no such channel" },
580   { STAT(NO_SUCH_SERVER),    "There was no such server" },
581   { STAT(INCOMPLETE_INFORMATION),  "Incomplete registration information" },
582   { STAT(NO_RECIPIENT),      "No recipient given" },
583   { STAT(UNKNOWN_COMMAND),   "Unknown command" },
584   { STAT(WILDCARDS),         "Wilcrads not allowed" },
585   { STAT(NO_CLIENT_ID),      "No Client ID given" },
586   { STAT(NO_CHANNEL_ID),     "No Channel ID given" },
587   { STAT(NO_SERVER_ID),      "No Server ID given" },
588   { STAT(BAD_CLIENT_ID),     "Bad Client ID" },
589   { STAT(BAD_CHANNEL_ID),    "Bad Channel ID" },
590   { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
591   { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
592   { STAT(NICKNAME_IN_USE),   "Nickname already exists" },
593   { STAT(NOT_ON_CHANNEL),    "You are not on that channel" },
594   { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
595   { STAT(USER_ON_CHANNEL),   "User already on the channel" },
596   { STAT(NOT_REGISTERED),    "You have not registered" },
597   { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
598   { STAT(TOO_MANY_PARAMS),   "Too many parameters" },
599   { STAT(PERM_DENIED),       "Permission denied" },
600   { STAT(BANNED_FROM_SERVER),"You are not allowed to connect" },
601   { STAT(BAD_PASSWORD),      "Cannot join channel. Incorrect password" },
602   { STAT(CHANNEL_IS_FULL),   "Cannot join channel. Channel is full" },
603   { STAT(NOT_INVITED),     "Cannot join channel. You have not been invited" },
604   { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
605   { STAT(UNKNOWN_MODE),    "Unknown mode" },
606   { STAT(NOT_YOU),         "Cannot change mode for other users" },
607   { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
608   { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
609   { STAT(NO_SERVER_PRIV),  "Permission denied. You are not server operator" },
610   { STAT(NO_ROUTER_PRIV),  "Permission denied. You are not SILC operator" },
611   { STAT(BAD_NICKNAME),    "Bad nickname" },
612   { STAT(BAD_CHANNEL),     "Bad channel name" },
613   { STAT(AUTH_FAILED),     "Authentication failed" },
614   { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
615   { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
616   { STAT(RESOURCE_LIMIT), "No more free resources" },
617   { STAT(NO_SUCH_SERVICE), "Service doesn't exist" },
618   { STAT(NOT_AUTHENTICATED), "You have not been authenticated" },
619   { STAT(BAD_SERVER_ID), "Server ID is not valid" },
620   { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" },
621   { STAT(BAD_VERSION), "Bad version" },
622   { STAT(TIMEDOUT), "Service timed out" },
623   { STAT(UNSUPPORTED_PUBLIC_KEY), "Unsupported public key type" },
624   { STAT(OPERATION_ALLOWED), "Operation is not allowed" },
625   { STAT(BAD_SERVER), "Bad server name" },
626   { STAT(BAD_USERNAME), "Bad user name" },
627   { STAT(NO_SUCH_PUBLIC_KEY), "Unknown public key" },
628
629   { 0, NULL }
630 };
631
632 /* Returns status message string */
633
634 const char *silc_get_status_message(unsigned char status)
635 {
636   int i;
637
638   for (i = 0; silc_status_messages[i].message; i++) {
639     if (silc_status_messages[i].status == status)
640       break;
641   }
642
643   if (silc_status_messages[i].message == NULL)
644     return "";
645
646   return silc_status_messages[i].message;
647 }
648
649 static const char *packet_name[] = {
650   "NONE",
651   "DISCONNECT",
652   "SUCCESS",
653   "FAILURE",
654   "REJECT",
655   "NOTIFY",
656   "ERROR",
657   "CHANNEL MESSAGE",
658   "CHANNEL KEY",
659   "PRIVATE MESSAGE",
660   "PRIVATE MESSAGE KEY",
661   "COMMAND",
662   "COMMAND REPLY",
663   "KEY EXCHANGE",
664   "KEY EXCHANGE 1",
665   "KEY EXCHANGE 2",
666   "CONNECTION AUTH REQUEST",
667   "CONNECTION AUTH",
668   "NEW ID",
669   "NEW CLIENT",
670   "NEW SERVER",
671   "NEW CHANNEL",
672   "REKEY",
673   "REKEY_DONE",
674   "HEARTBEAT",
675   "KEY AGREEMENT",
676   "RESUME ROUTER",
677   "FTP",
678   "RESUME CLIENT",
679 };
680
681 /* Returns packet type name */
682
683 const char *silc_get_packet_name(unsigned char type)
684 {
685   if (type >= SILC_PACKET_MAX)
686     return "RESERVED";
687   if (type >= SILC_PACKET_PRIVATE)
688     return "PRIVATE RANGE";
689   if (type > (sizeof(packet_name) / sizeof(*packet_name)))
690     return "UNKNOWN";
691   return packet_name[type];
692 }
693
694 static const char *command_name[] = {
695   "NONE",
696   "WHOIS",
697   "WHOWAS",
698   "IDENTIFY",
699   "NICK",
700   "LIST",
701   "TOPIC",
702   "INVITE",
703   "QUIT",
704   "KILL",
705   "INFO",
706   "STATS",
707   "PING",
708   "OPER",
709   "JOIN",
710   "MOTD",
711   "UMODE",
712   "CMODE",
713   "CUMODE",
714   "KICK",
715   "BAN",
716   "DETACH",
717   "WATCH",
718   "SILCOPER",
719   "LEAVE",
720   "USERS",
721   "GETKEY",
722   "SERVICE",
723 };
724
725 /* Returns command name */
726
727 const char *silc_get_command_name(unsigned char command)
728 {
729   if (command >= SILC_COMMAND_RESERVED)
730     return "RESERVED";
731   if (command >= SILC_COMMAND_PRIVATE)
732     return "PRIVATE RANGE";
733   if (command > (sizeof(command_name) / sizeof(*command_name)))
734     return "UNKNOWN";
735   return command_name[command];
736 }
737
738 /* Parses SILC protocol style version string. */
739
740 SilcBool silc_parse_version_string(const char *version,
741                                    SilcUInt32 *protocol_version,
742                                    char **protocol_version_string,
743                                    SilcUInt32 *software_version,
744                                    char **software_version_string,
745                                    char **vendor_version)
746 {
747   char *cp, buf[32];
748   int maj = 0, min = 0;
749
750   if (!strstr(version, "SILC-"))
751     return FALSE;
752
753   cp = (char *)version + 5;
754   if (!cp || !(*cp))
755     return FALSE;
756
757   /* Take protocol version */
758
759   maj = atoi(cp);
760   if (!strchr(cp, '.'))
761     return FALSE;
762   cp = strchr(cp, '.') + 1;
763   if (!cp || !(*cp))
764     return FALSE;
765   min = atoi(cp);
766
767   memset(buf, 0, sizeof(buf));
768   silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
769   if (protocol_version)
770     *protocol_version = atoi(buf);
771   memset(buf, 0, sizeof(buf));
772   silc_snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
773   if (protocol_version_string)
774     *protocol_version_string = strdup(buf);
775
776   /* Take software version */
777
778   maj = 0;
779   min = 0;
780   if (!strchr(cp, '-'))
781     return FALSE;
782   cp = strchr(cp, '-') + 1;
783   if (!cp || !(*cp))
784     return FALSE;
785
786   maj = atoi(cp);
787   if (strchr(cp, '.')) {
788     cp = strchr(cp, '.') + 1;
789     if (cp && *cp)
790       min = atoi(cp);
791   }
792
793   memset(buf, 0, sizeof(buf));
794   silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
795   if (software_version)
796     *software_version = atoi(buf);
797   memset(buf, 0, sizeof(buf));
798   silc_snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
799   if (software_version_string)
800     *software_version_string = strdup(buf);
801
802   /* Take vendor string */
803
804   if (strchr(cp, '.')) {
805     cp = strchr(cp, '.') + 1;
806     if (cp && *cp && vendor_version)
807       *vendor_version = strdup(cp);
808   } else if (strchr(cp, ' ')) {
809     cp = strchr(cp, ' ') + 1;
810     if (cp && *cp && vendor_version)
811       *vendor_version = strdup(cp);
812   }
813
814   return TRUE;
815 }
816
817 /* Converts version string x.x into number representation. */
818
819 SilcUInt32 silc_version_to_num(const char *version)
820 {
821   int maj = 0, min = 0;
822   char *cp, buf[32];
823
824   if (!version)
825     return 0;
826
827   cp = (char *)version;
828   maj = atoi(cp);
829   cp = strchr(cp, '.');
830   if (cp)
831     min = atoi(cp + 1);
832
833   memset(buf, 0, sizeof(buf));
834   silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
835   return (SilcUInt32)atoi(buf);
836 }
837
838 /* Parses mode mask and returns the mode as string. */
839
840 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
841 {
842   char string[100];
843
844   if (!mode)
845     return NULL;
846
847   memset(string, 0, sizeof(string));
848
849   if (mode & SILC_CHANNEL_MODE_PRIVATE)
850     strncat(string, "p", 1);
851
852   if (mode & SILC_CHANNEL_MODE_SECRET)
853     strncat(string, "s", 1);
854
855   if (mode & SILC_CHANNEL_MODE_PRIVKEY)
856     strncat(string, "k", 1);
857
858   if (mode & SILC_CHANNEL_MODE_INVITE)
859     strncat(string, "i", 1);
860
861   if (mode & SILC_CHANNEL_MODE_TOPIC)
862     strncat(string, "t", 1);
863
864   if (mode & SILC_CHANNEL_MODE_ULIMIT)
865     strncat(string, "l", 1);
866
867   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
868     strncat(string, "a", 1);
869
870   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
871     strncat(string, "f", 1);
872
873   if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
874     strncat(string, "C", 1);
875
876   if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
877     strncat(string, "m", 1);
878
879   if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
880     strncat(string, "M", 1);
881
882   if (mode & SILC_CHANNEL_MODE_CIPHER)
883     strncat(string, "c", 1);
884
885   if (mode & SILC_CHANNEL_MODE_HMAC)
886     strncat(string, "h", 1);
887
888   if (mode & SILC_CHANNEL_MODE_CIPHER) {
889     if (strlen(cipher) + strlen(string) + 1< sizeof(string)) {
890       strncat(string, " ", 1);
891       strncat(string, cipher, strlen(cipher));
892     }
893   }
894
895   if (mode & SILC_CHANNEL_MODE_HMAC) {
896     if (strlen(hmac) + strlen(string) + 1< sizeof(string)) {
897       strncat(string, " ", 1);
898       strncat(string, hmac, strlen(hmac));
899     }
900   }
901
902   /* Rest of mode is ignored */
903
904   return strdup(string);
905 }
906
907 /* Parses channel user mode mask and returns te mode as string */
908
909 char *silc_client_chumode(SilcUInt32 mode)
910 {
911   char string[64];
912
913   if (!mode)
914     return NULL;
915
916   memset(string, 0, sizeof(string));
917
918   if (mode & SILC_CHANNEL_UMODE_CHANFO)
919     strncat(string, "f", 1);
920
921   if (mode & SILC_CHANNEL_UMODE_CHANOP)
922     strncat(string, "o", 1);
923
924   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
925     strncat(string, "b", 1);
926
927   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
928     strncat(string, "u", 1);
929
930   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
931     strncat(string, "r", 1);
932
933   if (mode & SILC_CHANNEL_UMODE_QUIET)
934     strncat(string, "q", 1);
935
936   return strdup(string);
937 }
938
939 /* Parses channel user mode and returns it as special mode character. */
940
941 char *silc_client_chumode_char(SilcUInt32 mode)
942 {
943   char string[64];
944
945   if (!mode)
946     return NULL;
947
948   memset(string, 0, sizeof(string));
949
950   if (mode & SILC_CHANNEL_UMODE_CHANFO)
951     strncat(string, "*", 1);
952
953   if (mode & SILC_CHANNEL_UMODE_CHANOP)
954     strncat(string, "@", 1);
955
956   if (mode & SILC_CHANNEL_UMODE_QUIET)
957     strncat(string, "&", 1);
958
959   return strdup(string);
960 }
961
962 /* Renders ID to suitable to print for example to log file. */
963
964 static char rid[256];
965 #define _PUT_STRING(__d__, __s__)                                       \
966 do {                                                                    \
967   int __sp = sizeof(__d__) - 1 - strlen(__d__);                         \
968   if (__sp < strlen(__s__)) {                                           \
969     if (__sp)                                                           \
970       strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__));       \
971   } else {                                                              \
972     strncat(__d__, __s__, strlen(__s__));                               \
973   }                                                                     \
974 } while(0)
975
976 char *silc_id_render(void *id, SilcIdType id_type)
977 {
978   char tmp[100];
979   unsigned char tmps[2];
980   char *cp;
981
982   memset(rid, 0, sizeof(rid));
983   switch(id_type) {
984   case SILC_ID_SERVER:
985     {
986       SilcServerID *server_id = (SilcServerID *)id;
987       if (server_id->ip.data_len > 4) {
988 #ifdef HAVE_IPV6
989         struct sockaddr_in6 ipv6;
990         memset(&ipv6, 0, sizeof(ipv6));
991         ipv6.sin6_family = AF_INET6;
992         memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
993         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
994                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
995           _PUT_STRING(rid, tmp);
996 #endif
997       } else {
998         struct in_addr ipv4;
999         memmove(&ipv4.s_addr, server_id->ip.data, 4);
1000         cp = inet_ntoa(ipv4);
1001         if (cp)
1002           _PUT_STRING(rid, cp);
1003       }
1004
1005       memset(tmp, 0, sizeof(tmp));
1006       silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
1007       _PUT_STRING(rid, tmp);
1008       SILC_PUT16_MSB(server_id->rnd, tmps);
1009       memset(tmp, 0, sizeof(tmp));
1010       silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
1011       _PUT_STRING(rid, tmp);
1012     }
1013     break;
1014   case SILC_ID_CLIENT:
1015     {
1016       SilcClientID *client_id = (SilcClientID *)id;
1017       if (client_id->ip.data_len > 4) {
1018 #ifdef HAVE_IPV6
1019         struct sockaddr_in6 ipv6;
1020         memset(&ipv6, 0, sizeof(ipv6));
1021         ipv6.sin6_family = AF_INET6;
1022         memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
1023         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
1024                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
1025           _PUT_STRING(rid, tmp);
1026 #endif
1027       } else {
1028         struct in_addr ipv4;
1029         memmove(&ipv4.s_addr, client_id->ip.data, 4);
1030         cp = inet_ntoa(ipv4);
1031         if (cp)
1032           _PUT_STRING(rid, cp);
1033       }
1034
1035       memset(tmp, 0, sizeof(tmp));
1036       silc_snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
1037       _PUT_STRING(rid, tmp);
1038       memset(tmp, 0, sizeof(tmp));
1039       silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
1040                client_id->hash[0], client_id->hash[1],
1041                client_id->hash[2], client_id->hash[3]);
1042       _PUT_STRING(rid, tmp);
1043     }
1044     break;
1045   case SILC_ID_CHANNEL:
1046     {
1047       SilcChannelID *channel_id = (SilcChannelID *)id;
1048       if (channel_id->ip.data_len > 4) {
1049 #ifdef HAVE_IPV6
1050         struct sockaddr_in6 ipv6;
1051         memset(&ipv6, 0, sizeof(ipv6));
1052         ipv6.sin6_family = AF_INET6;
1053         memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
1054         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
1055                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
1056           _PUT_STRING(rid, tmp);
1057 #endif
1058       } else {
1059         struct in_addr ipv4;
1060         memmove(&ipv4.s_addr, channel_id->ip.data, 4);
1061         cp = inet_ntoa(ipv4);
1062         if (cp)
1063           _PUT_STRING(rid, cp);
1064       }
1065
1066       memset(tmp, 0, sizeof(tmp));
1067       silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
1068       _PUT_STRING(rid, tmp);
1069       SILC_PUT16_MSB(channel_id->rnd, tmps);
1070       memset(tmp, 0, sizeof(tmp));
1071       silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
1072       _PUT_STRING(rid, tmp);
1073     }
1074     break;
1075   }
1076
1077   return rid;
1078 }
1079 #undef _PUT_STRING