Rewrite prog stream support.
Two interfaces are provided: mu_prog_stream_create offers full control over the program execution environment (i.e. running privileges, cwd, resource limits) via a set of hints. A simpler interface, mu_command_stream_create, runs the command in the current environment. mu_filter_prog_stream_create is removed, because its functionality can be achieved by a correspondingly crafted set of hints to mu_prog_stream_create. * include/mailutils/prog.h: New file. * include/mailutils/mailutils.h: Include mailutils/prog.h * include/mailutils/Makefile.am (pkginclude_HEADERS): Add prog.h * include/mailutils/stream.h (mu_prog_stream_create) (mu_filter_prog_stream_create): Remove prototypes. * include/mailutils/sys/prog_stream.h (_mu_prog_stream): Change structure. (_mu_prog_limit_codes, _mu_prog_limit_flags): New externs. * include/mailutils/util.h (mu_set_user_privileges) (mu_switch_to_privs): New prototypes. * lib/userprivs.c: Move to libmailutils/base. * lib/Makefile.am (libmuaux_a_SOURCES): Remove userprivs.c * libmailutils/base/Makefile.am (libbase_la_SOURCES): Add userprivs.c * libmailutils/base/userprivs.c (mu_set_user_privileges): New function. (mu_switch_to_privs): Rewrite as another entry point to mu_set_user_privileges. * libmailutils/stream/prog_stream.c (_mu_prog_limit_flags) (_mu_prog_limit_codes): New global variables. (start_program_filter): Use hints to control execution environment. (_prog_stream_create): Save hints. (mu_prog_stream_create): Change signature. (mu_command_stream_create): New function (corresponds to the prior mu_prog_stream_create). (mu_filter_prog_stream_create): Remove function. * comsat/action.c (action_exec): Use new mu_prog_stream_create calling convention. * examples/murun.c: Rewrite. * mh/mhn.c (show_internal): Use new mu_prog_stream_create calling convention. * mh/tests/mhn.at: Reflect changes to mhn. * imap4d/preauth.c: Use mu_command_stream_create. * libmu_sieve/extensions/pipe.c * mail/decode.c * mail/pipe.c * mail/send.c * mh/mhl.c * mu/shell.c * mail/mail.h: Include mailutils/prog.h * mh/mh.h * po/POTFILES.in: Add libmailutils/base/userprivs.c.
Showing
24 changed files
with
639 additions
and
183 deletions
... | @@ -18,6 +18,7 @@ | ... | @@ -18,6 +18,7 @@ |
18 | #include "comsat.h" | 18 | #include "comsat.h" |
19 | #include <mailutils/io.h> | 19 | #include <mailutils/io.h> |
20 | #include <mailutils/argcv.h> | 20 | #include <mailutils/argcv.h> |
21 | #include <mailutils/prog.h> | ||
21 | #define obstack_chunk_alloc malloc | 22 | #define obstack_chunk_alloc malloc |
22 | #define obstack_chunk_free free | 23 | #define obstack_chunk_free free |
23 | #include <obstack.h> | 24 | #include <obstack.h> |
... | @@ -225,7 +226,6 @@ action_exec (mu_stream_t tty, int argc, char **argv) | ... | @@ -225,7 +226,6 @@ action_exec (mu_stream_t tty, int argc, char **argv) |
225 | { | 226 | { |
226 | mu_stream_t pstream; | 227 | mu_stream_t pstream; |
227 | struct stat stb; | 228 | struct stat stb; |
228 | char *command; | ||
229 | int status; | 229 | int status; |
230 | 230 | ||
231 | if (argc == 0) | 231 | if (argc == 0) |
... | @@ -249,25 +249,19 @@ action_exec (mu_stream_t tty, int argc, char **argv) | ... | @@ -249,25 +249,19 @@ action_exec (mu_stream_t tty, int argc, char **argv) |
249 | 249 | ||
250 | if (stb.st_mode & (S_ISUID|S_ISGID)) | 250 | if (stb.st_mode & (S_ISUID|S_ISGID)) |
251 | { | 251 | { |
252 | mu_diag_output (MU_DIAG_ERROR, _("will not execute set[ug]id programs")); | 252 | mu_diag_output (MU_DIAG_ERROR, |
253 | _("will not execute set[ug]id programs")); | ||
253 | return; | 254 | return; |
254 | } | 255 | } |
255 | 256 | ||
256 | /* FIXME: Redirect stderr to out */ | 257 | status = mu_prog_stream_create (&pstream, |
257 | /* FIXME: need this: | 258 | argv[0], argc, argv, |
258 | status = mu_prog_stream_create_argv (&pstream, argv[0], argv, | 259 | MU_PROG_HINT_ERRTOOUT, |
259 | MU_STREAM_READ); | 260 | NULL, |
260 | */ | 261 | MU_STREAM_READ); |
261 | status = mu_argcv_join (argc, argv, " ", mu_argcv_escape_no, &command); | ||
262 | if (status) | 262 | if (status) |
263 | { | 263 | { |
264 | mu_diag_funcall (MU_DIAG_ERROR, "mu_argcv_join", NULL, status); | 264 | mu_diag_funcall (MU_DIAG_ERROR, "mu_prog_stream_create", argv[0], |
265 | return; | ||
266 | } | ||
267 | status = mu_prog_stream_create (&pstream, command, MU_STREAM_READ); | ||
268 | if (status) | ||
269 | { | ||
270 | mu_diag_funcall (MU_DIAG_ERROR, "mu_prog_stream_create_argv", argv[0], | ||
271 | status); | 265 | status); |
272 | return; | 266 | return; |
273 | } | 267 | } | ... | ... |
... | @@ -24,20 +24,7 @@ | ... | @@ -24,20 +24,7 @@ |
24 | #include <ctype.h> | 24 | #include <ctype.h> |
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include <mailutils/mailutils.h> | 26 | #include <mailutils/mailutils.h> |
27 | #include <mailutils/argcv.h> | 27 | #include <mailutils/sys/prog_stream.h> |
28 | |||
29 | static void | ||
30 | read_and_print (mu_stream_t in, mu_stream_t out) | ||
31 | { | ||
32 | size_t size; | ||
33 | char buffer[128]; | ||
34 | |||
35 | while (mu_stream_readline (in, buffer, sizeof (buffer), &size) == 0 | ||
36 | && size > 0) | ||
37 | { | ||
38 | mu_stream_write (out, buffer, size, NULL); | ||
39 | } | ||
40 | } | ||
41 | 28 | ||
42 | int | 29 | int |
43 | main (int argc, char *argv[]) | 30 | main (int argc, char *argv[]) |
... | @@ -45,34 +32,154 @@ main (int argc, char *argv[]) | ... | @@ -45,34 +32,154 @@ main (int argc, char *argv[]) |
45 | int rc; | 32 | int rc; |
46 | mu_stream_t stream, out; | 33 | mu_stream_t stream, out; |
47 | int read_stdin = 0; | 34 | int read_stdin = 0; |
48 | int i = 1; | 35 | int i; |
49 | char *cmdline; | ||
50 | int flags = MU_STREAM_READ; | 36 | int flags = MU_STREAM_READ; |
51 | 37 | struct mu_prog_hints hints; | |
52 | if (argc > 1 && strcmp (argv[i], "--stdin") == 0) | 38 | int hint_flags = 0; |
39 | char *progname = NULL; | ||
40 | gid_t gid[20]; | ||
41 | size_t gn = 0; | ||
42 | |||
43 | for (i = 1; i < argc; i++) | ||
53 | { | 44 | { |
54 | read_stdin = 1; | 45 | if (strcmp (argv[i], "--stdin") == 0) |
55 | flags |= MU_STREAM_WRITE; | 46 | { |
56 | i++; | 47 | read_stdin = 1; |
48 | flags |= MU_STREAM_WRITE; | ||
49 | } | ||
50 | else if (strcmp (argv[i], "--chdir") == 0) | ||
51 | { | ||
52 | hints.mu_prog_workdir = argv[i+1]; | ||
53 | hint_flags |= MU_PROG_HINT_WORKDIR; | ||
54 | i++; | ||
55 | } | ||
56 | else if (strncmp (argv[i], "--limit", 7) == 0 | ||
57 | && mu_isdigit (argv[i][7])) | ||
58 | { | ||
59 | int n; | ||
60 | |||
61 | if (i + 1 == argc) | ||
62 | { | ||
63 | fprintf (stderr, "%s requires argument\n", argv[i]); | ||
64 | exit (1); | ||
65 | } | ||
66 | n = argv[i][7] - '0'; | ||
67 | if (!(_mu_prog_limit_flags & MU_PROG_HINT_LIMIT(n))) | ||
68 | { | ||
69 | fprintf (stderr, "%s is not supported\n", argv[i]+2); | ||
70 | continue; | ||
71 | } | ||
72 | hint_flags |= MU_PROG_HINT_LIMIT(n); | ||
73 | hints.mu_prog_limit[n] = strtoul (argv[i+1], NULL, 10); | ||
74 | i++; | ||
75 | } | ||
76 | else if (strcmp (argv[i], "--prio") == 0) | ||
77 | { | ||
78 | if (i + 1 == argc) | ||
79 | { | ||
80 | fprintf (stderr, "%s requires argument\n", argv[i]); | ||
81 | exit (1); | ||
82 | } | ||
83 | hint_flags |= MU_PROG_HINT_PRIO; | ||
84 | hints.mu_prog_prio = strtoul (argv[i+1], NULL, 10); | ||
85 | i++; | ||
86 | } | ||
87 | else if (strcmp (argv[i], "--exec") == 0) | ||
88 | { | ||
89 | if (i + 1 == argc) | ||
90 | { | ||
91 | fprintf (stderr, "%s requires argument\n", argv[i]); | ||
92 | exit (1); | ||
93 | } | ||
94 | progname = argv[++i]; | ||
95 | } | ||
96 | else if (strcmp (argv[i], "--errignore") == 0) | ||
97 | hint_flags |= MU_PROG_HINT_IGNOREFAIL; | ||
98 | else if (strcmp (argv[i], "--uid") == 0) | ||
99 | { | ||
100 | if (i + 1 == argc) | ||
101 | { | ||
102 | fprintf (stderr, "%s requires argument\n", argv[i]); | ||
103 | exit (1); | ||
104 | } | ||
105 | hint_flags |= MU_PROG_HINT_UID; | ||
106 | hints.mu_prog_uid = strtoul (argv[i+1], NULL, 10); | ||
107 | i++; | ||
108 | } | ||
109 | else if (strcmp (argv[i], "--gid") == 0) | ||
110 | { | ||
111 | mu_list_t list; | ||
112 | mu_iterator_t itr; | ||
113 | |||
114 | if (i + 1 == argc) | ||
115 | { | ||
116 | fprintf (stderr, "%s requires argument\n", argv[i]); | ||
117 | exit (1); | ||
118 | } | ||
119 | mu_list_create (&list); | ||
120 | mu_list_set_destroy_item (list, mu_list_free_item); | ||
121 | rc = mu_string_split (argv[++i], ",", list); | ||
122 | if (mu_list_get_iterator (list, &itr) == 0) | ||
123 | { | ||
124 | char *p; | ||
125 | |||
126 | for (mu_iterator_first (itr); | ||
127 | !mu_iterator_is_done (itr); mu_iterator_next (itr)) | ||
128 | { | ||
129 | if (gn >= MU_ARRAY_SIZE (gid)) | ||
130 | { | ||
131 | fprintf (stderr, "too many gids\n"); | ||
132 | exit (1); | ||
133 | } | ||
134 | gid[gn++] = strtoul (p, NULL, 10); | ||
135 | } | ||
136 | mu_iterator_destroy (&itr); | ||
137 | } | ||
138 | else | ||
139 | { | ||
140 | mu_diag_funcall (MU_DIAG_ERROR, "mu_list_get_iterator", NULL, | ||
141 | rc); | ||
142 | exit (1); | ||
143 | } | ||
144 | mu_list_destroy (&list); | ||
145 | hint_flags |= MU_PROG_HINT_GID; | ||
146 | } | ||
147 | else if (strcmp (argv[i], "--") == 0) | ||
148 | { | ||
149 | i++; | ||
150 | break; | ||
151 | } | ||
152 | else | ||
153 | break; | ||
57 | } | 154 | } |
58 | 155 | ||
59 | if (i == argc) | 156 | if (i == argc) |
60 | { | 157 | { |
61 | fprintf (stderr, "Usage: %s [--stdin] progname [args]\n", argv[0]); | 158 | fprintf (stderr, |
159 | "Usage: %s [--stdin] [--chdir dir] [--limit{0-9} lim] [--prio N]\n" | ||
160 | " [--exec progname] progname [args]\n", argv[0]); | ||
62 | exit (1); | 161 | exit (1); |
63 | } | 162 | } |
64 | 163 | ||
65 | MU_ASSERT (mu_argcv_string (argc - i, &argv[i], &cmdline)); | 164 | argc -= i; |
165 | argv += i; | ||
166 | |||
167 | if (!progname) | ||
168 | progname = argv[0]; | ||
169 | |||
66 | if (read_stdin) | 170 | if (read_stdin) |
67 | { | 171 | { |
68 | mu_stream_t in; | 172 | MU_ASSERT (mu_stdio_stream_create (&hints.mu_prog_input, |
69 | MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, 0)); | 173 | MU_STDIN_FD, 0)); |
70 | rc = mu_filter_prog_stream_create (&stream, cmdline, in); | 174 | hint_flags |= MU_PROG_HINT_INPUT; |
71 | /* Make sure closing/destroying stream will close/destroy in */ | ||
72 | mu_stream_unref (in); | ||
73 | } | 175 | } |
74 | else | 176 | |
75 | rc = mu_prog_stream_create (&stream, cmdline, flags); | 177 | rc = mu_prog_stream_create (&stream, progname, argc, argv, |
178 | hint_flags, &hints, flags); | ||
179 | if (hint_flags & MU_PROG_HINT_INPUT) | ||
180 | /* Make sure closing/destroying stream will close/destroy input */ | ||
181 | mu_stream_unref (hints.mu_prog_input); | ||
182 | |||
76 | if (rc) | 183 | if (rc) |
77 | { | 184 | { |
78 | fprintf (stderr, "%s: cannot create program filter stream: %s\n", | 185 | fprintf (stderr, "%s: cannot create program filter stream: %s\n", |
... | @@ -81,8 +188,8 @@ main (int argc, char *argv[]) | ... | @@ -81,8 +188,8 @@ main (int argc, char *argv[]) |
81 | } | 188 | } |
82 | 189 | ||
83 | MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0)); | 190 | MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0)); |
84 | 191 | ||
85 | read_and_print (stream, out); | 192 | mu_stream_copy (out, stream, 0, NULL); |
86 | mu_stream_close (stream); | 193 | mu_stream_close (stream); |
87 | mu_stream_destroy (&stream); | 194 | mu_stream_destroy (&stream); |
88 | mu_stream_close (out); | 195 | mu_stream_close (out); | ... | ... |
... | @@ -448,7 +448,7 @@ do_preauth_program (struct sockaddr *pcs, struct sockaddr *sa) | ... | @@ -448,7 +448,7 @@ do_preauth_program (struct sockaddr *pcs, struct sockaddr *sa) |
448 | return NULL; | 448 | return NULL; |
449 | } | 449 | } |
450 | 450 | ||
451 | rc = mu_prog_stream_create (&str, ws.ws_wordv[0], MU_STREAM_READ); | 451 | rc = mu_command_stream_create (&str, ws.ws_wordv[0], MU_STREAM_READ); |
452 | mu_wordsplit_free (&ws); | 452 | mu_wordsplit_free (&ws); |
453 | if (rc) | 453 | if (rc) |
454 | { | 454 | { | ... | ... |
... | @@ -66,5 +66,6 @@ | ... | @@ -66,5 +66,6 @@ |
66 | #include <mailutils/wordsplit.h> | 66 | #include <mailutils/wordsplit.h> |
67 | #include <mailutils/log.h> | 67 | #include <mailutils/log.h> |
68 | #include <mailutils/stdstream.h> | 68 | #include <mailutils/stdstream.h> |
69 | #include <mailutils/prog.h> | ||
69 | 70 | ||
70 | /* EOF */ | 71 | /* EOF */ | ... | ... |
include/mailutils/prog.h
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2009 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #ifndef _MAILUTILS_PROG_H | ||
18 | #define _MAILUTILS_PROG_H | ||
19 | |||
20 | #include <sys/time.h> | ||
21 | #include <sys/resource.h> | ||
22 | #include <mailutils/types.h> | ||
23 | |||
24 | #define MU_PROG_LIMIT_AS 0 | ||
25 | #define MU_PROG_LIMIT_CPU 1 | ||
26 | #define MU_PROG_LIMIT_DATA 2 | ||
27 | #define MU_PROG_LIMIT_FSIZE 3 | ||
28 | #define MU_PROG_LIMIT_NPROC 4 | ||
29 | #define MU_PROG_LIMIT_CORE 5 | ||
30 | #define MU_PROG_LIMIT_MEMLOCK 6 | ||
31 | #define MU_PROG_LIMIT_NOFILE 7 | ||
32 | #define MU_PROG_LIMIT_RSS 8 | ||
33 | #define MU_PROG_LIMIT_STACK 9 | ||
34 | |||
35 | #define _MU_PROG_LIMIT_MAX 10 | ||
36 | |||
37 | #define MU_PROG_HINT_WORKDIR 0x0001 /* Workdir is set */ | ||
38 | #define MU_PROG_HINT_PRIO 0x0002 /* Prio is set */ | ||
39 | #define MU_PROG_HINT_INPUT 0x0004 /* Input stream is set */ | ||
40 | #define MU_PROG_HINT_UID 0x0008 /* Uid is set */ | ||
41 | #define MU_PROG_HINT_GID 0x0010 /* Supplementary gids are set */ | ||
42 | #define MU_PROG_HINT_ERRTOOUT 0x0020 /* Redirect stderr to stdout */ | ||
43 | #define MU_PROG_HINT_ERRTOSTREAM 0x0040 /* Redirect stderr to errstream */ | ||
44 | #define MU_PROG_HINT_IGNOREFAIL 0x0080 /* Ignore hint setup failures */ | ||
45 | #define _MU_PROG_HINT_MASK 0x00ff | ||
46 | #define MU_PROG_HINT_LIMIT(n) (0x100 << (n)) /* MU_PROG_LIMIT_n is set */ | ||
47 | |||
48 | struct mu_prog_hints | ||
49 | { | ||
50 | char *mu_prog_workdir; /* Working directory */ | ||
51 | uid_t mu_prog_uid; /* Run as this user */ | ||
52 | gid_t *mu_prog_gidv; /* Array of supplementary gids */ | ||
53 | size_t mu_prog_gidc; /* Number of elements in gidv */ | ||
54 | rlim_t mu_prog_limit[_MU_PROG_LIMIT_MAX]; /* Limits */ | ||
55 | int mu_prog_prio; /* Scheduling priority */ | ||
56 | mu_stream_t mu_prog_input; /* Input stream */ | ||
57 | mu_stream_t mu_prog_error; /* Error stream */ | ||
58 | }; | ||
59 | |||
60 | int mu_prog_stream_create (mu_stream_t *pstream, | ||
61 | const char *progname, | ||
62 | size_t argc, char **argv, | ||
63 | int hflags, | ||
64 | struct mu_prog_hints *hints, | ||
65 | int flags); | ||
66 | int mu_command_stream_create (mu_stream_t *pstream, const char *command, | ||
67 | int flags); | ||
68 | |||
69 | #endif | ||
70 |
... | @@ -250,9 +250,6 @@ int mu_fd_stream_create (mu_stream_t *pstream, char *filename, int fd, | ... | @@ -250,9 +250,6 @@ int mu_fd_stream_create (mu_stream_t *pstream, char *filename, int fd, |
250 | #define MU_STDERR_FD 2 | 250 | #define MU_STDERR_FD 2 |
251 | int mu_stdio_stream_create (mu_stream_t *pstream, int fd, int flags); | 251 | int mu_stdio_stream_create (mu_stream_t *pstream, int fd, int flags); |
252 | 252 | ||
253 | int mu_prog_stream_create (mu_stream_t *pstream, const char *progname, int flags); | ||
254 | int mu_filter_prog_stream_create (mu_stream_t *pstream, const char *progname, | ||
255 | mu_stream_t input); | ||
256 | int mu_memory_stream_create (mu_stream_t *pstream, int flags); | 253 | int mu_memory_stream_create (mu_stream_t *pstream, int flags); |
257 | int mu_static_memory_stream_create (mu_stream_t *pstream, const void *mem, | 254 | int mu_static_memory_stream_create (mu_stream_t *pstream, const void *mem, |
258 | size_t size); | 255 | size_t size); | ... | ... |
... | @@ -18,18 +18,25 @@ | ... | @@ -18,18 +18,25 @@ |
18 | #define _MAILUTILS_SYS_PROG_STREAM_H | 18 | #define _MAILUTILS_SYS_PROG_STREAM_H |
19 | 19 | ||
20 | #include <mailutils/sys/stream.h> | 20 | #include <mailutils/sys/stream.h> |
21 | #include <mailutils/prog.h> | ||
21 | 22 | ||
22 | struct _mu_prog_stream | 23 | struct _mu_prog_stream |
23 | { | 24 | { |
24 | struct _mu_stream stream; | 25 | struct _mu_stream stream; /* Base stream */ |
26 | char *progname; /* Program name */ | ||
27 | size_t argc; /* Number of arguments */ | ||
28 | char **argv; /* Program arguments */ | ||
29 | int hint_flags; /* Hint flags */ | ||
30 | struct mu_prog_hints hints; /* Invocation hints */ | ||
31 | |||
25 | pid_t pid; | 32 | pid_t pid; |
26 | int status; | 33 | int status; |
27 | pid_t writer_pid; | 34 | pid_t writer_pid; |
28 | int argc; | 35 | |
29 | char **argv; | ||
30 | mu_stream_t in, out; | 36 | mu_stream_t in, out; |
31 | |||
32 | mu_stream_t input; | ||
33 | }; | 37 | }; |
34 | 38 | ||
39 | extern int _mu_prog_limit_flags; | ||
40 | extern int _mu_prog_limit_codes[_MU_PROG_LIMIT_MAX]; | ||
41 | |||
35 | #endif | 42 | #endif | ... | ... |
... | @@ -175,8 +175,10 @@ int mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt, | ... | @@ -175,8 +175,10 @@ int mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt, |
175 | /* ----------------------- */ | 175 | /* ----------------------- */ |
176 | /* Get the host name, doing a gethostbyname() if possible. */ | 176 | /* Get the host name, doing a gethostbyname() if possible. */ |
177 | int mu_get_host_name (char **host); | 177 | int mu_get_host_name (char **host); |
178 | int mu_spawnvp(const char *prog, char *av[], int *stat); | 178 | int mu_spawnvp (const char *prog, char *av[], int *stat); |
179 | int mu_scheme_autodetect_p (mu_url_t); | 179 | int mu_scheme_autodetect_p (mu_url_t); |
180 | int mu_set_user_privileges (uid_t uid, gid_t *gidv, size_t gidc); | ||
181 | int mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups); | ||
180 | 182 | ||
181 | struct timeval; | 183 | struct timeval; |
182 | int mu_fd_wait (int fd, int *pflags, struct timeval *tvp); | 184 | int mu_fd_wait (int fd, int *pflags, struct timeval *tvp); | ... | ... |
... | @@ -29,75 +29,90 @@ | ... | @@ -29,75 +29,90 @@ |
29 | #include <mailutils/nls.h> | 29 | #include <mailutils/nls.h> |
30 | #include <mailutils/list.h> | 30 | #include <mailutils/list.h> |
31 | #include <mailutils/iterator.h> | 31 | #include <mailutils/iterator.h> |
32 | #include <xalloc.h> | ||
33 | 32 | ||
34 | /* Switch to the given UID/GID */ | 33 | /* Switch to the given UID/GID */ |
35 | int | 34 | int |
36 | mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups) | 35 | mu_set_user_privileges (uid_t uid, gid_t *gidv, size_t gidc) |
37 | { | 36 | { |
38 | int rc = 0; | 37 | int rc = 0; |
39 | gid_t *emptygidset; | 38 | gid_t gid; |
40 | size_t size = 1, j = 1; | ||
41 | mu_iterator_t itr; | ||
42 | 39 | ||
40 | if (getuid ()) | ||
41 | return EACCES; | ||
42 | |||
43 | if (uid == 0) | 43 | if (uid == 0) |
44 | return 0; | 44 | return 0; |
45 | 45 | ||
46 | /* Create a list of supplementary groups */ | 46 | /* Reset group permissions */ |
47 | mu_list_count (retain_groups, &size); | 47 | if (gidv && gidc) |
48 | size++; | ||
49 | emptygidset = xmalloc (size * sizeof emptygidset[0]); | ||
50 | emptygidset[0] = gid ? gid : getegid (); | ||
51 | |||
52 | if (mu_list_get_iterator (retain_groups, &itr) == 0) | ||
53 | { | 48 | { |
54 | for (mu_iterator_first (itr); | 49 | if (geteuid () == 0 && setgroups (gidc, gidv)) |
55 | !mu_iterator_is_done (itr); mu_iterator_next (itr)) | 50 | { |
56 | mu_iterator_current (itr, | 51 | mu_error(_("setgroups(1, %lu) failed: %s"), |
57 | (void **)(emptygidset + j++)); | 52 | (unsigned long) gidv[0], mu_strerror (errno)); |
58 | mu_iterator_destroy (&itr); | 53 | return errno; |
54 | } | ||
55 | gid = gidv[0]; | ||
59 | } | 56 | } |
60 | 57 | else | |
61 | /* Reset group permissions */ | ||
62 | if (geteuid () == 0 && setgroups (j, emptygidset)) | ||
63 | { | 58 | { |
64 | mu_error(_("setgroups(1, %lu) failed: %s"), | 59 | struct passwd *pwd = getpwuid (uid); |
65 | (unsigned long) emptygidset[0], mu_strerror (errno)); | 60 | if (pwd) |
66 | rc = 1; | 61 | gid = pwd->pw_gid; |
62 | else | ||
63 | gid = getegid (); | ||
67 | } | 64 | } |
68 | free (emptygidset); | 65 | |
69 | |||
70 | /* Switch to the user's gid. On some OSes the effective gid must | 66 | /* Switch to the user's gid. On some OSes the effective gid must |
71 | be reset first */ | 67 | be reset first */ |
72 | 68 | ||
73 | #if defined(HAVE_SETEGID) | 69 | #if defined(HAVE_SETEGID) |
74 | if ((rc = setegid (gid)) < 0) | 70 | if (setegid (gid) < 0) |
75 | mu_error (_("setegid(%lu) failed: %s"), | 71 | { |
76 | (unsigned long) gid, mu_strerror (errno)); | 72 | rc = errno; |
73 | mu_error (_("setegid(%lu) failed: %s"), | ||
74 | (unsigned long) gid, mu_strerror (rc)); | ||
75 | } | ||
77 | #elif defined(HAVE_SETREGID) | 76 | #elif defined(HAVE_SETREGID) |
78 | if ((rc = setregid (gid, gid)) < 0) | 77 | if (setregid (gid, gid) < 0) |
79 | mu_error (_("setregid(%lu,%lu) failed: %s"), | 78 | { |
80 | (unsigned long) gid, (unsigned long) gid, | 79 | rc = errno; |
81 | mu_strerror (errno)); | 80 | mu_error (_("setregid(%lu,%lu) failed: %s"), |
81 | (unsigned long) gid, (unsigned long) gid, | ||
82 | mu_strerror (rc)); | ||
83 | } | ||
82 | #elif defined(HAVE_SETRESGID) | 84 | #elif defined(HAVE_SETRESGID) |
83 | if ((rc = setresgid (gid, gid, gid)) < 0) | 85 | if (setresgid (gid, gid, gid) < 0) |
84 | mu_error (_("setresgid(%lu,%lu,%lu) failed: %s"), | 86 | { |
85 | (unsigned long) gid, | 87 | rc = errno; |
86 | (unsigned long) gid, | 88 | mu_error (_("setresgid(%lu,%lu,%lu) failed: %s"), |
87 | (unsigned long) gid, | 89 | (unsigned long) gid, |
88 | mu_strerror (errno)); | 90 | (unsigned long) gid, |
91 | (unsigned long) gid, | ||
92 | mu_strerror (rc)); | ||
93 | } | ||
89 | #endif | 94 | #endif |
90 | 95 | ||
91 | if (rc == 0 && gid != 0) | 96 | if (rc == 0 && gid != 0) |
92 | { | 97 | { |
93 | if ((rc = setgid (gid)) < 0 && getegid () != gid) | 98 | if (setgid (gid) < 0) |
94 | mu_error (_("setgid(%lu) failed: %s"), | 99 | { |
95 | (unsigned long) gid, mu_strerror (errno)); | 100 | rc = errno; |
101 | mu_error (_("setgid(%lu) failed: %s"), | ||
102 | (unsigned long) gid, mu_strerror (rc)); | ||
103 | } | ||
104 | else if (getegid () != gid) | ||
105 | { | ||
106 | rc = MU_ERR_FAILURE; | ||
107 | mu_error (_("setgid(%lu) failed: %s"), | ||
108 | (unsigned long) gid, mu_strerror (rc)); | ||
109 | } | ||
110 | |||
96 | if (rc == 0 && getegid () != gid) | 111 | if (rc == 0 && getegid () != gid) |
97 | { | 112 | { |
98 | mu_error (_("Cannot set effective gid to %lu"), | 113 | mu_error (_("Cannot set effective gid to %lu"), |
99 | (unsigned long) gid); | 114 | (unsigned long) gid); |
100 | rc = 1; | 115 | rc = MU_ERR_FAILURE; |
101 | } | 116 | } |
102 | } | 117 | } |
103 | 118 | ||
... | @@ -114,24 +129,24 @@ mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups) | ... | @@ -114,24 +129,24 @@ mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups) |
114 | { | 129 | { |
115 | if (setreuid (uid, -1) < 0) | 130 | if (setreuid (uid, -1) < 0) |
116 | { | 131 | { |
132 | rc = errno; | ||
117 | mu_error (_("setreuid(%lu,-1) failed: %s"), | 133 | mu_error (_("setreuid(%lu,-1) failed: %s"), |
118 | (unsigned long) uid, | 134 | (unsigned long) uid, |
119 | mu_strerror (errno)); | 135 | mu_strerror (rc)); |
120 | rc = 1; | ||
121 | } | 136 | } |
122 | if (setuid (uid) < 0) | 137 | if (setuid (uid) < 0) |
123 | { | 138 | { |
139 | rc = errno; | ||
124 | mu_error (_("second setuid(%lu) failed: %s"), | 140 | mu_error (_("second setuid(%lu) failed: %s"), |
125 | (unsigned long) uid, mu_strerror (errno)); | 141 | (unsigned long) uid, mu_strerror (rc)); |
126 | rc = 1; | ||
127 | } | 142 | } |
128 | } else | 143 | } else |
129 | #endif | 144 | #endif |
130 | { | 145 | { |
146 | rc = errno; | ||
131 | mu_error (_("setuid(%lu) failed: %s"), | 147 | mu_error (_("setuid(%lu) failed: %s"), |
132 | (unsigned long) uid, | 148 | (unsigned long) uid, |
133 | mu_strerror (errno)); | 149 | mu_strerror (rc)); |
134 | rc = 1; | ||
135 | } | 150 | } |
136 | } | 151 | } |
137 | 152 | ||
... | @@ -139,15 +154,46 @@ mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups) | ... | @@ -139,15 +154,46 @@ mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups) |
139 | if (uid != 0 && setuid (0) == 0) | 154 | if (uid != 0 && setuid (0) == 0) |
140 | { | 155 | { |
141 | mu_error (_("seteuid(0) succeeded when it should not")); | 156 | mu_error (_("seteuid(0) succeeded when it should not")); |
142 | rc = 1; | 157 | rc = MU_ERR_FAILURE; |
143 | } | 158 | } |
144 | else if (uid != euid && setuid (euid) == 0) | 159 | else if (uid != euid && setuid (euid) == 0) |
145 | { | 160 | { |
146 | mu_error (_("Cannot drop non-root setuid privileges")); | 161 | mu_error (_("Cannot drop non-root setuid privileges")); |
147 | rc = 1; | 162 | rc = MU_ERR_FAILURE; |
148 | } | 163 | } |
149 | } | 164 | } |
150 | return rc; | 165 | return rc; |
151 | } | 166 | } |
152 | 167 | ||
168 | int | ||
169 | mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups) | ||
170 | { | ||
171 | int rc = 0; | ||
172 | gid_t *emptygidset; | ||
173 | size_t size = 1, j = 1; | ||
174 | mu_iterator_t itr; | ||
175 | |||
176 | if (uid == 0) | ||
177 | return 0; | ||
178 | |||
179 | /* Create a list of supplementary groups */ | ||
180 | mu_list_count (retain_groups, &size); | ||
181 | size++; | ||
182 | emptygidset = malloc (size * sizeof emptygidset[0]); | ||
183 | if (!emptygidset) | ||
184 | return ENOMEM; | ||
185 | emptygidset[0] = gid ? gid : getegid (); | ||
186 | |||
187 | if (mu_list_get_iterator (retain_groups, &itr) == 0) | ||
188 | { | ||
189 | for (mu_iterator_first (itr); | ||
190 | !mu_iterator_is_done (itr); mu_iterator_next (itr)) | ||
191 | mu_iterator_current (itr, | ||
192 | (void **)(emptygidset + j++)); | ||
193 | mu_iterator_destroy (&itr); | ||
194 | } | ||
195 | rc = mu_set_user_privileges (uid, emptygidset, j); | ||
196 | free (emptygidset); | ||
197 | return rc; | ||
198 | } | ||
153 | 199 | ... | ... |
... | @@ -71,9 +71,105 @@ _prog_stream_unregister (struct _mu_prog_stream *stream) | ... | @@ -71,9 +71,105 @@ _prog_stream_unregister (struct _mu_prog_stream *stream) |
71 | #define REDIRECT_STDIN_P(f) ((f) & MU_STREAM_WRITE) | 71 | #define REDIRECT_STDIN_P(f) ((f) & MU_STREAM_WRITE) |
72 | #define REDIRECT_STDOUT_P(f) ((f) & MU_STREAM_READ) | 72 | #define REDIRECT_STDOUT_P(f) ((f) & MU_STREAM_READ) |
73 | 73 | ||
74 | #ifdef RLIMIT_AS | ||
75 | # define _MU_RLIMIT_AS_FLAG MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_AS) | ||
76 | #else | ||
77 | # define _MU_RLIMIT_AS_FLAG 0 | ||
78 | # define RLIMIT_AS 0 | ||
79 | #endif | ||
80 | |||
81 | #ifdef RLIMIT_CPU | ||
82 | # define _MU_RLIMIT_CPU_FLAG MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_CPU) | ||
83 | #else | ||
84 | # define _MU_RLIMIT_CPU_FLAG 0 | ||
85 | # define RLIMIT_CPU 0 | ||
86 | #endif | ||
87 | |||
88 | #ifdef RLIMIT_DATA | ||
89 | # define _MU_RLIMIT_DATA_FLAG MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_DATA) | ||
90 | #else | ||
91 | # define _MU_RLIMIT_DATA_FLAG 0 | ||
92 | # define RLIMIT_DATA 0 | ||
93 | #endif | ||
94 | |||
95 | #ifdef RLIMIT_FSIZE | ||
96 | # define _MU_RLIMIT_FSIZE_FLAG MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_FSIZE) | ||
97 | #else | ||
98 | # define _MU_RLIMIT_FSIZE_FLAG 0 | ||
99 | # define RLIMIT_FSIZE 0 | ||
100 | #endif | ||
101 | |||
102 | #ifdef RLIMIT_NPROC | ||
103 | # define _MU_RLIMIT_NPROC_FLAG MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_NPROC) | ||
104 | #else | ||
105 | # define _MU_RLIMIT_NPROC_FLAG 0 | ||
106 | # define RLIMIT_NPROC 0 | ||
107 | #endif | ||
108 | |||
109 | #ifdef RLIMIT_CORE | ||
110 | # define _MU_RLIMIT_CORE_FLAG MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_CORE) | ||
111 | #else | ||
112 | # define _MU_RLIMIT_CORE_FLAG 0 | ||
113 | # define RLIMIT_CORE 0 | ||
114 | #endif | ||
115 | |||
116 | #ifdef RLIMIT_MEMLOCK | ||
117 | # define _MU_RLIMIT_MEMLOCK_FLAG MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_MEMLOCK) | ||
118 | #else | ||
119 | # define _MU_RLIMIT_MEMLOCK_FLAG 0 | ||
120 | # define RLIMIT_MEMLOCK 0 | ||
121 | #endif | ||
122 | |||
123 | #ifdef RLIMIT_NOFILE | ||
124 | # define _MU_RLIMIT_NOFILE_FLAG MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_NOFILE) | ||
125 | #else | ||
126 | # define _MU_RLIMIT_NOFILE_FLAG 0 | ||
127 | # define RLIMIT_NOFILE 0 | ||
128 | #endif | ||
129 | |||
130 | #ifdef RLIMIT_RSS | ||
131 | # define _MU_RLIMIT_RSS_FLAG MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_RSS) | ||
132 | #else | ||
133 | # define _MU_RLIMIT_RSS_FLAG 0 | ||
134 | # define RLIMIT_RSS 0 | ||
135 | #endif | ||
136 | |||
137 | #ifdef RLIMIT_STACK | ||
138 | # define _MU_RLIMIT_STACK MU_PROG_HINT_LIMIT(MU_PROG_LIMIT_STACK) | ||
139 | #else | ||
140 | # define _MU_RLIMIT_STACK 0 | ||
141 | # define RLIMIT_STACK 0 | ||
142 | #endif | ||
143 | |||
144 | #define _MU_PROG_AVAILABLE_LIMITS \ | ||
145 | (_MU_RLIMIT_AS_FLAG | \ | ||
146 | _MU_RLIMIT_CPU_FLAG | \ | ||
147 | _MU_RLIMIT_DATA_FLAG | \ | ||
148 | _MU_RLIMIT_FSIZE_FLAG | \ | ||
149 | _MU_RLIMIT_NPROC_FLAG | \ | ||
150 | _MU_RLIMIT_CORE_FLAG | \ | ||
151 | _MU_RLIMIT_MEMLOCK_FLAG | \ | ||
152 | _MU_RLIMIT_NOFILE_FLAG | \ | ||
153 | _MU_RLIMIT_RSS_FLAG | \ | ||
154 | _MU_RLIMIT_STACK) | ||
155 | |||
156 | int _mu_prog_limit_flags = _MU_PROG_AVAILABLE_LIMITS; | ||
157 | |||
158 | int _mu_prog_limit_codes[_MU_PROG_LIMIT_MAX] = { | ||
159 | RLIMIT_AS, | ||
160 | RLIMIT_CPU, | ||
161 | RLIMIT_DATA, | ||
162 | RLIMIT_FSIZE, | ||
163 | RLIMIT_NPROC, | ||
164 | RLIMIT_CORE, | ||
165 | RLIMIT_MEMLOCK, | ||
166 | RLIMIT_NOFILE, | ||
167 | RLIMIT_RSS, | ||
168 | RLIMIT_STACK | ||
169 | }; | ||
170 | |||
74 | static int | 171 | static int |
75 | start_program_filter (pid_t *pid, int *p, int argc, char **argv, | 172 | start_program_filter (int *p, struct _mu_prog_stream *fs, int flags) |
76 | char *errfile, int flags) | ||
77 | { | 173 | { |
78 | int rightp[2], leftp[2]; | 174 | int rightp[2], leftp[2]; |
79 | int i; | 175 | int i; |
... | @@ -84,7 +180,7 @@ start_program_filter (pid_t *pid, int *p, int argc, char **argv, | ... | @@ -84,7 +180,7 @@ start_program_filter (pid_t *pid, int *p, int argc, char **argv, |
84 | if (REDIRECT_STDOUT_P (flags)) | 180 | if (REDIRECT_STDOUT_P (flags)) |
85 | pipe (rightp); | 181 | pipe (rightp); |
86 | 182 | ||
87 | switch (*pid = fork ()) | 183 | switch (fs->pid = fork ()) |
88 | { | 184 | { |
89 | /* The child branch. */ | 185 | /* The child branch. */ |
90 | case 0: | 186 | case 0: |
... | @@ -111,28 +207,69 @@ start_program_filter (pid_t *pid, int *p, int argc, char **argv, | ... | @@ -111,28 +207,69 @@ start_program_filter (pid_t *pid, int *p, int argc, char **argv, |
111 | } | 207 | } |
112 | close (leftp[1]); | 208 | close (leftp[1]); |
113 | } | 209 | } |
210 | |||
211 | if (fs->hint_flags & MU_PROG_HINT_ERRTOOUT) | ||
212 | dup2 (1, 2); | ||
114 | 213 | ||
115 | /* Error output */ | 214 | if (fs->hint_flags & MU_PROG_HINT_WORKDIR) |
116 | if (errfile) | ||
117 | { | 215 | { |
118 | i = open (errfile, O_CREAT|O_WRONLY|O_APPEND, 0644); | 216 | if (chdir (fs->hints.mu_prog_workdir)) |
119 | if (i > 0 && i != 2) | ||
120 | { | 217 | { |
121 | dup2 (i, 2); | 218 | mu_error (_("cannot change to %s: %s"), |
122 | close (i); | 219 | fs->hints.mu_prog_workdir, mu_strerror (errno)); |
220 | if (!(fs->hint_flags & MU_PROG_HINT_IGNOREFAIL)) | ||
221 | _exit (127); | ||
123 | } | 222 | } |
124 | } | 223 | } |
224 | |||
225 | if (fs->hint_flags & MU_PROG_HINT_UID) | ||
226 | { | ||
227 | if (mu_set_user_privileges (fs->hints.mu_prog_uid, | ||
228 | fs->hints.mu_prog_gidv, | ||
229 | fs->hints.mu_prog_gidc) | ||
230 | && !(fs->hint_flags & MU_PROG_HINT_IGNOREFAIL)) | ||
231 | _exit (127); | ||
232 | } | ||
233 | |||
234 | for (i = 0; i < _MU_PROG_LIMIT_MAX; i++) | ||
235 | { | ||
236 | if (MU_PROG_HINT_LIMIT(i) & fs->hint_flags) | ||
237 | { | ||
238 | struct rlimit rlim; | ||
239 | |||
240 | rlim.rlim_cur = rlim.rlim_max = fs->hints.mu_prog_limit[i]; | ||
241 | if (setrlimit (_mu_prog_limit_codes[i], &rlim)) | ||
242 | { | ||
243 | mu_error (_("error setting limit %d to %lu: %s"), | ||
244 | i, (unsigned long) rlim.rlim_cur, | ||
245 | mu_strerror (errno)); | ||
246 | if (!(fs->hint_flags & MU_PROG_HINT_IGNOREFAIL)) | ||
247 | _exit (127); | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | if (MU_PROG_HINT_PRIO & fs->hint_flags) | ||
252 | { | ||
253 | if (setpriority (PRIO_PROCESS, 0, fs->hints.mu_prog_prio)) | ||
254 | { | ||
255 | mu_error (_("error setting priority: %s"), | ||
256 | mu_strerror (errno)); | ||
257 | if (!(fs->hint_flags & MU_PROG_HINT_IGNOREFAIL)) | ||
258 | _exit (127); | ||
259 | } | ||
260 | } | ||
261 | |||
125 | /* Close unneded descripitors */ | 262 | /* Close unneded descripitors */ |
126 | for (i = getmaxfd (); i > 2; i--) | 263 | for (i = getmaxfd (); i > 2; i--) |
127 | close (i); | 264 | close (i); |
128 | 265 | ||
129 | /*FIXME: Switch to other uid/gid if desired */ | 266 | /*FIXME: Switch to other uid/gid if desired */ |
130 | execvp (argv[0], argv); | 267 | execvp (fs->progname, fs->argv); |
131 | 268 | ||
132 | /* Report error via syslog */ | 269 | /* Report error via syslog */ |
133 | syslog (LOG_ERR|LOG_USER, "can't run %s (ruid=%d, euid=%d): %m", | 270 | syslog (LOG_ERR|LOG_USER, "can't run %s (ruid=%d, euid=%d): %m", |
134 | argv[0], getuid (), geteuid ()); | 271 | fs->progname, getuid (), geteuid ()); |
135 | exit (127); | 272 | _exit (127); |
136 | /********************/ | 273 | /********************/ |
137 | 274 | ||
138 | /* Parent branches: */ | 275 | /* Parent branches: */ |
... | @@ -187,10 +324,16 @@ _prog_wait (pid_t pid, int *pstatus) | ... | @@ -187,10 +324,16 @@ _prog_wait (pid_t pid, int *pstatus) |
187 | static void | 324 | static void |
188 | _prog_done (mu_stream_t stream) | 325 | _prog_done (mu_stream_t stream) |
189 | { | 326 | { |
190 | struct _mu_prog_stream *fs = (struct _mu_prog_stream *) stream; | ||
191 | int status; | 327 | int status; |
328 | struct _mu_prog_stream *fs = (struct _mu_prog_stream *) stream; | ||
192 | 329 | ||
193 | mu_argcv_free (fs->argc, fs->argv); | 330 | mu_argcv_free (fs->argc, fs->argv); |
331 | free (fs->progname); | ||
332 | if (fs->hint_flags & MU_PROG_HINT_WORKDIR) | ||
333 | free (fs->hints.mu_prog_workdir); | ||
334 | if (fs->hint_flags & MU_PROG_HINT_INPUT) | ||
335 | mu_stream_unref (fs->hints.mu_prog_input); | ||
336 | |||
194 | if (fs->in) | 337 | if (fs->in) |
195 | mu_stream_destroy (&fs->in); | 338 | mu_stream_destroy (&fs->in); |
196 | if (fs->out) | 339 | if (fs->out) |
... | @@ -245,8 +388,6 @@ static int | ... | @@ -245,8 +388,6 @@ static int |
245 | feed_input (struct _mu_prog_stream *fs) | 388 | feed_input (struct _mu_prog_stream *fs) |
246 | { | 389 | { |
247 | pid_t pid; | 390 | pid_t pid; |
248 | size_t size; | ||
249 | char buffer[128]; | ||
250 | int rc = 0; | 391 | int rc = 0; |
251 | 392 | ||
252 | pid = fork (); | 393 | pid = fork (); |
... | @@ -261,10 +402,7 @@ feed_input (struct _mu_prog_stream *fs) | ... | @@ -261,10 +402,7 @@ feed_input (struct _mu_prog_stream *fs) |
261 | 402 | ||
262 | case 0: | 403 | case 0: |
263 | /* Child */ | 404 | /* Child */ |
264 | while (mu_stream_read (fs->input, buffer, sizeof (buffer), | 405 | mu_stream_copy (fs->out, fs->hints.mu_prog_input, 0, NULL); |
265 | &size) == 0 | ||
266 | && size > 0) | ||
267 | mu_stream_write (fs->out, buffer, size, NULL); | ||
268 | mu_stream_close (fs->out); | 406 | mu_stream_close (fs->out); |
269 | exit (0); | 407 | exit (0); |
270 | 408 | ||
... | @@ -295,7 +433,7 @@ _prog_open (mu_stream_t stream) | ... | @@ -295,7 +433,7 @@ _prog_open (mu_stream_t stream) |
295 | mu_stream_get_flags (stream, &flags); | 433 | mu_stream_get_flags (stream, &flags); |
296 | seekable_flag = (flags & MU_STREAM_SEEK); | 434 | seekable_flag = (flags & MU_STREAM_SEEK); |
297 | 435 | ||
298 | rc = start_program_filter (&fs->pid, pfd, fs->argc, fs->argv, NULL, flags); | 436 | rc = start_program_filter (pfd, fs, flags); |
299 | if (rc) | 437 | if (rc) |
300 | return rc; | 438 | return rc; |
301 | 439 | ||
... | @@ -322,7 +460,7 @@ _prog_open (mu_stream_t stream) | ... | @@ -322,7 +460,7 @@ _prog_open (mu_stream_t stream) |
322 | } | 460 | } |
323 | 461 | ||
324 | _prog_stream_register (fs); | 462 | _prog_stream_register (fs); |
325 | if (fs->input) | 463 | if (fs->hint_flags & MU_PROG_HINT_INPUT) |
326 | return feed_input (fs); | 464 | return feed_input (fs); |
327 | return 0; | 465 | return 0; |
328 | } | 466 | } |
... | @@ -408,30 +546,25 @@ _prog_ioctl (struct _mu_stream *str, int code, int opcode, void *ptr) | ... | @@ -408,30 +546,25 @@ _prog_ioctl (struct _mu_stream *str, int code, int opcode, void *ptr) |
408 | return 0; | 546 | return 0; |
409 | } | 547 | } |
410 | 548 | ||
411 | struct _mu_prog_stream * | 549 | /* NOTE: Steals argv */ |
412 | _prog_stream_create (const char *progname, int flags) | 550 | static struct _mu_prog_stream * |
551 | _prog_stream_create (const char *progname, size_t argc, char **argv, | ||
552 | int hint_flags, struct mu_prog_hints *hints, int flags) | ||
413 | { | 553 | { |
414 | struct _mu_prog_stream *fs; | 554 | struct _mu_prog_stream *fs; |
415 | struct mu_wordsplit ws; | 555 | |
416 | |||
417 | fs = (struct _mu_prog_stream *) _mu_stream_create (sizeof (*fs), flags); | 556 | fs = (struct _mu_prog_stream *) _mu_stream_create (sizeof (*fs), flags); |
418 | if (!fs) | 557 | if (!fs) |
419 | return NULL; | 558 | return NULL; |
420 | 559 | ||
421 | ws.ws_comment = "#"; | 560 | fs->progname = strdup (progname); |
422 | if (mu_wordsplit (progname, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_COMMENT)) | 561 | if (!fs->progname) |
423 | { | 562 | { |
424 | mu_error (_("cannot split line `%s': %s"), progname, | ||
425 | mu_wordsplit_strerror (&ws)); | ||
426 | free (fs); | 563 | free (fs); |
427 | return NULL; | 564 | return NULL; |
428 | } | 565 | } |
429 | fs->argc = ws.ws_wordc; | 566 | fs->argc = argc; |
430 | fs->argv = ws.ws_wordv; | 567 | fs->argv = argv; |
431 | ws.ws_wordc = 0; | ||
432 | ws.ws_wordv = NULL; | ||
433 | mu_wordsplit_free (&ws); | ||
434 | |||
435 | fs->stream.read = _prog_read; | 568 | fs->stream.read = _prog_read; |
436 | fs->stream.write = _prog_write; | 569 | fs->stream.write = _prog_write; |
437 | fs->stream.open = _prog_open; | 570 | fs->stream.open = _prog_open; |
... | @@ -440,24 +573,95 @@ _prog_stream_create (const char *progname, int flags) | ... | @@ -440,24 +573,95 @@ _prog_stream_create (const char *progname, int flags) |
440 | fs->stream.flush = _prog_flush; | 573 | fs->stream.flush = _prog_flush; |
441 | fs->stream.done = _prog_done; | 574 | fs->stream.done = _prog_done; |
442 | 575 | ||
576 | if (!hints) | ||
577 | fs->hint_flags = 0; | ||
578 | else | ||
579 | { | ||
580 | fs->hint_flags = (hint_flags & _MU_PROG_HINT_MASK) | | ||
581 | (hint_flags & _MU_PROG_AVAILABLE_LIMITS); | ||
582 | if (fs->hint_flags & MU_PROG_HINT_WORKDIR) | ||
583 | { | ||
584 | fs->hints.mu_prog_workdir = strdup (hints->mu_prog_workdir); | ||
585 | if (!fs->hints.mu_prog_workdir) | ||
586 | { | ||
587 | free (fs); | ||
588 | return NULL; | ||
589 | } | ||
590 | } | ||
591 | memcpy (fs->hints.mu_prog_limit, hints->mu_prog_limit, | ||
592 | sizeof (fs->hints.mu_prog_limit)); | ||
593 | fs->hints.mu_prog_prio = hints->mu_prog_prio; | ||
594 | if (fs->hint_flags & MU_PROG_HINT_INPUT) | ||
595 | { | ||
596 | fs->hints.mu_prog_input = hints->mu_prog_input; | ||
597 | mu_stream_ref (fs->hints.mu_prog_input); | ||
598 | } | ||
599 | if (fs->hint_flags & MU_PROG_HINT_UID) | ||
600 | { | ||
601 | fs->hints.mu_prog_uid = hints->mu_prog_uid; | ||
602 | if (fs->hint_flags & MU_PROG_HINT_GID) | ||
603 | { | ||
604 | fs->hints.mu_prog_gidv = calloc (hints->mu_prog_gidc, | ||
605 | sizeof (fs->hints.mu_prog_gidv[0])); | ||
606 | if (!fs->hints.mu_prog_gidv) | ||
607 | { | ||
608 | mu_stream_unref ((mu_stream_t) fs); | ||
609 | return NULL; | ||
610 | } | ||
611 | memcpy (fs->hints.mu_prog_gidv, hints->mu_prog_gidv, | ||
612 | hints->mu_prog_gidc * fs->hints.mu_prog_gidv[0]); | ||
613 | fs->hints.mu_prog_gidc = hints->mu_prog_gidc; | ||
614 | } | ||
615 | else | ||
616 | { | ||
617 | fs->hints.mu_prog_gidc = 0; | ||
618 | fs->hints.mu_prog_gidv = NULL; | ||
619 | } | ||
620 | } | ||
621 | } | ||
622 | |||
443 | return fs; | 623 | return fs; |
444 | } | 624 | } |
445 | 625 | ||
446 | int | 626 | int |
447 | mu_prog_stream_create (mu_stream_t *pstream, const char *progname, int flags) | 627 | mu_prog_stream_create (mu_stream_t *pstream, |
628 | const char *progname, size_t argc, char **argv, | ||
629 | int hint_flags, | ||
630 | struct mu_prog_hints *hints, | ||
631 | int flags) | ||
448 | { | 632 | { |
449 | int rc; | 633 | int rc; |
450 | mu_stream_t stream; | 634 | mu_stream_t stream; |
451 | 635 | char **xargv; | |
636 | size_t i; | ||
637 | |||
452 | if (pstream == NULL) | 638 | if (pstream == NULL) |
453 | return MU_ERR_OUT_PTR_NULL; | 639 | return MU_ERR_OUT_PTR_NULL; |
454 | 640 | ||
455 | if (progname == NULL) | 641 | if (progname == NULL) |
456 | return EINVAL; | 642 | return EINVAL; |
457 | 643 | ||
458 | if ((stream = (mu_stream_t) _prog_stream_create (progname, flags)) == NULL) | 644 | xargv = calloc (argc + 1, sizeof (xargv[0])); |
645 | if (!xargv) | ||
459 | return ENOMEM; | 646 | return ENOMEM; |
460 | 647 | ||
648 | for (i = 0; i < argc; i++) | ||
649 | { | ||
650 | xargv[i] = strdup (argv[i]); | ||
651 | if (!xargv[i]) | ||
652 | { | ||
653 | mu_argcv_free (i, argv); | ||
654 | return ENOMEM; | ||
655 | } | ||
656 | } | ||
657 | stream = (mu_stream_t) _prog_stream_create (progname, argc, xargv, | ||
658 | hint_flags, hints, flags); | ||
659 | if (!stream) | ||
660 | { | ||
661 | mu_argcv_free (argc, xargv); | ||
662 | return ENOMEM; | ||
663 | } | ||
664 | |||
461 | rc = mu_stream_open (stream); | 665 | rc = mu_stream_open (stream); |
462 | if (rc) | 666 | if (rc) |
463 | mu_stream_destroy (&stream); | 667 | mu_stream_destroy (&stream); |
... | @@ -467,30 +671,38 @@ mu_prog_stream_create (mu_stream_t *pstream, const char *progname, int flags) | ... | @@ -467,30 +671,38 @@ mu_prog_stream_create (mu_stream_t *pstream, const char *progname, int flags) |
467 | } | 671 | } |
468 | 672 | ||
469 | int | 673 | int |
470 | mu_filter_prog_stream_create (mu_stream_t *pstream, const char *progname, | 674 | mu_command_stream_create (mu_stream_t *pstream, const char *command, |
471 | mu_stream_t input) | 675 | int flags) |
472 | { | 676 | { |
473 | int rc; | 677 | int rc; |
474 | mu_stream_t stream; | 678 | mu_stream_t stream; |
475 | struct _mu_prog_stream *fs; | 679 | struct mu_wordsplit ws; |
476 | 680 | ||
477 | if (pstream == NULL) | 681 | if (pstream == NULL) |
478 | return MU_ERR_OUT_PTR_NULL; | 682 | return MU_ERR_OUT_PTR_NULL; |
479 | 683 | ||
480 | if (progname == NULL) | 684 | if (command == NULL) |
481 | return EINVAL; | 685 | return EINVAL; |
482 | 686 | ||
483 | fs = _prog_stream_create (progname, MU_STREAM_RDWR); | 687 | ws.ws_comment = "#"; |
484 | if (!fs) | 688 | if (mu_wordsplit (command, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_COMMENT)) |
485 | return ENOMEM; | 689 | { |
486 | mu_stream_ref (input); | 690 | mu_error (_("cannot split line `%s': %s"), command, |
487 | fs->input = input; | 691 | mu_wordsplit_strerror (&ws)); |
488 | stream = (mu_stream_t) fs; | 692 | return errno; |
489 | rc = mu_stream_open (stream); | 693 | } |
490 | if (rc) | 694 | |
491 | mu_stream_destroy (&stream); | 695 | rc = mu_prog_stream_create (&stream, |
492 | else | 696 | ws.ws_wordv[0], |
493 | *pstream = stream; | 697 | ws.ws_wordc, ws.ws_wordv, |
698 | 0, NULL, flags); | ||
699 | if (rc == 0) | ||
700 | { | ||
701 | ws.ws_wordc = 0; | ||
702 | ws.ws_wordv = NULL; | ||
703 | *pstream = stream; | ||
704 | } | ||
705 | mu_wordsplit_free (&ws); | ||
706 | |||
494 | return rc; | 707 | return rc; |
495 | } | 708 | } |
496 | ... | ... |
... | @@ -39,6 +39,7 @@ | ... | @@ -39,6 +39,7 @@ |
39 | #include <signal.h> | 39 | #include <signal.h> |
40 | #include <regex.h> | 40 | #include <regex.h> |
41 | #include <mailutils/sieve.h> | 41 | #include <mailutils/sieve.h> |
42 | #include <mailutils/prog.h> | ||
42 | 43 | ||
43 | int | 44 | int |
44 | sieve_action_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) | 45 | sieve_action_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) |
... | @@ -86,7 +87,7 @@ sieve_action_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) | ... | @@ -86,7 +87,7 @@ sieve_action_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) |
86 | rc = mu_message_get_streamref (msg, &mstr); | 87 | rc = mu_message_get_streamref (msg, &mstr); |
87 | ONERR (rc, _("cannot get message stream"), NULL); | 88 | ONERR (rc, _("cannot get message stream"), NULL); |
88 | 89 | ||
89 | rc = mu_prog_stream_create (&pstr, cmd, MU_STREAM_WRITE); | 90 | rc = mu_command_stream_create (&pstr, cmd, MU_STREAM_WRITE); |
90 | ONERR (rc, _("cannot create command stream"), cmd); | 91 | ONERR (rc, _("cannot create command stream"), cmd); |
91 | 92 | ||
92 | if (mu_sieve_tag_lookup (tags, "envelope", &val)) | 93 | if (mu_sieve_tag_lookup (tags, "envelope", &val)) | ... | ... |
... | @@ -409,10 +409,11 @@ run_metamail (const char *mailcap_cmd, mu_message_t mesg) | ... | @@ -409,10 +409,11 @@ run_metamail (const char *mailcap_cmd, mu_message_t mesg) |
409 | break; | 409 | break; |
410 | } | 410 | } |
411 | 411 | ||
412 | status = mu_prog_stream_create (&pstr, mailcap_cmd, MU_STREAM_WRITE); | 412 | status = mu_command_stream_create (&pstr, mailcap_cmd, |
413 | MU_STREAM_WRITE); | ||
413 | if (status) | 414 | if (status) |
414 | { | 415 | { |
415 | mu_error ("mu_prog_stream_create: %s", mu_strerror (status)); | 416 | mu_error ("mu_command_stream_create: %s", mu_strerror (status)); |
416 | break; | 417 | break; |
417 | } | 418 | } |
418 | 419 | ... | ... |
... | @@ -82,6 +82,7 @@ | ... | @@ -82,6 +82,7 @@ |
82 | #include <mailutils/cstr.h> | 82 | #include <mailutils/cstr.h> |
83 | #include <mailutils/io.h> | 83 | #include <mailutils/io.h> |
84 | #include <mailutils/stdstream.h> | 84 | #include <mailutils/stdstream.h> |
85 | #include <mailutils/prog.h> | ||
85 | 86 | ||
86 | #ifdef __cplusplus | 87 | #ifdef __cplusplus |
87 | extern "C" { | 88 | extern "C" { | ... | ... |
... | @@ -38,7 +38,7 @@ mail_pipe (int argc, char **argv) | ... | @@ -38,7 +38,7 @@ mail_pipe (int argc, char **argv) |
38 | if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT, &list)) | 38 | if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT, &list)) |
39 | return 1; | 39 | return 1; |
40 | 40 | ||
41 | rc = mu_prog_stream_create (&outstr, cmd, MU_STREAM_WRITE); | 41 | rc = mu_command_stream_create (&outstr, cmd, MU_STREAM_WRITE); |
42 | if (rc) | 42 | if (rc) |
43 | { | 43 | { |
44 | mu_error (_("cannot open `%s': %s"), cmd, mu_strerror (rc)); | 44 | mu_error (_("cannot open `%s': %s"), cmd, mu_strerror (rc)); | ... | ... |
... | @@ -702,7 +702,7 @@ msg_to_pipe (const char *cmd, mu_message_t msg) | ... | @@ -702,7 +702,7 @@ msg_to_pipe (const char *cmd, mu_message_t msg) |
702 | mu_stream_t progstream, msgstream; | 702 | mu_stream_t progstream, msgstream; |
703 | int status, rc; | 703 | int status, rc; |
704 | 704 | ||
705 | status = mu_prog_stream_create (&progstream, cmd, MU_STREAM_WRITE); | 705 | status = mu_command_stream_create (&progstream, cmd, MU_STREAM_WRITE); |
706 | if (status) | 706 | if (status) |
707 | { | 707 | { |
708 | util_error (_("Cannot pipe to %s: %s"), cmd, mu_strerror (status)); | 708 | util_error (_("Cannot pipe to %s: %s"), cmd, mu_strerror (status)); | ... | ... |
... | @@ -56,6 +56,7 @@ | ... | @@ -56,6 +56,7 @@ |
56 | #include <mailutils/mime.h> | 56 | #include <mailutils/mime.h> |
57 | #include <mailutils/io.h> | 57 | #include <mailutils/io.h> |
58 | #include <mailutils/property.h> | 58 | #include <mailutils/property.h> |
59 | #include <mailutils/prog.h> | ||
59 | #include <mailutils/mh.h> | 60 | #include <mailutils/mh.h> |
60 | 61 | ||
61 | #include <mu_umaxtostr.h> | 62 | #include <mu_umaxtostr.h> | ... | ... |
... | @@ -149,7 +149,7 @@ open_output () | ... | @@ -149,7 +149,7 @@ open_output () |
149 | moreproc = NULL; | 149 | moreproc = NULL; |
150 | 150 | ||
151 | if (moreproc) | 151 | if (moreproc) |
152 | rc = mu_prog_stream_create (&output, moreproc, MU_STREAM_WRITE); | 152 | rc = mu_command_stream_create (&output, moreproc, MU_STREAM_WRITE); |
153 | else | 153 | else |
154 | rc = mu_stdio_stream_create (&output, MU_STDOUT_FD, MU_STREAM_WRITE); | 154 | rc = mu_stdio_stream_create (&output, MU_STDOUT_FD, MU_STREAM_WRITE); |
155 | 155 | ... | ... |
... | @@ -1403,7 +1403,7 @@ show_internal (mu_message_t msg, msg_part_t part, char *encoding, | ... | @@ -1403,7 +1403,7 @@ show_internal (mu_message_t msg, msg_part_t part, char *encoding, |
1403 | int | 1403 | int |
1404 | mhn_exec (mu_stream_t *str, const char *cmd, int flags) | 1404 | mhn_exec (mu_stream_t *str, const char *cmd, int flags) |
1405 | { | 1405 | { |
1406 | int rc = mu_prog_stream_create (str, cmd, MU_STREAM_WRITE); | 1406 | int rc = mu_command_stream_create (str, cmd, MU_STREAM_WRITE); |
1407 | if (rc) | 1407 | if (rc) |
1408 | { | 1408 | { |
1409 | mu_error (_("cannot create proc stream (command %s): %s"), | 1409 | mu_error (_("cannot create proc stream (command %s): %s"), |
... | @@ -1773,16 +1773,30 @@ store_handler (mu_message_t msg, msg_part_t part, char *type, char *encoding, | ... | @@ -1773,16 +1773,30 @@ store_handler (mu_message_t msg, msg_part_t part, char *type, char *encoding, |
1773 | break; | 1773 | break; |
1774 | 1774 | ||
1775 | case store_to_command: | 1775 | case store_to_command: |
1776 | /* FIXME: Change to homedir, reflect this in the message below. | 1776 | { |
1777 | Chdir should better be implemented within mu_prog_stream_create | 1777 | struct mu_prog_hints hints; |
1778 | Example message: | 1778 | struct mu_wordsplit ws; |
1779 | storing msg 4 part 1 using command (cd /home/gray; less) | 1779 | |
1780 | */ | 1780 | hints.mu_prog_workdir = mu_get_homedir (); |
1781 | printf (_("storing msg %s part %s using command %s\n"), | 1781 | ws.ws_comment = "#"; |
1782 | prefix, partstr, name); | 1782 | if (mu_wordsplit (name, &ws, MU_WRDSF_DEFFLAGS|MU_WRDSF_COMMENT)) |
1783 | rc = mu_prog_stream_create (&out, name, MU_STREAM_WRITE); | 1783 | { |
1784 | if (rc) | 1784 | mu_error (_("cannot split line `%s': %s"), name, |
1785 | mu_diag_funcall (MU_DIAG_ERROR, "mu_prog_stream_create", NULL, rc); | 1785 | mu_wordsplit_strerror (&ws)); |
1786 | break; | ||
1787 | } | ||
1788 | |||
1789 | printf (_("storing msg %s part %s using command (cd %s; %s)\n"), | ||
1790 | prefix, partstr, hints.mu_prog_workdir, name); | ||
1791 | rc = mu_prog_stream_create (&out, | ||
1792 | ws.ws_wordv[0], | ||
1793 | ws.ws_wordc, ws.ws_wordv, | ||
1794 | MU_PROG_HINT_WORKDIR, | ||
1795 | &hints, MU_STREAM_WRITE); | ||
1796 | mu_wordsplit_free (&ws); | ||
1797 | if (rc) | ||
1798 | mu_diag_funcall (MU_DIAG_ERROR, "mu_prog_stream_create", NULL, rc); | ||
1799 | } | ||
1786 | break; | 1800 | break; |
1787 | 1801 | ||
1788 | case store_to_stdout: | 1802 | case store_to_stdout: | ... | ... |
... | @@ -247,7 +247,7 @@ mkdir Mail/inbox | ... | @@ -247,7 +247,7 @@ mkdir Mail/inbox |
247 | cp $abs_top_srcdir/testsuite/mh/mbox1/4 Mail/inbox | 247 | cp $abs_top_srcdir/testsuite/mh/mbox1/4 Mail/inbox |
248 | echo "Current-Folder: inbox" > Mail/context | 248 | echo "Current-Folder: inbox" > Mail/context |
249 | echo "mhn-store-text: | $abs_top_srcdir/mh/tests/mhed -" >> $MH | 249 | echo "mhn-store-text: | $abs_top_srcdir/mh/tests/mhed -" >> $MH |
250 | mhn +inbox -store -part 1 4 | sed "s|$abs_top_srcdir/mh/tests/||;s| *$||" || exit $? | 250 | mhn +inbox -store -part 1 4 | sed "s|$abs_top_srcdir/mh/tests/||;s|(cd \(.*\)\;|(cd home\;|;s| *$||" || exit $? |
251 | ], | 251 | ], |
252 | [0], | 252 | [0], |
253 | [-- Editor invocation: - | 253 | [-- Editor invocation: - |
... | @@ -263,7 +263,7 @@ But, now that I'm perfectly sure I have none, | ... | @@ -263,7 +263,7 @@ But, now that I'm perfectly sure I have none, |
263 | Why, I do it again and again.' | 263 | Why, I do it again and again.' |
264 | 264 | ||
265 | -- Input file end | 265 | -- Input file end |
266 | storing msg 4 part 1 using command mhed - | 266 | storing msg 4 part 1 using command (cd home; mhed -) |
267 | ]) | 267 | ]) |
268 | 268 | ||
269 | dnl ------------------------------------------------------------------- | 269 | dnl ------------------------------------------------------------------- | ... | ... |
... | @@ -240,7 +240,7 @@ mutool_open_pager () | ... | @@ -240,7 +240,7 @@ mutool_open_pager () |
240 | if (mutool_shell_interactive && (pager = getenv ("PAGER")) != NULL) | 240 | if (mutool_shell_interactive && (pager = getenv ("PAGER")) != NULL) |
241 | { | 241 | { |
242 | mu_stream_t stream; | 242 | mu_stream_t stream; |
243 | int rc = mu_prog_stream_create (&stream, pager, MU_STREAM_WRITE); | 243 | int rc = mu_command_stream_create (&stream, pager, MU_STREAM_WRITE); |
244 | if (rc == 0) | 244 | if (rc == 0) |
245 | return stream; | 245 | return stream; |
246 | mu_error (_("cannot start pager: %s"), mu_strerror (rc)); | 246 | mu_error (_("cannot start pager: %s"), mu_strerror (rc)); | ... | ... |
... | @@ -118,6 +118,7 @@ mail/unalias.c | ... | @@ -118,6 +118,7 @@ mail/unalias.c |
118 | mail/util.c | 118 | mail/util.c |
119 | mail/z.c | 119 | mail/z.c |
120 | 120 | ||
121 | libmailutils/base/userprivs.c | ||
121 | libmailutils/cfg/driver.c | 122 | libmailutils/cfg/driver.c |
122 | libmailutils/cfg/format.c | 123 | libmailutils/cfg/format.c |
123 | libmailutils/cfg/lexer.l | 124 | libmailutils/cfg/lexer.l | ... | ... |
-
Please register or sign in to post a comment