Added support for unix sockets for the occtl communication.

D-BUS support is left, but is not enabled by default.
This commit is contained in:
Nikos Mavrogiannopoulos
2014-05-07 11:59:43 +02:00
parent 6f694915c7
commit 71104b36a3
19 changed files with 2867 additions and 1231 deletions

2
.gitignore vendored
View File

@@ -52,6 +52,8 @@ src/libcmd-ocpasswd.a
src/libcmd-ocserv.a
src/ipc.pb-c.c
src/ipc.pb-c.h
src/ctl.pb-c.c
src/ctl.pb-c.h
src/occtl
.dirstamp
config.h.in

View File

@@ -50,9 +50,9 @@ AC_DEFINE([HAVE_PKCS11], [], [PKCS11 detected in gnutls])
dbus_enabled=no
AC_ARG_WITH(dbus,
AS_HELP_STRING([--without-dbus], [do not include dbus support]),
AS_HELP_STRING([--with-dbus], [use dbus instead of unix sockets]),
test_for_dbus=$withval,
test_for_dbus=yes)
test_for_dbus=no)
if test "$test_for_dbus" = yes;then
PKG_CHECK_MODULES([LIBDBUS], [dbus-1 >= 1.1.1],
@@ -123,19 +123,15 @@ AC_ARG_WITH(libnl,
test_for_libnl=$withval,
test_for_libnl=yes)
occtl_enabled=no
if test "$test_for_libnl" = yes;then
PKG_CHECK_MODULES(LIBNL3, libnl-route-3.0 >= 3.1, [have_libnl3=yes], [have_libnl3=no])
if test "${have_libnl3}" = "yes"; then
AC_DEFINE(HAVE_LIBNL, 1, [have libnl])
PKG_CHECK_MODULES(LIBNL3, libnl-route-3.0 >= 3.1, [have_libnl3=yes], [have_libnl3=no])
if test "${have_libnl3}" = "yes"; then
AC_DEFINE(HAVE_LIBNL, 1, [have libnl])
fi
fi
if test "$dbus_enabled" = yes;then
occtl_enabled=yes
have_readline=no
AC_LIB_HAVE_LINKFLAGS(readline,, [
have_readline=no
AC_LIB_HAVE_LINKFLAGS(readline,, [
#include <stdio.h>
#include <readline/readline.h>], [rl_replace_line(0,0);])
if test x$ac_cv_libreadline = xyes; then
@@ -145,7 +141,6 @@ if test "$dbus_enabled" = yes;then
else
PKG_CHECK_MODULES(LIBREADLINE, libedit, [have_libedit=yes], [have_libedit=no])
if test "${have_libedit}" = "no"; then
occtl_enabled=no
AC_MSG_WARN([[***
*** libreadline or editline was not found. occtl will not be built.
***]])
@@ -153,12 +148,6 @@ if test "$dbus_enabled" = yes;then
have_readline=editline
fi
fi
else
occtl_enabled=no
fi
fi
AM_CONDITIONAL(ENABLE_OCCTL, test "x$occtl_enabled" = xyes)
pam_enabled=no
LIBS="$oldlibs -lpam"
@@ -380,9 +369,6 @@ Summary of build options:
local PCL library: ${with_local_pcl}
local libopts: ${enable_local_libopts}
local http-parser: ${with_local_http_parser}
Optional programs:
occtl: ${occtl_enabled}
])
if test "$occtl_enabled" = no;then

View File

@@ -3,12 +3,13 @@ SUBDIRS =
AM_CPPFLAGS = -I$(srcdir)/../gl/ -I$(builddir)/../gl/ \
-I$(srcdir)/ -I$(builddir)/../ $(LIBOPTS_CFLAGS) \
$(LIBGNUTLS_CFLAGS) \
$(LIBPROTOBUF_C_CFLAGS) $(LIBDBUS_CFLAGS) \
$(LIBPROTOBUF_C_CFLAGS) \
$(LIBNL3_CFLAGS) $(LIBREADLINE_CFLAGS) \
$(LIBTALLOC_CFLAGS)
$(LIBTALLOC_CFLAGS) $(LIBDBUS_CFLAGS)
BUILT_SOURCES = ocpasswd-args.c ocpasswd-args.h \
ocserv-args.c ocserv-args.h ipc.pb-c.c ipc.pb-c.h
ocserv-args.c ocserv-args.h ipc.pb-c.c ipc.pb-c.h \
ctl.pb-c.c ctl.pb-c.h
if LOCAL_HTTP_PARSER
AM_CPPFLAGS += -I$(srcdir)/http-parser/
@@ -28,10 +29,7 @@ EXTRA_DIST = ccan/licenses/BSD-MIT version.inc.in \
ccan/licenses/CC0 ccan/licenses/LGPL-2.1 version.inc \
occtl-args.def ipc.proto
bin_PROGRAMS = ocpasswd
if ENABLE_OCCTL
bin_PROGRAMS += occtl
endif
bin_PROGRAMS = ocpasswd occtl
sbin_PROGRAMS = ocserv
@@ -54,18 +52,18 @@ ocserv-args.c: $(srcdir)/ocserv-args.def
ocserv-args.h: ocserv-args.c
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
cookies.c main-misc.c main-ctl-handler.c \
group-config.c ip-lease.c ip-lease.h \
cookies.c main-misc.c group-config.c ip-lease.c ip-lease.h \
vpn.h cookies.h tlslib.h log.c tun.c tun.h \
config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \
worker-extras.c main-auth.h html.c html.h \
main-user.c worker-misc.c setproctitle.h route-add.c route-add.h \
setproctitle.c worker-privs.c plain.c plain.h common.h common.c \
sec-mod.c sec-mod.h script-list.h system.c system.h icmp-ping.c icmp-ping.h \
worker-bandwidth.c worker-bandwidth.h \
worker-bandwidth.c worker-bandwidth.h ctl.h \
str.c str.h gettime.h $(CCAN_SOURCES) $(HTTP_PARSER_SOURCES)
ocserv_SOURCES += ipc.pb-c.h ipc.pb-c.c
ocserv_SOURCES += ipc.pb-c.h ipc.pb-c.c ctl.pb-c.c ctl.pb-c.h
if LOCAL_PROTOBUF_C
ocserv_SOURCES += protobuf/google/protobuf-c/protobuf-c.h protobuf/google/protobuf-c/protobuf-c.c
@@ -74,7 +72,8 @@ endif
ocserv_LDADD = ../gl/libgnu.a $(NEEDED_LIBOPTS) libcmd-ocserv.a
ocserv_LDADD += $(LIBGNUTLS_LIBS) $(PAM_LIBS) $(LIBUTIL) \
$(LIBSECCOMP) $(LIBWRAP) $(LIBCRYPT) $(NEEDED_HTTP_PARSER_LIBS) \
$(LIBPROTOBUF_C_LIBS) $(LIBSYSTEMD_DAEMON) $(LIBDBUS_LIBS)
$(LIBPROTOBUF_C_LIBS) $(LIBSYSTEMD_DAEMON) $(LIBTALLOC_LIBS)
if PCL
ocserv_LDADD += $(PCL_LIBS)
@@ -97,11 +96,26 @@ ocpasswd-args.c: $(srcdir)/ocpasswd-args.def
ocpasswd-args.h: ocpasswd-args.c
occtl_SOURCES = occtl.c occtl-pager.c occtl.h occtl-time.c occtl-cache.c \
occtl-nl.c
occtl_LDADD = ../gl/libgnu.a $(LIBDBUS_LIBS) $(LIBREADLINE_LIBS) \
$(LIBNL3_LIBS)
occtl-nl.c ctl.h common.h common.c ctl.pb-c.c ctl.pb-c.h
occtl_LDADD = ../gl/libgnu.a $(LIBREADLINE_LIBS) \
$(LIBNL3_LIBS) $(LIBPROTOBUF_C_LIBS)
if HAVE_DBUS
ocserv_SOURCES += main-ctl-dbus.c
occtl_SOURCES += occtl-dbus.c
ocserv_LDADD += $(LIBDBUS_LIBS)
occtl_LDADD += $(LIBDBUS_LIBS)
else
ocserv_SOURCES += main-ctl-unix.c
occtl_SOURCES += occtl-unix.c
endif
ipc.pb-c.c: ipc.proto
protoc-c --c_out=. $<
ipc.pb-c.h: ipc.pb-c.c
ctl.pb-c.c: ctl.proto
protoc-c --c_out=. $<
ctl.pb-c.h: ctl.pb-c.c

View File

@@ -80,7 +80,7 @@ const uint8_t * p = buf;
if (errno != EAGAIN && errno != EINTR)
return ret;
}
if (ret > 0) {
left -= ret;
p += ret;
@@ -139,6 +139,9 @@ fd_set set;
if (ret == -1) {
if (errno != EAGAIN && errno != EINTR)
return ret;
} else if (ret == 0 && left != 0) {
errno = ENOENT;
return -1;
}
if (ret > 0) {

View File

@@ -80,7 +80,7 @@ static struct cfg_options available_options[] = {
{ .name = "always-require-cert", .type = OPTION_BOOLEAN, .mandatory = 0 },
{ .name = "cisco-client-compat", .type = OPTION_BOOLEAN, .mandatory = 0 },
{ .name = "use-utmp", .type = OPTION_BOOLEAN, .mandatory = 0 },
{ .name = "use-dbus", .type = OPTION_BOOLEAN, .mandatory = 1 },
{ .name = "use-dbus", .type = OPTION_BOOLEAN, .mandatory = 0 },
{ .name = "try-mtu-discovery", .type = OPTION_BOOLEAN, .mandatory = 0 },
{ .name = "ping-leases", .type = OPTION_BOOLEAN, .mandatory = 0 },
{ .name = "tls-priorities", .type = OPTION_STRING, .mandatory = 0 },

24
src/ctl.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef CTL_H
# define CTL_H
#define OCSERV_UNIX_NAME "/var/run/ocserv.usocket"
enum {
CTL_CMD_STATUS = 1,
CTL_CMD_RELOAD,
CTL_CMD_STOP,
CTL_CMD_LIST,
CTL_CMD_USER_INFO,
CTL_CMD_ID_INFO,
CTL_CMD_DISCONNECT_NAME,
CTL_CMD_DISCONNECT_ID,
CTL_CMD_STATUS_REP = 101,
CTL_CMD_RELOAD_REP,
CTL_CMD_STOP_REP,
CTL_CMD_LIST_REP,
CTL_CMD_DISCONNECT_NAME_REP,
CTL_CMD_DISCONNECT_ID_REP,
};
#endif

54
src/ctl.proto Normal file
View File

@@ -0,0 +1,54 @@
/* STATUS */
message status_rep
{
required bool status = 1;
required uint32 pid = 2;
required uint32 sec_mod_pid = 3;
required uint32 active_clients = 4;
}
message bool_msg
{
required bool status = 1 [default = false];
}
message user_info_rep
{
required sint32 id = 1;
required string username = 2;
optional string groupname = 3;
required string ip = 4;
optional string tun = 5;
optional string remote_ip = 6;
optional string local_ip = 7;
optional string remote_ip6 = 8;
optional string local_ip6 = 9;
required uint32 conn_time = 10;
optional string hostname = 11;
optional string user_agent = 12;
required string status = 13;
optional string tls_ciphersuite = 14;
optional string dtls_ciphersuite = 15;
optional uint32 rx_per_sec = 16;
optional uint32 tx_per_sec = 17;
repeated string dns = 18;
repeated string nbns = 19;
repeated string routes = 20;
repeated string iroutes = 21;
}
message user_list_rep
{
repeated user_info_rep user = 1;
}
message username_req
{
required string username = 1;
}
message id_req
{
required sint32 id = 1;
}

View File

@@ -29,34 +29,53 @@
#include <ip-lease.h>
#include <errno.h>
#ifdef HAVE_DBUS
#include <main-ctl.h>
#include <dbus/dbus.h>
#include <str.h>
static void method_status(main_server_st * s, DBusConnection * conn,
#define OCSERV_DBUS_NAME "org.infradead.ocserv"
struct ctl_list_st {
struct list_head head;
};
struct dbus_ctx {
struct ctl_list_st ctl_list;
DBusConnection *conn;
};
static void method_status(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg);
static void method_list_users(main_server_st * s, DBusConnection * conn,
static void method_list_users(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg);
static void method_disconnect_user_name(main_server_st * s,
DBusConnection * conn,
struct dbus_ctx *ctx,
DBusMessage * msg);
static void method_disconnect_user_id(main_server_st * s, DBusConnection * conn,
static void method_disconnect_user_id(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg);
static void method_introspect(main_server_st * s, DBusConnection * conn,
static void method_introspect(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg);
static void method_stop(main_server_st * s, DBusConnection * conn,
static void method_stop(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg);
static void method_reload(main_server_st * s, DBusConnection * conn,
static void method_reload(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg);
static void method_user_info(main_server_st * s, DBusConnection * conn,
static void method_user_info(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg);
static void method_id_info(main_server_st * s, DBusConnection * conn,
static void method_id_info(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg);
typedef void (*method_func) (main_server_st * s, DBusConnection * conn,
typedef void (*method_func) (main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg);
#define CTL_READ 1
#define CTL_WRITE 2
struct ctl_handler_st {
struct list_node list;
int fd;
unsigned type; /* CTL_READ/WRITE */
unsigned enabled;
void *watch;
};
typedef struct {
char *name;
@@ -137,7 +156,7 @@ static const ctl_method_st methods[] = {
{NULL, 0, NULL, 0, NULL}
};
static void add_ctl_fd(main_server_st * s, int fd, void *watch, unsigned type)
static void add_ctl_fd(struct dbus_ctx *ctx, int fd, void *watch, unsigned type)
{
struct ctl_handler_st *tmp;
@@ -153,25 +172,25 @@ static void add_ctl_fd(main_server_st * s, int fd, void *watch, unsigned type)
tmp->watch = watch;
tmp->type = type;
mslog(s, NULL, LOG_DEBUG, "dbus: adding %s %swatch for fd: %d",
syslog(LOG_DEBUG, "dbus: adding %s %swatch for fd: %d",
(type == CTL_READ) ? "read" : "write",
(tmp->enabled) ? "" : "(disabled) ", fd);
list_add(&s->ctl_list.head, &(tmp->list));
list_add(&ctx->ctl_list.head, &(tmp->list));
}
static dbus_bool_t add_watch(DBusWatch * watch, void *data)
{
int fd = dbus_watch_get_unix_fd(watch);
main_server_st *s = data;
struct dbus_ctx *ctx = data;
unsigned flags;
flags = dbus_watch_get_flags(watch);
if (flags & DBUS_WATCH_READABLE) {
add_ctl_fd(s, fd, watch, CTL_READ);
add_ctl_fd(ctx, fd, watch, CTL_READ);
} else {
add_ctl_fd(s, fd, watch, CTL_WRITE);
add_ctl_fd(ctx, fd, watch, CTL_WRITE);
}
return 1;
@@ -179,12 +198,12 @@ static dbus_bool_t add_watch(DBusWatch * watch, void *data)
static void remove_watch(DBusWatch * watch, void *data)
{
main_server_st *s = data;
struct dbus_ctx *ctx = data;
struct ctl_handler_st *btmp = NULL, *bpos;
list_for_each_safe(&s->ctl_list.head, btmp, bpos, list) {
list_for_each_safe(&ctx->ctl_list.head, btmp, bpos, list) {
if (btmp->watch == watch) {
mslog(s, NULL, LOG_DEBUG,
syslog(LOG_DEBUG,
"dbus: removing %s watch for fd: %d",
(btmp->type == CTL_READ) ? "read" : "write",
btmp->fd);
@@ -198,17 +217,17 @@ static void remove_watch(DBusWatch * watch, void *data)
static void toggle_watch(DBusWatch * watch, void *data)
{
main_server_st *s = data;
struct dbus_ctx *ctx = data;
struct ctl_handler_st *btmp = NULL;
list_for_each(&s->ctl_list.head, btmp, list) {
list_for_each(&ctx->ctl_list.head, btmp, list) {
if (btmp->watch == watch) {
if (dbus_watch_get_enabled(watch)) {
btmp->enabled = 1;
} else
btmp->enabled = 0;
mslog(s, NULL, LOG_DEBUG,
syslog(LOG_DEBUG,
"dbus: %s %s watch for fd: %d",
(btmp->enabled) ? "enabling" : "disabling",
(btmp->type == CTL_READ) ? "read" : "write",
@@ -218,61 +237,8 @@ static void toggle_watch(DBusWatch * watch, void *data)
}
}
#define OCSERV_DBUS_NAME "org.infradead.ocserv"
void ctl_handler_deinit(main_server_st * s)
{
if (s->config->use_dbus != 0 && s->ctl_ctx != NULL) {
mslog(s, NULL, LOG_DEBUG, "closing DBUS connection");
dbus_connection_close(s->ctl_ctx);
dbus_bus_release_name(s->ctl_ctx, OCSERV_DBUS_NAME, NULL);
dbus_connection_unref(s->ctl_ctx);
}
}
/* Initializes unix socket and stores the fd.
*/
int ctl_handler_init(main_server_st * s)
{
int ret;
DBusError err;
DBusConnection *conn;
if (s->config->use_dbus == 0)
return 0;
dbus_error_init(&err);
conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
if (conn == NULL)
goto error;
ret = dbus_bus_request_name(conn, OCSERV_DBUS_NAME,
DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
goto error;
s->ctl_ctx = conn;
if (!dbus_connection_set_watch_functions(conn,
add_watch, remove_watch,
toggle_watch, s, NULL)) {
goto error;
}
return 0;
error:
if (dbus_error_is_set(&err)) {
fprintf(stderr, "DBUS connection error (%s)", err.message);
dbus_error_free(&err);
}
ctl_handler_deinit(s);
return ERR_CTL;
}
static void method_status(main_server_st * s, DBusConnection * conn,
static void method_status(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg)
{
DBusMessage *reply;
@@ -315,7 +281,7 @@ static void method_status(main_server_st * s, DBusConnection * conn,
goto error;
}
if (!dbus_connection_send(conn, reply, NULL)) {
if (!dbus_connection_send(ctx->conn, reply, NULL)) {
mslog(s, NULL, LOG_ERR, "error sending dbus reply");
goto error;
}
@@ -326,7 +292,7 @@ static void method_status(main_server_st * s, DBusConnection * conn,
return;
}
static void method_reload(main_server_st * s, DBusConnection * conn,
static void method_reload(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg)
{
DBusMessage *reply;
@@ -352,7 +318,7 @@ static void method_reload(main_server_st * s, DBusConnection * conn,
request_reload(0);
if (!dbus_connection_send(conn, reply, NULL)) {
if (!dbus_connection_send(ctx->conn, reply, NULL)) {
mslog(s, NULL, LOG_ERR, "error sending dbus reply");
goto error;
}
@@ -363,7 +329,7 @@ static void method_reload(main_server_st * s, DBusConnection * conn,
return;
}
static void method_stop(main_server_st * s, DBusConnection * conn,
static void method_stop(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg)
{
DBusMessage *reply;
@@ -389,7 +355,7 @@ static void method_stop(main_server_st * s, DBusConnection * conn,
request_stop(0);
if (!dbus_connection_send(conn, reply, NULL)) {
if (!dbus_connection_send(ctx->conn, reply, NULL)) {
mslog(s, NULL, LOG_ERR, "error sending dbus reply");
goto error;
}
@@ -569,7 +535,8 @@ static int append_user_info(main_server_st * s, DBusMessageIter * subs,
else
tmp = s->config->rx_per_sec;
tmp *= 1000;
if (dbus_message_iter_append_basic(subs, DBUS_TYPE_UINT32, &tmp) == 0) {
if (dbus_message_iter_append_basic(subs, DBUS_TYPE_UINT32, &tmp)
== 0) {
return -1;
}
@@ -578,7 +545,8 @@ static int append_user_info(main_server_st * s, DBusMessageIter * subs,
else
tmp = s->config->tx_per_sec;
tmp *= 1000;
if (dbus_message_iter_append_basic(subs, DBUS_TYPE_UINT32, &tmp) == 0) {
if (dbus_message_iter_append_basic(subs, DBUS_TYPE_UINT32, &tmp)
== 0) {
return -1;
}
@@ -630,7 +598,7 @@ static int append_user_info(main_server_st * s, DBusMessageIter * subs,
return 0;
}
static void method_list_users(main_server_st * s, DBusConnection * conn,
static void method_list_users(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg)
{
DBusMessage *reply;
@@ -686,7 +654,7 @@ static void method_list_users(main_server_st * s, DBusConnection * conn,
goto error;
}
if (!dbus_connection_send(conn, reply, NULL)) {
if (!dbus_connection_send(ctx->conn, reply, NULL)) {
mslog(s, NULL, LOG_ERR, "error sending dbus reply");
goto error;
}
@@ -697,8 +665,8 @@ static void method_list_users(main_server_st * s, DBusConnection * conn,
return;
}
static void single_info_common(main_server_st * s, DBusConnection * conn,
DBusMessage * msg, const char *user, unsigned id)
static void single_info_common(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg, const char *user, unsigned id)
{
DBusMessage *reply;
DBusMessageIter args;
@@ -779,7 +747,7 @@ static void single_info_common(main_server_st * s, DBusConnection * conn,
mslog(s, NULL, LOG_INFO, "could not find ID '%u'", id);
}
if (!dbus_connection_send(conn, reply, NULL)) {
if (!dbus_connection_send(ctx->conn, reply, NULL)) {
mslog(s, NULL, LOG_ERR, "error sending dbus reply");
goto error;
}
@@ -790,7 +758,7 @@ static void single_info_common(main_server_st * s, DBusConnection * conn,
return;
}
static void method_user_info(main_server_st * s, DBusConnection * conn,
static void method_user_info(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg)
{
DBusMessageIter args;
@@ -810,12 +778,12 @@ static void method_user_info(main_server_st * s, DBusConnection * conn,
dbus_message_iter_get_basic(&args, &name);
single_info_common(s, conn, msg, name, 0);
single_info_common(s, ctx, msg, name, 0);
return;
}
static void method_id_info(main_server_st * s, DBusConnection * conn,
static void method_id_info(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg)
{
DBusMessageIter args;
@@ -835,13 +803,13 @@ static void method_id_info(main_server_st * s, DBusConnection * conn,
dbus_message_iter_get_basic(&args, &id);
single_info_common(s, conn, msg, NULL, id);
single_info_common(s, ctx, msg, NULL, id);
return;
}
static void method_disconnect_user_name(main_server_st * s,
DBusConnection * conn,
struct dbus_ctx *ctx,
DBusMessage * msg)
{
DBusMessage *reply;
@@ -889,7 +857,7 @@ static void method_disconnect_user_name(main_server_st * s,
goto error;
}
if (!dbus_connection_send(conn, reply, NULL)) {
if (!dbus_connection_send(ctx->conn, reply, NULL)) {
mslog(s, NULL, LOG_ERR, "error sending dbus reply");
goto error;
}
@@ -900,7 +868,7 @@ static void method_disconnect_user_name(main_server_st * s,
return;
}
static void method_disconnect_user_id(main_server_st * s, DBusConnection * conn,
static void method_disconnect_user_id(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg)
{
DBusMessage *reply;
@@ -950,7 +918,7 @@ static void method_disconnect_user_id(main_server_st * s, DBusConnection * conn,
goto error;
}
if (!dbus_connection_send(conn, reply, NULL)) {
if (!dbus_connection_send(ctx->conn, reply, NULL)) {
mslog(s, NULL, LOG_ERR, "error sending dbus reply");
goto error;
}
@@ -971,7 +939,7 @@ static void method_disconnect_user_id(main_server_st * s, DBusConnection * conn,
"</interface>" \
"</node>\n"
static void method_introspect(main_server_st * s, DBusConnection * conn,
static void method_introspect(main_server_st * s, struct dbus_ctx *ctx,
DBusMessage * msg)
{
DBusMessage *reply = NULL;
@@ -1020,7 +988,7 @@ static void method_introspect(main_server_st * s, DBusConnection * conn,
goto error;
}
if (!dbus_connection_send(conn, reply, NULL)) {
if (!dbus_connection_send(ctx->conn, reply, NULL)) {
mslog(s, NULL, LOG_ERR, "error sending dbus reply");
goto error;
}
@@ -1034,19 +1002,20 @@ static void method_introspect(main_server_st * s, DBusConnection * conn,
}
void ctl_handle_commands(main_server_st * s, struct ctl_handler_st *ctl)
static void ctl_handle_commands(main_server_st * s, struct ctl_handler_st *ctl)
{
DBusConnection *conn = s->ctl_ctx;
struct dbus_ctx *ctx = s->ctl_ctx;
DBusConnection *conn;
DBusMessage *msg;
int ret;
unsigned flags, i;
if (s->config->use_dbus == 0) {
mslog(s, NULL, LOG_ERR, "%s called when D-BUS is disabled!",
__func__);
if (s->config->use_dbus == 0 || ctx == NULL) {
return;
}
conn = ctx->conn;
if (ctl->type == CTL_READ)
flags = DBUS_WATCH_READABLE;
else
@@ -1083,7 +1052,7 @@ void ctl_handle_commands(main_server_st * s, struct ctl_handler_st *ctl)
}
if (dbus_message_is_method_call
(msg, methods[i].iface, methods[i].name)) {
methods[i].func(s, conn, msg);
methods[i].func(s, ctx, msg);
break;
}
}
@@ -1091,23 +1060,109 @@ void ctl_handle_commands(main_server_st * s, struct ctl_handler_st *ctl)
dbus_message_unref(msg);
} while (msg != NULL);
}
#else
int ctl_handler_set_fds(main_server_st * s, fd_set * rd_set, fd_set * wr_set)
{
struct ctl_handler_st *ctl_tmp = NULL;
struct dbus_ctx *ctx = s->ctl_ctx;
int n = -1;
if (ctx == NULL)
return -1;
list_for_each(&ctx->ctl_list.head, ctl_tmp, list) {
if (ctl_tmp->enabled) {
if (ctl_tmp->type == CTL_READ)
FD_SET(ctl_tmp->fd, rd_set);
else
FD_SET(ctl_tmp->fd, wr_set);
n = MAX(n, ctl_tmp->fd);
}
}
return n;
}
void ctl_handler_run_pending(main_server_st* s, fd_set *rd_set, fd_set *wr_set)
{
struct ctl_handler_st *ctl_tmp = NULL, *ctl_pos;
struct dbus_ctx *ctx = s->ctl_ctx;
if (ctx == NULL)
return;
list_for_each_safe(&ctx->ctl_list.head, ctl_tmp, ctl_pos, list) {
if (ctl_tmp->enabled == 0)
continue;
if (ctl_tmp->type == CTL_READ) {
if (FD_ISSET(ctl_tmp->fd, rd_set))
ctl_handle_commands(s, ctl_tmp);
} else {
if (FD_ISSET(ctl_tmp->fd, wr_set))
ctl_handle_commands(s, ctl_tmp);
}
}
}
void ctl_handler_deinit(main_server_st * s)
{
return;
struct dbus_ctx *ctx = s->ctl_ctx;
if (s->config->use_dbus != 0 && ctx != NULL && ctx->conn != NULL) {
mslog(s, NULL, LOG_DEBUG, "closing DBUS connection");
dbus_connection_close(ctx->conn);
dbus_bus_release_name(ctx->conn, OCSERV_DBUS_NAME, NULL);
dbus_connection_unref(ctx->conn);
}
}
/* Initializes unix socket and stores the fd.
*/
int ctl_handler_init(main_server_st * s)
{
int ret;
DBusError err;
DBusConnection *conn;
struct dbus_ctx *ctx;
if (s->config->use_dbus == 0)
return 0;
ctx = calloc(1, sizeof(struct dbus_ctx));
if (ctx == NULL)
return ERR_CTL;
list_head_init(&ctx->ctl_list.head);
dbus_error_init(&err);
conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
if (conn == NULL)
goto error;
ret = dbus_bus_request_name(conn, OCSERV_DBUS_NAME,
DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
goto error;
ctx->conn = conn;
s->ctl_ctx = ctx;
if (!dbus_connection_set_watch_functions(conn,
add_watch, remove_watch,
toggle_watch, ctx, NULL)) {
goto error;
}
return 0;
error:
if (dbus_error_is_set(&err)) {
fprintf(stderr, "DBUS connection error (%s)", err.message);
dbus_error_free(&err);
}
ctl_handler_deinit(s);
return ERR_CTL;
}
void ctl_handle_commands(main_server_st * s, struct ctl_handler_st *ctl)
{
return;
}
#endif

663
src/main-ctl-unix.c Normal file
View File

@@ -0,0 +1,663 @@
/*
* Copyright (C) 2014 Red Hat
*
* 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/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <main.h>
#include <vpn.h>
#include <talloc.h>
#include <ip-lease.h>
#include <errno.h>
#include <system.h>
#include <main-ctl.h>
#include <ctl.pb-c.h>
#include <str.h>
static void method_status(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size);
static void method_list_users(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size);
static void method_disconnect_user_name(main_server_st * s, int cfd,
uint8_t * msg, unsigned msg_size);
static void method_disconnect_user_id(main_server_st * s, int cfd,
uint8_t * msg, unsigned msg_size);
static void method_stop(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size);
static void method_reload(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size);
static void method_user_info(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size);
static void method_id_info(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size);
typedef void (*method_func) (main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size);
typedef struct {
char *name;
unsigned cmd;
method_func func;
} ctl_method_st;
#define ENTRY(cmd, func) \
{#cmd, cmd, func}
static const ctl_method_st methods[] = {
ENTRY(CTL_CMD_STATUS, method_status),
ENTRY(CTL_CMD_RELOAD, method_reload),
ENTRY(CTL_CMD_STOP, method_stop),
ENTRY(CTL_CMD_LIST, method_list_users),
ENTRY(CTL_CMD_USER_INFO, method_user_info),
ENTRY(CTL_CMD_ID_INFO, method_id_info),
ENTRY(CTL_CMD_DISCONNECT_NAME, method_disconnect_user_name),
ENTRY(CTL_CMD_DISCONNECT_ID, method_disconnect_user_id),
{NULL, 0, NULL}
};
void ctl_handler_deinit(main_server_st * s)
{
if (s->ctl_fd >= 0) {
mslog(s, NULL, LOG_DEBUG, "closing unix socket connection");
close(s->ctl_fd);
/*remove(OCSERV_UNIX_NAME); */
}
}
/* Initializes unix socket and stores the fd.
*/
int ctl_handler_init(main_server_st * s)
{
int ret;
struct sockaddr_un sa;
int sd, e;
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", OCSERV_UNIX_NAME);
remove(OCSERV_UNIX_NAME);
sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sd == -1) {
e = errno;
mslog(s, NULL, LOG_ERR, "could not create socket '%s': %s",
OCSERV_UNIX_NAME, strerror(e));
return -1;
}
umask(066);
ret = bind(sd, (struct sockaddr *)&sa, SUN_LEN(&sa));
if (ret == -1) {
e = errno;
mslog(s, NULL, LOG_ERR, "could not bind socket '%s': %s",
OCSERV_UNIX_NAME, strerror(e));
return -1;
}
ret = chown(OCSERV_UNIX_NAME, s->config->uid, s->config->gid);
if (ret == -1) {
e = errno;
mslog(s, NULL, LOG_ERR, "could not chown socket '%s': %s",
OCSERV_UNIX_NAME, strerror(e));
}
ret = listen(sd, 1024);
if (ret == -1) {
e = errno;
mslog(s, NULL, LOG_ERR, "could not listen to socket '%s': %s",
OCSERV_UNIX_NAME, strerror(e));
return -1;
}
s->ctl_fd = sd;
return sd;
}
static void method_status(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size)
{
StatusRep rep = STATUS_REP__INIT;
int ret;
mslog(s, NULL, LOG_DEBUG, "ctl: status");
rep.status = 1;
rep.pid = getpid();
rep.sec_mod_pid = s->sec_mod_pid;
rep.active_clients = s->active_clients;
ret = send_msg(cfd, CTL_CMD_STATUS_REP, &rep,
(pack_size_func) status_rep__get_packed_size,
(pack_func) status_rep__pack);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error sending ctl reply");
}
return;
}
static void method_reload(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size)
{
BoolMsg rep = BOOL_MSG__INIT;
int ret;
mslog(s, NULL, LOG_DEBUG, "ctl: reload");
request_reload(0);
rep.status = 1;
ret = send_msg(cfd, CTL_CMD_RELOAD_REP, &rep,
(pack_size_func) bool_msg__get_packed_size,
(pack_func) bool_msg__pack);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error sending ctl reply");
}
return;
}
static void method_stop(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size)
{
BoolMsg rep = BOOL_MSG__INIT;
int ret;
mslog(s, NULL, LOG_DEBUG, "ctl: stop");
request_stop(0);
rep.status = 1;
ret = send_msg(cfd, CTL_CMD_STOP_REP, &rep,
(pack_size_func) bool_msg__get_packed_size,
(pack_func) bool_msg__pack);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error sending ctl reply");
}
return;
}
#define IPBUF_SIZE 64
static int append_user_info(main_server_st * s, void *pool,
UserListRep * list,
struct proc_st *ctmp, unsigned single)
{
uint32_t tmp;
char *ipbuf;
char *strtmp;
UserInfoRep *rep;
list->user =
talloc_realloc(pool, list->user, UserInfoRep *, (1 + list->n_user));
if (list->user == NULL)
return -1;
rep = list->user[list->n_user] = talloc(pool, UserInfoRep);
if (rep == NULL)
return -1;
list->n_user++;
user_info_rep__init(rep);
/* ID: pid */
rep->id = ctmp->pid;
rep->username = ctmp->username;
rep->groupname = ctmp->groupname;
ipbuf = talloc_size(pool, IPBUF_SIZE);
if (ipbuf == NULL)
return -1;
strtmp =
human_addr2((struct sockaddr *)&ctmp->remote_addr,
ctmp->remote_addr_len, ipbuf, IPBUF_SIZE, 0);
if (strtmp == NULL)
strtmp = "";
rep->ip = strtmp;
rep->tun = ctmp->tun_lease.name;
ipbuf = talloc_size(pool, IPBUF_SIZE);
if (ipbuf == NULL)
return -1;
strtmp = NULL;
if (ctmp->ipv4 != NULL)
strtmp =
human_addr2((struct sockaddr *)&ctmp->ipv4->rip,
ctmp->ipv4->rip_len, ipbuf, IPBUF_SIZE, 0);
if (strtmp == NULL)
strtmp = "";
rep->local_ip = strtmp;
ipbuf = talloc_size(pool, IPBUF_SIZE);
if (ipbuf == NULL)
return -1;
strtmp = NULL;
if (ctmp->ipv4 != NULL)
strtmp =
human_addr2((struct sockaddr *)&ctmp->ipv4->lip,
ctmp->ipv4->lip_len, ipbuf, IPBUF_SIZE, 0);
if (strtmp == NULL)
strtmp = "";
rep->remote_ip = strtmp;
/* IPv6 */
ipbuf = talloc_size(pool, IPBUF_SIZE);
if (ipbuf == NULL)
return -1;
strtmp = NULL;
if (ctmp->ipv6 != NULL)
strtmp =
human_addr2((struct sockaddr *)&ctmp->ipv6->rip,
ctmp->ipv6->rip_len, ipbuf, IPBUF_SIZE, 0);
if (strtmp == NULL)
strtmp = "";
rep->local_ip6 = strtmp;
ipbuf = talloc_size(pool, IPBUF_SIZE);
if (ipbuf == NULL)
return -1;
strtmp = NULL;
if (ctmp->ipv6 != NULL)
strtmp =
human_addr2((struct sockaddr *)&ctmp->ipv6->lip,
ctmp->ipv6->lip_len, ipbuf, IPBUF_SIZE, 0);
if (strtmp == NULL)
strtmp = "";
rep->remote_ip6 = strtmp;
rep->conn_time = ctmp->conn_time;
rep->hostname = ctmp->hostname;
rep->user_agent = ctmp->user_agent;
if (ctmp->status == PS_AUTH_COMPLETED)
strtmp = "connected";
else if (ctmp->status == PS_AUTH_INIT)
strtmp = "auth";
else if (ctmp->status == PS_AUTH_ZOMBIE)
strtmp = "zombie";
else if (ctmp->status == PS_AUTH_DEAD)
strtmp = "dead";
else if (ctmp->status == PS_AUTH_INACTIVE)
strtmp = "pre-auth";
else if (ctmp->status == PS_AUTH_FAILED)
strtmp = "auth failed";
else
strtmp = "unknown";
rep->status = strtmp;
rep->tls_ciphersuite = ctmp->tls_ciphersuite;
rep->dtls_ciphersuite = ctmp->dtls_ciphersuite;
if (single > 0) {
if (ctmp->config.rx_per_sec > 0)
tmp = ctmp->config.rx_per_sec;
else
tmp = s->config->rx_per_sec;
tmp *= 1000;
rep->rx_per_sec = tmp;
if (ctmp->config.tx_per_sec > 0)
tmp = ctmp->config.tx_per_sec;
else
tmp = s->config->tx_per_sec;
tmp *= 1000;
rep->tx_per_sec = tmp;
if (ctmp->config.dns_size > 0) {
rep->dns = ctmp->config.dns;
rep->n_dns = ctmp->config.dns_size;
} else {
rep->dns = s->config->network.dns;
rep->n_dns = s->config->network.dns_size;
}
if (ctmp->config.nbns_size > 0) {
rep->nbns = ctmp->config.nbns;
rep->n_nbns = ctmp->config.nbns_size;
} else {
rep->nbns = s->config->network.nbns;
rep->n_nbns = s->config->network.nbns_size;
}
if (ctmp->config.routes_size > 0) {
rep->routes = ctmp->config.routes;
rep->n_routes = ctmp->config.routes_size;
} else {
rep->routes = s->config->network.routes;
rep->n_routes = s->config->network.routes_size;
}
if (ctmp->config.iroutes_size > 0) {
rep->iroutes = ctmp->config.iroutes;
rep->n_iroutes = ctmp->config.iroutes_size;
}
}
return 0;
}
static void method_list_users(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size)
{
UserListRep rep = USER_LIST_REP__INIT;
struct proc_st *ctmp = NULL;
int ret;
void *pool = talloc_init("list-users");
mslog(s, NULL, LOG_DEBUG, "ctl: list-users");
if (pool == NULL) {
mslog(s, NULL, LOG_ERR, "memory allocation error");
return;
}
list_for_each(&s->proc_list.head, ctmp, list) {
ret = append_user_info(s, pool, &rep, ctmp, 0);
if (ret < 0) {
mslog(s, NULL, LOG_ERR,
"error appending user info to reply");
goto error;
}
}
ret = send_msg(cfd, CTL_CMD_LIST_REP, &rep,
(pack_size_func) user_list_rep__get_packed_size,
(pack_func) user_list_rep__pack);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error sending ctl reply");
}
error:
talloc_free(pool);
return;
}
static void single_info_common(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size, const char *user, unsigned id)
{
UserListRep rep = USER_LIST_REP__INIT;
int ret;
unsigned found_user = 0;
struct proc_st *ctmp = NULL;
void *pool = talloc_init("info-common");
if (user != NULL)
mslog(s, NULL, LOG_INFO, "providing info for user '%s'", user);
else
mslog(s, NULL, LOG_INFO, "providing info for ID '%u'", id);
if (pool == NULL) {
mslog(s, NULL, LOG_ERR, "memory allocation error");
return;
}
list_for_each(&s->proc_list.head, ctmp, list) {
if (user == NULL) { /* id */
if (id == 0 || id == -1 || id != ctmp->pid) {
continue;
}
} else { /* username */
if (strcmp(ctmp->username, user) != 0) {
continue;
}
}
ret = append_user_info(s, pool, &rep, ctmp, 1);
if (ret < 0) {
mslog(s, NULL, LOG_ERR,
"error appending user info to reply");
goto error;
}
found_user = 1;
if (id != 0) /* id -> one a single element */
break;
}
if (found_user == 0) {
if (user != NULL)
mslog(s, NULL, LOG_INFO, "could not find user '%s'",
user);
else
mslog(s, NULL, LOG_INFO, "could not find ID '%u'", id);
}
ret = send_msg(cfd, CTL_CMD_LIST_REP, &rep,
(pack_size_func) user_list_rep__get_packed_size,
(pack_func) user_list_rep__pack);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error sending ctl reply");
}
error:
talloc_free(pool);
return;
}
static void method_user_info(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size)
{
UsernameReq *req;
mslog(s, NULL, LOG_DEBUG, "ctl: user_info (name)");
req = username_req__unpack(NULL, msg_size, msg);
if (req == NULL) {
mslog(s, NULL, LOG_ERR, "error parsing user_info request");
return;
}
single_info_common(s, cfd, msg, msg_size, req->username, 0);
username_req__free_unpacked(req, NULL);
return;
}
static void method_id_info(main_server_st * s, int cfd, uint8_t * msg,
unsigned msg_size)
{
IdReq *req;
mslog(s, NULL, LOG_DEBUG, "ctl: user_info (id)");
req = id_req__unpack(NULL, msg_size, msg);
if (req == NULL) {
mslog(s, NULL, LOG_ERR, "error parsing id_info request");
return;
}
single_info_common(s, cfd, msg, msg_size, NULL, req->id);
id_req__free_unpacked(req, NULL);
return;
}
static void method_disconnect_user_name(main_server_st * s,
int cfd, uint8_t * msg,
unsigned msg_size)
{
UsernameReq *req;
BoolMsg rep = BOOL_MSG__INIT;
struct proc_st *cpos;
struct proc_st *ctmp = NULL;
int ret;
mslog(s, NULL, LOG_DEBUG, "ctl: disconnect_name");
req = username_req__unpack(NULL, msg_size, msg);
if (req == NULL) {
mslog(s, NULL, LOG_ERR,
"error parsing disconnect_name request");
return;
}
/* got the name. Try to disconnect */
list_for_each_safe(&s->proc_list.head, ctmp, cpos, list) {
if (strcmp(ctmp->username, req->username) == 0) {
remove_proc(s, ctmp, 1);
rep.status = 1;
}
}
username_req__free_unpacked(req, NULL);
ret = send_msg(cfd, CTL_CMD_DISCONNECT_NAME_REP, &rep,
(pack_size_func) bool_msg__get_packed_size,
(pack_func) bool_msg__pack);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error sending ctl reply");
}
return;
}
static void method_disconnect_user_id(main_server_st * s, int cfd,
uint8_t * msg, unsigned msg_size)
{
IdReq *req;
BoolMsg rep = BOOL_MSG__INIT;
struct proc_st *cpos;
struct proc_st *ctmp = NULL;
int ret;
mslog(s, NULL, LOG_DEBUG, "ctl: disconnect_id");
req = id_req__unpack(NULL, msg_size, msg);
if (req == NULL) {
mslog(s, NULL, LOG_ERR, "error parsing disconnect_id request");
return;
}
/* got the ID. Try to disconnect */
list_for_each_safe(&s->proc_list.head, ctmp, cpos, list) {
if (ctmp->pid == req->id) {
remove_proc(s, ctmp, 1);
rep.status = 1;
if (req->id != -1)
break;
}
}
/* reply */
id_req__free_unpacked(req, NULL);
ret = send_msg(cfd, CTL_CMD_DISCONNECT_ID_REP, &rep,
(pack_size_func) bool_msg__get_packed_size,
(pack_func) bool_msg__pack);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error sending ctl reply");
}
return;
}
static void ctl_handle_commands(main_server_st * s)
{
int cfd, e, ret;
unsigned i;
struct sockaddr_un sa;
socklen_t sa_len;
uint16_t length;
uint8_t buffer[256];
unsigned buffer_size;
sa_len = sizeof(sa);
cfd = accept(s->ctl_fd, (struct sockaddr *)&sa, &sa_len);
if (cfd == -1) {
e = errno;
mslog(s, NULL, LOG_ERR,
"error accepting control connection: %s", strerror(e));
return;
}
ret = check_upeer_id("ctl", cfd, 0, 0);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "ctl: unauthorized connection");
goto cleanup;
}
/* read request */
ret = recv(cfd, buffer, sizeof(buffer), 0);
if (ret < 3) {
if (ret == -1) {
e = errno;
mslog(s, NULL, LOG_ERR, "error receiving ctl data: %s",
strerror(e));
} else {
mslog(s, NULL, LOG_ERR, "received ctl data: %d bytes",
ret);
}
goto cleanup;
}
length = (buffer[2] << 8) | buffer[1];
buffer_size = ret - 3;
if (length != buffer_size) {
mslog(s, NULL, LOG_ERR,
"received data length doesn't match received data (%d/%d)",
buffer_size, (int)length);
goto cleanup;
}
for (i = 0;; i++) {
if (methods[i].cmd == 0) {
mslog(s, NULL, LOG_INFO,
"unknown unix ctl message: 0x%.1x",
(unsigned)buffer[0]);
break;
} else if (methods[i].cmd == buffer[0]) {
methods[i].func(s, cfd, buffer + 3, buffer_size);
break;
}
}
cleanup:
close(cfd);
}
int ctl_handler_set_fds(main_server_st * s, fd_set * rd_set, fd_set * wr_set)
{
FD_SET(s->ctl_fd, rd_set);
return s->ctl_fd;
}
void ctl_handler_run_pending(main_server_st* s, fd_set *rd_set, fd_set *wr_set)
{
if (FD_ISSET(s->ctl_fd, rd_set)) {
ctl_handle_commands(s);
}
}

12
src/main-ctl.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef MAIN_CTL_HANDLER_H
# define MAIN_CTL_HANDLER_H
#include <ctl.h>
int ctl_handler_init(main_server_st* s);
void ctl_handler_deinit(main_server_st* s);
int ctl_handler_set_fds(main_server_st* s, fd_set *rd_set, fd_set *wr_set);
void ctl_handler_run_pending(main_server_st* s, fd_set *rd_set, fd_set *wr_set);
#endif

View File

@@ -46,6 +46,7 @@
# include <systemd/sd-daemon.h>
#endif
#include <main.h>
#include <main-ctl.h>
#include <route-add.h>
#include <main-auth.h>
#include <worker.h>
@@ -818,7 +819,6 @@ int main(int argc, char** argv)
int fd, pid, e;
struct listener_st *ltmp = NULL;
struct proc_st *ctmp = NULL, *cpos;
struct ctl_handler_st* ctl_tmp = NULL, *ctl_pos;
fd_set rd_set, wr_set;
int n = 0, ret, flags;
#ifdef HAVE_PSELECT
@@ -838,7 +838,6 @@ int main(int argc, char** argv)
list_head_init(&s.proc_list.head);
list_head_init(&s.ban_list.head);
list_head_init(&s.script_list.head);
list_head_init(&s.ctl_list.head);
tls_cache_init(&s.tls_db);
ip_lease_init(&s.ip_leases);
@@ -950,15 +949,8 @@ int main(int argc, char** argv)
}
}
list_for_each(&s.ctl_list.head, ctl_tmp, list) {
if (ctl_tmp->enabled) {
if (ctl_tmp->type == CTL_READ)
FD_SET(ctl_tmp->fd, &rd_set);
else
FD_SET(ctl_tmp->fd, &wr_set);
n = MAX(n, ctl_tmp->fd);
}
}
ret = ctl_handler_set_fds(&s, &rd_set, &wr_set);
n = MAX(n, ret);
#ifdef HAVE_PSELECT
ts.tv_nsec = 0;
@@ -1114,18 +1106,7 @@ fork_failed:
}
/* Check for pending control commands */
list_for_each_safe(&s.ctl_list.head, ctl_tmp, ctl_pos, list) {
if (ctl_tmp->enabled == 0)
continue;
if (ctl_tmp->type == CTL_READ) {
if (FD_ISSET(ctl_tmp->fd, &rd_set))
ctl_handle_commands(&s, ctl_tmp);
} else {
if (FD_ISSET(ctl_tmp->fd, &wr_set))
ctl_handle_commands(&s, ctl_tmp);
}
}
ctl_handler_run_pending(&s, &rd_set, &wr_set);
}
return 0;

View File

@@ -161,21 +161,6 @@ struct ban_list_st {
struct list_head head;
};
#define CTL_READ 1
#define CTL_WRITE 2
struct ctl_handler_st {
struct list_node list;
int fd;
unsigned type; /* CTL_READ/WRITE */
unsigned enabled;
void* watch;
};
struct ctl_list_st {
struct list_head head;
};
typedef struct main_server_st {
struct cfg_st *config;
@@ -200,8 +185,11 @@ typedef struct main_server_st {
void * auth_extra;
struct ctl_list_st ctl_list;
#ifdef HAVE_DBUS
void * ctl_ctx;
#else
int ctl_fd;
#endif
} main_server_st;
void clear_lists(main_server_st *s);
@@ -294,9 +282,6 @@ int send_socket_msg_to_worker(main_server_st* s, struct proc_st* proc, uint8_t c
return send_socket_msg(proc->fd, cmd, socketfd, msg, get_size, pack);
}
void ctl_handle_commands(main_server_st* s, struct ctl_handler_st* ctl);
int ctl_handler_init(main_server_st* s);
void ctl_handler_deinit(main_server_st* s);
void request_reload(int signo);
void request_stop(int signo);

973
src/occtl-dbus.c Normal file
View File

@@ -0,0 +1,973 @@
/*
* Copyright (C) 2014 Red Hat
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of ocserv.
*
* ocserv 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.
*
* ocserv 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 <time.h>
#include <signal.h>
#include <c-ctype.h>
#include <dbus/dbus.h>
#include <occtl.h>
#include <c-strcase.h>
/* sends a message and returns the reply */
DBusMessage *send_dbus_cmd(DBusConnection * conn,
const char *bus_name, const char *path,
const char *interface, const char *method,
unsigned type, const void *arg)
{
DBusMessage *msg;
DBusMessageIter args;
DBusPendingCall *pending = NULL;
msg = dbus_message_new_method_call(bus_name, path, interface, method);
if (msg == NULL) {
goto error;
}
dbus_message_iter_init_append(msg, &args);
if (arg != NULL) {
if (!dbus_message_iter_append_basic(&args, type, arg)) {
goto error;
}
}
if (!dbus_connection_send_with_reply
(conn, msg, &pending, DEFAULT_TIMEOUT)) {
goto error;
}
if (pending == NULL)
goto error;
dbus_connection_flush(conn);
dbus_message_unref(msg);
/* wait for reply */
dbus_pending_call_block(pending);
msg = dbus_pending_call_steal_reply(pending);
if (msg == NULL)
goto error;
dbus_pending_call_unref(pending);
return msg;
error:
if (msg != NULL)
dbus_message_unref(msg);
return NULL;
}
int handle_status_cmd(DBusConnection * conn, const char *arg)
{
DBusMessage *msg;
DBusMessageIter args;
dbus_bool_t status;
dbus_uint32_t pid;
dbus_uint32_t sec_mod_pid;
dbus_uint32_t clients;
msg = send_dbus_cmd(conn, "org.infradead.ocserv",
"/org/infradead/ocserv",
"org.infradead.ocserv", "status", 0, NULL);
if (msg == NULL) {
goto error_send;
}
if (!dbus_message_iter_init(msg, &args))
goto error;
if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))
goto error_status;
dbus_message_iter_get_basic(&args, &status);
if (!dbus_message_iter_next(&args))
goto error_recv;
if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
goto error_parse;
dbus_message_iter_get_basic(&args, &pid);
if (!dbus_message_iter_next(&args))
goto error_recv;
if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
goto error_parse;
dbus_message_iter_get_basic(&args, &sec_mod_pid);
if (!dbus_message_iter_next(&args))
goto error_recv;
if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
goto error_parse;
dbus_message_iter_get_basic(&args, &clients);
printf("OpenConnect SSL VPN server\n");
printf(" Status: %s\n", status != 0 ? "online" : "error");
printf(" Clients: %u\n", (unsigned)clients);
printf("\n");
printf(" Server PID: %u\n", (unsigned)pid);
printf("Sec-mod PID: %u\n", (unsigned)sec_mod_pid);
dbus_message_unref(msg);
return 0;
error_status:
printf("OpenConnect SSL VPN server\n");
printf(" Status: offline\n");
goto error;
error_parse:
fprintf(stderr, "%s: D-BUS message parsing error\n", __func__);
goto error;
error_send:
fprintf(stderr, "%s: D-BUS message creation error\n", __func__);
goto error;
error_recv:
fprintf(stderr, "%s: D-BUS message receiving error\n", __func__);
error:
if (msg != NULL)
dbus_message_unref(msg);
return 1;
}
int handle_reload_cmd(DBusConnection * conn, const char *arg)
{
DBusMessage *msg;
DBusMessageIter args;
dbus_bool_t status;
msg = send_dbus_cmd(conn, "org.infradead.ocserv",
"/org/infradead/ocserv",
"org.infradead.ocserv", "reload", 0, NULL);
if (msg == NULL) {
goto error_send;
}
if (!dbus_message_iter_init(msg, &args))
goto error_server;
if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))
goto error_server;
dbus_message_iter_get_basic(&args, &status);
if (status != 0)
printf("Server scheduled to reload\n");
else
goto error_status;
dbus_message_unref(msg);
return 0;
error_server:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
goto cleanup;
error_status:
printf("Error scheduling reload\n");
goto cleanup;
error_send:
fprintf(stderr, "%s: D-BUS message creation error\n", __func__);
goto cleanup;
cleanup:
if (msg != NULL)
dbus_message_unref(msg);
return 1;
}
int handle_stop_cmd(DBusConnection * conn, const char *arg)
{
DBusMessage *msg;
DBusMessageIter args;
dbus_bool_t status;
if (arg == NULL || need_help(arg) || c_strncasecmp(arg, "now", 3) != 0) {
check_cmd_help(rl_line_buffer);
return 1;
}
msg = send_dbus_cmd(conn, "org.infradead.ocserv",
"/org/infradead/ocserv",
"org.infradead.ocserv", "stop", 0, NULL);
if (msg == NULL) {
goto error_send;
}
if (!dbus_message_iter_init(msg, &args))
goto error_server;
if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))
goto error_server;
dbus_message_iter_get_basic(&args, &status);
if (status != 0)
printf("Server scheduled to stop\n");
else
goto error_status;
dbus_message_unref(msg);
return 0;
error_server:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
goto cleanup;
error_status:
printf("Error scheduling server stop\n");
goto cleanup;
error_send:
fprintf(stderr, "%s: D-BUS message creation error\n", __func__);
goto cleanup;
cleanup:
if (msg != NULL)
dbus_message_unref(msg);
return 1;
}
int handle_disconnect_user_cmd(DBusConnection * conn, const char *arg)
{
DBusMessage *msg;
DBusMessageIter args;
dbus_bool_t status;
if (arg == NULL || need_help(arg)) {
check_cmd_help(rl_line_buffer);
return 1;
}
msg = send_dbus_cmd(conn, "org.infradead.ocserv",
"/org/infradead/ocserv",
"org.infradead.ocserv",
"disconnect_name", DBUS_TYPE_STRING, &arg);
if (msg == NULL) {
goto error;
}
if (!dbus_message_iter_init(msg, &args))
goto error;
if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))
goto error;
dbus_message_iter_get_basic(&args, &status);
if (status != 0) {
printf("user '%s' was disconnected\n", arg);
} else {
printf("could not disconnect user '%s'\n", arg);
}
dbus_message_unref(msg);
return 0;
error:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
if (msg != NULL)
dbus_message_unref(msg);
return 1;
}
int handle_disconnect_id_cmd(DBusConnection * conn, const char *arg)
{
DBusMessage *msg;
DBusMessageIter args;
dbus_bool_t status;
dbus_uint32_t id = 0;
int ret;
if (arg != NULL)
id = atoi(arg);
if (arg == NULL || need_help(arg) || id == 0) {
check_cmd_help(rl_line_buffer);
return 1;
}
msg = send_dbus_cmd(conn, "org.infradead.ocserv",
"/org/infradead/ocserv",
"org.infradead.ocserv",
"disconnect_id", DBUS_TYPE_UINT32, &id);
if (msg == NULL) {
goto error;
}
if (!dbus_message_iter_init(msg, &args))
goto error;
if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))
goto error;
dbus_message_iter_get_basic(&args, &status);
if (status != 0) {
printf("connection ID '%s' was disconnected\n", arg);
ret = 0;
} else {
printf("could not disconnect ID '%s'\n", arg);
ret = 1;
}
dbus_message_unref(msg);
return ret;
error:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
if (msg != NULL)
dbus_message_unref(msg);
return 1;
}
int handle_list_users_cmd(DBusConnection * conn, const char *arg)
{
DBusMessage *msg;
DBusMessageIter args, suba, subs;
dbus_int32_t id = 0;
char *username = "";
dbus_uint32_t since = 0;
char *groupname = "", *ip = "";
char *vpn_ipv4 = "", *vpn_ptp_ipv4 = "";
char *vpn_ipv6 = "", *vpn_ptp_ipv6 = "";
char *hostname = "", *auth = "", *device = "";
char *user_agent = "";
char str_since[64];
const char *vpn_ip;
struct tm *tm;
time_t t;
FILE *out;
unsigned iteration = 0;
const char *dtls_ciphersuite, *tls_ciphersuite;
int ret = 1;
entries_clear();
out = pager_start();
msg = send_dbus_cmd(conn, "org.infradead.ocserv",
"/org/infradead/ocserv",
"org.infradead.ocserv", "list", 0, NULL);
if (msg == NULL) {
goto error_server;
}
if (!dbus_message_iter_init(msg, &args))
goto error_server;
if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
goto error_server;
dbus_message_iter_recurse(&args, &suba);
for (;;) {
if (dbus_message_iter_get_arg_type(&suba) != DBUS_TYPE_STRUCT)
goto cleanup;
dbus_message_iter_recurse(&suba, &subs);
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_INT32)
goto error_parse;
dbus_message_iter_get_basic(&subs, &id);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &username);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &groupname);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &ip);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &device);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &vpn_ptp_ipv4);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &vpn_ipv4);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &vpn_ptp_ipv6);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &vpn_ipv6);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_UINT32)
goto error_parse;
dbus_message_iter_get_basic(&subs, &since);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &hostname);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &user_agent);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &auth);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &tls_ciphersuite);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &dtls_ciphersuite);
if (vpn_ipv4 != NULL && vpn_ipv4[0] != 0)
vpn_ip = vpn_ipv4;
else
vpn_ip = vpn_ipv6;
/* add header */
if (iteration++ == 0) {
fprintf(out, "%8s %8s %8s %14s %14s %6s %7s %14s %9s\n",
"id", "user", "group", "ip", "vpn-ip", "device",
"since", "dtls-cipher", "status");
}
t = since;
tm = localtime(&t);
strftime(str_since, sizeof(str_since), "%Y-%m-%d %H:%M", tm);
if (groupname == NULL || groupname[0] == 0)
groupname = NO_GROUP;
if (username == NULL || username[0] == 0)
username = NO_USER;
fprintf(out, "%8d %8s %8s %14s %14s %6s ",
(int)id, username, groupname, ip, vpn_ip, device);
print_time_ival7(t, out);
if (dtls_ciphersuite != NULL && dtls_ciphersuite[0] != 0) {
if (strncmp(dtls_ciphersuite, "OC-DTLS", 7) == 0 && strlen(dtls_ciphersuite) > 11)
dtls_ciphersuite += 11;
fprintf(out, " %14s %9s\n", dtls_ciphersuite, auth);
} else {
fprintf(out, " %14s %9s\n", "(no dtls)", auth);
}
entries_add(username, strlen(username), id);
if (!dbus_message_iter_next(&suba))
break;
}
ret = 0;
goto cleanup;
error_server:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
goto cleanup;
error_parse:
fprintf(stderr, "%s: D-BUS message parsing error\n", __func__);
goto cleanup;
error_recv:
fprintf(stderr, "%s: D-BUS message receiving error\n", __func__);
cleanup:
pager_stop(out);
if (msg != NULL)
dbus_message_unref(msg);
return ret;
}
int print_list_entries(FILE* out, const char* name, DBusMessageIter * subs)
{
DBusMessageIter suba;
const char * tmp;
unsigned int i = 0;
if (dbus_message_iter_get_arg_type(subs) != DBUS_TYPE_ARRAY)
return -1;
dbus_message_iter_recurse(subs, &suba);
for (;;) {
if (dbus_message_iter_get_arg_type(&suba) != DBUS_TYPE_STRING)
break; /* empty */
dbus_message_iter_get_basic(&suba, &tmp);
if (tmp != NULL) {
if (i==0)
fprintf(out, "%s %s\n", name, tmp);
else
fprintf(out, "\t\t%s\n", tmp);
}
i++;
if (!dbus_message_iter_next(&suba))
break;
}
return i;
}
int common_info_cmd(DBusMessageIter * args)
{
DBusMessageIter suba, subs;
dbus_int32_t id = 0;
dbus_uint32_t rx = 0, tx = 0;
char *username = "";
dbus_uint32_t since = 0;
char *groupname = "", *ip = "";
char *vpn_ipv4 = "", *vpn_ptp_ipv4 = "";
char *vpn_ipv6 = "", *vpn_ptp_ipv6 = "";
char *hostname = "", *auth = "", *device = "";
char *user_agent = "";
char str_since[64];
struct tm *tm;
time_t t;
FILE *out;
unsigned at_least_one = 0;
const char *dtls_ciphersuite, *tls_ciphersuite;
int ret = 1, r;
out = pager_start();
if (dbus_message_iter_get_arg_type(args) != DBUS_TYPE_ARRAY)
goto cleanup;
dbus_message_iter_recurse(args, &suba);
for (;;) {
if (dbus_message_iter_get_arg_type(&suba) != DBUS_TYPE_STRUCT) {
ret = 2;
goto cleanup;
}
dbus_message_iter_recurse(&suba, &subs);
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_INT32)
goto error_parse;
dbus_message_iter_get_basic(&subs, &id);
if (at_least_one > 0)
fprintf(out, "\n");
fprintf(out, "ID: %d\n", (int)id);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &username);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &groupname);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &ip);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &device);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &vpn_ptp_ipv4);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &vpn_ipv4);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &vpn_ptp_ipv6);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &vpn_ipv6);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_UINT32)
goto error_parse;
dbus_message_iter_get_basic(&subs, &since);
t = since;
tm = localtime(&t);
strftime(str_since, sizeof(str_since), "%Y-%m-%d %H:%M", tm);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &hostname);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &user_agent);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &auth);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &tls_ciphersuite);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_STRING)
goto error_parse;
dbus_message_iter_get_basic(&subs, &dtls_ciphersuite);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_UINT32)
goto error_parse;
dbus_message_iter_get_basic(&subs, &rx);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (dbus_message_iter_get_arg_type(&subs) != DBUS_TYPE_UINT32)
goto error_parse;
dbus_message_iter_get_basic(&subs, &tx);
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (username == NULL || username[0] == 0)
username = NO_USER;
fprintf(out, "\tUsername: %s ", username);
if (groupname == NULL || groupname[0] == 0)
groupname = NO_GROUP;
fprintf(out, "Groupname: %s\n", groupname);
fprintf(out, "\tState: %s ", auth);
fprintf(out, "Remote IP: %s\n", ip);
if (vpn_ipv4 != NULL && vpn_ipv4[0] != 0 &&
vpn_ptp_ipv4 != NULL && vpn_ptp_ipv4[0] != 0) {
fprintf(out, "\tIPv4: %s ", vpn_ipv4);
fprintf(out, "P-t-P IPv4: %s\n", vpn_ptp_ipv4);
}
if (vpn_ipv6 != NULL && vpn_ipv6[0] != 0 &&
vpn_ptp_ipv6 != NULL && vpn_ptp_ipv6[0] != 0) {
fprintf(out, "\tIPv6: %s ", vpn_ipv6);
fprintf(out, "P-t-P IPv6: %s\n", vpn_ptp_ipv6);
}
fprintf(out, "\tDevice: %s ", device);
if (user_agent != NULL && user_agent[0] != 0)
fprintf(out, "User-Agent: %s\n", user_agent);
else
fprintf(out, "\n");
if (rx > 0 || tx > 0) {
/* print limits */
char buf[32];
if (rx > 0 && tx > 0) {
bytes2human(rx, buf, sizeof(buf), NULL);
fprintf(out, "\tLimit RX: %s/sec ", buf);
bytes2human(tx, buf, sizeof(buf), NULL);
fprintf(out, "TX: %s/sec\n", buf);
} else if (tx > 0) {
bytes2human(tx, buf, sizeof(buf), NULL);
fprintf(out, "\tLimit TX: %s/sec\n", buf);
} else if (rx > 0) {
bytes2human(rx, buf, sizeof(buf), NULL);
fprintf(out, "\tLimit RX: %s/sec\n", buf);
}
}
print_iface_stats(device, since, out);
if (hostname != NULL && hostname[0] != 0)
fprintf(out, "\tHostname: %s\n", hostname);
fprintf(out, "\tConnected at: %s (", str_since);
print_time_ival7(t, out);
fprintf(out, ")\n");
fprintf(out, "\tTLS ciphersuite: %s\n", tls_ciphersuite);
if (dtls_ciphersuite != NULL && dtls_ciphersuite[0] != 0)
fprintf(out, "\tDTLS cipher: %s\n", dtls_ciphersuite);
/* user network info */
fputs("\n", out);
if (print_list_entries(out, "\tDNS:", &subs) < 0)
goto error_parse;
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (print_list_entries(out, "\tNBNS:", &subs) < 0)
goto error_parse;
if (!dbus_message_iter_next(&subs))
goto error_recv;
if ((r = print_list_entries(out, "\tRoutes:", &subs)) < 0)
goto error_parse;
if (r == 0) {
fprintf(out, "Routes: defaultroute\n");
}
if (!dbus_message_iter_next(&subs))
goto error_recv;
if (print_list_entries(out, "\tiRoutes:", &subs) < 0)
goto error_parse;
at_least_one = 1;
if (!dbus_message_iter_next(&suba))
break;
}
ret = 0;
goto cleanup;
error_parse:
fprintf(stderr, "%s: D-BUS message parsing error\n", __func__);
goto cleanup;
error_recv:
fprintf(stderr, "%s: D-BUS message receiving error\n", __func__);
cleanup:
if (at_least_one == 0)
fprintf(out, "user or ID not found\n");
pager_stop(out);
return ret;
}
int handle_show_user_cmd(DBusConnection * conn, const char *arg)
{
DBusMessage *msg;
DBusMessageIter args;
int ret = 1;
if (arg == NULL || need_help(arg)) {
check_cmd_help(rl_line_buffer);
return 1;
}
msg = send_dbus_cmd(conn, "org.infradead.ocserv",
"/org/infradead/ocserv",
"org.infradead.ocserv", "user_info2",
DBUS_TYPE_STRING, &arg);
if (msg == NULL) {
goto error_send;
}
if (!dbus_message_iter_init(msg, &args))
goto error_server;
ret = common_info_cmd(&args);
if (ret != 0)
goto error_server;
goto cleanup;
error_server:
if (ret == 1)
fprintf(stderr, ERR_SERVER_UNREACHABLE);
goto cleanup;
error_send:
fprintf(stderr, "%s: D-BUS message creation error\n", __func__);
goto cleanup;
cleanup:
if (msg != NULL)
dbus_message_unref(msg);
return ret;
}
int handle_show_id_cmd(DBusConnection * conn, const char *arg)
{
DBusMessage *msg;
DBusMessageIter args;
dbus_uint32_t id = 0;
int ret = 1;
if (arg != NULL)
id = atoi(arg);
if (arg == NULL || need_help(arg) || id == 0) {
check_cmd_help(rl_line_buffer);
return 1;
}
msg = send_dbus_cmd(conn, "org.infradead.ocserv",
"/org/infradead/ocserv",
"org.infradead.ocserv", "id_info2",
DBUS_TYPE_UINT32, &id);
if (msg == NULL) {
goto error_send;
}
if (!dbus_message_iter_init(msg, &args))
goto error_server;
ret = common_info_cmd(&args);
if (ret != 0)
goto error_server;
goto cleanup;
error_server:
if (ret == 1)
fprintf(stderr, ERR_SERVER_UNREACHABLE);
goto cleanup;
error_send:
fprintf(stderr, "%s: D-BUS message creation error\n", __func__);
goto cleanup;
cleanup:
if (msg != NULL)
dbus_message_unref(msg);
return ret;
}
DBusConnection *conn_init(void)
{
DBusError err;
DBusConnection *conn;
dbus_error_init(&err);
conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "D-BUS connection error (%s)\n", err.message);
dbus_error_free(&err);
}
if (conn == NULL)
exit(1);
return conn;
}
void conn_close(DBusConnection* conn)
{
dbus_connection_close(conn);
}
int conn_prehandle(DBusConnection *ctx)
{
return 0;
}
void conn_posthandle(DBusConnection *ctx)
{
return;
}

772
src/occtl-unix.c Normal file
View File

@@ -0,0 +1,772 @@
/*
* Copyright (C) 2014 Red Hat
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of ocserv.
*
* ocserv 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.
*
* ocserv 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 <time.h>
#include <errno.h>
#include <signal.h>
#include <c-ctype.h>
#include <ctl.h>
#include <ctl.pb-c.h>
#include <occtl.h>
#include <common.h>
#include <c-strcase.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
struct unix_ctx {
int fd;
int is_open;
};
static uint8_t msg_map[] = {
[CTL_CMD_STATUS] = CTL_CMD_STATUS_REP,
[CTL_CMD_RELOAD] = CTL_CMD_RELOAD_REP,
[CTL_CMD_STOP] = CTL_CMD_STOP_REP,
[CTL_CMD_LIST] = CTL_CMD_LIST_REP,
[CTL_CMD_USER_INFO] = CTL_CMD_LIST_REP,
[CTL_CMD_ID_INFO] = CTL_CMD_LIST_REP,
[CTL_CMD_DISCONNECT_NAME] = CTL_CMD_DISCONNECT_NAME_REP,
[CTL_CMD_DISCONNECT_ID] = CTL_CMD_DISCONNECT_ID_REP,
};
struct cmd_reply_st {
unsigned cmd;
uint8_t *data;
unsigned data_size;
};
static void free_reply(struct cmd_reply_st *rep)
{
free(rep->data);
}
static void init_reply(struct cmd_reply_st *rep)
{
if (rep)
rep->data = NULL;
}
/* sends a message and returns the reply */
static
int send_cmd(int fd, unsigned cmd, const void *data,
pack_size_func get_size, pack_func pack,
struct cmd_reply_st *rep)
{
uint8_t header[3];
struct iovec iov[2];
unsigned iov_len = 1;
int e, ret;
unsigned length = 0;
void *packed = NULL;
if (get_size)
length = get_size(data);
header[0] = cmd;
header[1] = length;
header[2] = length >> 8;
iov[0].iov_base = header;
iov[0].iov_len = 3;
if (data != NULL) {
packed = malloc(length);
if (packed == NULL) {
fprintf(stderr, "memory error\n");
return -1;
}
iov[1].iov_base = packed;
iov[1].iov_len = length;
ret = pack(data, packed);
if (ret == 0) {
fprintf(stderr, "data packing error\n");
ret = -1;
goto fail;
}
iov_len++;
}
ret = writev(fd, iov, iov_len);
if (ret < 0) {
e = errno;
fprintf(stderr, "writev: %s\n", strerror(e));
ret = -1;
goto fail;
}
if (rep != NULL) {
ret = force_read_timeout(fd, header, 3, DEFAULT_TIMEOUT);
if (ret == -1) {
/*e = errno;
fprintf(stderr, "read: %s\n", strerror(e));*/
ret = -1;
goto fail;
}
if (ret != 3) {
fprintf(stderr, "short read %d\n", ret);
ret = -1;
goto fail;
}
rep->cmd = header[0];
if (msg_map[cmd] != rep->cmd) {
fprintf(stderr, "Unexpected message '%d', expected '%d'\n", (int)rep->cmd, (int)msg_map[cmd]);
ret = -1;
goto fail;
}
length = (header[2] << 8) | header[1];
rep->data_size = length;
rep->data = malloc(length);
if (rep->data == NULL) {
fprintf(stderr, "memory error\n");
ret = -1;
goto fail;
}
ret = force_read_timeout(fd, rep->data, length, DEFAULT_TIMEOUT);
if (ret == -1) {
e = errno;
free(rep->data);
rep->data = NULL;
fprintf(stderr, "read: %s\n", strerror(e));
ret = -1;
goto fail;
}
}
ret = 0;
fail:
free(packed);
return ret;
}
static
int connect_to_ocserv (void)
{
int sd, ret, e;
struct sockaddr_un sa;
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", OCSERV_UNIX_NAME);
sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sd == -1) {
e = errno;
fprintf(stderr, "error opening socket: %s\n", strerror(e));
return -1;
}
ret = connect(sd, (struct sockaddr *)&sa, sizeof(sa));
if (ret == -1) {
e = errno;
fprintf(stderr, "error connecting to ocserv socket '%s': %s\n",
sa.sun_path, strerror(e));
ret = -1;
goto error;
}
return sd;
error:
close(sd);
return ret;
}
int handle_status_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
StatusRep *rep;
init_reply(&raw);
ret = send_cmd(ctx->fd, CTL_CMD_STATUS, NULL, NULL, NULL, &raw);
if (ret < 0) {
goto error_status;
}
rep = status_rep__unpack(NULL, raw.data_size, raw.data);
if (rep == NULL)
goto error_status;
printf("OpenConnect SSL VPN server\n");
printf(" Status: %s\n", rep->status != 0 ? "online" : "error");
printf(" Clients: %u\n", (unsigned)rep->active_clients);
printf("\n");
printf(" Server PID: %u\n", (unsigned)rep->pid);
printf("Sec-mod PID: %u\n", (unsigned)rep->sec_mod_pid);
status_rep__free_unpacked(rep, NULL);
ret = 0;
goto cleanup;
error_status:
printf("OpenConnect SSL VPN server\n");
printf(" Status: offline\n");
ret = 1;
cleanup:
free_reply(&raw);
return ret;
}
int handle_reload_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
BoolMsg *rep;
unsigned status;
init_reply(&raw);
ret = send_cmd(ctx->fd, CTL_CMD_RELOAD, NULL, NULL, NULL, &raw);
if (ret < 0) {
goto error_status;
}
rep = bool_msg__unpack(NULL, raw.data_size, raw.data);
if (rep == NULL)
goto error_status;
status = rep->status;
bool_msg__free_unpacked(rep, NULL);
if (status != 0)
printf("Server scheduled to reload\n");
else
goto error_status;
ret = 0;
goto cleanup;
error_status:
printf("Error scheduling reload\n");
ret = 1;
cleanup:
free_reply(&raw);
return ret;
}
int handle_stop_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
BoolMsg *rep;
unsigned status;
init_reply(&raw);
ret = send_cmd(ctx->fd, CTL_CMD_STOP, NULL, NULL, NULL, &raw);
if (ret < 0) {
goto error_status;
}
rep = bool_msg__unpack(NULL, raw.data_size, raw.data);
if (rep == NULL)
goto error_status;
status = rep->status;
bool_msg__free_unpacked(rep, NULL);
if (status != 0)
printf("Server scheduled to stop\n");
else
goto error_status;
ret = 0;
goto cleanup;
error_status:
printf("Error scheduling server stop\n");
ret = 1;
goto cleanup;
cleanup:
free_reply(&raw);
return ret;
}
int handle_disconnect_user_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
BoolMsg *rep;
unsigned status;
UsernameReq req = USERNAME_REQ__INIT;
if (arg == NULL || need_help(arg)) {
check_cmd_help(rl_line_buffer);
return 1;
}
init_reply(&raw);
req.username = (void*)arg;
ret = send_cmd(ctx->fd, CTL_CMD_DISCONNECT_NAME, &req,
(pack_size_func)username_req__get_packed_size,
(pack_func)username_req__pack, &raw);
if (ret < 0) {
goto error;
}
rep = bool_msg__unpack(NULL, raw.data_size, raw.data);
if (rep == NULL)
goto error;
status = rep->status;
bool_msg__free_unpacked(rep, NULL);
if (status != 0) {
printf("user '%s' was disconnected\n", arg);
} else {
printf("could not disconnect user '%s'\n", arg);
}
ret = 0;
goto cleanup;
error:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
ret = 1;
cleanup:
free_reply(&raw);
return ret;
}
int handle_disconnect_id_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
BoolMsg *rep;
unsigned status;
unsigned id;
IdReq req = ID_REQ__INIT;
if (arg != NULL)
id = atoi(arg);
if (arg == NULL || need_help(arg) || id == 0) {
check_cmd_help(rl_line_buffer);
return 1;
}
init_reply(&raw);
req.id = id;
ret = send_cmd(ctx->fd, CTL_CMD_DISCONNECT_ID, &req,
(pack_size_func)id_req__get_packed_size,
(pack_func)id_req__pack, &raw);
if (ret < 0) {
goto error;
}
rep = bool_msg__unpack(NULL, raw.data_size, raw.data);
if (rep == NULL)
goto error;
status = rep->status;
bool_msg__free_unpacked(rep, NULL);
if (status != 0) {
printf("connection ID '%s' was disconnected\n", arg);
ret = 0;
} else {
printf("could not disconnect ID '%s'\n", arg);
ret = 1;
}
goto cleanup;
error:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
ret = 1;
cleanup:
free_reply(&raw);
return ret;
}
int handle_list_users_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
UserListRep *rep = NULL;
unsigned i;
const char *vpn_ip, *groupname, *username;
const char *dtls_ciphersuite;
FILE *out;
time_t t;
struct tm *tm;
char str_since[64];
init_reply(&raw);
entries_clear();
out = pager_start();
ret = send_cmd(ctx->fd, CTL_CMD_LIST, NULL, NULL, NULL, &raw);
if (ret < 0) {
goto error;
}
rep = user_list_rep__unpack(NULL, raw.data_size, raw.data);
if (rep == NULL)
goto error;
for (i=0;i<rep->n_user;i++) {
if (rep->user[i]->local_ip != NULL && rep->user[i]->local_ip[0] != 0)
vpn_ip = rep->user[i]->local_ip;
else
vpn_ip = rep->user[i]->local_ip6;
/* add header */
if (i == 0) {
fprintf(out, "%8s %8s %8s %14s %14s %6s %7s %14s %9s\n",
"id", "user", "group", "ip", "vpn-ip", "device",
"since", "dtls-cipher", "status");
}
t = rep->user[i]->conn_time;
tm = localtime(&t);
strftime(str_since, sizeof(str_since), "%Y-%m-%d %H:%M", tm);
groupname = rep->user[i]->groupname;
if (groupname == NULL || groupname[0] == 0)
groupname = NO_GROUP;
username = rep->user[i]->username;
if (username == NULL || username[0] == 0)
username = NO_USER;
fprintf(out, "%8d %8s %8s %14s %14s %6s ",
(int)rep->user[i]->id, username, groupname, rep->user[i]->ip, vpn_ip, rep->user[i]->tun);
print_time_ival7(t, out);
dtls_ciphersuite = rep->user[i]->dtls_ciphersuite;
if (dtls_ciphersuite != NULL && dtls_ciphersuite[0] != 0) {
if (strncmp(dtls_ciphersuite, "OC-DTLS", 7) == 0 && strlen(dtls_ciphersuite) > 11)
dtls_ciphersuite += 11;
fprintf(out, " %14s %9s\n", dtls_ciphersuite, rep->user[i]->status);
} else {
fprintf(out, " %14s %9s\n", "(no dtls)", rep->user[i]->status);
}
entries_add(username, strlen(username), rep->user[i]->id);
}
ret = 0;
goto cleanup;
error:
ret = 1;
fprintf(stderr, ERR_SERVER_UNREACHABLE);
cleanup:
if (rep != NULL)
user_list_rep__free_unpacked(rep, NULL);
free_reply(&raw);
pager_stop(out);
return ret;
}
int print_list_entries(FILE* out, const char* name, char **val, unsigned vsize)
{
const char * tmp;
unsigned int i = 0;
for (i=0;i<vsize;i++) {
tmp = val[i];
if (tmp != NULL) {
if (i==0)
fprintf(out, "%s %s\n", name, tmp);
else
fprintf(out, "\t\t%s\n", tmp);
}
}
return i;
}
int common_info_cmd(UserListRep * args)
{
char *username = "";
char *groupname = "";
char str_since[64];
struct tm *tm;
time_t t;
FILE *out;
unsigned at_least_one = 0;
int ret = 1, r;
unsigned i;
out = pager_start();
for (i=0;i<args->n_user;i++) {
if (at_least_one > 0)
fprintf(out, "\n");
fprintf(out, "ID: %d\n", (int)args->user[i]->id);
t = args->user[i]->conn_time;
tm = localtime(&t);
strftime(str_since, sizeof(str_since), "%Y-%m-%d %H:%M", tm);
username = args->user[i]->username;
if (username == NULL || username[0] == 0)
username = NO_USER;
fprintf(out, "\tUsername: %s ", username);
groupname = args->user[i]->groupname;
if (groupname == NULL || groupname[0] == 0)
groupname = NO_GROUP;
fprintf(out, "Groupname: %s\n", groupname);
fprintf(out, "\tState: %s ", args->user[i]->status);
fprintf(out, "Remote IP: %s\n", args->user[i]->ip);
if (args->user[i]->local_ip != NULL && args->user[i]->local_ip[0] != 0 &&
args->user[i]->remote_ip != NULL && args->user[i]->remote_ip[0] != 0) {
fprintf(out, "\tIPv4: %s ", args->user[i]->local_ip);
fprintf(out, "P-t-P IPv4: %s\n", args->user[i]->remote_ip);
}
if (args->user[i]->local_ip6 != NULL && args->user[i]->local_ip6[0] != 0 &&
args->user[i]->remote_ip6 != NULL && args->user[i]->remote_ip6[0] != 0) {
fprintf(out, "\tIPv6: %s ", args->user[i]->local_ip6);
fprintf(out, "P-t-P IPv6: %s\n", args->user[i]->remote_ip6);
}
fprintf(out, "\tDevice: %s ", args->user[i]->tun);
if (args->user[i]->user_agent != NULL && args->user[i]->user_agent[0] != 0)
fprintf(out, "User-Agent: %s\n", args->user[i]->user_agent);
else
fprintf(out, "\n");
if (args->user[i]->rx_per_sec > 0 || args->user[i]->tx_per_sec > 0) {
/* print limits */
char buf[32];
if (args->user[i]->rx_per_sec > 0 && args->user[i]->tx_per_sec > 0) {
bytes2human(args->user[i]->rx_per_sec, buf, sizeof(buf), NULL);
fprintf(out, "\tLimit RX: %s/sec ", buf);
bytes2human(args->user[i]->tx_per_sec, buf, sizeof(buf), NULL);
fprintf(out, "TX: %s/sec\n", buf);
} else if (args->user[i]->tx_per_sec > 0) {
bytes2human(args->user[i]->tx_per_sec, buf, sizeof(buf), NULL);
fprintf(out, "\tLimit TX: %s/sec\n", buf);
} else if (args->user[i]->rx_per_sec > 0) {
bytes2human(args->user[i]->rx_per_sec, buf, sizeof(buf), NULL);
fprintf(out, "\tLimit RX: %s/sec\n", buf);
}
}
print_iface_stats(args->user[i]->tun, args->user[i]->conn_time, out);
if (args->user[i]->hostname != NULL && args->user[i]->hostname[0] != 0)
fprintf(out, "\tHostname: %s\n", args->user[i]->hostname);
fprintf(out, "\tConnected at: %s (", str_since);
print_time_ival7(t, out);
fprintf(out, ")\n");
fprintf(out, "\tTLS ciphersuite: %s\n", args->user[i]->tls_ciphersuite);
if (args->user[i]->dtls_ciphersuite != NULL && args->user[i]->dtls_ciphersuite[0] != 0)
fprintf(out, "\tDTLS cipher: %s\n", args->user[i]->dtls_ciphersuite);
/* user network info */
fputs("\n", out);
if (print_list_entries(out, "\tDNS:", args->user[i]->dns, args->user[i]->n_dns) < 0)
goto error_parse;
if (print_list_entries(out, "\tNBNS:", args->user[i]->nbns, args->user[i]->n_nbns) < 0)
goto error_parse;
if ((r = print_list_entries(out, "\tRoutes:", args->user[i]->routes, args->user[i]->n_routes)) < 0)
goto error_parse;
if (r == 0) {
fprintf(out, "Routes: defaultroute\n");
}
if (print_list_entries(out, "\tiRoutes:", args->user[i]->iroutes, args->user[i]->n_iroutes) < 0)
goto error_parse;
at_least_one = 1;
}
ret = 0;
goto cleanup;
error_parse:
fprintf(stderr, "%s: message parsing error\n", __func__);
goto cleanup;
cleanup:
if (at_least_one == 0)
fprintf(out, "user or ID not found\n");
pager_stop(out);
return ret;
}
int handle_show_user_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
UserListRep *rep = NULL;
UsernameReq req = USERNAME_REQ__INIT;
if (arg == NULL || need_help(arg)) {
check_cmd_help(rl_line_buffer);
return 1;
}
init_reply(&raw);
req.username = (void*)arg;
ret = send_cmd(ctx->fd, CTL_CMD_USER_INFO, &req,
(pack_size_func)username_req__get_packed_size,
(pack_func)username_req__pack, &raw);
if (ret < 0) {
goto error;
}
rep = user_list_rep__unpack(NULL, raw.data_size, raw.data);
if (rep == NULL)
goto error;
ret = common_info_cmd(rep);
if (ret < 0)
goto error;
ret = 0;
goto cleanup;
error:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
ret = 1;
cleanup:
if (rep != NULL)
user_list_rep__free_unpacked(rep, NULL);
free_reply(&raw);
return ret;
}
int handle_show_id_cmd(struct unix_ctx *ctx, const char *arg)
{
int ret;
struct cmd_reply_st raw;
UserListRep *rep = NULL;
unsigned id;
IdReq req = ID_REQ__INIT;
if (arg != NULL)
id = atoi(arg);
if (arg == NULL || need_help(arg) || id == 0) {
check_cmd_help(rl_line_buffer);
return 1;
}
init_reply(&raw);
req.id = id;
ret = send_cmd(ctx->fd, CTL_CMD_ID_INFO, &req,
(pack_size_func)id_req__get_packed_size,
(pack_func)id_req__pack, &raw);
if (ret < 0) {
goto error;
}
rep = user_list_rep__unpack(NULL, raw.data_size, raw.data);
if (rep == NULL)
goto error;
ret = common_info_cmd(rep);
if (ret < 0)
goto error;
ret = 0;
goto cleanup;
error:
fprintf(stderr, ERR_SERVER_UNREACHABLE);
ret = 1;
cleanup:
if (rep != NULL)
user_list_rep__free_unpacked(rep, NULL);
free_reply(&raw);
return ret;
}
int conn_prehandle(struct unix_ctx *ctx)
{
ctx->fd = connect_to_ocserv();
if (ctx->fd != -1)
ctx->is_open = 1;
return ctx->fd;
}
void conn_posthandle(struct unix_ctx *ctx)
{
if (ctx->is_open) {
close(ctx->fd);
ctx->is_open = 0;
}
}
struct unix_ctx *conn_init(void)
{
return calloc(1, sizeof(struct unix_ctx));
}
void conn_close(struct unix_ctx* conn)
{
free(conn);
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,13 @@
#include <stdlib.h>
#include <time.h>
#ifdef HAVE_ORIG_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#else
# include <readline.h>
#endif
FILE* pager_start(void);
void pager_stop(FILE* fp);
void print_time_ival7(time_t t, FILE * fout);
@@ -17,4 +24,37 @@ char* search_for_user(unsigned idx, const char* match, int match_size);
void entries_add(const char* user, unsigned user_size, unsigned id);
void entries_clear(void);
#define DEFAULT_TIMEOUT (10*1000)
#define NO_GROUP "(none)"
#define NO_USER "(none)"
#define ERR_SERVER_UNREACHABLE "could not send message; possibly insufficient permissions or server is offline.\n"
unsigned need_help(const char *arg);
unsigned check_cmd_help(const char *line);
#ifdef HAVE_DBUS
# include <dbus/dbus.h>
# define CONN_TYPE DBusConnection
#else
# define CONN_TYPE struct unix_ctx
#endif
CONN_TYPE *conn_init(void);
void conn_close(CONN_TYPE*);
int conn_prehandle(CONN_TYPE *ctx);
void conn_posthandle(CONN_TYPE *ctx);
typedef int (*cmd_func) (CONN_TYPE * conn, const char *arg);
int handle_status_cmd(CONN_TYPE * conn, const char *arg);
int handle_list_users_cmd(CONN_TYPE * conn, const char *arg);
int handle_show_user_cmd(CONN_TYPE * conn, const char *arg);
int handle_show_id_cmd(CONN_TYPE * conn, const char *arg);
int handle_disconnect_user_cmd(CONN_TYPE * conn, const char *arg);
int handle_disconnect_id_cmd(CONN_TYPE * conn, const char *arg);
int handle_reload_cmd(CONN_TYPE * conn, const char *arg);
int handle_stop_cmd(CONN_TYPE * conn, const char *arg);
#endif

View File

@@ -159,6 +159,7 @@ int load_pins(struct cfg_st *config, struct pin_st *s)
return 0;
}
/* sec_mod_server:
* @config: server configuration
* @socket_file: the name of the socket
@@ -205,10 +206,6 @@ void sec_mod_server(struct cfg_st *config, const char *socket_file)
uint16_t length;
struct iovec iov[2];
int sd;
#if defined(SO_PEERCRED) && defined(HAVE_STRUCT_UCRED)
struct ucred cr;
socklen_t cr_len;
#endif
ocsignal(SIGHUP, SIG_IGN);
ocsignal(SIGINT, SIG_DFL);
@@ -320,56 +317,14 @@ void sec_mod_server(struct cfg_st *config, const char *socket_file)
strerror(e));
continue;
}
#if defined(SO_PEERCRED) && defined(HAVE_STRUCT_UCRED)
/* This check is superfluous in Linux and mostly for debugging
* purposes. The socket permissions set with umask should
* be sufficient already for access control, but not all
* UNIXes support that. */
cr_len = sizeof(cr);
ret = getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len);
if (ret == -1) {
e = errno;
ret = check_upeer_id("sec-mod", cfd, config->uid, config->gid);
if (ret < 0) {
syslog(LOG_ERR,
"sec-mod error obtaining peer credentials: %s",
strerror(e));
"sec-mod: unauthorized connection");
goto cont;
}
syslog(LOG_DEBUG,
"sec-mod received request from pid %u and uid %u",
(unsigned)cr.pid, (unsigned)cr.uid);
if (cr.uid != config->uid || cr.gid != config->gid) {
syslog(LOG_ERR,
"sec-mod received unauthorized request from pid %u and uid %u",
(unsigned)cr.pid, (unsigned)cr.uid);
goto cont;
}
#elif defined(HAVE_GETPEEREID)
{
pid_t euid;
gid_t egid;
ret = getpeereid(cfd, &euid, &egid);
if (ret == -1) {
e = errno;
syslog(LOG_ERR, "sec-mod getpeereid error: %s",
strerror(e));
goto cont;
}
syslog(LOG_DEBUG,
"sec-mod received request from a processes with uid %u",
(unsigned)euid);
if (euid != config->uid || egid != config->gid) {
syslog(LOG_ERR,
"sec-mod received unauthorized request from a process with uid %u",
(unsigned)euid);
goto cont;
}
}
#else
#error "Unsupported UNIX variant"
#endif
/* read request */
ret = recv(cfd, buffer, buffer_size, 0);
if (ret == 0)

View File

@@ -22,6 +22,12 @@
#ifdef __linux__
# include <sys/prctl.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <sys/errno.h>
#include <sys/syslog.h>
#include <signal.h>
@@ -44,3 +50,61 @@ SIGHANDLER_T ocsignal(int signum, SIGHANDLER_T handler)
sigaction (signum, &new_action, &old_action);
return old_action.sa_handler;
}
int check_upeer_id(const char *mod, int cfd, int uid, int gid)
{
int e, ret;
#if defined(SO_PEERCRED) && defined(HAVE_STRUCT_UCRED)
struct ucred cr;
socklen_t cr_len;
/* This check is superfluous in Linux and mostly for debugging
* purposes. The socket permissions set with umask should
* be sufficient already for access control, but not all
* UNIXes support that. */
cr_len = sizeof(cr);
ret = getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len);
if (ret == -1) {
e = errno;
syslog(LOG_ERR, "%s getsockopt SO_PEERCRED error: %s",
mod, strerror(e));
return -1;
}
syslog(LOG_DEBUG,
"%s received request from pid %u and uid %u",
mod, (unsigned)cr.pid, (unsigned)cr.uid);
if (cr.uid != uid || cr.gid != gid) {
syslog(LOG_ERR,
"%s received unauthorized request from pid %u and uid %u",
mod, (unsigned)cr.pid, (unsigned)cr.uid);
return -1;
}
#elif defined(HAVE_GETPEEREID)
pid_t euid;
gid_t egid;
ret = getpeereid(cfd, &euid, &egid);
if (ret == -1) {
e = errno;
syslog(LOG_ERR, "%s getpeereid error: %s",
mod, strerror(e));
return -1;
}
syslog(LOG_DEBUG,
"%s received request from a processes with uid %u",
mod, (unsigned)euid);
if (euid != uid || egid != gid) {
syslog(LOG_ERR,
"%s received unauthorized request from a process with uid %u",
mod, (unsigned)euid);
return -1;
}
#else
#error "Unsupported UNIX variant"
#endif
return 0;
}

View File

@@ -39,4 +39,6 @@ void kill_on_parent_kill(int sig);
SIGHANDLER_T ocsignal(int signum, SIGHANDLER_T handler);
int check_upeer_id(const char *mod, int cfg, int uid, int gid);
#endif