New upstream version 2.0pre9.2
Some checks failed
Master / Scheduled (FULL) (push) Has been cancelled
Master / Triggered (push) Has been cancelled
Master / Triggered (ASAN) (push) Has been cancelled
Master / Triggered (FULL) (push) Has been cancelled

This commit is contained in:
geos_one
2025-08-10 12:35:43 +02:00
commit 91736529d5
1056 changed files with 370820 additions and 0 deletions

257
src/base/core/priv.c Normal file
View File

@@ -0,0 +1,257 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <grp.h>
#ifdef HAVE_SYS_IO_H
#include <sys/io.h>
#endif
#include "emu.h"
#include "priv.h"
#include "dosemu_config.h"
#include "mapping.h"
#include "utilities.h"
#ifdef X86_EMULATOR
#include "cpu-emu.h"
#endif
#if 0
#define PRIV_TESTING
#endif
/* Some handy information to have around */
static uid_t uid,euid;
static gid_t gid,egid;
static uid_t cur_uid, cur_euid;
static gid_t cur_gid, cur_egid;
static int skip_priv_setting = 0;
int can_do_root_stuff;
int under_root_login;
int using_sudo;
int current_iopl;
#define PRIVS_ARE_ON (euid == cur_euid)
#define PRIVS_ARE_OFF (uid == cur_euid)
#define PRIVS_WERE_ON(privs) (pop_priv(privs))
static void push_priv(saved_priv_status *privs)
{
if (!privs || *privs != PRIV_MAGIC) {
error("Aiiiee... not in-sync saved priv status on push_priv\n");
leavedos(99);
}
*privs = PRIVS_ARE_ON;
#ifdef PRIV_TESTING
c_printf("PRIV: pushing %d privs_ptr=%p\n", *privs, privs);
#endif
}
static int pop_priv(saved_priv_status *privs)
{
int ret;
if (!privs || *privs == PRIV_MAGIC) {
error("Aiiiee... not in-sync saved priv status on pop_priv\n");
leavedos(99);
}
#ifdef PRIV_TESTING
c_printf("PRIV: popping %d privs_ptr=%p\n", *privs, privs);
#endif
ret = (int)*privs;
*privs = PRIV_MAGIC;
return ret;
}
static int _priv_on(void)
{
if (PRIVS_ARE_OFF) { /* make sure the privs need to be changed */
#ifdef PRIV_TESTING
c_printf("PRIV: on-in %d\n", cur_euid);
#endif
if (setreuid(uid,euid)) {
error("Cannot turn privs on!\n");
return 0;
}
cur_uid = uid;
cur_euid = euid;
if (setregid(gid,egid)) {
error("Cannot turn privs on!\n");
return 0;
}
cur_gid = gid;
cur_egid = egid;
}
#ifdef PRIV_TESTING
c_printf("PRIV: on-ex %d\n", cur_euid);
#endif
return 1;
}
static int _priv_off(void)
{
if (PRIVS_ARE_ON) { /* make sure the privs need to be changed */
#ifdef PRIV_TESTING
c_printf("PRIV: off-in %d\n", cur_euid);
#endif
if (setreuid(euid,uid)) {
error("Cannot turn privs off!\n");
return 0;
}
cur_uid = euid;
cur_euid = uid;
if (setregid(egid,gid)) {
error("Cannot turn privs off!\n");
return 0;
}
cur_gid = egid;
cur_egid = gid;
}
#ifdef PRIV_TESTING
c_printf("PRIV: off-ex %d\n", cur_euid);
#endif
return 1;
}
int real_enter_priv_on(saved_priv_status *privs)
{
if (skip_priv_setting) return 1;
push_priv(privs);
return _priv_on();
}
int real_enter_priv_off(saved_priv_status *privs)
{
if (skip_priv_setting) return 1;
push_priv(privs);
return _priv_off();
}
int real_leave_priv_setting(saved_priv_status *privs)
{
if (skip_priv_setting) return 1;
if (PRIVS_WERE_ON(privs)) return _priv_on();
return _priv_off();
}
int priv_iopl(int pl)
{
#ifdef HAVE_SYS_IO_H
int ret;
if (PRIVS_ARE_OFF) {
_priv_on();
ret = iopl(pl);
_priv_off();
}
else ret = iopl(pl);
#ifdef X86_EMULATOR
if (config.cpu_vm == CPUVM_EMU) e_priv_iopl(pl);
#endif
if (ret == 0)
current_iopl = pl;
return ret;
#else
return -1;
#endif
}
uid_t get_cur_uid(void)
{
return cur_uid;
}
uid_t get_cur_euid(void)
{
return cur_euid;
}
gid_t get_cur_egid(void)
{
return cur_egid;
}
uid_t get_orig_uid(void)
{
return uid;
}
uid_t get_orig_euid(void)
{
return euid;
}
gid_t get_orig_gid(void)
{
return gid;
}
int priv_drop(void)
{
if (setreuid(uid,uid) || setregid(gid,gid))
{
error("Cannot drop root uid or gid!\n");
return 0;
}
cur_euid = euid = cur_uid = uid;
cur_egid = egid = cur_gid = gid;
skip_priv_setting = 1;
if (uid) can_do_root_stuff = 0;
return 1;
}
void priv_init(void)
{
const char *sh = getenv("SUDO_HOME"); // theoretical future var
const char *h = getenv("HOME");
uid = cur_uid = getuid();
/* suid bit only sets euid & suid but not uid, sudo sets all 3 */
if (!uid) under_root_login = 1;
euid = cur_euid = geteuid();
if (!euid) can_do_root_stuff = 1;
if (!uid && !euid) skip_priv_setting = 1;
gid = cur_gid = getgid();
egid = cur_egid = getegid();
/* must store the /proc/self/exe symlink contents before dropping
privs! */
dosemu_proc_self_exe = readlink_malloc("/proc/self/exe");
/* For Fedora we must also save a file descriptor to /proc/self/maps */
dosemu_proc_self_maps_fd = open("/proc/self/maps", O_RDONLY | O_CLOEXEC);
if (!sh)
sh = getenv("DOSEMU_SUDO_HOME");
/* see if -E was used */
if (under_root_login && sh && h && strcmp(sh, h) == 0)
{
/* check for sudo and set to original user */
char *s = getenv("SUDO_GID");
if (s) {
gid = cur_gid = atoi(s);
if (gid) {
setregid(gid, egid);
}
}
s = getenv("SUDO_UID");
if (s) {
uid = cur_uid = atoi(s);
if (uid) {
skip_priv_setting = under_root_login = 0;
using_sudo = 1;
s = getenv("SUDO_USER");
if (s) {
initgroups(s, gid);
setenv("USER", s, 1);
}
setreuid(uid, euid);
}
}
}
if (!can_do_root_stuff)
{
skip_priv_setting = 1;
}
if (!skip_priv_setting) _priv_off();
}