2010-04-04 Nicolas François <nicolas.francois@centraliens.net>
* src/useradd.c: spool is a constant string. * src/useradd.c: Set the new copy_tree's paramater 'copy_root' to false 2010-04-04 Nicolas François <nicolas.francois@centraliens.net> * src/usermod.c: move_home() is only called if mflg is set. * src/usermod.c: Fail is -m is provided but the old home directory is not a directory. * src/usermod.c: Use the previous improvement of copy_tree to provide better error diagnosis. * src/usermod.c: When rename() is used, also change the ownership. * src/usermod.c: Do not change the ownership of the root directory twice. * src/usermod.c: When -u is provided, only change the ownership of the home directory if it is a directory. * src/usermod.c: Also change ownerships when -g is used. 2010-04-04 Nicolas François <nicolas.francois@centraliens.net> * lib/prototypes.h, libmisc/copydir.c: Add the old UID and GID to copy_tree to detect when ownership shall be changed. * libmisc/copydir.c: Document the behavior when the IDs are set to -1. * lib/prototypes.h, libmisc/copydir.c (copy_tree): Add parameter copy_root. * libmisc/copydir.c: error() and ctx can be static. * libmisc/copydir.c (copy_hardlink): Remove parameter src. 2010-04-04 Nicolas François <nicolas.francois@centraliens.net> * libmisc/chowndir.c: Dynamically allocate memory to support path longer than 1024 characters. * libmisc/chowndir.c: Fix typos in documentation. * libmisc/chowndir.c: Support and document the behavior when a old or new ID is set to -1. * libmisc/chowndir.c: Improved error detection when chown fails. * libmisc/chowndir.c: Harmonize error handling strategy when an error occurs: stop changing ownership as soon as an error was detected.
This commit is contained in:
parent
586a8f9e9e
commit
16362e289b
42
ChangeLog
42
ChangeLog
@ -1,3 +1,45 @@
|
|||||||
|
2010-04-04 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
|
* src/useradd.c: spool is a constant string.
|
||||||
|
* src/useradd.c: Set the new copy_tree's paramater 'copy_root' to false
|
||||||
|
|
||||||
|
2010-04-04 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
|
* src/usermod.c: move_home() is only called if mflg is set.
|
||||||
|
* src/usermod.c: Fail is -m is provided but the old home directory
|
||||||
|
is not a directory.
|
||||||
|
* src/usermod.c: Use the previous improvement of copy_tree to
|
||||||
|
provide better error diagnosis.
|
||||||
|
* src/usermod.c: When rename() is used, also change the ownership.
|
||||||
|
* src/usermod.c: Do not change the ownership of the root directory
|
||||||
|
twice.
|
||||||
|
* src/usermod.c: When -u is provided, only change the ownership of
|
||||||
|
the home directory if it is a directory.
|
||||||
|
* src/usermod.c: Also change ownerships when -g is used.
|
||||||
|
|
||||||
|
2010-04-04 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
|
* lib/prototypes.h, libmisc/copydir.c: Add the old UID and GID to
|
||||||
|
copy_tree to detect when ownership shall be changed.
|
||||||
|
* libmisc/copydir.c: Document the behavior when the IDs are set to
|
||||||
|
-1.
|
||||||
|
* lib/prototypes.h, libmisc/copydir.c (copy_tree): Add parameter
|
||||||
|
copy_root.
|
||||||
|
* libmisc/copydir.c: error() and ctx can be static.
|
||||||
|
* libmisc/copydir.c (copy_hardlink): Remove parameter src.
|
||||||
|
|
||||||
|
2010-04-04 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
|
* libmisc/chowndir.c: Dynamically allocate memory to support
|
||||||
|
path longer than 1024 characters.
|
||||||
|
* libmisc/chowndir.c: Fix typos in documentation.
|
||||||
|
* libmisc/chowndir.c: Support and document the behavior when a old
|
||||||
|
or new ID is set to -1.
|
||||||
|
* libmisc/chowndir.c: Improved error detection when chown fails.
|
||||||
|
* libmisc/chowndir.c: Harmonize error handling strategy when an
|
||||||
|
error occurs: stop changing ownership as soon as an error was
|
||||||
|
detected.
|
||||||
|
|
||||||
2010-04-03 Nicolas François <nicolas.francois@centraliens.net>
|
2010-04-03 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
* man/hu/passwd.5: Fix formatting typo.
|
* man/hu/passwd.5: Fix formatting typo.
|
||||||
|
@ -75,7 +75,9 @@ extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *);
|
|||||||
extern char *Basename (char *str);
|
extern char *Basename (char *str);
|
||||||
|
|
||||||
/* chowndir.c */
|
/* chowndir.c */
|
||||||
extern int chown_tree (const char *, uid_t, uid_t, gid_t, gid_t);
|
extern int chown_tree (const char *root,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
|
||||||
/* chowntty.c */
|
/* chowntty.c */
|
||||||
extern void chown_tty (const struct passwd *);
|
extern void chown_tty (const struct passwd *);
|
||||||
@ -116,8 +118,9 @@ extern bool console (const char *);
|
|||||||
|
|
||||||
/* copydir.c */
|
/* copydir.c */
|
||||||
extern int copy_tree (const char *src_root, const char *dst_root,
|
extern int copy_tree (const char *src_root, const char *dst_root,
|
||||||
long int uid, long int gid);
|
bool copy_root,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
extern int selinux_file_context (const char *dst_name);
|
extern int selinux_file_context (const char *dst_name);
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,23 +45,36 @@
|
|||||||
*
|
*
|
||||||
* chown_dir() walks a directory tree and changes the ownership
|
* chown_dir() walks a directory tree and changes the ownership
|
||||||
* of all files owned by the provided user ID.
|
* of all files owned by the provided user ID.
|
||||||
|
*
|
||||||
|
* Only files owned (resp. group-owned) by old_uid (resp. by old_gid)
|
||||||
|
* will have their ownership (resp. group-ownership) modified, unless
|
||||||
|
* old_uid (resp. old_gid) is set to -1.
|
||||||
|
*
|
||||||
|
* new_uid and new_gid can be set to -1 to indicate that no owner or
|
||||||
|
* group-owner shall be changed.
|
||||||
*/
|
*/
|
||||||
int
|
int chown_tree (const char *root,
|
||||||
chown_tree (const char *root,
|
uid_t old_uid,
|
||||||
uid_t old_uid,
|
uid_t new_uid,
|
||||||
uid_t new_uid,
|
gid_t old_gid,
|
||||||
gid_t old_gid,
|
gid_t new_gid)
|
||||||
gid_t new_gid)
|
|
||||||
{
|
{
|
||||||
char new_name[1024];
|
char *new_name;
|
||||||
|
size_t new_name_len;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct DIRECT *ent;
|
struct DIRECT *ent;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
|
new_name = malloc (1024);
|
||||||
|
if (NULL == new_name) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
new_name_len = 1024;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make certain the directory exists. This routine is called
|
* Make certain the directory exists. This routine is called
|
||||||
* directory by the invoker, or recursively.
|
* directly by the invoker, or recursively.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (access (root, F_OK) != 0) {
|
if (access (root, F_OK) != 0) {
|
||||||
@ -71,8 +84,8 @@ chown_tree (const char *root,
|
|||||||
/*
|
/*
|
||||||
* Open the directory and read each entry. Every entry is tested
|
* Open the directory and read each entry. Every entry is tested
|
||||||
* to see if it is a directory, and if so this routine is called
|
* to see if it is a directory, and if so this routine is called
|
||||||
* recursively. If not, it is checked to see if it is owned by
|
* recursively. If not, it is checked to see if an ownership
|
||||||
* old user ID.
|
* shall be changed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dir = opendir (root);
|
dir = opendir (root);
|
||||||
@ -81,6 +94,8 @@ chown_tree (const char *root,
|
|||||||
}
|
}
|
||||||
|
|
||||||
while ((ent = readdir (dir))) {
|
while ((ent = readdir (dir))) {
|
||||||
|
uid_t tmpuid = (uid_t) -1;
|
||||||
|
gid_t tmpgid = (gid_t) -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip the "." and ".." entries
|
* Skip the "." and ".." entries
|
||||||
@ -96,12 +111,16 @@ chown_tree (const char *root,
|
|||||||
* destination files.
|
* destination files.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) {
|
if (strlen (root) + strlen (ent->d_name) + 2 > new_name_len) {
|
||||||
break;
|
new_name = realloc (new_name, new_name_len + 1024);
|
||||||
|
if (NULL == new_name) {
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
new_name_len += 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf (new_name, sizeof new_name, "%s/%s", root,
|
snprintf (new_name, new_name_len, "%s/%s", root, ent->d_name);
|
||||||
ent->d_name);
|
|
||||||
|
|
||||||
/* Don't follow symbolic links! */
|
/* Don't follow symbolic links! */
|
||||||
if (LSTAT (new_name, &sb) == -1) {
|
if (LSTAT (new_name, &sb) == -1) {
|
||||||
@ -126,23 +145,52 @@ chown_tree (const char *root,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (sb.st_uid == old_uid) {
|
/*
|
||||||
LCHOWN (new_name, new_uid,
|
* By default, the IDs are not changed (-1).
|
||||||
(sb.st_gid == old_gid) ? new_gid : sb.st_gid);
|
*
|
||||||
|
* If the file is not owned by the user, the owner is not
|
||||||
|
* changed.
|
||||||
|
*
|
||||||
|
* If the file is not group-owned by the group, the
|
||||||
|
* group-owner is not changed.
|
||||||
|
*/
|
||||||
|
if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
|
||||||
|
tmpuid = new_uid;
|
||||||
|
}
|
||||||
|
if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
|
||||||
|
tmpgid = new_gid;
|
||||||
|
}
|
||||||
|
if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
|
||||||
|
rc = LCHOWN (new_name, tmpuid, tmpgid);
|
||||||
|
if (0 != rc) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free (new_name);
|
||||||
(void) closedir (dir);
|
(void) closedir (dir);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now do the root of the tree
|
* Now do the root of the tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (stat (root, &sb) == 0) {
|
if ((0 == rc) && (stat (root, &sb) == 0)) {
|
||||||
if (sb.st_uid == old_uid) {
|
uid_t tmpuid = (uid_t) -1;
|
||||||
LCHOWN (root, new_uid,
|
gid_t tmpgid = (gid_t) -1;
|
||||||
sb.st_gid == old_gid ? new_gid : sb.st_gid);
|
if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
|
||||||
|
tmpuid = new_uid;
|
||||||
}
|
}
|
||||||
|
if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
|
||||||
|
tmpgid = new_gid;
|
||||||
|
}
|
||||||
|
if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
|
||||||
|
rc = LCHOWN (root, tmpuid, tmpgid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,24 +68,38 @@ struct link_name {
|
|||||||
static /*@exposed@*/struct link_name *links;
|
static /*@exposed@*/struct link_name *links;
|
||||||
|
|
||||||
static int copy_entry (const char *src, const char *dst,
|
static int copy_entry (const char *src, const char *dst,
|
||||||
long int uid, long int gid);
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
static int copy_dir (const char *src, const char *dst,
|
static int copy_dir (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);
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
#ifdef S_IFLNK
|
#ifdef S_IFLNK
|
||||||
static char *readlink_malloc (const char *filename);
|
static char *readlink_malloc (const char *filename);
|
||||||
static int copy_symlink (const char *src, const char *dst,
|
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);
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
#endif /* S_IFLNK */
|
#endif /* S_IFLNK */
|
||||||
static int copy_hardlink (const char *src, const char *dst,
|
static int copy_hardlink (const char *dst,
|
||||||
struct link_name *lp);
|
struct link_name *lp);
|
||||||
static int copy_special (const char *src, const char *dst,
|
static int copy_special (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);
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
static int copy_file (const char *src, const char *dst,
|
static int copy_file (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);
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
static int chown_if_needed (const char *dst, const struct stat *statp,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
static int lchown_if_needed (const char *dst, const struct stat *statp,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
static int fchown_if_needed (int fdst, const struct stat *statp,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid);
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
/*
|
/*
|
||||||
@ -130,7 +144,10 @@ int selinux_file_context (const char *dst_name)
|
|||||||
#endif /* WITH_SELINUX */
|
#endif /* WITH_SELINUX */
|
||||||
|
|
||||||
#if defined(WITH_ACL) || defined(WITH_ATTR)
|
#if defined(WITH_ACL) || defined(WITH_ATTR)
|
||||||
void error (struct error_context *ctx, const char *fmt, ...)
|
/*
|
||||||
|
* error - format the error messages for the ACL and EQ libraries.
|
||||||
|
*/
|
||||||
|
static void error (struct error_context *ctx, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@ -143,7 +160,7 @@ void error (struct error_context *ctx, const char *fmt, ...)
|
|||||||
va_end (ap);
|
va_end (ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct error_context ctx = {
|
static struct error_context ctx = {
|
||||||
error
|
error
|
||||||
};
|
};
|
||||||
#endif /* WITH_ACL || WITH_ATTR */
|
#endif /* WITH_ACL || WITH_ATTR */
|
||||||
@ -225,15 +242,46 @@ static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, c
|
|||||||
*
|
*
|
||||||
* copy_tree() walks a directory tree and copies ordinary files
|
* copy_tree() walks a directory tree and copies ordinary files
|
||||||
* as it goes.
|
* as it goes.
|
||||||
|
*
|
||||||
|
* old_uid and new_uid are used to set the ownership of the copied
|
||||||
|
* files. Unless old_uid is set to -1, only the files owned by
|
||||||
|
* old_uid have their ownership changed to new_uid. In addition, if
|
||||||
|
* new_uid is set to -1, no ownership will be changed.
|
||||||
|
*
|
||||||
|
* The same logic applies for the group-ownership and
|
||||||
|
* old_gid/new_gid.
|
||||||
*/
|
*/
|
||||||
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)
|
bool copy_root,
|
||||||
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
bool set_orig = false;
|
bool set_orig = false;
|
||||||
struct DIRECT *ent;
|
struct DIRECT *ent;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
|
if (copy_root) {
|
||||||
|
struct stat sb;
|
||||||
|
if (access (dst_root, F_OK) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LSTAT (src_root, &sb) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISDIR (sb.st_mode)) {
|
||||||
|
fprintf (stderr,
|
||||||
|
"%s: %s is not a directory",
|
||||||
|
Prog, src_root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy_entry (src_root, dst_root,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make certain both directories exist. This routine is called
|
* Make certain both directories exist. This routine is called
|
||||||
* after the home directory is created, or recursively after the
|
* after the home directory is created, or recursively after the
|
||||||
@ -290,7 +338,9 @@ int copy_tree (const char *src_root, const char *dst_root,
|
|||||||
snprintf (dst_name, dst_len, "%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,
|
||||||
|
old_uid, new_uid,
|
||||||
|
old_gid, new_gid);
|
||||||
}
|
}
|
||||||
if (NULL != src_name) {
|
if (NULL != src_name) {
|
||||||
free (src_name);
|
free (src_name);
|
||||||
@ -330,13 +380,18 @@ int copy_tree (const char *src_root, const char *dst_root,
|
|||||||
*
|
*
|
||||||
* The access and modification time will not be modified.
|
* The access and modification time will not be modified.
|
||||||
*
|
*
|
||||||
* The permissions will be set to uid/gid.
|
* The permissions will be set to new_uid/new_gid.
|
||||||
*
|
*
|
||||||
* If uid (resp. gid) is equal to -1, the user (resp. group) will
|
* If new_uid (resp. new_gid) is equal to -1, the user (resp. group) will
|
||||||
* not be modified.
|
* not be modified.
|
||||||
|
*
|
||||||
|
* Only the files owned (resp. group-owned) by old_uid (resp.
|
||||||
|
* old_gid) will be modified, unless old_uid (resp. old_gid) is set
|
||||||
|
* to -1.
|
||||||
*/
|
*/
|
||||||
static int copy_entry (const char *src, const char *dst,
|
static int copy_entry (const char *src, const char *dst,
|
||||||
long int uid, long int gid)
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
@ -371,7 +426,8 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
#endif /* !HAVE_STRUCT_STAT_ST_MTIM */
|
#endif /* !HAVE_STRUCT_STAT_ST_MTIM */
|
||||||
|
|
||||||
if (S_ISDIR (sb.st_mode)) {
|
if (S_ISDIR (sb.st_mode)) {
|
||||||
err = copy_dir (src, dst, &sb, mt, uid, gid);
|
err = copy_dir (src, dst, &sb, mt,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef S_IFLNK
|
#ifdef S_IFLNK
|
||||||
@ -380,7 +436,8 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
else if (S_ISLNK (sb.st_mode)) {
|
else if (S_ISLNK (sb.st_mode)) {
|
||||||
err = copy_symlink (src, dst, &sb, mt, uid, gid);
|
err = copy_symlink (src, dst, &sb, mt,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
}
|
}
|
||||||
#endif /* S_IFLNK */
|
#endif /* S_IFLNK */
|
||||||
|
|
||||||
@ -389,7 +446,7 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
else if ((lp = check_link (src, &sb)) != NULL) {
|
else if ((lp = check_link (src, &sb)) != NULL) {
|
||||||
err = copy_hardlink (src, dst, lp);
|
err = copy_hardlink (dst, lp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -399,7 +456,8 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
else if (!S_ISREG (sb.st_mode)) {
|
else if (!S_ISREG (sb.st_mode)) {
|
||||||
err = copy_special (src, dst, &sb, mt, uid, gid);
|
err = copy_special (src, dst, &sb, mt,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -408,7 +466,8 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
else {
|
else {
|
||||||
err = copy_file (src, dst, &sb, mt, uid, gid);
|
err = copy_file (src, dst, &sb, mt,
|
||||||
|
old_uid, new_uid, old_gid, new_gid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,14 +479,15 @@ static int copy_entry (const char *src, const char *dst,
|
|||||||
*
|
*
|
||||||
* Copy a directory (recursively) from src to dst.
|
* Copy a directory (recursively) from src to dst.
|
||||||
*
|
*
|
||||||
* statp, mt, uid, gid are used to set the access and modification and the
|
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||||
* access rights.
|
* the access and modification and the access rights.
|
||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_dir (const char *src, const char *dst,
|
static int copy_dir (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)
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
@ -440,9 +500,8 @@ static int copy_dir (const char *src, const char *dst,
|
|||||||
selinux_file_context (dst);
|
selinux_file_context (dst);
|
||||||
#endif /* WITH_SELINUX */
|
#endif /* WITH_SELINUX */
|
||||||
if ( (mkdir (dst, statp->st_mode) != 0)
|
if ( (mkdir (dst, statp->st_mode) != 0)
|
||||||
|| (chown (dst,
|
|| (chown_if_needed (dst, statp,
|
||||||
(uid == - 1) ? statp->st_uid : (uid_t) uid,
|
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||||
(gid == - 1) ? statp->st_gid : (gid_t) gid) != 0)
|
|
||||||
#ifdef WITH_ACL
|
#ifdef WITH_ACL
|
||||||
|| (perm_copy_file (src, dst, &ctx) != 0)
|
|| (perm_copy_file (src, dst, &ctx) != 0)
|
||||||
#else /* !WITH_ACL */
|
#else /* !WITH_ACL */
|
||||||
@ -458,7 +517,8 @@ static int copy_dir (const char *src, const char *dst,
|
|||||||
*/
|
*/
|
||||||
|| (attr_copy_file (src, dst, NULL, &ctx) != 0)
|
|| (attr_copy_file (src, dst, NULL, &ctx) != 0)
|
||||||
#endif /* WITH_ATTR */
|
#endif /* WITH_ATTR */
|
||||||
|| (copy_tree (src, dst, uid, gid) != 0)
|
|| (copy_tree (src, dst, false,
|
||||||
|
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||||
|| (utimes (dst, mt) != 0)) {
|
|| (utimes (dst, mt) != 0)) {
|
||||||
err = -1;
|
err = -1;
|
||||||
}
|
}
|
||||||
@ -508,14 +568,15 @@ static char *readlink_malloc (const char *filename)
|
|||||||
*
|
*
|
||||||
* Copy a symlink from src to dst.
|
* Copy a symlink from src to dst.
|
||||||
*
|
*
|
||||||
* statp, mt, uid, gid are used to set the access and modification and the
|
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||||
* access rights.
|
* the access and modification and the access rights.
|
||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_symlink (const char *src, const char *dst,
|
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)
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
char *oldlink;
|
char *oldlink;
|
||||||
|
|
||||||
@ -554,9 +615,8 @@ static int copy_symlink (const char *src, const char *dst,
|
|||||||
selinux_file_context (dst);
|
selinux_file_context (dst);
|
||||||
#endif /* WITH_SELINUX */
|
#endif /* WITH_SELINUX */
|
||||||
if ( (symlink (oldlink, dst) != 0)
|
if ( (symlink (oldlink, dst) != 0)
|
||||||
|| (lchown (dst,
|
|| (lchown_if_needed (dst, statp,
|
||||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
old_uid, new_uid, old_gid, new_gid) != 0)) {
|
||||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
|
|
||||||
/* FIXME: there are no modes on symlinks, right?
|
/* FIXME: there are no modes on symlinks, right?
|
||||||
* ACL could be copied, but this would be much more
|
* ACL could be copied, but this would be much more
|
||||||
* complex than calling perm_copy_file.
|
* complex than calling perm_copy_file.
|
||||||
@ -589,7 +649,7 @@ static int copy_symlink (const char *src, const char *dst,
|
|||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_hardlink (const char *src, const char *dst,
|
static int copy_hardlink (const char *dst,
|
||||||
struct link_name *lp)
|
struct link_name *lp)
|
||||||
{
|
{
|
||||||
/* FIXME: selinux, ACL, Extended Attributes needed? */
|
/* FIXME: selinux, ACL, Extended Attributes needed? */
|
||||||
@ -613,14 +673,15 @@ static int copy_hardlink (const char *src, const char *dst,
|
|||||||
*
|
*
|
||||||
* Copy a special file from src to dst.
|
* Copy a special file from src to dst.
|
||||||
*
|
*
|
||||||
* statp, mt, uid, gid are used to set the access and modification and the
|
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||||
* access rights.
|
* the access and modification and the access rights.
|
||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_special (const char *src, const char *dst,
|
static int copy_special (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)
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
@ -629,9 +690,8 @@ static int copy_special (const char *src, const char *dst,
|
|||||||
#endif /* WITH_SELINUX */
|
#endif /* WITH_SELINUX */
|
||||||
|
|
||||||
if ( (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
|
if ( (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
|
||||||
|| (chown (dst,
|
|| (chown_if_needed (dst, statp,
|
||||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
|
|
||||||
#ifdef WITH_ACL
|
#ifdef WITH_ACL
|
||||||
|| (perm_copy_file (src, dst, &ctx) != 0)
|
|| (perm_copy_file (src, dst, &ctx) != 0)
|
||||||
#else /* !WITH_ACL */
|
#else /* !WITH_ACL */
|
||||||
@ -659,14 +719,15 @@ static int copy_special (const char *src, const char *dst,
|
|||||||
*
|
*
|
||||||
* Copy a file from src to dst.
|
* Copy a file from src to dst.
|
||||||
*
|
*
|
||||||
* statp, mt, uid, gid are used to set the access and modification and the
|
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||||
* access rights.
|
* the access and modification and the access rights.
|
||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
static int copy_file (const char *src, const char *dst,
|
static int copy_file (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)
|
uid_t old_uid, uid_t new_uid,
|
||||||
|
gid_t old_gid, gid_t new_gid)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int ifd;
|
int ifd;
|
||||||
@ -683,9 +744,8 @@ static int copy_file (const char *src, const char *dst,
|
|||||||
#endif /* WITH_SELINUX */
|
#endif /* WITH_SELINUX */
|
||||||
ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
|
ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
|
||||||
if ( (ofd < 0)
|
if ( (ofd < 0)
|
||||||
|| (fchown (ofd,
|
|| (fchown_if_needed (ofd, statp,
|
||||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
|
|
||||||
#ifdef WITH_ACL
|
#ifdef WITH_ACL
|
||||||
|| (perm_copy_fd (src, ifd, dst, ofd, &ctx) != 0)
|
|| (perm_copy_fd (src, ifd, dst, ofd, &ctx) != 0)
|
||||||
#else /* !WITH_ACL */
|
#else /* !WITH_ACL */
|
||||||
@ -734,3 +794,37 @@ static int copy_file (const char *src, const char *dst,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define def_chown_if_needed(chown_function, type_dst) \
|
||||||
|
static int chown_function ## _if_needed (type_dst dst, \
|
||||||
|
const struct stat *statp, \
|
||||||
|
uid_t old_uid, uid_t new_uid, \
|
||||||
|
gid_t old_gid, gid_t new_gid) \
|
||||||
|
{ \
|
||||||
|
uid_t tmpuid = (uid_t) -1; \
|
||||||
|
gid_t tmpgid = (gid_t) -1; \
|
||||||
|
\
|
||||||
|
/* Use new_uid if old_uid is set to -1 or if the file was \
|
||||||
|
* owned by the user. */ \
|
||||||
|
if (((uid_t) -1 == old_uid) || (statp->st_uid == old_uid)) { \
|
||||||
|
tmpuid = new_uid; \
|
||||||
|
} \
|
||||||
|
/* Otherwise, or if new_uid was set to -1, we keep the same \
|
||||||
|
* owner. */ \
|
||||||
|
if ((uid_t) -1 == tmpuid) { \
|
||||||
|
tmpuid = statp->st_uid; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (((gid_t) -1 == old_gid) || (statp->st_gid == old_gid)) { \
|
||||||
|
tmpgid = new_gid; \
|
||||||
|
} \
|
||||||
|
if ((gid_t) -1 == tmpgid) { \
|
||||||
|
tmpgid = statp->st_gid; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return chown_function (dst, tmpuid, tmpgid); \
|
||||||
|
}
|
||||||
|
|
||||||
|
def_chown_if_needed (chown, const char *)
|
||||||
|
def_chown_if_needed (lchown, const char *)
|
||||||
|
def_chown_if_needed (fchown, int)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2000 - 2006, Tomasz Kłoczko
|
* Copyright (c) 2000 - 2006, Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2009, Nicolas François
|
* Copyright (c) 2007 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -1806,7 +1806,8 @@ static void create_home (void)
|
|||||||
static void create_mail (void)
|
static void create_mail (void)
|
||||||
{
|
{
|
||||||
if (strcasecmp (create_mail_spool, "yes") == 0) {
|
if (strcasecmp (create_mail_spool, "yes") == 0) {
|
||||||
char *spool, *file;
|
const char *spool;
|
||||||
|
char *file;
|
||||||
int fd;
|
int fd;
|
||||||
struct group *gr;
|
struct group *gr;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
@ -2036,7 +2037,8 @@ int main (int argc, char **argv)
|
|||||||
if (mflg) {
|
if (mflg) {
|
||||||
create_home ();
|
create_home ();
|
||||||
if (home_added) {
|
if (home_added) {
|
||||||
copy_tree (def_template, user_home, user_id, user_gid);
|
copy_tree (def_template, user_home, false,
|
||||||
|
(uid_t)-1, user_id, (gid_t)-1, user_gid);
|
||||||
} else {
|
} else {
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
_("%s: warning: the home directory already exists.\n"
|
_("%s: warning: the home directory already exists.\n"
|
||||||
|
102
src/usermod.c
102
src/usermod.c
@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||||
* Copyright (c) 2000 - 2006, Tomasz Kłoczko
|
* Copyright (c) 2000 - 2006, Tomasz Kłoczko
|
||||||
* Copyright (c) 2007 - 2009, Nicolas François
|
* Copyright (c) 2007 - 2010, Nicolas François
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -1403,44 +1403,51 @@ static void move_home (void)
|
|||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
if (mflg && (stat (user_home, &sb) == 0)) {
|
if (stat (user_home, &sb) == 0) {
|
||||||
/*
|
/*
|
||||||
* Don't try to move it if it is not a directory
|
* If the new home directory already exist, the user
|
||||||
* (but /dev/null for example). --marekm
|
* should not use -m.
|
||||||
*/
|
*/
|
||||||
if (!S_ISDIR (sb.st_mode)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (access (user_newhome, F_OK) == 0) {
|
if (access (user_newhome, F_OK) == 0) {
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
_("%s: directory %s exists\n"),
|
_("%s: directory %s exists\n"),
|
||||||
Prog, user_newhome);
|
Prog, user_newhome);
|
||||||
fail_exit (E_HOMEDIR);
|
fail_exit (E_HOMEDIR);
|
||||||
} else if (rename (user_home, user_newhome) != 0) {
|
}
|
||||||
// FIXME: rename above may have broken symlinks
|
|
||||||
// pointing to the user's home directory
|
/*
|
||||||
// with an absolute path.
|
* Don't try to move it if it is not a directory
|
||||||
if (errno == EXDEV) {
|
* (but /dev/null for example). --marekm
|
||||||
if (mkdir (user_newhome, sb.st_mode & 0777) != 0) {
|
*/
|
||||||
fprintf (stderr,
|
if (!S_ISDIR (sb.st_mode)) {
|
||||||
_("%s: can't create %s\n"),
|
fprintf (stderr,
|
||||||
Prog, user_newhome);
|
_("%s: The previous home directory (%s) was "
|
||||||
}
|
"not a directory. It is not removed and no "
|
||||||
if (chown (user_newhome, sb.st_uid, sb.st_gid) != 0) {
|
"home directories are created.\n"),
|
||||||
fprintf (stderr,
|
Prog, user_home);
|
||||||
_("%s: can't chown %s\n"),
|
fail_exit (E_HOMEDIR);
|
||||||
Prog, user_newhome);
|
}
|
||||||
rmdir (user_newhome);
|
|
||||||
fail_exit (E_HOMEDIR);
|
if (rename (user_home, user_newhome) == 0) {
|
||||||
}
|
/* FIXME: rename above may have broken symlinks
|
||||||
// FIXME: the current uid & gid should
|
* pointing to the user's home directory
|
||||||
// also be provided so that only the files
|
* with an absolute path. */
|
||||||
// owned by the user/group have their
|
if (chown_tree (user_newhome,
|
||||||
// ownership changed.
|
user_id, uflg ? user_newid : (uid_t)-1,
|
||||||
if (copy_tree (user_home, user_newhome,
|
user_gid, gflg ? user_newgid : (gid_t)-1) != 0) {
|
||||||
uflg ? (long int)user_newid : -1,
|
fprintf (stderr,
|
||||||
gflg ? (long int)user_newgid : -1) == 0) {
|
_("%s: Failed to change ownership of the home directory"),
|
||||||
|
Prog);
|
||||||
|
fail_exit (E_HOMEDIR);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (EXDEV == errno) {
|
||||||
|
if (copy_tree (user_home, user_newhome, true,
|
||||||
|
user_id,
|
||||||
|
uflg ? user_newid : (uid_t)-1,
|
||||||
|
user_gid,
|
||||||
|
gflg ? user_newgid : (gid_t)-1) == 0) {
|
||||||
if (remove_tree (user_home, true) != 0) {
|
if (remove_tree (user_home, true) != 0) {
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
_("%s: warning: failed to completely remove old home directory %s"),
|
_("%s: warning: failed to completely remove old home directory %s"),
|
||||||
@ -1457,8 +1464,6 @@ static void move_home (void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: do some cleanup if the copy
|
|
||||||
* was started */
|
|
||||||
(void) remove_tree (user_newhome, true);
|
(void) remove_tree (user_newhome, true);
|
||||||
}
|
}
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
@ -1472,16 +1477,6 @@ static void move_home (void)
|
|||||||
user_newname, (unsigned int) user_newid, 1);
|
user_newname, (unsigned int) user_newid, 1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (uflg || gflg) {
|
|
||||||
#ifdef WITH_AUDIT
|
|
||||||
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
||||||
"changing home directory owner",
|
|
||||||
user_newname, (unsigned int) user_newid, 1);
|
|
||||||
#endif
|
|
||||||
chown (dflg ? user_newhome : user_home,
|
|
||||||
uflg ? user_newid : user_id,
|
|
||||||
gflg ? user_newgid : user_gid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1819,17 +1814,28 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (uflg) { // FIXME: gflg also, except for faillog/lastlog
|
if (uflg) {
|
||||||
update_lastlog ();
|
update_lastlog ();
|
||||||
update_faillog ();
|
update_faillog ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mflg && (uflg || gflg)) {
|
||||||
|
if (access (dflg ? user_newhome : user_home, F_OK) == 0) {
|
||||||
/*
|
/*
|
||||||
* Change the UID on all of the files owned by `user_id' to
|
* Change the UID on all of the files owned by `user_id' to
|
||||||
* `user_newid' in the user's home directory.
|
* `user_newid' in the user's home directory.
|
||||||
|
*
|
||||||
|
* move_home() already takes care of changing the ownership.
|
||||||
*/
|
*/
|
||||||
chown_tree (dflg ? user_newhome : user_home,
|
if (chown_tree (dflg ? user_newhome : user_home,
|
||||||
user_id, user_newid,
|
user_id, uflg ? user_newid : (uid_t)-1,
|
||||||
user_gid, gflg ? user_newgid : user_gid);
|
user_gid, gflg ? user_newgid : (gid_t)-1) != 0) {
|
||||||
|
fprintf (stderr,
|
||||||
|
_("%s: Failed to change ownership of the home directory"),
|
||||||
|
Prog);
|
||||||
|
fail_exit (E_HOMEDIR);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
|
Loading…
Reference in New Issue
Block a user