summaryrefslogtreecommitdiff
path: root/src/useradd.c
diff options
context:
space:
mode:
authorBalint Reczey <balint.reczey@canonical.com>2019-06-23 22:06:37 +0200
committerBalint Reczey <balint.reczey@canonical.com>2019-06-23 22:06:37 +0200
commitb28d45d2bd2462414b9dbbe38e6c7f3d5f7b462b (patch)
tree4b068e3513ef5c60228cddfcda72be0a31d09b14 /src/useradd.c
parentb0729855e8fb744192a0395ea24673557818172c (diff)
downloadshadow-b28d45d2bd2462414b9dbbe38e6c7f3d5f7b462b.tar.gz
New upstream version 4.7upstream/4.7
Diffstat (limited to 'src/useradd.c')
-rw-r--r--src/useradd.c156
1 files changed, 129 insertions, 27 deletions
diff --git a/src/useradd.c b/src/useradd.c
index e721e52b..bdd7fe8c 100644
--- a/src/useradd.c
+++ b/src/useradd.c
@@ -60,6 +60,7 @@
#include "getdef.h"
#include "groupio.h"
#include "nscd.h"
+#include "sssd.h"
#include "prototypes.h"
#include "pwauth.h"
#include "pwio.h"
@@ -164,6 +165,7 @@ static bool
oflg = false, /* permit non-unique user ID to be specified with -u */
rflg = false, /* create a system account */
sflg = false, /* shell program for new account */
+ subvolflg = false, /* create subvolume home on BTRFS */
uflg = false, /* specify user ID for new account */
Uflg = false; /* create a group having the same name as the user */
@@ -343,7 +345,7 @@ static void fail_exit (int code)
static void get_defaults (void)
{
FILE *fp;
- char* default_file = USER_DEFAULTS_FILE;
+ char *default_file = USER_DEFAULTS_FILE;
char buf[1024];
char *cp;
@@ -353,6 +355,8 @@ static void get_defaults (void)
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);
}
@@ -363,7 +367,7 @@ static void get_defaults (void)
fp = fopen (default_file, "r");
if (NULL == fp) {
- return;
+ goto getdef_err;
}
/*
@@ -474,7 +478,7 @@ static void get_defaults (void)
}
}
(void) fclose (fp);
-
+ getdef_err:
if(prefix[0]) {
free(default_file);
}
@@ -509,8 +513,8 @@ static int set_defaults (void)
FILE *ifp;
FILE *ofp;
char buf[1024];
- char* new_file = NEW_USER_FILE;
- char* default_file = USER_DEFAULTS_FILE;
+ char *new_file = NULL;
+ char *default_file = USER_DEFAULTS_FILE;
char *cp;
int ofd;
int wlen;
@@ -521,17 +525,30 @@ static int set_defaults (void)
bool out_shell = false;
bool out_skel = false;
bool out_create_mail_spool = false;
+ size_t len;
+ int ret = -1;
- if(prefix[0]) {
- size_t len;
- len = strlen(prefix) + strlen(NEW_USER_FILE) + 2;
- new_file = malloc(len);
- wlen = snprintf(new_file, len, "%s/%s", prefix, NEW_USER_FILE);
- assert (wlen == (int) len -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));
+ 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;
+ }
wlen = snprintf(default_file, len, "%s/%s", prefix, USER_DEFAULTS_FILE);
assert (wlen == (int) len -1);
}
@@ -544,7 +561,7 @@ static int set_defaults (void)
fprintf (stderr,
_("%s: cannot create new defaults file\n"),
Prog);
- return -1;
+ goto setdef_err;
}
ofp = fdopen (ofd, "w");
@@ -552,7 +569,7 @@ static int set_defaults (void)
fprintf (stderr,
_("%s: cannot open new defaults file\n"),
Prog);
- return -1;
+ goto setdef_err;
}
/*
@@ -579,7 +596,7 @@ static int set_defaults (void)
_("%s: line too long in %s: %s..."),
Prog, default_file, buf);
(void) fclose (ifp);
- return -1;
+ goto setdef_err;
}
}
@@ -643,7 +660,7 @@ static int set_defaults (void)
|| (fsync (fileno (ofp)) != 0)
|| (fclose (ofp) != 0)) {
unlink (new_file);
- return -1;
+ goto setdef_err;
}
/*
@@ -658,7 +675,7 @@ static int set_defaults (void)
_("%s: Cannot create backup file (%s): %s\n"),
Prog, buf, strerror (err));
unlink (new_file);
- return -1;
+ goto setdef_err;
}
/*
@@ -669,7 +686,7 @@ static int set_defaults (void)
fprintf (stderr,
_("%s: rename: %s: %s\n"),
Prog, new_file, strerror (err));
- return -1;
+ goto setdef_err;
}
#ifdef WITH_AUDIT
audit_logger (AUDIT_USYS_CONFIG, Prog,
@@ -683,13 +700,14 @@ static int set_defaults (void)
(unsigned int) def_group, def_home, def_shell,
def_inactive, def_expire, def_template,
def_create_mail_spool));
-
+ ret = 0;
+ setdef_err:
+ free(new_file);
if(prefix[0]) {
- free(new_file);
free(default_file);
}
- return 0;
+ return ret;
}
/*
@@ -805,6 +823,9 @@ static void usage (int status)
Prog, Prog, Prog);
(void) fputs (_(" -b, --base-dir BASE_DIR base directory for the home directory of the\n"
" new account\n"), usageout);
+#ifdef WITH_BTRFS
+ (void) fputs (_(" --btrfs-subvolume-home use BTRFS subvolume for home directory\n"), usageout);
+#endif
(void) fputs (_(" -c, --comment COMMENT GECOS field of the new account\n"), usageout);
(void) fputs (_(" -d, --home-dir HOME_DIR home directory of the new account\n"), usageout);
(void) fputs (_(" -D, --defaults print or change default useradd configuration\n"), usageout);
@@ -1085,6 +1106,9 @@ static void process_flags (int argc, char **argv)
int c;
static struct option long_options[] = {
{"base-dir", required_argument, NULL, 'b'},
+#ifdef WITH_BTRFS
+ {"btrfs-subvolume-home", no_argument, NULL, 200},
+#endif
{"comment", required_argument, NULL, 'c'},
{"home-dir", required_argument, NULL, 'd'},
{"defaults", no_argument, NULL, 'D'},
@@ -1131,6 +1155,9 @@ static void process_flags (int argc, char **argv)
def_home = optarg;
bflg = true;
break;
+ case 200:
+ subvolflg = true;
+ break;
case 'c':
if (!VALID (optarg)) {
fprintf (stderr,
@@ -1846,11 +1873,18 @@ static void lastlog_reset (uid_t uid)
struct lastlog ll;
int fd;
off_t offset_uid = (off_t) (sizeof ll) * uid;
+ uid_t max_uid;
if (access (LASTLOG_FILE, F_OK) != 0) {
return;
}
+ max_uid = (uid_t) getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL);
+ if (uid > max_uid) {
+ /* do not touch lastlog for large uids */
+ return;
+ }
+
memzero (&ll, sizeof (ll));
fd = open (LASTLOG_FILE, O_RDWR);
@@ -2018,6 +2052,19 @@ static void usr_update (void)
static void create_home (void)
{
if (access (prefix_user_home, F_OK) != 0) {
+ char path[strlen (prefix_user_home) + 2];
+ char *bhome, *cp;
+
+ 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);
+ }
+ ++bhome;
+
#ifdef WITH_SELINUX
if (set_selinux_file_context (prefix_user_home) != 0) {
fprintf (stderr,
@@ -2026,19 +2073,73 @@ static void create_home (void)
fail_exit (E_HOMEDIR);
}
#endif
- /* XXX - create missing parent directories. --marekm */
- if (mkdir (prefix_user_home, 0) != 0) {
+
+ /* Check for every part of the path, if the directory
+ exists. If not, create it with permissions 755 and
+ owner root:root.
+ */
+ cp = strtok (bhome, "/");
+ while (cp) {
+ 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
+#endif
+ if (mkdir (path, 0) != 0) {
fprintf (stderr,
- _("%s: cannot create directory %s\n"),
- Prog, prefix_user_home);
+ _("%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);
+ "adding home directory",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_FAILURE);
#endif
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, "/");
+ }
+
(void) chown (prefix_user_home, user_id, user_gid);
chmod (prefix_user_home,
0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
@@ -2389,6 +2490,7 @@ int main (int argc, char **argv)
nscd_flush_cache ("passwd");
nscd_flush_cache ("group");
+ sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP);
return E_SUCCESS;
}