1 #include <config.h>
2 #include "sharedanced.h"
3 #ifdef HAVE_SETLOCALE
4 # include <locale.h>
5 #endif
6 #include "log.h"
7
8 #ifdef WITH_DMALLOC
9 # include <dmalloc.h>
10 #endif
11
fd_nonblock(const int fd)12 void fd_nonblock(const int fd)
13 {
14 while (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) != 0 &&
15 (errno == EINTR || errno == EAGAIN));
16 }
17
safe_write(const int fd,const void * buf_,size_t count)18 int safe_write(const int fd, const void *buf_, size_t count)
19 {
20 ssize_t written;
21 register const char *buf = buf_;
22
23 while (count > (size_t) 0U) {
24 for (;;) {
25 if ((written = write(fd, buf, count)) <= (ssize_t) 0) {
26 if (errno == EAGAIN) {
27 sleep(1);
28 } else if (errno != EINTR) {
29 return -1;
30 }
31 continue;
32 }
33 break;
34 }
35 buf += written;
36 count -= written;
37 }
38 return 0;
39 }
40
client_disconnect(Client * const client)41 static void client_disconnect(Client * const client)
42 {
43 if (client->client_fd != -1) {
44 logfile(LOG_DEBUG, _("client_disconnect: closing fd #%d"),
45 client->client_fd);
46 (void) close(client->client_fd);
47 client->client_fd = -1;
48 }
49 if (client->read_mapped_zone != NULL) {
50 (void) munmap(client->read_mapped_zone,
51 client->read_mapped_zone_length);
52 client->read_mapped_zone = NULL;
53 client->read_mapped_zone_length = (size_t) 0U;
54 }
55 if (client->read_fd != -1) {
56 (void) close(client->read_fd);
57 client->read_fd = -1;
58 }
59 if (client->write_fd != -1) {
60 (void) close(client->write_fd);
61 client->write_fd = -1;
62 }
63 if (client->returncode_bufev != NULL) {
64 bufferevent_free(client->returncode_bufev);
65 client->returncode_bufev = NULL;
66 }
67 free(client->read_buf);
68 client->read_buf = NULL;
69 free(client);
70 }
71
returncode_bufferev_read_cb(struct bufferevent * bufferev,void * client_)72 static void returncode_bufferev_read_cb(struct bufferevent *bufferev,
73 void *client_)
74 {
75 (void) bufferev;
76 (void) client_;
77 logfile(LOG_DEBUG, _("returncode_bufferev_read_cb"));
78 }
79
returncode_bufferev_write_cb(struct bufferevent * bufferev,void * client_)80 static void returncode_bufferev_write_cb(struct bufferevent *bufferev,
81 void *client_)
82 {
83 Client * const client = client_;
84
85 (void) bufferev;
86 logfile(LOG_DEBUG, _("Return code successfully written for fd #%d"),
87 client->client_fd);
88 client_disconnect(client);
89 }
90
returncode_bufferev_error_cb(struct bufferevent * const bufferev,short what,void * client_)91 static void returncode_bufferev_error_cb(struct bufferevent * const bufferev,
92 short what, void *client_)
93 {
94 Client * const client = client_;
95
96 (void) bufferev;
97 logfile(LOG_DEBUG, _("Error %d when sending return code to fd #%d"),
98 (int) what, client->client_fd);
99 client_disconnect(client);
100 }
101
validate_key(const unsigned char * buf,size_t size)102 static int validate_key(const unsigned char *buf, size_t size)
103 {
104 if (size <= (size_t) 0U) {
105 return -2;
106 }
107 do {
108 size--;
109 if (buf[size] < 32U || buf[size] > 126U ||
110 buf[size] == '.' || buf[size] == '/') {
111 return -1;
112 }
113 } while (size > (size_t) 0U);
114
115 return 0;
116 }
117
client_process_store(Client * const client)118 static int client_process_store(Client * const client)
119 {
120 char *store_file;
121 char *store_file_tmp;
122 char *store_file_pnt;
123 char *store_file_tmp_pnt;
124 size_t sizeof_store_file;
125 size_t sizeof_store_file_tmp;
126
127 logfile(LOG_DEBUG, _("client_process_store, fd #%d"), client->client_fd);
128 if (client->offset_read_buf < (size_t) 10U) {
129 return -1;
130 }
131 sizeof_store_file = (sizeof "/") - (size_t) 1U +
132 client->key_len + (size_t) 1U;
133 if ((store_file = ALLOCA(sizeof_store_file)) == NULL) {
134 logfile(LOG_ERR, _("Out of stack for ALLOCA"));
135 return -1;
136 }
137 store_file_pnt = store_file;
138 *store_file_pnt++ = '/';
139 if (validate_key(client->read_buf + (size_t) 9U, client->key_len) != 0) {
140 ALLOCA_FREE(store_file);
141 logfile(LOG_WARNING, _("Invalid key name"));
142 return -1;
143 }
144 memcpy(store_file_pnt, client->read_buf + (size_t) 9U, client->key_len);
145 store_file_pnt += client->key_len;
146 *store_file_pnt = 0;
147
148 sizeof_store_file_tmp = (sizeof "/") - (size_t) 1U +
149 sizeof STOREFILE_TMP_PREFIX - (size_t) 1U +
150 client->key_len + (size_t) 1U;
151 if ((store_file_tmp = ALLOCA(sizeof_store_file_tmp)) == NULL) {
152 logfile(LOG_ERR, _("Out of stack for ALLOCA"));
153 ALLOCA_FREE(store_file);
154 return -1;
155 }
156 store_file_tmp_pnt = store_file_tmp;
157 *store_file_tmp_pnt++ = '/';
158 memcpy(store_file_tmp_pnt, STOREFILE_TMP_PREFIX,
159 sizeof STOREFILE_TMP_PREFIX - (size_t) 1U);
160 store_file_tmp_pnt += sizeof STOREFILE_TMP_PREFIX - (size_t) 1U;
161 memcpy(store_file_tmp_pnt,
162 client->read_buf + (size_t) 9U, client->key_len);
163 store_file_tmp_pnt += client->key_len;
164 *store_file_tmp_pnt = 0;
165
166 logfile(LOG_DEBUG, _("Creating [%s]"), store_file_tmp);
167 if ((client->write_fd =
168 open(store_file_tmp, O_CREAT | O_NOFOLLOW | O_WRONLY | O_TRUNC,
169 (mode_t) 0600)) == -1) {
170 logfile(LOG_WARNING, _("Unable to create [%s]: [%s]"), store_file,
171 strerror(errno));
172 ALLOCA_FREE(store_file);
173 ALLOCA_FREE(store_file_tmp);
174 return -1;
175 }
176 logfile(LOG_DEBUG, _("[%s] = fd #%d"), store_file, client->write_fd);
177 if (safe_write(client->write_fd,
178 client->read_buf + (size_t) 9U + client->key_len,
179 client->data_len) < 0) {
180 logfile(LOG_WARNING, _("Write error: [%s]"), strerror(errno));
181 }
182 (void) close(client->write_fd);
183 client->write_fd = -1;
184 logfile(LOG_DEBUG,
185 _("Renaming [%s] to [%s]"), store_file_tmp, store_file);
186 if (rename(store_file_tmp, store_file) != 0) {
187 logfile(LOG_WARNING, _("Unable to rename [%s] to [%s]: [%s]"),
188 store_file_tmp, store_file, strerror(errno));
189 (void) unlink(store_file_tmp);
190 ALLOCA_FREE(store_file);
191 ALLOCA_FREE(store_file_tmp);
192 return -1;
193 }
194 ALLOCA_FREE(store_file);
195 ALLOCA_FREE(store_file_tmp);
196 if ((client->returncode_bufev =
197 bufferevent_new(client->client_fd,
198 returncode_bufferev_read_cb,
199 returncode_bufferev_write_cb,
200 returncode_bufferev_error_cb,
201 client)) == NULL) {
202 logfile(LOG_WARNING, _("Unable to create a bufferevent for fd #%d"),
203 client->client_fd);
204 }
205 (void) bufferevent_write(client->returncode_bufev, (void *) RETURNCODE_OK,
206 sizeof RETURNCODE_OK - (size_t) 1U);
207
208 return 0;
209 }
210
client_process_fetch(Client * const client)211 static int client_process_fetch(Client * const client)
212 {
213 char *store_file;
214 char *store_file_pnt;
215 size_t sizeof_store_file;
216 struct stat st;
217
218 logfile(LOG_DEBUG, _("client_process_fetch, fd #%d"), client->client_fd);
219 if (client->offset_read_buf < (size_t) 6U) {
220 return -1;
221 }
222 sizeof_store_file = (sizeof "/") - (size_t) 1U +
223 client->key_len + (size_t) 1U;
224 if ((store_file = ALLOCA(sizeof_store_file)) == NULL) {
225 logfile(LOG_WARNING, _("Out of stack for ALLOCA"));
226 return -1;
227 }
228 store_file_pnt = store_file;
229 *store_file_pnt++ = '/';
230 if (validate_key(client->read_buf + (size_t) 5U, client->key_len) != 0) {
231 ALLOCA_FREE(store_file);
232 logfile(LOG_WARNING, _("Invalid key name"));
233 return -1;
234 }
235 memcpy(store_file_pnt, client->read_buf + (size_t) 5U, client->key_len);
236 store_file_pnt += client->key_len;
237 *store_file_pnt = 0;
238 logfile(LOG_DEBUG, _("Reading [%s]"), store_file);
239 if ((client->read_fd = open(store_file, O_RDONLY)) == -1) {
240 logfile(LOG_DEBUG, _("Unable to fetch [%s]: [%s]"), store_file,
241 strerror(errno));
242 ALLOCA_FREE(store_file);
243 return -1;
244 }
245 logfile(LOG_DEBUG, _("[%s] = fd #%d"), store_file, client->read_fd);
246 ALLOCA_FREE(store_file);
247 if (fstat(client->read_fd, &st) != 0 || st.st_size <= (off_t) 0) {
248 logfile(LOG_DEBUG, _("Unable to stat a previous key (%s) : [%s]"),
249 store_file, strerror(errno));
250 (void) close(client->read_fd);
251 client->read_fd = -1;
252 ALLOCA_FREE(store_file);
253 return -1;
254 }
255 if ((client->read_mapped_zone = mmap(NULL, st.st_size, PROT_READ,
256 MAP_SHARED, client->read_fd,
257 (off_t) 0)) == NULL) {
258 logfile(LOG_WARNING, _("Unable to map in memory: [%s]"),
259 strerror(errno));
260 (void) close(client->read_fd);
261 client->read_fd = -1;
262 ALLOCA_FREE(store_file);
263 return -1;
264 }
265 client->read_mapped_zone_length = st.st_size;
266 if ((client->returncode_bufev =
267 bufferevent_new(client->client_fd,
268 returncode_bufferev_read_cb,
269 returncode_bufferev_write_cb,
270 returncode_bufferev_error_cb,
271 client)) == NULL) {
272 logfile(LOG_WARNING, _("Unable to create a bufferevent for fd #%d"),
273 client->client_fd);
274 }
275 (void) bufferevent_write(client->returncode_bufev,
276 client->read_mapped_zone,
277 client->read_mapped_zone_length);
278
279 return 0;
280 }
281
client_process_delete(Client * const client)282 static int client_process_delete(Client * const client)
283 {
284 char *store_file;
285 char *store_file_pnt;
286 size_t sizeof_store_file;
287
288 logfile(LOG_DEBUG, _("client_process_delete, fd #%d"), client->client_fd);
289 if (client->offset_read_buf < (size_t) 6U) {
290 return -1;
291 }
292 sizeof_store_file = (sizeof "/") - (size_t) 1U +
293 client->key_len + (size_t) 1U;
294 if ((store_file = ALLOCA(sizeof_store_file)) == NULL) {
295 logfile(LOG_WARNING, _("Out of stack for ALLOCA"));
296 return -1;
297 }
298 store_file_pnt = store_file;
299 *store_file_pnt++ = '/';
300 if (validate_key(client->read_buf + (size_t) 5U, client->key_len) != 0) {
301 ALLOCA_FREE(store_file);
302 logfile(LOG_WARNING, _("Invalid key name"));
303 return -1;
304 }
305 memcpy(store_file_pnt, client->read_buf + (size_t) 5U, client->key_len);
306 store_file_pnt += client->key_len;
307 *store_file_pnt = 0;
308 logfile(LOG_DEBUG, _("Deleting [%s]"), store_file);
309 if (unlink(store_file) != 0) {
310 logfile(LOG_INFO, _("Unable to delete [%s]: [%s]"), store_file,
311 strerror(errno));
312 ALLOCA_FREE(store_file);
313 return -1;
314 }
315 if ((client->returncode_bufev =
316 bufferevent_new(client->client_fd,
317 returncode_bufferev_read_cb,
318 returncode_bufferev_write_cb,
319 returncode_bufferev_error_cb,
320 client)) == NULL) {
321 logfile(LOG_WARNING, _("Unable to create a bufferevent for fd #%d"),
322 client->client_fd);
323 }
324 (void) bufferevent_write(client->returncode_bufev, (void *) RETURNCODE_OK,
325 sizeof RETURNCODE_OK - (size_t) 1U);
326
327 return 0;
328 }
329
client_read(const int client_fd,short event,void * client_)330 static void client_read(const int client_fd, short event, void *client_)
331 {
332 Client * const client = client_;
333 size_t needed_size;
334 ssize_t readen;
335
336 if (event == EV_TIMEOUT) {
337 logfile(LOG_DEBUG, _("Timeout on descriptor #%d"), client->client_fd);
338 client_disconnect(client);
339 return;
340 }
341 needed_size = client->offset_read_buf + read_chunk_size;
342 if (client->sizeof_read_buf < needed_size) {
343 unsigned char *tmp_buf;
344
345 if ((tmp_buf = realloc(client->read_buf,
346 needed_size)) == NULL) {
347 logfile(LOG_ERR, _("Out of memory for client read buffers"));
348 client_disconnect(client);
349 return;
350 }
351 client->read_buf = tmp_buf;
352 client->sizeof_read_buf = needed_size;
353 }
354 readen = read
355 (client->client_fd,
356 client->read_buf + client->offset_read_buf,
357 client->sizeof_read_buf - client->offset_read_buf);
358 if (readen <= (ssize_t) 0) {
359 if (errno == EINTR || errno == EAGAIN) {
360 logfile(LOG_DEBUG, _("Interrupted read for fd #%d: [%s]"),
361 client_fd, strerror(errno));
362 event_add(&client->ev_client_read, &timeout);
363 return;
364 }
365 if (readen == (ssize_t) 0) {
366 logfile(LOG_DEBUG, _("Descriptor #%d has disconnected"),
367 client->client_fd);
368 } else {
369 logfile(LOG_DEBUG,
370 _("Descriptor #%d has disconnected with error [%s]"),
371 strerror(errno));
372 }
373 client_disconnect(client);
374 return;
375 }
376 client->offset_read_buf += readen;
377 logfile(LOG_DEBUG, _("Activity on client #%d (%d) offset=%lu"),
378 client->client_fd, event,
379 (unsigned int) client->offset_read_buf);
380 if (client->client_command == CC_UNDEF) {
381 if (client->read_buf[0] == CC_FETCH &&
382 client->offset_read_buf > 5) {
383 client->key_len =
384 client->read_buf[1] << 24 | client->read_buf[2] << 16 |
385 client->read_buf[3] << 8 | client->read_buf[4];
386 client->total_len = (size_t) 1U + (size_t) 4U + client->key_len;
387 client->client_command = CC_FETCH;
388 } else if (client->read_buf[0] == CC_DELETE &&
389 client->offset_read_buf > 5) {
390 client->key_len =
391 client->read_buf[1] << 24 | client->read_buf[2] << 16 |
392 client->read_buf[3] << 8 | client->read_buf[4];
393 client->total_len = (size_t) 1U + (size_t) 4U + client->key_len;
394 client->client_command = CC_DELETE;
395 } else if (client->read_buf[0] == CC_STORE &&
396 client->offset_read_buf > 9) {
397 client->key_len =
398 client->read_buf[1] << 24 | client->read_buf[2] << 16 |
399 client->read_buf[3] << 8 | client->read_buf[4];
400 client->data_len =
401 client->read_buf[5] << 24 | client->read_buf[6] << 16 |
402 client->read_buf[7] << 8 | client->read_buf[8];
403 client->total_len = (size_t) 1U + (size_t) 4U + (size_t) 4U +
404 client->key_len + client->data_len;
405 client->client_command = CC_STORE;
406 } else if (client->offset_read_buf > 0 &&
407 client->read_buf[0] != CC_STORE &&
408 client->read_buf[0] != CC_FETCH) {
409 logfile(LOG_WARNING, _("Unknown command [%d], good bye."),
410 (int) client->read_buf[0]);
411 client_disconnect(client);
412 return;
413 }
414 }
415 if (client->total_len > (size_t) 0U &&
416 client->offset_read_buf == client->total_len) {
417 if (client->client_command == CC_STORE) {
418 if (client_process_store(client) < 0) {
419 client_disconnect(client);
420 }
421 return;
422 } else if (client->client_command == CC_DELETE) {
423 if (client_process_delete(client) < 0) {
424 client_disconnect(client);
425 }
426 return;
427 } else if (client->client_command == CC_FETCH) {
428 if (client_process_fetch(client) < 0) {
429 client_disconnect(client);
430 }
431 return;
432 } else {
433 logfile(LOG_ERR, _("Unknown but ok command?"));
434 }
435 client_disconnect(client);
436 return;
437 }
438 if (client->total_len > (size_t) 0U &&
439 client->offset_read_buf > client->total_len) {
440 logfile(LOG_WARNING,
441 _("Request too long total len = %lu, now = %lu. Good bye."),
442 (unsigned long) client->total_len,
443 (unsigned long) client->offset_read_buf);
444 client_disconnect(client);
445 return;
446 }
447 if (client->offset_read_buf >= max_read_size) {
448 logfile(LOG_WARNING,
449 _("Request too long max = %lu, now = %lu. Good bye."),
450 (unsigned long) max_read_size,
451 (unsigned long) client->offset_read_buf);
452 client_disconnect(client);
453 return;
454 }
455 event_add(&client->ev_client_read, &timeout);
456 }
457
new_client(const int listen_fd,short event,void * ev)458 void new_client(const int listen_fd, short event, void *ev)
459 {
460 Client *client;
461 struct sockaddr_storage client_sa;
462 socklen_t client_sa_len = sizeof client_sa;
463 int client_fd;
464
465 (void) ev;
466 if ((event & EV_READ) == 0) {
467 logfile(LOG_DEBUG, _("Wrong event %d received on fd #%d"),
468 (int) event, listen_fd);
469 return;
470 }
471 memset(&client_sa, 0, sizeof client_sa);
472 if ((client_fd = accept(listen_fd, (struct sockaddr *) &client_sa,
473 &client_sa_len)) < 0) {
474 logfile(LOG_DEBUG, _("accept(): [%s]"), strerror(errno));
475 return;
476 }
477 if (client_sa_len <= (socklen_t) 0U) {
478 (void) close(client_fd);
479 return;
480 }
481 fd_nonblock(client_fd);
482 if ((client = malloc(sizeof *client)) == NULL) {
483 (void) close(client_fd);
484 logfile(LOG_ERR, _("Out of memory to accept a new client"));
485 return;
486 }
487 client->client_fd = client_fd;
488 client->read_buf = NULL;
489 client->sizeof_read_buf = (size_t) 0U;
490 client->offset_read_buf = (size_t) 0U;
491 client->client_command = CC_UNDEF;
492 client->key_len = (size_t) 0U;
493 client->data_len = (size_t) 0U;
494 client->total_len = (size_t) 0U;
495 client->write_fd = -1;
496 client->read_fd = -1;
497 client->read_mapped_zone = NULL;
498 client->read_mapped_zone_length = (size_t) 0U;
499 client->returncode_bufev = NULL;
500 event_set(&client->ev_client_read, client_fd, EV_READ,
501 client_read, client);
502 event_add(&client->ev_client_read, &timeout);
503 logfile(LOG_DEBUG, _("New client on fd #%d"), client_fd);
504 }
505