/* * Copyright (C) 2004 Daniel Walsh * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "udev.h" #include "udev_selinux.h" static security_context_t prev_scontext = NULL; static int is_selinux_running(struct udev *udev) { static int selinux_enabled = -1; if (selinux_enabled == -1) selinux_enabled = (is_selinux_enabled() > 0); dbg(udev, "selinux=%i\n", selinux_enabled); return selinux_enabled; } static char *get_media(struct udev *udev, const char *devname, int mode) { FILE *fp; char procfile[PATH_MAX]; char mediabuf[256]; int size; char *media = NULL; if (!(mode & S_IFBLK)) return NULL; snprintf(procfile, PATH_MAX, "/proc/ide/%s/media", devname); procfile[PATH_MAX-1] = '\0'; fp = fopen(procfile, "r"); if (!fp) goto out; if (fgets(mediabuf, sizeof(mediabuf), fp) == NULL) goto close_out; size = strlen(mediabuf); while (size-- > 0) { if (isspace(mediabuf[size])) { mediabuf[size] = '\0'; } else { break; } } media = strdup(mediabuf); info(udev, "selinux_get_media(%s)='%s'\n", devname, media); close_out: fclose(fp); out: return media; } void selinux_setfilecon(struct udev *udev, const char *file, const char *devname, unsigned int mode) { if (is_selinux_running(udev)) { security_context_t scontext = NULL; char *media; int ret = -1; if (devname) { media = get_media(udev, devname, mode); if (media) { ret = matchmediacon(media, &scontext); free(media); } } if (ret < 0) if (matchpathcon(file, mode, &scontext) < 0) { err(udev, "matchpathcon(%s) failed\n", file); return; } if (lsetfilecon(file, scontext) < 0) err(udev, "setfilecon %s failed: %s\n", file, strerror(errno)); freecon(scontext); } } void selinux_setfscreatecon(struct udev *udev, const char *file, const char *devname, unsigned int mode) { if (is_selinux_running(udev)) { security_context_t scontext = NULL; char *media; int ret = -1; if (devname) { media = get_media(udev, devname, mode); if (media) { ret = matchmediacon(media, &scontext); free(media); } } if (ret < 0) if (matchpathcon(file, mode, &scontext) < 0) { err(udev, "matchpathcon(%s) failed\n", file); return; } if (setfscreatecon(scontext) < 0) err(udev, "setfscreatecon %s failed: %s\n", file, strerror(errno)); freecon(scontext); } } void selinux_resetfscreatecon(struct udev *udev) { if (is_selinux_running(udev)) { if (setfscreatecon(prev_scontext) < 0) err(udev, "setfscreatecon failed: %s\n", strerror(errno)); } } void selinux_init(struct udev *udev) { /* * record the present security context, for file-creation * restoration creation purposes. */ if (is_selinux_running(udev)) { if (!udev_get_dev_path(udev)[0]) err(udev, "selinux_init: udev_root not set\n"); matchpathcon_init_prefix(NULL, udev_get_dev_path(udev)); if (getfscreatecon(&prev_scontext) < 0) { err(udev, "getfscreatecon failed\n"); prev_scontext = NULL; } } } void selinux_exit(struct udev *udev) { if (is_selinux_running(udev) && prev_scontext) { freecon(prev_scontext); prev_scontext = NULL; } }