2 * Sub-authentication Daemon
4 * (c) 2017 Martin Mares <mj@ucw.cz>
10 #include <ucw/mainloop.h>
15 #include <sys/socket.h>
21 static char *socket_path = "subauthd.socket";
22 static uint max_connections = ~0U;
24 static struct main_file listen_socket;
25 static uint num_connections;
27 #define SOCKET_TIMEOUT 60000 // in ms
28 #define MAX_PACKET_SIZE 4096
29 #define MAX_OOB_DATA_SIZE 4096
32 struct main_file socket;
33 struct main_timer timer;
36 static byte packet_buffer[MAX_PACKET_SIZE];
37 static byte oob_data_buffer[MAX_OOB_DATA_SIZE];
39 static void client_close(struct client *c)
41 msg(L_INFO, "Closing connection");
47 static void socket_timeout_handler(struct main_timer *tm)
49 struct client *c = tm->data;
51 msg(L_INFO, "Client timeout");
56 static int socket_read_handler(struct main_file *fi)
58 struct client *c = fi->data;
61 .iov_base = packet_buffer,
62 .iov_len = MAX_PACKET_SIZE,
68 .msg_control = oob_data_buffer,
69 .msg_controllen = MAX_OOB_DATA_SIZE,
72 ssize_t len = recvmsg(fi->fd, &mh, 0);
75 if (errno != EAGAIN && errno != EINTR)
76 msg(L_ERROR, "Socket read: %m");
86 msg(L_INFO, "Got packet: len=%zd", len);
88 struct ucred *cred = NULL;
89 for (struct cmsghdr *cm = CMSG_FIRSTHDR(&mh); cm; cm = CMSG_NXTHDR(&mh, cm))
91 if (cm->cmsg_level == SOL_SOCKET)
93 if (cm->cmsg_type == SCM_RIGHTS)
95 // We are not interested in receiving file descriptor, but despite
96 // that they could be attached to the message. If it happens, simply
98 int *fdptr = (int *) CMSG_DATA(cm);
99 int nfd = cm->cmsg_len / sizeof(int);
100 for (int i=0; i<nfd; i++)
103 else if (cm->cmsg_type == SCM_CREDENTIALS)
105 ASSERT(cm->cmsg_len >= sizeof(cred));
106 cred = (struct ucred *) CMSG_DATA(cm);
113 msg(L_ERROR, "Dropping message with no credentials");
117 msg(L_INFO, "Credentials: pid=%d uid=%d gid=%d", (int) cred->pid, (int) cred->uid, (int) cred->gid);
122 static int listen_read_handler(struct main_file *fi)
124 struct sockaddr_un client;
125 socklen_t addr_len = sizeof(client);
127 int new_sk = accept(fi->fd, &client, &addr_len);
130 if (errno != EAGAIN && errno != EINTR)
131 msg(L_ERROR, "Socket accept: %m");
135 if (num_connections >= max_connections)
137 msg(L_WARN, "Too many connections (you might need to increase MaxConnections)");
143 msg(L_INFO, "Accepted connection");
145 if (fcntl(new_sk, F_SETFL, fcntl(new_sk, F_GETFL) | O_NONBLOCK) < 0)
146 die("Cannot set O_NONBLOCK: %m");
148 struct client *c = xmalloc_zero(sizeof(*c));
149 c->socket.fd = new_sk;
150 c->socket.read_handler = socket_read_handler;
152 file_add(&c->socket);
154 c->timer.handler = socket_timeout_handler;
156 timer_add_rel(&c->timer, SOCKET_TIMEOUT);
161 static void init_socket(void)
163 int sk = socket(PF_UNIX, SOCK_SEQPACKET, 0);
165 die("socket(PF_UNIX, SOCK_SEQPACKET): %m");
167 if (fcntl(sk, F_SETFL, fcntl(sk, F_GETFL) | O_NONBLOCK) < 0)
168 die("Cannot set O_NONBLOCK: %m");
170 struct sockaddr_un sun;
171 sun.sun_family = AF_UNIX;
172 if (strlen(socket_path) >= sizeof(sun.sun_path))
173 die("SocketPath too long");
174 strcpy(sun.sun_path, socket_path);
176 if (unlink(socket_path) < 0 && errno != ENOENT)
177 die("Cannot unlink old socket %s: %m", socket_path);
179 if (bind(sk, (struct sockaddr *) &sun, sizeof(sun)) < 0)
180 die("Cannot bind to %s: %m", socket_path);
182 if (listen(sk, 64) < 0)
186 if (setsockopt(sk, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
187 die("setsockopt(SO_PASSCRED): %m");
189 listen_socket.fd = sk;
190 listen_socket.read_handler = listen_read_handler;
191 file_add(&listen_socket);
193 msg(L_INFO, "Listening on %s", socket_path);
196 static struct cf_section daemon_config = {
198 CF_STRING("SocketPath", &socket_path),
199 CF_UINT("MaxConnections", &max_connections),
204 static const struct opt_section options = {
206 OPT_HELP("A sub-authentication daemon."),
207 OPT_HELP("Usage: subauthd [options]"),
209 OPT_HELP("Options:"),
216 int main(int argc UNUSED, char **argv)
218 cf_def_file = CONFIG_DIR "/subauthd";
219 cf_declare_section("SubauthD", &daemon_config, 0);
220 opt_parse(&options, argv+1);