git ssb

0+

cel / sslh



Tree: 960373f54f4b7127b4be72a3bad8bd74327fee96

Files: 960373f54f4b7127b4be72a3bad8bd74327fee96 / common.c

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

Built with git-ssb-web