masqmail-0.2

view src/listen.c @ 179:ec3fe72a3e99

Fixed an important bug with folded headers! g_strconcat() returns a *copy* of the string, but hdr->value still pointed to the old header (which probably was a memory leak, too). If the folded part had been quite small it was likely that the new string was at the same position as the old one, thus making everything go well. But if pretty long headers were folded several times it was likely that the new string was allocated somewhere else in memory, thus breaking things. In result mails to lots of recipients (folded header) were frequently only sent to the ones in the first line. Sorry for the inconvenience.
author meillo@marmaro.de
date Fri, 03 Jun 2011 09:52:17 +0200
parents 26e34ae9a3e3
children
line source
1 /* MasqMail
2 Copyright (C) 1999/2000 Oliver Kurth
4 This program 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 2 of the License, or
7 (at your option) any later version.
9 This program 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.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
19 #include <sys/wait.h>
20 #include <sys/types.h>
22 #include "masqmail.h"
24 static int volatile sighup_seen = 0;
26 static void
27 sighup_handler(int sig)
28 {
29 sighup_seen = 1;
30 signal(SIGHUP, sighup_handler);
31 }
33 static void
34 sigchld_handler(int sig)
35 {
36 pid_t pid;
37 int status;
39 pid = waitpid(0, &status, 0);
40 if (pid > 0) {
41 if (WEXITSTATUS(status) != EXIT_SUCCESS)
42 logwrite(LOG_WARNING, "process %d exited with %d\n", pid, WEXITSTATUS(status));
43 if (WIFSIGNALED(status))
44 logwrite(LOG_WARNING, "process with pid %d got signal: %d\n", pid, WTERMSIG(status));
45 }
46 signal(SIGCHLD, sigchld_handler);
47 }
49 #ifdef ENABLE_SMTP_SERVER
50 void
51 accept_connect(int listen_sock, int sock, struct sockaddr_in *sock_addr)
52 {
53 pid_t pid;
54 int dup_sock = dup(sock);
55 FILE *out, *in;
56 gchar *rem_host;
57 gchar *ident = NULL;
59 rem_host = g_strdup(inet_ntoa(sock_addr->sin_addr));
60 #ifdef ENABLE_IDENT
61 {
62 gchar *id = NULL;
63 if ((id = (gchar *) ident_id(sock, 60))) {
64 ident = g_strdup(id);
65 }
66 logwrite(LOG_NOTICE, "connect from host %s, port %hd ident=%s\n", rem_host,
67 ntohs(sock_addr->sin_port), ident ? ident : "(unknown)");
68 }
69 #else
70 logwrite(LOG_NOTICE, "connect from host %s, port %hd\n", rem_host, ntohs(sock_addr->sin_port));
71 #endif
73 // start child for connection:
74 signal(SIGCHLD, sigchld_handler);
75 pid = fork();
76 if (pid == 0) {
77 close(listen_sock);
78 out = fdopen(sock, "w");
79 in = fdopen(dup_sock, "r");
81 smtp_in(in, out, rem_host, ident);
83 _exit(EXIT_SUCCESS);
84 } else if (pid < 0) {
85 logwrite(LOG_WARNING, "could not fork for incoming smtp connection: %s\n", strerror(errno));
86 }
87 #ifdef ENABLE_IDENT
88 if (ident != NULL)
89 g_free(ident);
90 #endif
92 close(sock);
93 close(dup_sock);
94 }
95 #endif /*ifdef ENABLE_SMTP_SERVER */
97 void
98 listen_port(GList * iface_list, gint qival, char *argv[])
99 {
100 int i;
101 fd_set active_fd_set, read_fd_set;
102 struct timeval tm;
103 time_t time_before, time_now;
104 struct sockaddr_in clientname;
105 size_t size;
106 GList *node, *node_next;
107 int sel_ret;
109 /* Create the sockets and set them up to accept connections. */
110 FD_ZERO(&active_fd_set);
111 #ifdef ENABLE_SMTP_SERVER
112 for (node = g_list_first(iface_list); node; node = node_next) {
113 interface *iface = (interface *) (node->data);
114 int sock;
116 node_next = g_list_next(node);
117 if ((sock = make_server_socket(iface)) < 0) {
118 iface_list = g_list_remove_link(iface_list, node);
119 g_list_free_1(node);
120 continue;
121 }
122 if (listen(sock, 1) < 0) {
123 logwrite(LOG_ALERT, "listen: (terminating): %s\n", strerror(errno));
124 exit(EXIT_FAILURE);
125 }
126 logwrite(LOG_NOTICE, "listening on interface %s:%d\n", iface->address, iface->port);
127 DEBUG(5) debugf("sock = %d\n", sock);
128 FD_SET(sock, &active_fd_set);
129 }
130 #endif
132 /* setup handler for HUP signal: */
133 signal(SIGHUP, sighup_handler);
134 signal(SIGCHLD, sigchld_handler);
136 /* now that we have our socket(s), we can give up root privileges */
137 if (!conf.run_as_user) {
138 if (setegid(conf.mail_gid) != 0) {
139 logwrite(LOG_ALERT, "could not change gid to %d: %s\n", conf.mail_gid, strerror(errno));
140 exit(EXIT_FAILURE);
141 }
142 if (seteuid(conf.mail_uid) != 0) {
143 logwrite(LOG_ALERT, "could not change uid to %d: %s\n", conf.mail_uid, strerror(errno));
144 exit(EXIT_FAILURE);
145 }
146 }
148 /* sel_ret = 0; */
149 time(&time_before);
150 time_before -= qival;
151 sel_ret = -1;
153 while (1) {
155 /* if we were interrupted by an incoming connection (or a signal)
156 we have to recalculate the time until the next queue run should
157 occur. select may put a value into tm, but doc for select() says
158 we should not use it. */
159 if (qival > 0) {
160 time(&time_now);
161 if (sel_ret == 0) { /* we are either just starting or did a queue run */
162 tm.tv_sec = qival;
163 tm.tv_usec = 0;
164 time_before = time_now;
165 } else {
166 tm.tv_sec = qival - (time_now - time_before);
167 tm.tv_usec = 0;
169 /* race condition, very unlikely (but possible): */
170 if (tm.tv_sec < 0)
171 tm.tv_sec = 0;
172 }
173 }
174 /* Block until input arrives on one or more active sockets,
175 or signal arrives, or queuing interval time elapsed (if qival > 0) */
176 read_fd_set = active_fd_set;
177 if ((sel_ret = select(FD_SETSIZE, &read_fd_set, NULL, NULL, qival > 0 ? &tm : NULL)) < 0) {
178 if (errno != EINTR) {
179 logwrite(LOG_ALERT, "select: (terminating): %s\n", strerror(errno));
180 exit(EXIT_FAILURE);
181 } else {
182 if (sighup_seen) {
183 logwrite(LOG_NOTICE, "HUP signal received. Restarting daemon\n");
185 for (i = 0; i < FD_SETSIZE; i++)
186 if (FD_ISSET(i, &active_fd_set))
187 close(i);
189 execv(argv[0], &(argv[0]));
190 logwrite(LOG_ALERT, "restarting failed: %s\n", strerror(errno));
191 exit(EXIT_FAILURE);
192 }
193 }
194 } else if (sel_ret > 0) {
195 #ifdef ENABLE_SMTP_SERVER
196 for (i = 0; i < FD_SETSIZE; i++) {
197 if (FD_ISSET(i, &read_fd_set)) {
198 int sock = i;
199 int new;
200 size = sizeof(clientname);
201 new = accept(sock, (struct sockaddr *) &clientname, &size);
202 if (new < 0) {
203 logwrite(LOG_ALERT, "accept: (ignoring): %s\n", strerror(errno));
204 } else
205 accept_connect(sock, new, &clientname);
206 }
207 }
208 #else
209 ;
210 #endif
211 } else {
212 /* If select returns 0, the interval time has elapsed.
213 We start a new queue runner process */
214 int pid;
215 signal(SIGCHLD, sigchld_handler);
216 if ((pid = fork()) == 0) {
217 queue_run();
219 _exit(EXIT_SUCCESS);
220 } else if (pid < 0) {
221 logwrite(LOG_ALERT, "could not fork for queue run");
222 }
223 }
224 }
225 }