Copy also skeleton files from /usr/etc/skel (boo#1173321) --- etc/useradd | 1 + src/useradd.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) Index: src/useradd.c =================================================================== --- src/useradd.c.orig +++ src/useradd.c @@ -61,6 +61,9 @@ #ifndef SKEL_DIR #define SKEL_DIR "/etc/skel" #endif +#ifndef USRSKELDIR +#define USRSKELDIR "/usr/etc/skel" +#endif #ifndef USER_DEFAULTS_FILE #define USER_DEFAULTS_FILE "/etc/default/useradd" #define NEW_USER_FILE "/etc/default/nuaddXXXXXX" @@ -84,6 +87,7 @@ static const char *def_gname = "other"; static const char *def_home = "/home"; static const char *def_shell = "/bin/bash"; static const char *def_template = SKEL_DIR; +static const char *def_usrtemplate = USRSKELDIR; static const char *def_create_mail_spool = "yes"; static const char *def_log_init = "yes"; @@ -188,6 +192,7 @@ static bool home_added = false; #define DINACT "INACTIVE=" #define DEXPIRE "EXPIRE=" #define DSKEL "SKEL=" +#define DUSRSKEL "USRSKEL=" #define DCREATE_MAIL_SPOOL "CREATE_MAIL_SPOOL=" #define DLOG_INIT "LOG_INIT=" @@ -461,6 +466,29 @@ static void get_defaults (void) } /* + * Default Usr Skeleton information + */ + else if (MATCH (buf, DUSRSKEL)) { + if ('\0' == *cp) { + cp = USRSKELDIR; /* XXX warning: const */ + } + + if(prefix[0]) { + size_t len; + int wlen; + char* _def_usrtemplate; /* avoid const warning */ + + len = strlen(prefix) + strlen(cp) + 2; + _def_usrtemplate = xmalloc(len); + wlen = snprintf(_def_usrtemplate, len, "%s/%s", prefix, cp); + assert (wlen == (int) len -1); + def_usrtemplate = _def_usrtemplate; + } + else { + def_usrtemplate = xstrdup (cp); + } + } + /* * Create by default user mail spool or not ? */ else if (MATCH (buf, DCREATE_MAIL_SPOOL)) { @@ -502,6 +530,7 @@ static void show_defaults (void) printf ("EXPIRE=%s\n", def_expire); printf ("SHELL=%s\n", def_shell); printf ("SKEL=%s\n", def_template); + printf ("USRSKEL=%s\n", def_usrtemplate); printf ("CREATE_MAIL_SPOOL=%s\n", def_create_mail_spool); printf ("LOG_INIT=%s\n", def_log_init); } @@ -530,6 +559,7 @@ static int set_defaults (void) bool out_expire = false; bool out_shell = false; bool out_skel = false; + bool out_usrskel = false; bool out_create_mail_spool = false; bool out_log_init = false; size_t len; @@ -643,6 +673,9 @@ static int set_defaults (void) } else if (!out_skel && MATCH (buf, DSKEL)) { fprintf (ofp, DSKEL "%s\n", def_template); out_skel = true; + } else if (!out_usrskel && MATCH (buf, DUSRSKEL)) { + fprintf (ofp, DUSRSKEL "%s\n", def_usrtemplate); + out_usrskel = true; } else if (!out_create_mail_spool && MATCH (buf, DCREATE_MAIL_SPOOL)) { fprintf (ofp, @@ -678,6 +711,8 @@ static int set_defaults (void) fprintf (ofp, DSHELL "%s\n", def_shell); if (!out_skel) fprintf (ofp, DSKEL "%s\n", def_template); + if (!out_usrskel) + fprintf (ofp, DUSRSKEL "%s\n", def_usrtemplate); if (!out_create_mail_spool) fprintf (ofp, DCREATE_MAIL_SPOOL "%s\n", def_create_mail_spool); @@ -2758,6 +2793,8 @@ int main (int argc, char **argv) if (home_added) { copy_tree (def_template, prefix_user_home, false, true, (uid_t)-1, user_id, (gid_t)-1, user_gid); + copy_tree (def_usrtemplate, prefix_user_home, false, false, + (uid_t)-1, user_id, (gid_t)-1, user_gid); } else { fprintf (stderr, _("%s: warning: the home directory %s already exists.\n" Index: libmisc/copydir.c =================================================================== --- libmisc/copydir.c.orig +++ libmisc/copydir.c @@ -449,6 +449,14 @@ static int copy_entry (const struct path } /* + * If the destination already exists do nothing. + * This is after the copy_dir above to still iterate into subdirectories. + */ + if (fstatat(dst->dirfd, dst->name, &sb, AT_SYMLINK_NOFOLLOW) != -1) { + return 0; + } + + /* * Copy any symbolic links */ @@ -507,6 +515,7 @@ static int copy_dir (const struct path_i gid_t old_gid, gid_t new_gid) { int err = 0; + struct stat dst_sb; /* * Create a new target directory, make it owned by @@ -518,6 +527,15 @@ static int copy_dir (const struct path_i return -1; } #endif /* WITH_SELINUX */ + /* + * If the destination is already a directory, don't change it + * but copy into it (recursively). + */ + if (fstatat(dst->dirfd, dst->name, &dst_sb, AT_SYMLINK_NOFOLLOW) == 0 && S_ISDIR(dst_sb.st_mode)) { + return (copy_tree (src, dst, false, reset_selinux, + old_uid, new_uid, old_gid, new_gid) != 0); + } + if ( (mkdirat (dst->dirfd, dst->name, 0700) != 0) || (chownat_if_needed (dst, statp, old_uid, new_uid, old_gid, new_gid) != 0)