1e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris/* 2e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris * Authors: Dan Walsh <dwalsh@redhat.com> 3e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris * Authors: Thomas Liu <tliu@fedoraproject.org> 4e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris */ 5e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris 639066bd0ac3839d9c247dd1b769906c7100a10e0Eric Paris#define _GNU_SOURCE 7d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <signal.h> 831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris#include <sys/fsuid.h> 931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris#include <sys/stat.h> 10d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <sys/types.h> 11d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <sys/wait.h> 12d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <syslog.h> 13d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <sys/mount.h> 1431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris#include <glob.h> 15d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <pwd.h> 16d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <sched.h> 17d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <string.h> 18d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <stdio.h> 194347a5c01d79778ffb9c74b02cd174b0469670c8Eric Paris#include <regex.h> 20d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <unistd.h> 21d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <stdlib.h> 22d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <cap-ng.h> 23d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <getopt.h> /* for getopt_long() form of getopt() */ 24d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <limits.h> 25d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <stdlib.h> 26d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <errno.h> 2731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris#include <fcntl.h> 28d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 29d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <selinux/selinux.h> 30d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <selinux/context.h> /* for context-mangling functions */ 31e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh#include <dirent.h> 32d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 33d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#ifdef USE_NLS 34d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <locale.h> /* for setlocale() */ 35d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#include <libintl.h> /* for gettext() */ 36d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#define _(msgid) gettext (msgid) 37d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#else 38d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#define _(msgid) (msgid) 39d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh#endif 40d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 41582fd00c7b493010f93696f0bfcc55412ab40c07Steve Lawrence#ifndef MS_REC 42582fd00c7b493010f93696f0bfcc55412ab40c07Steve Lawrence#define MS_REC 1<<14 43582fd00c7b493010f93696f0bfcc55412ab40c07Steve Lawrence#endif 44582fd00c7b493010f93696f0bfcc55412ab40c07Steve Lawrence 4570c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh#ifndef MS_SLAVE 4670c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh#define MS_SLAVE 1<<19 47582fd00c7b493010f93696f0bfcc55412ab40c07Steve Lawrence#endif 48582fd00c7b493010f93696f0bfcc55412ab40c07Steve Lawrence 49e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris#ifndef PACKAGE 50e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris#define PACKAGE "policycoreutils" /* the name of this package lang translation */ 51e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris#endif 52e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris 534347a5c01d79778ffb9c74b02cd174b0469670c8Eric Paris#define BUF_SIZE 1024 54406ae12e31ac60ccbecc67dc1314dd88491ca9cdEric Paris#define DEFAULT_PATH "/usr/bin:/bin" 55de0795a12edfa8c1239c3165bc4d6c566b6875afDan Walsh#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z CONTEXT ] -- executable [args] ") 56406ae12e31ac60ccbecc67dc1314dd88491ca9cdEric Paris 57406ae12e31ac60ccbecc67dc1314dd88491ca9cdEric Parisstatic int verbose = 0; 58216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walshstatic int child = 0; 59406ae12e31ac60ccbecc67dc1314dd88491ca9cdEric Paris 601f0b5bd920c8c43afb215b7455a9691198bd3a51Dan Walshstatic capng_select_t cap_set = CAPNG_SELECT_CAPS; 61149afc688a53839e57ca541dfa1f84c946bb6399Dan Walsh 62d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh/** 63d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris * This function will drop all capabilities. 64d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh */ 65c4a4a1a7ed42c167a7d4bae06a1fffa8c6c9cb8dNicolas Ioossstatic int drop_caps(void) 66d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh{ 67149afc688a53839e57ca541dfa1f84c946bb6399Dan Walsh if (capng_have_capabilities(cap_set) == CAPNG_NONE) 68d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris return 0; 69149afc688a53839e57ca541dfa1f84c946bb6399Dan Walsh capng_clear(cap_set); 70149afc688a53839e57ca541dfa1f84c946bb6399Dan Walsh if (capng_lock() == -1 || capng_apply(cap_set) == -1) { 71d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris fprintf(stderr, _("Failed to drop all capabilities\n")); 72d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 73d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris } 74d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris return 0; 75d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris} 76d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris 77d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris/** 78d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris * This function will drop all privileges. 79d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris */ 80d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Parisstatic int drop_privs(uid_t uid) 81d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris{ 82d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris if (drop_caps() == -1 || setresuid(uid, uid, uid) == -1) { 83d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris fprintf(stderr, _("Failed to drop privileges\n")); 84d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 85d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 86d6c09608cd6a1c29fa2befd1b9769350f3bdee50Eric Paris return 0; 87d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh} 88d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 89d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh/** 90216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh * If the user sends a siginto to seunshare, kill the child's session 91216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh */ 92216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walshvoid handler(int sig) { 93216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh if (child > 0) kill(-child,sig); 94216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh} 95216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh 96216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh/** 9789e3dd6c30edc2ffa1e52e8ed162c1085c6d6c9bEric Paris * Take care of any signal setup. 98d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh */ 99d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walshstatic int set_signal_handles(void) 100d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh{ 101d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh sigset_t empty; 102d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 103d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh /* Empty the signal mask in case someone is blocking a signal */ 104d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (sigemptyset(&empty)) { 105d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh fprintf(stderr, "Unable to obtain empty signal set\n"); 106d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 107d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 108d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 109d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh (void)sigprocmask(SIG_SETMASK, &empty, NULL); 110d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 11131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* Terminate on SIGHUP */ 112d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (signal(SIGHUP, SIG_DFL) == SIG_ERR) { 113d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh perror("Unable to set SIGHUP handler"); 114d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 115d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 116d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 117216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh if (signal(SIGINT, handler) == SIG_ERR) { 118216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh perror("Unable to set SIGINT handler"); 119216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh return -1; 120216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh } 121216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh 122d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return 0; 123d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh} 124d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 125f6558d9cecae6653e589039359465f796cca7d9aEric Paris#define status_to_retval(status,retval) do { \ 126f6558d9cecae6653e589039359465f796cca7d9aEric Paris if ((status) == -1) \ 127f6558d9cecae6653e589039359465f796cca7d9aEric Paris retval = -1; \ 128f6558d9cecae6653e589039359465f796cca7d9aEric Paris else if (WIFEXITED((status))) \ 129f6558d9cecae6653e589039359465f796cca7d9aEric Paris retval = WEXITSTATUS((status)); \ 130f6558d9cecae6653e589039359465f796cca7d9aEric Paris else if (WIFSIGNALED((status))) \ 131f6558d9cecae6653e589039359465f796cca7d9aEric Paris retval = 128 + WTERMSIG((status)); \ 132f6558d9cecae6653e589039359465f796cca7d9aEric Paris else \ 133f6558d9cecae6653e589039359465f796cca7d9aEric Paris retval = -1; \ 134f6558d9cecae6653e589039359465f796cca7d9aEric Paris } while(0) 135f6558d9cecae6653e589039359465f796cca7d9aEric Paris 136f6558d9cecae6653e589039359465f796cca7d9aEric Paris/** 137f6558d9cecae6653e589039359465f796cca7d9aEric Paris * Spawn external command using system() with dropped privileges. 138f6558d9cecae6653e589039359465f796cca7d9aEric Paris * TODO: avoid system() and use exec*() instead 139f6558d9cecae6653e589039359465f796cca7d9aEric Paris */ 140f6558d9cecae6653e589039359465f796cca7d9aEric Parisstatic int spawn_command(const char *cmd, uid_t uid){ 141f978b1b071fe38ecb406c1035df0912c43924b7dNicolas Iooss int childpid; 142f6558d9cecae6653e589039359465f796cca7d9aEric Paris int status = -1; 143f6558d9cecae6653e589039359465f796cca7d9aEric Paris 144f6558d9cecae6653e589039359465f796cca7d9aEric Paris if (verbose > 1) 145f6558d9cecae6653e589039359465f796cca7d9aEric Paris printf("spawn_command: %s\n", cmd); 146f6558d9cecae6653e589039359465f796cca7d9aEric Paris 147f978b1b071fe38ecb406c1035df0912c43924b7dNicolas Iooss childpid = fork(); 148f978b1b071fe38ecb406c1035df0912c43924b7dNicolas Iooss if (childpid == -1) { 149f6558d9cecae6653e589039359465f796cca7d9aEric Paris perror(_("Unable to fork")); 150f6558d9cecae6653e589039359465f796cca7d9aEric Paris return status; 151f6558d9cecae6653e589039359465f796cca7d9aEric Paris } 152f6558d9cecae6653e589039359465f796cca7d9aEric Paris 153f978b1b071fe38ecb406c1035df0912c43924b7dNicolas Iooss if (childpid == 0) { 154f6558d9cecae6653e589039359465f796cca7d9aEric Paris if (drop_privs(uid) != 0) exit(-1); 155f6558d9cecae6653e589039359465f796cca7d9aEric Paris 156f6558d9cecae6653e589039359465f796cca7d9aEric Paris status = system(cmd); 157f6558d9cecae6653e589039359465f796cca7d9aEric Paris status_to_retval(status, status); 158f6558d9cecae6653e589039359465f796cca7d9aEric Paris exit(status); 159f6558d9cecae6653e589039359465f796cca7d9aEric Paris } 160f6558d9cecae6653e589039359465f796cca7d9aEric Paris 161f978b1b071fe38ecb406c1035df0912c43924b7dNicolas Iooss waitpid(childpid, &status, 0); 162f6558d9cecae6653e589039359465f796cca7d9aEric Paris status_to_retval(status, status); 163f6558d9cecae6653e589039359465f796cca7d9aEric Paris return status; 164f6558d9cecae6653e589039359465f796cca7d9aEric Paris} 165f6558d9cecae6653e589039359465f796cca7d9aEric Paris 166d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh/** 167bf22cff3ea931abfe431856b015390600f969770Eric Paris * Check file/directory ownership, struct stat * must be passed to the 168bf22cff3ea931abfe431856b015390600f969770Eric Paris * functions. 169bf22cff3ea931abfe431856b015390600f969770Eric Paris */ 170bf22cff3ea931abfe431856b015390600f969770Eric Parisstatic int check_owner_uid(uid_t uid, const char *file, struct stat *st) { 171bf22cff3ea931abfe431856b015390600f969770Eric Paris if (S_ISLNK(st->st_mode)) { 172bf22cff3ea931abfe431856b015390600f969770Eric Paris fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file); 173bf22cff3ea931abfe431856b015390600f969770Eric Paris return -1; 174bf22cff3ea931abfe431856b015390600f969770Eric Paris } 175bf22cff3ea931abfe431856b015390600f969770Eric Paris if (st->st_uid != uid) { 176bf22cff3ea931abfe431856b015390600f969770Eric Paris fprintf(stderr, _("Error: %s not owned by UID %d\n"), file, uid); 177bf22cff3ea931abfe431856b015390600f969770Eric Paris return -1; 178bf22cff3ea931abfe431856b015390600f969770Eric Paris } 179bf22cff3ea931abfe431856b015390600f969770Eric Paris return 0; 180bf22cff3ea931abfe431856b015390600f969770Eric Paris} 181bf22cff3ea931abfe431856b015390600f969770Eric Paris 182bf22cff3ea931abfe431856b015390600f969770Eric Parisstatic int check_owner_gid(gid_t gid, const char *file, struct stat *st) { 183bf22cff3ea931abfe431856b015390600f969770Eric Paris if (S_ISLNK(st->st_mode)) { 184bf22cff3ea931abfe431856b015390600f969770Eric Paris fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file); 185bf22cff3ea931abfe431856b015390600f969770Eric Paris return -1; 186bf22cff3ea931abfe431856b015390600f969770Eric Paris } 187bf22cff3ea931abfe431856b015390600f969770Eric Paris if (st->st_gid != gid) { 188bf22cff3ea931abfe431856b015390600f969770Eric Paris fprintf(stderr, _("Error: %s not owned by GID %d\n"), file, gid); 189bf22cff3ea931abfe431856b015390600f969770Eric Paris return -1; 190bf22cff3ea931abfe431856b015390600f969770Eric Paris } 191bf22cff3ea931abfe431856b015390600f969770Eric Paris return 0; 192bf22cff3ea931abfe431856b015390600f969770Eric Paris} 193bf22cff3ea931abfe431856b015390600f969770Eric Paris 194bf22cff3ea931abfe431856b015390600f969770Eric Paris#define equal_stats(one,two) \ 195bf22cff3ea931abfe431856b015390600f969770Eric Paris ((one)->st_dev == (two)->st_dev && (one)->st_ino == (two)->st_ino && \ 196bf22cff3ea931abfe431856b015390600f969770Eric Paris (one)->st_uid == (two)->st_uid && (one)->st_gid == (two)->st_gid && \ 197bf22cff3ea931abfe431856b015390600f969770Eric Paris (one)->st_mode == (two)->st_mode) 198bf22cff3ea931abfe431856b015390600f969770Eric Paris 199bf22cff3ea931abfe431856b015390600f969770Eric Paris/** 200bf22cff3ea931abfe431856b015390600f969770Eric Paris * Sanity check specified directory. Store stat info for future comparison, or 201bf22cff3ea931abfe431856b015390600f969770Eric Paris * compare with previously saved info to detect replaced directories. 202bf22cff3ea931abfe431856b015390600f969770Eric Paris * Note: This function does not perform owner checks. 203bf22cff3ea931abfe431856b015390600f969770Eric Paris */ 204bf22cff3ea931abfe431856b015390600f969770Eric Parisstatic int verify_directory(const char *dir, struct stat *st_in, struct stat *st_out) { 205bf22cff3ea931abfe431856b015390600f969770Eric Paris struct stat sb; 206bf22cff3ea931abfe431856b015390600f969770Eric Paris 207bf22cff3ea931abfe431856b015390600f969770Eric Paris if (st_out == NULL) st_out = &sb; 208bf22cff3ea931abfe431856b015390600f969770Eric Paris 209bf22cff3ea931abfe431856b015390600f969770Eric Paris if (lstat(dir, st_out) == -1) { 210bf22cff3ea931abfe431856b015390600f969770Eric Paris fprintf(stderr, _("Failed to stat %s: %s\n"), dir, strerror(errno)); 211bf22cff3ea931abfe431856b015390600f969770Eric Paris return -1; 212bf22cff3ea931abfe431856b015390600f969770Eric Paris } 213bf22cff3ea931abfe431856b015390600f969770Eric Paris if (! S_ISDIR(st_out->st_mode)) { 214bf22cff3ea931abfe431856b015390600f969770Eric Paris fprintf(stderr, _("Error: %s is not a directory: %s\n"), dir, strerror(errno)); 215bf22cff3ea931abfe431856b015390600f969770Eric Paris return -1; 216bf22cff3ea931abfe431856b015390600f969770Eric Paris } 217bf22cff3ea931abfe431856b015390600f969770Eric Paris if (st_in && !equal_stats(st_in, st_out)) { 218bf22cff3ea931abfe431856b015390600f969770Eric Paris fprintf(stderr, _("Error: %s was replaced by a different directory\n"), dir); 219bf22cff3ea931abfe431856b015390600f969770Eric Paris return -1; 220bf22cff3ea931abfe431856b015390600f969770Eric Paris } 221bf22cff3ea931abfe431856b015390600f969770Eric Paris 222bf22cff3ea931abfe431856b015390600f969770Eric Paris return 0; 223bf22cff3ea931abfe431856b015390600f969770Eric Paris} 224bf22cff3ea931abfe431856b015390600f969770Eric Paris 225bf22cff3ea931abfe431856b015390600f969770Eric Paris/** 226d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh * This function checks to see if the shell is known in /etc/shells. 227d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh * If so, it returns 0. On error or illegal shell, it returns -1. 228d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh */ 229d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walshstatic int verify_shell(const char *shell_name) 230d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh{ 231d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh int rc = -1; 232d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh const char *buf; 233d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 234d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (!(shell_name && shell_name[0])) 235d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return rc; 236d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 237d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh while ((buf = getusershell()) != NULL) { 238d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh /* ignore comments */ 239d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (*buf == '#') 240d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh continue; 241d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 242d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh /* check the shell skipping newline char */ 243d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (!strcmp(shell_name, buf)) { 24431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris rc = 0; 245d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh break; 246d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 247d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 248d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh endusershell(); 249d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return rc; 250d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh} 251d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 25231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris/** 25331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * Mount directory and check that we mounted the right directory. 25431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris */ 25531edb319affb5e5c6298a53ca2de62abedb01630Eric Parisstatic int seunshare_mount(const char *src, const char *dst, struct stat *src_st) 25631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris{ 25770c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh int flags = 0; 25831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris int is_tmp = 0; 25931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 260d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (verbose) 26131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris printf(_("Mounting %s on %s\n"), src, dst); 26231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 26331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (strcmp("/tmp", dst) == 0) { 26431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris flags = flags | MS_NODEV | MS_NOSUID | MS_NOEXEC; 26531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris is_tmp = 1; 26631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 26731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 26831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* mount directory */ 26931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) { 270d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno)); 271d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 272d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 273d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 27431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* verify whether we mounted what we expected to mount */ 27531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (verify_directory(dst, src_st, NULL) < 0) return -1; 27631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 27731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* bind mount /tmp on /var/tmp too */ 27831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (is_tmp) { 27931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (verbose) 28031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris printf(_("Mounting /tmp on /var/tmp\n")); 28131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 28231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (mount("/tmp", "/var/tmp", NULL, MS_BIND | flags, NULL) < 0) { 28331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to mount /tmp on /var/tmp: %s\n"), strerror(errno)); 28431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris return -1; 28531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 28631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 28731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 28831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris return 0; 28931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 290d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh} 291d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 29231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris/* 29331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris If path is empy or ends with "/." or "/.. return -1 else return 0; 29431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris */ 29531edb319affb5e5c6298a53ca2de62abedb01630Eric Parisstatic int bad_path(const char *path) { 29631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris const char *ptr; 29731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris ptr = path; 29831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris while (*ptr) ptr++; 29931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (ptr == path) return -1; // ptr null 30031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris ptr--; 30131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (ptr != path && *ptr == '.') { 30231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris ptr--; 30331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (*ptr == '/') return -1; // path ends in /. 30431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (*ptr == '.') { 30531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (ptr != path) { 30631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris ptr--; 30731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (*ptr == '/') return -1; // path ends in /.. 30831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 30931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 31031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 31131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris return 0; 31231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris} 31331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 31431edb319affb5e5c6298a53ca2de62abedb01630Eric Parisstatic int rsynccmd(const char * src, const char *dst, char **cmdbuf) 31531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris{ 31631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris char *buf = NULL; 31731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris char *newbuf = NULL; 31831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris glob_t fglob; 31931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fglob.gl_offs = 0; 32031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris int flags = GLOB_PERIOD; 32131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris unsigned int i = 0; 32231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris int rc = -1; 32331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 32431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* match glob for all files in src dir */ 32531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (asprintf(&buf, "%s/*", src) == -1) { 32631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, "Out of memory\n"); 32731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris return -1; 32831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 32931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 33031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (glob(buf, flags, NULL, &fglob) != 0) { 33131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris free(buf); buf = NULL; 33231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris return -1; 33331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 33431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 33531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris free(buf); buf = NULL; 33631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 33731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris for ( i=0; i < fglob.gl_pathc; i++) { 33831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris const char *path = fglob.gl_pathv[i]; 33931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 34031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (bad_path(path)) continue; 34131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 34231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (!buf) { 34331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (asprintf(&newbuf, "\'%s\'", path) == -1) { 34431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, "Out of memory\n"); 34531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 34631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 34731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } else { 34831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (asprintf(&newbuf, "%s \'%s\'", buf, path) == -1) { 34931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, "Out of memory\n"); 35031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 35131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 35231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 35331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 35431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris free(buf); buf = newbuf; 35531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris newbuf = NULL; 35631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 35731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 35831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (buf) { 35931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (asprintf(&newbuf, "/usr/bin/rsync -trlHDq %s '%s'", buf, dst) == -1) { 36031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, "Out of memory\n"); 36131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 36231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 36331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris *cmdbuf=newbuf; 36431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 36531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris else { 36631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris *cmdbuf=NULL; 36731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 36831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris rc = 0; 36931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 37031edb319affb5e5c6298a53ca2de62abedb01630Eric Pariserr: 37131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris free(buf); buf = NULL; 37231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris globfree(&fglob); 37331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris return rc; 37431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris} 37531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 37631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris/** 37731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * Clean up runtime temporary directory. Returns 0 if no problem was detected, 37831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * >0 if some error was detected, but errors here are treated as non-fatal and 37931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * left to tmpwatch to finish incomplete cleanup. 38031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris */ 38131edb319affb5e5c6298a53ca2de62abedb01630Eric Parisstatic int cleanup_tmpdir(const char *tmpdir, const char *src, 38231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris struct passwd *pwd, int copy_content) 38331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris{ 38431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris char *cmdbuf = NULL; 38531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris int rc = 0; 38631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 38731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* rsync files back */ 38831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (copy_content) { 38931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (asprintf(&cmdbuf, "/usr/bin/rsync --exclude=.X11-unix -utrlHDq --delete '%s/' '%s/'", tmpdir, src) == -1) { 39031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Out of memory\n")); 39131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris cmdbuf = NULL; 39231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris rc++; 39331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 39431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) { 39531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to copy files from the runtime temporary directory\n")); 39631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris rc++; 39731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 39831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris free(cmdbuf); cmdbuf = NULL; 39931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 40031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 40131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* remove files from the runtime temporary directory */ 40231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (asprintf(&cmdbuf, "/bin/rm -r '%s/' 2>/dev/null", tmpdir) == -1) { 40331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Out of memory\n")); 40431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris cmdbuf = NULL; 40531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris rc++; 40631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 40731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* this may fail if there's root-owned file left in the runtime tmpdir */ 40831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) rc++; 40931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris free(cmdbuf); cmdbuf = NULL; 41031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 41131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* remove runtime temporary directory */ 412e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh if ((uid_t)setfsuid(0) != 0) { 413e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh /* setfsuid does not return errror, but this check makes code checkers happy */ 414221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris rc++; 415221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris } 416221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris 41731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (rmdir(tmpdir) == -1) 41831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to remove directory %s: %s\n"), tmpdir, strerror(errno)); 419221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris if ((uid_t)setfsuid(pwd->pw_uid) != 0) { 420221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris fprintf(stderr, _("unable to switch back to user after clearing tmp dir\n")); 421221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris rc++; 422221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris } 42331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 424221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris return rc; 42531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris} 42631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 42731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris/** 42831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * seunshare will create a tmpdir in /tmp, with root ownership. The parent 42931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * process waits for it child to exit to attempt to remove the directory. If 43031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * it fails to remove the directory, we will need to rely on tmpreaper/tmpwatch 43131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * to clean it up. 43231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris */ 43331edb319affb5e5c6298a53ca2de62abedb01630Eric Parisstatic char *create_tmpdir(const char *src, struct stat *src_st, 43431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris struct stat *out_st, struct passwd *pwd, security_context_t execcon) 43531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris{ 43631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris char *tmpdir = NULL; 43731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris char *cmdbuf = NULL; 43831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris int fd_t = -1, fd_s = -1; 43931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris struct stat tmp_st; 44031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris security_context_t con = NULL; 44131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 44231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* get selinux context */ 44331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (execcon) { 444221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris if ((uid_t)setfsuid(pwd->pw_uid) != 0) 445221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris goto err; 446221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris 44731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if ((fd_s = open(src, O_RDONLY)) < 0) { 44831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to open directory %s: %s\n"), src, strerror(errno)); 44931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 45031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 45131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (fstat(fd_s, &tmp_st) == -1) { 45231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to stat directory %s: %s\n"), src, strerror(errno)); 45331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 45431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 45531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (!equal_stats(src_st, &tmp_st)) { 45631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Error: %s was replaced by a different directory\n"), src); 45731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 45831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 45931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (fgetfilecon(fd_s, &con) == -1) { 46031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to get context of the directory %s: %s\n"), src, strerror(errno)); 46131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 46231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 46331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 46431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* ok to not reach this if there is an error */ 465221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris if ((uid_t)setfsuid(0) != pwd->pw_uid) 466221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris goto err; 46731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 46831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 46931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (asprintf(&tmpdir, "/tmp/.sandbox-%s-XXXXXX", pwd->pw_name) == -1) { 47031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Out of memory\n")); 47131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris tmpdir = NULL; 47231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 47331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 47431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (mkdtemp(tmpdir) == NULL) { 47531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to create temporary directory: %s\n"), strerror(errno)); 47631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 47731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 47831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 47931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* temporary directory must be owned by root:user */ 48031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (verify_directory(tmpdir, NULL, out_st) < 0) { 48131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 48231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 48331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 48431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (check_owner_uid(0, tmpdir, out_st) < 0) 48531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 48631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 48731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (check_owner_gid(getgid(), tmpdir, out_st) < 0) 48831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 48931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 49031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* change permissions of the temporary directory */ 49131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if ((fd_t = open(tmpdir, O_RDONLY)) < 0) { 49231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to open directory %s: %s\n"), tmpdir, strerror(errno)); 49331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 49431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 49531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (fstat(fd_t, &tmp_st) == -1) { 49631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno)); 49731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 49831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 49931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (!equal_stats(out_st, &tmp_st)) { 50031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Error: %s was replaced by a different directory\n"), tmpdir); 50131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 50231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 50331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (fchmod(fd_t, 01770) == -1) { 50431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Unable to change mode on %s: %s\n"), tmpdir, strerror(errno)); 50531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 50631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 50731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* re-stat again to pick change mode */ 50831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (fstat(fd_t, out_st) == -1) { 50931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno)); 51031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 51131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 51231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 51331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* copy selinux context */ 51431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (execcon) { 51531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (fsetfilecon(fd_t, con) == -1) { 51631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to set context of the directory %s: %s\n"), tmpdir, strerror(errno)); 51731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 51831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 51931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 52031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 521221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris if ((uid_t)setfsuid(pwd->pw_uid) != 0) 522221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris goto err; 52331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 52431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (rsynccmd(src, tmpdir, &cmdbuf) < 0) { 52531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 52631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 52731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 52831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* ok to not reach this if there is an error */ 529221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris if ((uid_t)setfsuid(0) != pwd->pw_uid) 530221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris goto err; 53131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 53231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) { 53331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to populate runtime temporary directory\n")); 53431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris cleanup_tmpdir(tmpdir, src, pwd, 0); 53531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 53631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 53731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 53831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto good; 53931edb319affb5e5c6298a53ca2de62abedb01630Eric Pariserr: 54031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris free(tmpdir); tmpdir = NULL; 54131edb319affb5e5c6298a53ca2de62abedb01630Eric Parisgood: 54231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris free(cmdbuf); cmdbuf = NULL; 54331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris freecon(con); con = NULL; 54431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (fd_t >= 0) close(fd_t); 54531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (fd_s >= 0) close(fd_s); 54631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris return tmpdir; 54731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris} 54831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 549e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh#define PROC_BASE "/proc" 550e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 551e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walshstatic int 552e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walshkillall (security_context_t execcon) 553e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh{ 554e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh DIR *dir; 555e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh security_context_t scon; 556e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh struct dirent *de; 557e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh pid_t *pid_table, pid, self; 558e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh int i; 559e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh int pids, max_pids; 560e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh int running = 0; 561e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh self = getpid(); 562e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh if (!(dir = opendir(PROC_BASE))) { 563e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh return -1; 564e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh } 565e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh max_pids = 256; 566e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh pid_table = malloc(max_pids * sizeof (pid_t)); 567e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh if (!pid_table) { 568e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh (void)closedir(dir); 569e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh return -1; 570e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh } 571e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh pids = 0; 572e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh context_t con; 573e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh con = context_new(execcon); 574e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh const char *mcs = context_range_get(con); 575e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh printf("mcs=%s\n", mcs); 576e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh while ((de = readdir (dir)) != NULL) { 577e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh if (!(pid = (pid_t)atoi(de->d_name)) || pid == self) 578e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh continue; 579e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 580e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh if (pids == max_pids) { 5810a5dc30456509f10fdc062f9caecc5d3d57b4306Eric Paris pid_t *new_pid_table = realloc(pid_table, 2*pids*sizeof(pid_t)); 5820a5dc30456509f10fdc062f9caecc5d3d57b4306Eric Paris if (!new_pid_table) { 5830a5dc30456509f10fdc062f9caecc5d3d57b4306Eric Paris free(pid_table); 584e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh (void)closedir(dir); 585e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh return -1; 586e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh } 5870a5dc30456509f10fdc062f9caecc5d3d57b4306Eric Paris pid_table = new_pid_table; 588e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh max_pids *= 2; 589e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh } 590e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh pid_table[pids++] = pid; 591e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh } 592e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 593e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh (void)closedir(dir); 594e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 595e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh for (i = 0; i < pids; i++) { 596e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh pid_t id = pid_table[i]; 597e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 598e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh if (getpidcon(id, &scon) == 0) { 599e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 600e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh context_t pidcon = context_new(scon); 601e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh /* Attempt to kill remaining processes */ 602e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh if (strcmp(context_range_get(pidcon), mcs) == 0) 603e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh kill(id, SIGKILL); 604e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 605e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh context_free(pidcon); 606e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh freecon(scon); 607e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh } 608e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh running++; 609e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh } 610e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 611e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh context_free(con); 612e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh free(pid_table); 613e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh return running; 614e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh} 615e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 616d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walshint main(int argc, char **argv) { 617d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh int status = -1; 61831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris security_context_t execcon = NULL; 619d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 620d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh int clflag; /* holds codes for command line flags */ 621e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh int kill_all = 0; 622d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 62331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris char *homedir_s = NULL; /* homedir spec'd by user in argv[] */ 62431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */ 62531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris char *tmpdir_r = NULL; /* tmpdir created by seunshare */ 62631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 627e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh struct stat st_curhomedir; 62831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris struct stat st_homedir; 62931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris struct stat st_tmpdir_s; 63031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris struct stat st_tmpdir_r; 63131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 632d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh const struct option long_options[] = { 633d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh {"homedir", 1, 0, 'h'}, 634d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh {"tmpdir", 1, 0, 't'}, 635e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh {"kill", 1, 0, 'k'}, 636d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh {"verbose", 1, 0, 'v'}, 637da7ae7951c692a60b6137ebaf6f33232a9bd63beEric Paris {"context", 1, 0, 'Z'}, 638149afc688a53839e57ca541dfa1f84c946bb6399Dan Walsh {"capabilities", 1, 0, 'C'}, 639d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh {NULL, 0, 0, 0} 640d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh }; 641d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 642d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh uid_t uid = getuid(); 643a0e2e16878c2aae375920f8fef8efe07bcd6ac3dDan Walsh/* 644d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (!uid) { 645d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh fprintf(stderr, _("Must not be root")); 646d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 647d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 648a0e2e16878c2aae375920f8fef8efe07bcd6ac3dDan Walsh*/ 649d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 650e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris#ifdef USE_NLS 651e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris setlocale(LC_ALL, ""); 652e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris bindtextdomain(PACKAGE, LOCALEDIR); 653e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris textdomain(PACKAGE); 654e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris#endif 655e134013ab705e6edaf3311d4dc9db7c81e84e775Eric Paris 656d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh struct passwd *pwd=getpwuid(uid); 657d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (!pwd) { 658d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh perror(_("getpwduid failed")); 659d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 660d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 661d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 662d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (verify_shell(pwd->pw_shell) < 0) { 66331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Error: User shell is not valid\n")); 664d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 665d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 666d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 667d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh while (1) { 668149afc688a53839e57ca541dfa1f84c946bb6399Dan Walsh clflag = getopt_long(argc, argv, "Ccvh:t:Z:", long_options, NULL); 669d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (clflag == -1) 670d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh break; 671d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 672d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh switch (clflag) { 673d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh case 't': 67431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris tmpdir_s = optarg; 675d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh break; 676e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh case 'k': 677e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh kill_all = 1; 678e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh break; 679d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh case 'h': 68031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris homedir_s = optarg; 681d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh break; 682d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh case 'v': 68331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris verbose++; 684d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh break; 685149afc688a53839e57ca541dfa1f84c946bb6399Dan Walsh case 'C': 686149afc688a53839e57ca541dfa1f84c946bb6399Dan Walsh cap_set = CAPNG_SELECT_CAPS; 687149afc688a53839e57ca541dfa1f84c946bb6399Dan Walsh break; 688da7ae7951c692a60b6137ebaf6f33232a9bd63beEric Paris case 'Z': 68931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris execcon = optarg; 690da7ae7951c692a60b6137ebaf6f33232a9bd63beEric Paris break; 691d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh default: 692d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh fprintf(stderr, "%s\n", USAGE_STRING); 693d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 694d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 695d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 696d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 697d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (! homedir_s && ! tmpdir_s) { 69831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Error: tmpdir and/or homedir required\n %s\n"), USAGE_STRING); 699d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 700d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 701d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 702da7ae7951c692a60b6137ebaf6f33232a9bd63beEric Paris if (argc - optind < 1) { 70331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Error: executable required\n %s\n"), USAGE_STRING); 70431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris return -1; 70531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 70631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 70731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (execcon && is_selinux_enabled() != 1) { 70831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Error: execution context specified, but SELinux is not enabled\n")); 709d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 710d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 711d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 712d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (set_signal_handles()) 713d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 714d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 71531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* set fsuid to ruid */ 71631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* Changing fsuid is usually required when user-specified directory is 71731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * on an NFS mount. It's also desired to avoid leaking info about 71831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris * existence of the files not accessible to the user. */ 719e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh if (((uid_t)setfsuid(uid) != 0) && (errno != 0)) { 720e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh fprintf(stderr, _("Error: unable to setfsuid %m\n")); 721e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh 722221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris return -1; 723e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh } 72431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 72531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* verify homedir and tmpdir */ 72631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (homedir_s && ( 72731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris verify_directory(homedir_s, NULL, &st_homedir) < 0 || 72831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris check_owner_uid(uid, homedir_s, &st_homedir))) return -1; 72931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (tmpdir_s && ( 73031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris verify_directory(tmpdir_s, NULL, &st_tmpdir_s) < 0 || 73131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris check_owner_uid(uid, tmpdir_s, &st_tmpdir_s))) return -1; 732221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris if ((uid_t)setfsuid(0) != uid) return -1; 73331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 73431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* create runtime tmpdir */ 73531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (tmpdir_s && (tmpdir_r = create_tmpdir(tmpdir_s, &st_tmpdir_s, 73631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris &st_tmpdir_r, pwd, execcon)) == NULL) { 73731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to create runtime temporary directory\n")); 738d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return -1; 739d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 740d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 74131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* spawn child process */ 742216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh child = fork(); 743d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (child == -1) { 744d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh perror(_("Unable to fork")); 74531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto err; 746d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 747d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 74831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (child == 0) { 74931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris char *display = NULL; 7505c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh char *LANG = NULL; 7516ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh char *RUNTIME_DIR = NULL; 75231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris int rc = -1; 753e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh char *resolved_path = NULL; 754d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 75531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (unshare(CLONE_NEWNS) < 0) { 75631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris perror(_("Failed to unshare")); 75731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto childerr; 75870c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh } 75970c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh 76070c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh /* Remount / as SLAVE so that nothing mounted in the namespace 76170c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh shows up in the parent */ 76270c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh if (mount("none", "/", NULL, MS_SLAVE | MS_REC , NULL) < 0) { 76370c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh perror(_("Failed to make / a SLAVE mountpoint\n")); 76470c582f4e0554bb41f6bab6336a3996f9499bfebDan Walsh goto childerr; 765d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 766da7ae7951c692a60b6137ebaf6f33232a9bd63beEric Paris 76731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* assume fsuid==ruid after this point */ 768221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris if ((uid_t)setfsuid(uid) != 0) goto childerr; 76931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 770e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh resolved_path = realpath(pwd->pw_dir,NULL); 771e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh if (! resolved_path) goto childerr; 772e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh 773e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh if (verify_directory(resolved_path, NULL, &st_curhomedir) < 0) 774e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh goto childerr; 775e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh if (check_owner_uid(uid, resolved_path, &st_curhomedir) < 0) 776e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh goto childerr; 777e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh 77831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* mount homedir and tmpdir, in this order */ 779e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh if (homedir_s && seunshare_mount(homedir_s, resolved_path, 78031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris &st_homedir) != 0) goto childerr; 78131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (tmpdir_s && seunshare_mount(tmpdir_r, "/tmp", 78231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris &st_tmpdir_r) != 0) goto childerr; 78331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 78431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (drop_privs(uid) != 0) goto childerr; 78531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 78631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* construct a new environment */ 78731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if ((display = getenv("DISPLAY")) != NULL) { 78831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if ((display = strdup(display)) == NULL) { 78931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris perror(_("Out of memory")); 79031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto childerr; 791da7ae7951c692a60b6137ebaf6f33232a9bd63beEric Paris } 792d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 793221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris 7945c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh /* construct a new environment */ 7955c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh if ((LANG = getenv("LANG")) != NULL) { 7965c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh if ((LANG = strdup(LANG)) == NULL) { 7975c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh perror(_("Out of memory")); 7985c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh goto childerr; 7995c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh } 8005c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh } 801221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris 8026ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh if ((RUNTIME_DIR = getenv("XDG_RUNTIME_DIR")) != NULL) { 8036ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh if ((RUNTIME_DIR = strdup(RUNTIME_DIR)) == NULL) { 8046ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh perror(_("Out of memory")); 8056ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh goto childerr; 8066ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh } 8076ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh } 8086ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh 80931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if ((rc = clearenv()) != 0) { 81031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris perror(_("Failed to clear environment")); 81131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto childerr; 81231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 81331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (display) 814d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh rc |= setenv("DISPLAY", display, 1); 815221e6d46651a921c843cbe5ac9b81f324a81e593Eric Paris if (LANG) 8165c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh rc |= setenv("LANG", LANG, 1); 8176ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh if (RUNTIME_DIR) 8186ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh rc |= setenv("XDG_RUNTIME_DIR", RUNTIME_DIR, 1); 819d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh rc |= setenv("HOME", pwd->pw_dir, 1); 820d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh rc |= setenv("SHELL", pwd->pw_shell, 1); 821d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh rc |= setenv("USER", pwd->pw_name, 1); 822d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh rc |= setenv("LOGNAME", pwd->pw_name, 1); 823d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh rc |= setenv("PATH", DEFAULT_PATH, 1); 82431edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (rc != 0) { 82531edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to construct environment\n")); 82631edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto childerr; 82731edb319affb5e5c6298a53ca2de62abedb01630Eric Paris } 82831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 829d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh if (chdir(pwd->pw_dir)) { 830d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh perror(_("Failed to change dir to homedir")); 83131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris goto childerr; 832d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 833d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh setsid(); 83474d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski 83574d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski /* selinux context */ 83674d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski if (execcon) { 83774d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski /* try dyntransition, since no_new_privs can interfere 83874d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski * with setexeccon */ 83974d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski if (setcon(execcon) != 0) { 84074d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski /* failed; fall back to setexeccon */ 84174d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski if (setexeccon(execcon) != 0) { 84274d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski fprintf(stderr, _("Could not set exec context to %s. %s\n"), execcon, strerror(errno)); 84374d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski goto childerr; 84474d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski } 84574d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski } 84674d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski } 84774d27a97338649951108727a0a142b260ce9a28bAndy Lutomirski 848d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh execv(argv[optind], argv + optind); 84931edb319affb5e5c6298a53ca2de62abedb01630Eric Paris fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno)); 85031edb319affb5e5c6298a53ca2de62abedb01630Eric Parischilderr: 851e4488ecd87760e4894354e15935e25ea82baf23cDan Walsh free(resolved_path); 852d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh free(display); 8535c2a0d143de7920b9edf070518d22f4e7dce5481Dan Walsh free(LANG); 8546ee0299ab76ffc62095bda0ae84c49150a83e255Dan Walsh free(RUNTIME_DIR); 855d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh exit(-1); 856d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh } 857d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh 85831edb319affb5e5c6298a53ca2de62abedb01630Eric Paris drop_caps(); 859582fd00c7b493010f93696f0bfcc55412ab40c07Steve Lawrence 86031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris /* parent waits for child exit to do the cleanup */ 86131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris waitpid(child, &status, 0); 86231edb319affb5e5c6298a53ca2de62abedb01630Eric Paris status_to_retval(status, status); 86331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 864216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh /* Make sure all child processes exit */ 865216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh kill(-child,SIGTERM); 866216f456401151d02b39bd3c7f47581a4b8632ab8Dan Walsh 867e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh if (execcon && kill_all) 868e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh killall(execcon); 869e8575bf497806eb5aea0ff0e207e35a5a1534064Dan Walsh 87031edb319affb5e5c6298a53ca2de62abedb01630Eric Paris if (tmpdir_r) cleanup_tmpdir(tmpdir_r, tmpdir_s, pwd, 1); 87131edb319affb5e5c6298a53ca2de62abedb01630Eric Paris 87231edb319affb5e5c6298a53ca2de62abedb01630Eric Pariserr: 87331edb319affb5e5c6298a53ca2de62abedb01630Eric Paris free(tmpdir_r); 874d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh return status; 875d6848ea77d9e0fed546a8286f8c62fe32be58aceDaniel J Walsh} 876