New status type string.
[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   { STAT(NO_SUCH_PUBLIC_KEY), "Unknown public key" },
622
623   { 0, NULL }
624 };
625
626 /* Returns status message string */
627
628 const char *silc_get_status_message(unsigned char status)
629 {
630   int i;
631
632   for (i = 0; silc_status_messages[i].message; i++) {
633     if (silc_status_messages[i].status == status)
634       break;
635   }
636
637   if (silc_status_messages[i].message == NULL)
638     return "";
639
640   return silc_status_messages[i].message;
641 }
642
643 static const char *packet_name[] = {
644   "NONE",
645   "DISCONNECT",
646   "SUCCESS",
647   "FAILURE",
648   "REJECT",
649   "NOTIFY",
650   "ERROR",
651   "CHANNEL MESSAGE",
652   "CHANNEL KEY",
653   "PRIVATE MESSAGE",
654   "PRIVATE MESSAGE KEY",
655   "COMMAND",
656   "COMMAND REPLY",
657   "KEY EXCHANGE",
658   "KEY EXCHANGE 1",
659   "KEY EXCHANGE 2",
660   "CONNECTION AUTH REQUEST",
661   "CONNECTION AUTH",
662   "NEW ID",
663   "NEW CLIENT",
664   "NEW SERVER",
665   "NEW CHANNEL",
666   "REKEY",
667   "REKEY_DONE",
668   "HEARTBEAT",
669   "KEY AGREEMENT",
670   "RESUME ROUTER",
671   "FTP",
672   "RESUME CLIENT",
673 };
674
675 /* Returns packet type name */
676
677 const char *silc_get_packet_name(unsigned char type)
678 {
679   if (type >= SILC_PACKET_MAX)
680     return "RESERVED";
681   if (type >= SILC_PACKET_PRIVATE)
682     return "PRIVATE RANGE";
683   if (type > (sizeof(packet_name) / sizeof(*packet_name)))
684     return "UNKNOWN";
685   return packet_name[type];
686 }
687
688 static const char *command_name[] = {
689   "NONE",
690   "WHOIS",
691   "WHOWAS",
692   "IDENTIFY",
693   "NICK",
694   "LIST",
695   "TOPIC",
696   "INVITE",
697   "QUIT",
698   "KILL",
699   "INFO",
700   "STATS",
701   "PING",
702   "OPER",
703   "JOIN",
704   "MOTD",
705   "UMODE",
706   "CMODE",
707   "CUMODE",
708   "KICK",
709   "BAN",
710   "DETACH",
711   "WATCH",
712   "SILCOPER",
713   "LEAVE",
714   "USERS",
715   "GETKEY",
716   "SERVICE",
717 };
718
719 /* Returns command name */
720
721 const char *silc_get_command_name(unsigned char command)
722 {
723   if (command >= SILC_COMMAND_RESERVED)
724     return "RESERVED";
725   if (command >= SILC_COMMAND_PRIVATE)
726     return "PRIVATE RANGE";
727   if (command > (sizeof(command_name) / sizeof(*command_name)))
728     return "UNKNOWN";
729   return command_name[command];
730 }
731
732 /* Parses SILC protocol style version string. */
733
734 SilcBool silc_parse_version_string(const char *version,
735                                    SilcUInt32 *protocol_version,
736                                    char **protocol_version_string,
737                                    SilcUInt32 *software_version,
738                                    char **software_version_string,
739                                    char **vendor_version)
740 {
741   char *cp, buf[32];
742   int maj = 0, min = 0;
743
744   if (!strstr(version, "SILC-"))
745     return FALSE;
746
747   cp = (char *)version + 5;
748   if (!cp || !(*cp))
749     return FALSE;
750
751   /* Take protocol version */
752
753   maj = atoi(cp);
754   if (!strchr(cp, '.'))
755     return FALSE;
756   cp = strchr(cp, '.') + 1;
757   if (!cp || !(*cp))
758     return FALSE;
759   min = atoi(cp);
760
761   memset(buf, 0, sizeof(buf));
762   silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
763   if (protocol_version)
764     *protocol_version = atoi(buf);
765   memset(buf, 0, sizeof(buf));
766   silc_snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
767   if (protocol_version_string)
768     *protocol_version_string = strdup(buf);
769
770   /* Take software version */
771
772   maj = 0;
773   min = 0;
774   if (!strchr(cp, '-'))
775     return FALSE;
776   cp = strchr(cp, '-') + 1;
777   if (!cp || !(*cp))
778     return FALSE;
779
780   maj = atoi(cp);
781   if (strchr(cp, '.')) {
782     cp = strchr(cp, '.') + 1;
783     if (cp && *cp)
784       min = atoi(cp);
785   }
786
787   memset(buf, 0, sizeof(buf));
788   silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
789   if (software_version)
790     *software_version = atoi(buf);
791   memset(buf, 0, sizeof(buf));
792   silc_snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
793   if (software_version_string)
794     *software_version_string = strdup(buf);
795
796   /* Take vendor string */
797
798   if (strchr(cp, '.')) {
799     cp = strchr(cp, '.') + 1;
800     if (cp && *cp && vendor_version)
801       *vendor_version = strdup(cp);
802   } else if (strchr(cp, ' ')) {
803     cp = strchr(cp, ' ') + 1;
804     if (cp && *cp && vendor_version)
805       *vendor_version = strdup(cp);
806   }
807
808   return TRUE;
809 }
810
811 /* Converts version string x.x into number representation. */
812
813 SilcUInt32 silc_version_to_num(const char *version)
814 {
815   int maj = 0, min = 0;
816   char *cp, buf[32];
817
818   if (!version)
819     return 0;
820
821   cp = (char *)version;
822   maj = atoi(cp);
823   cp = strchr(cp, '.');
824   if (cp)
825     min = atoi(cp + 1);
826
827   memset(buf, 0, sizeof(buf));
828   silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
829   return (SilcUInt32)atoi(buf);
830 }
831
832 /* Parses mode mask and returns the mode as string. */
833
834 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
835 {
836   char string[100];
837
838   if (!mode)
839     return NULL;
840
841   memset(string, 0, sizeof(string));
842
843   if (mode & SILC_CHANNEL_MODE_PRIVATE)
844     strncat(string, "p", 1);
845
846   if (mode & SILC_CHANNEL_MODE_SECRET)
847     strncat(string, "s", 1);
848
849   if (mode & SILC_CHANNEL_MODE_PRIVKEY)
850     strncat(string, "k", 1);
851
852   if (mode & SILC_CHANNEL_MODE_INVITE)
853     strncat(string, "i", 1);
854
855   if (mode & SILC_CHANNEL_MODE_TOPIC)
856     strncat(string, "t", 1);
857
858   if (mode & SILC_CHANNEL_MODE_ULIMIT)
859     strncat(string, "l", 1);
860
861   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
862     strncat(string, "a", 1);
863
864   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
865     strncat(string, "f", 1);
866
867   if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
868     strncat(string, "C", 1);
869
870   if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
871     strncat(string, "m", 1);
872
873   if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
874     strncat(string, "M", 1);
875
876   if (mode & SILC_CHANNEL_MODE_CIPHER)
877     strncat(string, "c", 1);
878
879   if (mode & SILC_CHANNEL_MODE_HMAC)
880     strncat(string, "h", 1);
881
882   if (mode & SILC_CHANNEL_MODE_CIPHER) {
883     if (strlen(cipher) + strlen(string) + 1< sizeof(string)) {
884       strncat(string, " ", 1);
885       strncat(string, cipher, strlen(cipher));
886     }
887   }
888
889   if (mode & SILC_CHANNEL_MODE_HMAC) {
890     if (strlen(hmac) + strlen(string) + 1< sizeof(string)) {
891       strncat(string, " ", 1);
892       strncat(string, hmac, strlen(hmac));
893     }
894   }
895
896   /* Rest of mode is ignored */
897
898   return strdup(string);
899 }
900
901 /* Parses channel user mode mask and returns te mode as string */
902
903 char *silc_client_chumode(SilcUInt32 mode)
904 {
905   char string[64];
906
907   if (!mode)
908     return NULL;
909
910   memset(string, 0, sizeof(string));
911
912   if (mode & SILC_CHANNEL_UMODE_CHANFO)
913     strncat(string, "f", 1);
914
915   if (mode & SILC_CHANNEL_UMODE_CHANOP)
916     strncat(string, "o", 1);
917
918   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
919     strncat(string, "b", 1);
920
921   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
922     strncat(string, "u", 1);
923
924   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
925     strncat(string, "r", 1);
926
927   if (mode & SILC_CHANNEL_UMODE_QUIET)
928     strncat(string, "q", 1);
929
930   return strdup(string);
931 }
932
933 /* Parses channel user mode and returns it as special mode character. */
934
935 char *silc_client_chumode_char(SilcUInt32 mode)
936 {
937   char string[64];
938
939   if (!mode)
940     return NULL;
941
942   memset(string, 0, sizeof(string));
943
944   if (mode & SILC_CHANNEL_UMODE_CHANFO)
945     strncat(string, "*", 1);
946
947   if (mode & SILC_CHANNEL_UMODE_CHANOP)
948     strncat(string, "@", 1);
949
950   if (mode & SILC_CHANNEL_UMODE_QUIET)
951     strncat(string, "&", 1);
952
953   return strdup(string);
954 }
955
956 /* Renders ID to suitable to print for example to log file. */
957
958 static char rid[256];
959 #define _PUT_STRING(__d__, __s__)                                       \
960 do {                                                                    \
961   int __sp = sizeof(__d__) - 1 - strlen(__d__);                         \
962   if (__sp < strlen(__s__)) {                                           \
963     if (__sp)                                                           \
964       strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__));       \
965   } else {                                                              \
966     strncat(__d__, __s__, strlen(__s__));                               \
967   }                                                                     \
968 } while(0)
969
970 char *silc_id_render(void *id, SilcIdType id_type)
971 {
972   char tmp[100];
973   unsigned char tmps[2];
974   char *cp;
975
976   memset(rid, 0, sizeof(rid));
977   switch(id_type) {
978   case SILC_ID_SERVER:
979     {
980       SilcServerID *server_id = (SilcServerID *)id;
981       if (server_id->ip.data_len > 4) {
982 #ifdef HAVE_IPV6
983         struct sockaddr_in6 ipv6;
984         memset(&ipv6, 0, sizeof(ipv6));
985         ipv6.sin6_family = AF_INET6;
986         memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
987         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
988                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
989           _PUT_STRING(rid, tmp);
990 #endif
991       } else {
992         struct in_addr ipv4;
993         memmove(&ipv4.s_addr, server_id->ip.data, 4);
994         cp = inet_ntoa(ipv4);
995         if (cp)
996           _PUT_STRING(rid, cp);
997       }
998
999       memset(tmp, 0, sizeof(tmp));
1000       silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
1001       _PUT_STRING(rid, tmp);
1002       SILC_PUT16_MSB(server_id->rnd, tmps);
1003       memset(tmp, 0, sizeof(tmp));
1004       silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
1005       _PUT_STRING(rid, tmp);
1006     }
1007     break;
1008   case SILC_ID_CLIENT:
1009     {
1010       SilcClientID *client_id = (SilcClientID *)id;
1011       if (client_id->ip.data_len > 4) {
1012 #ifdef HAVE_IPV6
1013         struct sockaddr_in6 ipv6;
1014         memset(&ipv6, 0, sizeof(ipv6));
1015         ipv6.sin6_family = AF_INET6;
1016         memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
1017         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
1018                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
1019           _PUT_STRING(rid, tmp);
1020 #endif
1021       } else {
1022         struct in_addr ipv4;
1023         memmove(&ipv4.s_addr, client_id->ip.data, 4);
1024         cp = inet_ntoa(ipv4);
1025         if (cp)
1026           _PUT_STRING(rid, cp);
1027       }
1028
1029       memset(tmp, 0, sizeof(tmp));
1030       silc_snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
1031       _PUT_STRING(rid, tmp);
1032       memset(tmp, 0, sizeof(tmp));
1033       silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
1034                client_id->hash[0], client_id->hash[1],
1035                client_id->hash[2], client_id->hash[3]);
1036       _PUT_STRING(rid, tmp);
1037     }
1038     break;
1039   case SILC_ID_CHANNEL:
1040     {
1041       SilcChannelID *channel_id = (SilcChannelID *)id;
1042       if (channel_id->ip.data_len > 4) {
1043 #ifdef HAVE_IPV6
1044         struct sockaddr_in6 ipv6;
1045         memset(&ipv6, 0, sizeof(ipv6));
1046         ipv6.sin6_family = AF_INET6;
1047         memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
1048         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
1049                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
1050           _PUT_STRING(rid, tmp);
1051 #endif
1052       } else {
1053         struct in_addr ipv4;
1054         memmove(&ipv4.s_addr, channel_id->ip.data, 4);
1055         cp = inet_ntoa(ipv4);
1056         if (cp)
1057           _PUT_STRING(rid, cp);
1058       }
1059
1060       memset(tmp, 0, sizeof(tmp));
1061       silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
1062       _PUT_STRING(rid, tmp);
1063       SILC_PUT16_MSB(channel_id->rnd, tmps);
1064       memset(tmp, 0, sizeof(tmp));
1065       silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
1066       _PUT_STRING(rid, tmp);
1067     }
1068     break;
1069   }
1070
1071   return rid;
1072 }
1073 #undef _PUT_STRING