summaryrefslogtreecommitdiffstats
path: root/src/useradd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/useradd.c')
-rw-r--r--src/useradd.c909
1 files changed, 467 insertions, 442 deletions
diff --git a/src/useradd.c b/src/useradd.c
index 7ea0a9c..347334a 100644
--- a/src/useradd.c
+++ b/src/useradd.c
@@ -17,9 +17,12 @@
#include <fcntl.h>
#include <getopt.h>
#include <grp.h>
+#ifdef ENABLE_LASTLOG
#include <lastlog.h>
+#endif /* ENABLE_LASTLOG */
#include <libgen.h>
#include <pwd.h>
+#include <signal.h>
#ifdef ACCT_TOOLS_SETUID
#ifdef USE_PAM
#include "pam_defs.h"
@@ -32,11 +35,15 @@
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
+
+#include "alloc.h"
+#include "atoi/str2i.h"
#include "chkname.h"
#include "defines.h"
#include "faillog.h"
#include "getdef.h"
#include "groupio.h"
+#include "memzero.h"
#include "nscd.h"
#include "sssd.h"
#include "prototypes.h"
@@ -57,10 +64,15 @@
#include "tcbfuncs.h"
#endif
#include "shadowlog.h"
+#include "string/sprintf.h"
+
#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"
@@ -74,16 +86,18 @@
/*
* Global variables
*/
-const char *Prog;
+static const char Prog[] = "useradd";
/*
* These defaults are used if there is no defaults file.
*/
static gid_t def_group = 1000;
+static const char *def_groups = "";
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";
@@ -106,6 +120,7 @@ static const char *prefix_user_home = NULL;
#ifdef WITH_SELINUX
static /*@notnull@*/const char *user_selinux = "";
+static const char *user_selinux_range = NULL;
#endif /* WITH_SELINUX */
static long user_expire = -1;
@@ -183,25 +198,26 @@ static bool home_added = false;
#endif /* ENABLE_SUBIDS */
#define DGROUP "GROUP="
+#define DGROUPS "GROUPS="
#define DHOME "HOME="
#define DSHELL "SHELL="
#define DINACT "INACTIVE="
#define DEXPIRE "EXPIRE="
#define DSKEL "SKEL="
+#define DUSRSKEL "USRSKEL="
#define DCREATE_MAIL_SPOOL "CREATE_MAIL_SPOOL="
#define DLOG_INIT "LOG_INIT="
/* local function prototypes */
-static void fail_exit (int);
+NORETURN static void fail_exit (int);
static void get_defaults (void);
static void show_defaults (void);
static int set_defaults (void);
static int get_groups (char *);
static struct group * get_local_group (char * grp_name);
-static void usage (int status);
+NORETURN static void usage (int status);
static void new_pwent (struct passwd *);
-static long scale_age (long);
static void new_spent (struct spwd *);
static void grp_update (void);
@@ -213,118 +229,97 @@ static void open_files (void);
static void open_group_files (void);
static void open_shadow (void);
static void faillog_reset (uid_t);
+#ifdef ENABLE_LASTLOG
static void lastlog_reset (uid_t);
+#endif /* ENABLE_LASTLOG */
static void tallylog_reset (const char *);
static void usr_update (unsigned long subuid_count, unsigned long subgid_count);
static void create_home (void);
static void create_mail (void);
static void check_uid_range(int rflg, uid_t user_id);
+static FILE *fmkstemp(char *template);
+
+
/*
* fail_exit - undo as much as possible
*/
static void fail_exit (int code)
{
- if (home_added) {
- if (rmdir (prefix_user_home) != 0) {
- fprintf (stderr,
- _("%s: %s was created, but could not be removed\n"),
- Prog, prefix_user_home);
- SYSLOG ((LOG_ERR, "failed to remove %s", prefix_user_home));
- }
+ if (home_added && rmdir(prefix_user_home) != 0) {
+ fprintf(stderr,
+ _("%s: %s was created, but could not be removed\n"),
+ Prog, prefix_user_home);
+ SYSLOG((LOG_ERR, "failed to remove %s", prefix_user_home));
}
- if (spw_locked) {
- if (spw_unlock () == 0) {
- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ());
- SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
+ if (spw_locked && spw_unlock() == 0) {
+ fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname());
+ SYSLOG((LOG_ERR, "failed to unlock %s", spw_dbname()));
#ifdef WITH_AUDIT
- audit_logger (AUDIT_ADD_USER, Prog,
- "unlocking shadow file",
- user_name, AUDIT_NO_ID,
- SHADOW_AUDIT_FAILURE);
+ audit_logger(AUDIT_ADD_USER, Prog, "unlocking shadow file",
+ user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
#endif
- /* continue */
- }
+ /* continue */
}
- if (pw_locked) {
- if (pw_unlock () == 0) {
- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
- SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
+ if (pw_locked && pw_unlock() == 0) {
+ fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname());
+ SYSLOG((LOG_ERR, "failed to unlock %s", pw_dbname()));
#ifdef WITH_AUDIT
- audit_logger (AUDIT_ADD_USER, Prog,
- "unlocking passwd file",
- user_name, AUDIT_NO_ID,
- SHADOW_AUDIT_FAILURE);
+ audit_logger(AUDIT_ADD_USER, Prog, "unlocking passwd file",
+ user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
#endif
- /* continue */
- }
+ /* continue */
}
- if (gr_locked) {
- if (gr_unlock () == 0) {
- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ());
- SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
+ if (gr_locked && gr_unlock() == 0) {
+ fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname());
+ SYSLOG((LOG_ERR, "failed to unlock %s", gr_dbname()));
#ifdef WITH_AUDIT
- audit_logger (AUDIT_ADD_USER, Prog,
- "unlocking group file",
- user_name, AUDIT_NO_ID,
- SHADOW_AUDIT_FAILURE);
+ audit_logger(AUDIT_ADD_USER, Prog, "unlocking group file",
+ user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
#endif
- /* continue */
- }
+ /* continue */
}
-#ifdef SHADOWGRP
- if (sgr_locked) {
- if (sgr_unlock () == 0) {
- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ());
- SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
-#ifdef WITH_AUDIT
- audit_logger (AUDIT_ADD_USER, Prog,
- "unlocking gshadow file",
- user_name, AUDIT_NO_ID,
- SHADOW_AUDIT_FAILURE);
-#endif
- /* continue */
- }
+#ifdef SHADOWGRP
+ if (sgr_locked && sgr_unlock() == 0) {
+ fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname());
+ SYSLOG((LOG_ERR, "failed to unlock %s", sgr_dbname()));
+# ifdef WITH_AUDIT
+ audit_logger(AUDIT_ADD_USER, Prog, "unlocking gshadow file",
+ user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
+# endif
+ /* continue */
}
#endif
#ifdef ENABLE_SUBIDS
- if (sub_uid_locked) {
- if (sub_uid_unlock () == 0) {
- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
- SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
-#ifdef WITH_AUDIT
- audit_logger (AUDIT_ADD_USER, Prog,
- "unlocking subordinate user file",
- user_name, AUDIT_NO_ID,
- SHADOW_AUDIT_FAILURE);
-#endif
- /* continue */
- }
+ if (sub_uid_locked && sub_uid_unlock() == 0) {
+ fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname());
+ SYSLOG((LOG_ERR, "failed to unlock %s", sub_uid_dbname()));
+# ifdef WITH_AUDIT
+ audit_logger(AUDIT_ADD_USER, Prog,
+ "unlocking subordinate user file",
+ user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
+# endif
+ /* continue */
}
- if (sub_gid_locked) {
- if (sub_gid_unlock () == 0) {
- fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
- SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
-#ifdef WITH_AUDIT
- audit_logger (AUDIT_ADD_USER, Prog,
- "unlocking subordinate group file",
- user_name, AUDIT_NO_ID,
- SHADOW_AUDIT_FAILURE);
-#endif
- /* continue */
- }
+ if (sub_gid_locked && sub_gid_unlock() == 0) {
+ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname());
+ SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname()));
+# ifdef WITH_AUDIT
+ audit_logger(AUDIT_ADD_USER, Prog,
+ "unlocking subordinate group file",
+ user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
+# endif
+ /* continue */
}
-#endif /* ENABLE_SUBIDS */
+#endif /* ENABLE_SUBIDS */
#ifdef WITH_AUDIT
- audit_logger (AUDIT_ADD_USER, Prog,
- "adding user",
- user_name, AUDIT_NO_ID,
- SHADOW_AUDIT_FAILURE);
+ audit_logger(AUDIT_ADD_USER, Prog, "adding user",
+ user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
#endif
- SYSLOG ((LOG_INFO, "failed adding user '%s', exit code: %d", user_name, code));
- exit (code);
+ SYSLOG((LOG_INFO, "failed adding user '%s', exit code: %d", user_name, code));
+ exit(code);
}
#define MATCH(x,y) (strncmp((x),(y),strlen(y)) == 0)
@@ -338,21 +333,15 @@ static void fail_exit (int code)
*/
static void get_defaults (void)
{
- FILE *fp;
- char *default_file = USER_DEFAULTS_FILE;
- char buf[1024];
- char *cp;
+ FILE *fp;
+ char *default_file = USER_DEFAULTS_FILE;
+ char buf[1024];
+ char *cp;
+ const char *ccp;
if (prefix[0]) {
- size_t len;
- int wlen;
-
- len = strlen(prefix) + strlen(USER_DEFAULTS_FILE) + 2;
- default_file = malloc(len);
- if (default_file == NULL)
- return;
- wlen = snprintf(default_file, len, "%s/%s", prefix, USER_DEFAULTS_FILE);
- assert (wlen == (int) len -1);
+ if (asprintf(&default_file, "%s/%s", prefix, USER_DEFAULTS_FILE) == -1)
+ return;
}
/*
@@ -368,7 +357,7 @@ static void get_defaults (void)
* Read the file a line at a time. Only the lines that have relevant
* values are used, everything else can be ignored.
*/
- while (fgets (buf, (int) sizeof buf, fp) == buf) {
+ while (fgets (buf, sizeof buf, fp) == buf) {
cp = strrchr (buf, '\n');
if (NULL != cp) {
*cp = '\0';
@@ -399,29 +388,42 @@ static void get_defaults (void)
}
}
+ ccp = cp;
+
+ if (MATCH (buf, DGROUPS)) {
+ if (get_groups (cp) != 0) {
+ fprintf (stderr,
+ _("%s: the '%s' configuration in %s has an invalid group, ignoring the bad group\n"),
+ Prog, DGROUPS, default_file);
+ }
+ if (user_groups[0] != NULL) {
+ do_grp_update = true;
+ def_groups = xstrdup (cp);
+ }
+ }
/*
* Default HOME filesystem
*/
else if (MATCH (buf, DHOME)) {
- def_home = xstrdup (cp);
+ def_home = xstrdup(ccp);
}
/*
* Default Login Shell command
*/
else if (MATCH (buf, DSHELL)) {
- def_shell = xstrdup (cp);
+ def_shell = xstrdup(ccp);
}
/*
* Default Password Inactive value
*/
else if (MATCH (buf, DINACT)) {
- if ( (getlong (cp, &def_inactive) == 0)
+ if ( (str2sl(&def_inactive, ccp) == -1)
|| (def_inactive < -1)) {
fprintf (stderr,
_("%s: invalid numeric argument '%s'\n"),
- Prog, cp);
+ Prog, ccp);
fprintf (stderr,
_("%s: the %s configuration in %s will be ignored\n"),
Prog, DINACT, default_file);
@@ -433,52 +435,60 @@ static void get_defaults (void)
* Default account expiration date
*/
else if (MATCH (buf, DEXPIRE)) {
- def_expire = xstrdup (cp);
+ def_expire = xstrdup(ccp);
}
/*
* Default Skeleton information
*/
else if (MATCH (buf, DSKEL)) {
- if ('\0' == *cp) {
- cp = SKEL_DIR; /* XXX warning: const */
- }
+ if ('\0' == *ccp)
+ ccp = SKEL_DIR;
if (prefix[0]) {
- size_t len;
- int wlen;
- char* _def_template; /* avoid const warning */
-
- len = strlen(prefix) + strlen(cp) + 2;
- _def_template = xmalloc(len);
- wlen = snprintf(_def_template, len, "%s/%s", prefix, cp);
- assert (wlen == (int) len -1);
- def_template = _def_template;
- }
- else {
- def_template = xstrdup (cp);
+ char *dt;
+
+ xasprintf(&dt, "%s/%s", prefix, ccp);
+ def_template = dt;
+ } else {
+ def_template = xstrdup(ccp);
}
}
/*
+ * Default Usr Skeleton information
+ */
+ else if (MATCH (buf, DUSRSKEL)) {
+ if ('\0' == *ccp)
+ ccp = USRSKELDIR;
+
+ if (prefix[0]) {
+ char *dut;
+
+ xasprintf(&dut, "%s/%s", prefix, ccp);
+ def_usrtemplate = dut;
+ } else {
+ def_usrtemplate = xstrdup(ccp);
+ }
+ }
+ /*
* Create by default user mail spool or not ?
*/
else if (MATCH (buf, DCREATE_MAIL_SPOOL)) {
- if (*cp == '\0') {
- cp = "no"; /* XXX warning: const */
- }
+ if (*ccp == '\0')
+ ccp = "no";
- def_create_mail_spool = xstrdup (cp);
+ def_create_mail_spool = xstrdup(ccp);
}
/*
* By default do we add the user to the lastlog and faillog databases ?
*/
else if (MATCH (buf, DLOG_INIT)) {
- if (*cp == '\0') {
- cp = def_log_init; /* XXX warning: const */
- }
- def_log_init = xstrdup (cp);
+ if (*ccp == '\0')
+ ccp = def_log_init;
+
+ def_log_init = xstrdup(ccp);
}
}
(void) fclose (fp);
@@ -497,11 +507,13 @@ static void get_defaults (void)
static void show_defaults (void)
{
printf ("GROUP=%u\n", (unsigned int) def_group);
+ printf ("GROUPS=%s\n", def_groups);
printf ("HOME=%s\n", def_home);
printf ("INACTIVE=%ld\n", def_inactive);
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);
}
@@ -515,49 +527,41 @@ static void show_defaults (void)
*/
static int set_defaults (void)
{
- FILE *ifp;
- FILE *ofp;
- char buf[1024];
- char *new_file = NULL;
- char *new_file_dup = NULL;
- char *default_file = USER_DEFAULTS_FILE;
- char *cp;
- int ofd;
- int wlen;
- bool out_group = false;
- bool out_home = false;
- bool out_inactive = false;
- bool out_expire = false;
- bool out_shell = false;
- bool out_skel = false;
- bool out_create_mail_spool = false;
- bool out_log_init = false;
- size_t len;
- int ret = -1;
-
-
- len = strlen(prefix) + strlen(NEW_USER_FILE) + 2;
- new_file = malloc(len);
- if (new_file == NULL) {
- fprintf (stderr,
- _("%s: cannot create new defaults file: %s\n"),
- Prog, strerror(errno));
+ int ret = -1;
+ bool out_group = false;
+ bool out_groups = false;
+ bool out_home = false;
+ bool out_inactive = false;
+ 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;
+ char buf[1024];
+ char *new_file = NULL;
+ char *new_file_dup = NULL;
+ char *default_file = USER_DEFAULTS_FILE;
+ char *cp;
+ FILE *ifp;
+ FILE *ofp;
+
+
+ if (asprintf(&new_file, "%s%s%s", prefix, prefix[0]?"/":"", NEW_USER_FILE) == -1)
+ {
+ fprintf(stderr, _("%s: cannot create new defaults file: %s\n"),
+ Prog, strerror(errno));
return -1;
}
- wlen = snprintf(new_file, len, "%s%s%s", prefix, prefix[0]?"/":"", NEW_USER_FILE);
- assert (wlen <= (int) len -1);
if (prefix[0]) {
- len = strlen(prefix) + strlen(USER_DEFAULTS_FILE) + 2;
- default_file = malloc(len);
- if (default_file == NULL) {
- fprintf (stderr,
- _("%s: cannot create new defaults file: %s\n"),
- Prog, strerror(errno));
- goto setdef_err;
+ if (asprintf(&default_file, "%s/%s", prefix, USER_DEFAULTS_FILE) == -1)
+ {
+ fprintf(stderr,
+ _("%s: cannot create new defaults file: %s\n"),
+ Prog, strerror(errno));
+ goto err_free_new;
}
- wlen = snprintf(default_file, len, "%s/%s", prefix, USER_DEFAULTS_FILE);
- assert (wlen == (int) len -1);
}
new_file_dup = strdup(new_file);
@@ -565,36 +569,27 @@ static int set_defaults (void)
fprintf (stderr,
_("%s: cannot create directory for defaults file\n"),
Prog);
- goto setdef_err;
+ goto err_free_def;
}
ret = mkdir(dirname(new_file_dup), 0755);
+ free(new_file_dup);
if (-1 == ret && EEXIST != errno) {
fprintf (stderr,
_("%s: cannot create directory for defaults file\n"),
Prog);
- free(new_file_dup);
- goto setdef_err;
+ goto err_free_def;
}
- free(new_file_dup);
/*
* Create a temporary file to copy the new output to.
*/
- ofd = mkstemp (new_file);
- if (-1 == ofd) {
- fprintf (stderr,
- _("%s: cannot create new defaults file\n"),
- Prog);
- goto setdef_err;
- }
-
- ofp = fdopen (ofd, "w");
+ ofp = fmkstemp(new_file);
if (NULL == ofp) {
fprintf (stderr,
_("%s: cannot open new defaults file\n"),
Prog);
- goto setdef_err;
+ goto err_free_def;
}
/*
@@ -608,7 +603,7 @@ static int set_defaults (void)
goto skip;
}
- while (fgets (buf, (int) sizeof buf, ifp) == buf) {
+ while (fgets (buf, sizeof buf, ifp) == buf) {
cp = strrchr (buf, '\n');
if (NULL != cp) {
*cp = '\0';
@@ -620,14 +615,18 @@ static int set_defaults (void)
fprintf (stderr,
_("%s: line too long in %s: %s..."),
Prog, default_file, buf);
- (void) fclose (ifp);
- goto setdef_err;
+ fclose(ifp);
+ fclose(ofp);
+ goto err_free_def;
}
}
if (!out_group && MATCH (buf, DGROUP)) {
fprintf (ofp, DGROUP "%u\n", (unsigned int) def_group);
out_group = true;
+ } else if (!out_groups && MATCH (buf, DGROUPS)) {
+ fprintf (ofp, DGROUPS "%s\n", def_groups);
+ out_groups = true;
} else if (!out_home && MATCH (buf, DHOME)) {
fprintf (ofp, DHOME "%s\n", def_home);
out_home = true;
@@ -643,6 +642,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,
@@ -668,6 +670,8 @@ static int set_defaults (void)
*/
if (!out_group)
fprintf (ofp, DGROUP "%u\n", (unsigned int) def_group);
+ if (!out_groups)
+ fprintf (ofp, DGROUPS "%s\n", def_groups);
if (!out_home)
fprintf (ofp, DHOME "%s\n", def_home);
if (!out_inactive)
@@ -678,6 +682,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);
@@ -690,16 +696,16 @@ static int set_defaults (void)
(void) fflush (ofp);
if ( (ferror (ofp) != 0)
|| (fsync (fileno (ofp)) != 0)
- || (fclose (ofp) != 0)) {
+ || (fclose (ofp) != 0))
+ {
unlink (new_file);
- goto setdef_err;
+ goto err_free_def;
}
/*
* Rename the current default file to its backup name.
*/
- wlen = snprintf (buf, sizeof buf, "%s-", default_file);
- assert (wlen < (int) sizeof buf);
+ assert(SNPRINTF(buf, "%s-", default_file) != -1);
unlink (buf);
if ((link (default_file, buf) != 0) && (ENOENT != errno)) {
int err = errno;
@@ -707,7 +713,7 @@ static int set_defaults (void)
_("%s: Cannot create backup file (%s): %s\n"),
Prog, buf, strerror (err));
unlink (new_file);
- goto setdef_err;
+ goto err_free_def;
}
/*
@@ -718,7 +724,7 @@ static int set_defaults (void)
fprintf (stderr,
_("%s: rename: %s: %s\n"),
Prog, new_file, strerror (err));
- goto setdef_err;
+ goto err_free_def;
}
#ifdef WITH_AUDIT
audit_logger (AUDIT_USYS_CONFIG, Prog,
@@ -733,11 +739,12 @@ static int set_defaults (void)
def_inactive, def_expire, def_template,
def_create_mail_spool, def_log_init));
ret = 0;
- setdef_err:
- free(new_file);
- if (prefix[0]) {
+
+err_free_def:
+ if (prefix[0])
free(default_file);
- }
+err_free_new:
+ free(new_file);
return ret;
}
@@ -807,20 +814,6 @@ static int get_groups (char *list)
continue;
}
-#ifdef USE_NIS
- /*
- * Don't add this group if they are an NIS group. Tell
- * the user to go to the server for this group.
- */
- if (__isgrNIS ()) {
- fprintf (stderr,
- _("%s: group '%s' is a NIS group.\n"),
- Prog, grp->gr_name);
- gr_free(grp);
- continue;
- }
-#endif
-
if (ngroups == sys_ngroups) {
fprintf (stderr,
_("%s: too many groups specified (max %d).\n"),
@@ -839,7 +832,7 @@ static int get_groups (char *list)
close_group_files ();
unlock_group_files ();
- user_groups[ngroups] = (char *) 0;
+ user_groups[ngroups] = NULL;
/*
* Any errors in finding group names are fatal
@@ -860,17 +853,17 @@ static int get_groups (char *list)
*/
static struct group * get_local_group(char * grp_name)
{
+ char *end;
const struct group *grp;
struct group *result_grp = NULL;
- long long int gid;
- char *endptr;
+ long long gid;
- gid = strtoll (grp_name, &endptr, 10);
+ gid = strtoll(grp_name, &end, 10);
if ( ('\0' != *grp_name)
- && ('\0' == *endptr)
+ && ('\0' == *end)
&& (ERANGE != errno)
&& (gid == (gid_t)gid)) {
- grp = gr_locate_gid ((gid_t) gid);
+ grp = gr_locate_gid (gid);
}
else {
grp = gr_locate(grp_name);
@@ -923,8 +916,10 @@ static void usage (int status)
(void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
(void) fputs (_(" -k, --skel SKEL_DIR use this alternative skeleton directory\n"), usageout);
(void) fputs (_(" -K, --key KEY=VALUE override /etc/login.defs defaults\n"), usageout);
+#ifdef ENABLE_LASTLOG
(void) fputs (_(" -l, --no-log-init do not add the user to the lastlog and\n"
" faillog databases\n"), usageout);
+#endif /* ENABLE_LASTLOG */
(void) fputs (_(" -m, --create-home create the user's home directory\n"), usageout);
(void) fputs (_(" -M, --no-create-home do not create the user's home directory\n"), usageout);
(void) fputs (_(" -N, --no-user-group do not create a group with the same name as\n"
@@ -940,6 +935,7 @@ static void usage (int status)
(void) fputs (_(" -U, --user-group create a group with the same name as the user\n"), usageout);
#ifdef WITH_SELINUX
(void) fputs (_(" -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n"), usageout);
+ (void) fputs (_(" --selinux-range SERANGE use a specific MLS range for the SELinux user mapping\n"), usageout);
#endif /* WITH_SELINUX */
(void) fputs ("\n", usageout);
exit (status);
@@ -968,15 +964,6 @@ static void new_pwent (struct passwd *pwent)
pwent->pw_shell = (char *) user_shell;
}
-static long scale_age (long x)
-{
- if (x <= 0) {
- return x;
- }
-
- return x * (DAY / SCALE);
-}
-
/*
* new_spent - initialize the values in a shadow password file entry
*
@@ -988,17 +975,17 @@ static void new_spent (struct spwd *spent)
memzero (spent, sizeof *spent);
spent->sp_namp = (char *) user_name;
spent->sp_pwdp = (char *) user_pass;
- spent->sp_lstchg = (long) gettime () / SCALE;
+ spent->sp_lstchg = gettime () / DAY;
if (0 == spent->sp_lstchg) {
/* Better disable aging than requiring a password change */
spent->sp_lstchg = -1;
}
if (!rflg) {
- spent->sp_min = scale_age (getdef_num ("PASS_MIN_DAYS", -1));
- spent->sp_max = scale_age (getdef_num ("PASS_MAX_DAYS", -1));
- spent->sp_warn = scale_age (getdef_num ("PASS_WARN_AGE", -1));
- spent->sp_inact = scale_age (def_inactive);
- spent->sp_expire = scale_age (user_expire);
+ spent->sp_min = getdef_num ("PASS_MIN_DAYS", -1);
+ spent->sp_max = getdef_num ("PASS_MAX_DAYS", -1);
+ spent->sp_warn = getdef_num ("PASS_WARN_AGE", -1);
+ spent->sp_inact = def_inactive;
+ spent->sp_expire = user_expire;
} else {
spent->sp_min = -1;
spent->sp_max = -1;
@@ -1223,6 +1210,7 @@ static void process_flags (int argc, char **argv)
{"user-group", no_argument, NULL, 'U'},
#ifdef WITH_SELINUX
{"selinux-user", required_argument, NULL, 'Z'},
+ {"selinux-range", required_argument, NULL, 202},
#endif /* WITH_SELINUX */
{NULL, 0, NULL, '\0'}
};
@@ -1310,7 +1298,7 @@ static void process_flags (int argc, char **argv)
eflg = true;
break;
case 'f':
- if ( (getlong (optarg, &def_inactive) == 0)
+ if ( (str2sl(&def_inactive, optarg) == -1)
|| (def_inactive < -1)) {
fprintf (stderr,
_("%s: invalid numeric argument '%s'\n"),
@@ -1382,7 +1370,7 @@ static void process_flags (int argc, char **argv)
/* terminate name, point to value */
*cp = '\0';
cp++;
- if (putdef_str (optarg, cp) < 0) {
+ if (putdef_str (optarg, cp, NULL) < 0) {
exit (E_BAD_ARG);
}
break;
@@ -1442,7 +1430,7 @@ static void process_flags (int argc, char **argv)
sflg = true;
break;
case 'u':
- if ( (get_uid (optarg, &user_id) == 0)
+ if ( (get_uid(optarg, &user_id) == -1)
|| (user_id == (gid_t)-1)) {
fprintf (stderr,
_("%s: invalid user ID '%s'\n"),
@@ -1472,6 +1460,9 @@ static void process_flags (int argc, char **argv)
exit (E_BAD_ARG);
}
break;
+ case 202:
+ user_selinux_range = optarg;
+ break;
#endif /* WITH_SELINUX */
default:
usage (E_USAGE);
@@ -1519,6 +1510,14 @@ static void process_flags (int argc, char **argv)
Prog, "-m", "-M");
usage (E_USAGE);
}
+#ifdef WITH_SELINUX
+ if (user_selinux_range && !Zflg) {
+ fprintf (stderr,
+ _("%s: %s flag is only allowed with the %s flag\n"),
+ Prog, "--selinux-range", "--selinux-user");
+ usage (E_USAGE);
+ }
+#endif /* WITH_SELINUX */
/*
* Either -D or username is required. Defaults can be set with -D
@@ -1551,26 +1550,17 @@ static void process_flags (int argc, char **argv)
exit (E_BAD_ARG);
}
if (!dflg) {
- char *uh;
- size_t len = strlen (def_home) + strlen (user_name) + 2;
- int wlen;
-
- uh = xmalloc (len);
- wlen = snprintf (uh, len, "%s/%s", def_home, user_name);
- assert (wlen == (int) len -1);
+ char *uh;
+ xasprintf(&uh, "%s/%s", def_home, user_name);
user_home = uh;
}
if (prefix[0]) {
- size_t len = strlen(prefix) + strlen(user_home) + 2;
- int wlen;
- char* _prefix_user_home; /* to avoid const warning */
- _prefix_user_home = xmalloc(len);
- wlen = snprintf(_prefix_user_home, len, "%s/%s", prefix, user_home);
- assert (wlen == (int) len -1);
- prefix_user_home = _prefix_user_home;
- }
- else {
+ char *puh; /* to avoid const warning */
+
+ xasprintf(&puh, "%s/%s", prefix, user_home);
+ prefix_user_home = puh;
+ } else {
prefix_user_home = user_home;
}
}
@@ -1716,23 +1706,25 @@ static void close_files (void)
*/
static void close_group_files (void)
{
- if (do_grp_update) {
- if (gr_close () == 0) {
- fprintf (stderr,
- _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ());
- SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ()));
- fail_exit (E_GRP_UPDATE);
- }
+ if (!do_grp_update)
+ return;
+
+ if (gr_close() == 0) {
+ fprintf(stderr,
+ _("%s: failure while writing changes to %s\n"),
+ Prog, gr_dbname());
+ SYSLOG((LOG_ERR, "failure while writing changes to %s", gr_dbname()));
+ fail_exit(E_GRP_UPDATE);
+ }
#ifdef SHADOWGRP
- if (is_shadow_grp && (sgr_close () == 0)) {
- fprintf (stderr,
- _("%s: failure while writing changes to %s\n"),
- Prog, sgr_dbname ());
- SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ()));
- fail_exit (E_GRP_UPDATE);
- }
-#endif /* SHADOWGRP */
+ if (is_shadow_grp && sgr_close() == 0) {
+ fprintf(stderr,
+ _("%s: failure while writing changes to %s\n"),
+ Prog, sgr_dbname());
+ SYSLOG((LOG_ERR, "failure while writing changes to %s", sgr_dbname()));
+ fail_exit(E_GRP_UPDATE);
}
+#endif /* SHADOWGRP */
}
/*
@@ -2013,14 +2005,14 @@ static void faillog_reset (uid_t uid)
return;
}
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
- || (write (fd, &fl, sizeof (fl)) != (ssize_t) sizeof (fl))
+ || (write_full(fd, &fl, sizeof (fl)) == -1)
|| (fsync (fd) != 0)) {
fprintf (stderr,
_("%s: failed to reset the faillog entry of UID %lu: %s\n"),
Prog, (unsigned long) uid, strerror (errno));
SYSLOG ((LOG_WARN, "failed to reset the faillog entry of UID %lu", (unsigned long) uid));
}
- if (close (fd) != 0) {
+ if (close (fd) != 0 && errno != EINTR) {
fprintf (stderr,
_("%s: failed to close the faillog file for UID %lu: %s\n"),
Prog, (unsigned long) uid, strerror (errno));
@@ -2028,6 +2020,7 @@ static void faillog_reset (uid_t uid)
}
}
+#ifdef ENABLE_LASTLOG
static void lastlog_reset (uid_t uid)
{
struct lastlog ll;
@@ -2040,7 +2033,7 @@ static void lastlog_reset (uid_t uid)
return;
}
- max_uid = (uid_t) getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL);
+ max_uid = getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL);
if (uid > max_uid) {
/* do not touch lastlog for large uids */
return;
@@ -2057,7 +2050,7 @@ static void lastlog_reset (uid_t uid)
return;
}
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
- || (write (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll))
+ || (write_full (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll))
|| (fsync (fd) != 0)) {
fprintf (stderr,
_("%s: failed to reset the lastlog entry of UID %lu: %s\n"),
@@ -2065,7 +2058,7 @@ static void lastlog_reset (uid_t uid)
SYSLOG ((LOG_WARN, "failed to reset the lastlog entry of UID %lu", (unsigned long) uid));
/* continue */
}
- if (close (fd) != 0) {
+ if (close (fd) != 0 && errno != EINTR) {
fprintf (stderr,
_("%s: failed to close the lastlog file for UID %lu: %s\n"),
Prog, (unsigned long) uid, strerror (errno));
@@ -2073,6 +2066,7 @@ static void lastlog_reset (uid_t uid)
/* continue */
}
}
+#endif /* ENABLE_LASTLOG */
static void tallylog_reset (const char *user_name)
{
@@ -2085,6 +2079,9 @@ static void tallylog_reset (const char *user_name)
if (access(pam_tally2, X_OK) == -1)
return;
+ /* set SIGCHLD to default for waitpid */
+ signal(SIGCHLD, SIG_DFL);
+
failed = 0;
switch (childpid = fork())
{
@@ -2159,7 +2156,9 @@ static void usr_update (unsigned long subuid_count, unsigned long subgid_count)
/* local, no need for xgetpwuid */
if ((!lflg) && (prefix_getpwuid (user_id) == NULL)) {
faillog_reset (user_id);
+#ifdef ENABLE_LASTLOG
lastlog_reset (user_id);
+#endif /* ENABLE_LASTLOG */
}
/*
@@ -2182,20 +2181,19 @@ static void usr_update (unsigned long subuid_count, unsigned long subgid_count)
#ifdef WITH_AUDIT
audit_logger (AUDIT_ADD_USER, Prog,
"adding shadow password",
- user_name, (unsigned int) user_id,
- SHADOW_AUDIT_FAILURE);
+ user_name, user_id, SHADOW_AUDIT_FAILURE);
#endif
fail_exit (E_PW_UPDATE);
}
#ifdef ENABLE_SUBIDS
- if (is_sub_uid &&
+ if (is_sub_uid && !local_sub_uid_assigned(user_name) &&
(sub_uid_add(user_name, sub_uid_start, subuid_count) == 0)) {
fprintf (stderr,
_("%s: failed to prepare the new %s entry\n"),
Prog, sub_uid_dbname ());
fail_exit (E_SUB_UID_UPDATE);
}
- if (is_sub_gid &&
+ if (is_sub_gid && !local_sub_gid_assigned(user_name) &&
(sub_gid_add(user_name, sub_gid_start, subgid_count) == 0)) {
fprintf (stderr,
_("%s: failed to prepare the new %s entry\n"),
@@ -2205,9 +2203,14 @@ static void usr_update (unsigned long subuid_count, unsigned long subgid_count)
#endif /* ENABLE_SUBIDS */
#ifdef WITH_AUDIT
+ /*
+ * Even though we have the ID of the user, we won't send it now
+ * because its not written to disk yet. After close_files it is
+ * and we can use the real ID thereafter.
+ */
audit_logger (AUDIT_ADD_USER, Prog,
"adding user",
- user_name, (unsigned int) user_id,
+ user_name, AUDIT_NO_ID,
SHADOW_AUDIT_SUCCESS);
#endif
/*
@@ -2227,123 +2230,120 @@ static void usr_update (unsigned long subuid_count, unsigned long subgid_count)
*/
static void create_home (void)
{
- if (access (prefix_user_home, F_OK) != 0) {
- char path[strlen (prefix_user_home) + 2];
- char *bhome, *cp;
+ char path[strlen(prefix_user_home) + 2];
+ char *bhome, *cp;
+ mode_t mode;
- path[0] = '\0';
- bhome = strdup (prefix_user_home);
- if (!bhome) {
- fprintf (stderr,
- _("%s: error while duplicating string %s\n"),
- Prog, user_home);
- fail_exit (E_HOMEDIR);
- }
+ if (access (prefix_user_home, F_OK) == 0)
+ return;
+
+ path[0] = '\0';
+ bhome = strdup(prefix_user_home);
+ if (!bhome) {
+ fprintf(stderr,
+ _("%s: error while duplicating string %s\n"),
+ Prog, user_home);
+ fail_exit(E_HOMEDIR);
+ }
#ifdef WITH_SELINUX
- if (set_selinux_file_context (prefix_user_home, S_IFDIR) != 0) {
- fprintf (stderr,
- _("%s: cannot set SELinux context for home directory %s\n"),
- Prog, user_home);
- fail_exit (E_HOMEDIR);
- }
+ if (set_selinux_file_context(prefix_user_home, S_IFDIR) != 0) {
+ fprintf(stderr,
+ _("%s: cannot set SELinux context for home directory %s\n"),
+ Prog, user_home);
+ fail_exit(E_HOMEDIR);
+ }
#endif
- /* Check for every part of the path, if the directory
- exists. If not, create it with permissions 755 and
- owner root:root.
+ /* Check for every part of the path, if the directory
+ exists. If not, create it with permissions 755 and
+ owner root:root.
+ */
+ for (cp = strtok(bhome, "/"); cp != NULL; cp = strtok(NULL, "/")) {
+ /* Avoid turning a relative path into an absolute path. */
+ if (bhome[0] == '/' || strlen(path) != 0) {
+ strcat(path, "/");
+ }
+ strcat(path, cp);
+ if (access(path, F_OK) == 0) {
+ continue;
+ }
+
+ /* Check if parent directory is BTRFS, fail if requesting
+ subvolume but no BTRFS. The paths could be different by the
+ trailing slash
*/
- cp = strtok (bhome, "/");
- while (cp) {
- /* Avoid turning a relative path into an absolute path.
- */
- if (bhome[0] == '/' || strlen (path) != 0) {
- strcat (path, "/");
- }
- strcat (path, cp);
- if (access (path, F_OK) != 0) {
- /* Check if parent directory is BTRFS, fail if requesting
- subvolume but no BTRFS. The paths cound be different by the
- trailing slash
- */
#if WITH_BTRFS
- if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) {
- char *btrfs_check = strdup(path);
-
- if (!btrfs_check) {
- fprintf (stderr,
- _("%s: error while duplicating string in BTRFS check %s\n"),
- Prog, path);
- fail_exit (E_HOMEDIR);
- }
- btrfs_check[strlen(path) - strlen(cp) - 1] = '\0';
- if (is_btrfs(btrfs_check) <= 0) {
- fprintf (stderr,
- _("%s: home directory \"%s\" must be mounted on BTRFS\n"),
- Prog, path);
- fail_exit (E_HOMEDIR);
- }
- // make subvolume to mount for user instead of directory
- if (btrfs_create_subvolume(path)) {
- fprintf (stderr,
- _("%s: failed to create BTRFS subvolume: %s\n"),
- Prog, path);
- fail_exit (E_HOMEDIR);
- }
- }
- else
+ if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) {
+ char *btrfs_check = strdup(path);
+
+ if (!btrfs_check) {
+ fprintf(stderr,
+ _("%s: error while duplicating string in BTRFS check %s\n"),
+ Prog, path);
+ fail_exit(E_HOMEDIR);
+ }
+ btrfs_check[strlen(path) - strlen(cp) - 1] = '\0';
+ if (is_btrfs(btrfs_check) <= 0) {
+ fprintf(stderr,
+ _("%s: home directory \"%s\" must be mounted on BTRFS\n"),
+ Prog, path);
+ fail_exit(E_HOMEDIR);
+ }
+ free(btrfs_check);
+ // make subvolume to mount for user instead of directory
+ if (btrfs_create_subvolume(path)) {
+ fprintf(stderr,
+ _("%s: failed to create BTRFS subvolume: %s\n"),
+ Prog, path);
+ fail_exit(E_HOMEDIR);
+ }
+ }
+ else
#endif
- if (mkdir (path, 0) != 0) {
- fprintf (stderr,
- _("%s: cannot create directory %s\n"),
- Prog, path);
+ if (mkdir(path, 0) != 0) {
+ fprintf(stderr, _("%s: cannot create directory %s\n"),
+ Prog, path);
#ifdef WITH_AUDIT
- audit_logger (AUDIT_ADD_USER, Prog,
- "adding home directory",
- user_name, (unsigned int) user_id,
- SHADOW_AUDIT_FAILURE);
+ audit_logger(AUDIT_ADD_USER, Prog, "adding home directory",
+ user_name, user_id, SHADOW_AUDIT_FAILURE);
#endif
- fail_exit (E_HOMEDIR);
+ fail_exit(E_HOMEDIR);
}
- if (chown (path, 0, 0) < 0) {
- fprintf (stderr,
- _("%s: warning: chown on `%s' failed: %m\n"),
- Prog, path);
- }
- if (chmod (path, 0755) < 0) {
- fprintf (stderr,
- _("%s: warning: chmod on `%s' failed: %m\n"),
- Prog, path);
- }
- }
- cp = strtok (NULL, "/");
+ if (chown(path, 0, 0) < 0) {
+ fprintf(stderr,
+ _("%s: warning: chown on `%s' failed: %m\n"),
+ Prog, path);
}
- free (bhome);
-
- (void) chown (prefix_user_home, user_id, user_gid);
- mode_t mode = getdef_num ("HOME_MODE",
- 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
- if (chmod (prefix_user_home, mode)) {
- fprintf (stderr, _("%s: warning: chown on '%s' failed: %m\n"),
- Prog, path);
+ if (chmod(path, 0755) < 0) {
+ fprintf(stderr,
+ _("%s: warning: chmod on `%s' failed: %m\n"),
+ Prog, path);
}
- home_added = true;
+ }
+ free(bhome);
+
+ (void) chown(prefix_user_home, user_id, user_gid);
+ mode = getdef_num("HOME_MODE",
+ 0777 & ~getdef_num("UMASK", GETDEF_DEFAULT_UMASK));
+ if (chmod(prefix_user_home, mode)) {
+ fprintf(stderr, _("%s: warning: chown on '%s' failed: %m\n"),
+ Prog, path);
+ }
+ home_added = true;
#ifdef WITH_AUDIT
- audit_logger (AUDIT_ADD_USER, Prog,
- "adding home directory",
- user_name, (unsigned int) user_id,
- SHADOW_AUDIT_SUCCESS);
+ audit_logger(AUDIT_ADD_USER, Prog, "adding home directory",
+ user_name, user_id, SHADOW_AUDIT_SUCCESS);
#endif
#ifdef WITH_SELINUX
- /* Reset SELinux to create files with default contexts */
- if (reset_selinux_file_context () != 0) {
- fprintf (stderr,
- _("%s: cannot reset SELinux file creation context\n"),
- Prog);
- fail_exit (E_HOMEDIR);
- }
-#endif
+ /* Reset SELinux to create files with default contexts */
+ if (reset_selinux_file_context() != 0) {
+ fprintf(stderr,
+ _("%s: cannot reset SELinux file creation context\n"),
+ Prog);
+ fail_exit(E_HOMEDIR);
}
+#endif
}
/*
@@ -2355,72 +2355,79 @@ static void create_home (void)
*/
static void create_mail (void)
{
- if (strcasecmp (create_mail_spool, "yes") == 0) {
- const char *spool;
- char *file;
- int fd;
- struct group *gr;
- gid_t gid;
- mode_t mode;
-
- spool = getdef_str ("MAIL_DIR");
+ int fd;
+ char *file;
+ gid_t gid;
+ mode_t mode;
+ const char *spool;
+ struct group *gr;
+
+ if (strcasecmp(create_mail_spool, "yes") != 0)
+ return;
+
+ spool = getdef_str("MAIL_DIR");
#ifdef MAIL_SPOOL_DIR
- if ((NULL == spool) && (getdef_str ("MAIL_FILE") == NULL)) {
- spool = MAIL_SPOOL_DIR;
- }
+ if ((NULL == spool) && (getdef_str("MAIL_FILE") == NULL)) {
+ spool = MAIL_SPOOL_DIR;
+ }
#endif /* MAIL_SPOOL_DIR */
- if (NULL == spool) {
- return;
- }
- file = alloca (strlen (prefix) + strlen (spool) + strlen (user_name) + 3);
- if (prefix[0])
- sprintf (file, "%s/%s/%s", prefix, spool, user_name);
- else
- sprintf (file, "%s/%s", spool, user_name);
+ if (NULL == spool) {
+ return;
+ }
+ if (prefix[0])
+ xasprintf(&file, "%s/%s/%s", prefix, spool, user_name);
+ else
+ xasprintf(&file, "%s/%s", spool, user_name);
#ifdef WITH_SELINUX
- if (set_selinux_file_context (file, S_IFREG) != 0) {
- fprintf (stderr,
- _("%s: cannot set SELinux context for mailbox file %s\n"),
- Prog, file);
- fail_exit (E_MAILBOXFILE);
- }
+ if (set_selinux_file_context(file, S_IFREG) != 0) {
+ fprintf(stderr,
+ _("%s: cannot set SELinux context for mailbox file %s\n"),
+ Prog, file);
+ fail_exit(E_MAILBOXFILE);
+ }
#endif
- fd = open (file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0);
- if (fd < 0) {
- perror (_("Creating mailbox file"));
- return;
- }
+ fd = open(file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0);
+ free(file);
- gr = prefix_getgrnam ("mail"); /* local, no need for xgetgrnam */
- if (NULL == gr) {
- fputs (_("Group 'mail' not found. Creating the user mailbox file with 0600 mode.\n"),
- stderr);
- gid = user_gid;
- mode = 0600;
- } else {
- gid = gr->gr_gid;
- mode = 0660;
- }
+ if (fd < 0) {
+ perror(_("Creating mailbox file"));
+ return;
+ }
- if ( (fchown (fd, user_id, gid) != 0)
- || (fchmod (fd, mode) != 0)) {
- perror (_("Setting mailbox file permissions"));
- }
+ gr = prefix_getgrnam("mail"); /* local, no need for xgetgrnam */
+ if (NULL == gr) {
+ fputs(_("Group 'mail' not found. Creating the user mailbox file with 0600 mode.\n"),
+ stderr);
+ gid = user_gid;
+ mode = 0600;
+ } else {
+ gid = gr->gr_gid;
+ mode = 0660;
+ }
+
+ if (fchown(fd, user_id, gid) != 0
+ || fchmod(fd, mode) != 0)
+ {
+ perror(_("Setting mailbox file permissions"));
+ }
- fsync (fd);
- close (fd);
+ if (fsync(fd) != 0) {
+ perror (_("Synchronize mailbox file"));
+ }
+ if (close(fd) != 0 && errno != EINTR) {
+ perror (_("Closing mailbox file"));
+ }
#ifdef WITH_SELINUX
- /* Reset SELinux to create files with default contexts */
- if (reset_selinux_file_context () != 0) {
- fprintf (stderr,
- _("%s: cannot reset SELinux file creation context\n"),
- Prog);
- fail_exit (E_MAILBOXFILE);
- }
-#endif
+ /* Reset SELinux to create files with default contexts */
+ if (reset_selinux_file_context() != 0) {
+ fprintf(stderr,
+ _("%s: cannot reset SELinux file creation context\n"),
+ Prog);
+ fail_exit(E_MAILBOXFILE);
}
+#endif
}
static void check_uid_range(int rflg, uid_t user_id)
@@ -2428,13 +2435,13 @@ static void check_uid_range(int rflg, uid_t user_id)
uid_t uid_min ;
uid_t uid_max ;
if (rflg) {
- uid_max = (uid_t)getdef_ulong("SYS_UID_MAX",getdef_ulong("UID_MIN",1000UL)-1);
+ uid_max = getdef_ulong("SYS_UID_MAX",getdef_ulong("UID_MIN",1000UL)-1);
if (user_id > uid_max) {
fprintf(stderr, _("%s warning: %s's uid %d is greater than SYS_UID_MAX %d\n"), Prog, user_name, user_id, uid_max);
}
}else{
- uid_min = (uid_t)getdef_ulong("UID_MIN", 1000UL);
- uid_max = (uid_t)getdef_ulong("UID_MAX", 6000UL);
+ uid_min = getdef_ulong("UID_MIN", 1000UL);
+ uid_max = getdef_ulong("UID_MAX", 6000UL);
if (uid_min <= uid_max) {
if (user_id < uid_min || user_id >uid_max)
fprintf(stderr, _("%s warning: %s's uid %d outside of the UID_MIN %d and UID_MAX %d range.\n"), Prog, user_name, user_id, uid_min, uid_max);
@@ -2461,10 +2468,6 @@ int main (int argc, char **argv)
unsigned long subuid_count = 0;
unsigned long subgid_count = 0;
- /*
- * Get my name so that I can use it to report errors.
- */
- Prog = Basename (argv[0]);
log_set_progname(Prog);
log_set_logfd(stderr);
@@ -2476,17 +2479,17 @@ int main (int argc, char **argv)
prefix = process_prefix_flag("-P", argc, argv);
- OPENLOG ("useradd");
+ OPENLOG (Prog);
#ifdef WITH_AUDIT
audit_help_open ();
#endif
sys_ngroups = sysconf (_SC_NGROUPS_MAX);
- user_groups = (char **) xmalloc ((1 + sys_ngroups) * sizeof (char *));
+ user_groups = XMALLOC(1 + sys_ngroups, char *);
/*
* Initialize the list to be empty
*/
- user_groups[0] = (char *) 0;
+ user_groups[0] = NULL;
is_shadow_pwd = spw_file_present ();
@@ -2499,8 +2502,8 @@ int main (int argc, char **argv)
process_flags (argc, argv);
#ifdef ENABLE_SUBIDS
- uid_min = (uid_t) getdef_ulong ("UID_MIN", 1000UL);
- uid_max = (uid_t) getdef_ulong ("UID_MAX", 60000UL);
+ uid_min = getdef_ulong ("UID_MIN", 1000UL);
+ uid_max = getdef_ulong ("UID_MAX", 60000UL);
subuid_count = getdef_ulong ("SUB_UID_COUNT", 65536);
subgid_count = getdef_ulong ("SUB_GID_COUNT", 65536);
is_sub_uid = subuid_count > 0 && sub_uid_file_present () &&
@@ -2528,7 +2531,7 @@ int main (int argc, char **argv)
fail_exit (1);
}
- retval = pam_start ("useradd", pampw?pampw->pw_name:"root", &conv, &pamh);
+ retval = pam_start (Prog, pampw?pampw->pw_name:"root", &conv, &pamh);
}
if (PAM_SUCCESS == retval) {
@@ -2629,7 +2632,7 @@ int main (int argc, char **argv)
#ifdef WITH_AUDIT
audit_logger (AUDIT_ADD_USER, Prog,
"adding user",
- user_name, (unsigned int) user_id,
+ user_name, user_id,
SHADOW_AUDIT_FAILURE);
#endif
fail_exit (E_UID_IN_USE);
@@ -2701,14 +2704,14 @@ int main (int argc, char **argv)
#ifdef WITH_SELINUX
if (Zflg) {
- if (set_seuser (user_name, user_selinux) != 0) {
+ if (set_seuser (user_name, user_selinux, user_selinux_range) != 0) {
fprintf (stderr,
_("%s: warning: the user name %s to %s SELinux user mapping failed.\n"),
Prog, user_name, user_selinux);
#ifdef WITH_AUDIT
audit_logger (AUDIT_ADD_USER, Prog,
"adding SELinux user mapping",
- user_name, (unsigned int) user_id, 0);
+ user_name, user_id, 0);
#endif /* WITH_AUDIT */
fail_exit (E_SE_UPDATE);
}
@@ -2720,6 +2723,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, true,
+ (uid_t)-1, user_id, (gid_t)-1, user_gid);
} else {
fprintf (stderr,
_("%s: warning: the home directory %s already exists.\n"
@@ -2742,3 +2747,23 @@ int main (int argc, char **argv)
return E_SUCCESS;
}
+
+static FILE *
+fmkstemp(char *template)
+{
+ int fd;
+ FILE *fp;
+
+ fd = mkstemp(template);
+ if (fd == -1)
+ return NULL;
+
+ fp = fdopen(fd, "w");
+ if (fp == NULL) {
+ close(fd);
+ unlink(template);
+ return NULL;
+ }
+
+ return fp;
+}