1 /* client.c file */ 2 /* 3 Copyright 2003 Aris Adamantiadis 4 5 This file is part of the SSH Library 6 7 The SSH Library is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published by 9 the Free Software Foundation; either version 2.1 of the License, or (at your 10 option) any later version. 11 12 The SSH Library is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with the SSH Library; see the file COPYING. If not, write to 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 20 MA 02111-1307, USA. */ 21 22 #include <stdio.h> 23 #include <unistd.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <netdb.h> 27 #include "libssh/priv.h" 28 #include "libssh/ssh2.h" 29 static void ssh_cleanup(SSH_SESSION *session); 30 #define set_status(opt,status) do {\ 31 if (opt->connect_status_function) \ 32 opt->connect_status_function(opt->connect_status_arg, status); \ 33 } while (0) 34 /* simply gets a banner from a socket */ 35 char *ssh_get_banner(SSH_SESSION *session){ 36 char buffer[128]; 37 int i = 0; 38 while (i < 127) { 39 if(read(session->fd, &buffer[i], 1)<=0){ 40 ssh_set_error(session,SSH_CONNECTION_LOST,"Remote host closed connection"); 41 return NULL; 42 } 43 if (buffer[i] == '\r') 44 buffer[i] = 0; 45 if (buffer[i] == '\n') { 46 buffer[i] = 0; 47 return strdup(buffer); 48 } 49 i++; 50 } 51 ssh_set_error(NULL,SSH_FATAL,"Too large banner"); 52 return NULL; 53 } 54 55 /* ssh_send_banner sends a SSH banner to the server */ 56 /* TODO select a banner compatible with server version */ 57 /* switch SSH1/1.5/2 */ 58 /* and quit when the server is SSH1 only */ 59 60 void ssh_send_banner(SSH_SESSION *session){ 61 char *banner=CLIENTBANNER ; 62 char buffer[128]; 63 if(session->options->clientbanner) 64 banner=session->options->clientbanner; 65 session->clientbanner=strdup(banner); 66 snprintf(buffer,128,"%s\r\n",session->clientbanner); 67 write(session->fd,buffer,strlen(buffer)); 68 } 69 70 71 int dh_handshake(SSH_SESSION *session){ 72 STRING *e,*f,*pubkey,*signature; 73 packet_clear_out(session); 74 buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT); 75 dh_generate_x(session); 76 dh_generate_e(session); 77 e=dh_get_e(session); 78 buffer_add_ssh_string(session->out_buffer,e); 79 packet_send(session); 80 free(e); 81 if(packet_wait(session,SSH2_MSG_KEXDH_REPLY,1)) 82 return -1; 83 pubkey=buffer_get_ssh_string(session->in_buffer); 84 if(!pubkey){ 85 ssh_set_error(NULL,SSH_FATAL,"No public key in packet"); 86 return -1; 87 } 88 dh_import_pubkey(session,pubkey); 89 f=buffer_get_ssh_string(session->in_buffer); 90 if(!f){ 91 ssh_set_error(NULL,SSH_FATAL,"No F number in packet"); 92 return -1; 93 } 94 dh_import_f(session,f); 95 free(f); 96 if(!(signature=buffer_get_ssh_string(session->in_buffer))){ 97 ssh_set_error(NULL,SSH_FATAL,"No signature in packet"); 98 return -1; 99 } 100 101 dh_build_k(session); 102 packet_wait(session,SSH2_MSG_NEWKEYS,1); 103 ssh_say(2,"Got SSH_MSG_NEWKEYS\n"); 104 packet_clear_out(session); 105 buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS); 106 packet_send(session); 107 ssh_say(2,"SSH_MSG_NEWKEYS sent\n"); 108 make_sessionid(session); 109 /* set the cryptographic functions for the next crypto (it is needed for generate_session_keys for key lenghts) */ 110 if(crypt_set_algorithms(session)) 111 return -1; 112 generate_session_keys(session); 113 /* verify the host's signature. XXX do it sooner */ 114 if(signature_verify(session,signature)){ 115 free(signature); 116 return -1; 117 } 118 free(signature); /* forget it for now ... */ 119 /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */ 120 if(session->current_crypto) 121 crypto_free(session->current_crypto); 122 /* XXX later, include a function to change keys */ 123 session->current_crypto=session->next_crypto; 124 session->next_crypto=crypto_new(); 125 return 0; 126 } 127 128 int ssh_service_request(SSH_SESSION *session,char *service){ 129 STRING *service_s; 130 packet_clear_out(session); 131 buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_REQUEST); 132 service_s=string_from_char(service); 133 buffer_add_ssh_string(session->out_buffer,service_s); 134 free(service_s); 135 packet_send(session); 136 ssh_say(3,"Sent SSH_MSG_SERVICE_REQUEST (service %s)\n",service); 137 if(packet_wait(session,SSH2_MSG_SERVICE_ACCEPT,1)){ 138 ssh_set_error(session,SSH_INVALID_DATA,"did not receive SERVICE_ACCEPT"); 139 return -1; 140 } 141 ssh_say(3,"Received SSH_MSG_SERVICE_ACCEPT (service %s)\n",service); 142 return 0; 143 } 144 145 SSH_SESSION *ssh_connect(SSH_OPTIONS *options){ 146 SSH_SESSION *session; 147 int fd; 148 if(!options){ 149 ssh_set_error(NULL,SSH_FATAL,"Null argument given to ssh_connect !"); 150 return NULL; 151 } 152 ssh_crypto_init(); 153 if(options->fd==-1 && !options->host){ 154 ssh_set_error(NULL,SSH_FATAL,"Hostname required"); 155 return NULL; 156 } 157 if(options->fd != -1) 158 fd=options->fd; 159 else 160 fd=ssh_connect_host(options->host,options->bindaddr,options->port, 161 options->timeout,options->timeout_usec); 162 if(fd<0) 163 return NULL; 164 set_status(options,0.2); 165 session=ssh_session_new(); 166 session->fd=fd; 167 session->alive=1; 168 session->options=options; 169 if(!(session->serverbanner=ssh_get_banner(session))){ 170 ssh_cleanup(session); 171 return NULL; 172 } 173 set_status(options,0.4); 174 ssh_say(2,"banner : %s\n",session->serverbanner); 175 ssh_send_banner(session); 176 set_status(options,0.5); 177 if(ssh_get_kex(session,0)){ 178 ssh_disconnect(session); 179 return NULL; 180 } 181 set_status(options,0.6); 182 list_kex(&session->server_kex); 183 if(set_kex(session)){ 184 ssh_disconnect(session); 185 return NULL; 186 } 187 send_kex(session,0); 188 set_status(options,0.8); 189 if(dh_handshake(session)){ 190 ssh_disconnect(session); 191 return NULL; 192 } 193 set_status(options,1.0); 194 session->connected=1; 195 return session; 196 } 197 198 static void ssh_cleanup(SSH_SESSION *session){ 199 int i; 200 if(session->serverbanner) 201 free(session->serverbanner); 202 if(session->clientbanner) 203 free(session->clientbanner); 204 if(session->in_buffer) 205 buffer_free(session->in_buffer); 206 if(session->out_buffer) 207 buffer_free(session->out_buffer); 208 if(session->banner) 209 free(session->banner); 210 if(session->options) 211 options_free(session->options); 212 if(session->current_crypto) 213 crypto_free(session->current_crypto); 214 if(session->next_crypto) 215 crypto_free(session->next_crypto); 216 217 // delete all channels 218 while(session->channels) 219 channel_free(session->channels); 220 if(session->client_kex.methods) 221 for(i=0;i<10;i++) 222 if(session->client_kex.methods[i]) 223 free(session->client_kex.methods[i]); 224 if(session->server_kex.methods) 225 for(i=0;i<10;++i) 226 if(session->server_kex.methods[i]) 227 free(session->server_kex.methods[i]); 228 free(session->client_kex.methods); 229 free(session->server_kex.methods); 230 memset(session,'X',sizeof(SSH_SESSION)); /* burn connection, it could hangs sensitive datas */ 231 free(session); 232 } 233 234 char *ssh_get_issue_banner(SSH_SESSION *session){ 235 if(!session->banner) 236 return NULL; 237 return string_to_char(session->banner); 238 } 239 240 void ssh_disconnect(SSH_SESSION *session){ 241 STRING *str; 242 if(session->fd!= -1) { 243 packet_clear_out(session); 244 buffer_add_u8(session->out_buffer,SSH2_MSG_DISCONNECT); 245 buffer_add_u32(session->out_buffer,htonl(SSH2_DISCONNECT_BY_APPLICATION)); 246 str=string_from_char("Bye Bye"); 247 buffer_add_ssh_string(session->out_buffer,str); 248 free(str); 249 packet_send(session); 250 close(session->fd); 251 session->fd=-1; 252 } 253 session->alive=0; 254 ssh_cleanup(session); 255 } 256 257 const char *ssh_copyright(){ 258 return LIBSSH_VERSION " (c) 2003-2004 Aris Adamantiadis (aris@0xbadc0de.be)" 259 " Distributed under the LGPL, please refer to COPYING file for informations" 260 " about your rights" ; 261 } |