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"
29 /* what user is current? */
30 extern struct current_user current_user
;
32 /****************************************************************************
33 Become the guest user without changing the security context stack.
34 ****************************************************************************/
36 bool change_to_guest(void)
40 pass
= Get_Pwnam_alloc(talloc_tos(), lp_guestaccount());
46 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
48 initgroups(pass
->pw_name
, pass
->pw_gid
);
51 set_sec_ctx(pass
->pw_uid
, pass
->pw_gid
, 0, NULL
, NULL
);
53 current_user
.conn
= NULL
;
54 current_user
.vuid
= UID_FIELD_INVALID
;
61 /****************************************************************************
62 talloc free the conn->session_info if not used in the vuid cache.
63 ****************************************************************************/
65 static void free_conn_session_info_if_unused(connection_struct
*conn
)
69 for (i
= 0; i
< VUID_CACHE_SIZE
; i
++) {
70 struct vuid_cache_entry
*ent
;
71 ent
= &conn
->vuid_cache
.array
[i
];
72 if (ent
->vuid
!= UID_FIELD_INVALID
&&
73 conn
->session_info
== ent
->session_info
) {
77 /* Not used, safe to free. */
78 TALLOC_FREE(conn
->session_info
);
81 /*******************************************************************
82 Check if a username is OK.
84 This sets up conn->session_info with a copy related to this vuser that
85 later code can then mess with.
86 ********************************************************************/
88 static bool check_user_ok(connection_struct
*conn
,
90 const struct auth_session_info
*session_info
,
93 bool valid_vuid
= (vuid
!= UID_FIELD_INVALID
);
99 struct vuid_cache_entry
*ent
;
101 for (i
=0; i
<VUID_CACHE_SIZE
; i
++) {
102 ent
= &conn
->vuid_cache
.array
[i
];
103 if (ent
->vuid
== vuid
) {
104 free_conn_session_info_if_unused(conn
);
105 conn
->session_info
= ent
->session_info
;
106 conn
->read_only
= ent
->read_only
;
112 if (!user_ok_token(session_info
->unix_info
->unix_name
,
113 session_info
->info
->domain_name
,
114 session_info
->security_token
, snum
))
117 readonly_share
= is_share_read_only_for_token(
118 session_info
->unix_info
->unix_name
,
119 session_info
->info
->domain_name
,
120 session_info
->security_token
,
123 if (!readonly_share
&&
124 !share_access_check(session_info
->security_token
,
125 lp_servicename(snum
), FILE_WRITE_DATA
,
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
,
135 lp_servicename(snum
),
137 FILE_READ_DATA
: FILE_WRITE_DATA
,
142 admin_user
= token_contains_name_in_list(
143 session_info
->unix_info
->unix_name
,
144 session_info
->info
->domain_name
,
145 NULL
, session_info
->security_token
, lp_admin_users(snum
));
148 struct vuid_cache_entry
*ent
=
149 &conn
->vuid_cache
.array
[conn
->vuid_cache
.next_entry
];
151 conn
->vuid_cache
.next_entry
=
152 (conn
->vuid_cache
.next_entry
+ 1) % VUID_CACHE_SIZE
;
154 TALLOC_FREE(ent
->session_info
);
157 * If force_user was set, all session_info's are based on the same
158 * username-based faked one.
161 ent
->session_info
= copy_session_info(
162 conn
, conn
->force_user
? conn
->session_info
: session_info
);
164 if (ent
->session_info
== NULL
) {
165 ent
->vuid
= UID_FIELD_INVALID
;
170 ent
->read_only
= readonly_share
;
171 free_conn_session_info_if_unused(conn
);
172 conn
->session_info
= ent
->session_info
;
175 conn
->read_only
= readonly_share
;
177 DEBUG(2,("check_user_ok: user %s is an admin user. "
178 "Setting uid as %d\n",
179 conn
->session_info
->unix_info
->unix_name
,
180 sec_initial_uid() ));
181 conn
->session_info
->unix_token
->uid
= sec_initial_uid();
187 /****************************************************************************
188 Become the user of a connection number without changing the security context
189 stack, but modify the current_user entries.
190 ****************************************************************************/
192 static bool change_to_user_internal(connection_struct
*conn
,
193 const struct auth_session_info
*session_info
,
201 gid_t
*group_list
= NULL
;
206 ok
= check_user_ok(conn
, vuid
, session_info
, snum
);
208 DEBUG(2,("SMB user %s (unix user %s) "
209 "not permitted access to share %s.\n",
210 session_info
->unix_info
->sanitized_username
,
211 session_info
->unix_info
->unix_name
,
212 lp_servicename(snum
)));
216 uid
= conn
->session_info
->unix_token
->uid
;
217 gid
= conn
->session_info
->unix_token
->gid
;
218 num_groups
= conn
->session_info
->unix_token
->ngroups
;
219 group_list
= conn
->session_info
->unix_token
->groups
;
222 * See if we should force group for this service. If so this overrides
223 * any group set in the force user code.
225 if((group_c
= *lp_force_group(snum
))) {
227 SMB_ASSERT(conn
->force_group_gid
!= (gid_t
)-1);
229 if (group_c
== '+') {
233 * Only force group if the user is a member of the
234 * service group. Check the group memberships for this
235 * user (we already have this) to see if we should force
238 for (i
= 0; i
< num_groups
; i
++) {
239 if (group_list
[i
] == conn
->force_group_gid
) {
240 conn
->session_info
->unix_token
->gid
=
241 conn
->force_group_gid
;
242 gid
= conn
->force_group_gid
;
243 gid_to_sid(&conn
->session_info
->security_token
249 conn
->session_info
->unix_token
->gid
= conn
->force_group_gid
;
250 gid
= conn
->force_group_gid
;
251 gid_to_sid(&conn
->session_info
->security_token
->sids
[1],
256 /*Set current_user since we will immediately also call set_sec_ctx() */
257 current_user
.ut
.ngroups
= num_groups
;
258 current_user
.ut
.groups
= group_list
;
262 current_user
.ut
.ngroups
,
263 current_user
.ut
.groups
,
264 conn
->session_info
->security_token
);
266 current_user
.conn
= conn
;
267 current_user
.vuid
= vuid
;
269 DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
278 bool change_to_user(connection_struct
*conn
, uint16_t vuid
)
280 const struct auth_session_info
*session_info
= NULL
;
282 int snum
= SNUM(conn
);
285 DEBUG(2,("Connection not open\n"));
289 vuser
= get_valid_user_struct(conn
->sconn
, vuid
);
292 * We need a separate check in security=share mode due to vuid
293 * always being UID_FIELD_INVALID. If we don't do this then
294 * in share mode security we are *always* changing uid's between
295 * SMB's - this hurts performance - Badly.
298 if((lp_security() == SEC_SHARE
) && (current_user
.conn
== conn
) &&
299 (current_user
.ut
.uid
== conn
->session_info
->unix_token
->uid
)) {
300 DEBUG(4,("Skipping user change - already "
303 } else if ((current_user
.conn
== conn
) &&
304 (vuser
!= NULL
) && (current_user
.vuid
== vuid
) &&
305 (current_user
.ut
.uid
== vuser
->session_info
->unix_token
->uid
)) {
306 DEBUG(4,("Skipping user change - already "
311 session_info
= vuser
? vuser
->session_info
: conn
->session_info
;
313 if (session_info
== NULL
) {
314 /* Invalid vuid sent - even with security = share. */
315 DEBUG(2,("Invalid vuid %d used on "
316 "share %s.\n", vuid
, lp_servicename(snum
) ));
320 /* security = share sets force_user. */
321 if (!conn
->force_user
&& vuser
== NULL
) {
322 DEBUG(2,("Invalid vuid used %d in accessing "
323 "share %s.\n", vuid
, lp_servicename(snum
) ));
327 return change_to_user_internal(conn
, session_info
, vuid
);
330 bool change_to_user_by_session(connection_struct
*conn
,
331 const struct auth_session_info
*session_info
)
333 SMB_ASSERT(conn
!= NULL
);
334 SMB_ASSERT(session_info
!= NULL
);
336 if ((current_user
.conn
== conn
) &&
337 (current_user
.ut
.uid
== session_info
->unix_token
->uid
)) {
338 DEBUG(7, ("Skipping user change - already user\n"));
343 return change_to_user_internal(conn
, session_info
, UID_FIELD_INVALID
);
346 /****************************************************************************
347 Go back to being root without changing the security context stack,
348 but modify the current_user entries.
349 ****************************************************************************/
351 bool smbd_change_to_root_user(void)
355 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
356 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
358 current_user
.conn
= NULL
;
359 current_user
.vuid
= UID_FIELD_INVALID
;
364 /****************************************************************************
365 Become the user of an authenticated connected named pipe.
366 When this is called we are currently running as the connection
367 user. Doesn't modify current_user.
368 ****************************************************************************/
370 bool become_authenticated_pipe_user(struct auth_session_info
*session_info
)
375 set_sec_ctx(session_info
->unix_token
->uid
, session_info
->unix_token
->gid
,
376 session_info
->unix_token
->ngroups
, session_info
->unix_token
->groups
,
377 session_info
->security_token
);
382 /****************************************************************************
383 Unbecome the user of an authenticated connected named pipe.
384 When this is called we are running as the authenticated pipe
385 user and need to go back to being the connection user. Doesn't modify
387 ****************************************************************************/
389 bool unbecome_authenticated_pipe_user(void)
391 return pop_sec_ctx();
394 /****************************************************************************
395 Utility functions used by become_xxx/unbecome_xxx.
396 ****************************************************************************/
398 static void push_conn_ctx(void)
400 struct conn_ctx
*ctx_p
;
402 /* Check we don't overflow our stack */
404 if (conn_ctx_stack_ndx
== MAX_SEC_CTX_DEPTH
) {
405 DEBUG(0, ("Connection context stack overflow!\n"));
406 smb_panic("Connection context stack overflow!\n");
409 /* Store previous user context */
410 ctx_p
= &conn_ctx_stack
[conn_ctx_stack_ndx
];
412 ctx_p
->conn
= current_user
.conn
;
413 ctx_p
->vuid
= current_user
.vuid
;
415 DEBUG(4, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
416 (unsigned int)ctx_p
->vuid
, conn_ctx_stack_ndx
));
418 conn_ctx_stack_ndx
++;
421 static void pop_conn_ctx(void)
423 struct conn_ctx
*ctx_p
;
425 /* Check for stack underflow. */
427 if (conn_ctx_stack_ndx
== 0) {
428 DEBUG(0, ("Connection context stack underflow!\n"));
429 smb_panic("Connection context stack underflow!\n");
432 conn_ctx_stack_ndx
--;
433 ctx_p
= &conn_ctx_stack
[conn_ctx_stack_ndx
];
435 current_user
.conn
= ctx_p
->conn
;
436 current_user
.vuid
= ctx_p
->vuid
;
439 ctx_p
->vuid
= UID_FIELD_INVALID
;
442 /****************************************************************************
443 Temporarily become a root user. Must match with unbecome_root(). Saves and
444 restores the connection context.
445 ****************************************************************************/
447 void smbd_become_root(void)
450 * no good way to handle push_sec_ctx() failing without changing
451 * the prototype of become_root()
453 if (!push_sec_ctx()) {
454 smb_panic("become_root: push_sec_ctx failed");
460 /* Unbecome the root user */
462 void smbd_unbecome_root(void)
468 /****************************************************************************
469 Push the current security context then force a change via change_to_user().
470 Saves and restores the connection context.
471 ****************************************************************************/
473 bool become_user(connection_struct
*conn
, uint16 vuid
)
480 if (!change_to_user(conn
, vuid
)) {
489 bool become_user_by_session(connection_struct
*conn
,
490 const struct auth_session_info
*session_info
)
497 if (!change_to_user_by_session(conn
, session_info
)) {
506 bool unbecome_user(void)
513 /****************************************************************************
514 Return the current user we are running effectively as on this connection.
515 I'd like to make this return conn->session_info->unix_token->uid, but become_root()
516 doesn't alter this value.
517 ****************************************************************************/
519 uid_t
get_current_uid(connection_struct
*conn
)
521 return current_user
.ut
.uid
;
524 /****************************************************************************
525 Return the current group we are running effectively as on this connection.
526 I'd like to make this return conn->session_info->unix_token->gid, but become_root()
527 doesn't alter this value.
528 ****************************************************************************/
530 gid_t
get_current_gid(connection_struct
*conn
)
532 return current_user
.ut
.gid
;
535 /****************************************************************************
536 Return the UNIX token we are running effectively as on this connection.
537 I'd like to make this return &conn->session_info->unix_token-> but become_root()
538 doesn't alter this value.
539 ****************************************************************************/
541 const struct security_unix_token
*get_current_utok(connection_struct
*conn
)
543 return ¤t_user
.ut
;
546 const struct security_token
*get_current_nttok(connection_struct
*conn
)
548 return current_user
.nt_user_token
;
551 uint16_t get_current_vuid(connection_struct
*conn
)
553 return current_user
.vuid
;