5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
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.
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.
20 * These are general utility functions that doesn't belong to any specific
25 #include "silcincludes.h"
27 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
28 This doesn't remove the newline sign from the destination buffer. The
29 argument begin is returned and should be passed again for the function. */
31 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
36 memset(dest, 0, destlen);
42 for ( ; start <= srclen; i++, start++) {
59 /* Checks line for illegal characters. Return -1 when illegal character
60 were found. This is used to check for bad lines when reading data from
61 for example a configuration file. */
63 int silc_check_line(char *buf)
65 /* Illegal characters in line */
66 if (strchr(buf, '#')) return -1;
67 if (strchr(buf, '\'')) return -1;
68 if (strchr(buf, '\\')) return -1;
69 if (strchr(buf, '\r')) return -1;
70 if (strchr(buf, '\a')) return -1;
71 if (strchr(buf, '\b')) return -1;
72 if (strchr(buf, '\f')) return -1;
81 /* Returns current time as string. */
89 return_time = ctime(&curtime);
90 return_time[strlen(return_time) - 1] = '\0';
95 /* Converts string to capital characters. */
97 char *silc_to_upper(char *string)
100 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
102 for (i = 0; i < strlen(string); i++)
103 ret[i] = toupper(string[i]);
108 /* Parse userfqdn string which is in user@fqdn format. */
110 bool silc_parse_userfqdn(const char *string, char **left, char **right)
117 if (string[0] == '@') {
119 *left = strdup(string);
123 if (strchr(string, '@')) {
124 tlen = strcspn(string, "@");
127 *left = silc_calloc(tlen + 1, sizeof(char));
128 memcpy(*left, string, tlen);
132 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
133 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
137 *left = strdup(string);
143 /* Parses command line. At most `max_args' is taken. Rest of the line
144 will be allocated as the last argument if there are more than `max_args'
145 arguments in the line. Note that the command name is counted as one
146 argument and is saved. */
148 void silc_parse_command_line(unsigned char *buffer,
149 unsigned char ***parsed,
150 SilcUInt32 **parsed_lens,
151 SilcUInt32 **parsed_types,
152 SilcUInt32 *parsed_num,
157 const char *cp = buffer;
160 *parsed = silc_calloc(1, sizeof(**parsed));
161 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
163 /* Get the command first */
164 len = strcspn(cp, " ");
165 tmp = silc_to_upper((char *)cp);
166 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
167 memcpy((*parsed)[0], tmp, len);
169 (*parsed_lens)[0] = len;
175 /* Parse arguments */
176 if (strchr(cp, ' ') || strlen(cp) != 0) {
177 for (i = 1; i < max_args; i++) {
179 if (i != max_args - 1)
180 len = strcspn(cp, " ");
183 while (len && cp[len - 1] == ' ')
188 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
189 *parsed_lens = silc_realloc(*parsed_lens,
190 sizeof(**parsed_lens) * (argc + 1));
191 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
192 memcpy((*parsed)[argc], cp, len);
193 (*parsed_lens)[argc] = len;
205 /* Save argument types. Protocol defines all argument types but
206 this implementation makes sure that they are always in correct
207 order hence this simple code. */
208 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
209 for (i = 0; i < argc; i++)
210 (*parsed_types)[i] = i;
215 /* Formats arguments to a string and returns it after allocating memory
216 for it. It must be remembered to free it later. */
218 char *silc_format(char *fmt, ...)
221 static char buf[8192];
223 memset(buf, 0, sizeof(buf));
225 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
231 /* Renders ID to suitable to print for example to log file. */
233 static char rid[256];
234 #define _PUT_STRING(__d__, __s__) \
236 int __sp = sizeof(__d__) - 1 - strlen(__d__); \
237 if (__sp < strlen(__s__)) { \
239 strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__)); \
241 strncat(__d__, __s__, strlen(__s__)); \
245 char *silc_id_render(void *id, SilcUInt16 type)
248 unsigned char tmps[2];
251 memset(rid, 0, sizeof(rid));
255 SilcServerID *server_id = (SilcServerID *)id;
256 if (server_id->ip.data_len > 4) {
258 struct sockaddr_in6 ipv6;
259 memset(&ipv6, 0, sizeof(ipv6));
260 ipv6.sin6_family = AF_INET6;
261 memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
262 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
263 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
264 _PUT_STRING(rid, tmp);
268 memmove(&ipv4.s_addr, server_id->ip.data, 4);
269 cp = inet_ntoa(ipv4);
271 _PUT_STRING(rid, cp);
274 memset(tmp, 0, sizeof(tmp));
275 snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
276 _PUT_STRING(rid, tmp);
277 SILC_PUT16_MSB(server_id->rnd, tmps);
278 memset(tmp, 0, sizeof(tmp));
279 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
280 _PUT_STRING(rid, tmp);
285 SilcClientID *client_id = (SilcClientID *)id;
286 if (client_id->ip.data_len > 4) {
288 struct sockaddr_in6 ipv6;
289 memset(&ipv6, 0, sizeof(ipv6));
290 ipv6.sin6_family = AF_INET6;
291 memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
292 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
293 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
294 _PUT_STRING(rid, tmp);
298 memmove(&ipv4.s_addr, client_id->ip.data, 4);
299 cp = inet_ntoa(ipv4);
301 _PUT_STRING(rid, cp);
304 memset(tmp, 0, sizeof(tmp));
305 snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
306 _PUT_STRING(rid, tmp);
307 memset(tmp, 0, sizeof(tmp));
308 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
309 client_id->hash[0], client_id->hash[1],
310 client_id->hash[2], client_id->hash[3]);
311 _PUT_STRING(rid, tmp);
314 case SILC_ID_CHANNEL:
316 SilcChannelID *channel_id = (SilcChannelID *)id;
317 if (channel_id->ip.data_len > 4) {
319 struct sockaddr_in6 ipv6;
320 memset(&ipv6, 0, sizeof(ipv6));
321 ipv6.sin6_family = AF_INET6;
322 memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
323 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
324 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
325 _PUT_STRING(rid, tmp);
329 memmove(&ipv4.s_addr, channel_id->ip.data, 4);
330 cp = inet_ntoa(ipv4);
332 _PUT_STRING(rid, cp);
335 memset(tmp, 0, sizeof(tmp));
336 snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
337 _PUT_STRING(rid, tmp);
338 SILC_PUT16_MSB(channel_id->rnd, tmps);
339 memset(tmp, 0, sizeof(tmp));
340 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
341 _PUT_STRING(rid, tmp);
350 /* Compares two strings. Strings may include wildcards '*' and '?'.
351 Returns TRUE if strings match. */
353 int silc_string_compare(char *string1, char *string2)
358 char *tmpstr1, *tmpstr2;
360 if (!string1 || !string2)
363 slen1 = strlen(string1);
364 slen2 = strlen(string2);
366 /* See if they are same already */
367 if (!strncmp(string1, string2, strlen(string2)))
371 if (!strchr(string1, '*'))
374 /* Take copies of the original strings as we will change them */
375 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
376 memcpy(tmpstr1, string1, slen1);
377 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
378 memcpy(tmpstr2, string2, slen2);
380 for (i = 0; i < slen1; i++) {
382 /* * wildcard. Only one * wildcard is possible. */
383 if (tmpstr1[i] == '*')
384 if (!strncmp(tmpstr1, tmpstr2, i)) {
385 memset(tmpstr2, 0, slen2);
386 strncpy(tmpstr2, tmpstr1, i);
391 if (tmpstr1[i] == '?') {
392 if (!strncmp(tmpstr1, tmpstr2, i)) {
393 if (!(slen1 < i + 1))
394 if (tmpstr1[i + 1] != '?' &&
395 tmpstr1[i + 1] != tmpstr2[i + 1])
398 if (!(slen1 < slen2))
404 /* if using *, remove it */
405 if (strchr(tmpstr1, '*'))
406 *strchr(tmpstr1, '*') = 0;
408 if (!strcmp(tmpstr1, tmpstr2)) {
409 memset(tmpstr1, 0, slen1);
410 memset(tmpstr2, 0, slen2);
416 memset(tmpstr1, 0, slen1);
417 memset(tmpstr2, 0, slen2);
423 /* Basic has function to hash strings. May be used with the SilcHashTable.
424 Note that this lowers the characters of the string (with tolower()) so
425 this is used usually with nicknames, channel and server names to provide
426 case insensitive keys. */
428 SilcUInt32 silc_hash_string(void *key, void *user_context)
430 char *s = (char *)key;
434 h = (h << 4) + tolower(*s);
435 if ((g = h & 0xf0000000)) {
445 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
447 SilcUInt32 silc_hash_uint(void *key, void *user_context)
449 return *(SilcUInt32 *)key;
452 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
454 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
456 return (SilcUInt32)key;
459 /* Hash a ID. The `user_context' is the ID type. */
461 SilcUInt32 silc_hash_id(void *key, void *user_context)
463 SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
470 SilcClientID *id = (SilcClientID *)key;
473 /* The client ID is hashed by hashing the hash of the ID
474 (which is a truncated MD5 hash of the nickname) so that we
475 can access the entry from the cache with both Client ID but
476 with just a hash from the ID as well. */
478 for (i = 0; i < sizeof(id->hash); i++) {
479 h = (h << 4) + id->hash[i];
480 if ((g = h & 0xf0000000)) {
491 SilcServerID *id = (SilcServerID *)key;
493 h = id->port * id->rnd;
494 for (i = 0; i < id->ip.data_len; i++)
500 case SILC_ID_CHANNEL:
502 SilcChannelID *id = (SilcChannelID *)key;
504 h = id->port * id->rnd;
505 for (i = 0; i < id->ip.data_len; i++)
518 /* Hash binary data. The `user_context' is the data length. */
520 SilcUInt32 silc_hash_data(void *key, void *user_context)
522 SilcUInt32 len = (SilcUInt32)user_context, h = 0;
523 unsigned char *data = (unsigned char *)key;
526 h = (data[0] * data[len - 1] + 1) * len;
527 for (i = 0; i < len; i++)
533 /* Hashed SILC Public key. */
535 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
537 SilcPublicKey pk = (SilcPublicKey)key;
538 return (pk->len + silc_hash_string(pk->name, NULL) +
539 silc_hash_string(pk->identifier, NULL) +
540 silc_hash_data(pk->pk, (void *)pk->pk_len));
543 /* Compares two strings. It may be used as SilcHashTable comparison
546 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
548 return !strcasecmp((char *)key1, (char *)key2);
551 /* Compares two ID's. May be used as SilcHashTable comparison function.
552 The Client ID's compares only the hash of the Client ID not any other
553 part of the Client ID. Other ID's are fully compared. */
555 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
557 SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
558 return (id_type == SILC_ID_CLIENT ?
559 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
560 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
563 /* Compare two Client ID's entirely and not just the hash from the ID. */
565 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
567 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
570 /* Compares binary data. May be used as SilcHashTable comparison function. */
572 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
574 SilcUInt32 len = (SilcUInt32)user_context;
575 return !memcmp(key1, key2, len);
578 /* Compares two SILC Public keys. It may be used as SilcHashTable
579 comparison function. */
581 bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
583 return silc_pkcs_public_key_compare(key1, key2);
586 /* Parses mode mask and returns the mode as string. */
588 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
595 memset(string, 0, sizeof(string));
597 if (mode & SILC_CHANNEL_MODE_PRIVATE)
598 strncat(string, "p", 1);
600 if (mode & SILC_CHANNEL_MODE_SECRET)
601 strncat(string, "s", 1);
603 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
604 strncat(string, "k", 1);
606 if (mode & SILC_CHANNEL_MODE_INVITE)
607 strncat(string, "i", 1);
609 if (mode & SILC_CHANNEL_MODE_TOPIC)
610 strncat(string, "t", 1);
612 if (mode & SILC_CHANNEL_MODE_ULIMIT)
613 strncat(string, "l", 1);
615 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
616 strncat(string, "a", 1);
618 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
619 strncat(string, "f", 1);
621 if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
622 strncat(string, "m", 1);
624 if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
625 strncat(string, "M", 1);
627 if (mode & SILC_CHANNEL_MODE_CIPHER)
628 strncat(string, cipher, strlen(cipher));
630 if (mode & SILC_CHANNEL_MODE_HMAC)
631 strncat(string, hmac, strlen(hmac));
633 /* Rest of mode is ignored */
635 return strdup(string);
638 /* Parses channel user mode mask and returns te mode as string */
640 char *silc_client_chumode(SilcUInt32 mode)
647 memset(string, 0, sizeof(string));
649 if (mode & SILC_CHANNEL_UMODE_CHANFO)
650 strncat(string, "f", 1);
652 if (mode & SILC_CHANNEL_UMODE_CHANOP)
653 strncat(string, "o", 1);
655 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
656 strncat(string, "b", 1);
658 return strdup(string);
661 /* Parses channel user mode and returns it as special mode character. */
663 char *silc_client_chumode_char(SilcUInt32 mode)
670 memset(string, 0, sizeof(string));
672 if (mode & SILC_CHANNEL_UMODE_CHANFO)
673 strncat(string, "*", 1);
675 if (mode & SILC_CHANNEL_UMODE_CHANOP)
676 strncat(string, "@", 1);
678 return strdup(string);
681 /* Creates fingerprint from data, usually used with SHA1 digests */
683 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
685 char fingerprint[64], *cp;
688 memset(fingerprint, 0, sizeof(fingerprint));
690 for (i = 0; i < data_len; i++) {
691 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
694 if ((i + 1) % 2 == 0)
695 snprintf(cp++, sizeof(fingerprint), " ");
697 if ((i + 1) % 10 == 0)
698 snprintf(cp++, sizeof(fingerprint), " ");
701 if ((i + 1) % 2 == 0)
703 if ((i + 1) % 10 == 0)
706 return strdup(fingerprint);
709 /* Return TRUE if the `data' is ASCII string. */
711 bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
715 for (i = 0; i < data_len; i++) {
716 if (!isascii(data[i]))
723 /* Parses SILC protocol style version string. */
725 bool silc_parse_version_string(const char *version,
726 SilcUInt32 *protocol_version,
727 char **protocol_version_string,
728 SilcUInt32 *software_version,
729 char **software_version_string,
730 char **vendor_version)
733 int maj = 0, min = 0;
735 if (!strstr(version, "SILC-"))
738 cp = (char *)version + 5;
742 /* Take protocol version */
745 cp = strchr(cp, '.');
751 memset(buf, 0, sizeof(buf));
752 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
753 if (protocol_version)
754 *protocol_version = atoi(buf);
755 memset(buf, 0, sizeof(buf));
756 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
757 if (protocol_version_string)
758 *protocol_version_string = strdup(buf);
760 /* Take software version */
764 cp = strchr(cp, '-');
769 cp = strchr(cp, '.');
773 memset(buf, 0, sizeof(buf));
774 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
775 if (software_version)
776 *software_version = atoi(buf);
777 memset(buf, 0, sizeof(buf));
778 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
779 if (software_version_string)
780 *software_version_string = strdup(buf);
782 /* Take vendor string */
786 cp = strchr(cp, '.');
787 if (cp && cp + 1 && vendor_version)
788 *vendor_version = strdup(cp + 1);
794 /* Converts version string x.x into number representation. */
796 SilcUInt32 silc_version_to_num(const char *version)
798 int maj = 0, min = 0;
804 cp = (char *)version;
806 cp = strchr(cp, '.');
810 memset(buf, 0, sizeof(buf));
811 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
812 return (SilcUInt32)atoi(buf);
815 /* Displays input prompt on command line and takes input data from user */
817 char *silc_get_input(const char *prompt, bool echo_off)
822 #ifdef HAVE_TERMIOS_H
826 struct termios to_old;
828 fd = open("/dev/tty", O_RDONLY);
830 fprintf(stderr, "silc: %s\n", strerror(errno));
834 signal(SIGINT, SIG_IGN);
836 /* Get terminal info */
841 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
842 tcsetattr(fd, TCSANOW, &to);
844 memset(input, 0, sizeof(input));
846 printf("%s", prompt);
849 if ((read(fd, input, sizeof(input))) < 0) {
850 fprintf(stderr, "silc: %s\n", strerror(errno));
854 if (strlen(input) <= 1) {
855 tcsetattr(fd, TCSANOW, &to_old);
859 if (strchr(input, '\n'))
860 *strchr(input, '\n') = '\0';
862 /* Restore old terminfo */
863 tcsetattr(fd, TCSANOW, &to_old);
864 signal(SIGINT, SIG_DFL);
866 ret = silc_calloc(strlen(input), sizeof(char));
867 memcpy(ret, input, strlen(input));
868 memset(input, 0, sizeof(input));
869 #endif /* HAVE_TERMIOS_H */
875 fd = open("/dev/tty", O_RDONLY);
877 fprintf(stderr, "silc: %s\n", strerror(errno));
881 memset(input, 0, sizeof(input));
883 printf("%s", prompt);
886 if ((read(fd, input, sizeof(input))) < 0) {
887 fprintf(stderr, "silc: %s\n", strerror(errno));
891 if (strlen(input) <= 1)
894 if (strchr(input, '\n'))
895 *strchr(input, '\n') = '\0';
897 return strdup(input);
901 #endif /* SILC_UNIX */
904 /* Return mode list */
906 bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
911 if (mode_list->len / 4 != mode_list_count)
914 *list = silc_calloc(mode_list_count, sizeof(**list));
916 for (i = 0; i < mode_list_count; i++) {
917 SILC_GET32_MSB((*list)[i], mode_list->data);
918 silc_buffer_pull(mode_list, 4);
921 silc_buffer_push(mode_list, mode_list->data - mode_list->head);