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>
54 #include "pwmd_error.h"
58 static void reload_rcfile()
60 log_write("reloading configuration file '%s'", rcfile
);
61 g_key_file_free(keyfileh
);
62 keyfileh
= parse_rcfile(0);
65 gpg_error_t
send_syserror(assuan_context_t ctx
, int e
)
67 gpg_error_t n
= gpg_error_from_errno(e
);
69 return assuan_set_error(ctx
, n
, gpg_strerror(n
));
72 gpg_error_t
send_error(assuan_context_t ctx
, gpg_error_t pwmd_errno
)
74 gpg_err_code_t n
= gpg_err_code(pwmd_errno
);
75 gpg_error_t code
= gpg_err_make(GPG_ERR_SOURCE_USER_1
, n
);
81 fprintf(stderr
, "%s\n", pwmd_strerror(pwmd_errno
));
85 return assuan_set_error(ctx
, code
, pwmd_strerror(pwmd_errno
));
88 void log_write(const gchar
*fmt
, ...)
97 if ((!logfile
&& !isatty(STDERR_FILENO
)) || !fmt
)
101 if ((fd
= open(logfile
, O_WRONLY
|O_CREAT
|O_APPEND
, 0600)) == -1) {
108 g_vasprintf(&args
, fmt
, ap
);
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
);
117 write(fd
, line
, strlen(line
));
122 if (isatty(STDERR_FILENO
))
123 fprintf(stderr
, "%s", line
);
129 static void catchsig(gint sig
)
134 log_write("caught signal %i (%s)", sig
, strsignal(sig
));
141 cache_clear(NULL
, 2);
145 cache_adjust_timer();
149 waitpid(-1, &status
, 0);
152 log_write("clearing file cache");
153 cache_clear(NULL
, 2);
157 shutdown(sfd
, SHUT_RDWR
);
163 static void usage(gchar
*pn
)
166 "Usage: %s [-hvDb] [-f <rcfile>] [-I <filename>] [file1] [...]\n"
167 " -b run as a background process\n"
168 " -f load the specified rcfile (~/.pwmd/config)\n"
169 " -I import an XML file and write the encrypted data to stdout\n"
170 " -D disable use of the LIST and DUMP commands\n"
172 " -h this help text\n",
177 static int gcry_SecureCheck(const void *ptr
)
182 static void setup_gcrypt()
184 gcry_check_version(NULL
);
186 gcry_set_allocation_handler(xmalloc
, xmalloc
, gcry_SecureCheck
, xrealloc
,
189 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256
, GCRYCTL_TEST_ALGO
, NULL
,
191 errx(EXIT_FAILURE
, "AES cipher not supported");
193 gcry_cipher_algo_info(GCRY_CIPHER_AES256
, GCRYCTL_GET_KEYLEN
, NULL
, &gcrykeysize
);
194 gcry_cipher_algo_info(GCRY_CIPHER_AES256
, GCRYCTL_GET_BLKLEN
, NULL
, &gcryblocksize
);
198 * Called every time a connection is made.
200 static void doit(int fd
)
202 assuan_context_t ctx
;
204 struct client_s
*cl
= g_malloc0(sizeof(struct client_s
));
206 signal(SIGCHLD
, SIG_DFL
);
207 signal(SIGHUP
, SIG_DFL
);
208 signal(SIGINT
, SIG_DFL
);
209 signal(SIGALRM
, SIG_DFL
);
211 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT
);
212 assuan_set_malloc_hooks(xmalloc
, xrealloc
, xfree
);
213 xmlMemSetup(xfree
, xmalloc
, xrealloc
, xstrdup
);
217 if (use_mlock
&& mlockall(MCL_FUTURE
) == -1) {
218 log_write("mlockall(): %s", strerror(errno
));
223 rc
= assuan_init_socket_server_ext(&ctx
, fd
, 2);
226 log_write("failed to initialize assuan server: %s", gpg_strerror(rc
));
230 assuan_set_pointer(ctx
, cl
);
231 rc
= register_commands(ctx
);
234 log_write("failed to register assuan commands: %s", gpg_strerror(rc
));
241 * It would be nice if there were an assuan_register_pre_cmd_notify().
242 * That way we can see if the file has been modified before calling the
245 rc
= assuan_accept(ctx
);
248 log_write("assuan_accept() failed: %s", gpg_strerror(rc
));
252 rc
= assuan_process(ctx
);
255 log_write("assuan_process() failed: %s", gpg_strerror(rc
));
258 assuan_deinit_server(ctx
);
259 log_write("exiting");
264 * Make sure all settings are set to either the specified setting or a
267 static void set_rcfile_defaults(GKeyFile
*kf
)
271 if (g_key_file_has_key(kf
, "default", "socket_path", NULL
) == FALSE
) {
272 snprintf(buf
, sizeof(buf
), "~/.pwmd/socket");
273 g_key_file_set_string(kf
, "default", "socket_path", buf
);
276 if (g_key_file_has_key(kf
, "default", "data_directory", NULL
) == FALSE
) {
277 snprintf(buf
, sizeof(buf
), "~/.pwmd/data");
278 g_key_file_set_string(kf
, "default", "data_directory", buf
);
281 if (g_key_file_has_key(kf
, "default", "log_path", NULL
) == FALSE
) {
282 snprintf(buf
, sizeof(buf
), "~/.pwmd/log");
283 g_key_file_set_string(kf
, "default", "log_path", buf
);
286 if (g_key_file_has_key(kf
, "default", "enable_logging", NULL
) == FALSE
)
287 g_key_file_set_boolean(kf
, "default", "enable_logging", FALSE
);
289 if (g_key_file_has_key(kf
, "default", "cache_size", NULL
) == FALSE
)
290 g_key_file_set_integer(kf
, "default", "cache_size", cache_size
);
292 if (g_key_file_has_key(kf
, "default", "disable_mlockall", NULL
) == FALSE
)
293 g_key_file_set_boolean(kf
, "default", "disable_mlockall", FALSE
);
295 if (g_key_file_has_key(kf
, "default", "cache_timeout", NULL
) == FALSE
)
296 g_key_file_set_integer(kf
, "default", "cache_timeout", -1);
298 if (g_key_file_has_key(kf
, "default", "iterations", NULL
) == FALSE
)
299 g_key_file_set_integer(kf
, "default", "iterations", 0);
301 if (g_key_file_has_key(kf
, "default", "disable_list_and_dump", NULL
) == FALSE
)
302 g_key_file_set_boolean(kf
, "default", "disable_list_and_dump", FALSE
);
304 if (g_key_file_has_key(kf
, "default", "iteration_progress", NULL
) == FALSE
)
305 g_key_file_set_integer(kf
, "default", "iteration_progress", 0);
308 static GKeyFile
*parse_rcfile(int cmdline
)
310 GKeyFile
*kf
= g_key_file_new();
311 GError
*error
= NULL
;
313 if (g_key_file_load_from_file(kf
, rcfile
, G_KEY_FILE_NONE
, &error
) == FALSE
) {
314 warnx("%s: %s", rcfile
, error
->message
);
319 if (error
->code
== G_FILE_ERROR_NOENT
) {
320 g_clear_error(&error
);
321 set_rcfile_defaults(kf
);
325 g_clear_error(&error
);
329 set_rcfile_defaults(kf
);
334 static gboolean
try_xml_decrypt(gint fd
, struct stat st
, guchar
*key
)
340 guchar tkey
[gcrykeysize
];
342 struct file_header_s
{
344 guchar iv
[gcryblocksize
];
347 if ((gcryerrno
= gcry_cipher_open(&gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0))) {
348 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
352 lseek(fd
, 0, SEEK_SET
);
353 insize
= st
.st_size
- sizeof(struct file_header_s
);
354 iv
= gcry_malloc(gcryblocksize
);
355 read(fd
, &file_header
, sizeof(struct file_header_s
));
356 memcpy(iv
, &file_header
.iv
, sizeof(file_header
.iv
));
357 inbuf
= gcry_malloc(insize
);
358 read(fd
, inbuf
, insize
);
359 memcpy(tkey
, key
, sizeof(tkey
));
362 if ((gcryerrno
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
363 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
364 gcry_cipher_close(gh
);
370 if ((gcryerrno
= gcry_cipher_setkey(gh
, key
, gcrykeysize
))) {
371 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
372 gcry_cipher_close(gh
);
378 if (decrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
379 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
380 gcry_cipher_close(gh
);
386 if ((gcryerrno
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
387 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
388 gcry_cipher_close(gh
);
394 iter
= file_header
.iter
;
397 if ((gcryerrno
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
398 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
399 gcry_cipher_close(gh
);
405 if (decrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
406 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
407 gcry_cipher_close(gh
);
414 gcry_cipher_close(gh
);
417 if (g_strncasecmp(inbuf
, "<?xml version=\"1.0\"?>", 21) != 0) {
426 static gchar
*get_password(const gchar
*prompt
)
428 gchar buf
[LINE_MAX
], *p
;
429 struct termios told
, tnew
;
432 if (tcgetattr(STDIN_FILENO
, &told
) == -1)
433 err(EXIT_FAILURE
, "tcgetattr()");
435 memcpy(&tnew
, &told
, sizeof(struct termios
));
436 tnew
.c_lflag
&= ~(ECHO
);
437 tnew
.c_lflag
|= ICANON
|ECHONL
;
439 if (tcsetattr(STDIN_FILENO
, TCSANOW
, &tnew
) == -1) {
440 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
441 err(EXIT_FAILURE
, "tcsetattr()");
444 fprintf(stderr
, "%s", prompt
);
446 if ((p
= fgets(buf
, sizeof(buf
), stdin
)) == NULL
) {
447 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
451 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
452 p
[strlen(p
) - 1] = 0;
457 key
= gcry_malloc(strlen(p
) + 1);
458 sprintf(key
, "%s", p
);
459 memset(&buf
, 0, sizeof(buf
));
463 static gboolean
do_try_xml_decrypt(const gchar
*filename
, guchar
*key
)
468 if ((fd
= open_file(filename
, &st
)) == -1) {
469 warn("%s", filename
);
473 if (st
.st_size
== 0) {
474 warnx("%s: skipping empty file", filename
);
479 if (try_xml_decrypt(fd
, st
, key
) == FALSE
) {
488 static gboolean
get_input(const gchar
*filename
, guchar
*key
)
494 if ((prompt
= xmalloc(strlen(filename
) + strlen("Password for '") + 4)) == NULL
) {
499 sprintf(prompt
, "Password for '%s': ", filename
);
502 if ((password
= get_password(prompt
)) == NULL
) {
503 warnx("%s: skipping file", filename
);
508 gcry_md_hash_buffer(GCRY_MD_SHA256
, key
, password
, strlen(password
));
511 if (do_try_xml_decrypt(filename
, key
) == FALSE
) {
513 warnx("%s: invalid password, skipping", filename
);
518 warnx("%s: invalid password", filename
);
527 static gboolean
xml_import(const gchar
*filename
, gint iter
)
537 guchar shakey
[gcrykeysize
];
542 if (use_mlock
&& mlockall(MCL_FUTURE
) == -1)
543 err(EXIT_FAILURE
, "mlockall()");
546 if (stat(filename
, &st
) == -1) {
547 warn("%s", filename
);
551 xmlMemSetup(xfree
, xmalloc
, xrealloc
, xstrdup
);
554 if ((gcryerrno
= gcry_cipher_open(&gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0))) {
555 send_error(NULL
, gcryerrno
);
556 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
560 if ((key
= get_password("New password: ")) == NULL
) {
561 fprintf(stderr
, "Invalid password.\n");
565 if ((key2
= get_password("Verify password: ")) == NULL
) {
566 fprintf(stderr
, "Passwords do not match.\n");
571 if (strcmp(key
, key2
) != 0) {
572 fprintf(stderr
, "Passwords do not match.\n");
580 if ((fd
= open(filename
, O_RDONLY
)) == -1) {
582 warn("%s", filename
);
586 if ((xmlbuf
= gcry_malloc(st
.st_size
+1)) == NULL
) {
589 warnx("gcry_malloc() failed");
593 read(fd
, xmlbuf
, st
.st_size
);
595 xmlbuf
[st
.st_size
] = 0;
598 * Make sure the document validates.
600 if ((doc
= xmlReadDoc(xmlbuf
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
)) == NULL
) {
601 warnx("xmlReadDoc() failed");
609 xmlDocDumpMemory(doc
, &xml
, &len
);
611 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, key
, strlen(key
));
613 error
= do_xml_encrypt(NULL
, gh
, NULL
, xml
, len
, shakey
, iter
);
616 memset(shakey
, 0, sizeof(shakey
));
618 warnx("%s", gpg_strerror(error
));
622 memset(shakey
, 0, sizeof(shakey
));
627 gchar
*get_key_file_string(const gchar
*section
, const gchar
*what
)
630 GError
*gerror
= NULL
;
632 if (g_key_file_has_key(keyfileh
, section
, what
, NULL
) == TRUE
) {
633 val
= g_key_file_get_string(keyfileh
, section
, what
, &gerror
);
636 log_write("%s(%i): %s", __FILE__
, __LINE__
, gerror
->message
);
637 g_clear_error(&gerror
);
641 if (g_key_file_has_key(keyfileh
, "default", what
, NULL
) == TRUE
) {
642 val
= g_key_file_get_string(keyfileh
, "default", what
, &gerror
);
645 log_write("%s(%i): %s", __FILE__
, __LINE__
, gerror
->message
);
646 g_clear_error(&gerror
);
654 gint
get_key_file_integer(const gchar
*section
, const gchar
*what
)
657 GError
*gerror
= NULL
;
659 if (g_key_file_has_key(keyfileh
, section
, what
, NULL
) == TRUE
) {
660 val
= g_key_file_get_integer(keyfileh
, section
, what
, &gerror
);
663 log_write("%s(%i): %s", __FILE__
, __LINE__
, gerror
->message
);
664 g_clear_error(&gerror
);
668 if (g_key_file_has_key(keyfileh
, "default", what
, NULL
) == TRUE
) {
669 val
= g_key_file_get_integer(keyfileh
, "default", what
, &gerror
);
672 log_write("%s(%i): %s", __FILE__
, __LINE__
, gerror
->message
);
673 g_clear_error(&gerror
);
681 gboolean
get_key_file_boolean(const gchar
*section
, const gchar
*what
)
683 gboolean val
= FALSE
;
684 GError
*gerror
= NULL
;
686 if (g_key_file_has_key(keyfileh
, section
, what
, NULL
) == TRUE
) {
687 val
= g_key_file_get_boolean(keyfileh
, section
, what
, &gerror
);
690 log_write("%s(%i): %s", __FILE__
, __LINE__
, gerror
->message
);
691 g_clear_error(&gerror
);
695 if (g_key_file_has_key(keyfileh
, "default", what
, NULL
) == TRUE
) {
696 val
= g_key_file_get_boolean(keyfileh
, "default", what
, &gerror
);
699 log_write("%s(%i): %s", __FILE__
, __LINE__
, gerror
->message
);
700 g_clear_error(&gerror
);
708 gchar
*expand_homedir(gchar
*str
)
715 snprintf(buf
, sizeof(buf
), "%s%s", g_get_home_dir(), p
--);
716 return g_strdup(buf
);
719 return g_strdup(str
);
722 static gchar
*_getline(const gchar
*file
)
725 gchar buf
[LINE_MAX
], *p
;
728 if ((fp
= fopen(file
, "r")) == NULL
) {
733 if ((p
= fgets(buf
, sizeof(buf
), fp
)) == NULL
) {
734 warnx("%s: empty file?", file
);
739 buf
[strlen(buf
) - 1] = 0;
740 str
= gcry_malloc(strlen(p
) + 1);
741 memcpy(str
, p
, strlen(p
));
743 memset(&buf
, 0, sizeof(buf
));
747 static gboolean
parse_keyfile_key()
754 groups
= g_key_file_get_groups(keyfileh
, &n
);
756 for (p
= groups
; *p
; p
++) {
757 GError
*error
= NULL
;
759 if (g_key_file_has_key(keyfileh
, *p
, "key", &error
) == TRUE
) {
760 str
= g_key_file_get_string(keyfileh
, *p
, "key", &error
);
764 warnx("%s", error
->message
);
765 g_clear_error(&error
);
771 do_cache_push(*p
, str
);
777 warnx("%s", error
->message
);
778 g_clear_error(&error
);
782 if (g_key_file_has_key(keyfileh
, *p
, "key_file", &error
) == TRUE
) {
784 gchar
*file
= g_key_file_get_string(keyfileh
, *p
, "key_file", &error
);
788 warnx("%s", error
->message
);
789 g_clear_error(&error
);
795 t
= expand_homedir(file
);
799 if ((str
= _getline(file
)) == NULL
) {
805 do_cache_push(*p
, str
);
811 warnx("%s", error
->message
);
812 g_clear_error(&error
);
820 static gboolean
do_cache_push(const gchar
*filename
, const gchar
*password
)
825 const gchar
*p
= filename
;
833 if (valid_filename(p
) == FALSE
) {
834 warnx("%s: invalid characters in filename", p
);
838 md5file
= gcry_malloc(16);
839 key
= gcry_malloc(gcrykeysize
);
840 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, p
, strlen(p
));
842 if (cache_iscached(md5file
) == TRUE
) {
843 warnx("%s: file already cached, skipping", p
);
849 if (access(p
, R_OK
|W_OK
) != 0) {
853 if (errno
!= ENOENT
) {
863 if (get_input(p
, key
) == FALSE
) {
870 gcry_md_hash_buffer(GCRY_MD_SHA256
, key
, password
, strlen(password
));
872 if (do_try_xml_decrypt(filename
, key
) == FALSE
) {
873 warnx("%s: invalid password, skipping", filename
);
880 if (cache_add_file(md5file
, key
) == FALSE
) {
881 warnx("%s: %s", p
, pwmd_strerror(EPWMD_MAX_SLOTS
));
887 timeout
= get_key_file_integer(p
, "cache_timeout");
888 cache_set_timeout(md5file
, timeout
);
889 warnx("%s: file added to the cache", filename
);
895 int main(int argc
, char *argv
[])
898 struct sockaddr_un addr
;
899 struct passwd
*pw
= getpwuid(getuid());
901 #ifndef MMAP_ANONYMOUS_SHARED
902 gchar shm_path
[PATH_MAX
];
904 gchar
*socketpath
= NULL
, *socketdir
, *socketname
= NULL
;
905 gchar
*socketarg
= NULL
;
906 gchar
*datadir
= NULL
;
910 gchar
**cache_push
= NULL
;
912 gchar
*import
= NULL
;
913 gint default_timeout
;
914 gint rcfile_spec
= 0;
915 gint estatus
= EXIT_FAILURE
;
916 GMemVTable mtable
= { xmalloc
, xrealloc
, xfree
, xcalloc
, NULL
, NULL
};
918 gboolean secure
= FALSE
;
922 #ifdef HAVE_SETRLIMIT
925 rl
.rlim_cur
= rl
.rlim_max
= 0;
927 if (setrlimit(RLIMIT_CORE
, &rl
) != 0)
928 err(EXIT_FAILURE
, "setrlimit()");
932 g_mem_set_vtable(&mtable
);
933 snprintf(buf
, sizeof(buf
), "%s/.pwmd", pw
->pw_dir
);
935 if (mkdir(buf
, 0700) == -1 && errno
!= EEXIST
)
936 err(EXIT_FAILURE
, "%s", buf
);
938 snprintf(buf
, sizeof(buf
), "%s/.pwmd/data", pw
->pw_dir
);
940 if (mkdir(buf
, 0700) == -1 && errno
!= EEXIST
)
941 err(EXIT_FAILURE
, "%s", buf
);
943 rcfile
= g_strdup_printf("%s/.pwmd/config", pw
->pw_dir
);
945 if ((page_size
= sysconf(_SC_PAGESIZE
)) == -1)
946 err(EXIT_FAILURE
, "sysconf()");
948 cache_size
= page_size
;
952 * Default to using mlockall().
957 while ((opt
= getopt(argc
, argv
, "bI:hvf:D")) != EOF
) {
970 rcfile
= g_strdup(optarg
);
974 printf("%s\n%s\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
982 if ((keyfileh
= parse_rcfile(rcfile_spec
)) == NULL
)
985 g_key_file_set_list_separator(keyfileh
, ',');
987 if ((p
= g_key_file_get_string(keyfileh
, "default", "socket_path", NULL
)) == NULL
)
988 errx(EXIT_FAILURE
, "%s: socket_path not defined", rcfile
);
992 snprintf(buf
, sizeof(buf
), "%s%s", g_get_home_dir(), p
--);
994 socketarg
= g_strdup(buf
);
999 if ((p
= g_key_file_get_string(keyfileh
, "default", "data_directory", NULL
)) == NULL
)
1000 errx(EXIT_FAILURE
, "%s: data_directory not defined", rcfile
);
1002 datadir
= expand_homedir(p
);
1005 if (secure
== FALSE
&& g_key_file_has_key(keyfileh
, "default", "disable_list_and_dump", NULL
) == TRUE
) {
1006 n
= g_key_file_get_boolean(keyfileh
, "default", "disable_list_and_dump", NULL
);
1007 disable_list_and_dump
= n
;
1010 disable_list_and_dump
= secure
;
1012 if (g_key_file_has_key(keyfileh
, "default", "cache_timeout", NULL
) == TRUE
)
1013 default_timeout
= g_key_file_get_integer(keyfileh
, "default", "cache_timeout", NULL
);
1015 default_timeout
= -1;
1017 if (g_key_file_has_key(keyfileh
, "default", "cache_size", NULL
) == TRUE
) {
1018 cache_size
= g_key_file_get_integer(keyfileh
, "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(keyfileh
, "default", "iterations", NULL
) == TRUE
)
1025 iter
= g_key_file_get_integer(keyfileh
, "default", "iterations", NULL
);
1027 #ifdef HAVE_MLOCKALL
1028 if (g_key_file_has_key(keyfileh
, "default", "disable_mlockall", NULL
) == TRUE
)
1029 use_mlock
= g_key_file_get_integer(keyfileh
, "default", "disable_mlockall", NULL
);
1032 if (g_key_file_has_key(keyfileh
, "default", "log_path", NULL
) == TRUE
) {
1033 if (g_key_file_has_key(keyfileh
, "default", "enable_logging", NULL
) == TRUE
) {
1034 n
= g_key_file_get_boolean(keyfileh
, "default", "enable_logging", NULL
);
1037 p
= g_key_file_get_string(keyfileh
, "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(keyfileh
, "default", "cache_push", NULL
) == TRUE
)
1052 cache_push
= g_key_file_get_string_list(keyfileh
, "default", "cache_push", NULL
, NULL
);
1054 if (argc
!= optind
) {
1056 ptotal
= g_strv_length(cache_push
);
1058 for (; optind
< argc
; optind
++)
1059 append_to_array(&cache_push
, &ptotal
, argv
[optind
]);
1062 if (strchr(socketarg
, '/') == NULL
) {
1063 socketdir
= g_get_current_dir();
1064 socketname
= g_strdup(socketarg
);
1065 socketpath
= g_strdup_printf("%s/%s", socketdir
, socketname
);
1068 socketname
= g_strdup(strrchr(socketarg
, '/'));
1070 socketarg
[strlen(socketarg
) - strlen(socketname
) -1] = 0;
1071 socketdir
= g_strdup(socketarg
);
1072 socketpath
= g_strdup_printf("%s/%s", socketdir
, socketname
);
1075 #ifdef MMAP_ANONYMOUS_SHARED
1076 if ((shm_data
= mmap(NULL
, cache_size
, PROT_READ
|PROT_WRITE
,
1077 #ifdef MMAP_ANONYMOUS
1078 MAP_SHARED
|MAP_ANONYMOUS
, -1, 0)) == NULL
) {
1080 MAP_SHARED
|MAP_ANON
, -1, 0)) == NULL
) {
1082 err(EXIT_FAILURE
, "mmap()");
1085 snprintf(shm_path
, sizeof(shm_path
), "/pwmd.%i", pw
->pw_uid
);
1087 if ((fd
= shm_open(shm_path
, O_CREAT
|O_RDWR
|O_EXCL
, 0600)) == -1)
1088 err(EXIT_FAILURE
, "shm_open(): %s", shm_path
);
1091 * Should be enough for the file cache.
1093 if (ftruncate(fd
, cache_size
) == -1) {
1094 warn("ftruncate()");
1095 shm_unlink(shm_path
);
1099 if ((shm_data
= mmap(NULL
, cache_size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
,
1102 shm_unlink(shm_path
);
1109 if (mlock(shm_data
, cache_size
) == -1)
1112 memset(shm_data
, 0, cache_size
);
1116 opt
= xml_import(import
, iter
);
1119 if (munmap(shm_data
, cache_size
) == -1)
1120 log_write("munmap(): %s", strerror(errno
));
1122 #ifndef MMAP_ANONYMOUS_SHARED
1123 if (shm_unlink(shm_path
) == -1)
1124 log_write("shm_unlink(): %s: %s", shm_path
, strerror(errno
));
1127 exit((opt
) == FALSE
? EXIT_FAILURE
: EXIT_SUCCESS
);
1130 getcwd(buf
, sizeof(buf
));
1133 * bind() doesn't like the full pathname of the socket or any non alphanum
1134 * characters so change to the directory where the socket is wanted then
1135 * create it then change to datadir.
1137 if (chdir(socketdir
)) {
1138 warn("%s", socketdir
);
1144 if ((sfd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) == -1) {
1149 addr
.sun_family
= AF_UNIX
;
1150 snprintf(addr
.sun_path
, sizeof(addr
.sun_path
), "%s", socketname
);
1151 g_free(--socketname
);
1153 if (bind(sfd
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr
)) == -1) {
1156 if (errno
== EADDRINUSE
)
1157 warnx("Either there is another pwmd running or '%s' is a \n"
1158 "stale socket. Please remove it manually.", socketpath
);
1164 if (chdir(datadir
)) {
1165 warn("%s", datadir
);
1173 if (parse_keyfile_key() == FALSE
)
1177 * Set the cache entry for a file. Prompts for the password.
1180 for (opt
= 0; cache_push
[opt
]; opt
++)
1181 do_cache_push(cache_push
[opt
], NULL
);
1183 g_strfreev(cache_push
);
1184 warnx("Done! %s", background
? "Daemonizing..." : "Waiting for connections...");
1189 if (listen(sfd
, 0) == -1) {
1194 signal(SIGCHLD
, catchsig
);
1195 signal(SIGTERM
, catchsig
);
1196 signal(SIGINT
, catchsig
);
1197 signal(SIGHUP
, catchsig
);
1198 signal(SIGALRM
, catchsig
);
1199 signal(SIGABRT
, catchsig
);
1200 signal(SIGUSR1
, catchsig
);
1218 log_write("%s started: %li slots available", PACKAGE_STRING
, cache_size
/ sizeof(file_cache_t
));
1221 socklen_t slen
= sizeof(struct sockaddr_un
);
1222 struct sockaddr_un raddr
;
1225 if ((fd
= accept(sfd
, (struct sockaddr
*)&raddr
, &slen
)) == -1) {
1229 if (errno
== EAGAIN
)
1232 log_write("accept(): %s", strerror(errno
));
1236 switch ((pid
= fork())) {
1238 log_write("fork(): %s", strerror(errno
));
1247 log_write("new connection: pid=%i", pid
);
1251 estatus
= EXIT_SUCCESS
;
1256 if (socketpath
&& do_unlink
) {
1261 g_key_file_free(keyfileh
);
1263 memset(shm_data
, 0, cache_size
);
1265 if (munmap(shm_data
, cache_size
) == -1)
1266 log_write("munmap(): %s", strerror(errno
));
1268 #ifndef MMAP_ANONYMOUS_SHARED
1269 if (shm_unlink(shm_path
) == -1)
1270 log_write("shm_unlink(): %s: %s", shm_path
, strerror(errno
));
1273 if (estatus
== EXIT_SUCCESS
)
1274 log_write("pwmd exiting normally");