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 int get_current_groups(int *p_ngroups, gid_t **p_groups)
132 int ngroups = sys_getgroups(0,&grp);
141 if((groups = (gid_t *)malloc(sizeof(gid_t)*ngroups)) == NULL) {
142 DEBUG(0,("setup_groups malloc fail !\n"));
146 if ((ngroups = sys_getgroups(ngroups,groups)) == -1)
149 (*p_ngroups) = ngroups;
150 (*p_groups) = groups;
152 DEBUG( 3, ( "get_current_groups: uid %u is in %u groups: ", (unsigned int)getuid() , ngroups ) );
153 for (i = 0; i < ngroups; i++ ) {
154 DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
156 DEBUG( 3, ( "\n" ) );
161 /* Create a new security context on the stack. It is the same as the old
162 one. User changes are done using the set_sec_ctx() function. */
164 BOOL push_sec_ctx(void)
166 struct sec_ctx *ctx_p;
168 /* Check we don't overflow our stack */
170 if (sec_ctx_stack_ndx == (MAX_SEC_CTX_DEPTH)) {
171 DEBUG(0, ("Security context stack overflow!\n"));
175 /* Store previous user context */
179 ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
181 ctx_p->uid = geteuid();
182 ctx_p->gid = getegid();
184 ctx_p->ngroups = sys_getgroups(0, NULL);
186 if (ctx_p->ngroups != 0) {
187 if (!(ctx_p->groups = malloc(ctx_p->ngroups * sizeof(gid_t)))) {
188 DEBUG(0, ("Out of memory in push_sec_ctx()\n"));
192 sys_getgroups(ctx_p->ngroups, ctx_p->groups);
194 ctx_p->groups = NULL;
200 /* Set the current security context to a given user */
202 void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
204 struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
206 /* Set the security context */
208 DEBUG(3, ("setting sec ctx (%d, %d)\n", uid, gid));
212 #ifdef HAVE_SETGROUPS
213 sys_setgroups(ngroups, groups);
216 ctx_p->ngroups = ngroups;
218 safe_free(ctx_p->groups);
220 ctx_p->groups = memdup(groups, sizeof(gid_t) * ngroups);
227 /* Update current_user stuff */
229 current_user.uid = uid;
230 current_user.gid = gid;
231 current_user.ngroups = ngroups;
232 current_user.groups = groups;
235 /* Become root context */
237 void set_root_sec_ctx(void)
239 /* May need to worry about supplementary groups at some stage */
241 set_sec_ctx(0, 0, 0, NULL);
244 /* Pop a security context from the stack */
246 BOOL pop_sec_ctx(void)
248 struct sec_ctx *ctx_p;
249 struct sec_ctx *prev_ctx_p;
251 /* Check for stack underflow */
253 if (sec_ctx_stack_ndx == 0) {
254 DEBUG(0, ("Security context stack underflow!\n"));
258 ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
260 /* Clear previous user info */
262 ctx_p->uid = (uid_t)-1;
263 ctx_p->gid = (gid_t)-1;
265 safe_free(ctx_p->groups);
268 /* Pop back previous user */
274 prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
276 #ifdef HAVE_SETGROUPS
277 sys_setgroups(prev_ctx_p->ngroups, prev_ctx_p->groups);
280 become_id(prev_ctx_p->uid, prev_ctx_p->gid);
282 /* Update current_user stuff */
284 current_user.uid = prev_ctx_p->uid;
285 current_user.gid = prev_ctx_p->gid;
286 current_user.ngroups = prev_ctx_p->ngroups;
287 current_user.groups = prev_ctx_p->groups;
289 DEBUG(3, ("popped off to sec ctx (%d, %d)\n", geteuid(), getegid()));
294 /* Initialise the security context system */
296 void init_sec_ctx(void)
299 struct sec_ctx *ctx_p;
301 /* Initialise security context stack */
303 memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH);
305 for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
306 sec_ctx_stack[i].uid = (uid_t)-1;
307 sec_ctx_stack[i].gid = (gid_t)-1;
310 /* Initialise first level of stack. It is the current context */
311 ctx_p = &sec_ctx_stack[0];
313 ctx_p->uid = geteuid();
314 ctx_p->gid = getegid();
316 get_current_groups(&ctx_p->ngroups, &ctx_p->groups);
318 /* Initialise current_user global */
320 current_user.uid = ctx_p->uid;
321 current_user.gid = ctx_p->gid;
322 current_user.ngroups = ctx_p->ngroups;
323 current_user.groups = ctx_p->groups;
325 /* The conn and vuid are usually taken care of by other modules.
326 We initialise them here. */
328 current_user.conn = NULL;
329 current_user.vuid = UID_FIELD_INVALID;