#include <grp.h>
#include <shadow.h>
#include <getopt.h>
+#include <utmp.h>
#include "util.h"
#include "hashmap.h"
#include "conf-files.h"
#include "copy.h"
#include "utf8.h"
+#include "label.h"
+#include "fileio-label.h"
typedef enum ItemType {
ADD_USER = 'u',
static char *arg_root = NULL;
static const char conf_file_dirs[] =
+ "/etc/sysusers.d\0"
+ "/run/sysusers.d\0"
"/usr/local/lib/sysusers.d\0"
"/usr/lib/sysusers.d\0"
#ifdef HAVE_SPLIT_USR
return 0;
}
-static int make_backup(const char *x) {
- _cleanup_close_ int src = -1, dst = -1;
+static int make_backup(const char *target, const char *x) {
+ _cleanup_close_ int src = -1;
+ _cleanup_fclose_ FILE *dst = NULL;
char *backup, *temp;
struct timespec ts[2];
struct stat st;
if (fstat(src, &st) < 0)
return -errno;
- temp = strappenda(x, ".XXXXXX");
- dst = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC|O_NOCTTY);
- if (dst < 0)
- return dst;
+ r = fopen_temporary_label(target, x, &dst, &temp);
+ if (r < 0)
+ return r;
- r = copy_bytes(src, dst, (off_t) -1);
+ r = copy_bytes(src, fileno(dst), (off_t) -1);
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, "-");
+
/* Copy over the access mask */
- if (fchmod(dst, st.st_mode & 07777) < 0) {
- r = -errno;
- goto fail;
- }
+ if (fchmod(fileno(dst), st.st_mode & 07777) < 0)
+ log_warning("Failed to change mode on %s: %m", backup);
- /* Don't fail on chmod(). If it stays owned by us, then it
- * isn't too bad... */
- fchown(dst, st.st_uid, st.st_gid);
+ if (fchown(fileno(dst), st.st_uid, st.st_gid)< 0)
+ log_warning("Failed to change ownership of %s: %m", backup);
ts[0] = st.st_atim;
ts[1] = st.st_mtim;
- futimens(dst, ts);
+ futimens(fileno(dst), ts);
- backup = strappenda(x, "-");
if (rename(temp, backup) < 0)
goto fail;
_cleanup_fclose_ FILE *original = NULL;
group_path = fix_root("/etc/group");
- r = fopen_temporary(group_path, &group, &group_tmp);
+ r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
if (r < 0)
goto finish;
_cleanup_fclose_ FILE *original = NULL;
passwd_path = fix_root("/etc/passwd");
- r = fopen_temporary(passwd_path, &passwd, &passwd_tmp);
+ r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
if (r < 0)
goto finish;
/* Make a backup of the old files */
if (group && group_changed) {
- r = make_backup(group_path);
+ r = make_backup("/etc/group", group_path);
if (r < 0)
goto finish;
}
if (passwd) {
- r = make_backup(passwd_path);
+ r = make_backup("/etc/passwd", passwd_path);
if (r < 0)
goto finish;
}
const char *i;
long sz;
- if (isempty(u) < 0)
+ if (isempty(u))
return false;
if (!(u[0] >= 'a' && u[0] <= 'z') &&
if ((size_t) (i-u) > (size_t) sz)
return false;
+ if ((size_t) (i-u) > UT_NAMESIZE - 1)
+ return false;
+
return true;
}
if (!utf8_is_valid(d))
return false;
- if (strpbrk(d, ":\n"))
+ if (string_has_cc(d, NULL))
+ return false;
+
+ /* Colons are used as field separators, and hence not OK */
+ if (strchr(d, ':'))
return false;
return true;
h = groups;
break;
+ default:
+ return -EBADMSG;
}
i->type = action[0];
return r;
}
-static int take_lock(void) {
-
- struct flock flock = {
- .l_type = F_WRLCK,
- .l_whence = SEEK_SET,
- .l_start = 0,
- .l_len = 0,
- };
-
- const char *path;
- int fd, r;
-
- /* This is roughly the same as lckpwdf(), but not as awful. We
- * don't want to use alarm() and signals, hence we implement
- * our own trivial version of this.
- *
- * Note that shadow-utils also takes per-database locks in
- * addition to lckpwdf(). However, we don't given that they
- * are redundant as they they invoke lckpwdf() first and keep
- * it during everything they do. The per-database locks are
- * awfully racy, and thus we just won't do them. */
-
- path = fix_root("/etc/.pwd.lock");
- fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
- if (fd < 0)
- return -errno;
-
- r = fcntl(fd, F_SETLKW, &flock);
- if (r < 0) {
- safe_close(fd);
- return -errno;
- }
-
- return fd;
-}
-
static void free_database(Hashmap *by_name, Hashmap *by_id) {
char *name;
hashmap_free(by_id);
}
-static int help(void) {
-
+static void help(void) {
printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
"Creates system user accounts.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
- " --root=PATH Operate on an alternate filesystem root\n",
- program_invocation_short_name);
-
- return 0;
+ " --root=PATH Operate on an alternate filesystem root\n"
+ , program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
switch (c) {
case 'h':
- return help();
+ help();
+ return 0;
case ARG_VERSION:
puts(PACKAGE_STRING);
default:
assert_not_reached("Unhandled option");
}
- }
return 1;
}
umask(0022);
- r = 0;
+ r = label_init(NULL);
+ if (r < 0) {
+ log_error("SELinux setup failed: %s", strerror(-r));
+ goto finish;
+ }
if (optind < argc) {
int j;
if (r < 0)
goto finish;
- lock = take_lock();
+ lock = take_password_lock(arg_root);
if (lock < 0) {
log_error("Failed to take lock: %s", strerror(-lock));
goto finish;