diff options
author | Franck Bui <fbui@suse.com> | 2017-05-09 09:37:37 +0200 |
---|---|---|
committer | Franck Bui <fbui@suse.com> | 2017-05-10 10:06:20 +0200 |
commit | b20b0b66066cef87da779b92aa7a18c7c3f71a2c (patch) | |
tree | ac4fa5d507caf1db9140747977c9cec1109320d7 /src/sysusers | |
parent | 9bfc0df113edd50bd01acba02a42f2a13db83d71 (diff) | |
download | systemd-b20b0b66066cef87da779b92aa7a18c7c3f71a2c.tar.gz |
sysusers: split make_files()
This patch extracts the code which is in charge to write the new users or
groups into temporary files and move it into 4 dedicated functions.
This part was previously inlined in makes_files() making this function quite
big and hard to read and maintain.
There should be no functional change.
Diffstat (limited to 'src/sysusers')
-rw-r--r-- | src/sysusers/sysusers.c | 617 |
1 files changed, 345 insertions, 272 deletions
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 4a0a49f2bb..5423978fed 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -370,341 +370,416 @@ static int rename_and_apply_smack(const char *temp_path, const char *dest_path) return r; } -static int write_files(void) { - - _cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL; - _cleanup_free_ char *passwd_tmp = NULL, *group_tmp = NULL, *shadow_tmp = NULL, *gshadow_tmp = NULL; - const char *passwd_path = NULL, *group_path = NULL, *shadow_path = NULL, *gshadow_path = NULL; - bool group_changed = false; +static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) { + _cleanup_fclose_ FILE *original = NULL, *passwd = NULL; + _cleanup_free_ char *passwd_tmp = NULL; Iterator iterator; Item *i; int r; - if (hashmap_size(todo_gids) > 0 || hashmap_size(members) > 0) { - _cleanup_fclose_ FILE *original = NULL; - - /* First we update the actual group list file */ - group_path = prefix_roota(arg_root, "/etc/group"); - r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp); - if (r < 0) - goto finish; + if (hashmap_size(todo_uids) == 0) + return 0; - original = fopen(group_path, "re"); - if (original) { - struct group *gr; + r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp); + if (r < 0) + return r; - r = sync_rights(original, group); - if (r < 0) - goto finish; + original = fopen(passwd_path, "re"); + if (original) { + struct passwd *pw; - errno = 0; - while ((gr = fgetgrent(original))) { - /* Safety checks against name and GID - * collisions. Normally, this should - * be unnecessary, but given that we - * look at the entries anyway here, - * let's make an extra verification - * step that we don't generate - * duplicate entries. */ - - i = hashmap_get(groups, gr->gr_name); - if (i && i->todo_group) { - log_error("%s: Group \"%s\" already exists.", group_path, gr->gr_name); - r = -EEXIST; - goto finish; - } + r = sync_rights(original, passwd); + if (r < 0) + goto fail; - if (hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) { - log_error("%s: Detected collision for GID " GID_FMT ".", group_path, gr->gr_gid); - r = -EEXIST; - goto finish; - } + errno = 0; + while ((pw = fgetpwent(original))) { - r = putgrent_with_members(gr, group); - if (r < 0) - goto finish; - if (r > 0) - group_changed = true; + i = hashmap_get(users, pw->pw_name); + if (i && i->todo_user) { + log_error("%s: User \"%s\" already exists.", passwd_path, pw->pw_name); + r = -EEXIST; + goto fail; + } - errno = 0; + if (hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) { + log_error("%s: Detected collision for UID " UID_FMT ".", passwd_path, pw->pw_uid); + r = -EEXIST; + goto fail; } - if (!IN_SET(errno, 0, ENOENT)) { - r = -errno; - goto finish; + + errno = 0; + if (putpwent(pw, passwd) < 0) { + r = errno ? -errno : -EIO; + goto fail; } - } else if (errno != ENOENT) { - r = -errno; - goto finish; - } else if (fchmod(fileno(group), 0644) < 0) { + errno = 0; + } + if (!IN_SET(errno, 0, ENOENT)) { r = -errno; - goto finish; + goto fail; } - HASHMAP_FOREACH(i, todo_gids, iterator) { - struct group n = { - .gr_name = i->name, - .gr_gid = i->gid, - .gr_passwd = (char*) "x", - }; + } else if (errno != ENOENT) { + r = -errno; + goto fail; + } else if (fchmod(fileno(passwd), 0644) < 0) { + r = -errno; + goto fail; + } - r = putgrent_with_members(&n, group); - if (r < 0) - goto finish; + HASHMAP_FOREACH(i, todo_uids, iterator) { + struct passwd n = { + .pw_name = i->name, + .pw_uid = i->uid, + .pw_gid = i->gid, + .pw_gecos = i->description, - group_changed = true; - } + /* "x" means the password is stored in the shadow file */ + .pw_passwd = (char*) "x", - r = fflush_and_check(group); - if (r < 0) - goto finish; + /* We default to the root directory as home */ + .pw_dir = i->home ? i->home : (char*) "/", + + /* Initialize the shell to nologin, with one exception: + * for root we patch in something special */ + .pw_shell = i->uid == 0 ? (char*) "/bin/sh" : (char*) "/sbin/nologin", + }; - if (original) { - fclose(original); - original = NULL; + errno = 0; + if (putpwent(&n, passwd) != 0) { + r = errno ? -errno : -EIO; + goto fail; } + } - /* OK, now also update the shadow file for the group list */ - gshadow_path = prefix_roota(arg_root, "/etc/gshadow"); - r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp); - if (r < 0) - goto finish; + r = fflush_and_check(passwd); + if (r < 0) + goto fail; - original = fopen(gshadow_path, "re"); - if (original) { - struct sgrp *sg; + *tmpfile = passwd; + *tmpfile_path = passwd_tmp; + passwd = NULL; + passwd_tmp = NULL; + return 0; - r = sync_rights(original, gshadow); - if (r < 0) - goto finish; +fail: + unlink(passwd_tmp); + return r; +} - errno = 0; - while ((sg = fgetsgent(original))) { +static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char **tmpfile_path) { + _cleanup_fclose_ FILE *original = NULL, *shadow = NULL; + _cleanup_free_ char *shadow_tmp = NULL; + Iterator iterator; + long lstchg; + Item *i; + int r; - i = hashmap_get(groups, sg->sg_namp); - if (i && i->todo_group) { - log_error("%s: Group \"%s\" already exists.", gshadow_path, sg->sg_namp); - r = -EEXIST; - goto finish; - } + if (hashmap_size(todo_uids) == 0) + return 0; - r = putsgent_with_members(sg, gshadow); - if (r < 0) - goto finish; - if (r > 0) - group_changed = true; + r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp); + if (r < 0) + return r; + + lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY); + + original = fopen(shadow_path, "re"); + if (original) { + struct spwd *sp; + + r = sync_rights(original, shadow); + if (r < 0) + goto fail; + + errno = 0; + while ((sp = fgetspent(original))) { + + i = hashmap_get(users, sp->sp_namp); + if (i && i->todo_user) { + /* we will update the existing entry */ + sp->sp_lstchg = lstchg; - errno = 0; + /* 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)); } - if (!IN_SET(errno, 0, ENOENT)) { - r = -errno; - goto finish; + + errno = 0; + if (putspent(sp, shadow) < 0) { + r = errno ? -errno : -EIO; + goto fail; } - } else if (errno != ENOENT) { - r = -errno; - goto finish; - } else if (fchmod(fileno(gshadow), 0000) < 0) { + errno = 0; + } + if (!IN_SET(errno, 0, ENOENT)) { r = -errno; - goto finish; + goto fail; } + } else if (errno != ENOENT) { + r = -errno; + goto fail; + } else if (fchmod(fileno(shadow), 0000) < 0) { + r = -errno; + goto fail; + } - HASHMAP_FOREACH(i, todo_gids, iterator) { - struct sgrp n = { - .sg_namp = i->name, - .sg_passwd = (char*) "!!", - }; + HASHMAP_FOREACH(i, todo_uids, iterator) { + struct spwd n = { + .sp_namp = i->name, + .sp_pwdp = (char*) "!!", + .sp_lstchg = lstchg, + .sp_min = -1, + .sp_max = -1, + .sp_warn = -1, + .sp_inact = -1, + .sp_expire = -1, + .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */ + }; - r = putsgent_with_members(&n, gshadow); - if (r < 0) - goto finish; - - group_changed = true; + errno = 0; + if (putspent(&n, shadow) != 0) { + r = errno ? -errno : -EIO; + goto fail; } - - r = fflush_and_check(gshadow); - if (r < 0) - goto finish; } - if (hashmap_size(todo_uids) > 0) { - _cleanup_fclose_ FILE *original = NULL; - long lstchg; + r = fflush_and_check(shadow); + if (r < 0) + goto fail; - /* First we update the user database itself */ - passwd_path = prefix_roota(arg_root, "/etc/passwd"); - r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp); - if (r < 0) - goto finish; + *tmpfile = shadow; + *tmpfile_path = shadow_tmp; + shadow = NULL; + shadow_tmp = NULL; + return 0; - original = fopen(passwd_path, "re"); - if (original) { - struct passwd *pw; +fail: + unlink(shadow_tmp); + return r; +} - r = sync_rights(original, passwd); - if (r < 0) - goto finish; +static int write_temporary_group(const char *group_path, FILE **tmpfile, char **tmpfile_path) { + _cleanup_fclose_ FILE *original = NULL, *group = NULL; + _cleanup_free_ char *group_tmp = NULL; + bool group_changed = false; + Iterator iterator; + Item *i; + int r; - errno = 0; - while ((pw = fgetpwent(original))) { + if (hashmap_size(todo_gids) == 0 && hashmap_size(members) == 0) + return 0; - i = hashmap_get(users, pw->pw_name); - if (i && i->todo_user) { - log_error("%s: User \"%s\" already exists.", passwd_path, pw->pw_name); - r = -EEXIST; - goto finish; - } + r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp); + if (r < 0) + return r; - if (hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) { - log_error("%s: Detected collision for UID " UID_FMT ".", passwd_path, pw->pw_uid); - r = -EEXIST; - goto finish; - } + original = fopen(group_path, "re"); + if (original) { + struct group *gr; - errno = 0; - if (putpwent(pw, passwd) < 0) { - r = errno ? -errno : -EIO; - goto finish; - } + r = sync_rights(original, group); + if (r < 0) + goto fail; - errno = 0; + errno = 0; + while ((gr = fgetgrent(original))) { + /* Safety checks against name and GID collisions. Normally, + * this should be unnecessary, but given that we look at the + * entries anyway here, let's make an extra verification + * step that we don't generate duplicate entries. */ + + i = hashmap_get(groups, gr->gr_name); + if (i && i->todo_group) { + log_error("%s: Group \"%s\" already exists.", group_path, gr->gr_name); + r = -EEXIST; + goto fail; } - if (!IN_SET(errno, 0, ENOENT)) { - r = -errno; - goto finish; + + if (hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) { + log_error("%s: Detected collision for GID " GID_FMT ".", group_path, gr->gr_gid); + r = -EEXIST; + goto fail; } - } else if (errno != ENOENT) { - r = -errno; - goto finish; - } else if (fchmod(fileno(passwd), 0644) < 0) { + r = putgrent_with_members(gr, group); + if (r < 0) + goto fail; + if (r > 0) + group_changed = true; + + errno = 0; + } + if (!IN_SET(errno, 0, ENOENT)) { r = -errno; - goto finish; + goto fail; } - HASHMAP_FOREACH(i, todo_uids, iterator) { - struct passwd n = { - .pw_name = i->name, - .pw_uid = i->uid, - .pw_gid = i->gid, - .pw_gecos = i->description, + } else if (errno != ENOENT) { + r = -errno; + goto fail; + } else if (fchmod(fileno(group), 0644) < 0) { + r = -errno; + goto fail; + } - /* "x" means the password is stored in - * the shadow file */ - .pw_passwd = (char*) "x", + HASHMAP_FOREACH(i, todo_gids, iterator) { + struct group n = { + .gr_name = i->name, + .gr_gid = i->gid, + .gr_passwd = (char*) "x", + }; - /* We default to the root directory as home */ - .pw_dir = i->home ? i->home : (char*) "/", + r = putgrent_with_members(&n, group); + if (r < 0) + goto fail; - /* Initialize the shell to nologin, - * with one exception: for root we - * patch in something special */ - .pw_shell = i->uid == 0 ? (char*) "/bin/sh" : (char*) "/sbin/nologin", - }; + group_changed = true; + } - errno = 0; - if (putpwent(&n, passwd) != 0) { - r = errno ? -errno : -EIO; - goto finish; - } - } + r = fflush_and_check(group); + if (r < 0) + goto fail; - r = fflush_and_check(passwd); - if (r < 0) - goto finish; + if (group_changed) { + *tmpfile = group; + *tmpfile_path = group_tmp; + group = NULL; + group_tmp = NULL; + } + return 0; - if (original) { - fclose(original); - original = NULL; - } +fail: + unlink(group_tmp); + return r; +} - /* The we update the shadow database */ - shadow_path = prefix_roota(arg_root, "/etc/shadow"); - r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp); - if (r < 0) - goto finish; +static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, char **tmpfile_path) { + _cleanup_fclose_ FILE *original = NULL, *gshadow = NULL; + _cleanup_free_ char *gshadow_tmp = NULL; + bool group_changed = false; + Iterator iterator; + Item *i; + int r; - lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY); + if (hashmap_size(todo_gids) == 0 && hashmap_size(members) == 0) + return 0; - original = fopen(shadow_path, "re"); - if (original) { - struct spwd *sp; + r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp); + if (r < 0) + return r; - r = sync_rights(original, shadow); - if (r < 0) - goto finish; + original = fopen(gshadow_path, "re"); + if (original) { + struct sgrp *sg; - errno = 0; - while ((sp = fgetspent(original))) { + r = sync_rights(original, gshadow); + if (r < 0) + goto fail; - i = hashmap_get(users, sp->sp_namp); - if (i && i->todo_user) { - /* we will update the existing entry */ - sp->sp_lstchg = lstchg; + errno = 0; + while ((sg = fgetsgent(original))) { - /* 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)); - } + i = hashmap_get(groups, sg->sg_namp); + if (i && i->todo_group) { + log_error("%s: Group \"%s\" already exists.", gshadow_path, sg->sg_namp); + r = -EEXIST; + goto fail; + } - errno = 0; - if (putspent(sp, shadow) < 0) { - r = errno ? -errno : -EIO; - goto finish; - } + r = putsgent_with_members(sg, gshadow); + if (r < 0) + goto fail; + if (r > 0) + group_changed = true; - errno = 0; - } - if (!IN_SET(errno, 0, ENOENT)) { - r = -errno; - goto finish; - } - } else if (errno != ENOENT) { - r = -errno; - goto finish; - } else if (fchmod(fileno(shadow), 0000) < 0) { + errno = 0; + } + if (!IN_SET(errno, 0, ENOENT)) { r = -errno; - goto finish; + goto fail; } - HASHMAP_FOREACH(i, todo_uids, iterator) { - struct spwd n = { - .sp_namp = i->name, - .sp_pwdp = (char*) "!!", - .sp_lstchg = lstchg, - .sp_min = -1, - .sp_max = -1, - .sp_warn = -1, - .sp_inact = -1, - .sp_expire = -1, - .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */ - }; + } else if (errno != ENOENT) { + r = -errno; + goto fail; + } else if (fchmod(fileno(gshadow), 0000) < 0) { + r = -errno; + goto fail; + } - errno = 0; - if (putspent(&n, shadow) != 0) { - r = errno ? -errno : -EIO; - goto finish; - } - } + HASHMAP_FOREACH(i, todo_gids, iterator) { + struct sgrp n = { + .sg_namp = i->name, + .sg_passwd = (char*) "!!", + }; - r = fflush_and_check(shadow); + r = putsgent_with_members(&n, gshadow); if (r < 0) - goto finish; + goto fail; + + group_changed = true; } - /* Make a backup of the old files */ + r = fflush_and_check(gshadow); + if (r < 0) + goto fail; + if (group_changed) { - if (group) { - r = make_backup("/etc/group", group_path); - if (r < 0) - goto finish; - } - if (gshadow) { - r = make_backup("/etc/gshadow", gshadow_path); - if (r < 0) - goto finish; - } + *tmpfile = gshadow; + *tmpfile_path = gshadow_tmp; + gshadow = NULL; + gshadow_tmp = NULL; + } + return 0; + +fail: + unlink(gshadow_tmp); + return r; +} + +static int write_files(void) { + + _cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL; + _cleanup_free_ char *passwd_tmp = NULL, *group_tmp = NULL, *shadow_tmp = NULL, *gshadow_tmp = NULL; + const char *passwd_path = NULL, *group_path = NULL, *shadow_path = NULL, *gshadow_path = NULL; + int r; + + passwd_path = prefix_roota(arg_root, "/etc/passwd"); + shadow_path = prefix_roota(arg_root, "/etc/shadow"); + group_path = prefix_roota(arg_root, "/etc/group"); + gshadow_path = prefix_roota(arg_root, "/etc/gshadow"); + + r = write_temporary_group(group_path, &group, &group_tmp); + if (r < 0) + goto finish; + + r = write_temporary_gshadow(gshadow_path, &gshadow, &gshadow_tmp); + if (r < 0) + goto finish; + + r = write_temporary_passwd(passwd_path, &passwd, &passwd_tmp); + if (r < 0) + goto finish; + + r = write_temporary_shadow(shadow_path, &shadow, &shadow_tmp); + if (r < 0) + goto finish; + + /* Make a backup of the old files */ + if (group) { + r = make_backup("/etc/group", group_path); + if (r < 0) + goto finish; + } + if (gshadow) { + r = make_backup("/etc/gshadow", gshadow_path); + if (r < 0) + goto finish; } if (passwd) { @@ -719,21 +794,19 @@ static int write_files(void) { } /* And make the new files count */ - if (group_changed) { - if (group) { - r = rename_and_apply_smack(group_tmp, group_path); - if (r < 0) - goto finish; + if (group) { + r = rename_and_apply_smack(group_tmp, group_path); + if (r < 0) + goto finish; - group_tmp = mfree(group_tmp); - } - if (gshadow) { - r = rename_and_apply_smack(gshadow_tmp, gshadow_path); - if (r < 0) - goto finish; + group_tmp = mfree(group_tmp); + } + if (gshadow) { + r = rename_and_apply_smack(gshadow_tmp, gshadow_path); + if (r < 0) + goto finish; - gshadow_tmp = mfree(gshadow_tmp); - } + gshadow_tmp = mfree(gshadow_tmp); } if (passwd) { |