simplify the communication between main and sec-mod

This commit is contained in:
Nikos Mavrogiannopoulos
2015-02-25 10:33:25 +01:00
parent b44d84f7a2
commit 3222cedb99
7 changed files with 272 additions and 68 deletions

View File

@@ -78,7 +78,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
script-list.h $(COMMON_SOURCES) $(AUTH_SOURCES) $(ACCT_SOURCES) \
icmp-ping.c icmp-ping.h worker-kkdcp.c subconfig.c \
sec-mod-sup-config.c sec-mod-sup-config.h \
sup-config/file.c sup-config/file.h \
sup-config/file.c sup-config/file.h main-sec-mod-cmd.c \
sup-config/radius.c sup-config/radius.h \
worker-bandwidth.c worker-bandwidth.h ctl.h main-ctl.h \
vasprintf.c vasprintf.h lzs.c lzs.h cfg.h \

View File

@@ -165,7 +165,7 @@ struct proc_st *ctmp;
static
int session_cmd(main_server_st * s, struct proc_st *proc, const uint8_t *cookie, unsigned cookie_size)
{
int sd, ret, e;
int ret, e;
SecAuthSessionMsg ireq = SEC_AUTH_SESSION_MSG__INIT;
SecAuthSessionReplyMsg *msg = NULL;
unsigned type, i;
@@ -176,26 +176,6 @@ int session_cmd(main_server_st * s, struct proc_st *proc, const uint8_t *cookie,
else
type = SM_CMD_AUTH_SESSION_CLOSE;
sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sd == -1) {
e = errno;
mslog(s, proc, LOG_ERR, "error opening unix socket (for sec-mod) %s",
strerror(e));
return -1;
}
ret =
connect(sd, (struct sockaddr *)&s->secmod_addr,
s->secmod_addr_len);
if (ret < 0) {
e = errno;
close(sd);
mslog(s, proc, LOG_ERR,
"error connecting to sec-mod socket '%s': %s",
s->secmod_addr.sun_path, strerror(e));
return -1;
}
ireq.uptime = time(0)-proc->conn_time;
ireq.has_uptime = 1;
ireq.bytes_in = proc->bytes_in;
@@ -213,23 +193,21 @@ int session_cmd(main_server_st * s, struct proc_st *proc, const uint8_t *cookie,
mslog(s, proc, LOG_DEBUG, "sending msg %s to sec-mod", cmd_request_to_str(type));
ret = send_msg(proc, sd, type,
ret = send_msg(proc, s->sec_mod_fd, type,
&ireq, (pack_size_func)sec_auth_session_msg__get_packed_size,
(pack_func)sec_auth_session_msg__pack);
if (ret < 0) {
close(sd);
mslog(s, proc, LOG_ERR,
"error sending message to sec-mod socket '%s'",
s->secmod_addr.sun_path);
"error sending message to sec-mod cmd socket");
return -1;
}
if (type == SM_CMD_AUTH_SESSION_OPEN) {
ret = recv_msg(proc, sd, SM_CMD_AUTH_SESSION_REPLY,
ret = recv_msg(proc, s->sec_mod_fd, SM_CMD_AUTH_SESSION_REPLY,
(void *)&msg, (unpack_func) sec_auth_session_reply_msg__unpack);
close(sd);
if (ret < 0) {
mslog(s, proc, LOG_ERR, "error receiving auth reply message");
e = errno;
mslog(s, proc, LOG_ERR, "error receiving auth reply message from sec-mod cmd socket: %s", strerror(e));
return ret;
}
@@ -322,8 +300,6 @@ int session_cmd(main_server_st * s, struct proc_st *proc, const uint8_t *cookie,
proc->config.nbns_size = msg->n_nbns;
}
sec_auth_session_reply_msg__free_unpacked(msg, &pa);
} else {
close(sd);
}
return 0;
@@ -755,9 +731,11 @@ int handle_commands(main_server_st * s, struct proc_st *proc)
return ret;
}
void run_sec_mod(main_server_st * s)
/* Returns a file descriptor to be used for communication with sec-mod
*/
int run_sec_mod(main_server_st * s)
{
int e;
int e, fd[2], ret;
pid_t pid;
const char *p;
@@ -773,6 +751,12 @@ void run_sec_mod(main_server_st * s)
}
p = s->full_socket_file;
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error creating sec-mod command socket");
exit(1);
}
pid = fork();
if (pid == 0) { /* child */
clear_lists(s);
@@ -784,11 +768,13 @@ void run_sec_mod(main_server_st * s)
malloc_trim(0);
#endif
setproctitle(PACKAGE_NAME "-secmod");
sec_mod_server(s->main_pool, s->config, p, s->cookie_key);
close(fd[1]);
sec_mod_server(s->main_pool, s->config, p, s->cookie_key, fd[0]);
exit(0);
} else if (pid > 0) { /* parent */
close(fd[0]);
s->sec_mod_pid = pid;
return fd[1];
} else {
e = errno;
mslog(s, NULL, LOG_ERR, "error in fork(): %s", strerror(e));

128
src/main-sec-mod-cmd.c Normal file
View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <system.h>
#include <errno.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <tlslib.h>
#include <sys/un.h>
#include <cloexec.h>
#include "common.h"
#include "str.h"
#include "setproctitle.h"
#include <sec-mod.h>
#include <route-add.h>
#include <ipc.pb-c.h>
#include <script-list.h>
#include <vpn.h>
#include <main.h>
#include <ccan/list/list.h>
int handle_sec_mod_commands(main_server_st * s)
{
struct iovec iov[3];
uint8_t cmd;
struct msghdr hdr;
uint16_t length;
uint8_t *raw;
int ret, raw_len, e;
void *pool = talloc_new(s);
//PROTOBUF_ALLOCATOR(pa, pool);
if (pool == NULL)
return -1;
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
iov[1].iov_base = &length;
iov[1].iov_len = 2;
memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = iov;
hdr.msg_iovlen = 2;
ret = recvmsg(s->sec_mod_fd, &hdr, 0);
if (ret == -1) {
e = errno;
mslog(s, NULL, LOG_ERR,
"cannot obtain metadata from command socket: %s",
strerror(e));
return ERR_BAD_COMMAND;
}
if (ret == 0) {
mslog(s, NULL, LOG_DEBUG, "command socket closed");
return ERR_WORKER_TERMINATED;
}
if (ret < 3) {
mslog(s, NULL, LOG_ERR, "command error");
return ERR_BAD_COMMAND;
}
mslog(s, NULL, LOG_DEBUG, "main received message '%s' from sec-mod of %u bytes\n",
cmd_request_to_str(cmd), (unsigned)length);
raw = talloc_size(pool, length);
if (raw == NULL) {
mslog(s, NULL, LOG_ERR, "memory error");
return ERR_MEM;
}
raw_len = force_read_timeout(s->sec_mod_fd, raw, length, 2);
if (raw_len != length) {
e = errno;
mslog(s, NULL, LOG_ERR,
"cannot obtain data from command socket: %s",
strerror(e));
ret = ERR_BAD_COMMAND;
goto cleanup;
}
switch (cmd) {
default:
mslog(s, NULL, LOG_ERR, "unknown CMD from sec-mod 0x%x.", (unsigned)cmd);
ret = ERR_BAD_COMMAND;
goto cleanup;
}
ret = 0;
cleanup:
talloc_free(raw);
talloc_free(pool);
return ret;
}

View File

@@ -1017,7 +1017,7 @@ int main(int argc, char** argv)
write_pid_file();
run_sec_mod(s);
s->sec_mod_fd = run_sec_mod(s);
ret = ctl_handler_init(s);
if (ret < 0) {
@@ -1079,6 +1079,7 @@ int main(int argc, char** argv)
check_other_work(s);
/* initialize select */
n = 0;
FD_ZERO(&rd_set);
FD_ZERO(&wr_set);
@@ -1096,6 +1097,9 @@ int main(int argc, char** argv)
}
}
FD_SET(s->sec_mod_fd, &rd_set);
n = MAX(n, s->sec_mod_fd);
ret = ctl_handler_set_fds(s, &rd_set, &wr_set);
n = MAX(n, ret);
@@ -1243,6 +1247,10 @@ fork_failed:
}
}
if (FD_ISSET(s->sec_mod_fd, &rd_set)) {
handle_sec_mod_commands(s);
}
/* Check for pending control commands */
ctl_handler_run_pending(s, &rd_set, &wr_set);

View File

@@ -208,12 +208,14 @@ typedef struct main_server_st {
#else
int ctl_fd;
#endif
int sec_mod_fd;
void *main_pool; /* talloc main pool */
} main_server_st;
void clear_lists(main_server_st *s);
int handle_commands(main_server_st *s, struct proc_st* cur);
int handle_sec_mod_commands(main_server_st *s);
int user_connected(main_server_st *s, struct proc_st* cur);
void user_disconnected(main_server_st *s, struct proc_st* cur);
@@ -264,7 +266,7 @@ int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc,
int check_multiple_users(main_server_st *s, struct proc_st* proc);
int handle_script_exit(main_server_st *s, struct proc_st* proc, int code);
void run_sec_mod(main_server_st * s);
int run_sec_mod(main_server_st * s);
struct proc_st *new_proc(main_server_st * s, pid_t pid, int cmd_fd,
struct sockaddr_storage *remote_addr, socklen_t remote_addr_len,

View File

@@ -48,6 +48,7 @@
#define MAX_WAIT_SECS 3
#define MAX_PIN_SIZE GNUTLS_PKCS11_MAX_PIN_LEN
#define MAINTAINANCE_TIME 310
#define MAX_MSG_SIZE 8*1024
static int need_maintainance = 0;
static int need_reload = 0;
@@ -188,7 +189,7 @@ static int handle_op(void *pool, int cfd, sec_mod_st * sec, uint8_t type, uint8_
static
int process_packet(void *pool, int cfd, sec_mod_st * sec, cmd_request_t cmd,
uid_t uid, uint8_t * buffer, size_t buffer_size)
uint8_t * buffer, size_t buffer_size)
{
unsigned i;
gnutls_datum_t data, out;
@@ -295,15 +296,32 @@ int process_packet(void *pool, int cfd, sec_mod_st * sec, cmd_request_t cmd,
sec_auth_cont_msg__free_unpacked(auth_cont, &pa);
return ret;
}
default:
seclog(sec, LOG_WARNING, "unknown type 0x%.2x", cmd);
return -1;
}
return 0;
}
static
int process_packet_from_main(void *pool, int cfd, sec_mod_st * sec, cmd_request_t cmd,
uint8_t * buffer, size_t buffer_size)
{
gnutls_datum_t data;
int ret;
PROTOBUF_ALLOCATOR(pa, pool);
seclog(sec, LOG_DEBUG, "cmd [size=%d] %s\n", (int)buffer_size,
cmd_request_to_str(cmd));
data.data = buffer;
data.size = buffer_size;
switch (cmd) {
case SM_CMD_AUTH_SESSION_OPEN:
case SM_CMD_AUTH_SESSION_CLOSE:{
SecAuthSessionMsg *msg;
if (uid != 0) {
seclog(sec, LOG_INFO, "received session open/close from unauthorized uid (%u)\n", (unsigned)uid);
return -1;
}
msg =
sec_auth_session_msg__unpack(&pa, data.size,
data.data);
@@ -374,7 +392,7 @@ static void check_other_work(sec_mod_st *sec)
}
static
void serve_request(sec_mod_st *sec, uid_t uid, int cfd, uint8_t *buffer, unsigned buffer_size)
void serve_request(sec_mod_st *sec, int cfd, unsigned is_main, uint8_t *buffer, unsigned buffer_size)
{
int ret, e;
unsigned cmd, length;
@@ -410,20 +428,22 @@ void serve_request(sec_mod_st *sec, uid_t uid, int cfd, uint8_t *buffer, unsigne
goto leave;
}
ret = process_packet(pool, cfd, sec, cmd, uid, buffer, ret);
if (is_main)
ret = process_packet_from_main(pool, cfd, sec, cmd, buffer, ret);
else
ret = process_packet(pool, cfd, sec, cmd, buffer, ret);
if (ret < 0) {
seclog(sec, LOG_INFO, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret);
}
leave:
talloc_free(pool);
close(cfd);
return;
}
/* sec_mod_server:
* @config: server configuration
* @socket_file: the name of the socket
* @cmd_fd: socket to exchange commands with main
*
* This is the main part of the security module.
* It creates the unix domain socket identified by @socket_file
@@ -449,11 +469,11 @@ void serve_request(sec_mod_st *sec, uid_t uid, int cfd, uint8_t *buffer, unsigne
* key operations.
*/
void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_file,
uint8_t cookie_key[COOKIE_KEY_SIZE])
uint8_t cookie_key[COOKIE_KEY_SIZE], int cmd_fd)
{
struct sockaddr_un sa;
socklen_t sa_len;
int cfd, ret, e;
int cfd, ret, e, n;
unsigned i, buffer_size;
uid_t uid;
uint8_t *buffer;
@@ -461,11 +481,26 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
int sd;
sec_mod_st *sec;
void *sec_mod_pool;
fd_set rd_set;
sigset_t emptyset, blockset;
#ifdef HAVE_PSELECT
struct timespec ts;
#else
struct timeval ts;
#endif
#ifdef DEBUG_LEAKS
talloc_enable_leak_report_full();
#endif
sigemptyset(&blockset);
sigemptyset(&emptyset);
sigaddset(&blockset, SIGALRM);
sigaddset(&blockset, SIGTERM);
sigaddset(&blockset, SIGINT);
sigaddset(&blockset, SIGCHLD);
sigaddset(&blockset, SIGHUP);
sec_mod_pool = talloc_init("sec-mod");
if (sec_mod_pool == NULL) {
seclog(sec, LOG_ERR, "error in memory allocation");
@@ -599,11 +634,54 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
}
}
sigprocmask(SIG_BLOCK, &blockset, &sig_default_set);
seclog(sec, LOG_INFO, "sec-mod initialized (socket: %s)", SOCKET_FILE);
for (;;) {
check_other_work(sec);
FD_ZERO(&rd_set);
n = 0;
FD_SET(cmd_fd, &rd_set);
n = MAX(n, cmd_fd);
FD_SET(sd, &rd_set);
n = MAX(n, sd);
#ifdef HAVE_PSELECT
ts.tv_nsec = 0;
ts.tv_sec = 30;
ret = pselect(n + 1, &rd_set, NULL, NULL, &ts, &emptyset);
#else
ts.tv_usec = 0;
ts.tv_sec = 30;
sigprocmask(SIG_UNBLOCK, &blockset, NULL);
ret = select(n + 1, &rd_set, &wr_set, NULL, &ts);
sigprocmask(SIG_BLOCK, &blockset, NULL);
#endif
if (ret == -1 && errno == EINTR)
continue;
if (ret < 0) {
e = errno;
seclog(sec, LOG_ERR, "Error in pselect(): %s",
strerror(e));
exit(1);
}
if (FD_ISSET(cmd_fd, &rd_set)) {
buffer_size = MAX_MSG_SIZE;
buffer = talloc_size(sec, buffer_size);
if (buffer == NULL) {
seclog(sec, LOG_ERR, "error in memory allocation");
} else {
serve_request(sec, cmd_fd, 1, buffer, buffer_size);
talloc_free(buffer);
}
}
if (FD_ISSET(sd, &rd_set)) {
sa_len = sizeof(sa);
cfd = accept(sd, (struct sockaddr *)&sa, &sa_len);
if (cfd == -1) {
@@ -612,9 +690,9 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
seclog(sec, LOG_DEBUG,
"sec-mod error accepting connection: %s",
strerror(e));
}
continue;
}
}
/* do not allow unauthorized processes to issue commands
*/
@@ -622,15 +700,17 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
if (ret < 0) {
seclog(sec, LOG_INFO, "rejected unauthorized connection");
} else {
buffer_size = 8 * 1024;
buffer_size = MAX_MSG_SIZE;
buffer = talloc_size(sec, buffer_size);
if (buffer == NULL) {
seclog(sec, LOG_ERR, "error in memory allocation");
close(cfd);
} else {
serve_request(sec, uid, cfd, buffer, buffer_size);
serve_request(sec, cfd, 0, buffer, buffer_size);
talloc_free(buffer);
}
}
close(cfd);
}
#ifdef DEBUG_LEAKS
talloc_report_full(sec, stderr);
#endif

View File

@@ -125,7 +125,7 @@ int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req);
void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e);
void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_file,
uint8_t cookie_key[COOKIE_KEY_SIZE]);
uint8_t cookie_key[COOKIE_KEY_SIZE], int cmd_fd);
void cleanup_banned_entries(sec_mod_st *sec);
unsigned check_if_banned(sec_mod_st *sec, const char *ip);