diff options
Diffstat (limited to 'src/usermod.c')
-rw-r--r-- | src/usermod.c | 104 |
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, |