* 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> 2009-05-09 Nicolas François <nicolas.francois@centraliens.net>
* src/pwck.c: Warn if an user has an entry in passwd and shadow, * 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) int lrename (const char *old, const char *new)
{ {
char resolved_path[PATH_MAX];
int res; int res;
char *r = NULL;
#if defined(S_ISLNK) #if defined(S_ISLNK)
#ifndef __GLIBC__
char resolved_path[PATH_MAX];
#endif /* !__GLIBC__ */
struct stat sb; struct stat sb;
if (lstat (new, &sb) == 0 && S_ISLNK (sb.st_mode)) { 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()"); perror ("realpath in lrename()");
} else { } else {
new = resolved_path; new = r;
} }
} }
#endif #endif /* S_ISLNK */
res = rename (old, new); res = rename (old, new);
#ifdef __GLIBC__
if (NULL != r) {
free (r);
}
#endif /* __GLIBC__ */
return res; 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, int copy_tree (const char *src_root, const char *dst_root,
long int uid, long int gid) long int uid, long int gid)
{ {
char src_name[PATH_MAX];
char dst_name[PATH_MAX];
int err = 0; int err = 0;
bool set_orig = false; bool set_orig = false;
struct DIRECT *ent; struct DIRECT *ent;
@ -240,27 +238,36 @@ int copy_tree (const char *src_root, const char *dst_root,
*/ */
if ((strcmp (ent->d_name, ".") != 0) && if ((strcmp (ent->d_name, ".") != 0) &&
(strcmp (ent->d_name, "..") != 0)) { (strcmp (ent->d_name, "..") != 0)) {
/* char *src_name;
* Make sure the resulting source and destination char *dst_name;
* filenames will fit in their buffers. size_t src_len = strlen (ent->d_name) + 2;
*/ size_t dst_len = strlen (ent->d_name) + 2;
if ( (strlen (src_root) + strlen (ent->d_name) + 2 > src_len += strlen (src_root);
sizeof src_name) dst_len += strlen (dst_root);
|| (strlen (dst_root) + strlen (ent->d_name) + 2 >
sizeof dst_name)) { src_name = (char *) malloc (src_len);
dst_name = (char *) malloc (dst_len);
if ((NULL == src_name) || (NULL == dst_name)) {
err = -1; err = -1;
} else { } else {
/* /*
* Build the filename for both the source and * Build the filename for both the source and
* the destination files. * the destination files.
*/ */
snprintf (src_name, sizeof src_name, "%s/%s", snprintf (src_name, src_len, "%s/%s",
src_root, ent->d_name); 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); dst_root, ent->d_name);
err = copy_entry (src_name, dst_name, uid, gid); 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); (void) closedir (dir);
@ -415,6 +422,41 @@ static int copy_dir (const char *src, const char *dst,
} }
#ifdef S_IFLNK #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 * 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[], const struct stat *statp, const struct timeval mt[],
long int uid, long int gid) long int uid, long int gid)
{ {
char oldlink[PATH_MAX]; char *oldlink;
char dummy[PATH_MAX];
int len;
int err = 0;
/* copy_tree () must be the entry point */ /* copy_tree () must be the entry point */
assert (NULL != src_orig); assert (NULL != src_orig);
@ -446,17 +485,25 @@ static int copy_symlink (const char *src, const char *dst,
* destination directory name. * destination directory name.
*/ */
len = readlink (src, oldlink, sizeof (oldlink) - 1); oldlink = readlink_malloc (src);
if (len < 0) { if (NULL == oldlink) {
return -1; 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) { 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, dst_orig,
oldlink + strlen (src_orig)); oldlink + strlen (src_orig));
strcpy (oldlink, dummy); free (oldlink);
oldlink = dummy;
} }
#ifdef WITH_SELINUX #ifdef WITH_SELINUX
selinux_file_context (dst); selinux_file_context (dst);
#endif #endif
@ -464,8 +511,10 @@ static int copy_symlink (const char *src, const char *dst,
|| (lchown (dst, || (lchown (dst,
(uid == -1) ? statp->st_uid : (uid_t) uid, (uid == -1) ? statp->st_uid : (uid_t) uid,
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) { (gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
free (oldlink);
return -1; return -1;
} }
free (oldlink);
#ifdef HAVE_LUTIMES #ifdef HAVE_LUTIMES
/* 2007-10-18: We don't care about /* 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); lutimes (dst, mt);
#endif #endif
return err; return 0;
} }
#endif #endif
@ -618,7 +667,7 @@ static int copy_file (const char *src, const char *dst,
int remove_tree (const char *root) int remove_tree (const char *root)
{ {
char new_name[PATH_MAX]; char *new_name = NULL;
int err = 0; int err = 0;
struct DIRECT *ent; struct DIRECT *ent;
struct stat sb; struct stat sb;
@ -645,6 +694,7 @@ int remove_tree (const char *root)
} }
while ((ent = readdir (dir))) { while ((ent = readdir (dir))) {
size_t new_len = strlen (root) + strlen (ent->d_name) + 2;
/* /*
* Skip the "." and ".." entries * Skip the "." and ".." entries
@ -659,12 +709,15 @@ int remove_tree (const char *root)
* Make the filename for the current entry. * 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; err = -1;
break; break;
} }
snprintf (new_name, sizeof new_name, "%s/%s", root, snprintf (new_name, new_len, "%s/%s", root, ent->d_name);
ent->d_name);
if (LSTAT (new_name, &sb) == -1) { if (LSTAT (new_name, &sb) == -1) {
continue; continue;
} }
@ -687,6 +740,9 @@ int remove_tree (const char *root)
} }
} }
} }
if (NULL != new_name) {
free (new_name);
}
(void) closedir (dir); (void) closedir (dir);
if (0 == err) { if (0 == err) {

View File

@ -434,11 +434,13 @@ int main (int argc, char **argv)
if (NULL != cp) { if (NULL != cp) {
*cp = '\0'; *cp = '\0';
} else { } else {
fprintf (stderr, if (feof (stdin) == 0) {
_("%s: line %d: line too long\n"), fprintf (stderr,
Prog, line); _("%s: line %d: line too long\n"),
errors++; Prog, line);
continue; errors++;
continue;
}
} }
/* /*

View File

@ -863,10 +863,13 @@ int main (int argc, char **argv)
if (NULL != cp) { if (NULL != cp) {
*cp = '\0'; *cp = '\0';
} else { } else {
fprintf (stderr, _("%s: line %d: line too long\n"), if (feof (stdin) == 0) {
Prog, line); fprintf (stderr,
errors++; _("%s: line %d: line too long\n"),
continue; Prog, line);
errors++;
continue;
}
} }
/* /*

View File

@ -421,7 +421,7 @@ static int set_defaults (void)
{ {
FILE *ifp; FILE *ifp;
FILE *ofp; FILE *ofp;
char buf[PATH_MAX]; char buf[1024];
static char new_file[] = NEW_USER_FILE; static char new_file[] = NEW_USER_FILE;
char *cp; char *cp;
int ofd; int ofd;
@ -468,6 +468,16 @@ static int set_defaults (void)
cp = strrchr (buf, '\n'); cp = strrchr (buf, '\n');
if (NULL != cp) { if (NULL != cp) {
*cp = '\0'; *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)) { if (!out_group && MATCH (buf, DGROUP)) {