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);
48 if (lseek(fd, (off_t)0L, SEEK_SET) < 0) {
54 SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
59 buffer = silc_calloc(filelen + 1, sizeof(char));
61 if ((read(fd, buffer, filelen)) == -1) {
62 memset(buffer, 0, sizeof(buffer));
64 SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
70 buffer[filelen] = EOF;
73 *return_len = filelen;
78 /* Writes a buffer to the file. */
80 int silc_file_write(const char *filename, const char *buffer, uint32 len)
84 if ((fd = creat(filename, 0644)) == -1) {
85 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
90 if ((write(fd, buffer, len)) == -1) {
91 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
101 /* Writes a buffer to the file. If the file is created specific mode is
104 int silc_file_write_mode(const char *filename, const char *buffer,
105 uint32 len, int mode)
109 if ((fd = creat(filename, mode)) == -1) {
110 SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
115 if ((write(fd, buffer, len)) == -1) {
116 SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
126 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
127 This doesn't remove the newline sign from the destination buffer. The
128 argument begin is returned and should be passed again for the function. */
130 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
132 static int start = 0;
135 memset(dest, 0, destlen);
141 for ( ; start <= srclen; i++, start++) {
145 dest[i] = src[start];
158 /* Checks line for illegal characters. Return -1 when illegal character
159 were found. This is used to check for bad lines when reading data from
160 for example a configuration file. */
162 int silc_check_line(char *buf)
164 /* Illegal characters in line */
165 if (strchr(buf, '#')) return -1;
166 if (strchr(buf, '\'')) return -1;
167 if (strchr(buf, '\\')) return -1;
168 if (strchr(buf, '\r')) return -1;
169 if (strchr(buf, '\a')) return -1;
170 if (strchr(buf, '\b')) return -1;
171 if (strchr(buf, '\f')) return -1;
180 /* Returns current time as string. */
182 char *silc_get_time()
187 curtime = time(NULL);
188 return_time = ctime(&curtime);
189 return_time[strlen(return_time) - 1] = '\0';
194 /* Converts string to capital characters */
196 char *silc_to_upper(char *string)
199 char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
201 for (i = 0; i < strlen(string); i++)
202 ret[i] = toupper(string[i]);
207 static unsigned char pem_enc[64] =
208 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
210 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
211 data string. Note: This is originally public domain code and is
214 char *silc_encode_pem(unsigned char *data, uint32 len)
217 uint32 bits, c, char_count;
224 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
226 for (i = 0; i < len; i++) {
231 if (char_count == 3) {
232 pem[j++] = pem_enc[bits >> 18];
233 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
234 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
235 pem[j++] = pem_enc[bits & 0x3f];
243 if (char_count != 0) {
244 bits <<= 16 - (8 * char_count);
245 pem[j++] = pem_enc[bits >> 18];
246 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
248 if (char_count == 1) {
252 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
260 /* Same as above but puts newline ('\n') every 72 characters. */
262 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
268 pem = silc_encode_pem(data, data_len);
271 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
273 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
288 /* Decodes PEM into data. Returns the decoded data. Note: This is
289 originally public domain code and is still PD. */
291 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
295 uint32 len, c, char_count, bits;
297 static char ialpha[256], decoder[256];
299 for (i = 64 - 1; i >= 0; i--) {
300 ialpha[pem_enc[i]] = 1;
301 decoder[pem_enc[i]] = i;
313 data = silc_calloc(((len * 6) / 8), sizeof(*data));
315 for (i = 0; i < len; i++) {
321 if (c > 127 || !ialpha[c])
327 if (char_count == 4) {
328 data[j++] = bits >> 16;
329 data[j++] = (bits >> 8) & 0xff;
330 data[j++] = bits & 0xff;
344 data[j++] = bits >> 10;
347 data[j++] = bits >> 16;
348 data[j++] = (bits >> 8) & 0xff;
358 /* Parse nickname string. The format may be <num>!<nickname>@<server> to
359 support multiple same nicknames. The <num> is the final unifier if same
360 nickname is on same server. Note, this is only local format and server
361 does not know anything about these. */
363 int silc_parse_nickname(char *string, char **nickname, char **server,
372 if (strchr(string, '!')) {
373 tlen = strcspn(string, "!");
374 memset(tmp, 0, sizeof(tmp));
375 memcpy(tmp, string, tlen);
380 if (tlen >= strlen(string))
386 if (strchr(string, '@')) {
387 tlen = strcspn(string, "@");
390 *nickname = silc_calloc(tlen + 1, sizeof(char));
391 memcpy(*nickname, string, tlen);
395 *server = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
396 memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
400 *nickname = strdup(string);
406 /* Parses command line. At most `max_args' is taken. Rest of the line
407 will be allocated as the last argument if there are more than `max_args'
408 arguments in the line. Note that the command name is counted as one
409 argument and is saved. */
411 void silc_parse_command_line(unsigned char *buffer,
412 unsigned char ***parsed,
413 uint32 **parsed_lens,
414 uint32 **parsed_types,
420 const char *cp = buffer;
422 *parsed = silc_calloc(1, sizeof(**parsed));
423 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
425 /* Get the command first */
426 len = strcspn(cp, " ");
427 (*parsed)[0] = silc_to_upper((char *)cp);
428 (*parsed_lens)[0] = len;
432 /* Parse arguments */
433 if (strchr(cp, ' ') || strlen(cp) != 0) {
434 for (i = 1; i < max_args; i++) {
436 if (i != max_args - 1)
437 len = strcspn(cp, " ");
441 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
442 *parsed_lens = silc_realloc(*parsed_lens,
443 sizeof(**parsed_lens) * (argc + 1));
444 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
445 memcpy((*parsed)[argc], cp, len);
446 (*parsed_lens)[argc] = len;
457 /* Save argument types. Protocol defines all argument types but
458 this implementation makes sure that they are always in correct
459 order hence this simple code. */
460 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
461 for (i = 0; i < argc; i++)
462 (*parsed_types)[i] = i;
467 /* Formats arguments to a string and returns it after allocating memory
468 for it. It must be remembered to free it later. */
470 char *silc_format(char *fmt, ...)
473 static char buf[8192];
475 memset(buf, 0, sizeof(buf));
477 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
483 /* Renders ID to suitable to print for example to log file. */
485 static char rid[256];
487 char *silc_id_render(void *id, uint16 type)
490 unsigned char tmps[2];
492 memset(rid, 0, sizeof(rid));
496 SilcServerID *server_id = (SilcServerID *)id;
499 if (server_id->ip.data_len > 4) {
502 SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
503 strcat(rid, inet_ntoa(ipv4));
506 memset(tmp, 0, sizeof(tmp));
507 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
509 SILC_PUT16_MSB(server_id->rnd, tmps);
510 memset(tmp, 0, sizeof(tmp));
511 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
517 SilcClientID *client_id = (SilcClientID *)id;
520 if (client_id->ip.data_len > 4) {
523 SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
524 strcat(rid, inet_ntoa(ipv4));
527 memset(tmp, 0, sizeof(tmp));
528 snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
530 memset(tmp, 0, sizeof(tmp));
531 snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]",
532 client_id->hash[0], client_id->hash[1],
533 client_id->hash[2], client_id->hash[3]);
537 case SILC_ID_CHANNEL:
539 SilcChannelID *channel_id = (SilcChannelID *)id;
542 if (channel_id->ip.data_len > 4) {
545 SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
546 strcat(rid, inet_ntoa(ipv4));
549 memset(tmp, 0, sizeof(tmp));
550 snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
552 SILC_PUT16_MSB(channel_id->rnd, tmps);
553 memset(tmp, 0, sizeof(tmp));
554 snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
563 /* Compares two strings. Strings may include wildcards * and ?.
564 Returns TRUE if strings match. */
566 int silc_string_compare(char *string1, char *string2)
569 int slen1 = strlen(string1);
570 int slen2 = strlen(string2);
571 char *tmpstr1, *tmpstr2;
573 if (!string1 || !string2)
576 /* See if they are same already */
577 if (!strncmp(string1, string2, strlen(string2)))
581 if (!strchr(string1, '*'))
584 /* Take copies of the original strings as we will change them */
585 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
586 memcpy(tmpstr1, string1, slen1);
587 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
588 memcpy(tmpstr2, string2, slen2);
590 for (i = 0; i < slen1; i++) {
592 /* * wildcard. Only one * wildcard is possible. */
593 if (tmpstr1[i] == '*')
594 if (!strncmp(tmpstr1, tmpstr2, i)) {
595 memset(tmpstr2, 0, slen2);
596 strncpy(tmpstr2, tmpstr1, i);
601 if (tmpstr1[i] == '?') {
602 if (!strncmp(tmpstr1, tmpstr2, i)) {
603 if (!(slen1 < i + 1))
604 if (tmpstr1[i + 1] != '?' &&
605 tmpstr1[i + 1] != tmpstr2[i + 1])
608 if (!(slen1 < slen2))
614 /* if using *, remove it */
615 if (strchr(tmpstr1, '*'))
616 *strchr(tmpstr1, '*') = 0;
618 if (!strcmp(tmpstr1, tmpstr2)) {
619 memset(tmpstr1, 0, slen1);
620 memset(tmpstr2, 0, slen2);
626 memset(tmpstr1, 0, slen1);
627 memset(tmpstr2, 0, slen2);
633 /* Inspects the `string' for wildcards and returns regex string that can
634 be used by the GNU regex library. A comma (`,') in the `string' means
635 that the string is list. */
637 char *silc_string_regexify(const char *string)
642 len = strlen(string);
644 for (i = 0; i < len; i++)
645 if (string[i] == '*' || string[i] == '?')
648 regex = silc_calloc(len + count, sizeof(*regex));
654 for (i = 0; i < len; i++) {
655 if (string[i] == '*' || string[i] == '?') {
658 } else if (string[i] == ',') {
664 regex[count] = string[i];
668 regex[count - 1] = ')';
674 /* Combines two regex strings into one regex string so that they can be
675 used as one by the GNU regex library. The `string2' is combine into
678 char *silc_string_regex_combine(const char *string1, const char *string2)
683 len1 = strlen(string1);
684 len2 = strlen(string2);
686 tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
687 strncat(tmp, string1, len1 - 2);
688 strncat(tmp, "|", 1);
689 strncat(tmp, string2 + 1, len2 - 1);
694 /* Matches the two strings and returns TRUE if the strings match. */
696 int silc_string_regex_match(const char *regex, const char *string)
701 if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0)
704 if (regexec(&preg, string, 0, NULL, 0) == 0)
712 /* Do regex match to the two strings `string1' and `string2'. If the
713 `string2' matches the `string1' this returns TRUE. */
715 int silc_string_match(const char *string1, const char *string2)
720 s1 = silc_string_regexify(string1);
721 ret = silc_string_regex_match(s1, string2);
727 /* Returns the username of the user. If the global variable LOGNAME
728 does not exists we will get the name from the password file. */
730 char *silc_get_username()
732 char *logname = NULL;
734 if (!getenv("LOGNAME")) {
735 fprintf(stderr, "Error: environment variable $LOGNAME not set\n");
739 logname = strdup(getenv("LOGNAME"));
741 logname = getlogin();
745 pw = getpwuid(getuid());
747 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
751 logname = strdup(pw->pw_name);
758 /* Returns the real name of ther user. */
760 char *silc_get_real_name()
762 char *realname = NULL;
765 pw = getpwuid(getuid());
767 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
771 if (strchr(pw->pw_gecos, ','))
772 *strchr(pw->pw_gecos, ',') = 0;
774 realname = strdup(pw->pw_gecos);
779 /* Basic has function to hash strings. May be used with the SilcHashTable.
780 Note that this lowers the characters of the string (with tolower()) so
781 this is used usually with nicknames, channel and server names to provide
782 case insensitive keys. */
784 uint32 silc_hash_string(void *key, void *user_context)
786 char *s = (char *)key;
790 h = (h << 4) + tolower(*s);
791 if ((g = h & 0xf0000000)) {
801 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
803 uint32 silc_hash_uint(void *key, void *user_context)
805 return *(uint32 *)key;
808 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
810 uint32 silc_hash_ptr(void *key, void *user_context)
815 /* Hash a ID. The `user_context' is the ID type. */
817 uint32 silc_hash_id(void *key, void *user_context)
819 SilcIdType id_type = (SilcIdType)(uint32)user_context;
826 SilcClientID *id = (SilcClientID *)key;
829 /* The client ID is hashed by hashing the hash of the ID
830 (which is a truncated MD5 hash of the nickname) so that we
831 can access the entry from the cache with both Client ID but
832 with just a hash from the ID as well. */
834 for (i = 0; i < sizeof(id->hash); i++) {
835 h = (h << 4) + id->hash[i];
836 if ((g = h & 0xf0000000)) {
847 SilcServerID *id = (SilcServerID *)key;
849 h = id->port * id->rnd;
850 for (i = 0; i < id->ip.data_len; i++)
856 case SILC_ID_CHANNEL:
858 SilcChannelID *id = (SilcChannelID *)key;
860 h = id->port * id->rnd;
861 for (i = 0; i < id->ip.data_len; i++)
874 /* Hash binary data. The `user_context' is the data length. */
876 uint32 silc_hash_data(void *key, void *user_context)
878 uint32 len = (uint32)user_context, h = 0;
879 unsigned char *data = (unsigned char *)key;
882 h = (data[0] * data[len - 1] + 1) * len;
883 for (i = 0; i < len; i++)
889 /* Compares two strings. May be used as SilcHashTable comparison function. */
891 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
893 return !strcasecmp((char *)key1, (char *)key2);
896 /* Compares two ID's. May be used as SilcHashTable comparison function.
897 The Client ID's compares only the hash of the Client ID not any other
898 part of the Client ID. Other ID's are fully compared. */
900 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
902 SilcIdType id_type = (SilcIdType)(uint32)user_context;
903 return (id_type == SILC_ID_CLIENT ?
904 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
905 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
908 /* Compare two Client ID's entirely and not just the hash from the ID. */
910 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
912 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
915 /* Compares binary data. May be used as SilcHashTable comparison function. */
917 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
919 uint32 len = (uint32)user_context;
920 return !memcmp(key1, key2, len);