Import mtools 4.0.26

Bug: 175204891
Bug: 180112530
Change-Id: I8a656b5da155f9857afa4f48c6b40fe72f68c052
diff --git a/privileges.c b/privileges.c
new file mode 100644
index 0000000..71de4c1
--- /dev/null
+++ b/privileges.c
@@ -0,0 +1,214 @@
+/*  Copyright 1997,1999,2001,2002,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+
+int noPrivileges=0;
+
+#ifdef OS_mingw32msvc
+void reclaim_privs(void)
+{
+}
+
+void drop_privs(void)
+{
+}
+
+void destroy_privs(void)
+{
+}
+
+uid_t get_real_uid(void)
+{
+	return 0;
+}
+
+void init_privs(void)
+{
+}
+
+void closeExec(int fd)
+{
+}
+
+#else
+/*#define PRIV_DEBUG*/
+
+#if 0
+#undef HAVE_SETEUID
+#define HAVE_SETRESUID
+#include <asm/unistd.h>
+int setresuid(int a, int b, int c)
+{
+	syscall(164, a, b, c);
+
+}
+#endif
+
+static __inline__ void print_privs(const char *message UNUSEDP)
+{
+#ifdef PRIV_DEBUG
+	/* for debugging purposes only */
+	fprintf(stderr,"%s egid=%d rgid=%d\n", message, getegid(), getgid());
+	fprintf(stderr,"%s euid=%d ruid=%d\n", message, geteuid(), getuid());
+#endif
+}
+
+
+static gid_t rgid, egid;
+static uid_t ruid, euid;
+
+/* privilege management routines for SunOS and Solaris.  These are
+ * needed in order to issue raw SCSI read/write ioctls.  Mtools drops
+ * its privileges at the beginning, and reclaims them just for the
+ * above-mentioned ioctl's.  Before popen(), exec() or system, it
+ * drops its privileges completely, and issues a warning.
+ */
+
+
+/* group id handling is lots easier, as long as we don't use group 0.
+ * If you want to use group id's, create a *new* group mtools or
+ * floppy.  Chgrp any devices that you only want to be accessible to
+ * mtools to this group, and give them the appropriate privs.  Make
+ * sure this group doesn't own any other files: be aware that any user
+ * with access to mtools may mformat these files!
+ */
+
+
+static __inline__ void Setuid(uid_t uid)
+{
+#if defined HAVE_SETEUID || defined HAVE_SETRESUID
+	if(euid == 0) {
+#ifdef HAVE_SETEUID
+		seteuid(uid);
+#else
+		setresuid(ruid, uid, euid);
+#endif
+	} else
+#endif
+		setuid(uid);
+}
+
+/* In reclaim_privs and drop privs, we have to manipulate group privileges
+ * when having no root privileges, else we might lose them */
+
+void reclaim_privs(void)
+{
+	if(noPrivileges)
+		return;
+	setgid(egid);
+	Setuid(euid);
+	print_privs("after reclaim privs, both uids should be 0 ");
+}
+
+void drop_privs(void)
+{
+	Setuid(ruid);
+	setgid(rgid);
+	print_privs("after drop_privs, real should be 0, effective should not ");
+}
+
+void destroy_privs(void)
+{
+
+#if defined HAVE_SETEUID || defined HAVE_SETRESUID
+	if(euid == 0) {
+#ifdef HAVE_SETEUID
+		setuid(0); /* get the necessary privs to drop real root id */
+		setuid(ruid); /* this should be enough to get rid of the three
+			       * ids */
+		seteuid(ruid); /* for good measure... just in case we came
+				* across a system which implemented sane
+				* semantics instead of POSIXly broken
+				* semantics for setuid */
+#else
+		setresuid(ruid, ruid, ruid);
+#endif
+	}
+#endif
+
+	/* we also destroy group privileges */
+	drop_privs();
+
+	/* saved set [ug]id will go away by itself on exec */
+
+	print_privs("destroy_privs, no uid should be zero  ");
+}
+
+
+uid_t get_real_uid(void)
+{
+	return ruid;
+}
+
+void init_privs(void)
+{
+	euid = geteuid();
+	ruid = getuid();
+	egid = getegid();
+	rgid = getgid();
+
+#ifndef F_SETFD
+	if(euid != ruid) {
+		fprintf(stderr,
+			"Setuid installation not supported on this platform\n");
+		fprintf(stderr,
+			"Missing F_SETFD");
+		exit(1);
+	}
+#endif
+
+	if(euid != ruid) {
+		unsetenv("SOURCE_DATE_EPOCH");
+	}
+	if(euid == 0 && ruid != 0) {
+#ifdef HAVE_SETEUID
+		setuid(0); /* set real uid to 0 */
+#else
+#ifndef HAVE_SETRESUID
+		/* on this machine, it is not possible to reversibly drop
+		 * root privileges.  We print an error and quit */
+
+		/* BEOS is no longer a special case, as both euid and ruid
+		 * return 0, and thus we do not get any longer into this
+		 * branch */
+		fprintf(stderr,
+			"Seteuid call not supported on this architecture.\n");
+		fprintf(stderr,
+			"Mtools cannot be installed setuid root.\n");
+		fprintf(stderr,
+			"However, it can be installed setuid to a non root");
+		fprintf(stderr,
+			"user or setgid to any id.\n");
+		exit(1);
+#endif
+#endif
+	}
+	
+	drop_privs();
+	print_privs("after init, real should be 0, effective should not ");
+}
+
+void closeExec(int fd)
+{
+#ifdef F_SETFD
+	fcntl(fd, F_SETFD, 1);
+#endif
+}
+#endif