summaryrefslogtreecommitdiffstats
path: root/lib/clplumbing/uids.c
blob: 0727e1d139c29f5f693a67f63503a2831e86a82c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <lha_internal.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <clplumbing/uids.h>
#include <clplumbing/coredumps.h>
#define	NOBODY	"nobody"

#if defined(HAVE_SETEUID) && defined(HAVE_SETEGID) &&	\
		 defined(_POSIX_SAVED_IDS)
#	define	CAN_DROP_PRIVS	1

#endif




#ifndef CAN_DROP_PRIVS
	int drop_privs(uid_t uid, gid_t gid)	{	return 0;	}
	int return_to_orig_privs(void)		{	return 0;	}
	int return_to_dropped_privs(void)	{	return 0;	}
	int cl_have_full_privs(void)		{	return 0;	}
#else

static int	anysaveduid = 0;
static uid_t	nobodyuid=-1;
static gid_t	nobodygid=-1;
static uid_t	poweruid=-1;
static gid_t	powergid=-1;
static int	privileged_state = 1;

/*	WARNING: uids are unsigned! */
#define	WANT_NOBODY(uid)	((uid) == 0)

int	/* Become nobody - and remember our original privileges */
drop_privs(uid_t uid, gid_t gid)
{
	int	rc;
	gid_t	curgid = getgid();

	if (!anysaveduid) {
		poweruid=getuid();
		powergid=curgid;
	}

	if (WANT_NOBODY(uid)) {
		struct passwd*	p;

		p = getpwnam(NOBODY);

		if (p == NULL) {
			return -1;
		}
		uid = p->pw_uid;
		gid = p->pw_gid;
	}
	if (setegid(gid) < 0) {
		return -1;
	}
	rc = seteuid(uid);

	if (rc >= 0) {
		anysaveduid = 1;
		nobodyuid=uid;
		nobodygid=gid;
		privileged_state = 0;
	}else{
		/* Attempt to recover original privileges */
		int	err = errno;
		setegid(curgid);
		errno = err;
	}
	cl_untaint_coredumps();
	return rc;
}

int	/* Return to our original privileges (if any) */
return_to_orig_privs(void)
{
	int	rc;
	if (!anysaveduid) {
		return 0;
	}
	if (seteuid(poweruid) < 0) {
		return -1;
	}
	privileged_state = 1;
	rc = setegid(powergid);
	/*
	 * Sad but true, for security reasons we can't call
	 * cl_untaint_coredumps() here - because it might cause an
	 * leak of confidential information for some applications.
	 * So, the applications need to use either cl_untaint_coredumps()
	 * when they change privileges, or they need to call
	 * cl_set_all_coredump_signal_handlers() to handle core dump
	 * signals and set their privileges to maximum before core
	 * dumping.  See the comments in coredumps.c for more details.
	 */
	return rc;
}

int	/* Return to "nobody" level of privs (if any) */
return_to_dropped_privs(void)
{
	int rc;

	if (!anysaveduid) {
		return 0;
	}
	setegid(nobodygid);
	privileged_state = 0;
	rc =  seteuid(nobodyuid);
	/* See note above about dumping core */
	return rc;
}

/* Return TRUE if we have full privileges at the moment */
int
cl_have_full_privs(void)
{
	return privileged_state != 0;
}
#endif