Ticket #131: ssh_api.h

File ssh_api.h, 16.5 KB (added by remicress, 9 years ago)

SSH api (WPS-server side)

Line 
1/*
2 * ssh_api.h
3 *
4 *  Created on: 2 juil. 2015
5 *      Author: cresson
6 */
7
8#ifndef SSH_API_H_
9#define SSH_API_H_
10
11#include <libssh/libssh.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <errno.h>
15#include <string.h>
16#include <iostream>
17#include <sstream>
18
19// For remote files upload
20#include <fstream>      // std::ifstream
21#include <libssh/sftp.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24
25// Remote constants TODO: get them from cfg
26const std::string REMOTE_PROCESS_GET_STATUS = "/gpfs-dell/data/work/GEOSUD/drmaa/test/drmaa_operator/bin/get_status ";
27const std::string REMOTE_PROCESS_SUBMIT_COMMAND_ASYNC = "/gpfs-dell/data/work/GEOSUD/drmaa/test/drmaa_operator/bin/submit_command_async ";
28const std::string REMOTE_PROCESS_SUBMIT_COMMAND_SYNC = "/gpfs-dell/data/work/GEOSUD/drmaa/test/drmaa_operator/bin/submit_command_sync ";
29const std::string REMOTE_SCRATCH_DIRECTORY = "/gpfs-dell/scratch/cressonr/";
30const std::string REMOTE_SERVER_NAME = "<your server name here (frontal)>";
31const int REMOTE_SHELL_TIMEOUT_MS = 10000; // 10 sec
32
33// Good chunk size
34#define MAX_XFER_BUF_SIZE 16384
35
36/*
37 * Authenticating the server
38 */
39int verify_knownhost(ssh_session &session)
40{
41        int state, hlen;
42        unsigned char *hash = NULL;
43        char *hexa;
44        char buf[10];
45        state = ssh_is_server_known(session);
46        ssh_key srv_pubkey;
47        if (ssh_get_publickey(session, &srv_pubkey) < 0)
48        {
49                fprintf(stderr, "Public key not found:\n");
50                return SSH_ERROR;
51        }
52        switch (state)
53        {
54        case SSH_SERVER_KNOWN_OK:
55                break; /* ok */
56        case SSH_SERVER_KNOWN_CHANGED:
57                fprintf(stderr, "Host key for server changed: it is now:\n");
58                ssh_print_hexa("Public key hash", hash, hlen);
59                fprintf(stderr, "For security reasons, connection will be stopped\n");
60                free(hash);
61                return SSH_ERROR;
62        case SSH_SERVER_FOUND_OTHER:
63                fprintf(stderr, "The host key for this server was not found but an other"
64                                "type of key exists.\n");
65                fprintf(stderr, "An attacker might change the default server key to"
66                                "confuse your client into thinking the key does not exist\n");
67                free(hash);
68                return SSH_ERROR;
69        case SSH_SERVER_FILE_NOT_FOUND:
70                fprintf(stderr, "Could not find known host file.\n");
71                fprintf(stderr, "If you accept the host key here, the file will be"
72                                "automatically created.\n");
73                return SSH_ERROR;
74        case SSH_SERVER_NOT_KNOWN:
75                hexa = ssh_get_hexa(hash, hlen);
76                fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
77                fprintf(stderr, "Public key hash: %s\n", hexa);
78                free(hexa);
79                if (fgets(buf, sizeof(buf), stdin) == NULL)
80                {
81                        free(hash);
82                        return SSH_ERROR;
83                }
84                if (strncasecmp(buf, "yes", 3) != 0)
85                {
86                        free(hash);
87                        return SSH_ERROR;
88                }
89                if (ssh_write_knownhost(session) < 0)
90                {
91                        fprintf(stderr, "Error %s\n", strerror(errno));
92                        free(hash);
93                        return SSH_ERROR;
94                }
95                break;
96        case SSH_SERVER_ERROR:
97                fprintf(stderr, "Error %s\n", ssh_get_error(session));
98                free(hash);
99                return SSH_ERROR;
100        }
101        free(hash);
102        return SSH_OK;
103}
104
105/*
106 * Authenticate ourselves
107 */
108int authenticate_pubkey(ssh_session &session)
109{
110        int rc;
111        rc = ssh_userauth_publickey_auto(session, "cressonr", NULL);
112        if (rc == SSH_AUTH_ERROR)
113        {
114                fprintf(stderr, "Authentication failed: %s\n",
115                                ssh_get_error(session));
116                return SSH_ERROR;
117        }
118        return SSH_OK;
119}
120
121/*
122 * Show remote process output
123 */
124int show_remote_processes(ssh_session &session, const std::string &command, std::string &output)
125{
126        output.clear();
127        ssh_channel channel;
128        int rc;
129        char buffer[256];
130        unsigned int nbytes;
131        channel = ssh_channel_new(session);
132        fprintf(stderr, "Opening ssh session\n" );
133        if (channel == NULL)
134        {
135                fprintf(stderr, "ssh_channel_new(session) failed %s\n", ssh_get_error(session));
136                output = "ssh_channel_new(session) failed";
137                return SSH_ERROR;
138        }
139
140        rc = ssh_channel_open_session(channel);
141        if (rc != SSH_OK)
142        {
143                fprintf(stderr, "Error opening session\n");
144                output = "Error opening session";
145                ssh_channel_free(channel);
146                return SSH_ERROR;
147        }
148
149        rc = ssh_channel_request_pty(channel);
150        if (rc != SSH_OK)
151        {
152                fprintf(stderr, "Error requesting pty\n");
153                output = "Error requesting pty\n";
154                ssh_channel_close(channel);
155                ssh_channel_free(channel);
156
157                return rc;
158        }
159        rc = ssh_channel_change_pty_size(channel, 80, 24);
160        if (rc != SSH_OK)
161        {
162                fprintf(stderr, "Error changing pty size\n");
163                output = "Error changing pty size\n";
164                ssh_channel_close(channel);
165                ssh_channel_free(channel);
166
167                return rc;
168        }
169        rc = ssh_channel_request_shell(channel);
170        if (rc != SSH_OK)
171        {
172                fprintf(stderr, "Error requesting shell\n");
173                output = "Error requesting shell\n";
174                ssh_channel_close(channel);
175                ssh_channel_free(channel);
176
177                return rc;
178        }
179
180        // Send the command to shell
181        std::string tosend = command + " ; RETVAL=$? ; [ $RETVAL -eq 0 ] && echo Success ; [ $RETVAL -ne 0 ] && echo Failure ; exit\n";
182        char * tosendBuffer = (char*)tosend.c_str();
183        nbytes = tosend.size(); //read(0, tosendBuffer, sizeof(tosendBuffer));
184        fprintf(stderr, "Sending number of bytes:%d\n", nbytes);
185        int nwritten;
186        if (nbytes < 0) return SSH_ERROR;
187        if (nbytes > 0)
188        {
189                nwritten = ssh_channel_write(channel, tosendBuffer, nbytes);
190                if (nwritten != nbytes) return SSH_ERROR;
191        }
192
193        // Receive the shell output
194        while (ssh_channel_is_open(channel) &&
195                        !ssh_channel_is_eof(channel))
196        {
197                nbytes = ssh_channel_read_timeout(channel, buffer, sizeof(buffer), 0, REMOTE_SHELL_TIMEOUT_MS);
198                if (nbytes < 0)
199                {
200                        if (nbytes==SSH_AGAIN)
201                        {
202                                fprintf(stderr, "SSH Channel read error: Timeout");
203                                output += "SSH Channel read error: Timeout";
204                        }
205                        return SSH_ERROR;
206                }
207                else if (nbytes>0)
208                {
209                        write(2, buffer, nbytes);
210
211                        char subbuff[nbytes+1];
212                        memcpy( subbuff, &buffer[0], nbytes);
213                        subbuff[nbytes] = '\0';
214                        std::string tmpStr(subbuff);
215                        output += tmpStr;
216
217                }
218        }
219
220        if (nbytes < 0)
221        {
222                fprintf(stderr, "Error receiving command result\n");
223                output = "Error receiving command result";
224                ssh_channel_close(channel);
225                ssh_channel_free(channel);
226                return SSH_ERROR;
227        }
228        ssh_channel_send_eof(channel);
229        ssh_channel_close(channel);
230        ssh_channel_free(channel);
231        return SSH_OK;
232}
233
234/*
235 * Open an SSH session
236 */
237int open_ssh_session(const std::string &hostname, ssh_session &my_ssh_session)
238{
239        int rc;
240        char *password;
241
242        // Open session and set options
243        my_ssh_session = ssh_new();
244        if (my_ssh_session == NULL)
245        {
246                fprintf(stderr, "ssh_new() failed: %s\n",
247                                ssh_get_error(my_ssh_session));
248                return SSH_ERROR;
249        }
250        ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, hostname.c_str());
251
252        // Connect to server
253        rc = ssh_connect(my_ssh_session);
254        if (rc != SSH_OK)
255        {
256                fprintf(stderr, "Error connecting to host: %s\n",
257                                ssh_get_error(my_ssh_session));
258                ssh_free(my_ssh_session);
259                return rc;
260        }
261
262        // Verify the server's identity
263        // For the source code of verify_knowhost(), check previous example
264        if (verify_knownhost(my_ssh_session) < 0)
265        {
266                fprintf(stderr, "Error verifying the server's identity: %s\n",
267                                ssh_get_error(my_ssh_session));
268                ssh_disconnect(my_ssh_session);
269                ssh_free(my_ssh_session);
270                return SSH_ERROR;
271        }
272
273        // Authenticate ourselves
274        rc = authenticate_pubkey(my_ssh_session);
275        if (rc != SSH_OK)
276        {
277                fprintf(stderr, "Error authenticating ourselves: %s\n",
278                                ssh_get_error(my_ssh_session));
279                ssh_free(my_ssh_session);
280        }
281        return rc;
282}
283
284
285/*
286 * Output the result of the given input command
287 */
288int get_command_output(const std::string &command, std::string &output)
289{
290        // Create a ssh session
291        ssh_session my_ssh_session;
292        fprintf(stderr,"Creating ssh session\n");
293        int rc = open_ssh_session(REMOTE_SERVER_NAME, my_ssh_session);
294        if (rc != SSH_OK)
295        {
296                fprintf(stderr, "Error creating ssh session %s \n",
297                                ssh_get_error(my_ssh_session));
298                output = "Error opening ssh session";
299                return SSH_ERROR;
300        }
301
302        // Execute remote process
303        fprintf(stderr,"Executing remote process\n");
304        rc = show_remote_processes(my_ssh_session, command, output);
305        if (rc != SSH_OK)
306        {
307                fprintf(stderr, "Error showing remote process %s : %s\n",
308                                command.c_str(),
309                                ssh_get_error(my_ssh_session));
310                output = "Error showing remote process";
311        }
312
313        // Disconnect session
314        ssh_disconnect(my_ssh_session);
315        ssh_free(my_ssh_session);
316
317        return rc;
318}
319
320/*
321 * Get the status of a job
322 */
323int get_status(int job_id, std::string &output)
324{
325        std::string command (REMOTE_PROCESS_GET_STATUS);
326        command += static_cast<std::ostringstream*>( &(std::ostringstream() << job_id) )->str();
327
328        return get_command_output(command, output);
329}
330
331/*
332 * Submit a command, asynchronous way (and returns its ID)
333 */
334int submit_command_async(const std::string &input_command, std::string &output)
335{
336        std::string command(REMOTE_PROCESS_SUBMIT_COMMAND_ASYNC);
337        command += input_command;
338
339        return get_command_output(command, output);
340}
341
342/*
343 * Submit a job, synchronous way (and returns its status)
344 */
345int submit_command_sync(const std::string &input_command, std::string &output)
346{
347
348        std::string command(REMOTE_PROCESS_SUBMIT_COMMAND_SYNC);
349        command += input_command;
350
351        return get_command_output(command, output);
352}
353
354/*
355 * sftp: upload a file
356 */
357int sftp_uploadfile(ssh_session &session, sftp_session &sftp)
358{
359        int access_type = O_WRONLY | O_CREAT | O_TRUNC;
360        sftp_file file;
361        const char *helloworld = "Hello, World!\n";
362        int length = strlen(helloworld);
363        int rc, nwritten;
364        //...
365        file = sftp_open(sftp, "helloworld.txt",
366                        access_type, S_IRWXU);
367        if (file == NULL)
368        {
369                fprintf(stderr, "Can't open file for writing: %s\n",
370                                ssh_get_error(session));
371                return SSH_ERROR;
372        }
373        nwritten = sftp_write(file, helloworld, length);
374        if (nwritten != length)
375        {
376                fprintf(stderr, "Can't write data to file: %s\n",
377                                ssh_get_error(session));
378                sftp_close(file);
379                return SSH_ERROR;
380        }
381        rc = sftp_close(file);
382        if (rc != SSH_OK)
383        {
384                fprintf(stderr, "Can't close the written file: %s\n",
385                                ssh_get_error(session));
386                return rc;
387        }
388        return SSH_OK;
389}
390
391void display_sftp_error_message(sftp_session &sftp)
392{
393        int error = sftp_get_error(sftp);
394
395        switch (error) {
396        case SSH_FX_NO_SUCH_FILE:
397                fprintf(stderr, "No such file\n");
398                break;
399        case SSH_FX_PERMISSION_DENIED:
400                fprintf(stderr, "Permission denied\n");
401                break;
402        case SSH_FX_EOF:
403                fprintf(stderr, "EOF encountered\n");
404                break;
405        case SSH_FX_FAILURE:
406                fprintf(stderr, "Failure\n");
407                break;
408        case SSH_FX_BAD_MESSAGE:
409                fprintf(stderr, "Strange error message received\n");
410                break;
411        case SSH_FX_NO_CONNECTION:
412                fprintf(stderr, "No connection\n");
413                break;
414        case SSH_FX_CONNECTION_LOST:
415                fprintf(stderr, "Conection lost\n");
416                break;
417        case SSH_FX_OP_UNSUPPORTED:
418                fprintf(stderr, "Operation not supported\n");
419                break;
420        case SSH_FX_INVALID_HANDLE:
421                fprintf(stderr, "Invalid handle\n");
422                break;
423        case SSH_FX_NO_SUCH_PATH:
424                fprintf(stderr, "No such path\n");
425                break;
426        case SSH_FX_FILE_ALREADY_EXISTS:
427                fprintf(stderr, "Already exists\n");
428                break;
429        case SSH_FX_WRITE_PROTECT:
430                fprintf(stderr, "Write protected\n");
431                break;
432        case SSH_FX_NO_MEDIA:
433                fprintf(stderr, "No media\n");
434                break;
435        }
436}
437
438/*
439 * sftp: mkdir
440 */
441int sftp_mkdir(ssh_session &session, sftp_session &sftp,
442                const std::string &directory)
443{
444        int rc;
445        rc = sftp_mkdir(sftp, directory.c_str(), S_IRWXU);
446        if (rc != SSH_OK)
447        {
448                display_sftp_error_message(sftp);
449        }
450        return rc;
451}
452
453/*
454 * init. a sftp session
455 */
456int initialize_sftp_session(ssh_session &session, sftp_session &sftp)
457{
458        // Connect to server
459        fprintf(stderr,"Open ssh session\n");
460        int rc = open_ssh_session(REMOTE_SERVER_NAME, session);
461        if (rc != SSH_OK)
462        {
463                fprintf(stderr, "open_ssh_session failed: %s\n",
464                                ssh_get_error(session));
465                return SSH_ERROR;
466        }
467
468        // init. sftp session
469        fprintf(stderr,"Init. sftp session\n");
470        sftp = sftp_new(session);
471        if (sftp == NULL)
472        {
473                fprintf(stderr, "sftp_new(session) failed: %s\n",
474                                ssh_get_error(session));
475                return SSH_ERROR;
476        }
477        rc = sftp_init(sftp);
478        if (rc != SSH_OK)
479        {
480                fprintf(stderr, "Error initializing SFTP session: %s\n",
481                                sftp_get_error(sftp));
482        }
483        return rc;
484}
485
486/*
487 * create a directory on the host
488 */
489int create_remote_dir(const std::string &directory_name)
490{
491        std::string dir = directory_name;
492        fprintf(stderr,"Creating directory: %s\n", dir.c_str() );
493
494        int rc;
495
496        // init. session
497        ssh_session session;
498        sftp_session sftp;
499        rc = initialize_sftp_session(session, sftp);
500        if (rc != SSH_OK)
501        {
502                return rc;
503        }
504
505        // create a directory
506        rc = sftp_mkdir(session, sftp, dir.c_str());
507        if (rc == SSH_OK)
508        {
509                fprintf(stderr,"Directory successfuly created\n");
510        }
511
512        // close sftp connection
513        sftp_free(sftp);
514
515        // Disconnect session
516        ssh_disconnect(session);
517        ssh_free(session);
518
519        return SSH_OK;
520}
521
522/*
523 * download a file
524 */
525int sftp_download_file(ssh_session &session, sftp_session &sftp,
526                const std::string &local_filename, const std::string &remote_filename)
527{
528        std::string true_remote_filename = remote_filename;
529        fprintf(stderr,"Creating local file: %s\n", local_filename.c_str() );
530
531        int access_type;
532        sftp_file file;
533        char buffer[MAX_XFER_BUF_SIZE];
534        int nbytes, nwritten, rc;
535        int fd;
536        access_type = O_RDONLY;
537        file = sftp_open(sftp, true_remote_filename.c_str(),
538                        access_type, 0);
539        if (file == NULL) {
540                fprintf(stderr, "Can't open file for reading: %s\n",
541                                ssh_get_error(session));
542                return SSH_ERROR;
543        }
544        mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
545        //      fd = open(local_filename.c_str(), O_RDWR|O_CREAT);
546        fd = open(local_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode);
547        if (fd < 0) {
548                fprintf(stderr, "Can't open file for writing: %s\n",
549                                strerror(errno));
550                return SSH_ERROR;
551        }
552        for (;;) {
553                nbytes = sftp_read(file, buffer, sizeof(buffer));
554                if (nbytes == 0) {
555                        break; // EOF
556                } else if (nbytes < 0) {
557                        fprintf(stderr, "Error while reading file: %s\n",
558                                        ssh_get_error(session));
559                        sftp_close(file);
560                        close(fd);
561                        return SSH_ERROR;
562                }
563                nwritten = write(fd, buffer, nbytes);
564                if (nwritten != nbytes) {
565                        fprintf(stderr, "Error writing: %s\n",
566                                        strerror(errno));
567                        sftp_close(file);
568                        close(fd);
569                        return SSH_ERROR;
570                }
571        }
572        rc = sftp_close(file);
573        if (rc != SSH_OK) {
574                fprintf(stderr, "Can't close the read file: %s\n",
575                                ssh_get_error(session));
576        }
577        close(fd);
578        return rc;
579}
580
581/*
582 * upload a file
583 */
584int sftp_upload_file(ssh_session &session, sftp_session &sftp,
585                const std::string &local_filename, const std::string &remote_filename)
586{
587        std::string true_remote_filename = remote_filename;
588        fprintf(stderr, "Creating remote file: %s\n", true_remote_filename.c_str() );
589
590        int access_type;
591        sftp_file file;
592        char buffer[MAX_XFER_BUF_SIZE];
593        int nbytes, nwritten, rc;
594        int fd;
595        //      access_type = O_WRONLY;
596        access_type = O_WRONLY | O_CREAT | O_TRUNC;
597        file = sftp_open(sftp, true_remote_filename.c_str(),
598                        access_type, S_IRWXU /* 0 */);
599        if (file == NULL) {
600                fprintf(stderr, "Can't open file for writing: %s\n",
601                                ssh_get_error(session));
602                return SSH_ERROR;
603        }
604
605        fd = open(local_filename.c_str(), O_RDONLY);
606        if (fd < 0) {
607                fprintf(stderr, "Can't open file for reading: %s\n",
608                                strerror(errno));
609                return SSH_ERROR;
610        }
611
612        for (;;) {
613                nbytes = read(fd, buffer, sizeof(buffer));
614                if (nbytes == 0) {
615                        break; // EOF
616                } else if (nbytes < 0) {
617                        fprintf(stderr, "Error while reading file: %s\n",
618                                        ssh_get_error(session));
619                        sftp_close(file);
620                        return SSH_ERROR;
621                }
622                nwritten = sftp_write(file, buffer, nbytes);
623                if (nwritten != nbytes) {
624                        fprintf(stderr, "Error writing: %s\n",
625                                        strerror(errno));
626                        sftp_close(file);
627                        return SSH_ERROR;
628                }
629        }
630        rc = sftp_close(file);
631        if (rc != SSH_OK) {
632                fprintf(stderr, "Can't close the write file: %s\n",
633                                ssh_get_error(session));
634                rc = SSH_ERROR;
635        }
636        return rc;
637}
638
639/*
640 * Upload a file to the remote host
641 */
642int upload_file(const std::string &local_filename, const std::string &remote_filename)
643{
644
645        fprintf(stderr, "Upload file %s (local) to %s (remote)\n", local_filename.c_str(), remote_filename.c_str() );
646
647        int rc;
648
649        // init. session
650        ssh_session session;
651        sftp_session sftp;
652        rc = initialize_sftp_session(session, sftp);
653        if (rc != SSH_OK)
654        {
655                return rc;
656        }
657
658        // transfert file
659        rc = sftp_upload_file(session, sftp, local_filename, remote_filename);
660        if (rc == SSH_OK)
661        {
662                fprintf(stderr,"Remote file successfuly uploaded\n");
663        }
664
665        // close sftp connection
666        sftp_free(sftp);
667
668        // Disconnect session
669        ssh_disconnect(session);
670        ssh_free(session);
671
672        return rc;
673}
674
675/*
676 * Download a file to the remote host
677 */
678int download_file(const std::string &local_filename, const std::string &remote_filename)
679{
680
681        fprintf(stderr,"Download file %s (remote) to %s (local)\n", remote_filename.c_str(), local_filename.c_str() );
682
683        int rc;
684
685        // init. session
686        ssh_session session;
687        sftp_session sftp;
688        rc = initialize_sftp_session(session, sftp);
689        if (rc != SSH_OK)
690        {
691                return rc;
692        }
693
694        // transfert file
695        rc = sftp_download_file(session, sftp, local_filename, remote_filename);
696        if (rc == SSH_OK)
697        {
698                fprintf(stderr,"Remote file successfuly downloaded\n");
699        }
700
701        // close sftp connection
702        sftp_free(sftp);
703
704        // Disconnect session
705        ssh_disconnect(session);
706        ssh_free(session);
707
708        return rc;
709}
710
711
712#endif /* SSH_API_H_ */

Search

Context Navigation

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png