]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/sysusers/sysusers.c
sysusers: also add support for NIS entries in /etc/shadow
[thirdparty/systemd.git] / src / sysusers / sysusers.c
index fab54b50402aa718a318a9c126cde15738bc141e..0af4af06aadd6a25a8e441254a9e43362dfb258f 100644 (file)
@@ -396,6 +396,7 @@ static const char* default_shell(uid_t uid) {
 static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) {
         _cleanup_fclose_ FILE *original = NULL, *passwd = NULL;
         _cleanup_(unlink_and_freep) char *passwd_tmp = NULL;
+        struct passwd *pw = NULL;
         Iterator iterator;
         Item *i;
         int r;
@@ -409,7 +410,6 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
 
         original = fopen(passwd_path, "re");
         if (original) {
-                struct passwd *pw;
 
                 r = sync_rights(original, passwd);
                 if (r < 0)
@@ -429,6 +429,10 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
                                 return -EEXIST;
                         }
 
+                        /* Make sure we keep the NIS entries (if any) at the end. */
+                        if (IN_SET(pw->pw_name[0], '+', '-'))
+                                break;
+
                         errno = 0;
                         if (putpwent(pw, passwd) < 0)
                                 return errno ? -errno : -EIO;
@@ -468,6 +472,17 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
                         return errno ? -errno : -EIO;
         }
 
+        /* Append the remaining NIS entries if any */
+        while (pw) {
+                errno = 0;
+                if (putpwent(pw, passwd) < 0)
+                        return errno ? -errno : -EIO;
+
+                pw = fgetpwent(original);
+        }
+        if (!IN_SET(errno, 0, ENOENT))
+                return -errno;
+
         r = fflush_and_check(passwd);
         if (r < 0)
                 return r;
@@ -482,6 +497,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
 static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char **tmpfile_path) {
         _cleanup_fclose_ FILE *original = NULL, *shadow = NULL;
         _cleanup_(unlink_and_freep) char *shadow_tmp = NULL;
+        struct spwd *sp = NULL;
         Iterator iterator;
         long lstchg;
         Item *i;
@@ -498,7 +514,6 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
 
         original = fopen(shadow_path, "re");
         if (original) {
-                struct spwd *sp;
 
                 r = sync_rights(original, shadow);
                 if (r < 0)
@@ -519,6 +534,11 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
                         }
 
                         errno = 0;
+
+                        /* Make sure we keep the NIS entries (if any) at the end. */
+                        if (IN_SET(sp->sp_namp[0], '+', '-'))
+                                break;
+
                         if (putspent(sp, shadow) < 0)
                                 return errno ? -errno : -EIO;
 
@@ -551,6 +571,19 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
                 if (putspent(&n, shadow) != 0)
                         return errno ? -errno : -EIO;
         }
+        errno = 0;
+
+        /* Append the remaining NIS entries if any */
+        while (sp) {
+                errno = 0;
+                if (putspent(sp, shadow) < 0)
+                        return errno ? -errno : -EIO;
+
+                errno = 0;
+                sp = fgetspent(original);
+        }
+        if (!IN_SET(errno, 0, ENOENT))
+                return -errno;
 
         r = fflush_sync_and_check(shadow);
         if (r < 0)
@@ -567,6 +600,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
         _cleanup_fclose_ FILE *original = NULL, *group = NULL;
         _cleanup_(unlink_and_freep) char *group_tmp = NULL;
         bool group_changed = false;
+        struct group *gr = NULL;
         Iterator iterator;
         Item *i;
         int r;
@@ -580,7 +614,6 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
 
         original = fopen(group_path, "re");
         if (original) {
-                struct group *gr;
 
                 r = sync_rights(original, group);
                 if (r < 0)
@@ -604,6 +637,10 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
                                 return  -EEXIST;
                         }
 
+                        /* Make sure we keep the NIS entries (if any) at the end. */
+                        if (IN_SET(gr->gr_name[0], '+', '-'))
+                                break;
+
                         r = putgrent_with_members(gr, group);
                         if (r < 0)
                                 return r;
@@ -636,6 +673,17 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
                 group_changed = true;
         }
 
+        /* Append the remaining NIS entries if any */
+        while (gr) {
+                errno = 0;
+                if (putgrent(gr, group) != 0)
+                        return errno > 0 ? -errno : -EIO;
+
+                gr = fgetgrent(original);
+        }
+        if (!IN_SET(errno, 0, ENOENT))
+                return -errno;
+
         r = fflush_sync_and_check(group);
         if (r < 0)
                 return r;
@@ -1209,12 +1257,25 @@ static int process_item(Item *i) {
 
         switch (i->type) {
 
-        case ADD_USER:
-                r = add_group(i);
-                if (r < 0)
-                        return r;
+        case ADD_USER: {
+                Item *j;
+
+                j = ordered_hashmap_get(groups, i->name);
+                if (j && j->todo_group) {
+                        /* When the group with the same name is already in queue,
+                         * use the information about the group and do not create
+                         * duplicated group entry. */
+                        i->gid_set = j->gid_set;
+                        i->gid = j->gid;
+                        i->id_set_strict = true;
+                } else {
+                        r = add_group(i);
+                        if (r < 0)
+                                return r;
+                }
 
                 return add_user(i);
+        }
 
         case ADD_GROUP:
                 return add_group(i);
@@ -1246,40 +1307,11 @@ static int add_implicit(void) {
         int r;
 
         /* Implicitly create additional users and groups, if they were listed in "m" lines */
-
         ORDERED_HASHMAP_FOREACH_KEY(l, g, members, iterator) {
-                Item *i;
                 char **m;
 
-                i = ordered_hashmap_get(groups, g);
-                if (!i) {
-                        _cleanup_(item_freep) Item *j = NULL;
-
-                        r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops);
-                        if (r < 0)
-                                return log_oom();
-
-                        j = new0(Item, 1);
-                        if (!j)
-                                return log_oom();
-
-                        j->type = ADD_GROUP;
-                        j->name = strdup(g);
-                        if (!j->name)
-                                return log_oom();
-
-                        r = ordered_hashmap_put(groups, j->name, j);
-                        if (r < 0)
-                                return log_oom();
-
-                        log_debug("Adding implicit group '%s' due to m line", j->name);
-                        j = NULL;
-                }
-
-                STRV_FOREACH(m, l) {
-
-                        i = ordered_hashmap_get(users, *m);
-                        if (!i) {
+                STRV_FOREACH(m, l)
+                        if (!ordered_hashmap_get(users, *m)) {
                                 _cleanup_(item_freep) Item *j = NULL;
 
                                 r = ordered_hashmap_ensure_allocated(&users, &string_hash_ops);
@@ -1302,6 +1334,30 @@ static int add_implicit(void) {
                                 log_debug("Adding implicit user '%s' due to m line", j->name);
                                 j = NULL;
                         }
+
+                if (!(ordered_hashmap_get(users, g) ||
+                      ordered_hashmap_get(groups, g))) {
+                        _cleanup_(item_freep) Item *j = NULL;
+
+                        r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops);
+                        if (r < 0)
+                                return log_oom();
+
+                        j = new0(Item, 1);
+                        if (!j)
+                                return log_oom();
+
+                        j->type = ADD_GROUP;
+                        j->name = strdup(g);
+                        if (!j->name)
+                                return log_oom();
+
+                        r = ordered_hashmap_put(groups, j->name, j);
+                        if (r < 0)
+                                return log_oom();
+
+                        log_debug("Adding implicit group '%s' due to m line", j->name);
+                        j = NULL;
                 }
         }
 
@@ -1591,11 +1647,12 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                                         i->id_set_strict = true;
                                         free_and_replace(resolved_id, uid);
                                 }
-                                r = parse_uid(resolved_id, &i->uid);
-                                if (r < 0)
-                                        return log_error_errno(r, "Failed to parse UID: '%s': %m", id);
-
-                                i->uid_set = true;
+                                if (!streq(resolved_id, "-")) {
+                                        r = parse_uid(resolved_id, &i->uid);
+                                        if (r < 0)
+                                                return log_error_errno(r, "Failed to parse UID: '%s': %m", id);
+                                        i->uid_set = true;
+                                }
                         }
                 }