2 Unix SMB/CIFS implementation.
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/>.
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
;
34 /* Don't need to free() this as its stored in a static */
35 pass
= getpwnam_alloc(talloc_autofree_context(), lp_guestaccount());
41 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
43 initgroups(pass
->pw_name
, pass
->pw_gid
);
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
;
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
)
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
) {
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
,
86 const struct auth_serversupplied_info
*server_info
,
89 bool valid_vuid
= (vuid
!= UID_FIELD_INVALID
);
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
;
109 if (!user_ok_token(server_info
->unix_name
,
110 pdb_get_domain(server_info
->sam_account
),
111 server_info
->ptok
, snum
))
114 readonly_share
= is_share_read_only_for_token(
115 server_info
->unix_name
,
116 pdb_get_domain(server_info
->sam_account
),
120 if (!readonly_share
&&
121 !share_access_check(server_info
->ptok
, lp_servicename(snum
),
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
),
132 FILE_READ_DATA
: FILE_WRITE_DATA
)) {
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
));
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
;
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
;
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
)
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
;
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
);
235 gid_t
*group_list
= NULL
;
238 DEBUG(2,("change_to_user: Connection not open\n"));
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 "
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 "
264 server_info
= vuser
? vuser
->server_info
: conn
->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
) ));
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
)));
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
;
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
;
298 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
299 "share %s.\n",vuid
, lp_servicename(snum
) ));
304 * See if we should force group for this service.
305 * If so this overrides any group set in the force
309 if((group_c
= *lp_force_group(snum
))) {
311 SMB_ASSERT(conn
->force_group_gid
!= (gid_t
)-1);
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.
323 for (i
= 0; i
< num_groups
; 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
);
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],
342 /* Now set current_user since we will immediately also call
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()));
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)
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
;
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
)
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
);
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
401 ****************************************************************************/
403 bool unbecome_authenticated_pipe_user(void)
405 return pop_sec_ctx();
408 /****************************************************************************
409 Utility functions used by become_xxx/unbecome_xxx.
410 ****************************************************************************/
413 connection_struct
*conn
;
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
;
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");
484 /* Unbecome the root user */
486 void unbecome_root(void)
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
)
504 if (!change_to_user(conn
, vuid
)) {
513 bool unbecome_user(void)