1/*
2Copyright 2010 Aris Adamantiadis
3
4This file is part of the SSH Library
5
6You are free to copy this file, modify it in any way, consider it being public
7domain. This does not apply to the rest of the library though, but it is
8allowed to cut-and-paste working code from this file to any license of
9program.
10The goal is to show the API in action. It's not a reference on how terminal
11clients must be made or how a client should react.
12*/
13
14#include "config.h"
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#ifdef HAVE_TERMIOS_H
19#include <termios.h>
20#endif
21#ifdef HAVE_UNISTD_H
22#include <unistd.h>
23#endif
24
25#include <sys/select.h>
26#include <sys/time.h>
27
28#include <sys/ioctl.h>
29#include <errno.h>
30#include <libssh/callbacks.h>
31#include <libssh/libssh.h>
32#include <libssh/sftp.h>
33
34#include <fcntl.h>
35
36#include "examples_common.h"
37char *host;
38const char *desthost="localhost";
39const char *port="22";
40
41#ifdef WITH_PCAP
42#include <libssh/pcap.h>
43char *pcap_file=NULL;
44#endif
45
46static void usage(){
47 fprintf(stderr,"Usage : sshnetcat [user@]host forwarded_host forwarded_port\n");
48 exit(1);
49}
50
51static int opts(int argc, char **argv){
52 int i;
53 while((i=getopt(argc,argv,"P:"))!=-1){
54 switch(i){
55#ifdef WITH_PCAP
56 case 'P':
57 pcap_file=optarg;
58 break;
59#endif
60 default:
61 fprintf(stderr,"unknown option %c\n",optopt);
62 usage();
63 }
64 }
65 if(optind < argc)
66 host=argv[optind++];
67 if(optind < argc)
68 desthost=argv[optind++];
69 if(optind < argc)
70 port=argv[optind++];
71 if(host==NULL)
72 usage();
73 return 0;
74}
75
76static void select_loop(ssh_session session,ssh_channel channel){
77 fd_set fds;
78 struct timeval timeout;
79 char buffer[4096];
80 /* channels will be set to the channels to poll.
81 * outchannels will contain the result of the poll
82 */
83 ssh_channel channels[2], outchannels[2];
84 int lus;
85 int eof=0;
86 int maxfd;
87 int ret;
88 while(channel){
89 do{
90 int fd;
91
92 FD_ZERO(&fds);
93 if(!eof)
94 FD_SET(0,&fds);
95 timeout.tv_sec=30;
96 timeout.tv_usec=0;
97
98 fd = ssh_get_fd(session);
99 if (fd == -1) {
100 fprintf(stderr, "Error getting the session file descriptor: %s\n",
101 ssh_get_error(session));
102 return;
103 }
104 FD_SET(fd, &fds);
105 maxfd = fd + 1;
106
107 channels[0]=channel; // set the first channel we want to read from
108 channels[1]=NULL;
109 ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout);
110 if(ret==EINTR)
111 continue;
112 if(FD_ISSET(0,&fds)){
113 lus=read(0,buffer,sizeof(buffer));
114 if(lus)
115 ssh_channel_write(channel,buffer,lus);
116 else {
117 eof=1;
118 ssh_channel_send_eof(channel);
119 }
120 }
121 if(channel && ssh_channel_is_closed(channel)){
122 ssh_channel_free(channel);
123 channel=NULL;
124 channels[0]=NULL;
125 }
126 if(outchannels[0]){
127 while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,0)){
128 lus = ssh_channel_read(channel,buffer,sizeof(buffer),0);
129 if(lus==-1){
130 fprintf(stderr, "Error reading channel: %s\n",
131 ssh_get_error(session));
132 return;
133 }
134 if(lus==0){
135 ssh_channel_free(channel);
136 channel=channels[0]=NULL;
137 } else {
138 ret = write(1, buffer, lus);
139 if (ret < 0) {
140 fprintf(stderr, "Error writing to stdin: %s",
141 strerror(errno));
142 return;
143 }
144 }
145 }
146 while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,1)){ /* stderr */
147 lus = ssh_channel_read(channel, buffer, sizeof(buffer), 1);
148 if(lus==-1){
149 fprintf(stderr, "Error reading channel: %s\n",
150 ssh_get_error(session));
151 return;
152 }
153 if(lus==0){
154 ssh_channel_free(channel);
155 channel=channels[0]=NULL;
156 } else {
157 ret = write(2, buffer, lus);
158 if (ret < 0) {
159 fprintf(stderr, "Error writing to stderr: %s",
160 strerror(errno));
161 return;
162 }
163 }
164 }
165 }
166 if(channel && ssh_channel_is_closed(channel)){
167 ssh_channel_free(channel);
168 channel=NULL;
169 }
170 } while (ret==EINTR || ret==SSH_EINTR);
171
172 }
173}
174
175static void forwarding(ssh_session session){
176 ssh_channel channel;
177 int r;
178 channel = ssh_channel_new(session);
179 r = ssh_channel_open_forward(channel, desthost, atoi(port), "localhost", 22);
180 if(r<0) {
181 printf("error forwarding port : %s\n",ssh_get_error(session));
182 return;
183 }
184 select_loop(session,channel);
185}
186
187static int client(ssh_session session){
188 int auth=0;
189 char *banner;
190 int state;
191
192 if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
193 return -1;
194 ssh_options_parse_config(session, NULL);
195
196 if(ssh_connect(session)){
197 fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
198 return -1;
199 }
200 state=verify_knownhost(session);
201 if (state != 0)
202 return -1;
203 ssh_userauth_none(session, NULL);
204 banner=ssh_get_issue_banner(session);
205 if(banner){
206 printf("%s\n",banner);
207 free(banner);
208 }
209 auth=authenticate_console(session);
210 if(auth != SSH_AUTH_SUCCESS){
211 return -1;
212 }
213 forwarding(session);
214 return 0;
215}
216
217#ifdef WITH_PCAP
218ssh_pcap_file pcap;
219void set_pcap(ssh_session session);
220void set_pcap(ssh_session session){
221 if(!pcap_file)
222 return;
223 pcap=ssh_pcap_file_new();
224 if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
225 printf("Error opening pcap file\n");
226 ssh_pcap_file_free(pcap);
227 pcap=NULL;
228 return;
229 }
230 ssh_set_pcap_file(session,pcap);
231}
232
233void cleanup_pcap(void);
234void cleanup_pcap(){
235 ssh_pcap_file_free(pcap);
236 pcap=NULL;
237}
238#endif
239
240int main(int argc, char **argv){
241 ssh_session session;
242
243 session = ssh_new();
244
245 if(ssh_options_getopt(session, &argc, argv)) {
246 fprintf(stderr, "error parsing command line :%s\n",
247 ssh_get_error(session));
248 usage();
249 }
250 opts(argc,argv);
251#ifdef WITH_PCAP
252 set_pcap(session);
253#endif
254 client(session);
255
256 ssh_disconnect(session);
257 ssh_free(session);
258#ifdef WITH_PCAP
259 cleanup_pcap();
260#endif
261
262 ssh_finalize();
263
264 return 0;
265}
266