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       strcat(rid, inet_ntoa(server_id->ip));
491       memset(tmp, 0, sizeof(tmp));
492       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
493       strcat(rid, tmp);
494       SILC_PUT16_MSB(server_id->rnd, tmps);
495       memset(tmp, 0, sizeof(tmp));
496       snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
497       strcat(rid, tmp);
498     }
499     break;
500   case SILC_ID_CLIENT:
501     {
502       SilcClientID *client_id = (SilcClientID *)id;
503       strcat(rid, inet_ntoa(client_id->ip));
504       memset(tmp, 0, sizeof(tmp));
505       snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
506       strcat(rid, tmp);
507       memset(tmp, 0, sizeof(tmp));
508       snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]", 
509                client_id->hash[0], client_id->hash[1],
510                client_id->hash[2], client_id->hash[3]);
511       strcat(rid, tmp);
512     }
513     break;
514   case SILC_ID_CHANNEL:
515     {
516       SilcChannelID *channel_id = (SilcChannelID *)id;
517       strcat(rid, inet_ntoa(channel_id->ip));
518       memset(tmp, 0, sizeof(tmp));
519       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
520       strcat(rid, tmp);
521       SILC_PUT16_MSB(channel_id->rnd, tmps);
522       memset(tmp, 0, sizeof(tmp));
523       snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
524       strcat(rid, tmp);
525     }
526     break;
527   }
528
529   return rid;
530 }
531
532 /* Compares two strings. Strings may include wildcards * and ?.
533    Returns TRUE if strings match. */
534
535 int silc_string_compare(char *string1, char *string2)
536 {
537   int i;
538   int slen1 = strlen(string1);
539   int slen2 = strlen(string2);
540   char *tmpstr1, *tmpstr2;
541
542   if (!string1 || !string2)
543     return FALSE;
544
545   /* See if they are same already */
546   if (!strncmp(string1, string2, strlen(string2)))
547     return TRUE;
548
549   if (slen2 < slen1)
550     if (!strchr(string1, '*'))
551       return FALSE;
552   
553   /* Take copies of the original strings as we will change them */
554   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
555   memcpy(tmpstr1, string1, slen1);
556   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
557   memcpy(tmpstr2, string2, slen2);
558   
559   for (i = 0; i < slen1; i++) {
560     
561     /* * wildcard. Only one * wildcard is possible. */
562     if (tmpstr1[i] == '*')
563       if (!strncmp(tmpstr1, tmpstr2, i)) {
564         memset(tmpstr2, 0, slen2);
565         strncpy(tmpstr2, tmpstr1, i);
566         break;
567       }
568     
569     /* ? wildcard */
570     if (tmpstr1[i] == '?') {
571       if (!strncmp(tmpstr1, tmpstr2, i)) {
572         if (!(slen1 < i + 1))
573           if (tmpstr1[i + 1] != '?' &&
574               tmpstr1[i + 1] != tmpstr2[i + 1])
575             continue;
576         
577         if (!(slen1 < slen2))
578           tmpstr2[i] = '?';
579       }
580     }
581   }
582   
583   /* if using *, remove it */
584   if (strchr(tmpstr1, '*'))
585     *strchr(tmpstr1, '*') = 0;
586   
587   if (!strcmp(tmpstr1, tmpstr2)) {
588     memset(tmpstr1, 0, slen1);
589     memset(tmpstr2, 0, slen2);
590     silc_free(tmpstr1);
591     silc_free(tmpstr2);
592     return TRUE;
593   }
594   
595   memset(tmpstr1, 0, slen1);
596   memset(tmpstr2, 0, slen2);
597   silc_free(tmpstr1);
598   silc_free(tmpstr2);
599   return FALSE;
600 }
601
602 /* Inspects the `string' for wildcards and returns regex string that can
603    be used by the GNU regex library. A comma (`,') in the `string' means
604    that the string is list. */
605
606 char *silc_string_regexify(const char *string)
607 {
608   int i, len, count;
609   char *regex;
610
611   len = strlen(string);
612   count = 4;
613   for (i = 0; i < len; i++)
614     if (string[i] == '*' || string[i] == '?')
615       count++;
616
617   regex = silc_calloc(len + count, sizeof(*regex));
618
619   count = 0;
620   regex[count] = '(';
621   count++;
622
623   for (i = 0; i < len; i++) {
624     if (string[i] == '*' || string[i] == '?') {
625       regex[count] = '.';
626       count++;
627     } else if (string[i] == ',') {
628       regex[count] = '|';
629       count++;
630       continue;
631     }
632
633     regex[count] = string[i];
634     count++;
635   }
636
637   regex[count - 1] = ')';
638   regex[count] = '$';
639
640   return regex;
641 }
642
643 /* Combines two regex strings into one regex string so that they can be
644    used as one by the GNU regex library. The `string2' is combine into
645    the `string1'. */
646
647 char *silc_string_regex_combine(const char *string1, const char *string2)
648 {
649   char *tmp;
650   int len1, len2;
651
652   len1 = strlen(string1);
653   len2 = strlen(string2);
654
655   tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
656   strncat(tmp, string1, len1 - 2);
657   strncat(tmp, "|", 1);
658   strncat(tmp, string2 + 1, len2 - 1);
659
660   return tmp;
661 }
662
663 /* Matches the two strings and returns TRUE if the strings match. */
664
665 int silc_string_regex_match(const char *regex, const char *string)
666 {
667   regex_t preg;
668   int ret = FALSE;
669   
670   if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0)
671     return FALSE;
672
673   if (regexec(&preg, string, 0, NULL, 0) == 0)
674     ret = TRUE;
675
676   regfree(&preg);
677
678   return ret;
679 }
680
681 /* Do regex match to the two strings `string1' and `string2'. If the
682    `string2' matches the `string1' this returns TRUE. */
683
684 int silc_string_match(const char *string1, const char *string2)
685 {
686   char *s1;
687   int ret = FALSE;
688
689   s1 = silc_string_regexify(string1);
690   ret = silc_string_regex_match(s1, string2);
691   silc_free(s1);
692
693   return ret;
694 }
695
696 /* Returns the username of the user. If the global variable LOGNAME
697    does not exists we will get the name from the password file. */
698
699 char *silc_get_username()
700 {
701   char *logname = NULL;
702   
703   logname = strdup(getenv("LOGNAME"));
704   if (!logname) {
705     logname = getlogin();
706     if (!logname) {
707       struct passwd *pw;
708
709       pw = getpwuid(getuid());
710       if (!pw) {
711         fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
712         return NULL;
713       }
714       
715       logname = strdup(pw->pw_name);
716     }
717   }
718   
719   return logname;
720 }                          
721
722 /* Returns the real name of ther user. */
723
724 char *silc_get_real_name()
725 {
726   char *realname = NULL;
727   struct passwd *pw;
728     
729   pw = getpwuid(getuid());
730   if (!pw) {
731     fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
732     return NULL;
733   }
734
735   if (strchr(pw->pw_gecos, ','))
736     *strchr(pw->pw_gecos, ',') = 0;
737
738   realname = strdup(pw->pw_gecos);
739
740   return realname;
741 }