~ubuntu-branches/ubuntu/trusty/libssh/trusty

« back to all changes in this revision

Viewing changes to sample.c

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Bigonville
  • Date: 2009-12-12 14:29:12 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20091212142912-ha5g2iibt6nfnjq8
Tags: 0.4.0-1
* New upstream release.
  - Bump soname
  - Adjust .symbols file
* Readd static library in -dev package
* Let dh_lintian install override file
* debian/README.Debian: Update file
* debian/rules: Add list-missing rule

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* client.c */
2
 
/*
3
 
Copyright 2003 Aris Adamantiadis
4
 
 
5
 
This file is part of the SSH Library
6
 
 
7
 
You are free to copy this file, modify it in any way, consider it being public
8
 
domain. This does not apply to the rest of the library though, but it is 
9
 
allowed to cut-and-paste working code from this file to any license of
10
 
program.
11
 
The goal is to show the API in action. It's not a reference on how terminal
12
 
clients must be made or how a client should react.
13
 
*/
14
 
 
15
 
#include "config.h"
16
 
#include <stdio.h>
17
 
#include <unistd.h>
18
 
#include <stdlib.h>
19
 
#include <string.h>
20
 
#include <termios.h>
21
 
 
22
 
#include <sys/select.h>
23
 
#include <sys/time.h>
24
 
#ifdef HAVE_PTY_H
25
 
#include <pty.h>
26
 
#endif
27
 
#include <sys/ioctl.h>
28
 
#include <signal.h>
29
 
#include <errno.h>
30
 
#include <libssh/libssh.h>
31
 
#include <libssh/sftp.h>
32
 
 
33
 
#include <fcntl.h>
34
 
 
35
 
#define MAXCMD 10
36
 
char *host;
37
 
char *user;
38
 
int sftp;
39
 
char *cmds[MAXCMD];
40
 
struct termios terminal;
41
 
void do_sftp(SSH_SESSION *session);
42
 
 
43
 
static void add_cmd(char *cmd){
44
 
    int n;
45
 
    for(n=0;cmds[n] && (n<MAXCMD);n++);
46
 
    if(n==MAXCMD)
47
 
        return;
48
 
    cmds[n]=strdup(cmd);
49
 
}
50
 
 
51
 
static void usage(){
52
 
    fprintf(stderr,"Usage : ssh [options] [login@]hostname\n"
53
 
    "sample client - libssh-%s\n"
54
 
    "Options :\n"
55
 
    "  -l user : log in as user\n"
56
 
    "  -p port : connect to port\n"
57
 
    "  -d : use DSS to verify host public key\n"
58
 
    "  -r : use RSA to verify host public key\n",
59
 
    ssh_version(0));
60
 
    exit(0);
61
 
}
62
 
 
63
 
static int opts(int argc, char **argv){
64
 
    int i;
65
 
    if(strstr(argv[0],"sftp"))
66
 
        sftp=1;
67
 
//    for(i=0;i<argc;i++)
68
 
//        printf("%d : %s\n",i,argv[i]);
69
 
    /* insert your own arguments here */
70
 
    while((i=getopt(argc,argv,""))!=-1){
71
 
        switch(i){
72
 
            default:
73
 
                fprintf(stderr,"unknown option %c\n",optopt);
74
 
                usage();
75
 
        }
76
 
    }
77
 
    if(optind < argc)
78
 
        host=argv[optind++];
79
 
    while(optind < argc)
80
 
        add_cmd(argv[optind++]);
81
 
    if(host==NULL)
82
 
        usage();
83
 
    return 0;
84
 
}
85
 
 
86
 
#ifndef HAVE_CFMAKERAW
87
 
static void cfmakeraw(struct termios *termios_p){
88
 
    termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
89
 
    termios_p->c_oflag &= ~OPOST;
90
 
    termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
91
 
    termios_p->c_cflag &= ~(CSIZE|PARENB);
92
 
    termios_p->c_cflag |= CS8;
93
 
}
94
 
#endif
95
 
 
96
 
 
97
 
static void do_cleanup(int i) {
98
 
  /* unused variable */
99
 
  (void) i;
100
 
 
101
 
  tcsetattr(0,TCSANOW,&terminal);
102
 
}
103
 
 
104
 
static void do_exit(int i) {
105
 
  /* unused variable */
106
 
  (void) i;
107
 
 
108
 
  do_cleanup(0);
109
 
  exit(0);
110
 
}
111
 
 
112
 
CHANNEL *chan;
113
 
int signal_delayed=0;
114
 
 
115
 
static void sigwindowchanged(int i){
116
 
  (void) i;
117
 
  signal_delayed=1;
118
 
}
119
 
 
120
 
static void setsignal(void){
121
 
    signal(SIGWINCH, sigwindowchanged);
122
 
    signal_delayed=0;
123
 
}
124
 
 
125
 
static void sizechanged(void){
126
 
    struct winsize win = { 0, 0, 0, 0 };
127
 
    ioctl(1, TIOCGWINSZ, &win);
128
 
    channel_change_pty_size(chan,win.ws_col, win.ws_row);
129
 
//    printf("Changed pty size\n");
130
 
    setsignal();
131
 
}
132
 
static void select_loop(SSH_SESSION *session,CHANNEL *channel){
133
 
    fd_set fds;
134
 
    struct timeval timeout;
135
 
    char buffer[10];
136
 
    BUFFER *readbuf=buffer_new();
137
 
    CHANNEL *channels[2];
138
 
    int lus;
139
 
    int eof=0;
140
 
    int maxfd;
141
 
    int ret;
142
 
    while(channel){
143
 
       /* when a signal is caught, ssh_select will return
144
 
         * with SSH_EINTR, which means it should be started 
145
 
         * again. It lets you handle the signal the faster you
146
 
         * can, like in this window changed example. Of course, if
147
 
         * your signal handler doesn't call libssh at all, you're
148
 
         * free to handle signals directly in sighandler.
149
 
         */
150
 
        do{
151
 
            FD_ZERO(&fds);
152
 
            if(!eof)
153
 
                FD_SET(0,&fds);
154
 
            timeout.tv_sec=30;
155
 
            timeout.tv_usec=0;
156
 
            FD_SET(ssh_get_fd(session),&fds);
157
 
            maxfd=ssh_get_fd(session)+1;
158
 
            ret=select(maxfd,&fds,NULL,NULL,&timeout);
159
 
            if(ret==EINTR)
160
 
                continue;
161
 
            if(FD_ISSET(0,&fds)){
162
 
                lus=read(0,buffer,10);
163
 
                if(lus)
164
 
                    channel_write(channel,buffer,lus);
165
 
                else {
166
 
                    eof=1;
167
 
                    channel_send_eof(channel);
168
 
                }
169
 
            }
170
 
            if(FD_ISSET(ssh_get_fd(session),&fds)){
171
 
                ssh_set_fd_toread(session);
172
 
            }
173
 
            channels[0]=channel; // set the first channel we want to read from
174
 
            channels[1]=NULL;
175
 
            ret=channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll
176
 
            if(signal_delayed)
177
 
                sizechanged();
178
 
        } while (ret==EINTR || ret==SSH_EINTR);
179
 
 
180
 
        // we already looked for input from stdin. Now, we are looking for input from the channel
181
 
        
182
 
        if(channel && channel_is_closed(channel)){
183
 
            ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
184
 
 
185
 
            channel_free(channel);
186
 
            channel=NULL;
187
 
            channels[0]=NULL;
188
 
        }
189
 
        if(channels[0]){
190
 
            while(channel && channel_is_open(channel) && channel_poll(channel,0)){
191
 
                lus=channel_read_buffer(channel,readbuf,0,0);
192
 
                if(lus==-1){
193
 
                    fprintf(stderr, "Error reading channel: %s\n",
194
 
                        ssh_get_error(session));
195
 
                    return;
196
 
                }
197
 
                if(lus==0){
198
 
                    ssh_log(session,SSH_LOG_RARE,"EOF received\n");
199
 
                    ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
200
 
 
201
 
                    channel_free(channel);
202
 
                    channel=channels[0]=NULL;
203
 
                } else
204
 
                    write(1,buffer_get(readbuf),lus);
205
 
            }
206
 
            while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
207
 
                lus=channel_read_buffer(channel,readbuf,0,1);
208
 
                if(lus==-1){
209
 
                    fprintf(stderr, "Error reading channel: %s\n",
210
 
                        ssh_get_error(session));
211
 
                    return;
212
 
                }
213
 
                if(lus==0){
214
 
                    ssh_log(session,SSH_LOG_RARE,"EOF received\n");
215
 
                    ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
216
 
                    channel_free(channel);
217
 
                    channel=channels[0]=NULL;
218
 
                } else
219
 
                    write(2,buffer_get(readbuf),lus);
220
 
            }
221
 
        }
222
 
        if(channel && channel_is_closed(channel)){
223
 
            channel_free(channel);
224
 
            channel=NULL;
225
 
        }
226
 
    }
227
 
    buffer_free(readbuf);
228
 
}
229
 
 
230
 
 
231
 
static void shell(SSH_SESSION *session){
232
 
    CHANNEL *channel;
233
 
    struct termios terminal_local;
234
 
    int interactive=isatty(0);
235
 
    channel = channel_new(session);
236
 
    if(interactive){
237
 
        tcgetattr(0,&terminal_local);
238
 
        memcpy(&terminal,&terminal_local,sizeof(struct termios));
239
 
    }
240
 
    if(channel_open_session(channel)){
241
 
        printf("error opening channel : %s\n",ssh_get_error(session));
242
 
        return;
243
 
    }
244
 
    chan=channel;
245
 
    if(interactive){
246
 
        channel_request_pty(channel);
247
 
        sizechanged();
248
 
    }
249
 
    if(channel_request_shell(channel)){
250
 
        printf("Requesting shell : %s\n",ssh_get_error(session));
251
 
        return;
252
 
    }
253
 
    if(interactive){
254
 
        cfmakeraw(&terminal_local);
255
 
        tcsetattr(0,TCSANOW,&terminal_local);
256
 
        setsignal();
257
 
    }
258
 
    signal(SIGTERM,do_cleanup);
259
 
    select_loop(session,channel);
260
 
}
261
 
 
262
 
static void batch_shell(SSH_SESSION *session){
263
 
    CHANNEL *channel;
264
 
    char buffer[1024];
265
 
    int i,s=0;
266
 
    for(i=0;i<MAXCMD && cmds[i];++i)
267
 
        s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
268
 
    channel=channel_new(session);
269
 
    channel_open_session(channel);
270
 
    if(channel_request_exec(channel,buffer)){
271
 
        printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
272
 
        return;
273
 
    }
274
 
    select_loop(session,channel);
275
 
}
276
 
 
277
 
#ifdef WITH_SFTP
278
 
/* it's just a proof of concept code for sftp, till i write a real documentation about it */
279
 
void do_sftp(SSH_SESSION *session){
280
 
    SFTP_SESSION *sftp_session=sftp_new(session);
281
 
    SFTP_DIR *dir;
282
 
    SFTP_ATTRIBUTES *file;
283
 
    SFTP_FILE *fichier;
284
 
    SFTP_FILE *to;
285
 
    int len=1;
286
 
    int i;
287
 
    char data[8000];
288
 
    if(!sftp_session){
289
 
        fprintf(stderr, "sftp error initialising channel: %s\n",
290
 
            ssh_get_error(session));
291
 
        return;
292
 
    }
293
 
    if(sftp_init(sftp_session)){
294
 
        fprintf(stderr, "error initialising sftp: %s\n",
295
 
            ssh_get_error(session));
296
 
        return;
297
 
    }
298
 
    /* the connection is made */
299
 
    /* opening a directory */
300
 
    dir=sftp_opendir(sftp_session,"./");
301
 
    if(!dir) {
302
 
        fprintf(stderr, "Directory not opened(%s)\n", ssh_get_error(session));
303
 
        return ;
304
 
    }
305
 
    /* reading the whole directory, file by file */
306
 
    while((file=sftp_readdir(sftp_session,dir))){
307
 
        fprintf(stderr, "%30s(%.8o) : %.5d.%.5d : %.10llu bytes\n",
308
 
            file->name,
309
 
            file->permissions,
310
 
            file->uid,
311
 
            file->gid,
312
 
            (long long unsigned int) file->size);
313
 
        sftp_attributes_free(file);
314
 
    }
315
 
    /* when file=NULL, an error has occured OR the directory listing is end of file */
316
 
    if(!sftp_dir_eof(dir)){
317
 
        fprintf(stderr, "Error: %s\n", ssh_get_error(session));
318
 
        return;
319
 
    }
320
 
    if(sftp_closedir(dir)){
321
 
        fprintf(stderr, "Error: %s\n", ssh_get_error(session));
322
 
        return;
323
 
    }
324
 
    /* this will open a file and copy it into your /home directory */
325
 
    /* the small buffer size was intended to stress the library. of course, you can use a buffer till 20kbytes without problem */
326
 
 
327
 
    fichier=sftp_open(sftp_session,"/usr/bin/ssh",O_RDONLY, 0);
328
 
    if(!fichier){
329
 
        fprintf(stderr, "Error opening /usr/bin/ssh: %s\n",
330
 
            ssh_get_error(session));
331
 
        return;
332
 
    }
333
 
    /* open a file for writing... */
334
 
    to=sftp_open(sftp_session,"ssh-copy",O_WRONLY | O_CREAT, 0);
335
 
    if(!to){
336
 
        fprintf(stderr, "Error opening ssh-copy for writing: %s\n",
337
 
            ssh_get_error(session));
338
 
        return;
339
 
    }
340
 
    while((len=sftp_read(fichier,data,4096)) > 0){
341
 
        if(sftp_write(to,data,len)!=len){
342
 
            fprintf(stderr, "Error writing %d bytes: %s\n",
343
 
                len, ssh_get_error(session));
344
 
            return;
345
 
        }
346
 
    }
347
 
    printf("finished\n");
348
 
    if(len<0)
349
 
        fprintf(stderr, "Error reading file: %s\n", ssh_get_error(session));
350
 
    sftp_close(fichier);
351
 
    sftp_close(to);
352
 
    printf("fichiers ferm\n");
353
 
    to=sftp_open(sftp_session,"/tmp/grosfichier",O_WRONLY|O_CREAT, 0644);
354
 
    for(i=0;i<1000;++i){
355
 
        len=sftp_write(to,data,8000);
356
 
        printf("wrote %d bytes\n",len);
357
 
        if(len != 8000){
358
 
            printf("chunk %d : %d (%s)\n",i,len,ssh_get_error(session));
359
 
        }
360
 
    }
361
 
    sftp_close(to);
362
 
    /* close the sftp session */
363
 
    sftp_free(sftp_session);
364
 
    printf("session sftp termin�\n");
365
 
}
366
 
#endif
367
 
 
368
 
static int auth_kbdint(SSH_SESSION *session){
369
 
    int err=ssh_userauth_kbdint(session,NULL,NULL);
370
 
    const char *name, *instruction, *prompt;
371
 
    char *ptr;
372
 
    char buffer[128];
373
 
    int i,n;
374
 
    char echo;
375
 
    while (err==SSH_AUTH_INFO){
376
 
        name=ssh_userauth_kbdint_getname(session);
377
 
        instruction=ssh_userauth_kbdint_getinstruction(session);
378
 
        n=ssh_userauth_kbdint_getnprompts(session);
379
 
        if(strlen(name)>0)
380
 
            printf("%s\n",name);
381
 
        if(strlen(instruction)>0)
382
 
            printf("%s\n",instruction);
383
 
        for(i=0;i<n;++i){
384
 
            prompt=ssh_userauth_kbdint_getprompt(session,i,&echo);
385
 
            if(echo){
386
 
                printf("%s",prompt);
387
 
                fgets(buffer,sizeof(buffer),stdin);
388
 
                buffer[sizeof(buffer)-1]=0;
389
 
                if((ptr=strchr(buffer,'\n')))
390
 
                    *ptr=0;
391
 
                if (ssh_userauth_kbdint_setanswer(session,i,buffer) < 0) {
392
 
                  return SSH_AUTH_ERROR;
393
 
                }
394
 
                memset(buffer,0,strlen(buffer));
395
 
            } else {
396
 
                ptr=getpass(prompt);
397
 
                if (ssh_userauth_kbdint_setanswer(session,i,ptr) < 0) {
398
 
                  return SSH_AUTH_ERROR;
399
 
                }
400
 
            }
401
 
        }
402
 
        err=ssh_userauth_kbdint(session,NULL,NULL);
403
 
    }
404
 
    return err;
405
 
}
406
 
 
407
 
int main(int argc, char **argv){
408
 
    SSH_SESSION *session;
409
 
    SSH_OPTIONS *options;
410
 
    int auth=0;
411
 
    char *password;
412
 
    char *banner;
413
 
    char *hexa;
414
 
    int state;
415
 
    char buf[10];
416
 
    unsigned char *hash = NULL;
417
 
    int hlen;
418
 
 
419
 
    options=ssh_options_new();
420
 
    if(ssh_options_getopt(options,&argc, argv)){
421
 
        fprintf(stderr,"error parsing command line :%s\n",ssh_get_error(options));
422
 
        usage();        
423
 
    }
424
 
    opts(argc,argv);
425
 
    signal(SIGTERM, do_exit);
426
 
 
427
 
    if (user) {
428
 
      if (ssh_options_set_username(options,user) < 0) {
429
 
        ssh_options_free(options);
430
 
        return 1;
431
 
      }
432
 
    }
433
 
 
434
 
    if (ssh_options_set_host(options,host) < 0) {
435
 
      ssh_options_free(options);
436
 
      return 1;
437
 
    }
438
 
    session=ssh_new();
439
 
    ssh_set_options(session,options);
440
 
    if(ssh_connect(session)){
441
 
        fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
442
 
        ssh_disconnect(session);
443
 
            ssh_finalize();
444
 
        return 1;
445
 
    }
446
 
    state=ssh_is_server_known(session);
447
 
 
448
 
    hlen = ssh_get_pubkey_hash(session, &hash);
449
 
    if (hlen < 0) {
450
 
      ssh_disconnect(session);
451
 
      ssh_finalize();
452
 
      return 1;
453
 
    }
454
 
    switch(state){
455
 
        case SSH_SERVER_KNOWN_OK:
456
 
            break; /* ok */
457
 
        case SSH_SERVER_KNOWN_CHANGED:
458
 
            fprintf(stderr,"Host key for server changed : server's one is now :\n");
459
 
            ssh_print_hexa("Public key hash",hash, hlen);
460
 
            free(hash);
461
 
            fprintf(stderr,"For security reason, connection will be stopped\n");
462
 
            ssh_disconnect(session);
463
 
                ssh_finalize();
464
 
            exit(-1);
465
 
        case SSH_SERVER_FOUND_OTHER:
466
 
            fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
467
 
            fprintf(stderr,"An attacker might change the default server key to confuse your client"
468
 
                "into thinking the key does not exist\n"
469
 
                "We advise you to rerun the client with -d or -r for more safety.\n");
470
 
            ssh_disconnect(session);
471
 
                    ssh_finalize();
472
 
            exit(-1);
473
 
        case SSH_SERVER_FILE_NOT_FOUND:
474
 
            fprintf(stderr,"Could not find known host file. If you accept the host key here,\n");
475
 
            fprintf(stderr,"the file will be automatically created.\n");
476
 
            /* fallback to SSH_SERVER_NOT_KNOWN behaviour */
477
 
        case SSH_SERVER_NOT_KNOWN:
478
 
            hexa = ssh_get_hexa(hash, hlen);
479
 
            fprintf(stderr,"The server is unknown. Do you trust the host key ?\n");
480
 
            fprintf(stderr, "Public key hash: %s\n", hexa);
481
 
            free(hexa);
482
 
            fgets(buf,sizeof(buf),stdin);
483
 
            if(strncasecmp(buf,"yes",3)!=0){
484
 
                ssh_disconnect(session);
485
 
                exit(-1);
486
 
            }
487
 
            fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n");
488
 
            fgets(buf,sizeof(buf),stdin);
489
 
            if(strncasecmp(buf,"yes",3)==0){
490
 
                if (ssh_write_knownhost(session) < 0) {
491
 
                  free(hash);
492
 
                  fprintf(stderr, "error %s\n", strerror(errno));
493
 
                  exit(-1);
494
 
                }
495
 
            }
496
 
            
497
 
            break;
498
 
        case SSH_SERVER_ERROR:
499
 
            free(hash);
500
 
            fprintf(stderr,"%s",ssh_get_error(session));
501
 
            ssh_disconnect(session);
502
 
            ssh_finalize();
503
 
            exit(-1);
504
 
    }
505
 
    free(hash);
506
 
 
507
 
    ssh_userauth_none(session, NULL);
508
 
 
509
 
    auth = ssh_auth_list(session);
510
 
    printf("auth: 0x%04x\n", auth);
511
 
    printf("supported auth methods: ");
512
 
    if (auth & SSH_AUTH_METHOD_PUBLICKEY) {
513
 
      printf("publickey");
514
 
    }
515
 
    if (auth & SSH_AUTH_METHOD_INTERACTIVE) {
516
 
      printf(", keyboard-interactive");
517
 
    }
518
 
    printf("\n");
519
 
 
520
 
    /* no ? you should :) */
521
 
    auth=ssh_userauth_autopubkey(session, NULL);
522
 
    if(auth==SSH_AUTH_ERROR){
523
 
        fprintf(stderr,"Authenticating with pubkey: %s\n",ssh_get_error(session));
524
 
            ssh_finalize();
525
 
        return -1;
526
 
    }
527
 
    banner=ssh_get_issue_banner(session);
528
 
    if(banner){
529
 
        printf("%s\n",banner);
530
 
        free(banner);
531
 
    }
532
 
    if(auth!=SSH_AUTH_SUCCESS){
533
 
        auth=auth_kbdint(session);
534
 
        if(auth==SSH_AUTH_ERROR){
535
 
            fprintf(stderr,"authenticating with keyb-interactive: %s\n",
536
 
                    ssh_get_error(session));
537
 
                ssh_finalize();
538
 
            return -1;
539
 
        }
540
 
    }
541
 
    if(auth!=SSH_AUTH_SUCCESS){
542
 
        password=getpass("Password: ");
543
 
        if(ssh_userauth_password(session,NULL,password) != SSH_AUTH_SUCCESS){
544
 
            fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
545
 
            ssh_disconnect(session);
546
 
                ssh_finalize();
547
 
            return -1;
548
 
        }
549
 
        memset(password,0,strlen(password));
550
 
    }
551
 
    ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success");
552
 
    if(strstr(argv[0],"sftp")){
553
 
        sftp=1;
554
 
        ssh_log(session, SSH_LOG_FUNCTIONS, "Doing sftp instead");
555
 
    }
556
 
    if(!sftp){
557
 
        if(!cmds[0])
558
 
            shell(session);
559
 
        else
560
 
            batch_shell(session);
561
 
    }
562
 
#ifdef WITH_SFTP
563
 
    else
564
 
        do_sftp(session);
565
 
#endif
566
 
    if(!sftp && !cmds[0])
567
 
        do_cleanup(0);
568
 
    ssh_disconnect(session);
569
 
    ssh_finalize();
570
 
 
571
 
    return 0;
572
 
}