mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
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:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||
|
||||
30
configure.ac
30
configure.ac
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
24
src/ctl.h
Normal 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
54
src/ctl.proto
Normal 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;
|
||||
}
|
||||
@@ -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
663
src/main-ctl-unix.c
Normal 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
12
src/main-ctl.h
Normal 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
|
||||
27
src/main.c
27
src/main.c
@@ -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;
|
||||
|
||||
23
src/main.h
23
src/main.h
@@ -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
973
src/occtl-dbus.c
Normal 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
772
src/occtl-unix.c
Normal 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);
|
||||
}
|
||||
1021
src/occtl.c
1021
src/occtl.c
File diff suppressed because it is too large
Load Diff
40
src/occtl.h
40
src/occtl.h
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
64
src/system.c
64
src/system.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user