"Fossies" - the Fresh Open Source Software Archive 
Member "amavisd-milter-1.7.2/amavisd-milter/main.c" (27 Jan 2019, 16694 Bytes) of package /linux/privat/amavisd-milter-1.7.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "main.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Copyright (c) 2005, Petr Rehor <rx@rx.cz>. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "amavisd-milter.h"
30
31 #include <stdarg.h>
32 #include <sys/socket.h>
33 #include <sysexits.h>
34
35
36 /*
37 ** GLOBAL VARIABLES
38 */
39 int daemonize = 1;
40 int daemonized = 0;
41 int debug_level = LOG_WARNING;
42 int max_conns = 0;
43 int max_wait = 5 * 60;
44 sem_t max_sem_t;
45 sem_t *max_sem = NULL;
46 const char *pid_file = LOCAL_STATE_DIR "/" PACKAGE ".pid";
47 char *mlfi_socket = LOCAL_STATE_DIR "/" PACKAGE ".sock";
48 #ifdef HAVE_SMFI_SETBACKLOG
49 int mlfi_socket_backlog = 0;
50 #endif
51 long mlfi_timeout = 600;
52 const char *amavisd_socket = LOCAL_STATE_DIR "/amavisd.sock";
53 long amavisd_timeout = 600;
54 int ignore_amavisd_error = 0;
55 const char *working_dir = WORKING_DIR;
56 const char *delivery_care_of = "client";
57 int policybank_from_daemon_name = 0;
58
59
60 /*
61 ** USAGE - Print usage info
62 */
63 static void
64 usage(const char *progname)
65 {
66 (void) fprintf(stdout, "\nUsage: %s [OPTIONS]\n", progname);
67 (void) fprintf(stdout, "Options are:\n");
68 (void) fprintf(stdout, " -B Use daemon_name policy bank\n");
69 (void) fprintf(stdout, " -d debug-level Set debug level\n");
70 (void) fprintf(stdout, " -D delivery Delivery care of server or client\n");
71 (void) fprintf(stdout, " -f Run in the foreground\n");
72 (void) fprintf(stdout, " -h Print this page\n");
73 (void) fprintf(stdout, " -m max-conns Maximum amavisd connections \n");
74 (void) fprintf(stdout, " -M max-wait Maximum wait for connection in seconds\n");
75 (void) fprintf(stdout, " -p pidfile Use this pid file\n");
76 (void) fprintf(stdout, " -P When amavisd fails mail will be passed\n through unchecked\n");
77 #ifdef HAVE_SMFI_SETBACKLOG
78 (void) fprintf(stdout, " -q backlog Milter communication socket backlog\n");
79 #endif
80 (void) fprintf(stdout, " -s socket Milter communication socket\n");
81 (void) fprintf(stdout, " -S socket Amavisd communication socket\n");
82 (void) fprintf(stdout, " -t timeout Milter connection timeout in seconds\n");
83 (void) fprintf(stdout, " -T timeout Amavisd connection timeout in seconds\n");
84 (void) fprintf(stdout, " -v Report the version and exit\n");
85 (void) fprintf(stdout, " -w directory Set the working directory\n\n");
86 }
87
88
89 /*
90 ** USAGEERR - Print error message, program usage and then exit
91 */
92 static void
93 usageerr(const char *progname, const char *fmt, ...)
94 {
95 char buf[MAXLOGBUF];
96 va_list ap;
97
98 /* Format err message */
99 va_start(ap, fmt);
100 (void) vsnprintf(buf, sizeof(buf), fmt, ap);
101 va_end(ap);
102
103 /* Print error message, program usage and then exit */
104 (void) fprintf(stderr, "%s: %s\n", progname , buf);
105 usage(progname);
106 exit(EX_USAGE);
107 }
108
109
110 /*
111 ** VERSIONINFO - Print program version info
112 */
113 static void
114 versioninfo(const char *progname)
115 {
116 (void) fprintf(stdout, "%s %s\n", progname, VERSION);
117 }
118
119
120 /*
121 ** MAIN - Main program loop
122 */
123 int
124 main(int argc, char *argv[])
125 {
126 static const char *args = "Bd:D:fhm:M:p:Pq:s:S:t:T:vw:";
127
128 int c, rstat;
129 char *p;
130 const char *progname, *socket_name;
131 FILE *fp;
132 struct stat st;
133 mode_t save_umask;
134 struct sockaddr_un unix_addr;
135
136 /* Program name */
137 p = strrchr(argv[0], '/');
138 if (p == NULL) {
139 progname = argv[0];
140 } else {
141 progname = p + 1;
142 }
143
144 /* Open syslog */
145 openlog(progname, LOG_PID, LOG_MAIL);
146
147 /* Process command line options */
148 while ((c = getopt(argc, argv, args)) != EOF) {
149 switch (c) {
150 case 'B': /* use daemon_name policy bank */
151 policybank_from_daemon_name = 1;
152 break;
153 case 'd': /* debug level */
154 if (optarg == NULL || *optarg == '\0') {
155 usageerr(progname, "option requires an argument -- %c",
156 (char)c);
157 }
158 debug_level = (int) strtol(optarg, &p, 10);
159 if (p != NULL && *p != '\0') {
160 usageerr(progname, "debug level is not valid number: %s",
161 optarg);
162 }
163 if (debug_level < 0) {
164 usageerr(progname, "negative debug level: %d", debug_level);
165 }
166 debug_level += LOG_WARNING;
167 break;
168 case 'D': /* delivery mechanism */
169 if (optarg == NULL || *optarg == '\0') {
170 usageerr(progname, "option requires an argument -- %c",
171 (char)c);
172 }
173 if (strcmp(optarg, "client") != 0 &&
174 strcmp(optarg, "server") != 0)
175 {
176 usageerr(progname, "unknown delivery mechanism '%s'", optarg);
177 }
178 delivery_care_of = optarg;
179 break;
180 case 'f': /* run in foreground */
181 daemonize = 0;
182 break;
183 case '?': /* options parsing error */
184 (void) fprintf(stderr, "\n");
185 case 'h': /* help */
186 usage(progname);
187 exit(EX_OK);
188 break;
189 case 'm': /* maximum amavisd connections */
190 max_conns = (int) strtol(optarg, &p, 10);
191 if (p != NULL && *p != '\0') {
192 usageerr(progname,
193 "maximum amavisd connections is not valid number: %s",
194 optarg);
195 }
196 if (max_conns < 0) {
197 usageerr(progname, "negative maximum amavisd connections: %d",
198 max_conns);
199 }
200 break;
201 case 'M': /* maximum wait for connection */
202 max_wait = (int) strtol(optarg, &p, 10);
203 if (p != NULL && *p != '\0') {
204 usageerr(progname,
205 "maximum wait for connection is not valid number: %s",
206 optarg);
207 }
208 if (max_wait < 0) {
209 usageerr(progname, "negative maximum wait for connection: %d",
210 max_wait);
211 }
212 break;
213 case 'p': /* pid file name */
214 if (optarg == NULL || *optarg == '\0') {
215 usageerr(progname, "option requires an argument -- %c",
216 (char)c);
217 }
218 pid_file = optarg;
219 break;
220 case 'P': /* when amavisd fails mail will be passed */
221 ignore_amavisd_error = 1; /* through unchecked */
222 break;
223 #ifdef HAVE_SMFI_SETBACKLOG
224 case 'q': /* milter communication socket backlog */
225 mlfi_socket_backlog = (int) strtol(optarg, &p, 10);
226 if (p != NULL && *p != '\0') {
227 usageerr(progname,
228 "milter communication socket backlog is not valid number: "
229 "%s", optarg);
230 }
231 if (mlfi_socket_backlog < 0) {
232 usageerr(progname,
233 "negative milter communication socket backlog: %d",
234 mlfi_socket_backlog);
235 }
236 break;
237 #endif
238 case 's': /* milter communication socket */
239 if (optarg == NULL || *optarg == '\0') {
240 usageerr(progname, "option requires an argument -- %c",
241 (char)c);
242 }
243 if (strlen(optarg) >= sizeof(unix_addr.sun_path) - 1) {
244 usageerr(progname,
245 "milter communication socket name too long: %s", optarg);
246 }
247 mlfi_socket = optarg;
248 break;
249 case 't': /* milter connection timeout */
250 if (optarg == NULL || *optarg == '\0') {
251 usageerr(progname, "option requires an argument -- %c",
252 (char)c);
253 }
254 mlfi_timeout = (int) strtol(optarg, &p, 10);
255 if (p != NULL && *p != '\0') {
256 usageerr(progname,
257 "milter connection timeout is not valid number: %s",
258 optarg);
259 }
260 if (mlfi_timeout < 0) {
261 usageerr(progname, "negative milter connection timeout: %ld",
262 mlfi_timeout);
263 }
264 break;
265 case 'v': /* version info */
266 versioninfo(progname);
267 exit(EX_OK);
268 break;
269 case 'w': /* working directory */
270 if (optarg == NULL || *optarg == '\0') {
271 usageerr(progname, "option requires an argument -- %c",
272 (char)c);
273 }
274 working_dir = optarg;
275 break;
276 case 'S': /* amavisd communication socket */
277 if (optarg == NULL || *optarg == '\0') {
278 usageerr(progname, "option requires an argument -- %c",
279 (char)c);
280 }
281 if (strlen(optarg) >= sizeof(unix_addr.sun_path) - 1) {
282 usageerr(progname,
283 "amavisd communication socket name too long: %s", optarg);
284 }
285 amavisd_socket = optarg;
286 break;
287 case 'T': /* amavisd connection timeout */
288 if (optarg == NULL || *optarg == '\0') {
289 usageerr(progname, "option requires an argument -- %c",
290 (char)c);
291 }
292 amavisd_timeout = (int) strtol(optarg, &p, 10);
293 if (p != NULL && *p != '\0') {
294 usageerr(progname,
295 "amavisd connection timeout is not valid number: %s",
296 optarg);
297 }
298 if (amavisd_timeout < 0) {
299 usageerr(progname, "negative amavisd connection timeout: %ld",
300 amavisd_timeout);
301 }
302 break;
303 default: /* unknown option */
304 usageerr(progname, "illegal option -- %c", (char)c);
305 break;
306 }
307 }
308
309 /* Create amavisd connections semaphore */
310 if (max_conns > 0) {
311 if (sem_init(&max_sem_t, 0, max_conns) == -1) {
312 logmsg(LOG_ERR,
313 "could not initialize amavisd connections semaphore: %s",
314 strerror(errno));
315 exit(EX_SOFTWARE);
316 } else {
317 max_sem = &max_sem_t;
318 }
319 }
320
321 /* Check permissions on working directory */
322 /* TODO: traverse working directory path */
323 if (stat(working_dir, &st) != 0) {
324 logmsg(LOG_ERR, "could not stat() to working directory %s: %s",
325 working_dir, strerror(errno));
326 exit(EX_SOFTWARE);
327 }
328 if (!S_ISDIR(st.st_mode)) {
329 logmsg(LOG_ERR, "%s is not directory", working_dir);
330 exit(EX_SOFTWARE);
331 }
332 if ((st.st_mode & S_IRWXO) != 0) {
333 logmsg(LOG_ERR, "working directory %s is world accessible", working_dir);
334 exit(EX_SOFTWARE);
335 }
336
337 /* Configure milter */
338 socket_name = NULL;
339 if (mlfi_socket[0] == '/') {
340 socket_name = mlfi_socket;
341 }
342 if (! strncmp(mlfi_socket, "unix:", 5)) {
343 socket_name = mlfi_socket + 5;
344 }
345 if (! strncmp(mlfi_socket, "local:", 6)) {
346 socket_name = mlfi_socket + 6;
347 }
348 if (socket_name != NULL && unlink(socket_name) != 0 && errno != ENOENT) {
349 logmsg(LOG_ERR, "could not unlink old milter socket %s: %s",
350 socket_name, strerror(errno));
351 exit(EX_SOFTWARE);
352 }
353 if (debug_level > LOG_DEBUG &&
354 smfi_setdbg(debug_level - LOG_DEBUG) != MI_SUCCESS)
355 {
356 logmsg(LOG_ERR, "could not set milter debug level");
357 exit(EX_SOFTWARE);
358 }
359 if (mlfi_timeout > 0 && smfi_settimeout(mlfi_timeout) != MI_SUCCESS) {
360 logmsg(LOG_ERR, "could not set milter timeout");
361 exit(EX_SOFTWARE);
362 }
363 if (smfi_setconn(mlfi_socket) != MI_SUCCESS) {
364 logmsg(LOG_ERR, "could not set milter socket");
365 exit(EX_SOFTWARE);
366 }
367 if (smfi_register(smfilter) != MI_SUCCESS) {
368 logmsg(LOG_ERR, "could not register milter");
369 exit(EX_SOFTWARE);
370 }
371
372 /* Unlink old pid file */
373 if (pid_file != NULL) {
374 if (unlink(pid_file) != 0 && errno != ENOENT) {
375 logmsg(LOG_WARNING, "could not unlink old pid file %s: %s",
376 pid_file, strerror(errno));
377 }
378 }
379
380 /* Connect to milter socket */
381 #ifdef HAVE_SMFI_SETBACKLOG
382 if (mlfi_socket_backlog > 0) {
383 if (smfi_setbacklog(mlfi_socket_backlog) != MI_SUCCESS) {
384 logmsg(LOG_WARNING, "could not set milter socket backlog to %d",
385 mlfi_socket_backlog);
386 }
387 }
388 #endif
389 #ifdef HAVE_SMFI_OPENSOCKET
390 if (smfi_opensocket(false) != MI_SUCCESS) {
391 logmsg(LOG_ERR, "could not open milter socket %s", mlfi_socket);
392 exit(EX_SOFTWARE);
393 }
394 #endif
395
396 /* Run in the background */
397 if (daemonize) {
398 if (daemon(1, 1) != -1) {
399 daemonized = 1;
400 } else {
401 logmsg(LOG_ERR, "could not fork daemon process: %s",
402 strerror(errno));
403 exit(EX_OSERR);
404 }
405 }
406
407 /* Greetings message */
408 logmsg(LOG_WARNING, "starting %s %s on socket %s", progname, VERSION,
409 mlfi_socket);
410
411 /* Create pid file */
412 if (pid_file != NULL) {
413 save_umask = umask(022);
414 fp = fopen(pid_file, "w");
415 if (fp == NULL) {
416 logmsg(LOG_WARNING, "could not create pid file %s: %s",
417 pid_file, strerror(errno));
418 } else {
419 (void) fprintf(fp, "%ld\n", (long) getpid());
420 if (ferror(fp)) {
421 logmsg(LOG_WARNING, "could not write to pid file %s: %s",
422 pid_file, strerror(errno));
423 clearerr(fp);
424 (void) fclose(fp);
425 } else if (fclose(fp) != 0) {
426 logmsg(LOG_WARNING, "could not close pid file %s: %s",
427 pid_file, strerror(errno));
428 }
429 }
430 umask(save_umask);
431 }
432
433 /* Run milter */
434 if ((rstat = smfi_main()) != MI_SUCCESS) {
435 logmsg(LOG_ERR, "%s failed", progname);
436 } else {
437 logmsg(LOG_WARNING, "stopping %s %s on socket %s", progname, VERSION,
438 mlfi_socket);
439 }
440
441 /* Unlink pid file */
442 if (pid_file != NULL) {
443 if (unlink(pid_file) != 0) {
444 logmsg(LOG_WARNING, "could not unlink pid file %s: %s",
445 pid_file, strerror(errno));
446 }
447 }
448
449 /* Destroy amavisd connections semaphore */
450 if (max_sem != NULL && sem_destroy(max_sem) == -1) {
451 logmsg(errno == EBUSY ? LOG_ERR : LOG_WARNING,
452 "%s: could not destroy amavisd connections semaphore: %s",
453 progname, strerror(errno));
454 }
455
456 return rstat;
457 }