git ssb

0+

cel / sslh



Tree: f02ce3821c018719536971dbb1bc1ed1517530a2

Files: f02ce3821c018719536971dbb1bc1ed1517530a2 / common.c

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

Built with git-ssb-web