+#ifdef HAVE_SELINUX
+ struct stat st;
+ security_context_t fcon;
+
+ if (!label_hnd)
+ return 0;
+
+ r = lstat(path, &st);
+ if (r == 0) {
+ r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
+
+ /* If there's no label to set, then exit without warning */
+ if (r < 0 && errno == ENOENT)
+ return 0;
+
+ if (r == 0) {
+ r = lsetfilecon(path, fcon);
+ freecon(fcon);
+
+ /* If the FS doesn't support labels, then exit without warning */
+ if (r < 0 && errno == ENOTSUP)
+ return 0;
+ }
+ }
+
+ if (r < 0) {
+ /* Ignore ENOENT in some cases */
+ if (ignore_enoent && errno == ENOENT)
+ return 0;
+
+ if (ignore_erofs && errno == EROFS)
+ return 0;
+
+ log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
+ "Unable to fix label of %s: %m", path);
+ r = security_getenforce() == 1 ? -errno : 0;
+ }
+#endif
+
+ return r;
+}
+
+void mac_selinux_finish(void) {
+
+#ifdef HAVE_SELINUX
+ if (!mac_selinux_use())
+ return;
+
+ if (label_hnd)
+ selabel_close(label_hnd);
+#endif
+}
+
+int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
+
+ int r = 0;
+
+#ifdef HAVE_SELINUX
+ _cleanup_security_context_free_ security_context_t mycon = NULL, fcon = NULL;
+ security_class_t sclass;
+
+ if (!mac_selinux_use()) {
+ *label = NULL;
+ return 0;
+ }
+
+ r = getcon(&mycon);
+ if (r < 0)
+ goto fail;
+
+ r = getfilecon(exe, &fcon);
+ if (r < 0)
+ goto fail;
+
+ sclass = string_to_security_class("process");
+ r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
+ if (r == 0)
+ log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
+
+fail:
+ if (r < 0 && security_getenforce() == 1)
+ r = -errno;
+#endif
+
+ return r;
+}
+
+int mac_selinux_get_our_label(char **label) {
+ int r = -EOPNOTSUPP;
+
+#ifdef HAVE_SELINUX
+ char *l = NULL;
+
+ r = getcon(&l);
+ if (r < 0)
+ return r;
+
+ *label = l;
+#endif
+
+ return r;
+}
+
+int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, char **label) {
+ int r = -EOPNOTSUPP;
+
+#ifdef HAVE_SELINUX
+
+ _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL, ret = NULL;
+ _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
+ security_class_t sclass;
+
+ const char *range = NULL;
+
+ assert(socket_fd >= 0);
+ assert(exe);
+ assert(label);
+
+ r = getcon(&mycon);
+ if (r < 0) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ r = getpeercon(socket_fd, &peercon);
+ if (r < 0) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ r = getexeccon(&fcon);
+ if (r < 0) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ if (!fcon) {
+ /* If there is no context set for next exec let's use context
+ of target executable */
+ r = getfilecon(exe, &fcon);
+ if (r < 0) {
+ r = -errno;
+ goto out;
+ }
+ }
+
+ bcon = context_new(mycon);
+ if (!bcon) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ pcon = context_new(peercon);
+ if (!pcon) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ range = context_range_get(pcon);
+ if (!range) {
+ r = -errno;
+ goto out;
+ }
+
+ r = context_range_set(bcon, range);
+ if (r) {
+ r = -errno;
+ goto out;
+ }
+
+ freecon(mycon);
+ mycon = strdup(context_str(bcon));
+ if (!mycon) {
+ r = -errno;
+ goto out;
+ }
+
+ sclass = string_to_security_class("process");
+ r = security_compute_create(mycon, fcon, sclass, &ret);
+ if (r < 0) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ *label = ret;
+ ret = NULL;
+ r = 0;
+
+out:
+ if (r < 0 && security_getenforce() == 1)
+ return r;
+#endif
+ return r;
+}
+
+int mac_selinux_context_set(const char *path, mode_t mode) {
+ int r = 0;
+
+#ifdef HAVE_SELINUX
+ _cleanup_security_context_free_ security_context_t filecon = NULL;
+
+ if (!mac_selinux_use() || !label_hnd)
+ return 0;
+
+ r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
+ if (r < 0 && errno != ENOENT)
+ r = -errno;
+ else if (r == 0) {
+ r = setfscreatecon(filecon);
+ if (r < 0) {
+ log_error("Failed to set SELinux file context on %s: %m", path);
+ r = -errno;
+ }
+ }
+
+ if (r < 0 && security_getenforce() == 0)
+ r = 0;
+#endif
+
+ return r;
+}
+
+int mac_selinux_socket_set(const char *label) {
+
+#ifdef HAVE_SELINUX
+ if (!mac_selinux_use())
+ return 0;
+
+ if (setsockcreatecon((security_context_t) label) < 0) {
+ log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
+ "Failed to set SELinux context (%s) on socket: %m", label);
+
+ if (security_getenforce() == 1)
+ return -errno;
+ }
+#endif
+
+ return 0;
+}
+
+void mac_selinux_context_clear(void) {
+
+#ifdef HAVE_SELINUX
+ PROTECT_ERRNO;
+
+ if (!mac_selinux_use())
+ return;
+
+ setfscreatecon(NULL);
+#endif
+}
+
+void mac_selinux_socket_clear(void) {
+
+#ifdef HAVE_SELINUX
+ PROTECT_ERRNO;
+
+ if (!mac_selinux_use())
+ return;
+
+ setsockcreatecon(NULL);
+#endif
+}
+
+void mac_selinux_free(const char *label) {
+
+#ifdef HAVE_SELINUX
+ if (!mac_selinux_use())
+ return;
+
+ freecon((security_context_t) label);
+#endif
+}
+
+int mac_selinux_mkdir(const char *path, mode_t mode) {
+ int r = 0;
+
+#ifdef HAVE_SELINUX
+ /* Creates a directory and labels it according to the SELinux policy */
+ _cleanup_security_context_free_ security_context_t fcon = NULL;
+
+ if (!label_hnd)
+ return 0;
+
+ if (path_is_absolute(path))
+ r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR);
+ else {
+ _cleanup_free_ char *newpath;
+
+ newpath = path_make_absolute_cwd(path);
+ if (!newpath)
+ return -ENOMEM;
+
+ r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR);
+ }
+
+ if (r == 0)
+ r = setfscreatecon(fcon);
+
+ if (r < 0 && errno != ENOENT) {
+ log_error("Failed to set security context %s for %s: %m", fcon, path);
+
+ if (security_getenforce() == 1) {
+ r = -errno;
+ goto finish;
+ }
+ }
+
+ r = mkdir(path, mode);
+ if (r < 0)
+ r = -errno;
+
+finish:
+ setfscreatecon(NULL);
+#endif
+
+ return r;