\ <ins > 2018/04/26 postscript
Write a shell function called find_agent
to resolve it manually each time.
It's certainly convenient to switch automatically, but there are few times when this is necessary, and LD_PRELOAD sometimes gets in the way when debugging, so there was not much merit ...
I have used github to check the connection of SSH_AUTH_SOCK. The key I usually use is also put in github, so I'm having trouble with ssh because it's about the timing of git push. Socket files should glob the pathname appropriately
find_agent () {
local GLOBS=("/tmp/com.apple.launchd.*/Listeners" "/tmp/ssh-*/agent.*");
for g in "${GLOBS[@]}"; do
for c in ${g}; do
SSH_AUTH_SOCK="$c";
[ ! -S "${SSH_AUTH_SOCK}" ] && continue;
ssh -T [email protected];
[ $? -eq 1 ] && return 0;
done;
done
}
</ins>
Below is the description of 2016/02/12
github https://github.com/takei-yuya/alt_ssh_auth_sock
I came to Akita on a ski trip, but I was free at the inn so I wrote it.
A story to prevent the problem that the reference of SSH_AUTH_SOCK used for ssh-agent transfer by detach / attach is misaligned when using screen at the connection destination of ssh.
In other words, this kind of thing
local $ # ssh-Enable agent forwarding and connect to hostA
local $ ssh -A hostA
hostA $ #Ssh automatically at the connection destination_AUTH_SOCK environment variable set
hostA $ declare -p SSH_AUTH_SOCK
declare -x SSH_AUTH_SOCK="/tmp/ssh-XXXXXXXXXX/agent.11111"
hostA $ #This socket is connected to the sshd for this session
hostA $ ps -p 11111
PID TTY TIME CMD
11111 ? 00:00:00 sshd
hostA $ #Even if there is no key on hostA, the key information is transferred through the socket.
hostA $ #You can connect to another host with key authentication
hostA $ ssh hostB
hostB $ exit
hostA $ #screen saves the environment variables when screen is started
hostA $ screen -S ssh_test
hostA(screen) $ declare -p SSH_AUTH_SOCK
declare -x SSH_AUTH_SOCK="/tmp/ssh-XXXXXXXXXX/agent.11111"
hostA(screen) $ ^A^D #Detach
hostA $ #This socket becomes invalid when the SSH session expires
hostA $ #Try to reconnect
hostA $ exit
local $ ssh -A hostA
hostA $ #The socket path changes because the session has changed
hostA $ declare -p SSH_AUTH_SOCK
declare -x SSH_AUTH_SOCK="/tmp/ssh-YYYYYYYYYY/agent.33333"
hostA $ #Old session sshd is gone
hostA $ ps -p 11111
PID TTY TIME CMD
hostA $ #But in the screen session, the environment variables are still out of date ...
hostA $ screen -x ssh_test
hostA(screen) $ declare -p SSH_AUTH_SOCK
declare -x SSH_AUTH_SOCK="/tmp/ssh-XXXXXXXXXX/agent.11111"
hostA(screen) $ #Old ssh-agent transfer does not connect ...
hostA(screen) $ ssh hostB
Permission denied (publickey).
So, it's been a long time, but this kind of phenomenon. I want to do something about this.
The cause is that the environment variables are not updated in the session on the screen.
Try using a mechanism called LD_PRELOAD.
Roughly speaking, it seems to be a mechanism to forcibly insert a dynamic library when starting a process. It can be used to hook or steal 400,000 system calls and library function calls.
The target function is getenv
. In other words, the idea of forcibly tampering with environment variables from the outside.
Check the current SSH_AUTH_SOCK
and if you can't connect to the socket, try another socket. The socket candidates to try are specified by the file glob pattern from another environment variable.
In other words
hostA(screen) $ ssh hostB
Permission denied (publickey).
hostA(screen) $ export LD_PRELOAD="/path/to/injection_lib"
hostA(screen) $ export ALT_SSH_AUTH_SOCK="/tmp/ssh-*/agent.*"
hostA(screen) $ ssh hostB
github: https://github.com/takei-yuya/alt_ssh_auth_sock
#define _GNU_SOURCE // for RTLD_NEXT
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#include <glob.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
//Static variable to save the original getenv
static char* (*_original_getenv)(const char *name) = NULL;
//It seems that you can create a function to execute before the main function by using the GNU extension.
static void _alt_ssh_auth_sock_init() __attribute__((constructor));
static void _alt_ssh_auth_sock_init() {
//Save the original getenv
_original_getenv = dlsym(RTLD_NEXT, "getenv");
}
//Make sure the socket is alive. ...... I'm just connecting.
int check_socket(const char* socket_file_path) {
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_file_path, sizeof(addr.sun_path) / sizeof(char));
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
int ret = connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));
close(fd);
return ret;
}
//Override the behavior of getenv
char* getenv(const char *name) {
if (!_original_getenv) {
//Something__attribute__((constructor))May not work, so just in case
_alt_ssh_auth_sock_init();
}
if (strcmp(name, "SSH_AUTH_SOCK") != 0) {
// SSH_AUTH_Except for SOCK, the original function is used as it is.
return _original_getenv(name);
}
char* ssh_auth_sock = _original_getenv("SSH_AUTH_SOCK");
if (!ssh_auth_sock) {
// SSH_AUTH_If SOCK is not defined, return as it is.
return ssh_auth_sock; // == NULL
}
char* alt_ssh_auth_sock = _original_getenv("ALT_SSH_AUTH_SOCK");
if (!alt_ssh_auth_sock) {
//If the alternative socket pattern is not given, nothing can be done, so give up and return as it is
return ssh_auth_sock;
}
if (check_socket(ssh_auth_sock) == 0) {
//If the current socket is alive, return as it is without glob expansion
return ssh_auth_sock;
}
//Expand glob pattern
glob_t pglob;
if (glob(alt_ssh_auth_sock, GLOB_NOSORT, NULL, &pglob) != 0) {
globfree(&pglob);
}
int i;
for (i = 0; i < pglob.gl_pathc; ++i) {
if (check_socket(pglob.gl_pathv[i]) == 0) {
//If you find a living socket
break;
}
}
if (i < pglob.gl_pathc) {
// SSH_AUTH_Overwrite SOCK
setenv("SSH_AUTH_SOCK", pglob.gl_pathv[i], 1);
ssh_auth_sock = _original_getenv("SSH_AUTH_SOCK");
}
globfree(&pglob);
return ssh_auth_sock;
}
All posted because it is short. The details are as I wrote in the comment, but after saving the original getenv, I am using it from within getenv to overwrite.
How to build
cc -Wall -fPIC -shared -o libaltsshauthsock.so alt_ssh_auth_sock.c -ldl
Maybe you need soname. A little suitable around here.
For the time being, I think it's okay to set environment variables in bashrc or something.
$ echo 'export LD_PRELOAD="/path/to/libaltsshauthsock.so"' >> ~/.bashrc
$ echo 'export ALT_SSH_AUTH_SOCK="/tmp/ssh-*/agent.*"' >> ~/.bashrc
All you have to do is use screen as usual. You should be able to use ssh and git without doing anything even if you repeat attaching / detaching and disconnecting the session.
TODO:
--Compatible with Mac --For Mac, it seems to use the environment variable DYLD_INSERT_LIBRARIES instead of LD_PRELOAD. --In addition, namespace? It seems that it is necessary to set the environment variable DYLD_FORCE_FLAT_NAMESPACE as well. --Make dylib with Makefile ―― …… But I don't have many chances to connect ssh to Mac ……. ――The cost of connecting the socket every time isn't it? ――I think it's huge, so I want to do something about it. ――Maybe the straightforward method is to set up a daemon that pipes one-to-many sockets while managing the life and death of sockets, and set the socket connected to that daemon to SSH_AUTH_SOCK. ――I tried to use gdb to hit a process, kick setenv, and forcibly rewrite the environment variables of that process, but I feel that it is too powerful. --Make it a proper implementation ――Would you like to check for errors? --Skiing ――I came to Akita to ski, so I will ski. Not for development.
Recommended Posts