summaryrefslogtreecommitdiff
path: root/server/internal.h
blob: 1c36b0baf55a30288e77bba5f4839e830be38b08 (plain)
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
198
/*
 * 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
 *
 * See LICENSE for licensing terms.
 */

#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 */