]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/sysusers/sysusers.c
Merge pull request #1374 from olof/autoconf_gcrypt_dep
[thirdparty/systemd.git] / src / sysusers / sysusers.c
index e69a5f58ad82d9195f8cfc77b17a443672d1c0c5..aaa33354f490ce0f0021cb8a98b4940f775b5c8d 100644 (file)
@@ -19,7 +19,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/types.h>
 #include <pwd.h>
 #include <grp.h>
 #include <shadow.h>
 #include "conf-files.h"
 #include "copy.h"
 #include "utf8.h"
-#include "label.h"
 #include "fileio-label.h"
 #include "uid-range.h"
+#include "selinux-util.h"
+#include "formats-util.h"
 
 typedef enum ItemType {
         ADD_USER = 'u',
@@ -76,25 +76,17 @@ static Hashmap *members = NULL;
 static Hashmap *database_uid = NULL, *database_user = NULL;
 static Hashmap *database_gid = NULL, *database_group = NULL;
 
-static uid_t search_uid = (uid_t) -1;
+static uid_t search_uid = UID_INVALID;
 static UidRange *uid_range = NULL;
 static unsigned n_uid_range = 0;
 
-#define UID_TO_PTR(u) (ULONG_TO_PTR(u+1))
-#define PTR_TO_UID(u) ((uid_t) (PTR_TO_ULONG(u)-1))
-
-#define GID_TO_PTR(g) (ULONG_TO_PTR(g+1))
-#define PTR_TO_GID(g) ((gid_t) (PTR_TO_ULONG(g)-1))
-
-#define fix_root(x) (arg_root ? strappenda(arg_root, x) : x)
-
 static int load_user_database(void) {
         _cleanup_fclose_ FILE *f = NULL;
         const char *passwd_path;
         struct passwd *pw;
         int r;
 
-        passwd_path = fix_root("/etc/passwd");
+        passwd_path = prefix_roota(arg_root, "/etc/passwd");
         f = fopen(passwd_path, "re");
         if (!f)
                 return errno == ENOENT ? 0 : -errno;
@@ -146,7 +138,7 @@ static int load_group_database(void) {
         struct group *gr;
         int r;
 
-        group_path = fix_root("/etc/group");
+        group_path = prefix_roota(arg_root, "/etc/group");
         f = fopen(group_path, "re");
         if (!f)
                 return errno == ENOENT ? 0 : -errno;
@@ -215,14 +207,14 @@ static int make_backup(const char *target, const char *x) {
         if (r < 0)
                 return r;
 
-        r = copy_bytes(src, fileno(dst), (off_t) -1);
+        r = copy_bytes(src, fileno(dst), (uint64_t) -1, true);
         if (r < 0)
                 goto fail;
 
         /* Don't fail on chmod() or chown(). If it stays owned by us
          * and/or unreadable by others, then it isn't too bad... */
 
-        backup = strappenda(x, "-");
+        backup = strjoina(x, "-");
 
         /* Copy over the access mask */
         if (fchmod(fileno(dst), st.st_mode & 07777) < 0)
@@ -375,7 +367,7 @@ static int write_files(void) {
                 _cleanup_fclose_ FILE *original = NULL;
 
                 /* First we update the actual group list file */
-                group_path = fix_root("/etc/group");
+                group_path = prefix_roota(arg_root, "/etc/group");
                 r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
                 if (r < 0)
                         goto finish;
@@ -454,7 +446,7 @@ static int write_files(void) {
                 }
 
                 /* OK, now also update the shadow file for the group list */
-                gshadow_path = fix_root("/etc/gshadow");
+                gshadow_path = prefix_roota(arg_root, "/etc/gshadow");
                 r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
                 if (r < 0)
                         goto finish;
@@ -520,7 +512,7 @@ static int write_files(void) {
                 long lstchg;
 
                 /* First we update the user database itself */
-                passwd_path = fix_root("/etc/passwd");
+                passwd_path = prefix_roota(arg_root, "/etc/passwd");
                 r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
                 if (r < 0)
                         goto finish;
@@ -605,11 +597,13 @@ static int write_files(void) {
                 }
 
                 /* The we update the shadow database */
-                shadow_path = fix_root("/etc/shadow");
+                shadow_path = prefix_roota(arg_root, "/etc/shadow");
                 r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
                 if (r < 0)
                         goto finish;
 
+                lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
+
                 original = fopen(shadow_path, "re");
                 if (original) {
                         struct spwd *sp;
@@ -623,8 +617,13 @@ static int write_files(void) {
 
                                 i = hashmap_get(users, sp->sp_namp);
                                 if (i && i->todo_user) {
-                                        r = -EEXIST;
-                                        goto finish;
+                                        /* we will update the existing entry */
+                                        sp->sp_lstchg = lstchg;
+
+                                        /* only the /etc/shadow stage is left, so we can
+                                         * safely remove the item from the todo set */
+                                        i->todo_user = false;
+                                        hashmap_remove(todo_uids, UID_TO_PTR(i->uid));
                                 }
 
                                 errno = 0;
@@ -647,7 +646,6 @@ static int write_files(void) {
                         goto finish;
                 }
 
-                lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
                 HASHMAP_FOREACH(i, todo_uids, iterator) {
                         struct spwd n = {
                                 .sp_namp = i->name,
@@ -706,8 +704,7 @@ static int write_files(void) {
                                 goto finish;
                         }
 
-                        free(group_tmp);
-                        group_tmp = NULL;
+                        group_tmp = mfree(group_tmp);
                 }
                 if (gshadow) {
                         if (rename(gshadow_tmp, gshadow_path) < 0) {
@@ -715,8 +712,7 @@ static int write_files(void) {
                                 goto finish;
                         }
 
-                        free(gshadow_tmp);
-                        gshadow_tmp = NULL;
+                        gshadow_tmp = mfree(gshadow_tmp);
                 }
         }
 
@@ -726,8 +722,7 @@ static int write_files(void) {
                         goto finish;
                 }
 
-                free(passwd_tmp);
-                passwd_tmp = NULL;
+                passwd_tmp = mfree(passwd_tmp);
         }
         if (shadow) {
                 if (rename(shadow_tmp, shadow_path) < 0) {
@@ -735,8 +730,7 @@ static int write_files(void) {
                         goto finish;
                 }
 
-                free(shadow_tmp);
-                shadow_tmp = NULL;
+                shadow_tmp = mfree(shadow_tmp);
         }
 
         r = 0;
@@ -802,7 +796,7 @@ static int uid_is_ok(uid_t uid, const char *name) {
 static int root_stat(const char *p, struct stat *st) {
         const char *fix;
 
-        fix = fix_root(p);
+        fix = prefix_roota(arg_root, p);
         if (stat(fix, st) < 0)
                 return -errno;
 
@@ -884,7 +878,6 @@ static int add_user(Item *i) {
 
         if (!arg_root) {
                 struct passwd *p;
-                struct spwd *sp;
 
                 /* Also check NSS */
                 errno = 0;
@@ -894,26 +887,14 @@ static int add_user(Item *i) {
                         i->uid = p->pw_uid;
                         i->uid_set = true;
 
-                        free(i->description);
-                        i->description = strdup(p->pw_gecos);
-                        return 0;
-                }
-                if (!IN_SET(errno, 0, ENOENT)) {
-                        log_error_errno(errno, "Failed to check if user %s already exists: %m", i->name);
-                        return -errno;
-                }
+                        r = free_and_strdup(&i->description, p->pw_gecos);
+                        if (r < 0)
+                                return log_oom();
 
-                /* And shadow too, just to be sure */
-                errno = 0;
-                sp = getspnam(i->name);
-                if (sp) {
-                        log_error("User %s already exists in shadow database, but not in user database.", i->name);
-                        return -EBADMSG;
-                }
-                if (!IN_SET(errno, 0, ENOENT)) {
-                        log_error_errno(errno, "Failed to check if user %s already exists in shadow database: %m", i->name);
-                        return -errno;
+                        return 0;
                 }
+                if (!IN_SET(errno, 0, ENOENT))
+                        return log_error_errno(errno, "Failed to check if user %s already exists: %m", i->name);
         }
 
         /* Try to use the suggested numeric uid */
@@ -1056,10 +1037,8 @@ static int add_group(Item *i) {
                         i->gid_set = true;
                         return 0;
                 }
-                if (!IN_SET(errno, 0, ENOENT)) {
-                        log_error_errno(errno, "Failed to check if group %s already exists: %m", i->name);
-                        return -errno;
-                }
+                if (!IN_SET(errno, 0, ENOENT))
+                        return log_error_errno(errno, "Failed to check if group %s already exists: %m", i->name);
         }
 
         /* Try to use the suggested numeric gid */
@@ -1168,9 +1147,8 @@ static int process_item(Item *i) {
                         }
 
                         if (i->gid_path) {
-                                free(j->gid_path);
-                                j->gid_path = strdup(i->gid_path);
-                                if (!j->gid_path)
+                                r = free_and_strdup(&j->gid_path, i->gid_path);
+                                if (r < 0)
                                         return log_oom();
                         }
 
@@ -1402,7 +1380,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         /* Parse columns */
         p = buffer;
-        r = unquote_many_words(&p, &action, &name, &id, &description, &home, NULL);
+        r = extract_many_words(&p, NULL, EXTRACT_QUOTES, &action, &name, &id, &description, &home, NULL);
         if (r < 0) {
                 log_error("[%s:%u] Syntax error.", fname, line);
                 return r;
@@ -1411,7 +1389,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                 log_error("[%s:%u] Missing action and name columns.", fname, line);
                 return -EINVAL;
         }
-        if (*p != 0) {
+        if (!isempty(p)) {
                 log_error("[%s:%u] Trailing garbage.", fname, line);
                 return -EINVAL;
         }
@@ -1428,10 +1406,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         }
 
         /* Verify name */
-        if (isempty(name) || streq(name, "-")) {
-                free(name);
-                name = NULL;
-        }
+        if (isempty(name) || streq(name, "-"))
+                name = mfree(name);
 
         if (name) {
                 r = specifier_printf(name, specifier_table, NULL, &resolved_name);
@@ -1447,10 +1423,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         }
 
         /* Verify id */
-        if (isempty(id) || streq(id, "-")) {
-                free(id);
-                id = NULL;
-        }
+        if (isempty(id) || streq(id, "-"))
+                id = mfree(id);
 
         if (id) {
                 r = specifier_printf(id, specifier_table, NULL, &resolved_id);
@@ -1461,10 +1435,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         }
 
         /* Verify description */
-        if (isempty(description) || streq(description, "-")) {
-                free(description);
-                description = NULL;
-        }
+        if (isempty(description) || streq(description, "-"))
+                description = mfree(description);
 
         if (description) {
                 if (!valid_gecos(description)) {
@@ -1474,10 +1446,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         }
 
         /* Verify home */
-        if (isempty(home) || streq(home, "-")) {
-                free(home);
-                home = NULL;
-        }
+        if (isempty(home) || streq(home, "-"))
+                home = mfree(home);
 
         if (home) {
                 if (!valid_home(home)) {