Fix coverity CID-602. Possible use of uninitialized var.
[Samba.git] / source / smbd / uid.c
blob52780698a0baa802cae1739ff846892c4d70b73f
1 /*
2 Unix SMB/CIFS implementation.
3 uid/user handling
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
22 /* what user is current? */
23 extern struct current_user current_user;
25 /****************************************************************************
26 Iterator functions for getting all gid's from current_user.
27 ****************************************************************************/
29 gid_t get_current_user_gid_first(int *piterator)
31 *piterator = 0;
32 return current_user.ut.gid;
35 gid_t get_current_user_gid_next(int *piterator)
37 gid_t ret;
39 if (!current_user.ut.groups || *piterator >= current_user.ut.ngroups) {
40 return (gid_t)-1;
43 ret = current_user.ut.groups[*piterator];
44 (*piterator) += 1;
45 return ret;
48 /****************************************************************************
49 Become the guest user without changing the security context stack.
50 ****************************************************************************/
52 bool change_to_guest(void)
54 static struct passwd *pass=NULL;
56 if (!pass) {
57 /* Don't need to free() this as its stored in a static */
58 pass = getpwnam_alloc(NULL, lp_guestaccount());
59 if (!pass)
60 return(False);
63 #ifdef AIX
64 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
65 setting IDs */
66 initgroups(pass->pw_name, pass->pw_gid);
67 #endif
69 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
71 current_user.conn = NULL;
72 current_user.vuid = UID_FIELD_INVALID;
74 TALLOC_FREE(pass);
75 pass = NULL;
77 return True;
80 /*******************************************************************
81 Check if a username is OK.
82 ********************************************************************/
84 static bool check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
86 unsigned int i;
87 struct vuid_cache_entry *ent = NULL;
88 bool readonly_share;
89 NT_USER_TOKEN *token;
91 for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
92 if (conn->vuid_cache.array[i].vuid == vuser->vuid) {
93 ent = &conn->vuid_cache.array[i];
94 conn->read_only = ent->read_only;
95 conn->admin_user = ent->admin_user;
96 return(True);
100 if (!user_ok_token(vuser->user.unix_name, vuser->nt_user_token, snum))
101 return(False);
103 readonly_share = is_share_read_only_for_token(vuser->user.unix_name,
104 vuser->nt_user_token,
105 conn);
107 token = conn->nt_user_token ?
108 conn->nt_user_token : vuser->nt_user_token;
110 if (!readonly_share &&
111 !share_access_check(token, lp_servicename(snum),
112 FILE_WRITE_DATA)) {
113 /* smb.conf allows r/w, but the security descriptor denies
114 * write. Fall back to looking at readonly. */
115 readonly_share = True;
116 DEBUG(5,("falling back to read-only access-evaluation due to "
117 "security descriptor\n"));
120 if (!share_access_check(token, lp_servicename(snum),
121 readonly_share ?
122 FILE_READ_DATA : FILE_WRITE_DATA)) {
123 return False;
126 i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
127 if (conn->vuid_cache.entries < VUID_CACHE_SIZE)
128 conn->vuid_cache.entries++;
130 ent = &conn->vuid_cache.array[i];
131 ent->vuid = vuser->vuid;
132 ent->read_only = readonly_share;
134 ent->admin_user = token_contains_name_in_list(
135 vuser->user.unix_name, NULL, vuser->nt_user_token,
136 lp_admin_users(SNUM(conn)));
138 conn->read_only = ent->read_only;
139 conn->admin_user = ent->admin_user;
141 return(True);
144 /*******************************************************************
145 Check if a username is OK in share level security.
146 ********************************************************************/
148 static bool check_user_ok_sharelevel_security(connection_struct *conn,
149 const char *unix_name,
150 int snum)
152 NT_USER_TOKEN *token = conn->nt_user_token;
154 if (!user_ok_token(unix_name, token, snum)) {
155 return false;
158 conn->read_only = is_share_read_only_for_token(unix_name,
159 token,
160 conn);
162 if (!conn->read_only &&
163 !share_access_check(token, lp_servicename(snum),
164 FILE_WRITE_DATA)) {
165 /* smb.conf allows r/w, but the security descriptor denies
166 * write. Fall back to looking at readonly. */
167 conn->read_only = true;
168 DEBUG(5,("falling back to read-only access-evaluation due to "
169 "security descriptor\n"));
172 if (!share_access_check(token, lp_servicename(snum),
173 conn->read_only ?
174 FILE_READ_DATA : FILE_WRITE_DATA)) {
175 return false;
178 conn->admin_user = token_contains_name_in_list(
179 unix_name, NULL, token,
180 lp_admin_users(SNUM(conn)));
182 return true;
186 /****************************************************************************
187 Become the user of a connection number without changing the security context
188 stack, but modify the current_user entries.
189 ****************************************************************************/
191 bool change_to_user(connection_struct *conn, uint16 vuid)
193 enum security_types sec = (enum security_types)lp_security();
194 user_struct *vuser = get_valid_user_struct(vuid);
195 int snum;
196 gid_t gid;
197 uid_t uid;
198 char group_c;
199 bool must_free_token = False;
200 NT_USER_TOKEN *token = NULL;
201 int num_groups = 0;
202 gid_t *group_list = NULL;
204 if (!conn) {
205 DEBUG(2,("change_to_user: Connection not open\n"));
206 return(False);
210 * We need a separate check in security=share mode due to vuid
211 * always being UID_FIELD_INVALID. If we don't do this then
212 * in share mode security we are *always* changing uid's between
213 * SMB's - this hurts performance - Badly.
216 if((sec == SEC_SHARE) && (current_user.conn == conn) &&
217 (current_user.ut.uid == conn->uid)) {
218 DEBUG(4,("change_to_user: Skipping user change - already "
219 "user\n"));
220 return(True);
221 } else if ((current_user.conn == conn) &&
222 (vuser != 0) && (current_user.vuid == vuid) &&
223 (current_user.ut.uid == vuser->uid)) {
224 DEBUG(4,("change_to_user: Skipping user change - already "
225 "user\n"));
226 return(True);
229 snum = SNUM(conn);
231 if ((vuser) && !check_user_ok(conn, vuser, snum)) {
232 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
233 "not permitted access to share %s.\n",
234 vuser->user.smb_name, vuser->user.unix_name, vuid,
235 lp_servicename(snum)));
236 return False;
237 } else if ((sec == SEC_SHARE) && !check_user_ok_sharelevel_security(conn,
238 conn->user, snum)) {
239 DEBUG(2,("change_to_user: unix user %s "
240 "not permitted access to share %s.\n",
241 conn->user,
242 lp_servicename(snum)));
243 return false;
246 if (conn->force_user) /* security = share sets this too */ {
247 uid = conn->uid;
248 gid = conn->gid;
249 group_list = conn->groups;
250 num_groups = conn->ngroups;
251 token = conn->nt_user_token;
252 } else if (vuser) {
253 uid = conn->admin_user ? 0 : vuser->uid;
254 gid = vuser->gid;
255 num_groups = vuser->n_groups;
256 group_list = vuser->groups;
257 token = vuser->nt_user_token;
258 } else {
259 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
260 "share %s.\n",vuid, lp_servicename(snum) ));
261 return False;
265 * See if we should force group for this service.
266 * If so this overrides any group set in the force
267 * user code.
270 if((group_c = *lp_force_group(snum))) {
272 token = dup_nt_token(NULL, token);
273 if (token == NULL) {
274 DEBUG(0, ("dup_nt_token failed\n"));
275 return False;
277 must_free_token = True;
279 if(group_c == '+') {
282 * Only force group if the user is a member of
283 * the service group. Check the group memberships for
284 * this user (we already have this) to
285 * see if we should force the group.
288 int i;
289 for (i = 0; i < num_groups; i++) {
290 if (group_list[i] == conn->gid) {
291 gid = conn->gid;
292 gid_to_sid(&token->user_sids[1], gid);
293 break;
296 } else {
297 gid = conn->gid;
298 gid_to_sid(&token->user_sids[1], gid);
302 /* Now set current_user since we will immediately also call
303 set_sec_ctx() */
305 current_user.ut.ngroups = num_groups;
306 current_user.ut.groups = group_list;
308 set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
309 token);
312 * Free the new token (as set_sec_ctx copies it).
315 if (must_free_token)
316 TALLOC_FREE(token);
318 current_user.conn = conn;
319 current_user.vuid = vuid;
321 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
322 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
324 return(True);
327 /****************************************************************************
328 Go back to being root without changing the security context stack,
329 but modify the current_user entries.
330 ****************************************************************************/
332 bool change_to_root_user(void)
334 set_root_sec_ctx();
336 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
337 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
339 current_user.conn = NULL;
340 current_user.vuid = UID_FIELD_INVALID;
342 return(True);
345 /****************************************************************************
346 Become the user of an authenticated connected named pipe.
347 When this is called we are currently running as the connection
348 user. Doesn't modify current_user.
349 ****************************************************************************/
351 bool become_authenticated_pipe_user(pipes_struct *p)
353 if (!push_sec_ctx())
354 return False;
356 set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid,
357 p->pipe_user.ut.ngroups, p->pipe_user.ut.groups,
358 p->pipe_user.nt_user_token);
360 return True;
363 /****************************************************************************
364 Unbecome the user of an authenticated connected named pipe.
365 When this is called we are running as the authenticated pipe
366 user and need to go back to being the connection user. Doesn't modify
367 current_user.
368 ****************************************************************************/
370 bool unbecome_authenticated_pipe_user(void)
372 return pop_sec_ctx();
375 /****************************************************************************
376 Utility functions used by become_xxx/unbecome_xxx.
377 ****************************************************************************/
379 struct conn_ctx {
380 connection_struct *conn;
381 uint16 vuid;
384 /* A stack of current_user connection contexts. */
386 static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
387 static int conn_ctx_stack_ndx;
389 static void push_conn_ctx(void)
391 struct conn_ctx *ctx_p;
393 /* Check we don't overflow our stack */
395 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
396 DEBUG(0, ("Connection context stack overflow!\n"));
397 smb_panic("Connection context stack overflow!\n");
400 /* Store previous user context */
401 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
403 ctx_p->conn = current_user.conn;
404 ctx_p->vuid = current_user.vuid;
406 DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
407 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
409 conn_ctx_stack_ndx++;
412 static void pop_conn_ctx(void)
414 struct conn_ctx *ctx_p;
416 /* Check for stack underflow. */
418 if (conn_ctx_stack_ndx == 0) {
419 DEBUG(0, ("Connection context stack underflow!\n"));
420 smb_panic("Connection context stack underflow!\n");
423 conn_ctx_stack_ndx--;
424 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
426 current_user.conn = ctx_p->conn;
427 current_user.vuid = ctx_p->vuid;
429 ctx_p->conn = NULL;
430 ctx_p->vuid = UID_FIELD_INVALID;
433 /****************************************************************************
434 Temporarily become a root user. Must match with unbecome_root(). Saves and
435 restores the connection context.
436 ****************************************************************************/
438 void become_root(void)
441 * no good way to handle push_sec_ctx() failing without changing
442 * the prototype of become_root()
444 if (!push_sec_ctx()) {
445 smb_panic("become_root: push_sec_ctx failed");
447 push_conn_ctx();
448 set_root_sec_ctx();
451 /* Unbecome the root user */
453 void unbecome_root(void)
455 pop_sec_ctx();
456 pop_conn_ctx();
459 /****************************************************************************
460 Push the current security context then force a change via change_to_user().
461 Saves and restores the connection context.
462 ****************************************************************************/
464 bool become_user(connection_struct *conn, uint16 vuid)
466 if (!push_sec_ctx())
467 return False;
469 push_conn_ctx();
471 if (!change_to_user(conn, vuid)) {
472 pop_sec_ctx();
473 pop_conn_ctx();
474 return False;
477 return True;
480 bool unbecome_user(void)
482 pop_sec_ctx();
483 pop_conn_ctx();
484 return True;