/* Creates a the parent directory of the specified path securely */ int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) { int ret = -1; char *dir; if (!(dir = pa_parent_dir(fn))) goto finish; if (pa_make_secure_dir(dir, m, uid, gid) < 0) goto finish; ret = 0; finish: pa_xfree(dir); return ret; }
static int change_user(void) { struct passwd *pw; struct group * gr; int r; /* This function is called only in system-wide mode. It creates a * runtime dir in /var/run/ with proper UID/GID and drops privs * afterwards. */ if (!(pw = getpwnam(PA_SYSTEM_USER))) { pa_log(_("Failed to find user '%s'."), PA_SYSTEM_USER); return -1; } if (!(gr = getgrnam(PA_SYSTEM_GROUP))) { pa_log(_("Failed to find group '%s'."), PA_SYSTEM_GROUP); return -1; } pa_log_info(_("Found user '%s' (UID %lu) and group '%s' (GID %lu)."), PA_SYSTEM_USER, (unsigned long) pw->pw_uid, PA_SYSTEM_GROUP, (unsigned long) gr->gr_gid); if (pw->pw_gid != gr->gr_gid) { pa_log(_("GID of user '%s' and of group '%s' don't match."), PA_SYSTEM_USER, PA_SYSTEM_GROUP); return -1; } if (!pa_streq(pw->pw_dir, PA_SYSTEM_RUNTIME_PATH)) pa_log_warn(_("Home directory of user '%s' is not '%s', ignoring."), PA_SYSTEM_USER, PA_SYSTEM_RUNTIME_PATH); if (pa_make_secure_dir(PA_SYSTEM_RUNTIME_PATH, 0755, pw->pw_uid, gr->gr_gid, true) < 0) { pa_log(_("Failed to create '%s': %s"), PA_SYSTEM_RUNTIME_PATH, pa_cstrerror(errno)); return -1; } if (pa_make_secure_dir(PA_SYSTEM_STATE_PATH, 0700, pw->pw_uid, gr->gr_gid, true) < 0) { pa_log(_("Failed to create '%s': %s"), PA_SYSTEM_STATE_PATH, pa_cstrerror(errno)); return -1; } /* We don't create the config dir here, because we don't need to write to it */ if (initgroups(PA_SYSTEM_USER, gr->gr_gid) != 0) { pa_log(_("Failed to change group list: %s"), pa_cstrerror(errno)); return -1; } #if defined(HAVE_SETRESGID) r = setresgid(gr->gr_gid, gr->gr_gid, gr->gr_gid); #elif defined(HAVE_SETEGID) if ((r = setgid(gr->gr_gid)) >= 0) r = setegid(gr->gr_gid); #elif defined(HAVE_SETREGID) r = setregid(gr->gr_gid, gr->gr_gid); #else #error "No API to drop privileges" #endif if (r < 0) { pa_log(_("Failed to change GID: %s"), pa_cstrerror(errno)); return -1; } #if defined(HAVE_SETRESUID) r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid); #elif defined(HAVE_SETEUID) if ((r = setuid(pw->pw_uid)) >= 0) r = seteuid(pw->pw_uid); #elif defined(HAVE_SETREUID) r = setreuid(pw->pw_uid, pw->pw_uid); #else #error "No API to drop privileges" #endif if (r < 0) { pa_log(_("Failed to change UID: %s"), pa_cstrerror(errno)); return -1; } pa_drop_caps(); pa_set_env("USER", PA_SYSTEM_USER); pa_set_env("USERNAME", PA_SYSTEM_USER); pa_set_env("LOGNAME", PA_SYSTEM_USER); pa_set_env("HOME", PA_SYSTEM_RUNTIME_PATH); /* Relevant for pa_runtime_path() */ if (!getenv("PULSE_RUNTIME_PATH")) pa_set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH); if (!getenv("PULSE_CONFIG_PATH")) pa_set_env("PULSE_CONFIG_PATH", PA_SYSTEM_CONFIG_PATH); if (!getenv("PULSE_STATE_PATH")) pa_set_env("PULSE_STATE_PATH", PA_SYSTEM_STATE_PATH); pa_log_info(_("Successfully changed user to \"" PA_SYSTEM_USER "\".")); return 0; }