Line data Source code
1 : #include <minipot.h>
2 : #include <minipot_utils.h>
3 : #include <unistd.h>
4 : #include <stdlib.h>
5 : #include <sys/prctl.h>
6 : #include <signal.h>
7 : #include <pwd.h>
8 : #include <grp.h>
9 : #include <string.h>
10 : #include "log.h"
11 :
12 : #define LISTEN_QUEUE_LIMIT 5
13 :
14 0 : static void sigint_cb(evutil_socket_t fd, short events, void *arg) {
15 0 : minipot_stop((struct minipot *)arg);
16 0 : }
17 :
18 0 : static int port_bind(int sock, uint16_t port) {
19 0 : struct sockaddr_in6 listen_addr;
20 0 : memset(&listen_addr, 0, sizeof(listen_addr));
21 0 : listen_addr.sin6_family = AF_INET6;
22 0 : listen_addr.sin6_addr = in6addr_any;
23 0 : listen_addr.sin6_port = htons(port);
24 0 : if (bind(sock, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) != 0)
25 0 : return -1;
26 : return 0;
27 : }
28 :
29 0 : static int create_sock() {
30 0 : int fd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
31 0 : if (fd < 0)
32 : return -1;
33 0 : int flag = 1;
34 0 : if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) != 0)
35 0 : goto err;
36 0 : flag = 0;
37 0 : if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) != 0)
38 0 : goto err;
39 : return fd;
40 0 : err:
41 0 : close(fd);
42 0 : return -1;
43 : }
44 :
45 0 : static int drop_priviledges(const char *username) {
46 0 : if (geteuid()) {
47 0 : if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
48 0 : return -1;
49 : } else {
50 : // running under super-user
51 0 : struct passwd *usr = getpwnam(username);
52 0 : if (!usr || chroot("/var/empty")
53 0 : || chdir("/")
54 0 : || setresgid(usr->pw_gid, usr->pw_gid, usr->pw_gid)
55 0 : || setgroups(1, &usr->pw_gid)
56 0 : || setresuid(usr->pw_uid, usr->pw_uid, usr->pw_uid)
57 0 : || (geteuid() == 0)
58 0 : || (getegid() == 0))
59 0 : return -1;
60 : }
61 : return 0;
62 : }
63 :
64 : void minipot_init(struct minipot *self, const struct minipot_config *config,
65 : int pipe_write_fd, event_callback_fn accept_cb, void *accept_cb_arg) {
66 :
67 0 : self->ev_base = event_base_new();
68 0 : assert(self->ev_base);
69 :
70 0 : self->sigint_ev = event_new(self->ev_base, SIGINT, EV_SIGNAL, sigint_cb,
71 : self);
72 0 : assert(self->sigint_ev);
73 0 : assert(event_add(self->sigint_ev, NULL) == 0);
74 :
75 0 : self->smsg_packer = minipot_sentinel_msg_packer_new();
76 0 : assert(self->smsg_packer);
77 :
78 0 : self->report_fd = pipe_write_fd;
79 :
80 0 : self->recv_buff = malloc(sizeof(*self->recv_buff) * MINIPOT_RECV_BUFF_LEN);
81 :
82 0 : self->ports_cnt = config->ports_cnt;
83 0 : self->listen_fds = malloc(sizeof(*self->listen_fds) * self->ports_cnt);
84 0 : self->accept_evs = malloc(sizeof(**self->accept_evs) * self->ports_cnt);
85 :
86 0 : for (size_t i = 0; i < self->ports_cnt; i++) {
87 0 : self->listen_fds[i] = create_sock();
88 0 : assert(self->listen_fds[i]);
89 0 : assert(port_bind(self->listen_fds[i], config->ports[i]) == 0);
90 0 : assert(listen(self->listen_fds[i], LISTEN_QUEUE_LIMIT) == 0);
91 0 : self->accept_evs[i] = event_new(self->ev_base, self->listen_fds[i],
92 : EV_READ | EV_PERSIST, accept_cb, accept_cb_arg);
93 0 : assert(self->accept_evs[i]);
94 : }
95 0 : assert(drop_priviledges(config->user) == 0);
96 0 : }
97 :
98 : void minipot_destroy(struct minipot *self) {
99 0 : event_free(self->sigint_ev);
100 0 : free(self->recv_buff);
101 0 : for (size_t i = 0; i < self->ports_cnt; i++) {
102 0 : event_free(self->accept_evs[i]);
103 0 : close(self->listen_fds[i]);
104 : }
105 0 : free(self->listen_fds);
106 0 : free(self->accept_evs);
107 0 : event_base_free(self->ev_base);
108 0 : minipot_sentinel_msg_packer_free(self->smsg_packer);
109 0 : }
110 :
111 : int minipot_run(struct minipot *self) {
112 0 : return event_base_dispatch(self->ev_base);
113 : }
114 :
115 : int minipot_stop(struct minipot *self) {
116 0 : return event_base_loopbreak(self->ev_base);
117 : }
118 :
119 : int minipot_start_accept_new_conn(struct minipot *self) {
120 0 : int ret = 0;
121 0 : for (size_t i = 0; i < self->ports_cnt; i++)
122 0 : if (event_add(self->accept_evs[i], NULL))
123 0 : ret = -1;
124 0 : return ret;
125 : }
126 :
127 : int minipot_stop_accept_new_conn(struct minipot *self) {
128 0 : int ret = 0;
129 0 : for (size_t i = 0; i < self->ports_cnt; i++)
130 0 : if (event_del(self->accept_evs[i]))
131 0 : ret = -1;
132 0 : return ret;
133 : }
|