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