3a0b77ece7535a59d59850c59d5b3ae3bee1644d
[silc.git] / lib / silccore / 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 /*
25  * $Id$
26  * $Log$
27  * Revision 1.4  2000/07/19 07:04:04  priikone
28  *      Minor bug fix in silc_encode_pem
29  *
30  * Revision 1.3  2000/07/10 05:34:40  priikone
31  *      Added PEM encoding/decoding functions.
32  *
33  * Revision 1.2  2000/07/05 06:06:12  priikone
34  *      Added file saving with specific mode.
35  *
36  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
37  *      Imported from internal CVS/Added Log headers.
38  *
39  *
40  */
41
42 #include "silcincludes.h"
43
44 /* Reads a file to a buffer. The allocated buffer is returned. Length of
45    the file read is returned to the return_len argument. */
46
47 char *silc_file_read(const char *filename, int *return_len)
48 {
49   int fd;
50   char *buffer;
51   int filelen;
52
53   fd = open(filename, O_RDONLY);
54   if (fd < 0) {
55     SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
56     return NULL;
57   }
58
59   filelen = lseek(fd, (off_t)0L, SEEK_END);
60   if (filelen < 0)
61     return NULL;
62   if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
63     return NULL;
64
65   if (filelen < 0) {
66     SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
67     return NULL;
68   }
69   
70   buffer = silc_calloc(filelen + 1, sizeof(char));
71   
72   if ((read(fd, buffer, filelen)) == -1) {
73     memset(buffer, 0, sizeof(buffer));
74     close(fd);
75     SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
76                     strerror(errno)));
77     return NULL;
78   }
79
80   close(fd);
81   buffer[filelen] = EOF;
82   
83   *return_len = filelen;
84   return buffer;
85 }
86
87 /* Writes a buffer to the file. */
88
89 int silc_file_write(const char *filename, const char *buffer, int len)
90 {
91   int fd;
92         
93   if ((fd = creat(filename, 0644)) == -1) {
94     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
95     return -1;
96   }
97   
98   if ((write(fd, buffer, len)) == -1) {
99     SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
100     return -1;
101   }
102
103   close(fd);
104   
105   return 0;
106 }
107
108 /* Writes a buffer to the file.  If the file is created specific mode is
109    set to the file. */
110
111 int silc_file_write_mode(const char *filename, const char *buffer, 
112                          int len, int mode)
113 {
114   int fd;
115         
116   if ((fd = creat(filename, mode)) == -1) {
117     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
118     return -1;
119   }
120   
121   if ((write(fd, buffer, len)) == -1) {
122     SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
123     return -1;
124   }
125
126   close(fd);
127   
128   return 0;
129 }
130
131 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
132    This doesn't remove the newline sign from the destination buffer. The
133    argument begin is returned and should be passed again for the function. */
134
135 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
136 {
137   static int start = 0;
138   int i;
139   
140   memset(dest, 0, destlen);
141   
142   if (begin != start)
143     start = 0;
144   
145   i = 0;
146   for ( ; start <= srclen; i++, start++) {
147     if (i > destlen)
148       return -1;
149     
150     dest[i] = src[start];
151     
152     if (dest[i] == EOF) 
153       return EOF;
154     
155     if (dest[i] == '\n') 
156       break;
157   }
158   start++;
159   
160   return start;
161 }
162
163 /* Checks line for illegal characters. Return -1 when illegal character
164    were found. This is used to check for bad lines when reading data from
165    for example a configuration file. */
166
167 int silc_check_line(char *buf) 
168 {
169   /* Illegal characters in line */
170   if (strchr(buf, '#')) return -1;
171   if (strchr(buf, '\'')) return -1;
172   if (strchr(buf, '\\')) return -1;
173   if (strchr(buf, '\r')) return -1;
174   if (strchr(buf, '\a')) return -1;
175   if (strchr(buf, '\b')) return -1;
176   if (strchr(buf, '\f')) return -1;
177   
178   /* Empty line */
179   if (buf[0] == '\n')
180     return -1;
181   
182   return 0;
183 }
184
185 /* Returns current time as string. */
186
187 char *silc_get_time()
188 {
189   time_t curtime;
190   char *return_time;
191
192   curtime = time(NULL);
193   return_time = ctime(&curtime);
194   return_time[strlen(return_time) - 1] = '\0';
195
196   return return_time;
197 }
198
199 /* Converts string to capital characters */
200
201 char *silc_to_upper(char *string)
202 {
203   int i;
204   char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
205
206   for (i = 0; i < strlen(string); i++)
207     ret[i] = toupper(string[i]);
208
209   return ret;
210 }
211
212 /* Compares two strings. Strings may include wildcards * and ?.
213    Returns TRUE if strings match. */
214
215 int silc_string_compare(char *string1, char *string2)
216 {
217   int i;
218   int slen1 = strlen(string1);
219   int slen2 = strlen(string2);
220   char *tmpstr1, *tmpstr2;
221
222   if (!string1 || !string2)
223     return FALSE;
224
225   /* See if they are same already */
226   if (!strncmp(string1, string2, strlen(string2)))
227     return TRUE;
228
229   if (slen2 < slen1)
230     if (!strchr(string1, '*'))
231       return FALSE;
232   
233   /* Take copies of the original strings as we will change them */
234   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
235   memcpy(tmpstr1, string1, slen1);
236   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
237   memcpy(tmpstr2, string2, slen2);
238   
239   for (i = 0; i < slen2; i++) {
240     
241     /* * wildcard. Only one * wildcard is possible. */
242     if (tmpstr1[i] == '*')
243       if (!strncmp(tmpstr1, tmpstr2, i)) {
244         memset(tmpstr2, 0, slen2);
245         strncpy(tmpstr2, tmpstr1, i);
246         break;
247       }
248     
249     /* ? wildcard */
250     if (tmpstr1[i] == '?') {
251       if (!strncmp(tmpstr1, tmpstr2, i)) {
252         if (!(slen1 < i + 1))
253           if (tmpstr1[i + 1] != '?' &&
254               tmpstr1[i + 1] != tmpstr2[i + 1])
255             continue;
256         
257         if (!(slen1 < slen2))
258           tmpstr2[i] = '?';
259       }
260 #if 0
261     } else {
262       if (strncmp(tmpstr1, tmpstr2, i))
263         strncpy(tmpstr2, string2, slen2);
264 #endif
265     }
266   }
267   
268   /* if using *, remove it */
269   if (strchr(tmpstr1, '*'))
270     *strchr(tmpstr1, '*') = 0;
271   
272   if (!strcmp(tmpstr1, tmpstr2)) {
273     memset(tmpstr1, 0, slen1);
274     memset(tmpstr2, 0, slen2);
275     silc_free(tmpstr1);
276     silc_free(tmpstr2);
277     return TRUE;
278   }
279   
280   memset(tmpstr1, 0, slen1);
281   memset(tmpstr2, 0, slen2);
282   silc_free(tmpstr1);
283   silc_free(tmpstr2);
284   return FALSE;
285 }
286
287 unsigned char pem_enc[64] =
288 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
289
290 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
291    data string. Note: This is originally public domain code and is 
292    still PD. */
293
294 char *silc_encode_pem(unsigned char *data, unsigned int len)
295 {
296   int i, j;
297   unsigned int bits, c, char_count;
298   char *pem;
299
300   char_count = 0;
301   bits = 0;
302   j = 0;
303
304   pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
305
306   for (i = 0; i < len; i++) {
307     c = data[i];
308     bits += c;
309     char_count++;
310
311     if (char_count == 3) {
312       pem[j++] = pem_enc[bits  >> 18];
313       pem[j++] = pem_enc[(bits >> 12) & 0x3f];
314       pem[j++] = pem_enc[(bits >> 6)  & 0x3f];
315       pem[j++] = pem_enc[bits & 0x3f];
316       bits = 0;
317       char_count = 0;
318     } else {
319       bits <<= 8;
320     }
321   }
322
323   if (char_count != 0) {
324     bits <<= 16 - (8 * char_count);
325     pem[j++] = pem_enc[bits >> 18];
326     pem[j++] = pem_enc[(bits >> 12) & 0x3f];
327
328     if (char_count == 1) {
329       pem[j++] = '=';
330       pem[j] = '=';
331     } else {
332       pem[j++] = pem_enc[(bits >> 6) & 0x3f];
333       pem[j] = '=';
334     }
335   }
336
337   return pem;
338 }
339
340 /* Same as above but puts newline ('\n') every 72 characters. */
341
342 char *silc_encode_pem_file(unsigned char *data, unsigned int data_len)
343 {
344   int i, j;
345   unsigned int len, cols;
346   char *pem, *pem2;
347
348   pem = silc_encode_pem(data, data_len);
349   len = strlen(pem);
350
351   pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
352
353   for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
354     if (cols == 72) {
355       pem2[i] = '\n';
356       cols = 0;
357       len++;
358       continue;
359     }
360
361     pem2[i] = pem[j++];
362   }
363
364   return pem2;
365 }
366
367 /* Decodes PEM into data. Returns the decoded data. Note: This is
368    originally public domain code and is still PD. */
369
370 unsigned char *silc_decode_pem(unsigned char *pem, unsigned int pem_len,
371                                unsigned int *ret_len)
372 {
373   int i, j;
374   unsigned int len, c, char_count, bits;
375   unsigned char *data;
376   static char ialpha[256], decoder[256];
377
378   for (i = 64 - 1; i >= 0; i--) {
379     ialpha[pem_enc[i]] = 1;
380     decoder[pem_enc[i]] = i;
381   }
382
383   char_count = 0;
384   bits = 0;
385   j = 0;
386
387   if (!pem_len)
388     len = strlen(pem);
389   else
390     len = pem_len;
391
392   data = silc_calloc(((len * 6) / 8), sizeof(*data));
393
394   for (i = 0; i < len; i++) {
395     c = pem[i];
396
397     if (c == '=')
398       break;
399
400     if (c > 127 || !ialpha[c])
401       continue;
402
403     bits += decoder[c];
404     char_count++;
405
406     if (char_count == 4) {
407       data[j++] = bits >> 16;
408       data[j++] = (bits >> 8) & 0xff;
409       data[j++] = bits & 0xff;
410       bits = 0;
411       char_count = 0;
412     } else {
413       bits <<= 6;
414     }
415   }
416
417   switch(char_count) {
418   case 1:
419     silc_free(data);
420     return NULL;
421     break;
422   case 2:
423     data[j++] = bits >> 10;
424     break;
425   case 3:
426     data[j++] = bits >> 16;
427     data[j++] = (bits >> 8) & 0xff;
428     break;
429   }
430
431   if (ret_len)
432     *ret_len = j;
433
434   return data;
435 }