* mailbox/cfg_driver.c (mu_cfg_tree_reduce): Format parse tree
before scanning the tree. * mailbox/cfg_parser.y (block rule): Accept empty blocks. (parse_param): bail out if callback is not declared when it should. * mailbox/daemon.c (mu_daemon_create_pidfile) (mu_daemon_remove_pidfile): If running with UID=0 and EUID != 0, temporarily switch to EUID=0 for accessing pidfile (when creating or deleting).
Showing
4 changed files
with
150 additions
and
25 deletions
1 | 2008-11-15 Sergey Poznyakoff <gray@gnu.org.ua> | ||
2 | |||
3 | * mailbox/cfg_driver.c (mu_cfg_tree_reduce): Format parse tree | ||
4 | before scanning the tree. | ||
5 | * mailbox/cfg_parser.y (block rule): Accept empty blocks. | ||
6 | (parse_param): bail out if callback is not declared when it | ||
7 | should. | ||
8 | * mailbox/daemon.c (mu_daemon_create_pidfile) | ||
9 | (mu_daemon_remove_pidfile): If running with UID=0 and EUID != 0, | ||
10 | temporarily switch to EUID=0 for accessing pidfile (when | ||
11 | creating or deleting). | ||
12 | |||
1 | 2008-11-12 Sergey Poznyakoff <gray@gnu.org.ua> | 13 | 2008-11-12 Sergey Poznyakoff <gray@gnu.org.ua> |
2 | 14 | ||
3 | * mailbox/cfg_parser.y (mu_cfg_format_error): Raise | 15 | * mailbox/cfg_parser.y (mu_cfg_format_error): Raise | ... | ... |
... | @@ -581,6 +581,16 @@ mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree, const char *progname, | ... | @@ -581,6 +581,16 @@ mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree, const char *progname, |
581 | { | 581 | { |
582 | int rc = 0; | 582 | int rc = 0; |
583 | 583 | ||
584 | if (flags & MU_PARSE_CONFIG_DUMP) | ||
585 | { | ||
586 | mu_stream_t stream; | ||
587 | mu_stdio_stream_create (&stream, stderr, | ||
588 | MU_STREAM_NO_CHECK|MU_STREAM_NO_CLOSE); | ||
589 | mu_stream_open (stream); | ||
590 | mu_cfg_format_parse_tree (stream, parse_tree); | ||
591 | mu_stream_destroy (&stream, NULL); | ||
592 | } | ||
593 | |||
584 | if (root_container) | 594 | if (root_container) |
585 | { | 595 | { |
586 | struct include_data idata; | 596 | struct include_data idata; |
... | @@ -598,16 +608,6 @@ mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree, const char *progname, | ... | @@ -598,16 +608,6 @@ mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree, const char *progname, |
598 | mu_config_destroy_container (&cont); | 608 | mu_config_destroy_container (&cont); |
599 | } | 609 | } |
600 | 610 | ||
601 | if (flags & MU_PARSE_CONFIG_DUMP) | ||
602 | { | ||
603 | mu_stream_t stream; | ||
604 | mu_stdio_stream_create (&stream, stderr, | ||
605 | MU_STREAM_NO_CHECK|MU_STREAM_NO_CLOSE); | ||
606 | mu_stream_open (stream); | ||
607 | mu_cfg_format_parse_tree (stream, parse_tree); | ||
608 | mu_stream_destroy (&stream, NULL); | ||
609 | } | ||
610 | |||
611 | return rc; | 611 | return rc; |
612 | } | 612 | } |
613 | 613 | ... | ... |
... | @@ -224,7 +224,14 @@ simple : ident vallist ';' | ... | @@ -224,7 +224,14 @@ simple : ident vallist ';' |
224 | } | 224 | } |
225 | ; | 225 | ; |
226 | 226 | ||
227 | block : ident tag '{' stmtlist '}' opt_sc | 227 | block : ident tag '{' '}' opt_sc |
228 | { | ||
229 | $$ = mu_cfg_alloc_node (mu_cfg_node_tag, &$1.locus, | ||
230 | $1.name, $2, | ||
231 | NULL); | ||
232 | |||
233 | } | ||
234 | | ident tag '{' stmtlist '}' opt_sc | ||
228 | { | 235 | { |
229 | $$ = mu_cfg_alloc_node (mu_cfg_node_tag, &$1.locus, | 236 | $$ = mu_cfg_alloc_node (mu_cfg_node_tag, &$1.locus, |
230 | $1.name, $2, | 237 | $1.name, $2, |
... | @@ -1126,6 +1133,13 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) | ... | @@ -1126,6 +1133,13 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) |
1126 | { | 1133 | { |
1127 | mu_debug_set_locus (sdata->tree->debug, node->locus.file, | 1134 | mu_debug_set_locus (sdata->tree->debug, node->locus.file, |
1128 | node->locus.line); | 1135 | node->locus.line); |
1136 | if (!param->callback) | ||
1137 | { | ||
1138 | _mu_cfg_perror (sdata->tree->debug, &node->locus, | ||
1139 | _("INTERNAL ERROR: %s: callback not defined"), | ||
1140 | node->tag); | ||
1141 | abort (); | ||
1142 | } | ||
1129 | if (param->callback (sdata->tree->debug, tgt, node->label)) | 1143 | if (param->callback (sdata->tree->debug, tgt, node->label)) |
1130 | return 1; | 1144 | return 1; |
1131 | 1145 | ... | ... |
... | @@ -30,41 +30,115 @@ | ... | @@ -30,41 +30,115 @@ |
30 | 30 | ||
31 | #include <mailutils/daemon.h> | 31 | #include <mailutils/daemon.h> |
32 | #include <mailutils/errno.h> | 32 | #include <mailutils/errno.h> |
33 | #include <mailutils/error.h> | ||
34 | #include <mailutils/nls.h> | ||
33 | #include <mu_umaxtostr.h> | 35 | #include <mu_umaxtostr.h> |
34 | 36 | ||
35 | static char *pidfile; | 37 | static char *pidfile; |
36 | static pid_t current_pid; | 38 | static pid_t current_pid; |
37 | 39 | ||
40 | /* Return 0 if DIR is writable for EUID/EGID. | ||
41 | Otherwise, return error code. */ | ||
42 | static int | ||
43 | ewraccess (const char *dir) | ||
44 | { | ||
45 | struct stat st; | ||
46 | if (stat (dir, &st)) | ||
47 | return errno; | ||
48 | if ((st.st_mode & S_IWOTH) | ||
49 | || (st.st_gid == getegid () && (st.st_mode & S_IWGRP)) | ||
50 | || (st.st_uid == geteuid () && (st.st_mode & S_IWUSR))) | ||
51 | return 0; | ||
52 | else | ||
53 | return EACCES; | ||
54 | } | ||
55 | |||
56 | /* Return 0 if DIR is writable. If necessary and possible, raise to | ||
57 | EUID 0, in that case return prior EUID in the memory location pointed to | ||
58 | by PUID. */ | ||
59 | static int | ||
60 | access_dir (const char *dir, uid_t *puid) | ||
61 | { | ||
62 | int ec = ewraccess (dir); | ||
63 | if (ec) | ||
64 | { | ||
65 | if (ec == EACCES && access (dir, W_OK) == 0) | ||
66 | { | ||
67 | uid_t uid = geteuid (); | ||
68 | /* See if we can become root */ | ||
69 | if (uid && getuid () == 0 && seteuid (0) == 0) | ||
70 | { | ||
71 | *puid = uid; | ||
72 | return 0; | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | return ec; | ||
77 | } | ||
78 | |||
38 | int | 79 | int |
39 | mu_daemon_create_pidfile (const char *filename) | 80 | mu_daemon_create_pidfile (const char *filename) |
40 | { | 81 | { |
82 | char *p; | ||
41 | const char *pid_string; | 83 | const char *pid_string; |
42 | int fd; | 84 | int fd; |
43 | 85 | uid_t uid = 0; | |
86 | int rc; | ||
87 | |||
44 | if (filename[0] != '/') | 88 | if (filename[0] != '/') |
45 | { | 89 | return EINVAL; |
46 | return EINVAL; /* failure */ | ||
47 | } | ||
48 | 90 | ||
49 | if (pidfile) | 91 | if (pidfile) |
50 | free (pidfile); | 92 | free (pidfile); |
51 | pidfile = strdup (filename); | 93 | pidfile = strdup (filename); |
94 | if (!pidfile) | ||
95 | return ENOMEM; | ||
52 | 96 | ||
97 | /* Determine the hosting directory name */ | ||
98 | p = strrchr (pidfile, '/'); | ||
99 | if (pidfile == p) | ||
100 | { | ||
101 | free (pidfile); | ||
102 | pidfile = NULL; | ||
103 | /* Sorry, pidfiles in root dir are not allowed */ | ||
104 | return EINVAL; | ||
105 | } | ||
106 | /* Check if we have write access to the directory */ | ||
107 | *p = 0; | ||
108 | rc = access_dir (pidfile, &uid); | ||
109 | if (rc) | ||
110 | { | ||
111 | /* Nope, clean up and return */ | ||
112 | free (pidfile); | ||
113 | pidfile = NULL; | ||
114 | return rc; | ||
115 | } | ||
116 | |||
117 | /* Restore directory separator */ | ||
118 | *p = '/'; | ||
119 | |||
53 | unlink (pidfile); | 120 | unlink (pidfile); |
54 | current_pid = getpid (); | 121 | current_pid = getpid (); |
55 | 122 | ||
56 | if ((fd = open (pidfile, O_WRONLY | O_CREAT | 123 | if ((fd = open (pidfile, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644)) != -1) |
57 | | O_TRUNC | O_EXCL, 0644)) == -1) | ||
58 | { | 124 | { |
59 | return errno; /* failure */ | 125 | pid_string = mu_umaxtostr (0, current_pid); |
126 | write (fd, pid_string, strlen (pid_string)); | ||
127 | close (fd); | ||
128 | atexit (mu_daemon_remove_pidfile); | ||
60 | } | 129 | } |
130 | else | ||
131 | { | ||
132 | rc = errno; | ||
133 | free (pidfile); | ||
134 | pidfile = NULL; | ||
135 | } | ||
136 | |||
137 | /* Restore previous EUID value. */ | ||
138 | if (uid) | ||
139 | seteuid (uid); | ||
61 | 140 | ||
62 | pid_string = mu_umaxtostr (0, current_pid); | 141 | return rc; |
63 | write (fd, pid_string, strlen (pid_string)); | ||
64 | close (fd); | ||
65 | |||
66 | atexit (mu_daemon_remove_pidfile); | ||
67 | return 0; | ||
68 | } | 142 | } |
69 | 143 | ||
70 | void | 144 | void |
... | @@ -72,7 +146,32 @@ mu_daemon_remove_pidfile (void) | ... | @@ -72,7 +146,32 @@ mu_daemon_remove_pidfile (void) |
72 | { | 146 | { |
73 | if (getpid () == current_pid) | 147 | if (getpid () == current_pid) |
74 | { | 148 | { |
75 | unlink (pidfile); | 149 | int rc; |
150 | uid_t uid = 0; | ||
151 | |||
152 | /* Determine the hosting directory name */ | ||
153 | char *p = strrchr (pidfile, '/'); | ||
154 | if (pidfile == p) | ||
155 | { | ||
156 | /* Should not happen */ | ||
157 | abort (); | ||
158 | } | ||
159 | /* Check if we have write access to the directory */ | ||
160 | *p = 0; | ||
161 | rc = access_dir (pidfile, &uid); | ||
162 | *p = '/'; | ||
163 | if (rc == 0) | ||
164 | { | ||
165 | if (unlink (pidfile) && errno != ENOENT) | ||
166 | rc = errno; | ||
167 | else | ||
168 | rc = 0; | ||
169 | } | ||
170 | |||
171 | if (rc) | ||
172 | mu_error (_("cannot remove pidfile %s: %s"), | ||
173 | pidfile, mu_strerror (rc)); | ||
174 | |||
76 | free (pidfile); | 175 | free (pidfile); |
77 | pidfile = NULL; | 176 | pidfile = NULL; |
78 | } | 177 | } | ... | ... |
-
Please register or sign in to post a comment