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 sprintf(buffer, "%s -r -", options.program);
449 sprintf(buffer, " -n %d", np);
451 else if (port != NULL && socket == NULL)
453 sprintf(buffer, "%s -r $(echo $SSH_CONNECTION | awk \'{print $1}\'):%d", options.program, *port);
455 sprintf(buffer, " -n %d", np);
459 error("ssh_exec_swarm", "Exactly *one* of the port or socket pointers must not be NULL");
462 while ((err = libssh2_channel_exec(channel, buffer)) == LIBSSH2_ERROR_EAGAIN)
464 waitsocket(s->socket, s->session);
470 pthread_mutex_lock(&ssh_thread_mutex);
472 ssh_tunnel * t = s->tunnel+(s->nTunnels++);
474 t->forward_sock = *socket;
475 t->channel = channel;
477 if (*socket > ssh_thread_maxfd)
478 ssh_thread_maxfd = *socket;
481 if (s->nTunnels >= s->reserved_tunnels)
483 s->reserved_tunnels *= 2;
484 s->tunnel = (ssh_tunnel*)(realloc(s->tunnel, s->reserved_tunnels * sizeof(ssh_tunnel)));
487 pthread_mutex_unlock(&ssh_thread_mutex);
492 // read everything and close the channel
495 while ((err = libssh2_channel_read(channel, buffer, sizeof(buffer))) > 0);
496 if (err == LIBSSH2_ERROR_EAGAIN)
498 waitsocket(s->socket, s->session);
506 while ((err = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN)
508 waitsocket(s->socket, s->session);
510 libssh2_channel_free(channel);
521 pthread_mutex_t ssh_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
522 pthread_t ssh_pthread;
524 void * ssh_thread(void * args)
536 //log_print(1, "ssh_thread", "loop - %d ssh's", ssh_array_used);
538 pthread_mutex_lock(&ssh_thread_mutex);
540 if (!ssh_thread_running) break;
542 for (int i = 0; i < ssh_array_used; ++i)
544 ssh * s = ssh_array[i];
545 if (s == NULL) continue;
546 for (int j = 0; j < s->nTunnels; ++j)
548 FD_SET(s->tunnel[j].forward_sock, &readSet);
552 pthread_mutex_unlock(&ssh_thread_mutex);
553 select(ssh_thread_maxfd+1, &readSet, NULL, NULL, &tv);
554 pthread_mutex_lock(&ssh_thread_mutex);
556 for (int i = 0; i < ssh_array_used; ++i)
558 ssh * s = ssh_array[i];
559 //log_print(2, "ssh_thread", "array[%d] = %p", i, s);
560 if (s == NULL) continue;
561 for (int j = 0; j < s->nTunnels; ++j)
563 //log_print(2, "ssh_thread", "Tunnel number %d, socket %d", j, s->tunnel[j].forward_sock);
564 if (FD_ISSET(s->tunnel[j].forward_sock, &readSet))
566 //log_print(2, "ssh_thread", "reading from socket %d", s->tunnel[j].forward_sock);
567 int len = read(s->tunnel[j].forward_sock, buffer, sizeof(buffer));
572 int written = 0; int w = 0;
575 //log_print(2, "ssh_thread", "writing %s to channel", buffer);
576 w = libssh2_channel_write(s->tunnel[j].channel, buffer+written, len-written);
580 while (w > 0 && written < len);
584 //log_print(2, "ssh_thread", "Try to read from channel %p", s->tunnel[j].channel);
585 int len = libssh2_channel_read(s->tunnel[j].channel, buffer, sizeof(buffer));
586 //log_print(2, "ssh_thread", "Read %s from channel", buffer);
587 if (len == LIBSSH2_ERROR_EAGAIN) break;
590 int written = 0; int w = 0;
591 while (written < len)
593 //log_print(2, "ssh_thread", "Wrote %s to socket %d", buffer+written, s->tunnel[j].forward_sock);
594 w = write(s->tunnel[j].forward_sock, buffer+written, len-written);
597 if (libssh2_channel_eof(s->tunnel[j].channel))
599 //log_print(1, "ssh_thread", "Got to eof in channel %p", s->tunnel[j].channel);
604 pthread_mutex_unlock(&ssh_thread_mutex);
610 void ssh_thread_add(ssh * s)
612 pthread_mutex_lock(&ssh_thread_mutex);
617 for (int i = 0; (i < ssh_array_reserved && !found); ++i)
619 if (ssh_array[i] == NULL)
630 int old = ssh_array_reserved;
631 ssh_array_reserved = (ssh_array_reserved + 1) * 2;
632 if (ssh_array == NULL)
633 ssh_array = (ssh**)(calloc(ssh_array_reserved, sizeof(ssh*)));
636 ssh_array = (ssh**)(realloc(ssh_array, ssh_array_reserved * sizeof(ssh*)));
637 for (int i = old+1; i < ssh_array_reserved; ++i)
644 for (int i = 0; i < s->nTunnels; ++i)
646 if (s->tunnel[i].forward_sock > ssh_thread_maxfd)
647 ssh_thread_maxfd = s->tunnel[i].forward_sock;
650 if (!ssh_thread_running)
652 ssh_thread_running = true;
656 err = pthread_sigmask(SIG_SETMASK, &set, NULL);
658 error("ssh_thread_add", "pthread_sigmask : %s", strerror(errno));
659 err = pthread_create(&ssh_pthread, NULL, ssh_thread, NULL);
661 error("ssh_thread_add", "pthread_create : %s", strerror(errno));
663 err = pthread_sigmask(SIG_SETMASK, &set, NULL);
665 error("ssh_thread_add", "pthread_sigmask : %s", strerror(errno));
670 pthread_mutex_unlock(&ssh_thread_mutex);
673 void ssh_thread_del(ssh * s)
675 pthread_mutex_lock(&ssh_thread_mutex);
677 for (int i = 0; i < ssh_array_reserved; ++i)
679 if (ssh_array[i] == s)
682 ssh_thread_running = !(--ssh_array_used == 0);
687 pthread_mutex_unlock(&ssh_thread_mutex);