diff --git a/util-linux-agetty-netlink.patch b/util-linux-agetty-netlink.patch index 139413f..cea20f8 100644 --- a/util-linux-agetty-netlink.patch +++ b/util-linux-agetty-netlink.patch @@ -1,8 +1,7 @@ -From 1ddc84875c150ca7c142adba9bfcd4bf4323a3c4 Mon Sep 17 00:00:00 2001 +From bf7c46ef9158f3baae6b637ebb73a24d8460d394 Mon Sep 17 00:00:00 2001 From: Stanislav Brabec Date: Wed, 9 Jul 2025 14:35:28 +0200 Subject: [PATCH 2/2] agetty: Implement netlink based IP processing -References: https://github.com/util-linux/util-linux/pull/3649 The current \4 and \6 issue file escapes implementation is inferior. It uses get getifaddrs() to get a list of IP addresses. This function does not @@ -48,8 +47,8 @@ so bad, as \a automatically skips interfaces without reliable addresses Signed-off-by: Stanislav Brabec --- term-utils/agetty.8.adoc | 6 + - term-utils/agetty.c | 414 ++++++++++++++++++++++----------------- - 2 files changed, 244 insertions(+), 176 deletions(-) + term-utils/agetty.c | 417 ++++++++++++++++++++++----------------- + 2 files changed, 246 insertions(+), 177 deletions(-) diff --git a/term-utils/agetty.8.adoc b/term-utils/agetty.8.adoc index a33f12a3f..6670498f5 100644 @@ -69,7 +68,7 @@ index a33f12a3f..6670498f5 100644 Insert the baudrate of the current line. diff --git a/term-utils/agetty.c b/term-utils/agetty.c -index f65e511ca..1f5d937e4 100644 +index 5e564c4f0..c37417e1e 100644 --- a/term-utils/agetty.c +++ b/term-utils/agetty.c @@ -32,10 +32,7 @@ @@ -109,7 +108,15 @@ index f65e511ca..1f5d937e4 100644 char *mem_old; #endif unsigned int do_tcsetattr : 1, -@@ -1603,81 +1603,7 @@ done: +@@ -364,6 +364,7 @@ int main(int argc, char **argv) + }; + struct issue issue = { + .mem = NULL, ++ .nl.fd = -1 + }; + char *login_argv[LOGIN_ARGV_MAX + 1]; + int login_argc = 0; +@@ -1603,81 +1604,7 @@ done: } #ifdef AGETTY_RELOAD @@ -192,7 +199,7 @@ index f65e511ca..1f5d937e4 100644 { char buffer[sizeof(struct inotify_event) + NAME_MAX + 1]; fd_set rfds; -@@ -1711,9 +1637,9 @@ static int wait_for_term_input(int fd) +@@ -1711,9 +1638,9 @@ static int wait_for_term_input(int fd) FD_SET(inotify_fd, &rfds); nfds = max(nfds, inotify_fd); } @@ -205,7 +212,7 @@ index f65e511ca..1f5d937e4 100644 } /* If waiting fails, just fall through, presumably reading input will fail */ -@@ -1725,9 +1651,10 @@ static int wait_for_term_input(int fd) +@@ -1725,9 +1652,10 @@ static int wait_for_term_input(int fd) } @@ -219,7 +226,7 @@ index f65e511ca..1f5d937e4 100644 /* Just drain the inotify buffer */ } else if (inotify_fd >= 0 && FD_ISSET(inotify_fd, &rfds)) { -@@ -1937,11 +1864,44 @@ static void eval_issue_file(struct issue *ie, +@@ -1937,11 +1865,44 @@ static void eval_issue_file(struct issue *ie, struct options *op, struct termios *tp) { @@ -241,7 +248,7 @@ index f65e511ca..1f5d937e4 100644 + netlink_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; + + /* Already initialized? */ -+ if (ie->nl.fd) ++ if (ie->nl.fd >= 0) + goto skip; + /* Prepare netlink. */ + ul_nl_init(&(ie->nl)); @@ -261,13 +268,13 @@ index f65e511ca..1f5d937e4 100644 + /* In case of any error, the addrq list is just empty, and we can use + * the code without any error checking. */ + ul_nl_close(&(ie->nl)); -+ ie->nl.fd = 0; ++ ie->nl.fd = -1; +skip: +#endif /* * The custom issue file or directory list specified by: * agetty --issue-file -@@ -1986,11 +1946,6 @@ static void eval_issue_file(struct issue *ie, +@@ -1986,11 +1947,6 @@ static void eval_issue_file(struct issue *ie, issuedir_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_DIRNAME, op, tp); done: @@ -279,7 +286,16 @@ index f65e511ca..1f5d937e4 100644 if (ie->output) { fclose(ie->output); ie->output = NULL; -@@ -2032,13 +1987,19 @@ again: +@@ -2002,7 +1958,7 @@ done: + */ + static void show_issue(struct options *op) + { +- struct issue ie = { .output = NULL }; ++ struct issue ie = { .output = NULL, .nl.fd = -1 }; + struct termios tp; + + memset(&tp, 0, sizeof(struct termios)); +@@ -2032,13 +1988,19 @@ again: puts(_("[press ENTER to login]")); #ifdef AGETTY_RELOAD /* reload issue */ @@ -293,15 +309,15 @@ index f65e511ca..1f5d937e4 100644 - goto again; + { + /* TODO: Close to set netlink_groups again using pass 1 */ -+ /* if (ie->nl.fd) ul_nl_close(&(ie->nl)); -+ * ie->nl.fd = NULL; */ ++ /* if (ie->nl.fd >= 0) ul_nl_close(&(ie->nl)); ++ * ie->nl.fd = -1; */ + + goto again; + } } } #endif -@@ -2168,7 +2129,7 @@ static char *get_logname(struct issue *ie, struct options *op, struct termios *t +@@ -2168,7 +2130,7 @@ static char *get_logname(struct issue *ie, struct options *op, struct termios *t no_reload: #ifdef AGETTY_RELOAD @@ -310,16 +326,16 @@ index f65e511ca..1f5d937e4 100644 /* refresh prompt -- discard input data, clear terminal * and call do_prompt() again */ -@@ -2177,6 +2138,8 @@ static char *get_logname(struct issue *ie, struct options *op, struct termios *t +@@ -2177,6 +2139,8 @@ static char *get_logname(struct issue *ie, struct options *op, struct termios *t eval_issue_file(ie, op, tp); if (!issue_is_changed(ie)) goto no_reload; -+ /* if (ie->nl.fd) ul_nl_close(&(ie->nl)); -+ * ie->nl.fd = NULL; */ ++ /* if (ie->nl.fd >= 0) ul_nl_close(&(ie->nl)); ++ * ie->nl.fd = -1; */ tcflush(STDIN_FILENO, TCIFLUSH); if ((op->flags & F_VCONSOLE) && (op->flags & F_NOCLEAR) == 0) -@@ -2576,92 +2539,170 @@ static void log_warn(const char *fmt, ...) +@@ -2576,92 +2540,170 @@ static void log_warn(const char *fmt, ...) va_end(ap); } @@ -560,7 +576,7 @@ index f65e511ca..1f5d937e4 100644 } /* -@@ -2860,26 +2901,47 @@ static void output_special_char(struct issue *ie, +@@ -2860,26 +2902,47 @@ static void output_special_char(struct issue *ie, case '4': case '6': { diff --git a/util-linux-agetty-ssh-host-keys.patch b/util-linux-agetty-ssh-host-keys.patch new file mode 100644 index 0000000..765353a --- /dev/null +++ b/util-linux-agetty-ssh-host-keys.patch @@ -0,0 +1,111 @@ +From 275a215e3ee02d8240d22b2bc61abcdd6b24c35f Mon Sep 17 00:00:00 2001 +From: Stanislav Brabec +Date: Fri, 8 Aug 2025 02:39:28 +0200 +Subject: [PATCH] agetty: Implement \k: print ssh host keys + +Implement new keyword \k that will print all ssh host keys. + +Signed-off-by: Stanislav Brabec +--- + term-utils/agetty.8.adoc | 3 +++ + term-utils/agetty.c | 56 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 59 insertions(+) + +diff --git a/term-utils/agetty.8.adoc b/term-utils/agetty.8.adoc +index 6670498f5..f84ec2e1e 100644 +--- a/term-utils/agetty.8.adoc ++++ b/term-utils/agetty.8.adoc +@@ -304,6 +304,9 @@ Insert the string "1 user" or " users" where is the number of current use + v:: + Insert the version of the OS, that is, the build-date and such. + ++k:: ++Print host ssh keys. ++ + An example. On my system, the following _/etc/issue_ file: + + .... +diff --git a/term-utils/agetty.c b/term-utils/agetty.c +index c37417e1e..d53882ef7 100644 +--- a/term-utils/agetty.c ++++ b/term-utils/agetty.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + + #include "strutils.h" +@@ -2706,6 +2707,58 @@ static void dump_iface_all(struct issue *ie, + fputs("\n", ie->output); + } + ++#define SSH_KEYGEN_BUFFER_SIZE 512 ++void print_ssh_keys(FILE *fd) { ++ glob_t glob_result; ++ int rc; ++ ++ rc = glob("/etc/ssh/ssh_host_*_key.pub", 0, NULL, &glob_result); ++ if (rc != 0) { ++ if (rc == GLOB_NOMATCH) { ++ fprintf(fd, _("No SSH host keys found.\n")); ++ } ++ globfree(&glob_result); ++ return; ++ } ++ ++ for (size_t i = 0; i < glob_result.gl_pathc; i++) { ++ int pipefd[2]; ++ pid_t pid; ++ ++ if (pipe(pipefd) == -1) { ++ continue; ++ } ++ pid = fork(); ++ if (pid == -1) { ++ close(pipefd[0]); ++ close(pipefd[1]); ++ continue; ++ } ++ if (pid == 0) { ++ char *argv[] = {"ssh-keygen", "-l", "-f", glob_result.gl_pathv[i], NULL}; ++ ++ close(pipefd[0]); ++ dup2(pipefd[1], STDOUT_FILENO); ++ close(pipefd[1]); ++ execvp("ssh-keygen", argv); ++ return; ++ } else { ++ char buffer[SSH_KEYGEN_BUFFER_SIZE]; ++ ++ close(pipefd[1]); ++ wait(NULL); ++ if (fgets(buffer, sizeof(buffer), fdopen(pipefd[0], "r")) != NULL) { ++ char field2[SSH_KEYGEN_BUFFER_SIZE], field4[SSH_KEYGEN_BUFFER_SIZE]; ++ if (sscanf(buffer, "%*s %s %*s %s", field2, field4) == 2) { ++ fprintf(fd, _("SSH host key: %s %s\n"), field2, field4); ++ } ++ } ++ close(pipefd[0]); ++ } ++ } ++ globfree(&glob_result); ++ return; ++} + /* + * parses \x{argument}, if not argument specified then returns NULL, the @fd + * has to point to one char after the sequence (it means '{'). +@@ -2944,6 +2997,9 @@ static void output_special_char(struct issue *ie, + } + break; + #endif ++ case 'k': ++ print_ssh_keys(ie->output); ++ break; + default: + putc(c, ie->output); + break; +-- +2.48.1 + diff --git a/util-linux-lib-netlink.patch b/util-linux-lib-netlink.patch index e931499..d4902e9 100644 --- a/util-linux-lib-netlink.patch +++ b/util-linux-lib-netlink.patch @@ -1,8 +1,7 @@ -From 7d11ab55ce140cb03ffebb55856c0a766853d83e Mon Sep 17 00:00:00 2001 +From 02b917ba6fa43908a39f15c9496de04910044c0e Mon Sep 17 00:00:00 2001 From: Stanislav Brabec Date: Wed, 9 Jul 2025 14:29:10 +0200 Subject: [PATCH 1/2] New netlink library -References: https://github.com/util-linux/util-linux/pull/3649 To support netlink and IP address processing, two new library files were added: @@ -18,13 +17,13 @@ etc. Signed-off-by: Stanislav Brabec --- include/Makemodule.am | 2 + - include/netaddrq.h | 124 +++++++ + include/netaddrq.h | 124 ++++++++ include/netlink.h | 171 ++++++++++ lib/Makemodule.am | 11 + lib/meson.build | 2 + - lib/netaddrq.c | 729 ++++++++++++++++++++++++++++++++++++++++++ + lib/netaddrq.c | 716 ++++++++++++++++++++++++++++++++++++++++++ lib/netlink.c | 465 +++++++++++++++++++++++++++ - 7 files changed, 1504 insertions(+) + 7 files changed, 1491 insertions(+) create mode 100644 include/netaddrq.h create mode 100644 include/netlink.h create mode 100644 lib/netaddrq.c @@ -406,10 +405,10 @@ index 25febbc19..8734108a3 100644 randutils.c diff --git a/lib/netaddrq.c b/lib/netaddrq.c new file mode 100644 -index 000000000..11730cf07 +index 000000000..67a43cb85 --- /dev/null +++ b/lib/netaddrq.c -@@ -0,0 +1,729 @@ +@@ -0,0 +1,716 @@ +/* + * Netlink address quality rating list builder + * @@ -503,7 +502,7 @@ index 000000000..11730cf07 + +#define DBG_CASE(x) case x: str = #x; break +#define DBG_CASE_DEF8(x) default: snprintf(strx+2, 3, "%02hhx", x); str = strx; break -+static char *ip_rating(enum ul_netaddrq_ip_rating q) ++static char *ip_rating_as_string(enum ul_netaddrq_ip_rating q) +{ + char *str; + static char strx[5] = "0x"; @@ -565,11 +564,7 @@ index 000000000..11730cf07 + DBG(LIST, ul_debugobj(addrq, + "new ifa_index in addrq")); + if (!(ifaceq = malloc(sizeof(struct ul_netaddrq_iface)))) -+ { -+ DBG(LIST, ul_debugobj(addrq, -+ "malloc() 1 failed")); -+ return -1; -+ } ++ return -ENOMEM; + INIT_LIST_HEAD(&(ifaceq->ip_quality_list_4)); + INIT_LIST_HEAD(&(ifaceq->ip_quality_list_6)); + ifaceq->ifa_index = nl->addr.ifa_index; @@ -602,7 +597,7 @@ index 000000000..11730cf07 + list_for_each(li, ipq_list) { + ipq = list_entry(li, struct ul_netaddrq_ip, entry); + if (ipq->addr->address_len == nl->addr.address_len) -+ if (memcmp(ipq->addr->address, nl->addr.address, ++ if (!memcmp(ipq->addr->address, nl->addr.address, + nl->addr.address_len)) + break; + } @@ -618,17 +613,13 @@ index 000000000..11730cf07 + + addr = ul_nl_addr_dup(&(nl->addr)); + if (!addr) { -+ DBG(LIST, ul_debugobj(addrq, -+ "ul_nl_addr_dup() failed")); -+ rc = -1; ++ rc = -ENOMEM; + goto error; + } + if (ipq == NULL) { + if (!(ipq = malloc(sizeof(struct ul_netaddrq_ip)))) + { -+ DBG(LIST, ul_debugobj(addrq, -+ "malloc() 3 failed")); -+ rc = -1; ++ rc = -ENOMEM; + ul_nl_addr_free(addr); + goto error; + } @@ -645,7 +636,7 @@ index 000000000..11730cf07 + DBG(ADDRQ, + ul_debugobj(addrq, "%s rating: %s", + ul_nl_addr_ntop_address(&(nl->addr)), -+ ip_rating(ipq->quality))); ++ ip_rating_as_string(ipq->quality))); + } else { + /* UL_NL_RTM_DEL */ + if (ipq == NULL) @@ -689,18 +680,14 @@ index 000000000..11730cf07 + struct ul_netaddrq_data *addrq; + + netaddrq_init_debug(); -+ if (!(nl->data_addr = malloc(sizeof(struct ul_netaddrq_data)))) -+ return -1; ++ if (!(nl->data_addr = calloc(1, sizeof(struct ul_netaddrq_data)))) ++ return -ENOMEM; + nl->callback_addr = callback_addrq; + addrq = UL_NETADDRQ_DATA(nl); + addrq->callback_pre = callback_pre; + addrq->callback_post = callback_post; + addrq->callback_data = data; -+ addrq->nifaces = 0; -+ addrq->overflow = false; + INIT_LIST_HEAD(&(addrq->ifaces)); -+ addrq->ifaces_change_4 = false; -+ addrq->ifaces_change_6 = false; + DBG(LIST, ul_debugobj(addrq, "callback initialized")); + return 0; +} @@ -725,7 +712,7 @@ index 000000000..11730cf07 + DBG(BEST, + ul_debugobj((*best), "%s -> best[%s]", + ul_nl_addr_ntop_address(ipq->addr), -+ ip_rating(ipq->quality))); ++ ip_rating_as_string(ipq->quality))); + (*best)[ipq->quality] = ipq; + } + @@ -733,7 +720,7 @@ index 000000000..11730cf07 + { + threshold = ipq->quality; + DBG(BEST, -+ ul_debug("threshold %s", ip_rating(threshold))); ++ ul_debug("threshold %s", ip_rating_as_string(threshold))); + + } + } @@ -793,8 +780,7 @@ index 000000000..11730cf07 + *threshold = ul_netaddrq_bestaddr(nl, best_ifaceq, &best, ifa_family); + if (best[*threshold]) + return ul_nl_addr_ntop_address(best[*threshold]->addr); -+ else -+ return NULL; ++ return NULL; +} + +struct ul_netaddrq_iface *ul_netaddrq_iface_by_name(const struct ul_nl_data *nl, @@ -1141,7 +1127,7 @@ index 000000000..11730cf07 +#endif /* TEST_PROGRAM_NETADDRQ */ diff --git a/lib/netlink.c b/lib/netlink.c new file mode 100644 -index 000000000..c57be4ce0 +index 000000000..fbe04dd4c --- /dev/null +++ b/lib/netlink.c @@ -0,0 +1,465 @@ @@ -1373,7 +1359,7 @@ index 000000000..c57be4ce0 + +int ul_nl_process(struct ul_nl_data *nl, bool async, bool loop) +{ -+ char buf[4096]; ++ char buf[BUFSIZ]; + struct sockaddr_nl snl; + struct nlmsghdr *nh; + int rc; @@ -1476,20 +1462,21 @@ index 000000000..c57be4ce0 + +struct ul_nl_addr *ul_nl_addr_dup (struct ul_nl_addr *addr) { + struct ul_nl_addr *newaddr; -+ newaddr = malloc(sizeof(struct ul_nl_addr)); -+ if (!newaddr) goto error1; ++ newaddr = calloc(1, sizeof(struct ul_nl_addr)); ++ if (!newaddr) ++ goto error; + memcpy(newaddr, addr, sizeof(struct ul_nl_addr)); + if (addr->ifa_address_len) { + newaddr->ifa_address = malloc(addr->ifa_address_len); + if (!newaddr->ifa_address) -+ goto error2; ++ goto error; + memcpy(newaddr->ifa_address, addr->ifa_address, + addr->ifa_address_len); + } + if (addr->ifa_local_len) { + newaddr->ifa_local = malloc(addr->ifa_local_len); + if (!newaddr->ifa_local) -+ goto error3; ++ goto error; + memcpy(newaddr->ifa_local, addr->ifa_local, + addr->ifa_local_len); + } @@ -1497,22 +1484,21 @@ index 000000000..c57be4ce0 + newaddr->address = newaddr->ifa_local; + else + newaddr->address = newaddr->ifa_address; -+ if ((newaddr->ifname = strdup(addr->ifname))) -+ return newaddr; -+ free(newaddr->ifa_local); -+error3: -+ free(newaddr->ifa_address); -+error2: -+ free(newaddr); -+error1: ++ if (!(newaddr->ifname = strdup(addr->ifname))) ++ goto error; ++ return newaddr; ++error: ++ ul_nl_addr_free(newaddr); + return NULL; +} + +void ul_nl_addr_free (struct ul_nl_addr *addr) { -+ free(addr->ifa_address); -+ free(addr->ifa_local); -+ free(addr->ifname); -+ free(addr); ++ if (addr) { ++ free(addr->ifa_address); ++ free(addr->ifa_local); ++ free(addr->ifname); ++ free(addr); ++ } +} + +const char *ul_nl_addr_ntop (const struct ul_nl_addr *addr, int addrid) { diff --git a/util-linux.changes b/util-linux.changes index 2eecd84..a6d2332 100644 --- a/util-linux.changes +++ b/util-linux.changes @@ -1,3 +1,12 @@ +------------------------------------------------------------------- +Mon Aug 11 23:54:47 UTC 2025 - Stanislav Brabec + +- Implement escape code for printing of ssh host keys in agetty + issue file (util-linux-agetty-ssh-host-keys.patch. +- Include fixes from + https://github.com/util-linux/util-linux/pull/3649 (jsc#PED-8734, + util-linux-lib-netlink.patch, util-linux-agetty-netlink.patch). + ------------------------------------------------------------------- Thu Jul 24 10:35:23 UTC 2025 - Dr. Werner Fink diff --git a/util-linux.spec b/util-linux.spec index 62226f3..e8fc51a 100644 --- a/util-linux.spec +++ b/util-linux.spec @@ -114,6 +114,8 @@ Patch5: static_lib.patch Patch6: util-linux-lib-netlink.patch # PATCH-FEATURE-UPSTREAM util-linux-agetty-netlink.patch boo1139983 jsc#PED-8734 sbrabec@suse.com -- Implement netlink based IP address detection and issue reload. Patch7: util-linux-agetty-netlink.patch +# PATCH-FEATURE-OPENSUSE util-linux-agetty-ssh-host-keys.patch sbrabec@suse.com -- Implement escape code for printing of ssh host keys in agetty issue file. +Patch8: util-linux-agetty-ssh-host-keys.patch BuildRequires: audit-devel BuildRequires: bc BuildRequires: binutils-devel