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