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 Iterator functions for getting all gid's from current_user.
27 ****************************************************************************/
29 gid_t
get_current_user_gid_first(int *piterator
)
32 return current_user
.ut
.gid
;
35 gid_t
get_current_user_gid_next(int *piterator
)
39 if (!current_user
.ut
.groups
|| *piterator
>= current_user
.ut
.ngroups
) {
43 ret
= current_user
.ut
.groups
[*piterator
];
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
;
57 /* Don't need to free() this as its stored in a static */
58 pass
= getpwnam_alloc(NULL
, lp_guestaccount());
64 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
66 initgroups(pass
->pw_name
, pass
->pw_gid
);
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
;
80 /*******************************************************************
81 Check if a username is OK.
82 ********************************************************************/
84 static bool check_user_ok(connection_struct
*conn
, user_struct
*vuser
,int snum
)
87 struct vuid_cache_entry
*ent
= NULL
;
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
;
100 if (!user_ok_token(vuser
->user
.unix_name
, vuser
->nt_user_token
, snum
))
103 readonly_share
= is_share_read_only_for_token(vuser
->user
.unix_name
,
104 vuser
->nt_user_token
,
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
),
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
),
122 FILE_READ_DATA
: FILE_WRITE_DATA
)) {
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
;
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
,
152 NT_USER_TOKEN
*token
= conn
->nt_user_token
;
154 if (!user_ok_token(unix_name
, token
, snum
)) {
158 conn
->read_only
= is_share_read_only_for_token(unix_name
,
162 if (!conn
->read_only
&&
163 !share_access_check(token
, lp_servicename(snum
),
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
),
174 FILE_READ_DATA
: FILE_WRITE_DATA
)) {
178 conn
->admin_user
= token_contains_name_in_list(
179 unix_name
, NULL
, token
,
180 lp_admin_users(SNUM(conn
)));
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
);
199 bool must_free_token
= False
;
200 NT_USER_TOKEN
*token
= NULL
;
202 gid_t
*group_list
= NULL
;
205 DEBUG(2,("change_to_user: Connection not open\n"));
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 "
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 "
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
)));
237 } else if ((sec
== SEC_SHARE
) && !check_user_ok_sharelevel_security(conn
,
239 DEBUG(2,("change_to_user: unix user %s "
240 "not permitted access to share %s.\n",
242 lp_servicename(snum
)));
246 if (conn
->force_user
) /* security = share sets this too */ {
249 group_list
= conn
->groups
;
250 num_groups
= conn
->ngroups
;
251 token
= conn
->nt_user_token
;
253 uid
= conn
->admin_user
? 0 : vuser
->uid
;
255 num_groups
= vuser
->n_groups
;
256 group_list
= vuser
->groups
;
257 token
= vuser
->nt_user_token
;
259 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
260 "share %s.\n",vuid
, lp_servicename(snum
) ));
265 * See if we should force group for this service.
266 * If so this overrides any group set in the force
270 if((group_c
= *lp_force_group(snum
))) {
272 token
= dup_nt_token(NULL
, token
);
274 DEBUG(0, ("dup_nt_token failed\n"));
277 must_free_token
= True
;
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.
289 for (i
= 0; i
< num_groups
; i
++) {
290 if (group_list
[i
] == conn
->gid
) {
292 gid_to_sid(&token
->user_sids
[1], gid
);
298 gid_to_sid(&token
->user_sids
[1], gid
);
302 /* Now set current_user since we will immediately also call
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
,
312 * Free the new token (as set_sec_ctx copies it).
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()));
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)
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
;
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
)
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
);
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
368 ****************************************************************************/
370 bool unbecome_authenticated_pipe_user(void)
372 return pop_sec_ctx();
375 /****************************************************************************
376 Utility functions used by become_xxx/unbecome_xxx.
377 ****************************************************************************/
380 connection_struct
*conn
;
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
;
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");
451 /* Unbecome the root user */
453 void unbecome_root(void)
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
)
471 if (!change_to_user(conn
, vuid
)) {
480 bool unbecome_user(void)