git ssb

0+

cel / sslh



Tree: e492c2808c90ee151362420d6ac0b0d22cb943db

Files: e492c2808c90ee151362420d6ac0b0d22cb943db / common.c

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

Built with git-ssb-web