new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / analysisd / cdb / cdb.c
1 /* Public domain */
2 /* Adapted from DJB's original cdb-0.75 package */
3
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <sys/mman.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <errno.h>
10 #include "cdb.h"
11
12 #ifndef EPROTO
13 #define EPROTO -15  /* cdb 0.75's default for PROTOless systems */
14 #endif
15
16
17 void cdb_free(struct cdb *c)
18 {
19     if (c->map) {
20         munmap(c->map, c->size);
21         c->map = 0;
22     }
23 }
24
25 void cdb_findstart(struct cdb *c)
26 {
27     c->loop = 0;
28 }
29
30 void cdb_init(struct cdb *c, int fd)
31 {
32     struct stat st;
33     char *x;
34
35     cdb_free(c);
36     cdb_findstart(c);
37     c->fd = fd;
38
39     if (fstat(fd, &st) == 0)
40         if ((size_t) st.st_size <= 0xffffffff) {
41             x = (char *) mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
42             if (x + 1) {
43                 c->size = st.st_size;
44                 c->map = x;
45             }
46         }
47 }
48
49 int cdb_read(struct cdb *c, char *buf, unsigned int len, uint32 pos)
50 {
51     if (c->map) {
52         if ((pos > c->size) || (c->size - pos < len)) {
53             goto FORMAT;
54         }
55         memcpy(buf, c->map + pos, len);
56     } else {
57         if (lseek(c->fd, pos, SEEK_SET) == -1) {
58             return -1;
59         }
60         /* if (seek_set(c->fd,pos) == -1) return -1; */
61         while (len > 0) {
62             int r;
63             do {
64                 r = read(c->fd, buf, len);
65             } while ((r == -1) && (errno == EINTR));
66             if (r == -1) {
67                 return -1;
68             }
69             if (r == 0) {
70                 goto FORMAT;
71             }
72             buf += r;
73             len -= r;
74         }
75     }
76     return 0;
77
78 FORMAT:
79     errno = EPROTO;
80     return -1;
81 }
82
83 static int match(struct cdb *c, char *key, unsigned int len, uint32 pos)
84 {
85     char buf[32];
86     unsigned int n;
87
88     while (len > 0) {
89         n = sizeof buf;
90         if (n > len) {
91             n = len;
92         }
93         if (cdb_read(c, buf, n, pos) == -1) {
94             return -1;
95         }
96         if (memcmp(buf, key, n)) {
97             return 0;
98         }
99         pos += n;
100         key += n;
101         len -= n;
102     }
103     return 1;
104 }
105
106 int cdb_findnext(struct cdb *c, char *key, unsigned int len)
107 {
108     char buf[8];
109     uint32 pos;
110     uint32 u;
111
112     if (!c->loop) {
113         u = cdb_hash(key, len);
114         if (cdb_read(c, buf, 8, (u << 3) & 2047) == -1) {
115             return -1;
116         }
117         uint32_unpack(buf + 4, &c->hslots);
118         if (!c->hslots) {
119             return 0;
120         }
121         uint32_unpack(buf, &c->hpos);
122         c->khash = u;
123         u >>= 8;
124         u %= c->hslots;
125         u <<= 3;
126         c->kpos = c->hpos + u;
127     }
128
129     while (c->loop < c->hslots) {
130         if (cdb_read(c, buf, 8, c->kpos) == -1) {
131             return -1;
132         }
133         uint32_unpack(buf + 4, &pos);
134         if (!pos) {
135             return 0;
136         }
137         c->loop += 1;
138         c->kpos += 8;
139         if (c->kpos == c->hpos + (c->hslots << 3)) {
140             c->kpos = c->hpos;
141         }
142         uint32_unpack(buf, &u);
143         if (u == c->khash) {
144             if (cdb_read(c, buf, 8, pos) == -1) {
145                 return -1;
146             }
147             uint32_unpack(buf, &u);
148             if (u == len)
149                 switch (match(c, key, len, pos + 8)) {
150                     case -1:
151                         return -1;
152                     case 1:
153                         uint32_unpack(buf + 4, &c->dlen);
154                         c->dpos = pos + 8 + len;
155                         return 1;
156                 }
157         }
158     }
159
160     return 0;
161 }
162
163 int cdb_find(struct cdb *c, char *key, unsigned int len)
164 {
165     cdb_findstart(c);
166     return cdb_findnext(c, key, len);
167 }