New upstream version 4.15.1

This commit is contained in:
Chris Hofstaedtler
2024-06-13 03:08:44 +02:00
parent 3987cc7880
commit f7f4fd7c05
759 changed files with 53132 additions and 39788 deletions
+94 -126
View File
@@ -18,15 +18,19 @@
#include <sys/types.h>
#include <time.h>
#include <assert.h>
#include "defines.h"
#include "faillog.h"
#include "memzero.h"
#include "prototypes.h"
/*@-exitarg@*/
#include "exitcodes.h"
#include "shadowlog.h"
#include "string/strftime.h"
/* local function prototypes */
static /*@noreturn@*/void usage (int status);
NORETURN static void usage (int status);
static void print_one (/*@null@*/const struct passwd *pw, bool force);
static void set_locktime (long locktime);
static bool set_locktime_one (uid_t uid, long locktime);
@@ -39,7 +43,7 @@ static void reset (void);
/*
* Global variables
*/
const char *Prog; /* Program name */
static const char Prog[] = "faillog"; /* Program name */
static FILE *fail; /* failure file stream */
static time_t seconds; /* that number of days in seconds */
static unsigned long umin; /* if uflg and has_umin, only display users with uid >= umin */
@@ -57,9 +61,11 @@ static bool rflg = false; /* reset the counters of login failures */
static struct stat statbuf; /* fstat buffer for file size */
#define NOW (time((time_t *) 0))
#define NOW time(NULL)
static /*@noreturn@*/void usage (int status)
NORETURN
static void
usage (int status)
{
FILE *usageout = (E_SUCCESS != status) ? stderr : stdout;
(void) fprintf (usageout,
@@ -81,11 +87,53 @@ static /*@noreturn@*/void usage (int status)
exit (status);
}
/*
* Looks up the offset in the faillog file for the given uid.
* Returns -1 on error.
*/
static off_t lookup_faillog(struct faillog *fl, uid_t uid)
{
off_t offset, size;
/* Ensure multiplication does not overflow and retrieving a wrong entry */
if (__builtin_mul_overflow(uid, sizeof(*fl), &offset)) {
fprintf(stderr,
_("%s: Failed to get the entry for UID %lu\n"),
Prog, (unsigned long)uid);
return -1;
}
if (!__builtin_add_overflow(offset, sizeof(*fl), &size)
&& size <= statbuf.st_size) {
/* fseeko errors are not really relevant for us. */
int err = fseeko(fail, offset, SEEK_SET);
assert(0 == err);
/* faillog is a sparse file. Even if no entries were
* entered for this user, which should be able to get the
* empty entry in this case.
*/
if (fread(fl, sizeof(*fl), 1, fail) != 1) {
fprintf(stderr,
_("%s: Failed to get the entry for UID %lu\n"),
Prog, (unsigned long)uid);
return -1;
}
} else {
/* Outsize of the faillog file.
* Behave as if there were a missing entry (same behavior
* as if we were reading an non existing entry in the
* sparse faillog file).
*/
memzero(fl, sizeof(*fl));
}
return offset;
}
static void print_one (/*@null@*/const struct passwd *pw, bool force)
{
static bool once = false;
struct tm *tm;
off_t offset;
struct faillog fl;
time_t now;
char *cp;
@@ -95,28 +143,8 @@ static void print_one (/*@null@*/const struct passwd *pw, bool force)
return;
}
offset = (off_t) pw->pw_uid * sizeof (fl);
if (offset + sizeof (fl) <= statbuf.st_size) {
/* fseeko errors are not really relevant for us. */
int err = fseeko (fail, offset, SEEK_SET);
assert (0 == err);
/* faillog is a sparse file. Even if no entries were
* entered for this user, which should be able to get the
* empty entry in this case.
*/
if (fread ((char *) &fl, sizeof (fl), 1, fail) != 1) {
fprintf (stderr,
_("%s: Failed to get the entry for UID %lu\n"),
Prog, (unsigned long int)pw->pw_uid);
return;
}
} else {
/* Outsize of the faillog file.
* Behave as if there were a missing entry (same behavior
* as if we were reading an non existing entry in the
* sparse faillog file).
*/
memzero (&fl, sizeof (fl));
if (lookup_faillog(&fl, pw->pw_uid) < 0) {
return;
}
/* Nothing to report */
@@ -142,7 +170,7 @@ static void print_one (/*@null@*/const struct passwd *pw, bool force)
fprintf (stderr, "Cannot read time from faillog.\n");
return;
}
strftime (ptime, sizeof (ptime), "%D %H:%M:%S %z", tm);
STRFTIME(ptime, "%D %H:%M:%S %z", tm);
cp = ptime;
printf ("%-9s %5d %5d ",
@@ -164,7 +192,7 @@ static void print_one (/*@null@*/const struct passwd *pw, bool force)
static void print (void)
{
if (uflg && has_umin && has_umax && (umin==umax)) {
print_one (getpwuid ((uid_t)umin), true);
print_one (getpwuid (umin), true);
} else {
/* We only print records for existing users.
* Loop based on the user database instead of reading the
@@ -197,28 +225,10 @@ static bool reset_one (uid_t uid)
off_t offset;
struct faillog fl;
offset = (off_t) uid * sizeof (fl);
if (offset + sizeof (fl) <= statbuf.st_size) {
/* fseeko errors are not really relevant for us. */
int err = fseeko (fail, offset, SEEK_SET);
assert (0 == err);
/* faillog is a sparse file. Even if no entries were
* entered for this user, which should be able to get the
* empty entry in this case.
*/
if (fread ((char *) &fl, sizeof (fl), 1, fail) != 1) {
fprintf (stderr,
_("%s: Failed to get the entry for UID %lu\n"),
Prog, (unsigned long int)uid);
return true;
}
} else {
/* Outsize of the faillog file.
* Behave as if there were a missing entry (same behavior
* as if we were reading an non existing entry in the
* sparse faillog file).
*/
memzero (&fl, sizeof (fl));
offset = lookup_faillog(&fl, uid);
if (offset < 0) {
/* failure */
return true;
}
if (0 == fl.fail_cnt) {
@@ -232,21 +242,21 @@ static bool reset_one (uid_t uid)
fl.fail_cnt = 0;
if ( (fseeko (fail, offset, SEEK_SET) == 0)
&& (fwrite ((char *) &fl, sizeof (fl), 1, fail) == 1)) {
&& (fwrite (&fl, sizeof (fl), 1, fail) == 1)) {
(void) fflush (fail);
return false;
}
fprintf (stderr,
_("%s: Failed to reset fail count for UID %lu\n"),
Prog, (unsigned long int)uid);
Prog, (unsigned long)uid);
return true;
}
static void reset (void)
{
if (uflg && has_umin && has_umax && (umin==umax)) {
if (reset_one ((uid_t)umin)) {
if (reset_one (umin)) {
errors = true;
}
} else {
@@ -258,7 +268,7 @@ static void reset (void)
uidmax--;
}
if (has_umax && (uid_t)umax < uidmax) {
uidmax = (uid_t)umax;
uidmax = umax;
}
/* Reset all entries in the specified range.
@@ -271,7 +281,7 @@ static void reset (void)
/* Make sure we stay in the umin-umax range if specified */
if (has_umin) {
uid = (uid_t)umin;
uid = umin;
}
while (uid <= uidmax) {
@@ -289,7 +299,7 @@ static void reset (void)
while ( (pwent = getpwent ()) != NULL ) {
if ( uflg
&& ( (has_umin && (pwent->pw_uid < (uid_t)umin))
|| (pwent->pw_uid > (uid_t)uidmax))) {
|| (pwent->pw_uid > uidmax))) {
continue;
}
if (reset_one (pwent->pw_uid)) {
@@ -311,28 +321,9 @@ static bool setmax_one (uid_t uid, short max)
off_t offset;
struct faillog fl;
offset = (off_t) uid * sizeof (fl);
if (offset + sizeof (fl) <= statbuf.st_size) {
/* fseeko errors are not really relevant for us. */
int err = fseeko (fail, offset, SEEK_SET);
assert (0 == err);
/* faillog is a sparse file. Even if no entries were
* entered for this user, which should be able to get the
* empty entry in this case.
*/
if (fread ((char *) &fl, sizeof (fl), 1, fail) != 1) {
fprintf (stderr,
_("%s: Failed to get the entry for UID %lu\n"),
Prog, (unsigned long int)uid);
return true;
}
} else {
/* Outsize of the faillog file.
* Behave as if there were a missing entry (same behavior
* as if we were reading an non existing entry in the
* sparse faillog file).
*/
memzero (&fl, sizeof (fl));
offset = lookup_faillog(&fl, uid);
if (offset < 0) {
return true;
}
if (max == fl.fail_max) {
@@ -347,21 +338,21 @@ static bool setmax_one (uid_t uid, short max)
fl.fail_max = max;
if ( (fseeko (fail, offset, SEEK_SET) == 0)
&& (fwrite ((char *) &fl, sizeof (fl), 1, fail) == 1)) {
&& (fwrite (&fl, sizeof (fl), 1, fail) == 1)) {
(void) fflush (fail);
return false;
}
fprintf (stderr,
_("%s: Failed to set max for UID %lu\n"),
Prog, (unsigned long int)uid);
Prog, (unsigned long)uid);
return true;
}
static void setmax (short max)
{
if (uflg && has_umin && has_umax && (umin==umax)) {
if (setmax_one ((uid_t)umin, max)) {
if (setmax_one (umin, max)) {
errors = true;
}
} else {
@@ -385,10 +376,10 @@ static void setmax (short max)
/* Make sure we stay in the umin-umax range if specified */
if (has_umin) {
uid = (uid_t)umin;
uid = umin;
}
if (has_umax) {
uidmax = (uid_t)umax;
uidmax = umax;
}
while (uid <= uidmax) {
@@ -428,28 +419,9 @@ static bool set_locktime_one (uid_t uid, long locktime)
off_t offset;
struct faillog fl;
offset = (off_t) uid * sizeof (fl);
if (offset + sizeof (fl) <= statbuf.st_size) {
/* fseeko errors are not really relevant for us. */
int err = fseeko (fail, offset, SEEK_SET);
assert (0 == err);
/* faillog is a sparse file. Even if no entries were
* entered for this user, which should be able to get the
* empty entry in this case.
*/
if (fread ((char *) &fl, sizeof (fl), 1, fail) != 1) {
fprintf (stderr,
_("%s: Failed to get the entry for UID %lu\n"),
Prog, (unsigned long int)uid);
return true;
}
} else {
/* Outsize of the faillog file.
* Behave as if there were a missing entry (same behavior
* as if we were reading an non existing entry in the
* sparse faillog file).
*/
memzero (&fl, sizeof (fl));
offset = lookup_faillog(&fl, uid);
if (offset < 0) {
return true;
}
if (locktime == fl.fail_locktime) {
@@ -464,21 +436,21 @@ static bool set_locktime_one (uid_t uid, long locktime)
fl.fail_locktime = locktime;
if ( (fseeko (fail, offset, SEEK_SET) == 0)
&& (fwrite ((char *) &fl, sizeof (fl), 1, fail) == 1)) {
&& (fwrite (&fl, sizeof (fl), 1, fail) == 1)) {
(void) fflush (fail);
return false;
}
fprintf (stderr,
_("%s: Failed to set locktime for UID %lu\n"),
Prog, (unsigned long int)uid);
Prog, (unsigned long)uid);
return true;
}
static void set_locktime (long locktime)
{
if (uflg && has_umin && has_umax && (umin==umax)) {
if (set_locktime_one ((uid_t)umin, locktime)) {
if (set_locktime_one (umin, locktime)) {
errors = true;
}
} else {
@@ -502,10 +474,10 @@ static void set_locktime (long locktime)
/* Make sure we stay in the umin-umax range if specified */
if (has_umin) {
uid = (uid_t)umin;
uid = umin;
}
if (has_umax) {
uidmax = (uid_t)umax;
uidmax = umax;
}
while (uid <= uidmax) {
@@ -541,11 +513,6 @@ int main (int argc, char **argv)
short fail_max = 0; // initialize to silence compiler warning
long days = 0;
/*
* Get the program name. The program name is used as a prefix to
* most error messages.
*/
Prog = Basename (argv[0]);
log_set_progname(Prog);
log_set_logfd(stderr);
@@ -578,7 +545,7 @@ int main (int argc, char **argv)
usage (E_SUCCESS);
/*@notreached@*/break;
case 'l':
if (getlong (optarg, &fail_locktime) == 0) {
if (getlong(optarg, &fail_locktime) == -1) {
fprintf (stderr,
_("%s: invalid numeric argument '%s'\n"),
Prog, optarg);
@@ -588,15 +555,16 @@ int main (int argc, char **argv)
break;
case 'm':
{
long int lmax;
if ( (getlong (optarg, &lmax) == 0)
|| ((long int)(short) lmax != lmax)) {
long lmax;
if ( (getlong(optarg, &lmax) == -1)
|| ((long)(short) lmax != lmax)) {
fprintf (stderr,
_("%s: invalid numeric argument '%s'\n"),
Prog, optarg);
exit (E_BAD_ARG);
}
fail_max = (short) lmax;
fail_max = lmax;
mflg = true;
break;
}
@@ -606,7 +574,7 @@ int main (int argc, char **argv)
case 'R': /* no-op, handled in process_root_flag () */
break;
case 't':
if (getlong (optarg, &days) == 0) {
if (getlong(optarg, &days) == -1) {
fprintf (stderr,
_("%s: invalid numeric argument '%s'\n"),
Prog, optarg);
@@ -630,14 +598,14 @@ int main (int argc, char **argv)
/* local, no need for xgetpwnam */
pwent = getpwnam (optarg);
if (NULL != pwent) {
umin = (unsigned long) pwent->pw_uid;
umin = pwent->pw_uid;
has_umin = true;
umax = umin;
has_umax = true;
} else {
if (getrange (optarg,
&umin, &has_umin,
&umax, &has_umax) == 0) {
if (getrange(optarg,
&umin, &has_umin,
&umax, &has_umax) == -1) {
fprintf (stderr,
_("%s: Unknown user or range: %s\n"),
Prog, optarg);