Change intercept IPC to use a localhost socket instead of inherited fd.
This allows intercept mode to work with shells that close all open fds upon startup. The ctor in sudo_intercept.so requests the port number and secret over the socket inherited from the parent then closes it. For each policy request, a TCP connection is made to the sudo parent process to perform the policy check. Child processes re-use the TCP socket to request the port number and secret just like the initial process started by sudo does.
This commit is contained in:
@@ -842,9 +842,6 @@
|
|||||||
/* Define to 1 if the system has the type `struct in6_addr'. */
|
/* Define to 1 if the system has the type `struct in6_addr'. */
|
||||||
#undef HAVE_STRUCT_IN6_ADDR
|
#undef HAVE_STRUCT_IN6_ADDR
|
||||||
|
|
||||||
/* Define to 1 if `msg_control' is a member of `struct msghdr'. */
|
|
||||||
#undef HAVE_STRUCT_MSGHDR_MSG_CONTROL
|
|
||||||
|
|
||||||
/* Define to 1 if `pr_ttydev' is a member of `struct psinfo'. */
|
/* Define to 1 if `pr_ttydev' is a member of `struct psinfo'. */
|
||||||
#undef HAVE_STRUCT_PSINFO_PR_TTYDEV
|
#undef HAVE_STRUCT_PSINFO_PR_TTYDEV
|
||||||
|
|
||||||
|
13
configure
vendored
13
configure
vendored
@@ -23254,19 +23254,6 @@ then :
|
|||||||
printf "%s\n" "#define HAVE_STRUCT_DIRENT_D_NAMLEN 1" >>confdefs.h
|
printf "%s\n" "#define HAVE_STRUCT_DIRENT_D_NAMLEN 1" >>confdefs.h
|
||||||
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_control" "ac_cv_member_struct_msghdr_msg_control" "
|
|
||||||
$ac_includes_default
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
"
|
|
||||||
if test "x$ac_cv_member_struct_msghdr_msg_control" = xyes
|
|
||||||
then :
|
|
||||||
|
|
||||||
printf "%s\n" "#define HAVE_STRUCT_MSGHDR_MSG_CONTROL 1" >>confdefs.h
|
|
||||||
|
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
openssl_missing=no
|
openssl_missing=no
|
||||||
|
@@ -2925,13 +2925,6 @@ AC_INCLUDES_DEFAULT
|
|||||||
#include <$ac_header_dirent>
|
#include <$ac_header_dirent>
|
||||||
])
|
])
|
||||||
dnl
|
dnl
|
||||||
dnl Check for POSIX sendmsg() ancillary data support.
|
|
||||||
dnl
|
|
||||||
AC_CHECK_MEMBERS(struct msghdr.msg_control, [], [], [
|
|
||||||
AC_INCLUDES_DEFAULT
|
|
||||||
#include <sys/socket.h>
|
|
||||||
])
|
|
||||||
dnl
|
|
||||||
dnl Check for functions only present in OpenSSL 1.1 and above
|
dnl Check for functions only present in OpenSSL 1.1 and above
|
||||||
dnl
|
dnl
|
||||||
openssl_missing=no
|
openssl_missing=no
|
||||||
|
@@ -15,12 +15,14 @@ PROTOBUF_C__BEGIN_DECLS
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct _InterceptMessage InterceptMessage;
|
typedef struct _InterceptRequest InterceptRequest;
|
||||||
|
typedef struct _ClientHello ClientHello;
|
||||||
|
typedef struct _HelloResponse HelloResponse;
|
||||||
typedef struct _PolicyCheckRequest PolicyCheckRequest;
|
typedef struct _PolicyCheckRequest PolicyCheckRequest;
|
||||||
typedef struct _PolicyAcceptMessage PolicyAcceptMessage;
|
typedef struct _PolicyAcceptMessage PolicyAcceptMessage;
|
||||||
typedef struct _PolicyRejectMessage PolicyRejectMessage;
|
typedef struct _PolicyRejectMessage PolicyRejectMessage;
|
||||||
typedef struct _PolicyErrorMessage PolicyErrorMessage;
|
typedef struct _PolicyErrorMessage PolicyErrorMessage;
|
||||||
typedef struct _PolicyCheckResult PolicyCheckResult;
|
typedef struct _InterceptResponse InterceptResponse;
|
||||||
|
|
||||||
|
|
||||||
/* --- enums --- */
|
/* --- enums --- */
|
||||||
@@ -29,30 +31,62 @@ typedef struct _PolicyCheckResult PolicyCheckResult;
|
|||||||
/* --- messages --- */
|
/* --- messages --- */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
INTERCEPT_MESSAGE__TYPE__NOT_SET = 0,
|
INTERCEPT_REQUEST__TYPE__NOT_SET = 0,
|
||||||
INTERCEPT_MESSAGE__TYPE_POLICY_CHECK_REQ = 1
|
INTERCEPT_REQUEST__TYPE_POLICY_CHECK_REQ = 1,
|
||||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(INTERCEPT_MESSAGE__TYPE)
|
INTERCEPT_REQUEST__TYPE_HELLO = 2
|
||||||
} InterceptMessage__TypeCase;
|
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(INTERCEPT_REQUEST__TYPE)
|
||||||
|
} InterceptRequest__TypeCase;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Intercept message from sudo_intercept.so. Messages on the
|
* Intercept message from sudo_intercept.so. Messages on the
|
||||||
* wire are prefixed with a 32-bit size in network byte order.
|
* wire are prefixed with a 32-bit size in network byte order.
|
||||||
*/
|
*/
|
||||||
struct _InterceptMessage
|
struct _InterceptRequest
|
||||||
{
|
{
|
||||||
ProtobufCMessage base;
|
ProtobufCMessage base;
|
||||||
InterceptMessage__TypeCase type_case;
|
InterceptRequest__TypeCase type_case;
|
||||||
union {
|
union {
|
||||||
PolicyCheckRequest *policy_check_req;
|
PolicyCheckRequest *policy_check_req;
|
||||||
|
ClientHello *hello;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
#define INTERCEPT_MESSAGE__INIT \
|
#define INTERCEPT_REQUEST__INIT \
|
||||||
{ PROTOBUF_C_MESSAGE_INIT (&intercept_message__descriptor) \
|
{ PROTOBUF_C_MESSAGE_INIT (&intercept_request__descriptor) \
|
||||||
, INTERCEPT_MESSAGE__TYPE__NOT_SET, {0} }
|
, INTERCEPT_REQUEST__TYPE__NOT_SET, {0} }
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hello message from sudo_intercept.so to main sudo process.
|
||||||
|
* Sudo sends back the secret and localhost port number.
|
||||||
|
*/
|
||||||
|
struct _ClientHello
|
||||||
|
{
|
||||||
|
ProtobufCMessage base;
|
||||||
|
int32_t pid;
|
||||||
|
};
|
||||||
|
#define CLIENT_HELLO__INIT \
|
||||||
|
{ PROTOBUF_C_MESSAGE_INIT (&client_hello__descriptor) \
|
||||||
|
, 0 }
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sudo response to a ClientHello from sudo_intercept.so.
|
||||||
|
* The client uses the port number and secret to connect back to sudo.
|
||||||
|
*/
|
||||||
|
struct _HelloResponse
|
||||||
|
{
|
||||||
|
ProtobufCMessage base;
|
||||||
|
uint64_t secret;
|
||||||
|
int32_t portno;
|
||||||
|
};
|
||||||
|
#define HELLO_RESPONSE__INIT \
|
||||||
|
{ PROTOBUF_C_MESSAGE_INIT (&hello_response__descriptor) \
|
||||||
|
, 0, 0 }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Policy check request from sudo_intercept.so.
|
* Policy check request from sudo_intercept.so.
|
||||||
|
* Must include the correct secret value.
|
||||||
* Note that the plugin API only currently supports passing
|
* Note that the plugin API only currently supports passing
|
||||||
* the new environment in to the open() function.
|
* the new environment in to the open() function.
|
||||||
*/
|
*/
|
||||||
@@ -64,10 +98,12 @@ struct _PolicyCheckRequest
|
|||||||
char **argv;
|
char **argv;
|
||||||
size_t n_envp;
|
size_t n_envp;
|
||||||
char **envp;
|
char **envp;
|
||||||
|
int32_t intercept_fd;
|
||||||
|
uint64_t secret;
|
||||||
};
|
};
|
||||||
#define POLICY_CHECK_REQUEST__INIT \
|
#define POLICY_CHECK_REQUEST__INIT \
|
||||||
{ PROTOBUF_C_MESSAGE_INIT (&policy_check_request__descriptor) \
|
{ PROTOBUF_C_MESSAGE_INIT (&policy_check_request__descriptor) \
|
||||||
, (char *)protobuf_c_empty_string, 0,NULL, 0,NULL }
|
, (char *)protobuf_c_empty_string, 0,NULL, 0,NULL, 0, 0 }
|
||||||
|
|
||||||
|
|
||||||
struct _PolicyAcceptMessage
|
struct _PolicyAcceptMessage
|
||||||
@@ -105,50 +141,89 @@ struct _PolicyErrorMessage
|
|||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
POLICY_CHECK_RESULT__TYPE__NOT_SET = 0,
|
INTERCEPT_RESPONSE__TYPE__NOT_SET = 0,
|
||||||
POLICY_CHECK_RESULT__TYPE_ACCEPT_MSG = 1,
|
INTERCEPT_RESPONSE__TYPE_HELLO_RESP = 1,
|
||||||
POLICY_CHECK_RESULT__TYPE_REJECT_MSG = 2,
|
INTERCEPT_RESPONSE__TYPE_ACCEPT_MSG = 2,
|
||||||
POLICY_CHECK_RESULT__TYPE_ERROR_MSG = 3
|
INTERCEPT_RESPONSE__TYPE_REJECT_MSG = 3,
|
||||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(POLICY_CHECK_RESULT__TYPE)
|
INTERCEPT_RESPONSE__TYPE_ERROR_MSG = 4
|
||||||
} PolicyCheckResult__TypeCase;
|
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(INTERCEPT_RESPONSE__TYPE)
|
||||||
|
} InterceptResponse__TypeCase;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Policy check result sent back to sudo_intercept.so.
|
* Response sent back to sudo_intercept.so.
|
||||||
*/
|
*/
|
||||||
struct _PolicyCheckResult
|
struct _InterceptResponse
|
||||||
{
|
{
|
||||||
ProtobufCMessage base;
|
ProtobufCMessage base;
|
||||||
uint64_t secret;
|
InterceptResponse__TypeCase type_case;
|
||||||
PolicyCheckResult__TypeCase type_case;
|
|
||||||
union {
|
union {
|
||||||
|
HelloResponse *hello_resp;
|
||||||
PolicyAcceptMessage *accept_msg;
|
PolicyAcceptMessage *accept_msg;
|
||||||
PolicyRejectMessage *reject_msg;
|
PolicyRejectMessage *reject_msg;
|
||||||
PolicyErrorMessage *error_msg;
|
PolicyErrorMessage *error_msg;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
#define POLICY_CHECK_RESULT__INIT \
|
#define INTERCEPT_RESPONSE__INIT \
|
||||||
{ PROTOBUF_C_MESSAGE_INIT (&policy_check_result__descriptor) \
|
{ PROTOBUF_C_MESSAGE_INIT (&intercept_response__descriptor) \
|
||||||
, 0, POLICY_CHECK_RESULT__TYPE__NOT_SET, {0} }
|
, INTERCEPT_RESPONSE__TYPE__NOT_SET, {0} }
|
||||||
|
|
||||||
|
|
||||||
/* InterceptMessage methods */
|
/* InterceptRequest methods */
|
||||||
void intercept_message__init
|
void intercept_request__init
|
||||||
(InterceptMessage *message);
|
(InterceptRequest *message);
|
||||||
size_t intercept_message__get_packed_size
|
size_t intercept_request__get_packed_size
|
||||||
(const InterceptMessage *message);
|
(const InterceptRequest *message);
|
||||||
size_t intercept_message__pack
|
size_t intercept_request__pack
|
||||||
(const InterceptMessage *message,
|
(const InterceptRequest *message,
|
||||||
uint8_t *out);
|
uint8_t *out);
|
||||||
size_t intercept_message__pack_to_buffer
|
size_t intercept_request__pack_to_buffer
|
||||||
(const InterceptMessage *message,
|
(const InterceptRequest *message,
|
||||||
ProtobufCBuffer *buffer);
|
ProtobufCBuffer *buffer);
|
||||||
InterceptMessage *
|
InterceptRequest *
|
||||||
intercept_message__unpack
|
intercept_request__unpack
|
||||||
(ProtobufCAllocator *allocator,
|
(ProtobufCAllocator *allocator,
|
||||||
size_t len,
|
size_t len,
|
||||||
const uint8_t *data);
|
const uint8_t *data);
|
||||||
void intercept_message__free_unpacked
|
void intercept_request__free_unpacked
|
||||||
(InterceptMessage *message,
|
(InterceptRequest *message,
|
||||||
|
ProtobufCAllocator *allocator);
|
||||||
|
/* ClientHello methods */
|
||||||
|
void client_hello__init
|
||||||
|
(ClientHello *message);
|
||||||
|
size_t client_hello__get_packed_size
|
||||||
|
(const ClientHello *message);
|
||||||
|
size_t client_hello__pack
|
||||||
|
(const ClientHello *message,
|
||||||
|
uint8_t *out);
|
||||||
|
size_t client_hello__pack_to_buffer
|
||||||
|
(const ClientHello *message,
|
||||||
|
ProtobufCBuffer *buffer);
|
||||||
|
ClientHello *
|
||||||
|
client_hello__unpack
|
||||||
|
(ProtobufCAllocator *allocator,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t *data);
|
||||||
|
void client_hello__free_unpacked
|
||||||
|
(ClientHello *message,
|
||||||
|
ProtobufCAllocator *allocator);
|
||||||
|
/* HelloResponse methods */
|
||||||
|
void hello_response__init
|
||||||
|
(HelloResponse *message);
|
||||||
|
size_t hello_response__get_packed_size
|
||||||
|
(const HelloResponse *message);
|
||||||
|
size_t hello_response__pack
|
||||||
|
(const HelloResponse *message,
|
||||||
|
uint8_t *out);
|
||||||
|
size_t hello_response__pack_to_buffer
|
||||||
|
(const HelloResponse *message,
|
||||||
|
ProtobufCBuffer *buffer);
|
||||||
|
HelloResponse *
|
||||||
|
hello_response__unpack
|
||||||
|
(ProtobufCAllocator *allocator,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t *data);
|
||||||
|
void hello_response__free_unpacked
|
||||||
|
(HelloResponse *message,
|
||||||
ProtobufCAllocator *allocator);
|
ProtobufCAllocator *allocator);
|
||||||
/* PolicyCheckRequest methods */
|
/* PolicyCheckRequest methods */
|
||||||
void policy_check_request__init
|
void policy_check_request__init
|
||||||
@@ -226,29 +301,35 @@ PolicyErrorMessage *
|
|||||||
void policy_error_message__free_unpacked
|
void policy_error_message__free_unpacked
|
||||||
(PolicyErrorMessage *message,
|
(PolicyErrorMessage *message,
|
||||||
ProtobufCAllocator *allocator);
|
ProtobufCAllocator *allocator);
|
||||||
/* PolicyCheckResult methods */
|
/* InterceptResponse methods */
|
||||||
void policy_check_result__init
|
void intercept_response__init
|
||||||
(PolicyCheckResult *message);
|
(InterceptResponse *message);
|
||||||
size_t policy_check_result__get_packed_size
|
size_t intercept_response__get_packed_size
|
||||||
(const PolicyCheckResult *message);
|
(const InterceptResponse *message);
|
||||||
size_t policy_check_result__pack
|
size_t intercept_response__pack
|
||||||
(const PolicyCheckResult *message,
|
(const InterceptResponse *message,
|
||||||
uint8_t *out);
|
uint8_t *out);
|
||||||
size_t policy_check_result__pack_to_buffer
|
size_t intercept_response__pack_to_buffer
|
||||||
(const PolicyCheckResult *message,
|
(const InterceptResponse *message,
|
||||||
ProtobufCBuffer *buffer);
|
ProtobufCBuffer *buffer);
|
||||||
PolicyCheckResult *
|
InterceptResponse *
|
||||||
policy_check_result__unpack
|
intercept_response__unpack
|
||||||
(ProtobufCAllocator *allocator,
|
(ProtobufCAllocator *allocator,
|
||||||
size_t len,
|
size_t len,
|
||||||
const uint8_t *data);
|
const uint8_t *data);
|
||||||
void policy_check_result__free_unpacked
|
void intercept_response__free_unpacked
|
||||||
(PolicyCheckResult *message,
|
(InterceptResponse *message,
|
||||||
ProtobufCAllocator *allocator);
|
ProtobufCAllocator *allocator);
|
||||||
/* --- per-message closures --- */
|
/* --- per-message closures --- */
|
||||||
|
|
||||||
typedef void (*InterceptMessage_Closure)
|
typedef void (*InterceptRequest_Closure)
|
||||||
(const InterceptMessage *message,
|
(const InterceptRequest *message,
|
||||||
|
void *closure_data);
|
||||||
|
typedef void (*ClientHello_Closure)
|
||||||
|
(const ClientHello *message,
|
||||||
|
void *closure_data);
|
||||||
|
typedef void (*HelloResponse_Closure)
|
||||||
|
(const HelloResponse *message,
|
||||||
void *closure_data);
|
void *closure_data);
|
||||||
typedef void (*PolicyCheckRequest_Closure)
|
typedef void (*PolicyCheckRequest_Closure)
|
||||||
(const PolicyCheckRequest *message,
|
(const PolicyCheckRequest *message,
|
||||||
@@ -262,8 +343,8 @@ typedef void (*PolicyRejectMessage_Closure)
|
|||||||
typedef void (*PolicyErrorMessage_Closure)
|
typedef void (*PolicyErrorMessage_Closure)
|
||||||
(const PolicyErrorMessage *message,
|
(const PolicyErrorMessage *message,
|
||||||
void *closure_data);
|
void *closure_data);
|
||||||
typedef void (*PolicyCheckResult_Closure)
|
typedef void (*InterceptResponse_Closure)
|
||||||
(const PolicyCheckResult *message,
|
(const InterceptResponse *message,
|
||||||
void *closure_data);
|
void *closure_data);
|
||||||
|
|
||||||
/* --- services --- */
|
/* --- services --- */
|
||||||
@@ -271,12 +352,14 @@ typedef void (*PolicyCheckResult_Closure)
|
|||||||
|
|
||||||
/* --- descriptors --- */
|
/* --- descriptors --- */
|
||||||
|
|
||||||
extern const ProtobufCMessageDescriptor intercept_message__descriptor;
|
extern const ProtobufCMessageDescriptor intercept_request__descriptor;
|
||||||
|
extern const ProtobufCMessageDescriptor client_hello__descriptor;
|
||||||
|
extern const ProtobufCMessageDescriptor hello_response__descriptor;
|
||||||
extern const ProtobufCMessageDescriptor policy_check_request__descriptor;
|
extern const ProtobufCMessageDescriptor policy_check_request__descriptor;
|
||||||
extern const ProtobufCMessageDescriptor policy_accept_message__descriptor;
|
extern const ProtobufCMessageDescriptor policy_accept_message__descriptor;
|
||||||
extern const ProtobufCMessageDescriptor policy_reject_message__descriptor;
|
extern const ProtobufCMessageDescriptor policy_reject_message__descriptor;
|
||||||
extern const ProtobufCMessageDescriptor policy_error_message__descriptor;
|
extern const ProtobufCMessageDescriptor policy_error_message__descriptor;
|
||||||
extern const ProtobufCMessageDescriptor policy_check_result__descriptor;
|
extern const ProtobufCMessageDescriptor intercept_response__descriptor;
|
||||||
|
|
||||||
PROTOBUF_C__END_DECLS
|
PROTOBUF_C__END_DECLS
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/uio.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#if defined(HAVE_STDINT_H)
|
#if defined(HAVE_STDINT_H)
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
#include "sudo_exec.h"
|
#include "sudo_exec.h"
|
||||||
#include "sudo_plugin.h"
|
#include "sudo_plugin.h"
|
||||||
#include "sudo_plugin_int.h"
|
#include "sudo_plugin_int.h"
|
||||||
|
#include "sudo_rand.h"
|
||||||
#include "intercept.pb-c.h"
|
#include "intercept.pb-c.h"
|
||||||
|
|
||||||
/* TCSASOFT is a BSD extension that ignores control flags and speed. */
|
/* TCSASOFT is a BSD extension that ignores control flags and speed. */
|
||||||
@@ -49,15 +50,6 @@
|
|||||||
# define TCSASOFT 0
|
# define TCSASOFT 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void intercept_cb(int fd, int what, void *v);
|
|
||||||
|
|
||||||
/* Must match start of exec_closure_nopty and monitor_closure. */
|
|
||||||
struct intercept_fd_closure {
|
|
||||||
uint64_t secret;
|
|
||||||
struct command_details *details;
|
|
||||||
struct sudo_event_base *evbase;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Closure for intercept_cb() */
|
/* Closure for intercept_cb() */
|
||||||
struct intercept_closure {
|
struct intercept_closure {
|
||||||
struct command_details *details;
|
struct command_details *details;
|
||||||
@@ -67,23 +59,68 @@ struct intercept_closure {
|
|||||||
char **run_argv; /* owned by plugin */
|
char **run_argv; /* owned by plugin */
|
||||||
char **run_envp; /* dynamically allocated */
|
char **run_envp; /* dynamically allocated */
|
||||||
uint8_t *buf; /* dynamically allocated */
|
uint8_t *buf; /* dynamically allocated */
|
||||||
uint64_t secret;
|
|
||||||
size_t len;
|
size_t len;
|
||||||
|
int listen_sock;
|
||||||
int policy_result;
|
int policy_result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint64_t intercept_secret;
|
||||||
|
static in_port_t intercept_listen_port;
|
||||||
|
static void intercept_accept_cb(int fd, int what, void *v);
|
||||||
|
static void intercept_cb(int fd, int what, void *v);
|
||||||
|
|
||||||
|
bool
|
||||||
|
intercept_setup(int fd, struct sudo_event_base *evbase,
|
||||||
|
struct command_details *details)
|
||||||
|
{
|
||||||
|
struct intercept_closure *closure;
|
||||||
|
debug_decl(intercept_setup, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
|
"intercept fd %d\n", fd);
|
||||||
|
|
||||||
|
closure = calloc(1, sizeof(*closure));
|
||||||
|
if (closure == NULL) {
|
||||||
|
sudo_warnx("%s", U_("unable to allocate memory"));
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
closure->details = details;
|
||||||
|
/* XXX - add proper state variable */
|
||||||
|
closure->policy_result = intercept_secret ? -1 : 1;
|
||||||
|
closure->listen_sock = -1;
|
||||||
|
|
||||||
|
if (sudo_ev_set(&closure->ev, fd, SUDO_EV_READ, intercept_cb, closure) == -1) {
|
||||||
|
/* This cannot (currently) fail. */
|
||||||
|
sudo_warn("%s", U_("unable to add event to queue"));
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
if (sudo_ev_add(evbase, &closure->ev, NULL, false) == -1) {
|
||||||
|
sudo_warn("%s", U_("unable to add event to queue"));
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return_bool(true);
|
||||||
|
|
||||||
|
bad:
|
||||||
|
free(closure);
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close intercept fd and free closure.
|
* Close intercept socket and free closure when we are done with
|
||||||
* Called on EOF from sudo_intercept.so due to program exit.
|
* the connection.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
intercept_close(int fd, struct intercept_closure *closure)
|
intercept_connection_close(int fd, struct intercept_closure *closure)
|
||||||
{
|
{
|
||||||
size_t n;
|
size_t n;
|
||||||
debug_decl(intercept_close, SUDO_DEBUG_EXEC);
|
debug_decl(intercept_connection_close, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
sudo_ev_del(NULL, &closure->ev);
|
sudo_ev_del(NULL, &closure->ev);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
if (closure->listen_sock != -1)
|
||||||
|
close(closure->listen_sock);
|
||||||
|
|
||||||
free(closure->buf);
|
free(closure->buf);
|
||||||
free(closure->command);
|
free(closure->command);
|
||||||
@@ -102,6 +139,59 @@ intercept_close(int fd, struct intercept_closure *closure)
|
|||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare to listen on localhost using an ephemeral port.
|
||||||
|
* Sets intercept_secret and intercept_listen_port as side effects.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
prepare_listener(struct intercept_closure *closure)
|
||||||
|
{
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
socklen_t sin_len = sizeof(sin);
|
||||||
|
int sock;
|
||||||
|
debug_decl(prepare_listener, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
/* Secret must be non-zero. */
|
||||||
|
do {
|
||||||
|
intercept_secret = arc4random() | ((uint64_t)arc4random() << 32);
|
||||||
|
} while (intercept_secret == 0);
|
||||||
|
|
||||||
|
/* Create localhost listener socket (currently AF_INET only). */
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock == -1) {
|
||||||
|
sudo_warn("socket");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
sin.sin_port = 0;
|
||||||
|
if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
|
||||||
|
sudo_warn("bind");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
if (getsockname(sock, (struct sockaddr *)&sin, &sin_len) == -1) {
|
||||||
|
sudo_warn("getsockname");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
if (listen(sock, SOMAXCONN) == -1) {
|
||||||
|
sudo_warn("listen");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
closure->listen_sock = sock;
|
||||||
|
intercept_listen_port = ntohs(sin.sin_port);
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
|
"%s: listening on port %hu", __func__, intercept_listen_port);
|
||||||
|
|
||||||
|
debug_return_bool(true);
|
||||||
|
|
||||||
|
bad:
|
||||||
|
if (sock != -1)
|
||||||
|
close(sock);
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
intercept_check_policy(PolicyCheckRequest *req,
|
intercept_check_policy(PolicyCheckRequest *req,
|
||||||
struct intercept_closure *closure, const char **errstr)
|
struct intercept_closure *closure, const char **errstr)
|
||||||
@@ -117,6 +207,13 @@ intercept_check_policy(PolicyCheckRequest *req,
|
|||||||
*errstr = N_("invalid PolicyCheckRequest");
|
*errstr = N_("invalid PolicyCheckRequest");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
if (req->secret != intercept_secret) {
|
||||||
|
*errstr = N_("invalid PolicyCheckRequest");
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"secret mismatch: got %" PRIu64 ", expected %" PRIu64, req->secret,
|
||||||
|
intercept_secret);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
if (sudo_debug_needed(SUDO_DEBUG_INFO)) {
|
if (sudo_debug_needed(SUDO_DEBUG_INFO)) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
@@ -255,45 +352,41 @@ bad:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a single message from sudo_intercept.so.
|
* Read a single message from sudo_intercept.so and unpack it.
|
||||||
|
* Assumes fd is in blocking mode.
|
||||||
*/
|
*/
|
||||||
static bool
|
static InterceptRequest *
|
||||||
intercept_read(int fd, struct intercept_closure *closure)
|
intercept_recv_request(int fd)
|
||||||
{
|
{
|
||||||
struct sudo_event_base *base = sudo_ev_get_base(&closure->ev);
|
InterceptRequest *req = NULL;
|
||||||
InterceptMessage *msg = NULL;
|
|
||||||
uint8_t *cp, *buf = NULL;
|
uint8_t *cp, *buf = NULL;
|
||||||
pid_t saved_pgrp = -1;
|
uint32_t req_len;
|
||||||
struct termios oterm;
|
|
||||||
uint32_t msg_len;
|
|
||||||
bool ret = false;
|
|
||||||
int ttyfd = -1;
|
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
debug_decl(intercept_read, SUDO_DEBUG_EXEC);
|
debug_decl(intercept_recv_request, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
/* Read message size (uint32_t in host byte order). */
|
/* Read message size (uint32_t in host byte order). */
|
||||||
nread = read(fd, &msg_len, sizeof(msg_len));
|
nread = recv(fd, &req_len, sizeof(req_len), 0);
|
||||||
if (nread != sizeof(msg_len)) {
|
if (nread != sizeof(req_len)) {
|
||||||
if (nread != 0)
|
if (nread != 0)
|
||||||
sudo_warn("read");
|
sudo_warn("read");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg_len > MESSAGE_SIZE_MAX) {
|
if (req_len > MESSAGE_SIZE_MAX) {
|
||||||
sudo_warnx(U_("client message too large: %zu"), (size_t)msg_len);
|
sudo_warnx(U_("client request too large: %zu"), (size_t)req_len);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg_len > 0) {
|
if (req_len > 0) {
|
||||||
size_t rem = msg_len;
|
size_t rem = req_len;
|
||||||
|
|
||||||
if ((buf = malloc(msg_len)) == NULL) {
|
if ((buf = malloc(req_len)) == NULL) {
|
||||||
sudo_warnx("%s", U_("unable to allocate memory"));
|
sudo_warnx("%s", U_("unable to allocate memory"));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cp = buf;
|
cp = buf;
|
||||||
do {
|
do {
|
||||||
nread = read(fd, cp, rem);
|
nread = recv(fd, cp, rem, 0);
|
||||||
switch (nread) {
|
switch (nread) {
|
||||||
case 0:
|
case 0:
|
||||||
/* EOF, other side must have exited. */
|
/* EOF, other side must have exited. */
|
||||||
@@ -309,15 +402,43 @@ intercept_read(int fd, struct intercept_closure *closure)
|
|||||||
} while (rem > 0);
|
} while (rem > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = intercept_message__unpack(NULL, msg_len, buf);
|
req = intercept_request__unpack(NULL, req_len, buf);
|
||||||
if (msg == NULL) {
|
if (req == NULL) {
|
||||||
sudo_warnx("unable to unpack %s size %zu", "InterceptMessage",
|
sudo_warnx("unable to unpack %s size %zu", "InterceptRequest",
|
||||||
(size_t)msg_len);
|
(size_t)req_len);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (msg->type_case != INTERCEPT_MESSAGE__TYPE_POLICY_CHECK_REQ) {
|
|
||||||
sudo_warnx(U_("unexpected type_case value %d in %s from %s"),
|
done:
|
||||||
msg->type_case, "InterceptMessage", "sudo_intercept.so");
|
free(buf);
|
||||||
|
debug_return_ptr(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a message from sudo_intercept.so and act on it.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
intercept_read(int fd, struct intercept_closure *closure)
|
||||||
|
{
|
||||||
|
struct sudo_event_base *base = sudo_ev_get_base(&closure->ev);
|
||||||
|
InterceptRequest *req;
|
||||||
|
pid_t saved_pgrp = -1;
|
||||||
|
struct termios oterm;
|
||||||
|
bool ret = false;
|
||||||
|
int ttyfd = -1;
|
||||||
|
debug_decl(intercept_read, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
req = intercept_recv_request(fd);
|
||||||
|
if (req == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
switch (req->type_case) {
|
||||||
|
case INTERCEPT_REQUEST__TYPE_POLICY_CHECK_REQ:
|
||||||
|
if (closure->policy_result != -1) {
|
||||||
|
/* Only a single policy check request is allowed. */
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"got another PolicyCheckRequest on the socket (%d)",
|
||||||
|
closure->policy_result);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,13 +453,33 @@ intercept_read(int fd, struct intercept_closure *closure)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closure->policy_result = intercept_check_policy(msg->u.policy_check_req,
|
closure->policy_result = intercept_check_policy(req->u.policy_check_req,
|
||||||
closure, &closure->errstr);
|
closure, &closure->errstr);
|
||||||
|
|
||||||
if (ttyfd != -1) {
|
if (ttyfd != -1) {
|
||||||
(void)tcsetattr(ttyfd, TCSASOFT|TCSAFLUSH, &oterm);
|
(void)tcsetattr(ttyfd, TCSASOFT|TCSAFLUSH, &oterm);
|
||||||
(void)tcsetpgrp(ttyfd, saved_pgrp);
|
(void)tcsetpgrp(ttyfd, saved_pgrp);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case INTERCEPT_REQUEST__TYPE_HELLO:
|
||||||
|
if (closure->policy_result != 1) {
|
||||||
|
/* Only accept hello on a socket with an accepted command. */
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"got ClientHello without an accepted command");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start listener after first Hello. */
|
||||||
|
if (intercept_secret == 0 && !prepare_listener(closure))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
closure->policy_result = 2; /* XXX */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sudo_warnx(U_("unexpected type_case value %d in %s from %s"),
|
||||||
|
req->type_case, "InterceptRequest", "sudo_intercept.so");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* Switch event to write mode for the reply. */
|
/* Switch event to write mode for the reply. */
|
||||||
if (sudo_ev_set(&closure->ev, fd, SUDO_EV_WRITE, intercept_cb, closure) == -1) {
|
if (sudo_ev_set(&closure->ev, fd, SUDO_EV_WRITE, intercept_cb, closure) == -1) {
|
||||||
@@ -356,38 +497,37 @@ intercept_read(int fd, struct intercept_closure *closure)
|
|||||||
done:
|
done:
|
||||||
if (ttyfd != -1)
|
if (ttyfd != -1)
|
||||||
close(ttyfd);
|
close(ttyfd);
|
||||||
intercept_message__free_unpacked(msg, NULL);
|
intercept_request__free_unpacked(req, NULL);
|
||||||
free(buf);
|
|
||||||
debug_return_bool(ret);
|
debug_return_bool(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
fmt_policy_check_result(PolicyCheckResult *res, struct intercept_closure *closure)
|
fmt_intercept_response(InterceptResponse *resp,
|
||||||
|
struct intercept_closure *closure)
|
||||||
{
|
{
|
||||||
uint32_t msg_len;
|
uint32_t resp_len;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
debug_decl(fmt_policy_check_result, SUDO_DEBUG_EXEC);
|
debug_decl(fmt_intercept_response, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
res->secret = closure->secret;
|
closure->len = intercept_response__get_packed_size(resp);
|
||||||
closure->len = policy_check_result__get_packed_size(res);
|
|
||||||
if (closure->len > MESSAGE_SIZE_MAX) {
|
if (closure->len > MESSAGE_SIZE_MAX) {
|
||||||
sudo_warnx(U_("server message too large: %zu"), closure->len);
|
sudo_warnx(U_("server message too large: %zu"), closure->len);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wire message size is used for length encoding, precedes message. */
|
/* Wire message size is used for length encoding, precedes message. */
|
||||||
msg_len = closure->len;
|
resp_len = closure->len;
|
||||||
closure->len += sizeof(msg_len);
|
closure->len += sizeof(resp_len);
|
||||||
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
"size + PolicyCheckResult %zu bytes", closure->len);
|
"size + InterceptResponse %zu bytes", closure->len);
|
||||||
|
|
||||||
if ((closure->buf = malloc(closure->len)) == NULL) {
|
if ((closure->buf = malloc(closure->len)) == NULL) {
|
||||||
sudo_warnx("%s", U_("unable to allocate memory"));
|
sudo_warnx("%s", U_("unable to allocate memory"));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memcpy(closure->buf, &msg_len, sizeof(msg_len));
|
memcpy(closure->buf, &resp_len, sizeof(resp_len));
|
||||||
policy_check_result__pack(res, closure->buf + sizeof(msg_len));
|
intercept_response__pack(resp, closure->buf + sizeof(resp_len));
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
@@ -395,11 +535,27 @@ done:
|
|||||||
debug_return_bool(ret);
|
debug_return_bool(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
fmt_hello_response(struct intercept_closure *closure)
|
||||||
|
{
|
||||||
|
HelloResponse hello_resp = HELLO_RESPONSE__INIT;
|
||||||
|
InterceptResponse resp = INTERCEPT_RESPONSE__INIT;
|
||||||
|
debug_decl(fmt_hello_response, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
hello_resp.portno = intercept_listen_port;
|
||||||
|
hello_resp.secret = intercept_secret;
|
||||||
|
|
||||||
|
resp.u.hello_resp = &hello_resp;
|
||||||
|
resp.type_case = INTERCEPT_RESPONSE__TYPE_HELLO_RESP;
|
||||||
|
|
||||||
|
debug_return_bool(fmt_intercept_response(&resp, closure));
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
fmt_accept_message(struct intercept_closure *closure)
|
fmt_accept_message(struct intercept_closure *closure)
|
||||||
{
|
{
|
||||||
PolicyAcceptMessage msg = POLICY_ACCEPT_MESSAGE__INIT;
|
PolicyAcceptMessage msg = POLICY_ACCEPT_MESSAGE__INIT;
|
||||||
PolicyCheckResult res = POLICY_CHECK_RESULT__INIT;
|
InterceptResponse resp = INTERCEPT_RESPONSE__INIT;
|
||||||
size_t n;
|
size_t n;
|
||||||
debug_decl(fmt_accept_message, SUDO_DEBUG_EXEC);
|
debug_decl(fmt_accept_message, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
@@ -413,40 +569,40 @@ fmt_accept_message(struct intercept_closure *closure)
|
|||||||
continue;
|
continue;
|
||||||
msg.n_run_envp = n;
|
msg.n_run_envp = n;
|
||||||
|
|
||||||
res.u.accept_msg = &msg;
|
resp.u.accept_msg = &msg;
|
||||||
res.type_case = POLICY_CHECK_RESULT__TYPE_ACCEPT_MSG;
|
resp.type_case = INTERCEPT_RESPONSE__TYPE_ACCEPT_MSG;
|
||||||
|
|
||||||
debug_return_bool(fmt_policy_check_result(&res, closure));
|
debug_return_bool(fmt_intercept_response(&resp, closure));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
fmt_reject_message(struct intercept_closure *closure)
|
fmt_reject_message(struct intercept_closure *closure)
|
||||||
{
|
{
|
||||||
PolicyRejectMessage msg = POLICY_REJECT_MESSAGE__INIT;
|
PolicyRejectMessage msg = POLICY_REJECT_MESSAGE__INIT;
|
||||||
PolicyCheckResult res = POLICY_CHECK_RESULT__INIT;
|
InterceptResponse resp = INTERCEPT_RESPONSE__INIT;
|
||||||
debug_decl(fmt_reject_message, SUDO_DEBUG_EXEC);
|
debug_decl(fmt_reject_message, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
msg.reject_message = (char *)closure->errstr;
|
msg.reject_message = (char *)closure->errstr;
|
||||||
|
|
||||||
res.u.reject_msg = &msg;
|
resp.u.reject_msg = &msg;
|
||||||
res.type_case = POLICY_CHECK_RESULT__TYPE_REJECT_MSG;
|
resp.type_case = INTERCEPT_RESPONSE__TYPE_REJECT_MSG;
|
||||||
|
|
||||||
debug_return_bool(fmt_policy_check_result(&res, closure));
|
debug_return_bool(fmt_intercept_response(&resp, closure));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
fmt_error_message(struct intercept_closure *closure)
|
fmt_error_message(struct intercept_closure *closure)
|
||||||
{
|
{
|
||||||
PolicyErrorMessage msg = POLICY_ERROR_MESSAGE__INIT;
|
PolicyErrorMessage msg = POLICY_ERROR_MESSAGE__INIT;
|
||||||
PolicyCheckResult res = POLICY_CHECK_RESULT__INIT;
|
InterceptResponse resp = INTERCEPT_RESPONSE__INIT;
|
||||||
debug_decl(fmt_error_message, SUDO_DEBUG_EXEC);
|
debug_decl(fmt_error_message, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
msg.error_message = (char *)closure->errstr;
|
msg.error_message = (char *)closure->errstr;
|
||||||
|
|
||||||
res.u.error_msg = &msg;
|
resp.u.error_msg = &msg;
|
||||||
res.type_case = POLICY_CHECK_RESULT__TYPE_ERROR_MSG;
|
resp.type_case = INTERCEPT_RESPONSE__TYPE_ERROR_MSG;
|
||||||
|
|
||||||
debug_return_bool(fmt_policy_check_result(&res, closure));
|
debug_return_bool(fmt_intercept_response(&resp, closure));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -455,13 +611,19 @@ fmt_error_message(struct intercept_closure *closure)
|
|||||||
static bool
|
static bool
|
||||||
intercept_write(int fd, struct intercept_closure *closure)
|
intercept_write(int fd, struct intercept_closure *closure)
|
||||||
{
|
{
|
||||||
size_t rem;
|
struct sudo_event_base *evbase = sudo_ev_get_base(&closure->ev);
|
||||||
uint8_t *cp;
|
|
||||||
ssize_t nwritten;
|
ssize_t nwritten;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
uint8_t *cp;
|
||||||
|
size_t rem;
|
||||||
debug_decl(intercept_write, SUDO_DEBUG_EXEC);
|
debug_decl(intercept_write, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
/* XXX - proper state variable */
|
||||||
switch (closure->policy_result) {
|
switch (closure->policy_result) {
|
||||||
|
case 2:
|
||||||
|
if (!fmt_hello_response(closure))
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (!fmt_accept_message(closure))
|
if (!fmt_accept_message(closure))
|
||||||
goto done;
|
goto done;
|
||||||
@@ -479,15 +641,55 @@ intercept_write(int fd, struct intercept_closure *closure)
|
|||||||
cp = closure->buf;
|
cp = closure->buf;
|
||||||
rem = closure->len;
|
rem = closure->len;
|
||||||
do {
|
do {
|
||||||
nwritten = write(fd, cp, rem);
|
nwritten = send(fd, cp, rem, 0);
|
||||||
if (nwritten == -1) {
|
if (nwritten == -1) {
|
||||||
sudo_warn("write");
|
sudo_warn("send");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cp += nwritten;
|
cp += nwritten;
|
||||||
rem -= nwritten;
|
rem -= nwritten;
|
||||||
} while (rem > 0);
|
} while (rem > 0);
|
||||||
|
|
||||||
|
switch (closure->policy_result) {
|
||||||
|
case 1:
|
||||||
|
/* Switch event to read mode for sudo_intercept.so ctor. */
|
||||||
|
if (sudo_ev_set(&closure->ev, fd, SUDO_EV_READ, intercept_cb, closure) == -1) {
|
||||||
|
/* This cannot (currently) fail. */
|
||||||
|
sudo_warn("%s", U_("unable to add event to queue"));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (sudo_ev_add(evbase, &closure->ev, NULL, false) == -1) {
|
||||||
|
sudo_warn("%s", U_("unable to add event to queue"));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (closure->listen_sock != -1) {
|
||||||
|
/* Re-use intercept_event for the listener. */
|
||||||
|
if (sudo_ev_set(&closure->ev, closure->listen_sock, SUDO_EV_READ|SUDO_EV_PERSIST, intercept_accept_cb, closure) == -1) {
|
||||||
|
/* This cannot (currently) fail. */
|
||||||
|
sudo_warn("%s", U_("unable to add event to queue"));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (sudo_ev_add(evbase, &closure->ev, NULL, false) == -1) {
|
||||||
|
sudo_warn("%s", U_("unable to add event to queue"));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
/* Reset bits of closure we used for Hello. */
|
||||||
|
free(closure->buf);
|
||||||
|
closure->buf = NULL;
|
||||||
|
closure->len = 0;
|
||||||
|
closure->listen_sock = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FALLTHROUGH;
|
||||||
|
default:
|
||||||
|
/* Done with this connection. */
|
||||||
|
intercept_connection_close(fd, closure);
|
||||||
|
}
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@@ -513,115 +715,40 @@ intercept_cb(int fd, int what, void *v)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success || what == SUDO_EV_WRITE) {
|
if (!success)
|
||||||
intercept_close(fd, closure);
|
intercept_connection_close(fd, closure);
|
||||||
}
|
|
||||||
|
|
||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Accept a single fd passed from the child to use for policy checks.
|
* Accept a new connection from the client and fill in a client closure.
|
||||||
* This acts a bit like accept() in reverse since the client allocates
|
* Registers a new event for the connection.
|
||||||
* the socketpair() that is used for the actual communication.
|
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
intercept_fd_cb(int fd, int what, void *v)
|
intercept_accept_cb(int fd, int what, void *v)
|
||||||
{
|
{
|
||||||
struct intercept_closure *closure = NULL;
|
struct intercept_closure *closure = v;
|
||||||
struct intercept_fd_closure *fdc = v;
|
struct sudo_event_base *evbase = sudo_ev_get_base(&closure->ev);
|
||||||
struct msghdr msg;
|
struct sockaddr_in sin;
|
||||||
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && HAVE_STRUCT_MSGHDR_MSG_CONTROL == 1
|
socklen_t sin_len = sizeof(sin);
|
||||||
union {
|
int client_sock;
|
||||||
struct cmsghdr hdr;
|
debug_decl(intercept_accept_cb, SUDO_DEBUG_EXEC);
|
||||||
char buf[CMSG_SPACE(sizeof(int))];
|
|
||||||
} cmsgbuf;
|
|
||||||
struct cmsghdr *cmsg;
|
|
||||||
#endif
|
|
||||||
struct iovec iov[1];
|
|
||||||
int newfd = -1;
|
|
||||||
char ch;
|
|
||||||
debug_decl(intercept_fd_cb, SUDO_DEBUG_EXEC);
|
|
||||||
|
|
||||||
/*
|
client_sock = accept(fd, (struct sockaddr *)&sin, &sin_len);
|
||||||
* We send a single byte of data along with the fd; some systems
|
if (client_sock == -1) {
|
||||||
* don't support sending file descriptors without data.
|
sudo_warn("accept");
|
||||||
* Note that the intercept fd is *blocking*.
|
|
||||||
*/
|
|
||||||
iov[0].iov_base = &ch;
|
|
||||||
iov[0].iov_len = 1;
|
|
||||||
memset(&msg, 0, sizeof(msg));
|
|
||||||
msg.msg_iov = iov;
|
|
||||||
msg.msg_iovlen = 1;
|
|
||||||
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && HAVE_STRUCT_MSGHDR_MSG_CONTROL == 1
|
|
||||||
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
|
||||||
msg.msg_control = &cmsgbuf.buf;
|
|
||||||
msg.msg_controllen = sizeof(cmsgbuf.buf);
|
|
||||||
#else
|
|
||||||
msg.msg_accrights = (caddr_t)&newfd;
|
|
||||||
msg.msg_accrightslen = sizeof(newfd);
|
|
||||||
#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
|
|
||||||
|
|
||||||
switch (recvmsg(fd, &msg, 0)) {
|
|
||||||
case -1:
|
|
||||||
if (errno != EAGAIN && errno != EINTR)
|
|
||||||
sudo_warn("recvmsg");
|
|
||||||
goto bad;
|
|
||||||
case 0:
|
|
||||||
/* EOF */
|
|
||||||
goto bad;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == INTERCEPT_REQ_SEC) {
|
|
||||||
/* Client requested secret from ctor, no fd is present. */
|
|
||||||
if (write(fd, &fdc->secret, sizeof(fdc->secret)) != sizeof(fdc->secret))
|
|
||||||
goto bad;
|
|
||||||
debug_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && HAVE_STRUCT_MSGHDR_MSG_CONTROL == 1
|
|
||||||
cmsg = CMSG_FIRSTHDR(&msg);
|
|
||||||
if (cmsg == NULL) {
|
|
||||||
sudo_warnx(U_("%s: missing message header"), __func__);
|
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmsg->cmsg_type != SCM_RIGHTS) {
|
if (!intercept_setup(client_sock, evbase, closure->details)) {
|
||||||
sudo_warnx(U_("%s: expected message type %d, got %d"), __func__,
|
|
||||||
SCM_RIGHTS, cmsg->cmsg_type);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
memcpy(&newfd, CMSG_DATA(cmsg), sizeof(newfd));
|
|
||||||
#else
|
|
||||||
if (msg.msg_accrightslen != sizeof(newfd)) {
|
|
||||||
sudo_warnx(U_("%s: missing message header"), __func__);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
|
|
||||||
|
|
||||||
closure = calloc(1, sizeof(*closure));
|
|
||||||
if (closure == NULL) {
|
|
||||||
sudo_warnx("%s", U_("unable to allocate memory"));
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
closure->secret = fdc->secret;
|
|
||||||
closure->details = fdc->details;
|
|
||||||
|
|
||||||
if (sudo_ev_set(&closure->ev, newfd, SUDO_EV_READ, intercept_cb, closure) == -1) {
|
|
||||||
sudo_warn("%s", U_("unable to add event to queue"));
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
if (sudo_ev_add(fdc->evbase, &closure->ev, NULL, false) == -1) {
|
|
||||||
sudo_warn("%s", U_("unable to add event to queue"));
|
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_return;
|
debug_return;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
if (newfd != -1)
|
if (client_sock != -1)
|
||||||
close(newfd);
|
close(client_sock);
|
||||||
free(closure);
|
|
||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
@@ -43,15 +43,11 @@
|
|||||||
#include "sudo_exec.h"
|
#include "sudo_exec.h"
|
||||||
#include "sudo_plugin.h"
|
#include "sudo_plugin.h"
|
||||||
#include "sudo_plugin_int.h"
|
#include "sudo_plugin_int.h"
|
||||||
#include "sudo_rand.h"
|
|
||||||
|
|
||||||
/* Note that details and evbase must come first. */
|
|
||||||
struct exec_closure_nopty {
|
struct exec_closure_nopty {
|
||||||
uint64_t secret;
|
|
||||||
struct command_details *details;
|
struct command_details *details;
|
||||||
struct sudo_event_base *evbase;
|
struct sudo_event_base *evbase;
|
||||||
struct sudo_event *errpipe_event;
|
struct sudo_event *errpipe_event;
|
||||||
struct sudo_event *intercept_event;
|
|
||||||
struct sudo_event *sigint_event;
|
struct sudo_event *sigint_event;
|
||||||
struct sudo_event *sigquit_event;
|
struct sudo_event *sigquit_event;
|
||||||
struct sudo_event *sigtstp_event;
|
struct sudo_event *sigtstp_event;
|
||||||
@@ -203,13 +199,11 @@ signal_cb_nopty(int signo, int what, void *v)
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
fill_exec_closure_nopty(struct exec_closure_nopty *ec,
|
fill_exec_closure_nopty(struct exec_closure_nopty *ec,
|
||||||
struct command_status *cstat, struct command_details *details,
|
struct command_status *cstat, struct command_details *details, int errfd)
|
||||||
int intercept_fd, int errfd)
|
|
||||||
{
|
{
|
||||||
debug_decl(fill_exec_closure_nopty, SUDO_DEBUG_EXEC);
|
debug_decl(fill_exec_closure_nopty, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
/* Fill in the non-event part of the closure. */
|
/* Fill in the non-event part of the closure. */
|
||||||
ec->secret = arc4random() | ((uint64_t)arc4random() << 32);
|
|
||||||
ec->ppgrp = getpgrp();
|
ec->ppgrp = getpgrp();
|
||||||
ec->cstat = cstat;
|
ec->cstat = cstat;
|
||||||
ec->details = details;
|
ec->details = details;
|
||||||
@@ -227,17 +221,6 @@ fill_exec_closure_nopty(struct exec_closure_nopty *ec,
|
|||||||
sudo_fatal("%s", U_("unable to add event to queue"));
|
sudo_fatal("%s", U_("unable to add event to queue"));
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "error pipe fd %d\n", errfd);
|
sudo_debug_printf(SUDO_DEBUG_INFO, "error pipe fd %d\n", errfd);
|
||||||
|
|
||||||
/* Event for sudo_intercept.so (optional). */
|
|
||||||
if (intercept_fd != -1) {
|
|
||||||
ec->intercept_event = sudo_ev_alloc(intercept_fd,
|
|
||||||
SUDO_EV_READ|SUDO_EV_PERSIST, intercept_fd_cb, ec);
|
|
||||||
if (ec->intercept_event == NULL)
|
|
||||||
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
|
||||||
if (sudo_ev_add(ec->evbase, ec->intercept_event, NULL, false) == -1)
|
|
||||||
sudo_fatal("%s", U_("unable to add event to queue"));
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "intercept fd %d\n", intercept_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Events for local signals. */
|
/* Events for local signals. */
|
||||||
ec->sigint_event = sudo_ev_alloc(SIGINT,
|
ec->sigint_event = sudo_ev_alloc(SIGINT,
|
||||||
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
|
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
|
||||||
@@ -387,7 +370,7 @@ exec_nopty(struct command_details *details, struct command_status *cstat)
|
|||||||
* This must be inherited across exec, hence no FD_CLOEXEC.
|
* This must be inherited across exec, hence no FD_CLOEXEC.
|
||||||
*/
|
*/
|
||||||
if (ISSET(details->flags, CD_INTERCEPT|CD_LOG_CHILDREN)) {
|
if (ISSET(details->flags, CD_INTERCEPT|CD_LOG_CHILDREN)) {
|
||||||
if (socketpair(PF_UNIX, SOCK_DGRAM, 0, intercept_sv) == -1)
|
if (socketpair(PF_UNIX, SOCK_STREAM, 0, intercept_sv) == -1)
|
||||||
sudo_fatal("%s", U_("unable to create sockets"));
|
sudo_fatal("%s", U_("unable to create sockets"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +437,13 @@ exec_nopty(struct command_details *details, struct command_status *cstat)
|
|||||||
* Fill in exec closure, allocate event base, signal events and
|
* Fill in exec closure, allocate event base, signal events and
|
||||||
* the error pipe event.
|
* the error pipe event.
|
||||||
*/
|
*/
|
||||||
fill_exec_closure_nopty(&ec, cstat, details, intercept_sv[0], errpipe[0]);
|
fill_exec_closure_nopty(&ec, cstat, details, errpipe[0]);
|
||||||
|
|
||||||
|
/* Create event and closure for intercept mode. */
|
||||||
|
if (intercept_sv[0] != -1) {
|
||||||
|
if (!intercept_setup(intercept_sv[0], ec.evbase, details))
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Restore signal mask now that signal handlers are setup. */
|
/* Restore signal mask now that signal handlers are setup. */
|
||||||
sigprocmask(SIG_SETMASK, &oset, NULL);
|
sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||||
|
@@ -47,7 +47,6 @@
|
|||||||
#include "sudo_exec.h"
|
#include "sudo_exec.h"
|
||||||
#include "sudo_plugin.h"
|
#include "sudo_plugin.h"
|
||||||
#include "sudo_plugin_int.h"
|
#include "sudo_plugin_int.h"
|
||||||
#include "sudo_rand.h"
|
|
||||||
|
|
||||||
/* Evaluates to true if the event has /dev/tty as its fd. */
|
/* Evaluates to true if the event has /dev/tty as its fd. */
|
||||||
#define USERTTY_EVENT(_ev) (sudo_ev_get_fd((_ev)) == io_fds[SFD_USERTTY])
|
#define USERTTY_EVENT(_ev) (sudo_ev_get_fd((_ev)) == io_fds[SFD_USERTTY])
|
||||||
@@ -62,14 +61,11 @@ struct monitor_message {
|
|||||||
};
|
};
|
||||||
TAILQ_HEAD(monitor_message_list, monitor_message);
|
TAILQ_HEAD(monitor_message_list, monitor_message);
|
||||||
|
|
||||||
/* Note that details and evbase must come first. */
|
|
||||||
struct exec_closure_pty {
|
struct exec_closure_pty {
|
||||||
uint64_t secret;
|
|
||||||
struct command_details *details;
|
struct command_details *details;
|
||||||
struct sudo_event_base *evbase;
|
struct sudo_event_base *evbase;
|
||||||
struct sudo_event *backchannel_event;
|
struct sudo_event *backchannel_event;
|
||||||
struct sudo_event *fwdchannel_event;
|
struct sudo_event *fwdchannel_event;
|
||||||
struct sudo_event *intercept_event;
|
|
||||||
struct sudo_event *sigint_event;
|
struct sudo_event *sigint_event;
|
||||||
struct sudo_event *sigquit_event;
|
struct sudo_event *sigquit_event;
|
||||||
struct sudo_event *sigtstp_event;
|
struct sudo_event *sigtstp_event;
|
||||||
@@ -1207,13 +1203,11 @@ fwdchannel_cb(int sock, int what, void *v)
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
fill_exec_closure_pty(struct exec_closure_pty *ec, struct command_status *cstat,
|
fill_exec_closure_pty(struct exec_closure_pty *ec, struct command_status *cstat,
|
||||||
struct command_details *details, pid_t ppgrp, int backchannel,
|
struct command_details *details, pid_t ppgrp, int backchannel)
|
||||||
int intercept_fd)
|
|
||||||
{
|
{
|
||||||
debug_decl(fill_exec_closure_pty, SUDO_DEBUG_EXEC);
|
debug_decl(fill_exec_closure_pty, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
/* Fill in the non-event part of the closure. */
|
/* Fill in the non-event part of the closure. */
|
||||||
ec->secret = arc4random() | ((uint64_t)arc4random() << 32);
|
|
||||||
ec->cmnd_pid = -1;
|
ec->cmnd_pid = -1;
|
||||||
ec->ppgrp = ppgrp;
|
ec->ppgrp = ppgrp;
|
||||||
ec->cstat = cstat;
|
ec->cstat = cstat;
|
||||||
@@ -1239,17 +1233,6 @@ fill_exec_closure_pty(struct exec_closure_pty *ec, struct command_status *cstat,
|
|||||||
sudo_fatal("%s", U_("unable to add event to queue"));
|
sudo_fatal("%s", U_("unable to add event to queue"));
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "backchannel fd %d\n", backchannel);
|
sudo_debug_printf(SUDO_DEBUG_INFO, "backchannel fd %d\n", backchannel);
|
||||||
|
|
||||||
/* Event for sudo_intercept.so (optional). */
|
|
||||||
if (intercept_fd != -1) {
|
|
||||||
ec->intercept_event = sudo_ev_alloc(intercept_fd,
|
|
||||||
SUDO_EV_READ|SUDO_EV_PERSIST, intercept_fd_cb, ec);
|
|
||||||
if (ec->intercept_event == NULL)
|
|
||||||
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
|
||||||
if (sudo_ev_add(ec->evbase, ec->intercept_event, NULL, false) == -1)
|
|
||||||
sudo_fatal("%s", U_("unable to add event to queue"));
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "intercept fd %d\n", intercept_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Events for local signals. */
|
/* Events for local signals. */
|
||||||
ec->sigint_event = sudo_ev_alloc(SIGINT,
|
ec->sigint_event = sudo_ev_alloc(SIGINT,
|
||||||
SUDO_EV_SIGINFO, signal_cb_pty, ec);
|
SUDO_EV_SIGINFO, signal_cb_pty, ec);
|
||||||
@@ -1409,7 +1392,7 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
|||||||
* This must be inherited across exec, hence no FD_CLOEXEC.
|
* This must be inherited across exec, hence no FD_CLOEXEC.
|
||||||
*/
|
*/
|
||||||
if (ISSET(details->flags, CD_INTERCEPT|CD_LOG_CHILDREN)) {
|
if (ISSET(details->flags, CD_INTERCEPT|CD_LOG_CHILDREN)) {
|
||||||
if (socketpair(PF_UNIX, SOCK_DGRAM, 0, intercept_sv) == -1)
|
if (socketpair(PF_UNIX, SOCK_STREAM, 0, intercept_sv) == -1)
|
||||||
sudo_fatal("%s", U_("unable to create sockets"));
|
sudo_fatal("%s", U_("unable to create sockets"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1652,7 +1635,13 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
|||||||
* Fill in exec closure, allocate event base, signal events and
|
* Fill in exec closure, allocate event base, signal events and
|
||||||
* the backchannel event.
|
* the backchannel event.
|
||||||
*/
|
*/
|
||||||
fill_exec_closure_pty(&ec, cstat, details, ppgrp, sv[0], intercept_sv[0]);
|
fill_exec_closure_pty(&ec, cstat, details, ppgrp, sv[0]);
|
||||||
|
|
||||||
|
/* Create event and closure for intercept mode. */
|
||||||
|
if (intercept_sv[0] != -1) {
|
||||||
|
if (!intercept_setup(intercept_sv[0], ec.evbase, details))
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Restore signal mask now that signal handlers are setup. */
|
/* Restore signal mask now that signal handlers are setup. */
|
||||||
sigprocmask(SIG_SETMASK, &oset, NULL);
|
sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||||
|
@@ -7,49 +7,139 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "intercept.pb-c.h"
|
#include "intercept.pb-c.h"
|
||||||
void intercept_message__init
|
void intercept_request__init
|
||||||
(InterceptMessage *message)
|
(InterceptRequest *message)
|
||||||
{
|
{
|
||||||
static const InterceptMessage init_value = INTERCEPT_MESSAGE__INIT;
|
static const InterceptRequest init_value = INTERCEPT_REQUEST__INIT;
|
||||||
*message = init_value;
|
*message = init_value;
|
||||||
}
|
}
|
||||||
size_t intercept_message__get_packed_size
|
size_t intercept_request__get_packed_size
|
||||||
(const InterceptMessage *message)
|
(const InterceptRequest *message)
|
||||||
{
|
{
|
||||||
assert(message->base.descriptor == &intercept_message__descriptor);
|
assert(message->base.descriptor == &intercept_request__descriptor);
|
||||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||||
}
|
}
|
||||||
size_t intercept_message__pack
|
size_t intercept_request__pack
|
||||||
(const InterceptMessage *message,
|
(const InterceptRequest *message,
|
||||||
uint8_t *out)
|
uint8_t *out)
|
||||||
{
|
{
|
||||||
assert(message->base.descriptor == &intercept_message__descriptor);
|
assert(message->base.descriptor == &intercept_request__descriptor);
|
||||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||||
}
|
}
|
||||||
size_t intercept_message__pack_to_buffer
|
size_t intercept_request__pack_to_buffer
|
||||||
(const InterceptMessage *message,
|
(const InterceptRequest *message,
|
||||||
ProtobufCBuffer *buffer)
|
ProtobufCBuffer *buffer)
|
||||||
{
|
{
|
||||||
assert(message->base.descriptor == &intercept_message__descriptor);
|
assert(message->base.descriptor == &intercept_request__descriptor);
|
||||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||||
}
|
}
|
||||||
InterceptMessage *
|
InterceptRequest *
|
||||||
intercept_message__unpack
|
intercept_request__unpack
|
||||||
(ProtobufCAllocator *allocator,
|
(ProtobufCAllocator *allocator,
|
||||||
size_t len,
|
size_t len,
|
||||||
const uint8_t *data)
|
const uint8_t *data)
|
||||||
{
|
{
|
||||||
return (InterceptMessage *)
|
return (InterceptRequest *)
|
||||||
protobuf_c_message_unpack (&intercept_message__descriptor,
|
protobuf_c_message_unpack (&intercept_request__descriptor,
|
||||||
allocator, len, data);
|
allocator, len, data);
|
||||||
}
|
}
|
||||||
void intercept_message__free_unpacked
|
void intercept_request__free_unpacked
|
||||||
(InterceptMessage *message,
|
(InterceptRequest *message,
|
||||||
ProtobufCAllocator *allocator)
|
ProtobufCAllocator *allocator)
|
||||||
{
|
{
|
||||||
if(!message)
|
if(!message)
|
||||||
return;
|
return;
|
||||||
assert(message->base.descriptor == &intercept_message__descriptor);
|
assert(message->base.descriptor == &intercept_request__descriptor);
|
||||||
|
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||||
|
}
|
||||||
|
void client_hello__init
|
||||||
|
(ClientHello *message)
|
||||||
|
{
|
||||||
|
static const ClientHello init_value = CLIENT_HELLO__INIT;
|
||||||
|
*message = init_value;
|
||||||
|
}
|
||||||
|
size_t client_hello__get_packed_size
|
||||||
|
(const ClientHello *message)
|
||||||
|
{
|
||||||
|
assert(message->base.descriptor == &client_hello__descriptor);
|
||||||
|
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||||
|
}
|
||||||
|
size_t client_hello__pack
|
||||||
|
(const ClientHello *message,
|
||||||
|
uint8_t *out)
|
||||||
|
{
|
||||||
|
assert(message->base.descriptor == &client_hello__descriptor);
|
||||||
|
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||||
|
}
|
||||||
|
size_t client_hello__pack_to_buffer
|
||||||
|
(const ClientHello *message,
|
||||||
|
ProtobufCBuffer *buffer)
|
||||||
|
{
|
||||||
|
assert(message->base.descriptor == &client_hello__descriptor);
|
||||||
|
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||||
|
}
|
||||||
|
ClientHello *
|
||||||
|
client_hello__unpack
|
||||||
|
(ProtobufCAllocator *allocator,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t *data)
|
||||||
|
{
|
||||||
|
return (ClientHello *)
|
||||||
|
protobuf_c_message_unpack (&client_hello__descriptor,
|
||||||
|
allocator, len, data);
|
||||||
|
}
|
||||||
|
void client_hello__free_unpacked
|
||||||
|
(ClientHello *message,
|
||||||
|
ProtobufCAllocator *allocator)
|
||||||
|
{
|
||||||
|
if(!message)
|
||||||
|
return;
|
||||||
|
assert(message->base.descriptor == &client_hello__descriptor);
|
||||||
|
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||||
|
}
|
||||||
|
void hello_response__init
|
||||||
|
(HelloResponse *message)
|
||||||
|
{
|
||||||
|
static const HelloResponse init_value = HELLO_RESPONSE__INIT;
|
||||||
|
*message = init_value;
|
||||||
|
}
|
||||||
|
size_t hello_response__get_packed_size
|
||||||
|
(const HelloResponse *message)
|
||||||
|
{
|
||||||
|
assert(message->base.descriptor == &hello_response__descriptor);
|
||||||
|
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||||
|
}
|
||||||
|
size_t hello_response__pack
|
||||||
|
(const HelloResponse *message,
|
||||||
|
uint8_t *out)
|
||||||
|
{
|
||||||
|
assert(message->base.descriptor == &hello_response__descriptor);
|
||||||
|
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||||
|
}
|
||||||
|
size_t hello_response__pack_to_buffer
|
||||||
|
(const HelloResponse *message,
|
||||||
|
ProtobufCBuffer *buffer)
|
||||||
|
{
|
||||||
|
assert(message->base.descriptor == &hello_response__descriptor);
|
||||||
|
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||||
|
}
|
||||||
|
HelloResponse *
|
||||||
|
hello_response__unpack
|
||||||
|
(ProtobufCAllocator *allocator,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t *data)
|
||||||
|
{
|
||||||
|
return (HelloResponse *)
|
||||||
|
protobuf_c_message_unpack (&hello_response__descriptor,
|
||||||
|
allocator, len, data);
|
||||||
|
}
|
||||||
|
void hello_response__free_unpacked
|
||||||
|
(HelloResponse *message,
|
||||||
|
ProtobufCAllocator *allocator)
|
||||||
|
{
|
||||||
|
if(!message)
|
||||||
|
return;
|
||||||
|
assert(message->base.descriptor == &hello_response__descriptor);
|
||||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||||
}
|
}
|
||||||
void policy_check_request__init
|
void policy_check_request__init
|
||||||
@@ -232,90 +322,192 @@ void policy_error_message__free_unpacked
|
|||||||
assert(message->base.descriptor == &policy_error_message__descriptor);
|
assert(message->base.descriptor == &policy_error_message__descriptor);
|
||||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||||
}
|
}
|
||||||
void policy_check_result__init
|
void intercept_response__init
|
||||||
(PolicyCheckResult *message)
|
(InterceptResponse *message)
|
||||||
{
|
{
|
||||||
static const PolicyCheckResult init_value = POLICY_CHECK_RESULT__INIT;
|
static const InterceptResponse init_value = INTERCEPT_RESPONSE__INIT;
|
||||||
*message = init_value;
|
*message = init_value;
|
||||||
}
|
}
|
||||||
size_t policy_check_result__get_packed_size
|
size_t intercept_response__get_packed_size
|
||||||
(const PolicyCheckResult *message)
|
(const InterceptResponse *message)
|
||||||
{
|
{
|
||||||
assert(message->base.descriptor == &policy_check_result__descriptor);
|
assert(message->base.descriptor == &intercept_response__descriptor);
|
||||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||||
}
|
}
|
||||||
size_t policy_check_result__pack
|
size_t intercept_response__pack
|
||||||
(const PolicyCheckResult *message,
|
(const InterceptResponse *message,
|
||||||
uint8_t *out)
|
uint8_t *out)
|
||||||
{
|
{
|
||||||
assert(message->base.descriptor == &policy_check_result__descriptor);
|
assert(message->base.descriptor == &intercept_response__descriptor);
|
||||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||||
}
|
}
|
||||||
size_t policy_check_result__pack_to_buffer
|
size_t intercept_response__pack_to_buffer
|
||||||
(const PolicyCheckResult *message,
|
(const InterceptResponse *message,
|
||||||
ProtobufCBuffer *buffer)
|
ProtobufCBuffer *buffer)
|
||||||
{
|
{
|
||||||
assert(message->base.descriptor == &policy_check_result__descriptor);
|
assert(message->base.descriptor == &intercept_response__descriptor);
|
||||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||||
}
|
}
|
||||||
PolicyCheckResult *
|
InterceptResponse *
|
||||||
policy_check_result__unpack
|
intercept_response__unpack
|
||||||
(ProtobufCAllocator *allocator,
|
(ProtobufCAllocator *allocator,
|
||||||
size_t len,
|
size_t len,
|
||||||
const uint8_t *data)
|
const uint8_t *data)
|
||||||
{
|
{
|
||||||
return (PolicyCheckResult *)
|
return (InterceptResponse *)
|
||||||
protobuf_c_message_unpack (&policy_check_result__descriptor,
|
protobuf_c_message_unpack (&intercept_response__descriptor,
|
||||||
allocator, len, data);
|
allocator, len, data);
|
||||||
}
|
}
|
||||||
void policy_check_result__free_unpacked
|
void intercept_response__free_unpacked
|
||||||
(PolicyCheckResult *message,
|
(InterceptResponse *message,
|
||||||
ProtobufCAllocator *allocator)
|
ProtobufCAllocator *allocator)
|
||||||
{
|
{
|
||||||
if(!message)
|
if(!message)
|
||||||
return;
|
return;
|
||||||
assert(message->base.descriptor == &policy_check_result__descriptor);
|
assert(message->base.descriptor == &intercept_response__descriptor);
|
||||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||||
}
|
}
|
||||||
static const ProtobufCFieldDescriptor intercept_message__field_descriptors[1] =
|
static const ProtobufCFieldDescriptor intercept_request__field_descriptors[2] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"policy_check_req",
|
"policy_check_req",
|
||||||
1,
|
1,
|
||||||
PROTOBUF_C_LABEL_NONE,
|
PROTOBUF_C_LABEL_NONE,
|
||||||
PROTOBUF_C_TYPE_MESSAGE,
|
PROTOBUF_C_TYPE_MESSAGE,
|
||||||
offsetof(InterceptMessage, type_case),
|
offsetof(InterceptRequest, type_case),
|
||||||
offsetof(InterceptMessage, u.policy_check_req),
|
offsetof(InterceptRequest, u.policy_check_req),
|
||||||
&policy_check_request__descriptor,
|
&policy_check_request__descriptor,
|
||||||
NULL,
|
NULL,
|
||||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"hello",
|
||||||
|
2,
|
||||||
|
PROTOBUF_C_LABEL_NONE,
|
||||||
|
PROTOBUF_C_TYPE_MESSAGE,
|
||||||
|
offsetof(InterceptRequest, type_case),
|
||||||
|
offsetof(InterceptRequest, u.hello),
|
||||||
|
&client_hello__descriptor,
|
||||||
|
NULL,
|
||||||
|
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||||
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
|
},
|
||||||
};
|
};
|
||||||
static const unsigned intercept_message__field_indices_by_name[] = {
|
static const unsigned intercept_request__field_indices_by_name[] = {
|
||||||
|
1, /* field[1] = hello */
|
||||||
0, /* field[0] = policy_check_req */
|
0, /* field[0] = policy_check_req */
|
||||||
};
|
};
|
||||||
static const ProtobufCIntRange intercept_message__number_ranges[1 + 1] =
|
static const ProtobufCIntRange intercept_request__number_ranges[1 + 1] =
|
||||||
|
{
|
||||||
|
{ 1, 0 },
|
||||||
|
{ 0, 2 }
|
||||||
|
};
|
||||||
|
const ProtobufCMessageDescriptor intercept_request__descriptor =
|
||||||
|
{
|
||||||
|
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||||
|
"InterceptRequest",
|
||||||
|
"InterceptRequest",
|
||||||
|
"InterceptRequest",
|
||||||
|
"",
|
||||||
|
sizeof(InterceptRequest),
|
||||||
|
2,
|
||||||
|
intercept_request__field_descriptors,
|
||||||
|
intercept_request__field_indices_by_name,
|
||||||
|
1, intercept_request__number_ranges,
|
||||||
|
(ProtobufCMessageInit) intercept_request__init,
|
||||||
|
NULL,NULL,NULL /* reserved[123] */
|
||||||
|
};
|
||||||
|
static const ProtobufCFieldDescriptor client_hello__field_descriptors[1] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"pid",
|
||||||
|
1,
|
||||||
|
PROTOBUF_C_LABEL_NONE,
|
||||||
|
PROTOBUF_C_TYPE_INT32,
|
||||||
|
0, /* quantifier_offset */
|
||||||
|
offsetof(ClientHello, pid),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0, /* flags */
|
||||||
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
|
},
|
||||||
|
};
|
||||||
|
static const unsigned client_hello__field_indices_by_name[] = {
|
||||||
|
0, /* field[0] = pid */
|
||||||
|
};
|
||||||
|
static const ProtobufCIntRange client_hello__number_ranges[1 + 1] =
|
||||||
{
|
{
|
||||||
{ 1, 0 },
|
{ 1, 0 },
|
||||||
{ 0, 1 }
|
{ 0, 1 }
|
||||||
};
|
};
|
||||||
const ProtobufCMessageDescriptor intercept_message__descriptor =
|
const ProtobufCMessageDescriptor client_hello__descriptor =
|
||||||
{
|
{
|
||||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||||
"InterceptMessage",
|
"ClientHello",
|
||||||
"InterceptMessage",
|
"ClientHello",
|
||||||
"InterceptMessage",
|
"ClientHello",
|
||||||
"",
|
"",
|
||||||
sizeof(InterceptMessage),
|
sizeof(ClientHello),
|
||||||
1,
|
1,
|
||||||
intercept_message__field_descriptors,
|
client_hello__field_descriptors,
|
||||||
intercept_message__field_indices_by_name,
|
client_hello__field_indices_by_name,
|
||||||
1, intercept_message__number_ranges,
|
1, client_hello__number_ranges,
|
||||||
(ProtobufCMessageInit) intercept_message__init,
|
(ProtobufCMessageInit) client_hello__init,
|
||||||
NULL,NULL,NULL /* reserved[123] */
|
NULL,NULL,NULL /* reserved[123] */
|
||||||
};
|
};
|
||||||
static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[3] =
|
static const ProtobufCFieldDescriptor hello_response__field_descriptors[2] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"secret",
|
||||||
|
1,
|
||||||
|
PROTOBUF_C_LABEL_NONE,
|
||||||
|
PROTOBUF_C_TYPE_FIXED64,
|
||||||
|
0, /* quantifier_offset */
|
||||||
|
offsetof(HelloResponse, secret),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0, /* flags */
|
||||||
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"portno",
|
||||||
|
2,
|
||||||
|
PROTOBUF_C_LABEL_NONE,
|
||||||
|
PROTOBUF_C_TYPE_INT32,
|
||||||
|
0, /* quantifier_offset */
|
||||||
|
offsetof(HelloResponse, portno),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0, /* flags */
|
||||||
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
|
},
|
||||||
|
};
|
||||||
|
static const unsigned hello_response__field_indices_by_name[] = {
|
||||||
|
1, /* field[1] = portno */
|
||||||
|
0, /* field[0] = secret */
|
||||||
|
};
|
||||||
|
static const ProtobufCIntRange hello_response__number_ranges[1 + 1] =
|
||||||
|
{
|
||||||
|
{ 1, 0 },
|
||||||
|
{ 0, 2 }
|
||||||
|
};
|
||||||
|
const ProtobufCMessageDescriptor hello_response__descriptor =
|
||||||
|
{
|
||||||
|
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||||
|
"HelloResponse",
|
||||||
|
"HelloResponse",
|
||||||
|
"HelloResponse",
|
||||||
|
"",
|
||||||
|
sizeof(HelloResponse),
|
||||||
|
2,
|
||||||
|
hello_response__field_descriptors,
|
||||||
|
hello_response__field_indices_by_name,
|
||||||
|
1, hello_response__number_ranges,
|
||||||
|
(ProtobufCMessageInit) hello_response__init,
|
||||||
|
NULL,NULL,NULL /* reserved[123] */
|
||||||
|
};
|
||||||
|
static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[5] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"command",
|
"command",
|
||||||
@@ -353,16 +545,42 @@ static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[3]
|
|||||||
0, /* flags */
|
0, /* flags */
|
||||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"intercept_fd",
|
||||||
|
4,
|
||||||
|
PROTOBUF_C_LABEL_NONE,
|
||||||
|
PROTOBUF_C_TYPE_INT32,
|
||||||
|
0, /* quantifier_offset */
|
||||||
|
offsetof(PolicyCheckRequest, intercept_fd),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0, /* flags */
|
||||||
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"secret",
|
||||||
|
5,
|
||||||
|
PROTOBUF_C_LABEL_NONE,
|
||||||
|
PROTOBUF_C_TYPE_FIXED64,
|
||||||
|
0, /* quantifier_offset */
|
||||||
|
offsetof(PolicyCheckRequest, secret),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0, /* flags */
|
||||||
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
|
},
|
||||||
};
|
};
|
||||||
static const unsigned policy_check_request__field_indices_by_name[] = {
|
static const unsigned policy_check_request__field_indices_by_name[] = {
|
||||||
1, /* field[1] = argv */
|
1, /* field[1] = argv */
|
||||||
0, /* field[0] = command */
|
0, /* field[0] = command */
|
||||||
2, /* field[2] = envp */
|
2, /* field[2] = envp */
|
||||||
|
3, /* field[3] = intercept_fd */
|
||||||
|
4, /* field[4] = secret */
|
||||||
};
|
};
|
||||||
static const ProtobufCIntRange policy_check_request__number_ranges[1 + 1] =
|
static const ProtobufCIntRange policy_check_request__number_ranges[1 + 1] =
|
||||||
{
|
{
|
||||||
{ 1, 0 },
|
{ 1, 0 },
|
||||||
{ 0, 3 }
|
{ 0, 5 }
|
||||||
};
|
};
|
||||||
const ProtobufCMessageDescriptor policy_check_request__descriptor =
|
const ProtobufCMessageDescriptor policy_check_request__descriptor =
|
||||||
{
|
{
|
||||||
@@ -372,7 +590,7 @@ const ProtobufCMessageDescriptor policy_check_request__descriptor =
|
|||||||
"PolicyCheckRequest",
|
"PolicyCheckRequest",
|
||||||
"",
|
"",
|
||||||
sizeof(PolicyCheckRequest),
|
sizeof(PolicyCheckRequest),
|
||||||
3,
|
5,
|
||||||
policy_check_request__field_descriptors,
|
policy_check_request__field_descriptors,
|
||||||
policy_check_request__field_indices_by_name,
|
policy_check_request__field_indices_by_name,
|
||||||
1, policy_check_request__number_ranges,
|
1, policy_check_request__number_ranges,
|
||||||
@@ -519,15 +737,27 @@ const ProtobufCMessageDescriptor policy_error_message__descriptor =
|
|||||||
(ProtobufCMessageInit) policy_error_message__init,
|
(ProtobufCMessageInit) policy_error_message__init,
|
||||||
NULL,NULL,NULL /* reserved[123] */
|
NULL,NULL,NULL /* reserved[123] */
|
||||||
};
|
};
|
||||||
static const ProtobufCFieldDescriptor policy_check_result__field_descriptors[4] =
|
static const ProtobufCFieldDescriptor intercept_response__field_descriptors[4] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"accept_msg",
|
"hello_resp",
|
||||||
1,
|
1,
|
||||||
PROTOBUF_C_LABEL_NONE,
|
PROTOBUF_C_LABEL_NONE,
|
||||||
PROTOBUF_C_TYPE_MESSAGE,
|
PROTOBUF_C_TYPE_MESSAGE,
|
||||||
offsetof(PolicyCheckResult, type_case),
|
offsetof(InterceptResponse, type_case),
|
||||||
offsetof(PolicyCheckResult, u.accept_msg),
|
offsetof(InterceptResponse, u.hello_resp),
|
||||||
|
&hello_response__descriptor,
|
||||||
|
NULL,
|
||||||
|
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||||
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"accept_msg",
|
||||||
|
2,
|
||||||
|
PROTOBUF_C_LABEL_NONE,
|
||||||
|
PROTOBUF_C_TYPE_MESSAGE,
|
||||||
|
offsetof(InterceptResponse, type_case),
|
||||||
|
offsetof(InterceptResponse, u.accept_msg),
|
||||||
&policy_accept_message__descriptor,
|
&policy_accept_message__descriptor,
|
||||||
NULL,
|
NULL,
|
||||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||||
@@ -535,11 +765,11 @@ static const ProtobufCFieldDescriptor policy_check_result__field_descriptors[4]
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"reject_msg",
|
"reject_msg",
|
||||||
2,
|
3,
|
||||||
PROTOBUF_C_LABEL_NONE,
|
PROTOBUF_C_LABEL_NONE,
|
||||||
PROTOBUF_C_TYPE_MESSAGE,
|
PROTOBUF_C_TYPE_MESSAGE,
|
||||||
offsetof(PolicyCheckResult, type_case),
|
offsetof(InterceptResponse, type_case),
|
||||||
offsetof(PolicyCheckResult, u.reject_msg),
|
offsetof(InterceptResponse, u.reject_msg),
|
||||||
&policy_reject_message__descriptor,
|
&policy_reject_message__descriptor,
|
||||||
NULL,
|
NULL,
|
||||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||||
@@ -547,52 +777,40 @@ static const ProtobufCFieldDescriptor policy_check_result__field_descriptors[4]
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"error_msg",
|
"error_msg",
|
||||||
3,
|
4,
|
||||||
PROTOBUF_C_LABEL_NONE,
|
PROTOBUF_C_LABEL_NONE,
|
||||||
PROTOBUF_C_TYPE_MESSAGE,
|
PROTOBUF_C_TYPE_MESSAGE,
|
||||||
offsetof(PolicyCheckResult, type_case),
|
offsetof(InterceptResponse, type_case),
|
||||||
offsetof(PolicyCheckResult, u.error_msg),
|
offsetof(InterceptResponse, u.error_msg),
|
||||||
&policy_error_message__descriptor,
|
&policy_error_message__descriptor,
|
||||||
NULL,
|
NULL,
|
||||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"secret",
|
|
||||||
4,
|
|
||||||
PROTOBUF_C_LABEL_NONE,
|
|
||||||
PROTOBUF_C_TYPE_FIXED64,
|
|
||||||
0, /* quantifier_offset */
|
|
||||||
offsetof(PolicyCheckResult, secret),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
0, /* flags */
|
|
||||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
static const unsigned policy_check_result__field_indices_by_name[] = {
|
static const unsigned intercept_response__field_indices_by_name[] = {
|
||||||
0, /* field[0] = accept_msg */
|
1, /* field[1] = accept_msg */
|
||||||
2, /* field[2] = error_msg */
|
3, /* field[3] = error_msg */
|
||||||
1, /* field[1] = reject_msg */
|
0, /* field[0] = hello_resp */
|
||||||
3, /* field[3] = secret */
|
2, /* field[2] = reject_msg */
|
||||||
};
|
};
|
||||||
static const ProtobufCIntRange policy_check_result__number_ranges[1 + 1] =
|
static const ProtobufCIntRange intercept_response__number_ranges[1 + 1] =
|
||||||
{
|
{
|
||||||
{ 1, 0 },
|
{ 1, 0 },
|
||||||
{ 0, 4 }
|
{ 0, 4 }
|
||||||
};
|
};
|
||||||
const ProtobufCMessageDescriptor policy_check_result__descriptor =
|
const ProtobufCMessageDescriptor intercept_response__descriptor =
|
||||||
{
|
{
|
||||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||||
"PolicyCheckResult",
|
"InterceptResponse",
|
||||||
"PolicyCheckResult",
|
"InterceptResponse",
|
||||||
"PolicyCheckResult",
|
"InterceptResponse",
|
||||||
"",
|
"",
|
||||||
sizeof(PolicyCheckResult),
|
sizeof(InterceptResponse),
|
||||||
4,
|
4,
|
||||||
policy_check_result__field_descriptors,
|
intercept_response__field_descriptors,
|
||||||
policy_check_result__field_indices_by_name,
|
intercept_response__field_indices_by_name,
|
||||||
1, policy_check_result__number_ranges,
|
1, intercept_response__number_ranges,
|
||||||
(ProtobufCMessageInit) policy_check_result__init,
|
(ProtobufCMessageInit) intercept_response__init,
|
||||||
NULL,NULL,NULL /* reserved[123] */
|
NULL,NULL,NULL /* reserved[123] */
|
||||||
};
|
};
|
||||||
|
@@ -4,14 +4,33 @@ syntax = "proto3";
|
|||||||
* Intercept message from sudo_intercept.so. Messages on the
|
* Intercept message from sudo_intercept.so. Messages on the
|
||||||
* wire are prefixed with a 32-bit size in network byte order.
|
* wire are prefixed with a 32-bit size in network byte order.
|
||||||
*/
|
*/
|
||||||
message InterceptMessage {
|
message InterceptRequest {
|
||||||
oneof type {
|
oneof type {
|
||||||
PolicyCheckRequest policy_check_req = 1;
|
PolicyCheckRequest policy_check_req = 1;
|
||||||
|
ClientHello hello = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hello message from sudo_intercept.so to main sudo process.
|
||||||
|
* Sudo sends back the secret and localhost port number.
|
||||||
|
*/
|
||||||
|
message ClientHello {
|
||||||
|
int32 pid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sudo response to a ClientHello from sudo_intercept.so.
|
||||||
|
* The client uses the port number and secret to connect back to sudo.
|
||||||
|
*/
|
||||||
|
message HelloResponse {
|
||||||
|
fixed64 secret = 1;
|
||||||
|
int32 portno = 2;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Policy check request from sudo_intercept.so.
|
* Policy check request from sudo_intercept.so.
|
||||||
|
* Must include the correct secret value.
|
||||||
* Note that the plugin API only currently supports passing
|
* Note that the plugin API only currently supports passing
|
||||||
* the new environment in to the open() function.
|
* the new environment in to the open() function.
|
||||||
*/
|
*/
|
||||||
@@ -19,6 +38,8 @@ message PolicyCheckRequest {
|
|||||||
string command = 1;
|
string command = 1;
|
||||||
repeated string argv = 2;
|
repeated string argv = 2;
|
||||||
repeated string envp = 3;
|
repeated string envp = 3;
|
||||||
|
int32 intercept_fd = 4;
|
||||||
|
fixed64 secret = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PolicyAcceptMessage {
|
message PolicyAcceptMessage {
|
||||||
@@ -36,13 +57,13 @@ message PolicyErrorMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Policy check result sent back to sudo_intercept.so.
|
* Response sent back to sudo_intercept.so.
|
||||||
*/
|
*/
|
||||||
message PolicyCheckResult {
|
message InterceptResponse {
|
||||||
oneof type {
|
oneof type {
|
||||||
PolicyAcceptMessage accept_msg = 1;
|
HelloResponse hello_resp = 1;
|
||||||
PolicyRejectMessage reject_msg = 2;
|
PolicyAcceptMessage accept_msg = 2;
|
||||||
PolicyErrorMessage error_msg = 3;
|
PolicyRejectMessage reject_msg = 3;
|
||||||
|
PolicyErrorMessage error_msg = 4;
|
||||||
}
|
}
|
||||||
fixed64 secret = 4;
|
|
||||||
}
|
}
|
||||||
|
@@ -80,7 +80,6 @@
|
|||||||
#define SESH_ERR_SOME_FILES 33 /* copy error, some files copied */
|
#define SESH_ERR_SOME_FILES 33 /* copy error, some files copied */
|
||||||
|
|
||||||
#define INTERCEPT_FD_MIN 64 /* minimum fd so shell won't close it */
|
#define INTERCEPT_FD_MIN 64 /* minimum fd so shell won't close it */
|
||||||
#define INTERCEPT_REQ_SEC 42 /* request intercept secret */
|
|
||||||
#define MESSAGE_SIZE_MAX 2097152 /* 2Mib max intercept message size */
|
#define MESSAGE_SIZE_MAX 2097152 /* 2Mib max intercept message size */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -88,19 +87,22 @@
|
|||||||
*/
|
*/
|
||||||
struct command_details;
|
struct command_details;
|
||||||
struct command_status;
|
struct command_status;
|
||||||
|
struct sudo_event_base;
|
||||||
struct stat;
|
struct stat;
|
||||||
|
|
||||||
/* exec.c */
|
/* exec.c */
|
||||||
void exec_cmnd(struct command_details *details, int intercept_fd, int errfd);
|
void exec_cmnd(struct command_details *details, int intercept_fd, int errfd);
|
||||||
void terminate_command(pid_t pid, bool use_pgrp);
|
void terminate_command(pid_t pid, bool use_pgrp);
|
||||||
bool sudo_terminated(struct command_status *cstat);
|
bool sudo_terminated(struct command_status *cstat);
|
||||||
void intercept_fd_cb(int fd, int what, void *v);
|
|
||||||
|
|
||||||
/* exec_common.c */
|
/* exec_common.c */
|
||||||
int sudo_execve(int fd, const char *path, char *const argv[], char *envp[], int intercept_fd, int flags);
|
int sudo_execve(int fd, const char *path, char *const argv[], char *envp[], int intercept_fd, int flags);
|
||||||
char **disable_execute(char *envp[], const char *dso);
|
char **disable_execute(char *envp[], const char *dso);
|
||||||
char **enable_monitor(char *envp[], const char *dso);
|
char **enable_monitor(char *envp[], const char *dso);
|
||||||
|
|
||||||
|
/* exec_intercept.c */
|
||||||
|
bool intercept_setup(int fd, struct sudo_event_base *evbase, struct command_details *details);
|
||||||
|
|
||||||
/* exec_nopty.c */
|
/* exec_nopty.c */
|
||||||
void exec_nopty(struct command_details *details, struct command_status *cstat);
|
void exec_nopty(struct command_details *details, struct command_status *cstat);
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#if defined(HAVE_STDINT_H)
|
#if defined(HAVE_STDINT_H)
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
@@ -57,8 +58,125 @@
|
|||||||
|
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
|
|
||||||
static int intercept_sock = -1;
|
|
||||||
static uint64_t secret;
|
static uint64_t secret;
|
||||||
|
static in_port_t intercept_port;
|
||||||
|
|
||||||
|
/* Send entire request to sudo (blocking). */
|
||||||
|
static bool
|
||||||
|
send_req(int sock, const uint8_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
const uint8_t *cp = buf;
|
||||||
|
ssize_t nwritten;
|
||||||
|
debug_decl(send_req, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
do {
|
||||||
|
nwritten = send(sock, cp, len, 0);
|
||||||
|
if (nwritten == -1) {
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
len -= nwritten;
|
||||||
|
cp += nwritten;
|
||||||
|
} while (len > 0);
|
||||||
|
|
||||||
|
debug_return_bool(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
send_client_hello(int sock)
|
||||||
|
{
|
||||||
|
InterceptRequest msg = INTERCEPT_REQUEST__INIT;
|
||||||
|
ClientHello hello = CLIENT_HELLO__INIT;
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
uint32_t msg_len;
|
||||||
|
size_t len;
|
||||||
|
bool ret = false;
|
||||||
|
debug_decl(send_client_hello, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
/* Setup policy check request. */
|
||||||
|
hello.pid = getpid();
|
||||||
|
msg.type_case = INTERCEPT_REQUEST__TYPE_HELLO;;
|
||||||
|
msg.u.hello = &hello;
|
||||||
|
|
||||||
|
len = intercept_request__get_packed_size(&msg);
|
||||||
|
if (len > MESSAGE_SIZE_MAX) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"InterceptRequest too large: %zu", len);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Wire message size is used for length encoding, precedes message. */
|
||||||
|
msg_len = len;
|
||||||
|
len += sizeof(msg_len);
|
||||||
|
|
||||||
|
if ((buf = malloc(len)) == NULL) {
|
||||||
|
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memcpy(buf, &msg_len, sizeof(msg_len));
|
||||||
|
intercept_request__pack(&msg, buf + sizeof(msg_len));
|
||||||
|
|
||||||
|
ret = send_req(sock, buf, len);
|
||||||
|
|
||||||
|
done:
|
||||||
|
free(buf);
|
||||||
|
debug_return_bool(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Receive HelloResponse from sudo over fd.
|
||||||
|
*/
|
||||||
|
InterceptResponse *
|
||||||
|
recv_intercept_response(int fd)
|
||||||
|
{
|
||||||
|
InterceptResponse *res = NULL;
|
||||||
|
ssize_t nread;
|
||||||
|
uint32_t res_len;
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
debug_decl(recv_intercept_response, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
/* Read message size (uint32_t in host byte order). */
|
||||||
|
nread = recv(fd, &res_len, sizeof(res_len), 0);
|
||||||
|
if ((size_t)nread != sizeof(res_len)) {
|
||||||
|
if (nread == 0) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"unexpected EOF reading response size");
|
||||||
|
} else {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
"error reading response size");
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (res_len > MESSAGE_SIZE_MAX) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"InterceptResponse too large: %u", res_len);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read response from sudo (blocking). */
|
||||||
|
if ((buf = malloc(res_len)) == NULL) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
nread = recv(fd, buf, res_len, 0);
|
||||||
|
if ((size_t)nread != res_len) {
|
||||||
|
if (nread == 0) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"unexpected EOF reading response");
|
||||||
|
} else {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
"error reading response");
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
res = intercept_response__unpack(NULL, res_len, buf);
|
||||||
|
if (res == NULL) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"unable to unpack %s size %u", "InterceptResponse", res_len);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
free(buf);
|
||||||
|
debug_return_ptr(res);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up SUDO_INTERCEPT_FD in the environment.
|
* Look up SUDO_INTERCEPT_FD in the environment.
|
||||||
@@ -67,11 +185,14 @@ static uint64_t secret;
|
|||||||
__attribute__((constructor)) static void
|
__attribute__((constructor)) static void
|
||||||
sudo_interposer_init(void)
|
sudo_interposer_init(void)
|
||||||
{
|
{
|
||||||
|
InterceptResponse *res = NULL;
|
||||||
static bool initialized;
|
static bool initialized;
|
||||||
|
int fd = -1;
|
||||||
char **p;
|
char **p;
|
||||||
debug_decl(sudo_interposer_init, SUDO_DEBUG_EXEC);
|
debug_decl(sudo_interposer_init, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
if (!initialized) {
|
if (initialized)
|
||||||
|
debug_return;
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
/* Read debug section of sudo.conf and init debugging. */
|
/* Read debug section of sudo.conf and init debugging. */
|
||||||
@@ -89,8 +210,6 @@ sudo_interposer_init(void)
|
|||||||
if (strncmp(*p, "SUDO_INTERCEPT_FD=", sizeof("SUDO_INTERCEPT_FD=") -1) == 0) {
|
if (strncmp(*p, "SUDO_INTERCEPT_FD=", sizeof("SUDO_INTERCEPT_FD=") -1) == 0) {
|
||||||
const char *fdstr = *p + sizeof("SUDO_INTERCEPT_FD=") - 1;
|
const char *fdstr = *p + sizeof("SUDO_INTERCEPT_FD=") - 1;
|
||||||
const char *errstr;
|
const char *errstr;
|
||||||
char ch = INTERCEPT_REQ_SEC;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, "%s", *p);
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, "%s", *p);
|
||||||
|
|
||||||
@@ -98,45 +217,51 @@ sudo_interposer_init(void)
|
|||||||
if (errstr != NULL) {
|
if (errstr != NULL) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
"invalid SUDO_INTERCEPT_FD: %s: %s", fdstr, errstr);
|
"invalid SUDO_INTERCEPT_FD: %s: %s", fdstr, errstr);
|
||||||
debug_return;
|
goto done;
|
||||||
}
|
|
||||||
|
|
||||||
/* Request secret from parent. */
|
|
||||||
if (send(fd, &ch, sizeof(ch), 0) != sizeof(ch)) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
|
||||||
"unable to request secret on fd %d: %s", fd,
|
|
||||||
strerror(errno));
|
|
||||||
debug_return;
|
|
||||||
}
|
|
||||||
if (recv(fd, &secret, sizeof(secret), 0) != sizeof(secret)) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
|
||||||
"unable to read secret on fd %d: %s", fd,
|
|
||||||
strerror(errno));
|
|
||||||
debug_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
intercept_sock = fd;
|
|
||||||
debug_return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (fd == -1) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
"SUDO_INTERCEPT_FD not found in environment");
|
"SUDO_INTERCEPT_FD not found in environment");
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send ClientHello message to over the fd.
|
||||||
|
*/
|
||||||
|
if (!send_client_hello(fd))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
res = recv_intercept_response(fd);
|
||||||
|
if (res != NULL) {
|
||||||
|
secret = res->u.hello_resp->secret;
|
||||||
|
intercept_port = res->u.hello_resp->portno;
|
||||||
|
intercept_response__free_unpacked(res, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
|
|
||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *
|
static bool
|
||||||
fmt_policy_check_req(const char *cmnd, char * const argv[], char * const envp[],
|
send_policy_check_req(int sock, const char *cmnd, char * const argv[],
|
||||||
size_t *buflen)
|
char * const envp[])
|
||||||
{
|
{
|
||||||
InterceptMessage msg = INTERCEPT_MESSAGE__INIT;
|
InterceptRequest msg = INTERCEPT_REQUEST__INIT;
|
||||||
PolicyCheckRequest req = POLICY_CHECK_REQUEST__INIT;
|
PolicyCheckRequest req = POLICY_CHECK_REQUEST__INIT;
|
||||||
uint8_t *buf = NULL;
|
uint8_t *buf = NULL;
|
||||||
|
bool ret = false;
|
||||||
uint32_t msg_len;
|
uint32_t msg_len;
|
||||||
size_t len;
|
size_t len;
|
||||||
debug_decl(sudo_interposer_init, SUDO_DEBUG_EXEC);
|
debug_decl(fmt_policy_check_req, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
/* Setup policy check request. */
|
/* Setup policy check request. */
|
||||||
|
req.secret = secret;
|
||||||
|
req.intercept_fd = sock;
|
||||||
req.command = (char *)cmnd;
|
req.command = (char *)cmnd;
|
||||||
req.argv = (char **)argv;
|
req.argv = (char **)argv;
|
||||||
for (len = 0; argv[len] != NULL; len++)
|
for (len = 0; argv[len] != NULL; len++)
|
||||||
@@ -146,13 +271,13 @@ fmt_policy_check_req(const char *cmnd, char * const argv[], char * const envp[],
|
|||||||
for (len = 0; envp[len] != NULL; len++)
|
for (len = 0; envp[len] != NULL; len++)
|
||||||
continue;
|
continue;
|
||||||
req.n_envp = len;
|
req.n_envp = len;
|
||||||
msg.type_case = INTERCEPT_MESSAGE__TYPE_POLICY_CHECK_REQ;
|
msg.type_case = INTERCEPT_REQUEST__TYPE_POLICY_CHECK_REQ;
|
||||||
msg.u.policy_check_req = &req;
|
msg.u.policy_check_req = &req;
|
||||||
|
|
||||||
len = intercept_message__get_packed_size(&msg);
|
len = intercept_request__get_packed_size(&msg);
|
||||||
if (len > MESSAGE_SIZE_MAX) {
|
if (len > MESSAGE_SIZE_MAX) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
"InterceptMessage too large: %zu", len);
|
"InterceptRequest too large: %zu", len);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Wire message size is used for length encoding, precedes message. */
|
/* Wire message size is used for length encoding, precedes message. */
|
||||||
@@ -164,78 +289,62 @@ fmt_policy_check_req(const char *cmnd, char * const argv[], char * const envp[],
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memcpy(buf, &msg_len, sizeof(msg_len));
|
memcpy(buf, &msg_len, sizeof(msg_len));
|
||||||
intercept_message__pack(&msg, buf + sizeof(msg_len));
|
intercept_request__pack(&msg, buf + sizeof(msg_len));
|
||||||
*buflen = len;
|
|
||||||
|
ret = send_req(sock, buf, len);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
debug_return_ptr(buf);
|
free(buf);
|
||||||
|
debug_return_bool(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send fd over a unix domain socket. */
|
|
||||||
static bool
|
|
||||||
intercept_send_fd(int sock, int fd)
|
|
||||||
{
|
|
||||||
struct msghdr msg;
|
|
||||||
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && HAVE_STRUCT_MSGHDR_MSG_CONTROL == 1
|
|
||||||
union {
|
|
||||||
struct cmsghdr hdr;
|
|
||||||
char buf[CMSG_SPACE(sizeof(int))];
|
|
||||||
} cmsgbuf;
|
|
||||||
struct cmsghdr *cmsg;
|
|
||||||
#endif
|
|
||||||
struct iovec iov[1];
|
|
||||||
char ch = '\0';
|
|
||||||
ssize_t nsent;
|
|
||||||
debug_decl(intercept_send_fd, SUDO_DEBUG_EXEC);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We send a single byte of data along with the fd; some systems
|
* Connect back to sudo process at localhost:intercept_port
|
||||||
* don't support sending file descriptors without data.
|
|
||||||
* Note that the intercept fd is *blocking*.
|
|
||||||
*/
|
*/
|
||||||
iov[0].iov_base = &ch;
|
static int
|
||||||
iov[0].iov_len = 1;
|
intercept_connect(void)
|
||||||
memset(&msg, 0, sizeof(msg));
|
{
|
||||||
msg.msg_iov = iov;
|
int sock = -1;
|
||||||
msg.msg_iovlen = 1;
|
struct sockaddr_in sin;
|
||||||
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && HAVE_STRUCT_MSGHDR_MSG_CONTROL == 1
|
debug_decl(command_allowed, SUDO_DEBUG_EXEC);
|
||||||
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
|
||||||
msg.msg_control = &cmsgbuf.buf;
|
|
||||||
msg.msg_controllen = sizeof(cmsgbuf.buf);
|
|
||||||
cmsg = CMSG_FIRSTHDR(&msg);
|
|
||||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
|
||||||
cmsg->cmsg_level = SOL_SOCKET;
|
|
||||||
cmsg->cmsg_type = SCM_RIGHTS;
|
|
||||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
|
||||||
#else
|
|
||||||
msg.msg_accrights = (caddr_t)&fd;
|
|
||||||
msg.msg_accrightslen = sizeof(fd);
|
|
||||||
#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
|
|
||||||
|
|
||||||
for (;;) {
|
if (intercept_port == 0) {
|
||||||
nsent = sendmsg(sock, &msg, 0);
|
sudo_warnx(U_("intercept port not set"));
|
||||||
if (nsent != -1)
|
goto done;
|
||||||
debug_return_bool(true);
|
|
||||||
if (errno != EAGAIN && errno != EINTR)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
sudo_warn("sendmsg(%d)", sock);
|
|
||||||
debug_return_bool(false);
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
sin.sin_port = htons(intercept_port);
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock == -1) {
|
||||||
|
sudo_warn("socket");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
|
||||||
|
sudo_warn("connect");
|
||||||
|
close(sock);
|
||||||
|
sock = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
debug_return_int(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
command_allowed(const char *cmnd, char * const argv[], char * const envp[],
|
command_allowed(const char *cmnd, char * const argv[],
|
||||||
char **ncmndp, char ***nargvp, char ***nenvpp)
|
char * const envp[], char **ncmndp, char ***nargvp, char ***nenvpp)
|
||||||
{
|
{
|
||||||
char *ncmnd = NULL, **nargv = NULL, **nenvp = NULL;
|
char *ncmnd = NULL, **nargv = NULL, **nenvp = NULL;
|
||||||
PolicyCheckResult *res = NULL;
|
InterceptResponse *res = NULL;
|
||||||
int sv[2] = { -1, -1 };
|
|
||||||
ssize_t nread, nwritten;
|
|
||||||
uint8_t *cp, *buf = NULL;
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
uint32_t res_len;
|
size_t idx, len = 0;
|
||||||
size_t idx, len;
|
int sock;
|
||||||
debug_decl(intercept_send_fd, SUDO_DEBUG_EXEC);
|
debug_decl(command_allowed, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
if (sudo_debug_needed(SUDO_DEBUG_INFO)) {
|
if (sudo_debug_needed(SUDO_DEBUG_INFO)) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
@@ -246,97 +355,19 @@ command_allowed(const char *cmnd, char * const argv[], char * const envp[],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intercept_sock < INTERCEPT_FD_MIN) {
|
sock = intercept_connect();
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
if (sock == -1)
|
||||||
"invalid intercept fd: %d", intercept_sock);
|
|
||||||
errno = EINVAL;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (fcntl(intercept_sock, F_GETFD, 0) == -1) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
|
||||||
"intercept fd %d not open", intercept_sock);
|
|
||||||
errno = EINVAL;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We communicate with the main sudo process over a socket pair
|
|
||||||
* which is passed over the intercept_sock. The reason for not
|
|
||||||
* using intercept_sock directly is that multiple processes
|
|
||||||
* could be trying to use it at once. Sending an fd like this
|
|
||||||
* is atomic but regular communication is not.
|
|
||||||
*/
|
|
||||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
|
|
||||||
sudo_warn("socketpair");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (!intercept_send_fd(intercept_sock, sv[1]))
|
|
||||||
goto done;
|
|
||||||
close(sv[1]);
|
|
||||||
sv[1] = -1;
|
|
||||||
|
|
||||||
buf = fmt_policy_check_req(cmnd, argv, envp, &len);
|
|
||||||
if (buf == NULL)
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Send request to sudo (blocking). */
|
if (!send_policy_check_req(sock, cmnd, argv, envp))
|
||||||
cp = buf;
|
|
||||||
do {
|
|
||||||
nwritten = write(sv[0], cp, len);
|
|
||||||
if (nwritten == -1) {
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
len -= nwritten;
|
|
||||||
cp += nwritten;
|
|
||||||
} while (len > 0);
|
|
||||||
free(buf);
|
|
||||||
buf = NULL;
|
|
||||||
|
|
||||||
/* Read message size (uint32_t in host byte order). */
|
res = recv_intercept_response(sock);
|
||||||
nread = read(sv[0], &res_len, sizeof(res_len));
|
if (res == NULL)
|
||||||
if ((size_t)nread != sizeof(res_len)) {
|
|
||||||
if (nread == 0) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
|
||||||
"unexpected EOF reading result size");
|
|
||||||
} else {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
|
||||||
"error reading result size");
|
|
||||||
}
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
if (res_len > MESSAGE_SIZE_MAX) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
|
||||||
"PolicyCheckResult too large: %zu", len);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read result from sudo (blocking). */
|
|
||||||
if ((buf = malloc(res_len)) == NULL) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
nread = read(sv[0], buf, res_len);
|
|
||||||
if ((size_t)nread != res_len) {
|
|
||||||
if (nread == 0) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
|
||||||
"unexpected EOF reading result");
|
|
||||||
} else {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
|
||||||
"error reading result");
|
|
||||||
}
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
res = policy_check_result__unpack(NULL, res_len, buf);
|
|
||||||
if (res == NULL) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
|
||||||
"unable to unpack %s size %u", "PolicyCheckResult", res_len);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (res->secret != secret) {
|
|
||||||
sudo_warnx("secret mismatch\r");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
switch (res->type_case) {
|
switch (res->type_case) {
|
||||||
case POLICY_CHECK_RESULT__TYPE_ACCEPT_MSG:
|
case INTERCEPT_RESPONSE__TYPE_ACCEPT_MSG:
|
||||||
if (sudo_debug_needed(SUDO_DEBUG_INFO)) {
|
if (sudo_debug_needed(SUDO_DEBUG_INFO)) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
"run_command: %s", res->u.accept_msg->run_command);
|
"run_command: %s", res->u.accept_msg->run_command);
|
||||||
@@ -360,7 +391,7 @@ command_allowed(const char *cmnd, char * const argv[], char * const envp[],
|
|||||||
nargv[len] = NULL;
|
nargv[len] = NULL;
|
||||||
// XXX - bogus cast
|
// XXX - bogus cast
|
||||||
nenvp = sudo_preload_dso((char **)envp, sudo_conf_intercept_path(),
|
nenvp = sudo_preload_dso((char **)envp, sudo_conf_intercept_path(),
|
||||||
intercept_sock);
|
sock);
|
||||||
if (nenvp == NULL)
|
if (nenvp == NULL)
|
||||||
goto oom;
|
goto oom;
|
||||||
*ncmndp = ncmnd;
|
*ncmndp = ncmnd;
|
||||||
@@ -368,11 +399,11 @@ command_allowed(const char *cmnd, char * const argv[], char * const envp[],
|
|||||||
*nenvpp = nenvp;
|
*nenvpp = nenvp;
|
||||||
ret = true;
|
ret = true;
|
||||||
goto done;
|
goto done;
|
||||||
case POLICY_CHECK_RESULT__TYPE_REJECT_MSG:
|
case INTERCEPT_RESPONSE__TYPE_REJECT_MSG:
|
||||||
/* Policy module displayed reject message but we are in raw mode. */
|
/* Policy module displayed reject message but we are in raw mode. */
|
||||||
fputc('\r', stderr);
|
fputc('\r', stderr);
|
||||||
goto done;
|
goto done;
|
||||||
case POLICY_CHECK_RESULT__TYPE_ERROR_MSG:
|
case INTERCEPT_RESPONSE__TYPE_ERROR_MSG:
|
||||||
/* Policy module may display error message but we are in raw mode. */
|
/* Policy module may display error message but we are in raw mode. */
|
||||||
fputc('\r', stderr);
|
fputc('\r', stderr);
|
||||||
sudo_warnx("%s", res->u.error_msg->error_message);
|
sudo_warnx("%s", res->u.error_msg->error_message);
|
||||||
@@ -380,7 +411,7 @@ command_allowed(const char *cmnd, char * const argv[], char * const envp[],
|
|||||||
default:
|
default:
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
"unexpected type_case value %d in %s from %s",
|
"unexpected type_case value %d in %s from %s",
|
||||||
res->type_case, "PolicyCheckResult", "sudo");
|
res->type_case, "InterceptResponse", "sudo");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,12 +421,10 @@ oom:
|
|||||||
free(nargv[--len]);
|
free(nargv[--len]);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
policy_check_result__free_unpacked(res, NULL);
|
/* Keep socket open for ctor when we execute the command. */
|
||||||
if (sv[0] != -1)
|
if (!ret && sock != -1)
|
||||||
close(sv[0]);
|
close(sock);
|
||||||
if (sv[1] != -1)
|
intercept_response__free_unpacked(res, NULL);
|
||||||
close(sv[1]);
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
debug_return_bool(ret);
|
debug_return_bool(ret);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user