1 /*
2  * bind.c : all ssh_bind functions
3  *
4  * This file is part of the SSH Library
5  *
6  * Copyright (c) 2004-2005 by Aris Adamantiadis
7  *
8  * The SSH Library is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or (at your
11  * option) any later version.
12  *
13  * The SSH Library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16  * License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with the SSH Library; see the file COPYING.  If not, write to
20  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21  * MA 02111-1307, USA.
22  */
23 
24 
25 #include "config.h"
26 
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 
33 #include "libssh/priv.h"
34 #include "libssh/bind.h"
35 #include "libssh/libssh.h"
36 #include "libssh/server.h"
37 #include "libssh/pki.h"
38 #include "libssh/buffer.h"
39 #include "libssh/socket.h"
40 #include "libssh/session.h"
41 
42 /**
43  * @addtogroup libssh_server
44  *
45  * @{
46  */
47 
48 
49 #ifdef _WIN32
50 #include <io.h>
51 #include <winsock2.h>
52 #include <ws2tcpip.h>
53 
54 /*
55  * <wspiapi.h> is necessary for getaddrinfo before Windows XP, but it isn't
56  * available on some platforms like MinGW.
57  */
58 #ifdef HAVE_WSPIAPI_H
59 # include <wspiapi.h>
60 #endif
61 
62 #define SOCKOPT_TYPE_ARG4 char
63 
64 /*
65  * We need to provide hstrerror. Not we can't call the parameter h_errno
66  * because it's #defined
67  */
hstrerror(int h_errno_val)68 static char *hstrerror(int h_errno_val) {
69   static char text[50] = {0};
70 
71   snprintf(text, sizeof(text), "getaddrino error %d\n", h_errno_val);
72 
73   return text;
74 }
75 #else /* _WIN32 */
76 
77 #include <sys/socket.h>
78 #include <netinet/in.h>
79 #include <netdb.h>
80 #define SOCKOPT_TYPE_ARG4 int
81 
82 #endif /* _WIN32 */
83 
bind_socket(ssh_bind sshbind,const char * hostname,int port)84 static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
85     int port) {
86     char port_c[6];
87     struct addrinfo *ai;
88     struct addrinfo hints;
89     int opt = 1;
90     socket_t s;
91     int rc;
92 
93     ZERO_STRUCT(hints);
94 
95     hints.ai_flags = AI_PASSIVE;
96     hints.ai_socktype = SOCK_STREAM;
97 
98     snprintf(port_c, 6, "%d", port);
99     rc = getaddrinfo(hostname, port_c, &hints, &ai);
100     if (rc != 0) {
101         ssh_set_error(sshbind,
102                       SSH_FATAL,
103                       "Resolving %s: %s", hostname, gai_strerror(rc));
104         return -1;
105     }
106 
107     s = socket (ai->ai_family,
108                            ai->ai_socktype,
109                            ai->ai_protocol);
110     if (s == SSH_INVALID_SOCKET) {
111         ssh_set_error(sshbind, SSH_FATAL, "%s", strerror(errno));
112         freeaddrinfo (ai);
113         return -1;
114     }
115 
116     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
117                    (char *)&opt, sizeof(opt)) < 0) {
118         ssh_set_error(sshbind,
119                       SSH_FATAL,
120                       "Setting socket options failed: %s",
121                       hstrerror(h_errno));
122         freeaddrinfo (ai);
123         close(s);
124         return -1;
125     }
126 
127     if (bind(s, ai->ai_addr, ai->ai_addrlen) != 0) {
128         ssh_set_error(sshbind,
129                       SSH_FATAL,
130                       "Binding to %s:%d: %s",
131                       hostname,
132                       port,
133                       strerror(errno));
134         freeaddrinfo (ai);
135         close(s);
136         return -1;
137     }
138 
139     freeaddrinfo (ai);
140     return s;
141 }
142 
ssh_bind_new(void)143 ssh_bind ssh_bind_new(void) {
144   ssh_bind ptr;
145 
146   ptr = malloc(sizeof(struct ssh_bind_struct));
147   if (ptr == NULL) {
148     return NULL;
149   }
150   ZERO_STRUCTP(ptr);
151   ptr->bindfd = SSH_INVALID_SOCKET;
152   ptr->bindport= 22;
153   ptr->common.log_verbosity = 0;
154 
155   return ptr;
156 }
157 
ssh_bind_listen(ssh_bind sshbind)158 int ssh_bind_listen(ssh_bind sshbind) {
159   const char *host;
160   socket_t fd;
161   int rc;
162 
163   if (ssh_init() < 0) {
164     ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
165     return -1;
166   }
167 
168   if (sshbind->dsakey == NULL && sshbind->rsakey == NULL) {
169       ssh_set_error(sshbind, SSH_FATAL,
170               "DSA or RSA host key file must be set before listen()");
171       return SSH_ERROR;
172   }
173 
174   if (sshbind->dsakey) {
175       rc = ssh_pki_import_privkey_file(sshbind->dsakey,
176                                        NULL,
177                                        NULL,
178                                        NULL,
179                                        &sshbind->dsa);
180       if (rc == SSH_ERROR) {
181           ssh_set_error(sshbind, SSH_FATAL,
182                   "Failed to import private DSA host key");
183           return SSH_ERROR;
184       }
185 
186       if (ssh_key_type(sshbind->dsa) != SSH_KEYTYPE_DSS) {
187           ssh_set_error(sshbind, SSH_FATAL,
188                   "The DSA host key has the wrong type");
189           ssh_key_free(sshbind->dsa);
190           return SSH_ERROR;
191       }
192   }
193 
194   if (sshbind->rsakey) {
195       rc = ssh_pki_import_privkey_file(sshbind->rsakey,
196                                        NULL,
197                                        NULL,
198                                        NULL,
199                                        &sshbind->rsa);
200       if (rc == SSH_ERROR) {
201           ssh_set_error(sshbind, SSH_FATAL,
202                   "Failed to import private RSA host key");
203           return SSH_ERROR;
204       }
205 
206       if (ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA &&
207           ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA1) {
208           ssh_set_error(sshbind, SSH_FATAL,
209                   "The RSA host key has the wrong type");
210           ssh_key_free(sshbind->rsa);
211           return SSH_ERROR;
212       }
213   }
214 
215   if (sshbind->bindfd == SSH_INVALID_SOCKET) {
216       host = sshbind->bindaddr;
217       if (host == NULL) {
218           host = "0.0.0.0";
219       }
220 
221       fd = bind_socket(sshbind, host, sshbind->bindport);
222       if (fd == SSH_INVALID_SOCKET) {
223           ssh_key_free(sshbind->dsa);
224           ssh_key_free(sshbind->rsa);
225           return -1;
226       }
227       sshbind->bindfd = fd;
228 
229       if (listen(fd, 10) < 0) {
230           ssh_set_error(sshbind, SSH_FATAL,
231                   "Listening to socket %d: %s",
232                   fd, strerror(errno));
233           close(fd);
234           ssh_key_free(sshbind->dsa);
235           ssh_key_free(sshbind->rsa);
236           return -1;
237       }
238   } else {
239       SSH_LOG(sshbind, SSH_LOG_INFO, "Using app-provided bind socket");
240   }
241   return 0;
242 }
243 
ssh_bind_set_callbacks(ssh_bind sshbind,ssh_bind_callbacks callbacks,void * userdata)244 int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks,
245     void *userdata){
246   if (sshbind == NULL) {
247     return SSH_ERROR;
248   }
249   if (callbacks == NULL) {
250     ssh_set_error_invalid(sshbind);
251     return SSH_ERROR;
252   }
253   if(callbacks->size <= 0 || callbacks->size > 1024 * sizeof(void *)){
254     ssh_set_error(sshbind,SSH_FATAL,
255         "Invalid callback passed in (badly initialized)");
256     return SSH_ERROR;
257   }
258   sshbind->bind_callbacks = callbacks;
259   sshbind->bind_callbacks_userdata=userdata;
260   return 0;
261 }
262 
263 /** @internal
264  * @brief callback being called by poll when an event happens
265  *
266  */
ssh_bind_poll_callback(ssh_poll_handle sshpoll,socket_t fd,int revents,void * user)267 static int ssh_bind_poll_callback(ssh_poll_handle sshpoll,
268     socket_t fd, int revents, void *user){
269   ssh_bind sshbind=(ssh_bind)user;
270   (void)sshpoll;
271   (void)fd;
272 
273   if(revents & POLLIN){
274     /* new incoming connection */
275     if(ssh_callbacks_exists(sshbind->bind_callbacks,incoming_connection)){
276       sshbind->bind_callbacks->incoming_connection(sshbind,
277           sshbind->bind_callbacks_userdata);
278     }
279   }
280   return 0;
281 }
282 
283 /** @internal
284  * @brief returns the current poll handle, or create it
285  * @param sshbind the ssh_bind object
286  * @returns a ssh_poll handle suitable for operation
287  */
ssh_bind_get_poll(ssh_bind sshbind)288 ssh_poll_handle ssh_bind_get_poll(ssh_bind sshbind){
289   if(sshbind->poll)
290     return sshbind->poll;
291   sshbind->poll=ssh_poll_new(sshbind->bindfd,POLLIN,
292       ssh_bind_poll_callback,sshbind);
293   return sshbind->poll;
294 }
295 
ssh_bind_set_blocking(ssh_bind sshbind,int blocking)296 void ssh_bind_set_blocking(ssh_bind sshbind, int blocking) {
297   sshbind->blocking = blocking ? 1 : 0;
298 }
299 
ssh_bind_get_fd(ssh_bind sshbind)300 socket_t ssh_bind_get_fd(ssh_bind sshbind) {
301   return sshbind->bindfd;
302 }
303 
ssh_bind_set_fd(ssh_bind sshbind,socket_t fd)304 void ssh_bind_set_fd(ssh_bind sshbind, socket_t fd) {
305   sshbind->bindfd = fd;
306 }
307 
ssh_bind_fd_toaccept(ssh_bind sshbind)308 void ssh_bind_fd_toaccept(ssh_bind sshbind) {
309   sshbind->toaccept = 1;
310 }
311 
ssh_bind_free(ssh_bind sshbind)312 void ssh_bind_free(ssh_bind sshbind){
313   int i;
314 
315   if (sshbind == NULL) {
316     return;
317   }
318 
319   if (sshbind->bindfd >= 0) {
320 #ifdef _WIN32
321     closesocket(sshbind->bindfd);
322 #else
323     close(sshbind->bindfd);
324 #endif
325   }
326   sshbind->bindfd = SSH_INVALID_SOCKET;
327 
328   /* options */
329   SAFE_FREE(sshbind->banner);
330   SAFE_FREE(sshbind->dsakey);
331   SAFE_FREE(sshbind->rsakey);
332   SAFE_FREE(sshbind->dsa);
333   SAFE_FREE(sshbind->rsa);
334   SAFE_FREE(sshbind->bindaddr);
335 
336   for (i = 0; i < 10; i++) {
337     if (sshbind->wanted_methods[i]) {
338       SAFE_FREE(sshbind->wanted_methods[i]);
339     }
340   }
341 
342   SAFE_FREE(sshbind);
343 }
344 
ssh_bind_accept_fd(ssh_bind sshbind,ssh_session session,socket_t fd)345 int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
346     int i;
347 
348     if (session == NULL){
349         ssh_set_error(sshbind, SSH_FATAL,"session is null");
350         return SSH_ERROR;
351     }
352 
353     session->server = 1;
354     session->version = 2;
355 
356     /* copy options */
357     for (i = 0; i < 10; ++i) {
358       if (sshbind->wanted_methods[i]) {
359         session->wanted_methods[i] = strdup(sshbind->wanted_methods[i]);
360         if (session->wanted_methods[i] == NULL) {
361           return SSH_ERROR;
362         }
363       }
364     }
365 
366     if (sshbind->bindaddr == NULL)
367       session->bindaddr = NULL;
368     else {
369       SAFE_FREE(session->bindaddr);
370       session->bindaddr = strdup(sshbind->bindaddr);
371       if (session->bindaddr == NULL) {
372         return SSH_ERROR;
373       }
374     }
375 
376     session->common.log_verbosity = sshbind->common.log_verbosity;
377 
378     ssh_socket_free(session->socket);
379     session->socket = ssh_socket_new(session);
380     if (session->socket == NULL) {
381       /* perhaps it may be better to copy the error from session to sshbind */
382       ssh_set_error_oom(sshbind);
383       return SSH_ERROR;
384     }
385     ssh_socket_set_fd(session->socket, fd);
386     ssh_socket_get_poll_handle_out(session->socket);
387 
388     if (sshbind->dsa) {
389         session->srv.dsa_key = ssh_key_dup(sshbind->dsa);
390         if (session->srv.dsa_key == NULL) {
391           ssh_set_error_oom(sshbind);
392           return SSH_ERROR;
393         }
394     }
395     if (sshbind->rsa) {
396         session->srv.rsa_key = ssh_key_dup(sshbind->rsa);
397         if (session->srv.rsa_key == NULL) {
398           ssh_set_error_oom(sshbind);
399           return SSH_ERROR;
400         }
401     }
402     return SSH_OK;
403 }
404 
ssh_bind_accept(ssh_bind sshbind,ssh_session session)405 int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
406   socket_t fd = SSH_INVALID_SOCKET;
407   int rc;
408   if (sshbind->bindfd == SSH_INVALID_SOCKET) {
409     ssh_set_error(sshbind, SSH_FATAL,
410         "Can't accept new clients on a not bound socket.");
411     return SSH_ERROR;
412   }
413 
414   if (session == NULL){
415       ssh_set_error(sshbind, SSH_FATAL,"session is null");
416       return SSH_ERROR;
417   }
418 
419   fd = accept(sshbind->bindfd, NULL, NULL);
420   if (fd == SSH_INVALID_SOCKET) {
421     ssh_set_error(sshbind, SSH_FATAL,
422         "Accepting a new connection: %s",
423         strerror(errno));
424     return SSH_ERROR;
425   }
426   rc = ssh_bind_accept_fd(sshbind, session, fd);
427 
428   if(rc == SSH_ERROR){
429 #ifdef _WIN32
430       closesocket(fd);
431 #else
432       close(fd);
433 #endif
434       if (session->socket)
435           ssh_socket_close(session->socket);
436   }
437   return rc;
438 }
439 
440 
441 /**
442  * @}
443  */
444