updates.
[silc.git] / lib / silcutil / silcutil.c
1 /*
2
3   silcutil.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 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; either version 2 of the License, or
12   (at your option) any later version.
13   
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.
18
19 */
20 /*
21  * These are general utility functions that doesn't belong to any specific
22  * group of routines.
23  */
24 /* $Id$ */
25
26 #include "silcincludes.h"
27
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. */
30
31 char *silc_file_read(const char *filename, uint32 *return_len)
32 {
33   int fd;
34   char *buffer;
35   int filelen;
36
37   fd = open(filename, O_RDONLY);
38   if (fd < 0) {
39     SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
40     return NULL;
41   }
42
43   filelen = lseek(fd, (off_t)0L, SEEK_END);
44   if (filelen < 0)
45     return NULL;
46   if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
47     return NULL;
48
49   if (filelen < 0) {
50     SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
51     return NULL;
52   }
53   
54   buffer = silc_calloc(filelen + 1, sizeof(char));
55   
56   if ((read(fd, buffer, filelen)) == -1) {
57     memset(buffer, 0, sizeof(buffer));
58     close(fd);
59     SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
60                     strerror(errno)));
61     return NULL;
62   }
63
64   close(fd);
65   buffer[filelen] = EOF;
66
67   if (return_len)
68     *return_len = filelen;
69
70   return buffer;
71 }
72
73 /* Writes a buffer to the file. */
74
75 int silc_file_write(const char *filename, const char *buffer, uint32 len)
76 {
77   int fd;
78         
79   if ((fd = creat(filename, 0644)) == -1) {
80     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
81                     strerror(errno)));
82     return -1;
83   }
84   
85   if ((write(fd, buffer, len)) == -1) {
86     SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
87     return -1;
88   }
89
90   close(fd);
91   
92   return 0;
93 }
94
95 /* Writes a buffer to the file.  If the file is created specific mode is
96    set to the file. */
97
98 int silc_file_write_mode(const char *filename, const char *buffer, 
99                          uint32 len, int mode)
100 {
101   int fd;
102         
103   if ((fd = creat(filename, mode)) == -1) {
104     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
105                     strerror(errno)));
106     return -1;
107   }
108   
109   if ((write(fd, buffer, len)) == -1) {
110     SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
111     return -1;
112   }
113
114   close(fd);
115   
116   return 0;
117 }
118
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. */
122
123 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
124 {
125   static int start = 0;
126   int i;
127   
128   memset(dest, 0, destlen);
129   
130   if (begin != start)
131     start = 0;
132   
133   i = 0;
134   for ( ; start <= srclen; i++, start++) {
135     if (i > destlen)
136       return -1;
137     
138     dest[i] = src[start];
139     
140     if (dest[i] == EOF) 
141       return EOF;
142     
143     if (dest[i] == '\n') 
144       break;
145   }
146   start++;
147   
148   return start;
149 }
150
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. */
154
155 int silc_check_line(char *buf) 
156 {
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;
165   
166   /* Empty line */
167   if (buf[0] == '\n')
168     return -1;
169   
170   return 0;
171 }
172
173 /* Returns current time as string. */
174
175 char *silc_get_time()
176 {
177   time_t curtime;
178   char *return_time;
179
180   curtime = time(NULL);
181   return_time = ctime(&curtime);
182   return_time[strlen(return_time) - 1] = '\0';
183
184   return return_time;
185 }
186
187 /* Converts string to capital characters */
188
189 char *silc_to_upper(char *string)
190 {
191   int i;
192   char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
193
194   for (i = 0; i < strlen(string); i++)
195     ret[i] = toupper(string[i]);
196
197   return ret;
198 }
199
200 static unsigned char pem_enc[64] =
201 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
202
203 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
204    data string. Note: This is originally public domain code and is 
205    still PD. */
206
207 char *silc_encode_pem(unsigned char *data, uint32 len)
208 {
209   int i, j;
210   uint32 bits, c, char_count;
211   char *pem;
212
213   char_count = 0;
214   bits = 0;
215   j = 0;
216
217   pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
218
219   for (i = 0; i < len; i++) {
220     c = data[i];
221     bits += c;
222     char_count++;
223
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];
229       bits = 0;
230       char_count = 0;
231     } else {
232       bits <<= 8;
233     }
234   }
235
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];
240
241     if (char_count == 1) {
242       pem[j++] = '=';
243       pem[j] = '=';
244     } else {
245       pem[j++] = pem_enc[(bits >> 6) & 0x3f];
246       pem[j] = '=';
247     }
248   }
249
250   return pem;
251 }
252
253 /* Same as above but puts newline ('\n') every 72 characters. */
254
255 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
256 {
257   int i, j;
258   uint32 len, cols;
259   char *pem, *pem2;
260
261   pem = silc_encode_pem(data, data_len);
262   len = strlen(pem);
263
264   pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
265
266   for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
267     if (cols == 72) {
268       pem2[i] = '\n';
269       cols = 0;
270       len++;
271       continue;
272     }
273
274     pem2[i] = pem[j++];
275   }
276
277   silc_free(pem);
278   return pem2;
279 }
280
281 /* Decodes PEM into data. Returns the decoded data. Note: This is
282    originally public domain code and is still PD. */
283
284 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
285                                uint32 *ret_len)
286 {
287   int i, j;
288   uint32 len, c, char_count, bits;
289   unsigned char *data;
290   static char ialpha[256], decoder[256];
291
292   for (i = 64 - 1; i >= 0; i--) {
293     ialpha[pem_enc[i]] = 1;
294     decoder[pem_enc[i]] = i;
295   }
296
297   char_count = 0;
298   bits = 0;
299   j = 0;
300
301   if (!pem_len)
302     len = strlen(pem);
303   else
304     len = pem_len;
305
306   data = silc_calloc(((len * 6) / 8), sizeof(*data));
307
308   for (i = 0; i < len; i++) {
309     c = pem[i];
310
311     if (c == '=')
312       break;
313
314     if (c > 127 || !ialpha[c])
315       continue;
316
317     bits += decoder[c];
318     char_count++;
319
320     if (char_count == 4) {
321       data[j++] = bits >> 16;
322       data[j++] = (bits >> 8) & 0xff;
323       data[j++] = bits & 0xff;
324       bits = 0;
325       char_count = 0;
326     } else {
327       bits <<= 6;
328     }
329   }
330
331   switch(char_count) {
332   case 1:
333     silc_free(data);
334     return NULL;
335     break;
336   case 2:
337     data[j++] = bits >> 10;
338     break;
339   case 3:
340     data[j++] = bits >> 16;
341     data[j++] = (bits >> 8) & 0xff;
342     break;
343   }
344
345   if (ret_len)
346     *ret_len = j;
347
348   return data;
349 }
350
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. */
355
356 int silc_parse_nickname(char *string, char **nickname, char **server,
357                         uint32 *num)
358 {
359   uint32 tlen;
360   char tmp[256];
361
362   if (!string)
363     return FALSE;
364
365   if (strchr(string, '!')) {
366     tlen = strcspn(string, "!");
367     memset(tmp, 0, sizeof(tmp));
368     memcpy(tmp, string, tlen);
369
370     if (num)
371       *num = atoi(tmp);
372
373     if (tlen >= strlen(string))
374       return FALSE;
375
376     string += tlen + 1;
377   }
378
379   if (strchr(string, '@')) {
380     tlen = strcspn(string, "@");
381     
382     if (nickname) {
383       *nickname = silc_calloc(tlen + 1, sizeof(char));
384       memcpy(*nickname, string, tlen);
385     }
386     
387     if (server) {
388       *server = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
389       memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
390     }
391   } else {
392     if (nickname)
393       *nickname = strdup(string);
394   }
395
396   return TRUE;
397 }
398
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. */
403
404 void silc_parse_command_line(unsigned char *buffer, 
405                              unsigned char ***parsed,
406                              uint32 **parsed_lens,
407                              uint32 **parsed_types,
408                              uint32 *parsed_num,
409                              uint32 max_args)
410 {
411   int i, len = 0;
412   int argc = 0;
413   const char *cp = buffer;
414
415   *parsed = silc_calloc(1, sizeof(**parsed));
416   *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
417
418   /* Get the command first */
419   len = strcspn(cp, " ");
420   (*parsed)[0] = silc_to_upper((char *)cp);
421   (*parsed_lens)[0] = len;
422   cp += len + 1;
423   argc++;
424
425   /* Parse arguments */
426   if (strchr(cp, ' ') || strlen(cp) != 0) {
427     for (i = 1; i < max_args; i++) {
428
429       if (i != max_args - 1)
430         len = strcspn(cp, " ");
431       else
432         len = strlen(cp);
433       
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;
440       argc++;
441
442       cp += len;
443       if (strlen(cp) == 0)
444         break;
445       else
446         cp++;
447     }
448   }
449
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;
456
457   *parsed_num = argc;
458 }
459
460 /* Formats arguments to a string and returns it after allocating memory
461    for it. It must be remembered to free it later. */
462
463 char *silc_format(char *fmt, ...)
464 {
465   va_list args;
466   static char buf[8192];
467
468   memset(buf, 0, sizeof(buf));
469   va_start(args, fmt);
470   vsnprintf(buf, sizeof(buf) - 1, fmt, args);
471   va_end(args);
472
473   return strdup(buf);
474 }
475
476 /* Renders ID to suitable to print for example to log file. */
477
478 static char rid[256];
479
480 char *silc_id_render(void *id, uint16 type)
481 {
482   char tmp[100];
483   unsigned char tmps[2];
484
485   memset(rid, 0, sizeof(rid));
486   switch(type) {
487   case SILC_ID_SERVER:
488     {
489       SilcServerID *server_id = (SilcServerID *)id;
490       struct in_addr ipv4;
491
492       if (server_id->ip.data_len > 4) {
493
494       } else {
495         SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
496         strcat(rid, inet_ntoa(ipv4));
497       }
498
499       memset(tmp, 0, sizeof(tmp));
500       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
501       strcat(rid, tmp);
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]);
505       strcat(rid, tmp);
506     }
507     break;
508   case SILC_ID_CLIENT:
509     {
510       SilcClientID *client_id = (SilcClientID *)id;
511       struct in_addr ipv4;
512
513       if (client_id->ip.data_len > 4) {
514
515       } else {
516         SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
517         strcat(rid, inet_ntoa(ipv4));
518       }
519
520       memset(tmp, 0, sizeof(tmp));
521       snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
522       strcat(rid, tmp);
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]);
527       strcat(rid, tmp);
528     }
529     break;
530   case SILC_ID_CHANNEL:
531     {
532       SilcChannelID *channel_id = (SilcChannelID *)id;
533       struct in_addr ipv4;
534
535       if (channel_id->ip.data_len > 4) {
536
537       } else {
538         SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
539         strcat(rid, inet_ntoa(ipv4));
540       }
541
542       memset(tmp, 0, sizeof(tmp));
543       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
544       strcat(rid, tmp);
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]);
548       strcat(rid, tmp);
549     }
550     break;
551   }
552
553   return rid;
554 }
555
556 /* Compares two strings. Strings may include wildcards * and ?.
557    Returns TRUE if strings match. */
558
559 int silc_string_compare(char *string1, char *string2)
560 {
561   int i;
562   int slen1 = strlen(string1);
563   int slen2 = strlen(string2);
564   char *tmpstr1, *tmpstr2;
565
566   if (!string1 || !string2)
567     return FALSE;
568
569   /* See if they are same already */
570   if (!strncmp(string1, string2, strlen(string2)))
571     return TRUE;
572
573   if (slen2 < slen1)
574     if (!strchr(string1, '*'))
575       return FALSE;
576   
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);
582   
583   for (i = 0; i < slen1; i++) {
584     
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);
590         break;
591       }
592     
593     /* ? wildcard */
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])
599             continue;
600         
601         if (!(slen1 < slen2))
602           tmpstr2[i] = '?';
603       }
604     }
605   }
606   
607   /* if using *, remove it */
608   if (strchr(tmpstr1, '*'))
609     *strchr(tmpstr1, '*') = 0;
610   
611   if (!strcmp(tmpstr1, tmpstr2)) {
612     memset(tmpstr1, 0, slen1);
613     memset(tmpstr2, 0, slen2);
614     silc_free(tmpstr1);
615     silc_free(tmpstr2);
616     return TRUE;
617   }
618   
619   memset(tmpstr1, 0, slen1);
620   memset(tmpstr2, 0, slen2);
621   silc_free(tmpstr1);
622   silc_free(tmpstr2);
623   return FALSE;
624 }
625
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. */
629
630 char *silc_string_regexify(const char *string)
631 {
632   int i, len, count;
633   char *regex;
634
635   len = strlen(string);
636   count = 4;
637   for (i = 0; i < len; i++)
638     if (string[i] == '*' || string[i] == '?')
639       count++;
640
641   regex = silc_calloc(len + count, sizeof(*regex));
642
643   count = 0;
644   regex[count] = '(';
645   count++;
646
647   for (i = 0; i < len; i++) {
648     if (string[i] == '*' || string[i] == '?') {
649       regex[count] = '.';
650       count++;
651     } else if (string[i] == ',') {
652       regex[count] = '|';
653       count++;
654       continue;
655     }
656
657     regex[count] = string[i];
658     count++;
659   }
660
661   regex[count - 1] = ')';
662   regex[count] = '$';
663
664   return regex;
665 }
666
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
669    the `string1'. */
670
671 char *silc_string_regex_combine(const char *string1, const char *string2)
672 {
673   char *tmp;
674   int len1, len2;
675
676   len1 = strlen(string1);
677   len2 = strlen(string2);
678
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);
683
684   return tmp;
685 }
686
687 /* Matches the two strings and returns TRUE if the strings match. */
688
689 int silc_string_regex_match(const char *regex, const char *string)
690 {
691   regex_t preg;
692   int ret = FALSE;
693   
694   if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0)
695     return FALSE;
696
697   if (regexec(&preg, string, 0, NULL, 0) == 0)
698     ret = TRUE;
699
700   regfree(&preg);
701
702   return ret;
703 }
704
705 /* Do regex match to the two strings `string1' and `string2'. If the
706    `string2' matches the `string1' this returns TRUE. */
707
708 int silc_string_match(const char *string1, const char *string2)
709 {
710   char *s1;
711   int ret = FALSE;
712
713   s1 = silc_string_regexify(string1);
714   ret = silc_string_regex_match(s1, string2);
715   silc_free(s1);
716
717   return ret;
718 }
719
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. */
722
723 char *silc_get_username()
724 {
725   char *logname = NULL;
726   
727   if (!getenv("LOGNAME")) {
728     fprintf(stderr, "Error: environment variable $LOGNAME not set\n");
729     return NULL;
730   }
731
732   logname = strdup(getenv("LOGNAME"));
733   if (!logname) {
734     logname = getlogin();
735     if (!logname) {
736       struct passwd *pw;
737
738       pw = getpwuid(getuid());
739       if (!pw) {
740         fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
741         return NULL;
742       }
743       
744       logname = strdup(pw->pw_name);
745     }
746   }
747   
748   return logname;
749 }                          
750
751 /* Returns the real name of ther user. */
752
753 char *silc_get_real_name()
754 {
755   char *realname = NULL;
756   struct passwd *pw;
757     
758   pw = getpwuid(getuid());
759   if (!pw) {
760     fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
761     return NULL;
762   }
763
764   if (strchr(pw->pw_gecos, ','))
765     *strchr(pw->pw_gecos, ',') = 0;
766
767   realname = strdup(pw->pw_gecos);
768
769   return realname;
770 }
771
772 /* Basic has function to hash strings. May be used with the SilcHashTable. */
773
774 uint32 silc_hash_string(void *key)
775 {
776   char *s = (char *)key;
777   uint32 h = 0, g;
778   
779   while (*s != '\0') {
780     h = (h << 4) + toupper(*s);
781     if ((g = h & 0xf0000000)) {
782       h = h ^ (g >> 24);
783       h = h ^ g;
784     }
785     s++;
786   }
787   
788   return h;
789 }
790
791 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
792
793 uint32 silc_hash_uint(void *key)
794 {
795   return *(uint32 *)key;
796 }
797
798 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
799
800 uint32 silc_hash_ptr(void *key)
801 {
802   return (uint32)key;
803 }
804
805 /* Hash a Server ID. */
806
807 uint32 silc_hash_server_id(void *key)
808 {
809   SilcServerID *id = (SilcServerID *)key;
810   int i;
811   uint32 h;
812
813   h = id->port * id->rnd;
814   for (i = 0; i < id->ip.data_len; i++)
815     h ^= id->ip.data[i];
816
817   return h;
818 }
819
820 /* Hash a Client ID. */
821
822 uint32 silc_hash_client_id(void *key)
823 {
824   SilcClientID *id = (SilcClientID *)key;
825   int i;
826   uint32 h;
827
828   h = id->rnd;
829   for (i = 0; i < sizeof(id->hash); i++)
830     h ^= id->hash[i];
831   for (i = 0; i < id->ip.data_len; i++)
832     h ^= id->ip.data[i];
833
834   return h;
835 }
836
837 /* Hash a Channel ID. */
838
839 uint32 silc_hash_channel_id(void *key)
840 {
841   SilcChannelID *id = (SilcChannelID *)key;
842   int i;
843   uint32 h;
844
845   h = id->port * id->rnd;
846   for (i = 0; i < id->ip.data_len; i++)
847     h ^= id->ip.data[i];
848
849   return h;
850 }