Compare commits

..

3 Commits

Author SHA1 Message Date
Alejandro Colomar
7d974e3e9b configure.ac: Release 4.15.2
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2024-06-21 11:15:34 +02:00
Serge Hallyn
c53b76cc49 configure.ac: specify tar-pax to avoid 99 char filename limit
Signed-off-by: Serge Hallyn <serge@hallyn.com>
Cherry-picked-from: 9b7d786b6f ("configure.ac: specify tar-pax to avoid 99 char filename limit")
Link: <https://github.com/shadow-maint/shadow/pull/1021#issuecomment-2167025950>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2024-06-21 11:15:33 +02:00
Alejandro Colomar
ec00428f90 lib/csrand.c: Fix the lower part of the domain of csrand_uniform()
I accidentally broke this code during an un-optimization.  We need to
start from a random value of the width of the limit, that is, 32 bits.

Thanks to Jason for pointing to his similar code in the kernel, which
made me see my mistake.

Fixes: 2a61122b5e ("Unoptimize the higher part of the domain of csrand_uniform()")
Closes: <https://github.com/shadow-maint/shadow/issues/1015>
Reported-by: Michael Brunnbauer <https://github.com/michaelbrunnbauer>
Link: <https://git.zx2c4.com/linux-rng/tree/drivers/char/random.c#n535>
Cc: "Jason A. Donenfeld" <Jason@zx2c4.com>
Link: <https://github.com/shadow-maint/shadow/pull/638>
Link: <https://github.com/shadow-maint/shadow/issues/634>
Link: <https://github.com/shadow-maint/shadow/pull/624>
Tested-by: Michael Brunnbauer <https://github.com/michaelbrunnbauer>
Reviewed-by: Michael Brunnbauer <https://github.com/michaelbrunnbauer>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Cherry-picked-from: 4119a2dce564 ("lib/csrand.c: Fix the lower part of the domain of csrand_uniform()")
Cc: "Serge E. Hallyn" <serge@hallyn.com>
Link: <https://github.com/shadow-maint/shadow/pull/1025>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2024-06-21 10:57:17 +02:00
16 changed files with 301 additions and 71 deletions

View File

@@ -1,10 +1,10 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
m4_define([libsubid_abi_major], 5)
m4_define([libsubid_abi_major], 4)
m4_define([libsubid_abi_minor], 0)
m4_define([libsubid_abi_micro], 0)
m4_define([libsubid_abi], [libsubid_abi_major.libsubid_abi_minor.libsubid_abi_micro])
AC_INIT([shadow], [4.16.0], [pkg-shadow-devel@lists.alioth.debian.org], [],
AC_INIT([shadow], [4.15.2], [pkg-shadow-devel@lists.alioth.debian.org], [],
[https://github.com/shadow-maint/shadow])
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects tar-pax])
AC_CONFIG_MACRO_DIRS([m4])
@@ -159,6 +159,13 @@ fi])
AC_DEFINE_UNQUOTED(PASSWD_PROGRAM, "$shadow_cv_passwd_dir/passwd",
[Path to passwd program.])
dnl XXX - quick hack, should disappear before anyone notices :).
dnl XXX - I just read the above message :).
if test "$ac_cv_func_ruserok" = "yes"; then
AC_DEFINE(RLOGIN, 1, [Define if login should support the -r flag for rlogind.])
AC_DEFINE(RUSEROK, 0, [Define to the ruserok() "success" return value (0 or 1).])
fi
AC_ARG_ENABLE(shadowgrp,
[AS_HELP_STRING([--enable-shadowgrp], [enable shadow group support @<:@default=yes@:>@])],
[case "${enableval}" in

View File

@@ -119,6 +119,7 @@ libshadow_la_SOURCES = \
pwdcheck.c \
pwmem.c \
remove_tree.c \
rlogin.c \
root_flag.c \
run_part.h \
run_part.c \

View File

@@ -23,6 +23,7 @@
#include "sizeof.h"
static uint32_t csrand32(void);
static uint32_t csrand_uniform32(uint32_t n);
static unsigned long csrand_uniform_slow(unsigned long n);
@@ -97,6 +98,13 @@ csrand_interval(unsigned long min, unsigned long max)
}
static uint32_t
csrand32(void)
{
return csrand();
}
/*
* Fast Random Integer Generation in an Interval
* ACM Transactions on Modeling and Computer Simulation 29 (1), 2019
@@ -109,12 +117,12 @@ csrand_uniform32(uint32_t n)
uint64_t r, mult;
if (n == 0)
return csrand();
return csrand32();
bound = -n % n; // analogous to `2^32 % n`, since `x % y == (x-y) % y`
do {
r = csrand();
r = csrand32();
mult = r * n;
rem = mult; // analogous to `mult % 2^32`
} while (rem < bound); // p = (2^32 % n) / 2^32; W.C.: n=2^31+1, p=0.5

View File

@@ -131,11 +131,6 @@ void nss_init(const char *nsswitch_path) {
fprintf(shadow_logfd, "%s did not provide @find_subid_owners@\n", libname);
goto close_lib;
}
subid_nss->free = dlsym(h, "shadow_subid_free");
if (!subid_nss->free) {
fprintf(shadow_logfd, "%s did not provide @subid_free@\n", libname);
goto close_lib;
}
subid_nss->handle = h;
goto done;

View File

@@ -284,19 +284,6 @@ struct subid_nss_ops {
*/
enum subid_status (*find_subid_owners)(unsigned long id, enum subid_type id_type, uid_t **uids, int *count);
/*
* nss_free: free a memory block allocated by a subid plugin.
*
* @ptr - a pointer to a memory block to deallocate
*
* Some routines of subid_nss_ops allocate memory which should be freed by
* caller after use. In order to deallocate that memory block, one should
* use this routine to release that memory. By default, this function
* pointer is set to free(3) for backward compatibility. However, it is
* strongly recommended to define this routine explicitly.
*/
void (*free)(void *ptr);
/* The dlsym handle to close */
void *handle;
};
@@ -369,6 +356,10 @@ unsigned long csrand_interval (unsigned long min, unsigned long max);
/* remove_tree.c */
extern int remove_tree (const char *root, bool remove_root);
/* rlogin.c */
extern int do_rlogin(const char *remote_host, char *name, size_t namesize,
char *term, size_t termsize);
/* root_flag.c */
extern void process_root_flag (const char* short_opt, int argc, char **argv);

135
lib/rlogin.c Normal file
View File

@@ -0,0 +1,135 @@
/*
* SPDX-FileCopyrightText: 1989 - 1994, Julianne Frances Haugh
* SPDX-FileCopyrightText: 1996 - 1999, Marek Michałkiewicz
* SPDX-FileCopyrightText: 2003 - 2005, Tomasz Kłoczko
* SPDX-FileCopyrightText: 2007 - 2008, Nicolas François
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <config.h>
#ifdef RLOGIN
#ident "$Id$"
#include "prototypes.h"
#include "defines.h"
#include <stdio.h>
#include <pwd.h>
#include <netdb.h>
#include "atoi/str2i.h"
static struct {
int spd_name;
int spd_baud;
} speed_table[] =
{
{ B50, 50},
{ B75, 75},
{ B110, 110},
{ B134, 134},
{ B150, 150},
{ B200, 200},
{ B300, 300},
{ B600, 600},
{ B1200, 1200},
{ B1800, 1800},
{ B2400, 2400},
{ B4800, 4800},
{ B9600, 9600},
{ B19200, 19200},
{ B38400, 38400},
{ -1, -1}
};
static void
get_remote_string(char *buf, size_t size)
{
for (;;) {
if (read (0, buf, 1) != 1) {
exit (EXIT_FAILURE);
}
if ('\0' == *buf) {
return;
}
--size;
if (size > 0) {
++buf;
}
}
/*NOTREACHED*/
}
int
do_rlogin(const char *remote_host, char *name, size_t namesize, char *term,
size_t termsize)
{
struct passwd *pwd;
char remote_name[32];
char *cp;
unsigned long remote_speed = 9600;
int speed_name = B9600;
int i;
TERMIO termio;
get_remote_string(remote_name, sizeof(remote_name));
get_remote_string(name, namesize);
get_remote_string(term, termsize);
cp = strchr (term, '/');
if (NULL != cp) {
*cp = '\0';
cp++;
if (str2ul(&remote_speed, cp) == -1)
remote_speed = 9600;
}
for (i = 0;
( (speed_table[i].spd_baud != remote_speed)
&& (speed_table[i].spd_name != -1));
i++);
if (-1 != speed_table[i].spd_name) {
speed_name = speed_table[i].spd_name;
}
/*
* Put the terminal in cooked mode with echo turned on.
*/
GTTY (0, &termio);
termio.c_iflag |= ICRNL | IXON;
termio.c_oflag |= OPOST | ONLCR;
termio.c_lflag |= ICANON | ECHO | ECHOE;
#ifdef CBAUD
termio.c_cflag = (termio.c_cflag & ~CBAUD) | speed_name;
#else
termio.c_cflag = (termio.c_cflag) | speed_name;
#endif
STTY (0, &termio);
pwd = getpwnam (name); /* local, no need for xgetpwnam */
if (NULL == pwd) {
return 0;
}
/*
* ruserok() returns 0 for success on modern systems, and 1 on
* older ones. If you are having trouble with people logging
* in without giving a required password, THIS is the culprit -
* go fix the #define in config.h.
*/
#ifndef RUSEROK
return 0;
#else
return ruserok (remote_host, pwd->pw_uid == 0,
remote_name, name) == RUSEROK;
#endif
}
#endif /* RLOGIN */

View File

@@ -1117,16 +1117,6 @@ bool release_subid_range(struct subordinate_range *range, enum subid_type id_typ
return ret;
}
void free_subid_pointer(void *ptr)
{
struct subid_nss_ops *h = get_subid_nss_handle();
if (h) {
h->free(ptr);
} else {
free(ptr);
}
}
#else /* !ENABLE_SUBIDS */
extern int ISO_C_forbids_an_empty_translation_unit;
#endif /* !ENABLE_SUBIDS */

View File

@@ -43,9 +43,6 @@ extern int sub_gid_unlock (void);
extern int sub_gid_add (const char *owner, gid_t start, unsigned long count);
extern int sub_gid_remove (const char *owner, gid_t start, unsigned long count);
extern uid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count);
extern void free_subid_pointer(void *ptr);
#endif /* ENABLE_SUBIDS */
#endif

View File

@@ -42,11 +42,6 @@ bool subid_init(const char *progname, FILE * logfd)
return true;
}
void subid_free(void *ptr)
{
free_subid_pointer(ptr);
}
static
int get_subid_ranges(const char *owner, enum subid_type id_type, struct subid_range **ranges)
{

View File

@@ -55,19 +55,6 @@ extern "C" {
*/
bool subid_init(const char *progname, FILE *logfd);
/*
* subid_free: free memory allocated in any subid_* function
*
* @ptr: Pointer to a memory block to release.
*
* Some functions like @subid_get_uid_ranges allocate memory internally. As
* soon as a result is no longer needed, it should be freed with this routine.
* Initially, default function `free()` was used. Thus for backward
* compatibility this function falls back to `free()` if a plugin does not
* explicitly specify routine to free allocated memory.
*/
void subid_free(void *ptr);
/*
* subid_get_uid_ranges: return a list of UID ranges for a user
*

View File

@@ -215,6 +215,14 @@
<para>Preserve environment.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-r</option>
</term>
<listitem>
<para>Perform autologin protocol for rlogin.</para>
</listitem>
</varlistentry>
</variablelist>
<para>

View File

@@ -53,6 +53,7 @@ lib/pwdcheck.c
lib/pwio.c
lib/pwmem.c
lib/remove_tree.c
lib/rlogin.c
lib/root_flag.c
lib/salt.c
lib/selinux.c

View File

@@ -44,6 +44,6 @@ int main(int argc, char *argv[])
printf("%d: %s %lu %lu\n", i, owner,
ranges[i].start, ranges[i].count);
}
subid_free(ranges);
free(ranges);
return 0;
}

View File

@@ -85,6 +85,11 @@ static struct lastlog ll;
static bool pflg = false;
static bool fflg = false;
#ifdef RLOGIN
static bool rflg = false;
#else /* RLOGIN */
#define rflg false
#endif /* !RLOGIN */
static bool hflg = false;
static bool preauth_flag = false;
@@ -129,6 +134,7 @@ static void exit_handler (int);
* usage - print login command usage and exit
*
* login [ name ]
* login -r hostname (for rlogind)
* login -h hostname (for telnetd, etc.)
* login -f name (for pre-authenticated login: datakit, xterm, etc.)
*/
@@ -139,6 +145,9 @@ static void usage (void)
exit (1);
}
fprintf (stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
#ifdef RLOGIN
fprintf (stderr, _(" %s [-p] -r host\n"), Prog);
#endif /* RLOGIN */
exit (1);
}
@@ -262,7 +271,7 @@ static void process_flags (int argc, char *const *argv)
/*
* Check the flags for proper form. Every argument starting with
* "-" must be exactly two characters long. This closes all the
* clever telnet, and getty holes.
* clever rlogin, telnet, and getty holes.
*/
for (arg = 1; arg < argc; arg++) {
if (argv[arg][0] == '-' && strlen (argv[arg]) > 2) {
@@ -289,6 +298,13 @@ static void process_flags (int argc, char *const *argv)
hostname = optarg;
reason = PW_TELNET;
break;
#ifdef RLOGIN
case 'r':
rflg = true;
hostname = optarg;
reason = PW_RLOGIN;
break;
#endif /* RLOGIN */
case 'p':
pflg = true;
break;
@@ -297,11 +313,21 @@ static void process_flags (int argc, char *const *argv)
}
}
#ifdef RLOGIN
/*
* Neither -h nor -f should be combined with -r.
*/
if (rflg && (hflg || fflg)) {
usage ();
}
#endif /* RLOGIN */
/*
* Allow authentication bypass only if real UID is zero.
*/
if ((fflg || hflg) && !amroot) {
if ((rflg || fflg || hflg) && !amroot) {
fprintf (stderr, _("%s: Permission denied.\n"), Prog);
exit (1);
}
@@ -316,6 +342,11 @@ static void process_flags (int argc, char *const *argv)
++optind;
}
#ifdef RLOGIN
if (rflg && (NULL != username)) {
usage ();
}
#endif /* RLOGIN */
if (fflg && (NULL == username)) {
usage ();
}
@@ -443,6 +474,7 @@ static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *use
* the flags which login supports are
*
* -p - preserve the environment
* -r - perform autologin protocol for rlogin
* -f - do not perform authentication, user is preauthenticated
* -h - the name of the remote host
*/
@@ -473,6 +505,9 @@ int main (int argc, char **argv)
# if defined(ENABLE_LASTLOG)
char ptime[80];
# endif
#endif
#if defined(RLOGIN)
char term[128] = "";
#endif
/*
@@ -524,7 +559,7 @@ int main (int argc, char **argv)
is_console = console (tty);
#endif
if (hflg) {
if (rflg || hflg) {
/*
* Add remote hostname to the environment. I think
* (not sure) I saw it once on Irix. --marekm
@@ -537,6 +572,23 @@ int main (int argc, char **argv)
if (hflg) {
reason = PW_RLOGIN;
}
#ifdef RLOGIN
if (rflg) {
size_t max_size;
max_size = login_name_max_size();
assert (NULL == username);
username = XMALLOC(max_size, char);
username[max_size - 1] = '\0';
if (do_rlogin(hostname, username, max_size, term, sizeof(term)))
{
preauth_flag = true;
} else {
free (username);
username = NULL;
}
}
#endif /* RLOGIN */
OPENLOG (Prog);
@@ -571,11 +623,18 @@ int main (int argc, char **argv)
}
}
/* preserve TERM from getty */
if (!pflg) {
tmp = getenv ("TERM");
if (NULL != tmp) {
addenv ("TERM", tmp);
#ifdef RLOGIN
if (term[0] != '\0') {
addenv ("TERM", term);
} else
#endif /* RLOGIN */
{
/* preserve TERM from getty */
if (!pflg) {
tmp = getenv ("TERM");
if (NULL != tmp) {
addenv ("TERM", tmp);
}
}
}
@@ -585,7 +644,7 @@ int main (int argc, char **argv)
set_env (argc - optind, &argv[optind]);
}
if (hflg) {
if (rflg || hflg) {
cp = hostname;
} else if ((host != NULL) && (host[0] != '\0')) {
cp = host;
@@ -895,7 +954,7 @@ int main (int argc, char **argv)
}
/*
* The -f flag provides a name which has already
* The -r and -f flags provide a name which has already
* been authenticated by some server.
*/
if (preauth_flag) {
@@ -984,8 +1043,8 @@ int main (int argc, char **argv)
(void) puts (_("Login incorrect"));
/* allow only one attempt with -f */
if (fflg || (retries <= 0)) {
/* allow only one attempt with -r or -f */
if (rflg || fflg || (retries <= 0)) {
closelog ();
exit (1);
}

61
tests/bug332198-test.exp Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/expect -f
# This is a script for repeatedly logging into the localhost
# using `rlogin` in order to apparently see a symptoms described
# in bug #332198.
# As described in the bug log, sometimes `rlogind` will fail to
# establish a connection, because it starts "login" process and
# the latter fails with "unable to determine TTY name, got /dev/pts/1"
# message.
#
# BUGS
#
# * the script rlogins to localhost
# * the script doesn't handle passwdord prompt, because it's intended
# to use .rhosts auth and expects shell prompt immediately after
# `rlogin`
# * the regexp for shell prompt is hardcoded
log_user 0
match_max 8192
while {1} {
set rlogin_spawn [spawn rlogin localhost]
if { $rlogin_spawn == 0 } { exit 1 }
expect {
-timeout 10 -re "^.*(Last login\[^\r\n\]*).*\n(\[^\r\n\]*\[#$\] )$" {
send_error "$expect_out(1,string)\n"
send_error "$expect_out(2,string)\n"
# send_error "$expect_out(0,string)\n"
}
timeout {
send_error "TIMEOUT/prompt\n"
send_error "$expect_out(buffer)\n"
send_error "RETRYING\n"
log_user 1
send "tty /\r"
expect -timeout 2 -re "^.*\r?\n(\[^\r\n\]*# )$" {}
send "tty /\r"
expect -timeout 2 -re "^.*\r?\n(\[^\r\n\]*# )$" {}
send_error "\n"
exit 2
}
}
send "tty\r"
expect {
-timeout 4 -re "tty\r?\n(\[^\r\n\]*)\r?\n(\[^\r\n\]*\[#$\] )$" {
send_error "$expect_out(2,string)$expect_out(1,string)\n"
# send_error "$expect_out(0,string)\n"
}
timeout { send_error "TIMEOUT/tty\n" ; exit 3 }
}
send "exit\r"
expect {
-timeout 2 eof {
# send_error "OK4: EOF\n"
}
timeout { send_error "TIMEOUT/eof\n" ; exit 4 }
}
wait
}
# vi: set sw=4:

View File

@@ -138,8 +138,3 @@ enum subid_status shadow_subid_list_owner_ranges(const char *owner, enum subid_t
return SUBID_STATUS_SUCCESS;
}
void shadow_subid_free(void *ptr)
{
free(ptr);
}