1 /*
2 daemon.c
3
4 This file is part of GNU Anubis.
5 Copyright (C) 2001-2014 The Anubis Team.
6
7 GNU Anubis is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 GNU Anubis is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with GNU Anubis. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "headers.h"
22 #include "extern.h"
23
24 /* TCP wrappers */
25 #ifdef USE_LIBWRAP
26 # include <tcpd.h>
27 int deny_severity = LOG_INFO;
28 int allow_severity = LOG_INFO;
29 #endif /* USE_LIBWRAP */
30
31 char *log_tag = "anubis";
32 int log_facility = LOG_MAIL;
33
34 /************
35 DAEMONIZE
36 *************/
37
38 void
daemonize(void)39 daemonize (void)
40 {
41 signal (SIGHUP, SIG_IGN);
42 #ifdef HAVE_DAEMON
43 if (daemon (0, 0) == -1)
44 anubis_error (EXIT_FAILURE, errno, _("daemon() failed"));
45 #else
46 chdir ("/");
47 umask (0);
48 switch (fork ())
49 {
50 case -1: /* fork() failed */
51 anubis_error (EXIT_FAILURE, errno, _("Cannot fork."));
52 break;
53 case 0: /* child process */
54 break;
55 default: /* parent process */
56 quit (0);
57 }
58 if (setsid () == -1)
59 anubis_error (EXIT_FAILURE, errno, _("setsid() failed"));
60
61 close (0);
62 close (1);
63 close (2);
64 #endif /* HAVE_DAEMON */
65
66 topt &= ~T_FOREGROUND;
67 topt |= T_DAEMON;
68
69 openlog (log_tag, LOG_PID, log_facility);
70 info (NORMAL, _("%s daemon startup succeeded."), version);
71 write_pid_file ();
72 return;
73 }
74
75 char *
format_exit_status(char * buffer,size_t buflen,int status)76 format_exit_status (char *buffer, size_t buflen, int status)
77 {
78 if (WIFEXITED(status))
79 {
80 if (WEXITSTATUS(status) == 0)
81 snprintf(buffer, buflen, _("Exited successfully"));
82 else
83 snprintf(buffer, buflen, _("Failed with status %d"),
84 WEXITSTATUS(status));
85 }
86 else if (WIFSIGNALED(status))
87 snprintf(buffer, buflen,
88 _("Terminated on signal %d"), WTERMSIG(status));
89 else if (WIFSTOPPED(status))
90 snprintf(buffer, buflen,
91 _("Stopped on signal %d"), WSTOPSIG(status));
92 #ifdef WCOREDUMP
93 else if (WCOREDUMP(status))
94 snprintf(buffer, buflen, _("Dumped core"));
95 #endif
96 else
97 snprintf(buffer, buflen, _("Terminated"));
98 return buffer;
99 }
100
101 static void
report_process_status(size_t count,pid_t pid,int status)102 report_process_status (size_t count, pid_t pid, int status)
103 {
104 char buffer[LINEBUFFER];
105
106 count--;
107 info (VERBOSE,
108 ngettext
109 ("Child [%lu] finished. %s. %d client left.",
110 "Child [%lu] finished. %s. %d clients left.",
111 count),
112 (unsigned long) pid,
113 format_exit_status (buffer, sizeof buffer, status), count);
114 }
115
116 static void
subprocess_report_status(size_t count,pid_t pid,int status)117 subprocess_report_status (size_t count, pid_t pid, int status)
118 {
119 char buffer[LINEBUFFER];
120
121 info (VERBOSE, _("Local program [%lu] finished. %s"),
122 (unsigned long) pid,
123 format_exit_status (buffer, sizeof buffer, status));
124 }
125
126 /************************************
127 If a service is not available,
128 then close a transmission channel.
129 *************************************/
130
131 void
service_unavailable(NET_STREAM * sd_client)132 service_unavailable (NET_STREAM * sd_client)
133 {
134 char buf[LINEBUFFER + 1];
135
136 snprintf (buf, LINEBUFFER,
137 "421 %s Service not available, closing transmission channel."
138 CRLF, (topt & T_LOCAL_MTA) ? "localhost" : session.mta);
139
140 swrite (SERVER, *sd_client, buf);
141 stream_close (*sd_client);
142 stream_destroy (sd_client);
143 return;
144 }
145
146 /*************************
147 Set an unprivileged user
148 (if possible).
149 **************************/
150
151 void
set_unprivileged_user(void)152 set_unprivileged_user (void)
153 {
154 if (topt & T_USER_NOTPRIVIL)
155 {
156 if (check_username (session.notprivileged)) {
157 anubis_changeowner (session.notprivileged);
158 assign_string (&session.clientname, session.notprivileged);
159 }
160 else
161 anubis_error (EXIT_FAILURE, 0,
162 _("WARNING: An unprivileged user cannot be resolved. Verify your settings!"));
163 }
164 else
165 {
166 if (check_username (DEFAULT_UNPRIVILEGED_USER)) {
167 anubis_changeowner (DEFAULT_UNPRIVILEGED_USER);
168 assign_string (&session.clientname, DEFAULT_UNPRIVILEGED_USER);
169 }
170 else
171 info (NORMAL,
172 _("WARNING: An unprivileged user has not been specified!"));
173 }
174 return;
175 }
176
177 int
anubis_child_main(struct sockaddr_in * addr)178 anubis_child_main (struct sockaddr_in *addr)
179 {
180 int rc;
181
182 proclist_init ();
183 switch (anubis_mode)
184 {
185 case anubis_transparent:
186 rc = anubis_transparent_mode (addr);
187 break;
188
189 #ifdef WITH_GSASL
190 case anubis_authenticate:
191 rc = anubis_authenticate_mode (addr);
192 break;
193 #endif /* WITH_GSASL */
194
195 case anubis_proxy:
196 rc = anubis_proxy_mode (addr);
197 break;
198
199 default:
200 abort();
201 }
202 proclist_cleanup (subprocess_report_status);
203 net_close_stream (&remote_client);
204 return rc;
205 }
206
207 /**************
208 DAEMON loop
209 ***************/
210
211 void
loop(int sd_bind)212 loop (int sd_bind)
213 {
214 struct sockaddr_in addr;
215 pid_t childpid = 0;
216 socklen_t addrlen;
217 #ifdef USE_LIBWRAP
218 struct request_info req;
219 #endif /* USE_LIBWRAP */
220
221 addrlen = sizeof (addr);
222
223 proclist_init ();
224
225 info (VERBOSE, _("GNU Anubis is running..."));
226
227 for (;;)
228 {
229 int fd;
230 size_t count;
231
232 fd = accept (sd_bind, (struct sockaddr *) &addr, &addrlen);
233 count = proclist_cleanup (report_process_status);
234
235 if (fd < 0)
236 {
237 if (errno == EINTR)
238 continue;
239 else
240 {
241 anubis_error (0, errno, _("accept() failed"));
242 continue;
243 }
244 }
245
246 /* Create the TCP stream */
247 net_create_stream (&remote_client, fd);
248 remote_server = NULL;
249
250 /*
251 Check the TCP wrappers settings.
252 */
253
254 #ifdef USE_LIBWRAP
255 request_init (&req, RQ_DAEMON, "anubis", RQ_FILE, fd, 0);
256 fromhost (&req);
257 if (hosts_access (&req) == 0)
258 {
259 info (NORMAL,
260 _("TCP wrappers: connection from %s:%u rejected."),
261 inet_ntoa (addr.sin_addr), ntohs (addr.sin_port));
262 service_unavailable (&remote_client);
263 continue;
264 }
265 #endif /* USE_LIBWRAP */
266
267 /*
268 Read the system configuration file (SUPERVISOR).
269 */
270
271 if (!(topt & T_NORC))
272 {
273 open_rcfile (CF_SUPERVISOR);
274 process_rcfile (CF_SUPERVISOR);
275 }
276
277 if (count >= MAXCLIENTS)
278 {
279 info (NORMAL,
280 _("Too many clients. Connection from %s:%u rejected."),
281 inet_ntoa (addr.sin_addr), ntohs (addr.sin_port));
282 service_unavailable (&remote_client);
283 }
284 else
285 {
286 info (NORMAL, _("Connection from %s:%u"),
287 inet_ntoa (addr.sin_addr), ntohs (addr.sin_port));
288
289 childpid = fork ();
290 if (childpid == -1)
291 anubis_error (0, errno, _("daemon: cannot fork"));
292 else if (childpid == 0)
293 { /* a child process */
294 /* FIXME */
295 signal (SIGCHLD, SIG_IGN);
296 quit (anubis_child_main (&addr));
297 }
298 else /* master process */
299 proclist_register (childpid);
300
301 net_close_stream (&remote_client);
302 }
303 }
304 return;
305 }
306
307 /********************************************
308 Run an outgoing mail processor on standard
309 input and output as described in RFC 821.
310 *********************************************/
311
312 static int
_stdio_write(void * sd,const char * data,size_t size,size_t * nbytes)313 _stdio_write (void *sd, const char *data, size_t size, size_t * nbytes)
314 {
315 int rc;
316 int fd = (int) sd;
317
318 if (fd == 0)
319 fd = 1;
320 rc = write (fd, data, size);
321 if (rc > 0)
322 {
323 *nbytes = rc;
324 return 0;
325 }
326 return errno;
327 }
328
329 static int
_stdio_read(void * sd,char * data,size_t size,size_t * nbytes)330 _stdio_read (void *sd, char *data, size_t size, size_t * nbytes)
331 {
332 int n;
333 int fd = (int) sd;
334 fd_set rds;
335
336 errno = 0;
337 FD_ZERO (&rds);
338 FD_SET (fd, &rds);
339 do
340 n = select (fd + 1, &rds, NULL, NULL, NULL);
341 while (n < 0 && errno == EINTR);
342 if (n > 0)
343 {
344 n = read (fd, data, size);
345 if (n >= 0)
346 *nbytes = n;
347 else
348 return errno;
349 }
350 return 0;
351 }
352
353 static const char *
_stdio_strerror(void * ignored_data,int rc)354 _stdio_strerror (void *ignored_data, int rc)
355 {
356 return strerror (rc);
357 }
358
359 void
create_stdio_stream(NET_STREAM * s)360 create_stdio_stream (NET_STREAM *s)
361 {
362 net_create_stream (s, 0);
363 stream_set_read (*s, _stdio_read);
364 stream_set_write (*s, _stdio_write);
365 stream_set_strerror (*s, _stdio_strerror);
366 }
367
368 void
stdinout(void)369 stdinout (void)
370 {
371 topt &= ~T_SSL;
372 topt |= T_FOREGROUND;
373 topt |= T_SMTP_ERROR_CODES;
374
375 proclist_init ();
376
377 anubis_getlogin (&session.clientname);
378 auth_tunnel (); /* session.clientname = session.supervisor */
379
380 ASSERT_MTA_CONFIG ();
381
382 create_stdio_stream (&remote_client);
383
384 alarm (300);
385 if (topt & T_LOCAL_MTA)
386 remote_server = make_local_connection (session.execpath, session.execargs);
387 else
388 remote_server = make_remote_connection (session.mta, session.mta_port);
389 alarm (0);
390
391 if (remote_server == NULL)
392 {
393 service_unavailable (&remote_client);
394 free_mem ();
395 return;
396 }
397 stream_set_read (remote_server, _stdio_read);
398 stream_set_write (remote_server, _stdio_write);
399 stream_set_strerror (remote_server, _stdio_strerror);
400
401 smtp_session_transparent ();
402 proclist_cleanup (subprocess_report_status);
403
404 net_close_stream (&remote_server);
405 free_mem ();
406 return;
407 }
408
409 /* EOF */
410