summaryrefslogtreecommitdiff
path: root/icedax/setuid.c
diff options
context:
space:
mode:
Diffstat (limited to 'icedax/setuid.c')
-rw-r--r--icedax/setuid.c332
1 files changed, 332 insertions, 0 deletions
diff --git a/icedax/setuid.c b/icedax/setuid.c
new file mode 100644
index 0000000..7f3e63c
--- /dev/null
+++ b/icedax/setuid.c
@@ -0,0 +1,332 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)setuid.c 1.11 06/02/19 Copyright 1998,1999,2004 Heiko Eissfeldt, Copyright 2004-2006 J. Schilling */
+/* Security functions by zblaxell
+
+ If these functions fail, it is because there was an installation error
+ or a programming error, and we can't be sure about what privileges
+ we do or do not have. This means we might not be able to recover
+ the privileges we need to fix anything that may be broken (e.g. the
+ CDDA state of some interface types), and we may in fact do something
+ quite dangerous (like write to the WAV file as root).
+
+ In any case, it is unsafe to do anything but exit *now*. Ideally we'd
+ kill -9 our process group too, just to be sure. Root privileges are not
+ something you want floating around at random in user-level applications.
+
+ If any signal handlers or child processes are introduced into this
+ program, it will be necessary to call dontneedroot() or neverneedroot()
+ on entry, respectively; otherwise, it will be possible to trick
+ the program into executing the signal handler or child process with
+ root privileges by sending signals at the right time.
+ */
+
+#include "config.h"
+#include <unixstd.h>
+#include <stdio.h>
+#include <stdxlib.h>
+
+#include "exitcodes.h"
+#include "setuid.h"
+
+/*#undef DEBUG*/
+/*#define DEBUG*/
+
+/* True at return from initsecurity */
+static uid_t real_uid = (uid_t) (-1);
+static uid_t effective_uid = (uid_t) (-1);
+static gid_t real_gid = (gid_t) (-1);
+static gid_t effective_gid = (gid_t) (-1);
+
+/* Run this at the beginning of the program to initialize this code and
+ to drop privileges before someone uses them to shoot us in the foot.
+ Do not pass(go), do not dollars += 200. */
+
+void initsecurity()
+{
+ int leffective_uid;
+
+ alarm(0); /* can be inherited from parent process */
+ real_uid = getuid();
+ leffective_uid = geteuid();
+ if ((int) real_uid != leffective_uid && leffective_uid != 0) { /* sanity check */
+ fprintf(stderr, "Warning: setuid but not to root (uid=%ld, euid=%d)\n", (long) real_uid, leffective_uid);
+ fprintf(stderr, "Dropping setuid privileges now.\n");
+ neverneedroot();
+ } else {
+ effective_uid = leffective_uid;
+ }
+ real_gid = getgid();
+ effective_gid = getegid();
+ dontneedroot();
+ dontneedgroup();
+}
+
+/* Temporarily gain root privileges. */
+
+#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEUID) && defined SCO
+/* SCO seems to lack the prototypes... */
+int seteuid(uid_t euid);
+int setegid(gid_t guid);
+#endif
+
+void needroot(int necessary)
+{
+#ifdef DEBUG
+ fprintf(stderr, "call to needroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
+ effective_uid, real_uid, geteuid(), getuid(), getpid());
+#endif
+ if (effective_uid) {
+ if (necessary) {
+ fprintf(stderr, "Fatal error: require root privilege but not setuid root.\n");
+ exit(PERM_ERROR);
+ } else
+ return;
+ }
+ if (real_uid == (uid_t) (-1)) {
+ fprintf(stderr, "Fatal error: initsecurity() not called.\n");
+ exit(INTERNAL_ERROR);
+ }
+
+ if (geteuid() == 0) return; /* nothing to do */
+
+#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEUID)
+ if (seteuid(effective_uid)) {
+ perror("seteuid in needroot()");
+ exit(PERM_ERROR);
+ }
+#else
+#if defined (HAVE_SETREUID)
+ if (setreuid(real_uid, effective_uid)) {
+ perror("setreuid in needroot()");
+ exit(PERM_ERROR);
+ }
+#endif
+#endif
+ if (geteuid() != 0 && necessary) {
+ fprintf(stderr, "Fatal error: did not get root privilege.\n");
+ exit(PERM_ERROR);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "exit of needroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
+ effective_uid, real_uid, geteuid(), getuid(), getpid());
+#endif
+}
+
+/* Temporarily drop root privileges. */
+
+void dontneedroot()
+{
+#ifdef DEBUG
+ fprintf(stderr, "call to dontneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
+ effective_uid, real_uid, geteuid(), getuid(), getpid());
+#endif
+ if (real_uid == (uid_t) (-1)) {
+ fprintf(stderr, "Fatal error: initsecurity() not called.\n");
+ exit(INTERNAL_ERROR);
+ }
+ if (effective_uid)
+ return;
+ if (geteuid() != 0) return; /* nothing to do */
+
+#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEUID)
+ if (seteuid(real_uid)) {
+ perror("seteuid in dontneedroot()");
+ exit(PERM_ERROR);
+ }
+#else
+#if defined (HAVE_SETREUID)
+ if (setreuid(effective_uid, real_uid)) {
+ perror("setreuid in dontneedroot()");
+ exit(PERM_ERROR);
+ }
+#endif
+#endif
+ if (geteuid() != real_uid) {
+ fprintf(stderr, "Fatal error: did not drop root privilege.\n");
+#ifdef DEBUG
+ fprintf(stderr, "in to dontneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
+ effective_uid, real_uid, geteuid(), getuid(), getpid());
+#endif
+ exit(PERM_ERROR);
+ }
+}
+
+/* Permanently drop root privileges. */
+
+void neverneedroot()
+{
+#ifdef DEBUG
+ fprintf(stderr, "call to neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
+ effective_uid, real_uid, geteuid(), getuid(), getpid());
+#endif
+ if (real_uid == (uid_t) (-1)) {
+ fprintf(stderr, "Fatal error: initsecurity() not called.\n");
+ exit(INTERNAL_ERROR);
+ }
+ if (geteuid() == effective_uid) {
+#if defined (HAVE_SETUID)
+ if (setuid(real_uid)) {
+ perror("setuid in neverneedroot()");
+ exit(PERM_ERROR);
+ }
+#endif
+ }
+#if defined(__FreeBSD__) || defined(__DragonFly__) /* XXX this is a big hack and and not a permanent solution */
+ else {
+#if defined (HAVE_SETUID)
+ if (setuid(real_uid)) {
+ perror("setuid in neverneedroot()");
+ exit(PERM_ERROR);
+ }
+#endif
+ }
+#endif
+ if (geteuid() != real_uid || getuid() != real_uid) {
+ fprintf(stderr, "Fatal error: did not drop root privilege.\n");
+#ifdef DEBUG
+ fprintf(stderr, "in to neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
+ effective_uid, real_uid, geteuid(), getuid(), getpid());
+#endif
+ exit(PERM_ERROR);
+ }
+ effective_uid = real_uid;
+#ifdef DEBUG
+ fprintf(stderr, "exit of neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
+ effective_uid, real_uid, geteuid(), getuid(), getpid());
+#endif
+}
+
+/* Temporarily gain group privileges. */
+
+void needgroup(int necessary)
+{
+#ifdef DEBUG
+ fprintf(stderr, "call to needgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
+ effective_gid, real_gid, getegid(), getgid(), getpid());
+#endif
+ if (real_gid == (gid_t) (-1)) {
+ fprintf(stderr, "Fatal error: initsecurity() not called.\n");
+ exit(INTERNAL_ERROR);
+ }
+
+ if (getegid() == effective_gid) return; /* nothing to do */
+
+#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEGID)
+ if (setegid(effective_gid)) {
+ perror("setegid in needgroup()");
+ exit(PERM_ERROR);
+ }
+#else
+#if defined (HAVE_SETREGID)
+ if (setregid(real_gid, effective_gid)) {
+ perror("setregid in needgroup()");
+ exit(PERM_ERROR);
+ }
+#endif
+#endif
+ if (necessary && getegid() != effective_gid) {
+ fprintf(stderr, "Fatal error: did not get group privilege.\n");
+ exit(PERM_ERROR);
+ }
+}
+
+/* Temporarily drop group privileges. */
+
+void dontneedgroup()
+{
+#ifdef DEBUG
+ fprintf(stderr, "call to dontneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
+ effective_gid, real_gid, getegid(), getgid(), getpid());
+#endif
+ if (real_gid == (gid_t) (-1)) {
+ fprintf(stderr, "Fatal error: initsecurity() not called.\n");
+ exit(INTERNAL_ERROR);
+ }
+ if (getegid() != effective_gid) return; /* nothing to do */
+#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEGID)
+ if (setegid(real_gid)) {
+ perror("setegid in dontneedgroup()");
+ exit(PERM_ERROR);
+ }
+#else
+#if defined (HAVE_SETREGID)
+ if (setregid(effective_gid, real_gid)) {
+ perror("setregid in dontneedgroup()");
+ exit(PERM_ERROR);
+ }
+#endif
+#endif
+ if (getegid() != real_gid) {
+ fprintf(stderr, "Fatal error: did not drop group privilege.\n");
+ exit(PERM_ERROR);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "exit if dontneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
+ effective_gid, real_gid, getegid(), getgid(), getpid());
+#endif
+}
+
+/* Permanently drop group privileges. */
+
+void neverneedgroup()
+{
+#ifdef DEBUG
+ fprintf(stderr, "call to neverneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
+ effective_gid, real_gid, getegid(), getgid(), getpid());
+#endif
+ if (real_gid == (gid_t) (-1)) {
+ fprintf(stderr, "Fatal error: initsecurity() not called.\n");
+ exit(INTERNAL_ERROR);
+ }
+ if (getegid() == effective_gid) {
+#if defined (HAVE_SETGID)
+ if (setgid(real_gid)) {
+ perror("setgid in neverneedgroup()");
+ exit(PERM_ERROR);
+ }
+#endif
+ }
+#if defined(__FreeBSD__) || defined(__DragonFly__) /* XXX this is a big hack and and not a permanent solution */
+ else {
+#if defined (HAVE_SETGID)
+ if (setgid(real_gid)) {
+ perror("setgid in neverneedgroup()");
+ exit(PERM_ERROR);
+ }
+#endif
+ }
+#endif
+ if (getegid() != real_gid || getgid() != real_gid) {
+ fprintf(stderr, "Fatal error: did not drop group privilege.\n");
+ exit(PERM_ERROR);
+ }
+ effective_gid = real_gid;
+}
+
+#if defined (HPUX)
+int seteuid(uid_t uid)
+{
+ return setresuid(-1, uid, -1);
+}
+
+int setreuid(uid_t uid1, uid_t uid2)
+{
+ return setresuid(uid2, uid2, uid1 == uid2 ? uid2 : 0);
+}
+
+int setregid(gid_t gid1, gid_t gid2)
+{
+ return setresgid(gid2, gid2, gid1 == gid2 ? gid2 : 0);
+}
+#endif