maidag: improve forwarding capability, add a testcase for it.
* maidag/forward.c (check_forward_permissions): Keep track of the processed files. Refuse to process a file twice. (process_forward): Rewrite using streams instead of FILE. (maidag_forward): Accept absolute file names (mainly for testing). * maidag/maidag.c (forward_checks): New keyword "owner". (cb2_forward_file_checks): New keyword "none". (main): Require at least one recipient in MDA mode. * maidag/maidag.h (FWD_OWNER): New mask. * maidag/tests/forward.at: New file. * maidag/tests/Makefile.am (TESTSUITE_AT): Add forward.at * maidag/tests/testsuite.at: Include forward.at.
Showing
6 changed files
with
97 additions
and
15 deletions
... | @@ -74,6 +74,52 @@ static struct perm_checker perm_check_tab[] = { | ... | @@ -74,6 +74,52 @@ static struct perm_checker perm_check_tab[] = { |
74 | { 0 } | 74 | { 0 } |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static mu_list_t idlist; | ||
78 | |||
79 | struct file_id | ||
80 | { | ||
81 | dev_t dev; | ||
82 | ino_t inode; | ||
83 | }; | ||
84 | |||
85 | static int | ||
86 | file_id_cmp (const void *item, const void *data) | ||
87 | { | ||
88 | const struct file_id *a = item; | ||
89 | const struct file_id *b = data; | ||
90 | |||
91 | if (a->dev != b->dev) | ||
92 | return 1; | ||
93 | if (a->inode != b->inode) | ||
94 | return 1; | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int | ||
99 | file_id_lookup (dev_t dev, ino_t ino) | ||
100 | { | ||
101 | struct file_id id; | ||
102 | |||
103 | id.dev = dev; | ||
104 | id.inode = ino; | ||
105 | return mu_list_locate (idlist, &id, NULL); | ||
106 | } | ||
107 | |||
108 | static int | ||
109 | file_id_remember (dev_t dev, ino_t ino) | ||
110 | { | ||
111 | struct file_id *id = malloc (sizeof (*id)); | ||
112 | if (!id) | ||
113 | { | ||
114 | mu_error ("%s", mu_strerror (errno)); | ||
115 | return 1; | ||
116 | } | ||
117 | id->dev = dev; | ||
118 | id->inode = ino; | ||
119 | return mu_list_append (idlist, id); | ||
120 | } | ||
121 | |||
122 | |||
77 | /* Check if the forwrd file FILENAME has right permissions and file mode. | 123 | /* Check if the forwrd file FILENAME has right permissions and file mode. |
78 | DIRST describes the directory holding the file, AUTH gives current user | 124 | DIRST describes the directory holding the file, AUTH gives current user |
79 | authority. */ | 125 | authority. */ |
... | @@ -87,7 +133,21 @@ check_forward_permissions (const char *filename, struct stat *dirst, | ... | @@ -87,7 +133,21 @@ check_forward_permissions (const char *filename, struct stat *dirst, |
87 | { | 133 | { |
88 | int i; | 134 | int i; |
89 | 135 | ||
90 | if (auth->uid != st.st_uid) | 136 | if (!idlist) |
137 | { | ||
138 | mu_list_create (&idlist); | ||
139 | mu_list_set_comparator (idlist, file_id_cmp); | ||
140 | } | ||
141 | else if (file_id_lookup (st.st_dev, st.st_ino) == 0) | ||
142 | { | ||
143 | mu_diag_output (MU_DIAG_NOTICE, | ||
144 | _("skipping forward file %s: already processed"), | ||
145 | filename); | ||
146 | return 1; | ||
147 | } | ||
148 | |||
149 | if ((forward_file_checks & FWD_OWNER) && | ||
150 | auth->uid != st.st_uid) | ||
91 | { | 151 | { |
92 | mu_error (_("%s not owned by %s"), filename, auth->name); | 152 | mu_error (_("%s not owned by %s"), filename, auth->name); |
93 | return 1; | 153 | return 1; |
... | @@ -99,6 +159,7 @@ check_forward_permissions (const char *filename, struct stat *dirst, | ... | @@ -99,6 +159,7 @@ check_forward_permissions (const char *filename, struct stat *dirst, |
99 | mu_error ("%s: %s", filename, gettext (perm_check_tab[i].descr)); | 159 | mu_error ("%s: %s", filename, gettext (perm_check_tab[i].descr)); |
100 | return 1; | 160 | return 1; |
101 | } | 161 | } |
162 | file_id_remember (st.st_dev, st.st_ino); | ||
102 | return 0; | 163 | return 0; |
103 | } | 164 | } |
104 | else if (errno != ENOENT) | 165 | else if (errno != ENOENT) |
... | @@ -203,22 +264,23 @@ create_from_address (mu_message_t msg, mu_address_t *pfrom) | ... | @@ -203,22 +264,23 @@ create_from_address (mu_message_t msg, mu_address_t *pfrom) |
203 | enum maidag_forward_result | 264 | enum maidag_forward_result |
204 | process_forward (mu_message_t msg, char *filename, const char *myname) | 265 | process_forward (mu_message_t msg, char *filename, const char *myname) |
205 | { | 266 | { |
206 | FILE *fp; | 267 | int rc; |
207 | size_t size = 0; | 268 | mu_stream_t file; |
269 | size_t size = 0, n; | ||
208 | char *buf = NULL; | 270 | char *buf = NULL; |
209 | enum maidag_forward_result result = maidag_forward_ok; | 271 | enum maidag_forward_result result = maidag_forward_ok; |
210 | mu_mailer_t mailer = NULL; | 272 | mu_mailer_t mailer = NULL; |
211 | mu_address_t from = NULL; | 273 | mu_address_t from = NULL; |
212 | 274 | ||
213 | fp = fopen (filename, "r"); | 275 | rc = mu_file_stream_create (&file, filename, MU_STREAM_READ); |
214 | if (!fp) | 276 | if (rc) |
215 | { | 277 | { |
216 | mu_error (_("%s: cannot open forward file: %s"), | 278 | mu_error (_("%s: cannot open forward file: %s"), |
217 | filename, mu_strerror (errno)); | 279 | filename, mu_strerror (rc)); |
218 | return maidag_forward_error; | 280 | return maidag_forward_error; |
219 | } | 281 | } |
220 | 282 | ||
221 | while (getline (&buf, &size, fp) > 0) | 283 | while (mu_stream_getline (file, &buf, &size, &n) == 0 && n > 0) |
222 | { | 284 | { |
223 | char *p; | 285 | char *p; |
224 | 286 | ||
... | @@ -256,7 +318,7 @@ process_forward (mu_message_t msg, char *filename, const char *myname) | ... | @@ -256,7 +318,7 @@ process_forward (mu_message_t msg, char *filename, const char *myname) |
256 | mu_mailer_destroy (&mailer); | 318 | mu_mailer_destroy (&mailer); |
257 | } | 319 | } |
258 | free (buf); | 320 | free (buf); |
259 | fclose (fp); | 321 | mu_stream_destroy (&file); |
260 | return result; | 322 | return result; |
261 | } | 323 | } |
262 | 324 | ||
... | @@ -269,6 +331,8 @@ maidag_forward (mu_message_t msg, struct mu_auth_data *auth, char *fwfile) | ... | @@ -269,6 +331,8 @@ maidag_forward (mu_message_t msg, struct mu_auth_data *auth, char *fwfile) |
269 | char *filename; | 331 | char *filename; |
270 | enum maidag_forward_result result = maidag_forward_none; | 332 | enum maidag_forward_result result = maidag_forward_none; |
271 | 333 | ||
334 | if (fwfile[0] != '/') | ||
335 | { | ||
272 | if (stat (auth->dir, &st)) | 336 | if (stat (auth->dir, &st)) |
273 | { | 337 | { |
274 | if (errno == ENOENT) | 338 | if (errno == ENOENT) |
... | @@ -281,6 +345,10 @@ maidag_forward (mu_message_t msg, struct mu_auth_data *auth, char *fwfile) | ... | @@ -281,6 +345,10 @@ maidag_forward (mu_message_t msg, struct mu_auth_data *auth, char *fwfile) |
281 | return maidag_forward_none; | 345 | return maidag_forward_none; |
282 | } | 346 | } |
283 | asprintf (&filename, "%s/%s", auth->dir, fwfile); | 347 | asprintf (&filename, "%s/%s", auth->dir, fwfile); |
348 | } | ||
349 | else | ||
350 | filename = strdup (fwfile); | ||
351 | |||
284 | if (!filename) | 352 | if (!filename) |
285 | { | 353 | { |
286 | mu_error ("%s", mu_strerror (errno)); | 354 | mu_error ("%s", mu_strerror (errno)); | ... | ... |
... | @@ -321,6 +321,7 @@ cb_group (mu_debug_t debug, void *data, mu_config_value_t *arg) | ... | @@ -321,6 +321,7 @@ cb_group (mu_debug_t debug, void *data, mu_config_value_t *arg) |
321 | 321 | ||
322 | static struct mu_kwd forward_checks[] = { | 322 | static struct mu_kwd forward_checks[] = { |
323 | { "all", FWD_ALL }, | 323 | { "all", FWD_ALL }, |
324 | { "owner", FWD_OWNER }, | ||
324 | { "groupwritablefile", FWD_IWGRP }, | 325 | { "groupwritablefile", FWD_IWGRP }, |
325 | { "file_iwgrp", FWD_IWGRP }, | 326 | { "file_iwgrp", FWD_IWGRP }, |
326 | { "worldwritablefile", FWD_IWOTH }, | 327 | { "worldwritablefile", FWD_IWOTH }, |
... | @@ -341,6 +342,12 @@ cb2_forward_file_checks (mu_debug_t debug, const char *name, void *data) | ... | @@ -341,6 +342,12 @@ cb2_forward_file_checks (mu_debug_t debug, const char *name, void *data) |
341 | const char *str; | 342 | const char *str; |
342 | int val; | 343 | int val; |
343 | 344 | ||
345 | if (strcmp (name, "none") == 0) | ||
346 | { | ||
347 | forward_file_checks = 0; | ||
348 | return 0; | ||
349 | } | ||
350 | |||
344 | if (strlen (name) > 2 && mu_c_strncasecmp (name, "no", 2) == 0) | 351 | if (strlen (name) > 2 && mu_c_strncasecmp (name, "no", 2) == 0) |
345 | { | 352 | { |
346 | negate = 1; | 353 | negate = 1; |
... | @@ -609,6 +616,11 @@ main (int argc, char *argv[]) | ... | @@ -609,6 +616,11 @@ main (int argc, char *argv[]) |
609 | break; | 616 | break; |
610 | 617 | ||
611 | case mode_mda: | 618 | case mode_mda: |
619 | if (argc == 0) | ||
620 | { | ||
621 | mu_error (_("recipients not given")); | ||
622 | return EX_USAGE; | ||
623 | } | ||
612 | delivery_fun = deliver_to_user; | 624 | delivery_fun = deliver_to_user; |
613 | break; | 625 | break; |
614 | } | 626 | } | ... | ... |
... | @@ -111,12 +111,13 @@ extern int debug_level; | ... | @@ -111,12 +111,13 @@ extern int debug_level; |
111 | #define EX_QUOTA() (ex_quota_tempfail ? EX_TEMPFAIL : EX_UNAVAILABLE) | 111 | #define EX_QUOTA() (ex_quota_tempfail ? EX_TEMPFAIL : EX_UNAVAILABLE) |
112 | 112 | ||
113 | /* .forward file checks */ | 113 | /* .forward file checks */ |
114 | #define FWD_IWGRP 0x0001 /* group writable forward file */ | 114 | #define FWD_OWNER 0x0001 /* file ownership */ |
115 | #define FWD_IWOTH 0x0002 /* world writable forward file */ | 115 | #define FWD_IWGRP 0x0002 /* group writable forward file */ |
116 | #define FWD_LINK 0x0004 /* linked forward file in writable dir */ | 116 | #define FWD_IWOTH 0x0004 /* world writable forward file */ |
117 | #define FWD_DIR_IWGRP 0x0008 /* forward file in group writable directory */ | 117 | #define FWD_LINK 0x0008 /* linked forward file in writable dir */ |
118 | #define FWD_DIR_IWOTH 0x0010 /* forward file in world writable directory */ | 118 | #define FWD_DIR_IWGRP 0x0010 /* forward file in group writable directory */ |
119 | #define FWD_ALL (FWD_IWGRP|FWD_IWOTH|FWD_LINK|FWD_DIR_IWOTH|FWD_DIR_IWGRP) | 119 | #define FWD_DIR_IWOTH 0x0020 /* forward file in world writable directory */ |
120 | #define FWD_ALL (FWD_OWNER|FWD_IWGRP|FWD_IWOTH|FWD_LINK|FWD_DIR_IWOTH|FWD_DIR_IWGRP) | ||
120 | 121 | ||
121 | enum maidag_mode | 122 | enum maidag_mode |
122 | { | 123 | { | ... | ... |
... | @@ -39,6 +39,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac | ... | @@ -39,6 +39,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac |
39 | ## ------------ ## | 39 | ## ------------ ## |
40 | 40 | ||
41 | TESTSUITE_AT = \ | 41 | TESTSUITE_AT = \ |
42 | forward.at\ | ||
42 | lmtp.at\ | 43 | lmtp.at\ |
43 | mda.at\ | 44 | mda.at\ |
44 | testsuite.at\ | 45 | testsuite.at\ | ... | ... |
... | @@ -95,7 +95,6 @@ if ![mu_check_capability ENABLE_SENDMAIL] { | ... | @@ -95,7 +95,6 @@ if ![mu_check_capability ENABLE_SENDMAIL] { |
95 | " 48: > All mimsy were the borogoves,"\ | 95 | " 48: > All mimsy were the borogoves,"\ |
96 | " 49: > And the mome raths outgrabe."\ | 96 | " 49: > And the mome raths outgrabe."\ |
97 | " 50: > "\ | 97 | " 50: > "\ |
98 | " 51: "\ | ||
99 | "END OF MESSAGE" | 98 | "END OF MESSAGE" |
100 | } | 99 | } |
101 | 100 | ... | ... |
-
Please register or sign in to post a comment