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