2 Unix SMB/Netbios implementation.
5 Copyright (C) Tim Potter 2000
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 extern int DEBUGLEVEL;
25 extern struct current_user current_user;
34 /* A stack of security contexts. We include the current context as being
35 the first one, so there is room for another MAX_SEC_CTX_DEPTH more. */
37 static struct sec_ctx sec_ctx_stack[MAX_SEC_CTX_DEPTH + 1];
38 static int sec_ctx_stack_ndx;
40 /* Become the specified uid */
42 static BOOL become_uid(uid_t uid)
44 /* Check for dodgy uid values */
46 if (uid == (uid_t)-1 ||
47 ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) {
51 DEBUG(1,("WARNING: using uid %d is a security risk\n",
57 /* Set effective user id */
59 set_effective_uid(uid);
60 current_user.uid = uid;
63 profile_p->uid_changes++;
69 /* Become the specified gid */
71 static BOOL become_gid(gid_t gid)
73 /* Check for dodgy gid values */
75 if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) &&
76 (gid == (gid_t)65535))) {
80 DEBUG(1,("WARNING: using gid %d is a security risk\n",
86 /* Set effective group id */
88 set_effective_gid(gid);
89 current_user.gid = gid;
94 /* Become the specified uid and gid */
96 static BOOL become_id(uid_t uid, gid_t gid)
98 return become_gid(gid) && become_uid(uid);
101 /* Drop back to root privileges in order to change to another user */
103 static void gain_root(void)
105 if (geteuid() != 0) {
106 set_effective_uid(0);
108 if (geteuid() != 0) {
110 ("Warning: You appear to have a trapdoor "
115 if (getegid() != 0) {
116 set_effective_gid(0);
118 if (getegid() != 0) {
120 ("Warning: You appear to have a trapdoor "
126 /* Get the list of current groups */
128 static void get_current_groups(int *ngroups, gid_t **groups)
130 *ngroups = getgroups(0, NULL);
131 *groups = (gid_t *)malloc(*ngroups * sizeof(gid_t));
134 DEBUG(0, ("Out of memory in get_current_groups\n"));
138 getgroups(*ngroups, *groups);
141 /* Create a new security context on the stack. It is the same as the old
142 one. User changes are done using the set_sec_ctx() function. */
144 BOOL push_sec_ctx(void)
146 /* Check we don't overflow our stack */
148 if (sec_ctx_stack_ndx == (MAX_SEC_CTX_DEPTH)) {
149 DEBUG(0, ("Security context stack overflow!\n"));
153 /* Store previous user context */
157 sec_ctx_stack[sec_ctx_stack_ndx].uid = geteuid();
158 sec_ctx_stack[sec_ctx_stack_ndx].gid = getegid();
160 sec_ctx_stack[sec_ctx_stack_ndx].ngroups = sys_getgroups(0, NULL);
162 if (!(sec_ctx_stack[sec_ctx_stack_ndx].groups =
163 malloc(sec_ctx_stack[sec_ctx_stack_ndx].ngroups *
165 DEBUG(0, ("Out of memory in push_sec_ctx()\n"));
169 sys_getgroups(sec_ctx_stack[sec_ctx_stack_ndx].ngroups,
170 sec_ctx_stack[sec_ctx_stack_ndx].groups);
175 /* Set the current security context to a given user */
177 void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
179 /* Set the security context */
181 DEBUG(3, ("setting sec ctx (%d, %d)\n", uid, gid));
185 #ifdef HAVE_SETGROUPS
186 sys_setgroups(ngroups, groups);
189 sec_ctx_stack[sec_ctx_stack_ndx].ngroups = ngroups;
191 if (sec_ctx_stack[sec_ctx_stack_ndx].groups != NULL)
192 free(sec_ctx_stack[sec_ctx_stack_ndx].groups);
194 sec_ctx_stack[sec_ctx_stack_ndx].groups =
195 memdup(groups, sizeof(gid_t) * ngroups);
199 sec_ctx_stack[sec_ctx_stack_ndx].uid = uid;
200 sec_ctx_stack[sec_ctx_stack_ndx].gid = gid;
202 /* Update current_user stuff */
204 current_user.uid = uid;
205 current_user.gid = gid;
206 current_user.ngroups = ngroups;
207 current_user.groups = groups;
210 /* Become root context */
212 void set_root_sec_ctx(void)
214 /* May need to worry about supplementary groups at some stage */
216 set_sec_ctx(0, 0, 0, NULL);
219 /* Pop a security context from the stack */
221 BOOL pop_sec_ctx(void)
223 /* Check for stack underflow */
225 if (sec_ctx_stack_ndx == 0) {
226 DEBUG(0, ("Security context stack underflow!\n"));
230 /* Clear previous user info */
232 sec_ctx_stack[sec_ctx_stack_ndx].uid = (uid_t)-1;
233 sec_ctx_stack[sec_ctx_stack_ndx].gid = (gid_t)-1;
235 safe_free(sec_ctx_stack[sec_ctx_stack_ndx].groups);
236 sec_ctx_stack[sec_ctx_stack_ndx].ngroups = 0;
238 /* Pop back previous user */
244 #ifdef HAVE_SETGROUPS
245 sys_setgroups(sec_ctx_stack[sec_ctx_stack_ndx].ngroups,
246 sec_ctx_stack[sec_ctx_stack_ndx].groups);
249 become_id(sec_ctx_stack[sec_ctx_stack_ndx].uid,
250 sec_ctx_stack[sec_ctx_stack_ndx].gid);
252 /* Update current_user stuff */
254 current_user.uid = sec_ctx_stack[sec_ctx_stack_ndx].uid;
255 current_user.gid = sec_ctx_stack[sec_ctx_stack_ndx].gid;
256 current_user.ngroups = sec_ctx_stack[sec_ctx_stack_ndx].ngroups;
257 current_user.groups = sec_ctx_stack[sec_ctx_stack_ndx].groups;
259 DEBUG(3, ("popped off to sec ctx (%d, %d)\n", geteuid(), getegid()));
264 /* Initialise the security context system */
266 void init_sec_ctx(void)
270 /* Initialise security context stack */
272 memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH);
274 for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
275 sec_ctx_stack[i].uid = (uid_t)-1;
276 sec_ctx_stack[i].gid = (gid_t)-1;
279 /* Initialise first level of stack. It is the current context */
281 sec_ctx_stack[0].uid = geteuid();
282 sec_ctx_stack[0].gid = getegid();
284 get_current_groups(&sec_ctx_stack[0].ngroups,
285 &sec_ctx_stack[0].groups);
287 /* Initialise current_user global */
289 current_user.uid = sec_ctx_stack[sec_ctx_stack_ndx].uid;
290 current_user.gid = sec_ctx_stack[sec_ctx_stack_ndx].gid;
291 current_user.ngroups = sec_ctx_stack[sec_ctx_stack_ndx].ngroups;
292 current_user.groups = sec_ctx_stack[sec_ctx_stack_ndx].groups;
294 /* The conn and vuid are usually taken care of by other modules.
295 We initialise them here. */
297 current_user.conn = NULL;
298 current_user.vuid = UID_FIELD_INVALID;