5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * These are general utility functions that doesn't belong to any specific
26 #include "silcincludes.h"
28 /* Reads a file to a buffer. The allocated buffer is returned. Length of
29 the file read is returned to the return_len argument. */
31 char *silc_file_read(const char *filename, uint32 *return_len)
37 fd = open(filename, O_RDONLY);
39 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
43 filelen = lseek(fd, (off_t)0L, SEEK_END);
46 if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
50 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
54 buffer = silc_calloc(filelen + 1, sizeof(char));
56 if ((read(fd, buffer, filelen)) == -1) {
57 memset(buffer, 0, sizeof(buffer));
59 SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
65 buffer[filelen] = EOF;
68 *return_len = filelen;
73 /* Writes a buffer to the file. */
75 int silc_file_write(const char *filename, const char *buffer, uint32 len)
79 if ((fd = creat(filename, 0644)) == -1) {
80 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
85 if ((write(fd, buffer, len)) == -1) {
86 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
95 /* Writes a buffer to the file. If the file is created specific mode is
98 int silc_file_write_mode(const char *filename, const char *buffer,
103 if ((fd = creat(filename, mode)) == -1) {
104 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
109 if ((write(fd, buffer, len)) == -1) {
110 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
119 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
120 This doesn't remove the newline sign from the destination buffer. The
121 argument begin is returned and should be passed again for the function. */
123 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
125 static int start = 0;
128 memset(dest, 0, destlen);
134 for ( ; start <= srclen; i++, start++) {
138 dest[i] = src[start];
151 /* Checks line for illegal characters. Return -1 when illegal character
152 were found. This is used to check for bad lines when reading data from
153 for example a configuration file. */
155 int silc_check_line(char *buf)
157 /* Illegal characters in line */
158 if (strchr(buf, '#')) return -1;
159 if (strchr(buf, '\'')) return -1;
160 if (strchr(buf, '\\')) return -1;
161 if (strchr(buf, '\r')) return -1;
162 if (strchr(buf, '\a')) return -1;
163 if (strchr(buf, '\b')) return -1;
164 if (strchr(buf, '\f')) return -1;
173 /* Returns current time as string. */
175 char *silc_get_time()
180 curtime = time(NULL);
181 return_time = ctime(&curtime);
182 return_time[strlen(return_time) - 1] = '\0';
187 /* Converts string to capital characters */
189 char *silc_to_upper(char *string)
192 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
194 for (i = 0; i < strlen(string); i++)
195 ret[i] = toupper(string[i]);
200 static unsigned char pem_enc[64] =
201 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
203 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
204 data string. Note: This is originally public domain code and is
207 char *silc_encode_pem(unsigned char *data, uint32 len)
210 uint32 bits, c, char_count;
217 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
219 for (i = 0; i < len; i++) {
224 if (char_count == 3) {
225 pem[j++] = pem_enc[bits >> 18];
226 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
227 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
228 pem[j++] = pem_enc[bits & 0x3f];
236 if (char_count != 0) {
237 bits <<= 16 - (8 * char_count);
238 pem[j++] = pem_enc[bits >> 18];
239 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
241 if (char_count == 1) {
245 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
253 /* Same as above but puts newline ('\n') every 72 characters. */
255 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
261 pem = silc_encode_pem(data, data_len);
264 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
266 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
281 /* Decodes PEM into data. Returns the decoded data. Note: This is
282 originally public domain code and is still PD. */
284 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
288 uint32 len, c, char_count, bits;
290 static char ialpha[256], decoder[256];
292 for (i = 64 - 1; i >= 0; i--) {
293 ialpha[pem_enc[i]] = 1;
294 decoder[pem_enc[i]] = i;
306 data = silc_calloc(((len * 6) / 8), sizeof(*data));
308 for (i = 0; i < len; i++) {
314 if (c > 127 || !ialpha[c])
320 if (char_count == 4) {
321 data[j++] = bits >> 16;
322 data[j++] = (bits >> 8) & 0xff;
323 data[j++] = bits & 0xff;
337 data[j++] = bits >> 10;
340 data[j++] = bits >> 16;
341 data[j++] = (bits >> 8) & 0xff;
351 /* Parse nickname string. The format may be <num>!<nickname>@<server> to
352 support multiple same nicknames. The <num> is the final unifier if same
353 nickname is on same server. Note, this is only local format and server
354 does not know anything about these. */
356 int silc_parse_nickname(char *string, char **nickname, char **server,
365 if (strchr(string, '!')) {
366 tlen = strcspn(string, "!");
367 memset(tmp, 0, sizeof(tmp));
368 memcpy(tmp, string, tlen);
373 if (tlen >= strlen(string))
379 if (strchr(string, '@')) {
380 tlen = strcspn(string, "@");
383 *nickname = silc_calloc(tlen + 1, sizeof(char));
384 memcpy(*nickname, string, tlen);
388 *server = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
389 memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
393 *nickname = strdup(string);
399 /* Parses command line. At most `max_args' is taken. Rest of the line
400 will be allocated as the last argument if there are more than `max_args'
401 arguments in the line. Note that the command name is counted as one
402 argument and is saved. */
404 void silc_parse_command_line(unsigned char *buffer,
405 unsigned char ***parsed,
406 uint32 **parsed_lens,
407 uint32 **parsed_types,
413 const char *cp = buffer;
415 *parsed = silc_calloc(1, sizeof(**parsed));
416 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
418 /* Get the command first */
419 len = strcspn(cp, " ");
420 (*parsed)[0] = silc_to_upper((char *)cp);
421 (*parsed_lens)[0] = len;
425 /* Parse arguments */
426 if (strchr(cp, ' ') || strlen(cp) != 0) {
427 for (i = 1; i < max_args; i++) {
429 if (i != max_args - 1)
430 len = strcspn(cp, " ");
434 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
435 *parsed_lens = silc_realloc(*parsed_lens,
436 sizeof(**parsed_lens) * (argc + 1));
437 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
438 memcpy((*parsed)[argc], cp, len);
439 (*parsed_lens)[argc] = len;
450 /* Save argument types. Protocol defines all argument types but
451 this implementation makes sure that they are always in correct
452 order hence this simple code. */
453 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
454 for (i = 0; i < argc; i++)
455 (*parsed_types)[i] = i;
460 /* Formats arguments to a string and returns it after allocating memory
461 for it. It must be remembered to free it later. */
463 char *silc_format(char *fmt, ...)
466 static char buf[8192];
468 memset(buf, 0, sizeof(buf));
470 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
476 /* Renders ID to suitable to print for example to log file. */
478 static char rid[256];
480 char *silc_id_render(void *id, uint16 type)
483 unsigned char tmps[2];
485 memset(rid, 0, sizeof(rid));
489 SilcServerID *server_id = (SilcServerID *)id;
492 if (server_id->ip.data_len > 4) {
495 SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
496 strcat(rid, inet_ntoa(ipv4));
499 memset(tmp, 0, sizeof(tmp));
500 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
502 SILC_PUT16_MSB(server_id->rnd, tmps);
503 memset(tmp, 0, sizeof(tmp));
504 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
510 SilcClientID *client_id = (SilcClientID *)id;
513 if (client_id->ip.data_len > 4) {
516 SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
517 strcat(rid, inet_ntoa(ipv4));
520 memset(tmp, 0, sizeof(tmp));
521 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
523 memset(tmp, 0, sizeof(tmp));
524 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
525 client_id->hash[0], client_id->hash[1],
526 client_id->hash[2], client_id->hash[3]);
530 case SILC_ID_CHANNEL:
532 SilcChannelID *channel_id = (SilcChannelID *)id;
535 if (channel_id->ip.data_len > 4) {
538 SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
539 strcat(rid, inet_ntoa(ipv4));
542 memset(tmp, 0, sizeof(tmp));
543 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
545 SILC_PUT16_MSB(channel_id->rnd, tmps);
546 memset(tmp, 0, sizeof(tmp));
547 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
556 /* Compares two strings. Strings may include wildcards * and ?.
557 Returns TRUE if strings match. */
559 int silc_string_compare(char *string1, char *string2)
562 int slen1 = strlen(string1);
563 int slen2 = strlen(string2);
564 char *tmpstr1, *tmpstr2;
566 if (!string1 || !string2)
569 /* See if they are same already */
570 if (!strncmp(string1, string2, strlen(string2)))
574 if (!strchr(string1, '*'))
577 /* Take copies of the original strings as we will change them */
578 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
579 memcpy(tmpstr1, string1, slen1);
580 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
581 memcpy(tmpstr2, string2, slen2);
583 for (i = 0; i < slen1; i++) {
585 /* * wildcard. Only one * wildcard is possible. */
586 if (tmpstr1[i] == '*')
587 if (!strncmp(tmpstr1, tmpstr2, i)) {
588 memset(tmpstr2, 0, slen2);
589 strncpy(tmpstr2, tmpstr1, i);
594 if (tmpstr1[i] == '?') {
595 if (!strncmp(tmpstr1, tmpstr2, i)) {
596 if (!(slen1 < i + 1))
597 if (tmpstr1[i + 1] != '?' &&
598 tmpstr1[i + 1] != tmpstr2[i + 1])
601 if (!(slen1 < slen2))
607 /* if using *, remove it */
608 if (strchr(tmpstr1, '*'))
609 *strchr(tmpstr1, '*') = 0;
611 if (!strcmp(tmpstr1, tmpstr2)) {
612 memset(tmpstr1, 0, slen1);
613 memset(tmpstr2, 0, slen2);
619 memset(tmpstr1, 0, slen1);
620 memset(tmpstr2, 0, slen2);
626 /* Inspects the `string' for wildcards and returns regex string that can
627 be used by the GNU regex library. A comma (`,') in the `string' means
628 that the string is list. */
630 char *silc_string_regexify(const char *string)
635 len = strlen(string);
637 for (i = 0; i < len; i++)
638 if (string[i] == '*' || string[i] == '?')
641 regex = silc_calloc(len + count, sizeof(*regex));
647 for (i = 0; i < len; i++) {
648 if (string[i] == '*' || string[i] == '?') {
651 } else if (string[i] == ',') {
657 regex[count] = string[i];
661 regex[count - 1] = ')';
667 /* Combines two regex strings into one regex string so that they can be
668 used as one by the GNU regex library. The `string2' is combine into
671 char *silc_string_regex_combine(const char *string1, const char *string2)
676 len1 = strlen(string1);
677 len2 = strlen(string2);
679 tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
680 strncat(tmp, string1, len1 - 2);
681 strncat(tmp, "|", 1);
682 strncat(tmp, string2 + 1, len2 - 1);
687 /* Matches the two strings and returns TRUE if the strings match. */
689 int silc_string_regex_match(const char *regex, const char *string)
694 if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0)
697 if (regexec(&preg, string, 0, NULL, 0) == 0)
705 /* Do regex match to the two strings `string1' and `string2'. If the
706 `string2' matches the `string1' this returns TRUE. */
708 int silc_string_match(const char *string1, const char *string2)
713 s1 = silc_string_regexify(string1);
714 ret = silc_string_regex_match(s1, string2);
720 /* Returns the username of the user. If the global variable LOGNAME
721 does not exists we will get the name from the password file. */
723 char *silc_get_username()
725 char *logname = NULL;
727 if (!getenv("LOGNAME")) {
728 fprintf(stderr, "Error: environment variable $LOGNAME not set\n");
732 logname = strdup(getenv("LOGNAME"));
734 logname = getlogin();
738 pw = getpwuid(getuid());
740 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
744 logname = strdup(pw->pw_name);
751 /* Returns the real name of ther user. */
753 char *silc_get_real_name()
755 char *realname = NULL;
758 pw = getpwuid(getuid());
760 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
764 if (strchr(pw->pw_gecos, ','))
765 *strchr(pw->pw_gecos, ',') = 0;
767 realname = strdup(pw->pw_gecos);
772 /* Basic has function to hash strings. May be used with the SilcHashTable.
773 Note that this lowers the characters of the string (with tolower()) so
774 this is used usually with nicknames, channel and server names to provide
775 case insensitive keys. */
777 uint32 silc_hash_string(void *key, void *user_context)
779 char *s = (char *)key;
783 h = (h << 4) + tolower(*s);
784 if ((g = h & 0xf0000000)) {
794 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
796 uint32 silc_hash_uint(void *key, void *user_context)
798 return *(uint32 *)key;
801 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
803 uint32 silc_hash_ptr(void *key, void *user_context)
808 /* Hash a ID. The `user_context' is the ID type. */
810 uint32 silc_hash_id(void *key, void *user_context)
812 SilcIdType id_type = (SilcIdType)(uint32)user_context;
819 SilcClientID *id = (SilcClientID *)key;
822 /* The client ID is hashed by hashing the hash of the ID
823 (which is a truncated MD5 hash of the nickname) so that we
824 can access the entry from the cache with both Client ID but
825 with just a hash from the ID as well. */
827 for (i = 0; i < sizeof(id->hash); i++) {
828 h = (h << 4) + id->hash[i];
829 if ((g = h & 0xf0000000)) {
840 SilcServerID *id = (SilcServerID *)key;
842 h = id->port * id->rnd;
843 for (i = 0; i < id->ip.data_len; i++)
849 case SILC_ID_CHANNEL:
851 SilcChannelID *id = (SilcChannelID *)key;
853 h = id->port * id->rnd;
854 for (i = 0; i < id->ip.data_len; i++)
867 /* Hash binary data. The `user_context' is the data length. */
869 uint32 silc_hash_data(void *key, void *user_context)
871 uint32 len = (uint32)user_context, h = 0;
872 unsigned char *data = (unsigned char *)key;
875 h = (data[0] * data[len - 1] + 1) * len;
876 for (i = 0; i < len; i++)
882 /* Compares two strings. May be used as SilcHashTable comparison function. */
884 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
886 return !strcasecmp((char *)key1, (char *)key2);
889 /* Compares two ID's. May be used as SilcHashTable comparison function.
890 The Client ID's compares only the hash of the Client ID not any other
891 part of the Client ID. Other ID's are fully compared. */
893 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
895 SilcIdType id_type = (SilcIdType)(uint32)user_context;
896 return (id_type == SILC_ID_CLIENT ?
897 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
898 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
901 /* Compare two Client ID's entirely and not just the hash from the ID. */
903 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
905 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
908 /* Compares binary data. May be used as SilcHashTable comparison function. */
910 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
912 uint32 len = (uint32)user_context;
913 return !memcmp(key1, key2, len);