aboutsummaryrefslogtreecommitdiff
path: root/bastion/proxy.c
blob: f608d315b54bd26cf4e82aea01589c65c8061a3d (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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#include <libssh/callbacks.h>
#include <stdio.h>
#include <stdlib.h>

#include "common/mysql.h"
#include "client.h"
#include "proxy.h"
#include "state.h"

// callback function for channel data and exceptions
static int proxy_data_function(ssh_session session, ssh_channel channel, void *data,
                         uint32_t len, int is_stderr, void *userdata) {
    struct proxy_channel_data_struct *pdata = (struct proxy_channel_data_struct *) userdata;
    (void) session;
    (void) channel;
    (void) is_stderr;

    if (ssh_channel_is_open(pdata->client_channel))
        return ssh_channel_write(pdata->client_channel, (char*) data, len);
    else
        return SSH_ERROR;
}

// callback function for SSH channel PTY request from a client
static int proxy_pty_request(ssh_session session, ssh_channel channel,
                const char *term, int cols, int rows, int py, int px,
                void *userdata) {
    struct proxy_channel_data_struct *pdata = (struct proxy_channel_data_struct *)userdata;

    (void) session;
    (void) channel;
    (void) py;
    (void) px;

    // TODO record pty size in recorder
    if (ssh_channel_is_open(pdata->client_channel)) {
        if (ssh_channel_request_pty_size(pdata->client_channel, term, cols, rows) == SSH_OK)
            return SSH_OK;
        else
            fprintf(stderr, "pty request failed\n");
    } else {
        fprintf(stderr, "pty request while client_channel not opened\n");
    }
    return SSH_ERROR;
}

// callback function for SSH channel PTY resize from a client
static int proxy_pty_resize(ssh_session session, ssh_channel channel, int cols,
               int rows, int py, int px, void *userdata) {
    struct proxy_channel_data_struct *pdata = (struct proxy_channel_data_struct *)userdata;

    (void) session;
    (void) channel;
    (void) py;
    (void) px;

    // TODO record pty size in recorder
    if (ssh_channel_is_open(pdata->client_channel)) {
        if (ssh_channel_change_pty_size(pdata->client_channel, cols, rows) == SSH_OK)
            return SSH_OK;
        else
            fprintf(stderr, "pty resize failed\n");
    } else {
        fprintf(stderr, "pty resize while client_channel not opened\n");
    }
    return SSH_ERROR;
}

static int proxy_exec_request(ssh_session session, ssh_channel channel,
                        const char *command, void *userdata) {
    struct proxy_channel_data_struct *pdata = (struct proxy_channel_data_struct *) userdata;

    (void) session;
    (void) channel;

    if (ssh_channel_is_open(pdata->client_channel)) {
        if (ssh_channel_request_exec(pdata->client_channel, command) == SSH_OK)
            return SSH_OK;
        else
            printf("exec request failed\n");
    } else {
        fprintf(stderr, "exec request while client_channel not opened\n");
    }
    return SSH_ERROR;
}

static int proxy_shell_request(ssh_session session, ssh_channel channel,
                         void *userdata) {
    struct proxy_channel_data_struct *pdata = (struct proxy_channel_data_struct *) userdata;

    (void) session;
    (void) channel;

    if (ssh_channel_is_open(pdata->client_channel)) {
        if (ssh_channel_request_shell(pdata->client_channel) == SSH_OK)
            return SSH_OK;
        else
            fprintf(stderr, "shell request failed\n");
    } else {
        fprintf(stderr, "shell request while client channel not opened\n");
    }
    return SSH_ERROR;
}

static int proxy_subsystem_request(ssh_session session, ssh_channel channel,
                             const char *subsystem, void *userdata) {
    (void) session;
    (void) channel;
    (void) subsystem;
    (void) userdata;
    return SSH_ERROR; // TODO ssh subsystem request
    //if (ssh_channel_is_open(pdata->client_channel)) {
    //}
}

static void proxy_channel_eof_callback (ssh_session session, ssh_channel channel, void *userdata)
{
    struct proxy_channel_data_struct *pdata = (struct proxy_channel_data_struct *) userdata;
    (void) session;
    (void) channel;
    if (ssh_channel_is_open(pdata->client_channel))
        ssh_channel_send_eof(pdata->client_channel);
}

static void proxy_channel_close_callback (ssh_session session, ssh_channel channel, void *userdata)
{
    struct proxy_channel_data_struct *pdata = (struct proxy_channel_data_struct *) userdata;
    (void) session;
    (void) channel;
    if (ssh_channel_is_open(pdata->client_channel))
        ssh_channel_close(pdata->client_channel);
}

static void proxy_channel_exit_status_callback (ssh_session session, ssh_channel channel, int exit_status, void *userdata)
{
    (void) session;
    (void) channel;
    (void) exit_status;
    (void) userdata;
    printf("proxy exit status callback\n");
}

static void proxy_channel_signal_callback (ssh_session session, ssh_channel channel,
                                    const char *signal, void *userdata) {
    (void) session;
    (void) channel;
    (void) signal;
    (void) userdata;
    printf("proxy signal callback\n");
}

static void proxy_channel_exit_signal_callback (ssh_session session, ssh_channel channel,
                                    const char *signal, int core, const char *errmsg,
                                    const char *lang, void *userdata) {
    (void) session;
    (void) channel;
    (void) signal;
    (void) core;
    (void) errmsg;
    (void) lang;
    (void) userdata;
    printf("proxy exit signal callback\n");
}

void handle_proxy_session(ssh_event event, ssh_session session, ssh_channel my_channel)
{
    struct client_channel_data_struct * cdata;

    struct proxy_channel_data_struct pdata = {
        .event = event,
        .my_session = session,
        .my_channel = my_channel,
        .client_channel = NULL,
    };

    cdata = client_dial(event, &pdata);

    if (cdata == NULL) {
        return;
    }
    pdata.client_channel = cdata->my_channel;

    /* We tie everything together */
    struct ssh_channel_callbacks_struct channel_cb = {
        .userdata = &pdata,
        .channel_data_function = proxy_data_function,
        .channel_eof_function = proxy_channel_eof_callback,
        .channel_close_function = proxy_channel_close_callback,
        .channel_signal_function = proxy_channel_signal_callback,
        .channel_exit_status_function = proxy_channel_exit_status_callback,
        .channel_exit_signal_function = proxy_channel_exit_signal_callback,
        .channel_pty_request_function = proxy_pty_request,
        .channel_shell_request_function = proxy_shell_request,
        .channel_pty_window_change_function = proxy_pty_resize,
        .channel_exec_request_function = proxy_exec_request,
        .channel_subsystem_request_function = proxy_subsystem_request,
        .channel_auth_agent_req_function = NULL,
        .channel_x11_req_function = NULL,
        .channel_env_request_function = NULL,
        .channel_write_wontblock_function = NULL,
    };
    ssh_callbacks_init(&channel_cb);
    ssh_set_channel_callbacks(my_channel, &channel_cb);

    db_clean(); // we close the mysql connection before the main loop, as to not waste ressources

    do {
        /* Poll the main event which takes care of the sessions and channels */
        if (ssh_event_dopoll(event, -1) == SSH_ERROR) {
            break;
        }
    } while(ssh_channel_is_open(my_channel) && ssh_channel_is_open(pdata.client_channel));
    if (ssh_channel_is_open(cdata->my_channel))
        ssh_channel_close(cdata->my_channel);
    if (ssh_channel_is_open(my_channel))
        ssh_channel_close(my_channel);

    client_cleanup(cdata);
}