Added a libpwmd manual page.
[pwmd.git] / src / pwmd.c
blob087f59e27b322800157761079dbfeba35b4d604d
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2007 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <sys/wait.h>
32 #include <fcntl.h>
33 #include <pwd.h>
34 #include <glib.h>
35 #include <glib/gprintf.h>
36 #include <gcrypt.h>
37 #include <sys/mman.h>
38 #include <termios.h>
39 #include <assert.h>
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
45 #ifdef HAVE_SETRLIMIT
46 #include <sys/time.h>
47 #include <sys/resource.h>
48 #endif
50 #include "xml.h"
51 #include "common.h"
52 #include "commands.h"
53 #include "pwmd_error.h"
54 #include "pwmd.h"
56 void send_to_client(struct client_s *client, const gchar *fmt, ...)
58 va_list ap;
59 gint n = 0;
60 gchar **p;
62 if (!client)
63 return;
65 va_start(ap, fmt);
67 if (client->outbuf)
68 for (p = client->outbuf, n = 0; *p; p++, n++);
70 if ((client->outbuf = g_realloc(client->outbuf, (n + 2) * sizeof(gchar *))) == NULL) {
71 warn("g_realloc()");
72 return;
75 client->outbuf[n++] = g_strdup_vprintf(fmt, ap);
76 client->outbuf[n] = NULL;
77 va_end(ap);
80 void send_error(struct client_s *client, int pwmd_errno)
82 send_to_client(client, "ERR %03i %s\n", pwmd_errno, pwmd_strerror(pwmd_errno));
85 void log_write(const gchar *fmt, ...)
87 gchar *args, *line;
88 va_list ap;
89 struct tm *tm;
90 time_t now;
91 gchar tbuf[21];
92 gint fd;
93 gint tofile = !isatty(STDOUT_FILENO);
95 if (!logfile || !fmt)
96 return;
98 if (tofile) {
99 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
100 warn("logfile");
101 return;
105 va_start(ap, fmt);
106 g_vasprintf(&args, fmt, ap);
107 va_end(ap);
109 if (tofile) {
110 time(&now);
111 tm = localtime(&now);
112 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
113 tbuf[sizeof(tbuf) - 1] = 0;
114 line = g_strdup_printf("%s %i %s\n", tbuf, getpid(), args);
115 write(fd, line, strlen(line));
116 fsync(fd);
117 close(fd);
118 g_free(line);
120 else
121 fprintf(stderr, "%s\n", args);
123 g_free(args);
126 static void cache_adjust_timer()
128 file_cache_t f;
129 void *p;
130 glong len;
132 for (p = shm_data, len = 0; len <= cache_size;) {
133 memcpy(&f, p, sizeof(file_cache_t));
135 if (f.timeout >= 0 && f.when > 0) {
136 f.when--;
138 if (f.when <= 0)
139 memset(&f.key, 0, sizeof(f.key));
141 memcpy(p, &f, sizeof(file_cache_t));
144 p += sizeof(file_cache_t);
145 len += sizeof(file_cache_t);
147 if (len + sizeof(file_cache_t) > cache_size)
148 break;
152 static void catchsig(gint sig)
154 gint status;
156 if (sig != SIGALRM)
157 log_write("caught signal %i (%s)", sig, strsignal(sig));
159 switch (sig) {
160 case SIGALRM:
161 cache_adjust_timer();
162 alarm(1);
163 break;
164 case SIGCHLD:
165 waitpid(-1, &status, 0);
166 break;
167 case SIGHUP:
168 log_write("clearing file cache");
169 memset(shm_data, 0, cache_size);
170 break;
171 default:
172 quit = 1;
173 shutdown(sfd, SHUT_RDWR);
174 close(sfd);
175 break;
179 static void usage(gchar *pn)
181 g_printf(
182 "Usage: %s [-hv] [-f <rcfile>] [-I <filename>]\n"
183 " -f load the specified rcfile (~/.pwmdrc)\n"
184 " -I import an XML file and write the encrypted data to stdout\n"
185 " -v version\n"
186 " -h this help text\n",
187 pn);
188 exit(EXIT_SUCCESS);
191 gchar **split_input_line(gchar *str, gchar *delim, gint n)
193 if (!str || !*str)
194 return NULL;
196 return g_strsplit(str, delim, n);
199 static int gcry_SecureCheck(const void *ptr)
201 return 1;
204 static void setup_gcrypt()
206 gcry_check_version(NULL);
208 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
209 xfree);
211 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
212 NULL) != 0)
213 errx(EXIT_FAILURE, "AES cipher not supported");
215 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
216 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
219 static gint input_parser(gchar *str)
221 gchar *p, *t;
222 gchar **req = NULL;
224 if (str)
225 str = g_strchug(str);
227 if (!*str)
228 return P_OK;
230 while ((p = strsep(&str, "\n")) != NULL) {
231 if (g_ascii_strcasecmp(p, "QUIT") == 0)
232 return P_QUIT;
233 else if (g_ascii_strcasecmp(p, "HELP") == 0)
234 help_command(cl, NULL);
235 else if (g_ascii_strncasecmp(p, "HELP ", 5) == 0) {
236 t = p + 5;
237 t = g_strchug(t);
238 help_command(cl, t);
240 else if (g_ascii_strcasecmp(p, "LIST") == 0 ||
241 g_ascii_strncasecmp(p, "LIST ", 5) == 0) {
242 if (cl->state != STATE_OPEN)
243 send_error(cl, EPWMD_NO_FILE);
244 else
245 list_command(cl, p);
247 else if (g_ascii_strncasecmp(p, "STORE ", 6) == 0) {
248 t = p + 6;
249 t = g_strchug(t);
251 if (cl->state != STATE_OPEN)
252 send_error(cl, EPWMD_NO_FILE);
253 else {
254 if ((req = split_input_line(t, "\t", 0)) != NULL) {
255 if (store_command(cl, req) == TRUE)
256 send_to_client(cl, "OK \n");
258 else
259 send_error(cl, EPWMD_COMMAND_SYNTAX);
262 else if (g_ascii_strncasecmp(p, "DELETE ", 7) == 0) {
263 t = p + 7;
265 if (cl->state != STATE_OPEN)
266 send_error(cl, EPWMD_NO_FILE);
267 else {
268 if ((req = split_input_line(t, "\t", 0)) != NULL) {
269 if (delete_command(cl, req) == TRUE)
270 send_to_client(cl, "OK \n");
272 else
273 send_error(cl, EPWMD_COMMAND_SYNTAX);
276 else if (g_ascii_strncasecmp(p, "GET ", 4) == 0) {
277 t = p + 4;
278 t = g_strchug(t);
280 if (cl->state != STATE_OPEN)
281 send_error(cl, EPWMD_NO_FILE);
282 else {
283 if ((req = split_input_line(t, "\t", 0)) != NULL)
284 get_command(cl, &cl->reader, req, 0);
285 else
286 send_error(cl, EPWMD_COMMAND_SYNTAX);
289 else if (g_ascii_strncasecmp(p, "ATTR ", 5) == 0) {
290 t = p + 5;
291 t = g_strchug(t);
293 if (cl->state != STATE_OPEN)
294 send_error(cl, EPWMD_NO_FILE);
295 else {
296 if ((req = split_input_line(t, " ", 4)) != NULL) {
297 if (attr_command(cl, req) == TRUE)
298 send_to_client(cl, "OK \n");
300 else
301 send_error(cl, EPWMD_COMMAND_SYNTAX);
304 else if (g_ascii_strncasecmp(p, "OPEN ", 5) == 0) {
305 t = p + 5;
306 t = g_strchug(t);
308 if (cl->state == STATE_OPEN)
309 send_error(cl, EPWMD_FILE_OPENED);
310 else {
311 if ((req = split_input_line(t, " ", 2)) != NULL) {
312 if (open_command(cl, req) == TRUE) {
313 send_to_client(cl, "OK \n");
314 cl->state = STATE_OPEN;
318 * The document has been parsed and is stored in cl->doc.
320 if (cl->xml) {
321 gcry_free(cl->xml);
322 cl->xml = NULL;
325 else
326 send_error(cl, EPWMD_COMMAND_SYNTAX);
329 else if (g_ascii_strncasecmp(p, "SAVE", 4) == 0) {
330 t = p + 4;
332 if (*t && *t != ' ')
333 send_error(cl, EPWMD_COMMAND_SYNTAX);
334 else {
335 t = g_strchug(t);
337 if (cl->state != STATE_OPEN)
338 send_error(cl, EPWMD_NO_FILE);
339 else {
340 req = split_input_line(t, " ", 1);
342 if (save_command(cl, cl->filename, (req) ? req[0] : NULL) == TRUE)
343 send_to_client(cl, "OK \n");
347 else if (g_ascii_strncasecmp(p, "CACHE ", 6) == 0) {
348 t = p + 6;
349 t = g_strchug(t);
350 req = split_input_line(t, " ", 0);
352 if (cache_command(cl, req) == TRUE)
353 send_to_client(cl, "OK \n");
355 else if (g_ascii_strncasecmp(p, "DUMP", 4) == 0) {
356 if (cl->state != STATE_OPEN)
357 send_error(cl, EPWMD_NO_FILE);
358 else {
359 if (dump_command(cl) == TRUE)
360 send_to_client(cl, "OK \n");
363 else
364 send_error(cl, EPWMD_COMMAND_SYNTAX);
367 if (req) {
368 g_strfreev(req);
369 req = NULL;
372 return P_OK;
375 static gboolean source_prepare(GSource *src, gint *to)
377 if (cl->gfd.revents & (G_IO_HUP|G_IO_NVAL|G_IO_ERR))
378 return TRUE;
380 return FALSE;
383 static gboolean source_check(GSource *src)
385 if (cl->gfd.revents & (G_IO_IN|G_IO_PRI))
386 return TRUE;
388 if (cl->outbuf && (cl->gfd.revents & (G_IO_OUT)))
389 return TRUE;
391 return FALSE;
394 static gboolean source_dispatch(GSource *src, GSourceFunc cb, gpointer data)
396 return (*cb)(data);
399 static gboolean source_cb(gpointer data)
401 GIOStatus ret;
402 gsize len;
403 gchar *line = NULL;
404 GError *gerror = NULL;
405 gchar **p;
407 if (cl->gfd.revents & (G_IO_HUP|G_IO_NVAL|G_IO_ERR))
408 goto quit;
410 if (cl->outbuf && (cl->gfd.revents & (G_IO_OUT))) {
411 for (p = cl->outbuf; *p; p++) {
412 ret = g_io_channel_write_chars(cl->ioc, *p, -1, &len, &gerror);
414 if (ret == G_IO_STATUS_NORMAL)
415 g_io_channel_flush(cl->ioc, &gerror);
416 else
417 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gerror->message);
419 g_clear_error(&gerror);
421 if (quit)
422 goto quit;
425 g_strfreev(cl->outbuf);
426 cl->outbuf = NULL;
429 if (!cl->gfd.revents & (G_IO_IN))
430 return TRUE;
432 ret = g_io_channel_read_line(cl->ioc, &line, &len, NULL, &gerror);
434 if (ret != G_IO_STATUS_NORMAL) {
435 if (ret == G_IO_STATUS_EOF)
436 goto quit;
438 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gerror->message);
439 g_clear_error(&gerror);
440 return TRUE;
443 line[g_utf8_strlen(line, -1) - 1] = 0;
445 switch (input_parser(line)) {
446 case P_QUIT:
447 quit:
448 if (line) {
449 memset(line, 0, len);
450 g_free(line);
453 g_clear_error(&gerror);
455 if (cl->xml)
456 gcry_free(cl->xml);
458 if (cl->gh)
459 gcry_cipher_close(cl->gh);
461 if (cl->doc)
462 xmlFreeDoc(cl->doc);
464 if (cl->reader)
465 xmlFreeTextReader(cl->reader);
467 if (cl->outbuf)
468 g_free(cl->outbuf);
470 if (cl->filename)
471 g_free(cl->filename);
473 #if 0
474 if (memlist)
475 g_slist_free(memlist);
476 #endif
478 g_main_loop_unref(gloop);
479 g_main_loop_quit(gloop);
480 return FALSE;
481 default:
482 break;
485 memset(line, 0, len);
486 g_free(line);
487 return TRUE;
490 static struct memlist_s *memlist_remove(struct memlist_s *list, struct memlist_s *r)
492 struct memlist_s *m, *last = NULL, *p;
494 for (m = list; m; m = m->next) {
495 if (m->ptr == r->ptr) {
496 memset(m->ptr, 0, m->size);
497 free(m->ptr);
498 p = m->next;
499 free(m);
501 if (last) {
502 if (p)
503 last->next = p;
504 else
505 last->next = NULL;
507 else if (p)
508 list = p;
509 else
510 list = NULL;
512 break;
515 last = m;
518 return list;
521 static struct memlist_s *memlist_append(struct memlist_s *list, struct memlist_s *new)
523 struct memlist_s *m;
525 if (!list) {
526 list = new;
527 list->next = NULL;
528 return list;
531 for (m = list; m; m = m->next) {
532 if (!m->next) {
533 m->next = new;
534 m = m->next;
535 m->next = NULL;
536 break;
540 return list;
543 void xfree(void *ptr)
545 struct memlist_s *m;
547 if (!ptr)
548 return;
550 for (m = memlist; m; m = m->next) {
551 if (m->ptr == ptr) {
552 #ifdef DEBUG
553 fprintf(stderr, "xfree(): %p %i\n", ptr, m->size);
554 #endif
555 memlist = memlist_remove(memlist, m);
556 return;
560 warnx("xfree(): %p not found", ptr);
561 assert(0);
564 void *xmalloc(size_t size)
566 void *p;
567 struct memlist_s *new;
569 if (size <= 0)
570 return NULL;
572 if ((new = malloc(sizeof(struct memlist_s))) == NULL)
573 return NULL;
575 if ((p = malloc(size)) == NULL) {
576 free(new);
577 return NULL;
580 new->ptr = p;
581 new->size = size;
582 memlist = memlist_append(memlist, new);
583 #ifdef DEBUG
584 fprintf(stderr, "xmalloc(): %p %i\n", p, size);
585 #endif
586 return new->ptr;
589 void *xcalloc(size_t nmemb, size_t size)
591 void *p;
592 struct memlist_s *new;
594 if (size <= 0)
595 return NULL;
597 if ((new = malloc(sizeof(struct memlist_s))) == NULL)
598 return NULL;
600 if ((p = calloc(nmemb, size)) == NULL) {
601 free(new);
602 return NULL;
605 new->ptr = p;
606 new->size = size;
607 memlist = memlist_append(memlist, new);
608 #ifdef DEBUG
609 fprintf(stderr, "xcalloc(): %p %i\n", p, size);
610 #endif
611 return new->ptr;
614 void *xrealloc(void *ptr, size_t size)
616 void *new;
617 struct memlist_s *m;
619 if (!ptr)
620 return xmalloc(size);
622 if (size <= 0)
623 return ptr;
625 for (m = memlist; m; m = m->next) {
626 if (m->ptr == ptr) {
627 if ((new = malloc(size)) == NULL)
628 return NULL;
630 memcpy(new, m->ptr, (size < m->size) ? size : m->size);
631 memset(m->ptr, 0, m->size);
632 free(m->ptr);
633 m->ptr = new;
634 m->size = size;
635 #ifdef DEBUG
636 fprintf(stderr, "xrealloc(): %p %i\n", new, size);
637 #endif
638 return m->ptr;
642 warnx("xrealloc(): %p not found", ptr);
643 assert(0);
644 return NULL;
647 char *xstrdup(const char *str)
649 char *new;
650 size_t len;
651 const char *p;
652 char *np;
654 if (!str)
655 return NULL;
657 len = strlen(str) + 1;
659 if ((new = xmalloc(len * sizeof(char))) == NULL)
660 return NULL;
662 for (p = str, np = new; *p; p++)
663 *np++ = *p;
665 *np = 0;
666 #ifdef DEBUG
667 fprintf(stderr, "xstrdup(): %p\n", new);
668 #endif
669 return new;
673 * Called every time a connection is made.
675 static void doit(int fd)
677 static GSourceFuncs gsrcf = {
678 source_prepare, source_check, source_dispatch, NULL, 0, 0
680 GPollFD gfd = { fd, G_IO_IN|G_IO_OUT|G_IO_HUP|G_IO_ERR, 0 };
682 signal(SIGCHLD, SIG_DFL);
683 signal(SIGHUP, SIG_DFL);
684 signal(SIGINT, SIG_DFL);
685 signal(SIGALRM, SIG_DFL);
687 #ifdef HAVE_MLOCKALL
688 if (use_mlock && mlockall(MCL_FUTURE) == -1) {
689 log_write("mlockall(): %s", strerror(errno));
690 exit(EXIT_FAILURE);
692 #endif
694 gloop = g_main_loop_new(NULL, TRUE);
695 cl = g_malloc0(sizeof(struct client_s));
696 cl->src = g_source_new(&gsrcf, sizeof(GSource));
697 cl->gfd = gfd;
698 cl->state = STATE_CONNECTED;
699 cl->ioc = g_io_channel_unix_new(fd);
700 g_source_add_poll(cl->src, &cl->gfd);
701 g_source_set_callback(cl->src, source_cb, NULL, NULL);
702 g_source_attach(cl->src, NULL);
704 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
705 xmlInitMemory();
707 if ((gcryerrno = gcry_cipher_open(&cl->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
708 send_to_client(cl, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
709 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
710 quit = 1;
712 else
713 // FIXME 100% CPU if removed (poll()).
714 send_to_client(cl, "OK \n");
716 g_main_loop_run(gloop);
717 g_io_channel_unref(cl->ioc);
718 g_free(cl);
719 shutdown(fd, SHUT_RDWR);
720 log_write("exiting");
721 _exit(EXIT_SUCCESS);
724 static void set_rcfile_defaults(GKeyFile *kf)
726 gchar buf[PATH_MAX];
728 snprintf(buf, sizeof(buf), "~/.pwmd/socket");
729 g_key_file_set_string(kf, "default", "socket_path", buf);
730 snprintf(buf, sizeof(buf), "~/.pwmd");
731 g_key_file_set_string(kf, "default", "data_directory", buf);
732 snprintf(buf, sizeof(buf), "~/.pwmd/.log");
733 g_key_file_set_string(kf, "default", "log_path", buf);
734 g_key_file_set_boolean(kf, "default", "enable_logging", FALSE);
735 g_key_file_set_integer(kf, "default", "cache_size", cache_size);
736 g_key_file_set_boolean(kf, "default", "disable_mlockall", FALSE);
737 g_key_file_set_integer(kf, "default", "cache_timeout", -1);
738 g_key_file_set_integer(kf, "default", "iterations", 0);
741 static GKeyFile *parse_rcfile(const gchar *filename, int cmdline)
743 GKeyFile *kf = g_key_file_new();
744 GError *error = NULL;
746 if (g_key_file_load_from_file(kf, filename, G_KEY_FILE_NONE, &error) == FALSE) {
747 warnx("%s: %s", filename, error->message);
749 if (cmdline)
750 exit(EXIT_FAILURE);
752 if (error->code == G_FILE_ERROR_NOENT) {
753 g_clear_error(&error);
754 set_rcfile_defaults(kf);
755 return kf;
758 g_clear_error(&error);
759 return NULL;
762 return kf;
765 static gboolean try_xml_decrypt(gint fd, struct stat st, guchar *key)
767 guchar *iv;
768 void *inbuf;
769 gcry_cipher_hd_t gh;
770 gsize insize;
771 guchar tkey[gcrykeysize];
772 gint iter;
773 struct file_header_s {
774 guint iter;
775 guchar iv[gcryblocksize];
776 } file_header;
778 if ((gcryerrno = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
779 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
780 return FALSE;
783 lseek(fd, 0, SEEK_SET);
784 insize = st.st_size - sizeof(struct file_header_s);
785 iv = gcry_malloc(gcryblocksize);
786 read(fd, &file_header, sizeof(struct file_header_s));
787 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
788 inbuf = gcry_malloc(insize);
789 read(fd, inbuf, insize);
790 memcpy(tkey, key, sizeof(tkey));
791 tkey[0] ^= 1;
793 if ((gcryerrno = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
794 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
795 gcry_cipher_close(gh);
796 gcry_free(inbuf);
797 gcry_free(iv);
798 return FALSE;
801 if ((gcryerrno = gcry_cipher_setkey(gh, key, gcrykeysize))) {
802 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
803 gcry_cipher_close(gh);
804 gcry_free(inbuf);
805 gcry_free(iv);
806 return FALSE;
809 if (decrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
810 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
811 gcry_cipher_close(gh);
812 gcry_free(inbuf);
813 gcry_free(iv);
814 return FALSE;
817 if ((gcryerrno = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
818 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
819 gcry_cipher_close(gh);
820 gcry_free(inbuf);
821 gcry_free(iv);
822 return FALSE;
825 iter = file_header.iter;
827 while (iter-- > 0) {
828 if ((gcryerrno = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
829 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
830 gcry_cipher_close(gh);
831 gcry_free(inbuf);
832 gcry_free(iv);
833 return FALSE;
836 if (decrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
837 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
838 gcry_cipher_close(gh);
839 gcry_free(inbuf);
840 gcry_free(iv);
841 return FALSE;
845 gcry_cipher_close(gh);
846 gcry_free(iv);
848 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
849 gcry_free(inbuf);
850 return FALSE;
853 gcry_free(inbuf);
854 return TRUE;
857 static gchar *get_password(const gchar *prompt)
859 gchar buf[LINE_MAX], *p;
860 struct termios told, tnew;
861 gchar *key;
863 if (tcgetattr(STDIN_FILENO, &told) == -1)
864 err(EXIT_FAILURE, "tcgetattr()");
866 memcpy(&tnew, &told, sizeof(struct termios));
867 tnew.c_lflag &= ~(ECHO);
868 tnew.c_lflag |= ICANON|ECHONL;
870 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
871 tcsetattr(STDIN_FILENO, TCSANOW, &told);
872 err(EXIT_FAILURE, "tcsetattr()");
875 fprintf(stderr, "%s", prompt);
877 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
878 tcsetattr(STDIN_FILENO, TCSANOW, &told);
879 return NULL;
882 tcsetattr(STDIN_FILENO, TCSANOW, &told);
883 p[strlen(p) - 1] = 0;
885 if (!p || !*p)
886 return NULL;
888 key = gcry_malloc(strlen(p) + 1);
889 sprintf(key, "%s", p);
890 return key;
893 static gboolean get_input(const gchar *filename, guchar *key)
895 gint fd;
896 struct stat st;
897 int try = 0;
898 gchar *password;
899 gchar *prompt;
901 if ((fd = open_file(filename, &st)) == -1) {
902 warn("%s", filename);
903 return FALSE;
906 if (st.st_size == 0) {
907 fprintf(stderr, "Skipping empty file '%s'.\n", filename);
908 close(fd);
909 return FALSE;
912 if ((prompt = xmalloc(strlen(filename) + strlen("Password for '") + 4)) == NULL) {
913 close(fd);
914 warn("malloc()");
915 return FALSE;
918 sprintf(prompt, "Password for '%s': ", filename);
920 again:
921 if ((password = get_password(prompt)) == NULL) {
922 fprintf(stderr, "Skipping.\n");
923 close(fd);
924 xfree(prompt);
925 return FALSE;
928 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password));
929 xfree(password);
931 if (try_xml_decrypt(fd, st, key) == FALSE) {
932 if (try++ == 2) {
933 fprintf(stderr, "Invalid password. Skipping file.\n");
934 close(fd);
935 xfree(prompt);
936 return FALSE;
938 else {
939 fprintf(stderr, "Invalid password.\n");
940 goto again;
944 close(fd);
945 xfree(prompt);
946 return TRUE;
949 gint cache_file_count()
951 void *p;
952 gint n = 0;
953 glong len;
954 file_cache_t f;
956 for (p = shm_data, len = 0; len <= cache_size;) {
957 memcpy(&f, p, sizeof(file_cache_t));
959 if (f.used == TRUE)
960 n++;
962 p += sizeof(file_cache_t);
963 len += sizeof(file_cache_t);
965 if (len + sizeof(file_cache_t) > cache_size)
966 break;
969 return n;
972 gboolean cache_add_file(const guchar *md5file, const guchar *shakey)
974 void *p;
975 file_cache_t f;
976 gint nfiles = cache_file_count();
977 glong len;
980 * Make sure there is enough secure memory.
982 if (!md5file || (nfiles + 1) * sizeof(file_cache_t) > cache_size)
983 return FALSE;
986 * Find the first available "slot".
988 for (p = shm_data, len = 0; len <= cache_size;) {
989 memcpy(&f, p, sizeof(file_cache_t));
991 if (f.used == FALSE) {
992 memset(&f, 0, sizeof(f));
993 memcpy(&f.filename, md5file, sizeof(f.filename));
995 if (shakey)
996 memcpy(&f.key, shakey, sizeof(f.key));
998 f.used = TRUE;
999 f.when = 0;
1000 f.timeout = -1;
1001 memcpy(p, &f, sizeof(file_cache_t));
1002 return TRUE;
1005 p += sizeof(file_cache_t);
1006 len += sizeof(file_cache_t);
1008 if (len + sizeof(file_cache_t) > cache_size)
1009 break;
1012 return FALSE;
1015 static gboolean xml_import(const gchar *filename, gint iter)
1017 xmlDocPtr doc;
1018 gint fd;
1019 struct stat st;
1020 int len;
1021 xmlChar *xmlbuf;
1022 xmlChar *xml;
1023 gchar *key = NULL;
1024 gchar *key2 = NULL;
1025 guchar shakey[gcrykeysize];
1026 gcry_cipher_hd_t gh;
1028 #ifdef HAVE_MLOCKALL
1029 if (use_mlock && mlockall(MCL_FUTURE) == -1)
1030 err(EXIT_FAILURE, "mlockall()");
1031 #endif
1033 if (stat(filename, &st) == -1) {
1034 warn("%s", filename);
1035 return FALSE;
1038 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1039 xmlInitMemory();
1041 if ((gcryerrno = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
1042 send_to_client(NULL, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
1043 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
1044 return FALSE;
1047 if ((key = get_password("New password: ")) == NULL) {
1048 fprintf(stderr, "Invalid password.\n");
1049 return FALSE;
1052 if ((key2 = get_password("Verify password: ")) == NULL) {
1053 fprintf(stderr, "Passwords do not match.\n");
1054 gcry_free(key);
1055 return FALSE;
1058 if (strcmp(key, key2) != 0) {
1059 fprintf(stderr, "Passwords do not match.\n");
1060 gcry_free(key);
1061 gcry_free(key2);
1062 return FALSE;
1065 gcry_free(key2);
1067 if ((fd = open(filename, O_RDONLY)) == -1) {
1068 gcry_free(key);
1069 warn("%s", filename);
1070 return FALSE;
1073 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1074 gcry_free(key);
1075 close(fd);
1076 warnx("gcry_malloc() failed");
1077 return FALSE;
1080 read(fd, xmlbuf, st.st_size);
1081 close(fd);
1082 xmlbuf[st.st_size] = 0;
1085 * Make sure the document validates.
1087 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1088 warnx("xmlReadDoc() failed");
1089 close(fd);
1090 gcry_free(key);
1091 gcry_free(xmlbuf);
1092 return FALSE;
1095 gcry_free(xmlbuf);
1096 xmlDocDumpMemory(doc, &xml, &len);
1097 xmlFreeDoc(doc);
1098 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key));
1099 gcry_free(key);
1101 if (do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter) == FALSE) {
1102 memset(shakey, 0, sizeof(shakey));
1103 xmlFree(xml);
1104 return FALSE;
1107 memset(shakey, 0, sizeof(shakey));
1108 xmlFree(xml);
1109 return TRUE;
1112 gchar *get_key_file_string(const gchar *section, const gchar *what)
1114 gchar *val = NULL;
1115 GError *gerror = NULL;
1117 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1118 val = g_key_file_get_string(keyfileh, section, what, &gerror);
1120 if (gerror) {
1121 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
1122 g_clear_error(&gerror);
1125 else {
1126 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
1127 val = g_key_file_get_string(keyfileh, "default", what, &gerror);
1129 if (gerror) {
1130 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
1131 g_clear_error(&gerror);
1136 return val;
1139 gint get_key_file_integer(const gchar *section, const gchar *what)
1141 gint val = -1;
1142 GError *gerror = NULL;
1144 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1145 val = g_key_file_get_integer(keyfileh, section, what, &gerror);
1147 if (gerror) {
1148 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
1149 g_clear_error(&gerror);
1152 else {
1153 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
1154 val = g_key_file_get_integer(keyfileh, "default", what, &gerror);
1156 if (gerror) {
1157 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
1158 g_clear_error(&gerror);
1163 return val;
1166 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1168 gboolean val = FALSE;
1169 GError *gerror = NULL;
1171 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1172 val = g_key_file_get_boolean(keyfileh, section, what, &gerror);
1174 if (gerror) {
1175 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
1176 g_clear_error(&gerror);
1179 else {
1180 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
1181 val = g_key_file_get_boolean(keyfileh, "default", what, &gerror);
1183 if (gerror) {
1184 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
1185 g_clear_error(&gerror);
1190 return val;
1193 gchar *expand_homedir(gchar *str)
1195 gchar *p = str;
1196 gchar buf[PATH_MAX];
1198 if (*p == '~') {
1199 p++;
1200 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1201 return g_strdup(buf);
1204 return g_strdup(str);
1207 static gboolean do_add_keyfile_key(const gchar *filename, const gchar *value)
1209 guchar md5file[16];
1210 guchar *shakey;
1211 gboolean ret;
1212 gint timeout;
1214 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1215 shakey = gcry_malloc(gcrykeysize);
1216 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, value, strlen(value));
1217 ret = cache_add_file(md5file, shakey);
1218 gcry_free(shakey);
1219 timeout = get_key_file_integer(filename, "cache_timeout");
1220 cache_set_timeout(md5file, timeout);
1221 return ret;
1224 static gchar *_getline(const gchar *file)
1226 FILE *fp;
1227 gchar buf[LINE_MAX], *p;
1228 gchar *str = NULL;
1230 if ((fp = fopen(file, "r")) == NULL) {
1231 warn("%s", file);
1232 return NULL;
1235 if ((p = fgets(buf, sizeof(buf), fp)) == NULL) {
1236 warnx("%s: empty file?", file);
1237 return NULL;
1240 fclose(fp);
1241 buf[strlen(buf) - 1] = 0;
1242 str = gcry_malloc(strlen(p) + 1);
1243 memcpy(str, p, strlen(p));
1244 str[strlen(p)] = 0;
1245 memset(&buf, 0, sizeof(buf));
1246 return str;
1249 static gboolean parse_keyfile_key()
1251 gsize n;
1252 gchar **groups;
1253 gchar **p;
1254 gchar *str;
1256 groups = g_key_file_get_groups(keyfileh, &n);
1258 for (p = groups ; *p; p++) {
1259 GError *error = NULL;
1261 if (g_key_file_has_key(keyfileh, *p, "key", &error) == TRUE) {
1262 str = g_key_file_get_string(keyfileh, *p, "key", &error);
1264 if (!str) {
1265 if (error) {
1266 warnx("%s", error->message);
1267 g_clear_error(&error);
1270 continue;
1273 do_add_keyfile_key(*p, str);
1274 g_free(str);
1275 continue;
1278 if (error) {
1279 warnx("%s", error->message);
1280 g_clear_error(&error);
1281 continue;
1284 if (g_key_file_has_key(keyfileh, *p, "key_file", &error) == TRUE) {
1285 gchar *t;
1286 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &error);
1288 if (!file) {
1289 if (error) {
1290 warnx("%s", error->message);
1291 g_clear_error(&error);
1294 continue;
1297 t = expand_homedir(file);
1298 g_free(file);
1299 file = t;
1301 if ((str = _getline(file)) == NULL) {
1302 g_free(file);
1303 continue;
1306 g_free(file);
1307 do_add_keyfile_key(*p, str);
1308 gcry_free(str);
1309 continue;
1312 if (error) {
1313 warnx("%s", error->message);
1314 g_clear_error(&error);
1318 g_strfreev(groups);
1319 return TRUE;
1322 int main(int argc, char *argv[])
1324 gint opt;
1325 struct sockaddr_un addr;
1326 struct passwd *pw = getpwuid(getuid());
1327 gchar buf[PATH_MAX];
1328 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1329 gchar *socketarg = NULL;
1330 gchar *datadir = NULL;
1331 gint fd;
1332 gboolean n;
1333 gchar *p;
1334 gchar **cache_push = NULL;
1335 gchar *rcfile;
1336 gint iter = 0;
1337 gchar *import = NULL;
1338 gint default_timeout;
1339 gint rcfile_spec = 0;
1340 gint estatus = EXIT_FAILURE;
1341 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1342 #ifndef DEBUG
1343 #ifdef HAVE_SETRLIMIT
1344 struct rlimit rl;
1346 rl.rlim_cur = rl.rlim_max = 0;
1348 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1349 err(EXIT_FAILURE, "setrlimit()");
1350 #endif
1351 #endif
1353 g_mem_set_vtable(&mtable);
1354 rcfile = g_strdup_printf("%s/.pwmdrc", pw->pw_dir);
1356 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1357 err(EXIT_FAILURE, "sysconf()");
1359 cache_size = page_size;
1361 #ifdef HAVE_MLOCKALL
1363 * Default to using mlockall().
1365 use_mlock = 1;
1366 #endif
1368 while ((opt = getopt(argc, argv, "I:hvf:")) != EOF) {
1369 switch (opt) {
1370 case 'I':
1371 import = optarg;
1372 break;
1373 case 'f':
1374 g_free(rcfile);
1375 rcfile = g_strdup(optarg);
1376 rcfile_spec = 1;
1377 break;
1378 case 'v':
1379 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1380 exit(EXIT_SUCCESS);
1381 case 'h':
1382 default:
1383 usage(argv[0]);
1387 if ((keyfileh = parse_rcfile(rcfile, rcfile_spec)) == NULL)
1388 exit(EXIT_FAILURE);
1390 g_key_file_set_list_separator(keyfileh, ',');
1392 if ((p = g_key_file_get_string(keyfileh, "default", "socket_path", NULL)) == NULL)
1393 errx(EXIT_FAILURE, "%s: socket_path not defined", rcfile);
1395 if (*p == '~') {
1396 p++;
1397 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1398 g_free(p);
1399 socketarg = g_strdup(buf);
1401 else
1402 socketarg = p;
1404 if ((p = g_key_file_get_string(keyfileh, "default", "data_directory", NULL)) == NULL)
1405 errx(EXIT_FAILURE, "%s: data_directory not defined", rcfile);
1407 datadir = expand_homedir(p);
1408 g_free(p);
1410 if (g_key_file_has_key(keyfileh, "default", "cache_timeout", NULL) == TRUE)
1411 default_timeout = g_key_file_get_integer(keyfileh, "default", "cache_timeout", NULL);
1412 else
1413 default_timeout = -1;
1415 if (g_key_file_has_key(keyfileh, "default", "cache_size", NULL) == TRUE) {
1416 cache_size = g_key_file_get_integer(keyfileh, "default", "cache_size", NULL);
1418 if (cache_size < page_size || cache_size % page_size)
1419 errx(EXIT_FAILURE, "cache size must be in multiples of %li.", page_size);
1422 if (g_key_file_has_key(keyfileh, "default", "iterations", NULL) == TRUE)
1423 iter = g_key_file_get_integer(keyfileh, "default", "iterations", NULL);
1425 #ifdef HAVE_MLOCKALL
1426 if (g_key_file_has_key(keyfileh, "default", "disable_mlockall", NULL) == TRUE)
1427 use_mlock = g_key_file_get_integer(keyfileh, "default", "disable_mlockall", NULL);
1428 #endif
1430 if (g_key_file_has_key(keyfileh, "default", "log_path", NULL) == TRUE) {
1431 if (g_key_file_has_key(keyfileh, "default", "enable_logging", NULL) == TRUE) {
1432 n = g_key_file_get_boolean(keyfileh, "default", "enable_logging", NULL);
1434 if (n == TRUE) {
1435 p = g_key_file_get_string(keyfileh, "default", "log_path", NULL);
1437 if (*p == '~') {
1438 p++;
1439 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1440 g_free(p);
1441 logfile = g_strdup(buf);
1443 else
1444 logfile = p;
1449 if (g_key_file_has_key(keyfileh, "default", "cache_push", NULL) == TRUE)
1450 cache_push = g_key_file_get_string_list(keyfileh, "default", "cache_push", NULL, NULL);
1452 if (strchr(socketarg, '/') == NULL) {
1453 socketdir = g_get_current_dir();
1454 socketname = g_strdup(socketarg);
1455 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1457 else {
1458 socketname = g_strdup(strrchr(socketarg, '/'));
1459 socketname++;
1460 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1461 socketdir = g_strdup(socketarg);
1462 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1465 snprintf(buf, sizeof(buf), "%s", datadir);
1467 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1468 err(EXIT_FAILURE, "%s", buf);
1470 #ifdef MMAP_ANONYMOUS_SHARED
1471 if ((shm_data = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1472 MAP_SHARED|MAP_ANONYMOUS, -1, 0)) == NULL) {
1473 err(EXIT_FAILURE, "mmap()");
1475 #else
1476 snprintf(buf, sizeof(buf), "pwmd.%i", pw->pw_uid);
1478 if ((fd = shm_open(buf, O_CREAT|O_RDWR|O_EXCL, 0600)) == -1)
1479 err(EXIT_FAILURE, "shm_open(): %s", buf);
1482 * Should be enough for the file cache.
1484 if (ftruncate(fd, cache_size) == -1) {
1485 warn("ftruncate()");
1486 shm_unlink(buf);
1487 exit(EXIT_FAILURE);
1490 if ((shm_data = mmap(NULL, cache_size, PROT_READ|PROT_WRITE, MAP_SHARED,
1491 fd, 0)) == NULL) {
1492 warn("mmap()");
1493 shm_unlink(buf);
1494 exit(EXIT_FAILURE);
1497 close(fd);
1498 #endif
1500 if (mlock(shm_data, cache_size) == -1)
1501 warn("mlock()");
1503 memset(shm_data, 0, cache_size);
1504 setup_gcrypt();
1506 if (import) {
1507 opt = xml_import(import, iter);
1508 g_free(socketpath);
1510 if (munmap(shm_data, cache_size) == -1)
1511 log_write("munmap(): %s", strerror(errno));
1513 #ifndef MMAP_ANONYMOUS_SHARED
1514 if (shm_unlink(buf) == -1)
1515 log_write("shm_unlink(): %s: %s", buf, strerror(errno));
1516 #endif
1518 exit((opt) == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1521 if (parse_keyfile_key() == FALSE)
1522 goto do_exit;
1524 getcwd(buf, sizeof(buf));
1527 * bind() doesn't like the full pathname of the socket or any non alphanum
1528 * characters so change to the directory where the socket is wanted then
1529 * create it then change to datadir.
1531 if (chdir(socketdir)) {
1532 warn("%s", socketdir);
1533 goto do_exit;
1536 g_free(socketdir);
1538 if ((sfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1539 warn("socket()");
1540 goto do_exit;
1543 addr.sun_family = AF_UNIX;
1544 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1545 g_free(--socketname);
1547 if (bind(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1548 warn("bind()");
1549 goto do_exit;
1552 if (chdir(datadir)) {
1553 warn("%s", datadir);
1554 close(sfd);
1555 unlink(socketpath);
1556 goto do_exit;
1559 g_free(datadir);
1562 * Set the cache entry for a file. Prompts for the password.
1564 if (cache_push) {
1565 guchar *md5file;
1566 guchar *key;
1567 gint timeout = default_timeout;
1569 for (opt = 0; cache_push[opt]; opt++) {
1570 p = cache_push[opt];
1572 while (isspace(*p))
1573 p++;
1575 if (!*p)
1576 continue;
1578 md5file = gcry_malloc(16);
1579 key = gcry_malloc(gcrykeysize);
1580 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1582 if (cache_iscached(md5file) == TRUE) {
1583 warnx("%s: file already cached, skipping", p);
1584 gcry_free(md5file);
1585 continue;
1588 if (access(p, R_OK|W_OK) != 0) {
1589 if (errno != ENOENT) {
1590 warn("%s", p);
1591 unlink(socketpath);
1592 goto do_exit;
1595 warn("%s", p);
1596 continue;
1599 if (get_input(p, key) == FALSE) {
1600 gcry_free(key);
1601 gcry_free(md5file);
1602 continue;
1605 if (cache_add_file(md5file, key) == FALSE) {
1606 warnx("%s: couldn't add file (cache_size?)", p);
1607 gcry_free(key);
1608 goto do_exit;
1611 timeout = get_key_file_integer(p, "cache_timeout");
1612 cache_set_timeout(md5file, timeout);
1613 fprintf(stderr, "Added.\n");
1614 gcry_free(key);
1615 gcry_free(md5file);
1618 g_strfreev(cache_push);
1619 fprintf(stderr, "Done! Daemonizing...\n");
1622 chdir(buf);
1623 g_free(rcfile);
1625 if (listen(sfd, 0) == -1) {
1626 warn("listen()");
1627 goto do_exit;
1630 signal(SIGCHLD, catchsig);
1631 signal(SIGTERM, catchsig);
1632 signal(SIGINT, catchsig);
1633 signal(SIGHUP, catchsig);
1634 signal(SIGALRM, catchsig);
1635 alarm(1);
1637 #ifndef DEBUG
1638 close(0);
1639 close(1);
1640 close(2);
1641 #endif
1643 log_write("%s starting: %li slots available", PACKAGE_STRING, cache_size / sizeof(file_cache_t));
1645 while (!quit) {
1646 socklen_t slen = sizeof(struct sockaddr_un);
1647 struct sockaddr_un raddr;
1648 pid_t pid;
1650 if ((fd = accept(sfd, (struct sockaddr_un *)&raddr, &slen)) == -1) {
1651 if (errno == EAGAIN)
1652 continue;
1654 if (!quit)
1655 log_write("accept(): %s", strerror(errno));
1657 continue;
1660 switch ((pid = fork())) {
1661 case -1:
1662 log_write("fork(): %s", strerror(errno));
1663 break;
1664 case 0:
1665 doit(fd);
1666 break;
1667 default:
1668 break;
1671 log_write("new connection: fd=%i, pid=%i", fd, pid);
1674 estatus = EXIT_SUCCESS;
1676 do_exit:
1677 chdir(buf);
1679 if (socketpath) {
1680 unlink(socketpath);
1681 g_free(socketpath);
1684 g_key_file_free(keyfileh);
1686 if (munmap(shm_data, cache_size) == -1)
1687 log_write("munmap(): %s", strerror(errno));
1689 #ifndef MMAP_ANONYMOUS_SHARED
1690 if (shm_unlink(buf) == -1)
1691 log_write("shm_unlink(): %s: %s", buf, strerror(errno));
1692 #endif
1694 if (estatus == EXIT_SUCCESS)
1695 log_write("pwmd exiting normally");
1697 exit(estatus);