* lib/commonio.c: Avoid PATH_MAX. On glibc, we can use realpath

with a NULL argument.
	* src/useradd.c: Replace PATH_MAX by a fixed constant. The buffer
	was not meant as a storage for a path.
	* src/useradd.c, src/newusers.c, src/chpasswd.c: Better detection
	of fgets errors. Lines shall end with a \n, unless we reached the
	end of file.
	* libmisc/copydir.c: Avoid PATH_MAX. Support file paths with any
	length. Added readlink_malloc().
This commit is contained in:
nekral-guest 2009-05-10 13:49:03 +00:00
parent a01499179f
commit 750093a3ed
6 changed files with 139 additions and 41 deletions

View File

@ -1,3 +1,15 @@
2009-05-10 Nicolas François <nicolas.francois@centraliens.net>
* lib/commonio.c: Avoid PATH_MAX. On glibc, we can use realpath
with a NULL argument.
* src/useradd.c: Replace PATH_MAX by a fixed constant. The buffer
was not meant as a storage for a path.
* src/useradd.c, src/newusers.c, src/chpasswd.c: Better detection
of fgets errors. Lines shall end with a \n, unless we reached the
end of file.
* libmisc/copydir.c: Avoid PATH_MAX. Support file paths with any
length. Added readlink_malloc().
2009-05-09 Nicolas François <nicolas.francois@centraliens.net>
* src/pwck.c: Warn if an user has an entry in passwd and shadow,

View File

@ -83,21 +83,36 @@ static bool nscd_need_reload = false;
*/
int lrename (const char *old, const char *new)
{
char resolved_path[PATH_MAX];
int res;
char *r = NULL;
#if defined(S_ISLNK)
#ifndef __GLIBC__
char resolved_path[PATH_MAX];
#endif /* !__GLIBC__ */
struct stat sb;
if (lstat (new, &sb) == 0 && S_ISLNK (sb.st_mode)) {
if (realpath (new, resolved_path) == NULL) {
#ifdef __GLIBC__ /* now a POSIX.1-2008 feature */
r = realpath (new, NULL);
#else /* !__GLIBC__ */
r = realpath (new, resolved_path);
#endif /* !__GLIBC__ */
if (NULL == r) {
perror ("realpath in lrename()");
} else {
new = resolved_path;
new = r;
}
}
#endif
#endif /* S_ISLNK */
res = rename (old, new);
#ifdef __GLIBC__
if (NULL != r) {
free (r);
}
#endif /* __GLIBC__ */
return res;
}

View File

@ -199,8 +199,6 @@ static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, c
int copy_tree (const char *src_root, const char *dst_root,
long int uid, long int gid)
{
char src_name[PATH_MAX];
char dst_name[PATH_MAX];
int err = 0;
bool set_orig = false;
struct DIRECT *ent;
@ -240,27 +238,36 @@ int copy_tree (const char *src_root, const char *dst_root,
*/
if ((strcmp (ent->d_name, ".") != 0) &&
(strcmp (ent->d_name, "..") != 0)) {
/*
* Make sure the resulting source and destination
* filenames will fit in their buffers.
*/
if ( (strlen (src_root) + strlen (ent->d_name) + 2 >
sizeof src_name)
|| (strlen (dst_root) + strlen (ent->d_name) + 2 >
sizeof dst_name)) {
char *src_name;
char *dst_name;
size_t src_len = strlen (ent->d_name) + 2;
size_t dst_len = strlen (ent->d_name) + 2;
src_len += strlen (src_root);
dst_len += strlen (dst_root);
src_name = (char *) malloc (src_len);
dst_name = (char *) malloc (dst_len);
if ((NULL == src_name) || (NULL == dst_name)) {
err = -1;
} else {
/*
* Build the filename for both the source and
* the destination files.
*/
snprintf (src_name, sizeof src_name, "%s/%s",
snprintf (src_name, src_len, "%s/%s",
src_root, ent->d_name);
snprintf (dst_name, sizeof dst_name, "%s/%s",
snprintf (dst_name, dst_len, "%s/%s",
dst_root, ent->d_name);
err = copy_entry (src_name, dst_name, uid, gid);
}
if (NULL != src_name) {
free (src_name);
}
if (NULL != dst_name) {
free (dst_name);
}
}
}
(void) closedir (dir);
@ -415,6 +422,41 @@ static int copy_dir (const char *src, const char *dst,
}
#ifdef S_IFLNK
/*
* readlink_malloc - wrapper for readlink
*
* return NULL on error.
* The return string shall be freed by the caller.
*/
char *readlink_malloc (const char *filename)
{
size_t size = 1024;
while (1) {
ssize_t nchars;
char *buffer = (char *) malloc (size);
if (NULL == buffer) {
return NULL;
}
nchars = readlink (filename, buffer, size);
if (nchars < 0) {
return NULL;
}
if ( (size_t) nchars < size) { /* The buffer was large enough */
/* readlink does not nul-terminate */
buffer[nchars] = '\0';
return buffer;
}
/* Try again with a bigger buffer */
free (buffer);
size *= 2;
}
}
/*
* copy_symlink - copy a symlink
*
@ -429,10 +471,7 @@ static int copy_symlink (const char *src, const char *dst,
const struct stat *statp, const struct timeval mt[],
long int uid, long int gid)
{
char oldlink[PATH_MAX];
char dummy[PATH_MAX];
int len;
int err = 0;
char *oldlink;
/* copy_tree () must be the entry point */
assert (NULL != src_orig);
@ -446,17 +485,25 @@ static int copy_symlink (const char *src, const char *dst,
* destination directory name.
*/
len = readlink (src, oldlink, sizeof (oldlink) - 1);
if (len < 0) {
oldlink = readlink_malloc (src);
if (NULL == oldlink) {
return -1;
}
oldlink[len] = '\0'; /* readlink() does not NUL-terminate */
/* If src was a link to an entry of the src_orig directory itself,
* create a link to the corresponding entry in the dst_orig
* directory.
*/
if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
snprintf (dummy, sizeof dummy, "%s%s",
size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
char *dummy = (char *) malloc (len);
snprintf (dummy, len, "%s%s",
dst_orig,
oldlink + strlen (src_orig));
strcpy (oldlink, dummy);
free (oldlink);
oldlink = dummy;
}
#ifdef WITH_SELINUX
selinux_file_context (dst);
#endif
@ -464,8 +511,10 @@ static int copy_symlink (const char *src, const char *dst,
|| (lchown (dst,
(uid == -1) ? statp->st_uid : (uid_t) uid,
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
free (oldlink);
return -1;
}
free (oldlink);
#ifdef HAVE_LUTIMES
/* 2007-10-18: We don't care about
@ -476,7 +525,7 @@ static int copy_symlink (const char *src, const char *dst,
lutimes (dst, mt);
#endif
return err;
return 0;
}
#endif
@ -618,7 +667,7 @@ static int copy_file (const char *src, const char *dst,
int remove_tree (const char *root)
{
char new_name[PATH_MAX];
char *new_name = NULL;
int err = 0;
struct DIRECT *ent;
struct stat sb;
@ -645,6 +694,7 @@ int remove_tree (const char *root)
}
while ((ent = readdir (dir))) {
size_t new_len = strlen (root) + strlen (ent->d_name) + 2;
/*
* Skip the "." and ".." entries
@ -659,12 +709,15 @@ int remove_tree (const char *root)
* Make the filename for the current entry.
*/
if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) {
if (NULL != new_name) {
free (new_name);
}
new_name = (char *) malloc (new_len);
if (NULL == new_name) {
err = -1;
break;
}
snprintf (new_name, sizeof new_name, "%s/%s", root,
ent->d_name);
snprintf (new_name, new_len, "%s/%s", root, ent->d_name);
if (LSTAT (new_name, &sb) == -1) {
continue;
}
@ -687,6 +740,9 @@ int remove_tree (const char *root)
}
}
}
if (NULL != new_name) {
free (new_name);
}
(void) closedir (dir);
if (0 == err) {

View File

@ -434,12 +434,14 @@ int main (int argc, char **argv)
if (NULL != cp) {
*cp = '\0';
} else {
if (feof (stdin) == 0) {
fprintf (stderr,
_("%s: line %d: line too long\n"),
Prog, line);
errors++;
continue;
}
}
/*
* The username is the first field. It is separated from the

View File

@ -863,11 +863,14 @@ int main (int argc, char **argv)
if (NULL != cp) {
*cp = '\0';
} else {
fprintf (stderr, _("%s: line %d: line too long\n"),
if (feof (stdin) == 0) {
fprintf (stderr,
_("%s: line %d: line too long\n"),
Prog, line);
errors++;
continue;
}
}
/*
* Break the string into fields and screw around with them.

View File

@ -421,7 +421,7 @@ static int set_defaults (void)
{
FILE *ifp;
FILE *ofp;
char buf[PATH_MAX];
char buf[1024];
static char new_file[] = NEW_USER_FILE;
char *cp;
int ofd;
@ -468,6 +468,16 @@ static int set_defaults (void)
cp = strrchr (buf, '\n');
if (NULL != cp) {
*cp = '\0';
} else {
/* A line which does not end with \n is only valid
* at the end of the file.
*/
if (feof (ifp) == 0) {
fprintf (stderr,
_("%s: line too long in %s: %s..."),
Prog, def_file, buf);
return -1;
}
}
if (!out_group && MATCH (buf, DGROUP)) {