Sun Mar 11 15:22:42 CET 2007 Jochen Eisinger <coffee@silcnet.org>
[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)
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   }
802
803   return TRUE;
804 }
805
806 /* Converts version string x.x into number representation. */
807
808 SilcUInt32 silc_version_to_num(const char *version)
809 {
810   int maj = 0, min = 0;
811   char *cp, buf[32];
812
813   if (!version)
814     return 0;
815
816   cp = (char *)version;
817   maj = atoi(cp);
818   cp = strchr(cp, '.');
819   if (cp)
820     min = atoi(cp + 1);
821
822   memset(buf, 0, sizeof(buf));
823   silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
824   return (SilcUInt32)atoi(buf);
825 }
826
827 /* Parses mode mask and returns the mode as string. */
828
829 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
830 {
831   char string[100];
832
833   if (!mode)
834     return NULL;
835
836   memset(string, 0, sizeof(string));
837
838   if (mode & SILC_CHANNEL_MODE_PRIVATE)
839     strncat(string, "p", 1);
840
841   if (mode & SILC_CHANNEL_MODE_SECRET)
842     strncat(string, "s", 1);
843
844   if (mode & SILC_CHANNEL_MODE_PRIVKEY)
845     strncat(string, "k", 1);
846
847   if (mode & SILC_CHANNEL_MODE_INVITE)
848     strncat(string, "i", 1);
849
850   if (mode & SILC_CHANNEL_MODE_TOPIC)
851     strncat(string, "t", 1);
852
853   if (mode & SILC_CHANNEL_MODE_ULIMIT)
854     strncat(string, "l", 1);
855
856   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
857     strncat(string, "a", 1);
858
859   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
860     strncat(string, "f", 1);
861
862   if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
863     strncat(string, "C", 1);
864
865   if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
866     strncat(string, "m", 1);
867
868   if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
869     strncat(string, "M", 1);
870
871   if (mode & SILC_CHANNEL_MODE_CIPHER)
872     strncat(string, "c", 1);
873
874   if (mode & SILC_CHANNEL_MODE_HMAC)
875     strncat(string, "h", 1);
876
877   if (mode & SILC_CHANNEL_MODE_CIPHER) {
878     if (strlen(cipher) + strlen(string) + 1< sizeof(string)) {
879       strncat(string, " ", 1);
880       strncat(string, cipher, strlen(cipher));
881     }
882   }
883
884   if (mode & SILC_CHANNEL_MODE_HMAC) {
885     if (strlen(hmac) + strlen(string) + 1< sizeof(string)) {
886       strncat(string, " ", 1);
887       strncat(string, hmac, strlen(hmac));
888     }
889   }
890
891   /* Rest of mode is ignored */
892
893   return strdup(string);
894 }
895
896 /* Parses channel user mode mask and returns te mode as string */
897
898 char *silc_client_chumode(SilcUInt32 mode)
899 {
900   char string[64];
901
902   if (!mode)
903     return NULL;
904
905   memset(string, 0, sizeof(string));
906
907   if (mode & SILC_CHANNEL_UMODE_CHANFO)
908     strncat(string, "f", 1);
909
910   if (mode & SILC_CHANNEL_UMODE_CHANOP)
911     strncat(string, "o", 1);
912
913   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
914     strncat(string, "b", 1);
915
916   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
917     strncat(string, "u", 1);
918
919   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
920     strncat(string, "r", 1);
921
922   if (mode & SILC_CHANNEL_UMODE_QUIET)
923     strncat(string, "q", 1);
924
925   return strdup(string);
926 }
927
928 /* Parses channel user mode and returns it as special mode character. */
929
930 char *silc_client_chumode_char(SilcUInt32 mode)
931 {
932   char string[64];
933
934   if (!mode)
935     return NULL;
936
937   memset(string, 0, sizeof(string));
938
939   if (mode & SILC_CHANNEL_UMODE_CHANFO)
940     strncat(string, "*", 1);
941
942   if (mode & SILC_CHANNEL_UMODE_CHANOP)
943     strncat(string, "@", 1);
944
945   if (mode & SILC_CHANNEL_UMODE_QUIET)
946     strncat(string, "&", 1);
947
948   return strdup(string);
949 }
950
951 /* Renders ID to suitable to print for example to log file. */
952
953 static char rid[256];
954 #define _PUT_STRING(__d__, __s__)                                       \
955 do {                                                                    \
956   int __sp = sizeof(__d__) - 1 - strlen(__d__);                         \
957   if (__sp < strlen(__s__)) {                                           \
958     if (__sp)                                                           \
959       strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__));       \
960   } else {                                                              \
961     strncat(__d__, __s__, strlen(__s__));                               \
962   }                                                                     \
963 } while(0)
964
965 char *silc_id_render(void *id, SilcIdType id_type)
966 {
967   char tmp[100];
968   unsigned char tmps[2];
969   char *cp;
970
971   memset(rid, 0, sizeof(rid));
972   switch(id_type) {
973   case SILC_ID_SERVER:
974     {
975       SilcServerID *server_id = (SilcServerID *)id;
976       if (server_id->ip.data_len > 4) {
977 #ifdef HAVE_IPV6
978         struct sockaddr_in6 ipv6;
979         memset(&ipv6, 0, sizeof(ipv6));
980         ipv6.sin6_family = AF_INET6;
981         memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
982         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
983                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
984           _PUT_STRING(rid, tmp);
985 #endif
986       } else {
987         struct in_addr ipv4;
988         memmove(&ipv4.s_addr, server_id->ip.data, 4);
989         cp = inet_ntoa(ipv4);
990         if (cp)
991           _PUT_STRING(rid, cp);
992       }
993
994       memset(tmp, 0, sizeof(tmp));
995       silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
996       _PUT_STRING(rid, tmp);
997       SILC_PUT16_MSB(server_id->rnd, tmps);
998       memset(tmp, 0, sizeof(tmp));
999       silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
1000       _PUT_STRING(rid, tmp);
1001     }
1002     break;
1003   case SILC_ID_CLIENT:
1004     {
1005       SilcClientID *client_id = (SilcClientID *)id;
1006       if (client_id->ip.data_len > 4) {
1007 #ifdef HAVE_IPV6
1008         struct sockaddr_in6 ipv6;
1009         memset(&ipv6, 0, sizeof(ipv6));
1010         ipv6.sin6_family = AF_INET6;
1011         memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
1012         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
1013                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
1014           _PUT_STRING(rid, tmp);
1015 #endif
1016       } else {
1017         struct in_addr ipv4;
1018         memmove(&ipv4.s_addr, client_id->ip.data, 4);
1019         cp = inet_ntoa(ipv4);
1020         if (cp)
1021           _PUT_STRING(rid, cp);
1022       }
1023
1024       memset(tmp, 0, sizeof(tmp));
1025       silc_snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
1026       _PUT_STRING(rid, tmp);
1027       memset(tmp, 0, sizeof(tmp));
1028       silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
1029                client_id->hash[0], client_id->hash[1],
1030                client_id->hash[2], client_id->hash[3]);
1031       _PUT_STRING(rid, tmp);
1032     }
1033     break;
1034   case SILC_ID_CHANNEL:
1035     {
1036       SilcChannelID *channel_id = (SilcChannelID *)id;
1037       if (channel_id->ip.data_len > 4) {
1038 #ifdef HAVE_IPV6
1039         struct sockaddr_in6 ipv6;
1040         memset(&ipv6, 0, sizeof(ipv6));
1041         ipv6.sin6_family = AF_INET6;
1042         memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
1043         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
1044                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
1045           _PUT_STRING(rid, tmp);
1046 #endif
1047       } else {
1048         struct in_addr ipv4;
1049         memmove(&ipv4.s_addr, channel_id->ip.data, 4);
1050         cp = inet_ntoa(ipv4);
1051         if (cp)
1052           _PUT_STRING(rid, cp);
1053       }
1054
1055       memset(tmp, 0, sizeof(tmp));
1056       silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
1057       _PUT_STRING(rid, tmp);
1058       SILC_PUT16_MSB(channel_id->rnd, tmps);
1059       memset(tmp, 0, sizeof(tmp));
1060       silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
1061       _PUT_STRING(rid, tmp);
1062     }
1063     break;
1064   }
1065
1066   return rid;
1067 }
1068 #undef _PUT_STRING