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   return pem2;
278 }
279
280 /* Decodes PEM into data. Returns the decoded data. Note: This is
281    originally public domain code and is still PD. */
282
283 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
284                                uint32 *ret_len)
285 {
286   int i, j;
287   uint32 len, c, char_count, bits;
288   unsigned char *data;
289   static char ialpha[256], decoder[256];
290
291   for (i = 64 - 1; i >= 0; i--) {
292     ialpha[pem_enc[i]] = 1;
293     decoder[pem_enc[i]] = i;
294   }
295
296   char_count = 0;
297   bits = 0;
298   j = 0;
299
300   if (!pem_len)
301     len = strlen(pem);
302   else
303     len = pem_len;
304
305   data = silc_calloc(((len * 6) / 8), sizeof(*data));
306
307   for (i = 0; i < len; i++) {
308     c = pem[i];
309
310     if (c == '=')
311       break;
312
313     if (c > 127 || !ialpha[c])
314       continue;
315
316     bits += decoder[c];
317     char_count++;
318
319     if (char_count == 4) {
320       data[j++] = bits >> 16;
321       data[j++] = (bits >> 8) & 0xff;
322       data[j++] = bits & 0xff;
323       bits = 0;
324       char_count = 0;
325     } else {
326       bits <<= 6;
327     }
328   }
329
330   switch(char_count) {
331   case 1:
332     silc_free(data);
333     return NULL;
334     break;
335   case 2:
336     data[j++] = bits >> 10;
337     break;
338   case 3:
339     data[j++] = bits >> 16;
340     data[j++] = (bits >> 8) & 0xff;
341     break;
342   }
343
344   if (ret_len)
345     *ret_len = j;
346
347   return data;
348 }
349
350 /* Parse nickname string. The format may be <num>!<nickname>@<server> to
351    support multiple same nicknames. The <num> is the final unifier if same
352    nickname is on same server. Note, this is only local format and server
353    does not know anything about these. */
354
355 int silc_parse_nickname(char *string, char **nickname, char **server,
356                         uint32 *num)
357 {
358   uint32 tlen;
359   char tmp[256];
360
361   if (!string)
362     return FALSE;
363
364   if (strchr(string, '!')) {
365     tlen = strcspn(string, "!");
366     memset(tmp, 0, sizeof(tmp));
367     memcpy(tmp, string, tlen);
368
369     if (num)
370       *num = atoi(tmp);
371
372     if (tlen >= strlen(string))
373       return FALSE;
374
375     string += tlen + 1;
376   }
377
378   if (strchr(string, '@')) {
379     tlen = strcspn(string, "@");
380     
381     if (nickname) {
382       *nickname = silc_calloc(tlen + 1, sizeof(char));
383       memcpy(*nickname, string, tlen);
384     }
385     
386     if (server) {
387       *server = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
388       memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
389     }
390   } else {
391     if (nickname)
392       *nickname = strdup(string);
393   }
394
395   return TRUE;
396 }
397
398 /* Parses command line. At most `max_args' is taken. Rest of the line
399    will be allocated as the last argument if there are more than `max_args'
400    arguments in the line. Note that the command name is counted as one
401    argument and is saved. */
402
403 void silc_parse_command_line(unsigned char *buffer, 
404                              unsigned char ***parsed,
405                              uint32 **parsed_lens,
406                              uint32 **parsed_types,
407                              uint32 *parsed_num,
408                              uint32 max_args)
409 {
410   int i, len = 0;
411   int argc = 0;
412   const char *cp = buffer;
413
414   *parsed = silc_calloc(1, sizeof(**parsed));
415   *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
416
417   /* Get the command first */
418   len = strcspn(cp, " ");
419   (*parsed)[0] = silc_to_upper((char *)cp);
420   (*parsed_lens)[0] = len;
421   cp += len + 1;
422   argc++;
423
424   /* Parse arguments */
425   if (strchr(cp, ' ') || strlen(cp) != 0) {
426     for (i = 1; i < max_args; i++) {
427
428       if (i != max_args - 1)
429         len = strcspn(cp, " ");
430       else
431         len = strlen(cp);
432       
433       *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
434       *parsed_lens = silc_realloc(*parsed_lens, 
435                                   sizeof(**parsed_lens) * (argc + 1));
436       (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
437       memcpy((*parsed)[argc], cp, len);
438       (*parsed_lens)[argc] = len;
439       argc++;
440
441       cp += len;
442       if (strlen(cp) == 0)
443         break;
444       else
445         cp++;
446     }
447   }
448
449   /* Save argument types. Protocol defines all argument types but
450      this implementation makes sure that they are always in correct
451      order hence this simple code. */
452   *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
453   for (i = 0; i < argc; i++)
454     (*parsed_types)[i] = i;
455
456   *parsed_num = argc;
457 }
458
459 /* Formats arguments to a string and returns it after allocating memory
460    for it. It must be remembered to free it later. */
461
462 char *silc_format(char *fmt, ...)
463 {
464   va_list args;
465   static char buf[8192];
466
467   memset(buf, 0, sizeof(buf));
468   va_start(args, fmt);
469   vsnprintf(buf, sizeof(buf) - 1, fmt, args);
470   va_end(args);
471
472   return strdup(buf);
473 }
474
475 /* Renders ID to suitable to print for example to log file. */
476
477 static char rid[256];
478
479 char *silc_id_render(void *id, uint16 type)
480 {
481   char tmp[100];
482   unsigned char tmps[2];
483
484   memset(rid, 0, sizeof(rid));
485   switch(type) {
486   case SILC_ID_SERVER:
487     {
488       SilcServerID *server_id = (SilcServerID *)id;
489       strcat(rid, inet_ntoa(server_id->ip));
490       memset(tmp, 0, sizeof(tmp));
491       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
492       strcat(rid, tmp);
493       SILC_PUT16_MSB(server_id->rnd, tmps);
494       memset(tmp, 0, sizeof(tmp));
495       snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
496       strcat(rid, tmp);
497     }
498     break;
499   case SILC_ID_CLIENT:
500     {
501       SilcClientID *client_id = (SilcClientID *)id;
502       strcat(rid, inet_ntoa(client_id->ip));
503       memset(tmp, 0, sizeof(tmp));
504       snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
505       strcat(rid, tmp);
506       memset(tmp, 0, sizeof(tmp));
507       snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]", 
508                client_id->hash[0], client_id->hash[1],
509                client_id->hash[2], client_id->hash[3]);
510       strcat(rid, tmp);
511     }
512     break;
513   case SILC_ID_CHANNEL:
514     {
515       SilcChannelID *channel_id = (SilcChannelID *)id;
516       strcat(rid, inet_ntoa(channel_id->ip));
517       memset(tmp, 0, sizeof(tmp));
518       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
519       strcat(rid, tmp);
520       SILC_PUT16_MSB(channel_id->rnd, tmps);
521       memset(tmp, 0, sizeof(tmp));
522       snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
523       strcat(rid, tmp);
524     }
525     break;
526   }
527
528   return rid;
529 }
530
531 /* Compares two strings. Strings may include wildcards * and ?.
532    Returns TRUE if strings match. */
533
534 int silc_string_compare(char *string1, char *string2)
535 {
536   int i;
537   int slen1 = strlen(string1);
538   int slen2 = strlen(string2);
539   char *tmpstr1, *tmpstr2;
540
541   if (!string1 || !string2)
542     return FALSE;
543
544   /* See if they are same already */
545   if (!strncmp(string1, string2, strlen(string2)))
546     return TRUE;
547
548   if (slen2 < slen1)
549     if (!strchr(string1, '*'))
550       return FALSE;
551   
552   /* Take copies of the original strings as we will change them */
553   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
554   memcpy(tmpstr1, string1, slen1);
555   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
556   memcpy(tmpstr2, string2, slen2);
557   
558   for (i = 0; i < slen1; i++) {
559     
560     /* * wildcard. Only one * wildcard is possible. */
561     if (tmpstr1[i] == '*')
562       if (!strncmp(tmpstr1, tmpstr2, i)) {
563         memset(tmpstr2, 0, slen2);
564         strncpy(tmpstr2, tmpstr1, i);
565         break;
566       }
567     
568     /* ? wildcard */
569     if (tmpstr1[i] == '?') {
570       if (!strncmp(tmpstr1, tmpstr2, i)) {
571         if (!(slen1 < i + 1))
572           if (tmpstr1[i + 1] != '?' &&
573               tmpstr1[i + 1] != tmpstr2[i + 1])
574             continue;
575         
576         if (!(slen1 < slen2))
577           tmpstr2[i] = '?';
578       }
579     }
580   }
581   
582   /* if using *, remove it */
583   if (strchr(tmpstr1, '*'))
584     *strchr(tmpstr1, '*') = 0;
585   
586   if (!strcmp(tmpstr1, tmpstr2)) {
587     memset(tmpstr1, 0, slen1);
588     memset(tmpstr2, 0, slen2);
589     silc_free(tmpstr1);
590     silc_free(tmpstr2);
591     return TRUE;
592   }
593   
594   memset(tmpstr1, 0, slen1);
595   memset(tmpstr2, 0, slen2);
596   silc_free(tmpstr1);
597   silc_free(tmpstr2);
598   return FALSE;
599 }
600
601 /* Inspects the `string' for wildcards and returns regex string that can
602    be used by the GNU regex library. A comma (`,') in the `string' means
603    that the string is list. */
604
605 char *silc_string_regexify(const char *string)
606 {
607   int i, len, count;
608   char *regex;
609
610   len = strlen(string);
611   count = 4;
612   for (i = 0; i < len; i++)
613     if (string[i] == '*' || string[i] == '?')
614       count++;
615
616   regex = silc_calloc(len + count, sizeof(*regex));
617
618   count = 0;
619   regex[count] = '(';
620   count++;
621
622   for (i = 0; i < len; i++) {
623     if (string[i] == '*' || string[i] == '?') {
624       regex[count] = '.';
625       count++;
626     } else if (string[i] == ',') {
627       regex[count] = '|';
628       count++;
629       continue;
630     }
631
632     regex[count] = string[i];
633     count++;
634   }
635
636   regex[count - 1] = ')';
637   regex[count] = '$';
638
639   return regex;
640 }
641
642 /* Combines two regex strings into one regex string so that they can be
643    used as one by the GNU regex library. The `string2' is combine into
644    the `string1'. */
645
646 char *silc_string_regex_combine(const char *string1, const char *string2)
647 {
648   char *tmp;
649   int len1, len2;
650
651   len1 = strlen(string1);
652   len2 = strlen(string2);
653
654   tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
655   strncat(tmp, string1, len1 - 2);
656   strncat(tmp, "|", 1);
657   strncat(tmp, string2 + 1, len2 - 1);
658
659   return tmp;
660 }
661
662 /* Matches the two strings and returns TRUE if the strings match. */
663
664 int silc_string_regex_match(const char *regex, const char *string)
665 {
666   regex_t preg;
667   int ret = FALSE;
668   
669   if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0)
670     return FALSE;
671
672   if (regexec(&preg, string, 0, NULL, 0) == 0)
673     ret = TRUE;
674
675   regfree(&preg);
676
677   return ret;
678 }
679
680 /* Do regex match to the two strings `string1' and `string2'. If the
681    `string2' matches the `string1' this returns TRUE. */
682
683 int silc_string_match(const char *string1, const char *string2)
684 {
685   char *s1;
686   int ret = FALSE;
687
688   s1 = silc_string_regexify(string1);
689   ret = silc_string_regex_match(s1, string2);
690   silc_free(s1);
691
692   return ret;
693 }
694
695 /* Returns the username of the user. If the global variable LOGNAME
696    does not exists we will get the name from the password file. */
697
698 char *silc_get_username()
699 {
700   char *logname = NULL;
701   
702   logname = strdup(getenv("LOGNAME"));
703   if (!logname) {
704     logname = getlogin();
705     if (!logname) {
706       struct passwd *pw;
707
708       pw = getpwuid(getuid());
709       if (!pw) {
710         fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
711         return NULL;
712       }
713       
714       logname = strdup(pw->pw_name);
715     }
716   }
717   
718   return logname;
719 }                          
720
721 /* Returns the real name of ther user. */
722
723 char *silc_get_real_name()
724 {
725   char *realname = NULL;
726   struct passwd *pw;
727     
728   pw = getpwuid(getuid());
729   if (!pw) {
730     fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
731     return NULL;
732   }
733
734   if (strchr(pw->pw_gecos, ','))
735     *strchr(pw->pw_gecos, ',') = 0;
736
737   realname = strdup(pw->pw_gecos);
738
739   return realname;
740 }