Skip to content

Instantly share code, notes, and snippets.

@FGasper
Created July 1, 2020 01:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FGasper/4fb5b702489b9eb12c2133e9da5c5beb to your computer and use it in GitHub Desktop.
Save FGasper/4fb5b702489b9eb12c2133e9da5c5beb to your computer and use it in GitHub Desktop.
proof-of-concept: SSH authn via pre-existing sockets
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <libssh/libssh.h>
#define SOCKET_PATH "mysocket"
#define USERNAME "hank"
#define HOSTNAME "remote.host"
#define CLIENT_KEYFILE "client_ed25519"
#define STRINGIFY(s) _STR(s)
#define _STR(s) #s
//----------------------------------------------------------------------
// copied
static int auth_keyfile(ssh_session session, char* keyfile)
{
fprintf(stderr, "in auth_keyfile\n");
ssh_key key = NULL;
char pubkey[132] = {0}; // +".pub"
int rc;
snprintf(pubkey, sizeof(pubkey), "%s.pub", keyfile);
fprintf(stderr, "importing keyfile “%s.pub”\n", keyfile);
rc = ssh_pki_import_pubkey_file( pubkey, &key);
if (rc != SSH_OK)
return SSH_AUTH_DENIED;
fprintf(stderr, "============= trying keyfile “%s.pub”\n", keyfile);
rc = ssh_userauth_try_publickey(session, NULL, key);
ssh_key_free(key);
if (rc!=SSH_AUTH_SUCCESS)
return SSH_AUTH_DENIED;
fprintf(stderr, "============= sleeping …\n");
sleep(5);
fprintf(stderr, "============= importing keyfile “%s”\n", keyfile);
rc = ssh_pki_import_privkey_file(keyfile, NULL, NULL, NULL, &key);
if (rc != SSH_OK)
return SSH_AUTH_DENIED;
fprintf(stderr, "============= trying keyfile “%s”\n", keyfile);
rc = ssh_userauth_publickey(session, NULL, key);
ssh_key_free(key);
return rc;
}
//----------------------------------------------------------------------
int main() {
int sockfd = socket( PF_LOCAL, SOCK_STREAM, 0 );
if (-1 == sockfd) {
perror("socket");
return 1;
}
const struct sockaddr_un sockaddr = {
strlen(SOCKET_PATH),
PF_LOCAL,
SOCKET_PATH
};
if ( connect(sockfd, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) ) {
perror("connect");
return 1;
}
ssh_session session;
session=ssh_new();
if (session == NULL) {
fprintf(stderr, "ssh_new failed\n");
return 1;
}
if (ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, STRINGIFY(SSH_LOG_FUNCTIONS)) < 0) {
fprintf(stderr, "ssh_options_set SSH_OPTIONS_LOG_VERBOSITY failed\n");
ssh_free(session);
return 1;
}
if (ssh_options_set(session, SSH_OPTIONS_USER, USERNAME) < 0) {
fprintf(stderr, "ssh_options_set SSH_OPTIONS_USER failed\n");
ssh_free(session);
return 1;
}
if (ssh_options_set(session, SSH_OPTIONS_HOST, HOSTNAME) < 0) {
fprintf(stderr, "ssh_options_set SSH_OPTIONS_HOST failed\n");
ssh_free(session);
return 1;
}
if (ssh_options_set(session, SSH_OPTIONS_FD, &sockfd) < 0) {
fprintf(stderr, "ssh_options_set SSH_OPTIONS_FD failed\n");
ssh_free(session);
return 1;
}
if (ssh_connect(session)){
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
ssh_disconnect(session);
ssh_free(session);
return 1;
}
else {
fprintf(stderr,"Connection OK!\n");
}
int auth_ok = auth_keyfile(session, CLIENT_KEYFILE);
if (auth_ok == SSH_AUTH_SUCCESS) {
fprintf(stderr, "authn ok!\n");
}
else {
fprintf(stderr, "authn failed!\n");
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <libssh/libssh.h>
#include <libssh/server.h>
#include <libssh/callbacks.h>
#define SOCKET_PATH "mysocket"
#define USERNAME "hank"
#define HOSTNAME "remote.host"
#define STRINGIFY(s) _STR(s)
#define _STR(s) #s
#define HOST_KEY_ED25519 "host_ed25519"
#define AUTHORIZED_KEYS_FILE "my_authorized_keys"
//----------------------------------------------------------------------
// copied from ssh_server_fork.c …
/* A userdata struct for session. */
struct session_data_struct {
/* Pointer to the channel the session will allocate. */
ssh_channel channel;
int auth_attempts;
int authenticated;
};
//----------------------------------------------------------------------
static int auth_publickey(ssh_session session,
const char *user,
struct ssh_key_struct *pubkey,
char signature_state,
void *userdata)
{
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
fprintf(stderr, "======= in auth_publickey\n");
(void) user;
(void) session;
if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
fprintf(stderr, "======= in auth_publickey - ret1\n");
return SSH_AUTH_SUCCESS;
}
if (signature_state != SSH_PUBLICKEY_STATE_VALID) {
fprintf(stderr, "======= in auth_publickey - ret2\n");
return SSH_AUTH_DENIED;
}
sdata->auth_attempts++;
// valid so far. Now look through authorized keys for a match
ssh_key key = NULL;
int result;
struct stat buf;
if (stat(AUTHORIZED_KEYS_FILE, &buf) == 0) {
fprintf(stderr, "Reading authorized keys file “%s” …\n", AUTHORIZED_KEYS_FILE);
result = ssh_pki_import_pubkey_file( AUTHORIZED_KEYS_FILE, &key );
if ((result != SSH_OK) || (key==NULL)) {
fprintf(stderr,
"Failed to import public key file %s\n",
AUTHORIZED_KEYS_FILE);
} else {
result = ssh_key_cmp( key, pubkey, SSH_KEY_CMP_PUBLIC );
ssh_key_free(key);
if (result == 0) {
sdata->authenticated = 1;
fprintf(stderr, "======= in auth_publickey - ret3 OK\n");
return SSH_AUTH_SUCCESS;
}
}
}
else {
perror("stat(" AUTHORIZED_KEYS_FILE ")");
}
// no matches
sdata->authenticated = 0;
fprintf(stderr, "======= in auth_publickey - ret4 NO\n");
return SSH_AUTH_DENIED;
}
int main() {
int servfd = socket( PF_LOCAL, SOCK_STREAM, 0 );
if (-1 == servfd) {
perror("socket");
return 1;
}
const struct sockaddr_un sockaddr = {
strlen(SOCKET_PATH),
PF_LOCAL,
SOCKET_PATH
};
unlink(SOCKET_PATH);
if ( bind(servfd, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) ) {
perror("bind");
return 1;
}
if ( listen(servfd, 1) ) {
perror("listen");
return 1;
}
fprintf(stderr, "waiting …\n");
int sockfd = accept(servfd, NULL, NULL);
fprintf(stderr, "got connection! Starting SSH …\n");
//----------------------------------------------------------------------
ssh_session session = ssh_new();
if (session == NULL) {
fprintf(stderr, "ssh_new failed\n");
return 1;
}
if (ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, STRINGIFY(SSH_LOG_FUNCTIONS)) < 0) {
fprintf(stderr, "ssh_options_set SSH_OPTIONS_LOG_VERBOSITY failed\n");
ssh_free(session);
return 1;
}
ssh_bind sshbind = ssh_bind_new();
if (sshbind == NULL) {
fprintf(stderr, "ssh_bind_new failed\n");
return 1;
}
if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY, STRINGIFY(SSH_LOG_FUNCTIONS)) < 0) {
fprintf(stderr, "ssh_bind_options_set SSH_BIND_OPTIONS_LOG_VERBOSITY failed\n");
ssh_free(session);
return 1;
}
if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, HOST_KEY_ED25519) < 0) {
fprintf(stderr, "ssh_bind_options_set SSH_BIND_OPTIONS_HOSTKEY failed\n");
ssh_free(session);
return 1;
}
int status = ssh_bind_accept_fd(sshbind, session, sockfd);
if (SSH_OK == status) {
fprintf(stderr, "ssh_bind_accept_fd OK\n");
}
else {
fprintf(stderr, "ssh_bind_accept_fd: %s\n", ssh_get_error(sshbind));
return 1;
}
//----------------------------------------------------------------------
/* Our struct holding information about the session. */
struct session_data_struct sdata = {
.channel = NULL,
.auth_attempts = 0,
.authenticated = 0,
};
struct ssh_server_callbacks_struct server_cb = {
.userdata = &sdata,
.auth_pubkey_function = auth_publickey,
};
ssh_callbacks_init(&server_cb);
ssh_set_server_callbacks(session, &server_cb);
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
//----------------------------------------------------------------------
if (ssh_handle_key_exchange(session)) {
printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session));
return 1;
}
else {
fprintf(stderr, "ssh_handle_key_exchange OK\n");
}
ssh_event event = ssh_event_new();
if (event == NULL) {
fprintf(stderr, "Could not create polling context\n");
return 1;
}
ssh_event_add_session(event, session);
while (sdata.authenticated == 0 && sdata.auth_attempts == 0) {
fprintf(stderr, "In loop …\n");
/* If the user has used up all attempts, or if he hasn't been able to
* authenticate in 10 seconds (n * 100ms), disconnect. */
if (sdata.auth_attempts > 0) {
break;
}
if (ssh_event_dopoll(event, 100) == SSH_ERROR) {
fprintf(stderr, "%s\n", ssh_get_error(session));
break;
}
}
ssh_event_free(event);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment