new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_crypto / shared / keys.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights reserved.
3  *
4  * This program is a free software; you can redistribute it
5  * and/or modify it under the terms of the GNU General Public
6  * License (version 2) as published by the FSF - Free Software
7  * Foundation.
8  */
9
10 #include "headers/shared.h"
11 #include "headers/sec.h"
12 #include "os_crypto/md5/md5_op.h"
13 #include "os_crypto/blowfish/bf_op.h"
14
15 /* Prototypes */
16 static void __memclear(char *id, char *name, char *ip, char *key, size_t size) __attribute((nonnull));
17 static void __chash(keystore *keys, const char *id, const char *name, char *ip, const char *key) __attribute((nonnull));
18
19 static int pass_empty_keyfile = 0;
20
21 /* Clear keys entries */
22 static void __memclear(char *id, char *name, char *ip, char *key, size_t size)
23 {
24     memset(id, '\0', size);
25     memset(name, '\0', size);
26     memset(key, '\0', size);
27     memset(ip, '\0', size);
28 }
29
30 /* Create the final key */
31 static void __chash(keystore *keys, const char *id, const char *name, char *ip, const char *key)
32 {
33     os_md5 filesum1;
34     os_md5 filesum2;
35
36     char *tmp_str;
37     char _finalstr[KEYSIZE];
38
39     /* Allocate for the whole structure */
40     keys->keyentries = (keyentry **)realloc(keys->keyentries,
41                                             (keys->keysize + 2) * sizeof(keyentry *));
42     if (!keys->keyentries) {
43         ErrorExit(MEM_ERROR, __local_name, errno, strerror(errno));
44     }
45     os_calloc(1, sizeof(keyentry), keys->keyentries[keys->keysize]);
46
47     /* Set configured values for id */
48     os_strdup(id, keys->keyentries[keys->keysize]->id);
49     OSHash_Add(keys->keyhash_id,
50                keys->keyentries[keys->keysize]->id,
51                keys->keyentries[keys->keysize]);
52
53     /* Agent IP */
54     os_calloc(1, sizeof(os_ip), keys->keyentries[keys->keysize]->ip);
55     if (OS_IsValidIP(ip, keys->keyentries[keys->keysize]->ip) == 0) {
56         ErrorExit(INVALID_IP, __local_name, ip);
57     }
58
59     /* We need to remove the "/" from the CIDR */
60     if ((tmp_str = strchr(keys->keyentries[keys->keysize]->ip->ip, '/')) != NULL) {
61         *tmp_str = '\0';
62     }
63     OSHash_Add(keys->keyhash_ip,
64                keys->keyentries[keys->keysize]->ip->ip,
65                keys->keyentries[keys->keysize]);
66
67     /* Agent name */
68     os_strdup(name, keys->keyentries[keys->keysize]->name);
69
70     /* Initialize the variables */
71     keys->keyentries[keys->keysize]->rcvd = 0;
72     keys->keyentries[keys->keysize]->local = 0;
73     keys->keyentries[keys->keysize]->keyid = keys->keysize;
74     keys->keyentries[keys->keysize]->global = 0;
75     keys->keyentries[keys->keysize]->fp = NULL;
76
77     /** Generate final symmetric key **/
78
79     /* MD5 from name, id and key */
80     OS_MD5_Str(name, filesum1);
81     OS_MD5_Str(id,  filesum2);
82
83     /* Generate new filesum1 */
84     snprintf(_finalstr, sizeof(_finalstr) - 1, "%s%s", filesum1, filesum2);
85
86     /* Use just half of the first MD5 (name/id) */
87     OS_MD5_Str(_finalstr, filesum1);
88     filesum1[15] = '\0';
89     filesum1[16] = '\0';
90
91     /* Second md is just the key */
92     OS_MD5_Str(key, filesum2);
93
94     /* Generate final key */
95     snprintf(_finalstr, 49, "%s%s", filesum2, filesum1);
96
97     /* Final key is 48 * 4 = 192bits */
98     os_strdup(_finalstr, keys->keyentries[keys->keysize]->key);
99
100     /* Clean final string from memory */
101     memset_secure(_finalstr, '\0', sizeof(_finalstr));
102
103     /* Ready for next */
104     keys->keysize++;
105
106     return;
107 }
108
109 /* Check if the authentication key file is present */
110 int OS_CheckKeys()
111 {
112     FILE *fp;
113
114     if (File_DateofChange(KEYSFILE_PATH) < 0) {
115         merror(NO_AUTHFILE, __local_name, KEYSFILE_PATH);
116         merror(NO_CLIENT_KEYS, __local_name);
117         return (0);
118     }
119
120     fp = fopen(KEYSFILE_PATH, "r");
121     if (!fp) {
122         /* We can leave from here */
123         merror(FOPEN_ERROR, __local_name, KEYSFILE_PATH, errno, strerror(errno));
124         merror(NO_AUTHFILE, __local_name, KEYSFILE_PATH);
125         merror(NO_CLIENT_KEYS, __local_name);
126         return (0);
127     }
128
129     fclose(fp);
130
131     /* Authentication keys are present */
132     return (1);
133 }
134
135 /* Read the authentication keys */
136 void OS_ReadKeys(keystore *keys)
137 {
138     FILE *fp;
139
140     char buffer[OS_BUFFER_SIZE + 1];
141
142     char name[KEYSIZE + 1];
143     char ip[KEYSIZE + 1];
144     char id[KEYSIZE + 1];
145     char key[KEYSIZE + 1];
146
147     /* Check if the keys file is present and we can read it */
148     if ((keys->file_change = File_DateofChange(KEYS_FILE)) < 0) {
149         merror(NO_AUTHFILE, __local_name, KEYS_FILE);
150         ErrorExit(NO_CLIENT_KEYS, __local_name);
151
152     }
153     fp = fopen(KEYS_FILE, "r");
154     if (!fp) {
155         /* We can leave from here */
156         merror(FOPEN_ERROR, __local_name, KEYS_FILE, errno, strerror(errno));
157         ErrorExit(NO_CLIENT_KEYS, __local_name);
158
159     }
160
161     /* Initialize hashes */
162     keys->keyhash_id = OSHash_Create();
163     keys->keyhash_ip = OSHash_Create();
164     if (!keys->keyhash_id || !keys->keyhash_ip) {
165         ErrorExit(MEM_ERROR, __local_name, errno, strerror(errno));
166     }
167
168     /* Initialize structure */
169     os_calloc(1, sizeof(keyentry*), keys->keyentries);
170     keys->keysize = 0;
171
172     /* Zero the buffers */
173     __memclear(id, name, ip, key, KEYSIZE + 1);
174     memset(buffer, '\0', OS_BUFFER_SIZE + 1);
175
176     /* Read each line. Lines are divided as "id name ip key" */
177     while (fgets(buffer, OS_BUFFER_SIZE, fp) != NULL) {
178         char *tmp_str;
179         char *valid_str;
180
181         if ((buffer[0] == '#') || (buffer[0] == ' ')) {
182             continue;
183         }
184
185         /* Get ID */
186         valid_str = buffer;
187         tmp_str = strchr(buffer, ' ');
188         if (!tmp_str) {
189             merror(INVALID_KEY, __local_name, buffer);
190             continue;
191         }
192
193         *tmp_str = '\0';
194         tmp_str++;
195         strncpy(id, valid_str, KEYSIZE - 1);
196
197         /* Removed entry */
198         if (*tmp_str == '#') {
199             continue;
200         }
201
202         /* Get name */
203         valid_str = tmp_str;
204         tmp_str = strchr(tmp_str, ' ');
205         if (!tmp_str) {
206             merror(INVALID_KEY, __local_name, buffer);
207             continue;
208         }
209
210         *tmp_str = '\0';
211         tmp_str++;
212         strncpy(name, valid_str, KEYSIZE - 1);
213
214         /* Get IP address */
215         valid_str = tmp_str;
216         tmp_str = strchr(tmp_str, ' ');
217         if (!tmp_str) {
218             merror(INVALID_KEY, __local_name, buffer);
219             continue;
220         }
221
222         *tmp_str = '\0';
223         tmp_str++;
224         strncpy(ip, valid_str, KEYSIZE - 1);
225
226         /* Get key */
227         valid_str = tmp_str;
228         tmp_str = strchr(tmp_str, '\n');
229         if (tmp_str) {
230             *tmp_str = '\0';
231         }
232
233         strncpy(key, valid_str, KEYSIZE - 1);
234
235         /* Generate the key hash */
236         __chash(keys, id, name, ip, key);
237
238         /* Clear the memory */
239         __memclear(id, name, ip, key, KEYSIZE + 1);
240
241         /* Check for maximum agent size */
242         if (keys->keysize >= (MAX_AGENTS - 2)) {
243             merror(AG_MAX_ERROR, __local_name, MAX_AGENTS - 2);
244             ErrorExit(CONFIG_ERROR, __local_name, KEYS_FILE);
245         }
246
247         continue;
248     }
249
250     /* Close key file */
251     fclose(fp);
252
253     /* Clear one last time before leaving */
254     __memclear(id, name, ip, key, KEYSIZE + 1);
255
256     /* Check if there are any agents available */
257     if (keys->keysize == 0) {
258         merror(NO_CLIENT_KEYS, __local_name);
259         if (!pass_empty_keyfile) {
260             exit(1);
261         }
262     }
263
264     /* Add additional entry for sender == keysize */
265     os_calloc(1, sizeof(keyentry), keys->keyentries[keys->keysize]);
266
267     return;
268 }
269
270 /* Free the auth keys */
271 void OS_FreeKeys(keystore *keys)
272 {
273     unsigned int i = 0;
274     unsigned int _keysize = 0;
275     OSHash *hashid;
276     OSHash *haship;
277
278     _keysize = keys->keysize;
279     hashid = keys->keyhash_id;
280     haship = keys->keyhash_ip;
281
282     /* Zero the entries */
283     keys->keysize = 0;
284     keys->keyhash_id = NULL;
285     keys->keyhash_ip = NULL;
286
287     /* Sleep to give time to other threads to stop using them */
288     sleep(1);
289
290     /* Free the hashes */
291     OSHash_Free(hashid);
292     OSHash_Free(haship);
293
294     for (i = 0; i <= _keysize; i++) {
295         if (keys->keyentries[i]) {
296             if (keys->keyentries[i]->ip) {
297                 free(keys->keyentries[i]->ip->ip);
298                 free(keys->keyentries[i]->ip);
299             }
300
301             if (keys->keyentries[i]->id) {
302                 free(keys->keyentries[i]->id);
303             }
304
305             if (keys->keyentries[i]->key) {
306                 free(keys->keyentries[i]->key);
307             }
308
309             if (keys->keyentries[i]->name) {
310                 free(keys->keyentries[i]->name);
311             }
312
313             /* Close counter */
314             if (keys->keyentries[i]->fp) {
315                 fclose(keys->keyentries[i]->fp);
316             }
317
318             free(keys->keyentries[i]);
319             keys->keyentries[i] = NULL;
320         }
321     }
322
323     /* Free structure */
324     free(keys->keyentries);
325     keys->keyentries = NULL;
326     keys->keysize = 0;
327 }
328
329 /* Check if key changed */
330 int OS_CheckUpdateKeys(const keystore *keys)
331 {
332     if (keys->file_change !=  File_DateofChange(KEYS_FILE)) {
333         return (1);
334     }
335     return (0);
336 }
337
338 /* Update the keys if changed */
339 int OS_UpdateKeys(keystore *keys)
340 {
341     if (keys->file_change !=  File_DateofChange(KEYS_FILE)) {
342         merror(ENCFILE_CHANGED, __local_name);
343         debug1("%s: DEBUG: Freekeys", __local_name);
344
345         OS_FreeKeys(keys);
346         debug1("%s: DEBUG: OS_ReadKeys", __local_name);
347
348         /* Read keys */
349         verbose(ENC_READ, __local_name);
350
351         OS_ReadKeys(keys);
352         debug1("%s: DEBUG: OS_StartCounter", __local_name);
353
354         OS_StartCounter(keys);
355         debug1("%s: DEBUG: OS_UpdateKeys completed", __local_name);
356
357         return (1);
358     }
359     return (0);
360 }
361
362 /* Check if an IP address is allowed to connect */
363 int OS_IsAllowedIP(keystore *keys, const char *srcip)
364 {
365     keyentry *entry;
366
367     if (srcip == NULL) {
368         return (-1);
369     }
370
371     entry = (keyentry *) OSHash_Get(keys->keyhash_ip, srcip);
372     if (entry) {
373         return ((int)entry->keyid);
374     }
375
376     return (-1);
377 }
378
379 /* Check if the agent name is valid */
380 int OS_IsAllowedName(const keystore *keys, const char *name)
381 {
382     unsigned int i = 0;
383
384     for (i = 0; i < keys->keysize; i++) {
385         if (strcmp(keys->keyentries[i]->name, name) == 0) {
386             return ((int)i);
387         }
388     }
389
390     return (-1);
391 }
392
393 int OS_IsAllowedID(keystore *keys, const char *id)
394 {
395     keyentry *entry;
396
397     if (id == NULL) {
398         return (-1);
399     }
400
401     entry = (keyentry *) OSHash_Get(keys->keyhash_id, id);
402     if (entry) {
403         return ((int)entry->keyid);
404     }
405     return (-1);
406 }
407
408
409 /* Used for dynamic IP addresses */
410 int OS_IsAllowedDynamicID(keystore *keys, const char *id, const char *srcip)
411 {
412     keyentry *entry;
413
414     if (id == NULL) {
415         return (-1);
416     }
417
418     entry = (keyentry *) OSHash_Get(keys->keyhash_id, id);
419     if (entry) {
420         if (OS_IPFound(srcip, entry->ip)) {
421             return ((int)entry->keyid);
422         }
423     }
424
425     return (-1);
426 }
427  /* Configure to pass if keys file is empty */
428  void OS_PassEmptyKeyfile() {
429      pass_empty_keyfile = 1;
430  }