Move the definition of struct vuid_cache_entry *ent outside blocks.
[Samba/vl.git] / source3 / smbd / uid.c
blob9361e490a3cc597a9736c5b23fdde2b7629c0dd7
1 /*
2 Unix SMB/CIFS implementation.
3 uid/user handling
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/>.
20 #include "includes.h"
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"
27 #include "auth.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)
38 struct passwd *pass;
40 pass = Get_Pwnam_alloc(talloc_tos(), lp_guestaccount());
41 if (!pass) {
42 return false;
45 #ifdef AIX
46 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
47 setting IDs */
48 initgroups(pass->pw_name, pass->pw_gid);
49 #endif
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;
56 TALLOC_FREE(pass);
58 return true;
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)
67 unsigned int i;
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) {
74 return;
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,
89 uint64_t vuid,
90 const struct auth_session_info *session_info,
91 int snum)
93 unsigned int i;
94 bool readonly_share;
95 bool admin_user;
96 struct vuid_cache_entry *ent = NULL;
99 for (i=0; i<VUID_CACHE_SIZE; i++) {
100 ent = &conn->vuid_cache.array[i];
101 if (ent->vuid == vuid) {
102 free_conn_session_info_if_unused(conn);
103 conn->session_info = ent->session_info;
104 conn->read_only = ent->read_only;
105 return(True);
110 if (!user_ok_token(session_info->unix_info->unix_name,
111 session_info->info->domain_name,
112 session_info->security_token, snum))
113 return(False);
115 readonly_share = is_share_read_only_for_token(
116 session_info->unix_info->unix_name,
117 session_info->info->domain_name,
118 session_info->security_token,
119 conn);
121 if (!readonly_share &&
122 !share_access_check(session_info->security_token,
123 lp_servicename(talloc_tos(), snum),
124 FILE_WRITE_DATA,
125 NULL)) {
126 /* smb.conf allows r/w, but the security descriptor denies
127 * write. Fall back to looking at readonly. */
128 readonly_share = True;
129 DEBUG(5,("falling back to read-only access-evaluation due to "
130 "security descriptor\n"));
133 if (!share_access_check(session_info->security_token,
134 lp_servicename(talloc_tos(), snum),
135 readonly_share ?
136 FILE_READ_DATA : FILE_WRITE_DATA,
137 NULL)) {
138 return False;
141 admin_user = token_contains_name_in_list(
142 session_info->unix_info->unix_name,
143 session_info->info->domain_name,
144 NULL, session_info->security_token, lp_admin_users(snum));
147 ent = &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_session_info(
160 conn, conn->force_user ? conn->session_info : session_info);
162 if (ent->session_info == NULL) {
163 ent->vuid = UID_FIELD_INVALID;
164 return false;
167 ent->vuid = vuid;
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;
174 if (admin_user) {
175 DEBUG(2,("check_user_ok: user %s is an admin user. "
176 "Setting uid as %d\n",
177 conn->session_info->unix_info->unix_name,
178 sec_initial_uid() ));
179 conn->session_info->unix_token->uid = sec_initial_uid();
182 return(True);
185 /****************************************************************************
186 Become the user of a connection number without changing the security context
187 stack, but modify the current_user entries.
188 ****************************************************************************/
190 static bool change_to_user_internal(connection_struct *conn,
191 const struct auth_session_info *session_info,
192 uint64_t vuid)
194 int snum;
195 gid_t gid;
196 uid_t uid;
197 char group_c;
198 int num_groups = 0;
199 gid_t *group_list = NULL;
200 bool ok;
202 snum = SNUM(conn);
204 ok = check_user_ok(conn, vuid, session_info, snum);
205 if (!ok) {
206 DEBUG(2,("SMB user %s (unix user %s) "
207 "not permitted access to share %s.\n",
208 session_info->unix_info->sanitized_username,
209 session_info->unix_info->unix_name,
210 lp_servicename(talloc_tos(), snum)));
211 return false;
214 uid = conn->session_info->unix_token->uid;
215 gid = conn->session_info->unix_token->gid;
216 num_groups = conn->session_info->unix_token->ngroups;
217 group_list = conn->session_info->unix_token->groups;
220 * See if we should force group for this service. If so this overrides
221 * any group set in the force user code.
223 if((group_c = *lp_force_group(talloc_tos(), snum))) {
225 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
227 if (group_c == '+') {
228 int i;
231 * Only force group if the user is a member of the
232 * service group. Check the group memberships for this
233 * user (we already have this) to see if we should force
234 * the group.
236 for (i = 0; i < num_groups; i++) {
237 if (group_list[i] == conn->force_group_gid) {
238 conn->session_info->unix_token->gid =
239 conn->force_group_gid;
240 gid = conn->force_group_gid;
241 gid_to_sid(&conn->session_info->security_token
242 ->sids[1], gid);
243 break;
246 } else {
247 conn->session_info->unix_token->gid = conn->force_group_gid;
248 gid = conn->force_group_gid;
249 gid_to_sid(&conn->session_info->security_token->sids[1],
250 gid);
254 /*Set current_user since we will immediately also call set_sec_ctx() */
255 current_user.ut.ngroups = num_groups;
256 current_user.ut.groups = group_list;
258 set_sec_ctx(uid,
259 gid,
260 current_user.ut.ngroups,
261 current_user.ut.groups,
262 conn->session_info->security_token);
264 current_user.conn = conn;
265 current_user.vuid = vuid;
267 DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
268 (int)getuid(),
269 (int)geteuid(),
270 (int)getgid(),
271 (int)getegid()));
273 return true;
276 bool change_to_user(connection_struct *conn, uint64_t vuid)
278 const struct auth_session_info *session_info = NULL;
279 struct user_struct *vuser;
280 int snum = SNUM(conn);
282 if (!conn) {
283 DEBUG(2,("Connection not open\n"));
284 return(False);
287 vuser = get_valid_user_struct(conn->sconn, vuid);
289 if ((current_user.conn == conn) &&
290 (vuser != NULL) && (current_user.vuid == vuid) &&
291 (current_user.ut.uid == vuser->session_info->unix_token->uid)) {
292 DEBUG(4,("Skipping user change - already "
293 "user\n"));
294 return(True);
297 if (vuser == NULL) {
298 /* Invalid vuid sent */
299 DEBUG(2,("Invalid vuid %llu used on share %s.\n",
300 (unsigned long long)vuid, lp_servicename(talloc_tos(),
301 snum)));
302 return false;
305 session_info = vuser->session_info;
307 if (!conn->force_user && vuser == NULL) {
308 DEBUG(2,("Invalid vuid used %llu in accessing share %s.\n",
309 (unsigned long long)vuid,
310 lp_servicename(talloc_tos(), snum)));
311 return False;
314 return change_to_user_internal(conn, session_info, vuid);
317 static bool change_to_user_by_session(connection_struct *conn,
318 const struct auth_session_info *session_info)
320 SMB_ASSERT(conn != NULL);
321 SMB_ASSERT(session_info != NULL);
323 if ((current_user.conn == conn) &&
324 (current_user.ut.uid == session_info->unix_token->uid)) {
325 DEBUG(7, ("Skipping user change - already user\n"));
327 return true;
330 return change_to_user_internal(conn, session_info, UID_FIELD_INVALID);
333 /****************************************************************************
334 Go back to being root without changing the security context stack,
335 but modify the current_user entries.
336 ****************************************************************************/
338 bool smbd_change_to_root_user(void)
340 set_root_sec_ctx();
342 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
343 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
345 current_user.conn = NULL;
346 current_user.vuid = UID_FIELD_INVALID;
348 return(True);
351 /****************************************************************************
352 Become the user of an authenticated connected named pipe.
353 When this is called we are currently running as the connection
354 user. Doesn't modify current_user.
355 ****************************************************************************/
357 bool become_authenticated_pipe_user(struct auth_session_info *session_info)
359 if (!push_sec_ctx())
360 return False;
362 set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
363 session_info->unix_token->ngroups, session_info->unix_token->groups,
364 session_info->security_token);
366 return True;
369 /****************************************************************************
370 Unbecome the user of an authenticated connected named pipe.
371 When this is called we are running as the authenticated pipe
372 user and need to go back to being the connection user. Doesn't modify
373 current_user.
374 ****************************************************************************/
376 bool unbecome_authenticated_pipe_user(void)
378 return pop_sec_ctx();
381 /****************************************************************************
382 Utility functions used by become_xxx/unbecome_xxx.
383 ****************************************************************************/
385 static void push_conn_ctx(void)
387 struct conn_ctx *ctx_p;
389 /* Check we don't overflow our stack */
391 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
392 DEBUG(0, ("Connection context stack overflow!\n"));
393 smb_panic("Connection context stack overflow!\n");
396 /* Store previous user context */
397 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
399 ctx_p->conn = current_user.conn;
400 ctx_p->vuid = current_user.vuid;
402 DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
403 (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
405 conn_ctx_stack_ndx++;
408 static void pop_conn_ctx(void)
410 struct conn_ctx *ctx_p;
412 /* Check for stack underflow. */
414 if (conn_ctx_stack_ndx == 0) {
415 DEBUG(0, ("Connection context stack underflow!\n"));
416 smb_panic("Connection context stack underflow!\n");
419 conn_ctx_stack_ndx--;
420 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
422 current_user.conn = ctx_p->conn;
423 current_user.vuid = ctx_p->vuid;
425 ctx_p->conn = NULL;
426 ctx_p->vuid = UID_FIELD_INVALID;
429 /****************************************************************************
430 Temporarily become a root user. Must match with unbecome_root(). Saves and
431 restores the connection context.
432 ****************************************************************************/
434 void smbd_become_root(void)
437 * no good way to handle push_sec_ctx() failing without changing
438 * the prototype of become_root()
440 if (!push_sec_ctx()) {
441 smb_panic("become_root: push_sec_ctx failed");
443 push_conn_ctx();
444 set_root_sec_ctx();
447 /* Unbecome the root user */
449 void smbd_unbecome_root(void)
451 pop_sec_ctx();
452 pop_conn_ctx();
455 /****************************************************************************
456 Push the current security context then force a change via change_to_user().
457 Saves and restores the connection context.
458 ****************************************************************************/
460 bool become_user(connection_struct *conn, uint64_t vuid)
462 if (!push_sec_ctx())
463 return False;
465 push_conn_ctx();
467 if (!change_to_user(conn, vuid)) {
468 pop_sec_ctx();
469 pop_conn_ctx();
470 return False;
473 return True;
476 bool become_user_by_session(connection_struct *conn,
477 const struct auth_session_info *session_info)
479 if (!push_sec_ctx())
480 return false;
482 push_conn_ctx();
484 if (!change_to_user_by_session(conn, session_info)) {
485 pop_sec_ctx();
486 pop_conn_ctx();
487 return false;
490 return true;
493 bool unbecome_user(void)
495 pop_sec_ctx();
496 pop_conn_ctx();
497 return True;
500 /****************************************************************************
501 Return the current user we are running effectively as on this connection.
502 I'd like to make this return conn->session_info->unix_token->uid, but become_root()
503 doesn't alter this value.
504 ****************************************************************************/
506 uid_t get_current_uid(connection_struct *conn)
508 return current_user.ut.uid;
511 /****************************************************************************
512 Return the current group we are running effectively as on this connection.
513 I'd like to make this return conn->session_info->unix_token->gid, but become_root()
514 doesn't alter this value.
515 ****************************************************************************/
517 gid_t get_current_gid(connection_struct *conn)
519 return current_user.ut.gid;
522 /****************************************************************************
523 Return the UNIX token we are running effectively as on this connection.
524 I'd like to make this return &conn->session_info->unix_token-> but become_root()
525 doesn't alter this value.
526 ****************************************************************************/
528 const struct security_unix_token *get_current_utok(connection_struct *conn)
530 return &current_user.ut;
533 /****************************************************************************
534 Return the Windows token we are running effectively as on this connection.
535 If this is currently a NULL token as we're inside become_root() - a temporary
536 UNIX security override, then we search up the stack for the previous active
537 token.
538 ****************************************************************************/
540 const struct security_token *get_current_nttok(connection_struct *conn)
542 if (current_user.nt_user_token) {
543 return current_user.nt_user_token;
545 return sec_ctx_active_token();
548 uint64_t get_current_vuid(connection_struct *conn)
550 return current_user.vuid;