Используйте ssh -A
или установите эквивалент в вашем /etc/ssh/ssh_config
файле (на вашей локальной машине:
-A Enables forwarding of the authentication agent connection. This
can also be specified on a per-host basis in a configuration
file.
Agent forwarding should be enabled with caution. Users with the
ability to bypass file permissions on the remote host (for the
agent's UNIX-domain socket) can access the local agent through
the forwarded connection. An attacker cannot obtain key mate‐
rial from the agent, however they can perform operations on the
keys that enable them to authenticate using the identities
loaded into the agent.
В вашем /etc/ssh/ssh_config
вы должны добавить/установить:
ForwardAgent yes
Он получает pid через вспомогательные данные SCM_CREDENTIALS
на сокете unix с помощью recvmsg()
, см. unix(7)
. Учетные данные не обязательно отправлять явно.
Пример:
$ cc -Wall scm_cred.c -o scm_cred
$./scm_cred
scm_cred: received from 10114: pid=10114 uid=2000 gid=2000
Процессы с данными CAP_SYS_ADMIN
могут отправлять любой pid через SCM_CREDENTIALS
; в случае systemd-journald
это означает, что они могут подделывать записи, как если бы они были зарегистрированы другим процессом:
# cc -Wall fake.c -o fake
# setcap CAP_SYS_ADMIN+ep fake
$./fake `pgrep -f /usr/sbin/sshd`
# journalctl --no-pager -n 1
...
Dec 29 11:04:57 debin sshd[419]: fake log message from 14202
# rm fake
# lsb_release -d
Description: Debian GNU/Linux 9.6 (stretch)
systemd-journald
обрабатывает дейтаграммы и учетные данные, отправленные через вспомогательные данные, в функцииserver_process_datagram()
из journald-server.c
. Обе стандартные функции syslog(3)
из libc
и sd_journal_sendv()
из libsystemd
будут отправлять свои данные через сокет SOCK_DGRAM
по умолчанию, а getsockopt(SO_PEERCRED)
не работает с дейтаграммами (без установления соединения ). Ни systemd-journald
, ни rsyslogd
не принимают соединения SOCK_STREAM
на /dev/log
.
скм _доп.с
#define _GNU_SOURCE 1
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <err.h>
int main(void){
int fd[2]; pid_t pid;
if(socketpair(AF_LOCAL, SOCK_DGRAM, 0, fd)) err(1, "socketpair");
if((pid = fork()) == -1) err(1, "fork");
if(pid){ /* parent */
int on = 1;
union {
struct cmsghdr h;
char data[CMSG_SPACE(sizeof(struct ucred))];
} buf;
struct msghdr m = {0};
struct ucred *uc = (struct ucred*)CMSG_DATA(&buf.h);
m.msg_control = &buf;
m.msg_controllen = sizeof buf;
if(setsockopt(fd[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof on))
err(1, "setsockopt");
if(recvmsg(fd[0], &m, 0) == -1) err(1, "recvmsg");
warnx("received from %d: pid=%d uid=%d gid=%d", pid,
uc->pid, uc->uid, uc->gid);
}else /* child */
write(fd[1], 0, 0);
return 0;
}
фейк.с
#define _GNU_SOURCE 1
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
int main(int ac, char **av){
union {
struct cmsghdr h;
char data[CMSG_SPACE(sizeof(struct ucred))];
} cm;
int fd; char buf[256];
struct ucred *uc = (struct ucred*)CMSG_DATA(&cm.h);
struct msghdr m = {0};
struct sockaddr_un ua = {AF_UNIX, "/dev/log"};
struct iovec iov = {buf};
if((fd = socket(AF_LOCAL, SOCK_DGRAM, 0)) == -1) err(1, "socket");
if(connect(fd, (struct sockaddr*)&ua, SUN_LEN(&ua))) err(1, "connect");
m.msg_control = &cm;
m.msg_controllen = cm.h.cmsg_len = CMSG_LEN(sizeof(struct ucred));
cm.h.cmsg_level = SOL_SOCKET;
cm.h.cmsg_type = SCM_CREDENTIALS;
uc->pid = ac > 1 ? atoi(av[1]) : getpid();
uc->uid = ac > 2 ? atoi(av[2]) : geteuid();
uc->gid = ac > 3 ? atoi(av[3]) : getegid();
iov.iov_len = snprintf(buf, sizeof buf, "<13>%s from %d",
ac > 4 ? av[4] : "fake log message", getpid());
if(iov.iov_len >= sizeof buf) errx(1, "message too long");
m.msg_iov = &iov;
m.msg_iovlen = 1;
if(sendmsg(fd, &m, 0) == -1) err(1, "sendmsg");
return 0;
}
EUID, EGID и PID исходного клиентского процесса, который подключился к потоковому сокету AF_LOCAL
в /run/systemd/journal/stdout
, доступны из ядра через параметр сокета SO_PEERCRED
, , который он использует . UCSPI -Инструменты UNIX получают ту же информацию с помощью одного и того же системного вызова.
Дочерние сервисные процессы, конечно, наследуют свои стандартные файловые дескрипторы ввода-вывода, уже открытые (, если только родительский сервисный процесс не изменит это, конечно ), и поэтому systemd-journald
все выходные данные журнала имеют учетные данные исходного родительский процесс.
Выходные данные журнала, созданные через сокет AF_LOCAL
в /run/systemd/journal/socket
, говорят о том, что идиосинкразический протокол systemd-journald
поступает через сокет дейтаграммы, а не через поток. Этот сокет помечен с помощью параметра сокета SO_PASSCRED
, чтобы ядро записывало одну и ту же информацию в каждую отправленную дейтаграмму, которая извлекается из каждой дейтаграммы с помощью systemd-journald
.
getsockopt()
. Руководство Linux-программиста . 2017 -09 -15. socket
. Руководство Linux-программиста . 2018 -02 -02. local-stream-socket-accept
. Направляющая ноша . Программное обеспечение.