12 #include <sys/select.h>
23 static bool ssh_fingerprint_ok(char * f);
25 static void ssh_get_passwd(char * buffer, int len);
27 static bool ssh_agent_auth(ssh * s);
29 static bool ssh_publickey_auth(ssh * s, char * dir, int nAttempts);
31 static bool ssh_thread_running = false;
32 static int ssh_array_reserved = 0;
33 static int ssh_array_used = 0;
34 static ssh ** ssh_array = NULL;
35 static int ssh_thread_maxfd = 0;
37 static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
39 struct timeval timeout;
42 fd_set *writefd = NULL;
43 fd_set *readfd = NULL;
51 FD_SET(socket_fd, &fd);
53 /* now make sure we wait in the correct direction */
54 dir = libssh2_session_block_directions(session);
57 if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
60 if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
63 rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
68 ssh * ssh_new(char * username, char * addr, int port)
70 ssh * s = (ssh*)(calloc(1, sizeof(ssh)));
74 s->socket = Network_client(addr, port,100);
75 s->session = libssh2_session_init();
76 if (s->session == NULL)
79 log_print(2,"ssh_new", "libssh2_session_init returned NULL");
85 int err = libssh2_session_handshake(s->session, s->socket);
89 log_print(2,"ssh_new", "libssh2_session_handshake fails - error code %d", err);
92 s->fingerprint = (char*)(libssh2_hostkey_hash(s->session, LIBSSH2_HOSTKEY_HASH_SHA1));
93 if (!ssh_fingerprint_ok(s->fingerprint))
96 log_print(2,"ssh_new", "Fingerprint of host \"%s\" was not OK", addr);
100 char * userauthlist = libssh2_userauth_list(s->session, username, strlen(username));
102 int auth = AUTH_NONE;
103 if (strstr(userauthlist, "password"))
104 auth |= AUTH_PASSWORD;
105 if (strstr(userauthlist, "publickey"))
106 auth |= AUTH_PUBLICKEY;
110 if (auth & AUTH_PUBLICKEY)
112 // first try connecting with agent
113 ok = ssh_agent_auth(s);
119 log_print(3, "ssh_new", "Agent authentication failed, looking at public keys");
121 if (SSH_DIR[0] == '~' && SSH_DIR[1] == '/')
123 char ssh_dir[BUFSIZ];
124 sprintf(ssh_dir, "%s/%s",getenv("HOME"),SSH_DIR+2);
125 ok = ssh_publickey_auth(s, ssh_dir,3);
128 ok = ssh_publickey_auth(s, SSH_DIR,3);
133 if (auth & AUTH_PASSWORD && !ok)
135 log_print(3, "ssh_new", "public keys failed, try password");
136 for (int i = 0; i < 3 && !ok; ++i)
138 printf("Password for %s@%s:", username, addr);
139 char password[BUFSIZ];
140 ssh_get_passwd(password, BUFSIZ);
142 if (libssh2_userauth_password(s->session, username, password) == 0)
148 log_print(3, "ssh_new", "Failed to authenticate by password.");
154 log_print(2, "ssh_new", "All attempts at authenticating failed.");
157 log_print(3, "ssh_new", "Authenticated!");
159 s->reserved_tunnels = 1;
160 s->tunnel = (ssh_tunnel*)(calloc(s->reserved_tunnels, sizeof(ssh_tunnel)));
162 libssh2_session_set_blocking(s->session, 0);
166 void ssh_destroy(ssh * s)
170 for (int i = 0; i < s->nTunnels; ++i)
176 err = libssh2_channel_read(s->tunnel[i].channel, buffer, sizeof(buffer));
177 write(s->tunnel[i].forward_sock, buffer, err);
181 while ((err = libssh2_channel_close(s->tunnel[i].channel)) == LIBSSH2_ERROR_EAGAIN)
182 waitsocket(s->socket, s->session);
184 libssh2_channel_free(s->tunnel[i].channel);
185 close(s->tunnel[i].forward_sock);
189 libssh2_session_disconnect(s->session, "goodbye");
190 libssh2_session_free(s->session);
195 bool ssh_fingerprint_ok(char * f)
197 //TODO: Check fingerprint
198 log_print(1, "ssh_fingerprint_ok", "Unimplemented!");
202 void ssh_get_passwd(char * buffer, int len)
204 struct termios oflags, nflags;
206 tcgetattr(fileno(stdin), &oflags);
208 nflags.c_lflag &= ~ECHO;
209 nflags.c_lflag |= ECHONL;
211 if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0)
213 error("ssh_get_passwd", "tcsetattr : %s", strerror(errno));
216 fgets(buffer, len * sizeof(char), stdin);
217 buffer[strlen(buffer) - 1] = '\0';
219 if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0)
221 error("ssh_get_passwd", "tcsetattr : %s", strerror(errno));
225 bool ssh_publickey_auth(ssh * s, char * dir, int nAttempts)
229 DIR * d = opendir(dir);
233 log_print(0, "ssh_publickey_auth", "Couldn't open directory %s : %s", dir, strerror(errno));
237 while ((dp = readdir(d)) != NULL)
241 if (strstr(dp->d_name, ".pub") != NULL)
244 // assume file is a private key
245 // find corresponding public key
246 char pub[BUFSIZ]; char priv[BUFSIZ];
247 if (dir[strlen(dir)-1] == '/')
249 sprintf(pub, "%s%s.pub", dir,dp->d_name);
250 sprintf(priv, "%s%s", dir, dp->d_name);
254 sprintf(pub, "%s/%s.pub", dir,dp->d_name);
255 sprintf(priv, "%s/%s", dir, dp->d_name);
259 if (stat(priv, &t) != 0)
261 log_print(3,"ssh_publickey_auth", "Can't stat file %s : %s", priv, strerror(errno));
265 if (!S_ISREG(t.st_mode))
267 log_print(3, "ssh_publickey_auth", "%s doesn't appear to be a regular file", priv);
271 if (stat(pub, &t) != 0)
273 log_print(3,"ssh_publickey_auth", "Can't stat file %s : %s", pub, strerror(errno));
277 if (!S_ISREG(t.st_mode))
279 log_print(3, "ssh_publickey_auth", "%s doesn't appear to be a regular file", pub);
288 //libssh2_trace(s->session, LIBSSH2_TRACE_AUTH | LIBSSH2_TRACE_PUBLICKEY);
289 int err = libssh2_userauth_publickey_fromfile(s->session, s->user, pub, priv,"");
292 log_print(1, "ssh_publickey_auth", "Shouldn't use keys with no passphrase");
294 else if (err == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED)
297 char passphrase[BUFSIZ];
298 for (int i = 0; i < nAttempts; ++i)
300 printf("Passphrase for key %s:", priv);
301 ssh_get_passwd(passphrase, BUFSIZ);
302 err = libssh2_userauth_publickey_fromfile(s->session, s->user, pub, priv,passphrase);
303 if (err != LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) break;
322 bool ssh_agent_auth(ssh * s)
324 LIBSSH2_AGENT * agent = libssh2_agent_init(s->session);
327 log_print(0, "ssh_agent_auth", "Couldn't initialise agent support.");
331 if (libssh2_agent_connect(agent) != 0)
333 log_print(0, "ssh_agent_auth", "Failed to connect to ssh-agent.");
337 if (libssh2_agent_list_identities(agent) != 0)
339 log_print(0, "ssh_agent_auth", "Failure requesting identities to ssh-agent.");
343 struct libssh2_agent_publickey * identity = NULL;
344 struct libssh2_agent_publickey * prev_identity = NULL;
348 int err = libssh2_agent_get_identity(agent, &identity, prev_identity);
351 log_print(0, "ssh_agent_auth", "Couldn't continue authentication.");
356 log_print(0, "ssh_agent_auth", "Failure obtaining identity from ssh-agent support.");
360 if (libssh2_agent_userauth(agent, s->user, identity) == 0)
362 log_print(3, "ssh_agent_auth", "Authentication with username %s and public key %s succeeded!", s->user, identity->comment);
367 log_print(3, "ssh_agent_auth", "Authentication with username %s and public key %s failed.", s->user, identity->comment);
369 prev_identity = identity;
376 LIBSSH2_LISTENER * ssh_get_listener(ssh * s, int * port)
378 pthread_mutex_lock(&ssh_thread_mutex);
379 libssh2_session_set_blocking(s->session, 1);
380 //libssh2_trace(s->session, ~0);
381 LIBSSH2_LISTENER * l = libssh2_channel_forward_listen_ex(s->session, "localhost", *port, port,1);
385 libssh2_session_last_error(s->session, &error, NULL, 0);
386 log_print(0, "ssh_get_listener", "Error: %s", error);
388 libssh2_session_set_blocking(s->session, 0);
389 pthread_mutex_unlock(&ssh_thread_mutex);
393 void ssh_add_tunnel(ssh * s, LIBSSH2_LISTENER * listener, int socket)
395 pthread_mutex_lock(&ssh_thread_mutex);
396 //log_print(3, "ssh_add_tunnel", "accepting connection...");
397 libssh2_session_set_blocking(s->session , 1);
398 //libssh2_trace(s->session, ~0);
399 LIBSSH2_CHANNEL * channel = libssh2_channel_forward_accept(listener);
403 libssh2_session_last_error(s->session, &error, NULL, 0);
404 log_print(0, "ssh_add_tunnel", "Error: %s", error);
406 libssh2_session_set_blocking(s->session , 0);
407 //log_print(3, "ssh_add_tunnel", "accepted remote connection...");
409 ssh_tunnel * t = s->tunnel+(s->nTunnels++);
410 t->forward_sock = socket;
411 t->channel = channel;
413 if (socket > ssh_thread_maxfd)
414 ssh_thread_maxfd = socket;
416 if (s->nTunnels >= s->reserved_tunnels)
418 s->reserved_tunnels *= 2;
419 s->tunnel = (ssh_tunnel*)(realloc(s->tunnel, s->reserved_tunnels * sizeof(ssh_tunnel)));
422 pthread_mutex_unlock(&ssh_thread_mutex);
425 void ssh_exec_swarm(ssh * s, int * port, int * socket, int np)
429 LIBSSH2_CHANNEL * channel = NULL;
430 while ((channel = libssh2_channel_open_session(s->session)) == NULL
431 && libssh2_session_last_error(s->session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN)
433 waitsocket(s->socket, s->session);
438 error("ssh_exec_swarm", "Couldn't create channel with ssh session");
445 if (port == NULL && socket != NULL)
447 int len = sprintf(buffer, "%s -r - -l :%d", options.program, options.verbosity);
449 len += sprintf(buffer+len, " -n %d", np);
452 else if (port != NULL && socket == NULL)
454 int len = sprintf(buffer, "%s -r $(echo $SSH_CONNECTION | awk \'{print $1}\'):%d -l :%d", options.program, *port);
456 len += sprintf(buffer+len, " -n %d", np);
461 error("ssh_exec_swarm", "Exactly *one* of the port or socket pointers must not be NULL");
464 while ((err = libssh2_channel_exec(channel, buffer)) == LIBSSH2_ERROR_EAGAIN)
466 waitsocket(s->socket, s->session);
472 pthread_mutex_lock(&ssh_thread_mutex);
474 ssh_tunnel * t = s->tunnel+(s->nTunnels++);
476 t->forward_sock = *socket;
477 t->channel = channel;
479 if (*socket > ssh_thread_maxfd)
480 ssh_thread_maxfd = *socket;
483 if (s->nTunnels >= s->reserved_tunnels)
485 s->reserved_tunnels *= 2;
486 s->tunnel = (ssh_tunnel*)(realloc(s->tunnel, s->reserved_tunnels * sizeof(ssh_tunnel)));
489 pthread_mutex_unlock(&ssh_thread_mutex);
494 // read everything and close the channel
497 while ((err = libssh2_channel_read(channel, buffer, sizeof(buffer))) > 0);
498 if (err == LIBSSH2_ERROR_EAGAIN)
500 waitsocket(s->socket, s->session);
508 while ((err = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN)
510 waitsocket(s->socket, s->session);
512 libssh2_channel_free(channel);
523 pthread_mutex_t ssh_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
524 pthread_t ssh_pthread;
526 void * ssh_thread(void * args)
538 //log_print(1, "ssh_thread", "loop - %d ssh's", ssh_array_used);
540 pthread_mutex_lock(&ssh_thread_mutex);
542 if (!ssh_thread_running) break;
544 for (int i = 0; i < ssh_array_used; ++i)
546 ssh * s = ssh_array[i];
547 if (s == NULL) continue;
548 for (int j = 0; j < s->nTunnels; ++j)
550 FD_SET(s->tunnel[j].forward_sock, &readSet);
554 pthread_mutex_unlock(&ssh_thread_mutex);
555 select(ssh_thread_maxfd+1, &readSet, NULL, NULL, &tv);
556 pthread_mutex_lock(&ssh_thread_mutex);
558 for (int i = 0; i < ssh_array_used; ++i)
560 ssh * s = ssh_array[i];
561 //log_print(2, "ssh_thread", "array[%d] = %p", i, s);
562 if (s == NULL) continue;
563 for (int j = 0; j < s->nTunnels; ++j)
565 //log_print(2, "ssh_thread", "Tunnel number %d, socket %d", j, s->tunnel[j].forward_sock);
566 if (FD_ISSET(s->tunnel[j].forward_sock, &readSet))
568 //log_print(2, "ssh_thread", "reading from socket %d", s->tunnel[j].forward_sock);
569 int len = read(s->tunnel[j].forward_sock, buffer, sizeof(buffer));
574 int written = 0; int w = 0;
577 //log_print(2, "ssh_thread", "writing %s to channel", buffer);
578 w = libssh2_channel_write(s->tunnel[j].channel, buffer+written, len-written);
582 while (w > 0 && written < len);
586 //log_print(2, "ssh_thread", "Try to read from channel %p", s->tunnel[j].channel);
587 int len = libssh2_channel_read(s->tunnel[j].channel, buffer, sizeof(buffer));
588 //log_print(2, "ssh_thread", "Read %s from channel", buffer);
589 if (len == LIBSSH2_ERROR_EAGAIN) break;
592 int written = 0; int w = 0;
593 while (written < len)
595 //log_print(2, "ssh_thread", "Wrote %s to socket %d", buffer+written, s->tunnel[j].forward_sock);
596 w = write(s->tunnel[j].forward_sock, buffer+written, len-written);
599 if (libssh2_channel_eof(s->tunnel[j].channel))
601 //log_print(1, "ssh_thread", "Got to eof in channel %p", s->tunnel[j].channel);
606 pthread_mutex_unlock(&ssh_thread_mutex);
612 void ssh_thread_add(ssh * s)
614 pthread_mutex_lock(&ssh_thread_mutex);
619 for (int i = 0; (i < ssh_array_reserved && !found); ++i)
621 if (ssh_array[i] == NULL)
632 int old = ssh_array_reserved;
633 ssh_array_reserved = (ssh_array_reserved + 1) * 2;
634 if (ssh_array == NULL)
635 ssh_array = (ssh**)(calloc(ssh_array_reserved, sizeof(ssh*)));
638 ssh_array = (ssh**)(realloc(ssh_array, ssh_array_reserved * sizeof(ssh*)));
639 for (int i = old+1; i < ssh_array_reserved; ++i)
646 for (int i = 0; i < s->nTunnels; ++i)
648 if (s->tunnel[i].forward_sock > ssh_thread_maxfd)
649 ssh_thread_maxfd = s->tunnel[i].forward_sock;
652 if (!ssh_thread_running)
654 ssh_thread_running = true;
658 err = pthread_sigmask(SIG_SETMASK, &set, NULL);
660 error("ssh_thread_add", "pthread_sigmask : %s", strerror(errno));
661 err = pthread_create(&ssh_pthread, NULL, ssh_thread, NULL);
663 error("ssh_thread_add", "pthread_create : %s", strerror(errno));
665 err = pthread_sigmask(SIG_SETMASK, &set, NULL);
667 error("ssh_thread_add", "pthread_sigmask : %s", strerror(errno));
672 pthread_mutex_unlock(&ssh_thread_mutex);
675 void ssh_thread_del(ssh * s)
677 pthread_mutex_lock(&ssh_thread_mutex);
679 for (int i = 0; i < ssh_array_reserved; ++i)
681 if (ssh_array[i] == s)
684 ssh_thread_running = !(--ssh_array_used == 0);
689 pthread_mutex_unlock(&ssh_thread_mutex);