1 |
/* GNU Mailutils -- a suite of utilities for electronic mail |
/* GNU Mailutils -- a suite of utilities for electronic mail |
2 |
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. |
Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. |
3 |
|
|
4 |
GNU Mailutils is free software; you can redistribute it and/or modify |
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 |
it under the terms of the GNU General Public License as published by |
13 |
|
|
14 |
You should have received a copy of the GNU General Public License |
You should have received a copy of the GNU General Public License |
15 |
along with GNU Mailutils; if not, write to the Free Software |
along with GNU Mailutils; if not, write to the Free Software |
16 |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
17 |
|
|
18 |
#include "imap4d.h" |
#include "imap4d.h" |
19 |
|
|
|
FILE *ifile; |
|
|
FILE *ofile; |
|
20 |
mailbox_t mbox; |
mailbox_t mbox; |
21 |
char *homedir; |
char *homedir; |
22 |
int state = STATE_NONAUTH; |
int state = STATE_NONAUTH; |
23 |
int debug_mode = 0; |
int debug_mode = 0; |
24 |
struct mu_auth_data *auth_data; |
struct mu_auth_data *auth_data; |
25 |
|
|
26 |
struct daemon_param daemon_param = { |
struct daemon_param daemon_param = { |
27 |
MODE_INTERACTIVE, /* Start in interactive (inetd) mode */ |
MODE_INTERACTIVE, /* Start in interactive (inetd) mode */ |
28 |
20, /* Default maximum number of children */ |
20, /* Default maximum number of children */ |
29 |
143, /* Standard IMAP4 port */ |
143, /* Standard IMAP4 port */ |
30 |
1800, /* RFC2060: 30 minutes. */ |
1800, /* RFC2060: 30 minutes. */ |
31 |
0 /* No transcript by default */ |
0 /* No transcript by default */ |
32 |
}; |
}; |
33 |
|
|
34 |
|
#ifdef WITH_TLS |
35 |
|
int tls_available; |
36 |
|
int tls_done; |
37 |
|
#endif /* WITH_TLS */ |
38 |
|
|
39 |
/* Number of child processes. */ |
/* Number of child processes. */ |
40 |
volatile size_t children; |
volatile size_t children; |
41 |
|
|
42 |
const char *argp_program_version = "imap4d (" PACKAGE_STRING ")"; |
const char *argp_program_version = "imap4d (" PACKAGE_STRING ")"; |
43 |
static char doc[] = N_("GNU imap4d -- the IMAP4D daemon"); |
static char doc[] = N_("GNU imap4d -- the IMAP4D daemon"); |
44 |
|
|
45 |
static struct argp_option options[] = |
static struct argp_option options[] = { |
|
{ |
|
46 |
{"other-namespace", 'O', N_("PATHLIST"), 0, |
{"other-namespace", 'O', N_("PATHLIST"), 0, |
47 |
N_("set the `other' namespace"), 0}, |
N_("set the `other' namespace"), 0}, |
48 |
{"shared-namespace", 'S', N_("PATHLIST"), 0, |
{"shared-namespace", 'S', N_("PATHLIST"), 0, |
49 |
N_("set the `shared' namespace"), 0}, |
N_("set the `shared' namespace"), 0}, |
50 |
{ NULL, 0, NULL, 0, NULL, 0 } |
{NULL, 0, NULL, 0, NULL, 0} |
51 |
}; |
}; |
52 |
|
|
53 |
static error_t imap4d_parse_opt (int key, char *arg, struct argp_state *state); |
static error_t imap4d_parse_opt (int key, char *arg, |
54 |
|
struct argp_state *state); |
55 |
|
|
56 |
static struct argp argp = { |
static struct argp argp = { |
57 |
options, |
options, |
58 |
imap4d_parse_opt, |
imap4d_parse_opt, |
59 |
NULL, |
NULL, |
60 |
doc, |
doc, |
61 |
NULL, |
NULL, |
62 |
NULL, NULL |
NULL, NULL |
65 |
static const char *imap4d_capa[] = { |
static const char *imap4d_capa[] = { |
66 |
"daemon", |
"daemon", |
67 |
"auth", |
"auth", |
68 |
|
#ifdef WITH_TLS |
69 |
|
"tls", |
70 |
|
#endif /* WITH_TLS */ |
71 |
"common", |
"common", |
72 |
"mailbox", |
"mailbox", |
73 |
"logging", |
"logging", |
75 |
NULL |
NULL |
76 |
}; |
}; |
77 |
|
|
78 |
static int imap4d_mainloop __P ((int, int)); |
static int imap4d_mainloop __P ((int, int)); |
79 |
static void imap4d_daemon_init __P ((void)); |
static void imap4d_daemon_init __P ((void)); |
80 |
static void imap4d_daemon __P ((unsigned int, unsigned int)); |
static void imap4d_daemon __P ((unsigned int, unsigned int)); |
81 |
static int imap4d_mainloop __P ((int, int)); |
static int imap4d_mainloop __P ((int, int)); |
82 |
|
|
83 |
static error_t |
static error_t |
84 |
imap4d_parse_opt (int key, char *arg, struct argp_state *state) |
imap4d_parse_opt (int key, char *arg, struct argp_state *state) |
88 |
case ARGP_KEY_INIT: |
case ARGP_KEY_INIT: |
89 |
state->child_inputs[0] = state->input; |
state->child_inputs[0] = state->input; |
90 |
break; |
break; |
91 |
|
|
92 |
case 'O': |
case 'O': |
93 |
set_namespace (NS_OTHER, arg); |
set_namespace (NS_OTHER, arg); |
94 |
break; |
break; |
95 |
|
|
96 |
case 'S': |
case 'S': |
97 |
set_namespace (NS_SHARED, arg); |
set_namespace (NS_SHARED, arg); |
98 |
break; |
break; |
99 |
|
|
100 |
default: |
default: |
101 |
return ARGP_ERR_UNKNOWN; |
return ARGP_ERR_UNKNOWN; |
102 |
} |
} |
112 |
/* Native Language Support */ |
/* Native Language Support */ |
113 |
mu_init_nls (); |
mu_init_nls (); |
114 |
|
|
115 |
state = STATE_NONAUTH; /* Starting state in non-auth. */ |
state = STATE_NONAUTH; /* Starting state in non-auth. */ |
116 |
|
|
117 |
MU_AUTH_REGISTER_ALL_MODULES(); |
MU_AUTH_REGISTER_ALL_MODULES (); |
118 |
|
#ifdef WITH_TLS |
119 |
|
mu_tls_init_argp (); |
120 |
|
#endif /* WITH_TLS */ |
121 |
mu_argp_parse (&argp, &argc, &argv, 0, imap4d_capa, NULL, &daemon_param); |
mu_argp_parse (&argp, &argc, &argv, 0, imap4d_capa, NULL, &daemon_param); |
122 |
|
|
123 |
#ifdef USE_LIBPAM |
#ifdef USE_LIBPAM |
140 |
perror (_("Error getting mail group")); |
perror (_("Error getting mail group")); |
141 |
exit (1); |
exit (1); |
142 |
} |
} |
143 |
|
|
144 |
if (setgid (gr->gr_gid) == -1) |
if (setgid (gr->gr_gid) == -1) |
145 |
{ |
{ |
146 |
perror (_("Error setting mail group")); |
perror (_("Error setting mail group")); |
152 |
{ |
{ |
153 |
list_t bookie; |
list_t bookie; |
154 |
registrar_get_list (&bookie); |
registrar_get_list (&bookie); |
155 |
list_append (bookie, mbox_record); |
list_append (bookie, mbox_record); |
156 |
list_append (bookie, path_record); |
list_append (bookie, path_record); |
157 |
} |
} |
158 |
|
|
183 |
/* Redirect any stdout error from the library to syslog, they |
/* Redirect any stdout error from the library to syslog, they |
184 |
should not go to the client. */ |
should not go to the client. */ |
185 |
mu_error_set_print (mu_syslog_error_printer); |
mu_error_set_print (mu_syslog_error_printer); |
186 |
|
|
187 |
umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */ |
umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */ |
188 |
|
|
189 |
|
/* Check TLS environment, i.e. cert and key files */ |
190 |
|
#ifdef WITH_TLS |
191 |
|
tls_available = mu_check_tls_environment (); |
192 |
|
if (tls_available) |
193 |
|
tls_available = mu_init_tls_libs (); |
194 |
|
#endif /* WITH_TLS */ |
195 |
|
|
196 |
/* Actually run the daemon. */ |
/* Actually run the daemon. */ |
197 |
if (daemon_param.mode == MODE_DAEMON) |
if (daemon_param.mode == MODE_DAEMON) |
210 |
imap4d_mainloop (int infile, int outfile) |
imap4d_mainloop (int infile, int outfile) |
211 |
{ |
{ |
212 |
char *text; |
char *text; |
213 |
|
|
214 |
/* Reset hup to exit. */ |
/* Reset hup to exit. */ |
215 |
signal (SIGHUP, imap4d_signal); |
signal (SIGHUP, imap4d_signal); |
216 |
/* Timeout alarm. */ |
/* Timeout alarm. */ |
217 |
signal (SIGALRM, imap4d_signal); |
signal (SIGALRM, imap4d_signal); |
218 |
|
|
219 |
ifile = fdopen (infile, "r"); |
util_setio (infile, outfile); |
|
ofile = fdopen (outfile, "w"); |
|
|
if (!ofile || !ifile) |
|
|
imap4d_bye (ERR_NO_OFILE); |
|
|
|
|
|
setvbuf(ofile, NULL, _IOLBF, 0); |
|
220 |
|
|
221 |
/* log information on the connecting client */ |
/* log information on the connecting client */ |
222 |
if (!debug_mode) |
if (!debug_mode) |
225 |
int len = sizeof cs; |
int len = sizeof cs; |
226 |
|
|
227 |
syslog (LOG_INFO, _("Incoming connection opened")); |
syslog (LOG_INFO, _("Incoming connection opened")); |
228 |
if (getpeername (infile, (struct sockaddr*)&cs, &len) < 0) |
if (getpeername (infile, (struct sockaddr *) &cs, &len) < 0) |
229 |
syslog (LOG_ERR, _("can't obtain IP address of client: %s"), |
syslog (LOG_ERR, _("can't obtain IP address of client: %s"), |
230 |
strerror (errno)); |
strerror (errno)); |
231 |
else |
else |
232 |
syslog (LOG_INFO, _("connect from %s"), inet_ntoa(cs.sin_addr)); |
syslog (LOG_INFO, _("connect from %s"), inet_ntoa (cs.sin_addr)); |
233 |
text = "IMAP4rev1"; |
text = "IMAP4rev1"; |
234 |
} |
} |
235 |
else |
else |
237 |
syslog (LOG_INFO, _("Started in debugging mode")); |
syslog (LOG_INFO, _("Started in debugging mode")); |
238 |
text = "IMAP4rev1 Debugging mode"; |
text = "IMAP4rev1 Debugging mode"; |
239 |
} |
} |
240 |
|
|
241 |
/* Greetings. */ |
/* Greetings. */ |
242 |
util_out (RESP_OK, text); |
util_out (RESP_OK, text); |
243 |
fflush (ofile); |
util_flush_output (); |
244 |
|
|
245 |
while (1) |
while (1) |
246 |
{ |
{ |
247 |
char *cmd = imap4d_readline (ifile); |
char *cmd = imap4d_readline (); |
248 |
/* check for updates */ |
/* check for updates */ |
249 |
imap4d_sync (); |
imap4d_sync (); |
250 |
util_do_command (cmd); |
util_do_command (cmd); |
251 |
imap4d_sync (); |
imap4d_sync (); |
252 |
free (cmd); |
free (cmd); |
253 |
fflush (ofile); |
util_flush_output (); |
254 |
} |
} |
255 |
|
|
|
closelog (); |
|
256 |
return EXIT_SUCCESS; |
return EXIT_SUCCESS; |
257 |
} |
} |
258 |
|
|
266 |
first three one, in, out, err */ |
first three one, in, out, err */ |
267 |
if (daemon (0, 0) < 0) |
if (daemon (0, 0) < 0) |
268 |
{ |
{ |
269 |
perror(_("fork failed:")); |
perror (_("fork failed:")); |
270 |
exit (1); |
exit (1); |
271 |
} |
} |
272 |
|
|
299 |
listenfd = socket (AF_INET, SOCK_STREAM, 0); |
listenfd = socket (AF_INET, SOCK_STREAM, 0); |
300 |
if (listenfd == -1) |
if (listenfd == -1) |
301 |
{ |
{ |
302 |
syslog (LOG_ERR, "socket: %s", strerror(errno)); |
syslog (LOG_ERR, "socket: %s", strerror (errno)); |
303 |
exit (1); |
exit (1); |
304 |
} |
} |
305 |
size = 1; /* Use size here to avoid making a new variable. */ |
size = 1; /* Use size here to avoid making a new variable. */ |
306 |
setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &size, sizeof(size)); |
setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &size, sizeof (size)); |
307 |
size = sizeof (server); |
size = sizeof (server); |
308 |
memset (&server, 0, size); |
memset (&server, 0, size); |
309 |
server.sin_family = AF_INET; |
server.sin_family = AF_INET; |
310 |
server.sin_addr.s_addr = htonl (INADDR_ANY); |
server.sin_addr.s_addr = htonl (INADDR_ANY); |
311 |
server.sin_port = htons (port); |
server.sin_port = htons (port); |
312 |
|
|
313 |
if (bind (listenfd, (struct sockaddr *)&server, size) == -1) |
if (bind (listenfd, (struct sockaddr *) &server, size) == -1) |
314 |
{ |
{ |
315 |
syslog (LOG_ERR, "bind: %s", strerror (errno)); |
syslog (LOG_ERR, "bind: %s", strerror (errno)); |
316 |
exit (1); |
exit (1); |
325 |
for (;;) |
for (;;) |
326 |
{ |
{ |
327 |
if (children > maxchildren) |
if (children > maxchildren) |
328 |
{ |
{ |
329 |
syslog (LOG_ERR, _("too many children (%lu)"), |
syslog (LOG_ERR, _("too many children (%lu)"), |
330 |
(unsigned long) children); |
(unsigned long) children); |
331 |
pause (); |
pause (); |
332 |
continue; |
continue; |
333 |
} |
} |
334 |
connfd = accept (listenfd, (struct sockaddr *)&client, |
connfd = accept (listenfd, (struct sockaddr *) &client, |
335 |
(socklen_t*) &size); |
(socklen_t *) & size); |
336 |
if (connfd == -1) |
if (connfd == -1) |
337 |
{ |
{ |
338 |
if (errno == EINTR) |
if (errno == EINTR) |
339 |
continue; |
continue; |
340 |
syslog (LOG_ERR, "accept: %s", strerror (errno)); |
syslog (LOG_ERR, "accept: %s", strerror (errno)); |
341 |
exit (1); |
exit (1); |
342 |
} |
} |
343 |
|
|
344 |
pid = fork (); |
pid = fork (); |
345 |
if (pid == -1) |
if (pid == -1) |
346 |
syslog(LOG_ERR, "fork: %s", strerror (errno)); |
syslog (LOG_ERR, "fork: %s", strerror (errno)); |
347 |
else if (pid == 0) /* Child. */ |
else if (pid == 0) /* Child. */ |
348 |
{ |
{ |
349 |
int status; |
int status; |
350 |
close (listenfd); |
close (listenfd); |
351 |
status = imap4d_mainloop (connfd, connfd); |
status = imap4d_mainloop (connfd, connfd); |
352 |
closelog (); |
closelog (); |
353 |
exit (status); |
exit (status); |
354 |
} |
} |
355 |
else |
else |
356 |
{ |
{ |
357 |
++children; |
++children; |
358 |
} |
} |
359 |
close (connfd); |
close (connfd); |
360 |
} |
} |
361 |
} |
} |
|
|
|