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