s3: Fix an uninitialized variable reference
[Samba.git] / source / smbd / uid.c
blob02aadbe59e6658f041926959392c832a975b77ff
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 Become the guest user without changing the security context stack.
27 ****************************************************************************/
29 bool change_to_guest(void)
31 static struct passwd *pass=NULL;
33 if (!pass) {
34 /* Don't need to free() this as its stored in a static */
35 pass = getpwnam_alloc(talloc_autofree_context(), lp_guestaccount());
36 if (!pass)
37 return(False);
40 #ifdef AIX
41 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
42 setting IDs */
43 initgroups(pass->pw_name, pass->pw_gid);
44 #endif
46 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
48 current_user.conn = NULL;
49 current_user.vuid = UID_FIELD_INVALID;
51 TALLOC_FREE(pass);
52 pass = NULL;
54 return True;
57 /****************************************************************************
58 talloc free the conn->server_info if not used in the vuid cache.
59 ****************************************************************************/
61 static void free_conn_server_info_if_unused(connection_struct *conn)
63 unsigned int i;
65 for (i = 0; i < VUID_CACHE_SIZE; i++) {
66 struct vuid_cache_entry *ent;
67 ent = &conn->vuid_cache.array[i];
68 if (ent->vuid != UID_FIELD_INVALID &&
69 conn->server_info == ent->server_info) {
70 return;
73 /* Not used, safe to free. */
74 TALLOC_FREE(conn->server_info);
77 /*******************************************************************
78 Check if a username is OK.
80 This sets up conn->server_info with a copy related to this vuser that
81 later code can then mess with.
82 ********************************************************************/
84 static bool check_user_ok(connection_struct *conn,
85 uint16_t vuid,
86 const struct auth_serversupplied_info *server_info,
87 int snum)
89 bool valid_vuid = (vuid != UID_FIELD_INVALID);
90 unsigned int i;
91 bool readonly_share;
92 bool admin_user;
94 if (valid_vuid) {
95 struct vuid_cache_entry *ent;
97 for (i=0; i<VUID_CACHE_SIZE; i++) {
98 ent = &conn->vuid_cache.array[i];
99 if (ent->vuid == vuid) {
100 free_conn_server_info_if_unused(conn);
101 conn->server_info = ent->server_info;
102 conn->read_only = ent->read_only;
103 conn->admin_user = ent->admin_user;
104 return(True);
109 if (!user_ok_token(server_info->unix_name,
110 pdb_get_domain(server_info->sam_account),
111 server_info->ptok, snum))
112 return(False);
114 readonly_share = is_share_read_only_for_token(
115 server_info->unix_name,
116 pdb_get_domain(server_info->sam_account),
117 server_info->ptok,
118 conn);
120 if (!readonly_share &&
121 !share_access_check(server_info->ptok, lp_servicename(snum),
122 FILE_WRITE_DATA)) {
123 /* smb.conf allows r/w, but the security descriptor denies
124 * write. Fall back to looking at readonly. */
125 readonly_share = True;
126 DEBUG(5,("falling back to read-only access-evaluation due to "
127 "security descriptor\n"));
130 if (!share_access_check(server_info->ptok, lp_servicename(snum),
131 readonly_share ?
132 FILE_READ_DATA : FILE_WRITE_DATA)) {
133 return False;
136 admin_user = token_contains_name_in_list(
137 server_info->unix_name,
138 pdb_get_domain(server_info->sam_account),
139 NULL, server_info->ptok, lp_admin_users(snum));
141 if (valid_vuid) {
142 struct vuid_cache_entry *ent =
143 &conn->vuid_cache.array[conn->vuid_cache.next_entry];
145 conn->vuid_cache.next_entry =
146 (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
148 TALLOC_FREE(ent->server_info);
151 * If force_user was set, all server_info's are based on the same
152 * username-based faked one.
155 ent->server_info = copy_serverinfo(
156 conn, conn->force_user ? conn->server_info : server_info);
158 if (ent->server_info == NULL) {
159 ent->vuid = UID_FIELD_INVALID;
160 return false;
163 ent->vuid = vuid;
164 ent->read_only = readonly_share;
165 ent->admin_user = admin_user;
166 free_conn_server_info_if_unused(conn);
167 conn->server_info = ent->server_info;
170 conn->read_only = readonly_share;
171 conn->admin_user = admin_user;
173 return(True);
176 /****************************************************************************
177 Clear a vuid out of the connection's vuid cache
178 This is only called on SMBulogoff.
179 ****************************************************************************/
181 void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid)
183 int i;
185 for (i=0; i<VUID_CACHE_SIZE; i++) {
186 struct vuid_cache_entry *ent;
188 ent = &conn->vuid_cache.array[i];
190 if (ent->vuid == vuid) {
191 ent->vuid = UID_FIELD_INVALID;
193 * We need to keep conn->server_info around
194 * if it's equal to ent->server_info as a SMBulogoff
195 * is often followed by a SMBtdis (with an invalid
196 * vuid). The debug code (or regular code in
197 * vfs_full_audit) wants to refer to the
198 * conn->server_info pointer to print debug
199 * statements. Theoretically this is a bug,
200 * as once the vuid is gone the server_info
201 * on the conn struct isn't valid any more,
202 * but there's enough code that assumes
203 * conn->server_info is never null that
204 * it's easier to hold onto the old pointer
205 * until we get a new sessionsetupX.
206 * As everything is hung off the
207 * conn pointer as a talloc context we're not
208 * leaking memory here. See bug #6315. JRA.
210 if (conn->server_info == ent->server_info) {
211 ent->server_info = NULL;
212 } else {
213 TALLOC_FREE(ent->server_info);
215 ent->read_only = False;
216 ent->admin_user = False;
221 /****************************************************************************
222 Become the user of a connection number without changing the security context
223 stack, but modify the current_user entries.
224 ****************************************************************************/
226 bool change_to_user(connection_struct *conn, uint16 vuid)
228 const struct auth_serversupplied_info *server_info = NULL;
229 user_struct *vuser = get_valid_user_struct(vuid);
230 int snum;
231 gid_t gid;
232 uid_t uid;
233 char group_c;
234 int num_groups = 0;
235 gid_t *group_list = NULL;
237 if (!conn) {
238 DEBUG(2,("change_to_user: Connection not open\n"));
239 return(False);
243 * We need a separate check in security=share mode due to vuid
244 * always being UID_FIELD_INVALID. If we don't do this then
245 * in share mode security we are *always* changing uid's between
246 * SMB's - this hurts performance - Badly.
249 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
250 (current_user.ut.uid == conn->server_info->utok.uid)) {
251 DEBUG(4,("change_to_user: Skipping user change - already "
252 "user\n"));
253 return(True);
254 } else if ((current_user.conn == conn) &&
255 (vuser != NULL) && (current_user.vuid == vuid) &&
256 (current_user.ut.uid == vuser->server_info->utok.uid)) {
257 DEBUG(4,("change_to_user: Skipping user change - already "
258 "user\n"));
259 return(True);
262 snum = SNUM(conn);
264 server_info = vuser ? vuser->server_info : conn->server_info;
266 if (!server_info) {
267 /* Invalid vuid sent - even with security = share. */
268 DEBUG(2,("change_to_user: Invalid vuid %d used on "
269 "share %s.\n",vuid, lp_servicename(snum) ));
270 return false;
273 if (!check_user_ok(conn, vuid, server_info, snum)) {
274 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
275 "not permitted access to share %s.\n",
276 server_info->sanitized_username,
277 server_info->unix_name, vuid,
278 lp_servicename(snum)));
279 return false;
283 * conn->server_info is now correctly set up with a copy we can mess
284 * with for force_group etc.
287 if (conn->force_user) /* security = share sets this too */ {
288 uid = conn->server_info->utok.uid;
289 gid = conn->server_info->utok.gid;
290 group_list = conn->server_info->utok.groups;
291 num_groups = conn->server_info->utok.ngroups;
292 } else if (vuser) {
293 uid = conn->admin_user ? 0 : vuser->server_info->utok.uid;
294 gid = conn->server_info->utok.gid;
295 num_groups = conn->server_info->utok.ngroups;
296 group_list = conn->server_info->utok.groups;
297 } else {
298 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
299 "share %s.\n",vuid, lp_servicename(snum) ));
300 return False;
304 * See if we should force group for this service.
305 * If so this overrides any group set in the force
306 * user code.
309 if((group_c = *lp_force_group(snum))) {
311 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
313 if(group_c == '+') {
316 * Only force group if the user is a member of
317 * the service group. Check the group memberships for
318 * this user (we already have this) to
319 * see if we should force the group.
322 int i;
323 for (i = 0; i < num_groups; i++) {
324 if (group_list[i]
325 == conn->force_group_gid) {
326 conn->server_info->utok.gid =
327 conn->force_group_gid;
328 gid = conn->force_group_gid;
329 gid_to_sid(&conn->server_info->ptok
330 ->user_sids[1], gid);
331 break;
334 } else {
335 conn->server_info->utok.gid = conn->force_group_gid;
336 gid = conn->force_group_gid;
337 gid_to_sid(&conn->server_info->ptok->user_sids[1],
338 gid);
342 /* Now set current_user since we will immediately also call
343 set_sec_ctx() */
345 current_user.ut.ngroups = num_groups;
346 current_user.ut.groups = group_list;
348 set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
349 conn->server_info->ptok);
351 current_user.conn = conn;
352 current_user.vuid = vuid;
354 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
355 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
357 return(True);
360 /****************************************************************************
361 Go back to being root without changing the security context stack,
362 but modify the current_user entries.
363 ****************************************************************************/
365 bool change_to_root_user(void)
367 set_root_sec_ctx();
369 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
370 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
372 current_user.conn = NULL;
373 current_user.vuid = UID_FIELD_INVALID;
375 return(True);
378 /****************************************************************************
379 Become the user of an authenticated connected named pipe.
380 When this is called we are currently running as the connection
381 user. Doesn't modify current_user.
382 ****************************************************************************/
384 bool become_authenticated_pipe_user(pipes_struct *p)
386 if (!push_sec_ctx())
387 return False;
389 set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid,
390 p->pipe_user.ut.ngroups, p->pipe_user.ut.groups,
391 p->pipe_user.nt_user_token);
393 return True;
396 /****************************************************************************
397 Unbecome the user of an authenticated connected named pipe.
398 When this is called we are running as the authenticated pipe
399 user and need to go back to being the connection user. Doesn't modify
400 current_user.
401 ****************************************************************************/
403 bool unbecome_authenticated_pipe_user(void)
405 return pop_sec_ctx();
408 /****************************************************************************
409 Utility functions used by become_xxx/unbecome_xxx.
410 ****************************************************************************/
412 struct conn_ctx {
413 connection_struct *conn;
414 uint16 vuid;
417 /* A stack of current_user connection contexts. */
419 static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
420 static int conn_ctx_stack_ndx;
422 static void push_conn_ctx(void)
424 struct conn_ctx *ctx_p;
426 /* Check we don't overflow our stack */
428 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
429 DEBUG(0, ("Connection context stack overflow!\n"));
430 smb_panic("Connection context stack overflow!\n");
433 /* Store previous user context */
434 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
436 ctx_p->conn = current_user.conn;
437 ctx_p->vuid = current_user.vuid;
439 DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
440 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
442 conn_ctx_stack_ndx++;
445 static void pop_conn_ctx(void)
447 struct conn_ctx *ctx_p;
449 /* Check for stack underflow. */
451 if (conn_ctx_stack_ndx == 0) {
452 DEBUG(0, ("Connection context stack underflow!\n"));
453 smb_panic("Connection context stack underflow!\n");
456 conn_ctx_stack_ndx--;
457 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
459 current_user.conn = ctx_p->conn;
460 current_user.vuid = ctx_p->vuid;
462 ctx_p->conn = NULL;
463 ctx_p->vuid = UID_FIELD_INVALID;
466 /****************************************************************************
467 Temporarily become a root user. Must match with unbecome_root(). Saves and
468 restores the connection context.
469 ****************************************************************************/
471 void become_root(void)
474 * no good way to handle push_sec_ctx() failing without changing
475 * the prototype of become_root()
477 if (!push_sec_ctx()) {
478 smb_panic("become_root: push_sec_ctx failed");
480 push_conn_ctx();
481 set_root_sec_ctx();
484 /* Unbecome the root user */
486 void unbecome_root(void)
488 pop_sec_ctx();
489 pop_conn_ctx();
492 /****************************************************************************
493 Push the current security context then force a change via change_to_user().
494 Saves and restores the connection context.
495 ****************************************************************************/
497 bool become_user(connection_struct *conn, uint16 vuid)
499 if (!push_sec_ctx())
500 return False;
502 push_conn_ctx();
504 if (!change_to_user(conn, vuid)) {
505 pop_sec_ctx();
506 pop_conn_ctx();
507 return False;
510 return True;
513 bool unbecome_user(void)
515 pop_sec_ctx();
516 pop_conn_ctx();
517 return True;