summaryrefslogtreecommitdiff
path: root/src/usermod.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/usermod.c')
-rw-r--r--src/usermod.c104
1 files changed, 78 insertions, 26 deletions
diff --git a/src/usermod.c b/src/usermod.c
index 9c5e479f..e571426f 100644
--- a/src/usermod.c
+++ b/src/usermod.c
@@ -34,6 +34,7 @@
#ident "$Id$"
+#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -124,6 +125,10 @@ static long user_newinactive;
static long sys_ngroups;
static char **user_groups; /* NULL-terminated list */
+static const char* prefix = "";
+static char* prefix_user_home = NULL;
+static char* prefix_user_newhome = NULL;
+
static bool
aflg = false, /* append to existing secondary group set */
cflg = false, /* new comment (GECOS) field */
@@ -264,7 +269,7 @@ static int get_groups (char *list)
* Names starting with digits are treated as numerical GID
* values, otherwise the string is looked up as is.
*/
- grp = getgr_nam_gid (list);
+ grp = prefix_getgr_nam_gid (list);
/*
* There must be a match, either by GID value or by
@@ -411,7 +416,7 @@ static /*@noreturn@*/void usage (int status)
(void) fputs (_(" -G, --groups GROUPS new list of supplementary GROUPS\n"), usageout);
(void) fputs (_(" -a, --append append the user to the supplemental GROUPS\n"
" mentioned by the -G option without removing\n"
- " him/her from other groups\n"), usageout);
+ " the user from other groups\n"), usageout);
(void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
(void) fputs (_(" -l, --login NEW_LOGIN new value of the login name\n"), usageout);
(void) fputs (_(" -L, --lock lock the user account\n"), usageout);
@@ -420,6 +425,7 @@ static /*@noreturn@*/void usage (int status)
(void) fputs (_(" -o, --non-unique allow using duplicate (non-unique) UID\n"), usageout);
(void) fputs (_(" -p, --password PASSWORD use encrypted password for the new password\n"), usageout);
(void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout);
+ (void) fputs (_(" -P, --prefix PREFIX_DIR prefix directory where are located the /etc/* files\n"), usageout);
(void) fputs (_(" -s, --shell SHELL new login shell for the user account\n"), usageout);
(void) fputs (_(" -u, --uid UID new UID for the user account\n"), usageout);
(void) fputs (_(" -U, --unlock unlock the user account\n"), usageout);
@@ -997,6 +1003,7 @@ static void process_flags (int argc, char **argv)
{"non-unique", no_argument, NULL, 'o'},
{"password", required_argument, NULL, 'p'},
{"root", required_argument, NULL, 'R'},
+ {"prefix", required_argument, NULL, 'P'},
{"shell", required_argument, NULL, 's'},
{"uid", required_argument, NULL, 'u'},
{"unlock", no_argument, NULL, 'U'},
@@ -1012,7 +1019,7 @@ static void process_flags (int argc, char **argv)
{NULL, 0, NULL, '\0'}
};
while ((c = getopt_long (argc, argv,
- "ac:d:e:f:g:G:hl:Lmop:R:s:u:U"
+ "ac:d:e:f:g:G:hl:Lmop:R:s:u:UP:"
#ifdef ENABLE_SUBIDS
"v:w:V:W:"
#endif /* ENABLE_SUBIDS */
@@ -1114,6 +1121,8 @@ static void process_flags (int argc, char **argv)
break;
case 'R': /* no-op, handled in process_root_flag () */
break;
+ case 'P': /* no-op, handled in process_prefix_flag () */
+ break;
case 's':
if (!VALID (optarg)) {
fprintf (stderr,
@@ -1177,6 +1186,12 @@ static void process_flags (int argc, char **argv)
#endif /* ENABLE_SUBIDS */
#ifdef WITH_SELINUX
case 'Z':
+ if (prefix[0]) {
+ fprintf (stderr,
+ _("%s: -Z cannot be used with --prefix\n"),
+ Prog);
+ exit (E_BAD_ARG);
+ }
if (is_selinux_enabled () > 0) {
user_selinux = optarg;
Zflg = true;
@@ -1204,7 +1219,7 @@ static void process_flags (int argc, char **argv)
{
const struct passwd *pwd;
/* local, no need for xgetpwnam */
- pwd = getpwnam (user_name);
+ pwd = prefix_getpwnam (user_name);
if (NULL == pwd) {
fprintf (stderr,
_("%s: user '%s' does not exist\n"),
@@ -1230,6 +1245,22 @@ static void process_flags (int argc, char **argv)
if (!gflg) {
user_newgid = user_gid;
}
+ if(prefix[0]) {
+ size_t len = strlen(prefix) + strlen(user_home) + 2;
+ int wlen;
+ prefix_user_home = xmalloc(len);
+ wlen = snprintf(prefix_user_home, len, "%s/%s", prefix, user_home);
+ assert (wlen == (int) len -1);
+
+ len = strlen(prefix) + strlen(user_newhome) + 2;
+ prefix_user_newhome = xmalloc(len);
+ wlen = snprintf(prefix_user_newhome, len, "%s/%s", prefix, user_newhome);
+ assert (wlen == (int) len -1);
+ }
+ else {
+ prefix_user_home = user_home;
+ prefix_user_newhome = user_newhome;
+ }
#ifdef USE_NIS
/*
@@ -1256,7 +1287,7 @@ static void process_flags (int argc, char **argv)
{
const struct spwd *spwd = NULL;
/* local, no need for xgetspnam */
- if (is_shadow_pwd && ((spwd = getspnam (user_name)) != NULL)) {
+ if (is_shadow_pwd && ((spwd = prefix_getspnam (user_name)) != NULL)) {
user_expire = spwd->sp_expire;
user_inactive = spwd->sp_inact;
}
@@ -1346,7 +1377,7 @@ static void process_flags (int argc, char **argv)
}
/* local, no need for xgetpwnam */
- if (lflg && (getpwnam (user_newname) != NULL)) {
+ if (lflg && (prefix_getpwnam (user_newname) != NULL)) {
fprintf (stderr,
_("%s: user '%s' already exists\n"),
Prog, user_newname);
@@ -1354,7 +1385,7 @@ static void process_flags (int argc, char **argv)
}
/* local, no need for xgetpwuid */
- if (uflg && !oflg && (getpwuid (user_newid) != NULL)) {
+ if (uflg && !oflg && (prefix_getpwuid (user_newid) != NULL)) {
fprintf (stderr,
_("%s: UID '%lu' already exists\n"),
Prog, (unsigned long) user_newid);
@@ -1731,7 +1762,7 @@ static void move_home (void)
{
struct stat sb;
- if (access (user_newhome, F_OK) == 0) {
+ if (access (prefix_user_newhome, F_OK) == 0) {
/*
* If the new home directory already exist, the user
* should not use -m.
@@ -1742,7 +1773,7 @@ static void move_home (void)
fail_exit (E_HOMEDIR);
}
- if (stat (user_home, &sb) == 0) {
+ if (stat (prefix_user_home, &sb) == 0) {
/*
* Don't try to move it if it is not a directory
* (but /dev/null for example). --marekm
@@ -1764,11 +1795,11 @@ static void move_home (void)
}
#endif
- if (rename (user_home, user_newhome) == 0) {
+ if (rename (prefix_user_home, prefix_user_newhome) == 0) {
/* FIXME: rename above may have broken symlinks
* pointing to the user's home directory
* with an absolute path. */
- if (chown_tree (user_newhome,
+ if (chown_tree (prefix_user_newhome,
user_id, uflg ? user_newid : (uid_t)-1,
user_gid, gflg ? user_newgid : (gid_t)-1) != 0) {
fprintf (stderr,
@@ -1785,16 +1816,16 @@ static void move_home (void)
return;
} else {
if (EXDEV == errno) {
- if (copy_tree (user_home, user_newhome, true,
+ if (copy_tree (prefix_user_home, prefix_user_newhome, true,
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 (prefix_user_home, true) != 0) {
fprintf (stderr,
_("%s: warning: failed to completely remove old home directory %s"),
- Prog, user_home);
+ Prog, prefix_user_home);
}
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK,
@@ -1807,11 +1838,11 @@ static void move_home (void)
return;
}
- (void) remove_tree (user_newhome, true);
+ (void) remove_tree (prefix_user_newhome, true);
}
fprintf (stderr,
_("%s: cannot rename directory %s to %s\n"),
- Prog, user_home, user_newhome);
+ Prog, prefix_user_home, prefix_user_newhome);
fail_exit (E_HOMEDIR);
}
}
@@ -1949,9 +1980,11 @@ static void update_faillog (void)
static void move_mailbox (void)
{
const char *maildir;
- char mailfile[1024], newmailfile[1024];
+ char* mailfile;
+ char* newmailfile;
int fd;
struct stat st;
+ size_t len;
maildir = getdef_str ("MAIL_DIR");
#ifdef MAIL_SPOOL_DIR
@@ -1962,6 +1995,8 @@ static void move_mailbox (void)
if (NULL == maildir) {
return;
}
+ len = strlen (prefix) + strlen (maildir) + strlen (user_name) + 2;
+ mailfile = alloca (len);
/*
* O_NONBLOCK is to make sure open won't hang on mandatory locks.
@@ -1969,9 +2004,16 @@ static void move_mailbox (void)
* replacing /var/spool/mail/luser with a hard link to /etc/passwd
* between stat and chown). --marekm
*/
- (void) snprintf (mailfile, sizeof mailfile, "%s/%s",
- maildir, user_name);
- mailfile[(sizeof mailfile) - 1] = '\0';
+ if (prefix[0]) {
+ (void) snprintf (mailfile, len, "%s/%s/%s",
+ prefix, maildir, user_name);
+ }
+ else {
+ (void) snprintf (mailfile, len, "%s/%s",
+ maildir, user_name);
+ }
+ mailfile[len-1] = '\0';
+
fd = open (mailfile, O_RDONLY | O_NONBLOCK, 0);
if (fd < 0) {
/* no need for warnings if the mailbox doesn't exist */
@@ -2008,9 +2050,17 @@ static void move_mailbox (void)
(void) close (fd);
if (lflg) {
- (void) snprintf (newmailfile, sizeof newmailfile, "%s/%s",
- maildir, user_newname);
- newmailfile[(sizeof newmailfile) - 1] = '\0';
+ len = strlen (prefix) + strlen (maildir) + strlen (user_newname) + 2;
+ newmailfile = alloca(len);
+ if (prefix[0]) {
+ (void) snprintf (newmailfile, len, "%s/%s/%s",
+ prefix, maildir, user_newname);
+ }
+ else {
+ (void) snprintf (newmailfile, len, "%s/%s",
+ maildir, user_newname);
+ }
+ newmailfile[len - 1] = '\0';
if ( (link (mailfile, newmailfile) != 0)
|| (unlink (mailfile) != 0)) {
perror (_("failed to rename mailbox"));
@@ -2048,6 +2098,7 @@ int main (int argc, char **argv)
(void) textdomain (PACKAGE);
process_root_flag ("-R", argc, argv);
+ prefix = process_prefix_flag ("-P", argc, argv);
OPENLOG ("usermod");
#ifdef WITH_AUDIT
@@ -2072,8 +2123,9 @@ int main (int argc, char **argv)
/*
* The home directory, the username and the user's UID should not
* be changed while the user is logged in.
+ * Note: no need to check if a prefix is specified...
*/
- if ( (uflg || lflg || dflg
+ if ( (prefix[0] == '\0') && (uflg || lflg || dflg
#ifdef ENABLE_SUBIDS
|| Vflg || Wflg
#endif /* ENABLE_SUBIDS */
@@ -2250,7 +2302,7 @@ int main (int argc, char **argv)
}
if (!mflg && (uflg || gflg)) {
- if (access (dflg ? user_newhome : user_home, F_OK) == 0) {
+ if (access (dflg ? prefix_user_newhome : prefix_user_home, F_OK) == 0) {
/*
* Change the UID on all of the files owned by
* `user_id' to `user_newid' in the user's home
@@ -2267,7 +2319,7 @@ int main (int argc, char **argv)
user_newname, (unsigned int) user_newid, 1);
}
#endif
- if (chown_tree (dflg ? user_newhome : user_home,
+ if (chown_tree (dflg ? prefix_user_newhome : prefix_user_home,
user_id,
uflg ? user_newid : (uid_t)-1,
user_gid,