libssh2

Форк
0
/
ssh2_echo.c 
380 строк · 10.7 Кб
1
/* Copyright (C) The libssh2 project and its contributors.
2
 *
3
 * The code sends a 'cat' command, and then writes a lot of data to it only to
4
 * check that reading the returned data sums up to the same amount.
5
 *
6
 * $ ./ssh2_echo 127.0.0.1 user password
7
 *
8
 * SPDX-License-Identifier: BSD-3-Clause
9
 */
10

11
#include "libssh2_setup.h"
12
#include <libssh2.h>
13

14
#ifdef HAVE_SYS_SOCKET_H
15
#include <sys/socket.h>
16
#endif
17
#ifdef HAVE_UNISTD_H
18
#include <unistd.h>
19
#endif
20
#ifdef HAVE_NETINET_IN_H
21
#include <netinet/in.h>
22
#endif
23
#ifdef HAVE_ARPA_INET_H
24
#include <arpa/inet.h>
25
#endif
26

27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30

31
static const char *hostname = "127.0.0.1";
32
static const char *commandline = "cat";
33
static const char *username = "user";
34
static const char *password = "password";
35

36
static int waitsocket(libssh2_socket_t socket_fd, LIBSSH2_SESSION *session)
37
{
38
    struct timeval timeout;
39
    int rc;
40
    fd_set fd;
41
    fd_set *writefd = NULL;
42
    fd_set *readfd = NULL;
43
    int dir;
44

45
    timeout.tv_sec = 10;
46
    timeout.tv_usec = 0;
47

48
    FD_ZERO(&fd);
49

50
#if defined(__GNUC__)
51
#pragma GCC diagnostic push
52
#pragma GCC diagnostic ignored "-Wsign-conversion"
53
#endif
54
    FD_SET(socket_fd, &fd);
55
#if defined(__GNUC__)
56
#pragma GCC diagnostic pop
57
#endif
58

59
    /* now make sure we wait in the correct direction */
60
    dir = libssh2_session_block_directions(session);
61

62
    if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
63
        readfd = &fd;
64

65
    if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
66
        writefd = &fd;
67

68
    rc = select((int)(socket_fd + 1), readfd, writefd, NULL, &timeout);
69

70
    return rc;
71
}
72

73
#define BUFSIZE 32000
74

75
int main(int argc, char *argv[])
76
{
77
    uint32_t hostaddr;
78
    libssh2_socket_t sock;
79
    struct sockaddr_in sin;
80
    const char *fingerprint;
81
    int rc;
82
    LIBSSH2_SESSION *session = NULL;
83
    LIBSSH2_CHANNEL *channel;
84
    int exitcode = 0;
85
    char *exitsignal = (char *)"none";
86
    size_t len;
87
    LIBSSH2_KNOWNHOSTS *nh;
88
    int type;
89

90
#ifdef _WIN32
91
    WSADATA wsadata;
92

93
    rc = WSAStartup(MAKEWORD(2, 0), &wsadata);
94
    if(rc) {
95
        fprintf(stderr, "WSAStartup failed with error: %d\n", rc);
96
        return 1;
97
    }
98
#endif
99

100
    if(argc > 1) {
101
        hostname = argv[1];  /* must be ip address only */
102
    }
103
    if(argc > 2) {
104
        username = argv[2];
105
    }
106
    if(argc > 3) {
107
        password = argv[3];
108
    }
109

110
    rc = libssh2_init(0);
111
    if(rc) {
112
        fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
113
        return 1;
114
    }
115

116
    hostaddr = inet_addr(hostname);
117

118
    /* Ultra basic "connect to port 22 on localhost".  Your code is
119
     * responsible for creating the socket establishing the connection
120
     */
121
    sock = socket(AF_INET, SOCK_STREAM, 0);
122
    if(sock == LIBSSH2_INVALID_SOCKET) {
123
        fprintf(stderr, "failed to create socket.\n");
124
        goto shutdown;
125
    }
126

127
    sin.sin_family = AF_INET;
128
    sin.sin_port = htons(22);
129
    sin.sin_addr.s_addr = hostaddr;
130
    if(connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in))) {
131
        fprintf(stderr, "failed to connect.\n");
132
        goto shutdown;
133
    }
134

135
    /* Create a session instance */
136
    session = libssh2_session_init();
137
    if(!session) {
138
        fprintf(stderr, "Could not initialize SSH session.\n");
139
        goto shutdown;
140
    }
141

142
    /* tell libssh2 we want it all done non-blocking */
143
    libssh2_session_set_blocking(session, 0);
144

145
    /* ... start it up. This will trade welcome banners, exchange keys,
146
     * and setup crypto, compression, and MAC layers
147
     */
148
    while((rc = libssh2_session_handshake(session, sock)) ==
149
          LIBSSH2_ERROR_EAGAIN);
150
    if(rc) {
151
        fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
152
        goto shutdown;
153
    }
154

155
    nh = libssh2_knownhost_init(session);
156
    if(!nh) {
157
        /* eeek, do cleanup here */
158
        return 2;
159
    }
160

161
    /* read all hosts from here */
162
    libssh2_knownhost_readfile(nh, "known_hosts",
163
                               LIBSSH2_KNOWNHOST_FILE_OPENSSH);
164

165
    /* store all known hosts to here */
166
    libssh2_knownhost_writefile(nh, "dumpfile",
167
                                LIBSSH2_KNOWNHOST_FILE_OPENSSH);
168

169
    fingerprint = libssh2_session_hostkey(session, &len, &type);
170
    if(fingerprint) {
171
        struct libssh2_knownhost *host;
172
        int check = libssh2_knownhost_checkp(nh, hostname, 22,
173
                                             fingerprint, len,
174
                                             LIBSSH2_KNOWNHOST_TYPE_PLAIN|
175
                                             LIBSSH2_KNOWNHOST_KEYENC_RAW,
176
                                             &host);
177

178
        fprintf(stderr, "Host check: %d, key: %s\n", check,
179
                (check <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) ?
180
                host->key : "<none>");
181

182
        /*****
183
         * At this point, we could verify that 'check' tells us the key is
184
         * fine or bail out.
185
         *****/
186
    }
187
    else {
188
        /* eeek, do cleanup here */
189
        return 3;
190
    }
191
    libssh2_knownhost_free(nh);
192

193
    if(strlen(password) != 0) {
194
        /* We could authenticate via password */
195
        while((rc = libssh2_userauth_password(session, username, password)) ==
196
              LIBSSH2_ERROR_EAGAIN);
197
        if(rc) {
198
            fprintf(stderr, "Authentication by password failed.\n");
199
            exit(1);
200
        }
201
    }
202

203
    libssh2_trace(session, LIBSSH2_TRACE_SOCKET);
204

205
    /* Exec non-blocking on the remote host */
206
    do {
207
        channel = libssh2_channel_open_session(session);
208
        if(channel ||
209
           libssh2_session_last_error(session, NULL, NULL, 0) !=
210
           LIBSSH2_ERROR_EAGAIN)
211
            break;
212
        waitsocket(sock, session);
213
    } while(1);
214
    if(!channel) {
215
        fprintf(stderr, "Error\n");
216
        exit(1);
217
    }
218
    while((rc = libssh2_channel_exec(channel, commandline)) ==
219
          LIBSSH2_ERROR_EAGAIN) {
220
        waitsocket(sock, session);
221
    }
222
    if(rc) {
223
        fprintf(stderr, "exec error\n");
224
        exit(1);
225
    }
226
    else {
227
        LIBSSH2_POLLFD *fds = NULL;
228
        int running = 1;
229
        size_t bufsize = BUFSIZE;
230
        char buffer[BUFSIZE];
231
        size_t totsize = 1500000;
232
        size_t totwritten = 0;
233
        size_t totread = 0;
234
        int rereads = 0;
235
        int rewrites = 0;
236
        int i;
237

238
        for(i = 0; i < BUFSIZE; i++)
239
            buffer[i] = 'A';
240

241
        fds = malloc(sizeof(LIBSSH2_POLLFD));
242
        if(!fds) {
243
            fprintf(stderr, "malloc failed\n");
244
            exit(1);
245
        }
246

247
        fds[0].type = LIBSSH2_POLLFD_CHANNEL;
248
        fds[0].fd.channel = channel;
249
        fds[0].events = LIBSSH2_POLLFD_POLLIN | LIBSSH2_POLLFD_POLLOUT;
250

251
        do {
252
            int act = 0;
253
            rc = libssh2_poll(fds, 1, 10);
254

255
            if(rc < 1)
256
                continue;
257

258
            if(fds[0].revents & LIBSSH2_POLLFD_POLLIN) {
259
                ssize_t n = libssh2_channel_read(channel,
260
                                                 buffer, sizeof(buffer));
261
                act++;
262

263
                if(n == LIBSSH2_ERROR_EAGAIN) {
264
                    rereads++;
265
                    fprintf(stderr, "will read again\n");
266
                }
267
                else if(n < 0) {
268
                    fprintf(stderr, "read failed\n");
269
                    exit(1);
270
                }
271
                else {
272
                    totread += (size_t)n;
273
                    fprintf(stderr, "read %ld bytes (%lu in total)\n",
274
                            (long)n, (unsigned long)totread);
275
                }
276
            }
277

278
            if(fds[0].revents & LIBSSH2_POLLFD_POLLOUT) {
279
                act++;
280

281
                if(totwritten < totsize) {
282
                    /* we have not written all data yet */
283
                    size_t left = totsize - totwritten;
284
                    size_t size = (left < bufsize) ? left : bufsize;
285
                    ssize_t n = libssh2_channel_write_ex(channel, 0,
286
                                                         buffer, size);
287

288
                    if(n == LIBSSH2_ERROR_EAGAIN) {
289
                        rewrites++;
290
                        fprintf(stderr, "will write again\n");
291
                    }
292
                    else if(n < 0) {
293
                        fprintf(stderr, "write failed\n");
294
                        exit(1);
295
                    }
296
                    else {
297
                        totwritten += (size_t)n;
298
                        fprintf(stderr, "wrote %ld bytes (%lu in total)",
299
                                (long)n, (unsigned long)totwritten);
300
                        if(left >= bufsize && (size_t)n != bufsize) {
301
                            fprintf(stderr, " PARTIAL");
302
                        }
303
                        fprintf(stderr, "\n");
304
                    }
305
                }
306
                else {
307
                    /* all data written, send EOF */
308
                    rc = libssh2_channel_send_eof(channel);
309

310
                    if(rc == LIBSSH2_ERROR_EAGAIN) {
311
                        fprintf(stderr, "will send eof again\n");
312
                    }
313
                    else if(rc < 0) {
314
                        fprintf(stderr, "send eof failed\n");
315
                        exit(1);
316
                    }
317
                    else {
318
                        fprintf(stderr, "sent eof\n");
319
                        /* we're done writing, stop listening for OUT events */
320
                        fds[0].events &=
321
                            ~(unsigned long)LIBSSH2_POLLFD_POLLOUT;
322
                    }
323
                }
324
            }
325

326
            if(fds[0].revents & LIBSSH2_POLLFD_CHANNEL_CLOSED) {
327
                if(!act) /* don't leave loop until we have read all data */
328
                    running = 0;
329
            }
330
        } while(running);
331

332
        exitcode = 127;
333
        while((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN)
334
            waitsocket(sock, session);
335

336
        if(rc == 0) {
337
            exitcode = libssh2_channel_get_exit_status(channel);
338
            libssh2_channel_get_exit_signal(channel, &exitsignal,
339
                                            NULL, NULL, NULL, NULL, NULL);
340
        }
341

342
        if(exitsignal)
343
            fprintf(stderr, "\nGot signal: %s\n", exitsignal);
344

345
        libssh2_channel_free(channel);
346
        channel = NULL;
347

348
        fprintf(stderr, "\nrereads: %d rewrites: %d totwritten %lu\n",
349
                rereads, rewrites, (unsigned long)totwritten);
350

351
        if(totwritten != totread) {
352
            fprintf(stderr, "\n*** FAIL bytes written: "
353
                    "%lu bytes read: %lu ***\n",
354
                    (unsigned long)totwritten, (unsigned long)totread);
355
            exit(1);
356
        }
357
    }
358

359
shutdown:
360

361
    if(session) {
362
        libssh2_session_disconnect(session, "Normal Shutdown");
363
        libssh2_session_free(session);
364
    }
365

366
    if(sock != LIBSSH2_INVALID_SOCKET) {
367
        shutdown(sock, 2);
368
        LIBSSH2_SOCKET_CLOSE(sock);
369
    }
370

371
    fprintf(stderr, "all done\n");
372

373
    libssh2_exit();
374

375
#ifdef _WIN32
376
    WSACleanup();
377
#endif
378

379
    return exitcode;
380
}
381

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.