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"
30 /* what user is current? */
31 extern struct current_user current_user;
33 /****************************************************************************
34 Become the guest user without changing the security context stack.
35 ****************************************************************************/
37 bool change_to_guest(void)
41 pass = Get_Pwnam_alloc(talloc_tos(), lp_guestaccount());
47 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
49 initgroups(pass->pw_name, pass->pw_gid);
52 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
54 current_user.conn = NULL;
55 current_user.vuid = UID_FIELD_INVALID;
62 /****************************************************************************
63 talloc free the conn->session_info if not used in the vuid cache.
64 ****************************************************************************/
66 static void free_conn_session_info_if_unused(connection_struct *conn)
70 for (i = 0; i < VUID_CACHE_SIZE; i++) {
71 struct vuid_cache_entry *ent;
72 ent = &conn->vuid_cache.array[i];
73 if (ent->vuid != UID_FIELD_INVALID &&
74 conn->session_info == ent->session_info) {
78 /* Not used, safe to free. */
79 TALLOC_FREE(conn->session_info);
82 /*******************************************************************
83 Check if a username is OK.
85 This sets up conn->session_info with a copy related to this vuser that
86 later code can then mess with.
87 ********************************************************************/
89 static bool check_user_ok(connection_struct *conn,
91 const struct auth_serversupplied_info *session_info,
94 bool valid_vuid = (vuid != UID_FIELD_INVALID);
100 struct vuid_cache_entry *ent;
102 for (i=0; i<VUID_CACHE_SIZE; i++) {
103 ent = &conn->vuid_cache.array[i];
104 if (ent->vuid == vuid) {
105 free_conn_session_info_if_unused(conn);
106 conn->session_info = ent->session_info;
107 conn->read_only = ent->read_only;
113 if (!user_ok_token(session_info->unix_name,
114 session_info->info3->base.domain.string,
115 session_info->security_token, snum))
118 readonly_share = is_share_read_only_for_token(
119 session_info->unix_name,
120 session_info->info3->base.domain.string,
121 session_info->security_token,
124 if (!readonly_share &&
125 !share_access_check(session_info->security_token, lp_servicename(snum),
127 /* smb.conf allows r/w, but the security descriptor denies
128 * write. Fall back to looking at readonly. */
129 readonly_share = True;
130 DEBUG(5,("falling back to read-only access-evaluation due to "
131 "security descriptor\n"));
134 if (!share_access_check(session_info->security_token, lp_servicename(snum),
136 FILE_READ_DATA : FILE_WRITE_DATA)) {
140 admin_user = token_contains_name_in_list(
141 session_info->unix_name,
142 session_info->info3->base.domain.string,
143 NULL, session_info->security_token, lp_admin_users(snum));
146 struct vuid_cache_entry *ent =
147 &conn->vuid_cache.array[conn->vuid_cache.next_entry];
149 conn->vuid_cache.next_entry =
150 (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
152 TALLOC_FREE(ent->session_info);
155 * If force_user was set, all session_info's are based on the same
156 * username-based faked one.
159 ent->session_info = copy_serverinfo(
160 conn, conn->force_user ? conn->session_info : session_info);
162 if (ent->session_info == NULL) {
163 ent->vuid = UID_FIELD_INVALID;
168 ent->read_only = readonly_share;
169 free_conn_session_info_if_unused(conn);
170 conn->session_info = ent->session_info;
173 conn->read_only = readonly_share;
175 DEBUG(2,("check_user_ok: user %s is an admin user. "
176 "Setting uid as %d\n",
177 conn->session_info->unix_name,
178 sec_initial_uid() ));
179 conn->session_info->utok.uid = sec_initial_uid();
185 /****************************************************************************
186 Clear a vuid out of the connection's vuid cache
187 This is only called on SMBulogoff.
188 ****************************************************************************/
190 void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid)
194 for (i=0; i<VUID_CACHE_SIZE; i++) {
195 struct vuid_cache_entry *ent;
197 ent = &conn->vuid_cache.array[i];
199 if (ent->vuid == vuid) {
200 ent->vuid = UID_FIELD_INVALID;
202 * We need to keep conn->session_info around
203 * if it's equal to ent->session_info as a SMBulogoff
204 * is often followed by a SMBtdis (with an invalid
205 * vuid). The debug code (or regular code in
206 * vfs_full_audit) wants to refer to the
207 * conn->session_info pointer to print debug
208 * statements. Theoretically this is a bug,
209 * as once the vuid is gone the session_info
210 * on the conn struct isn't valid any more,
211 * but there's enough code that assumes
212 * conn->session_info is never null that
213 * it's easier to hold onto the old pointer
214 * until we get a new sessionsetupX.
215 * As everything is hung off the
216 * conn pointer as a talloc context we're not
217 * leaking memory here. See bug #6315. JRA.
219 if (conn->session_info == ent->session_info) {
220 ent->session_info = NULL;
222 TALLOC_FREE(ent->session_info);
224 ent->read_only = False;
229 /****************************************************************************
230 Become the user of a connection number without changing the security context
231 stack, but modify the current_user entries.
232 ****************************************************************************/
234 bool change_to_user(connection_struct *conn, uint16 vuid)
236 const struct auth_serversupplied_info *session_info = NULL;
243 gid_t *group_list = NULL;
246 DEBUG(2,("change_to_user: Connection not open\n"));
250 vuser = get_valid_user_struct(conn->sconn, vuid);
253 * We need a separate check in security=share mode due to vuid
254 * always being UID_FIELD_INVALID. If we don't do this then
255 * in share mode security we are *always* changing uid's between
256 * SMB's - this hurts performance - Badly.
259 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
260 (current_user.ut.uid == conn->session_info->utok.uid)) {
261 DEBUG(4,("change_to_user: Skipping user change - already "
264 } else if ((current_user.conn == conn) &&
265 (vuser != NULL) && (current_user.vuid == vuid) &&
266 (current_user.ut.uid == vuser->session_info->utok.uid)) {
267 DEBUG(4,("change_to_user: Skipping user change - already "
274 session_info = vuser ? vuser->session_info : conn->session_info;
277 /* Invalid vuid sent - even with security = share. */
278 DEBUG(2,("change_to_user: Invalid vuid %d used on "
279 "share %s.\n",vuid, lp_servicename(snum) ));
283 if (!check_user_ok(conn, vuid, session_info, snum)) {
284 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
285 "not permitted access to share %s.\n",
286 session_info->sanitized_username,
287 session_info->unix_name, vuid,
288 lp_servicename(snum)));
292 /* security = share sets force_user. */
293 if (!conn->force_user && !vuser) {
294 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
295 "share %s.\n",vuid, lp_servicename(snum) ));
300 * conn->session_info is now correctly set up with a copy we can mess
301 * with for force_group etc.
304 uid = conn->session_info->utok.uid;
305 gid = conn->session_info->utok.gid;
306 num_groups = conn->session_info->utok.ngroups;
307 group_list = conn->session_info->utok.groups;
310 * See if we should force group for this service.
311 * If so this overrides any group set in the force
315 if((group_c = *lp_force_group(snum))) {
317 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
322 * Only force group if the user is a member of
323 * the service group. Check the group memberships for
324 * this user (we already have this) to
325 * see if we should force the group.
329 for (i = 0; i < num_groups; i++) {
331 == conn->force_group_gid) {
332 conn->session_info->utok.gid =
333 conn->force_group_gid;
334 gid = conn->force_group_gid;
335 gid_to_sid(&conn->session_info->security_token
341 conn->session_info->utok.gid = conn->force_group_gid;
342 gid = conn->force_group_gid;
343 gid_to_sid(&conn->session_info->security_token->sids[1],
348 /* Now set current_user since we will immediately also call
351 current_user.ut.ngroups = num_groups;
352 current_user.ut.groups = group_list;
354 set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
355 conn->session_info->security_token);
357 current_user.conn = conn;
358 current_user.vuid = vuid;
360 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
361 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
366 /****************************************************************************
367 Go back to being root without changing the security context stack,
368 but modify the current_user entries.
369 ****************************************************************************/
371 bool change_to_root_user(void)
375 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
376 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
378 current_user.conn = NULL;
379 current_user.vuid = UID_FIELD_INVALID;
384 /****************************************************************************
385 Become the user of an authenticated connected named pipe.
386 When this is called we are currently running as the connection
387 user. Doesn't modify current_user.
388 ****************************************************************************/
390 bool become_authenticated_pipe_user(struct pipes_struct *p)
395 set_sec_ctx(p->session_info->utok.uid, p->session_info->utok.gid,
396 p->session_info->utok.ngroups, p->session_info->utok.groups,
397 p->session_info->security_token);
402 /****************************************************************************
403 Unbecome the user of an authenticated connected named pipe.
404 When this is called we are running as the authenticated pipe
405 user and need to go back to being the connection user. Doesn't modify
407 ****************************************************************************/
409 bool unbecome_authenticated_pipe_user(void)
411 return pop_sec_ctx();
414 /****************************************************************************
415 Utility functions used by become_xxx/unbecome_xxx.
416 ****************************************************************************/
418 static void push_conn_ctx(void)
420 struct conn_ctx *ctx_p;
422 /* Check we don't overflow our stack */
424 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
425 DEBUG(0, ("Connection context stack overflow!\n"));
426 smb_panic("Connection context stack overflow!\n");
429 /* Store previous user context */
430 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
432 ctx_p->conn = current_user.conn;
433 ctx_p->vuid = current_user.vuid;
435 DEBUG(4, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
436 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
438 conn_ctx_stack_ndx++;
441 static void pop_conn_ctx(void)
443 struct conn_ctx *ctx_p;
445 /* Check for stack underflow. */
447 if (conn_ctx_stack_ndx == 0) {
448 DEBUG(0, ("Connection context stack underflow!\n"));
449 smb_panic("Connection context stack underflow!\n");
452 conn_ctx_stack_ndx--;
453 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
455 current_user.conn = ctx_p->conn;
456 current_user.vuid = ctx_p->vuid;
459 ctx_p->vuid = UID_FIELD_INVALID;
462 /****************************************************************************
463 Temporarily become a root user. Must match with unbecome_root(). Saves and
464 restores the connection context.
465 ****************************************************************************/
467 void become_root(void)
470 * no good way to handle push_sec_ctx() failing without changing
471 * the prototype of become_root()
473 if (!push_sec_ctx()) {
474 smb_panic("become_root: push_sec_ctx failed");
480 /* Unbecome the root user */
482 void unbecome_root(void)
488 /****************************************************************************
489 Push the current security context then force a change via change_to_user().
490 Saves and restores the connection context.
491 ****************************************************************************/
493 bool become_user(connection_struct *conn, uint16 vuid)
500 if (!change_to_user(conn, vuid)) {
509 bool unbecome_user(void)
516 /****************************************************************************
517 Return the current user we are running effectively as on this connection.
518 I'd like to make this return conn->session_info->utok.uid, but become_root()
519 doesn't alter this value.
520 ****************************************************************************/
522 uid_t get_current_uid(connection_struct *conn)
524 return current_user.ut.uid;
527 /****************************************************************************
528 Return the current group we are running effectively as on this connection.
529 I'd like to make this return conn->session_info->utok.gid, but become_root()
530 doesn't alter this value.
531 ****************************************************************************/
533 gid_t get_current_gid(connection_struct *conn)
535 return current_user.ut.gid;
538 /****************************************************************************
539 Return the UNIX token we are running effectively as on this connection.
540 I'd like to make this return &conn->session_info->utok, but become_root()
541 doesn't alter this value.
542 ****************************************************************************/
544 const struct security_unix_token *get_current_utok(connection_struct *conn)
546 return ¤t_user.ut;
549 const struct security_token *get_current_nttok(connection_struct *conn)
551 return current_user.nt_user_token;
554 uint16_t get_current_vuid(connection_struct *conn)
556 return current_user.vuid;