Commit 1819c2db 1819c2db46ba750821f072a83b019e2f1355867d by Sergey Poznyakoff

* 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).
1 parent a3bd178c
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 }
......