Esempio n. 1
0
static int node_fixup(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid)
{
        struct udev *udev = udev_device_get_udev(dev);
        const char *devnode = udev_device_get_devnode(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 (lstat(devnode, &stats) != 0) {
                err = -errno;
                info(udev, "can not stat() node '%s' (%m)\n", devnode);
                goto out;
        }

        if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) {
                err = -EEXIST;
                info(udev, "found node '%s' with non-matching devnum %s, skip handling\n",
                     udev_device_get_devnode(dev), udev_device_get_id_filename(dev));
                goto out;
        }

        if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) {
                info(udev, "set permissions %s, %#o, uid=%u, gid=%u\n", devnode, mode, uid, gid);
                chmod(devnode, mode);
                chown(devnode, uid, gid);
        } else {
                info(udev, "preserve permissions %s, %#o, uid=%u, gid=%u\n", devnode, 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, devnode, mode);

        /* always update timestamp when we re-use the node, like on media change events */
        utimensat(AT_FDCWD, devnode, NULL, 0);
out:
        return err;
}
Esempio n. 2
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. 3
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. 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
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;
}