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 return strdup(string);
658 /* Parses channel user mode and returns it as special mode character. */
660 char *silc_client_chumode_char(SilcUInt32 mode)
667 memset(string, 0, sizeof(string));
669 if (mode & SILC_CHANNEL_UMODE_CHANFO)
670 strncat(string, "*", 1);
672 if (mode & SILC_CHANNEL_UMODE_CHANOP)
673 strncat(string, "@", 1);
675 return strdup(string);
678 /* Creates fingerprint from data, usually used with SHA1 digests */
680 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
682 char fingerprint[64], *cp;
685 memset(fingerprint, 0, sizeof(fingerprint));
687 for (i = 0; i < data_len; i++) {
688 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
691 if ((i + 1) % 2 == 0)
692 snprintf(cp++, sizeof(fingerprint), " ");
694 if ((i + 1) % 10 == 0)
695 snprintf(cp++, sizeof(fingerprint), " ");
698 if ((i + 1) % 2 == 0)
700 if ((i + 1) % 10 == 0)
703 return strdup(fingerprint);
706 /* Return TRUE if the `data' is ASCII string. */
708 bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
712 for (i = 0; i < data_len; i++) {
713 if (!isascii(data[i]))
720 /* Parses SILC protocol style version string. */
722 bool silc_parse_version_string(const char *version,
723 SilcUInt32 *protocol_version,
724 char **protocol_version_string,
725 SilcUInt32 *software_version,
726 char **software_version_string,
727 char **vendor_version)
730 int maj = 0, min = 0;
732 if (!strstr(version, "SILC-"))
735 cp = (char *)version + 5;
739 /* Take protocol version */
742 cp = strchr(cp, '.');
748 memset(buf, 0, sizeof(buf));
749 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
750 if (protocol_version)
751 *protocol_version = atoi(buf);
752 memset(buf, 0, sizeof(buf));
753 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
754 if (protocol_version_string)
755 *protocol_version_string = strdup(buf);
757 /* Take software version */
761 cp = strchr(cp, '-');
766 cp = strchr(cp, '.');
770 memset(buf, 0, sizeof(buf));
771 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
772 if (software_version)
773 *software_version = atoi(buf);
774 memset(buf, 0, sizeof(buf));
775 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
776 if (software_version_string)
777 *software_version_string = strdup(buf);
779 /* Take vendor string */
783 cp = strchr(cp, '.');
784 if (cp && cp + 1 && vendor_version)
785 *vendor_version = strdup(cp + 1);
791 /* Converts version string x.x into number representation. */
793 SilcUInt32 silc_version_to_num(const char *version)
795 int maj = 0, min = 0;
801 cp = (char *)version;
803 cp = strchr(cp, '.');
807 memset(buf, 0, sizeof(buf));
808 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
809 return (SilcUInt32)atoi(buf);
812 /* Displays input prompt on command line and takes input data from user */
814 char *silc_get_input(const char *prompt, bool echo_off)
819 #ifdef HAVE_TERMIOS_H
823 struct termios to_old;
825 fd = open("/dev/tty", O_RDONLY);
827 fprintf(stderr, "silc: %s\n", strerror(errno));
831 signal(SIGINT, SIG_IGN);
833 /* Get terminal info */
838 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
839 tcsetattr(fd, TCSANOW, &to);
841 memset(input, 0, sizeof(input));
843 printf("%s", prompt);
846 if ((read(fd, input, sizeof(input))) < 0) {
847 fprintf(stderr, "silc: %s\n", strerror(errno));
851 if (strlen(input) <= 1) {
852 tcsetattr(fd, TCSANOW, &to_old);
856 if (strchr(input, '\n'))
857 *strchr(input, '\n') = '\0';
859 /* Restore old terminfo */
860 tcsetattr(fd, TCSANOW, &to_old);
861 signal(SIGINT, SIG_DFL);
863 ret = silc_calloc(strlen(input), sizeof(char));
864 memcpy(ret, input, strlen(input));
865 memset(input, 0, sizeof(input));
866 #endif /* HAVE_TERMIOS_H */
872 fd = open("/dev/tty", O_RDONLY);
874 fprintf(stderr, "silc: %s\n", strerror(errno));
878 memset(input, 0, sizeof(input));
880 printf("%s", prompt);
883 if ((read(fd, input, sizeof(input))) < 0) {
884 fprintf(stderr, "silc: %s\n", strerror(errno));
888 if (strlen(input) <= 1)
891 if (strchr(input, '\n'))
892 *strchr(input, '\n') = '\0';
894 return strdup(input);
898 #endif /* SILC_UNIX */