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/>.
21 #include "system/passwd.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../librpc/gen_ndr/netlogon.h"
25 #include "libcli/security/security.h"
26 #include "passdb/lookup_sid.h"
28 /* what user is current? */
29 extern struct current_user current_user;
31 /****************************************************************************
32 Become the guest user without changing the security context stack.
33 ****************************************************************************/
35 bool change_to_guest(void)
39 pass = Get_Pwnam_alloc(talloc_tos(), lp_guestaccount());
45 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
47 initgroups(pass->pw_name, pass->pw_gid);
50 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
52 current_user.conn = NULL;
53 current_user.vuid = UID_FIELD_INVALID;
60 /****************************************************************************
61 talloc free the conn->session_info if not used in the vuid cache.
62 ****************************************************************************/
64 static void free_conn_session_info_if_unused(connection_struct *conn)
68 for (i = 0; i < VUID_CACHE_SIZE; i++) {
69 struct vuid_cache_entry *ent;
70 ent = &conn->vuid_cache.array[i];
71 if (ent->vuid != UID_FIELD_INVALID &&
72 conn->session_info == ent->session_info) {
76 /* Not used, safe to free. */
77 TALLOC_FREE(conn->session_info);
80 /*******************************************************************
81 Check if a username is OK.
83 This sets up conn->session_info with a copy related to this vuser that
84 later code can then mess with.
85 ********************************************************************/
87 static bool check_user_ok(connection_struct *conn,
89 const struct auth_serversupplied_info *session_info,
92 bool valid_vuid = (vuid != UID_FIELD_INVALID);
98 struct vuid_cache_entry *ent;
100 for (i=0; i<VUID_CACHE_SIZE; i++) {
101 ent = &conn->vuid_cache.array[i];
102 if (ent->vuid == vuid) {
103 free_conn_session_info_if_unused(conn);
104 conn->session_info = ent->session_info;
105 conn->read_only = ent->read_only;
111 if (!user_ok_token(session_info->unix_name,
112 session_info->info3->base.domain.string,
113 session_info->security_token, snum))
116 readonly_share = is_share_read_only_for_token(
117 session_info->unix_name,
118 session_info->info3->base.domain.string,
119 session_info->security_token,
122 if (!readonly_share &&
123 !share_access_check(session_info->security_token, lp_servicename(snum),
125 /* smb.conf allows r/w, but the security descriptor denies
126 * write. Fall back to looking at readonly. */
127 readonly_share = True;
128 DEBUG(5,("falling back to read-only access-evaluation due to "
129 "security descriptor\n"));
132 if (!share_access_check(session_info->security_token, lp_servicename(snum),
134 FILE_READ_DATA : FILE_WRITE_DATA)) {
138 admin_user = token_contains_name_in_list(
139 session_info->unix_name,
140 session_info->info3->base.domain.string,
141 NULL, session_info->security_token, lp_admin_users(snum));
144 struct vuid_cache_entry *ent =
145 &conn->vuid_cache.array[conn->vuid_cache.next_entry];
147 conn->vuid_cache.next_entry =
148 (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
150 TALLOC_FREE(ent->session_info);
153 * If force_user was set, all session_info's are based on the same
154 * username-based faked one.
157 ent->session_info = copy_serverinfo(
158 conn, conn->force_user ? conn->session_info : session_info);
160 if (ent->session_info == NULL) {
161 ent->vuid = UID_FIELD_INVALID;
166 ent->read_only = readonly_share;
167 free_conn_session_info_if_unused(conn);
168 conn->session_info = ent->session_info;
171 conn->read_only = readonly_share;
173 DEBUG(2,("check_user_ok: user %s is an admin user. "
174 "Setting uid as %d\n",
175 conn->session_info->unix_name,
176 sec_initial_uid() ));
177 conn->session_info->utok.uid = sec_initial_uid();
183 /****************************************************************************
184 Clear a vuid out of the connection's vuid cache
185 This is only called on SMBulogoff.
186 ****************************************************************************/
188 void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid)
192 for (i=0; i<VUID_CACHE_SIZE; i++) {
193 struct vuid_cache_entry *ent;
195 ent = &conn->vuid_cache.array[i];
197 if (ent->vuid == vuid) {
198 ent->vuid = UID_FIELD_INVALID;
200 * We need to keep conn->session_info around
201 * if it's equal to ent->session_info as a SMBulogoff
202 * is often followed by a SMBtdis (with an invalid
203 * vuid). The debug code (or regular code in
204 * vfs_full_audit) wants to refer to the
205 * conn->session_info pointer to print debug
206 * statements. Theoretically this is a bug,
207 * as once the vuid is gone the session_info
208 * on the conn struct isn't valid any more,
209 * but there's enough code that assumes
210 * conn->session_info is never null that
211 * it's easier to hold onto the old pointer
212 * until we get a new sessionsetupX.
213 * As everything is hung off the
214 * conn pointer as a talloc context we're not
215 * leaking memory here. See bug #6315. JRA.
217 if (conn->session_info == ent->session_info) {
218 ent->session_info = NULL;
220 TALLOC_FREE(ent->session_info);
222 ent->read_only = False;
227 /****************************************************************************
228 Become the user of a connection number without changing the security context
229 stack, but modify the current_user entries.
230 ****************************************************************************/
232 bool change_to_user(connection_struct *conn, uint16 vuid)
234 const struct auth_serversupplied_info *session_info = NULL;
241 gid_t *group_list = NULL;
244 DEBUG(2,("change_to_user: Connection not open\n"));
248 vuser = get_valid_user_struct(conn->sconn, vuid);
251 * We need a separate check in security=share mode due to vuid
252 * always being UID_FIELD_INVALID. If we don't do this then
253 * in share mode security we are *always* changing uid's between
254 * SMB's - this hurts performance - Badly.
257 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
258 (current_user.ut.uid == conn->session_info->utok.uid)) {
259 DEBUG(4,("change_to_user: Skipping user change - already "
262 } else if ((current_user.conn == conn) &&
263 (vuser != NULL) && (current_user.vuid == vuid) &&
264 (current_user.ut.uid == vuser->session_info->utok.uid)) {
265 DEBUG(4,("change_to_user: Skipping user change - already "
272 session_info = vuser ? vuser->session_info : conn->session_info;
275 /* Invalid vuid sent - even with security = share. */
276 DEBUG(2,("change_to_user: Invalid vuid %d used on "
277 "share %s.\n",vuid, lp_servicename(snum) ));
281 if (!check_user_ok(conn, vuid, session_info, snum)) {
282 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
283 "not permitted access to share %s.\n",
284 session_info->sanitized_username,
285 session_info->unix_name, vuid,
286 lp_servicename(snum)));
290 /* security = share sets force_user. */
291 if (!conn->force_user && !vuser) {
292 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
293 "share %s.\n",vuid, lp_servicename(snum) ));
298 * conn->session_info is now correctly set up with a copy we can mess
299 * with for force_group etc.
302 uid = conn->session_info->utok.uid;
303 gid = conn->session_info->utok.gid;
304 num_groups = conn->session_info->utok.ngroups;
305 group_list = conn->session_info->utok.groups;
308 * See if we should force group for this service.
309 * If so this overrides any group set in the force
313 if((group_c = *lp_force_group(snum))) {
315 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
320 * Only force group if the user is a member of
321 * the service group. Check the group memberships for
322 * this user (we already have this) to
323 * see if we should force the group.
327 for (i = 0; i < num_groups; i++) {
329 == conn->force_group_gid) {
330 conn->session_info->utok.gid =
331 conn->force_group_gid;
332 gid = conn->force_group_gid;
333 gid_to_sid(&conn->session_info->security_token
339 conn->session_info->utok.gid = conn->force_group_gid;
340 gid = conn->force_group_gid;
341 gid_to_sid(&conn->session_info->security_token->sids[1],
346 /* Now set current_user since we will immediately also call
349 current_user.ut.ngroups = num_groups;
350 current_user.ut.groups = group_list;
352 set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
353 conn->session_info->security_token);
355 current_user.conn = conn;
356 current_user.vuid = vuid;
358 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
359 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
364 /****************************************************************************
365 Go back to being root without changing the security context stack,
366 but modify the current_user entries.
367 ****************************************************************************/
369 bool change_to_root_user(void)
373 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
374 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
376 current_user.conn = NULL;
377 current_user.vuid = UID_FIELD_INVALID;
382 /****************************************************************************
383 Become the user of an authenticated connected named pipe.
384 When this is called we are currently running as the connection
385 user. Doesn't modify current_user.
386 ****************************************************************************/
388 bool become_authenticated_pipe_user(struct pipes_struct *p)
393 set_sec_ctx(p->session_info->utok.uid, p->session_info->utok.gid,
394 p->session_info->utok.ngroups, p->session_info->utok.groups,
395 p->session_info->security_token);
400 /****************************************************************************
401 Unbecome the user of an authenticated connected named pipe.
402 When this is called we are running as the authenticated pipe
403 user and need to go back to being the connection user. Doesn't modify
405 ****************************************************************************/
407 bool unbecome_authenticated_pipe_user(void)
409 return pop_sec_ctx();
412 /****************************************************************************
413 Utility functions used by become_xxx/unbecome_xxx.
414 ****************************************************************************/
416 static void push_conn_ctx(void)
418 struct conn_ctx *ctx_p;
420 /* Check we don't overflow our stack */
422 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
423 DEBUG(0, ("Connection context stack overflow!\n"));
424 smb_panic("Connection context stack overflow!\n");
427 /* Store previous user context */
428 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
430 ctx_p->conn = current_user.conn;
431 ctx_p->vuid = current_user.vuid;
433 DEBUG(4, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
434 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
436 conn_ctx_stack_ndx++;
439 static void pop_conn_ctx(void)
441 struct conn_ctx *ctx_p;
443 /* Check for stack underflow. */
445 if (conn_ctx_stack_ndx == 0) {
446 DEBUG(0, ("Connection context stack underflow!\n"));
447 smb_panic("Connection context stack underflow!\n");
450 conn_ctx_stack_ndx--;
451 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
453 current_user.conn = ctx_p->conn;
454 current_user.vuid = ctx_p->vuid;
457 ctx_p->vuid = UID_FIELD_INVALID;
460 /****************************************************************************
461 Temporarily become a root user. Must match with unbecome_root(). Saves and
462 restores the connection context.
463 ****************************************************************************/
465 void become_root(void)
468 * no good way to handle push_sec_ctx() failing without changing
469 * the prototype of become_root()
471 if (!push_sec_ctx()) {
472 smb_panic("become_root: push_sec_ctx failed");
478 /* Unbecome the root user */
480 void unbecome_root(void)
486 /****************************************************************************
487 Push the current security context then force a change via change_to_user().
488 Saves and restores the connection context.
489 ****************************************************************************/
491 bool become_user(connection_struct *conn, uint16 vuid)
498 if (!change_to_user(conn, vuid)) {
507 bool unbecome_user(void)
514 /****************************************************************************
515 Return the current user we are running effectively as on this connection.
516 I'd like to make this return conn->session_info->utok.uid, but become_root()
517 doesn't alter this value.
518 ****************************************************************************/
520 uid_t get_current_uid(connection_struct *conn)
522 return current_user.ut.uid;
525 /****************************************************************************
526 Return the current group we are running effectively as on this connection.
527 I'd like to make this return conn->session_info->utok.gid, but become_root()
528 doesn't alter this value.
529 ****************************************************************************/
531 gid_t get_current_gid(connection_struct *conn)
533 return current_user.ut.gid;
536 /****************************************************************************
537 Return the UNIX token we are running effectively as on this connection.
538 I'd like to make this return &conn->session_info->utok, but become_root()
539 doesn't alter this value.
540 ****************************************************************************/
542 const struct security_unix_token *get_current_utok(connection_struct *conn)
544 return ¤t_user.ut;
547 const struct security_token *get_current_nttok(connection_struct *conn)
549 return current_user.nt_user_token;
552 uint16_t get_current_vuid(connection_struct *conn)
554 return current_user.vuid;