git ssb

0+

cel / sslh



Tree: 414ed7de1108da241c640db0319e0b18a3d5b4c8

Files: 414ed7de1108da241c640db0319e0b18a3d5b4c8 / common.c

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

Built with git-ssb-web