1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library 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 GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/stat.h>
25 #include <netinet/in.h>
26 #include <sys/un.h>
27 #include <arpa/inet.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <mailutils/acl.h>
32 #include <mailutils/server.h>
33 #include <mailutils/debug.h>
34 #include <mailutils/diag.h>
35 #include <mailutils/errno.h>
36 #include <mailutils/nls.h>
37 #include <mailutils/sockaddr.h>
38 #include <mailutils/stream.h>
39 #include <mailutils/stdstream.h>
40 #include <mailutils/filter.h>
41 #include <mailutils/syslog.h>
42
43 struct _mu_ip_server
44 {
45 char *ident;
46 struct mu_sockaddr *addr;
47 int fd;
48 int type;
49 mu_acl_t acl;
50 mu_ip_server_conn_fp f_conn;
51 mu_ip_server_intr_fp f_intr;
52 mu_ip_server_free_fp f_free;
53 void *data;
54 union
55 {
56 struct
57 {
58 int backlog;
59 } tcp_data;
60 struct
61 {
62 char *buf;
63 size_t bufsize;
64 ssize_t rdsize;
65 } udp_data;
66 } v;
67 };
68
69 #define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
70
71 int
mu_ip_server_create(mu_ip_server_t * psrv,struct mu_sockaddr * addr,int type)72 mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr, int type)
73 {
74 struct _mu_ip_server *srv;
75
76 switch (type)
77 {
78 case MU_IP_UDP:
79 case MU_IP_TCP:
80 break;
81
82 default:
83 return EINVAL;
84 }
85
86 srv = calloc (1, sizeof *srv);
87 if (!srv)
88 return ENOMEM;
89 srv->addr = addr;
90 srv->type = type;
91 srv->fd = -1;
92 switch (type)
93 {
94 case MU_IP_UDP:
95 srv->v.udp_data.bufsize = 4096;
96 break;
97
98 case MU_IP_TCP:
99 srv->v.tcp_data.backlog = 4;
100 }
101
102 *psrv = srv;
103 return 0;
104 }
105
106 int
mu_ip_server_destroy(mu_ip_server_t * psrv)107 mu_ip_server_destroy (mu_ip_server_t *psrv)
108 {
109 mu_ip_server_t srv;
110 if (!psrv)
111 return EINVAL;
112 srv = *psrv;
113 if (!srv)
114 return 0;
115 if (srv->f_free)
116 srv->f_free (srv->data);
117 close (srv->fd);
118 mu_sockaddr_free (srv->addr);
119 free (srv->ident);
120 if (srv->type == MU_IP_UDP && srv->v.udp_data.buf)
121 free (srv->v.udp_data.buf);
122 free (srv);
123 *psrv = NULL;
124 return 0;
125 }
126
127 int
mu_ip_server_get_type(mu_ip_server_t srv,int * ptype)128 mu_ip_server_get_type (mu_ip_server_t srv, int *ptype)
129 {
130 if (!srv)
131 return EINVAL;
132 *ptype = srv->type;
133 return 0;
134 }
135
136 int
mu_tcp_server_set_backlog(mu_ip_server_t srv,int backlog)137 mu_tcp_server_set_backlog (mu_ip_server_t srv, int backlog)
138 {
139 if (!srv || srv->type != MU_IP_TCP)
140 return EINVAL;
141 srv->v.tcp_data.backlog = backlog;
142 return 0;
143 }
144
145 int
mu_udp_server_get_bufsize(mu_ip_server_t srv,size_t * psize)146 mu_udp_server_get_bufsize (mu_ip_server_t srv, size_t *psize)
147 {
148 if (!srv || srv->type != MU_IP_UDP)
149 return EINVAL;
150 *psize = srv->v.udp_data.bufsize;
151 return 0;
152 }
153
154 int
mu_udp_server_set_bufsize(mu_ip_server_t srv,size_t size)155 mu_udp_server_set_bufsize (mu_ip_server_t srv, size_t size)
156 {
157 if (!srv || srv->type != MU_IP_UDP)
158 return EINVAL;
159 srv->v.udp_data.bufsize = size;
160 if (srv->v.udp_data.buf)
161 {
162 char *p = realloc (srv->v.udp_data.buf, size);
163 if (!p)
164 return ENOMEM;
165 srv->v.udp_data.buf = p;
166 }
167 return 0;
168 }
169
170 int
mu_ip_server_set_ident(mu_ip_server_t srv,const char * ident)171 mu_ip_server_set_ident (mu_ip_server_t srv, const char *ident)
172 {
173 if (!srv)
174 return EINVAL;
175 if (srv->ident)
176 free (srv->ident);
177 srv->ident = strdup (ident);
178 if (!srv->ident)
179 return ENOMEM;
180 return 0;
181 }
182
183 int
mu_ip_server_set_acl(mu_ip_server_t srv,mu_acl_t acl)184 mu_ip_server_set_acl (mu_ip_server_t srv, mu_acl_t acl)
185 {
186 if (!srv)
187 return EINVAL;
188 srv->acl = acl;
189 return 0;
190 }
191
192 int
mu_ip_server_set_conn(mu_ip_server_t srv,mu_ip_server_conn_fp conn)193 mu_ip_server_set_conn (mu_ip_server_t srv, mu_ip_server_conn_fp conn)
194 {
195 if (!srv)
196 return EINVAL;
197 srv->f_conn = conn;
198 return 0;
199 }
200
201 int
mu_ip_server_set_intr(mu_ip_server_t srv,mu_ip_server_intr_fp intr)202 mu_ip_server_set_intr (mu_ip_server_t srv, mu_ip_server_intr_fp intr)
203 {
204 if (!srv)
205 return EINVAL;
206 srv->f_intr = intr;
207 return 0;
208 }
209
210 int
mu_ip_server_set_data(mu_ip_server_t srv,void * data,mu_ip_server_free_fp free)211 mu_ip_server_set_data (mu_ip_server_t srv,
212 void *data, mu_ip_server_free_fp free)
213 {
214 if (!srv)
215 return EINVAL;
216 srv->data = data;
217 srv->f_free = free;
218 return 0;
219 }
220
221 void *
mu_ip_server_get_data(mu_ip_server_t tcpsrv)222 mu_ip_server_get_data (mu_ip_server_t tcpsrv)
223 {
224 return tcpsrv->data;
225 }
226
227 int
mu_address_family_to_domain(int family)228 mu_address_family_to_domain (int family)
229 {
230 switch (family)
231 {
232 case AF_UNIX:
233 return PF_UNIX;
234
235 case AF_INET:
236 return PF_INET;
237
238 #ifdef MAILUTILS_IPV6
239 case AF_INET6:
240 return PF_INET6;
241 #endif
242
243 default:
244 abort ();
245 }
246 }
247
248 int
mu_ip_server_open(mu_ip_server_t srv)249 mu_ip_server_open (mu_ip_server_t srv)
250 {
251 int fd;
252
253 if (!srv || srv->fd != -1)
254 return EINVAL;
255
256 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
257 ("opening server \"%s\" %s", IDENTSTR (srv),
258 mu_sockaddr_str (srv->addr)));
259
260 fd = socket (mu_address_family_to_domain (srv->addr->addr->sa_family),
261 ((srv->type == MU_IP_UDP) ? SOCK_DGRAM : SOCK_STREAM), 0);
262 if (fd == -1)
263 {
264 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
265 ("%s: socket: %s", IDENTSTR (srv), mu_strerror (errno)));
266 return errno;
267 }
268
269 switch (srv->addr->addr->sa_family)
270 {
271 case AF_UNIX:
272 {
273 struct stat st;
274 struct sockaddr_un *s_un = (struct sockaddr_un *) srv->addr;
275
276 if (stat (s_un->sun_path, &st))
277 {
278 if (errno != ENOENT)
279 {
280 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
281 ("%s: file %s exists but cannot be stat'd: %s",
282 IDENTSTR (srv),
283 s_un->sun_path,
284 mu_strerror (errno)));
285 return EAGAIN;
286 }
287 }
288 else if (!S_ISSOCK (st.st_mode))
289 {
290 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
291 ("%s: file %s is not a socket",
292 IDENTSTR (srv), s_un->sun_path));
293 return EAGAIN;
294 }
295 else if (unlink (s_un->sun_path))
296 {
297 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
298 ("%s: cannot unlink file %s: %s",
299 IDENTSTR (srv), s_un->sun_path, mu_strerror (errno)));
300 return EAGAIN;
301 }
302 }
303 break;
304
305 default:
306 {
307 int t;
308
309 t = 1;
310 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof (t));
311 }
312 }
313
314 if (bind (fd, srv->addr->addr, srv->addr->addrlen) == -1)
315 {
316 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
317 ("%s: bind: %s", IDENTSTR (srv), mu_strerror (errno)));
318 close (fd);
319 return errno;
320 }
321
322 if (srv->type == MU_IP_TCP)
323 {
324 if (listen (fd, srv->v.tcp_data.backlog) == -1)
325 {
326 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
327 ("%s: listen: %s", IDENTSTR (srv), mu_strerror (errno)));
328 close (fd);
329 return errno;
330 }
331 }
332
333 srv->fd = fd;
334 return 0;
335 }
336
337 int
mu_ip_server_shutdown(mu_ip_server_t srv)338 mu_ip_server_shutdown (mu_ip_server_t srv)
339 {
340 if (!srv || srv->fd != -1)
341 return EINVAL;
342 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
343 ("closing server \"%s\" %s", IDENTSTR (srv),
344 mu_sockaddr_str (srv->addr)));
345 close (srv->fd);
346 return 0;
347 }
348
349 int
mu_ip_tcp_accept(mu_ip_server_t srv,void * call_data)350 mu_ip_tcp_accept (mu_ip_server_t srv, void *call_data)
351 {
352 int rc;
353 int connfd;
354 union
355 {
356 struct sockaddr sa;
357 struct sockaddr_in s_in;
358 struct sockaddr_un s_un;
359 #ifdef MAILUTILS_IPV6
360 struct sockaddr_in6 s_in6;
361 #endif
362 } client;
363
364 socklen_t size = sizeof (client);
365
366 if (!srv || srv->fd == -1 || srv->type == MU_IP_UDP)
367 return EINVAL;
368
369 connfd = accept (srv->fd, &client.sa, &size);
370 if (connfd == -1)
371 {
372 int ec = errno;
373 switch (ec)
374 {
375 case EINTR:
376 if (srv->f_intr && srv->f_intr (srv->data, call_data))
377 break;
378 /* fall through */
379 case EAGAIN:
380 case ECONNABORTED:
381 ec = 0;
382 }
383 return ec;
384 }
385
386 if (srv->acl)
387 {
388 mu_acl_result_t res;
389 int rc;
390
391 rc = mu_acl_check_sockaddr (srv->acl, &client.sa, size, &res);
392 if (rc)
393 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
394 ("%s: mu_acl_check_sockaddr: %s",
395 IDENTSTR (srv), strerror (rc)));
396 if (res == mu_acl_result_deny)
397 {
398 char *p = mu_sys_sockaddr_to_astr (&client.sa, size);
399 mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p);
400 free (p);
401
402 close (connfd);
403 return 0;
404 }
405 }
406 rc = srv->f_conn (connfd, &client.sa, size, srv->data, call_data, srv);
407 close (connfd);
408 return rc;
409 }
410
411 int
mu_ip_udp_accept(mu_ip_server_t srv,void * call_data)412 mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
413 {
414 int rc;
415 union
416 {
417 struct sockaddr sa;
418 struct sockaddr_in s_in;
419 struct sockaddr_un s_un;
420 #ifdef MAILUTILS_IPV6
421 struct sockaddr_in6 s_in6;
422 #endif
423 } client;
424 fd_set rdset;
425
426 socklen_t salen = sizeof (client);
427 ssize_t size;
428
429 if (!srv->v.udp_data.buf)
430 {
431 srv->v.udp_data.buf = malloc (srv->v.udp_data.bufsize);
432 if (!srv->v.udp_data.buf)
433 return ENOMEM;
434 }
435
436 FD_ZERO (&rdset);
437 FD_SET (srv->fd, &rdset);
438 for (;;)
439 {
440 rc = select (srv->fd + 1, &rdset, NULL, NULL, NULL);
441 if (rc == -1)
442 {
443 if (errno == EINTR)
444 {
445 if (srv->f_intr && srv->f_intr (srv->data, call_data))
446 break;
447 else
448 continue;
449 }
450 }
451 else
452 break;
453 }
454
455 if (rc == -1)
456 return errno;
457
458 size = recvfrom (srv->fd, srv->v.udp_data.buf, srv->v.udp_data.bufsize,
459 0, &client.sa, &salen);
460 if (size < 0)
461 {
462 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
463 ("%s: recvfrom: %s",
464 IDENTSTR (srv), strerror (errno)));
465 return MU_ERR_FAILURE;
466 }
467 srv->v.udp_data.rdsize = size;
468
469 if (srv->acl)
470 {
471 mu_acl_result_t res;
472 int rc;
473
474 rc = mu_acl_check_sockaddr (srv->acl, &client.sa, size, &res);
475 if (rc)
476 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
477 ("%s: mu_acl_check_sockaddr: %s\n",
478 IDENTSTR (srv), strerror (rc)));
479 if (res == mu_acl_result_deny)
480 {
481 char *p = mu_sys_sockaddr_to_astr (&client.sa, salen);
482 mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p);
483 free (p);
484 return 0;
485 }
486 }
487 rc = srv->f_conn (-1, &client.sa, size, srv->data, call_data, srv);
488 return rc;
489 }
490
491 static int
set_strerr_flt(void)492 set_strerr_flt (void)
493 {
494 mu_stream_t flt, trans[2];
495 int rc;
496
497 if (!mu_log_session_id)
498 return ENOSYS;
499
500 rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_TOPSTREAM, MU_IOCTL_OP_GET, trans);
501 if (rc == 0)
502 {
503 char *sid;
504 char *argv[] = { "inline-comment", NULL, "-S", NULL };
505
506 rc = mu_sid (&sid);
507 if (rc)
508 {
509 mu_diag_funcall (MU_DIAG_ERR, "mu_sid", NULL, rc);
510 return 0;
511 }
512
513 argv[1] = sid;
514 rc = mu_filter_create_args (&flt, trans[0], "inline-comment", 3,
515 (const char **)argv,
516 MU_FILTER_ENCODE, MU_STREAM_WRITE);
517 free (sid);
518 mu_stream_unref (trans[0]);
519 if (rc == 0)
520 {
521 mu_stream_set_buffer (flt, mu_buffer_line, 0);
522 trans[0] = flt;
523 trans[1] = NULL;
524 rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_TOPSTREAM,
525 MU_IOCTL_OP_SET, trans);
526 mu_stream_unref (trans[0]);
527 if (rc)
528 mu_error (_("%s failed: %s"), "MU_IOCTL_SET_STREAM",
529 mu_stream_strerror (mu_strerr, rc));
530 }
531 else
532 mu_error (_("cannot create log filter stream: %s"), mu_strerror (rc));
533 }
534 else
535 {
536 mu_error (_("%s failed: %s"), "MU_IOCTL_GET_STREAM",
537 mu_stream_strerror (mu_strerr, rc));
538 }
539 return rc;
540 }
541
542 static void
clr_strerr_flt(void)543 clr_strerr_flt (void)
544 {
545 mu_stream_t flt, trans[2];
546 int rc;
547
548 rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_TOPSTREAM, MU_IOCTL_OP_GET, trans);
549 if (rc == 0)
550 {
551 flt = trans[0];
552
553 rc = mu_stream_ioctl (flt, MU_IOCTL_TOPSTREAM, MU_IOCTL_OP_GET, trans);
554 if (rc == 0)
555 {
556 mu_stream_unref (trans[0]);
557 rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_TOPSTREAM,
558 MU_IOCTL_OP_SET, trans);
559 if (rc == 0)
560 mu_stream_unref (flt);
561 }
562 }
563 }
564
565 int
mu_ip_server_accept(mu_ip_server_t srv,void * call_data)566 mu_ip_server_accept (mu_ip_server_t srv, void *call_data)
567 {
568 int rc;
569 int flt;
570
571 if (!srv || srv->fd == -1)
572 return EINVAL;
573
574 flt = set_strerr_flt ();
575
576 switch (srv->type)
577 {
578 case MU_IP_UDP:
579 rc = mu_ip_udp_accept (srv, call_data);
580 break;
581
582 case MU_IP_TCP:
583 rc = mu_ip_tcp_accept (srv, call_data);
584 }
585
586 if (rc)
587 {
588 mu_error (_("socket error on \"%s\": %s"), IDENTSTR (srv),
589 mu_strerror (rc));
590 mu_ip_server_shutdown (srv);
591 }
592 if (flt == 0)
593 clr_strerr_flt ();
594 return rc;
595 }
596
597 int
mu_ip_server_get_fd(mu_ip_server_t srv)598 mu_ip_server_get_fd (mu_ip_server_t srv)
599 {
600 return srv->fd;
601 }
602
603 int
mu_udp_server_get_rdata(mu_ip_server_t srv,char ** pbuf,size_t * pbufsize)604 mu_udp_server_get_rdata (mu_ip_server_t srv, char **pbuf, size_t *pbufsize)
605 {
606 if (!srv || srv->type != MU_IP_UDP)
607 return EINVAL;
608 *pbuf = srv->v.udp_data.buf;
609 *pbufsize = srv->v.udp_data.rdsize;
610 return 0;
611 }
612
613 int
mu_ip_server_get_sockaddr(mu_ip_server_t srv,struct mu_sockaddr ** psa)614 mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa)
615 {
616 if (!srv || !psa)
617 return EINVAL;
618 return mu_sockaddr_copy (psa, srv->addr);
619 }
620
621 const char *
mu_ip_server_addrstr(mu_ip_server_t srv)622 mu_ip_server_addrstr (mu_ip_server_t srv)
623 {
624 return mu_sockaddr_str (srv->addr);
625 }
626
627