X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsysusers%2Fsysusers.c;h=b7c16092429163b73d00be9aea6b6ded1f801be9;hp=1209a5a8b411aeed49b6a2e70156b3d3ad1617a8;hb=9f1c19405a1ccaf59dcc8c32c13a1619541189ad;hpb=a12b0cc34d80a2d13c87d1f57059339cfc780912 diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 1209a5a8b..b7c160924 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "util.h" #include "hashmap.h" @@ -34,6 +35,8 @@ #include "conf-files.h" #include "copy.h" #include "utf8.h" +#include "label.h" +#include "fileio-label.h" typedef enum ItemType { ADD_USER = 'u', @@ -61,6 +64,8 @@ typedef struct Item { 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 @@ -190,8 +195,9 @@ static int load_group_database(void) { 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; @@ -208,30 +214,30 @@ static int make_backup(const char *x) { 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; @@ -309,7 +315,7 @@ static int write_files(void) { _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; @@ -385,7 +391,7 @@ static int write_files(void) { _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; @@ -464,13 +470,13 @@ static int write_files(void) { /* 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; } @@ -1095,6 +1101,9 @@ static bool valid_user_group_name(const char *u) { if ((size_t) (i-u) > (size_t) sz) return false; + if ((size_t) (i-u) > UT_NAMESIZE - 1) + return false; + return true; } @@ -1103,7 +1112,11 @@ static bool valid_gecos(const char *d) { 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; @@ -1312,6 +1325,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { h = groups; break; + default: + return -EBADMSG; } i->type = action[0]; @@ -1377,42 +1392,6 @@ static int read_config_file(const char *fn, bool ignore_enoent) { 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; @@ -1515,7 +1494,11 @@ int main(int argc, char *argv[]) { 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; @@ -1546,7 +1529,7 @@ int main(int argc, char *argv[]) { 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;