sshd-socket-generator

Gbp-Pq: Name sshd-socket-generator.patch
This commit is contained in:
Ubuntu Developers 2024-04-10 14:39:11 +08:00 committed by lixiuwen
parent 07d2d6338d
commit c8ee260ebc
2 changed files with 310 additions and 1 deletions

View File

@ -17,6 +17,7 @@ srcdir=@srcdir@
top_srcdir=@top_srcdir@
abs_top_srcdir=@abs_top_srcdir@
abs_top_builddir=@abs_top_builddir@
systemd_system_generator_dir=$(shell pkg-config --variable=systemd_system_generator_dir systemd)
DESTDIR=
VPATH=@srcdir@
@ -69,7 +70,7 @@ MKDIR_P=@MKDIR_P@
.SUFFIXES: .lo
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT)
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) sshd-socket-generator$(EXEEXT)
XMSS_OBJS=\
ssh-xmss.o \
@ -134,6 +135,16 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \
sandbox-solaris.o uidswap.o $(SKOBJS)
SSHD_SOCKET_GEN_OBJS=sshd-socket-generator.o \
platform.o servconf.o groupaccess.o audit.o audit-linux.o \
auth2.o auth2-none.o auth2-gss.o \
auth2-passwd.o auth2-kbdint.o auth2-hostbased.o \
auth-options.o uidswap.o auth2-pubkey.o auth.o \
auth2-pubkeyfile.o auth-rhosts.o auth-passwd.o \
gss-serv.o auth2-chall.o auth-pam.o gss-serv-krb5.o \
loginrec.o auth-krb5.o auth-shadow.o \
monitor.o monitor_wrap.o
SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o
SCP_OBJS= scp.o progressmeter.o $(SFTP_CLIENT_OBJS)
@ -210,6 +221,9 @@ ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS)
$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS)
sshd-socket-generator$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHD_SOCKET_GEN_OBJS)
$(LD) -o $@ $(SSHD_SOCKET_GEN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS)
scp$(EXEEXT): $(LIBCOMPAT) libssh.a $(SCP_OBJS)
$(LD) -o $@ $(SCP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
@ -392,6 +406,7 @@ install-files:
$(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)5
$(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)8
$(MKDIR_P) $(DESTDIR)$(libexecdir)
$(MKDIR_P) $(DESTDIR)$(systemd_system_generator_dir)
$(MKDIR_P) -m 0755 $(DESTDIR)$(PRIVSEP_PATH)
$(INSTALL) -m 0755 $(STRIP_OPT) ssh$(EXEEXT) $(DESTDIR)$(bindir)/ssh$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) scp$(EXEEXT) $(DESTDIR)$(bindir)/scp$(EXEEXT)
@ -421,6 +436,7 @@ install-files:
$(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
$(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
$(INSTALL) -m 644 ssh-sk-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-sk-helper.8
$(INSTALL) -m 0755 $(STRIP_OPT) sshd-socket-generator$(EXEEXT) $(DESTDIR)$(systemd_system_generator_dir)/sshd-socket-generator$(EXEEXT)
install-sysconf:
$(MKDIR_P) $(DESTDIR)$(sysconfdir)
@ -478,6 +494,7 @@ uninstall:
-rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT)
-rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
-rm -f $(DESTDIR)$(systemd_system_generator_dir)/sshd-socket-generator$(EXEEXT)
-rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
-rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
-rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)

292
sshd-socket-generator.c Normal file
View File

@ -0,0 +1,292 @@
#include <errno.h>
#include <linux/limits.h>
#include <netdb.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "includes.h"
#include "hostfile.h" /* Needs to be included before auth.h */
#include "auth.h"
#include "kex.h"
#include "log.h"
#include "misc.h"
#include "monitor.h"
#include "ssh-gss.h" /* Needs to be included before monitor_wrap.h */
#include "monitor_wrap.h"
#include "pathnames.h"
#include "servconf.h"
#include "sshbuf.h"
#define MAX_LISTEN_STREAMS (16)
#define MAX_LISTEN_STREAM_LEN (NI_MAXHOST + NI_MAXSERV + sizeof("ListenAddress=[:]") + 1)
typedef char listen_stream_set[MAX_LISTEN_STREAMS][MAX_LISTEN_STREAM_LEN];
/* Global variables required for sshd config parsing. */
ServerOptions options = {};
struct sshbuf *cfg = NULL;
struct include_list includes = TAILQ_HEAD_INITIALIZER(includes);
/* Other global variables that are required for this to build, because of their
* use throughout the codebase. We do NOT use these variables for the
* generator. */
Authctxt *the_authctxt = NULL;
int privsep_is_preauth = 1;
int use_privsep = -1;
struct monitor *pmonitor = NULL;
struct ssh *the_active_state = NULL;
struct sshauthopt *auth_opts = NULL;
struct sshbuf *loginmsg = NULL;
static int listen_stream_set_append(listen_stream_set set, const char *listen_stream) {
size_t n;
if (!set)
return -EINVAL;
n = strnlen(listen_stream, MAX_LISTEN_STREAM_LEN);
if (n == MAX_LISTEN_STREAM_LEN)
return -EINVAL;
for (int i = 0; i < MAX_LISTEN_STREAMS; i++) {
if (strcmp(set[i], listen_stream) == 0)
return 0;
if (strnlen(set[i], MAX_LISTEN_STREAM_LEN) > 0)
continue;
memcpy(set[i], listen_stream, n);
return 0;
}
return -E2BIG;
}
static int listen_stream_set_len(listen_stream_set set) {
int r = 0;
if (!set)
return 0;
for (int i = 0; i < MAX_LISTEN_STREAMS; i++) {
if (strnlen(set[i], MAX_LISTEN_STREAM_LEN) > 0)
r++;
else
break;
}
return r;
}
static char *path_append(const char *base, const char *append) {
bool add_slash;
size_t n = 0, len_base, len_append;
char *path = NULL;
len_base = strnlen(base, PATH_MAX);
len_append = strnlen(append, PATH_MAX);
add_slash = base[len_base - 1] != '/';
path = calloc(len_base + len_append + (add_slash ? 2 : 1), sizeof(char));
if (!path)
return NULL;
memcpy(path, base, len_base);
n += len_base;
if (add_slash)
path[n++] = '/';
memcpy(path + n, append, len_append);
n += len_append;
path[n] = '\0';
return path;
}
static int fflush_and_check(FILE *f) {
errno = 0;
fflush(f);
if (ferror(f))
return errno > 0 ? -errno : -EIO;
return 0;
}
static int write_systemd_socket_file(const char *destdir) {
listen_stream_set listen_streams = {};
int num_listen_streams;
char *conf = NULL, *overridedir = NULL;
FILE *f = NULL;
int r;
overridedir = path_append(destdir, "ssh.socket.d");
if (!overridedir) {
r = -ENOMEM;
goto out;
}
if (mkdir(overridedir, 0755) < 0 && errno != EEXIST) {
r = -errno;
goto out;
}
conf = path_append(overridedir, "addresses.conf");
if (!conf) {
r = -ENOMEM;
goto out;
}
f = fopen(conf, "we");
if (!f) {
r = -errno;
goto out;
}
fprintf(f,
"# Automatically generated by sshd-socket-generator\n"
"\n[Socket]\n"
"ListenStream=\n");
for (u_int i = 0; i < options.num_listen_addrs; i++) {
for (struct addrinfo *ai = options.listen_addrs[i].addrs; ai; ai = ai->ai_next) {
char addr[NI_MAXHOST] = {}, port[NI_MAXSERV] = {},
listen_stream[MAX_LISTEN_STREAM_LEN] = {};
r = getnameinfo(ai->ai_addr, ai->ai_addrlen,
addr, sizeof(addr),
port, sizeof(port),
NI_NUMERICHOST|NI_NUMERICSERV);
if (r != 0) {
fprintf(stderr, "%s\n", gai_strerror(r));
r = r == EAI_SYSTEM ? -errno : -EINVAL;
goto out;
}
if (strcmp(addr, "0.0.0.0") == 0 || strcmp(addr, "::") == 0) {
/* If ListenAddress is 0.0.0.0 or ::, only
* write the port in ListenStream=. */
snprintf(listen_stream,
MAX_LISTEN_STREAM_LEN,
"ListenStream=%s",
port);
} else
snprintf(listen_stream,
MAX_LISTEN_STREAM_LEN,
"ListenStream=%s%s%s:%s",
ai->ai_family == AF_INET6 ? "[" : "",
addr,
ai->ai_family == AF_INET6 ? "]" : "",
port);
r = listen_stream_set_append(listen_streams, listen_stream);
if (r < 0)
goto out;
}
}
num_listen_streams = listen_stream_set_len(listen_streams);
if (num_listen_streams <= 0) {
/* We didn't generate anything useful, so clean up and leave
* ssh.socket as-is. */
r = -ENODATA;
goto out;
}
if (num_listen_streams == 1 && strcmp(listen_streams[0], "ListenStream=22") == 0) {
/* This is the default already specified in ssh.socket. No need
* to write the override. */
r = -ENODATA;
goto out;
}
for (int i = 0; i < num_listen_streams; i++)
fprintf(f, "%s\n", listen_streams[i]);
r = fflush_and_check(f);
if (r < 0)
goto out;
out:
if (f)
fclose(f);
if (r < 0) {
(void) remove(conf);
(void) remove(overridedir);
}
free(overridedir);
free(conf);
return r;
}
static int parse_sshd_config_options() {
struct connection_info *connection_info;
cfg = sshbuf_new();
if (!cfg)
return -ENOMEM;
initialize_server_options(&options);
load_server_config(_PATH_SERVER_CONFIG_FILE, cfg);
parse_server_config(&options, _PATH_SERVER_CONFIG_FILE, cfg, &includes, NULL, 0);
fill_default_server_options(&options);
connection_info = get_connection_info(NULL, 0, 0);
connection_info->test = 1;
parse_server_match_config(&options, &includes, connection_info);
return 0;
}
int main(int argc, char **argv) {
const char *destdir = NULL;
int r;
if (argc < 2) {
fprintf(stderr, "Expected at least one argument.\n");
return EXIT_FAILURE;
}
destdir = argv[1];
r = parse_sshd_config_options();
if (r < 0) {
fprintf(stderr, "Faild to parse sshd config: %s\n", strerror(-r));
return EXIT_FAILURE;
}
if (options.num_listen_addrs <= 0) {
/* No listen addresses configured? Don't generate anything. */
fprintf(stderr, "No listen addresses configured. Will not generate anything.\n");
return EXIT_SUCCESS;
}
r = write_systemd_socket_file(destdir);
if (r == -ENODATA) {
fprintf(stderr, "No custom listen addresses configured. Will not generated anything.\n");
return EXIT_SUCCESS;
}
if (r < 0) {
fprintf(stderr, "Failed to generate ssh.socket: %s\n", strerror(-r));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}