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
|