1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
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
26 #include <sys/socket.h>
35 #include <glib/gprintf.h>
47 #include <sys/resource.h>
53 #include "pwmd_error.h"
56 void send_to_client(struct client_s
*client
, const gchar
*fmt
, ...)
65 for (p
= client
->outbuf
, n
= 0; *p
; p
++, n
++);
67 if ((client
->outbuf
= g_realloc(client
->outbuf
, (n
+ 2) * sizeof(gchar
*))) == NULL
) {
72 client
->outbuf
[n
++] = g_strdup_vprintf(fmt
, ap
);
73 client
->outbuf
[n
] = NULL
;
77 void send_error(struct client_s
*client
, int pwmd_errno
)
79 send_to_client(client
, "ERR %03i %s\n", pwmd_errno
, pwmd_strerror(pwmd_errno
));
82 void log_write(const gchar
*fmt
, ...)
94 if ((fd
= open(logfile
, O_WRONLY
|O_CREAT
|O_APPEND
, 0600)) == -1) {
100 g_vasprintf(&args
, fmt
, ap
);
103 tm
= localtime(&now
);
104 strftime(tbuf
, sizeof(tbuf
), "%b %d %Y %H:%M:%S ", tm
);
105 tbuf
[sizeof(tbuf
) - 1] = 0;
106 line
= g_strdup_printf("%s %i %s\n", tbuf
, getpid(), args
);
107 write(fd
, line
, strlen(line
));
113 static void catchsig(gint sig
)
117 log_write("caught signal %i (%s)", sig
, strsignal(sig
));
121 waitpid(-1, &status
, 0);
124 log_write("clearing file cache");
125 memset(shm_data
, 0, cache_size
);
129 shutdown(sfd
, SHUT_RDWR
);
135 static void usage(gchar
*pn
)
138 "Usage: %s [-hv] [-f <rcfile>]\n"
139 " -f load the specified rcfile (~/.pwmdrc)\n"
141 " -h this help text\n",
146 gchar
**split_input_line(gchar
*str
, gchar
*delim
, gint n
)
151 return g_strsplit(str
, delim
, n
);
154 static int gcry_SecureCheck(const void *ptr
)
159 static void setup_gcrypt()
161 gcry_check_version(NULL
);
163 gcry_set_allocation_handler(xmalloc
, xmalloc
, gcry_SecureCheck
, xrealloc
,
166 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256
, GCRYCTL_TEST_ALGO
, NULL
,
168 errx(EXIT_FAILURE
, "AES cipher not supported");
170 gcry_cipher_algo_info(GCRY_CIPHER_AES256
, GCRYCTL_GET_KEYLEN
, NULL
, &gcrykeysize
);
171 gcry_cipher_algo_info(GCRY_CIPHER_AES256
, GCRYCTL_GET_BLKLEN
, NULL
, &gcryblocksize
);
174 static gint
input_parser(gchar
*str
)
180 str
= g_strchug(str
);
185 while ((p
= strsep(&str
, "\n")) != NULL
) {
186 if (g_ascii_strcasecmp(p
, "QUIT") == 0)
188 else if (g_ascii_strcasecmp(p
, "HELP") == 0)
189 help_command(cl
, NULL
);
190 else if (g_ascii_strncasecmp(p
, "HELP ", 5) == 0) {
195 else if (g_ascii_strcasecmp(p
, "LIST") == 0 ||
196 g_ascii_strncasecmp(p
, "LIST ", 5) == 0) {
197 if (cl
->state
!= STATE_OPEN
)
198 send_error(cl
, EPWMD_NO_FILE
);
202 else if (g_ascii_strncasecmp(p
, "STORE ", 6) == 0) {
206 if (cl
->state
!= STATE_OPEN
)
207 send_error(cl
, EPWMD_NO_FILE
);
209 if ((req
= split_input_line(t
, "\t", 0)) != NULL
) {
210 if (store_command(cl
, req
) == TRUE
)
211 send_to_client(cl
, "OK \n");
214 send_error(cl
, EPWMD_COMMAND_SYNTAX
);
217 else if (g_ascii_strncasecmp(p
, "DELETE ", 7) == 0) {
220 if (cl
->state
!= STATE_OPEN
)
221 send_error(cl
, EPWMD_NO_FILE
);
223 if ((req
= split_input_line(t
, "\t", 0)) != NULL
) {
224 if (delete_command(cl
, req
) == TRUE
)
225 send_to_client(cl
, "OK \n");
228 send_error(cl
, EPWMD_COMMAND_SYNTAX
);
231 else if (g_ascii_strncasecmp(p
, "GET ", 4) == 0) {
235 if (cl
->state
!= STATE_OPEN
)
236 send_error(cl
, EPWMD_NO_FILE
);
238 if ((req
= split_input_line(t
, "\t", 0)) != NULL
)
239 get_command(cl
, &cl
->reader
, req
, 0);
241 send_error(cl
, EPWMD_COMMAND_SYNTAX
);
244 else if (g_ascii_strncasecmp(p
, "ATTR ", 5) == 0) {
248 if (cl
->state
!= STATE_OPEN
)
249 send_error(cl
, EPWMD_NO_FILE
);
251 if ((req
= split_input_line(t
, " ", 4)) != NULL
) {
252 if (attr_command(cl
, req
) == TRUE
)
253 send_to_client(cl
, "OK \n");
256 send_error(cl
, EPWMD_COMMAND_SYNTAX
);
259 else if (g_ascii_strncasecmp(p
, "OPEN ", 5) == 0) {
263 if (cl
->state
== STATE_OPEN
)
264 send_error(cl
, EPWMD_FILE_OPENED
);
266 if ((req
= split_input_line(t
, " ", 2)) != NULL
) {
267 if (open_command(cl
, req
) == TRUE
) {
268 send_to_client(cl
, "OK \n");
269 cl
->state
= STATE_OPEN
;
273 * The document has been parsed and is stored in cl->doc.
281 send_error(cl
, EPWMD_COMMAND_SYNTAX
);
284 else if (g_ascii_strncasecmp(p
, "SAVE", 4) == 0) {
288 if (cl
->state
!= STATE_OPEN
)
289 send_error(cl
, EPWMD_NO_FILE
);
291 req
= split_input_line(t
, " ", 1);
293 if (save_command(cl
, cl
->filename
, (req
) ? req
[0] : NULL
) == TRUE
)
294 send_to_client(cl
, "OK \n");
297 else if (g_ascii_strncasecmp(p
, "CACHE ", 6) == 0) {
300 req
= split_input_line(t
, " ", 2);
302 if (cache_command(cl
, req
) == TRUE
)
303 send_to_client(cl
, "OK \n");
305 else if (g_ascii_strncasecmp(p
, "DUMP", 4) == 0) {
306 if (cl
->state
!= STATE_OPEN
)
307 send_error(cl
, EPWMD_NO_FILE
);
309 if (dump_command(cl
) == TRUE
)
310 send_to_client(cl
, "OK \n");
314 send_error(cl
, EPWMD_COMMAND_SYNTAX
);
325 static gboolean
source_prepare(GSource
*src
, gint
*to
)
327 if (cl
->gfd
.revents
& (G_IO_HUP
|G_IO_NVAL
|G_IO_ERR
))
333 static gboolean
source_check(GSource
*src
)
335 if (cl
->gfd
.revents
& (G_IO_IN
|G_IO_PRI
))
338 if (cl
->outbuf
&& (cl
->gfd
.revents
& (G_IO_OUT
)))
344 static gboolean
source_dispatch(GSource
*src
, GSourceFunc cb
, gpointer data
)
349 static gboolean
source_cb(gpointer data
)
354 GError
*gerror
= NULL
;
357 if (cl
->gfd
.revents
& (G_IO_HUP
|G_IO_NVAL
|G_IO_ERR
))
360 if (cl
->outbuf
&& (cl
->gfd
.revents
& (G_IO_OUT
))) {
361 for (p
= cl
->outbuf
; *p
; p
++) {
362 ret
= g_io_channel_write_chars(cl
->ioc
, *p
, -1, &len
, &gerror
);
364 if (ret
== G_IO_STATUS_NORMAL
)
365 g_io_channel_flush(cl
->ioc
, &gerror
);
367 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gerror
->message
);
369 g_clear_error(&gerror
);
375 g_strfreev(cl
->outbuf
);
379 if (!cl
->gfd
.revents
& (G_IO_IN
))
382 ret
= g_io_channel_read_line(cl
->ioc
, &line
, &len
, NULL
, &gerror
);
384 if (ret
!= G_IO_STATUS_NORMAL
) {
385 if (ret
== G_IO_STATUS_EOF
)
388 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gerror
->message
);
389 g_clear_error(&gerror
);
393 line
[g_utf8_strlen(line
, -1) - 1] = 0;
395 switch (input_parser(line
)) {
399 memset(line
, 0, len
);
403 g_clear_error(&gerror
);
409 gcry_cipher_close(cl
->gh
);
415 xmlFreeTextReader(cl
->reader
);
421 g_free(cl
->filename
);
425 g_slist_free(memlist
);
428 g_main_loop_unref(gloop
);
429 g_main_loop_quit(gloop
);
435 memset(line
, 0, len
);
440 static struct memlist_s
*memlist_remove(struct memlist_s
*list
, struct memlist_s
*r
)
442 struct memlist_s
*m
, *last
= NULL
;
444 for (m
= list
; m
; m
= m
->next
) {
445 if (m
->ptr
== r
->ptr
) {
446 memset(m
->ptr
, 0, m
->size
);
451 last
->next
= m
->next
;
469 static struct memlist_s
*memlist_append(struct memlist_s
*list
, struct memlist_s
*new)
479 for (m
= list
; m
; m
= m
->next
) {
491 void xfree(void *ptr
)
498 for (m
= memlist
; m
; m
= m
->next
) {
501 fprintf(stderr
, "xfree(): %p %i\n", ptr
, m
->size
);
503 memlist
= memlist_remove(memlist
, m
);
508 warnx("xfree(): %p not found", ptr
);
512 void *xmalloc(size_t size
)
515 struct memlist_s
*new;
520 if ((new = malloc(sizeof(struct memlist_s
))) == NULL
)
523 if ((p
= malloc(size
)) == NULL
) {
530 memlist
= memlist_append(memlist
, new);
532 fprintf(stderr
, "xmalloc(): %p %i\n", p
, size
);
537 void *xcalloc(size_t nmemb
, size_t size
)
540 struct memlist_s
*new;
545 if ((new = malloc(sizeof(struct memlist_s
))) == NULL
)
548 if ((p
= calloc(nmemb
, size
)) == NULL
) {
555 memlist
= memlist_append(memlist
, new);
557 fprintf(stderr
, "xcalloc(): %p %i\n", p
, size
);
562 void *xrealloc(void *ptr
, size_t size
)
568 return xmalloc(size
);
573 for (m
= memlist
; m
; m
= m
->next
) {
575 if ((new = malloc(size
)) == NULL
)
578 memcpy(new, m
->ptr
, (size
< m
->size
) ? size
: m
->size
);
579 memset(m
->ptr
, 0, m
->size
);
584 fprintf(stderr
, "xrealloc(): %p %i\n", new, size
);
590 warnx("xrealloc(): %p not found", ptr
);
595 char *xstrdup(const char *str
)
605 len
= strlen(str
) + 1;
607 if ((new = xmalloc(len
* sizeof(char))) == NULL
)
610 for (p
= str
, np
= new; *p
; p
++)
615 fprintf(stderr
, "xstrdup(): %p\n", new);
621 * Called every time a connection is made.
623 static void doit(int fd
, gint iter
)
625 static GSourceFuncs gsrcf
= {
626 source_prepare
, source_check
, source_dispatch
, NULL
, 0, 0
628 GPollFD gfd
= { fd
, G_IO_IN
|G_IO_OUT
|G_IO_HUP
|G_IO_ERR
, 0 };
629 GMemVTable mtable
= { xmalloc
, xrealloc
, xfree
, xcalloc
, NULL
, NULL
};
631 g_mem_set_vtable(&mtable
);
634 if (use_mlock
&& mlockall(MCL_FUTURE
) == -1)
635 err(EXIT_FAILURE
, "mlockall()");
638 gloop
= g_main_loop_new(NULL
, TRUE
);
639 cl
= g_malloc0(sizeof(struct client_s
));
640 cl
->src
= g_source_new(&gsrcf
, sizeof(GSource
));
643 cl
->state
= STATE_CONNECTED
;
644 cl
->ioc
= g_io_channel_unix_new(fd
);
645 g_source_add_poll(cl
->src
, &cl
->gfd
);
646 g_source_set_callback(cl
->src
, source_cb
, NULL
, NULL
);
647 g_source_attach(cl
->src
, NULL
);
654 xmlMemSetup(xfree
, xmalloc
, xrealloc
, xstrdup
);
657 if ((gcryerrno
= gcry_cipher_open(&cl
->gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0))) {
658 send_to_client(cl
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
659 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
663 // FIXME 100% CPU if removed (poll()).
664 send_to_client(cl
, "OK \n");
666 g_main_loop_run(gloop
);
667 g_io_channel_unref(cl
->ioc
);
669 shutdown(fd
, SHUT_RDWR
);
670 log_write("exiting");
674 static void set_rcfile_defaults(GKeyFile
*kf
)
678 snprintf(buf
, sizeof(buf
), "~/.pwmd/socket");
679 g_key_file_set_string(kf
, "default", "socket_path", buf
);
680 snprintf(buf
, sizeof(buf
), "~/.pwmd");
681 g_key_file_set_string(kf
, "default", "data_directory", buf
);
682 snprintf(buf
, sizeof(buf
), "~/.pwmd/.log");
683 g_key_file_set_string(kf
, "default", "log_path", buf
);
684 g_key_file_set_boolean(kf
, "default", "enable_logging", FALSE
);
685 g_key_file_set_integer(kf
, "default", "cache_size", cache_size
);
686 g_key_file_set_boolean(kf
, "default", "disable_mlockall", FALSE
);
689 static GKeyFile
*parse_rcfile(const gchar
*filename
)
691 GKeyFile
*kf
= g_key_file_new();
692 GError
*error
= NULL
;
694 if (g_key_file_load_from_file(kf
, filename
, G_KEY_FILE_NONE
, &error
) == FALSE
) {
695 if (error
->code
== G_FILE_ERROR_NOENT
) {
696 g_clear_error(&error
);
697 set_rcfile_defaults(kf
);
701 warnx("%s: %s", filename
, error
->message
);
702 g_clear_error(&error
);
710 static gboolean
try_xml_decrypt(gint fd
, struct stat st
, guchar
*key
, gint iter
)
716 guchar tkey
[gcrykeysize
];
718 if ((gcryerrno
= gcry_cipher_open(&gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0))) {
719 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
723 insize
= st
.st_size
- gcryblocksize
;
724 iv
= gcry_malloc(gcryblocksize
);
725 read(fd
, iv
, gcryblocksize
);
726 inbuf
= gcry_malloc(insize
);
727 read(fd
, inbuf
, insize
);
729 memcpy(tkey
, key
, sizeof(tkey
));
732 if ((gcryerrno
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
733 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
734 gcry_cipher_close(gh
);
740 if ((gcryerrno
= gcry_cipher_setkey(gh
, key
, gcrykeysize
))) {
741 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
742 gcry_cipher_close(gh
);
748 if (decrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
749 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
750 gcry_cipher_close(gh
);
756 if ((gcryerrno
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
757 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
758 gcry_cipher_close(gh
);
765 if ((gcryerrno
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
766 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
767 gcry_cipher_close(gh
);
773 if (decrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
774 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
775 gcry_cipher_close(gh
);
782 gcry_cipher_close(gh
);
785 if (g_strncasecmp(inbuf
, "<?xml version=\"1.0\"?>", 21) != 0) {
794 static gboolean
get_input(const gchar
*filename
, guchar
*key
, gint iter
)
796 gchar buf
[LINE_MAX
], *p
;
797 struct termios told
, tnew
;
801 gint tty
= isatty(STDIN_FILENO
);
803 if ((fd
= open_file(filename
, &st
)) == -1) {
804 warn("%s", filename
);
808 if (st
.st_size
== 0) {
809 fprintf(stderr
, "Skipping empty file '%s'.\n", filename
);
815 if (tcgetattr(STDIN_FILENO
, &told
) == -1)
816 err(EXIT_FAILURE
, "tcgetattr()");
818 memcpy(&tnew
, &told
, sizeof(struct termios
));
819 tnew
.c_lflag
&= ~(ECHO
);
820 tnew
.c_lflag
|= ICANON
|ECHONL
;
825 if (tcsetattr(STDIN_FILENO
, TCSANOW
, &tnew
) == -1) {
826 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
827 err(EXIT_FAILURE
, "tcsetattr()");
831 printf("Password for '%s': ", filename
);
833 if ((p
= fgets(buf
, sizeof(buf
), stdin
)) == NULL
) {
835 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
842 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
844 p
[strlen(p
) - 1] = 0;
847 fprintf(stderr
, "Skipping.\n");
852 gcry_md_hash_buffer(GCRY_MD_SHA256
, key
, p
, strlen(p
));
853 memset(buf
, 0, sizeof(buf
));
855 if (try_xml_decrypt(fd
, st
, key
, iter
) == FALSE
) {
857 fprintf(stderr
, "Invalid password. Skipping file.\n");
861 fprintf(stderr
, "Invalid password.\n");
869 gint
cache_file_count()
876 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
877 memcpy(&f
, p
, sizeof(file_cache_t
));
882 p
+= sizeof(file_cache_t
);
883 len
+= sizeof(file_cache_t
);
885 if (len
+ sizeof(file_cache_t
) > cache_size
)
892 gboolean
cache_add_file(const guchar
*md5file
, const guchar
*shakey
)
896 gint nfiles
= cache_file_count();
900 * Make sure there is enough secure memory.
902 if (!md5file
|| (nfiles
+ 1) * sizeof(file_cache_t
) > cache_size
)
906 * Find the first available "slot".
908 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
909 memcpy(&f
, p
, sizeof(file_cache_t
));
911 if (f
.used
== FALSE
) {
912 memcpy(&f
.filename
, md5file
, sizeof(f
.filename
));
915 memcpy(&f
.key
, shakey
, sizeof(f
.key
));
918 memcpy(p
, &f
, sizeof(file_cache_t
));
922 p
+= sizeof(file_cache_t
);
923 len
+= sizeof(file_cache_t
);
925 if (len
+ sizeof(file_cache_t
) > cache_size
)
932 int main(int argc
, char *argv
[])
935 struct sockaddr_un addr
;
936 struct passwd
*pw
= getpwuid(getuid());
938 gchar
*socketpath
= NULL
, *socketdir
, *socketname
= NULL
;
939 gchar
*socketarg
= NULL
;
940 gchar
*datadir
= NULL
;
945 gchar
**cache_push
= NULL
;
949 #ifdef HAVE_SETRLIMIT
952 rl
.rlim_cur
= rl
.rlim_max
= 0;
954 if (setrlimit(RLIMIT_CORE
, &rl
) != 0)
955 err(EXIT_FAILURE
, "setrlimit()");
959 rcfile
= g_strdup_printf("%s/.pwmdrc", pw
->pw_dir
);
961 if ((page_size
= sysconf(_SC_PAGESIZE
)) == -1)
962 err(EXIT_FAILURE
, "sysconf()");
964 cache_size
= page_size
;
968 * Default to using mlockall().
973 while ((opt
= getopt(argc
, argv
, "hvf:")) != EOF
) {
977 rcfile
= g_strdup(optarg
);
980 printf("%s\n%s\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
988 if ((kf
= parse_rcfile(rcfile
)) == NULL
)
991 g_key_file_set_list_separator(kf
, ',');
993 if ((p
= g_key_file_get_string(kf
, "default", "socket_path", NULL
)) == NULL
)
994 errx(EXIT_FAILURE
, "%s: socket_path not defined", rcfile
);
998 snprintf(buf
, sizeof(buf
), "%s%s", g_get_home_dir(), p
--);
1000 socketarg
= g_strdup(buf
);
1005 if ((p
= g_key_file_get_string(kf
, "default", "data_directory", NULL
)) == NULL
)
1006 errx(EXIT_FAILURE
, "%s: data_directory not defined", rcfile
);
1010 snprintf(buf
, sizeof(buf
), "%s%s", g_get_home_dir(), p
--);
1012 datadir
= g_strdup(buf
);
1017 if (g_key_file_has_key(kf
, "default", "cache_size", NULL
) == TRUE
) {
1018 cache_size
= g_key_file_get_integer(kf
, "default", "cache_size", NULL
);
1020 if (cache_size
< page_size
|| cache_size
% page_size
)
1021 errx(EXIT_FAILURE
, "cache size must be in multiples of %li.", page_size
);
1024 if (g_key_file_has_key(kf
, "default", "iterations", NULL
) == TRUE
)
1025 iter
= g_key_file_get_integer(kf
, "default", "iterations", NULL
);
1027 #ifdef HAVE_MLOCKALL
1028 if (g_key_file_has_key(kf
, "default", "disable_mlockall", NULL
) == TRUE
)
1029 use_mlock
= g_key_file_get_integer(kf
, "default", "disable_mlockall", NULL
);
1032 if (g_key_file_has_key(kf
, "default", "log_path", NULL
) == TRUE
) {
1033 if (g_key_file_has_key(kf
, "default", "enable_logging", NULL
) == TRUE
) {
1034 n
= g_key_file_get_boolean(kf
, "default", "enable_logging", NULL
);
1037 p
= g_key_file_get_string(kf
, "default", "log_path", NULL
);
1041 snprintf(buf
, sizeof(buf
), "%s%s", g_get_home_dir(), p
--);
1043 logfile
= g_strdup(buf
);
1051 if (g_key_file_has_key(kf
, "default", "cache_push", NULL
) == TRUE
)
1052 cache_push
= g_key_file_get_string_list(kf
, "default", "cache_push", NULL
, NULL
);
1054 g_key_file_free(kf
);
1056 if (strchr(socketarg
, '/') == NULL
) {
1057 socketdir
= g_get_current_dir();
1058 socketname
= g_strdup(socketarg
);
1059 socketpath
= g_strdup_printf("%s/%s", socketdir
, socketname
);
1062 socketname
= g_strdup(strrchr(socketarg
, '/'));
1064 socketarg
[strlen(socketarg
) - strlen(socketname
) -1] = 0;
1065 socketdir
= g_strdup(socketarg
);
1066 socketpath
= g_strdup_printf("%s/%s", socketdir
, socketname
);
1069 snprintf(buf
, sizeof(buf
), "%s", datadir
);
1071 if (mkdir(buf
, 0700) == -1 && errno
!= EEXIST
)
1072 err(EXIT_FAILURE
, "%s", buf
);
1074 #ifdef MMAP_ANONYMOUS_SHARED
1075 if ((shm_data
= mmap(NULL
, cache_size
, PROT_READ
|PROT_WRITE
,
1076 MAP_SHARED
|MAP_ANONYMOUS
, -1, 0)) == NULL
) {
1077 err(EXIT_FAILURE
, "mmap()");
1080 snprintf(buf
, sizeof(buf
), "pwmd.%i", pw
->pw_uid
);
1082 if ((fd
= shm_open(buf
, O_CREAT
|O_RDWR
|O_EXCL
, 0600)) == -1)
1083 err(EXIT_FAILURE
, "shm_open(): %s", buf
);
1086 * Should be enough for the file cache.
1088 if (ftruncate(fd
, cache_size
) == -1)
1089 err(EXIT_FAILURE
, "ftruncate()");
1091 if ((shm_data
= mmap(NULL
, cache_size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
,
1094 err(EXIT_FAILURE
, "mmap()");
1100 if (mlock(shm_data
, cache_size
) == -1)
1104 * bind() doesn't like the full pathname of the socket or any non alphanum
1105 * characters so change to the directory where the socket is wanted then
1106 * create it then change to datadir.
1108 if (chdir(socketdir
))
1109 err(EXIT_FAILURE
, "%s", socketdir
);
1113 if ((sfd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) == -1)
1114 err(EXIT_FAILURE
, "socket()");
1116 addr
.sun_family
= AF_UNIX
;
1117 snprintf(addr
.sun_path
, sizeof(addr
.sun_path
), "%s", socketname
);
1118 g_free(--socketname
);
1120 if (bind(sfd
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr
)) == -1)
1121 err(EXIT_FAILURE
, "bind()");
1123 if (chdir(datadir
)) {
1126 err(EXIT_FAILURE
, "%s", datadir
);
1132 // FIXME broken is the password is wrong.
1134 * Set the cache entry for a file. Prompts for the password.
1140 for (opt
= 0; cache_push
[opt
]; opt
++) {
1141 p
= cache_push
[opt
];
1149 md5file
= gcry_malloc(16);
1150 key
= gcry_malloc(gcrykeysize
);
1151 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, p
, strlen(p
));
1153 if (access(p
, R_OK
|W_OK
) != 0) {
1154 if (errno
!= ENOENT
) {
1156 err(EXIT_FAILURE
, "%s", p
);
1163 if (get_input(p
, key
, iter
) == FALSE
) {
1169 if (cache_add_file(md5file
, key
) == FALSE
) {
1171 errx(EXIT_FAILURE
, "%s: couldn't add file (cache_size?)", p
);
1174 fprintf(stderr
, "Added.\n");
1179 g_strfreev(cache_push
);
1180 fprintf(stderr
, "Done! Daemonizing...\n");
1185 if (listen(sfd
, 0) == -1)
1186 err(EXIT_FAILURE
, "listen()");
1188 signal(SIGCHLD
, catchsig
);
1189 signal(SIGTERM
, catchsig
);
1190 signal(SIGINT
, catchsig
);
1191 signal(SIGHUP
, catchsig
);
1192 log_write("%s starting: %li slots available", PACKAGE_STRING
, cache_size
/ sizeof(file_cache_t
));
1195 socklen_t slen
= sizeof(struct sockaddr_un
);
1196 struct sockaddr_un raddr
;
1199 if ((fd
= accept(sfd
, (struct sockaddr_un
*)&raddr
, &slen
)) == -1) {
1201 log_write("accept(): %s", strerror(errno
));
1206 switch ((pid
= fork())) {
1208 log_write("fork(): %s", strerror(errno
));
1217 log_write("new connection: fd=%i, pid=%i", fd
, pid
);
1223 if (munmap(shm_data
, cache_size
) == -1)
1224 log_write("munmap(): %s", strerror(errno
));
1226 #ifndef MMAP_ANONYMOUS_SHARED
1227 if (shm_unlink(buf
) == -1)
1228 log_write("shm_unlink(): %s: %s", buf
, strerror(errno
));
1231 log_write("pwmd exiting normally");