git ssb

0+

cel / sslh



Tree: 8f39c106e18eccb66afa2288c4557d4947278538

Files: 8f39c106e18eccb66afa2288c4557d4947278538 / common.c

19802 bytesRaw
1/* Code and variables that is common to both fork and select-based
2 * servers.
3 *
4 * No code here should assume whether sockets are blocking or not.
5 **/
6
7#define _GNU_SOURCE
8#include <stdarg.h>
9#include <grp.h>
10
11#include "common.h"
12#include "probe.h"
13
14/* Added to make the code compilable under CYGWIN
15 * */
16#ifndef SA_NOCLDWAIT
17#define SA_NOCLDWAIT 0
18#endif
19
20/* Make use of systemd socket activation
21 * */
22#ifdef SYSTEMD
23#include <systemd/sd-daemon.h>
24#endif
25
26/*
27 * Settings that depend on the command line. They're set in main(), but also
28 * used in other places in common.c, and it'd be heavy-handed to pass it all as
29 * parameters
30 */
31int verbose = 0;
32int probing_timeout = 2;
33int inetd = 0;
34int foreground = 0;
35int background = 0;
36int transparent = 0;
37int numeric = 0;
38const char *user_name, *pid_file;
39
40struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */
41
42#ifdef LIBWRAP
43#include <tcpd.h>
44int allow_severity =0, deny_severity = 0;
45#endif
46
47/* check result and die, printing the offending address and error */
48void check_res_dumpdie(int res, struct addrinfo *addr, char* syscall)
49{
50 char buf[NI_MAXHOST];
51
52 if (res == -1) {
53 fprintf(stderr, "%s:%s: %s\n",
54 sprintaddr(buf, sizeof(buf), addr),
55 syscall,
56 strerror(errno));
57 exit(1);
58 }
59}
60
61int get_fd_sockets(int *sockfd[])
62{
63 int sd = 0;
64
65#ifdef SYSTEMD
66 sd = sd_listen_fds(0);
67 if (sd < 0) {
68 fprintf(stderr, "sd_listen_fds(): %s\n", strerror(-sd));
69 exit(1);
70 }
71 if (sd > 0) {
72 *sockfd = malloc(sd * sizeof(*sockfd[0]));
73 for (int i = 0; i < sd; i++) {
74 (*sockfd)[i] = SD_LISTEN_FDS_START + i;
75 }
76 }
77#endif
78
79 return sd;
80}
81
82/* Starts listening sockets on specified addresses.
83 * IN: addr[], num_addr
84 * OUT: *sockfd[] pointer to newly-allocated array of file descriptors
85 * Returns number of addresses bound
86 * Bound file descriptors are returned in newly-allocated *sockfd pointer
87 */
88int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list)
89{
90 struct sockaddr_storage *saddr;
91 struct addrinfo *addr;
92 int i, res, one;
93 int num_addr = 0;
94 int sd_socks = 0;
95
96 sd_socks = get_fd_sockets(sockfd);
97
98 if (sd_socks > 0) {
99 return sd_socks;
100 }
101
102 for (addr = addr_list; addr; addr = addr->ai_next)
103 num_addr++;
104
105 if (verbose)
106 fprintf(stderr, "listening to %d addresses\n", num_addr);
107
108 *sockfd = malloc(num_addr * sizeof(*sockfd[0]));
109
110 for (i = 0, addr = addr_list; i < num_addr && addr; i++, addr = addr->ai_next) {
111 if (!addr) {
112 fprintf(stderr, "FATAL: Inconsistent listen number. This should not happen.\n");
113 exit(1);
114 }
115 saddr = (struct sockaddr_storage*)addr->ai_addr;
116
117 (*sockfd)[i] = socket(saddr->ss_family, SOCK_STREAM, 0);
118 check_res_dumpdie((*sockfd)[i], addr, "socket");
119
120 one = 1;
121 res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one));
122 check_res_dumpdie(res, addr, "setsockopt(SO_REUSEADDR)");
123
124 if (addr->ai_flags & SO_KEEPALIVE) {
125 res = setsockopt((*sockfd)[i], SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(one));
126 check_res_dumpdie(res, addr, "setsockopt(SO_KEEPALIVE)");
127 printf("set up keepalive\n");
128 }
129
130 if (IP_FREEBIND) {
131 res = setsockopt((*sockfd)[i], IPPROTO_IP, IP_FREEBIND, (char*)&one, sizeof(one));
132 check_res_dumpdie(res, addr, "setsockopt(IP_FREEBIND)");
133 }
134
135 res = bind((*sockfd)[i], addr->ai_addr, addr->ai_addrlen);
136 check_res_dumpdie(res, addr, "bind");
137
138 res = listen ((*sockfd)[i], 50);
139 check_res_dumpdie(res, addr, "listen");
140
141 }
142
143 return num_addr;
144}
145
146/* Transparent proxying: bind the peer address of fd to the peer address of
147 * fd_from */
148#define IP_TRANSPARENT 19
149int bind_peer(int fd, int fd_from)
150{
151 struct addrinfo from;
152 struct sockaddr_storage ss;
153 int res, trans = 1;
154
155 memset(&from, 0, sizeof(from));
156 from.ai_addr = (struct sockaddr*)&ss;
157 from.ai_addrlen = sizeof(ss);
158
159 /* getpeername can fail with ENOTCONN if connection was dropped before we
160 * got here */
161 res = getpeername(fd_from, from.ai_addr, &from.ai_addrlen);
162 CHECK_RES_RETURN(res, "getpeername");
163#ifndef IP_BINDANY /* use IP_TRANSPARENT */
164 res = setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &trans, sizeof(trans));
165 CHECK_RES_DIE(res, "setsockopt");
166#else
167 if (from.ai_addr->sa_family==AF_INET) { /* IPv4 */
168 res = setsockopt(fd, IPPROTO_IP, IP_BINDANY, &trans, sizeof(trans));
169 CHECK_RES_RETURN(res, "setsockopt IP_BINDANY");
170#ifdef IPV6_BINDANY
171 } else { /* IPv6 */
172 res = setsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, &trans, sizeof(trans));
173 CHECK_RES_RETURN(res, "setsockopt IPV6_BINDANY");
174#endif /* IPV6_BINDANY */
175 }
176#endif /* IP_TRANSPARENT / IP_BINDANY */
177 res = bind(fd, from.ai_addr, from.ai_addrlen);
178 CHECK_RES_RETURN(res, "bind");
179
180 return 0;
181}
182
183/* Connect to first address that works and returns a file descriptor, or -1 if
184 * none work.
185 * If transparent proxying is on, use fd_from peer address on external address
186 * of new file descriptor. */
187int connect_addr(struct connection *cnx, int fd_from)
188{
189 struct addrinfo *a, from;
190 struct sockaddr_storage ss;
191 char buf[NI_MAXHOST];
192 int fd, res, one;
193
194 memset(&from, 0, sizeof(from));
195 from.ai_addr = (struct sockaddr*)&ss;
196 from.ai_addrlen = sizeof(ss);
197
198 res = getpeername(fd_from, from.ai_addr, &from.ai_addrlen);
199 CHECK_RES_RETURN(res, "getpeername");
200
201 for (a = cnx->proto->saddr; a; a = a->ai_next) {
202 /* When transparent, make sure both connections use the same address family */
203 if (transparent && a->ai_family != from.ai_addr->sa_family)
204 continue;
205 if (verbose)
206 fprintf(stderr, "connecting to %s family %d len %d\n",
207 sprintaddr(buf, sizeof(buf), a),
208 a->ai_addr->sa_family, a->ai_addrlen);
209
210 /* XXX Needs to match ai_family from fd_from when being transparent! */
211 fd = socket(a->ai_family, SOCK_STREAM, 0);
212 if (fd == -1) {
213 log_message(LOG_ERR, "forward to %s failed:socket: %s\n",
214 cnx->proto->description, strerror(errno));
215 } else {
216 if (transparent) {
217 res = bind_peer(fd, fd_from);
218 CHECK_RES_RETURN(res, "bind_peer");
219 }
220 res = connect(fd, a->ai_addr, a->ai_addrlen);
221 if (res == -1) {
222 log_message(LOG_ERR, "forward to %s failed:connect: %s\n",
223 cnx->proto->description, strerror(errno));
224 close(fd);
225 } else {
226 if (cnx->proto->keepalive) {
227 one = 1;
228 res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(one));
229 CHECK_RES_RETURN(res, "setsockopt(SO_KEEPALIVE)");
230 printf("set up keepalive\n");
231 }
232 return fd;
233 }
234 }
235 }
236 return -1;
237}
238
239/* Store some data to write to the queue later */
240int defer_write(struct queue *q, void* data, int data_size)
241{
242 char *p;
243 if (verbose)
244 fprintf(stderr, "**** writing deferred on fd %d\n", q->fd);
245
246 p = realloc(q->begin_deferred_data, q->deferred_data_size + data_size);
247 if (!p) {
248 perror("realloc");
249 exit(1);
250 }
251
252 q->deferred_data = q->begin_deferred_data = p;
253 p += q->deferred_data_size;
254 q->deferred_data_size += data_size;
255 memcpy(p, data, data_size);
256
257 return 0;
258}
259
260/* tries to flush some of the data for specified queue
261 * Upon success, the number of bytes written is returned.
262 * Upon failure, -1 returned (e.g. connexion closed)
263 * */
264int flush_deferred(struct queue *q)
265{
266 int n;
267
268 if (verbose)
269 fprintf(stderr, "flushing deferred data to fd %d\n", q->fd);
270
271 n = write(q->fd, q->deferred_data, q->deferred_data_size);
272 if (n == -1)
273 return n;
274
275 if (n == q->deferred_data_size) {
276 /* All has been written -- release the memory */
277 free(q->begin_deferred_data);
278 q->begin_deferred_data = NULL;
279 q->deferred_data = NULL;
280 q->deferred_data_size = 0;
281 } else {
282 /* There is data left */
283 q->deferred_data += n;
284 q->deferred_data_size -= n;
285 }
286
287 return n;
288}
289
290
291void init_cnx(struct connection *cnx)
292{
293 memset(cnx, 0, sizeof(*cnx));
294 cnx->q[0].fd = -1;
295 cnx->q[1].fd = -1;
296 cnx->proto = get_first_protocol();
297}
298
299void dump_connection(struct connection *cnx)
300{
301 printf("state: %d\n", cnx->state);
302 printf("fd %d, %d deferred\n", cnx->q[0].fd, cnx->q[0].deferred_data_size);
303 printf("fd %d, %d deferred\n", cnx->q[1].fd, cnx->q[1].deferred_data_size);
304}
305
306
307/*
308 * moves data from one fd to other
309 *
310 * returns number of bytes copied if success
311 * returns 0 (FD_CNXCLOSED) if incoming socket closed
312 * returns FD_NODATA if no data was available
313 * returns FD_STALLED if data was read, could not be written, and has been
314 * stored in temporary buffer.
315 */
316int fd2fd(struct queue *target_q, struct queue *from_q)
317{
318 char buffer[BUFSIZ];
319 int target, from, size_r, size_w;
320
321 target = target_q->fd;
322 from = from_q->fd;
323
324 size_r = read(from, buffer, sizeof(buffer));
325 if (size_r == -1) {
326 switch (errno) {
327 case EAGAIN:
328 if (verbose)
329 fprintf(stderr, "reading 0 from %d\n", from);
330 return FD_NODATA;
331
332 case ECONNRESET:
333 case EPIPE:
334 return FD_CNXCLOSED;
335 }
336 }
337
338 CHECK_RES_RETURN(size_r, "read");
339
340 if (size_r == 0)
341 return FD_CNXCLOSED;
342
343 size_w = write(target, buffer, size_r);
344 /* process -1 when we know how to deal with it */
345 if (size_w == -1) {
346 switch (errno) {
347 case EAGAIN:
348 /* write blocked: Defer data */
349 defer_write(target_q, buffer, size_r);
350 return FD_STALLED;
351
352 case ECONNRESET:
353 case EPIPE:
354 /* remove end closed -- drop the connection */
355 return FD_CNXCLOSED;
356 }
357 } else if (size_w < size_r) {
358 /* incomplete write -- defer the rest of the data */
359 defer_write(target_q, buffer + size_w, size_r - size_w);
360 return FD_STALLED;
361 }
362
363 CHECK_RES_RETURN(size_w, "write");
364
365 return size_w;
366}
367
368/* returns a string that prints the IP and port of the sockaddr */
369char* sprintaddr(char* buf, size_t size, struct addrinfo *a)
370{
371 char host[NI_MAXHOST], serv[NI_MAXSERV];
372 int res;
373
374 res = getnameinfo(a->ai_addr, a->ai_addrlen,
375 host, sizeof(host),
376 serv, sizeof(serv),
377 numeric ? NI_NUMERICHOST | NI_NUMERICSERV : 0 );
378
379 if (res) {
380 log_message(LOG_ERR, "sprintaddr:getnameinfo: %s\n", gai_strerror(res));
381 /* Name resolution failed: do it numerically instead */
382 res = getnameinfo(a->ai_addr, a->ai_addrlen,
383 host, sizeof(host),
384 serv, sizeof(serv),
385 NI_NUMERICHOST | NI_NUMERICSERV);
386 /* should not fail but... */
387 if (res) {
388 log_message(LOG_ERR, "sprintaddr:getnameinfo(NUM): %s\n", gai_strerror(res));
389 strcpy(host, "?");
390 strcpy(serv, "?");
391 }
392 }
393
394 snprintf(buf, size, "%s:%s", host, serv);
395
396 return buf;
397}
398
399/* Turns a hostname and port (or service) into a list of struct addrinfo
400 * returns 0 on success, -1 otherwise and logs error
401 **/
402int resolve_split_name(struct addrinfo **out, const char* host, const char* serv)
403{
404 struct addrinfo hint;
405 int res;
406
407 memset(&hint, 0, sizeof(hint));
408 hint.ai_family = PF_UNSPEC;
409 hint.ai_socktype = SOCK_STREAM;
410
411 res = getaddrinfo(host, serv, &hint, out);
412 if (res)
413 log_message(LOG_ERR, "%s `%s:%s'\n", gai_strerror(res), host, serv);
414 return res;
415}
416
417/* turns a "hostname:port" string into a list of struct addrinfo;
418out: list of newly allocated addrinfo (see getaddrinfo(3)); freeaddrinfo(3) when done
419fullname: input string -- it gets clobbered
420*/
421void resolve_name(struct addrinfo **out, char* fullname)
422{
423 char *serv, *host, *end;
424 int res;
425
426 /* Find port */
427 char *sep = strrchr(fullname, ':');
428 if (!sep) { /* No separator: parameter is just a port */
429 fprintf(stderr, "%s: names must be fully specified as hostname:port\n", fullname);
430 exit(1);
431 }
432 serv = sep+1;
433 *sep = 0;
434
435 host = fullname;
436
437 /* If it is a RFC-Compliant IPv6 address ("[1234::12]:443"), remove brackets
438 * around IP address */
439 if (host[0] == '[') {
440 end = strrchr(host, ']');
441 if (!end) {
442 fprintf(stderr, "%s: no closing bracket in IPv6 address?\n", host);
443 }
444 host++; /* skip first bracket */
445 *end = 0; /* remove last bracket */
446 }
447
448 res = resolve_split_name(out, host, serv);
449 if (res) {
450 fprintf(stderr, "%s `%s'\n", gai_strerror(res), fullname);
451 if (res == EAI_SERVICE)
452 fprintf(stderr, "(Check you have specified all ports)\n");
453 exit(4);
454 }
455}
456
457/* Log to syslog or stderr if foreground */
458void log_message(int type, char* msg, ...)
459{
460 va_list ap;
461
462 va_start(ap, msg);
463 if (foreground)
464 vfprintf(stderr, msg, ap);
465 else
466 vsyslog(type, msg, ap);
467 va_end(ap);
468}
469
470/* syslogs who connected to where */
471void log_connection(struct connection *cnx)
472{
473 struct addrinfo addr;
474 struct sockaddr_storage ss;
475#define MAX_NAMELENGTH (NI_MAXHOST + NI_MAXSERV + 1)
476 char peer[MAX_NAMELENGTH], service[MAX_NAMELENGTH],
477 local[MAX_NAMELENGTH], target[MAX_NAMELENGTH];
478 int res;
479
480 if (cnx->proto->log_level < 1)
481 return;
482
483 addr.ai_addr = (struct sockaddr*)&ss;
484 addr.ai_addrlen = sizeof(ss);
485
486 res = getpeername(cnx->q[0].fd, addr.ai_addr, &addr.ai_addrlen);
487 if (res == -1) return; /* Can happen if connection drops before we get here.
488 In that case, don't log anything (there is no connection) */
489 sprintaddr(peer, sizeof(peer), &addr);
490
491 addr.ai_addrlen = sizeof(ss);
492 res = getsockname(cnx->q[0].fd, addr.ai_addr, &addr.ai_addrlen);
493 if (res == -1) return;
494 sprintaddr(service, sizeof(service), &addr);
495
496 addr.ai_addrlen = sizeof(ss);
497 res = getpeername(cnx->q[1].fd, addr.ai_addr, &addr.ai_addrlen);
498 if (res == -1) return;
499 sprintaddr(target, sizeof(target), &addr);
500
501 addr.ai_addrlen = sizeof(ss);
502 res = getsockname(cnx->q[1].fd, addr.ai_addr, &addr.ai_addrlen);
503 if (res == -1) return;
504 sprintaddr(local, sizeof(local), &addr);
505
506 log_message(LOG_INFO, "%s:connection from %s to %s forwarded from %s to %s\n",
507 cnx->proto->description,
508 peer,
509 service,
510 local,
511 target);
512}
513
514
515/* libwrap (tcpd): check the connection is legal. This is necessary because
516 * the actual server will only see a connection coming from localhost and can't
517 * apply the rules itself.
518 *
519 * Returns -1 if access is denied, 0 otherwise
520 */
521int check_access_rights(int in_socket, const char* service)
522{
523#ifdef LIBWRAP
524 union {
525 struct sockaddr saddr;
526 struct sockaddr_storage ss;
527 } peer;
528 socklen_t size = sizeof(peer);
529 char addr_str[NI_MAXHOST], host[NI_MAXHOST];
530 int res;
531
532 res = getpeername(in_socket, &peer.saddr, &size);
533 CHECK_RES_RETURN(res, "getpeername");
534
535 /* extract peer address */
536 res = getnameinfo(&peer.saddr, size, addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST);
537 if (res) {
538 if (verbose)
539 fprintf(stderr, "getnameinfo(NI_NUMERICHOST):%s\n", gai_strerror(res));
540 strcpy(addr_str, STRING_UNKNOWN);
541 }
542 /* extract peer name */
543 strcpy(host, STRING_UNKNOWN);
544 if (!numeric) {
545 res = getnameinfo(&peer.saddr, size, host, sizeof(host), NULL, 0, NI_NAMEREQD);
546 if (res) {
547 if (verbose)
548 fprintf(stderr, "getnameinfo(NI_NAMEREQD):%s\n", gai_strerror(res));
549 }
550 }
551
552 if (!hosts_ctl(service, host, addr_str, STRING_UNKNOWN)) {
553 if (verbose)
554 fprintf(stderr, "access denied\n");
555 log_message(LOG_INFO, "connection from %s(%s): access denied", host, addr_str);
556 close(in_socket);
557 return -1;
558 }
559#endif
560 return 0;
561}
562
563void setup_signals(void)
564{
565 int res;
566 struct sigaction action;
567
568 /* Request no SIGCHLD is sent upon termination of
569 * the children */
570 memset(&action, 0, sizeof(action));
571 action.sa_handler = NULL;
572 action.sa_flags = SA_NOCLDWAIT;
573 res = sigaction(SIGCHLD, &action, NULL);
574 CHECK_RES_DIE(res, "sigaction");
575
576 /* Set SIGTERM to exit. For some reason if it's not set explicitly,
577 * coverage information is lost when killing the process */
578 memset(&action, 0, sizeof(action));
579 action.sa_handler = exit;
580 res = sigaction(SIGTERM, &action, NULL);
581 CHECK_RES_DIE(res, "sigaction");
582
583 /* Ignore SIGPIPE . */
584 action.sa_handler = SIG_IGN;
585 res = sigaction(SIGPIPE, &action, NULL);
586 CHECK_RES_DIE(res, "sigaction");
587
588}
589
590/* Open syslog connection with appropriate banner;
591 * banner is made up of basename(bin_name)+"[pid]" */
592void setup_syslog(const char* bin_name) {
593 char *name1, *name2;
594 int res;
595
596 name1 = strdup(bin_name);
597 res = asprintf(&name2, "%s[%d]", basename(name1), getpid());
598 CHECK_RES_DIE(res, "asprintf");
599 openlog(name2, LOG_CONS, LOG_AUTH);
600 free(name1);
601 /* Don't free name2, as openlog(3) uses it (at least in glibc) */
602
603 log_message(LOG_INFO, "%s %s started\n", server_type, VERSION);
604}
605
606/* Ask OS to keep capabilities over a setuid(nonzero) */
607void set_keepcaps(int val) {
608#ifdef LIBCAP
609 int res;
610 res = prctl(PR_SET_KEEPCAPS, val, 0, 0, 0);
611 if (res) {
612 perror("prctl");
613 exit(1);
614 }
615#endif
616}
617
618/* set needed capabilities for effective and permitted, clear rest */
619void set_capabilities(void) {
620#ifdef LIBCAP
621 int res;
622 cap_t caps;
623 cap_value_t cap_list[10];
624 int ncap = 0;
625
626 if (transparent)
627 cap_list[ncap++] = CAP_NET_ADMIN;
628
629 caps = cap_init();
630
631#define _cap_set_flag(flag) do { \
632 res = cap_clear_flag(caps, flag); \
633 CHECK_RES_DIE(res, "cap_clear_flag(" #flag ")"); \
634 if (ncap > 0) { \
635 res = cap_set_flag(caps, flag, ncap, cap_list, CAP_SET); \
636 CHECK_RES_DIE(res, "cap_set_flag(" #flag ")"); \
637 } \
638 } while(0)
639
640 _cap_set_flag(CAP_EFFECTIVE);
641 _cap_set_flag(CAP_PERMITTED);
642
643#undef _cap_set_flag
644
645 res = cap_set_proc(caps);
646 CHECK_RES_DIE(res, "cap_set_proc");
647
648 res = cap_free(caps);
649 if (res) {
650 perror("cap_free");
651 exit(1);
652 }
653#endif
654}
655
656/* We don't want to run as root -- drop privileges if required */
657void drop_privileges(const char* user_name)
658{
659 int res;
660 struct passwd *pw = getpwnam(user_name);
661 if (!pw) {
662 fprintf(stderr, "%s: not found\n", user_name);
663 exit(2);
664 }
665 if (verbose)
666 fprintf(stderr, "turning into %s\n", user_name);
667
668 set_keepcaps(1);
669
670 /* remove extraneous groups in case we belong to several extra groups that
671 * may have unwanted rights. If non-root when calling setgroups(), it
672 * fails, which is fine because... we have no unwanted rights
673 * (see POS36-C for security context)
674 * */
675 setgroups(0, NULL);
676
677 res = setgid(pw->pw_gid);
678 CHECK_RES_DIE(res, "setgid");
679 res = setuid(pw->pw_uid);
680 CHECK_RES_DIE(res, "setuid");
681
682 set_capabilities();
683 set_keepcaps(0);
684}
685
686/* Writes my PID */
687void write_pid_file(const char* pidfile)
688{
689 FILE *f;
690
691 f = fopen(pidfile, "w");
692 if (!f) {
693 perror(pidfile);
694 exit(3);
695 }
696
697 fprintf(f, "%d\n", getpid());
698 fclose(f);
699}
700
701

Built with git-ssb-web