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