-
-
Save FGasper/4fb5b702489b9eb12c2133e9da5c5beb to your computer and use it in GitHub Desktop.
proof-of-concept: SSH authn via pre-existing sockets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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