Esempio n. 1
0
static int create_path(struct udev *udev, const char *path, bool selinux)
{
        char p[UTIL_PATH_SIZE];
        char *pos;
        struct stat stats;
        int err;

        util_strscpy(p, sizeof(p), path);
        pos = strrchr(p, '/');
        if (pos == NULL)
                return 0;
        while (pos != p && pos[-1] == '/')
                pos--;
        if (pos == p)
                return 0;
        pos[0] = '\0';

        dbg(udev, "stat '%s'\n", p);
        if (stat(p, &stats) == 0) {
                if ((stats.st_mode & S_IFMT) == S_IFDIR)
                        return 0;
                else
                        return -ENOTDIR;
        }

        err = util_create_path(udev, p);
        if (err != 0)
                return err;

        dbg(udev, "mkdir '%s'\n", p);
        if (selinux)
                udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755);
        err = mkdir(p, 0755);
        if (err != 0) {
                err = -errno;
                if (err == -EEXIST && stat(p, &stats) == 0) {
                        if ((stats.st_mode & S_IFMT) == S_IFDIR)
                                err = 0;
                        else
                                err = -ENOTDIR;
                }
        }
        if (selinux)
                udev_selinux_resetfscreatecon(udev);
        return err;
}
Esempio n. 2
0
void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode)
{
	char filename[UTIL_PATH_SIZE];

	if (!selinux_enabled)
		return;

	/* resolve relative filename */
	if (file[0] != '/') {
		char procfd[UTIL_PATH_SIZE];
		char target[UTIL_PATH_SIZE];
		ssize_t len;

		snprintf(procfd, sizeof(procfd), "/proc/%u/fd/%u", getpid(), dfd);
		len = readlink(procfd, target, sizeof(target));
		if (len <= 0 || len == sizeof(target))
			return;
		target[len] = '\0';

		util_strscpyl(filename, sizeof(filename), target, "/", file, NULL);
		file = filename;
	}
	udev_selinux_setfscreatecon(udev, file, mode);
}
Esempio n. 3
0
static int node_symlink(struct udev *udev, const char *node, const char *slink)
{
        struct stat stats;
        char target[UTIL_PATH_SIZE];
        char *s;
        size_t l;
        char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
        int i = 0;
        int tail = 0;
        int err = 0;

        /* use relative link */
        target[0] = '\0';
        while (node[i] && (node[i] == slink[i])) {
                if (node[i] == '/')
                        tail = i+1;
                i++;
        }
        s = target;
        l = sizeof(target);
        while (slink[i] != '\0') {
                if (slink[i] == '/')
                        l = util_strpcpy(&s, l, "../");
                i++;
        }
        l = util_strscpy(s, l, &node[tail]);
        if (l == 0) {
                err = -EINVAL;
                goto exit;
        }

        /* preserve link with correct target, do not replace node of other device */
        if (lstat(slink, &stats) == 0) {
                if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
                        struct stat stats2;

                        info(udev, "found existing node instead of symlink '%s'\n", slink);
                        if (lstat(node, &stats2) == 0) {
                                if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
                                    stats.st_rdev == stats2.st_rdev && stats.st_ino != stats2.st_ino) {
                                        info(udev, "replace device node '%s' with symlink to our node '%s'\n",
                                             slink, node);
                                } else {
                                        err(udev, "device node '%s' already exists, "
                                            "link to '%s' will not overwrite it\n",
                                            slink, node);
                                        goto exit;
                                }
                        }
                } else if (S_ISLNK(stats.st_mode)) {
                        char buf[UTIL_PATH_SIZE];
                        int len;

                        dbg(udev, "found existing symlink '%s'\n", slink);
                        len = readlink(slink, buf, sizeof(buf));
                        if (len > 0 && len < (int)sizeof(buf)) {
                                buf[len] = '\0';
                                if (strcmp(target, buf) == 0) {
                                        info(udev, "preserve already existing symlink '%s' to '%s'\n",
                                             slink, target);
                                        udev_selinux_lsetfilecon(udev, slink, S_IFLNK);
                                        utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
                                        goto exit;
                                }
                        }
                }
        } else {
                info(udev, "creating symlink '%s' to '%s'\n", slink, target);
                do {
                        err = util_create_path_selinux(udev, slink);
                        if (err != 0 && err != -ENOENT)
                                break;
                        udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
                        err = symlink(target, slink);
                        if (err != 0)
                                err = -errno;
                        udev_selinux_resetfscreatecon(udev);
                } while (err == -ENOENT);
                if (err == 0)
                        goto exit;
        }

        info(udev, "atomically replace '%s'\n", slink);
        util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
        unlink(slink_tmp);
        do {
                err = util_create_path_selinux(udev, slink_tmp);
                if (err != 0 && err != -ENOENT)
                        break;
                udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK);
                err = symlink(target, slink_tmp);
                if (err != 0)
                        err = -errno;
                udev_selinux_resetfscreatecon(udev);
        } while (err == -ENOENT);
        if (err != 0) {
                err(udev, "symlink '%s' '%s' failed: %m\n", target, slink_tmp);
                goto exit;
        }
        err = rename(slink_tmp, slink);
        if (err != 0) {
                err(udev, "rename '%s' '%s' failed: %m\n", slink_tmp, slink);
                unlink(slink_tmp);
        }
exit:
        return err;
}
Esempio n. 4
0
int udev_node_mknod(struct udev_device *dev, const char *file, dev_t devnum, mode_t mode, uid_t uid, gid_t gid)
{
	struct udev *udev = udev_device_get_udev(dev);
	char file_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
	struct stat stats;
	int preserve = 0;
	int err = 0;

	if (major(devnum) == 0)
		devnum = udev_device_get_devnum(dev);

	if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
		mode |= S_IFBLK;
	else
		mode |= S_IFCHR;

	if (file == NULL)
		file = udev_device_get_devnode(dev);

	if (lstat(file, &stats) == 0) {
		if (((stats.st_mode & S_IFMT) == (mode & S_IFMT)) && (stats.st_rdev == devnum)) {
			info(udev, "preserve file '%s', because it has correct dev_t\n", file);
			preserve = 1;
			udev_selinux_lsetfilecon(udev, file, mode);
		} else {
			info(udev, "atomically replace existing file '%s'\n", file);
			util_strlcpy(file_tmp, file, sizeof(file_tmp));
			util_strlcat(file_tmp, TMP_FILE_EXT, sizeof(file_tmp));
			unlink(file_tmp);
			udev_selinux_setfscreatecon(udev, file_tmp, mode);
			err = mknod(file_tmp, mode, devnum);
			udev_selinux_resetfscreatecon(udev);
			if (err != 0) {
				err(udev, "mknod(%s, %#o, %u, %u) failed: %m\n",
				    file_tmp, mode, major(devnum), minor(devnum));
				goto exit;
			}
			err = rename(file_tmp, file);
			if (err != 0) {
				err(udev, "rename(%s, %s) failed: %m\n", file_tmp, file);
				unlink(file_tmp);
			}
		}
	} else {
		info(udev, "mknod(%s, %#o, (%u,%u))\n", file, mode, major(devnum), minor(devnum));
		udev_selinux_setfscreatecon(udev, file, mode);
		err = mknod(file, mode, devnum);
		udev_selinux_resetfscreatecon(udev);
		if (err != 0) {
			err(udev, "mknod(%s, %#o, (%u,%u) failed: %m\n", file, mode, major(devnum), minor(devnum));
			goto exit;
		}
	}

	if (!preserve || stats.st_mode != mode) {
		info(udev, "chmod(%s, %#o)\n", file, mode);
		err = chmod(file, mode);
		if (err != 0) {
			err(udev, "chmod(%s, %#o) failed: %m\n", file, mode);
			goto exit;
		}
	}

	if (!preserve || stats.st_uid != uid || stats.st_gid != gid) {
		info(udev, "chown(%s, %u, %u)\n", file, uid, gid);
		err = chown(file, uid, gid);
		if (err != 0) {
			err(udev, "chown(%s, %u, %u) failed: %m\n", file, uid, gid);
			goto exit;
		}
	}
exit:
	return err;
}
Esempio n. 5
0
static int node_symlink(struct udev *udev, const char *node, const char *slink)
{
	struct stat stats;
	char target[UTIL_PATH_SIZE];
	char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
	int i = 0;
	int tail = 0;
	int len;
	int err = 0;

	/* use relative link */
	target[0] = '\0';
	while (node[i] && (node[i] == slink[i])) {
		if (node[i] == '/')
			tail = i+1;
		i++;
	}
	while (slink[i] != '\0') {
		if (slink[i] == '/')
			util_strlcat(target, "../", sizeof(target));
		i++;
	}
	util_strlcat(target, &node[tail], sizeof(target));

	/* preserve link with correct target, do not replace node of other device */
	if (lstat(slink, &stats) == 0) {
		if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
			struct stat stats2;

			info(udev, "found existing node instead of symlink '%s'\n", slink);
			if (lstat(node, &stats2) == 0) {
				if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
				    stats.st_rdev == stats2.st_rdev) {
					info(udev, "replace device node '%s' with symlink to our node '%s'\n",
					     slink, node);
				} else {
					err(udev, "device node '%s' already exists, "
					    "link to '%s' will not overwrite it\n",
					    slink, node);
					goto exit;
				}
			}
		} else if (S_ISLNK(stats.st_mode)) {
			char buf[UTIL_PATH_SIZE];

			dbg(udev, "found existing symlink '%s'\n", slink);
			len = readlink(slink, buf, sizeof(buf));
			if (len > 0) {
				buf[len] = '\0';
				if (strcmp(target, buf) == 0) {
					info(udev, "preserve already existing symlink '%s' to '%s'\n",
					     slink, target);
					udev_selinux_lsetfilecon(udev, slink, S_IFLNK);
					goto exit;
				}
			}
		}
	} else {
		info(udev, "creating symlink '%s' to '%s'\n", slink, target);
		udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
		err = symlink(target, slink);
		udev_selinux_resetfscreatecon(udev);
		if (err == 0)
			goto exit;
	}

	info(udev, "atomically replace '%s'\n", slink);
	util_strlcpy(slink_tmp, slink, sizeof(slink_tmp));
	util_strlcat(slink_tmp, TMP_FILE_EXT, sizeof(slink_tmp));
	unlink(slink_tmp);
	udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
	err = symlink(target, slink_tmp);
	udev_selinux_resetfscreatecon(udev);
	if (err != 0) {
		err(udev, "symlink(%s, %s) failed: %m\n", target, slink_tmp);
		goto exit;
	}
	err = rename(slink_tmp, slink);
	if (err != 0) {
		err(udev, "rename(%s, %s) failed: %m\n", slink_tmp, slink);
		unlink(slink_tmp);
		goto exit;
	}
exit:
	return err;
}
Esempio n. 6
0
int udev_node_mknod(struct udev_device *dev, const char *file, mode_t mode, uid_t uid, gid_t gid)
{
	struct udev *udev = udev_device_get_udev(dev);
	dev_t devnum = udev_device_get_devnum(dev);
	struct stat stats;
	int err = 0;


	if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
		mode |= S_IFBLK;
	else
		mode |= S_IFCHR;

	if (file == NULL)
		file = udev_device_get_devnode(dev);

	if (lstat(file, &stats) == 0) {
		if (((stats.st_mode & S_IFMT) == (mode & S_IFMT)) && (stats.st_rdev == devnum)) {
			info(udev, "preserve file '%s', because it has correct dev_t\n", file);
			if (stats.st_mode != mode || stats.st_uid != uid || stats.st_gid != gid) {
				info(udev, "set permissions %s, %#o, uid=%u, gid=%u\n", file, mode, uid, gid);
				chmod(file, mode);
				chown(file, uid, gid);
			} else {
				info(udev, "preserve permissions %s, %#o, uid=%u, gid=%u\n", file, mode, uid, gid);
			}
			/*
			 * Set initial selinux file context only on add events.
			 * We set the proper context on bootup (triger) or for newly
			 * added devices, but we don't change it later, in case
			 * something else has set a custom context in the meantime.
			 */
			if (strcmp(udev_device_get_action(dev), "add") == 0)
				udev_selinux_lsetfilecon(udev, file, mode);
			/* always update timestamp when we re-use the node, like on media change events */
			utimensat(AT_FDCWD, file, NULL, 0);
		} else {
			char file_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];

			info(udev, "atomically replace existing file '%s'\n", file);
			util_strscpyl(file_tmp, sizeof(file_tmp), file, TMP_FILE_EXT, NULL);
			unlink(file_tmp);
			udev_selinux_setfscreatecon(udev, file_tmp, mode);
			err = mknod(file_tmp, mode, devnum);
			udev_selinux_resetfscreatecon(udev);
			if (err != 0) {
				err(udev, "mknod '%s' %u:%u %#o failed: %m\n",
				    file_tmp, major(devnum), minor(devnum), mode);
				goto exit;
			}
			err = rename(file_tmp, file);
			if (err != 0) {
				err(udev, "rename '%s' '%s' failed: %m\n", file_tmp, file);
				unlink(file_tmp);
				goto exit;
			}
			info(udev, "set permissions '%s' %#o uid=%u gid=%u\n", file, mode, uid, gid);
			chmod(file, mode);
			chown(file, uid, gid);
		}
	} else {
		info(udev, "mknod '%s' %u:%u %#o\n", file, major(devnum), minor(devnum), mode);
		do {
			err = util_create_path(udev, file);
			if (err != 0 && err != -ENOENT)
				break;
			udev_selinux_setfscreatecon(udev, file, mode);
			err = mknod(file, mode, devnum);
			if (err != 0)
				err = -errno;
			udev_selinux_resetfscreatecon(udev);
		} while (err == -ENOENT);
		if (err != 0)
			err(udev, "mknod '%s' %u:%u %#o' failed: %m\n", file, major(devnum), minor(devnum), mode);
		info(udev, "set permissions '%s' %#o uid=%u gid=%u\n", file, mode, uid, gid);
		chmod(file, mode);
		chown(file, uid, gid);
	}
exit:
	return err;
}