1/*  Copyright 1997,1999,2001,2002,2007,2009 Alain Knaff.
2 *  This file is part of mtools.
3 *
4 *  Mtools is free software: you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License as published by
6 *  the Free Software Foundation, either version 3 of the License, or
7 *  (at your option) any later version.
8 *
9 *  Mtools is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *  GNU General Public License for more details.
13 *
14 *  You should have received a copy of the GNU General Public License
15 *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "sysincludes.h"
19#include "msdos.h"
20#include "mtools.h"
21
22int noPrivileges=0;
23
24#ifdef OS_mingw32msvc
25void reclaim_privs(void)
26{
27}
28
29void drop_privs(void)
30{
31}
32
33void destroy_privs(void)
34{
35}
36
37uid_t get_real_uid(void)
38{
39	return 0;
40}
41
42void init_privs(void)
43{
44}
45
46void closeExec(int fd)
47{
48}
49
50#else
51/*#define PRIV_DEBUG*/
52
53#if 0
54#undef HAVE_SETEUID
55#define HAVE_SETRESUID
56#include <asm/unistd.h>
57int setresuid(int a, int b, int c)
58{
59	syscall(164, a, b, c);
60
61}
62#endif
63
64static __inline__ void print_privs(const char *message)
65{
66#ifdef PRIV_DEBUG
67	/* for debugging purposes only */
68	fprintf(stderr,"%s egid=%d rgid=%d\n", message, getegid(), getgid());
69	fprintf(stderr,"%s euid=%d ruid=%d\n", message, geteuid(), getuid());
70#endif
71}
72
73
74static gid_t rgid, egid;
75static uid_t ruid, euid;
76
77/* privilege management routines for SunOS and Solaris.  These are
78 * needed in order to issue raw SCSI read/write ioctls.  Mtools drops
79 * its privileges at the beginning, and reclaims them just for the
80 * above-mentioned ioctl's.  Before popen(), exec() or system, it
81 * drops its privileges completely, and issues a warning.
82 */
83
84
85/* group id handling is lots easyer, as long as we don't use group 0.
86 * If you want to use group id's, create a *new* group mtools or
87 * floppy.  Chgrp any devices that you only want to be accessible to
88 * mtools to this group, and give them the appropriate privs.  Make
89 * sure this group doesn't own any other files: be aware that any user
90 * with access to mtools may mformat these files!
91 */
92
93
94static __inline__ void Setuid(uid_t uid)
95{
96#if defined HAVE_SETEUID || defined HAVE_SETRESUID
97	if(euid == 0) {
98#ifdef HAVE_SETEUID
99		seteuid(uid);
100#else
101		setresuid(ruid, uid, euid);
102#endif
103	} else
104#endif
105		setuid(uid);
106}
107
108/* In reclaim_privs and drop privs, we have to manipulate group privileges
109 * when having no root privileges, else we might lose them */
110
111void reclaim_privs(void)
112{
113	if(noPrivileges)
114		return;
115	setgid(egid);
116	Setuid(euid);
117	print_privs("after reclaim privs, both uids should be 0 ");
118}
119
120void drop_privs(void)
121{
122	Setuid(ruid);
123	setgid(rgid);
124	print_privs("after drop_privs, real should be 0, effective should not ");
125}
126
127void destroy_privs(void)
128{
129
130#if defined HAVE_SETEUID || defined HAVE_SETRESUID
131	if(euid == 0) {
132#ifdef HAVE_SETEUID
133		setuid(0); /* get the necessary privs to drop real root id */
134		setuid(ruid); /* this should be enough to get rid of the three
135			       * ids */
136		seteuid(ruid); /* for good measure... just in case we came
137				* accross a system which implemented sane
138				* semantics instead of POSIXly broken
139				* semantics for setuid */
140#else
141		setresuid(ruid, ruid, ruid);
142#endif
143	}
144#endif
145
146	/* we also destroy group privileges */
147	drop_privs();
148
149	/* saved set [ug]id will go away by itself on exec */
150
151	print_privs("destroy_privs, no uid should be zero  ");
152}
153
154
155uid_t get_real_uid(void)
156{
157	return ruid;
158}
159
160void init_privs(void)
161{
162	euid = geteuid();
163	ruid = getuid();
164	egid = getegid();
165	rgid = getgid();
166
167#ifndef F_SETFD
168	if(euid != ruid) {
169		fprintf(stderr,
170			"Setuid installation not supported on this platform\n");
171		fprintf(stderr,
172			"Missing F_SETFD");
173		exit(1);
174	}
175#endif
176
177	if(euid == 0 && ruid != 0) {
178#ifdef HAVE_SETEUID
179		setuid(0); /* set real uid to 0 */
180#else
181#ifndef HAVE_SETRESUID
182		/* on this machine, it is not possible to reversibly drop
183		 * root privileges.  We print an error and quit */
184
185		/* BEOS is no longer a special case, as both euid and ruid
186		 * return 0, and thus we do not get any longer into this
187		 * branch */
188		fprintf(stderr,
189			"Seteuid call not supported on this architecture.\n");
190		fprintf(stderr,
191			"Mtools cannot be installed setuid root.\n");
192		fprintf(stderr,
193			"However, it can be installed setuid to a non root");
194		fprintf(stderr,
195			"user or setgid to any id.\n");
196		exit(1);
197#endif
198#endif
199	}
200
201	drop_privs();
202	print_privs("after init, real should be 0, effective should not ");
203}
204
205void closeExec(int fd)
206{
207#ifdef F_SETFD
208	fcntl(fd, F_SETFD, 1);
209#endif
210}
211#endif
212