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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /* what user is current? */
24 extern struct current_user current_user
;
26 /****************************************************************************
27 Iterator functions for getting all gid's from current_user.
28 ****************************************************************************/
30 gid_t
get_current_user_gid_first(int *piterator
)
33 return current_user
.ut
.gid
;
36 gid_t
get_current_user_gid_next(int *piterator
)
40 if (!current_user
.ut
.groups
|| *piterator
>= current_user
.ut
.ngroups
) {
44 ret
= current_user
.ut
.groups
[*piterator
];
49 /****************************************************************************
50 Become the guest user without changing the security context stack.
51 ****************************************************************************/
53 BOOL
change_to_guest(void)
55 static struct passwd
*pass
=NULL
;
58 /* Don't need to free() this as its stored in a static */
59 pass
= getpwnam_alloc(NULL
, lp_guestaccount());
65 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
67 initgroups(pass
->pw_name
, pass
->pw_gid
);
70 set_sec_ctx(pass
->pw_uid
, pass
->pw_gid
, 0, NULL
, NULL
);
72 current_user
.conn
= NULL
;
73 current_user
.vuid
= UID_FIELD_INVALID
;
81 /*******************************************************************
82 Check if a username is OK.
83 ********************************************************************/
85 static BOOL
check_user_ok(connection_struct
*conn
, user_struct
*vuser
,int snum
)
88 struct vuid_cache_entry
*ent
= NULL
;
92 for (i
=0;i
<conn
->vuid_cache
.entries
&& i
< VUID_CACHE_SIZE
;i
++) {
93 if (conn
->vuid_cache
.array
[i
].vuid
== vuser
->vuid
) {
94 ent
= &conn
->vuid_cache
.array
[i
];
95 conn
->read_only
= ent
->read_only
;
96 conn
->admin_user
= ent
->admin_user
;
101 if (!user_ok_token(vuser
->user
.unix_name
, vuser
->nt_user_token
, snum
))
104 readonly_share
= is_share_read_only_for_token(vuser
->user
.unix_name
,
105 vuser
->nt_user_token
,
108 token
= conn
->nt_user_token
?
109 conn
->nt_user_token
: vuser
->nt_user_token
;
111 if (!readonly_share
&&
112 !share_access_check(token
, lp_servicename(snum
),
114 /* smb.conf allows r/w, but the security descriptor denies
115 * write. Fall back to looking at readonly. */
116 readonly_share
= True
;
117 DEBUG(5,("falling back to read-only access-evaluation due to "
118 "security descriptor\n"));
121 if (!share_access_check(token
, lp_servicename(snum
),
123 FILE_READ_DATA
: FILE_WRITE_DATA
)) {
127 i
= conn
->vuid_cache
.entries
% VUID_CACHE_SIZE
;
128 if (conn
->vuid_cache
.entries
< VUID_CACHE_SIZE
)
129 conn
->vuid_cache
.entries
++;
131 ent
= &conn
->vuid_cache
.array
[i
];
132 ent
->vuid
= vuser
->vuid
;
133 ent
->read_only
= readonly_share
;
135 ent
->admin_user
= token_contains_name_in_list(
136 vuser
->user
.unix_name
, NULL
, vuser
->nt_user_token
,
137 lp_admin_users(SNUM(conn
)));
139 conn
->read_only
= ent
->read_only
;
140 conn
->admin_user
= ent
->admin_user
;
145 /*******************************************************************
146 Check if a username is OK in share level security.
147 ********************************************************************/
149 static bool check_user_ok_sharelevel_security(connection_struct
*conn
,
150 const char *unix_name
,
153 NT_USER_TOKEN
*token
= conn
->nt_user_token
;
155 if (!user_ok_token(unix_name
, token
, snum
)) {
159 conn
->read_only
= is_share_read_only_for_token(unix_name
,
163 if (!conn
->read_only
&&
164 !share_access_check(token
, lp_servicename(snum
),
166 /* smb.conf allows r/w, but the security descriptor denies
167 * write. Fall back to looking at readonly. */
168 conn
->read_only
= true;
169 DEBUG(5,("falling back to read-only access-evaluation due to "
170 "security descriptor\n"));
173 if (!share_access_check(token
, lp_servicename(snum
),
175 FILE_READ_DATA
: FILE_WRITE_DATA
)) {
179 conn
->admin_user
= token_contains_name_in_list(
180 unix_name
, NULL
, token
,
181 lp_admin_users(SNUM(conn
)));
187 /****************************************************************************
188 Become the user of a connection number without changing the security context
189 stack, but modify the current_user entries.
190 ****************************************************************************/
192 BOOL
change_to_user(connection_struct
*conn
, uint16 vuid
)
194 enum security_types sec
= (enum security_types
)lp_security();
195 user_struct
*vuser
= get_valid_user_struct(vuid
);
200 BOOL must_free_token
= False
;
201 NT_USER_TOKEN
*token
= NULL
;
203 gid_t
*group_list
= NULL
;
206 DEBUG(2,("change_to_user: Connection not open\n"));
211 * We need a separate check in security=share mode due to vuid
212 * always being UID_FIELD_INVALID. If we don't do this then
213 * in share mode security we are *always* changing uid's between
214 * SMB's - this hurts performance - Badly.
217 if((sec
== SEC_SHARE
) && (current_user
.conn
== conn
) &&
218 (current_user
.ut
.uid
== conn
->uid
)) {
219 DEBUG(4,("change_to_user: Skipping user change - already "
222 } else if ((current_user
.conn
== conn
) &&
223 (vuser
!= 0) && (current_user
.vuid
== vuid
) &&
224 (current_user
.ut
.uid
== vuser
->uid
)) {
225 DEBUG(4,("change_to_user: Skipping user change - already "
232 if ((vuser
) && !check_user_ok(conn
, vuser
, snum
)) {
233 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
234 "not permitted access to share %s.\n",
235 vuser
->user
.smb_name
, vuser
->user
.unix_name
, vuid
,
236 lp_servicename(snum
)));
238 } else if ((sec
== SEC_SHARE
) && !check_user_ok_sharelevel_security(conn
,
240 DEBUG(2,("change_to_user: unix user %s "
241 "not permitted access to share %s.\n",
243 lp_servicename(snum
)));
247 if (conn
->force_user
) /* security = share sets this too */ {
250 group_list
= conn
->groups
;
251 num_groups
= conn
->ngroups
;
252 token
= conn
->nt_user_token
;
254 uid
= conn
->admin_user
? 0 : vuser
->uid
;
256 num_groups
= vuser
->n_groups
;
257 group_list
= vuser
->groups
;
258 token
= vuser
->nt_user_token
;
260 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
261 "share %s.\n",vuid
, lp_servicename(snum
) ));
266 * See if we should force group for this service.
267 * If so this overrides any group set in the force
271 if((group_c
= *lp_force_group(snum
))) {
273 token
= dup_nt_token(NULL
, token
);
275 DEBUG(0, ("dup_nt_token failed\n"));
278 must_free_token
= True
;
283 * Only force group if the user is a member of
284 * the service group. Check the group memberships for
285 * this user (we already have this) to
286 * see if we should force the group.
290 for (i
= 0; i
< num_groups
; i
++) {
291 if (group_list
[i
] == conn
->gid
) {
293 gid_to_sid(&token
->user_sids
[1], gid
);
299 gid_to_sid(&token
->user_sids
[1], gid
);
303 /* Now set current_user since we will immediately also call
306 current_user
.ut
.ngroups
= num_groups
;
307 current_user
.ut
.groups
= group_list
;
309 set_sec_ctx(uid
, gid
, current_user
.ut
.ngroups
, current_user
.ut
.groups
,
313 * Free the new token (as set_sec_ctx copies it).
319 current_user
.conn
= conn
;
320 current_user
.vuid
= vuid
;
322 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
323 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
328 /****************************************************************************
329 Go back to being root without changing the security context stack,
330 but modify the current_user entries.
331 ****************************************************************************/
333 BOOL
change_to_root_user(void)
337 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
338 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
340 current_user
.conn
= NULL
;
341 current_user
.vuid
= UID_FIELD_INVALID
;
346 /****************************************************************************
347 Become the user of an authenticated connected named pipe.
348 When this is called we are currently running as the connection
349 user. Doesn't modify current_user.
350 ****************************************************************************/
352 BOOL
become_authenticated_pipe_user(pipes_struct
*p
)
357 set_sec_ctx(p
->pipe_user
.ut
.uid
, p
->pipe_user
.ut
.gid
,
358 p
->pipe_user
.ut
.ngroups
, p
->pipe_user
.ut
.groups
,
359 p
->pipe_user
.nt_user_token
);
364 /****************************************************************************
365 Unbecome the user of an authenticated connected named pipe.
366 When this is called we are running as the authenticated pipe
367 user and need to go back to being the connection user. Doesn't modify
369 ****************************************************************************/
371 BOOL
unbecome_authenticated_pipe_user(void)
373 return pop_sec_ctx();
376 /****************************************************************************
377 Utility functions used by become_xxx/unbecome_xxx.
378 ****************************************************************************/
381 connection_struct
*conn
;
385 /* A stack of current_user connection contexts. */
387 static struct conn_ctx conn_ctx_stack
[MAX_SEC_CTX_DEPTH
];
388 static int conn_ctx_stack_ndx
;
390 static void push_conn_ctx(void)
392 struct conn_ctx
*ctx_p
;
394 /* Check we don't overflow our stack */
396 if (conn_ctx_stack_ndx
== MAX_SEC_CTX_DEPTH
) {
397 DEBUG(0, ("Connection context stack overflow!\n"));
398 smb_panic("Connection context stack overflow!\n");
401 /* Store previous user context */
402 ctx_p
= &conn_ctx_stack
[conn_ctx_stack_ndx
];
404 ctx_p
->conn
= current_user
.conn
;
405 ctx_p
->vuid
= current_user
.vuid
;
407 DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
408 (unsigned int)ctx_p
->vuid
, conn_ctx_stack_ndx
));
410 conn_ctx_stack_ndx
++;
413 static void pop_conn_ctx(void)
415 struct conn_ctx
*ctx_p
;
417 /* Check for stack underflow. */
419 if (conn_ctx_stack_ndx
== 0) {
420 DEBUG(0, ("Connection context stack underflow!\n"));
421 smb_panic("Connection context stack underflow!\n");
424 conn_ctx_stack_ndx
--;
425 ctx_p
= &conn_ctx_stack
[conn_ctx_stack_ndx
];
427 current_user
.conn
= ctx_p
->conn
;
428 current_user
.vuid
= ctx_p
->vuid
;
431 ctx_p
->vuid
= UID_FIELD_INVALID
;
434 /****************************************************************************
435 Temporarily become a root user. Must match with unbecome_root(). Saves and
436 restores the connection context.
437 ****************************************************************************/
439 void become_root(void)
446 /* Unbecome the root user */
448 void unbecome_root(void)
454 /****************************************************************************
455 Push the current security context then force a change via change_to_user().
456 Saves and restores the connection context.
457 ****************************************************************************/
459 BOOL
become_user(connection_struct
*conn
, uint16 vuid
)
466 if (!change_to_user(conn
, vuid
)) {
475 BOOL
unbecome_user(void)