1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
/*
* Internal support functions for the remctld daemon.
*
* Written by Russ Allbery <eagle@eyrie.org>
* Copyright 2015-2016, 2018 Russ Allbery <eagle@eyrie.org>
* Copyright 2016 Dropbox, Inc.
* Copyright 2006-2010, 2012, 2014
* The Board of Trustees of the Leland Stanford Junior University
*
* SPDX-License-Identifier: MIT
*/
#ifndef SERVER_INTERNAL_H
#define SERVER_INTERNAL_H 1
#include <config.h>
#include <portable/gssapi.h>
#include <portable/macros.h>
#include <portable/socket.h>
#include <portable/stdbool.h>
#include <sys/types.h>
#include <util/protocol.h>
/* Forward declarations to avoid extra includes. */
struct bufferevent;
struct evbuffer;
struct event;
struct event_base;
struct iovec;
struct process;
/*
* The maximum size of argc passed to the server (4K arguments), and the
* maximum size of a single command including all of its arguments (100MB).
* These are arbitrary limit to protect against memory-based denial of service
* attacks on the server.
*/
#define COMMAND_MAX_ARGS (4 * 1024)
#define COMMAND_MAX_DATA (100UL * 1024 * 1024)
/*
* The timeout. We won't wait for longer than this number of seconds for more
* data from the client. This needs to be configurable.
*/
#define TIMEOUT (60 * 60)
/*
* Normally set by the build system, but don't fail to compile if it's not
* defined since it makes the build rules for the test suite irritating.
*/
#ifndef PATH_SUDO
# define PATH_SUDO "sudo"
#endif
/* Holds the information about a client connection. */
struct client {
int fd; /* File descriptor of client connection. */
int stderr_fd; /* stderr file descriptor for remctl-shell. */
char *hostname; /* Hostname of client (if available). */
char *ipaddress; /* IP address of client as a string. */
int protocol; /* Protocol version number. */
gss_ctx_id_t context; /* GSS-API context. */
char *user; /* Name of the client as a string. */
bool anonymous; /* Whether the client is anonymous. */
OM_uint32 flags; /* Connection flags. */
time_t expires; /* Expiration time of GSS-API session. */
bool keepalive; /* Whether keep-alive was set. */
bool fatal; /* Whether a fatal error has occurred. */
/*
* Callbacks used by generic server code handle the separate protocols,
* set up when the client opens the connection.
*/
void (*setup)(struct process *);
bool (*finish)(struct client *, struct evbuffer *, int);
bool (*error)(struct client *, enum error_codes, const char *);
};
/* Holds the configuration for a single command. */
struct rule {
char *file; /* Config file name. */
size_t lineno; /* Config file line number. */
struct vector *line; /* The split configuration line. */
char *command; /* Command (first argument). */
char *subcommand; /* Subcommand (second argument). */
char *program; /* Full file name of executable. */
unsigned int *logmask; /* Zero-terminated list of args to mask. */
long stdin_arg; /* Arg to pass on stdin, -1 for last. */
char *user; /* Run executable as user. */
char *sudo_user; /* Run executable as user with sudo. */
uid_t uid; /* Run executable with this UID. */
gid_t gid; /* Run executable with this GID. */
char *summary; /* Argument that gives a command summary. */
char *help; /* Argument that gives help for a command. */
char **acls; /* Full file names of ACL files. */
};
/* Holds the complete parsed configuration for remctld. */
struct config {
struct rule **rules;
size_t count;
size_t allocated;
};
/*
* Holds details about a running process. The events we hook into the event
* loop are also stored here so that the event handlers can use this as their
* data and have their pointers so that they can remove themselves when
* needed.
*/
struct process {
struct client *client; /* Pointer to corresponding remctl client. */
/* Command input. */
const char *command; /* The remctl command run by the user. */
const char **argv; /* argv for running the command. */
struct rule *rule; /* Configuration rule for the command. */
struct evbuffer *input; /* Buffer of input to process. */
/* Command output. */
struct evbuffer *output; /* Buffer of output from process. */
int status; /* Exit status. */
/* Everything below this point is used internally by the process loop. */
/* Process data. */
socket_type stdinout_fd; /* File descriptor for input and output. */
socket_type stderr_fd; /* File descriptor for standard error. */
pid_t pid; /* Process ID of child. */
/* Event loop. */
struct event_base *loop; /* Event base for the process event loop. */
struct bufferevent *inout; /* Input and output from process. */
struct bufferevent *err; /* Standard error from process. */
struct event *sigchld; /* Handle the SIGCHLD signal for exit. */
/* State flags. */
bool reaped; /* Whether we've reaped the process. */
bool saw_error; /* Whether we encountered some error. */
bool saw_output; /* Whether we saw process output. */
};
BEGIN_DECLS
/* Logging functions. */
void warn_gssapi(const char *, OM_uint32 major, OM_uint32 minor);
void warn_token(const char *, int status, OM_uint32 major, OM_uint32 minor);
void server_log_command(struct iovec **, struct rule *, const char *user);
/* Configuration file functions. */
struct config *server_config_load(const char *file);
void server_config_free(struct config *);
bool server_config_acl_permit(const struct rule *, const struct client *);
void server_config_set_gput_file(char *file);
/* Running commands. */
int server_run_command(struct client *, struct config *, struct iovec **);
/* Freeing the command structure. */
void server_free_command(struct iovec **);
/* Running processes. */
bool server_process_run(struct process *process);
void server_handle_io_event(struct bufferevent *, short, void *);
void server_handle_input_end(struct bufferevent *, void *);
/* Generic GSS-API protocol functions. */
struct client *server_new_client(int fd, gss_cred_id_t creds);
void server_free_client(struct client *);
struct iovec **server_parse_command(struct client *, const char *, size_t);
/* Protocol v1 functions. */
void server_v1_command_setup(struct process *);
bool server_v1_send_output(struct client *, struct evbuffer *, int status);
bool server_v1_send_error(struct client *, enum error_codes, const char *);
void server_v1_handle_messages(struct client *, struct config *);
/* Protocol v2 functions. */
void server_v2_command_setup(struct process *);
bool server_v2_command_finish(struct client *, struct evbuffer *, int status);
bool server_v2_send_error(struct client *, enum error_codes, const char *);
void server_v2_handle_messages(struct client *, struct config *);
/* ssh protocol functions. */
struct client *server_ssh_new_client(const char *user);
void server_ssh_free_client(struct client *);
struct iovec **server_ssh_parse_command(const char *);
/* libevent utility functions. */
void server_event_log_callback(int, const char *);
void server_event_fatal_callback(int) __attribute__((__noreturn__));
END_DECLS
#endif /* !SERVER_INTERNAL_H */
|