ItemType type;
char *name;
+ char *group_name;
char *uid_path;
char *gid_path;
char *description;
STATIC_DESTRUCTOR_REGISTER(uid_range, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
+static int errno_is_not_exists(int code) {
+ /* See getpwnam(3) and getgrnam(3): those codes and others can be returned if the user or group are
+ * not found. */
+ return IN_SET(code, 0, ENOENT, ESRCH, EBADF, EPERM);
+}
+
static int load_user_database(void) {
_cleanup_fclose_ FILE *f = NULL;
const char *passwd_path;
static int make_backup(const char *target, const char *x) {
_cleanup_close_ int src = -1;
_cleanup_fclose_ FILE *dst = NULL;
- _cleanup_free_ char *temp = NULL;
+ _cleanup_free_ char *dst_tmp = NULL;
char *backup;
struct timespec ts[2];
struct stat st;
if (fstat(src, &st) < 0)
return -errno;
- r = fopen_temporary_label(target, x, &dst, &temp);
+ r = fopen_temporary_label(target, x, &dst, &dst_tmp);
if (r < 0)
return r;
backup = strjoina(x, "-");
/* Copy over the access mask */
- r = fchmod_and_chown(fileno(dst), st.st_mode & 07777, st.st_uid, st.st_gid);
+ r = chmod_and_chown_unsafe(dst_tmp, st.st_mode & 07777, st.st_uid, st.st_gid);
if (r < 0)
log_warning_errno(r, "Failed to change access mode or ownership of %s: %m", backup);
if (r < 0)
goto fail;
- if (rename(temp, backup) < 0) {
+ if (rename(dst_tmp, backup) < 0) {
r = -errno;
goto fail;
}
return 0;
fail:
- (void) unlink(temp);
+ (void) unlink(dst_tmp);
return r;
}
}
#endif
-static int sync_rights(FILE *from, FILE *to) {
- struct stat st;
-
- if (fstat(fileno(from), &st) < 0)
- return -errno;
-
- return fchmod_and_chown(fileno(to), st.st_mode & 07777, st.st_uid, st.st_gid);
-}
-
-static int rename_and_apply_smack(const char *temp_path, const char *dest_path) {
- int r = 0;
- if (rename(temp_path, dest_path) < 0)
- return -errno;
-
-#ifdef SMACK_RUN_LABEL
- r = mac_smack_apply(dest_path, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
- if (r < 0)
- return r;
-#endif
- return r;
-}
-
static const char* default_shell(uid_t uid) {
return uid == 0 ? "/bin/sh" : NOLOGIN;
}
original = fopen(passwd_path, "re");
if (original) {
- r = sync_rights(original, passwd);
+ r = sync_rights(original, passwd_tmp);
if (r < 0)
return r;
original = fopen(shadow_path, "re");
if (original) {
- r = sync_rights(original, shadow);
+ r = sync_rights(original, shadow_tmp);
if (r < 0)
return r;
ORDERED_HASHMAP_FOREACH(i, todo_uids, iterator) {
struct spwd n = {
.sp_namp = i->name,
- .sp_pwdp = (char*) "!!", /* lock this password, and make it invalid */
+ .sp_pwdp = (char*) "!*", /* lock this password, and make it invalid */
.sp_lstchg = lstchg,
.sp_min = -1,
.sp_max = -1,
original = fopen(group_path, "re");
if (original) {
- r = sync_rights(original, group);
+ r = sync_rights(original, group_tmp);
if (r < 0)
return r;
if (original) {
struct sgrp *sg;
- r = sync_rights(original, gshadow);
+ r = sync_rights(original, gshadow_tmp);
if (r < 0)
return r;
return 0;
}
- if (!IN_SET(errno, 0, ENOENT))
+ if (!errno_is_not_exists(errno))
return log_error_errno(errno, "Failed to check if user %s already exists: %m", i->name);
}
return 1;
}
-static int add_group(Item *i) {
+static int get_gid_by_name(const char *name, gid_t *gid) {
void *z;
- int r;
- assert(i);
+ assert(gid);
/* Check the database directly */
- z = hashmap_get(database_by_groupname, i->name);
+ z = hashmap_get(database_by_groupname, name);
if (z) {
- log_debug("Group %s already exists.", i->name);
- i->gid = PTR_TO_GID(z);
- i->gid_set = true;
+ *gid = PTR_TO_GID(z);
return 0;
}
struct group *g;
errno = 0;
- g = getgrnam(i->name);
+ g = getgrnam(name);
if (g) {
- log_debug("Group %s already exists.", i->name);
- i->gid = g->gr_gid;
- i->gid_set = true;
+ *gid = g->gr_gid;
return 0;
}
- if (!IN_SET(errno, 0, ENOENT))
- return log_error_errno(errno, "Failed to check if group %s already exists: %m", i->name);
+ if (!errno_is_not_exists(errno))
+ return log_error_errno(errno, "Failed to check if group %s already exists: %m", name);
+ }
+
+ return -ENOENT;
+}
+
+static int add_group(Item *i) {
+ int r;
+
+ assert(i);
+
+ r = get_gid_by_name(i->name, &i->gid);
+ if (r != -ENOENT) {
+ if (r < 0)
+ return r;
+ log_debug("Group %s already exists.", i->name);
+ i->gid_set = true;
+ return 0;
}
/* Try to use the suggested numeric gid */
case ADD_USER: {
Item *j;
- j = ordered_hashmap_get(groups, i->name);
+ j = ordered_hashmap_get(groups, i->group_name ?: i->name);
if (j && j->todo_group) {
- /* When the group with the same name is already in queue,
+ /* When a group with the target 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 if (i->group_name) {
+ /* When a group name was given instead of a GID and it's
+ * not in queue, then it must already exist. */
+ r = get_gid_by_name(i->group_name, &i->gid);
+ if (r < 0)
+ return log_error_errno(r, "Group %s not found.", i->group_name);
+ i->gid_set = true;
+ i->id_set_strict = true;
} else {
r = add_group(i);
if (r < 0)
return NULL;
free(i->name);
+ free(i->group_name);
free(i->uid_path);
free(i->gid_path);
free(i->description);
static int parse_line(const char *fname, unsigned line, const char *buffer) {
static const Specifier specifier_table[] = {
- { 'm', specifier_machine_id, NULL },
- { 'b', specifier_boot_id, NULL },
- { 'H', specifier_host_name, NULL },
- { 'v', specifier_kernel_release, NULL },
- { 'T', specifier_tmp_dir, NULL },
- { 'V', specifier_var_tmp_dir, NULL },
+ { 'm', specifier_machine_id, NULL },
+ { 'b', specifier_boot_id, NULL },
+ { 'H', specifier_host_name, NULL },
+ { 'l', specifier_short_host_name, NULL },
+ { 'v', specifier_kernel_release, NULL },
+ { 'a', specifier_architecture, NULL },
+ { 'o', specifier_os_id, NULL },
+ { 'w', specifier_os_version_id, NULL },
+ { 'B', specifier_os_build_id, NULL },
+ { 'W', specifier_os_variant_id, NULL },
+ { 'T', specifier_tmp_dir, NULL },
+ { 'V', specifier_var_tmp_dir, NULL },
{}
};
if (name) {
r = specifier_printf(name, specifier_table, NULL, &resolved_name);
if (r < 0)
- log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, name);
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, name);
- if (!valid_user_group_name(resolved_name))
+ if (!valid_user_group_name(resolved_name, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"[%s:%u] '%s' is not a valid user or group name.",
fname, line, resolved_name);
if (id) {
r = specifier_printf(id, specifier_table, NULL, &resolved_id);
if (r < 0)
- return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, name);
}
if (description) {
r = specifier_printf(description, specifier_table, NULL, &resolved_description);
if (r < 0)
- return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, description);
if (!valid_gecos(resolved_description))
if (home) {
r = specifier_printf(home, specifier_table, NULL, &resolved_home);
if (r < 0)
- return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, home);
if (!valid_home(resolved_home))
if (shell) {
r = specifier_printf(shell, specifier_table, NULL, &resolved_shell);
if (r < 0)
- return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, shell);
if (!valid_shell(resolved_shell))
"[%s:%u] Lines of type 'm' require a group name in the third field.",
fname, line);
- if (!valid_user_group_name(resolved_id))
+ if (!valid_user_group_name(resolved_id, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"[%s:%u] '%s' is not a valid user or group name.",
fname, line, resolved_id);
_cleanup_free_ char *uid = NULL, *gid = NULL;
if (split_pair(resolved_id, ":", &uid, &gid) == 0) {
r = parse_gid(gid, &i->gid);
- if (r < 0)
- return log_error_errno(r, "Failed to parse GID: '%s': %m", id);
- i->gid_set = true;
- i->id_set_strict = true;
+ if (r < 0) {
+ if (valid_user_group_name(gid, 0))
+ i->group_name = TAKE_PTR(gid);
+ else
+ return log_error_errno(r, "Failed to parse GID: '%s': %m", id);
+ } else {
+ i->gid_set = true;
+ i->id_set_strict = true;
+ }
free_and_replace(resolved_id, uid);
}
if (!streq(resolved_id, "-")) {
break;
case ARG_ROOT:
- r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_root);
if (r < 0)
return r;
break;