shadow/lib/fields.c

107 lines
2.1 KiB
C
Raw Normal View History

/*
* SPDX-FileCopyrightText: 1990 , Julianne Frances Haugh
* SPDX-FileCopyrightText: 1996 - 1997, Marek Michałkiewicz
* SPDX-FileCopyrightText: 2003 - 2005, Tomasz Kłoczko
* SPDX-FileCopyrightText: 2007 , Nicolas François
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <config.h>
#ident "$Id$"
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include "prototypes.h"
/*
* valid_field - insure that a field contains all legal characters
*
* The supplied field is scanned for non-printable and other illegal
* characters.
* + -1 is returned if an illegal character is present.
* + 1 is returned if no illegal characters are present, but the field
* contains a non-printable character.
* + 0 is returned otherwise.
*/
int valid_field (const char *field, const char *illegal)
{
const char *cp;
int err = 0;
if (NULL == field) {
return -1;
}
/* For each character of field, search if it appears in the list
* of illegal characters. */
for (cp = field; '\0' != *cp; cp++) {
if (strchr (illegal, *cp) != NULL) {
err = -1;
break;
}
}
if (0 == err) {
/* Search if there are some non-printable characters */
for (cp = field; '\0' != *cp; cp++) {
if (!isprint (*cp)) {
err = 1;
break;
}
}
}
return err;
}
/*
* change_field - change a single field if a new value is given.
*
* prompt the user with the name of the field being changed and the
* current value.
*/
void change_field (char *buf, size_t maxsize, const char *prompt)
{
char newf[200];
char *cp;
if (maxsize > sizeof (newf)) {
maxsize = sizeof (newf);
}
printf ("\t%s [%s]: ", prompt, buf);
(void) fflush (stdout);
if (fgets (newf, maxsize, stdin) != newf) {
return;
}
cp = strchr (newf, '\n');
if (NULL == cp) {
return;
}
*cp = '\0';
if ('\0' != newf[0]) {
/*
* Remove leading and trailing whitespace. This also
* makes it possible to change the field to empty, by
* entering a space. --marekm
*/
while (--cp >= newf && isspace (*cp));
cp++;
*cp = '\0';
cp = newf;
while (('\0' != *cp) && isspace (*cp)) {
cp++;
}
Use strlcpy(3) instead of its pattern - Since strncpy(3) is not designed to write strings, but rather (null-padded) character sequences (a.k.a. unterminated strings), we had to manually append a '\0'. strlcpy(3) creates strings, so they are always terminated. This removes dependencies between lines, and also removes chances of accidents. - Repurposing strncpy(3) to create strings requires calculating the location of the terminating null byte, which involves a '-1' calculation. This is a source of off-by-one bugs. The new code has no '-1' calculations, so there's almost-zero chance of these bugs. - strlcpy(3) doesn't padd with null bytes. Padding is relevant when writing fixed-width buffers to binary files, when interfacing certain APIs (I believe utmpx requires null padding at lease in some systems), or when sending them to other processes or through the network. This is not the case, so padding is effectively ignored. - strlcpy(3) requires that the input string is really a string; otherwise it crashes (SIGSEGV). Let's check if the input strings are really strings: - lib/fields.c: - 'cp' was assigned from 'newft', and 'newft' comes from fgets(3). - lib/gshadow.c: - strlen(string) is calculated a few lines above. - libmisc/console.c: - 'cons' comes from getdef_str, which is a bit cryptic, but seems to generate strings, I guess.1 - libmisc/date_to_str.c: - It receives a string literal. :) - libmisc/utmp.c: - 'tname' comes from ttyname(3), which returns a string. - src/su.c: - 'tmp_name' has been passed to strcmp(3) a few lines above. Signed-off-by: Alejandro Colomar <alx@kernel.org>
2022-12-16 08:43:53 +05:30
strlcpy (buf, cp, maxsize);
}
}